From f9e2faf45a54efd2173d8852d3e61e2f0699028f Mon Sep 17 00:00:00 2001 From: Mike Diskett Date: Sat, 20 May 2017 11:14:17 +1000 Subject: [PATCH] first commit --- MFLib1/Headers/Display.h | 125 + MFLib1/Headers/Draw2d.h | 101 + MFLib1/Headers/DrawPoly.h | 8 + MFLib1/Headers/Keyboard.h | 142 + MFLib1/Headers/MFD3D.h | 26 + MFLib1/Headers/MFErrors.h | 46 + MFLib1/Headers/MFFile.h | 41 + MFLib1/Headers/MFHeader.h | 81 + MFLib1/Headers/MFHost.h | 36 + MFLib1/Headers/MFLbType.h | 133 + MFLib1/Headers/MFMaths.h | 70 + MFLib1/Headers/MFMem.h | 12 + MFLib1/Headers/MFStd.h | 16 + MFLib1/Headers/MFTypes.h | 26 + MFLib1/Headers/MFUtils.h | 23 + MFLib1/Headers/Mouse.h | 32 + MFLib1/Headers/Palette.h | 24 + MFLib1/Headers/Sprites.h | 41 + MFLib1/MFLib1.dsp | 242 + MFLib1/Source/C/Common/DModes.cpp | 101 + MFLib1/Source/C/Common/Draw2d.cpp | 265 + MFLib1/Source/C/Common/DrawBox.cpp | 329 + MFLib1/Source/C/Common/DrawLine.cpp | 562 + MFLib1/Source/C/Common/DrawPnt.cpp | 75 + MFLib1/Source/C/Common/DrawPxl.cpp | 59 + MFLib1/Source/C/Common/DrawRect.cpp | 24 + MFLib1/Source/C/Common/Maths.cpp | 145 + MFLib1/Source/C/Common/QuickTxt.cpp | 481 + MFLib1/Source/C/Common/Sprites.cpp | 809 + MFLib1/Source/C/Common/TextDef.cpp | 930 + MFLib1/Source/C/Common/Trig.cpp | 5924 ++++ MFLib1/Source/C/Windows/D3D.cpp | 363 + MFLib1/Source/C/Windows/Display.cpp | 926 + MFLib1/Source/C/Windows/File.cpp | 176 + MFLib1/Source/C/Windows/Keyboard.cpp | 117 + MFLib1/Source/C/Windows/MFHost.cpp | 449 + MFLib1/Source/C/Windows/Mem.cpp | 67 + MFLib1/Source/C/Windows/Mouse.cpp | 17 + MFLib1/Source/C/Windows/Palette.cpp | 245 + MFStdLib/Headers/MFStdLib.h | 312 + MFStdLib/Headers/StdFile.h | 48 + MFStdLib/Headers/StdKeybd.h | 152 + MFStdLib/Headers/StdMaths.h | 44 + MFStdLib/Headers/StdMem.h | 42 + MFStdLib/Headers/StdMouse.h | 31 + MFStdLib/Source/StdLib/StdFile.cpp | 346 + MFStdLib/Source/StdLib/StdMaths.cpp | 6058 +++++ MFStdLib/Source/StdLib/StdMem.cpp | 254 + MuckyBasic/Always.h | 414 + MuckyBasic/Key.h | 133 + MuckyBasic/Matrix.cpp | 450 + MuckyBasic/Matrix.h | 167 + MuckyBasic/Tga.cpp | 343 + MuckyBasic/Tga.h | 80 + MuckyBasic/cg.cpp | 2727 ++ MuckyBasic/cg.h | 32 + MuckyBasic/clip.cpp | 155 + MuckyBasic/clip.h | 22 + MuckyBasic/comp.cpp | 62 + MuckyBasic/comp.h | 18 + MuckyBasic/console.cpp | 300 + MuckyBasic/console.h | 33 + MuckyBasic/d3denum.cpp | 643 + MuckyBasic/d3denum.h | 180 + MuckyBasic/d3dframe.cpp | 755 + MuckyBasic/d3dframe.h | 135 + MuckyBasic/d3dutil.cpp | 394 + MuckyBasic/d3dutil.h | 110 + MuckyBasic/font.cpp | 480 + MuckyBasic/font.h | 37 + MuckyBasic/icon1.ico | Bin 0 -> 3310 bytes MuckyBasic/lex.cpp | 820 + MuckyBasic/lex.h | 161 + MuckyBasic/link.cpp | 975 + MuckyBasic/link.h | 139 + MuckyBasic/ll.cpp | 405 + MuckyBasic/ll.h | 220 + MuckyBasic/main.cpp | 113 + MuckyBasic/mem.cpp | 55 + MuckyBasic/mem.h | 40 + MuckyBasic/ml.h | 243 + MuckyBasic/muckyBASIC.dsp | 291 + MuckyBasic/muckyBASIC.dsw | 37 + MuckyBasic/muckyBASIC.rc | 116 + MuckyBasic/os.cpp | 5945 ++++ MuckyBasic/os.h | 664 + MuckyBasic/parse.cpp | 3994 +++ MuckyBasic/parse.h | 196 + MuckyBasic/resource.h | 85 + MuckyBasic/st.cpp | 400 + MuckyBasic/st.h | 85 + MuckyBasic/sysvar.cpp | 37 + MuckyBasic/sysvar.h | 33 + MuckyBasic/test.mbs | 23 + MuckyBasic/test2.mbs | 32 + MuckyBasic/userdlg.cpp | 384 + MuckyBasic/vm.cpp | 4435 +++ MuckyBasic/vm.h | 17 + MuckyBasic/wave.c | 896 + MuckyBasic/wave.h | 68 + fallen/AutoRun/AutoRun.cpp | 626 + fallen/AutoRun/AutoRun.cur | Bin 0 -> 326 bytes fallen/AutoRun/AutoRun.dsp | 163 + fallen/AutoRun/AutoRun.h | 12 + fallen/AutoRun/AutoRun.ico | Bin 0 -> 1078 bytes fallen/AutoRun/AutoRun.rc | 106 + fallen/AutoRun/Autorun/English.txt | 57 + fallen/AutoRun/Autorun/French.txt | 45 + fallen/AutoRun/Autorun/German.txt | 45 + fallen/AutoRun/Autorun/Spanish.txt | 45 + fallen/AutoRun/Director.cpp | 289 + fallen/AutoRun/Director.h | 72 + fallen/AutoRun/ReadMe.txt | 134 + fallen/AutoRun/StdAfx.cpp | 5 + fallen/AutoRun/StdAfx.h | 22 + fallen/AutoRun/resource.h | 28 + fallen/DDEngine/Headers/BreakTimer.h | 34 + fallen/DDEngine/Headers/Bucket.h | 178 + fallen/DDEngine/Headers/Crinkle.h | 75 + fallen/DDEngine/Headers/DCback.h | 26 + fallen/DDEngine/Headers/DCcredits.h | 14 + fallen/DDEngine/Headers/DCfont.h | 56 + fallen/DDEngine/Headers/DCos.h | 47 + fallen/DDEngine/Headers/DrawXtra.h | 66 + fallen/DDEngine/Headers/Engine.h | 383 + fallen/DDEngine/Headers/Font.h | 101 + fallen/DDEngine/Headers/Gamut.h | 32 + fallen/DDEngine/Headers/Matrix.h | 139 + fallen/DDEngine/Headers/Message.h | 37 + fallen/DDEngine/Headers/NGamut.h | 88 + fallen/DDEngine/Headers/Quaternion.h | 20 + fallen/DDEngine/Headers/Text.h | 21 + fallen/DDEngine/Headers/aa.h | 27 + fallen/DDEngine/Headers/aeng.h | 493 + fallen/DDEngine/Headers/build.h | 24 + fallen/DDEngine/Headers/comp.h | 68 + fallen/DDEngine/Headers/cone.h | 65 + fallen/DDEngine/Headers/console.h | 33 + fallen/DDEngine/Headers/facet.h | 55 + fallen/DDEngine/Headers/fall.h | 55 + fallen/DDEngine/Headers/farfacet.h | 42 + fallen/DDEngine/Headers/fastprim.h | 48 + fallen/DDEngine/Headers/figure.h | 50 + fallen/DDEngine/Headers/flamengine.h | 82 + fallen/DDEngine/Headers/font2d.h | 99 + fallen/DDEngine/Headers/font3d.h | 68 + fallen/DDEngine/Headers/ic.h | 54 + fallen/DDEngine/Headers/map.h | 52 + fallen/DDEngine/Headers/menufont.h | 84 + fallen/DDEngine/Headers/mesh.h | 124 + fallen/DDEngine/Headers/oval.h | 28 + fallen/DDEngine/Headers/pack.h | 17 + fallen/DDEngine/Headers/panel.h | 138 + fallen/DDEngine/Headers/planmap.h | 35 + fallen/DDEngine/Headers/poly.h | 736 + fallen/DDEngine/Headers/polypage.h | 313 + fallen/DDEngine/Headers/polypoint.h | 112 + fallen/DDEngine/Headers/qeng.h | 87 + fallen/DDEngine/Headers/ray.h | 19 + fallen/DDEngine/Headers/renderstate.h | 105 + fallen/DDEngine/Headers/shape.h | 161 + fallen/DDEngine/Headers/sky.h | 88 + fallen/DDEngine/Headers/smap.h | 62 + fallen/DDEngine/Headers/sprite.h | 72 + fallen/DDEngine/Headers/supercrinkle.h | 57 + fallen/DDEngine/Headers/superfacet.h | 43 + fallen/DDEngine/Headers/sw.h | 84 + fallen/DDEngine/Headers/texture.h | 288 + fallen/DDEngine/Headers/truetype.h | 81 + fallen/DDEngine/Headers/vertexbuffer.h | 94 + fallen/DDEngine/Headers/wibble.h | 28 + fallen/DDEngine/Source/Attract.cpp | 40 + fallen/DDEngine/Source/BreakTimer.cpp | 223 + fallen/DDEngine/Source/Bucket.cpp | 20 + fallen/DDEngine/Source/Crinkle.cpp | 984 + fallen/DDEngine/Source/DCback.cpp | 257 + fallen/DDEngine/Source/DCcredits.cpp | 660 + fallen/DDEngine/Source/DCfont.cpp | 575 + fallen/DDEngine/Source/DCos.cpp | 47 + fallen/DDEngine/Source/Font.cpp | 1848 ++ fallen/DDEngine/Source/Gamut.cpp | 100 + fallen/DDEngine/Source/Matrix.cpp | 434 + fallen/DDEngine/Source/Message.cpp | 211 + fallen/DDEngine/Source/NGamut.cpp | 335 + fallen/DDEngine/Source/Quaternion.cpp | 621 + fallen/DDEngine/Source/Temp.cpp | 2410 ++ fallen/DDEngine/Source/Text.cpp | 325 + fallen/DDEngine/Source/aa.cpp | 987 + fallen/DDEngine/Source/aeng.cpp | 17084 ++++++++++++ fallen/DDEngine/Source/build.cpp | 528 + fallen/DDEngine/Source/comp.cpp | 715 + fallen/DDEngine/Source/cone.cpp | 1142 + fallen/DDEngine/Source/console.cpp | 671 + fallen/DDEngine/Source/drawxtra.cpp | 3426 +++ fallen/DDEngine/Source/facet.cpp | 5698 ++++ fallen/DDEngine/Source/farfacet.cpp | 1165 + fallen/DDEngine/Source/fastprim.cpp | 1416 + fallen/DDEngine/Source/figure.cpp | 10243 +++++++ fallen/DDEngine/Source/flamengine.cpp | 793 + fallen/DDEngine/Source/font2d.cpp | 1104 + fallen/DDEngine/Source/font3d.cpp | 457 + fallen/DDEngine/Source/ic.cpp | 319 + fallen/DDEngine/Source/map.cpp | 1858 ++ fallen/DDEngine/Source/menufont.cpp | 1004 + fallen/DDEngine/Source/mesh.cpp | 2311 ++ fallen/DDEngine/Source/oval.cpp | 310 + fallen/DDEngine/Source/pack.cpp | 1492 + fallen/DDEngine/Source/panel.cpp | 6689 +++++ fallen/DDEngine/Source/planmap.cpp | 478 + fallen/DDEngine/Source/poly.cpp | 5028 ++++ fallen/DDEngine/Source/polypage.cpp | 1168 + fallen/DDEngine/Source/polypoint.cpp | 12 + fallen/DDEngine/Source/polyrenderstate.cpp | 1776 ++ fallen/DDEngine/Source/qeng.cpp | 240 + fallen/DDEngine/Source/ray.cpp | 1426 + fallen/DDEngine/Source/renderstate.cpp | 1101 + fallen/DDEngine/Source/shape.cpp | 2178 ++ fallen/DDEngine/Source/sky.cpp | 1195 + fallen/DDEngine/Source/smap.cpp | 1667 ++ fallen/DDEngine/Source/sprite.cpp | 357 + fallen/DDEngine/Source/supercrinkle.cpp | 1105 + fallen/DDEngine/Source/superfacet.cpp | 2341 ++ fallen/DDEngine/Source/sw.cpp | 6438 +++++ fallen/DDEngine/Source/texture.cpp | 3391 +++ fallen/DDEngine/Source/tom.cpp | 1037 + fallen/DDEngine/Source/truetype.cpp | 869 + fallen/DDEngine/Source/vertexbuffer.cpp | 463 + fallen/DDEngine/Source/wibble.cpp | 155 + fallen/DDLibrary/DDlib.rc | 2231 ++ fallen/DDLibrary/Headers/A3DManager.h | 244 + fallen/DDLibrary/Headers/AsyncFile.h | 48 + fallen/DDLibrary/Headers/AsyncFile2.h | 49 + fallen/DDLibrary/Headers/BinkClient.h | 7 + fallen/DDLibrary/Headers/D3DTexture.h | 297 + fallen/DDLibrary/Headers/DCLowLevel.h | 149 + fallen/DDLibrary/Headers/DDManager.h | 309 + fallen/DDLibrary/Headers/DDlib.h | 128 + fallen/DDLibrary/Headers/DIManager.h | 364 + fallen/DDLibrary/Headers/DSManager.h | 48 + fallen/DDLibrary/Headers/Debug.h | 28 + fallen/DDLibrary/Headers/Drive.h | 12 + fallen/DDLibrary/Headers/FFManager.h | 35 + fallen/DDLibrary/Headers/FileClump.h | 32 + fallen/DDLibrary/Headers/GDisplay.h | 467 + fallen/DDLibrary/Headers/GWorkScreen.h | 48 + fallen/DDLibrary/Headers/MFX_Miles.h | 121 + fallen/DDLibrary/Headers/MFx.h | 106 + fallen/DDLibrary/Headers/QSManager.h | 154 + fallen/DDLibrary/Headers/SampleManager.h | 109 + fallen/DDLibrary/Headers/Tga.h | 67 + fallen/DDLibrary/Headers/WindProcs.h | 32 + fallen/DDLibrary/Headers/net.h | 190 + fallen/DDLibrary/Headers/resource.h | 331 + fallen/DDLibrary/Headers/snd_type.h | 19 + fallen/DDLibrary/Source/A3DManager.cpp | 783 + fallen/DDLibrary/Source/AsyncFile.cpp | 155 + fallen/DDLibrary/Source/AsyncFile2.cpp | 319 + fallen/DDLibrary/Source/BinkClient.cpp | 246 + fallen/DDLibrary/Source/D3DTexture.cpp | 4486 +++ fallen/DDLibrary/Source/DCLowLevel.cpp | 2710 ++ fallen/DDLibrary/Source/DDManager.cpp | 2511 ++ fallen/DDLibrary/Source/DIManager.cpp | 2754 ++ fallen/DDLibrary/Source/DSManager.cpp | 80 + fallen/DDLibrary/Source/Drive.cpp | 124 + fallen/DDLibrary/Source/FFManager.cpp | 90 + fallen/DDLibrary/Source/FileClump.cpp | 144 + fallen/DDLibrary/Source/GDebug.cpp | 281 + fallen/DDLibrary/Source/GDisplay.cpp | 6608 +++++ fallen/DDLibrary/Source/GFile.cpp | 209 + fallen/DDLibrary/Source/GHost.cpp | 584 + fallen/DDLibrary/Source/GKeyboard.cpp | 183 + fallen/DDLibrary/Source/GMouse.cpp | 122 + fallen/DDLibrary/Source/GWorkScreen.cpp | 300 + fallen/DDLibrary/Source/MFX_DC.cpp | 845 + fallen/DDLibrary/Source/MFX_Miles.cpp | 2090 ++ fallen/DDLibrary/Source/MFx.cpp | 758 + fallen/DDLibrary/Source/MFx_QMDX.cpp | 670 + fallen/DDLibrary/Source/QSManager.cpp | 670 + fallen/DDLibrary/Source/SampleManager.cpp | 666 + fallen/DDLibrary/Source/Tga.cpp | 1384 + fallen/DDLibrary/Source/WindProcs.cpp | 733 + fallen/DDLibrary/Source/net.cpp | 1179 + fallen/DDLibrary/ahead.bmp | Bin 0 -> 4324 bytes fallen/DDLibrary/arrowcop.cur | Bin 0 -> 326 bytes fallen/DDLibrary/bitmap1.bmp | Bin 0 -> 5162 bytes fallen/DDLibrary/bitmap2.bmp | Bin 0 -> 598 bytes fallen/DDLibrary/bm_red1.bmp | Bin 0 -> 246 bytes fallen/DDLibrary/bm_red2.bmp | Bin 0 -> 246 bytes fallen/DDLibrary/bm_red3.bmp | Bin 0 -> 246 bytes fallen/DDLibrary/bm_red4.bmp | Bin 0 -> 246 bytes fallen/DDLibrary/bm_red5.bmp | Bin 0 -> 246 bytes fallen/DDLibrary/bm_red6.bmp | Bin 0 -> 246 bytes fallen/DDLibrary/bm_red7.bmp | Bin 0 -> 246 bytes fallen/DDLibrary/bmp00001.bmp | Bin 0 -> 2398 bytes fallen/DDLibrary/ico00001.ico | Bin 0 -> 766 bytes fallen/DDLibrary/icon1.ico | Bin 0 -> 7078 bytes fallen/DDLibrary/icon2.ico | Bin 0 -> 1078 bytes fallen/DDLibrary/mucky_lo.bmp | Bin 0 -> 5162 bytes fallen/DDLibrary/rightturn.bmp | Bin 0 -> 4300 bytes fallen/DDLibrary/scene_ic.bmp | Bin 0 -> 958 bytes fallen/DDLibrary/stop.bmp | Bin 0 -> 4232 bytes fallen/DDLibrary/toolbar.bmp | Bin 0 -> 478 bytes fallen/DDLibrary/uturn.BMP | Bin 0 -> 4364 bytes fallen/Debug/Fallen.tlog/CL.command.1.tlog | Bin 0 -> 104568 bytes fallen/Debug/Fallen.tlog/CL.read.1.tlog | Bin 0 -> 191174 bytes fallen/Debug/Fallen.tlog/CL.write.1.tlog | Bin 0 -> 17282 bytes .../Debug/Fallen.tlog/Fallen.lastbuildstate | 2 + fallen/Debug/Fallen.tlog/unsuccessfulbuild | 0 fallen/Editor/Headers/Alert.hpp | 23 + fallen/Editor/Headers/Anim.h | 415 + fallen/Editor/Headers/BuildTab.hpp | 155 + fallen/Editor/Headers/ColTab.hpp | 80 + fallen/Editor/Headers/ComTab.h | 54 + fallen/Editor/Headers/CondTab.h | 54 + fallen/Editor/Headers/Controls.hpp | 283 + fallen/Editor/Headers/CtrlSet.hpp | 66 + fallen/Editor/Headers/DarkCity.h | 8 + fallen/Editor/Headers/EdCom.h | 137 + fallen/Editor/Headers/EdUtils.h | 60 + fallen/Editor/Headers/EdWay.h | 34 + fallen/Editor/Headers/Edit.h | 224 + fallen/Editor/Headers/EditMod.hpp | 43 + fallen/Editor/Headers/Editor.h | 14 + fallen/Editor/Headers/Editor.hpp | 74 + fallen/Editor/Headers/EditorLib.h | 106 + fallen/Editor/Headers/FileReq.hpp | 28 + fallen/Editor/Headers/GameEd.h | 110 + fallen/Editor/Headers/HmTab.hpp | 33 + fallen/Editor/Headers/Icon.hpp | 29 + fallen/Editor/Headers/Intrface.hpp | 96 + fallen/Editor/Headers/KFrameEd.hpp | 135 + fallen/Editor/Headers/KFramer.hpp | 43 + fallen/Editor/Headers/LevelEd.hpp | 97 + fallen/Editor/Headers/LightTab.hpp | 63 + fallen/Editor/Headers/MapEdTab.hpp | 67 + fallen/Editor/Headers/MapTab.hpp | 80 + fallen/Editor/Headers/ModeTab.hpp | 75 + fallen/Editor/Headers/ObjectEd.hpp | 36 + fallen/Editor/Headers/PaintTab.hpp | 122 + fallen/Editor/Headers/Poly.h | 104 + fallen/Editor/Headers/PrPiTab.hpp | 93 + fallen/Editor/Headers/Prim.h | 723 + fallen/Editor/Headers/Primativ.hpp | 47 + fallen/Editor/Headers/SaveTab.h | 44 + fallen/Editor/Headers/Stealth.h | 40 + fallen/Editor/Headers/Structs.h | 78 + fallen/Editor/Headers/TexTab.hpp | 58 + fallen/Editor/Headers/Thing.h | 136 + fallen/Editor/Headers/ThingTab.h | 62 + fallen/Editor/Headers/Window.hpp | 121 + fallen/Editor/Headers/building.hpp | 241 + fallen/Editor/Headers/collide.hpp | 43 + fallen/Editor/Headers/convert.h | 7 + fallen/Editor/Headers/engine.h | 400 + fallen/Editor/Headers/extra.h | 44 + fallen/Editor/Headers/game.h | 10 + fallen/Editor/Headers/macros.h | 50 + fallen/Editor/Headers/map.h | 42 + fallen/Editor/Headers/outline.h | 57 + fallen/Editor/Headers/perstex.h | 35 + fallen/Editor/Headers/prim_draw.h | 24 + fallen/Editor/Headers/prim_edit.h | 35 + fallen/Editor/Headers/primtex.h | 31 + fallen/Editor/Headers/scan.h | 9 + fallen/Editor/Headers/scrflc.h | 152 + fallen/Editor/Headers/sewertab.hpp | 144 + fallen/Editor/Headers/spare.h | 26 + fallen/Editor/Headers/undo.hpp | 90 + fallen/Editor/Library/Draw2d.cpp | 210 + fallen/Editor/Library/DrawBox.cpp | 329 + fallen/Editor/Library/DrawCirc.cpp | 58 + fallen/Editor/Library/DrawLine.cpp | 562 + fallen/Editor/Library/DrawPnt.cpp | 75 + fallen/Editor/Library/DrawPxl.cpp | 59 + fallen/Editor/Library/DrawRect.cpp | 24 + fallen/Editor/Library/QuickTxt.cpp | 487 + fallen/Editor/Library/Sprites.cpp | 815 + fallen/Editor/Library/TextDef.cpp | 937 + fallen/Editor/Source/Alert.cpp | 141 + fallen/Editor/Source/BuildTab.cpp | 5976 ++++ fallen/Editor/Source/ColTab.cpp | 1063 + fallen/Editor/Source/ComTab.cpp | 1148 + fallen/Editor/Source/ComTab.def | 160 + fallen/Editor/Source/CondTab.cpp | 1111 + fallen/Editor/Source/CondTab.def | 154 + fallen/Editor/Source/Control.cpp | 15 + fallen/Editor/Source/Controls.cpp | 1806 ++ fallen/Editor/Source/CtrlSet.cpp | 486 + fallen/Editor/Source/EdCom.cpp | 465 + fallen/Editor/Source/EdText.cpp | 93 + fallen/Editor/Source/EdUtils.cpp | 1153 + fallen/Editor/Source/EdWay.cpp | 141 + fallen/Editor/Source/Edit.cpp | 4842 ++++ fallen/Editor/Source/EditMod.cpp | 183 + fallen/Editor/Source/Editor.cpp | 634 + fallen/Editor/Source/Engine.cpp | 1872 ++ fallen/Editor/Source/FileReq.cpp | 394 + fallen/Editor/Source/Game.cpp | 296 + fallen/Editor/Source/GameEd.cpp | 1912 ++ fallen/Editor/Source/HmTab.cpp | 1589 ++ fallen/Editor/Source/Icon.cpp | 85 + fallen/Editor/Source/Intrface.cpp | 150 + fallen/Editor/Source/KFDef.c | 44 + fallen/Editor/Source/KFDef2.c | 15 + fallen/Editor/Source/KFrameEd.cpp | 6341 +++++ fallen/Editor/Source/KFramer.cpp | 514 + fallen/Editor/Source/LevelEd.cpp | 3798 +++ fallen/Editor/Source/LightTab.cpp | 1593 ++ fallen/Editor/Source/Main.cpp | 583 + fallen/Editor/Source/MapEdTab.cpp | 1450 + fallen/Editor/Source/MapTab.cpp | 1167 + fallen/Editor/Source/ModeTab.cpp | 184 + fallen/Editor/Source/Move.cpp | 65 + fallen/Editor/Source/PaintTab.cpp | 3537 +++ fallen/Editor/Source/Poly.cpp | 5863 ++++ fallen/Editor/Source/PrPiTab.cpp | 2441 ++ fallen/Editor/Source/Primativ.cpp | 283 + fallen/Editor/Source/Quaternion.cpp | 260 + fallen/Editor/Source/SaveTab.cpp | 879 + fallen/Editor/Source/SaveTab.def | 14 + fallen/Editor/Source/Thing.cpp | 139 + fallen/Editor/Source/ThingTab.cpp | 681 + fallen/Editor/Source/ThingTab.def | 263 + fallen/Editor/Source/Window.cpp | 545 + fallen/Editor/Source/building.cpp | 5806 ++++ fallen/Editor/Source/collide.cpp | 2258 ++ fallen/Editor/Source/extra.cpp | 89 + fallen/Editor/Source/hair.cpp | 161 + fallen/Editor/Source/interact.cpp | 1754 ++ fallen/Editor/Source/map.cpp | 9 + fallen/Editor/Source/outline.cpp | 412 + fallen/Editor/Source/pch_ed.cpp | 1 + fallen/Editor/Source/perstex.cpp | 178 + fallen/Editor/Source/prim_draw.cpp | 1189 + fallen/Editor/Source/prim_edit.cpp | 4631 ++++ fallen/Editor/Source/primtex.cpp | 155 + fallen/Editor/Source/scan.cpp | 175 + fallen/Editor/Source/scrflc.cpp | 1107 + fallen/Editor/Source/sewertab.cpp | 3637 +++ fallen/Editor/Source/undo.cpp | 347 + fallen/Fallen.dsp | 975 + fallen/Fallen.sln | 22 + fallen/Fallen.vcxproj | 687 + fallen/Fallen.vcxproj.filters | 661 + fallen/GEdit.dsp | 504 + fallen/GEdit/Headers/CamTargetSetup.h | 17 + fallen/GEdit/Headers/CameraSetup.h | 17 + fallen/GEdit/Headers/EdStrings.h | 51 + fallen/GEdit/Headers/EnemySetup.h | 16 + fallen/GEdit/Headers/EngWind.h | 16 + fallen/GEdit/Headers/GEdit.h | 57 + fallen/GEdit/Headers/ItemSetup.h | 15 + fallen/GEdit/Headers/MapExitSetup.h | 17 + fallen/GEdit/Headers/MapView.h | 61 + fallen/GEdit/Headers/Mission.h | 564 + fallen/GEdit/Headers/PlayerSetup.h | 17 + fallen/GEdit/Headers/SubClass.h | 24 + fallen/GEdit/Headers/TabCtl.h | 48 + fallen/GEdit/Headers/TriggerSetup.h | 14 + fallen/GEdit/Headers/WSpace.h | 89 + fallen/GEdit/Headers/WayWind.h | 17 + fallen/GEdit/Headers/activatesetup.h | 17 + fallen/GEdit/Headers/cutscene.h | 17 + fallen/GEdit/Headers/inputbox.h | 14 + fallen/GEdit/Headers/platformSetup.h | 17 + fallen/GEdit/Headers/propedit.h | 154 + fallen/GEdit/Headers/ticklist.h | 50 + fallen/GEdit/Headers/trapsetup.h | 17 + fallen/GEdit/Headers/waypointSetup.h | 17 + fallen/GEdit/Source/BonusSetup.cpp | 167 + fallen/GEdit/Source/CamTargetSetup.cpp | 116 + fallen/GEdit/Source/CameraSetup.cpp | 135 + fallen/GEdit/Source/CreatureSetup.cpp | 118 + fallen/GEdit/Source/EdStrings.cpp | 799 + fallen/GEdit/Source/EnemySetup.cpp | 467 + fallen/GEdit/Source/EngWind.cpp | 414 + fallen/GEdit/Source/ExtendSetup.cpp | 120 + fallen/GEdit/Source/GEdit.cpp | 1817 ++ fallen/GEdit/Source/ItemSetup.cpp | 152 + fallen/GEdit/Source/MapExitSetup.cpp | 89 + fallen/GEdit/Source/MapView.cpp | 1936 ++ fallen/GEdit/Source/MessageSetup.cpp | 452 + fallen/GEdit/Source/Mission.cpp | 1719 ++ fallen/GEdit/Source/MoveSetup.cpp | 102 + fallen/GEdit/Source/NavSetup.cpp | 157 + fallen/GEdit/Source/PeeSetup.cpp | 102 + fallen/GEdit/Source/PlayerSetup.cpp | 110 + fallen/GEdit/Source/ResetSetup.cpp | 101 + fallen/GEdit/Source/SfxSetup.cpp | 146 + fallen/GEdit/Source/SubClass.cpp | 1286 + fallen/GEdit/Source/TabCtl.cpp | 111 + fallen/GEdit/Source/TransferSetup.cpp | 101 + fallen/GEdit/Source/TrapSetup.cpp | 194 + fallen/GEdit/Source/TriggerSetup.cpp | 294 + fallen/GEdit/Source/VehicleSetup.cpp | 165 + fallen/GEdit/Source/VfxSetup.cpp | 89 + fallen/GEdit/Source/WSpace.cpp | 1536 ++ fallen/GEdit/Source/WayWind.cpp | 352 + fallen/GEdit/Source/activatesetup.cpp | 128 + fallen/GEdit/Source/animSetup.cpp | 101 + fallen/GEdit/Source/barrelSetup.cpp | 88 + fallen/GEdit/Source/bombSetup.cpp | 107 + fallen/GEdit/Source/burnsetup.cpp | 95 + fallen/GEdit/Source/converse.cpp | 180 + fallen/GEdit/Source/countersetup.cpp | 75 + fallen/GEdit/Source/cutscene.cpp | 2156 ++ fallen/GEdit/Source/dlightSetup.cpp | 268 + fallen/GEdit/Source/enemyflagsetup.cpp | 139 + fallen/GEdit/Source/inputbox.cpp | 93 + fallen/GEdit/Source/locksetup.cpp | 122 + fallen/GEdit/Source/platformSetup.cpp | 89 + fallen/GEdit/Source/propedit.cpp | 921 + fallen/GEdit/Source/setskills.cpp | 104 + fallen/GEdit/Source/signsetup.cpp | 141 + fallen/GEdit/Source/spotfxSetup.cpp | 99 + fallen/GEdit/Source/stallsetup.cpp | 102 + fallen/GEdit/Source/ticklist.cpp | 159 + fallen/GEdit/Source/treasuresetup.cpp | 70 + fallen/GEdit/Source/warefxsetup.cpp | 90 + fallen/GEdit/Source/waypointSetup.cpp | 73 + fallen/GEdit/Source/wptSetup.cpp | 101 + fallen/GEdit/toolbar.bmp | Bin 0 -> 358 bytes fallen/Glide Engine/Headers/clip.h | 22 + fallen/Glide Engine/Headers/glpoly.h | 201 + fallen/Glide Engine/Headers/gltexture.h | 101 + fallen/Glide Engine/Source/clip.cpp | 155 + fallen/Glide Engine/Source/glaeng.cpp | 1622 ++ fallen/Glide Engine/Source/glbuild.cpp | 504 + fallen/Glide Engine/Source/glfigure.cpp | 634 + fallen/Glide Engine/Source/glmesh.cpp | 213 + fallen/Glide Engine/Source/glpoly.cpp | 1278 + fallen/Glide Engine/Source/gltexture.cpp | 725 + fallen/Glide Library/Headers/glidelib.h | 15 + fallen/Glide Library/Source/glidelib.cpp | 365 + fallen/Headers/Attract.h | 25 + fallen/Headers/CamTargetSetup.h | 17 + fallen/Headers/Camera.h | 52 + fallen/Headers/CameraSetup.h | 17 + fallen/Headers/Command.h | 206 + fallen/Headers/Controls.h | 13 + fallen/Headers/Cop.h | 39 + fallen/Headers/Darci.h | 16 + fallen/Headers/EdStrings.h | 51 + fallen/Headers/Editor.h | 9 + fallen/Headers/EnemySetup.h | 16 + fallen/Headers/EngWind.h | 16 + fallen/Headers/Engine.h | 144 + fallen/Headers/Enter.h | 66 + fallen/Headers/Env.h | 49 + fallen/Headers/FMatrix.h | 90 + fallen/Headers/Furn.h | 166 + fallen/Headers/GEdit.h | 57 + fallen/Headers/Game.h | 587 + fallen/Headers/Hierarchy.h | 14 + fallen/Headers/ItemSetup.h | 15 + fallen/Headers/Level.h | 139 + fallen/Headers/Map.h | 90 + fallen/Headers/MapView.h | 61 + fallen/Headers/Mission.h | 564 + fallen/Headers/Nav.h | 83 + fallen/Headers/PSystem.h | 88 + fallen/Headers/Person.h | 541 + fallen/Headers/Pjectile.h | 33 + fallen/Headers/Player.h | 76 + fallen/Headers/PlayerSetup.h | 17 + fallen/Headers/Roper.h | 16 + fallen/Headers/Sound.h | 122 + fallen/Headers/Special.h | 189 + fallen/Headers/State.h | 33 + fallen/Headers/Structs.h | 92 + fallen/Headers/SubClass.h | 24 + fallen/Headers/Switch.h | 57 + fallen/Headers/TabCtl.h | 48 + fallen/Headers/Thing.h | 226 + fallen/Headers/Thug.h | 17 + fallen/Headers/TriggerSetup.h | 14 + fallen/Headers/WSpace.h | 89 + fallen/Headers/Wallhug.h | 107 + fallen/Headers/WayWind.h | 17 + fallen/Headers/america.h | 1 + fallen/Headers/animal.h | 95 + fallen/Headers/animate.h | 781 + fallen/Headers/animtmap.h | 42 + fallen/Headers/az.h | 45 + fallen/Headers/balloon.h | 89 + fallen/Headers/bang.h | 60 + fallen/Headers/barrel.h | 124 + fallen/Headers/bat.h | 76 + fallen/Headers/bike.h | 192 + fallen/Headers/briefing.h | 14 + fallen/Headers/build2.h | 31 + fallen/Headers/building.h | 509 + fallen/Headers/cache.h | 75 + fallen/Headers/cam.h | 163 + fallen/Headers/canid.h | 17 + fallen/Headers/chopper.h | 85 + fallen/Headers/cloth.h | 111 + fallen/Headers/cnet.h | 24 + fallen/Headers/collide.h | 483 + fallen/Headers/combat.h | 161 + fallen/Headers/demo.h | 1 + fallen/Headers/dike.h | 126 + fallen/Headers/dirt.h | 282 + fallen/Headers/door.h | 44 + fallen/Headers/drawtype.h | 102 + fallen/Headers/drip.h | 63 + fallen/Headers/elev.h | 43 + fallen/Headers/eway.h | 615 + fallen/Headers/fc.h | 138 + fallen/Headers/fire.h | 78 + fallen/Headers/fog.h | 74 + fallen/Headers/frontend.h | 28 + fallen/Headers/gamemenu.h | 66 + fallen/Headers/glitter.h | 81 + fallen/Headers/grenade.h | 22 + fallen/Headers/guns.h | 31 + fallen/Headers/heap.h | 31 + fallen/Headers/hm.h | 205 + fallen/Headers/hook.h | 97 + fallen/Headers/id.h | 337 + fallen/Headers/inline.h | 165 + fallen/Headers/inside2.h | 112 + fallen/Headers/interact.h | 120 + fallen/Headers/interfac.h | 223 + fallen/Headers/io.h | 79 + fallen/Headers/lead.h | 88 + fallen/Headers/light.h | 295 + fallen/Headers/maths.h | 24 + fallen/Headers/mav.h | 206 + fallen/Headers/memory.h | 103 + fallen/Headers/mist.h | 64 + fallen/Headers/morph.h | 39 + fallen/Headers/music.h | 99 + fallen/Headers/nd.h | 156 + fallen/Headers/night.h | 589 + fallen/Headers/noserver.h | 6 + fallen/Headers/ns.h | 371 + fallen/Headers/ob.h | 221 + fallen/Headers/overlay.h | 10 + fallen/Headers/pap.h | 192 + fallen/Headers/password.h | 221 + fallen/Headers/pause.h | 20 + fallen/Headers/pcom.h | 389 + fallen/Headers/pigeon.h | 13 + fallen/Headers/plat.h | 81 + fallen/Headers/playcuts.h | 96 + fallen/Headers/pow.h | 171 + fallen/Headers/pq.h | 21 + fallen/Headers/puddle.h | 93 + fallen/Headers/pyro.h | 148 + fallen/Headers/qedit.h | 17 + fallen/Headers/qls.h | 42 + fallen/Headers/qmap.h | 467 + fallen/Headers/ribbon.h | 53 + fallen/Headers/road.h | 189 + fallen/Headers/sample.h | 26 + fallen/Headers/save.h | 20 + fallen/Headers/sewer.h | 89 + fallen/Headers/shadow.h | 106 + fallen/Headers/sm.h | 61 + fallen/Headers/snipe.h | 54 + fallen/Headers/sound_id.h | 353 + fallen/Headers/soundenv.h | 11 + fallen/Headers/spark.h | 104 + fallen/Headers/stair.h | 56 + fallen/Headers/startscr.h | 50 + fallen/Headers/statedef.h | 232 + fallen/Headers/supermap.h | 241 + fallen/Headers/tracks.h | 88 + fallen/Headers/trip.h | 104 + fallen/Headers/vehicle.h | 267 + fallen/Headers/walkable.h | 53 + fallen/Headers/wand.h | 41 + fallen/Headers/ware.h | 177 + fallen/Headers/water.h | 73 + fallen/Headers/widget.h | 160 + fallen/Headers/wmove.h | 99 + fallen/Headers/xlat_str.h | 270 + fallen/Ledit/Headers/ed.h | 195 + fallen/Ledit/Headers/gi.h | 122 + fallen/Ledit/Headers/ledit.h | 18 + fallen/Ledit/Source/ed.cpp | 849 + fallen/Ledit/Source/gi.cpp | 275 + fallen/Ledit/Source/ledit.cpp | 2939 ++ fallen/Loader/Loader.dsp | 100 + fallen/Loader/Source/Loader.cpp | 540 + fallen/PSXENG/SOURCE/DrawXtra.cpp | 1338 + fallen/PSXENG/SOURCE/Matrix.cpp | 168 + fallen/PSXENG/SOURCE/Wadmenu.cpp | 4097 +++ fallen/PSXENG/SOURCE/build.cpp | 801 + fallen/PSXENG/SOURCE/engine.cpp | 8184 ++++++ fallen/PSXENG/SOURCE/facet.cpp | 4880 ++++ fallen/PSXENG/SOURCE/fendsave.cpp | 9 + fallen/PSXENG/SOURCE/feng.cpp | 196 + fallen/PSXENG/SOURCE/figure.cpp | 2669 ++ fallen/PSXENG/SOURCE/frontend.cpp | 7 + fallen/PSXENG/SOURCE/gamut.cpp | 463 + fallen/PSXENG/SOURCE/kanji.cpp | 145 + fallen/PSXENG/SOURCE/map.cpp | 22 + fallen/PSXENG/SOURCE/mcard.cpp | 158 + fallen/PSXENG/SOURCE/mdec.cpp | 350 + fallen/PSXENG/SOURCE/mesh.cpp | 731 + fallen/PSXENG/SOURCE/panel.cpp | 2026 ++ fallen/PSXENG/SOURCE/planmap.cpp | 317 + fallen/PSXENG/SOURCE/poly.cpp | 918 + fallen/PSXENG/SOURCE/shape.cpp | 1763 ++ fallen/PSXENG/SOURCE/topmap.cpp | 790 + fallen/PSXENG/SOURCE/wadpart.cpp | 578 + fallen/PSXENG/headers/Gamut.h | 89 + fallen/PSXENG/headers/Matrix.h | 158 + fallen/PSXENG/headers/build.h | 29 + fallen/PSXENG/headers/engine.h | 27 + fallen/PSXENG/headers/facet.h | 43 + fallen/PSXENG/headers/figure.h | 26 + fallen/PSXENG/headers/frontend.h | 11 + fallen/PSXENG/headers/kanji.h | 14 + fallen/PSXENG/headers/mcard.h | 88 + fallen/PSXENG/headers/mesh.h | 43 + fallen/PSXENG/headers/panel.h | 45 + fallen/PSXENG/headers/poly.h | 317 + fallen/PSXENG/headers/psxeng.h | 837 + fallen/PSXENG/headers/shape.h | 140 + fallen/PSXENG/headers/wadpart.h | 78 + fallen/PSXENG/headers/wadstr.h | 123 + fallen/PSXENG/psxeng.dsp | 181 + fallen/SoundConverter/SoundConverter.dsp | 102 + fallen/SoundConverter/soundconv.cpp | 166 + fallen/Source/Anim.cpp | 1998 ++ fallen/Source/Attract.cpp | 1420 + fallen/Source/BonusSetup.cpp | 167 + fallen/Source/CamTargetSetup.cpp | 116 + fallen/Source/Camera.cpp | 774 + fallen/Source/CameraSetup.cpp | 135 + fallen/Source/Command.cpp | 520 + fallen/Source/Controls.cpp | 5169 ++++ fallen/Source/Cop.cpp | 329 + fallen/Source/CreatureSetup.cpp | 118 + fallen/Source/Darci.cpp | 1424 + fallen/Source/EdStrings.cpp | 799 + fallen/Source/Effect.cpp | 38 + fallen/Source/Enemy.cpp | 40 + fallen/Source/EnemySetup.cpp | 467 + fallen/Source/EngWind.cpp | 414 + fallen/Source/Enter.cpp | 819 + fallen/Source/Env.cpp | 281 + fallen/Source/ExtendSetup.cpp | 120 + fallen/Source/FMatrix.cpp | 395 + fallen/Source/Furn.cpp | 1237 + fallen/Source/GEdit.cpp | 1815 ++ fallen/Source/Game.cpp | 2988 ++ fallen/Source/Hierarchy.cpp | 140 + fallen/Source/ItemSetup.cpp | 152 + fallen/Source/Level.cpp | 549 + fallen/Source/Levelpsx.cpp | 70 + fallen/Source/Main.cpp | 387 + fallen/Source/Map.cpp | 63 + fallen/Source/MapExitSetup.cpp | 89 + fallen/Source/MapView.cpp | 1936 ++ fallen/Source/MessageSetup.cpp | 452 + fallen/Source/Mission.cpp | 1719 ++ fallen/Source/MoveSetup.cpp | 102 + fallen/Source/Nav.cpp | 288 + fallen/Source/NavSetup.cpp | 157 + fallen/Source/PeeSetup.cpp | 102 + fallen/Source/Person.cpp | 22465 ++++++++++++++++ fallen/Source/Pjectile.cpp | 58 + fallen/Source/Player.cpp | 353 + fallen/Source/PlayerSetup.cpp | 110 + fallen/Source/Prim.cpp | 2690 ++ fallen/Source/ResetSetup.cpp | 101 + fallen/Source/Roper.cpp | 65 + fallen/Source/SfxSetup.cpp | 146 + fallen/Source/Sound.cpp | 1157 + fallen/Source/Special.cpp | 1843 ++ fallen/Source/State.cpp | 92 + fallen/Source/SubClass.cpp | 1286 + fallen/Source/Switch.cpp | 166 + fallen/Source/TabCtl.cpp | 111 + fallen/Source/Thing.cpp | 1726 ++ fallen/Source/Thug.cpp | 155 + fallen/Source/TransferSetup.cpp | 101 + fallen/Source/TrapSetup.cpp | 194 + fallen/Source/TriggerSetup.cpp | 294 + fallen/Source/VehicleSetup.cpp | 165 + fallen/Source/VfxSetup.cpp | 89 + fallen/Source/WSpace.cpp | 1536 ++ fallen/Source/Wallhug.cpp | 644 + fallen/Source/WayWind.cpp | 352 + fallen/Source/activatesetup.cpp | 128 + fallen/Source/animSetup.cpp | 101 + fallen/Source/animal.cpp | 615 + fallen/Source/animtmap.cpp | 111 + fallen/Source/az.cpp | 192 + fallen/Source/balloon.cpp | 576 + fallen/Source/bang.cpp | 723 + fallen/Source/barrel.cpp | 1937 ++ fallen/Source/barrelSetup.cpp | 88 + fallen/Source/bat.cpp | 2714 ++ fallen/Source/bike.cpp | 1867 ++ fallen/Source/bombSetup.cpp | 107 + fallen/Source/briefing.cpp | 216 + fallen/Source/build2.cpp | 1154 + fallen/Source/building.cpp | 11654 ++++++++ fallen/Source/burnsetup.cpp | 95 + fallen/Source/cache.cpp | 264 + fallen/Source/cam.cpp | 2146 ++ fallen/Source/canid.cpp | 1475 + fallen/Source/chopper.cpp | 804 + fallen/Source/cloth.cpp | 763 + fallen/Source/cnet.cpp | 422 + fallen/Source/collide.cpp | 11434 ++++++++ fallen/Source/combat.cpp | 3614 +++ fallen/Source/converse.cpp | 180 + fallen/Source/countersetup.cpp | 75 + fallen/Source/cutscene.cpp | 2156 ++ fallen/Source/dc_credits.cpp | 1565 ++ fallen/Source/dike.cpp | 448 + fallen/Source/dirt.cpp | 3149 +++ fallen/Source/dlightSetup.cpp | 268 + fallen/Source/door.cpp | 442 + fallen/Source/drawtype.cpp | 165 + fallen/Source/drip.cpp | 168 + fallen/Source/elev.cpp | 3436 +++ fallen/Source/enemyflagsetup.cpp | 139 + fallen/Source/env2.cpp | 366 + fallen/Source/eway.cpp | 8237 ++++++ fallen/Source/fc.cpp | 2145 ++ fallen/Source/fire.cpp | 382 + fallen/Source/fog.cpp | 367 + fallen/Source/frontend.cpp | 7847 ++++++ fallen/Source/gamemenu.cpp | 695 + fallen/Source/glitter.cpp | 490 + fallen/Source/grenade.cpp | 491 + fallen/Source/guns.cpp | 792 + fallen/Source/heap.cpp | 381 + fallen/Source/hm.cpp | 3075 +++ fallen/Source/hm_psx.cpp | 2976 ++ fallen/Source/hook.cpp | 758 + fallen/Source/id.cpp | 9309 +++++++ fallen/Source/inputbox.cpp | 93 + fallen/Source/inside2.cpp | 1295 + fallen/Source/interact.cpp | 1596 ++ fallen/Source/interfac.cpp | 8459 ++++++ fallen/Source/io.cpp | 3034 +++ fallen/Source/io_psx.cpp | 872 + fallen/Source/lead.cpp | 264 + fallen/Source/light.cpp | 2077 ++ fallen/Source/locksetup.cpp | 122 + fallen/Source/maths.cpp | 224 + fallen/Source/mav.cpp | 3287 +++ fallen/Source/memory.cpp | 4294 +++ fallen/Source/mesh.cpp | 1591 ++ fallen/Source/mist.cpp | 522 + fallen/Source/morph.cpp | 159 + fallen/Source/music.cpp | 593 + fallen/Source/nd.cpp | 1 + fallen/Source/night.cpp | 4148 +++ fallen/Source/nightpsx.cpp | 2988 ++ fallen/Source/ns.cpp | 3920 +++ fallen/Source/ob.cpp | 1824 ++ fallen/Source/overlay.cpp | 1611 ++ fallen/Source/pap.cpp | 598 + fallen/Source/pause.cpp | 244 + fallen/Source/pausepsx.cpp | 356 + fallen/Source/pch_fall.cpp | 1 + fallen/Source/pcom.cpp | 15104 +++++++++++ fallen/Source/pigeon.cpp | 1046 + fallen/Source/plat.cpp | 666 + fallen/Source/platformSetup.cpp | 89 + fallen/Source/playcuts.cpp | 666 + fallen/Source/pow.cpp | 973 + fallen/Source/pq.cpp | 140 + fallen/Source/propedit.cpp | 921 + fallen/Source/psystem.cpp | 695 + fallen/Source/puddle.cpp | 935 + fallen/Source/pyro.cpp | 1348 + fallen/Source/qedit.cpp | 434 + fallen/Source/qls.cpp | 103 + fallen/Source/qmap.cpp | 1270 + fallen/Source/ribbon.cpp | 143 + fallen/Source/road.cpp | 1563 ++ fallen/Source/save.cpp | 880 + fallen/Source/setskills.cpp | 104 + fallen/Source/sewer.cpp | 1926 ++ fallen/Source/shadow.cpp | 247 + fallen/Source/signsetup.cpp | 141 + fallen/Source/sm.cpp | 502 + fallen/Source/snipe.cpp | 129 + fallen/Source/sound_id.cpp | 562 + fallen/Source/soundenv.cpp | 122 + fallen/Source/spark.cpp | 1326 + fallen/Source/spotfxSetup.cpp | 99 + fallen/Source/stair.cpp | 1304 + fallen/Source/stallsetup.cpp | 102 + fallen/Source/startscr.cpp | 1857 ++ fallen/Source/supermap.cpp | 3797 +++ fallen/Source/ticklist.cpp | 159 + fallen/Source/tracks.cpp | 378 + fallen/Source/treasuresetup.cpp | 70 + fallen/Source/trip.cpp | 361 + fallen/Source/vehicle.cpp | 4864 ++++ fallen/Source/walkable.cpp | 984 + fallen/Source/wand.cpp | 585 + fallen/Source/ware.cpp | 1363 + fallen/Source/warefxsetup.cpp | 90 + fallen/Source/water.cpp | 747 + fallen/Source/waypointSetup.cpp | 73 + fallen/Source/widget.cpp | 1164 + fallen/Source/wmove.cpp | 976 + fallen/Source/wptSetup.cpp | 101 + fallen/Source/xlat_str.cpp | 437 + fallen/UnInst/UnInst.c | 112 + fallen/UnInst/UnInst.dsp | 109 + fallen/UnInst/uninst.def | 11 + fallen/UnInst/uninst.rc | 170 + fallen/UpgradeLog.htm | Bin 0 -> 30488 bytes fallen/cdsrc.bat | 3 + fallen/clumps.bat | 15 + fallen/compress.bat | 5 + fallen/copysrc.bat | 24 + fallen/doneclumps.bat | 5 + fallen/dxinstall/dinstall.c | 401 + fallen/dxinstall/dinstall.rc | 171 + fallen/dxinstall/directx.ico | Bin 0 -> 1078 bytes fallen/dxinstall/dxinstall.dsp | 126 + fallen/dxinstall/readme.txt | 59 + fallen/dxinstall/resource.h | 53 + fallen/dxinstall/wincode.c | 359 + fallen/english.bat | 3 + fallen/englishsrc.bat | 24 + fallen/french.bat | 3 + fallen/frenchsrc.bat | 24 + fallen/german.bat | 3 + fallen/germansrc.bat | 24 + fallen/outro/Always.h | 387 + fallen/outro/Key.h | 133 + fallen/outro/Matrix.cpp | 459 + fallen/outro/Matrix.h | 146 + fallen/outro/Tga.cpp | 296 + fallen/outro/Tga.h | 65 + fallen/outro/back.cpp | 164 + fallen/outro/back.h | 26 + fallen/outro/cam.cpp | 173 + fallen/outro/cam.h | 40 + fallen/outro/checker.cpp | 215 + fallen/outro/checker.h | 26 + fallen/outro/credits.cpp | 658 + fallen/outro/credits.h | 27 + fallen/outro/font.cpp | 570 + fallen/outro/font.h | 56 + fallen/outro/imp.cpp | 1288 + fallen/outro/imp.h | 254 + fallen/outro/lmap.cpp | 421 + fallen/outro/lmap.h | 67 + fallen/outro/main.cpp | 156 + fallen/outro/mf.cpp | 1513 ++ fallen/outro/mf.h | 178 + fallen/outro/midasdll.h | 518 + fallen/outro/os.cpp | 4085 +++ fallen/outro/os.h | 477 + fallen/outro/outro.dsp | 205 + fallen/outro/slap.cpp | 451 + fallen/outro/slap.h | 41 + fallen/outro/wire.cpp | 502 + fallen/outro/wire.h | 24 + fallen/psxlib/Headers/GDisplay.h | 108 + fallen/psxlib/Headers/GMaths.h | 72 + fallen/psxlib/Headers/GMem.h | 12 + fallen/psxlib/Headers/Ghost.h | 43 + fallen/psxlib/Headers/MFx.h | 88 + fallen/psxlib/Headers/mfxmusic.h | 16 + fallen/psxlib/Headers/myheap.h | 13 + fallen/psxlib/Source/GDisplay.cpp | 406 + fallen/psxlib/Source/GHost.cpp | 597 + fallen/psxlib/Source/GMaths.cpp | 6051 +++++ fallen/psxlib/Source/GMem.cpp | 90 + fallen/psxlib/Source/MFx.cpp | 1056 + fallen/psxlib/Source/Sample.cpp | 67 + fallen/psxlib/Source/malloc.cpp | 111 + fallen/psxlib/Source/myheap.cpp | 11 + fallen/psxlib/Source/vsprintf.cpp | 60 + fallen/psxlib/psxlib.dsp | 161 + fallen/psxlib1/Debug/vc50.idb | Bin 0 -> 50176 bytes fallen/psxlib1/ErrorLog.txt | 3 + fallen/psxlib1/Headers/Display.h | 126 + fallen/psxlib1/Headers/Draw2d.h | 101 + fallen/psxlib1/Headers/DrawPoly.h | 8 + fallen/psxlib1/Headers/Keyboard.h | 144 + fallen/psxlib1/Headers/MFD3D.h | 26 + fallen/psxlib1/Headers/MFErrors.h | 44 + fallen/psxlib1/Headers/MFFile.h | 41 + fallen/psxlib1/Headers/MFHeader.err | 179 + fallen/psxlib1/Headers/MFHeader.h | 71 + fallen/psxlib1/Headers/MFHost.err | 111 + fallen/psxlib1/Headers/MFHost.h | 36 + fallen/psxlib1/Headers/MFLbType.h | 131 + fallen/psxlib1/Headers/MFMaths.err | 12 + fallen/psxlib1/Headers/MFMaths.h | 75 + fallen/psxlib1/Headers/MFMem.h | 12 + fallen/psxlib1/Headers/MFStd.h | 16 + fallen/psxlib1/Headers/MFStdLib.h | 341 + fallen/psxlib1/Headers/MFTypes.h | 26 + fallen/psxlib1/Headers/MFUtils.err | 101 + fallen/psxlib1/Headers/MFUtils.h | 23 + fallen/psxlib1/Headers/Mouse.err | 67 + fallen/psxlib1/Headers/Mouse.h | 32 + fallen/psxlib1/Headers/Palette.h | 24 + fallen/psxlib1/Headers/Sprites.h | 41 + fallen/psxlib1/Headers/StdFile.h | 38 + fallen/psxlib1/Headers/StdKeybd.h | 138 + fallen/psxlib1/Headers/StdMaths.h | 47 + fallen/psxlib1/Headers/StdMem.h | 16 + fallen/psxlib1/Headers/StdMouse.h | 31 + fallen/psxlib1/LibsToDo.txt | 6 + fallen/psxlib1/MFLib.ptg | Bin 0 -> 102141 bytes fallen/psxlib1/MFLib.tag | 3560 +++ fallen/psxlib1/MakeLibs | 11 + fallen/psxlib1/MakeLibs.bat | 15 + fallen/psxlib1/Release/vc50.idb | Bin 0 -> 50176 bytes fallen/psxlib1/Source/C/Common/DModes.cpp | 101 + fallen/psxlib1/Source/C/Common/DModes.err | 35 + fallen/psxlib1/Source/C/Common/Draw2d.cpp | 265 + fallen/psxlib1/Source/C/Common/DrawBox.cpp | 329 + fallen/psxlib1/Source/C/Common/DrawBox.err | 35 + fallen/psxlib1/Source/C/Common/DrawLine.cpp | 562 + fallen/psxlib1/Source/C/Common/DrawPnt.cpp | 75 + fallen/psxlib1/Source/C/Common/DrawPxl.cpp | 59 + fallen/psxlib1/Source/C/Common/DrawRect.cpp | 24 + fallen/psxlib1/Source/C/Common/DrawRect.err | 31 + fallen/psxlib1/Source/C/Common/Maths.cpp | 127 + fallen/psxlib1/Source/C/Common/Maths.err | 35 + fallen/psxlib1/Source/C/Common/QuickTxt.cpp | 481 + fallen/psxlib1/Source/C/Common/QuickTxt.err | 93 + fallen/psxlib1/Source/C/Common/Sprites.cpp | 809 + fallen/psxlib1/Source/C/Common/Sprites.err | 35 + fallen/psxlib1/Source/C/Common/TextDef.cpp | 930 + fallen/psxlib1/Source/C/Common/TextDef.err | 59 + fallen/psxlib1/Source/C/Common/Trig.cpp | 5924 ++++ fallen/psxlib1/Source/C/DOS/DDisplay.cpp | 512 + fallen/psxlib1/Source/C/DOS/DDisplay.err | 73 + fallen/psxlib1/Source/C/DOS/DFile.cpp | 168 + fallen/psxlib1/Source/C/DOS/DFile.err | 39 + fallen/psxlib1/Source/C/DOS/DKeybrd.cpp | 103 + fallen/psxlib1/Source/C/DOS/DKeybrd.err | 37 + fallen/psxlib1/Source/C/DOS/DMFHost.cpp | 93 + fallen/psxlib1/Source/C/DOS/DMem.cpp | 36 + fallen/psxlib1/Source/C/DOS/DMouse.cpp | 276 + fallen/psxlib1/Source/C/DOS/DMouse.err | 103 + fallen/psxlib1/Source/C/Windows/D3D.cpp | 363 + fallen/psxlib1/Source/C/Windows/Display.cpp | 927 + fallen/psxlib1/Source/C/Windows/Display.err | 189 + fallen/psxlib1/Source/C/Windows/File.cpp | 176 + fallen/psxlib1/Source/C/Windows/Keyboard.cpp | 116 + fallen/psxlib1/Source/C/Windows/Keyboard.err | 35 + .../Source/C/Windows/MDebug/MFLib1.bsc | Bin 0 -> 2999296 bytes .../psxlib1/Source/C/Windows/MDebug/vc50.idb | Bin 0 -> 66560 bytes fallen/psxlib1/Source/C/Windows/MFHost.cpp | 404 + .../Source/C/Windows/MRelease/vc50.idb | Bin 0 -> 66560 bytes fallen/psxlib1/Source/C/Windows/Mem.cpp | 67 + fallen/psxlib1/Source/C/Windows/Mouse.cpp | 17 + fallen/psxlib1/Source/C/Windows/Palette.cpp | 240 + fallen/psxlib1/Source/StdLib/StdFile.cpp | 193 + fallen/psxlib1/Source/StdLib/StdMaths.cpp | 6044 +++++ fallen/psxlib1/Source/StdLib/StdMem.cpp | 60 + fallen/psxlib1/W_DOS1_D.LBC | 1 + fallen/psxlib1/W_DOS1_R.LBC | 1 + fallen/psxlib1/W_WIN1_D.LBC | 1 + fallen/psxlib1/W_WIN1_R.LBC | 1 + fallen/psxlib1/mfstdlib.dsp | 122 + fallen/psxlib1/mfstdlib.dsw | 29 + fallen/psxlib1/mfstdlib.opt | Bin 0 -> 55808 bytes fallen/psxlib1/psxlib1.dsw | 17 + fallen/psxlib1/psxlib1.opt | Bin 0 -> 43520 bytes fallen/psxlib1/update.PIF | Bin 0 -> 967 bytes fallen/psxlib1/update.bat | 3 + fallen/sedit/Headers/es.h | 286 + fallen/sedit/Headers/sedit.h | 18 + fallen/sedit/Source/es.cpp | 1841 ++ fallen/sedit/Source/sedit.cpp | 1944 ++ fallen/server/extract.bat | 79 + fallen/text/lang_english.txt | 212 + fallen/text/lang_french.txt | 216 + fallen/text/lang_german.txt | 178 + thrust/Always.h | 414 + thrust/Key.h | 133 + thrust/Matrix.cpp | 455 + thrust/Matrix.h | 146 + thrust/Tga.cpp | 295 + thrust/Tga.h | 62 + thrust/ab.h | 29 + thrust/cam.cpp | 185 + thrust/cam.h | 40 + thrust/d3denum.cpp | 642 + thrust/d3denum.h | 180 + thrust/d3dframe.cpp | 755 + thrust/d3dframe.h | 135 + thrust/d3dutil.cpp | 394 + thrust/d3dutil.h | 110 + thrust/font.cpp | 509 + thrust/font.h | 50 + thrust/game.cpp | 1488 + thrust/game.h | 36 + thrust/gamestate.cpp | 37 + thrust/gamestate.h | 47 + thrust/icon1.ico | Bin 0 -> 3310 bytes thrust/imp.cpp | 1044 + thrust/imp.h | 219 + thrust/land.cpp | 458 + thrust/land.h | 58 + thrust/lmap.cpp | 421 + thrust/lmap.h | 67 + thrust/log.cpp | 135 + thrust/log.h | 21 + thrust/main.cpp | 521 + thrust/menu.h | 20 + thrust/mf.cpp | 1208 + thrust/mf.h | 128 + thrust/net.cpp | 630 + thrust/net.h | 152 + thrust/orb.cpp | 175 + thrust/orb.h | 71 + thrust/os.cpp | 4503 ++++ thrust/os.h | 527 + thrust/ping.cpp | 222 + thrust/ping.h | 25 + thrust/player.cpp | 921 + thrust/player.h | 177 + thrust/resource.h | 25 + thrust/server.cpp | 868 + thrust/server.h | 256 + thrust/ship.cpp | 462 + thrust/ship.h | 108 + thrust/slap.cpp | 451 + thrust/slap.h | 41 + thrust/tb.cpp | 276 + thrust/tb.h | 64 + thrust/thrust.dsp | 331 + thrust/thrust.dsw | 37 + thrust/thrust.rc | 118 + thrust/userdlg.cpp | 384 + thrust/wave.c | 896 + thrust/wave.h | 68 + 1142 files changed, 697829 insertions(+) create mode 100644 MFLib1/Headers/Display.h create mode 100644 MFLib1/Headers/Draw2d.h create mode 100644 MFLib1/Headers/DrawPoly.h create mode 100644 MFLib1/Headers/Keyboard.h create mode 100644 MFLib1/Headers/MFD3D.h create mode 100644 MFLib1/Headers/MFErrors.h create mode 100644 MFLib1/Headers/MFFile.h create mode 100644 MFLib1/Headers/MFHeader.h create mode 100644 MFLib1/Headers/MFHost.h create mode 100644 MFLib1/Headers/MFLbType.h create mode 100644 MFLib1/Headers/MFMaths.h create mode 100644 MFLib1/Headers/MFMem.h create mode 100644 MFLib1/Headers/MFStd.h create mode 100644 MFLib1/Headers/MFTypes.h create mode 100644 MFLib1/Headers/MFUtils.h create mode 100644 MFLib1/Headers/Mouse.h create mode 100644 MFLib1/Headers/Palette.h create mode 100644 MFLib1/Headers/Sprites.h create mode 100644 MFLib1/MFLib1.dsp create mode 100644 MFLib1/Source/C/Common/DModes.cpp create mode 100644 MFLib1/Source/C/Common/Draw2d.cpp create mode 100644 MFLib1/Source/C/Common/DrawBox.cpp create mode 100644 MFLib1/Source/C/Common/DrawLine.cpp create mode 100644 MFLib1/Source/C/Common/DrawPnt.cpp create mode 100644 MFLib1/Source/C/Common/DrawPxl.cpp create mode 100644 MFLib1/Source/C/Common/DrawRect.cpp create mode 100644 MFLib1/Source/C/Common/Maths.cpp create mode 100644 MFLib1/Source/C/Common/QuickTxt.cpp create mode 100644 MFLib1/Source/C/Common/Sprites.cpp create mode 100644 MFLib1/Source/C/Common/TextDef.cpp create mode 100644 MFLib1/Source/C/Common/Trig.cpp create mode 100644 MFLib1/Source/C/Windows/D3D.cpp create mode 100644 MFLib1/Source/C/Windows/Display.cpp create mode 100644 MFLib1/Source/C/Windows/File.cpp create mode 100644 MFLib1/Source/C/Windows/Keyboard.cpp create mode 100644 MFLib1/Source/C/Windows/MFHost.cpp create mode 100644 MFLib1/Source/C/Windows/Mem.cpp create mode 100644 MFLib1/Source/C/Windows/Mouse.cpp create mode 100644 MFLib1/Source/C/Windows/Palette.cpp create mode 100644 MFStdLib/Headers/MFStdLib.h create mode 100644 MFStdLib/Headers/StdFile.h create mode 100644 MFStdLib/Headers/StdKeybd.h create mode 100644 MFStdLib/Headers/StdMaths.h create mode 100644 MFStdLib/Headers/StdMem.h create mode 100644 MFStdLib/Headers/StdMouse.h create mode 100644 MFStdLib/Source/StdLib/StdFile.cpp create mode 100644 MFStdLib/Source/StdLib/StdMaths.cpp create mode 100644 MFStdLib/Source/StdLib/StdMem.cpp create mode 100644 MuckyBasic/Always.h create mode 100644 MuckyBasic/Key.h create mode 100644 MuckyBasic/Matrix.cpp create mode 100644 MuckyBasic/Matrix.h create mode 100644 MuckyBasic/Tga.cpp create mode 100644 MuckyBasic/Tga.h create mode 100644 MuckyBasic/cg.cpp create mode 100644 MuckyBasic/cg.h create mode 100644 MuckyBasic/clip.cpp create mode 100644 MuckyBasic/clip.h create mode 100644 MuckyBasic/comp.cpp create mode 100644 MuckyBasic/comp.h create mode 100644 MuckyBasic/console.cpp create mode 100644 MuckyBasic/console.h create mode 100644 MuckyBasic/d3denum.cpp create mode 100644 MuckyBasic/d3denum.h create mode 100644 MuckyBasic/d3dframe.cpp create mode 100644 MuckyBasic/d3dframe.h create mode 100644 MuckyBasic/d3dutil.cpp create mode 100644 MuckyBasic/d3dutil.h create mode 100644 MuckyBasic/font.cpp create mode 100644 MuckyBasic/font.h create mode 100644 MuckyBasic/icon1.ico create mode 100644 MuckyBasic/lex.cpp create mode 100644 MuckyBasic/lex.h create mode 100644 MuckyBasic/link.cpp create mode 100644 MuckyBasic/link.h create mode 100644 MuckyBasic/ll.cpp create mode 100644 MuckyBasic/ll.h create mode 100644 MuckyBasic/main.cpp create mode 100644 MuckyBasic/mem.cpp create mode 100644 MuckyBasic/mem.h create mode 100644 MuckyBasic/ml.h create mode 100644 MuckyBasic/muckyBASIC.dsp create mode 100644 MuckyBasic/muckyBASIC.dsw create mode 100644 MuckyBasic/muckyBASIC.rc create mode 100644 MuckyBasic/os.cpp create mode 100644 MuckyBasic/os.h create mode 100644 MuckyBasic/parse.cpp create mode 100644 MuckyBasic/parse.h create mode 100644 MuckyBasic/resource.h create mode 100644 MuckyBasic/st.cpp create mode 100644 MuckyBasic/st.h create mode 100644 MuckyBasic/sysvar.cpp create mode 100644 MuckyBasic/sysvar.h create mode 100644 MuckyBasic/test.mbs create mode 100644 MuckyBasic/test2.mbs create mode 100644 MuckyBasic/userdlg.cpp create mode 100644 MuckyBasic/vm.cpp create mode 100644 MuckyBasic/vm.h create mode 100644 MuckyBasic/wave.c create mode 100644 MuckyBasic/wave.h create mode 100644 fallen/AutoRun/AutoRun.cpp create mode 100644 fallen/AutoRun/AutoRun.cur create mode 100644 fallen/AutoRun/AutoRun.dsp create mode 100644 fallen/AutoRun/AutoRun.h create mode 100644 fallen/AutoRun/AutoRun.ico create mode 100644 fallen/AutoRun/AutoRun.rc create mode 100644 fallen/AutoRun/Autorun/English.txt create mode 100644 fallen/AutoRun/Autorun/French.txt create mode 100644 fallen/AutoRun/Autorun/German.txt create mode 100644 fallen/AutoRun/Autorun/Spanish.txt create mode 100644 fallen/AutoRun/Director.cpp create mode 100644 fallen/AutoRun/Director.h create mode 100644 fallen/AutoRun/ReadMe.txt create mode 100644 fallen/AutoRun/StdAfx.cpp create mode 100644 fallen/AutoRun/StdAfx.h create mode 100644 fallen/AutoRun/resource.h create mode 100644 fallen/DDEngine/Headers/BreakTimer.h create mode 100644 fallen/DDEngine/Headers/Bucket.h create mode 100644 fallen/DDEngine/Headers/Crinkle.h create mode 100644 fallen/DDEngine/Headers/DCback.h create mode 100644 fallen/DDEngine/Headers/DCcredits.h create mode 100644 fallen/DDEngine/Headers/DCfont.h create mode 100644 fallen/DDEngine/Headers/DCos.h create mode 100644 fallen/DDEngine/Headers/DrawXtra.h create mode 100644 fallen/DDEngine/Headers/Engine.h create mode 100644 fallen/DDEngine/Headers/Font.h create mode 100644 fallen/DDEngine/Headers/Gamut.h create mode 100644 fallen/DDEngine/Headers/Matrix.h create mode 100644 fallen/DDEngine/Headers/Message.h create mode 100644 fallen/DDEngine/Headers/NGamut.h create mode 100644 fallen/DDEngine/Headers/Quaternion.h create mode 100644 fallen/DDEngine/Headers/Text.h create mode 100644 fallen/DDEngine/Headers/aa.h create mode 100644 fallen/DDEngine/Headers/aeng.h create mode 100644 fallen/DDEngine/Headers/build.h create mode 100644 fallen/DDEngine/Headers/comp.h create mode 100644 fallen/DDEngine/Headers/cone.h create mode 100644 fallen/DDEngine/Headers/console.h create mode 100644 fallen/DDEngine/Headers/facet.h create mode 100644 fallen/DDEngine/Headers/fall.h create mode 100644 fallen/DDEngine/Headers/farfacet.h create mode 100644 fallen/DDEngine/Headers/fastprim.h create mode 100644 fallen/DDEngine/Headers/figure.h create mode 100644 fallen/DDEngine/Headers/flamengine.h create mode 100644 fallen/DDEngine/Headers/font2d.h create mode 100644 fallen/DDEngine/Headers/font3d.h create mode 100644 fallen/DDEngine/Headers/ic.h create mode 100644 fallen/DDEngine/Headers/map.h create mode 100644 fallen/DDEngine/Headers/menufont.h create mode 100644 fallen/DDEngine/Headers/mesh.h create mode 100644 fallen/DDEngine/Headers/oval.h create mode 100644 fallen/DDEngine/Headers/pack.h create mode 100644 fallen/DDEngine/Headers/panel.h create mode 100644 fallen/DDEngine/Headers/planmap.h create mode 100644 fallen/DDEngine/Headers/poly.h create mode 100644 fallen/DDEngine/Headers/polypage.h create mode 100644 fallen/DDEngine/Headers/polypoint.h create mode 100644 fallen/DDEngine/Headers/qeng.h create mode 100644 fallen/DDEngine/Headers/ray.h create mode 100644 fallen/DDEngine/Headers/renderstate.h create mode 100644 fallen/DDEngine/Headers/shape.h create mode 100644 fallen/DDEngine/Headers/sky.h create mode 100644 fallen/DDEngine/Headers/smap.h create mode 100644 fallen/DDEngine/Headers/sprite.h create mode 100644 fallen/DDEngine/Headers/supercrinkle.h create mode 100644 fallen/DDEngine/Headers/superfacet.h create mode 100644 fallen/DDEngine/Headers/sw.h create mode 100644 fallen/DDEngine/Headers/texture.h create mode 100644 fallen/DDEngine/Headers/truetype.h create mode 100644 fallen/DDEngine/Headers/vertexbuffer.h create mode 100644 fallen/DDEngine/Headers/wibble.h create mode 100644 fallen/DDEngine/Source/Attract.cpp create mode 100644 fallen/DDEngine/Source/BreakTimer.cpp create mode 100644 fallen/DDEngine/Source/Bucket.cpp create mode 100644 fallen/DDEngine/Source/Crinkle.cpp create mode 100644 fallen/DDEngine/Source/DCback.cpp create mode 100644 fallen/DDEngine/Source/DCcredits.cpp create mode 100644 fallen/DDEngine/Source/DCfont.cpp create mode 100644 fallen/DDEngine/Source/DCos.cpp create mode 100644 fallen/DDEngine/Source/Font.cpp create mode 100644 fallen/DDEngine/Source/Gamut.cpp create mode 100644 fallen/DDEngine/Source/Matrix.cpp create mode 100644 fallen/DDEngine/Source/Message.cpp create mode 100644 fallen/DDEngine/Source/NGamut.cpp create mode 100644 fallen/DDEngine/Source/Quaternion.cpp create mode 100644 fallen/DDEngine/Source/Temp.cpp create mode 100644 fallen/DDEngine/Source/Text.cpp create mode 100644 fallen/DDEngine/Source/aa.cpp create mode 100644 fallen/DDEngine/Source/aeng.cpp create mode 100644 fallen/DDEngine/Source/build.cpp create mode 100644 fallen/DDEngine/Source/comp.cpp create mode 100644 fallen/DDEngine/Source/cone.cpp create mode 100644 fallen/DDEngine/Source/console.cpp create mode 100644 fallen/DDEngine/Source/drawxtra.cpp create mode 100644 fallen/DDEngine/Source/facet.cpp create mode 100644 fallen/DDEngine/Source/farfacet.cpp create mode 100644 fallen/DDEngine/Source/fastprim.cpp create mode 100644 fallen/DDEngine/Source/figure.cpp create mode 100644 fallen/DDEngine/Source/flamengine.cpp create mode 100644 fallen/DDEngine/Source/font2d.cpp create mode 100644 fallen/DDEngine/Source/font3d.cpp create mode 100644 fallen/DDEngine/Source/ic.cpp create mode 100644 fallen/DDEngine/Source/map.cpp create mode 100644 fallen/DDEngine/Source/menufont.cpp create mode 100644 fallen/DDEngine/Source/mesh.cpp create mode 100644 fallen/DDEngine/Source/oval.cpp create mode 100644 fallen/DDEngine/Source/pack.cpp create mode 100644 fallen/DDEngine/Source/panel.cpp create mode 100644 fallen/DDEngine/Source/planmap.cpp create mode 100644 fallen/DDEngine/Source/poly.cpp create mode 100644 fallen/DDEngine/Source/polypage.cpp create mode 100644 fallen/DDEngine/Source/polypoint.cpp create mode 100644 fallen/DDEngine/Source/polyrenderstate.cpp create mode 100644 fallen/DDEngine/Source/qeng.cpp create mode 100644 fallen/DDEngine/Source/ray.cpp create mode 100644 fallen/DDEngine/Source/renderstate.cpp create mode 100644 fallen/DDEngine/Source/shape.cpp create mode 100644 fallen/DDEngine/Source/sky.cpp create mode 100644 fallen/DDEngine/Source/smap.cpp create mode 100644 fallen/DDEngine/Source/sprite.cpp create mode 100644 fallen/DDEngine/Source/supercrinkle.cpp create mode 100644 fallen/DDEngine/Source/superfacet.cpp create mode 100644 fallen/DDEngine/Source/sw.cpp create mode 100644 fallen/DDEngine/Source/texture.cpp create mode 100644 fallen/DDEngine/Source/tom.cpp create mode 100644 fallen/DDEngine/Source/truetype.cpp create mode 100644 fallen/DDEngine/Source/vertexbuffer.cpp create mode 100644 fallen/DDEngine/Source/wibble.cpp create mode 100644 fallen/DDLibrary/DDlib.rc create mode 100644 fallen/DDLibrary/Headers/A3DManager.h create mode 100644 fallen/DDLibrary/Headers/AsyncFile.h create mode 100644 fallen/DDLibrary/Headers/AsyncFile2.h create mode 100644 fallen/DDLibrary/Headers/BinkClient.h create mode 100644 fallen/DDLibrary/Headers/D3DTexture.h create mode 100644 fallen/DDLibrary/Headers/DCLowLevel.h create mode 100644 fallen/DDLibrary/Headers/DDManager.h create mode 100644 fallen/DDLibrary/Headers/DDlib.h create mode 100644 fallen/DDLibrary/Headers/DIManager.h create mode 100644 fallen/DDLibrary/Headers/DSManager.h create mode 100644 fallen/DDLibrary/Headers/Debug.h create mode 100644 fallen/DDLibrary/Headers/Drive.h create mode 100644 fallen/DDLibrary/Headers/FFManager.h create mode 100644 fallen/DDLibrary/Headers/FileClump.h create mode 100644 fallen/DDLibrary/Headers/GDisplay.h create mode 100644 fallen/DDLibrary/Headers/GWorkScreen.h create mode 100644 fallen/DDLibrary/Headers/MFX_Miles.h create mode 100644 fallen/DDLibrary/Headers/MFx.h create mode 100644 fallen/DDLibrary/Headers/QSManager.h create mode 100644 fallen/DDLibrary/Headers/SampleManager.h create mode 100644 fallen/DDLibrary/Headers/Tga.h create mode 100644 fallen/DDLibrary/Headers/WindProcs.h create mode 100644 fallen/DDLibrary/Headers/net.h create mode 100644 fallen/DDLibrary/Headers/resource.h create mode 100644 fallen/DDLibrary/Headers/snd_type.h create mode 100644 fallen/DDLibrary/Source/A3DManager.cpp create mode 100644 fallen/DDLibrary/Source/AsyncFile.cpp create mode 100644 fallen/DDLibrary/Source/AsyncFile2.cpp create mode 100644 fallen/DDLibrary/Source/BinkClient.cpp create mode 100644 fallen/DDLibrary/Source/D3DTexture.cpp create mode 100644 fallen/DDLibrary/Source/DCLowLevel.cpp create mode 100644 fallen/DDLibrary/Source/DDManager.cpp create mode 100644 fallen/DDLibrary/Source/DIManager.cpp create mode 100644 fallen/DDLibrary/Source/DSManager.cpp create mode 100644 fallen/DDLibrary/Source/Drive.cpp create mode 100644 fallen/DDLibrary/Source/FFManager.cpp create mode 100644 fallen/DDLibrary/Source/FileClump.cpp create mode 100644 fallen/DDLibrary/Source/GDebug.cpp create mode 100644 fallen/DDLibrary/Source/GDisplay.cpp create mode 100644 fallen/DDLibrary/Source/GFile.cpp create mode 100644 fallen/DDLibrary/Source/GHost.cpp create mode 100644 fallen/DDLibrary/Source/GKeyboard.cpp create mode 100644 fallen/DDLibrary/Source/GMouse.cpp create mode 100644 fallen/DDLibrary/Source/GWorkScreen.cpp create mode 100644 fallen/DDLibrary/Source/MFX_DC.cpp create mode 100644 fallen/DDLibrary/Source/MFX_Miles.cpp create mode 100644 fallen/DDLibrary/Source/MFx.cpp create mode 100644 fallen/DDLibrary/Source/MFx_QMDX.cpp create mode 100644 fallen/DDLibrary/Source/QSManager.cpp create mode 100644 fallen/DDLibrary/Source/SampleManager.cpp create mode 100644 fallen/DDLibrary/Source/Tga.cpp create mode 100644 fallen/DDLibrary/Source/WindProcs.cpp create mode 100644 fallen/DDLibrary/Source/net.cpp create mode 100644 fallen/DDLibrary/ahead.bmp create mode 100644 fallen/DDLibrary/arrowcop.cur create mode 100644 fallen/DDLibrary/bitmap1.bmp create mode 100644 fallen/DDLibrary/bitmap2.bmp create mode 100644 fallen/DDLibrary/bm_red1.bmp create mode 100644 fallen/DDLibrary/bm_red2.bmp create mode 100644 fallen/DDLibrary/bm_red3.bmp create mode 100644 fallen/DDLibrary/bm_red4.bmp create mode 100644 fallen/DDLibrary/bm_red5.bmp create mode 100644 fallen/DDLibrary/bm_red6.bmp create mode 100644 fallen/DDLibrary/bm_red7.bmp create mode 100644 fallen/DDLibrary/bmp00001.bmp create mode 100644 fallen/DDLibrary/ico00001.ico create mode 100644 fallen/DDLibrary/icon1.ico create mode 100644 fallen/DDLibrary/icon2.ico create mode 100644 fallen/DDLibrary/mucky_lo.bmp create mode 100644 fallen/DDLibrary/rightturn.bmp create mode 100644 fallen/DDLibrary/scene_ic.bmp create mode 100644 fallen/DDLibrary/stop.bmp create mode 100644 fallen/DDLibrary/toolbar.bmp create mode 100644 fallen/DDLibrary/uturn.BMP create mode 100644 fallen/Debug/Fallen.tlog/CL.command.1.tlog create mode 100644 fallen/Debug/Fallen.tlog/CL.read.1.tlog create mode 100644 fallen/Debug/Fallen.tlog/CL.write.1.tlog create mode 100644 fallen/Debug/Fallen.tlog/Fallen.lastbuildstate create mode 100644 fallen/Debug/Fallen.tlog/unsuccessfulbuild create mode 100644 fallen/Editor/Headers/Alert.hpp create mode 100644 fallen/Editor/Headers/Anim.h create mode 100644 fallen/Editor/Headers/BuildTab.hpp create mode 100644 fallen/Editor/Headers/ColTab.hpp create mode 100644 fallen/Editor/Headers/ComTab.h create mode 100644 fallen/Editor/Headers/CondTab.h create mode 100644 fallen/Editor/Headers/Controls.hpp create mode 100644 fallen/Editor/Headers/CtrlSet.hpp create mode 100644 fallen/Editor/Headers/DarkCity.h create mode 100644 fallen/Editor/Headers/EdCom.h create mode 100644 fallen/Editor/Headers/EdUtils.h create mode 100644 fallen/Editor/Headers/EdWay.h create mode 100644 fallen/Editor/Headers/Edit.h create mode 100644 fallen/Editor/Headers/EditMod.hpp create mode 100644 fallen/Editor/Headers/Editor.h create mode 100644 fallen/Editor/Headers/Editor.hpp create mode 100644 fallen/Editor/Headers/EditorLib.h create mode 100644 fallen/Editor/Headers/FileReq.hpp create mode 100644 fallen/Editor/Headers/GameEd.h create mode 100644 fallen/Editor/Headers/HmTab.hpp create mode 100644 fallen/Editor/Headers/Icon.hpp create mode 100644 fallen/Editor/Headers/Intrface.hpp create mode 100644 fallen/Editor/Headers/KFrameEd.hpp create mode 100644 fallen/Editor/Headers/KFramer.hpp create mode 100644 fallen/Editor/Headers/LevelEd.hpp create mode 100644 fallen/Editor/Headers/LightTab.hpp create mode 100644 fallen/Editor/Headers/MapEdTab.hpp create mode 100644 fallen/Editor/Headers/MapTab.hpp create mode 100644 fallen/Editor/Headers/ModeTab.hpp create mode 100644 fallen/Editor/Headers/ObjectEd.hpp create mode 100644 fallen/Editor/Headers/PaintTab.hpp create mode 100644 fallen/Editor/Headers/Poly.h create mode 100644 fallen/Editor/Headers/PrPiTab.hpp create mode 100644 fallen/Editor/Headers/Prim.h create mode 100644 fallen/Editor/Headers/Primativ.hpp create mode 100644 fallen/Editor/Headers/SaveTab.h create mode 100644 fallen/Editor/Headers/Stealth.h create mode 100644 fallen/Editor/Headers/Structs.h create mode 100644 fallen/Editor/Headers/TexTab.hpp create mode 100644 fallen/Editor/Headers/Thing.h create mode 100644 fallen/Editor/Headers/ThingTab.h create mode 100644 fallen/Editor/Headers/Window.hpp create mode 100644 fallen/Editor/Headers/building.hpp create mode 100644 fallen/Editor/Headers/collide.hpp create mode 100644 fallen/Editor/Headers/convert.h create mode 100644 fallen/Editor/Headers/engine.h create mode 100644 fallen/Editor/Headers/extra.h create mode 100644 fallen/Editor/Headers/game.h create mode 100644 fallen/Editor/Headers/macros.h create mode 100644 fallen/Editor/Headers/map.h create mode 100644 fallen/Editor/Headers/outline.h create mode 100644 fallen/Editor/Headers/perstex.h create mode 100644 fallen/Editor/Headers/prim_draw.h create mode 100644 fallen/Editor/Headers/prim_edit.h create mode 100644 fallen/Editor/Headers/primtex.h create mode 100644 fallen/Editor/Headers/scan.h create mode 100644 fallen/Editor/Headers/scrflc.h create mode 100644 fallen/Editor/Headers/sewertab.hpp create mode 100644 fallen/Editor/Headers/spare.h create mode 100644 fallen/Editor/Headers/undo.hpp create mode 100644 fallen/Editor/Library/Draw2d.cpp create mode 100644 fallen/Editor/Library/DrawBox.cpp create mode 100644 fallen/Editor/Library/DrawCirc.cpp create mode 100644 fallen/Editor/Library/DrawLine.cpp create mode 100644 fallen/Editor/Library/DrawPnt.cpp create mode 100644 fallen/Editor/Library/DrawPxl.cpp create mode 100644 fallen/Editor/Library/DrawRect.cpp create mode 100644 fallen/Editor/Library/QuickTxt.cpp create mode 100644 fallen/Editor/Library/Sprites.cpp create mode 100644 fallen/Editor/Library/TextDef.cpp create mode 100644 fallen/Editor/Source/Alert.cpp create mode 100644 fallen/Editor/Source/BuildTab.cpp create mode 100644 fallen/Editor/Source/ColTab.cpp create mode 100644 fallen/Editor/Source/ComTab.cpp create mode 100644 fallen/Editor/Source/ComTab.def create mode 100644 fallen/Editor/Source/CondTab.cpp create mode 100644 fallen/Editor/Source/CondTab.def create mode 100644 fallen/Editor/Source/Control.cpp create mode 100644 fallen/Editor/Source/Controls.cpp create mode 100644 fallen/Editor/Source/CtrlSet.cpp create mode 100644 fallen/Editor/Source/EdCom.cpp create mode 100644 fallen/Editor/Source/EdText.cpp create mode 100644 fallen/Editor/Source/EdUtils.cpp create mode 100644 fallen/Editor/Source/EdWay.cpp create mode 100644 fallen/Editor/Source/Edit.cpp create mode 100644 fallen/Editor/Source/EditMod.cpp create mode 100644 fallen/Editor/Source/Editor.cpp create mode 100644 fallen/Editor/Source/Engine.cpp create mode 100644 fallen/Editor/Source/FileReq.cpp create mode 100644 fallen/Editor/Source/Game.cpp create mode 100644 fallen/Editor/Source/GameEd.cpp create mode 100644 fallen/Editor/Source/HmTab.cpp create mode 100644 fallen/Editor/Source/Icon.cpp create mode 100644 fallen/Editor/Source/Intrface.cpp create mode 100644 fallen/Editor/Source/KFDef.c create mode 100644 fallen/Editor/Source/KFDef2.c create mode 100644 fallen/Editor/Source/KFrameEd.cpp create mode 100644 fallen/Editor/Source/KFramer.cpp create mode 100644 fallen/Editor/Source/LevelEd.cpp create mode 100644 fallen/Editor/Source/LightTab.cpp create mode 100644 fallen/Editor/Source/Main.cpp create mode 100644 fallen/Editor/Source/MapEdTab.cpp create mode 100644 fallen/Editor/Source/MapTab.cpp create mode 100644 fallen/Editor/Source/ModeTab.cpp create mode 100644 fallen/Editor/Source/Move.cpp create mode 100644 fallen/Editor/Source/PaintTab.cpp create mode 100644 fallen/Editor/Source/Poly.cpp create mode 100644 fallen/Editor/Source/PrPiTab.cpp create mode 100644 fallen/Editor/Source/Primativ.cpp create mode 100644 fallen/Editor/Source/Quaternion.cpp create mode 100644 fallen/Editor/Source/SaveTab.cpp create mode 100644 fallen/Editor/Source/SaveTab.def create mode 100644 fallen/Editor/Source/Thing.cpp create mode 100644 fallen/Editor/Source/ThingTab.cpp create mode 100644 fallen/Editor/Source/ThingTab.def create mode 100644 fallen/Editor/Source/Window.cpp create mode 100644 fallen/Editor/Source/building.cpp create mode 100644 fallen/Editor/Source/collide.cpp create mode 100644 fallen/Editor/Source/extra.cpp create mode 100644 fallen/Editor/Source/hair.cpp create mode 100644 fallen/Editor/Source/interact.cpp create mode 100644 fallen/Editor/Source/map.cpp create mode 100644 fallen/Editor/Source/outline.cpp create mode 100644 fallen/Editor/Source/pch_ed.cpp create mode 100644 fallen/Editor/Source/perstex.cpp create mode 100644 fallen/Editor/Source/prim_draw.cpp create mode 100644 fallen/Editor/Source/prim_edit.cpp create mode 100644 fallen/Editor/Source/primtex.cpp create mode 100644 fallen/Editor/Source/scan.cpp create mode 100644 fallen/Editor/Source/scrflc.cpp create mode 100644 fallen/Editor/Source/sewertab.cpp create mode 100644 fallen/Editor/Source/undo.cpp create mode 100644 fallen/Fallen.dsp create mode 100644 fallen/Fallen.sln create mode 100644 fallen/Fallen.vcxproj create mode 100644 fallen/Fallen.vcxproj.filters create mode 100644 fallen/GEdit.dsp create mode 100644 fallen/GEdit/Headers/CamTargetSetup.h create mode 100644 fallen/GEdit/Headers/CameraSetup.h create mode 100644 fallen/GEdit/Headers/EdStrings.h create mode 100644 fallen/GEdit/Headers/EnemySetup.h create mode 100644 fallen/GEdit/Headers/EngWind.h create mode 100644 fallen/GEdit/Headers/GEdit.h create mode 100644 fallen/GEdit/Headers/ItemSetup.h create mode 100644 fallen/GEdit/Headers/MapExitSetup.h create mode 100644 fallen/GEdit/Headers/MapView.h create mode 100644 fallen/GEdit/Headers/Mission.h create mode 100644 fallen/GEdit/Headers/PlayerSetup.h create mode 100644 fallen/GEdit/Headers/SubClass.h create mode 100644 fallen/GEdit/Headers/TabCtl.h create mode 100644 fallen/GEdit/Headers/TriggerSetup.h create mode 100644 fallen/GEdit/Headers/WSpace.h create mode 100644 fallen/GEdit/Headers/WayWind.h create mode 100644 fallen/GEdit/Headers/activatesetup.h create mode 100644 fallen/GEdit/Headers/cutscene.h create mode 100644 fallen/GEdit/Headers/inputbox.h create mode 100644 fallen/GEdit/Headers/platformSetup.h create mode 100644 fallen/GEdit/Headers/propedit.h create mode 100644 fallen/GEdit/Headers/ticklist.h create mode 100644 fallen/GEdit/Headers/trapsetup.h create mode 100644 fallen/GEdit/Headers/waypointSetup.h create mode 100644 fallen/GEdit/Source/BonusSetup.cpp create mode 100644 fallen/GEdit/Source/CamTargetSetup.cpp create mode 100644 fallen/GEdit/Source/CameraSetup.cpp create mode 100644 fallen/GEdit/Source/CreatureSetup.cpp create mode 100644 fallen/GEdit/Source/EdStrings.cpp create mode 100644 fallen/GEdit/Source/EnemySetup.cpp create mode 100644 fallen/GEdit/Source/EngWind.cpp create mode 100644 fallen/GEdit/Source/ExtendSetup.cpp create mode 100644 fallen/GEdit/Source/GEdit.cpp create mode 100644 fallen/GEdit/Source/ItemSetup.cpp create mode 100644 fallen/GEdit/Source/MapExitSetup.cpp create mode 100644 fallen/GEdit/Source/MapView.cpp create mode 100644 fallen/GEdit/Source/MessageSetup.cpp create mode 100644 fallen/GEdit/Source/Mission.cpp create mode 100644 fallen/GEdit/Source/MoveSetup.cpp create mode 100644 fallen/GEdit/Source/NavSetup.cpp create mode 100644 fallen/GEdit/Source/PeeSetup.cpp create mode 100644 fallen/GEdit/Source/PlayerSetup.cpp create mode 100644 fallen/GEdit/Source/ResetSetup.cpp create mode 100644 fallen/GEdit/Source/SfxSetup.cpp create mode 100644 fallen/GEdit/Source/SubClass.cpp create mode 100644 fallen/GEdit/Source/TabCtl.cpp create mode 100644 fallen/GEdit/Source/TransferSetup.cpp create mode 100644 fallen/GEdit/Source/TrapSetup.cpp create mode 100644 fallen/GEdit/Source/TriggerSetup.cpp create mode 100644 fallen/GEdit/Source/VehicleSetup.cpp create mode 100644 fallen/GEdit/Source/VfxSetup.cpp create mode 100644 fallen/GEdit/Source/WSpace.cpp create mode 100644 fallen/GEdit/Source/WayWind.cpp create mode 100644 fallen/GEdit/Source/activatesetup.cpp create mode 100644 fallen/GEdit/Source/animSetup.cpp create mode 100644 fallen/GEdit/Source/barrelSetup.cpp create mode 100644 fallen/GEdit/Source/bombSetup.cpp create mode 100644 fallen/GEdit/Source/burnsetup.cpp create mode 100644 fallen/GEdit/Source/converse.cpp create mode 100644 fallen/GEdit/Source/countersetup.cpp create mode 100644 fallen/GEdit/Source/cutscene.cpp create mode 100644 fallen/GEdit/Source/dlightSetup.cpp create mode 100644 fallen/GEdit/Source/enemyflagsetup.cpp create mode 100644 fallen/GEdit/Source/inputbox.cpp create mode 100644 fallen/GEdit/Source/locksetup.cpp create mode 100644 fallen/GEdit/Source/platformSetup.cpp create mode 100644 fallen/GEdit/Source/propedit.cpp create mode 100644 fallen/GEdit/Source/setskills.cpp create mode 100644 fallen/GEdit/Source/signsetup.cpp create mode 100644 fallen/GEdit/Source/spotfxSetup.cpp create mode 100644 fallen/GEdit/Source/stallsetup.cpp create mode 100644 fallen/GEdit/Source/ticklist.cpp create mode 100644 fallen/GEdit/Source/treasuresetup.cpp create mode 100644 fallen/GEdit/Source/warefxsetup.cpp create mode 100644 fallen/GEdit/Source/waypointSetup.cpp create mode 100644 fallen/GEdit/Source/wptSetup.cpp create mode 100644 fallen/GEdit/toolbar.bmp create mode 100644 fallen/Glide Engine/Headers/clip.h create mode 100644 fallen/Glide Engine/Headers/glpoly.h create mode 100644 fallen/Glide Engine/Headers/gltexture.h create mode 100644 fallen/Glide Engine/Source/clip.cpp create mode 100644 fallen/Glide Engine/Source/glaeng.cpp create mode 100644 fallen/Glide Engine/Source/glbuild.cpp create mode 100644 fallen/Glide Engine/Source/glfigure.cpp create mode 100644 fallen/Glide Engine/Source/glmesh.cpp create mode 100644 fallen/Glide Engine/Source/glpoly.cpp create mode 100644 fallen/Glide Engine/Source/gltexture.cpp create mode 100644 fallen/Glide Library/Headers/glidelib.h create mode 100644 fallen/Glide Library/Source/glidelib.cpp create mode 100644 fallen/Headers/Attract.h create mode 100644 fallen/Headers/CamTargetSetup.h create mode 100644 fallen/Headers/Camera.h create mode 100644 fallen/Headers/CameraSetup.h create mode 100644 fallen/Headers/Command.h create mode 100644 fallen/Headers/Controls.h create mode 100644 fallen/Headers/Cop.h create mode 100644 fallen/Headers/Darci.h create mode 100644 fallen/Headers/EdStrings.h create mode 100644 fallen/Headers/Editor.h create mode 100644 fallen/Headers/EnemySetup.h create mode 100644 fallen/Headers/EngWind.h create mode 100644 fallen/Headers/Engine.h create mode 100644 fallen/Headers/Enter.h create mode 100644 fallen/Headers/Env.h create mode 100644 fallen/Headers/FMatrix.h create mode 100644 fallen/Headers/Furn.h create mode 100644 fallen/Headers/GEdit.h create mode 100644 fallen/Headers/Game.h create mode 100644 fallen/Headers/Hierarchy.h create mode 100644 fallen/Headers/ItemSetup.h create mode 100644 fallen/Headers/Level.h create mode 100644 fallen/Headers/Map.h create mode 100644 fallen/Headers/MapView.h create mode 100644 fallen/Headers/Mission.h create mode 100644 fallen/Headers/Nav.h create mode 100644 fallen/Headers/PSystem.h create mode 100644 fallen/Headers/Person.h create mode 100644 fallen/Headers/Pjectile.h create mode 100644 fallen/Headers/Player.h create mode 100644 fallen/Headers/PlayerSetup.h create mode 100644 fallen/Headers/Roper.h create mode 100644 fallen/Headers/Sound.h create mode 100644 fallen/Headers/Special.h create mode 100644 fallen/Headers/State.h create mode 100644 fallen/Headers/Structs.h create mode 100644 fallen/Headers/SubClass.h create mode 100644 fallen/Headers/Switch.h create mode 100644 fallen/Headers/TabCtl.h create mode 100644 fallen/Headers/Thing.h create mode 100644 fallen/Headers/Thug.h create mode 100644 fallen/Headers/TriggerSetup.h create mode 100644 fallen/Headers/WSpace.h create mode 100644 fallen/Headers/Wallhug.h create mode 100644 fallen/Headers/WayWind.h create mode 100644 fallen/Headers/america.h create mode 100644 fallen/Headers/animal.h create mode 100644 fallen/Headers/animate.h create mode 100644 fallen/Headers/animtmap.h create mode 100644 fallen/Headers/az.h create mode 100644 fallen/Headers/balloon.h create mode 100644 fallen/Headers/bang.h create mode 100644 fallen/Headers/barrel.h create mode 100644 fallen/Headers/bat.h create mode 100644 fallen/Headers/bike.h create mode 100644 fallen/Headers/briefing.h create mode 100644 fallen/Headers/build2.h create mode 100644 fallen/Headers/building.h create mode 100644 fallen/Headers/cache.h create mode 100644 fallen/Headers/cam.h create mode 100644 fallen/Headers/canid.h create mode 100644 fallen/Headers/chopper.h create mode 100644 fallen/Headers/cloth.h create mode 100644 fallen/Headers/cnet.h create mode 100644 fallen/Headers/collide.h create mode 100644 fallen/Headers/combat.h create mode 100644 fallen/Headers/demo.h create mode 100644 fallen/Headers/dike.h create mode 100644 fallen/Headers/dirt.h create mode 100644 fallen/Headers/door.h create mode 100644 fallen/Headers/drawtype.h create mode 100644 fallen/Headers/drip.h create mode 100644 fallen/Headers/elev.h create mode 100644 fallen/Headers/eway.h create mode 100644 fallen/Headers/fc.h create mode 100644 fallen/Headers/fire.h create mode 100644 fallen/Headers/fog.h create mode 100644 fallen/Headers/frontend.h create mode 100644 fallen/Headers/gamemenu.h create mode 100644 fallen/Headers/glitter.h create mode 100644 fallen/Headers/grenade.h create mode 100644 fallen/Headers/guns.h create mode 100644 fallen/Headers/heap.h create mode 100644 fallen/Headers/hm.h create mode 100644 fallen/Headers/hook.h create mode 100644 fallen/Headers/id.h create mode 100644 fallen/Headers/inline.h create mode 100644 fallen/Headers/inside2.h create mode 100644 fallen/Headers/interact.h create mode 100644 fallen/Headers/interfac.h create mode 100644 fallen/Headers/io.h create mode 100644 fallen/Headers/lead.h create mode 100644 fallen/Headers/light.h create mode 100644 fallen/Headers/maths.h create mode 100644 fallen/Headers/mav.h create mode 100644 fallen/Headers/memory.h create mode 100644 fallen/Headers/mist.h create mode 100644 fallen/Headers/morph.h create mode 100644 fallen/Headers/music.h create mode 100644 fallen/Headers/nd.h create mode 100644 fallen/Headers/night.h create mode 100644 fallen/Headers/noserver.h create mode 100644 fallen/Headers/ns.h create mode 100644 fallen/Headers/ob.h create mode 100644 fallen/Headers/overlay.h create mode 100644 fallen/Headers/pap.h create mode 100644 fallen/Headers/password.h create mode 100644 fallen/Headers/pause.h create mode 100644 fallen/Headers/pcom.h create mode 100644 fallen/Headers/pigeon.h create mode 100644 fallen/Headers/plat.h create mode 100644 fallen/Headers/playcuts.h create mode 100644 fallen/Headers/pow.h create mode 100644 fallen/Headers/pq.h create mode 100644 fallen/Headers/puddle.h create mode 100644 fallen/Headers/pyro.h create mode 100644 fallen/Headers/qedit.h create mode 100644 fallen/Headers/qls.h create mode 100644 fallen/Headers/qmap.h create mode 100644 fallen/Headers/ribbon.h create mode 100644 fallen/Headers/road.h create mode 100644 fallen/Headers/sample.h create mode 100644 fallen/Headers/save.h create mode 100644 fallen/Headers/sewer.h create mode 100644 fallen/Headers/shadow.h create mode 100644 fallen/Headers/sm.h create mode 100644 fallen/Headers/snipe.h create mode 100644 fallen/Headers/sound_id.h create mode 100644 fallen/Headers/soundenv.h create mode 100644 fallen/Headers/spark.h create mode 100644 fallen/Headers/stair.h create mode 100644 fallen/Headers/startscr.h create mode 100644 fallen/Headers/statedef.h create mode 100644 fallen/Headers/supermap.h create mode 100644 fallen/Headers/tracks.h create mode 100644 fallen/Headers/trip.h create mode 100644 fallen/Headers/vehicle.h create mode 100644 fallen/Headers/walkable.h create mode 100644 fallen/Headers/wand.h create mode 100644 fallen/Headers/ware.h create mode 100644 fallen/Headers/water.h create mode 100644 fallen/Headers/widget.h create mode 100644 fallen/Headers/wmove.h create mode 100644 fallen/Headers/xlat_str.h create mode 100644 fallen/Ledit/Headers/ed.h create mode 100644 fallen/Ledit/Headers/gi.h create mode 100644 fallen/Ledit/Headers/ledit.h create mode 100644 fallen/Ledit/Source/ed.cpp create mode 100644 fallen/Ledit/Source/gi.cpp create mode 100644 fallen/Ledit/Source/ledit.cpp create mode 100644 fallen/Loader/Loader.dsp create mode 100644 fallen/Loader/Source/Loader.cpp create mode 100644 fallen/PSXENG/SOURCE/DrawXtra.cpp create mode 100644 fallen/PSXENG/SOURCE/Matrix.cpp create mode 100644 fallen/PSXENG/SOURCE/Wadmenu.cpp create mode 100644 fallen/PSXENG/SOURCE/build.cpp create mode 100644 fallen/PSXENG/SOURCE/engine.cpp create mode 100644 fallen/PSXENG/SOURCE/facet.cpp create mode 100644 fallen/PSXENG/SOURCE/fendsave.cpp create mode 100644 fallen/PSXENG/SOURCE/feng.cpp create mode 100644 fallen/PSXENG/SOURCE/figure.cpp create mode 100644 fallen/PSXENG/SOURCE/frontend.cpp create mode 100644 fallen/PSXENG/SOURCE/gamut.cpp create mode 100644 fallen/PSXENG/SOURCE/kanji.cpp create mode 100644 fallen/PSXENG/SOURCE/map.cpp create mode 100644 fallen/PSXENG/SOURCE/mcard.cpp create mode 100644 fallen/PSXENG/SOURCE/mdec.cpp create mode 100644 fallen/PSXENG/SOURCE/mesh.cpp create mode 100644 fallen/PSXENG/SOURCE/panel.cpp create mode 100644 fallen/PSXENG/SOURCE/planmap.cpp create mode 100644 fallen/PSXENG/SOURCE/poly.cpp create mode 100644 fallen/PSXENG/SOURCE/shape.cpp create mode 100644 fallen/PSXENG/SOURCE/topmap.cpp create mode 100644 fallen/PSXENG/SOURCE/wadpart.cpp create mode 100644 fallen/PSXENG/headers/Gamut.h create mode 100644 fallen/PSXENG/headers/Matrix.h create mode 100644 fallen/PSXENG/headers/build.h create mode 100644 fallen/PSXENG/headers/engine.h create mode 100644 fallen/PSXENG/headers/facet.h create mode 100644 fallen/PSXENG/headers/figure.h create mode 100644 fallen/PSXENG/headers/frontend.h create mode 100644 fallen/PSXENG/headers/kanji.h create mode 100644 fallen/PSXENG/headers/mcard.h create mode 100644 fallen/PSXENG/headers/mesh.h create mode 100644 fallen/PSXENG/headers/panel.h create mode 100644 fallen/PSXENG/headers/poly.h create mode 100644 fallen/PSXENG/headers/psxeng.h create mode 100644 fallen/PSXENG/headers/shape.h create mode 100644 fallen/PSXENG/headers/wadpart.h create mode 100644 fallen/PSXENG/headers/wadstr.h create mode 100644 fallen/PSXENG/psxeng.dsp create mode 100644 fallen/SoundConverter/SoundConverter.dsp create mode 100644 fallen/SoundConverter/soundconv.cpp create mode 100644 fallen/Source/Anim.cpp create mode 100644 fallen/Source/Attract.cpp create mode 100644 fallen/Source/BonusSetup.cpp create mode 100644 fallen/Source/CamTargetSetup.cpp create mode 100644 fallen/Source/Camera.cpp create mode 100644 fallen/Source/CameraSetup.cpp create mode 100644 fallen/Source/Command.cpp create mode 100644 fallen/Source/Controls.cpp create mode 100644 fallen/Source/Cop.cpp create mode 100644 fallen/Source/CreatureSetup.cpp create mode 100644 fallen/Source/Darci.cpp create mode 100644 fallen/Source/EdStrings.cpp create mode 100644 fallen/Source/Effect.cpp create mode 100644 fallen/Source/Enemy.cpp create mode 100644 fallen/Source/EnemySetup.cpp create mode 100644 fallen/Source/EngWind.cpp create mode 100644 fallen/Source/Enter.cpp create mode 100644 fallen/Source/Env.cpp create mode 100644 fallen/Source/ExtendSetup.cpp create mode 100644 fallen/Source/FMatrix.cpp create mode 100644 fallen/Source/Furn.cpp create mode 100644 fallen/Source/GEdit.cpp create mode 100644 fallen/Source/Game.cpp create mode 100644 fallen/Source/Hierarchy.cpp create mode 100644 fallen/Source/ItemSetup.cpp create mode 100644 fallen/Source/Level.cpp create mode 100644 fallen/Source/Levelpsx.cpp create mode 100644 fallen/Source/Main.cpp create mode 100644 fallen/Source/Map.cpp create mode 100644 fallen/Source/MapExitSetup.cpp create mode 100644 fallen/Source/MapView.cpp create mode 100644 fallen/Source/MessageSetup.cpp create mode 100644 fallen/Source/Mission.cpp create mode 100644 fallen/Source/MoveSetup.cpp create mode 100644 fallen/Source/Nav.cpp create mode 100644 fallen/Source/NavSetup.cpp create mode 100644 fallen/Source/PeeSetup.cpp create mode 100644 fallen/Source/Person.cpp create mode 100644 fallen/Source/Pjectile.cpp create mode 100644 fallen/Source/Player.cpp create mode 100644 fallen/Source/PlayerSetup.cpp create mode 100644 fallen/Source/Prim.cpp create mode 100644 fallen/Source/ResetSetup.cpp create mode 100644 fallen/Source/Roper.cpp create mode 100644 fallen/Source/SfxSetup.cpp create mode 100644 fallen/Source/Sound.cpp create mode 100644 fallen/Source/Special.cpp create mode 100644 fallen/Source/State.cpp create mode 100644 fallen/Source/SubClass.cpp create mode 100644 fallen/Source/Switch.cpp create mode 100644 fallen/Source/TabCtl.cpp create mode 100644 fallen/Source/Thing.cpp create mode 100644 fallen/Source/Thug.cpp create mode 100644 fallen/Source/TransferSetup.cpp create mode 100644 fallen/Source/TrapSetup.cpp create mode 100644 fallen/Source/TriggerSetup.cpp create mode 100644 fallen/Source/VehicleSetup.cpp create mode 100644 fallen/Source/VfxSetup.cpp create mode 100644 fallen/Source/WSpace.cpp create mode 100644 fallen/Source/Wallhug.cpp create mode 100644 fallen/Source/WayWind.cpp create mode 100644 fallen/Source/activatesetup.cpp create mode 100644 fallen/Source/animSetup.cpp create mode 100644 fallen/Source/animal.cpp create mode 100644 fallen/Source/animtmap.cpp create mode 100644 fallen/Source/az.cpp create mode 100644 fallen/Source/balloon.cpp create mode 100644 fallen/Source/bang.cpp create mode 100644 fallen/Source/barrel.cpp create mode 100644 fallen/Source/barrelSetup.cpp create mode 100644 fallen/Source/bat.cpp create mode 100644 fallen/Source/bike.cpp create mode 100644 fallen/Source/bombSetup.cpp create mode 100644 fallen/Source/briefing.cpp create mode 100644 fallen/Source/build2.cpp create mode 100644 fallen/Source/building.cpp create mode 100644 fallen/Source/burnsetup.cpp create mode 100644 fallen/Source/cache.cpp create mode 100644 fallen/Source/cam.cpp create mode 100644 fallen/Source/canid.cpp create mode 100644 fallen/Source/chopper.cpp create mode 100644 fallen/Source/cloth.cpp create mode 100644 fallen/Source/cnet.cpp create mode 100644 fallen/Source/collide.cpp create mode 100644 fallen/Source/combat.cpp create mode 100644 fallen/Source/converse.cpp create mode 100644 fallen/Source/countersetup.cpp create mode 100644 fallen/Source/cutscene.cpp create mode 100644 fallen/Source/dc_credits.cpp create mode 100644 fallen/Source/dike.cpp create mode 100644 fallen/Source/dirt.cpp create mode 100644 fallen/Source/dlightSetup.cpp create mode 100644 fallen/Source/door.cpp create mode 100644 fallen/Source/drawtype.cpp create mode 100644 fallen/Source/drip.cpp create mode 100644 fallen/Source/elev.cpp create mode 100644 fallen/Source/enemyflagsetup.cpp create mode 100644 fallen/Source/env2.cpp create mode 100644 fallen/Source/eway.cpp create mode 100644 fallen/Source/fc.cpp create mode 100644 fallen/Source/fire.cpp create mode 100644 fallen/Source/fog.cpp create mode 100644 fallen/Source/frontend.cpp create mode 100644 fallen/Source/gamemenu.cpp create mode 100644 fallen/Source/glitter.cpp create mode 100644 fallen/Source/grenade.cpp create mode 100644 fallen/Source/guns.cpp create mode 100644 fallen/Source/heap.cpp create mode 100644 fallen/Source/hm.cpp create mode 100644 fallen/Source/hm_psx.cpp create mode 100644 fallen/Source/hook.cpp create mode 100644 fallen/Source/id.cpp create mode 100644 fallen/Source/inputbox.cpp create mode 100644 fallen/Source/inside2.cpp create mode 100644 fallen/Source/interact.cpp create mode 100644 fallen/Source/interfac.cpp create mode 100644 fallen/Source/io.cpp create mode 100644 fallen/Source/io_psx.cpp create mode 100644 fallen/Source/lead.cpp create mode 100644 fallen/Source/light.cpp create mode 100644 fallen/Source/locksetup.cpp create mode 100644 fallen/Source/maths.cpp create mode 100644 fallen/Source/mav.cpp create mode 100644 fallen/Source/memory.cpp create mode 100644 fallen/Source/mesh.cpp create mode 100644 fallen/Source/mist.cpp create mode 100644 fallen/Source/morph.cpp create mode 100644 fallen/Source/music.cpp create mode 100644 fallen/Source/nd.cpp create mode 100644 fallen/Source/night.cpp create mode 100644 fallen/Source/nightpsx.cpp create mode 100644 fallen/Source/ns.cpp create mode 100644 fallen/Source/ob.cpp create mode 100644 fallen/Source/overlay.cpp create mode 100644 fallen/Source/pap.cpp create mode 100644 fallen/Source/pause.cpp create mode 100644 fallen/Source/pausepsx.cpp create mode 100644 fallen/Source/pch_fall.cpp create mode 100644 fallen/Source/pcom.cpp create mode 100644 fallen/Source/pigeon.cpp create mode 100644 fallen/Source/plat.cpp create mode 100644 fallen/Source/platformSetup.cpp create mode 100644 fallen/Source/playcuts.cpp create mode 100644 fallen/Source/pow.cpp create mode 100644 fallen/Source/pq.cpp create mode 100644 fallen/Source/propedit.cpp create mode 100644 fallen/Source/psystem.cpp create mode 100644 fallen/Source/puddle.cpp create mode 100644 fallen/Source/pyro.cpp create mode 100644 fallen/Source/qedit.cpp create mode 100644 fallen/Source/qls.cpp create mode 100644 fallen/Source/qmap.cpp create mode 100644 fallen/Source/ribbon.cpp create mode 100644 fallen/Source/road.cpp create mode 100644 fallen/Source/save.cpp create mode 100644 fallen/Source/setskills.cpp create mode 100644 fallen/Source/sewer.cpp create mode 100644 fallen/Source/shadow.cpp create mode 100644 fallen/Source/signsetup.cpp create mode 100644 fallen/Source/sm.cpp create mode 100644 fallen/Source/snipe.cpp create mode 100644 fallen/Source/sound_id.cpp create mode 100644 fallen/Source/soundenv.cpp create mode 100644 fallen/Source/spark.cpp create mode 100644 fallen/Source/spotfxSetup.cpp create mode 100644 fallen/Source/stair.cpp create mode 100644 fallen/Source/stallsetup.cpp create mode 100644 fallen/Source/startscr.cpp create mode 100644 fallen/Source/supermap.cpp create mode 100644 fallen/Source/ticklist.cpp create mode 100644 fallen/Source/tracks.cpp create mode 100644 fallen/Source/treasuresetup.cpp create mode 100644 fallen/Source/trip.cpp create mode 100644 fallen/Source/vehicle.cpp create mode 100644 fallen/Source/walkable.cpp create mode 100644 fallen/Source/wand.cpp create mode 100644 fallen/Source/ware.cpp create mode 100644 fallen/Source/warefxsetup.cpp create mode 100644 fallen/Source/water.cpp create mode 100644 fallen/Source/waypointSetup.cpp create mode 100644 fallen/Source/widget.cpp create mode 100644 fallen/Source/wmove.cpp create mode 100644 fallen/Source/wptSetup.cpp create mode 100644 fallen/Source/xlat_str.cpp create mode 100644 fallen/UnInst/UnInst.c create mode 100644 fallen/UnInst/UnInst.dsp create mode 100644 fallen/UnInst/uninst.def create mode 100644 fallen/UnInst/uninst.rc create mode 100644 fallen/UpgradeLog.htm create mode 100644 fallen/cdsrc.bat create mode 100644 fallen/clumps.bat create mode 100644 fallen/compress.bat create mode 100644 fallen/copysrc.bat create mode 100644 fallen/doneclumps.bat create mode 100644 fallen/dxinstall/dinstall.c create mode 100644 fallen/dxinstall/dinstall.rc create mode 100644 fallen/dxinstall/directx.ico create mode 100644 fallen/dxinstall/dxinstall.dsp create mode 100644 fallen/dxinstall/readme.txt create mode 100644 fallen/dxinstall/resource.h create mode 100644 fallen/dxinstall/wincode.c create mode 100644 fallen/english.bat create mode 100644 fallen/englishsrc.bat create mode 100644 fallen/french.bat create mode 100644 fallen/frenchsrc.bat create mode 100644 fallen/german.bat create mode 100644 fallen/germansrc.bat create mode 100644 fallen/outro/Always.h create mode 100644 fallen/outro/Key.h create mode 100644 fallen/outro/Matrix.cpp create mode 100644 fallen/outro/Matrix.h create mode 100644 fallen/outro/Tga.cpp create mode 100644 fallen/outro/Tga.h create mode 100644 fallen/outro/back.cpp create mode 100644 fallen/outro/back.h create mode 100644 fallen/outro/cam.cpp create mode 100644 fallen/outro/cam.h create mode 100644 fallen/outro/checker.cpp create mode 100644 fallen/outro/checker.h create mode 100644 fallen/outro/credits.cpp create mode 100644 fallen/outro/credits.h create mode 100644 fallen/outro/font.cpp create mode 100644 fallen/outro/font.h create mode 100644 fallen/outro/imp.cpp create mode 100644 fallen/outro/imp.h create mode 100644 fallen/outro/lmap.cpp create mode 100644 fallen/outro/lmap.h create mode 100644 fallen/outro/main.cpp create mode 100644 fallen/outro/mf.cpp create mode 100644 fallen/outro/mf.h create mode 100644 fallen/outro/midasdll.h create mode 100644 fallen/outro/os.cpp create mode 100644 fallen/outro/os.h create mode 100644 fallen/outro/outro.dsp create mode 100644 fallen/outro/slap.cpp create mode 100644 fallen/outro/slap.h create mode 100644 fallen/outro/wire.cpp create mode 100644 fallen/outro/wire.h create mode 100644 fallen/psxlib/Headers/GDisplay.h create mode 100644 fallen/psxlib/Headers/GMaths.h create mode 100644 fallen/psxlib/Headers/GMem.h create mode 100644 fallen/psxlib/Headers/Ghost.h create mode 100644 fallen/psxlib/Headers/MFx.h create mode 100644 fallen/psxlib/Headers/mfxmusic.h create mode 100644 fallen/psxlib/Headers/myheap.h create mode 100644 fallen/psxlib/Source/GDisplay.cpp create mode 100644 fallen/psxlib/Source/GHost.cpp create mode 100644 fallen/psxlib/Source/GMaths.cpp create mode 100644 fallen/psxlib/Source/GMem.cpp create mode 100644 fallen/psxlib/Source/MFx.cpp create mode 100644 fallen/psxlib/Source/Sample.cpp create mode 100644 fallen/psxlib/Source/malloc.cpp create mode 100644 fallen/psxlib/Source/myheap.cpp create mode 100644 fallen/psxlib/Source/vsprintf.cpp create mode 100644 fallen/psxlib/psxlib.dsp create mode 100644 fallen/psxlib1/Debug/vc50.idb create mode 100644 fallen/psxlib1/ErrorLog.txt create mode 100644 fallen/psxlib1/Headers/Display.h create mode 100644 fallen/psxlib1/Headers/Draw2d.h create mode 100644 fallen/psxlib1/Headers/DrawPoly.h create mode 100644 fallen/psxlib1/Headers/Keyboard.h create mode 100644 fallen/psxlib1/Headers/MFD3D.h create mode 100644 fallen/psxlib1/Headers/MFErrors.h create mode 100644 fallen/psxlib1/Headers/MFFile.h create mode 100644 fallen/psxlib1/Headers/MFHeader.err create mode 100644 fallen/psxlib1/Headers/MFHeader.h create mode 100644 fallen/psxlib1/Headers/MFHost.err create mode 100644 fallen/psxlib1/Headers/MFHost.h create mode 100644 fallen/psxlib1/Headers/MFLbType.h create mode 100644 fallen/psxlib1/Headers/MFMaths.err create mode 100644 fallen/psxlib1/Headers/MFMaths.h create mode 100644 fallen/psxlib1/Headers/MFMem.h create mode 100644 fallen/psxlib1/Headers/MFStd.h create mode 100644 fallen/psxlib1/Headers/MFStdLib.h create mode 100644 fallen/psxlib1/Headers/MFTypes.h create mode 100644 fallen/psxlib1/Headers/MFUtils.err create mode 100644 fallen/psxlib1/Headers/MFUtils.h create mode 100644 fallen/psxlib1/Headers/Mouse.err create mode 100644 fallen/psxlib1/Headers/Mouse.h create mode 100644 fallen/psxlib1/Headers/Palette.h create mode 100644 fallen/psxlib1/Headers/Sprites.h create mode 100644 fallen/psxlib1/Headers/StdFile.h create mode 100644 fallen/psxlib1/Headers/StdKeybd.h create mode 100644 fallen/psxlib1/Headers/StdMaths.h create mode 100644 fallen/psxlib1/Headers/StdMem.h create mode 100644 fallen/psxlib1/Headers/StdMouse.h create mode 100644 fallen/psxlib1/LibsToDo.txt create mode 100644 fallen/psxlib1/MFLib.ptg create mode 100644 fallen/psxlib1/MFLib.tag create mode 100644 fallen/psxlib1/MakeLibs create mode 100644 fallen/psxlib1/MakeLibs.bat create mode 100644 fallen/psxlib1/Release/vc50.idb create mode 100644 fallen/psxlib1/Source/C/Common/DModes.cpp create mode 100644 fallen/psxlib1/Source/C/Common/DModes.err create mode 100644 fallen/psxlib1/Source/C/Common/Draw2d.cpp create mode 100644 fallen/psxlib1/Source/C/Common/DrawBox.cpp create mode 100644 fallen/psxlib1/Source/C/Common/DrawBox.err create mode 100644 fallen/psxlib1/Source/C/Common/DrawLine.cpp create mode 100644 fallen/psxlib1/Source/C/Common/DrawPnt.cpp create mode 100644 fallen/psxlib1/Source/C/Common/DrawPxl.cpp create mode 100644 fallen/psxlib1/Source/C/Common/DrawRect.cpp create mode 100644 fallen/psxlib1/Source/C/Common/DrawRect.err create mode 100644 fallen/psxlib1/Source/C/Common/Maths.cpp create mode 100644 fallen/psxlib1/Source/C/Common/Maths.err create mode 100644 fallen/psxlib1/Source/C/Common/QuickTxt.cpp create mode 100644 fallen/psxlib1/Source/C/Common/QuickTxt.err create mode 100644 fallen/psxlib1/Source/C/Common/Sprites.cpp create mode 100644 fallen/psxlib1/Source/C/Common/Sprites.err create mode 100644 fallen/psxlib1/Source/C/Common/TextDef.cpp create mode 100644 fallen/psxlib1/Source/C/Common/TextDef.err create mode 100644 fallen/psxlib1/Source/C/Common/Trig.cpp create mode 100644 fallen/psxlib1/Source/C/DOS/DDisplay.cpp create mode 100644 fallen/psxlib1/Source/C/DOS/DDisplay.err create mode 100644 fallen/psxlib1/Source/C/DOS/DFile.cpp create mode 100644 fallen/psxlib1/Source/C/DOS/DFile.err create mode 100644 fallen/psxlib1/Source/C/DOS/DKeybrd.cpp create mode 100644 fallen/psxlib1/Source/C/DOS/DKeybrd.err create mode 100644 fallen/psxlib1/Source/C/DOS/DMFHost.cpp create mode 100644 fallen/psxlib1/Source/C/DOS/DMem.cpp create mode 100644 fallen/psxlib1/Source/C/DOS/DMouse.cpp create mode 100644 fallen/psxlib1/Source/C/DOS/DMouse.err create mode 100644 fallen/psxlib1/Source/C/Windows/D3D.cpp create mode 100644 fallen/psxlib1/Source/C/Windows/Display.cpp create mode 100644 fallen/psxlib1/Source/C/Windows/Display.err create mode 100644 fallen/psxlib1/Source/C/Windows/File.cpp create mode 100644 fallen/psxlib1/Source/C/Windows/Keyboard.cpp create mode 100644 fallen/psxlib1/Source/C/Windows/Keyboard.err create mode 100644 fallen/psxlib1/Source/C/Windows/MDebug/MFLib1.bsc create mode 100644 fallen/psxlib1/Source/C/Windows/MDebug/vc50.idb create mode 100644 fallen/psxlib1/Source/C/Windows/MFHost.cpp create mode 100644 fallen/psxlib1/Source/C/Windows/MRelease/vc50.idb create mode 100644 fallen/psxlib1/Source/C/Windows/Mem.cpp create mode 100644 fallen/psxlib1/Source/C/Windows/Mouse.cpp create mode 100644 fallen/psxlib1/Source/C/Windows/Palette.cpp create mode 100644 fallen/psxlib1/Source/StdLib/StdFile.cpp create mode 100644 fallen/psxlib1/Source/StdLib/StdMaths.cpp create mode 100644 fallen/psxlib1/Source/StdLib/StdMem.cpp create mode 100644 fallen/psxlib1/W_DOS1_D.LBC create mode 100644 fallen/psxlib1/W_DOS1_R.LBC create mode 100644 fallen/psxlib1/W_WIN1_D.LBC create mode 100644 fallen/psxlib1/W_WIN1_R.LBC create mode 100644 fallen/psxlib1/mfstdlib.dsp create mode 100644 fallen/psxlib1/mfstdlib.dsw create mode 100644 fallen/psxlib1/mfstdlib.opt create mode 100644 fallen/psxlib1/psxlib1.dsw create mode 100644 fallen/psxlib1/psxlib1.opt create mode 100644 fallen/psxlib1/update.PIF create mode 100644 fallen/psxlib1/update.bat create mode 100644 fallen/sedit/Headers/es.h create mode 100644 fallen/sedit/Headers/sedit.h create mode 100644 fallen/sedit/Source/es.cpp create mode 100644 fallen/sedit/Source/sedit.cpp create mode 100644 fallen/server/extract.bat create mode 100644 fallen/text/lang_english.txt create mode 100644 fallen/text/lang_french.txt create mode 100644 fallen/text/lang_german.txt create mode 100644 thrust/Always.h create mode 100644 thrust/Key.h create mode 100644 thrust/Matrix.cpp create mode 100644 thrust/Matrix.h create mode 100644 thrust/Tga.cpp create mode 100644 thrust/Tga.h create mode 100644 thrust/ab.h create mode 100644 thrust/cam.cpp create mode 100644 thrust/cam.h create mode 100644 thrust/d3denum.cpp create mode 100644 thrust/d3denum.h create mode 100644 thrust/d3dframe.cpp create mode 100644 thrust/d3dframe.h create mode 100644 thrust/d3dutil.cpp create mode 100644 thrust/d3dutil.h create mode 100644 thrust/font.cpp create mode 100644 thrust/font.h create mode 100644 thrust/game.cpp create mode 100644 thrust/game.h create mode 100644 thrust/gamestate.cpp create mode 100644 thrust/gamestate.h create mode 100644 thrust/icon1.ico create mode 100644 thrust/imp.cpp create mode 100644 thrust/imp.h create mode 100644 thrust/land.cpp create mode 100644 thrust/land.h create mode 100644 thrust/lmap.cpp create mode 100644 thrust/lmap.h create mode 100644 thrust/log.cpp create mode 100644 thrust/log.h create mode 100644 thrust/main.cpp create mode 100644 thrust/menu.h create mode 100644 thrust/mf.cpp create mode 100644 thrust/mf.h create mode 100644 thrust/net.cpp create mode 100644 thrust/net.h create mode 100644 thrust/orb.cpp create mode 100644 thrust/orb.h create mode 100644 thrust/os.cpp create mode 100644 thrust/os.h create mode 100644 thrust/ping.cpp create mode 100644 thrust/ping.h create mode 100644 thrust/player.cpp create mode 100644 thrust/player.h create mode 100644 thrust/resource.h create mode 100644 thrust/server.cpp create mode 100644 thrust/server.h create mode 100644 thrust/ship.cpp create mode 100644 thrust/ship.h create mode 100644 thrust/slap.cpp create mode 100644 thrust/slap.h create mode 100644 thrust/tb.cpp create mode 100644 thrust/tb.h create mode 100644 thrust/thrust.dsp create mode 100644 thrust/thrust.dsw create mode 100644 thrust/thrust.rc create mode 100644 thrust/userdlg.cpp create mode 100644 thrust/wave.c create mode 100644 thrust/wave.h diff --git a/MFLib1/Headers/Display.h b/MFLib1/Headers/Display.h new file mode 100644 index 0000000..3b052f6 --- /dev/null +++ b/MFLib1/Headers/Display.h @@ -0,0 +1,125 @@ +// Display.h +// Guy Simmons, 6th October 1996. + +#ifndef _DISPLAY_H_ +#define _DISPLAY_H_ + +#ifndef _MF_TYPES_H_ + #include +#endif + + +//--------------------------------------------------------------- +// DModes.cpp + +#define DS_THREAD_ACTIVE (1<<0) +#define DS_SHELL_WINDOW_OPEN (1<<1) +#define DS_DIRECT_DRAW_ACTIVE (1<<2) +#define DS_DISPLAY_MODE_SET (1<<3) +#define DS_CREATED_SURFACES (1<<4) +#define DS_SCREEN_LOCKED (1<<5) + +enum DisplayModes +{ + DISPLAY_MODE_NONE = 0, + + DISPLAY_MODE_320_200_8, // 320x200 + DISPLAY_MODE_320_200_16, + DISPLAY_MODE_320_200_24, + DISPLAY_MODE_320_200_32, + DISPLAY_MODE_320_240_8, // 320x240 + DISPLAY_MODE_320_240_16, + DISPLAY_MODE_320_240_24, + DISPLAY_MODE_320_240_32, + DISPLAY_MODE_320_400_8, // 320x400 + DISPLAY_MODE_320_400_16, + DISPLAY_MODE_320_400_24, + DISPLAY_MODE_320_400_32, + DISPLAY_MODE_512_384_8, // 512x384 + DISPLAY_MODE_512_384_16, + DISPLAY_MODE_512_384_24, + DISPLAY_MODE_512_384_32, + DISPLAY_MODE_640_400_8, // 640x400 + DISPLAY_MODE_640_400_16, + DISPLAY_MODE_640_400_24, + DISPLAY_MODE_640_400_32, + DISPLAY_MODE_640_480_8, // 640x480 + DISPLAY_MODE_640_480_16, + DISPLAY_MODE_640_480_24, + DISPLAY_MODE_640_480_32, + DISPLAY_MODE_800_600_8, // 800x600 + DISPLAY_MODE_800_600_16, + DISPLAY_MODE_800_600_24, + DISPLAY_MODE_800_600_32, + DISPLAY_MODE_1024_768_8, // 1024x768 + DISPLAY_MODE_1024_768_16, + DISPLAY_MODE_1024_768_24, + DISPLAY_MODE_1024_768_32, + DISPLAY_MODE_1152_864_8, // 1152x864 + DISPLAY_MODE_1152_864_16, + DISPLAY_MODE_1152_864_24, + DISPLAY_MODE_1152_864_32, + DISPLAY_MODE_1280_1024_8, // 1280x1024 + DISPLAY_MODE_1280_1024_16, + DISPLAY_MODE_1280_1024_24, + DISPLAY_MODE_1280_1024_32, + + DISPLAY_MODE_COUNT +}; + +typedef struct +{ + BOOL Availability; // Do we have this mode? + ULONG Width, // Display dimensions. + Height, + Depth; + SLONG DisplayMode; // Internal host screen mode identifier. +#ifdef _MF_WINDOWS + DDSURFACEDESC DD_ModeDesc; +#endif +}DisplayModeInfo; + +extern DisplayModeInfo DisplayModes[]; + + +SLONG DisplayModeAvailable(ULONG width, ULONG height, ULONG depth); + + +//--------------------------------------------------------------- +// Display.cpp + +#define FLAGS_USE_3DFX (1<<0) + +#define DS_WAIT_VBI (1<<0) +#define DS_DO_FLIP (1<<1) + +extern UBYTE DisplayActive, + WorkScreenDepth, + *WorkScreen; +extern SLONG WorkScreenHeight, + WorkScreenPixelWidth, + WorkScreenWidth; + +#ifdef _MF_WINDOWS +extern DDSURFACEDESC DD_DisplayDesc; +extern LPDIRECTDRAW lp_DD; // Main DirectDraw object +extern LPDIRECTDRAWSURFACE lp_DD_FrontSurface, + lp_DD_BackSurface; +extern volatile UBYTE MFShellActive; +#endif + +SLONG OpenDisplay(ULONG width, ULONG height, ULONG depth, ULONG flags); +SLONG CloseDisplay(void); +SLONG SetDisplay(ULONG width,ULONG height,ULONG depth); +void ClearDisplay(void); +void FadeDisplay(UBYTE mode); +void *LockWorkScreen(void); +void UnlockWorkScreen(void); +void ShowWorkScreen(ULONG flags); +void ShowWorkWindow(ULONG flags); +void ClearWorkScreen(UBYTE colour); + + +//--------------------------------------------------------------- + +#endif diff --git a/MFLib1/Headers/Draw2d.h b/MFLib1/Headers/Draw2d.h new file mode 100644 index 0000000..cf5911a --- /dev/null +++ b/MFLib1/Headers/Draw2d.h @@ -0,0 +1,101 @@ +// Draw2D.h +// Guy Simmons, 7th October 1996. + +#ifndef _DRAW2D_H_ +#define _DRAW2D_H_ + +#ifndef _MF_TYPES_H_ + #include +#endif + +#ifndef _DISPLAY_H_ + #include +#endif + + +typedef struct +{ + SLONG X, + Y; +}MFPoint; + +typedef struct +{ + SLONG Left, + Top, + Right, + Bottom, + Width, + Height; +}MFRect; + +inline BOOL XYInRect(SLONG x,SLONG y,MFRect *the_rect) { if(x>=the_rect->Left&&y>=the_rect->Top&&x<=the_rect->Right&&y<=the_rect->Bottom)return TRUE;else return FALSE; } +inline BOOL PointInRect(MFPoint *the_point,MFRect *the_rect) { if(the_point->X>=the_rect->Left&&the_point->Y>=the_rect->Top&&the_point->X<=the_rect->Right&&the_point->Y<=the_rect->Bottom)return TRUE;else return FALSE; } + +//--------------------------------------------------------------- +// Draw2D.c + +extern UBYTE *WorkWindow; +extern SLONG WorkWindowHeight, + WorkWindowWidth; +extern MFRect WorkWindowRect; + +void SetWorkWindowBounds(SLONG left, SLONG top, SLONG width, SLONG height); +MFPoint *GlobalToLocal(MFPoint *the_point); +void GlobalXYToLocal(SLONG *x,SLONG *y); +inline void SetWorkWindow(void) { WorkWindow=(WorkScreen+WorkWindowRect.Left*WorkScreenDepth+(WorkWindowRect.Top*WorkScreenWidth)); } + +//--------------------------------------------------------------- +// DrawBox.c + +extern void (*DrawBox)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void (*DrawBoxC)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); + +//--------------------------------------------------------------- +// DrawLine.c + +extern void (*DrawLine)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void (*DrawLineC)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void (*DrawHLine)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void (*DrawHLineC)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void (*DrawVLine)(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void (*DrawVLineC)(SLONG x,SLONG y1,SLONG y2,ULONG colour); + + +//--------------------------------------------------------------- +// DrawPoint.c + +extern void (*DrawPoint)(MFPoint *the_point,ULONG colour); +extern void (*DrawPointC)(MFPoint *the_point,ULONG colour); + +//--------------------------------------------------------------- +// DrawPixel.c + +extern void (*DrawPixel)(SLONG x,SLONG y,ULONG colour); +extern void (*DrawPixelC)(SLONG x,SLONG y,ULONG colour); + +//--------------------------------------------------------------- +// DrawRect.c + +void DrawRect(MFRect *the_rect,ULONG colour); +void DrawRectC(MFRect *the_rect,ULONG colour); + +//--------------------------------------------------------------- +// QuickText.c + +extern UBYTE *CharTable[]; + + +extern void (*QuickText)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void (*QuickTextC)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void (*QuickChar)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void (*QuickCharC)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); + +SLONG QTStringWidth(CBYTE *the_string); +inline SLONG QTStringHeight(void) { return 8; } +inline SLONG QTCharWidth(CBYTE the_char) { return (CharTable[the_char])[0]; } +inline SLONG QTCharHeight(CBYTE the_char) { return (CharTable[the_char])[1]; } + +//--------------------------------------------------------------- + +#endif \ No newline at end of file diff --git a/MFLib1/Headers/DrawPoly.h b/MFLib1/Headers/DrawPoly.h new file mode 100644 index 0000000..41a9d5f --- /dev/null +++ b/MFLib1/Headers/DrawPoly.h @@ -0,0 +1,8 @@ +// DrawPoly.h +// Guy Simmons, 1st November 1996. + +#ifndef _DRAWPOLY_H_ +#define _DRAWPOLY_H_ + + +#endif diff --git a/MFLib1/Headers/Keyboard.h b/MFLib1/Headers/Keyboard.h new file mode 100644 index 0000000..f45f1eb --- /dev/null +++ b/MFLib1/Headers/Keyboard.h @@ -0,0 +1,142 @@ +// Keyboard.h +// Guy Simmons, 11th February 1997. + +#ifndef _KEYBOARD_H_ +#define _KEYBOARD_H_ + +#ifndef _MF_TYPES_H_ + #include +#endif + +// Row1 +#define KB_ESC 0x01 +#define KB_1 0x02 +#define KB_2 0x03 +#define KB_3 0x04 +#define KB_4 0x05 +#define KB_5 0x06 +#define KB_6 0x07 +#define KB_7 0x08 +#define KB_8 0x09 +#define KB_9 0x0a +#define KB_0 0x0b +#define KB_MINUS 0x0c +#define KB_PLUS 0x0d +#define KB_BS 0x0e + +// Row2 +#define KB_TAB 0x0f +#define KB_Q 0x10 +#define KB_W 0x11 +#define KB_E 0x12 +#define KB_R 0x13 +#define KB_T 0x14 +#define KB_Y 0x15 +#define KB_U 0x16 +#define KB_I 0x17 +#define KB_O 0x18 +#define KB_P 0x19 +#define KB_LBRACE 0x1a +#define KB_RBRACE 0x1b +#define KB_ENTER 0x1c + +// Row3 +#define KB_LCONTROL 0x1d +#define KB_CAPSLOCK 0x3a +#define KB_A 0x1e +#define KB_S 0x1f +#define KB_D 0x20 +#define KB_F 0x21 +#define KB_G 0x22 +#define KB_H 0x23 +#define KB_J 0x24 +#define KB_K 0x25 +#define KB_L 0x26 +#define KB_COLON 0x27 +#define KB_QUOTE 0x28 +#define KB_TILD 0x29 + +// Row4 +#define KB_LSHIFT 0x2a +#define KB_BACKSLASH 0x2b +#define KB_Z 0x2c +#define KB_X 0x2d +#define KB_C 0x2e +#define KB_V 0x2f +#define KB_B 0x30 +#define KB_N 0x31 +#define KB_M 0x32 +#define KB_COMMA 0x33 +#define KB_POINT 0x34 +#define KB_FORESLASH 0x35 +#define KB_RSHIFT 0x36 +#define KB_LALT 0x38 +#define KB_SPACE 0x39 +#define KB_RALT (0x38+0x80) +#define KB_RCONTROL (0x1d+0x80) + +// Function key row. +#define KB_F1 0x3b +#define KB_F2 0x3c +#define KB_F3 0x3d +#define KB_F4 0x3e + +#define KB_F5 0x3f +#define KB_F6 0x40 +#define KB_F7 0x41 +#define KB_F8 0x42 + +#define KB_F9 0x43 +#define KB_F10 0x44 +#define KB_F11 0x57 +#define KB_F12 0x58 + +#define KB_PRTSC (0x37+0x80) +#define KB_SCROLLLOCK 0x46 +//#define KB_PAUSE ???? + +// Edit pad. +#define KB_INS (0x52+0x80) +#define KB_HOME (0x47+0x80) +#define KB_PGUP (0x49+0x80) +#define KB_DEL (0x53+0x80) +#define KB_END (0x4f+0x80) +#define KB_PGDN (0x51+0x80) + +// Cursor pad. +#define KB_LEFT (0x4b+0x80) +#define KB_UP (0x48+0x80) +#define KB_RIGHT (0x4d+0x80) +#define KB_DOWN (0x50+0x80) + +// Key pad. +#define KB_NUMLOCK 0x45 +#define KB_PSLASH (0x35+0x80) +#define KB_ASTERISK 0x37 +#define KB_PMINUS 0x4a +#define KB_P7 0x47 +#define KB_P8 0x48 +#define KB_P9 0x49 +#define KB_PPLUS 0x4e +#define KB_P4 0x4b +#define KB_P5 0x4c +#define KB_P6 0x4d +#define KB_P1 0x4f +#define KB_P2 0x50 +#define KB_P3 0x51 +#define KB_PENTER (0x1c+0x80) +#define KB_P0 0x52 +#define KB_PPOINT 0x53 + + +extern volatile UBYTE AltFlag, + ControlFlag, + ShiftFlag; +extern volatile UBYTE Keys[256], + LastKey; + + +BOOL SetupKeyboard(void); +void ResetKeyboard(void); + +#endif diff --git a/MFLib1/Headers/MFD3D.h b/MFLib1/Headers/MFD3D.h new file mode 100644 index 0000000..833e5d3 --- /dev/null +++ b/MFLib1/Headers/MFD3D.h @@ -0,0 +1,26 @@ +// MFD3D.h +// Guy Simmons, 13th May 1997. + +#ifndef MFD3D_H +#define MFD3D_H + +#define D3D_HARDWARE (1<<0) +#define D3D_GOURAUD (1<<1) +#define D3D_ZBUFFER (1<<2) +#define D3D_RAMP (1<<3) + +extern BOOL HasHardware; +extern IDirect3DDevice2 *lp_D3D_Device; +extern LPDIRECT3D2 lp_D3D_2; + +//---------------------------------------------------------------------- + +void SetupD3D2(void); +void ResetD3D2(void); +BOOL ChooseD3DDevice(ULONG flags); + +//---------------------------------------------------------------------- + + + +#endif diff --git a/MFLib1/Headers/MFErrors.h b/MFLib1/Headers/MFErrors.h new file mode 100644 index 0000000..aab54c9 --- /dev/null +++ b/MFLib1/Headers/MFErrors.h @@ -0,0 +1,46 @@ +// Errors.h +// Guy Simmons, 6th October 1996. + +#ifndef _MF_ERRORS_H_ +#define _MF_ERRORS_H_ + +#ifdef _DEBUG + +#else + +#endif + +extern int MFMessage(const char *pMessage, const char *pFile, ULONG dwLine); + +#define ERROR_MSG(e,m) { if(!e) MFMessage(m,__FILE__,__LINE__); } +#ifndef ASSERT +#define ASSERT(e) ERROR_MSG(e,"Assert failed"); +#endif + +// Library Errors. +enum +{ + NoError = 0 +}; + + +// Display Errors. +enum +{ + DisplayCreationError = -100, + DisplayShutdownError = -101 +}; + +// File Errors. +enum +{ + FileOpenError = -1, + FileCloseError = -2, + FileCreationError = -3, + FileSizeError = -4, + FileReadError = -5, + FileWriteError = -6, + FileSeekError = -7, + FileLoadAtError = -8 +}; +#endif \ No newline at end of file diff --git a/MFLib1/Headers/MFFile.h b/MFLib1/Headers/MFFile.h new file mode 100644 index 0000000..34a2faa --- /dev/null +++ b/MFLib1/Headers/MFFile.h @@ -0,0 +1,41 @@ +// MFFile.h +// Guy Simmons, 10th February 1997. + +#ifndef _MF_FILE_H_ +#define _MF_FILE_H_ + +#ifdef _MF_WINDOWS +typedef HANDLE MFFileHandle; +#else +typedef SLONG MFFileHandle; +#endif + +#define FILE_OPEN_ERROR ((MFFileHandle)FileOpenError) +#define FILE_CLOSE_ERROR ((MFFileHandle)FileCloseError) +#define FILE_CREATION_ERROR ((MFFileHandle)FileCreationError) +#define FILE_SIZE_ERROR ((SLONG)FileSizeError) +#define FILE_READ_ERROR ((SLONG)FileReadError) +#define FILE_WRITE_ERROR ((SLONG)FileWriteError) +#define FILE_SEEK_ERROR ((SLONG)FileSeekError) +#define FILE_LOAD_AT_ERROR ((SLONG)FileLoadAtError) + +enum SeekModes +{ + SEEK_MODE_BEGINNING, + SEEK_MODE_CURRENT, + SEEK_MODE_END +}; + +BOOL FileExists(CBYTE *file_name); +MFFileHandle FileOpen(CBYTE *file_name); +void FileClose(MFFileHandle file_handle); +MFFileHandle FileCreate(CBYTE *file_name,BOOL overwrite); +void FileDelete(CBYTE *file_name); +SLONG FileSize(MFFileHandle file_handle); +SLONG FileRead(MFFileHandle file_handle,void *buffer,ULONG size); +SLONG FileWrite(MFFileHandle file_handle,void *buffer,ULONG size); +SLONG FileSeek(MFFileHandle file_handle,enum SeekModes mode,SLONG offset); +SLONG FileLoadAt(CBYTE *file_name,void *buffer); + + +#endif diff --git a/MFLib1/Headers/MFHeader.h b/MFLib1/Headers/MFHeader.h new file mode 100644 index 0000000..5ed6945 --- /dev/null +++ b/MFLib1/Headers/MFHeader.h @@ -0,0 +1,81 @@ +// MFHeader.h +// Guy Simmons, 1st Februry 1997. + +#ifndef MFHEADER_H +#define MFHEADER_H + +// Standard 'C' includes. +#ifndef TARGET_DC +#include +#include +#endif +#include +#include +#include +#include + + +// Set up Compilation defines. +#include + + +// Specific Windows includes. +#ifdef _MF_WINDOWS + + #ifndef _WIN32 + #define _WIN32 + #endif + + #ifndef WIN32 + #define WIN32 + #endif + +#define D3D_OVERLOADS + #include + #include +// #include + #include +// #include + #include + #include + #include + +#ifdef TARGET_DC +// Dreamcast-specific fixups and so on. +#include "target.h" +#endif + + #include + +#endif + +// Specific DOS includes. +#ifdef _MF_DOSX + #include + #include + #include + #include + #include + #include +#endif + + + + +// Mucky Foot library includes. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/MFLib1/Headers/MFHost.h b/MFLib1/Headers/MFHost.h new file mode 100644 index 0000000..a1a9cc3 --- /dev/null +++ b/MFLib1/Headers/MFHost.h @@ -0,0 +1,36 @@ +// MFHost.h - Windows. +// Guy Simmons, 1st February 1997. + + +#define H_CREATE_LOG (1<<0) + +#ifdef _MF_WINDOWS + +extern int iGlobalCmdShow; +extern HINSTANCE hGlobalInstance, + hGlobalPrevInstance; +extern LPSTR szGlobalCmdLine; + +#define main(ac,av) MF_main(ac,av) + +SLONG main(UWORD argc, TCHAR** argv); + +#endif + +struct MFTime +{ + SLONG Hours, + Minutes, + Seconds, + MSeconds; + SLONG DayOfWeek, // 0 - 6; Sunday = 0 + Day, + Month, // 1 - 12; January = 1 + Year; + SLONG Ticks; // Number of ticks(milliseconds) since windows started. +}; + +BOOL SetupHost(ULONG flags); +void ResetHost(void); +void LogText(CBYTE *error, ...); +void Time(struct MFTime *the_time); diff --git a/MFLib1/Headers/MFLbType.h b/MFLib1/Headers/MFLbType.h new file mode 100644 index 0000000..1ec76da --- /dev/null +++ b/MFLib1/Headers/MFLbType.h @@ -0,0 +1,133 @@ +// MFLbType.h +// Guy Simmons, 31st January 1997. + +#ifndef _MFLBTYPE_H_ +#define _MFLBTYPE_H_ + +//---------------------------------------------------------------------- +// Common header for generic types, macros & functions +//---------------------------------------------------------------------- + +/* + Predefined macros - Environment & Compilation defines. + + + Compile state: + _DEBUG Compiles a debug build. + + _RELEASE Comples a release build. + + Compiler: + _CW_ Codewarrior + + __MSC__ Microsoft Visual C++. + + __WATCOMC__ Watcom C++ Optimising compiler. + + Host Platform: + _MF_WINDOWS Microsoft Windows OS conforming to Win32 specification (Win95, NT3.51). + + _MF_DOSX Extended DOS. + + _MAC68K Macintosh 68K based machines. + + _MACPPC Macintosh PPC based machines. + + _PSX Sony Playstation. + + Host Processor: + _X86_ Intel compatible (PC). + + _68K_ Motorola 68K series compatible (Amiga, Macintosh, Pilot). + + _PPC_ Motorola PPC series compatible (M2, Macintosh). + + _MIPS_ (PSX) +*/ + + +#ifdef _DEBUG + #ifdef _RELEASE + #error Cannot compile Debug & Release builds at the same time. + #endif +#else + #ifndef _RELEASE + #error _DEBUG or _RELEASE need to be defined. + #endif +#endif + +#ifdef __WINDOWS_386__ // Watcom predefined for Windows build + #define _MF_WINDOWS +#elif defined(WIN32) + #define _MF_WINDOWS +#elif defined(_WIN32_WCE) + #define _MF_WINDOWS +#endif + +#ifdef __DOS__ + #define _MF_DOSX +#endif + + +/* + Implicit library linking - Set according to compile state. + + Naming convention. + + Compiler : (C)Codewarrior, + (M)MSDev, + (W)Watcom. + + Platform : (_DOS)Extended dos, + (_M68)Macintosh 68K, + (_MPP)Macintosh PPC, + (_PSX)Playstation, + (_WIN)Windows. + + Version : 1 + + Compilation : (_D)Debug, + (_R)Release. + + +*/ + +#ifdef _DEBUG + #ifdef _MSC_VER + #pragma comment(lib, "ddraw.lib") + #ifndef TARGET_DC + #pragma comment(lib, "dplay.lib") + #pragma comment(lib, "d3drm.lib") + #else + #pragma comment(lib, "dplayx.lib") + #endif + #pragma comment(lib, "M_WIN1_D") + #elif defined(__WATCOMC__) + #ifdef _MF_WINDOWS + #pragma library("W_WIN1_D") + #elif defined(_MF_DOSX) + #pragma library("W_DOS1_D") + #endif + #endif +#else + #ifdef _MSC_VER + #pragma comment(lib, "ddraw.lib") + #ifndef TARGET_DC + #pragma comment(lib, "dplay.lib") + #pragma comment(lib, "d3drm.lib") + #else + #pragma comment(lib, "dplayx.lib") + #endif + #pragma comment(lib, "M_WIN1_R") + #elif defined(__WATCOMC__) + #ifdef _MF_WINDOWS + #pragma library("W_WIN1_R") + #elif defined(_MF_DOSX) + #pragma library("W_DOS1_R") + #endif + #endif +#endif + +//---------------------------------------------------------------------- + +#endif diff --git a/MFLib1/Headers/MFMaths.h b/MFLib1/Headers/MFMaths.h new file mode 100644 index 0000000..b0e000d --- /dev/null +++ b/MFLib1/Headers/MFMaths.h @@ -0,0 +1,70 @@ +// Trig.h +// Guy Simmons, 16th February 1997. + + +#define SIN(a) SinTable[a] +#define COS(a) CosTable[a] + +#define SIN_F(a) SinTableF[a] +#define COS_F(a) CosTableF[a] + +//--------------------------------------------------------------- +// Maths.cpp + +SLONG Arctan(SLONG X,SLONG Y); +SLONG Root(SLONG square); +#ifdef __WATCOMC__ +extern UWORD ini_table[]; +SLONG Root(SLONG square); +#pragma aux Root = \ + " xor ebx,ebx "\ + " bsr eax,ecx "\ + " je done_it "\ + " movzx ebx,ini_table[eax*2] "\ + "do_it: "\ + " mov eax,ecx "\ + " xor edx,edx "\ + " div ebx "\ + " cmp eax,ebx "\ + " jge done_it "\ + " add ebx,eax "\ + " shr ebx,1 "\ + " jmp do_it "\ + "done_it: "\ + " mov eax,ebx "\ + parm[ecx] \ + modify[eax ebx ecx edx] \ + value[eax]; +#endif + + +//--------------------------------------------------------------- +// Trig.cpp + +extern float *CosTableF, + SinTableF[]; +extern SWORD AtanTable[]; +extern SLONG *CosTable, + SinTable[]; +extern SLONG Proportions[]; + + +//--------------------------------------------------------------- + +#define PROPTABLE_SIZE 256 +#define PROP(x) Proportions[(x)+PROPTABLE_SIZE] + +static inline SLONG Hypotenuse(SLONG x,SLONG y) +{ + x = abs(x); + y = abs(y); + if(x>y) + return((PROP((y<<8)/x)*x)>>13); + else + if(y) + return((PROP((x<<8)/y)*y)>>13); + else + return(0); +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Headers/MFMem.h b/MFLib1/Headers/MFMem.h new file mode 100644 index 0000000..397feac --- /dev/null +++ b/MFLib1/Headers/MFMem.h @@ -0,0 +1,12 @@ +// MFMem.h +// Guy Simmons, 10th February 1997. + +#ifndef _MF_MEM_H_ +#define _MF_MEM_H_ + +BOOL SetupMemory(void); +void ResetMemory(void); +void *MemAlloc(ULONG size); +void MemFree(void *mem_ptr); + +#endif diff --git a/MFLib1/Headers/MFStd.h b/MFLib1/Headers/MFStd.h new file mode 100644 index 0000000..b4149c0 --- /dev/null +++ b/MFLib1/Headers/MFStd.h @@ -0,0 +1,16 @@ +// MFStd.h +// Guy Simmons, 17th October 1996. + +#ifndef _MFSTD_H_ +#define _MFSTD_H_ + +#ifndef _MF_TYPES_H_ + #include +#endif + +#ifndef _MF_ERRORS_H_ + #include +#endif + + +#endif \ No newline at end of file diff --git a/MFLib1/Headers/MFTypes.h b/MFLib1/Headers/MFTypes.h new file mode 100644 index 0000000..492db91 --- /dev/null +++ b/MFLib1/Headers/MFTypes.h @@ -0,0 +1,26 @@ +// MFTypes.h +// Guy Simmons, 6th October 1996. + +// Type definitions for 'Mucky Foot' Libraries. + + +#ifndef _MF_TYPES_H_ +#define _MF_TYPES_H_ + +#define TRUE 1 +#define FALSE 0 + +#if defined(_MF_DOSX) +typedef unsigned long BOOL; +#endif + +typedef unsigned char UBYTE; +typedef signed char SBYTE; +typedef char CBYTE; +typedef unsigned short UWORD; +typedef signed short SWORD; +typedef unsigned long ULONG; +typedef signed long SLONG; + + +#endif diff --git a/MFLib1/Headers/MFUtils.h b/MFLib1/Headers/MFUtils.h new file mode 100644 index 0000000..153dff2 --- /dev/null +++ b/MFLib1/Headers/MFUtils.h @@ -0,0 +1,23 @@ +// Utils.h +// Guy Simmons, 7th October 1996. + +#ifndef _MF_UTILS_H_ +#define _MF_UTILS_H_ + +#ifdef __WATCOMC__ +#define abs(a) (((a)<0) ? -(a) : (a)) +#endif +#define sgn(a) (((a)<0) ? -1 : 1) +#define swap(a,b) {a^=b;b^=a;a^=b;} + +#define in_range(a,min,max) {if(a>(max))a=(max);else if(a<(min))a=(min);} +#ifndef min +#define min(a,b) (((a)<(b)) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) (((a)>(b)) ? (a) : (b)) +#endif + + +#endif diff --git a/MFLib1/Headers/Mouse.h b/MFLib1/Headers/Mouse.h new file mode 100644 index 0000000..16c1935 --- /dev/null +++ b/MFLib1/Headers/Mouse.h @@ -0,0 +1,32 @@ +// Mouse.h +// Guy Simmons, 19th February 1997. + +#ifndef _MOUSE_H_ +#define _MOUSE_H_ + + +struct LastMouse +{ + SLONG ButtonState, + MouseX, + MouseY; + MFPoint MousePoint; +}; + + + +extern volatile UBYTE MouseMoved, + LeftButton, + MiddleButton, + RightButton; +extern volatile SLONG MouseX, + MouseY; +extern volatile LastMouse LeftMouse, + MiddleMouse, + RightMouse; +extern volatile MFPoint MousePoint; + +extern void RemoveMouse(void); +extern void PlaceMouse(void); + +#endif diff --git a/MFLib1/Headers/Palette.h b/MFLib1/Headers/Palette.h new file mode 100644 index 0000000..3eeb74c --- /dev/null +++ b/MFLib1/Headers/Palette.h @@ -0,0 +1,24 @@ +// Palette.h +// Guy Simmons, 11th February 1997. + +#ifndef _PALETTE_H_ +#define _PALETTE_H_ + +#ifndef _MF_TYPES_H_ + #include +#endif + +#define FADE_IN 1<<0 +#define FADE_OUT 1<<1 + +extern UBYTE CurrentPalette[256*3]; + +void InitPalettes(void); +SLONG CreatePalettes(void); +void DestroyPalettes(void); +void RestorePalettes(void); +void SetPalette(UBYTE *the_palette); +SLONG FindColour(UBYTE *pal,SLONG r,SLONG g,SLONG b); + + +#endif diff --git a/MFLib1/Headers/Sprites.h b/MFLib1/Headers/Sprites.h new file mode 100644 index 0000000..10a38c2 --- /dev/null +++ b/MFLib1/Headers/Sprites.h @@ -0,0 +1,41 @@ +// Sprites.h +// Guy Simmons, 13th February 1997. + +#ifndef _SPRITES_H_ +#define _SPRITES_H_ + +#ifndef _MF_TYPES_H_ + #include +#endif + +#define END_LINE 0x00 +#define COPY_PIXELS 0x01 +#define SKIP_PIXELS 0x02 +#define DUPLICATE_PIXELS 0x03 +#define FINISHED 0x04 + + +typedef struct +{ + UBYTE *SpriteData; + UWORD SpriteHeight; + UWORD SpriteWidth; +}BSprite; + + +extern void (*DrawBSprite)(SLONG x,SLONG y,BSprite *the_sprite); +extern void (*DrawBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite); + +extern void DrawBSpritePal16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +extern void DrawBSpritePal32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); + +extern void (*DrawMonoBSprite)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void (*DrawMonoBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + + +extern void DrawBSpritePalC16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +extern void DrawBSpritePalC32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); + +extern void SetupBSprites(BSprite *sprite_ref,UBYTE *sprite_data); + +#endif diff --git a/MFLib1/MFLib1.dsp b/MFLib1/MFLib1.dsp new file mode 100644 index 0000000..6fb9400 --- /dev/null +++ b/MFLib1/MFLib1.dsp @@ -0,0 +1,242 @@ +# Microsoft Developer Studio Project File - Name="MFLib1" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=MFLib1 - 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 "MFLib1.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 "MFLib1.mak" CFG="MFLib1 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MFLib1 - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "MFLib1 - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName ""$/MFLib1", NABAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe + +!IF "$(CFG)" == "MFLib1 - 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 ".\Source\C\Windows\MRelease" +# PROP Intermediate_Dir ".\Source\C\Windows\MRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_RELEASE" /YX /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:".\Libs\M_win1_r.lib" + +!ELSEIF "$(CFG)" == "MFLib1 - 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 ".\Source\C\Windows\MDebug" +# PROP Intermediate_Dir ".\Source\C\Windows\MDebug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:".\Libs\M_win1_d.lib" + +!ENDIF + +# Begin Target + +# Name "MFLib1 - Win32 Release" +# Name "MFLib1 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\Source\C\Windows\D3D.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Windows\Display.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\DModes.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\Draw2d.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\DrawBox.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\DrawLine.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\DrawPnt.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\DrawPxl.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\DrawRect.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Windows\File.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Windows\Keyboard.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\Maths.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Windows\Mem.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Windows\MFHost.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Windows\Mouse.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Windows\Palette.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\QuickTxt.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\Sprites.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\TextDef.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\C\Common\Trig.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\Headers\Display.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\Draw2d.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\DrawPoly.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\Keyboard.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFD3D.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFErrors.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFFile.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFHeader.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFHost.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFLbType.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFMaths.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFMem.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFStd.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFTypes.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\MFUtils.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\Mouse.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\Palette.h +# End Source File +# Begin Source File + +SOURCE=.\Headers\Sprites.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 +# End Target +# End Project diff --git a/MFLib1/Source/C/Common/DModes.cpp b/MFLib1/Source/C/Common/DModes.cpp new file mode 100644 index 0000000..fd0fe01 --- /dev/null +++ b/MFLib1/Source/C/Common/DModes.cpp @@ -0,0 +1,101 @@ +// DModes.cpp +// Guy Simmons, 8th February 1996. + +#include + +//--------------------------------------------------------------- + +DisplayModeInfo DisplayModes[] = +{ + { FALSE, 0,0,0, DISPLAY_MODE_NONE }, + + { FALSE, 320,200,8, DISPLAY_MODE_320_200_8 }, // 320x200 + { FALSE, 320,200,16, DISPLAY_MODE_320_200_16 }, + { FALSE, 320,200,24, DISPLAY_MODE_320_200_24 }, + { FALSE, 320,200,32, DISPLAY_MODE_320_200_32 }, + { FALSE, 320,240,8, DISPLAY_MODE_320_240_8 }, // 320x240 + { FALSE, 320,240,16, DISPLAY_MODE_320_240_16 }, + { FALSE, 320,240,24, DISPLAY_MODE_320_240_24 }, + { FALSE, 320,240,32, DISPLAY_MODE_320_240_32 }, + { FALSE, 320,400,8, DISPLAY_MODE_320_400_8 }, // 320x400 + { FALSE, 320,400,16, DISPLAY_MODE_320_400_16 }, + { FALSE, 320,400,24, DISPLAY_MODE_320_400_24 }, + { FALSE, 320,400,32, DISPLAY_MODE_320_400_32 }, + { FALSE, 512,384,8, DISPLAY_MODE_512_384_8 }, // 512x384 + { FALSE, 512,384,16, DISPLAY_MODE_512_384_16 }, + { FALSE, 512,384,24, DISPLAY_MODE_512_384_24 }, + { FALSE, 512,384,32, DISPLAY_MODE_512_384_32 }, + { FALSE, 640,400,8, DISPLAY_MODE_640_400_8 }, // 640x400 + { FALSE, 640,400,16, DISPLAY_MODE_640_400_16 }, + { FALSE, 640,400,24, DISPLAY_MODE_640_400_24 }, + { FALSE, 640,400,32, DISPLAY_MODE_640_400_32 }, + { FALSE, 640,480,8, DISPLAY_MODE_640_480_8 }, // 640x480 + { FALSE, 640,480,16, DISPLAY_MODE_640_480_16 }, + { FALSE, 640,480,24, DISPLAY_MODE_640_480_24 }, + { FALSE, 640,480,32, DISPLAY_MODE_640_480_32 }, + { FALSE, 800,600,8, DISPLAY_MODE_800_600_8 }, // 800x600 + { FALSE, 800,600,16, DISPLAY_MODE_800_600_16 }, + { FALSE, 800,600,24, DISPLAY_MODE_800_600_24 }, + { FALSE, 800,600,32, DISPLAY_MODE_800_600_32 }, + { FALSE, 1024,768,8, DISPLAY_MODE_1024_768_8 }, // 1024x768 + { FALSE, 1024,768,16, DISPLAY_MODE_1024_768_16 }, + { FALSE, 1024,768,24, DISPLAY_MODE_1024_768_24 }, + { FALSE, 1024,768,32, DISPLAY_MODE_1024_768_32 }, + { FALSE, 1152,864,8, DISPLAY_MODE_1152_864_8 }, // 1152x864 + { FALSE, 1152,864,16, DISPLAY_MODE_1152_864_16 }, + { FALSE, 1152,864,24, DISPLAY_MODE_1152_864_24 }, + { FALSE, 1152,864,32, DISPLAY_MODE_1152_864_32 }, + { FALSE, 1280,1024,8, DISPLAY_MODE_1280_1024_8 }, // 1280x1024 + { FALSE, 1280,1024,16, DISPLAY_MODE_1280_1024_16 }, + { FALSE, 1280,1024,24, DISPLAY_MODE_1280_1024_24 }, + { FALSE, 1280,1024,32, DISPLAY_MODE_1280_1024_32 } +}; + +//--------------------------------------------------------------- + +extern BOOL EmulateLoRes; + +SLONG DisplayModeAvailable(ULONG width, ULONG height, ULONG depth) +{ +#ifdef _DEBUG + // Shut the compiler up. + width = width; + height = height; + depth = depth; + return TRUE; +#else + ULONG c0; + SLONG result = DISPLAY_MODE_NONE; + + + EmulateLoRes = FALSE; + for(c0=1;c0 + +UBYTE *WorkWindow; +SLONG WorkWindowHeight, + WorkWindowWidth; +MFRect WorkWindowRect; + +//--------------------------------------------------------------- + +extern void DrawBox8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBoxC8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBox16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBoxC16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBox32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBoxC32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); + +extern void DrawLine8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLineC8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLine16(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLineC16(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLine32(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLineC32(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); + +extern void DrawHLine8(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLineC8(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLine16(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLineC16(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLine32(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLineC32(SLONG x1,SLONG x2,SLONG y,ULONG colour); + +extern void DrawVLine8(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLineC8(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLine16(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLineC16(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLine32(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLineC32(SLONG x,SLONG y1,SLONG y2,ULONG colour); + +extern void DrawPoint8(MFPoint *the_point,ULONG colour); +extern void DrawPointC8(MFPoint *the_point,ULONG colour); +extern void DrawPoint16(MFPoint *the_point,ULONG colour); +extern void DrawPointC16(MFPoint *the_point,ULONG colour); +extern void DrawPoint32(MFPoint *the_point,ULONG colour); +extern void DrawPointC32(MFPoint *the_point,ULONG colour); + +extern void DrawPixel8(SLONG x,SLONG y,ULONG colour); +extern void DrawPixelC8(SLONG x,SLONG y,ULONG colour); +extern void DrawPixel16(SLONG x,SLONG y,ULONG colour); +extern void DrawPixelC16(SLONG x,SLONG y,ULONG colour); +extern void DrawPixel32(SLONG x,SLONG y,ULONG colour); +extern void DrawPixelC32(SLONG x,SLONG y,ULONG colour); + +extern void QuickText8(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickTextC8(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickChar8(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void QuickCharC8_16_32(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void QuickText16(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickTextC16(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickChar16(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void QuickText32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickTextC32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickChar32(SLONG x,SLONG y,CBYTE the_char,ULONG colour); + +extern void DrawBSprite8(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSprite16(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSprite32(SLONG x,SLONG y,BSprite *the_sprite); + +extern void DrawBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite); + +extern void DrawMonoBSprite8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSprite16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSprite32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + +extern void DrawMonoBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + +//--------------------------------------------------------------- +// Set Function pointers for this display depth +void (*DrawBox)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +void (*DrawBoxC)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); + +void (*DrawLine)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +void (*DrawLineC)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +void (*DrawHLine)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +void (*DrawHLineC)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +void (*DrawVLine)(SLONG x,SLONG y1,SLONG y2,ULONG colour); +void (*DrawVLineC)(SLONG x,SLONG y1,SLONG y2,ULONG colour); + +void (*DrawPoint)(MFPoint *the_point,ULONG colour); +void (*DrawPointC)(MFPoint *the_point,ULONG colour); + + +void (*DrawPixel)(SLONG x,SLONG y,ULONG colour); +void (*DrawPixelC)(SLONG x,SLONG y,ULONG colour); + +void (*QuickText)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +void (*QuickTextC)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +void (*QuickChar)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +void (*QuickCharC)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); + +void (*DrawBSprite)(SLONG x,SLONG y,BSprite *the_sprite); +void (*DrawBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite); + +void (*DrawMonoBSprite)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +void (*DrawMonoBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + +void SetDrawFunctions(ULONG depth) +{ + switch (depth) + { + case 8: + DrawBox=DrawBox8; + DrawBoxC=DrawBoxC8; + + DrawLine=DrawLine8; + DrawLineC=DrawLineC8; + DrawHLine=DrawHLine8; + DrawHLineC=DrawHLineC8; + DrawVLine=DrawVLine8; + DrawVLineC=DrawVLineC8; + + DrawPoint=DrawPoint8; + DrawPointC=DrawPointC8; + + DrawPixel=DrawPixel8; + DrawPixelC=DrawPixelC8; + + QuickText =QuickText8; + QuickTextC=QuickTextC8; + QuickChar =QuickChar8; + QuickCharC=QuickCharC8_16_32; + + DrawBSprite=DrawBSprite8; + DrawBSpriteC=DrawBSpriteC8; + + DrawMonoBSprite=DrawMonoBSprite8; + DrawMonoBSpriteC=DrawMonoBSpriteC8; + + WorkScreenDepth=1; + break; + case 15: + case 16: + DrawBox=DrawBox16; + DrawBoxC=DrawBoxC16; + + DrawLine=DrawLine16; + DrawLineC=DrawLineC8; + DrawHLine=DrawHLine16; + DrawHLineC=DrawHLineC16; + DrawVLine=DrawVLine16; + DrawVLineC=DrawVLineC16; + + DrawPoint=DrawPoint16; + DrawPointC=DrawPointC16; + + DrawPixel=DrawPixel16; + DrawPixelC=DrawPixelC16; + + QuickText =QuickText16; + QuickTextC=QuickTextC16; + QuickChar =QuickChar16; + QuickCharC=QuickCharC8_16_32; + + DrawBSprite=DrawBSprite16; + DrawBSpriteC=DrawBSpriteC16; + + DrawMonoBSprite=DrawMonoBSprite16; + DrawMonoBSpriteC=DrawMonoBSpriteC16; + + WorkScreenDepth=2; + break; + case 24: + case 32: + DrawBox=DrawBox32; + DrawBoxC=DrawBoxC32; + + DrawLine=DrawLine32; + DrawLineC=DrawLineC8; + DrawHLine=DrawHLine32; + DrawHLineC=DrawHLineC32; + DrawVLine=DrawVLine32; + DrawVLineC=DrawVLineC32; + + DrawPoint=DrawPoint32; + DrawPointC=DrawPointC32; + + DrawPixel=DrawPixel32; + DrawPixelC=DrawPixelC32; + + QuickText =QuickText32; + QuickTextC=QuickTextC32; + QuickChar =QuickChar32; + QuickCharC=QuickCharC8_16_32; + + DrawBSprite=DrawBSprite32; + DrawBSpriteC=DrawBSpriteC32; + + DrawMonoBSprite=DrawMonoBSprite32; + DrawMonoBSpriteC=DrawMonoBSpriteC32; + + WorkScreenDepth=4; + break; + } +} + +//--------------------------------------------------------------- + +void SetWorkWindowBounds(SLONG left, SLONG top, SLONG width, SLONG height) +{ + if((left+width)>=WorkScreenPixelWidth) + { + width -= (left+width)-WorkScreenPixelWidth; + if(width<1) + { + left = 0; + width = 1; + } + } + if((top+height)>=WorkScreenHeight) + { + height -= (top+height)-WorkScreenHeight; + if(height<1) + { + top = 0; + height = 1; + } + } + WorkWindowRect.Left = left; + WorkWindowRect.Top = top; + WorkWindowRect.Right = (left+width)-1; + WorkWindowRect.Bottom = (top+height)-1; + WorkWindowRect.Width = width; + WorkWindowRect.Height = height; + + WorkWindowHeight = height; + WorkWindowWidth = width; + + SetWorkWindow(); +} + +//--------------------------------------------------------------- + +MFPoint *GlobalToLocal(MFPoint *the_point) +{ + the_point->X -= WorkWindowRect.Left; + the_point->Y -= WorkWindowRect.Top; + + return the_point; +} + +//--------------------------------------------------------------- + +void GlobalXYToLocal(SLONG *x,SLONG *y) +{ + *x -= WorkWindowRect.Left; + *y -= WorkWindowRect.Top; +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/DrawBox.cpp b/MFLib1/Source/C/Common/DrawBox.cpp new file mode 100644 index 0000000..7025d81 --- /dev/null +++ b/MFLib1/Source/C/Common/DrawBox.cpp @@ -0,0 +1,329 @@ +// DrawBox.cpp +// Guy Simmons, 11th February 1997. + + +#include + +#define COLOUR_TO_LONG(c) (0x01010101*c) +#define COLOURW_TO_LONG(c) (0x00010001*c) + + +//--------------------------------------------------------------- + +void DrawBox8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UBYTE *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + + ptr = WorkWindow+x+(y*WorkScreenWidth); //have to use window + temp_width = width; + if(width<=4) + { + // Thin rectangles. + for(;height>=0;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOUR_TO_LONG(colour); + + for(;height>=0;height--) + { + for(width=x&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + w2 = temp_width-(x&3); + ptr_big = (ULONG*)ptr; + for(width=w2>>2;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UBYTE*)ptr_big; + for(width=w2&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } +} + +void DrawBox16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UWORD *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + ptr = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); //have to use window + temp_width = width; + if(width<=2) + { + // Thin rectangles. + for(;height>=0;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOURW_TO_LONG(colour); + + for(;height>=0;height--) + { + for(width=x&1;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + w2 = temp_width-(x&1); + ptr_big = (ULONG*)ptr; + for(width=w2>>1;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UWORD*)ptr_big; + for(width=w2&1;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += (WorkScreenWidth>>1)-temp_width; + } + } +} + +void DrawBox32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + ULONG *ptr; + SLONG temp_width; + + + ptr = (ULONG*)WorkWindow+x+(y*WorkScreenWidth>>2); //have to use window + temp_width = width; + { + // Thin rectangles. + for(;height>=0;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = colour; + } + ptr += ((WorkScreenWidth>>2)-temp_width); + } + } +} + +//--------------------------------------------------------------- + +void DrawBoxC8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UBYTE *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0) + { + width += x; + x = 0; + } + if(y<0) + { + height += y; + y = 0; + } + if((x+width)>=WorkWindowWidth) + { + width -= (x+width)-WorkWindowWidth; + } + if((y+height)>=WorkWindowHeight) + { + height -= (y+height)-WorkWindowHeight; + } + + if(width<=0 || height<=0) + return; + + ptr = WorkWindow+x+(y*WorkScreenWidth); //have to use window + temp_width = width; + if(width<=4) + { + // Thin rectangles. + for(;height;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOUR_TO_LONG(colour); + + for(;height;height--) + { + for(width=x&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + w2 = temp_width-(x&3); + ptr_big = (ULONG*)ptr; + for(width=w2>>2;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UBYTE*)ptr_big; + for(width=w2&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } +} + +void DrawBoxC16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UWORD *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0) + { + width += x; + x = 0; + } + if(y<0) + { + height += y; + y = 0; + } + if((x+width)>=WorkWindowWidth) + { + width -= (x+width)-WorkWindowWidth; + } + if((y+height)>=WorkWindowHeight) + { + height -= (y+height)-WorkWindowHeight; + } + + if(width<=0 || height<=0) + return; + + ptr = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); //have to use window + temp_width = width; + if(width<=2) + { + // Thin rectangles. + for(;height;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + ptr += (WorkScreenWidth>>1)-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOURW_TO_LONG(colour); + + for(;height;height--) + { + for(width=x&1;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + w2 = temp_width-(x&1); + ptr_big = (ULONG*)ptr; + for(width=w2>>1;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UWORD*)ptr_big; + for(width=w2&1;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + ptr += (WorkScreenWidth>>1)-temp_width; + } + } +} + +void DrawBoxC32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + ULONG *ptr; + SLONG temp_width; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0) + { + width += x; + x = 0; + } + if(y<0) + { + height += y; + y = 0; + } + if((x+width)>=WorkWindowWidth) + { + width -= (x+width)-WorkWindowWidth; + } + if((y+height)>=WorkWindowHeight) + { + height -= (y+height)-WorkWindowHeight; + } + + if(width<=0 || height<=0) + return; + + ptr = (ULONG*)WorkWindow+(x)+(y*WorkScreenWidth>>2); //have to use window + temp_width = width; + + for(;height;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = colour; + } + ptr += ((WorkScreenWidth>>2)-temp_width); + } +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/DrawLine.cpp b/MFLib1/Source/C/Common/DrawLine.cpp new file mode 100644 index 0000000..5d58a67 --- /dev/null +++ b/MFLib1/Source/C/Common/DrawLine.cpp @@ -0,0 +1,562 @@ +// DrawLine.c +// Guy Simmons, 7th October 1996 + + +#include + + +//--------------------------------------------------------------- +// Standard Bresenham algorithm. + +void DrawLine8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + UBYTE *line_dest; + SLONG ax,ay, + d, + dx,dy, + modulo, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + modulo = WorkScreenWidth*sy; + + x = x1; + y = y1; + line_dest = WorkWindow+x+(y*WorkScreenWidth); + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + *line_dest = (UBYTE)colour; + if(x==x2) + return; + if(d>=0) + { + d -= ax; + line_dest += modulo; + } + x += sx; + d += ay; + line_dest += sx; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + *line_dest = (UBYTE)colour; + if(y==y2) + return; + if(d>=0) + { + d -= ay; + line_dest += sx; + } + y += sy; + d += ax; + line_dest += modulo; + } + } +} + +void DrawLine16(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + UWORD *line_dest; + SLONG ax,ay, + d, + dx,dy, + modulo, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + modulo = (WorkScreenWidth>>1)*sy; + + x = x1; + y = y1; + line_dest = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + *line_dest = (UWORD)colour; + if(x==x2) + return; + if(d>=0) + { + d -= ax; + line_dest += modulo; + } + x += sx; + d += ay; + line_dest += sx; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + *line_dest = (UWORD)colour; + if(y==y2) + return; + if(d>=0) + { + d -= ay; + line_dest += sx; + } + y += sy; + d += ax; + line_dest += modulo; + } + } +} + +void DrawLine32(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + ULONG *line_dest; + SLONG ax,ay, + d, + dx,dy, + modulo, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + modulo = (WorkScreenWidth>>2)*sy; + + x = x1; + y = y1; + line_dest = (ULONG*)WorkWindow+x+(y*WorkScreenWidth>>2); + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + *line_dest = (ULONG)colour; + if(x==x2) + return; + if(d>=0) + { + d -= ax; + line_dest += modulo; + } + x += sx; + d += ay; + line_dest += sx; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + *line_dest = (ULONG)colour; + if(y==y2) + return; + if(d>=0) + { + d -= ay; + line_dest += sx; + } + y += sy; + d += ax; + line_dest += modulo; + } + } +} + +//--------------------------------------------------------------- +// Standard Bresenham algorithm. +// Bloody slow at clipping tho' + +void DrawLineC8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + SLONG ax,ay, + d, + dx,dy, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + + x = x1; + y = y1; + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + DrawPixelC(x,y,colour); + if(x==x2) + return; + if(d>=0) + { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + DrawPixelC(x,y,colour); + if(y==y2) + return; + if(d>=0) + { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } +} + +//--------------------------------------------------------------- + +void DrawHLine8(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UBYTE *line_dest; + ULONG count; + + + if(x1>x2) + { + swap(x1,x2); + } + line_dest = WorkWindow+x1+(y*WorkScreenWidth); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UBYTE)colour; + } +} + +void DrawHLine16(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UWORD *line_dest; + ULONG count; + + + if(x1>x2) + { + swap(x1,x2); + } + line_dest = (UWORD*)WorkWindow+x1+(y*WorkScreenWidth>>1); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UWORD)colour; + } +} + +void DrawHLine32(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + ULONG *line_dest; + ULONG count; + + + if(x1>x2) + { + swap(x1,x2); + } + line_dest = (ULONG*)WorkWindow+x1+(y*WorkScreenWidth>>2); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (ULONG)colour; + } +} + +//--------------------------------------------------------------- + +void DrawHLineC8(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UBYTE *line_dest; + ULONG count; + + + if(y>=0 && yx2) + { + swap(x1,x2); + } + if(x1=0) + { + if(x1<0) + x1 = 0; + if(x2>=WorkWindowWidth) + x2 = WorkWindowWidth-1; + line_dest = WorkWindow+x1+(y*WorkScreenWidth); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UBYTE)colour; + } + } + } +} + +void DrawHLineC16(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UWORD *line_dest; + ULONG count; + + + if(y>=0 && yx2) + { + swap(x1,x2); + } + if(x1=0) + { + if(x1<0) + x1 = 0; + if(x2>=WorkWindowWidth) + x2 = WorkWindowWidth-1; + line_dest = (UWORD*)WorkWindow+x1+(y*WorkScreenWidth>>1); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UWORD)colour; + } + } + } +} + +void DrawHLineC32(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + ULONG *line_dest; + ULONG count; + + + if(y>=0 && yx2) + { + swap(x1,x2); + } + if(x1=0) + { + if(x1<0) + x1 = 0; + if(x2>=WorkWindowWidth) + x2 = WorkWindowWidth-1; + line_dest = (ULONG*)WorkWindow+x1+(y*WorkScreenWidth>>2); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (ULONG)colour; + } + } + } +} + +//--------------------------------------------------------------- + +void DrawVLine8(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UBYTE *line_dest; + ULONG count, + modulo; + + + if(y1>y2) + { + swap(y1,y2); + } + line_dest = WorkWindow+x+(y1*WorkScreenWidth); + count = (y2-y1)+1; + modulo = WorkScreenWidth; + while(count--) + { + *line_dest = (UBYTE)colour; + line_dest += modulo; + } +} + +void DrawVLine16(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UWORD *line_dest; + ULONG count, + modulo; + + + if(y1>y2) + { + swap(y1,y2); + } + line_dest = (UWORD*)WorkWindow+x+(y1*WorkScreenWidth>>1); + count = (y2-y1)+1; + modulo = WorkScreenWidth>>1; + while(count--) + { + *line_dest = (UWORD)colour; + line_dest += modulo; + } +} + +void DrawVLine32(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + ULONG *line_dest; + ULONG count, + modulo; + + + if(y1>y2) + { + swap(y1,y2); + } + line_dest = (ULONG*)WorkWindow+x+(y1*WorkScreenWidth>>2); + count = (y2-y1)+1; + modulo = WorkScreenWidth>>2; + while(count--) + { + *line_dest = (ULONG)colour; + line_dest += modulo; + } +} + + +//--------------------------------------------------------------- + +void DrawVLineC8(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UBYTE *line_dest; + ULONG count; + + + if(x>=0 && xy2) + { + swap(y1,y2); + } + if(y1=0) + { + if(y1<0) + y1 = 0; + if(y2>=WorkWindowHeight) + y2 = WorkWindowHeight-1; + line_dest = WorkWindow+x+(y1*WorkScreenWidth); + count = (y2-y1)+1; + while(count--) + { + *line_dest = (UBYTE)colour; + line_dest += WorkScreenWidth; + } + } + } +} + +void DrawVLineC16(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UWORD *line_dest; + ULONG count; + + + if(x>=0 && xy2) + { + swap(y1,y2); + } + if(y1=0) + { + if(y1<0) + y1 = 0; + if(y2>=WorkWindowHeight) + y2 = WorkWindowHeight-1; + line_dest = (UWORD*)WorkWindow+x+(y1*WorkScreenWidth>>1); + count = (y2-y1)+1; + while(count--) + { + *line_dest = (UWORD)colour; + line_dest += WorkScreenWidth>>1; + } + } + } +} + +void DrawVLineC32(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + ULONG *line_dest; + ULONG count; + + + if(x>=0 && xy2) + { + swap(y1,y2); + } + if(y1=0) + { + if(y1<0) + y1 = 0; + if(y2>=WorkWindowHeight) + y2 = WorkWindowHeight-1; + line_dest = (ULONG*)WorkWindow+x+(y1*WorkScreenWidth>>2); + count = (y2-y1)+1; + while(count--) + { + *line_dest = (ULONG)colour; + line_dest += WorkScreenWidth>>2; + } + } + } +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/DrawPnt.cpp b/MFLib1/Source/C/Common/DrawPnt.cpp new file mode 100644 index 0000000..fee9123 --- /dev/null +++ b/MFLib1/Source/C/Common/DrawPnt.cpp @@ -0,0 +1,75 @@ +// DrawPoint.c +// Guy Simmons, 7th October 1996. + + +#include + + +//--------------------------------------------------------------- + +void DrawPoint8(MFPoint *the_point,ULONG colour) +{ + *(WorkWindow+the_point->X+(the_point->Y*WorkScreenWidth)) = (UBYTE)colour; +} + +void DrawPoint16(MFPoint *the_point,ULONG colour) +{ + UWORD *ptr; + ptr = (UWORD*)WorkWindow+the_point->X+(the_point->Y*WorkScreenWidth>>1); + *ptr = (UWORD)colour; + +} + +void DrawPoint32(MFPoint *the_point,ULONG colour) +{ + ULONG *ptr; + ptr = (ULONG*)WorkWindow+the_point->X+(the_point->Y*WorkScreenWidth>>2); + *ptr = (ULONG)colour; +} + +//--------------------------------------------------------------- + +void DrawPointC8(MFPoint *the_point,ULONG colour) +{ + if ( + the_point->X>=0 && + the_point->XY>=0 && + the_point->YX+(the_point->Y*WorkScreenWidth)) = (UBYTE)colour; + } +} + +void DrawPointC16(MFPoint *the_point,ULONG colour) +{ + UWORD *ptr; + if ( + the_point->X>=0 && + the_point->XY>=0 && + the_point->YX+(the_point->Y*WorkScreenWidth>>1); + *ptr = (UWORD)colour; + } +} + +void DrawPointC32(MFPoint *the_point,ULONG colour) +{ + ULONG *ptr; + if ( + the_point->X>=0 && + the_point->XY>=0 && + the_point->YX+(the_point->Y*WorkScreenWidth>>2); + *ptr = (ULONG)colour; + } +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/DrawPxl.cpp b/MFLib1/Source/C/Common/DrawPxl.cpp new file mode 100644 index 0000000..f257965 --- /dev/null +++ b/MFLib1/Source/C/Common/DrawPxl.cpp @@ -0,0 +1,59 @@ +// DrawPixel.c +// Guy Simmons, 7th October 1996. + + +#include + + +//--------------------------------------------------------------- + +void DrawPixel8(SLONG x,SLONG y,ULONG colour) +{ + *(WorkWindow+x+(y*WorkScreenWidth)) = (UBYTE)colour; +} + +void DrawPixel16(SLONG x,SLONG y,ULONG colour) +{ + UWORD *ptr; + ptr = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); + *ptr = (UWORD)colour; +} + +void DrawPixel32(SLONG x,SLONG y,ULONG colour) +{ + ULONG *ptr; + ptr = (ULONG*)WorkWindow+x+(y*WorkScreenWidth>>2); + *ptr = (ULONG)colour; +} + +//--------------------------------------------------------------- + +void DrawPixelC8(SLONG x,SLONG y,ULONG colour) +{ + if(x>=0 && x=0 && y=0 && x=0 && y>1); + *ptr = (UWORD)colour; + } +} + +void DrawPixelC32(SLONG x,SLONG y,ULONG colour) +{ + if(x>=0 && x=0 && y>2); + *ptr = (ULONG)colour; + } +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/DrawRect.cpp b/MFLib1/Source/C/Common/DrawRect.cpp new file mode 100644 index 0000000..035488c --- /dev/null +++ b/MFLib1/Source/C/Common/DrawRect.cpp @@ -0,0 +1,24 @@ +// DrawRect.cpp +// Guy Simmons, 11th February 1997. + + +#include + + +//--------------------------------------------------------------- + +void DrawRect(MFRect *the_rect,ULONG colour) +{ + the_rect = the_rect; + colour = colour; +} + +//--------------------------------------------------------------- + +void DrawRectC(MFRect *the_rect,ULONG colour) +{ + the_rect = the_rect; + colour = colour; +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/Maths.cpp b/MFLib1/Source/C/Common/Maths.cpp new file mode 100644 index 0000000..d23feb8 --- /dev/null +++ b/MFLib1/Source/C/Common/Maths.cpp @@ -0,0 +1,145 @@ +// Maths.cpp +// Guy Simmons, 27th March 1997. + +#include +#ifdef TARGET_DC +#include +#endif + + +//--------------------------------------------------------------- + +#define LookUp ax = AtanTable[(ax<<8)/bx]; +#define xchg(a,b) {a^=b;b^=a;a^=b;} + + +SLONG Arctan(SLONG X,SLONG Y) +{ + register SLONG ax,bx; + + ax = X; + if(ax) + goto just_do_it; + bx = Y; + if(bx) + goto done_it; + return 0; +just_do_it: + bx = Y; +done_it: + if(ax < 0) + goto xneg; + +// x positive + if(bx < 0) + goto xposyneg; + +// x positive, y positive + if(ax < bx) + goto ppyprimary; + +// ppxprimary + xchg(ax,bx) + LookUp + return ax+512; +ppyprimary: + LookUp + return (-ax)+1024; +xposyneg: //******************************************************************* + bx = -bx; + if(ax < bx) + goto pnyprimary; + +// pnxprimary + xchg(ax,bx) + LookUp + return (-ax)+512; +pnyprimary: + LookUp + return ax; +xneg: + ax = -ax; + if(bx < 0) + goto xnegyneg; +// x negative, y positive + if(ax < bx) + goto npyprimary; + +// npxprimary + xchg(ax,bx) + LookUp + return (-ax)+1536; +npyprimary: + LookUp + return ax+1024; + +// x negative, y negative +xnegyneg: + bx = -bx; + if(ax < bx) + goto nnyprimary; + +// nnxprimary + xchg(ax,bx) + LookUp + return ax+1536; +nnyprimary: + LookUp + return (-ax)+2048; +} + +//--------------------------------------------------------------- + + +#ifndef TARGET_DC + +UWORD ini_table[] = +{ + 1, 2, 2, 4, + 5, 8, 11, 16, + 22, 32, 45, 64, + 90, 128, 181, 256, + 362, 512, 724, 1024, + 1448, 2048, 2896, 4096, + 5792, 8192, 11585, 16384, + 23170, 32768, 46340, 65535 +}; + +#ifdef _MSC_VER +SLONG Root(SLONG square) +{ + __asm + { + xor ebx,ebx + mov ecx,square + bsr eax,ecx + je done_it + movzx ebx,ini_table[eax*2] +do_it: + mov eax,ecx + xor edx,edx + div ebx + cmp eax,ebx + jge done_it + add ebx,eax + shr ebx,1 + jmp do_it +done_it: + mov eax,ebx + } +} +#endif + + +#else //#ifndef TARGET_DC + +// Just use the standard rout for the moment - it uses a fast path anyway. +SLONG Root ( SLONG square ) +{ + return ( (int) sqrtf ( (float)square ) ); +} + +#endif //#else //#ifndef TARGET_DC + + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/QuickTxt.cpp b/MFLib1/Source/C/Common/QuickTxt.cpp new file mode 100644 index 0000000..9466d54 --- /dev/null +++ b/MFLib1/Source/C/Common/QuickTxt.cpp @@ -0,0 +1,481 @@ +// QuickText.c +// Guy Simmons, 7th October 1996. + +#include + +extern UBYTE *CharTable[]; + +#define DRAW_CHAR for(c0=char_height;c0;c0--,string_dest+=WorkScreenWidth) \ + { \ + for(c1=0;c1>1) \ + { \ + for(c1=0;c1>2) \ + { \ + for(c1=0;c1>1); + + DRAW_CHAR16 + x += char_width+1; + } +} + +void QuickText32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + UBYTE *the_char_def; + ULONG *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = (ULONG*)WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth>>2); + + DRAW_CHAR32 + x += char_width+1; + } +} + +//--------------------------------------------------------------- + +void QuickTextC8(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + UBYTE *string_dest, + *the_char_def, + *the_pixel; + SLONG c0,c1, + char_draw_height, + char_draw_width, + char_height, + char_width, + char_v_offset, + char_x_offset, + char_y, + char_y_offset, + clip; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + char_v_offset = *(the_char_def++); + char_draw_width = char_width; + char_draw_height= char_height; + char_x_offset = 0; + char_y_offset = 0; + char_y = y; + + clip = 0; + if(x<0) + { + if((x+char_width)<0) + goto done_char; + char_x_offset = -x; + char_draw_width += x; + x = 0; + clip = 1; + } + if(y<0) + { + if((y+char_v_offset+char_height)<0) + goto done_char; + if((y+char_v_offset)<0) + { + char_y_offset = -(y+char_v_offset); + char_draw_height+= y+char_v_offset; + char_v_offset = 0; + } + else + { + char_v_offset += y; + } + char_y = 0; + clip = 1; + } + if((x+char_draw_width)>=WorkWindowWidth) + { + char_draw_width -= (x+char_draw_width)-WorkWindowWidth; + clip = 1; + } + if((y+char_v_offset+char_draw_height)>=WorkWindowHeight) + { + char_draw_height-= (char_y+char_v_offset+char_draw_height)-WorkWindowHeight; + if(char_draw_height<=0) + goto done_char; + clip = 1; + } + + string_dest = WorkWindow+x+((char_y+char_v_offset)*WorkScreenWidth); + + if(clip) + { + for(c0=0;c0=WorkWindowWidth) + return; + } +} + +void QuickTextC16(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + UWORD *string_dest; + UBYTE *the_char_def, + *the_pixel; + SLONG c0,c1, + char_draw_height, + char_draw_width, + char_height, + char_width, + char_v_offset, + char_x_offset, + char_y, + char_y_offset, + clip; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + char_v_offset = *(the_char_def++); + char_draw_width = char_width; + char_draw_height= char_height; + char_x_offset = 0; + char_y_offset = 0; + char_y = y; + + clip = 0; + if(x<0) + { + if((x+char_width)<0) + goto done_char; + char_x_offset = -x; + char_draw_width += x; + x = 0; + clip = 1; + } + if(y<0) + { + if((y+char_v_offset+char_height)<0) + goto done_char; + if((y+char_v_offset)<0) + { + char_y_offset = -(y+char_v_offset); + char_draw_height+= y+char_v_offset; + char_v_offset = 0; + } + else + { + char_v_offset += y; + } + char_y = 0; + clip = 1; + } + if((x+char_draw_width)>=WorkWindowWidth) + { + char_draw_width -= (x+char_draw_width)-WorkWindowWidth; + clip = 1; + } + if((y+char_v_offset+char_draw_height)>=WorkWindowHeight) + { + char_draw_height-= (char_y+char_v_offset+char_draw_height)-WorkWindowHeight; + if(char_draw_height<=0) + goto done_char; + clip = 1; + } + + string_dest = (UWORD*)WorkWindow+x+((char_y+char_v_offset)*WorkScreenWidth>>1); + + if(clip) + { + for(c0=0;c0=WorkWindowWidth) + return; + } +} + +void QuickTextC32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + ULONG *string_dest; + UBYTE *the_char_def, + *the_pixel; + SLONG c0,c1, + char_draw_height, + char_draw_width, + char_height, + char_width, + char_v_offset, + char_x_offset, + char_y, + char_y_offset, + clip; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + char_v_offset = *(the_char_def++); + char_draw_width = char_width; + char_draw_height= char_height; + char_x_offset = 0; + char_y_offset = 0; + char_y = y; + + clip = 0; + if(x<0) + { + if((x+char_width)<0) + goto done_char; + char_x_offset = -x; + char_draw_width += x; + x = 0; + clip = 1; + } + if(y<0) + { + if((y+char_v_offset+char_height)<0) + goto done_char; + if((y+char_v_offset)<0) + { + char_y_offset = -(y+char_v_offset); + char_draw_height+= y+char_v_offset; + char_v_offset = 0; + } + else + { + char_v_offset += y; + } + char_y = 0; + clip = 1; + } + if((x+char_draw_width)>=WorkWindowWidth) + { + char_draw_width -= (x+char_draw_width)-WorkWindowWidth; + clip = 1; + } + if((y+char_v_offset+char_draw_height)>=WorkWindowHeight) + { + char_draw_height-= (char_y+char_v_offset+char_draw_height)-WorkWindowHeight; + if(char_draw_height<=0) + goto done_char; + clip = 1; + } + + string_dest = (ULONG*)WorkWindow+x+((char_y+char_v_offset)*WorkScreenWidth>>2); + + if(clip) + { + for(c0=0;c0=WorkWindowWidth) + return; + } +} + +//--------------------------------------------------------------- + +void QuickChar8(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + UBYTE *the_char_def, + *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + the_char_def = CharTable[the_char]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth); + DRAW_CHAR +} + +void QuickChar16(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + UBYTE *the_char_def; + UWORD *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + the_char_def = CharTable[the_char]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = (UWORD*)WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth>>1); + DRAW_CHAR16 +} + +void QuickChar32(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + UBYTE *the_char_def; + ULONG *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + the_char_def = CharTable[the_char]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = (ULONG*)WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth>>2); + DRAW_CHAR32 +} +//--------------------------------------------------------------- + +void QuickCharC8_16_32(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0 || y<0) + return; + + QuickChar(x,y,the_char,colour); +} + +//--------------------------------------------------------------- + +SLONG QTStringWidth(CBYTE *the_string) +{ + SLONG width = 0; + + + while(*the_string) + { + width += (*CharTable[*(the_string++)])+1; + } + return width; +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/Sprites.cpp b/MFLib1/Source/C/Common/Sprites.cpp new file mode 100644 index 0000000..448602c --- /dev/null +++ b/MFLib1/Source/C/Common/Sprites.cpp @@ -0,0 +1,809 @@ +// Sprites.cpp +// Guy Simmons, 13th February 1997. + +#include +extern UBYTE CurrentPalette[256*3]; + +#define RGB_TO_RGB565(r,g,b) (UWORD)(((r>>4)<<11)|((g>>3)<<5)|(b>>4)) +#define RGB_TO_RGB888(r,g,b) ((r<<16)|(g<<8)|(b)) +#define COL_TO_RGB565(col,PALETTE) (UWORD)(((PALETTE[(col)*3]>>3)<<11)|((PALETTE[(col)*3+1]>>2)<<5)|(PALETTE[(col)*3+2]>>3)) +#define COL_TO_RGB888(col,PALETTE) ((PALETTE[(col)*3]<<16)|(PALETTE[(col)*3+1]<<8)|PALETTE[(col)*3+2]) + +#define DRAW_SPRITE while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + while(c0--) \ + *line_ptr++ = *src_ptr++; \ + break; \ + case SKIP_PIXELS: \ + line_ptr += (*src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + dup_pixel = *src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define DRAW_SPRITE16(pal) while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + while(c0--) \ + { \ + *line_ptr++ =COL_TO_RGB565(*src_ptr,pal); \ + src_ptr++; \ + } \ + break; \ + case SKIP_PIXELS: \ + line_ptr += *(src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + dup_pixel =COL_TO_RGB565(*src_ptr,pal); \ + src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define DRAW_SPRITE32(pal) while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + while(c0--) \ + { \ + *line_ptr++ =COL_TO_RGB888(*src_ptr,pal); \ + src_ptr++; \ + } \ + break; \ + case SKIP_PIXELS: \ + line_ptr += *(src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + dup_pixel =COL_TO_RGB888(*src_ptr,pal); \ + src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define DRAW_M_SPRITE while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + src_ptr += c0; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case SKIP_PIXELS: \ + line_ptr += (*src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + + +#define V_SCAN while(v_scan) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + v_scan--; \ + break; \ + case COPY_PIXELS: \ + src_ptr += 1+*(src_ptr++); \ + break; \ + case SKIP_PIXELS: \ + src_ptr++; \ + break; \ + case DUPLICATE_PIXELS: \ + src_ptr += 2; \ + break; \ + } \ + } + +#define L_SCAN while(l_scan&&sprite_height) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + sprite_height--; \ + pixel_count = 0; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + if((pixel_count+c0)>=l_scan) \ + { \ + src_ptr += l_scan-pixel_count; \ + c0 -= l_scan-pixel_count; \ + pixel_count = l_scan; \ + goto copy_pixels; \ + } \ + else \ + { \ + pixel_count += c0; \ + src_ptr += c0; \ + } \ + break; \ + case SKIP_PIXELS: \ + c0 = (*src_ptr++)+1; \ + if((pixel_count+c0)>=l_scan) \ + { \ + c0 -= l_scan-pixel_count; \ + pixel_count = l_scan; \ + goto skip_pixels; \ + } \ + else \ + { \ + pixel_count += c0; \ + } \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + if((pixel_count+c0)>=l_scan) \ + { \ + c0 -= l_scan-pixel_count; \ + pixel_count = l_scan; \ + goto duplicate_pixels; \ + } \ + else \ + { \ + pixel_count += c0; \ + src_ptr++; \ + } \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define R_SCAN while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + goto end_line; \ + case COPY_PIXELS: \ + src_ptr += 1+*(src_ptr++); \ + break; \ + case SKIP_PIXELS: \ + src_ptr++; \ + break; \ + case DUPLICATE_PIXELS: \ + src_ptr += 2; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + + +//--------------------------------------------------------------- + + +void DrawBSpritePal16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + UWORD dup_pixel, + *dst_ptr, + *line_ptr; + + + dst_ptr = (UWORD*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + DRAW_SPRITE16(pal) +} + +void DrawBSpritePal32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + ULONG dup_pixel, + *dst_ptr, + *line_ptr; + + + dst_ptr = (ULONG*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + DRAW_SPRITE32(pal) +} + +void DrawBSprite8(SLONG x,SLONG y,BSprite *the_sprite) +{ + UBYTE dup_pixel, + packet, + *dst_ptr, + *line_ptr, + *src_ptr; + ULONG c0; + + + dst_ptr = WorkWindow+x+(y*WorkScreenWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + DRAW_SPRITE +} + +void DrawBSprite16(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePal16(x,y,the_sprite,CurrentPalette); +} + +void DrawBSprite32(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePal32(x,y,the_sprite,CurrentPalette); +} + +//--------------------------------------------------------------- + +void DrawMonoBSprite8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + UBYTE dup_pixel, + packet, + *dst_ptr, + *line_ptr, + *src_ptr; + ULONG c0; + + dst_ptr = WorkWindow+x+(y*WorkScreenWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + dup_pixel = (UBYTE)colour; + DRAW_M_SPRITE +} + +void DrawMonoBSprite16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + + UWORD dup_pixel, + *dst_ptr, + *line_ptr; + + dst_ptr = (UWORD*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + dup_pixel = (UWORD)colour; + DRAW_M_SPRITE +} + +void DrawMonoBSprite32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + + ULONG dup_pixel, + *dst_ptr, + *line_ptr; + + dst_ptr = (ULONG*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + dup_pixel = (ULONG)colour; + DRAW_M_SPRITE +} + +void DrawMonoBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + if(x<0 || (x+the_sprite->SpriteWidth)>=WorkWindowWidth || y<0 || (y+the_sprite->SpriteHeight)>=WorkWindowHeight) + return; + + DrawMonoBSprite8(x,y,the_sprite,colour); +} + +void DrawMonoBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + if(x<0 || (x+the_sprite->SpriteWidth)>=WorkWindowWidth || y<0 || (y+the_sprite->SpriteHeight)>=WorkWindowHeight) + return; + + DrawMonoBSprite16(x,y,the_sprite,colour); +} + +void DrawMonoBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + if(x<0 || (x+the_sprite->SpriteWidth)>=WorkWindowWidth || y<0 || (y+the_sprite->SpriteHeight)>=WorkWindowHeight) + return; + + DrawMonoBSprite32(x,y,the_sprite,colour); +} + +//--------------------------------------------------------------- + +void DrawBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite) +{ + UBYTE dup_pixel, + packet, + *dst_ptr, + *line_ptr, + *src_ptr; + ULONG c0, + clip, + count_diff, + pixel_count, + sprite_height; + ULONG l_scan, + v_scan; + SLONG sprite_x; + + + if(x>=WorkWindowWidth || (x+the_sprite->SpriteWidth)<0 || y>=WorkWindowHeight || (y+the_sprite->SpriteHeight)<0) + return; + + sprite_height = the_sprite->SpriteHeight; + sprite_x = x; + src_ptr = the_sprite->SpriteData; + clip = 0; + l_scan = 0; + + + if(x<0) + { + l_scan = -x; + sprite_x= 0; + clip = 1; + } + if(y<0) + { + v_scan = -y; + sprite_height += y; + V_SCAN + y = 0; + clip = 1; + } + if((SLONG)(x+the_sprite->SpriteWidth)>=WorkWindowWidth) + { + clip = 1; + } + if((SLONG)(y+sprite_height)>=WorkWindowHeight) + { + sprite_height -= (y+sprite_height)-WorkWindowHeight; + clip = 1; + } + + dst_ptr = WorkWindow+sprite_x+(y*WorkScreenWidth); + line_ptr = dst_ptr; + + if(clip) + { + pixel_count = 0; + L_SCAN + while(sprite_height) + { + packet = *src_ptr++; + switch(packet) + { + case END_LINE: +end_line: + dst_ptr += WorkScreenWidth; + line_ptr = dst_ptr; + sprite_height--; + pixel_count = 0; + L_SCAN + break; + case COPY_PIXELS: + c0 = (*src_ptr++)+1; +copy_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + count_diff = (x+pixel_count)-WorkWindowWidth; + c0 -= count_diff; + while(c0--) + *line_ptr++ = *src_ptr++; + src_ptr += count_diff; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = *src_ptr++; + } + break; + case SKIP_PIXELS: + c0 = (*src_ptr++)+1; +skip_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + R_SCAN + } + else + line_ptr += c0; + break; + case DUPLICATE_PIXELS: + c0 = (*src_ptr++)+1; +duplicate_pixels: + pixel_count += c0; + dup_pixel = *src_ptr++; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + c0 -= (x+pixel_count)-WorkWindowWidth; + while(c0--) + *line_ptr++ = dup_pixel; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = dup_pixel; + } + break; + case FINISHED: + return; + } + } + } + else + { + DRAW_SPRITE + } +} + +extern void DrawBSpritePalC16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +extern void DrawBSpritePalC32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); + +void DrawBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePalC16(x,y,the_sprite,CurrentPalette); +} + +void DrawBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePalC32(x,y,the_sprite,CurrentPalette); +} + +void DrawBSpritePalC16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0, + clip, + count_diff, + pixel_count, + sprite_height; + ULONG l_scan, + v_scan; + SLONG sprite_x; + + UWORD dup_pixel, + *dst_ptr, + *line_ptr; + + + if(x>=WorkWindowWidth || (x+the_sprite->SpriteWidth)<0 || y>=WorkWindowHeight || (y+the_sprite->SpriteHeight)<0) + return; + + sprite_height = the_sprite->SpriteHeight; + sprite_x = x; + src_ptr = the_sprite->SpriteData; + clip = 0; + l_scan = 0; + + + if(x<0) + { + l_scan = -x; + sprite_x= 0; + clip = 1; + } + if(y<0) + { + v_scan = -y; + sprite_height += y; + V_SCAN + y = 0; + clip = 1; + } + if((SLONG)(x+the_sprite->SpriteWidth)>=WorkWindowWidth) + { + clip = 1; + } + if((SLONG)(y+sprite_height)>=WorkWindowHeight) + { + sprite_height -= (y+sprite_height)-WorkWindowHeight; + clip = 1; + } + + dst_ptr = (UWORD*)WorkWindow+sprite_x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + + if(clip) + { + pixel_count = 0; + L_SCAN + while(sprite_height) + { + packet = *src_ptr++; + switch(packet) + { + case END_LINE: +end_line: + dst_ptr += WorkScreenPixelWidth; + line_ptr = dst_ptr; + sprite_height--; + pixel_count = 0; + L_SCAN + break; + case COPY_PIXELS: + c0 = (*src_ptr++)+1; +copy_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + count_diff = (x+pixel_count)-WorkWindowWidth; + c0 -= count_diff; + while(c0--) + { + *line_ptr++ =COL_TO_RGB565(*src_ptr,pal); + src_ptr++; + } + src_ptr += count_diff; + R_SCAN + } + else + { + while(c0--) + { + *line_ptr++ =COL_TO_RGB565(*src_ptr,pal); + src_ptr++; + } + } + break; + case SKIP_PIXELS: + c0 = (*src_ptr++)+1; +skip_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + R_SCAN + } + else + line_ptr += c0; + break; + case DUPLICATE_PIXELS: + c0 = (*src_ptr++)+1; +duplicate_pixels: + pixel_count += c0; + dup_pixel = COL_TO_RGB565(*src_ptr,pal); + src_ptr++; + + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + c0 -= (x+pixel_count)-WorkWindowWidth; + while(c0--) + *line_ptr++ = dup_pixel; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = dup_pixel; + } + break; + case FINISHED: + return; + } + } + } + else + { + DRAW_SPRITE16(pal) + } +} + +void DrawBSpritePalC32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0, + clip, + count_diff, + pixel_count, + sprite_height; + ULONG l_scan, + v_scan; + SLONG sprite_x; + + ULONG dup_pixel, + *dst_ptr, + *line_ptr; + + + if(x>=WorkWindowWidth || (x+the_sprite->SpriteWidth)<0 || y>=WorkWindowHeight || (y+the_sprite->SpriteHeight)<0) + return; + + sprite_height = the_sprite->SpriteHeight; + sprite_x = x; + src_ptr = the_sprite->SpriteData; + clip = 0; + l_scan = 0; + + + if(x<0) + { + l_scan = -x; + sprite_x= 0; + clip = 1; + } + if(y<0) + { + v_scan = -y; + sprite_height += y; + V_SCAN + y = 0; + clip = 1; + } + if((SLONG)(x+the_sprite->SpriteWidth)>=WorkWindowWidth) + { + clip = 1; + } + if((SLONG)(y+sprite_height)>=WorkWindowHeight) + { + sprite_height -= (y+sprite_height)-WorkWindowHeight; + clip = 1; + } + + dst_ptr = (ULONG*)WorkWindow+sprite_x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + + if(clip) + { + pixel_count = 0; + L_SCAN + while(sprite_height) + { + packet = *src_ptr++; + switch(packet) + { + case END_LINE: +end_line: + dst_ptr += WorkScreenPixelWidth; + line_ptr = dst_ptr; + sprite_height--; + pixel_count = 0; + L_SCAN + break; + case COPY_PIXELS: + c0 = (*src_ptr++)+1; +copy_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + count_diff = (x+pixel_count)-WorkWindowWidth; + c0 -= count_diff; + while(c0--) + { + *line_ptr++ =COL_TO_RGB888(*src_ptr,pal); + src_ptr++; + } + src_ptr += count_diff; + R_SCAN + } + else + { + while(c0--) + { + *line_ptr++ =COL_TO_RGB888(*src_ptr,pal); + src_ptr++; + } + } + break; + case SKIP_PIXELS: + c0 = (*src_ptr++)+1; +skip_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + R_SCAN + } + else + line_ptr += c0; + break; + case DUPLICATE_PIXELS: + c0 = (*src_ptr++)+1; +duplicate_pixels: + pixel_count += c0; + dup_pixel = COL_TO_RGB888(*src_ptr,pal); + src_ptr++; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + c0 -= (x+pixel_count)-WorkWindowWidth; + while(c0--) + *line_ptr++ = dup_pixel; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = dup_pixel; + } + break; + case FINISHED: + return; + } + } + } + else + { + DRAW_SPRITE32(pal) + } +} + +//--------------------------------------------------------------- + +void SetupBSprites(BSprite *sprite_ref,UBYTE *sprite_data) +{ + ULONG spr_count; + + + spr_count = *(ULONG*)(&sprite_ref->SpriteHeight); + sprite_ref++; + while(spr_count--) + { + sprite_ref->SpriteData += (ULONG)sprite_data; + sprite_ref++; + } +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/TextDef.cpp b/MFLib1/Source/C/Common/TextDef.cpp new file mode 100644 index 0000000..3ba2478 --- /dev/null +++ b/MFLib1/Source/C/Common/TextDef.cpp @@ -0,0 +1,930 @@ +// TextDef.c +// Guy Simmons, 7th October 1996. + +// Hard coded font definition for quick text functions. + +#include + +//--------------------------------------------------------------- +// Byte1 - Width +// Byte2 - Height +// Byte3 - Vertical offset. + + +//--------------------------------------------------------------- + +static UBYTE Null[]= +{ + 0,0,0, +}; + +static UBYTE Space[] = +{ + 4,0,0, +}; + +static UBYTE Excl[] = +{ + 1,7,1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, +}; + +static UBYTE Dollar[] = +{ + 5,9,0, + 0,0,1,0,0, + 0,1,1,1,0, + 1,0,1,0,1, + 1,0,1,0,0, + 0,1,1,1,0, + 0,0,1,0,1, + 1,0,1,0,1, + 0,1,1,1,0, + 0,0,1,0,0, +}; + +static UBYTE Percent[] = +{ + 8,7,1, + 0,1,1,1,1,1,1,1, + 1,0,0,1,0,0,1,0, + 1,0,0,1,0,1,0,0, + 0,1,1,0,1,1,1,0, + 0,0,0,1,1,0,0,1, + 0,0,1,0,1,0,0,1, + 0,1,0,0,0,1,1,0, +}; + +static UBYTE And[] = +{ + 7,8,0, + 0,0,1,1,0,0,0, + 0,1,0,0,1,0,0, + 0,1,0,1,0,0,0, + 0,0,1,0,0,0,0, + 0,1,0,1,0,1,0, + 1,0,0,0,1,0,0, + 1,0,0,1,0,1,0, + 0,1,1,0,0,0,1, +}; + +static UBYTE Quotes[] = +{ + 3,2,1, + 1,0,1, + 1,0,1, +}; + +static UBYTE Astrisk[] = +{ + 5,5,1, + 0,1,0,1,0, + 0,0,1,0,0, + 1,1,1,1,1, + 0,0,1,0,0, + 0,1,0,1,0, +}; + +static UBYTE BrackO[] = +{ + 3,9,0, + 0,0,1, + 0,1,0, + 1,0,0, + 1,0,0, + 1,0,0, + 1,0,0, + 1,0,0, + 0,1,0, + 0,0,1, +}; + +static UBYTE BrackC[] = +{ + 3,9,0, + 1,0,0, + 0,1,0, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,1,0, + 1,0,0, +}; + +static UBYTE Plus[] = +{ + 5,5,2, + 0,0,1,0,0, + 0,0,1,0,0, + 1,1,1,1,1, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE Comma[] = +{ + 2,4,6, + 1,1, + 1,1, + 0,1, + 1,0, +}; + +static UBYTE Minus[] = +{ + 5,1,4, + 1,1,1,1,1 +}; + +static UBYTE Stop[] = +{ + 2,2,6, + 1,1, + 1,1, +}; + +static UBYTE Zero[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE One[] = +{ + 2,7,1, + 0,1, + 1,1, + 0,1, + 0,1, + 0,1, + 0,1, + 0,1, +}; + +static UBYTE Two[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,0,1,0,0, + 0,1,0,0,0, + 1,1,1,1,1, +}; + +static UBYTE Three[] = +{ + 5,7,1, + 1,1,1,1,1, + 0,0,0,1,0, + 0,0,1,0,0, + 0,1,1,1,0, + 0,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Four[] = +{ + 5,7,1, + 0,0,0,1,0, + 0,0,1,1,0, + 0,1,0,1,0, + 1,0,0,1,0, + 1,1,1,1,1, + 0,0,0,1,0, + 0,0,0,1,0, +}; + +static UBYTE Five[] = +{ + 5,7,1, + 1,1,1,1,1, + 1,0,0,0,0, + 1,1,1,1,0, + 0,0,0,0,1, + 0,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Six[] = +{ + 5,7,1, + 0,0,1,1,0, + 0,1,0,0,0, + 1,0,0,0,0, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Seven[] = +{ + 5,7,1, + 1,1,1,1,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,0,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE Eight[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Nine[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,1,1,0,0, +}; + +static UBYTE Colon[] = +{ + 2,3,4, + 0,1, + 0,0, + 0,1, +}; + +static UBYTE QMark[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,0,1,0,0, + 0,0,0,0,0, + 0,0,1,0,0, +}; + +static UBYTE At[] = +{ + 7,8,1, + 0,0,1,1,1,0,0, + 0,1,0,0,0,1,0, + 1,0,0,1,1,0,1, + 1,0,1,0,1,0,1, + 1,0,1,0,1,0,1, + 1,0,0,1,1,1,0, + 0,1,0,0,0,0,0, + 0,0,1,1,1,0,0, +}; + +static UBYTE A[] = +{ + 5,7,1, + 0,0,1,0,0, + 0,0,1,0,0, + 0,1,0,1,0, + 0,1,0,1,0, + 1,1,1,1,1, + 1,0,0,0,1, + 1,0,0,0,1 +}; + +static UBYTE B[] = +{ + 5,7,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, +}; + +static UBYTE C[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,1, + 0,1,1,1,0 +}; + +static UBYTE D[] = +{ + 5,7,1, + 1,1,1,0,0, + 1,0,0,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,1,0, + 1,1,1,0,0, +}; + +static UBYTE E[] = +{ + 4,7,1, + 1,1,1,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +static UBYTE F[] = +{ + 4,7,1, + 1,1,1,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, +}; + +static UBYTE G[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,0, + 1,0,0,1,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE H[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, +}; + +static UBYTE I[] = +{ + 1,7,1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, +}; + +static UBYTE J[] = +{ + 5,7,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE K[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,1,0, + 1,0,1,0,0, + 1,1,0,0,0, + 1,0,1,0,0, + 1,0,0,1,0, + 1,0,0,0,1, +}; + +static UBYTE L[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +static UBYTE M[] = +{ + 7,7,1, + 1,0,0,0,0,0,1, + 1,1,0,0,0,1,1, + 1,0,1,0,1,0,1, + 1,0,0,1,0,0,1, + 1,0,0,0,0,0,1, + 1,0,0,0,0,0,1, + 1,0,0,0,0,0,1, +}; + +static UBYTE N[] = +{ + 5,7,1, + 1,1,0,0,1, + 1,1,0,0,1, + 1,0,1,0,1, + 1,0,1,0,1, + 1,0,0,1,1, + 1,0,0,1,1, + 1,0,0,0,1, +}; + +static UBYTE O[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE P[] = +{ + 5,7,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, +}; + +static UBYTE Q[] = +{ + 5,8,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,1,0,1, + 0,1,1,1,0, + 0,0,0,1,0, +}; + +static UBYTE R[] = +{ + 5,7,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, + 1,0,1,0,0, + 1,0,0,1,0, + 1,0,0,0,1, +}; + +static UBYTE S[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,0, + 0,1,1,1,0, + 0,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE T[] = +{ + 5,7,1, + 1,1,1,1,1, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE U[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE V[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,0,1,0, + 0,1,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE W[] = +{ + 7,7,1, + 1,0,0,0,0,0,1, + 1,0,0,0,0,0,1, + 0,1,0,1,0,1,0, + 0,1,0,1,0,1,0, + 0,0,1,0,1,0,0, + 0,0,1,0,1,0,0, + 0,0,1,0,1,0,0, +}; + +static UBYTE X[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0, + 0,1,0,1,0, + 1,0,0,0,1, + 1,0,0,0,1, +}; + +static UBYTE Y[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE Z[] = +{ + 4,7,1, + 1,1,1,1, + 0,0,0,1, + 0,0,1,0, + 0,1,0,0, + 1,0,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +static UBYTE _a[] = +{ + 4,5,3, + 0,1,1,0, + 0,0,0,1, + 0,1,1,1, + 1,0,0,1, + 0,1,1,1, +}; + +static UBYTE _b[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,1,1,0, +}; + +static UBYTE _c[] = +{ + 4,5,3, + 0,1,1,0, + 1,0,0,1, + 1,0,0,0, + 1,0,0,1, + 0,1,1,0, +}; + +static UBYTE _d[] = +{ + 4,7,1, + 0,0,0,1, + 0,0,0,1, + 0,1,1,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, +}; + +static UBYTE _e[] = +{ + 4,5,3, + 0,1,1,0, + 1,0,0,1, + 1,1,1,1, + 1,0,0,0, + 0,1,1,0, +}; + +static UBYTE _f[] = +{ + 4,7,1, + 0,0,1,1, + 0,1,0,0, + 1,1,1,0, + 0,1,0,0, + 0,1,0,0, + 0,1,0,0, + 0,1,0,0, +}; + +static UBYTE _g[] = +{ + 4,7,3, + 0,1,1,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, + 0,0,0,1, + 0,1,1,0, +}; + +static UBYTE _h[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, +}; + +static UBYTE _i[] = +{ + 2,7,1, + 0,1, + 0,0, + 1,1, + 0,1, + 0,1, + 0,1, + 0,1, +}; + +static UBYTE _j[] = +{ + 3,9,1, + 0,0,1, + 0,0,0, + 0,1,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 1,1,0, +}; + +static UBYTE _k[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,0,0,1, + 1,0,1,0, + 1,1,0,0, + 1,0,1,0, + 1,0,0,1, +}; + +static UBYTE _l[] = +{ + 2,7,1, + 1,1, + 0,1, + 0,1, + 0,1, + 0,1, + 0,1, + 0,1, +}; + +static UBYTE _m[] = +{ + 7,5,3, + 1,1,1,0,1,1,0, + 1,0,0,1,0,0,1, + 1,0,0,1,0,0,1, + 1,0,0,1,0,0,1, + 1,0,0,1,0,0,1, +}; + +static UBYTE _n[] = +{ + 4,5,3, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, +}; + +static UBYTE _o[] = +{ + 4,5,3, + 0,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,0, +}; + +static UBYTE _p[] = +{ + 4,7,3, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,1,1,0, + 1,0,0,0, + 1,0,0,0, +}; + +static UBYTE _q[] = +{ + 4,7,3, + 0,1,1,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, + 0,0,0,1, + 0,0,0,1, +}; + +static UBYTE _r[] = +{ + 4,5,3, + 1,0,1,1, + 1,1,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, +}; + +static UBYTE _s[] = +{ + 4,5,3, + 0,1,1,1, + 1,0,0,0, + 0,1,1,0, + 0,0,0,1, + 1,1,1,0, +}; + +static UBYTE _t[] = +{ + 3,7,1, + 0,1,0, + 0,1,0, + 1,1,1, + 0,1,0, + 0,1,0, + 0,1,0, + 0,0,1, +}; + +static UBYTE _u[] = +{ + 4,5,3, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, +}; + +static UBYTE _v[] = +{ + 5,5,3, + 1,0,0,0,1, + 0,1,0,1,0, + 0,1,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE _w[] = +{ + 7,5,3, + 1,0,0,0,0,0,1, + 0,1,0,1,0,1,0, + 0,1,0,1,0,1,0, + 0,0,1,0,1,0,0, + 0,0,1,0,1,0,0, +}; + +static UBYTE _x[] = +{ + 5,5,3, + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0, + 0,1,0,1,0, + 1,0,0,0,1, +}; + +static UBYTE _y[] = +{ + 4,7,3, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, + 0,0,0,1, + 0,1,1,0, +}; + +static UBYTE _z[] = +{ + 4,5,3, + 1,1,1,1, + 0,0,1,0, + 0,1,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +//--------------------------------------------------------------- + +UBYTE *CharTable[] = +{ + Null, Null, Null, Null, Null, Null, Null, Null, + Null, Null, Null, Null, Null, Null, Null, Null, + Null, Null, Null, Null, Null, Null, Null, Null, + Null, Null, Null, Null, NULL, Null, Null, Null, + Space, Excl, Quotes, Null, Dollar, Percent,And, Null, + BrackO, BrackC, Astrisk,Plus, Comma, Minus, Stop, Null, + Zero, One, Two, Three, Four, Five, Six, Seven, + Eight, Nine, Colon, Null, Null, Null, Null, QMark, + At, A, B, C, D, E, F, G, + H, I, J, K, L, M, N, O, + P, Q, R, S, T, U, V, W, + X, Y, Z, Null, Null, Null, Null, Null, + Null, _a, _b, _c, _d, _e, _f, _g, + _h, _i, _j, _k, _l, _m, _n, _o, + _p, _q, _r, _s, _t, _u, _v, _w, + _x, _y, _z, Null, Null, Null, Null, Null +}; + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Common/Trig.cpp b/MFLib1/Source/C/Common/Trig.cpp new file mode 100644 index 0000000..713d837 --- /dev/null +++ b/MFLib1/Source/C/Common/Trig.cpp @@ -0,0 +1,5924 @@ +// Trig.cpp +// Guy Simmons, 16th February 1997 + + +#include + +//--------------------------------------------------------------- + +SWORD AtanTable[] = +{ + 2048L*0/131072L, + 2048L*81/131072L, + 2048L*162/131072L, + 2048L*244/131072L, + 2048L*325/131072L, + 2048L*407/131072L, + 2048L*488/131072L, + 2048L*570/131072L, + 2048L*651/131072L, + 2048L*733/131072L, + 2048L*814/131072L, + 2048L*895/131072L, + 2048L*977/131072L, + 2048L*1058/131072L, + 2048L*1139/131072L, + 2048L*1220/131072L, + 2048L*1302/131072L, + 2048L*1383/131072L, + 2048L*1464/131072L, + 2048L*1545/131072L, + 2048L*1626/131072L, + 2048L*1707/131072L, + 2048L*1788/131072L, + 2048L*1869/131072L, + 2048L*1949/131072L, + 2048L*2030/131072L, + 2048L*2111/131072L, + 2048L*2192/131072L, + 2048L*2272/131072L, + 2048L*2353/131072L, + 2048L*2433/131072L, + 2048L*2513/131072L, + 2048L*2594/131072L, + 2048L*2674/131072L, + 2048L*2754/131072L, + 2048L*2834/131072L, + 2048L*2914/131072L, + 2048L*2994/131072L, + 2048L*3074/131072L, + 2048L*3153/131072L, + 2048L*3233/131072L, + 2048L*3312/131072L, + 2048L*3392/131072L, + 2048L*3471/131072L, + 2048L*3550/131072L, + 2048L*3629/131072L, + 2048L*3708/131072L, + 2048L*3787/131072L, + 2048L*3866/131072L, + 2048L*3945/131072L, + 2048L*4023/131072L, + 2048L*4102/131072L, + 2048L*4180/131072L, + 2048L*4258/131072L, + 2048L*4336/131072L, + 2048L*4414/131072L, + 2048L*4492/131072L, + 2048L*4570/131072L, + 2048L*4647/131072L, + 2048L*4725/131072L, + 2048L*4802/131072L, + 2048L*4879/131072L, + 2048L*4956/131072L, + 2048L*5033/131072L, + 2048L*5110/131072L, + 2048L*5187/131072L, + 2048L*5263/131072L, + 2048L*5339/131072L, + 2048L*5416/131072L, + 2048L*5492/131072L, + 2048L*5568/131072L, + 2048L*5643/131072L, + 2048L*5719/131072L, + 2048L*5794/131072L, + 2048L*5870/131072L, + 2048L*5945/131072L, + 2048L*6020/131072L, + 2048L*6094/131072L, + 2048L*6169/131072L, + 2048L*6244/131072L, + 2048L*6318/131072L, + 2048L*6392/131072L, + 2048L*6466/131072L, + 2048L*6540/131072L, + 2048L*6614/131072L, + 2048L*6687/131072L, + 2048L*6760/131072L, + 2048L*6833/131072L, + 2048L*6906/131072L, + 2048L*6979/131072L, + 2048L*7052/131072L, + 2048L*7124/131072L, + 2048L*7197/131072L, + 2048L*7269/131072L, + 2048L*7340/131072L, + 2048L*7412/131072L, + 2048L*7484/131072L, + 2048L*7555/131072L, + 2048L*7626/131072L, + 2048L*7697/131072L, + 2048L*7768/131072L, + 2048L*7839/131072L, + 2048L*7909/131072L, + 2048L*7979/131072L, + 2048L*8049/131072L, + 2048L*8119/131072L, + 2048L*8189/131072L, + 2048L*8258/131072L, + 2048L*8328/131072L, + 2048L*8397/131072L, + 2048L*8466/131072L, + 2048L*8534/131072L, + 2048L*8603/131072L, + 2048L*8671/131072L, + 2048L*8739/131072L, + 2048L*8807/131072L, + 2048L*8875/131072L, + 2048L*8942/131072L, + 2048L*9010/131072L, + 2048L*9077/131072L, + 2048L*9144/131072L, + 2048L*9210/131072L, + 2048L*9277/131072L, + 2048L*9343/131072L, + 2048L*9409/131072L, + 2048L*9475/131072L, + 2048L*9541/131072L, + 2048L*9606/131072L, + 2048L*9672/131072L, + 2048L*9737/131072L, + 2048L*9802/131072L, + 2048L*9866/131072L, + 2048L*9931/131072L, + 2048L*9995/131072L, + 2048L*10059/131072L, + 2048L*10123/131072L, + 2048L*10187/131072L, + 2048L*10250/131072L, + 2048L*10313/131072L, + 2048L*10376/131072L, + 2048L*10439/131072L, + 2048L*10502/131072L, + 2048L*10564/131072L, + 2048L*10626/131072L, + 2048L*10688/131072L, + 2048L*10750/131072L, + 2048L*10812/131072L, + 2048L*10873/131072L, + 2048L*10934/131072L, + 2048L*10995/131072L, + 2048L*11056/131072L, + 2048L*11117/131072L, + 2048L*11177/131072L, + 2048L*11237/131072L, + 2048L*11297/131072L, + 2048L*11357/131072L, + 2048L*11416/131072L, + 2048L*11476/131072L, + 2048L*11535/131072L, + 2048L*11594/131072L, + 2048L*11652/131072L, + 2048L*11711/131072L, + 2048L*11769/131072L, + 2048L*11827/131072L, + 2048L*11885/131072L, + 2048L*11943/131072L, + 2048L*12000/131072L, + 2048L*12057/131072L, + 2048L*12115/131072L, + 2048L*12171/131072L, + 2048L*12228/131072L, + 2048L*12284/131072L, + 2048L*12341/131072L, + 2048L*12397/131072L, + 2048L*12453/131072L, + 2048L*12508/131072L, + 2048L*12564/131072L, + 2048L*12619/131072L, + 2048L*12674/131072L, + 2048L*12729/131072L, + 2048L*12783/131072L, + 2048L*12838/131072L, + 2048L*12892/131072L, + 2048L*12946/131072L, + 2048L*13000/131072L, + 2048L*13054/131072L, + 2048L*13107/131072L, + 2048L*13160/131072L, + 2048L*13213/131072L, + 2048L*13266/131072L, + 2048L*13319/131072L, + 2048L*13371/131072L, + 2048L*13423/131072L, + 2048L*13475/131072L, + 2048L*13527/131072L, + 2048L*13579/131072L, + 2048L*13630/131072L, + 2048L*13682/131072L, + 2048L*13733/131072L, + 2048L*13784/131072L, + 2048L*13834/131072L, + 2048L*13885/131072L, + 2048L*13935/131072L, + 2048L*13985/131072L, + 2048L*14035/131072L, + 2048L*14085/131072L, + 2048L*14135/131072L, + 2048L*14184/131072L, + 2048L*14233/131072L, + 2048L*14282/131072L, + 2048L*14331/131072L, + 2048L*14380/131072L, + 2048L*14428/131072L, + 2048L*14476/131072L, + 2048L*14524/131072L, + 2048L*14572/131072L, + 2048L*14620/131072L, + 2048L*14667/131072L, + 2048L*14715/131072L, + 2048L*14762/131072L, + 2048L*14809/131072L, + 2048L*14856/131072L, + 2048L*14902/131072L, + 2048L*14949/131072L, + 2048L*14995/131072L, + 2048L*15041/131072L, + 2048L*15087/131072L, + 2048L*15132/131072L, + 2048L*15178/131072L, + 2048L*15223/131072L, + 2048L*15269/131072L, + 2048L*15314/131072L, + 2048L*15358/131072L, + 2048L*15403/131072L, + 2048L*15448/131072L, + 2048L*15492/131072L, + 2048L*15536/131072L, + 2048L*15580/131072L, + 2048L*15624/131072L, + 2048L*15667/131072L, + 2048L*15711/131072L, + 2048L*15754/131072L, + 2048L*15797/131072L, + 2048L*15840/131072L, + 2048L*15883/131072L, + 2048L*15926/131072L, + 2048L*15968/131072L, + 2048L*16010/131072L, + 2048L*16052/131072L, + 2048L*16094/131072L, + 2048L*16136/131072L, + 2048L*16178/131072L, + 2048L*16219/131072L, + 2048L*16261/131072L, + 2048L*16302/131072L, + 2048L*16343/131072L, + 2048L*16384/131072L +}; + +//--------------------------------------------------------------- + +SLONG SinTable[]= +{ + 0, // 0 0.00 0.000000 + 201, // 1 0.18 0.003068 + 402, // 2 0.35 0.006136 + 603, // 3 0.53 0.009204 + 804, // 4 0.70 0.012272 + 1005, // 5 0.88 0.015340 + 1206, // 6 1.05 0.018408 + 1407, // 7 1.23 0.021476 + 1608, // 8 1.41 0.024544 + 1809, // 9 1.58 0.027612 + 2010, // 10 1.76 0.030680 + 2211, // 11 1.93 0.033748 + 2412, // 12 2.11 0.036816 + 2613, // 13 2.29 0.039884 + 2814, // 14 2.46 0.042951 + 3014, // 15 2.64 0.046019 + 3215, // 16 2.81 0.049087 + 3416, // 17 2.99 0.052155 + 3617, // 18 3.16 0.055223 + 3818, // 19 3.34 0.058291 + 4018, // 20 3.52 0.061359 + 4219, // 21 3.69 0.064427 + 4420, // 22 3.87 0.067495 + 4620, // 23 4.04 0.070563 + 4821, // 24 4.22 0.073631 + 5021, // 25 4.39 0.076699 + 5222, // 26 4.57 0.079767 + 5422, // 27 4.75 0.082835 + 5622, // 28 4.92 0.085903 + 5823, // 29 5.10 0.088971 + 6023, // 30 5.27 0.092039 + 6223, // 31 5.45 0.095107 + 6423, // 32 5.62 0.098175 + 6623, // 33 5.80 0.101243 + 6823, // 34 5.98 0.104311 + 7023, // 35 6.15 0.107379 + 7223, // 36 6.33 0.110447 + 7423, // 37 6.50 0.113515 + 7623, // 38 6.68 0.116583 + 7822, // 39 6.86 0.119651 + 8022, // 40 7.03 0.122718 + 8221, // 41 7.21 0.125786 + 8421, // 42 7.38 0.128854 + 8620, // 43 7.56 0.131922 + 8819, // 44 7.73 0.134990 + 9019, // 45 7.91 0.138058 + 9218, // 46 8.09 0.141126 + 9417, // 47 8.26 0.144194 + 9616, // 48 8.44 0.147262 + 9814, // 49 8.61 0.150330 + 10013, // 50 8.79 0.153398 + 10212, // 51 8.96 0.156466 + 10410, // 52 9.14 0.159534 + 10609, // 53 9.32 0.162602 + 10807, // 54 9.49 0.165670 + 11006, // 55 9.67 0.168738 + 11204, // 56 9.84 0.171806 + 11402, // 57 10.02 0.174874 + 11600, // 58 10.20 0.177942 + 11797, // 59 10.37 0.181010 + 11995, // 60 10.55 0.184078 + 12193, // 61 10.72 0.187146 + 12390, // 62 10.90 0.190214 + 12588, // 63 11.07 0.193282 + 12785, // 64 11.25 0.196350 + 12982, // 65 11.43 0.199418 + 13179, // 66 11.60 0.202485 + 13376, // 67 11.78 0.205553 + 13573, // 68 11.95 0.208621 + 13769, // 69 12.13 0.211689 + 13966, // 70 12.30 0.214757 + 14162, // 71 12.48 0.217825 + 14359, // 72 12.66 0.220893 + 14555, // 73 12.83 0.223961 + 14751, // 74 13.01 0.227029 + 14946, // 75 13.18 0.230097 + 15142, // 76 13.36 0.233165 + 15338, // 77 13.54 0.236233 + 15533, // 78 13.71 0.239301 + 15728, // 79 13.89 0.242369 + 15923, // 80 14.06 0.245437 + 16118, // 81 14.24 0.248505 + 16313, // 82 14.41 0.251573 + 16508, // 83 14.59 0.254641 + 16702, // 84 14.77 0.257709 + 16897, // 85 14.94 0.260777 + 17091, // 86 15.12 0.263845 + 17285, // 87 15.29 0.266913 + 17479, // 88 15.47 0.269981 + 17672, // 89 15.64 0.273049 + 17866, // 90 15.82 0.276117 + 18059, // 91 16.00 0.279185 + 18253, // 92 16.17 0.282252 + 18446, // 93 16.35 0.285320 + 18638, // 94 16.52 0.288388 + 18831, // 95 16.70 0.291456 + 19024, // 96 16.88 0.294524 + 19216, // 97 17.05 0.297592 + 19408, // 98 17.23 0.300660 + 19600, // 99 17.40 0.303728 + 19792, // 100 17.58 0.306796 + 19983, // 101 17.75 0.309864 + 20175, // 102 17.93 0.312932 + 20366, // 103 18.11 0.316000 + 20557, // 104 18.28 0.319068 + 20748, // 105 18.46 0.322136 + 20938, // 106 18.63 0.325204 + 21129, // 107 18.81 0.328272 + 21319, // 108 18.98 0.331340 + 21509, // 109 19.16 0.334408 + 21699, // 110 19.34 0.337476 + 21889, // 111 19.51 0.340544 + 22078, // 112 19.69 0.343612 + 22267, // 113 19.86 0.346680 + 22456, // 114 20.04 0.349748 + 22645, // 115 20.21 0.352816 + 22833, // 116 20.39 0.355884 + 23022, // 117 20.57 0.358952 + 23210, // 118 20.74 0.362019 + 23398, // 119 20.92 0.365087 + 23586, // 120 21.09 0.368155 + 23773, // 121 21.27 0.371223 + 23960, // 122 21.45 0.374291 + 24147, // 123 21.62 0.377359 + 24334, // 124 21.80 0.380427 + 24521, // 125 21.97 0.383495 + 24707, // 126 22.15 0.386563 + 24893, // 127 22.32 0.389631 + 25079, // 128 22.50 0.392699 + 25265, // 129 22.68 0.395767 + 25450, // 130 22.85 0.398835 + 25635, // 131 23.03 0.401903 + 25820, // 132 23.20 0.404971 + 26005, // 133 23.38 0.408039 + 26189, // 134 23.55 0.411107 + 26373, // 135 23.73 0.414175 + 26557, // 136 23.91 0.417243 + 26741, // 137 24.08 0.420311 + 26925, // 138 24.26 0.423379 + 27108, // 139 24.43 0.426447 + 27291, // 140 24.61 0.429515 + 27473, // 141 24.79 0.432583 + 27656, // 142 24.96 0.435651 + 27838, // 143 25.14 0.438719 + 28020, // 144 25.31 0.441786 + 28201, // 145 25.49 0.444854 + 28383, // 146 25.66 0.447922 + 28564, // 147 25.84 0.450990 + 28745, // 148 26.02 0.454058 + 28925, // 149 26.19 0.457126 + 29105, // 150 26.37 0.460194 + 29285, // 151 26.54 0.463262 + 29465, // 152 26.72 0.466330 + 29645, // 153 26.89 0.469398 + 29824, // 154 27.07 0.472466 + 30003, // 155 27.25 0.475534 + 30181, // 156 27.42 0.478602 + 30360, // 157 27.60 0.481670 + 30538, // 158 27.77 0.484738 + 30715, // 159 27.95 0.487806 + 30893, // 160 28.12 0.490874 + 31070, // 161 28.30 0.493942 + 31247, // 162 28.48 0.497010 + 31424, // 163 28.65 0.500078 + 31600, // 164 28.83 0.503146 + 31776, // 165 29.00 0.506214 + 31952, // 166 29.18 0.509282 + 32127, // 167 29.36 0.512350 + 32302, // 168 29.53 0.515418 + 32477, // 169 29.71 0.518486 + 32651, // 170 29.88 0.521553 + 32826, // 171 30.06 0.524621 + 32999, // 172 30.23 0.527689 + 33173, // 173 30.41 0.530757 + 33346, // 174 30.59 0.533825 + 33519, // 175 30.76 0.536893 + 33692, // 176 30.94 0.539961 + 33864, // 177 31.11 0.543029 + 34036, // 178 31.29 0.546097 + 34208, // 179 31.46 0.549165 + 34379, // 180 31.64 0.552233 + 34550, // 181 31.82 0.555301 + 34721, // 182 31.99 0.558369 + 34891, // 183 32.17 0.561437 + 35061, // 184 32.34 0.564505 + 35231, // 185 32.52 0.567573 + 35400, // 186 32.70 0.570641 + 35569, // 187 32.87 0.573709 + 35738, // 188 33.05 0.576777 + 35906, // 189 33.22 0.579845 + 36074, // 190 33.40 0.582913 + 36242, // 191 33.57 0.585981 + 36409, // 192 33.75 0.589049 + 36576, // 193 33.93 0.592117 + 36743, // 194 34.10 0.595185 + 36909, // 195 34.28 0.598253 + 37075, // 196 34.45 0.601320 + 37241, // 197 34.63 0.604388 + 37406, // 198 34.80 0.607456 + 37571, // 199 34.98 0.610524 + 37736, // 200 35.16 0.613592 + 37900, // 201 35.33 0.616660 + 38064, // 202 35.51 0.619728 + 38227, // 203 35.68 0.622796 + 38390, // 204 35.86 0.625864 + 38553, // 205 36.04 0.628932 + 38716, // 206 36.21 0.632000 + 38878, // 207 36.39 0.635068 + 39039, // 208 36.56 0.638136 + 39201, // 209 36.74 0.641204 + 39362, // 210 36.91 0.644272 + 39522, // 211 37.09 0.647340 + 39682, // 212 37.27 0.650408 + 39842, // 213 37.44 0.653476 + 40002, // 214 37.62 0.656544 + 40161, // 215 37.79 0.659612 + 40319, // 216 37.97 0.662680 + 40478, // 217 38.14 0.665748 + 40636, // 218 38.32 0.668816 + 40793, // 219 38.50 0.671884 + 40950, // 220 38.67 0.674952 + 41107, // 221 38.85 0.678020 + 41263, // 222 39.02 0.681087 + 41419, // 223 39.20 0.684155 + 41575, // 224 39.38 0.687223 + 41730, // 225 39.55 0.690291 + 41885, // 226 39.73 0.693359 + 42040, // 227 39.90 0.696427 + 42194, // 228 40.08 0.699495 + 42347, // 229 40.25 0.702563 + 42501, // 230 40.43 0.705631 + 42653, // 231 40.61 0.708699 + 42806, // 232 40.78 0.711767 + 42958, // 233 40.96 0.714835 + 43110, // 234 41.13 0.717903 + 43261, // 235 41.31 0.720971 + 43412, // 236 41.48 0.724039 + 43562, // 237 41.66 0.727107 + 43712, // 238 41.84 0.730175 + 43862, // 239 42.01 0.733243 + 44011, // 240 42.19 0.736311 + 44160, // 241 42.36 0.739379 + 44308, // 242 42.54 0.742447 + 44456, // 243 42.71 0.745515 + 44603, // 244 42.89 0.748583 + 44750, // 245 43.07 0.751651 + 44897, // 246 43.24 0.754719 + 45043, // 247 43.42 0.757787 + 45189, // 248 43.59 0.760854 + 45335, // 249 43.77 0.763922 + 45480, // 250 43.95 0.766990 + 45624, // 251 44.12 0.770058 + 45768, // 252 44.30 0.773126 + 45912, // 253 44.47 0.776194 + 46055, // 254 44.65 0.779262 + 46198, // 255 44.82 0.782330 + 46340, // 256 45.00 0.785398 + 46482, // 257 45.18 0.788466 + 46624, // 258 45.35 0.791534 + 46765, // 259 45.53 0.794602 + 46906, // 260 45.70 0.797670 + 47046, // 261 45.88 0.800738 + 47186, // 262 46.05 0.803806 + 47325, // 263 46.23 0.806874 + 47464, // 264 46.41 0.809942 + 47602, // 265 46.58 0.813010 + 47740, // 266 46.76 0.816078 + 47878, // 267 46.93 0.819146 + 48015, // 268 47.11 0.822214 + 48151, // 269 47.29 0.825282 + 48288, // 270 47.46 0.828350 + 48423, // 271 47.64 0.831418 + 48558, // 272 47.81 0.834486 + 48693, // 273 47.99 0.837554 + 48828, // 274 48.16 0.840621 + 48961, // 275 48.34 0.843689 + 49095, // 276 48.52 0.846757 + 49228, // 277 48.69 0.849825 + 49360, // 278 48.87 0.852893 + 49492, // 279 49.04 0.855961 + 49624, // 280 49.22 0.859029 + 49755, // 281 49.39 0.862097 + 49886, // 282 49.57 0.865165 + 50016, // 283 49.75 0.868233 + 50146, // 284 49.92 0.871301 + 50275, // 285 50.10 0.874369 + 50403, // 286 50.27 0.877437 + 50532, // 287 50.45 0.880505 + 50660, // 288 50.62 0.883573 + 50787, // 289 50.80 0.886641 + 50914, // 290 50.98 0.889709 + 51040, // 291 51.15 0.892777 + 51166, // 292 51.33 0.895845 + 51291, // 293 51.50 0.898913 + 51416, // 294 51.68 0.901981 + 51541, // 295 51.86 0.905049 + 51665, // 296 52.03 0.908117 + 51788, // 297 52.21 0.911185 + 51911, // 298 52.38 0.914253 + 52033, // 299 52.56 0.917321 + 52155, // 300 52.73 0.920388 + 52277, // 301 52.91 0.923456 + 52398, // 302 53.09 0.926524 + 52518, // 303 53.26 0.929592 + 52639, // 304 53.44 0.932660 + 52758, // 305 53.61 0.935728 + 52877, // 306 53.79 0.938796 + 52996, // 307 53.96 0.941864 + 53114, // 308 54.14 0.944932 + 53231, // 309 54.32 0.948000 + 53348, // 310 54.49 0.951068 + 53465, // 311 54.67 0.954136 + 53581, // 312 54.84 0.957204 + 53696, // 313 55.02 0.960272 + 53811, // 314 55.20 0.963340 + 53926, // 315 55.37 0.966408 + 54040, // 316 55.55 0.969476 + 54153, // 317 55.72 0.972544 + 54266, // 318 55.90 0.975612 + 54379, // 319 56.07 0.978680 + 54491, // 320 56.25 0.981748 + 54602, // 321 56.43 0.984816 + 54713, // 322 56.60 0.987884 + 54823, // 323 56.78 0.990952 + 54933, // 324 56.95 0.994020 + 55043, // 325 57.13 0.997088 + 55152, // 326 57.30 1.000155 + 55260, // 327 57.48 1.003223 + 55368, // 328 57.66 1.006291 + 55475, // 329 57.83 1.009359 + 55582, // 330 58.01 1.012427 + 55688, // 331 58.18 1.015495 + 55794, // 332 58.36 1.018563 + 55899, // 333 58.54 1.021631 + 56004, // 334 58.71 1.024699 + 56108, // 335 58.89 1.027767 + 56212, // 336 59.06 1.030835 + 56315, // 337 59.24 1.033903 + 56417, // 338 59.41 1.036971 + 56519, // 339 59.59 1.040039 + 56621, // 340 59.77 1.043107 + 56722, // 341 59.94 1.046175 + 56822, // 342 60.12 1.049243 + 56922, // 343 60.29 1.052311 + 57022, // 344 60.47 1.055379 + 57120, // 345 60.64 1.058447 + 57219, // 346 60.82 1.061515 + 57316, // 347 61.00 1.064583 + 57414, // 348 61.17 1.067651 + 57510, // 349 61.35 1.070719 + 57606, // 350 61.52 1.073787 + 57702, // 351 61.70 1.076855 + 57797, // 352 61.88 1.079922 + 57892, // 353 62.05 1.082990 + 57986, // 354 62.23 1.086058 + 58079, // 355 62.40 1.089126 + 58172, // 356 62.58 1.092194 + 58264, // 357 62.75 1.095262 + 58356, // 358 62.93 1.098330 + 58447, // 359 63.11 1.101398 + 58538, // 360 63.28 1.104466 + 58628, // 361 63.46 1.107534 + 58718, // 362 63.63 1.110602 + 58807, // 363 63.81 1.113670 + 58895, // 364 63.98 1.116738 + 58983, // 365 64.16 1.119806 + 59070, // 366 64.34 1.122874 + 59157, // 367 64.51 1.125942 + 59243, // 368 64.69 1.129010 + 59329, // 369 64.86 1.132078 + 59414, // 370 65.04 1.135146 + 59499, // 371 65.21 1.138214 + 59583, // 372 65.39 1.141282 + 59666, // 373 65.57 1.144350 + 59749, // 374 65.74 1.147418 + 59831, // 375 65.92 1.150486 + 59913, // 376 66.09 1.153554 + 59994, // 377 66.27 1.156622 + 60075, // 378 66.45 1.159689 + 60155, // 379 66.62 1.162757 + 60235, // 380 66.80 1.165825 + 60313, // 381 66.97 1.168893 + 60392, // 382 67.15 1.171961 + 60470, // 383 67.32 1.175029 + 60547, // 384 67.50 1.178097 + 60624, // 385 67.68 1.181165 + 60700, // 386 67.85 1.184233 + 60775, // 387 68.03 1.187301 + 60850, // 388 68.20 1.190369 + 60924, // 389 68.38 1.193437 + 60998, // 390 68.55 1.196505 + 61071, // 391 68.73 1.199573 + 61144, // 392 68.91 1.202641 + 61216, // 393 69.08 1.205709 + 61288, // 394 69.26 1.208777 + 61359, // 395 69.43 1.211845 + 61429, // 396 69.61 1.214913 + 61499, // 397 69.79 1.217981 + 61568, // 398 69.96 1.221049 + 61637, // 399 70.14 1.224117 + 61705, // 400 70.31 1.227185 + 61772, // 401 70.49 1.230253 + 61839, // 402 70.66 1.233321 + 61905, // 403 70.84 1.236389 + 61971, // 404 71.02 1.239456 + 62036, // 405 71.19 1.242524 + 62100, // 406 71.37 1.245592 + 62164, // 407 71.54 1.248660 + 62228, // 408 71.72 1.251728 + 62291, // 409 71.89 1.254796 + 62353, // 410 72.07 1.257864 + 62414, // 411 72.25 1.260932 + 62475, // 412 72.42 1.264000 + 62536, // 413 72.60 1.267068 + 62596, // 414 72.77 1.270136 + 62655, // 415 72.95 1.273204 + 62714, // 416 73.12 1.276272 + 62772, // 417 73.30 1.279340 + 62829, // 418 73.48 1.282408 + 62886, // 419 73.65 1.285476 + 62942, // 420 73.83 1.288544 + 62998, // 421 74.00 1.291612 + 63053, // 422 74.18 1.294680 + 63108, // 423 74.36 1.297748 + 63162, // 424 74.53 1.300816 + 63215, // 425 74.71 1.303884 + 63268, // 426 74.88 1.306952 + 63320, // 427 75.06 1.310020 + 63371, // 428 75.23 1.313088 + 63422, // 429 75.41 1.316156 + 63473, // 430 75.59 1.319223 + 63522, // 431 75.76 1.322291 + 63571, // 432 75.94 1.325359 + 63620, // 433 76.11 1.328427 + 63668, // 434 76.29 1.331495 + 63715, // 435 76.46 1.334563 + 63762, // 436 76.64 1.337631 + 63808, // 437 76.82 1.340699 + 63854, // 438 76.99 1.343767 + 63899, // 439 77.17 1.346835 + 63943, // 440 77.34 1.349903 + 63987, // 441 77.52 1.352971 + 64030, // 442 77.70 1.356039 + 64073, // 443 77.87 1.359107 + 64115, // 444 78.05 1.362175 + 64156, // 445 78.22 1.365243 + 64197, // 446 78.40 1.368311 + 64237, // 447 78.57 1.371379 + 64276, // 448 78.75 1.374447 + 64315, // 449 78.93 1.377515 + 64353, // 450 79.10 1.380583 + 64391, // 451 79.28 1.383651 + 64428, // 452 79.45 1.386719 + 64465, // 453 79.63 1.389787 + 64501, // 454 79.80 1.392855 + 64536, // 455 79.98 1.395923 + 64571, // 456 80.16 1.398990 + 64605, // 457 80.33 1.402058 + 64638, // 458 80.51 1.405126 + 64671, // 459 80.68 1.408194 + 64703, // 460 80.86 1.411262 + 64735, // 461 81.04 1.414330 + 64766, // 462 81.21 1.417398 + 64796, // 463 81.39 1.420466 + 64826, // 464 81.56 1.423534 + 64855, // 465 81.74 1.426602 + 64884, // 466 81.91 1.429670 + 64912, // 467 82.09 1.432738 + 64939, // 468 82.27 1.435806 + 64966, // 469 82.44 1.438874 + 64992, // 470 82.62 1.441942 + 65018, // 471 82.79 1.445010 + 65043, // 472 82.97 1.448078 + 65067, // 473 83.14 1.451146 + 65091, // 474 83.32 1.454214 + 65114, // 475 83.50 1.457282 + 65136, // 476 83.67 1.460350 + 65158, // 477 83.85 1.463418 + 65179, // 478 84.02 1.466486 + 65200, // 479 84.20 1.469554 + 65220, // 480 84.38 1.472622 + 65239, // 481 84.55 1.475690 + 65258, // 482 84.73 1.478757 + 65276, // 483 84.90 1.481825 + 65294, // 484 85.08 1.484893 + 65311, // 485 85.25 1.487961 + 65327, // 486 85.43 1.491029 + 65343, // 487 85.61 1.494097 + 65358, // 488 85.78 1.497165 + 65372, // 489 85.96 1.500233 + 65386, // 490 86.13 1.503301 + 65400, // 491 86.31 1.506369 + 65412, // 492 86.48 1.509437 + 65424, // 493 86.66 1.512505 + 65436, // 494 86.84 1.515573 + 65446, // 495 87.01 1.518641 + 65457, // 496 87.19 1.521709 + 65466, // 497 87.36 1.524777 + 65475, // 498 87.54 1.527845 + 65483, // 499 87.71 1.530913 + 65491, // 500 87.89 1.533981 + 65498, // 501 88.07 1.537049 + 65505, // 502 88.24 1.540117 + 65511, // 503 88.42 1.543185 + 65516, // 504 88.59 1.546253 + 65520, // 505 88.77 1.549321 + 65524, // 506 88.95 1.552389 + 65528, // 507 89.12 1.555457 + 65531, // 508 89.30 1.558524 + 65533, // 509 89.47 1.561592 + 65534, // 510 89.65 1.564660 + 65535, // 511 89.82 1.567728 + 65536, // 512 90.00 1.570796 + 65535, // 513 90.18 1.573864 + 65534, // 514 90.35 1.576932 + 65533, // 515 90.53 1.580000 + 65531, // 516 90.70 1.583068 + 65528, // 517 90.88 1.586136 + 65524, // 518 91.05 1.589204 + 65520, // 519 91.23 1.592272 + 65516, // 520 91.41 1.595340 + 65511, // 521 91.58 1.598408 + 65505, // 522 91.76 1.601476 + 65498, // 523 91.93 1.604544 + 65491, // 524 92.11 1.607612 + 65483, // 525 92.29 1.610680 + 65475, // 526 92.46 1.613748 + 65466, // 527 92.64 1.616816 + 65457, // 528 92.81 1.619884 + 65446, // 529 92.99 1.622952 + 65436, // 530 93.16 1.626020 + 65424, // 531 93.34 1.629088 + 65412, // 532 93.52 1.632156 + 65400, // 533 93.69 1.635224 + 65386, // 534 93.87 1.638291 + 65372, // 535 94.04 1.641359 + 65358, // 536 94.22 1.644427 + 65343, // 537 94.39 1.647495 + 65327, // 538 94.57 1.650563 + 65311, // 539 94.75 1.653631 + 65294, // 540 94.92 1.656699 + 65276, // 541 95.10 1.659767 + 65258, // 542 95.27 1.662835 + 65239, // 543 95.45 1.665903 + 65220, // 544 95.62 1.668971 + 65200, // 545 95.80 1.672039 + 65179, // 546 95.98 1.675107 + 65158, // 547 96.15 1.678175 + 65136, // 548 96.33 1.681243 + 65114, // 549 96.50 1.684311 + 65091, // 550 96.68 1.687379 + 65067, // 551 96.86 1.690447 + 65043, // 552 97.03 1.693515 + 65018, // 553 97.21 1.696583 + 64992, // 554 97.38 1.699651 + 64966, // 555 97.56 1.702719 + 64939, // 556 97.73 1.705787 + 64912, // 557 97.91 1.708855 + 64884, // 558 98.09 1.711923 + 64855, // 559 98.26 1.714991 + 64826, // 560 98.44 1.718058 + 64796, // 561 98.61 1.721126 + 64766, // 562 98.79 1.724194 + 64735, // 563 98.96 1.727262 + 64703, // 564 99.14 1.730330 + 64671, // 565 99.32 1.733398 + 64638, // 566 99.49 1.736466 + 64605, // 567 99.67 1.739534 + 64571, // 568 99.84 1.742602 + 64536, // 569 100.02 1.745670 + 64501, // 570 100.20 1.748738 + 64465, // 571 100.37 1.751806 + 64428, // 572 100.55 1.754874 + 64391, // 573 100.72 1.757942 + 64353, // 574 100.90 1.761010 + 64315, // 575 101.07 1.764078 + 64276, // 576 101.25 1.767146 + 64237, // 577 101.43 1.770214 + 64197, // 578 101.60 1.773282 + 64156, // 579 101.78 1.776350 + 64115, // 580 101.95 1.779418 + 64073, // 581 102.13 1.782486 + 64030, // 582 102.30 1.785554 + 63987, // 583 102.48 1.788622 + 63943, // 584 102.66 1.791690 + 63899, // 585 102.83 1.794758 + 63854, // 586 103.01 1.797825 + 63808, // 587 103.18 1.800893 + 63762, // 588 103.36 1.803961 + 63715, // 589 103.54 1.807029 + 63668, // 590 103.71 1.810097 + 63620, // 591 103.89 1.813165 + 63571, // 592 104.06 1.816233 + 63522, // 593 104.24 1.819301 + 63473, // 594 104.41 1.822369 + 63422, // 595 104.59 1.825437 + 63371, // 596 104.77 1.828505 + 63320, // 597 104.94 1.831573 + 63268, // 598 105.12 1.834641 + 63215, // 599 105.29 1.837709 + 63162, // 600 105.47 1.840777 + 63108, // 601 105.64 1.843845 + 63053, // 602 105.82 1.846913 + 62998, // 603 106.00 1.849981 + 62942, // 604 106.17 1.853049 + 62886, // 605 106.35 1.856117 + 62829, // 606 106.52 1.859185 + 62772, // 607 106.70 1.862253 + 62714, // 608 106.88 1.865321 + 62655, // 609 107.05 1.868389 + 62596, // 610 107.23 1.871457 + 62536, // 611 107.40 1.874525 + 62475, // 612 107.58 1.877592 + 62414, // 613 107.75 1.880660 + 62353, // 614 107.93 1.883728 + 62291, // 615 108.11 1.886796 + 62228, // 616 108.28 1.889864 + 62164, // 617 108.46 1.892932 + 62100, // 618 108.63 1.896000 + 62036, // 619 108.81 1.899068 + 61971, // 620 108.98 1.902136 + 61905, // 621 109.16 1.905204 + 61839, // 622 109.34 1.908272 + 61772, // 623 109.51 1.911340 + 61705, // 624 109.69 1.914408 + 61637, // 625 109.86 1.917476 + 61568, // 626 110.04 1.920544 + 61499, // 627 110.21 1.923612 + 61429, // 628 110.39 1.926680 + 61359, // 629 110.57 1.929748 + 61288, // 630 110.74 1.932816 + 61216, // 631 110.92 1.935884 + 61144, // 632 111.09 1.938952 + 61071, // 633 111.27 1.942020 + 60998, // 634 111.45 1.945088 + 60924, // 635 111.62 1.948156 + 60850, // 636 111.80 1.951224 + 60775, // 637 111.97 1.954292 + 60700, // 638 112.15 1.957359 + 60624, // 639 112.32 1.960427 + 60547, // 640 112.50 1.963495 + 60470, // 641 112.68 1.966563 + 60392, // 642 112.85 1.969631 + 60313, // 643 113.03 1.972699 + 60235, // 644 113.20 1.975767 + 60155, // 645 113.38 1.978835 + 60075, // 646 113.55 1.981903 + 59994, // 647 113.73 1.984971 + 59913, // 648 113.91 1.988039 + 59831, // 649 114.08 1.991107 + 59749, // 650 114.26 1.994175 + 59666, // 651 114.43 1.997243 + 59583, // 652 114.61 2.000311 + 59499, // 653 114.79 2.003379 + 59414, // 654 114.96 2.006447 + 59329, // 655 115.14 2.009515 + 59243, // 656 115.31 2.012583 + 59157, // 657 115.49 2.015651 + 59070, // 658 115.66 2.018719 + 58983, // 659 115.84 2.021787 + 58895, // 660 116.02 2.024855 + 58807, // 661 116.19 2.027923 + 58718, // 662 116.37 2.030991 + 58628, // 663 116.54 2.034059 + 58538, // 664 116.72 2.037126 + 58447, // 665 116.89 2.040194 + 58356, // 666 117.07 2.043262 + 58264, // 667 117.25 2.046330 + 58172, // 668 117.42 2.049398 + 58079, // 669 117.60 2.052466 + 57986, // 670 117.77 2.055534 + 57892, // 671 117.95 2.058602 + 57797, // 672 118.12 2.061670 + 57702, // 673 118.30 2.064738 + 57606, // 674 118.48 2.067806 + 57510, // 675 118.65 2.070874 + 57414, // 676 118.83 2.073942 + 57316, // 677 119.00 2.077010 + 57219, // 678 119.18 2.080078 + 57120, // 679 119.36 2.083146 + 57022, // 680 119.53 2.086214 + 56922, // 681 119.71 2.089282 + 56822, // 682 119.88 2.092350 + 56722, // 683 120.06 2.095418 + 56621, // 684 120.23 2.098486 + 56519, // 685 120.41 2.101554 + 56417, // 686 120.59 2.104622 + 56315, // 687 120.76 2.107690 + 56212, // 688 120.94 2.110758 + 56108, // 689 121.11 2.113826 + 56004, // 690 121.29 2.116893 + 55899, // 691 121.46 2.119961 + 55794, // 692 121.64 2.123029 + 55688, // 693 121.82 2.126097 + 55582, // 694 121.99 2.129165 + 55475, // 695 122.17 2.132233 + 55368, // 696 122.34 2.135301 + 55260, // 697 122.52 2.138369 + 55152, // 698 122.70 2.141437 + 55043, // 699 122.87 2.144505 + 54933, // 700 123.05 2.147573 + 54823, // 701 123.22 2.150641 + 54713, // 702 123.40 2.153709 + 54602, // 703 123.57 2.156777 + 54491, // 704 123.75 2.159845 + 54379, // 705 123.93 2.162913 + 54266, // 706 124.10 2.165981 + 54153, // 707 124.28 2.169049 + 54040, // 708 124.45 2.172117 + 53926, // 709 124.63 2.175185 + 53811, // 710 124.80 2.178253 + 53696, // 711 124.98 2.181321 + 53581, // 712 125.16 2.184389 + 53465, // 713 125.33 2.187457 + 53348, // 714 125.51 2.190525 + 53231, // 715 125.68 2.193593 + 53114, // 716 125.86 2.196660 + 52996, // 717 126.04 2.199728 + 52877, // 718 126.21 2.202796 + 52758, // 719 126.39 2.205864 + 52639, // 720 126.56 2.208932 + 52518, // 721 126.74 2.212000 + 52398, // 722 126.91 2.215068 + 52277, // 723 127.09 2.218136 + 52155, // 724 127.27 2.221204 + 52033, // 725 127.44 2.224272 + 51911, // 726 127.62 2.227340 + 51788, // 727 127.79 2.230408 + 51665, // 728 127.97 2.233476 + 51541, // 729 128.14 2.236544 + 51416, // 730 128.32 2.239612 + 51291, // 731 128.50 2.242680 + 51166, // 732 128.67 2.245748 + 51040, // 733 128.85 2.248816 + 50914, // 734 129.02 2.251884 + 50787, // 735 129.20 2.254952 + 50660, // 736 129.38 2.258020 + 50532, // 737 129.55 2.261088 + 50403, // 738 129.73 2.264156 + 50275, // 739 129.90 2.267224 + 50146, // 740 130.08 2.270292 + 50016, // 741 130.25 2.273360 + 49886, // 742 130.43 2.276427 + 49755, // 743 130.61 2.279495 + 49624, // 744 130.78 2.282563 + 49492, // 745 130.96 2.285631 + 49360, // 746 131.13 2.288699 + 49228, // 747 131.31 2.291767 + 49095, // 748 131.48 2.294835 + 48961, // 749 131.66 2.297903 + 48828, // 750 131.84 2.300971 + 48693, // 751 132.01 2.304039 + 48558, // 752 132.19 2.307107 + 48423, // 753 132.36 2.310175 + 48288, // 754 132.54 2.313243 + 48151, // 755 132.71 2.316311 + 48015, // 756 132.89 2.319379 + 47878, // 757 133.07 2.322447 + 47740, // 758 133.24 2.325515 + 47602, // 759 133.42 2.328583 + 47464, // 760 133.59 2.331651 + 47325, // 761 133.77 2.334719 + 47186, // 762 133.95 2.337787 + 47046, // 763 134.12 2.340855 + 46906, // 764 134.30 2.343923 + 46765, // 765 134.47 2.346991 + 46624, // 766 134.65 2.350059 + 46482, // 767 134.82 2.353127 + 46340, // 768 135.00 2.356194 + 46198, // 769 135.18 2.359262 + 46055, // 770 135.35 2.362330 + 45912, // 771 135.53 2.365398 + 45768, // 772 135.70 2.368466 + 45624, // 773 135.88 2.371534 + 45480, // 774 136.05 2.374602 + 45335, // 775 136.23 2.377670 + 45189, // 776 136.41 2.380738 + 45043, // 777 136.58 2.383806 + 44897, // 778 136.76 2.386874 + 44750, // 779 136.93 2.389942 + 44603, // 780 137.11 2.393010 + 44456, // 781 137.29 2.396078 + 44308, // 782 137.46 2.399146 + 44160, // 783 137.64 2.402214 + 44011, // 784 137.81 2.405282 + 43862, // 785 137.99 2.408350 + 43712, // 786 138.16 2.411418 + 43562, // 787 138.34 2.414486 + 43412, // 788 138.52 2.417554 + 43261, // 789 138.69 2.420622 + 43110, // 790 138.87 2.423690 + 42958, // 791 139.04 2.426758 + 42806, // 792 139.22 2.429826 + 42653, // 793 139.39 2.432894 + 42501, // 794 139.57 2.435961 + 42347, // 795 139.75 2.439029 + 42194, // 796 139.92 2.442097 + 42040, // 797 140.10 2.445165 + 41885, // 798 140.27 2.448233 + 41730, // 799 140.45 2.451301 + 41575, // 800 140.62 2.454369 + 41419, // 801 140.80 2.457437 + 41263, // 802 140.98 2.460505 + 41107, // 803 141.15 2.463573 + 40950, // 804 141.33 2.466641 + 40793, // 805 141.50 2.469709 + 40636, // 806 141.68 2.472777 + 40478, // 807 141.86 2.475845 + 40319, // 808 142.03 2.478913 + 40161, // 809 142.21 2.481981 + 40002, // 810 142.38 2.485049 + 39842, // 811 142.56 2.488117 + 39682, // 812 142.73 2.491185 + 39522, // 813 142.91 2.494253 + 39362, // 814 143.09 2.497321 + 39201, // 815 143.26 2.500389 + 39039, // 816 143.44 2.503457 + 38878, // 817 143.61 2.506525 + 38716, // 818 143.79 2.509593 + 38553, // 819 143.96 2.512661 + 38390, // 820 144.14 2.515728 + 38227, // 821 144.32 2.518796 + 38064, // 822 144.49 2.521864 + 37900, // 823 144.67 2.524932 + 37736, // 824 144.84 2.528000 + 37571, // 825 145.02 2.531068 + 37406, // 826 145.20 2.534136 + 37241, // 827 145.37 2.537204 + 37075, // 828 145.55 2.540272 + 36909, // 829 145.72 2.543340 + 36743, // 830 145.90 2.546408 + 36576, // 831 146.07 2.549476 + 36409, // 832 146.25 2.552544 + 36242, // 833 146.43 2.555612 + 36074, // 834 146.60 2.558680 + 35906, // 835 146.78 2.561748 + 35738, // 836 146.95 2.564816 + 35569, // 837 147.13 2.567884 + 35400, // 838 147.30 2.570952 + 35231, // 839 147.48 2.574020 + 35061, // 840 147.66 2.577088 + 34891, // 841 147.83 2.580156 + 34721, // 842 148.01 2.583224 + 34550, // 843 148.18 2.586292 + 34379, // 844 148.36 2.589360 + 34208, // 845 148.54 2.592428 + 34036, // 846 148.71 2.595495 + 33864, // 847 148.89 2.598563 + 33692, // 848 149.06 2.601631 + 33519, // 849 149.24 2.604699 + 33346, // 850 149.41 2.607767 + 33173, // 851 149.59 2.610835 + 32999, // 852 149.77 2.613903 + 32826, // 853 149.94 2.616971 + 32651, // 854 150.12 2.620039 + 32477, // 855 150.29 2.623107 + 32302, // 856 150.47 2.626175 + 32127, // 857 150.64 2.629243 + 31952, // 858 150.82 2.632311 + 31776, // 859 151.00 2.635379 + 31600, // 860 151.17 2.638447 + 31424, // 861 151.35 2.641515 + 31247, // 862 151.52 2.644583 + 31070, // 863 151.70 2.647651 + 30893, // 864 151.88 2.650719 + 30715, // 865 152.05 2.653787 + 30538, // 866 152.23 2.656855 + 30360, // 867 152.40 2.659923 + 30181, // 868 152.58 2.662991 + 30003, // 869 152.75 2.666059 + 29824, // 870 152.93 2.669127 + 29645, // 871 153.11 2.672195 + 29465, // 872 153.28 2.675262 + 29285, // 873 153.46 2.678330 + 29105, // 874 153.63 2.681398 + 28925, // 875 153.81 2.684466 + 28745, // 876 153.98 2.687534 + 28564, // 877 154.16 2.690602 + 28383, // 878 154.34 2.693670 + 28201, // 879 154.51 2.696738 + 28020, // 880 154.69 2.699806 + 27838, // 881 154.86 2.702874 + 27656, // 882 155.04 2.705942 + 27473, // 883 155.21 2.709010 + 27291, // 884 155.39 2.712078 + 27108, // 885 155.57 2.715146 + 26925, // 886 155.74 2.718214 + 26741, // 887 155.92 2.721282 + 26557, // 888 156.09 2.724350 + 26373, // 889 156.27 2.727418 + 26189, // 890 156.45 2.730486 + 26005, // 891 156.62 2.733554 + 25820, // 892 156.80 2.736622 + 25635, // 893 156.97 2.739690 + 25450, // 894 157.15 2.742758 + 25265, // 895 157.32 2.745826 + 25079, // 896 157.50 2.748894 + 24893, // 897 157.68 2.751962 + 24707, // 898 157.85 2.755029 + 24521, // 899 158.03 2.758097 + 24334, // 900 158.20 2.761165 + 24147, // 901 158.38 2.764233 + 23960, // 902 158.55 2.767301 + 23773, // 903 158.73 2.770369 + 23586, // 904 158.91 2.773437 + 23398, // 905 159.08 2.776505 + 23210, // 906 159.26 2.779573 + 23022, // 907 159.43 2.782641 + 22833, // 908 159.61 2.785709 + 22645, // 909 159.79 2.788777 + 22456, // 910 159.96 2.791845 + 22267, // 911 160.14 2.794913 + 22078, // 912 160.31 2.797981 + 21889, // 913 160.49 2.801049 + 21699, // 914 160.66 2.804117 + 21509, // 915 160.84 2.807185 + 21319, // 916 161.02 2.810253 + 21129, // 917 161.19 2.813321 + 20938, // 918 161.37 2.816389 + 20748, // 919 161.54 2.819457 + 20557, // 920 161.72 2.822525 + 20366, // 921 161.89 2.825593 + 20175, // 922 162.07 2.828661 + 19983, // 923 162.25 2.831729 + 19792, // 924 162.42 2.834796 + 19600, // 925 162.60 2.837864 + 19408, // 926 162.77 2.840932 + 19216, // 927 162.95 2.844000 + 19024, // 928 163.12 2.847068 + 18831, // 929 163.30 2.850136 + 18638, // 930 163.48 2.853204 + 18446, // 931 163.65 2.856272 + 18253, // 932 163.83 2.859340 + 18059, // 933 164.00 2.862408 + 17866, // 934 164.18 2.865476 + 17672, // 935 164.36 2.868544 + 17479, // 936 164.53 2.871612 + 17285, // 937 164.71 2.874680 + 17091, // 938 164.88 2.877748 + 16897, // 939 165.06 2.880816 + 16702, // 940 165.23 2.883884 + 16508, // 941 165.41 2.886952 + 16313, // 942 165.59 2.890020 + 16118, // 943 165.76 2.893088 + 15923, // 944 165.94 2.896156 + 15728, // 945 166.11 2.899224 + 15533, // 946 166.29 2.902292 + 15338, // 947 166.46 2.905360 + 15142, // 948 166.64 2.908428 + 14946, // 949 166.82 2.911496 + 14751, // 950 166.99 2.914563 + 14555, // 951 167.17 2.917631 + 14359, // 952 167.34 2.920699 + 14162, // 953 167.52 2.923767 + 13966, // 954 167.70 2.926835 + 13769, // 955 167.87 2.929903 + 13573, // 956 168.05 2.932971 + 13376, // 957 168.22 2.936039 + 13179, // 958 168.40 2.939107 + 12982, // 959 168.57 2.942175 + 12785, // 960 168.75 2.945243 + 12588, // 961 168.93 2.948311 + 12390, // 962 169.10 2.951379 + 12193, // 963 169.28 2.954447 + 11995, // 964 169.45 2.957515 + 11797, // 965 169.63 2.960583 + 11600, // 966 169.80 2.963651 + 11402, // 967 169.98 2.966719 + 11204, // 968 170.16 2.969787 + 11006, // 969 170.33 2.972855 + 10807, // 970 170.51 2.975923 + 10609, // 971 170.68 2.978991 + 10410, // 972 170.86 2.982059 + 10212, // 973 171.04 2.985127 + 10013, // 974 171.21 2.988195 + 9814, // 975 171.39 2.991263 + 9616, // 976 171.56 2.994330 + 9417, // 977 171.74 2.997398 + 9218, // 978 171.91 3.000466 + 9019, // 979 172.09 3.003534 + 8819, // 980 172.27 3.006602 + 8620, // 981 172.44 3.009670 + 8421, // 982 172.62 3.012738 + 8221, // 983 172.79 3.015806 + 8022, // 984 172.97 3.018874 + 7822, // 985 173.14 3.021942 + 7623, // 986 173.32 3.025010 + 7423, // 987 173.50 3.028078 + 7223, // 988 173.67 3.031146 + 7023, // 989 173.85 3.034214 + 6823, // 990 174.02 3.037282 + 6623, // 991 174.20 3.040350 + 6423, // 992 174.38 3.043418 + 6223, // 993 174.55 3.046486 + 6023, // 994 174.73 3.049554 + 5823, // 995 174.90 3.052622 + 5622, // 996 175.08 3.055690 + 5422, // 997 175.25 3.058758 + 5222, // 998 175.43 3.061826 + 5021, // 999 175.61 3.064894 + 4821, // 1000 175.78 3.067962 + 4620, // 1001 175.96 3.071030 + 4420, // 1002 176.13 3.074097 + 4219, // 1003 176.31 3.077165 + 4018, // 1004 176.48 3.080233 + 3818, // 1005 176.66 3.083301 + 3617, // 1006 176.84 3.086369 + 3416, // 1007 177.01 3.089437 + 3215, // 1008 177.19 3.092505 + 3014, // 1009 177.36 3.095573 + 2814, // 1010 177.54 3.098641 + 2613, // 1011 177.71 3.101709 + 2412, // 1012 177.89 3.104777 + 2211, // 1013 178.07 3.107845 + 2010, // 1014 178.24 3.110913 + 1809, // 1015 178.42 3.113981 + 1608, // 1016 178.59 3.117049 + 1407, // 1017 178.77 3.120117 + 1206, // 1018 178.95 3.123185 + 1005, // 1019 179.12 3.126253 + 804, // 1020 179.30 3.129321 + 603, // 1021 179.47 3.132389 + 402, // 1022 179.65 3.135457 + 201, // 1023 179.82 3.138525 + 0, // 1024 180.00 3.141593 + -201, // 1025 180.18 3.144661 + -402, // 1026 180.35 3.147729 + -603, // 1027 180.53 3.150797 + -804, // 1028 180.70 3.153865 + -1005, // 1029 180.88 3.156932 + -1206, // 1030 181.05 3.160000 + -1407, // 1031 181.23 3.163068 + -1608, // 1032 181.41 3.166136 + -1809, // 1033 181.58 3.169204 + -2010, // 1034 181.76 3.172272 + -2211, // 1035 181.93 3.175340 + -2412, // 1036 182.11 3.178408 + -2613, // 1037 182.29 3.181476 + -2814, // 1038 182.46 3.184544 + -3014, // 1039 182.64 3.187612 + -3215, // 1040 182.81 3.190680 + -3416, // 1041 182.99 3.193748 + -3617, // 1042 183.16 3.196816 + -3818, // 1043 183.34 3.199884 + -4018, // 1044 183.52 3.202952 + -4219, // 1045 183.69 3.206020 + -4420, // 1046 183.87 3.209088 + -4620, // 1047 184.04 3.212156 + -4821, // 1048 184.22 3.215224 + -5021, // 1049 184.39 3.218292 + -5222, // 1050 184.57 3.221360 + -5422, // 1051 184.75 3.224428 + -5622, // 1052 184.92 3.227496 + -5823, // 1053 185.10 3.230564 + -6023, // 1054 185.27 3.233632 + -6223, // 1055 185.45 3.236699 + -6423, // 1056 185.62 3.239767 + -6623, // 1057 185.80 3.242835 + -6823, // 1058 185.98 3.245903 + -7023, // 1059 186.15 3.248971 + -7223, // 1060 186.33 3.252039 + -7423, // 1061 186.50 3.255107 + -7623, // 1062 186.68 3.258175 + -7822, // 1063 186.86 3.261243 + -8022, // 1064 187.03 3.264311 + -8221, // 1065 187.21 3.267379 + -8421, // 1066 187.38 3.270447 + -8620, // 1067 187.56 3.273515 + -8819, // 1068 187.73 3.276583 + -9019, // 1069 187.91 3.279651 + -9218, // 1070 188.09 3.282719 + -9417, // 1071 188.26 3.285787 + -9616, // 1072 188.44 3.288855 + -9814, // 1073 188.61 3.291923 + -10013, // 1074 188.79 3.294991 + -10212, // 1075 188.96 3.298059 + -10410, // 1076 189.14 3.301127 + -10609, // 1077 189.32 3.304195 + -10807, // 1078 189.49 3.307263 + -11006, // 1079 189.67 3.310331 + -11204, // 1080 189.84 3.313399 + -11402, // 1081 190.02 3.316466 + -11600, // 1082 190.20 3.319534 + -11797, // 1083 190.37 3.322602 + -11995, // 1084 190.55 3.325670 + -12193, // 1085 190.72 3.328738 + -12390, // 1086 190.90 3.331806 + -12588, // 1087 191.07 3.334874 + -12785, // 1088 191.25 3.337942 + -12982, // 1089 191.43 3.341010 + -13179, // 1090 191.60 3.344078 + -13376, // 1091 191.78 3.347146 + -13573, // 1092 191.95 3.350214 + -13769, // 1093 192.13 3.353282 + -13966, // 1094 192.30 3.356350 + -14162, // 1095 192.48 3.359418 + -14359, // 1096 192.66 3.362486 + -14555, // 1097 192.83 3.365554 + -14751, // 1098 193.01 3.368622 + -14946, // 1099 193.18 3.371690 + -15142, // 1100 193.36 3.374758 + -15338, // 1101 193.54 3.377826 + -15533, // 1102 193.71 3.380894 + -15728, // 1103 193.89 3.383962 + -15923, // 1104 194.06 3.387030 + -16118, // 1105 194.24 3.390098 + -16313, // 1106 194.41 3.393166 + -16508, // 1107 194.59 3.396233 + -16702, // 1108 194.77 3.399301 + -16897, // 1109 194.94 3.402369 + -17091, // 1110 195.12 3.405437 + -17285, // 1111 195.29 3.408505 + -17479, // 1112 195.47 3.411573 + -17672, // 1113 195.64 3.414641 + -17866, // 1114 195.82 3.417709 + -18059, // 1115 196.00 3.420777 + -18253, // 1116 196.17 3.423845 + -18446, // 1117 196.35 3.426913 + -18638, // 1118 196.52 3.429981 + -18831, // 1119 196.70 3.433049 + -19024, // 1120 196.88 3.436117 + -19216, // 1121 197.05 3.439185 + -19408, // 1122 197.23 3.442253 + -19600, // 1123 197.40 3.445321 + -19792, // 1124 197.58 3.448389 + -19983, // 1125 197.75 3.451457 + -20175, // 1126 197.93 3.454525 + -20366, // 1127 198.11 3.457593 + -20557, // 1128 198.28 3.460661 + -20748, // 1129 198.46 3.463729 + -20938, // 1130 198.63 3.466797 + -21129, // 1131 198.81 3.469865 + -21319, // 1132 198.98 3.472933 + -21509, // 1133 199.16 3.476000 + -21699, // 1134 199.34 3.479068 + -21889, // 1135 199.51 3.482136 + -22078, // 1136 199.69 3.485204 + -22267, // 1137 199.86 3.488272 + -22456, // 1138 200.04 3.491340 + -22645, // 1139 200.21 3.494408 + -22833, // 1140 200.39 3.497476 + -23022, // 1141 200.57 3.500544 + -23210, // 1142 200.74 3.503612 + -23398, // 1143 200.92 3.506680 + -23586, // 1144 201.09 3.509748 + -23773, // 1145 201.27 3.512816 + -23960, // 1146 201.45 3.515884 + -24147, // 1147 201.62 3.518952 + -24334, // 1148 201.80 3.522020 + -24521, // 1149 201.97 3.525088 + -24707, // 1150 202.15 3.528156 + -24893, // 1151 202.32 3.531224 + -25079, // 1152 202.50 3.534292 + -25265, // 1153 202.68 3.537360 + -25450, // 1154 202.85 3.540428 + -25635, // 1155 203.03 3.543496 + -25820, // 1156 203.20 3.546564 + -26005, // 1157 203.38 3.549632 + -26189, // 1158 203.55 3.552700 + -26373, // 1159 203.73 3.555767 + -26557, // 1160 203.91 3.558835 + -26741, // 1161 204.08 3.561903 + -26925, // 1162 204.26 3.564971 + -27108, // 1163 204.43 3.568039 + -27291, // 1164 204.61 3.571107 + -27473, // 1165 204.79 3.574175 + -27656, // 1166 204.96 3.577243 + -27838, // 1167 205.14 3.580311 + -28020, // 1168 205.31 3.583379 + -28201, // 1169 205.49 3.586447 + -28383, // 1170 205.66 3.589515 + -28564, // 1171 205.84 3.592583 + -28745, // 1172 206.02 3.595651 + -28925, // 1173 206.19 3.598719 + -29105, // 1174 206.37 3.601787 + -29285, // 1175 206.54 3.604855 + -29465, // 1176 206.72 3.607923 + -29645, // 1177 206.89 3.610991 + -29824, // 1178 207.07 3.614059 + -30003, // 1179 207.25 3.617127 + -30181, // 1180 207.42 3.620195 + -30360, // 1181 207.60 3.623263 + -30538, // 1182 207.77 3.626331 + -30715, // 1183 207.95 3.629399 + -30893, // 1184 208.12 3.632467 + -31070, // 1185 208.30 3.635534 + -31247, // 1186 208.48 3.638602 + -31424, // 1187 208.65 3.641670 + -31600, // 1188 208.83 3.644738 + -31776, // 1189 209.00 3.647806 + -31952, // 1190 209.18 3.650874 + -32127, // 1191 209.36 3.653942 + -32302, // 1192 209.53 3.657010 + -32477, // 1193 209.71 3.660078 + -32651, // 1194 209.88 3.663146 + -32826, // 1195 210.06 3.666214 + -32999, // 1196 210.23 3.669282 + -33173, // 1197 210.41 3.672350 + -33346, // 1198 210.59 3.675418 + -33519, // 1199 210.76 3.678486 + -33692, // 1200 210.94 3.681554 + -33864, // 1201 211.11 3.684622 + -34036, // 1202 211.29 3.687690 + -34208, // 1203 211.46 3.690758 + -34379, // 1204 211.64 3.693826 + -34550, // 1205 211.82 3.696894 + -34721, // 1206 211.99 3.699962 + -34891, // 1207 212.17 3.703030 + -35061, // 1208 212.34 3.706098 + -35231, // 1209 212.52 3.709166 + -35400, // 1210 212.70 3.712234 + -35569, // 1211 212.87 3.715301 + -35738, // 1212 213.05 3.718369 + -35906, // 1213 213.22 3.721437 + -36074, // 1214 213.40 3.724505 + -36242, // 1215 213.57 3.727573 + -36409, // 1216 213.75 3.730641 + -36576, // 1217 213.93 3.733709 + -36743, // 1218 214.10 3.736777 + -36909, // 1219 214.28 3.739845 + -37075, // 1220 214.45 3.742913 + -37241, // 1221 214.63 3.745981 + -37406, // 1222 214.80 3.749049 + -37571, // 1223 214.98 3.752117 + -37736, // 1224 215.16 3.755185 + -37900, // 1225 215.33 3.758253 + -38064, // 1226 215.51 3.761321 + -38227, // 1227 215.68 3.764389 + -38390, // 1228 215.86 3.767457 + -38553, // 1229 216.04 3.770525 + -38716, // 1230 216.21 3.773593 + -38878, // 1231 216.39 3.776661 + -39039, // 1232 216.56 3.779729 + -39201, // 1233 216.74 3.782797 + -39362, // 1234 216.91 3.785865 + -39522, // 1235 217.09 3.788933 + -39682, // 1236 217.27 3.792001 + -39842, // 1237 217.44 3.795068 + -40002, // 1238 217.62 3.798136 + -40161, // 1239 217.79 3.801204 + -40319, // 1240 217.97 3.804272 + -40478, // 1241 218.14 3.807340 + -40636, // 1242 218.32 3.810408 + -40793, // 1243 218.50 3.813476 + -40950, // 1244 218.67 3.816544 + -41107, // 1245 218.85 3.819612 + -41263, // 1246 219.02 3.822680 + -41419, // 1247 219.20 3.825748 + -41575, // 1248 219.38 3.828816 + -41730, // 1249 219.55 3.831884 + -41885, // 1250 219.73 3.834952 + -42040, // 1251 219.90 3.838020 + -42194, // 1252 220.08 3.841088 + -42347, // 1253 220.25 3.844156 + -42501, // 1254 220.43 3.847224 + -42653, // 1255 220.61 3.850292 + -42806, // 1256 220.78 3.853360 + -42958, // 1257 220.96 3.856428 + -43110, // 1258 221.13 3.859496 + -43261, // 1259 221.31 3.862564 + -43412, // 1260 221.48 3.865632 + -43562, // 1261 221.66 3.868700 + -43712, // 1262 221.84 3.871768 + -43862, // 1263 222.01 3.874835 + -44011, // 1264 222.19 3.877903 + -44160, // 1265 222.36 3.880971 + -44308, // 1266 222.54 3.884039 + -44456, // 1267 222.71 3.887107 + -44603, // 1268 222.89 3.890175 + -44750, // 1269 223.07 3.893243 + -44897, // 1270 223.24 3.896311 + -45043, // 1271 223.42 3.899379 + -45189, // 1272 223.59 3.902447 + -45335, // 1273 223.77 3.905515 + -45480, // 1274 223.95 3.908583 + -45624, // 1275 224.12 3.911651 + -45768, // 1276 224.30 3.914719 + -45912, // 1277 224.47 3.917787 + -46055, // 1278 224.65 3.920855 + -46198, // 1279 224.82 3.923923 + -46340, // 1280 225.00 3.926991 + -46482, // 1281 225.18 3.930059 + -46624, // 1282 225.35 3.933127 + -46765, // 1283 225.53 3.936195 + -46906, // 1284 225.70 3.939263 + -47046, // 1285 225.88 3.942331 + -47186, // 1286 226.05 3.945399 + -47325, // 1287 226.23 3.948467 + -47464, // 1288 226.41 3.951535 + -47602, // 1289 226.58 3.954602 + -47740, // 1290 226.76 3.957670 + -47878, // 1291 226.93 3.960738 + -48015, // 1292 227.11 3.963806 + -48151, // 1293 227.29 3.966874 + -48288, // 1294 227.46 3.969942 + -48423, // 1295 227.64 3.973010 + -48558, // 1296 227.81 3.976078 + -48693, // 1297 227.99 3.979146 + -48828, // 1298 228.16 3.982214 + -48961, // 1299 228.34 3.985282 + -49095, // 1300 228.52 3.988350 + -49228, // 1301 228.69 3.991418 + -49360, // 1302 228.87 3.994486 + -49492, // 1303 229.04 3.997554 + -49624, // 1304 229.22 4.000622 + -49755, // 1305 229.39 4.003690 + -49886, // 1306 229.57 4.006758 + -50016, // 1307 229.75 4.009826 + -50146, // 1308 229.92 4.012894 + -50275, // 1309 230.10 4.015962 + -50403, // 1310 230.27 4.019030 + -50532, // 1311 230.45 4.022098 + -50660, // 1312 230.62 4.025166 + -50787, // 1313 230.80 4.028234 + -50914, // 1314 230.98 4.031302 + -51040, // 1315 231.15 4.034369 + -51166, // 1316 231.33 4.037437 + -51291, // 1317 231.50 4.040505 + -51416, // 1318 231.68 4.043573 + -51541, // 1319 231.86 4.046641 + -51665, // 1320 232.03 4.049709 + -51788, // 1321 232.21 4.052777 + -51911, // 1322 232.38 4.055845 + -52033, // 1323 232.56 4.058913 + -52155, // 1324 232.73 4.061981 + -52277, // 1325 232.91 4.065049 + -52398, // 1326 233.09 4.068117 + -52518, // 1327 233.26 4.071185 + -52639, // 1328 233.44 4.074253 + -52758, // 1329 233.61 4.077321 + -52877, // 1330 233.79 4.080389 + -52996, // 1331 233.96 4.083457 + -53114, // 1332 234.14 4.086525 + -53231, // 1333 234.32 4.089593 + -53348, // 1334 234.49 4.092661 + -53465, // 1335 234.67 4.095729 + -53581, // 1336 234.84 4.098797 + -53696, // 1337 235.02 4.101865 + -53811, // 1338 235.20 4.104933 + -53926, // 1339 235.37 4.108001 + -54040, // 1340 235.55 4.111069 + -54153, // 1341 235.72 4.114136 + -54266, // 1342 235.90 4.117204 + -54379, // 1343 236.07 4.120272 + -54491, // 1344 236.25 4.123340 + -54602, // 1345 236.43 4.126408 + -54713, // 1346 236.60 4.129476 + -54823, // 1347 236.78 4.132544 + -54933, // 1348 236.95 4.135612 + -55043, // 1349 237.13 4.138680 + -55152, // 1350 237.30 4.141748 + -55260, // 1351 237.48 4.144816 + -55368, // 1352 237.66 4.147884 + -55475, // 1353 237.83 4.150952 + -55582, // 1354 238.01 4.154020 + -55688, // 1355 238.18 4.157088 + -55794, // 1356 238.36 4.160156 + -55899, // 1357 238.54 4.163224 + -56004, // 1358 238.71 4.166292 + -56108, // 1359 238.89 4.169360 + -56212, // 1360 239.06 4.172428 + -56315, // 1361 239.24 4.175496 + -56417, // 1362 239.41 4.178564 + -56519, // 1363 239.59 4.181632 + -56621, // 1364 239.77 4.184700 + -56722, // 1365 239.94 4.187768 + -56822, // 1366 240.12 4.190836 + -56922, // 1367 240.29 4.193903 + -57022, // 1368 240.47 4.196971 + -57120, // 1369 240.64 4.200039 + -57219, // 1370 240.82 4.203107 + -57316, // 1371 241.00 4.206175 + -57414, // 1372 241.17 4.209243 + -57510, // 1373 241.35 4.212311 + -57606, // 1374 241.52 4.215379 + -57702, // 1375 241.70 4.218447 + -57797, // 1376 241.88 4.221515 + -57892, // 1377 242.05 4.224583 + -57986, // 1378 242.23 4.227651 + -58079, // 1379 242.40 4.230719 + -58172, // 1380 242.58 4.233787 + -58264, // 1381 242.75 4.236855 + -58356, // 1382 242.93 4.239923 + -58447, // 1383 243.11 4.242991 + -58538, // 1384 243.28 4.246059 + -58628, // 1385 243.46 4.249127 + -58718, // 1386 243.63 4.252195 + -58807, // 1387 243.81 4.255263 + -58895, // 1388 243.98 4.258331 + -58983, // 1389 244.16 4.261399 + -59070, // 1390 244.34 4.264467 + -59157, // 1391 244.51 4.267535 + -59243, // 1392 244.69 4.270603 + -59329, // 1393 244.86 4.273670 + -59414, // 1394 245.04 4.276738 + -59499, // 1395 245.21 4.279806 + -59583, // 1396 245.39 4.282874 + -59666, // 1397 245.57 4.285942 + -59749, // 1398 245.74 4.289010 + -59831, // 1399 245.92 4.292078 + -59913, // 1400 246.09 4.295146 + -59994, // 1401 246.27 4.298214 + -60075, // 1402 246.45 4.301282 + -60155, // 1403 246.62 4.304350 + -60235, // 1404 246.80 4.307418 + -60313, // 1405 246.97 4.310486 + -60392, // 1406 247.15 4.313554 + -60470, // 1407 247.32 4.316622 + -60547, // 1408 247.50 4.319690 + -60624, // 1409 247.68 4.322758 + -60700, // 1410 247.85 4.325826 + -60775, // 1411 248.03 4.328894 + -60850, // 1412 248.20 4.331962 + -60924, // 1413 248.38 4.335030 + -60998, // 1414 248.55 4.338098 + -61071, // 1415 248.73 4.341166 + -61144, // 1416 248.91 4.344234 + -61216, // 1417 249.08 4.347302 + -61288, // 1418 249.26 4.350370 + -61359, // 1419 249.43 4.353437 + -61429, // 1420 249.61 4.356505 + -61499, // 1421 249.79 4.359573 + -61568, // 1422 249.96 4.362641 + -61637, // 1423 250.14 4.365709 + -61705, // 1424 250.31 4.368777 + -61772, // 1425 250.49 4.371845 + -61839, // 1426 250.66 4.374913 + -61905, // 1427 250.84 4.377981 + -61971, // 1428 251.02 4.381049 + -62036, // 1429 251.19 4.384117 + -62100, // 1430 251.37 4.387185 + -62164, // 1431 251.54 4.390253 + -62228, // 1432 251.72 4.393321 + -62291, // 1433 251.89 4.396389 + -62353, // 1434 252.07 4.399457 + -62414, // 1435 252.25 4.402525 + -62475, // 1436 252.42 4.405593 + -62536, // 1437 252.60 4.408661 + -62596, // 1438 252.77 4.411729 + -62655, // 1439 252.95 4.414797 + -62714, // 1440 253.12 4.417865 + -62772, // 1441 253.30 4.420933 + -62829, // 1442 253.48 4.424001 + -62886, // 1443 253.65 4.427069 + -62942, // 1444 253.83 4.430137 + -62998, // 1445 254.00 4.433204 + -63053, // 1446 254.18 4.436272 + -63108, // 1447 254.36 4.439340 + -63162, // 1448 254.53 4.442408 + -63215, // 1449 254.71 4.445476 + -63268, // 1450 254.88 4.448544 + -63320, // 1451 255.06 4.451612 + -63371, // 1452 255.23 4.454680 + -63422, // 1453 255.41 4.457748 + -63473, // 1454 255.59 4.460816 + -63522, // 1455 255.76 4.463884 + -63571, // 1456 255.94 4.466952 + -63620, // 1457 256.11 4.470020 + -63668, // 1458 256.29 4.473088 + -63715, // 1459 256.46 4.476156 + -63762, // 1460 256.64 4.479224 + -63808, // 1461 256.82 4.482292 + -63854, // 1462 256.99 4.485360 + -63899, // 1463 257.17 4.488428 + -63943, // 1464 257.34 4.491496 + -63987, // 1465 257.52 4.494564 + -64030, // 1466 257.70 4.497632 + -64073, // 1467 257.87 4.500700 + -64115, // 1468 258.05 4.503768 + -64156, // 1469 258.22 4.506836 + -64197, // 1470 258.40 4.509904 + -64237, // 1471 258.57 4.512971 + -64276, // 1472 258.75 4.516039 + -64315, // 1473 258.93 4.519107 + -64353, // 1474 259.10 4.522175 + -64391, // 1475 259.28 4.525243 + -64428, // 1476 259.45 4.528311 + -64465, // 1477 259.63 4.531379 + -64501, // 1478 259.80 4.534447 + -64536, // 1479 259.98 4.537515 + -64571, // 1480 260.16 4.540583 + -64605, // 1481 260.33 4.543651 + -64638, // 1482 260.51 4.546719 + -64671, // 1483 260.68 4.549787 + -64703, // 1484 260.86 4.552855 + -64735, // 1485 261.04 4.555923 + -64766, // 1486 261.21 4.558991 + -64796, // 1487 261.39 4.562059 + -64826, // 1488 261.56 4.565127 + -64855, // 1489 261.74 4.568195 + -64884, // 1490 261.91 4.571263 + -64912, // 1491 262.09 4.574331 + -64939, // 1492 262.27 4.577399 + -64966, // 1493 262.44 4.580467 + -64992, // 1494 262.62 4.583535 + -65018, // 1495 262.79 4.586603 + -65043, // 1496 262.97 4.589671 + -65067, // 1497 263.14 4.592738 + -65091, // 1498 263.32 4.595806 + -65114, // 1499 263.50 4.598874 + -65136, // 1500 263.67 4.601942 + -65158, // 1501 263.85 4.605010 + -65179, // 1502 264.02 4.608078 + -65200, // 1503 264.20 4.611146 + -65220, // 1504 264.38 4.614214 + -65239, // 1505 264.55 4.617282 + -65258, // 1506 264.73 4.620350 + -65276, // 1507 264.90 4.623418 + -65294, // 1508 265.08 4.626486 + -65311, // 1509 265.25 4.629554 + -65327, // 1510 265.43 4.632622 + -65343, // 1511 265.61 4.635690 + -65358, // 1512 265.78 4.638758 + -65372, // 1513 265.96 4.641826 + -65386, // 1514 266.13 4.644894 + -65400, // 1515 266.31 4.647962 + -65412, // 1516 266.48 4.651030 + -65424, // 1517 266.66 4.654098 + -65436, // 1518 266.84 4.657166 + -65446, // 1519 267.01 4.660234 + -65457, // 1520 267.19 4.663302 + -65466, // 1521 267.36 4.666370 + -65475, // 1522 267.54 4.669438 + -65483, // 1523 267.71 4.672505 + -65491, // 1524 267.89 4.675573 + -65498, // 1525 268.07 4.678641 + -65505, // 1526 268.24 4.681709 + -65511, // 1527 268.42 4.684777 + -65516, // 1528 268.59 4.687845 + -65520, // 1529 268.77 4.690913 + -65524, // 1530 268.95 4.693981 + -65528, // 1531 269.12 4.697049 + -65531, // 1532 269.30 4.700117 + -65533, // 1533 269.47 4.703185 + -65534, // 1534 269.65 4.706253 + -65535, // 1535 269.82 4.709321 + -65536, // 1536 270.00 4.712389 + -65535, // 1537 270.18 4.715457 + -65534, // 1538 270.35 4.718525 + -65533, // 1539 270.53 4.721593 + -65531, // 1540 270.70 4.724661 + -65528, // 1541 270.88 4.727729 + -65524, // 1542 271.05 4.730797 + -65520, // 1543 271.23 4.733865 + -65516, // 1544 271.41 4.736933 + -65511, // 1545 271.58 4.740001 + -65505, // 1546 271.76 4.743069 + -65498, // 1547 271.93 4.746137 + -65491, // 1548 272.11 4.749205 + -65483, // 1549 272.29 4.752272 + -65475, // 1550 272.46 4.755340 + -65466, // 1551 272.64 4.758408 + -65457, // 1552 272.81 4.761476 + -65446, // 1553 272.99 4.764544 + -65436, // 1554 273.16 4.767612 + -65424, // 1555 273.34 4.770680 + -65412, // 1556 273.52 4.773748 + -65400, // 1557 273.69 4.776816 + -65386, // 1558 273.87 4.779884 + -65372, // 1559 274.04 4.782952 + -65358, // 1560 274.22 4.786020 + -65343, // 1561 274.39 4.789088 + -65327, // 1562 274.57 4.792156 + -65311, // 1563 274.75 4.795224 + -65294, // 1564 274.92 4.798292 + -65276, // 1565 275.10 4.801360 + -65258, // 1566 275.27 4.804428 + -65239, // 1567 275.45 4.807496 + -65220, // 1568 275.62 4.810564 + -65200, // 1569 275.80 4.813632 + -65179, // 1570 275.98 4.816700 + -65158, // 1571 276.15 4.819768 + -65136, // 1572 276.33 4.822836 + -65114, // 1573 276.50 4.825904 + -65091, // 1574 276.68 4.828972 + -65067, // 1575 276.86 4.832039 + -65043, // 1576 277.03 4.835107 + -65018, // 1577 277.21 4.838175 + -64992, // 1578 277.38 4.841243 + -64966, // 1579 277.56 4.844311 + -64939, // 1580 277.73 4.847379 + -64912, // 1581 277.91 4.850447 + -64884, // 1582 278.09 4.853515 + -64855, // 1583 278.26 4.856583 + -64826, // 1584 278.44 4.859651 + -64796, // 1585 278.61 4.862719 + -64766, // 1586 278.79 4.865787 + -64735, // 1587 278.96 4.868855 + -64703, // 1588 279.14 4.871923 + -64671, // 1589 279.32 4.874991 + -64638, // 1590 279.49 4.878059 + -64605, // 1591 279.67 4.881127 + -64571, // 1592 279.84 4.884195 + -64536, // 1593 280.02 4.887263 + -64501, // 1594 280.20 4.890331 + -64465, // 1595 280.37 4.893399 + -64428, // 1596 280.55 4.896467 + -64391, // 1597 280.72 4.899535 + -64353, // 1598 280.90 4.902603 + -64315, // 1599 281.07 4.905671 + -64276, // 1600 281.25 4.908739 + -64237, // 1601 281.43 4.911806 + -64197, // 1602 281.60 4.914874 + -64156, // 1603 281.78 4.917942 + -64115, // 1604 281.95 4.921010 + -64073, // 1605 282.13 4.924078 + -64030, // 1606 282.30 4.927146 + -63987, // 1607 282.48 4.930214 + -63943, // 1608 282.66 4.933282 + -63899, // 1609 282.83 4.936350 + -63854, // 1610 283.01 4.939418 + -63808, // 1611 283.18 4.942486 + -63762, // 1612 283.36 4.945554 + -63715, // 1613 283.54 4.948622 + -63668, // 1614 283.71 4.951690 + -63620, // 1615 283.89 4.954758 + -63571, // 1616 284.06 4.957826 + -63522, // 1617 284.24 4.960894 + -63473, // 1618 284.41 4.963962 + -63422, // 1619 284.59 4.967030 + -63371, // 1620 284.77 4.970098 + -63320, // 1621 284.94 4.973166 + -63268, // 1622 285.12 4.976234 + -63215, // 1623 285.29 4.979302 + -63162, // 1624 285.47 4.982370 + -63108, // 1625 285.64 4.985438 + -63053, // 1626 285.82 4.988506 + -62998, // 1627 286.00 4.991573 + -62942, // 1628 286.17 4.994641 + -62886, // 1629 286.35 4.997709 + -62829, // 1630 286.52 5.000777 + -62772, // 1631 286.70 5.003845 + -62714, // 1632 286.88 5.006913 + -62655, // 1633 287.05 5.009981 + -62596, // 1634 287.23 5.013049 + -62536, // 1635 287.40 5.016117 + -62475, // 1636 287.58 5.019185 + -62414, // 1637 287.75 5.022253 + -62353, // 1638 287.93 5.025321 + -62291, // 1639 288.11 5.028389 + -62228, // 1640 288.28 5.031457 + -62164, // 1641 288.46 5.034525 + -62100, // 1642 288.63 5.037593 + -62036, // 1643 288.81 5.040661 + -61971, // 1644 288.98 5.043729 + -61905, // 1645 289.16 5.046797 + -61839, // 1646 289.34 5.049865 + -61772, // 1647 289.51 5.052933 + -61705, // 1648 289.69 5.056001 + -61637, // 1649 289.86 5.059069 + -61568, // 1650 290.04 5.062137 + -61499, // 1651 290.21 5.065205 + -61429, // 1652 290.39 5.068273 + -61359, // 1653 290.57 5.071340 + -61288, // 1654 290.74 5.074408 + -61216, // 1655 290.92 5.077476 + -61144, // 1656 291.09 5.080544 + -61071, // 1657 291.27 5.083612 + -60998, // 1658 291.45 5.086680 + -60924, // 1659 291.62 5.089748 + -60850, // 1660 291.80 5.092816 + -60775, // 1661 291.97 5.095884 + -60700, // 1662 292.15 5.098952 + -60624, // 1663 292.32 5.102020 + -60547, // 1664 292.50 5.105088 + -60470, // 1665 292.68 5.108156 + -60392, // 1666 292.85 5.111224 + -60313, // 1667 293.03 5.114292 + -60235, // 1668 293.20 5.117360 + -60155, // 1669 293.38 5.120428 + -60075, // 1670 293.55 5.123496 + -59994, // 1671 293.73 5.126564 + -59913, // 1672 293.91 5.129632 + -59831, // 1673 294.08 5.132700 + -59749, // 1674 294.26 5.135768 + -59666, // 1675 294.43 5.138836 + -59583, // 1676 294.61 5.141904 + -59499, // 1677 294.79 5.144972 + -59414, // 1678 294.96 5.148040 + -59329, // 1679 295.14 5.151107 + -59243, // 1680 295.31 5.154175 + -59157, // 1681 295.49 5.157243 + -59070, // 1682 295.66 5.160311 + -58983, // 1683 295.84 5.163379 + -58895, // 1684 296.02 5.166447 + -58807, // 1685 296.19 5.169515 + -58718, // 1686 296.37 5.172583 + -58628, // 1687 296.54 5.175651 + -58538, // 1688 296.72 5.178719 + -58447, // 1689 296.89 5.181787 + -58356, // 1690 297.07 5.184855 + -58264, // 1691 297.25 5.187923 + -58172, // 1692 297.42 5.190991 + -58079, // 1693 297.60 5.194059 + -57986, // 1694 297.77 5.197127 + -57892, // 1695 297.95 5.200195 + -57797, // 1696 298.12 5.203263 + -57702, // 1697 298.30 5.206331 + -57606, // 1698 298.48 5.209399 + -57510, // 1699 298.65 5.212467 + -57414, // 1700 298.83 5.215535 + -57316, // 1701 299.00 5.218603 + -57219, // 1702 299.18 5.221671 + -57120, // 1703 299.36 5.224739 + -57022, // 1704 299.53 5.227807 + -56922, // 1705 299.71 5.230874 + -56822, // 1706 299.88 5.233942 + -56722, // 1707 300.06 5.237010 + -56621, // 1708 300.23 5.240078 + -56519, // 1709 300.41 5.243146 + -56417, // 1710 300.59 5.246214 + -56315, // 1711 300.76 5.249282 + -56212, // 1712 300.94 5.252350 + -56108, // 1713 301.11 5.255418 + -56004, // 1714 301.29 5.258486 + -55899, // 1715 301.46 5.261554 + -55794, // 1716 301.64 5.264622 + -55688, // 1717 301.82 5.267690 + -55582, // 1718 301.99 5.270758 + -55475, // 1719 302.17 5.273826 + -55368, // 1720 302.34 5.276894 + -55260, // 1721 302.52 5.279962 + -55152, // 1722 302.70 5.283030 + -55043, // 1723 302.87 5.286098 + -54933, // 1724 303.05 5.289166 + -54823, // 1725 303.22 5.292234 + -54713, // 1726 303.40 5.295302 + -54602, // 1727 303.57 5.298370 + -54491, // 1728 303.75 5.301438 + -54379, // 1729 303.93 5.304506 + -54266, // 1730 304.10 5.307574 + -54153, // 1731 304.28 5.310641 + -54040, // 1732 304.45 5.313709 + -53926, // 1733 304.63 5.316777 + -53811, // 1734 304.80 5.319845 + -53696, // 1735 304.98 5.322913 + -53581, // 1736 305.16 5.325981 + -53465, // 1737 305.33 5.329049 + -53348, // 1738 305.51 5.332117 + -53231, // 1739 305.68 5.335185 + -53114, // 1740 305.86 5.338253 + -52996, // 1741 306.04 5.341321 + -52877, // 1742 306.21 5.344389 + -52758, // 1743 306.39 5.347457 + -52639, // 1744 306.56 5.350525 + -52518, // 1745 306.74 5.353593 + -52398, // 1746 306.91 5.356661 + -52277, // 1747 307.09 5.359729 + -52155, // 1748 307.27 5.362797 + -52033, // 1749 307.44 5.365865 + -51911, // 1750 307.62 5.368933 + -51788, // 1751 307.79 5.372001 + -51665, // 1752 307.97 5.375069 + -51541, // 1753 308.14 5.378137 + -51416, // 1754 308.32 5.381205 + -51291, // 1755 308.50 5.384273 + -51166, // 1756 308.67 5.387341 + -51040, // 1757 308.85 5.390408 + -50914, // 1758 309.02 5.393476 + -50787, // 1759 309.20 5.396544 + -50660, // 1760 309.38 5.399612 + -50532, // 1761 309.55 5.402680 + -50403, // 1762 309.73 5.405748 + -50275, // 1763 309.90 5.408816 + -50146, // 1764 310.08 5.411884 + -50016, // 1765 310.25 5.414952 + -49886, // 1766 310.43 5.418020 + -49755, // 1767 310.61 5.421088 + -49624, // 1768 310.78 5.424156 + -49492, // 1769 310.96 5.427224 + -49360, // 1770 311.13 5.430292 + -49228, // 1771 311.31 5.433360 + -49095, // 1772 311.48 5.436428 + -48961, // 1773 311.66 5.439496 + -48828, // 1774 311.84 5.442564 + -48693, // 1775 312.01 5.445632 + -48558, // 1776 312.19 5.448700 + -48423, // 1777 312.36 5.451768 + -48288, // 1778 312.54 5.454836 + -48151, // 1779 312.71 5.457904 + -48015, // 1780 312.89 5.460972 + -47878, // 1781 313.07 5.464040 + -47740, // 1782 313.24 5.467108 + -47602, // 1783 313.42 5.470175 + -47464, // 1784 313.59 5.473243 + -47325, // 1785 313.77 5.476311 + -47186, // 1786 313.95 5.479379 + -47046, // 1787 314.12 5.482447 + -46906, // 1788 314.30 5.485515 + -46765, // 1789 314.47 5.488583 + -46624, // 1790 314.65 5.491651 + -46482, // 1791 314.82 5.494719 + -46340, // 1792 315.00 5.497787 + -46198, // 1793 315.18 5.500855 + -46055, // 1794 315.35 5.503923 + -45912, // 1795 315.53 5.506991 + -45768, // 1796 315.70 5.510059 + -45624, // 1797 315.88 5.513127 + -45480, // 1798 316.05 5.516195 + -45335, // 1799 316.23 5.519263 + -45189, // 1800 316.41 5.522331 + -45043, // 1801 316.58 5.525399 + -44897, // 1802 316.76 5.528467 + -44750, // 1803 316.93 5.531535 + -44603, // 1804 317.11 5.534603 + -44456, // 1805 317.29 5.537671 + -44308, // 1806 317.46 5.540739 + -44160, // 1807 317.64 5.543807 + -44011, // 1808 317.81 5.546875 + -43862, // 1809 317.99 5.549942 + -43712, // 1810 318.16 5.553010 + -43562, // 1811 318.34 5.556078 + -43412, // 1812 318.52 5.559146 + -43261, // 1813 318.69 5.562214 + -43110, // 1814 318.87 5.565282 + -42958, // 1815 319.04 5.568350 + -42806, // 1816 319.22 5.571418 + -42653, // 1817 319.39 5.574486 + -42501, // 1818 319.57 5.577554 + -42347, // 1819 319.75 5.580622 + -42194, // 1820 319.92 5.583690 + -42040, // 1821 320.10 5.586758 + -41885, // 1822 320.27 5.589826 + -41730, // 1823 320.45 5.592894 + -41575, // 1824 320.62 5.595962 + -41419, // 1825 320.80 5.599030 + -41263, // 1826 320.98 5.602098 + -41107, // 1827 321.15 5.605166 + -40950, // 1828 321.33 5.608234 + -40793, // 1829 321.50 5.611302 + -40636, // 1830 321.68 5.614370 + -40478, // 1831 321.86 5.617438 + -40319, // 1832 322.03 5.620506 + -40161, // 1833 322.21 5.623574 + -40002, // 1834 322.38 5.626642 + -39842, // 1835 322.56 5.629709 + -39682, // 1836 322.73 5.632777 + -39522, // 1837 322.91 5.635845 + -39362, // 1838 323.09 5.638913 + -39201, // 1839 323.26 5.641981 + -39039, // 1840 323.44 5.645049 + -38878, // 1841 323.61 5.648117 + -38716, // 1842 323.79 5.651185 + -38553, // 1843 323.96 5.654253 + -38390, // 1844 324.14 5.657321 + -38227, // 1845 324.32 5.660389 + -38064, // 1846 324.49 5.663457 + -37900, // 1847 324.67 5.666525 + -37736, // 1848 324.84 5.669593 + -37571, // 1849 325.02 5.672661 + -37406, // 1850 325.20 5.675729 + -37241, // 1851 325.37 5.678797 + -37075, // 1852 325.55 5.681865 + -36909, // 1853 325.72 5.684933 + -36743, // 1854 325.90 5.688001 + -36576, // 1855 326.07 5.691069 + -36409, // 1856 326.25 5.694137 + -36242, // 1857 326.43 5.697205 + -36074, // 1858 326.60 5.700273 + -35906, // 1859 326.78 5.703341 + -35738, // 1860 326.95 5.706409 + -35569, // 1861 327.13 5.709476 + -35400, // 1862 327.30 5.712544 + -35231, // 1863 327.48 5.715612 + -35061, // 1864 327.66 5.718680 + -34891, // 1865 327.83 5.721748 + -34721, // 1866 328.01 5.724816 + -34550, // 1867 328.18 5.727884 + -34379, // 1868 328.36 5.730952 + -34208, // 1869 328.54 5.734020 + -34036, // 1870 328.71 5.737088 + -33864, // 1871 328.89 5.740156 + -33692, // 1872 329.06 5.743224 + -33519, // 1873 329.24 5.746292 + -33346, // 1874 329.41 5.749360 + -33173, // 1875 329.59 5.752428 + -32999, // 1876 329.77 5.755496 + -32826, // 1877 329.94 5.758564 + -32651, // 1878 330.12 5.761632 + -32477, // 1879 330.29 5.764700 + -32302, // 1880 330.47 5.767768 + -32127, // 1881 330.64 5.770836 + -31952, // 1882 330.82 5.773904 + -31776, // 1883 331.00 5.776972 + -31600, // 1884 331.17 5.780040 + -31424, // 1885 331.35 5.783108 + -31247, // 1886 331.52 5.786176 + -31070, // 1887 331.70 5.789243 + -30893, // 1888 331.88 5.792311 + -30715, // 1889 332.05 5.795379 + -30538, // 1890 332.23 5.798447 + -30360, // 1891 332.40 5.801515 + -30181, // 1892 332.58 5.804583 + -30003, // 1893 332.75 5.807651 + -29824, // 1894 332.93 5.810719 + -29645, // 1895 333.11 5.813787 + -29465, // 1896 333.28 5.816855 + -29285, // 1897 333.46 5.819923 + -29105, // 1898 333.63 5.822991 + -28925, // 1899 333.81 5.826059 + -28745, // 1900 333.98 5.829127 + -28564, // 1901 334.16 5.832195 + -28383, // 1902 334.34 5.835263 + -28201, // 1903 334.51 5.838331 + -28020, // 1904 334.69 5.841399 + -27838, // 1905 334.86 5.844467 + -27656, // 1906 335.04 5.847535 + -27473, // 1907 335.21 5.850603 + -27291, // 1908 335.39 5.853671 + -27108, // 1909 335.57 5.856739 + -26925, // 1910 335.74 5.859807 + -26741, // 1911 335.92 5.862875 + -26557, // 1912 336.09 5.865943 + -26373, // 1913 336.27 5.869010 + -26189, // 1914 336.45 5.872078 + -26005, // 1915 336.62 5.875146 + -25820, // 1916 336.80 5.878214 + -25635, // 1917 336.97 5.881282 + -25450, // 1918 337.15 5.884350 + -25265, // 1919 337.32 5.887418 + -25079, // 1920 337.50 5.890486 + -24893, // 1921 337.68 5.893554 + -24707, // 1922 337.85 5.896622 + -24521, // 1923 338.03 5.899690 + -24334, // 1924 338.20 5.902758 + -24147, // 1925 338.38 5.905826 + -23960, // 1926 338.55 5.908894 + -23773, // 1927 338.73 5.911962 + -23586, // 1928 338.91 5.915030 + -23398, // 1929 339.08 5.918098 + -23210, // 1930 339.26 5.921166 + -23022, // 1931 339.43 5.924234 + -22833, // 1932 339.61 5.927302 + -22645, // 1933 339.79 5.930370 + -22456, // 1934 339.96 5.933438 + -22267, // 1935 340.14 5.936506 + -22078, // 1936 340.31 5.939574 + -21889, // 1937 340.49 5.942642 + -21699, // 1938 340.66 5.945710 + -21509, // 1939 340.84 5.948777 + -21319, // 1940 341.02 5.951845 + -21129, // 1941 341.19 5.954913 + -20938, // 1942 341.37 5.957981 + -20748, // 1943 341.54 5.961049 + -20557, // 1944 341.72 5.964117 + -20366, // 1945 341.89 5.967185 + -20175, // 1946 342.07 5.970253 + -19983, // 1947 342.25 5.973321 + -19792, // 1948 342.42 5.976389 + -19600, // 1949 342.60 5.979457 + -19408, // 1950 342.77 5.982525 + -19216, // 1951 342.95 5.985593 + -19024, // 1952 343.12 5.988661 + -18831, // 1953 343.30 5.991729 + -18638, // 1954 343.48 5.994797 + -18446, // 1955 343.65 5.997865 + -18253, // 1956 343.83 6.000933 + -18059, // 1957 344.00 6.004001 + -17866, // 1958 344.18 6.007069 + -17672, // 1959 344.36 6.010137 + -17479, // 1960 344.53 6.013205 + -17285, // 1961 344.71 6.016273 + -17091, // 1962 344.88 6.019341 + -16897, // 1963 345.06 6.022409 + -16702, // 1964 345.23 6.025477 + -16508, // 1965 345.41 6.028544 + -16313, // 1966 345.59 6.031612 + -16118, // 1967 345.76 6.034680 + -15923, // 1968 345.94 6.037748 + -15728, // 1969 346.11 6.040816 + -15533, // 1970 346.29 6.043884 + -15338, // 1971 346.46 6.046952 + -15142, // 1972 346.64 6.050020 + -14946, // 1973 346.82 6.053088 + -14751, // 1974 346.99 6.056156 + -14555, // 1975 347.17 6.059224 + -14359, // 1976 347.34 6.062292 + -14162, // 1977 347.52 6.065360 + -13966, // 1978 347.70 6.068428 + -13769, // 1979 347.87 6.071496 + -13573, // 1980 348.05 6.074564 + -13376, // 1981 348.22 6.077632 + -13179, // 1982 348.40 6.080700 + -12982, // 1983 348.57 6.083768 + -12785, // 1984 348.75 6.086836 + -12588, // 1985 348.93 6.089904 + -12390, // 1986 349.10 6.092972 + -12193, // 1987 349.28 6.096040 + -11995, // 1988 349.45 6.099108 + -11797, // 1989 349.63 6.102176 + -11600, // 1990 349.80 6.105244 + -11402, // 1991 349.98 6.108311 + -11204, // 1992 350.16 6.111379 + -11006, // 1993 350.33 6.114447 + -10807, // 1994 350.51 6.117515 + -10609, // 1995 350.68 6.120583 + -10410, // 1996 350.86 6.123651 + -10212, // 1997 351.04 6.126719 + -10013, // 1998 351.21 6.129787 + -9814, // 1999 351.39 6.132855 + -9616, // 2000 351.56 6.135923 + -9417, // 2001 351.74 6.138991 + -9218, // 2002 351.91 6.142059 + -9019, // 2003 352.09 6.145127 + -8819, // 2004 352.27 6.148195 + -8620, // 2005 352.44 6.151263 + -8421, // 2006 352.62 6.154331 + -8221, // 2007 352.79 6.157399 + -8022, // 2008 352.97 6.160467 + -7822, // 2009 353.14 6.163535 + -7623, // 2010 353.32 6.166603 + -7423, // 2011 353.50 6.169671 + -7223, // 2012 353.67 6.172739 + -7023, // 2013 353.85 6.175807 + -6823, // 2014 354.02 6.178875 + -6623, // 2015 354.20 6.181943 + -6423, // 2016 354.38 6.185011 + -6223, // 2017 354.55 6.188078 + -6023, // 2018 354.73 6.191146 + -5823, // 2019 354.90 6.194214 + -5622, // 2020 355.08 6.197282 + -5422, // 2021 355.25 6.200350 + -5222, // 2022 355.43 6.203418 + -5021, // 2023 355.61 6.206486 + -4821, // 2024 355.78 6.209554 + -4620, // 2025 355.96 6.212622 + -4420, // 2026 356.13 6.215690 + -4219, // 2027 356.31 6.218758 + -4018, // 2028 356.48 6.221826 + -3818, // 2029 356.66 6.224894 + -3617, // 2030 356.84 6.227962 + -3416, // 2031 357.01 6.231030 + -3215, // 2032 357.19 6.234098 + -3014, // 2033 357.36 6.237166 + -2814, // 2034 357.54 6.240234 + -2613, // 2035 357.71 6.243302 + -2412, // 2036 357.89 6.246370 + -2211, // 2037 358.07 6.249438 + -2010, // 2038 358.24 6.252506 + -1809, // 2039 358.42 6.255574 + -1608, // 2040 358.59 6.258642 + -1407, // 2041 358.77 6.261710 + -1206, // 2042 358.95 6.264778 + -1005, // 2043 359.12 6.267846 + -804, // 2044 359.30 6.270913 + -603, // 2045 359.47 6.273981 + -402, // 2046 359.65 6.277049 + -201, // 2047 359.82 6.280117 + 0, // 2048 360.00 6.283185 + 201, // 2049 360.18 6.286253 + 402, // 2050 360.35 6.289321 + 603, // 2051 360.53 6.292389 + 804, // 2052 360.70 6.295457 + 1005, // 2053 360.88 6.298525 + 1206, // 2054 361.05 6.301593 + 1407, // 2055 361.23 6.304661 + 1608, // 2056 361.41 6.307729 + 1809, // 2057 361.58 6.310797 + 2010, // 2058 361.76 6.313865 + 2211, // 2059 361.93 6.316933 + 2412, // 2060 362.11 6.320001 + 2613, // 2061 362.29 6.323069 + 2814, // 2062 362.46 6.326137 + 3014, // 2063 362.64 6.329205 + 3215, // 2064 362.81 6.332273 + 3416, // 2065 362.99 6.335341 + 3617, // 2066 363.16 6.338409 + 3818, // 2067 363.34 6.341477 + 4018, // 2068 363.52 6.344545 + 4219, // 2069 363.69 6.347613 + 4420, // 2070 363.87 6.350680 + 4620, // 2071 364.04 6.353748 + 4821, // 2072 364.22 6.356816 + 5021, // 2073 364.39 6.359884 + 5222, // 2074 364.57 6.362952 + 5422, // 2075 364.75 6.366020 + 5622, // 2076 364.92 6.369088 + 5823, // 2077 365.10 6.372156 + 6023, // 2078 365.27 6.375224 + 6223, // 2079 365.45 6.378292 + 6423, // 2080 365.62 6.381360 + 6623, // 2081 365.80 6.384428 + 6823, // 2082 365.98 6.387496 + 7023, // 2083 366.15 6.390564 + 7223, // 2084 366.33 6.393632 + 7423, // 2085 366.50 6.396700 + 7623, // 2086 366.68 6.399768 + 7822, // 2087 366.86 6.402836 + 8022, // 2088 367.03 6.405904 + 8221, // 2089 367.21 6.408972 + 8421, // 2090 367.38 6.412040 + 8620, // 2091 367.56 6.415108 + 8819, // 2092 367.73 6.418176 + 9019, // 2093 367.91 6.421244 + 9218, // 2094 368.09 6.424312 + 9417, // 2095 368.26 6.427380 + 9616, // 2096 368.44 6.430447 + 9814, // 2097 368.61 6.433515 + 10013, // 2098 368.79 6.436583 + 10212, // 2099 368.96 6.439651 + 10410, // 2100 369.14 6.442719 + 10609, // 2101 369.32 6.445787 + 10807, // 2102 369.49 6.448855 + 11006, // 2103 369.67 6.451923 + 11204, // 2104 369.84 6.454991 + 11402, // 2105 370.02 6.458059 + 11600, // 2106 370.20 6.461127 + 11797, // 2107 370.37 6.464195 + 11995, // 2108 370.55 6.467263 + 12193, // 2109 370.72 6.470331 + 12390, // 2110 370.90 6.473399 + 12588, // 2111 371.07 6.476467 + 12785, // 2112 371.25 6.479535 + 12982, // 2113 371.43 6.482603 + 13179, // 2114 371.60 6.485671 + 13376, // 2115 371.78 6.488739 + 13573, // 2116 371.95 6.491807 + 13769, // 2117 372.13 6.494875 + 13966, // 2118 372.30 6.497943 + 14162, // 2119 372.48 6.501011 + 14359, // 2120 372.66 6.504079 + 14555, // 2121 372.83 6.507147 + 14751, // 2122 373.01 6.510214 + 14946, // 2123 373.18 6.513282 + 15142, // 2124 373.36 6.516350 + 15338, // 2125 373.54 6.519418 + 15533, // 2126 373.71 6.522486 + 15728, // 2127 373.89 6.525554 + 15923, // 2128 374.06 6.528622 + 16118, // 2129 374.24 6.531690 + 16313, // 2130 374.41 6.534758 + 16508, // 2131 374.59 6.537826 + 16702, // 2132 374.77 6.540894 + 16897, // 2133 374.94 6.543962 + 17091, // 2134 375.12 6.547030 + 17285, // 2135 375.29 6.550098 + 17479, // 2136 375.47 6.553166 + 17672, // 2137 375.64 6.556234 + 17866, // 2138 375.82 6.559302 + 18059, // 2139 376.00 6.562370 + 18253, // 2140 376.17 6.565438 + 18446, // 2141 376.35 6.568506 + 18638, // 2142 376.52 6.571574 + 18831, // 2143 376.70 6.574642 + 19024, // 2144 376.88 6.577710 + 19216, // 2145 377.05 6.580778 + 19408, // 2146 377.23 6.583846 + 19600, // 2147 377.40 6.586914 + 19792, // 2148 377.58 6.589981 + 19983, // 2149 377.75 6.593049 + 20175, // 2150 377.93 6.596117 + 20366, // 2151 378.11 6.599185 + 20557, // 2152 378.28 6.602253 + 20748, // 2153 378.46 6.605321 + 20938, // 2154 378.63 6.608389 + 21129, // 2155 378.81 6.611457 + 21319, // 2156 378.98 6.614525 + 21509, // 2157 379.16 6.617593 + 21699, // 2158 379.34 6.620661 + 21889, // 2159 379.51 6.623729 + 22078, // 2160 379.69 6.626797 + 22267, // 2161 379.86 6.629865 + 22456, // 2162 380.04 6.632933 + 22645, // 2163 380.21 6.636001 + 22833, // 2164 380.39 6.639069 + 23022, // 2165 380.57 6.642137 + 23210, // 2166 380.74 6.645205 + 23398, // 2167 380.92 6.648273 + 23586, // 2168 381.09 6.651341 + 23773, // 2169 381.27 6.654409 + 23960, // 2170 381.45 6.657477 + 24147, // 2171 381.62 6.660545 + 24334, // 2172 381.80 6.663613 + 24521, // 2173 381.97 6.666681 + 24707, // 2174 382.15 6.669748 + 24893, // 2175 382.32 6.672816 + 25079, // 2176 382.50 6.675884 + 25265, // 2177 382.68 6.678952 + 25450, // 2178 382.85 6.682020 + 25635, // 2179 383.03 6.685088 + 25820, // 2180 383.20 6.688156 + 26005, // 2181 383.38 6.691224 + 26189, // 2182 383.55 6.694292 + 26373, // 2183 383.73 6.697360 + 26557, // 2184 383.91 6.700428 + 26741, // 2185 384.08 6.703496 + 26925, // 2186 384.26 6.706564 + 27108, // 2187 384.43 6.709632 + 27291, // 2188 384.61 6.712700 + 27473, // 2189 384.79 6.715768 + 27656, // 2190 384.96 6.718836 + 27838, // 2191 385.14 6.721904 + 28020, // 2192 385.31 6.724972 + 28201, // 2193 385.49 6.728040 + 28383, // 2194 385.66 6.731108 + 28564, // 2195 385.84 6.734176 + 28745, // 2196 386.02 6.737244 + 28925, // 2197 386.19 6.740312 + 29105, // 2198 386.37 6.743380 + 29285, // 2199 386.54 6.746448 + 29465, // 2200 386.72 6.749515 + 29645, // 2201 386.89 6.752583 + 29824, // 2202 387.07 6.755651 + 30003, // 2203 387.25 6.758719 + 30181, // 2204 387.42 6.761787 + 30360, // 2205 387.60 6.764855 + 30538, // 2206 387.77 6.767923 + 30715, // 2207 387.95 6.770991 + 30893, // 2208 388.12 6.774059 + 31070, // 2209 388.30 6.777127 + 31247, // 2210 388.48 6.780195 + 31424, // 2211 388.65 6.783263 + 31600, // 2212 388.83 6.786331 + 31776, // 2213 389.00 6.789399 + 31952, // 2214 389.18 6.792467 + 32127, // 2215 389.36 6.795535 + 32302, // 2216 389.53 6.798603 + 32477, // 2217 389.71 6.801671 + 32651, // 2218 389.88 6.804739 + 32826, // 2219 390.06 6.807807 + 32999, // 2220 390.23 6.810875 + 33173, // 2221 390.41 6.813943 + 33346, // 2222 390.59 6.817011 + 33519, // 2223 390.76 6.820079 + 33692, // 2224 390.94 6.823147 + 33864, // 2225 391.11 6.826215 + 34036, // 2226 391.29 6.829282 + 34208, // 2227 391.46 6.832350 + 34379, // 2228 391.64 6.835418 + 34550, // 2229 391.82 6.838486 + 34721, // 2230 391.99 6.841554 + 34891, // 2231 392.17 6.844622 + 35061, // 2232 392.34 6.847690 + 35231, // 2233 392.52 6.850758 + 35400, // 2234 392.70 6.853826 + 35569, // 2235 392.87 6.856894 + 35738, // 2236 393.05 6.859962 + 35906, // 2237 393.22 6.863030 + 36074, // 2238 393.40 6.866098 + 36242, // 2239 393.57 6.869166 + 36409, // 2240 393.75 6.872234 + 36576, // 2241 393.93 6.875302 + 36743, // 2242 394.10 6.878370 + 36909, // 2243 394.28 6.881438 + 37075, // 2244 394.45 6.884506 + 37241, // 2245 394.63 6.887574 + 37406, // 2246 394.80 6.890642 + 37571, // 2247 394.98 6.893710 + 37736, // 2248 395.16 6.896778 + 37900, // 2249 395.33 6.899846 + 38064, // 2250 395.51 6.902914 + 38227, // 2251 395.68 6.905982 + 38390, // 2252 395.86 6.909049 + 38553, // 2253 396.04 6.912117 + 38716, // 2254 396.21 6.915185 + 38878, // 2255 396.39 6.918253 + 39039, // 2256 396.56 6.921321 + 39201, // 2257 396.74 6.924389 + 39362, // 2258 396.91 6.927457 + 39522, // 2259 397.09 6.930525 + 39682, // 2260 397.27 6.933593 + 39842, // 2261 397.44 6.936661 + 40002, // 2262 397.62 6.939729 + 40161, // 2263 397.79 6.942797 + 40319, // 2264 397.97 6.945865 + 40478, // 2265 398.14 6.948933 + 40636, // 2266 398.32 6.952001 + 40793, // 2267 398.50 6.955069 + 40950, // 2268 398.67 6.958137 + 41107, // 2269 398.85 6.961205 + 41263, // 2270 399.02 6.964273 + 41419, // 2271 399.20 6.967341 + 41575, // 2272 399.38 6.970409 + 41730, // 2273 399.55 6.973477 + 41885, // 2274 399.73 6.976545 + 42040, // 2275 399.90 6.979613 + 42194, // 2276 400.08 6.982681 + 42347, // 2277 400.25 6.985749 + 42501, // 2278 400.43 6.988816 + 42653, // 2279 400.61 6.991884 + 42806, // 2280 400.78 6.994952 + 42958, // 2281 400.96 6.998020 + 43110, // 2282 401.13 7.001088 + 43261, // 2283 401.31 7.004156 + 43412, // 2284 401.48 7.007224 + 43562, // 2285 401.66 7.010292 + 43712, // 2286 401.84 7.013360 + 43862, // 2287 402.01 7.016428 + 44011, // 2288 402.19 7.019496 + 44160, // 2289 402.36 7.022564 + 44308, // 2290 402.54 7.025632 + 44456, // 2291 402.71 7.028700 + 44603, // 2292 402.89 7.031768 + 44750, // 2293 403.07 7.034836 + 44897, // 2294 403.24 7.037904 + 45043, // 2295 403.42 7.040972 + 45189, // 2296 403.59 7.044040 + 45335, // 2297 403.77 7.047108 + 45480, // 2298 403.95 7.050176 + 45624, // 2299 404.12 7.053244 + 45768, // 2300 404.30 7.056312 + 45912, // 2301 404.47 7.059380 + 46055, // 2302 404.65 7.062448 + 46198, // 2303 404.82 7.065516 + 46340, // 2304 405.00 7.068583 + 46482, // 2305 405.18 7.071651 + 46624, // 2306 405.35 7.074719 + 46765, // 2307 405.53 7.077787 + 46906, // 2308 405.70 7.080855 + 47046, // 2309 405.88 7.083923 + 47186, // 2310 406.05 7.086991 + 47325, // 2311 406.23 7.090059 + 47464, // 2312 406.41 7.093127 + 47602, // 2313 406.58 7.096195 + 47740, // 2314 406.76 7.099263 + 47878, // 2315 406.93 7.102331 + 48015, // 2316 407.11 7.105399 + 48151, // 2317 407.29 7.108467 + 48288, // 2318 407.46 7.111535 + 48423, // 2319 407.64 7.114603 + 48558, // 2320 407.81 7.117671 + 48693, // 2321 407.99 7.120739 + 48828, // 2322 408.16 7.123807 + 48961, // 2323 408.34 7.126875 + 49095, // 2324 408.52 7.129943 + 49228, // 2325 408.69 7.133011 + 49360, // 2326 408.87 7.136079 + 49492, // 2327 409.04 7.139147 + 49624, // 2328 409.22 7.142215 + 49755, // 2329 409.39 7.145283 + 49886, // 2330 409.57 7.148350 + 50016, // 2331 409.75 7.151418 + 50146, // 2332 409.92 7.154486 + 50275, // 2333 410.10 7.157554 + 50403, // 2334 410.27 7.160622 + 50532, // 2335 410.45 7.163690 + 50660, // 2336 410.62 7.166758 + 50787, // 2337 410.80 7.169826 + 50914, // 2338 410.98 7.172894 + 51040, // 2339 411.15 7.175962 + 51166, // 2340 411.33 7.179030 + 51291, // 2341 411.50 7.182098 + 51416, // 2342 411.68 7.185166 + 51541, // 2343 411.86 7.188234 + 51665, // 2344 412.03 7.191302 + 51788, // 2345 412.21 7.194370 + 51911, // 2346 412.38 7.197438 + 52033, // 2347 412.56 7.200506 + 52155, // 2348 412.73 7.203574 + 52277, // 2349 412.91 7.206642 + 52398, // 2350 413.09 7.209710 + 52518, // 2351 413.26 7.212778 + 52639, // 2352 413.44 7.215846 + 52758, // 2353 413.61 7.218914 + 52877, // 2354 413.79 7.221982 + 52996, // 2355 413.96 7.225050 + 53114, // 2356 414.14 7.228117 + 53231, // 2357 414.32 7.231185 + 53348, // 2358 414.49 7.234253 + 53465, // 2359 414.67 7.237321 + 53581, // 2360 414.84 7.240389 + 53696, // 2361 415.02 7.243457 + 53811, // 2362 415.20 7.246525 + 53926, // 2363 415.37 7.249593 + 54040, // 2364 415.55 7.252661 + 54153, // 2365 415.72 7.255729 + 54266, // 2366 415.90 7.258797 + 54379, // 2367 416.07 7.261865 + 54491, // 2368 416.25 7.264933 + 54602, // 2369 416.43 7.268001 + 54713, // 2370 416.60 7.271069 + 54823, // 2371 416.78 7.274137 + 54933, // 2372 416.95 7.277205 + 55043, // 2373 417.13 7.280273 + 55152, // 2374 417.30 7.283341 + 55260, // 2375 417.48 7.286409 + 55368, // 2376 417.66 7.289477 + 55475, // 2377 417.83 7.292545 + 55582, // 2378 418.01 7.295613 + 55688, // 2379 418.18 7.298681 + 55794, // 2380 418.36 7.301749 + 55899, // 2381 418.54 7.304817 + 56004, // 2382 418.71 7.307884 + 56108, // 2383 418.89 7.310952 + 56212, // 2384 419.06 7.314020 + 56315, // 2385 419.24 7.317088 + 56417, // 2386 419.41 7.320156 + 56519, // 2387 419.59 7.323224 + 56621, // 2388 419.77 7.326292 + 56722, // 2389 419.94 7.329360 + 56822, // 2390 420.12 7.332428 + 56922, // 2391 420.29 7.335496 + 57022, // 2392 420.47 7.338564 + 57120, // 2393 420.64 7.341632 + 57219, // 2394 420.82 7.344700 + 57316, // 2395 421.00 7.347768 + 57414, // 2396 421.17 7.350836 + 57510, // 2397 421.35 7.353904 + 57606, // 2398 421.52 7.356972 + 57702, // 2399 421.70 7.360040 + 57797, // 2400 421.88 7.363108 + 57892, // 2401 422.05 7.366176 + 57986, // 2402 422.23 7.369244 + 58079, // 2403 422.40 7.372312 + 58172, // 2404 422.58 7.375380 + 58264, // 2405 422.75 7.378448 + 58356, // 2406 422.93 7.381516 + 58447, // 2407 423.11 7.384584 + 58538, // 2408 423.28 7.387651 + 58628, // 2409 423.46 7.390719 + 58718, // 2410 423.63 7.393787 + 58807, // 2411 423.81 7.396855 + 58895, // 2412 423.98 7.399923 + 58983, // 2413 424.16 7.402991 + 59070, // 2414 424.34 7.406059 + 59157, // 2415 424.51 7.409127 + 59243, // 2416 424.69 7.412195 + 59329, // 2417 424.86 7.415263 + 59414, // 2418 425.04 7.418331 + 59499, // 2419 425.21 7.421399 + 59583, // 2420 425.39 7.424467 + 59666, // 2421 425.57 7.427535 + 59749, // 2422 425.74 7.430603 + 59831, // 2423 425.92 7.433671 + 59913, // 2424 426.09 7.436739 + 59994, // 2425 426.27 7.439807 + 60075, // 2426 426.45 7.442875 + 60155, // 2427 426.62 7.445943 + 60235, // 2428 426.80 7.449011 + 60313, // 2429 426.97 7.452079 + 60392, // 2430 427.15 7.455147 + 60470, // 2431 427.32 7.458215 + 60547, // 2432 427.50 7.461283 + 60624, // 2433 427.68 7.464351 + 60700, // 2434 427.85 7.467418 + 60775, // 2435 428.03 7.470486 + 60850, // 2436 428.20 7.473554 + 60924, // 2437 428.38 7.476622 + 60998, // 2438 428.55 7.479690 + 61071, // 2439 428.73 7.482758 + 61144, // 2440 428.91 7.485826 + 61216, // 2441 429.08 7.488894 + 61288, // 2442 429.26 7.491962 + 61359, // 2443 429.43 7.495030 + 61429, // 2444 429.61 7.498098 + 61499, // 2445 429.79 7.501166 + 61568, // 2446 429.96 7.504234 + 61637, // 2447 430.14 7.507302 + 61705, // 2448 430.31 7.510370 + 61772, // 2449 430.49 7.513438 + 61839, // 2450 430.66 7.516506 + 61905, // 2451 430.84 7.519574 + 61971, // 2452 431.02 7.522642 + 62036, // 2453 431.19 7.525710 + 62100, // 2454 431.37 7.528778 + 62164, // 2455 431.54 7.531846 + 62228, // 2456 431.72 7.534914 + 62291, // 2457 431.89 7.537982 + 62353, // 2458 432.07 7.541050 + 62414, // 2459 432.25 7.544118 + 62475, // 2460 432.42 7.547185 + 62536, // 2461 432.60 7.550253 + 62596, // 2462 432.77 7.553321 + 62655, // 2463 432.95 7.556389 + 62714, // 2464 433.12 7.559457 + 62772, // 2465 433.30 7.562525 + 62829, // 2466 433.48 7.565593 + 62886, // 2467 433.65 7.568661 + 62942, // 2468 433.83 7.571729 + 62998, // 2469 434.00 7.574797 + 63053, // 2470 434.18 7.577865 + 63108, // 2471 434.36 7.580933 + 63162, // 2472 434.53 7.584001 + 63215, // 2473 434.71 7.587069 + 63268, // 2474 434.88 7.590137 + 63320, // 2475 435.06 7.593205 + 63371, // 2476 435.23 7.596273 + 63422, // 2477 435.41 7.599341 + 63473, // 2478 435.59 7.602409 + 63522, // 2479 435.76 7.605477 + 63571, // 2480 435.94 7.608545 + 63620, // 2481 436.11 7.611613 + 63668, // 2482 436.29 7.614681 + 63715, // 2483 436.46 7.617749 + 63762, // 2484 436.64 7.620817 + 63808, // 2485 436.82 7.623885 + 63854, // 2486 436.99 7.626952 + 63899, // 2487 437.17 7.630020 + 63943, // 2488 437.34 7.633088 + 63987, // 2489 437.52 7.636156 + 64030, // 2490 437.70 7.639224 + 64073, // 2491 437.87 7.642292 + 64115, // 2492 438.05 7.645360 + 64156, // 2493 438.22 7.648428 + 64197, // 2494 438.40 7.651496 + 64237, // 2495 438.57 7.654564 + 64276, // 2496 438.75 7.657632 + 64315, // 2497 438.93 7.660700 + 64353, // 2498 439.10 7.663768 + 64391, // 2499 439.28 7.666836 + 64428, // 2500 439.45 7.669904 + 64465, // 2501 439.63 7.672972 + 64501, // 2502 439.80 7.676040 + 64536, // 2503 439.98 7.679108 + 64571, // 2504 440.16 7.682176 + 64605, // 2505 440.33 7.685244 + 64638, // 2506 440.51 7.688312 + 64671, // 2507 440.68 7.691380 + 64703, // 2508 440.86 7.694448 + 64735, // 2509 441.04 7.697516 + 64766, // 2510 441.21 7.700584 + 64796, // 2511 441.39 7.703652 + 64826, // 2512 441.56 7.706719 + 64855, // 2513 441.74 7.709787 + 64884, // 2514 441.91 7.712855 + 64912, // 2515 442.09 7.715923 + 64939, // 2516 442.27 7.718991 + 64966, // 2517 442.44 7.722059 + 64992, // 2518 442.62 7.725127 + 65018, // 2519 442.79 7.728195 + 65043, // 2520 442.97 7.731263 + 65067, // 2521 443.14 7.734331 + 65091, // 2522 443.32 7.737399 + 65114, // 2523 443.50 7.740467 + 65136, // 2524 443.67 7.743535 + 65158, // 2525 443.85 7.746603 + 65179, // 2526 444.02 7.749671 + 65200, // 2527 444.20 7.752739 + 65220, // 2528 444.38 7.755807 + 65239, // 2529 444.55 7.758875 + 65258, // 2530 444.73 7.761943 + 65276, // 2531 444.90 7.765011 + 65294, // 2532 445.08 7.768079 + 65311, // 2533 445.25 7.771147 + 65327, // 2534 445.43 7.774215 + 65343, // 2535 445.61 7.777283 + 65358, // 2536 445.78 7.780351 + 65372, // 2537 445.96 7.783419 + 65386, // 2538 446.13 7.786486 + 65400, // 2539 446.31 7.789554 + 65412, // 2540 446.48 7.792622 + 65424, // 2541 446.66 7.795690 + 65436, // 2542 446.84 7.798758 + 65446, // 2543 447.01 7.801826 + 65457, // 2544 447.19 7.804894 + 65466, // 2545 447.36 7.807962 + 65475, // 2546 447.54 7.811030 + 65483, // 2547 447.71 7.814098 + 65491, // 2548 447.89 7.817166 + 65498, // 2549 448.07 7.820234 + 65505, // 2550 448.24 7.823302 + 65511, // 2551 448.42 7.826370 + 65516, // 2552 448.59 7.829438 + 65520, // 2553 448.77 7.832506 + 65524, // 2554 448.95 7.835574 + 65528, // 2555 449.12 7.838642 + 65531, // 2556 449.30 7.841710 + 65533, // 2557 449.47 7.844778 + 65534, // 2558 449.65 7.847846 + 65535, // 2559 449.82 7.850914 +}; + +SLONG *CosTable = &SinTable[512]; + +//--------------------------------------------------------------- + +float SinTableF[] = +{ + (float)0.000000, // 0 + (float)0.003068, // 1 + (float)0.006136, // 2 + (float)0.009204, // 3 + (float)0.012272, // 4 + (float)0.015339, // 5 + (float)0.018407, // 6 + (float)0.021474, // 7 + (float)0.024541, // 8 + (float)0.027608, // 9 + (float)0.030675, // 10 + (float)0.033741, // 11 + (float)0.036807, // 12 + (float)0.039873, // 13 + (float)0.042938, // 14 + (float)0.046003, // 15 + (float)0.049068, // 16 + (float)0.052132, // 17 + (float)0.055195, // 18 + (float)0.058258, // 19 + (float)0.061321, // 20 + (float)0.064383, // 21 + (float)0.067444, // 22 + (float)0.070505, // 23 + (float)0.073565, // 24 + (float)0.076624, // 25 + (float)0.079682, // 26 + (float)0.082740, // 27 + (float)0.085797, // 28 + (float)0.088854, // 29 + (float)0.091909, // 30 + (float)0.094963, // 31 + (float)0.098017, // 32 + (float)0.101070, // 33 + (float)0.104122, // 34 + (float)0.107172, // 35 + (float)0.110222, // 36 + (float)0.113271, // 37 + (float)0.116319, // 38 + (float)0.119365, // 39 + (float)0.122411, // 40 + (float)0.125455, // 41 + (float)0.128498, // 42 + (float)0.131540, // 43 + (float)0.134581, // 44 + (float)0.137620, // 45 + (float)0.140658, // 46 + (float)0.143695, // 47 + (float)0.146730, // 48 + (float)0.149765, // 49 + (float)0.152797, // 50 + (float)0.155828, // 51 + (float)0.158858, // 52 + (float)0.161886, // 53 + (float)0.164913, // 54 + (float)0.167938, // 55 + (float)0.170962, // 56 + (float)0.173984, // 57 + (float)0.177004, // 58 + (float)0.180023, // 59 + (float)0.183040, // 60 + (float)0.186055, // 61 + (float)0.189069, // 62 + (float)0.192080, // 63 + (float)0.195090, // 64 + (float)0.198098, // 65 + (float)0.201105, // 66 + (float)0.204109, // 67 + (float)0.207111, // 68 + (float)0.210112, // 69 + (float)0.213110, // 70 + (float)0.216107, // 71 + (float)0.219101, // 72 + (float)0.222094, // 73 + (float)0.225084, // 74 + (float)0.228072, // 75 + (float)0.231058, // 76 + (float)0.234042, // 77 + (float)0.237024, // 78 + (float)0.240003, // 79 + (float)0.242980, // 80 + (float)0.245955, // 81 + (float)0.248928, // 82 + (float)0.251898, // 83 + (float)0.254866, // 84 + (float)0.257831, // 85 + (float)0.260794, // 86 + (float)0.263755, // 87 + (float)0.266713, // 88 + (float)0.269668, // 89 + (float)0.272621, // 90 + (float)0.275572, // 91 + (float)0.278520, // 92 + (float)0.281465, // 93 + (float)0.284408, // 94 + (float)0.287347, // 95 + (float)0.290285, // 96 + (float)0.293219, // 97 + (float)0.296151, // 98 + (float)0.299080, // 99 + (float)0.302006, // 100 + (float)0.304929, // 101 + (float)0.307850, // 102 + (float)0.310767, // 103 + (float)0.313682, // 104 + (float)0.316593, // 105 + (float)0.319502, // 106 + (float)0.322408, // 107 + (float)0.325310, // 108 + (float)0.328210, // 109 + (float)0.331106, // 110 + (float)0.334000, // 111 + (float)0.336890, // 112 + (float)0.339777, // 113 + (float)0.342661, // 114 + (float)0.345541, // 115 + (float)0.348419, // 116 + (float)0.351293, // 117 + (float)0.354164, // 118 + (float)0.357031, // 119 + (float)0.359895, // 120 + (float)0.362756, // 121 + (float)0.365613, // 122 + (float)0.368467, // 123 + (float)0.371317, // 124 + (float)0.374164, // 125 + (float)0.377007, // 126 + (float)0.379847, // 127 + (float)0.382683, // 128 + (float)0.385516, // 129 + (float)0.388345, // 130 + (float)0.391170, // 131 + (float)0.393992, // 132 + (float)0.396810, // 133 + (float)0.399624, // 134 + (float)0.402435, // 135 + (float)0.405241, // 136 + (float)0.408044, // 137 + (float)0.410843, // 138 + (float)0.413638, // 139 + (float)0.416430, // 140 + (float)0.419217, // 141 + (float)0.422000, // 142 + (float)0.424780, // 143 + (float)0.427555, // 144 + (float)0.430326, // 145 + (float)0.433094, // 146 + (float)0.435857, // 147 + (float)0.438616, // 148 + (float)0.441371, // 149 + (float)0.444122, // 150 + (float)0.446869, // 151 + (float)0.449611, // 152 + (float)0.452350, // 153 + (float)0.455084, // 154 + (float)0.457813, // 155 + (float)0.460539, // 156 + (float)0.463260, // 157 + (float)0.465976, // 158 + (float)0.468689, // 159 + (float)0.471397, // 160 + (float)0.474100, // 161 + (float)0.476799, // 162 + (float)0.479494, // 163 + (float)0.482184, // 164 + (float)0.484869, // 165 + (float)0.487550, // 166 + (float)0.490226, // 167 + (float)0.492898, // 168 + (float)0.495565, // 169 + (float)0.498228, // 170 + (float)0.500885, // 171 + (float)0.503538, // 172 + (float)0.506187, // 173 + (float)0.508830, // 174 + (float)0.511469, // 175 + (float)0.514103, // 176 + (float)0.516732, // 177 + (float)0.519356, // 178 + (float)0.521975, // 179 + (float)0.524590, // 180 + (float)0.527199, // 181 + (float)0.529804, // 182 + (float)0.532403, // 183 + (float)0.534998, // 184 + (float)0.537587, // 185 + (float)0.540171, // 186 + (float)0.542751, // 187 + (float)0.545325, // 188 + (float)0.547894, // 189 + (float)0.550458, // 190 + (float)0.553017, // 191 + (float)0.555570, // 192 + (float)0.558119, // 193 + (float)0.560662, // 194 + (float)0.563199, // 195 + (float)0.565732, // 196 + (float)0.568259, // 197 + (float)0.570781, // 198 + (float)0.573297, // 199 + (float)0.575808, // 200 + (float)0.578314, // 201 + (float)0.580814, // 202 + (float)0.583309, // 203 + (float)0.585798, // 204 + (float)0.588282, // 205 + (float)0.590760, // 206 + (float)0.593232, // 207 + (float)0.595699, // 208 + (float)0.598161, // 209 + (float)0.600616, // 210 + (float)0.603067, // 211 + (float)0.605511, // 212 + (float)0.607950, // 213 + (float)0.610383, // 214 + (float)0.612810, // 215 + (float)0.615232, // 216 + (float)0.617647, // 217 + (float)0.620057, // 218 + (float)0.622461, // 219 + (float)0.624859, // 220 + (float)0.627252, // 221 + (float)0.629638, // 222 + (float)0.632019, // 223 + (float)0.634393, // 224 + (float)0.636762, // 225 + (float)0.639124, // 226 + (float)0.641481, // 227 + (float)0.643832, // 228 + (float)0.646176, // 229 + (float)0.648514, // 230 + (float)0.650847, // 231 + (float)0.653173, // 232 + (float)0.655493, // 233 + (float)0.657807, // 234 + (float)0.660114, // 235 + (float)0.662416, // 236 + (float)0.664711, // 237 + (float)0.667000, // 238 + (float)0.669283, // 239 + (float)0.671559, // 240 + (float)0.673829, // 241 + (float)0.676093, // 242 + (float)0.678350, // 243 + (float)0.680601, // 244 + (float)0.682846, // 245 + (float)0.685084, // 246 + (float)0.687315, // 247 + (float)0.689541, // 248 + (float)0.691759, // 249 + (float)0.693971, // 250 + (float)0.696177, // 251 + (float)0.698376, // 252 + (float)0.700569, // 253 + (float)0.702755, // 254 + (float)0.704934, // 255 + (float)0.707107, // 256 + (float)0.709273, // 257 + (float)0.711432, // 258 + (float)0.713585, // 259 + (float)0.715731, // 260 + (float)0.717870, // 261 + (float)0.720003, // 262 + (float)0.722128, // 263 + (float)0.724247, // 264 + (float)0.726359, // 265 + (float)0.728464, // 266 + (float)0.730563, // 267 + (float)0.732654, // 268 + (float)0.734739, // 269 + (float)0.736817, // 270 + (float)0.738887, // 271 + (float)0.740951, // 272 + (float)0.743008, // 273 + (float)0.745058, // 274 + (float)0.747101, // 275 + (float)0.749136, // 276 + (float)0.751165, // 277 + (float)0.753187, // 278 + (float)0.755201, // 279 + (float)0.757209, // 280 + (float)0.759209, // 281 + (float)0.761202, // 282 + (float)0.763188, // 283 + (float)0.765167, // 284 + (float)0.767139, // 285 + (float)0.769103, // 286 + (float)0.771061, // 287 + (float)0.773010, // 288 + (float)0.774953, // 289 + (float)0.776888, // 290 + (float)0.778817, // 291 + (float)0.780737, // 292 + (float)0.782651, // 293 + (float)0.784557, // 294 + (float)0.786455, // 295 + (float)0.788346, // 296 + (float)0.790230, // 297 + (float)0.792107, // 298 + (float)0.793975, // 299 + (float)0.795837, // 300 + (float)0.797691, // 301 + (float)0.799537, // 302 + (float)0.801376, // 303 + (float)0.803208, // 304 + (float)0.805031, // 305 + (float)0.806848, // 306 + (float)0.808656, // 307 + (float)0.810457, // 308 + (float)0.812251, // 309 + (float)0.814036, // 310 + (float)0.815814, // 311 + (float)0.817585, // 312 + (float)0.819348, // 313 + (float)0.821103, // 314 + (float)0.822850, // 315 + (float)0.824589, // 316 + (float)0.826321, // 317 + (float)0.828045, // 318 + (float)0.829761, // 319 + (float)0.831470, // 320 + (float)0.833170, // 321 + (float)0.834863, // 322 + (float)0.836548, // 323 + (float)0.838225, // 324 + (float)0.839894, // 325 + (float)0.841555, // 326 + (float)0.843208, // 327 + (float)0.844854, // 328 + (float)0.846491, // 329 + (float)0.848120, // 330 + (float)0.849742, // 331 + (float)0.851355, // 332 + (float)0.852961, // 333 + (float)0.854558, // 334 + (float)0.856147, // 335 + (float)0.857729, // 336 + (float)0.859302, // 337 + (float)0.860867, // 338 + (float)0.862424, // 339 + (float)0.863973, // 340 + (float)0.865514, // 341 + (float)0.867046, // 342 + (float)0.868571, // 343 + (float)0.870087, // 344 + (float)0.871595, // 345 + (float)0.873095, // 346 + (float)0.874587, // 347 + (float)0.876070, // 348 + (float)0.877545, // 349 + (float)0.879012, // 350 + (float)0.880471, // 351 + (float)0.881921, // 352 + (float)0.883363, // 353 + (float)0.884797, // 354 + (float)0.886223, // 355 + (float)0.887640, // 356 + (float)0.889048, // 357 + (float)0.890449, // 358 + (float)0.891841, // 359 + (float)0.893224, // 360 + (float)0.894599, // 361 + (float)0.895966, // 362 + (float)0.897325, // 363 + (float)0.898674, // 364 + (float)0.900016, // 365 + (float)0.901349, // 366 + (float)0.902673, // 367 + (float)0.903989, // 368 + (float)0.905297, // 369 + (float)0.906596, // 370 + (float)0.907886, // 371 + (float)0.909168, // 372 + (float)0.910441, // 373 + (float)0.911706, // 374 + (float)0.912962, // 375 + (float)0.914210, // 376 + (float)0.915449, // 377 + (float)0.916679, // 378 + (float)0.917901, // 379 + (float)0.919114, // 380 + (float)0.920318, // 381 + (float)0.921514, // 382 + (float)0.922701, // 383 + (float)0.923880, // 384 + (float)0.925049, // 385 + (float)0.926210, // 386 + (float)0.927363, // 387 + (float)0.928506, // 388 + (float)0.929641, // 389 + (float)0.930767, // 390 + (float)0.931884, // 391 + (float)0.932993, // 392 + (float)0.934093, // 393 + (float)0.935184, // 394 + (float)0.936266, // 395 + (float)0.937339, // 396 + (float)0.938404, // 397 + (float)0.939459, // 398 + (float)0.940506, // 399 + (float)0.941544, // 400 + (float)0.942573, // 401 + (float)0.943593, // 402 + (float)0.944605, // 403 + (float)0.945607, // 404 + (float)0.946601, // 405 + (float)0.947586, // 406 + (float)0.948561, // 407 + (float)0.949528, // 408 + (float)0.950486, // 409 + (float)0.951435, // 410 + (float)0.952375, // 411 + (float)0.953306, // 412 + (float)0.954228, // 413 + (float)0.955141, // 414 + (float)0.956045, // 415 + (float)0.956940, // 416 + (float)0.957826, // 417 + (float)0.958703, // 418 + (float)0.959572, // 419 + (float)0.960431, // 420 + (float)0.961280, // 421 + (float)0.962121, // 422 + (float)0.962953, // 423 + (float)0.963776, // 424 + (float)0.964590, // 425 + (float)0.965394, // 426 + (float)0.966190, // 427 + (float)0.966976, // 428 + (float)0.967754, // 429 + (float)0.968522, // 430 + (float)0.969281, // 431 + (float)0.970031, // 432 + (float)0.970772, // 433 + (float)0.971504, // 434 + (float)0.972226, // 435 + (float)0.972940, // 436 + (float)0.973644, // 437 + (float)0.974339, // 438 + (float)0.975025, // 439 + (float)0.975702, // 440 + (float)0.976370, // 441 + (float)0.977028, // 442 + (float)0.977677, // 443 + (float)0.978317, // 444 + (float)0.978948, // 445 + (float)0.979570, // 446 + (float)0.980182, // 447 + (float)0.980785, // 448 + (float)0.981379, // 449 + (float)0.981964, // 450 + (float)0.982539, // 451 + (float)0.983105, // 452 + (float)0.983662, // 453 + (float)0.984210, // 454 + (float)0.984749, // 455 + (float)0.985278, // 456 + (float)0.985798, // 457 + (float)0.986308, // 458 + (float)0.986809, // 459 + (float)0.987301, // 460 + (float)0.987784, // 461 + (float)0.988258, // 462 + (float)0.988722, // 463 + (float)0.989177, // 464 + (float)0.989622, // 465 + (float)0.990058, // 466 + (float)0.990485, // 467 + (float)0.990903, // 468 + (float)0.991311, // 469 + (float)0.991710, // 470 + (float)0.992099, // 471 + (float)0.992480, // 472 + (float)0.992850, // 473 + (float)0.993212, // 474 + (float)0.993564, // 475 + (float)0.993907, // 476 + (float)0.994240, // 477 + (float)0.994565, // 478 + (float)0.994879, // 479 + (float)0.995185, // 480 + (float)0.995481, // 481 + (float)0.995767, // 482 + (float)0.996045, // 483 + (float)0.996313, // 484 + (float)0.996571, // 485 + (float)0.996820, // 486 + (float)0.997060, // 487 + (float)0.997290, // 488 + (float)0.997511, // 489 + (float)0.997723, // 490 + (float)0.997925, // 491 + (float)0.998118, // 492 + (float)0.998302, // 493 + (float)0.998476, // 494 + (float)0.998640, // 495 + (float)0.998795, // 496 + (float)0.998941, // 497 + (float)0.999078, // 498 + (float)0.999205, // 499 + (float)0.999322, // 500 + (float)0.999431, // 501 + (float)0.999529, // 502 + (float)0.999619, // 503 + (float)0.999699, // 504 + (float)0.999769, // 505 + (float)0.999831, // 506 + (float)0.999882, // 507 + (float)0.999925, // 508 + (float)0.999958, // 509 + (float)0.999981, // 510 + (float)0.999995, // 511 + (float)1.000000, // 512 + (float)0.999995, // 513 + (float)0.999981, // 514 + (float)0.999958, // 515 + (float)0.999925, // 516 + (float)0.999882, // 517 + (float)0.999831, // 518 + (float)0.999769, // 519 + (float)0.999699, // 520 + (float)0.999619, // 521 + (float)0.999529, // 522 + (float)0.999431, // 523 + (float)0.999322, // 524 + (float)0.999205, // 525 + (float)0.999078, // 526 + (float)0.998941, // 527 + (float)0.998795, // 528 + (float)0.998640, // 529 + (float)0.998476, // 530 + (float)0.998302, // 531 + (float)0.998118, // 532 + (float)0.997925, // 533 + (float)0.997723, // 534 + (float)0.997511, // 535 + (float)0.997290, // 536 + (float)0.997060, // 537 + (float)0.996820, // 538 + (float)0.996571, // 539 + (float)0.996313, // 540 + (float)0.996045, // 541 + (float)0.995767, // 542 + (float)0.995481, // 543 + (float)0.995185, // 544 + (float)0.994879, // 545 + (float)0.994565, // 546 + (float)0.994240, // 547 + (float)0.993907, // 548 + (float)0.993564, // 549 + (float)0.993212, // 550 + (float)0.992850, // 551 + (float)0.992480, // 552 + (float)0.992099, // 553 + (float)0.991710, // 554 + (float)0.991311, // 555 + (float)0.990903, // 556 + (float)0.990485, // 557 + (float)0.990058, // 558 + (float)0.989622, // 559 + (float)0.989177, // 560 + (float)0.988722, // 561 + (float)0.988258, // 562 + (float)0.987784, // 563 + (float)0.987301, // 564 + (float)0.986809, // 565 + (float)0.986308, // 566 + (float)0.985798, // 567 + (float)0.985278, // 568 + (float)0.984749, // 569 + (float)0.984210, // 570 + (float)0.983662, // 571 + (float)0.983105, // 572 + (float)0.982539, // 573 + (float)0.981964, // 574 + (float)0.981379, // 575 + (float)0.980785, // 576 + (float)0.980182, // 577 + (float)0.979570, // 578 + (float)0.978948, // 579 + (float)0.978317, // 580 + (float)0.977677, // 581 + (float)0.977028, // 582 + (float)0.976370, // 583 + (float)0.975702, // 584 + (float)0.975025, // 585 + (float)0.974339, // 586 + (float)0.973644, // 587 + (float)0.972940, // 588 + (float)0.972226, // 589 + (float)0.971504, // 590 + (float)0.970772, // 591 + (float)0.970031, // 592 + (float)0.969281, // 593 + (float)0.968522, // 594 + (float)0.967754, // 595 + (float)0.966976, // 596 + (float)0.966190, // 597 + (float)0.965394, // 598 + (float)0.964590, // 599 + (float)0.963776, // 600 + (float)0.962953, // 601 + (float)0.962121, // 602 + (float)0.961280, // 603 + (float)0.960431, // 604 + (float)0.959572, // 605 + (float)0.958703, // 606 + (float)0.957826, // 607 + (float)0.956940, // 608 + (float)0.956045, // 609 + (float)0.955141, // 610 + (float)0.954228, // 611 + (float)0.953306, // 612 + (float)0.952375, // 613 + (float)0.951435, // 614 + (float)0.950486, // 615 + (float)0.949528, // 616 + (float)0.948561, // 617 + (float)0.947586, // 618 + (float)0.946601, // 619 + (float)0.945607, // 620 + (float)0.944605, // 621 + (float)0.943593, // 622 + (float)0.942573, // 623 + (float)0.941544, // 624 + (float)0.940506, // 625 + (float)0.939459, // 626 + (float)0.938404, // 627 + (float)0.937339, // 628 + (float)0.936266, // 629 + (float)0.935184, // 630 + (float)0.934093, // 631 + (float)0.932993, // 632 + (float)0.931884, // 633 + (float)0.930767, // 634 + (float)0.929641, // 635 + (float)0.928506, // 636 + (float)0.927363, // 637 + (float)0.926210, // 638 + (float)0.925049, // 639 + (float)0.923880, // 640 + (float)0.922701, // 641 + (float)0.921514, // 642 + (float)0.920318, // 643 + (float)0.919114, // 644 + (float)0.917901, // 645 + (float)0.916679, // 646 + (float)0.915449, // 647 + (float)0.914210, // 648 + (float)0.912962, // 649 + (float)0.911706, // 650 + (float)0.910441, // 651 + (float)0.909168, // 652 + (float)0.907886, // 653 + (float)0.906596, // 654 + (float)0.905297, // 655 + (float)0.903989, // 656 + (float)0.902673, // 657 + (float)0.901349, // 658 + (float)0.900016, // 659 + (float)0.898674, // 660 + (float)0.897325, // 661 + (float)0.895966, // 662 + (float)0.894599, // 663 + (float)0.893224, // 664 + (float)0.891841, // 665 + (float)0.890449, // 666 + (float)0.889048, // 667 + (float)0.887640, // 668 + (float)0.886223, // 669 + (float)0.884797, // 670 + (float)0.883363, // 671 + (float)0.881921, // 672 + (float)0.880471, // 673 + (float)0.879012, // 674 + (float)0.877545, // 675 + (float)0.876070, // 676 + (float)0.874587, // 677 + (float)0.873095, // 678 + (float)0.871595, // 679 + (float)0.870087, // 680 + (float)0.868571, // 681 + (float)0.867046, // 682 + (float)0.865514, // 683 + (float)0.863973, // 684 + (float)0.862424, // 685 + (float)0.860867, // 686 + (float)0.859302, // 687 + (float)0.857729, // 688 + (float)0.856147, // 689 + (float)0.854558, // 690 + (float)0.852961, // 691 + (float)0.851355, // 692 + (float)0.849742, // 693 + (float)0.848120, // 694 + (float)0.846491, // 695 + (float)0.844854, // 696 + (float)0.843208, // 697 + (float)0.841555, // 698 + (float)0.839894, // 699 + (float)0.838225, // 700 + (float)0.836548, // 701 + (float)0.834863, // 702 + (float)0.833170, // 703 + (float)0.831470, // 704 + (float)0.829761, // 705 + (float)0.828045, // 706 + (float)0.826321, // 707 + (float)0.824589, // 708 + (float)0.822850, // 709 + (float)0.821103, // 710 + (float)0.819348, // 711 + (float)0.817585, // 712 + (float)0.815814, // 713 + (float)0.814036, // 714 + (float)0.812251, // 715 + (float)0.810457, // 716 + (float)0.808656, // 717 + (float)0.806848, // 718 + (float)0.805031, // 719 + (float)0.803208, // 720 + (float)0.801376, // 721 + (float)0.799537, // 722 + (float)0.797691, // 723 + (float)0.795837, // 724 + (float)0.793975, // 725 + (float)0.792107, // 726 + (float)0.790230, // 727 + (float)0.788346, // 728 + (float)0.786455, // 729 + (float)0.784557, // 730 + (float)0.782651, // 731 + (float)0.780737, // 732 + (float)0.778817, // 733 + (float)0.776888, // 734 + (float)0.774953, // 735 + (float)0.773010, // 736 + (float)0.771061, // 737 + (float)0.769103, // 738 + (float)0.767139, // 739 + (float)0.765167, // 740 + (float)0.763188, // 741 + (float)0.761202, // 742 + (float)0.759209, // 743 + (float)0.757209, // 744 + (float)0.755201, // 745 + (float)0.753187, // 746 + (float)0.751165, // 747 + (float)0.749136, // 748 + (float)0.747101, // 749 + (float)0.745058, // 750 + (float)0.743008, // 751 + (float)0.740951, // 752 + (float)0.738887, // 753 + (float)0.736817, // 754 + (float)0.734739, // 755 + (float)0.732654, // 756 + (float)0.730563, // 757 + (float)0.728464, // 758 + (float)0.726359, // 759 + (float)0.724247, // 760 + (float)0.722128, // 761 + (float)0.720003, // 762 + (float)0.717870, // 763 + (float)0.715731, // 764 + (float)0.713585, // 765 + (float)0.711432, // 766 + (float)0.709273, // 767 + (float)0.707107, // 768 + (float)0.704934, // 769 + (float)0.702755, // 770 + (float)0.700569, // 771 + (float)0.698376, // 772 + (float)0.696177, // 773 + (float)0.693971, // 774 + (float)0.691759, // 775 + (float)0.689541, // 776 + (float)0.687315, // 777 + (float)0.685084, // 778 + (float)0.682846, // 779 + (float)0.680601, // 780 + (float)0.678350, // 781 + (float)0.676093, // 782 + (float)0.673829, // 783 + (float)0.671559, // 784 + (float)0.669283, // 785 + (float)0.667000, // 786 + (float)0.664711, // 787 + (float)0.662416, // 788 + (float)0.660114, // 789 + (float)0.657807, // 790 + (float)0.655493, // 791 + (float)0.653173, // 792 + (float)0.650847, // 793 + (float)0.648514, // 794 + (float)0.646176, // 795 + (float)0.643832, // 796 + (float)0.641481, // 797 + (float)0.639124, // 798 + (float)0.636762, // 799 + (float)0.634393, // 800 + (float)0.632019, // 801 + (float)0.629638, // 802 + (float)0.627252, // 803 + (float)0.624859, // 804 + (float)0.622461, // 805 + (float)0.620057, // 806 + (float)0.617647, // 807 + (float)0.615232, // 808 + (float)0.612810, // 809 + (float)0.610383, // 810 + (float)0.607950, // 811 + (float)0.605511, // 812 + (float)0.603067, // 813 + (float)0.600616, // 814 + (float)0.598161, // 815 + (float)0.595699, // 816 + (float)0.593232, // 817 + (float)0.590760, // 818 + (float)0.588282, // 819 + (float)0.585798, // 820 + (float)0.583309, // 821 + (float)0.580814, // 822 + (float)0.578314, // 823 + (float)0.575808, // 824 + (float)0.573297, // 825 + (float)0.570781, // 826 + (float)0.568259, // 827 + (float)0.565732, // 828 + (float)0.563199, // 829 + (float)0.560662, // 830 + (float)0.558119, // 831 + (float)0.555570, // 832 + (float)0.553017, // 833 + (float)0.550458, // 834 + (float)0.547894, // 835 + (float)0.545325, // 836 + (float)0.542751, // 837 + (float)0.540171, // 838 + (float)0.537587, // 839 + (float)0.534998, // 840 + (float)0.532403, // 841 + (float)0.529804, // 842 + (float)0.527199, // 843 + (float)0.524590, // 844 + (float)0.521975, // 845 + (float)0.519356, // 846 + (float)0.516732, // 847 + (float)0.514103, // 848 + (float)0.511469, // 849 + (float)0.508830, // 850 + (float)0.506187, // 851 + (float)0.503538, // 852 + (float)0.500885, // 853 + (float)0.498228, // 854 + (float)0.495565, // 855 + (float)0.492898, // 856 + (float)0.490226, // 857 + (float)0.487550, // 858 + (float)0.484869, // 859 + (float)0.482184, // 860 + (float)0.479494, // 861 + (float)0.476799, // 862 + (float)0.474100, // 863 + (float)0.471397, // 864 + (float)0.468689, // 865 + (float)0.465976, // 866 + (float)0.463260, // 867 + (float)0.460539, // 868 + (float)0.457813, // 869 + (float)0.455084, // 870 + (float)0.452350, // 871 + (float)0.449611, // 872 + (float)0.446869, // 873 + (float)0.444122, // 874 + (float)0.441371, // 875 + (float)0.438616, // 876 + (float)0.435857, // 877 + (float)0.433094, // 878 + (float)0.430326, // 879 + (float)0.427555, // 880 + (float)0.424780, // 881 + (float)0.422000, // 882 + (float)0.419217, // 883 + (float)0.416430, // 884 + (float)0.413638, // 885 + (float)0.410843, // 886 + (float)0.408044, // 887 + (float)0.405241, // 888 + (float)0.402435, // 889 + (float)0.399624, // 890 + (float)0.396810, // 891 + (float)0.393992, // 892 + (float)0.391170, // 893 + (float)0.388345, // 894 + (float)0.385516, // 895 + (float)0.382683, // 896 + (float)0.379847, // 897 + (float)0.377007, // 898 + (float)0.374164, // 899 + (float)0.371317, // 900 + (float)0.368467, // 901 + (float)0.365613, // 902 + (float)0.362756, // 903 + (float)0.359895, // 904 + (float)0.357031, // 905 + (float)0.354164, // 906 + (float)0.351293, // 907 + (float)0.348419, // 908 + (float)0.345541, // 909 + (float)0.342661, // 910 + (float)0.339777, // 911 + (float)0.336890, // 912 + (float)0.334000, // 913 + (float)0.331106, // 914 + (float)0.328210, // 915 + (float)0.325310, // 916 + (float)0.322408, // 917 + (float)0.319502, // 918 + (float)0.316593, // 919 + (float)0.313682, // 920 + (float)0.310767, // 921 + (float)0.307850, // 922 + (float)0.304929, // 923 + (float)0.302006, // 924 + (float)0.299080, // 925 + (float)0.296151, // 926 + (float)0.293219, // 927 + (float)0.290285, // 928 + (float)0.287347, // 929 + (float)0.284408, // 930 + (float)0.281465, // 931 + (float)0.278520, // 932 + (float)0.275572, // 933 + (float)0.272621, // 934 + (float)0.269668, // 935 + (float)0.266713, // 936 + (float)0.263755, // 937 + (float)0.260794, // 938 + (float)0.257831, // 939 + (float)0.254866, // 940 + (float)0.251898, // 941 + (float)0.248928, // 942 + (float)0.245955, // 943 + (float)0.242980, // 944 + (float)0.240003, // 945 + (float)0.237024, // 946 + (float)0.234042, // 947 + (float)0.231058, // 948 + (float)0.228072, // 949 + (float)0.225084, // 950 + (float)0.222094, // 951 + (float)0.219101, // 952 + (float)0.216107, // 953 + (float)0.213110, // 954 + (float)0.210112, // 955 + (float)0.207111, // 956 + (float)0.204109, // 957 + (float)0.201105, // 958 + (float)0.198098, // 959 + (float)0.195090, // 960 + (float)0.192080, // 961 + (float)0.189069, // 962 + (float)0.186055, // 963 + (float)0.183040, // 964 + (float)0.180023, // 965 + (float)0.177004, // 966 + (float)0.173984, // 967 + (float)0.170962, // 968 + (float)0.167938, // 969 + (float)0.164913, // 970 + (float)0.161886, // 971 + (float)0.158858, // 972 + (float)0.155828, // 973 + (float)0.152797, // 974 + (float)0.149765, // 975 + (float)0.146730, // 976 + (float)0.143695, // 977 + (float)0.140658, // 978 + (float)0.137620, // 979 + (float)0.134581, // 980 + (float)0.131540, // 981 + (float)0.128498, // 982 + (float)0.125455, // 983 + (float)0.122411, // 984 + (float)0.119365, // 985 + (float)0.116319, // 986 + (float)0.113271, // 987 + (float)0.110222, // 988 + (float)0.107172, // 989 + (float)0.104122, // 990 + (float)0.101070, // 991 + (float)0.098017, // 992 + (float)0.094963, // 993 + (float)0.091909, // 994 + (float)0.088854, // 995 + (float)0.085797, // 996 + (float)0.082740, // 997 + (float)0.079682, // 998 + (float)0.076624, // 999 + (float)0.073565, // 1000 + (float)0.070505, // 1001 + (float)0.067444, // 1002 + (float)0.064383, // 1003 + (float)0.061321, // 1004 + (float)0.058258, // 1005 + (float)0.055195, // 1006 + (float)0.052132, // 1007 + (float)0.049068, // 1008 + (float)0.046003, // 1009 + (float)0.042938, // 1010 + (float)0.039873, // 1011 + (float)0.036807, // 1012 + (float)0.033741, // 1013 + (float)0.030675, // 1014 + (float)0.027608, // 1015 + (float)0.024541, // 1016 + (float)0.021474, // 1017 + (float)0.018407, // 1018 + (float)0.015339, // 1019 + (float)0.012272, // 1020 + (float)0.009204, // 1021 + (float)0.006136, // 1022 + (float)0.003068, // 1023 + (float)-0.000000, // 1024 + (float)-0.003068, // 1025 + (float)-0.006136, // 1026 + (float)-0.009204, // 1027 + (float)-0.012272, // 1028 + (float)-0.015339, // 1029 + (float)-0.018407, // 1030 + (float)-0.021474, // 1031 + (float)-0.024541, // 1032 + (float)-0.027608, // 1033 + (float)-0.030675, // 1034 + (float)-0.033741, // 1035 + (float)-0.036807, // 1036 + (float)-0.039873, // 1037 + (float)-0.042938, // 1038 + (float)-0.046003, // 1039 + (float)-0.049068, // 1040 + (float)-0.052132, // 1041 + (float)-0.055195, // 1042 + (float)-0.058258, // 1043 + (float)-0.061321, // 1044 + (float)-0.064383, // 1045 + (float)-0.067444, // 1046 + (float)-0.070505, // 1047 + (float)-0.073565, // 1048 + (float)-0.076624, // 1049 + (float)-0.079682, // 1050 + (float)-0.082740, // 1051 + (float)-0.085797, // 1052 + (float)-0.088854, // 1053 + (float)-0.091909, // 1054 + (float)-0.094963, // 1055 + (float)-0.098017, // 1056 + (float)-0.101070, // 1057 + (float)-0.104122, // 1058 + (float)-0.107172, // 1059 + (float)-0.110222, // 1060 + (float)-0.113271, // 1061 + (float)-0.116319, // 1062 + (float)-0.119365, // 1063 + (float)-0.122411, // 1064 + (float)-0.125455, // 1065 + (float)-0.128498, // 1066 + (float)-0.131540, // 1067 + (float)-0.134581, // 1068 + (float)-0.137620, // 1069 + (float)-0.140658, // 1070 + (float)-0.143695, // 1071 + (float)-0.146730, // 1072 + (float)-0.149765, // 1073 + (float)-0.152797, // 1074 + (float)-0.155828, // 1075 + (float)-0.158858, // 1076 + (float)-0.161886, // 1077 + (float)-0.164913, // 1078 + (float)-0.167938, // 1079 + (float)-0.170962, // 1080 + (float)-0.173984, // 1081 + (float)-0.177004, // 1082 + (float)-0.180023, // 1083 + (float)-0.183040, // 1084 + (float)-0.186055, // 1085 + (float)-0.189069, // 1086 + (float)-0.192080, // 1087 + (float)-0.195090, // 1088 + (float)-0.198098, // 1089 + (float)-0.201105, // 1090 + (float)-0.204109, // 1091 + (float)-0.207111, // 1092 + (float)-0.210112, // 1093 + (float)-0.213110, // 1094 + (float)-0.216107, // 1095 + (float)-0.219101, // 1096 + (float)-0.222094, // 1097 + (float)-0.225084, // 1098 + (float)-0.228072, // 1099 + (float)-0.231058, // 1100 + (float)-0.234042, // 1101 + (float)-0.237024, // 1102 + (float)-0.240003, // 1103 + (float)-0.242980, // 1104 + (float)-0.245955, // 1105 + (float)-0.248928, // 1106 + (float)-0.251898, // 1107 + (float)-0.254866, // 1108 + (float)-0.257831, // 1109 + (float)-0.260794, // 1110 + (float)-0.263755, // 1111 + (float)-0.266713, // 1112 + (float)-0.269668, // 1113 + (float)-0.272621, // 1114 + (float)-0.275572, // 1115 + (float)-0.278520, // 1116 + (float)-0.281465, // 1117 + (float)-0.284408, // 1118 + (float)-0.287347, // 1119 + (float)-0.290285, // 1120 + (float)-0.293219, // 1121 + (float)-0.296151, // 1122 + (float)-0.299080, // 1123 + (float)-0.302006, // 1124 + (float)-0.304929, // 1125 + (float)-0.307850, // 1126 + (float)-0.310767, // 1127 + (float)-0.313682, // 1128 + (float)-0.316593, // 1129 + (float)-0.319502, // 1130 + (float)-0.322408, // 1131 + (float)-0.325310, // 1132 + (float)-0.328210, // 1133 + (float)-0.331106, // 1134 + (float)-0.334000, // 1135 + (float)-0.336890, // 1136 + (float)-0.339777, // 1137 + (float)-0.342661, // 1138 + (float)-0.345541, // 1139 + (float)-0.348419, // 1140 + (float)-0.351293, // 1141 + (float)-0.354164, // 1142 + (float)-0.357031, // 1143 + (float)-0.359895, // 1144 + (float)-0.362756, // 1145 + (float)-0.365613, // 1146 + (float)-0.368467, // 1147 + (float)-0.371317, // 1148 + (float)-0.374164, // 1149 + (float)-0.377007, // 1150 + (float)-0.379847, // 1151 + (float)-0.382683, // 1152 + (float)-0.385516, // 1153 + (float)-0.388345, // 1154 + (float)-0.391170, // 1155 + (float)-0.393992, // 1156 + (float)-0.396810, // 1157 + (float)-0.399624, // 1158 + (float)-0.402435, // 1159 + (float)-0.405241, // 1160 + (float)-0.408044, // 1161 + (float)-0.410843, // 1162 + (float)-0.413638, // 1163 + (float)-0.416430, // 1164 + (float)-0.419217, // 1165 + (float)-0.422000, // 1166 + (float)-0.424780, // 1167 + (float)-0.427555, // 1168 + (float)-0.430326, // 1169 + (float)-0.433094, // 1170 + (float)-0.435857, // 1171 + (float)-0.438616, // 1172 + (float)-0.441371, // 1173 + (float)-0.444122, // 1174 + (float)-0.446869, // 1175 + (float)-0.449611, // 1176 + (float)-0.452350, // 1177 + (float)-0.455084, // 1178 + (float)-0.457813, // 1179 + (float)-0.460539, // 1180 + (float)-0.463260, // 1181 + (float)-0.465976, // 1182 + (float)-0.468689, // 1183 + (float)-0.471397, // 1184 + (float)-0.474100, // 1185 + (float)-0.476799, // 1186 + (float)-0.479494, // 1187 + (float)-0.482184, // 1188 + (float)-0.484869, // 1189 + (float)-0.487550, // 1190 + (float)-0.490226, // 1191 + (float)-0.492898, // 1192 + (float)-0.495565, // 1193 + (float)-0.498228, // 1194 + (float)-0.500885, // 1195 + (float)-0.503538, // 1196 + (float)-0.506187, // 1197 + (float)-0.508830, // 1198 + (float)-0.511469, // 1199 + (float)-0.514103, // 1200 + (float)-0.516732, // 1201 + (float)-0.519356, // 1202 + (float)-0.521975, // 1203 + (float)-0.524590, // 1204 + (float)-0.527199, // 1205 + (float)-0.529804, // 1206 + (float)-0.532403, // 1207 + (float)-0.534998, // 1208 + (float)-0.537587, // 1209 + (float)-0.540171, // 1210 + (float)-0.542751, // 1211 + (float)-0.545325, // 1212 + (float)-0.547894, // 1213 + (float)-0.550458, // 1214 + (float)-0.553017, // 1215 + (float)-0.555570, // 1216 + (float)-0.558119, // 1217 + (float)-0.560662, // 1218 + (float)-0.563199, // 1219 + (float)-0.565732, // 1220 + (float)-0.568259, // 1221 + (float)-0.570781, // 1222 + (float)-0.573297, // 1223 + (float)-0.575808, // 1224 + (float)-0.578314, // 1225 + (float)-0.580814, // 1226 + (float)-0.583309, // 1227 + (float)-0.585798, // 1228 + (float)-0.588282, // 1229 + (float)-0.590760, // 1230 + (float)-0.593232, // 1231 + (float)-0.595699, // 1232 + (float)-0.598161, // 1233 + (float)-0.600616, // 1234 + (float)-0.603067, // 1235 + (float)-0.605511, // 1236 + (float)-0.607950, // 1237 + (float)-0.610383, // 1238 + (float)-0.612810, // 1239 + (float)-0.615232, // 1240 + (float)-0.617647, // 1241 + (float)-0.620057, // 1242 + (float)-0.622461, // 1243 + (float)-0.624859, // 1244 + (float)-0.627252, // 1245 + (float)-0.629638, // 1246 + (float)-0.632019, // 1247 + (float)-0.634393, // 1248 + (float)-0.636762, // 1249 + (float)-0.639124, // 1250 + (float)-0.641481, // 1251 + (float)-0.643832, // 1252 + (float)-0.646176, // 1253 + (float)-0.648514, // 1254 + (float)-0.650847, // 1255 + (float)-0.653173, // 1256 + (float)-0.655493, // 1257 + (float)-0.657807, // 1258 + (float)-0.660114, // 1259 + (float)-0.662416, // 1260 + (float)-0.664711, // 1261 + (float)-0.667000, // 1262 + (float)-0.669283, // 1263 + (float)-0.671559, // 1264 + (float)-0.673829, // 1265 + (float)-0.676093, // 1266 + (float)-0.678350, // 1267 + (float)-0.680601, // 1268 + (float)-0.682846, // 1269 + (float)-0.685084, // 1270 + (float)-0.687315, // 1271 + (float)-0.689541, // 1272 + (float)-0.691759, // 1273 + (float)-0.693971, // 1274 + (float)-0.696177, // 1275 + (float)-0.698376, // 1276 + (float)-0.700569, // 1277 + (float)-0.702755, // 1278 + (float)-0.704934, // 1279 + (float)-0.707107, // 1280 + (float)-0.709273, // 1281 + (float)-0.711432, // 1282 + (float)-0.713585, // 1283 + (float)-0.715731, // 1284 + (float)-0.717870, // 1285 + (float)-0.720003, // 1286 + (float)-0.722128, // 1287 + (float)-0.724247, // 1288 + (float)-0.726359, // 1289 + (float)-0.728464, // 1290 + (float)-0.730563, // 1291 + (float)-0.732654, // 1292 + (float)-0.734739, // 1293 + (float)-0.736817, // 1294 + (float)-0.738887, // 1295 + (float)-0.740951, // 1296 + (float)-0.743008, // 1297 + (float)-0.745058, // 1298 + (float)-0.747101, // 1299 + (float)-0.749136, // 1300 + (float)-0.751165, // 1301 + (float)-0.753187, // 1302 + (float)-0.755201, // 1303 + (float)-0.757209, // 1304 + (float)-0.759209, // 1305 + (float)-0.761202, // 1306 + (float)-0.763188, // 1307 + (float)-0.765167, // 1308 + (float)-0.767139, // 1309 + (float)-0.769103, // 1310 + (float)-0.771061, // 1311 + (float)-0.773010, // 1312 + (float)-0.774953, // 1313 + (float)-0.776888, // 1314 + (float)-0.778817, // 1315 + (float)-0.780737, // 1316 + (float)-0.782651, // 1317 + (float)-0.784557, // 1318 + (float)-0.786455, // 1319 + (float)-0.788346, // 1320 + (float)-0.790230, // 1321 + (float)-0.792107, // 1322 + (float)-0.793975, // 1323 + (float)-0.795837, // 1324 + (float)-0.797691, // 1325 + (float)-0.799537, // 1326 + (float)-0.801376, // 1327 + (float)-0.803208, // 1328 + (float)-0.805031, // 1329 + (float)-0.806848, // 1330 + (float)-0.808656, // 1331 + (float)-0.810457, // 1332 + (float)-0.812251, // 1333 + (float)-0.814036, // 1334 + (float)-0.815814, // 1335 + (float)-0.817585, // 1336 + (float)-0.819348, // 1337 + (float)-0.821103, // 1338 + (float)-0.822850, // 1339 + (float)-0.824589, // 1340 + (float)-0.826321, // 1341 + (float)-0.828045, // 1342 + (float)-0.829761, // 1343 + (float)-0.831470, // 1344 + (float)-0.833170, // 1345 + (float)-0.834863, // 1346 + (float)-0.836548, // 1347 + (float)-0.838225, // 1348 + (float)-0.839894, // 1349 + (float)-0.841555, // 1350 + (float)-0.843208, // 1351 + (float)-0.844854, // 1352 + (float)-0.846491, // 1353 + (float)-0.848120, // 1354 + (float)-0.849742, // 1355 + (float)-0.851355, // 1356 + (float)-0.852961, // 1357 + (float)-0.854558, // 1358 + (float)-0.856147, // 1359 + (float)-0.857729, // 1360 + (float)-0.859302, // 1361 + (float)-0.860867, // 1362 + (float)-0.862424, // 1363 + (float)-0.863973, // 1364 + (float)-0.865514, // 1365 + (float)-0.867046, // 1366 + (float)-0.868571, // 1367 + (float)-0.870087, // 1368 + (float)-0.871595, // 1369 + (float)-0.873095, // 1370 + (float)-0.874587, // 1371 + (float)-0.876070, // 1372 + (float)-0.877545, // 1373 + (float)-0.879012, // 1374 + (float)-0.880471, // 1375 + (float)-0.881921, // 1376 + (float)-0.883363, // 1377 + (float)-0.884797, // 1378 + (float)-0.886223, // 1379 + (float)-0.887640, // 1380 + (float)-0.889048, // 1381 + (float)-0.890449, // 1382 + (float)-0.891841, // 1383 + (float)-0.893224, // 1384 + (float)-0.894599, // 1385 + (float)-0.895966, // 1386 + (float)-0.897325, // 1387 + (float)-0.898674, // 1388 + (float)-0.900016, // 1389 + (float)-0.901349, // 1390 + (float)-0.902673, // 1391 + (float)-0.903989, // 1392 + (float)-0.905297, // 1393 + (float)-0.906596, // 1394 + (float)-0.907886, // 1395 + (float)-0.909168, // 1396 + (float)-0.910441, // 1397 + (float)-0.911706, // 1398 + (float)-0.912962, // 1399 + (float)-0.914210, // 1400 + (float)-0.915449, // 1401 + (float)-0.916679, // 1402 + (float)-0.917901, // 1403 + (float)-0.919114, // 1404 + (float)-0.920318, // 1405 + (float)-0.921514, // 1406 + (float)-0.922701, // 1407 + (float)-0.923880, // 1408 + (float)-0.925049, // 1409 + (float)-0.926210, // 1410 + (float)-0.927363, // 1411 + (float)-0.928506, // 1412 + (float)-0.929641, // 1413 + (float)-0.930767, // 1414 + (float)-0.931884, // 1415 + (float)-0.932993, // 1416 + (float)-0.934093, // 1417 + (float)-0.935184, // 1418 + (float)-0.936266, // 1419 + (float)-0.937339, // 1420 + (float)-0.938404, // 1421 + (float)-0.939459, // 1422 + (float)-0.940506, // 1423 + (float)-0.941544, // 1424 + (float)-0.942573, // 1425 + (float)-0.943593, // 1426 + (float)-0.944605, // 1427 + (float)-0.945607, // 1428 + (float)-0.946601, // 1429 + (float)-0.947586, // 1430 + (float)-0.948561, // 1431 + (float)-0.949528, // 1432 + (float)-0.950486, // 1433 + (float)-0.951435, // 1434 + (float)-0.952375, // 1435 + (float)-0.953306, // 1436 + (float)-0.954228, // 1437 + (float)-0.955141, // 1438 + (float)-0.956045, // 1439 + (float)-0.956940, // 1440 + (float)-0.957826, // 1441 + (float)-0.958703, // 1442 + (float)-0.959572, // 1443 + (float)-0.960431, // 1444 + (float)-0.961280, // 1445 + (float)-0.962121, // 1446 + (float)-0.962953, // 1447 + (float)-0.963776, // 1448 + (float)-0.964590, // 1449 + (float)-0.965394, // 1450 + (float)-0.966190, // 1451 + (float)-0.966976, // 1452 + (float)-0.967754, // 1453 + (float)-0.968522, // 1454 + (float)-0.969281, // 1455 + (float)-0.970031, // 1456 + (float)-0.970772, // 1457 + (float)-0.971504, // 1458 + (float)-0.972226, // 1459 + (float)-0.972940, // 1460 + (float)-0.973644, // 1461 + (float)-0.974339, // 1462 + (float)-0.975025, // 1463 + (float)-0.975702, // 1464 + (float)-0.976370, // 1465 + (float)-0.977028, // 1466 + (float)-0.977677, // 1467 + (float)-0.978317, // 1468 + (float)-0.978948, // 1469 + (float)-0.979570, // 1470 + (float)-0.980182, // 1471 + (float)-0.980785, // 1472 + (float)-0.981379, // 1473 + (float)-0.981964, // 1474 + (float)-0.982539, // 1475 + (float)-0.983105, // 1476 + (float)-0.983662, // 1477 + (float)-0.984210, // 1478 + (float)-0.984749, // 1479 + (float)-0.985278, // 1480 + (float)-0.985798, // 1481 + (float)-0.986308, // 1482 + (float)-0.986809, // 1483 + (float)-0.987301, // 1484 + (float)-0.987784, // 1485 + (float)-0.988258, // 1486 + (float)-0.988722, // 1487 + (float)-0.989177, // 1488 + (float)-0.989622, // 1489 + (float)-0.990058, // 1490 + (float)-0.990485, // 1491 + (float)-0.990903, // 1492 + (float)-0.991311, // 1493 + (float)-0.991710, // 1494 + (float)-0.992099, // 1495 + (float)-0.992480, // 1496 + (float)-0.992850, // 1497 + (float)-0.993212, // 1498 + (float)-0.993564, // 1499 + (float)-0.993907, // 1500 + (float)-0.994240, // 1501 + (float)-0.994565, // 1502 + (float)-0.994879, // 1503 + (float)-0.995185, // 1504 + (float)-0.995481, // 1505 + (float)-0.995767, // 1506 + (float)-0.996045, // 1507 + (float)-0.996313, // 1508 + (float)-0.996571, // 1509 + (float)-0.996820, // 1510 + (float)-0.997060, // 1511 + (float)-0.997290, // 1512 + (float)-0.997511, // 1513 + (float)-0.997723, // 1514 + (float)-0.997925, // 1515 + (float)-0.998118, // 1516 + (float)-0.998302, // 1517 + (float)-0.998476, // 1518 + (float)-0.998640, // 1519 + (float)-0.998795, // 1520 + (float)-0.998941, // 1521 + (float)-0.999078, // 1522 + (float)-0.999205, // 1523 + (float)-0.999322, // 1524 + (float)-0.999431, // 1525 + (float)-0.999529, // 1526 + (float)-0.999619, // 1527 + (float)-0.999699, // 1528 + (float)-0.999769, // 1529 + (float)-0.999831, // 1530 + (float)-0.999882, // 1531 + (float)-0.999925, // 1532 + (float)-0.999958, // 1533 + (float)-0.999981, // 1534 + (float)-0.999995, // 1535 + (float)-1.000000, // 1536 + (float)-0.999995, // 1537 + (float)-0.999981, // 1538 + (float)-0.999958, // 1539 + (float)-0.999925, // 1540 + (float)-0.999882, // 1541 + (float)-0.999831, // 1542 + (float)-0.999769, // 1543 + (float)-0.999699, // 1544 + (float)-0.999619, // 1545 + (float)-0.999529, // 1546 + (float)-0.999431, // 1547 + (float)-0.999322, // 1548 + (float)-0.999205, // 1549 + (float)-0.999078, // 1550 + (float)-0.998941, // 1551 + (float)-0.998795, // 1552 + (float)-0.998640, // 1553 + (float)-0.998476, // 1554 + (float)-0.998302, // 1555 + (float)-0.998118, // 1556 + (float)-0.997925, // 1557 + (float)-0.997723, // 1558 + (float)-0.997511, // 1559 + (float)-0.997290, // 1560 + (float)-0.997060, // 1561 + (float)-0.996820, // 1562 + (float)-0.996571, // 1563 + (float)-0.996313, // 1564 + (float)-0.996045, // 1565 + (float)-0.995767, // 1566 + (float)-0.995481, // 1567 + (float)-0.995185, // 1568 + (float)-0.994879, // 1569 + (float)-0.994565, // 1570 + (float)-0.994240, // 1571 + (float)-0.993907, // 1572 + (float)-0.993564, // 1573 + (float)-0.993212, // 1574 + (float)-0.992850, // 1575 + (float)-0.992480, // 1576 + (float)-0.992099, // 1577 + (float)-0.991710, // 1578 + (float)-0.991311, // 1579 + (float)-0.990903, // 1580 + (float)-0.990485, // 1581 + (float)-0.990058, // 1582 + (float)-0.989622, // 1583 + (float)-0.989177, // 1584 + (float)-0.988722, // 1585 + (float)-0.988258, // 1586 + (float)-0.987784, // 1587 + (float)-0.987301, // 1588 + (float)-0.986809, // 1589 + (float)-0.986308, // 1590 + (float)-0.985798, // 1591 + (float)-0.985278, // 1592 + (float)-0.984749, // 1593 + (float)-0.984210, // 1594 + (float)-0.983662, // 1595 + (float)-0.983105, // 1596 + (float)-0.982539, // 1597 + (float)-0.981964, // 1598 + (float)-0.981379, // 1599 + (float)-0.980785, // 1600 + (float)-0.980182, // 1601 + (float)-0.979570, // 1602 + (float)-0.978948, // 1603 + (float)-0.978317, // 1604 + (float)-0.977677, // 1605 + (float)-0.977028, // 1606 + (float)-0.976370, // 1607 + (float)-0.975702, // 1608 + (float)-0.975025, // 1609 + (float)-0.974339, // 1610 + (float)-0.973644, // 1611 + (float)-0.972940, // 1612 + (float)-0.972226, // 1613 + (float)-0.971504, // 1614 + (float)-0.970772, // 1615 + (float)-0.970031, // 1616 + (float)-0.969281, // 1617 + (float)-0.968522, // 1618 + (float)-0.967754, // 1619 + (float)-0.966976, // 1620 + (float)-0.966190, // 1621 + (float)-0.965394, // 1622 + (float)-0.964590, // 1623 + (float)-0.963776, // 1624 + (float)-0.962953, // 1625 + (float)-0.962121, // 1626 + (float)-0.961280, // 1627 + (float)-0.960431, // 1628 + (float)-0.959572, // 1629 + (float)-0.958703, // 1630 + (float)-0.957826, // 1631 + (float)-0.956940, // 1632 + (float)-0.956045, // 1633 + (float)-0.955141, // 1634 + (float)-0.954228, // 1635 + (float)-0.953306, // 1636 + (float)-0.952375, // 1637 + (float)-0.951435, // 1638 + (float)-0.950486, // 1639 + (float)-0.949528, // 1640 + (float)-0.948561, // 1641 + (float)-0.947586, // 1642 + (float)-0.946601, // 1643 + (float)-0.945607, // 1644 + (float)-0.944605, // 1645 + (float)-0.943593, // 1646 + (float)-0.942573, // 1647 + (float)-0.941544, // 1648 + (float)-0.940506, // 1649 + (float)-0.939459, // 1650 + (float)-0.938404, // 1651 + (float)-0.937339, // 1652 + (float)-0.936266, // 1653 + (float)-0.935184, // 1654 + (float)-0.934093, // 1655 + (float)-0.932993, // 1656 + (float)-0.931884, // 1657 + (float)-0.930767, // 1658 + (float)-0.929641, // 1659 + (float)-0.928506, // 1660 + (float)-0.927363, // 1661 + (float)-0.926210, // 1662 + (float)-0.925049, // 1663 + (float)-0.923880, // 1664 + (float)-0.922701, // 1665 + (float)-0.921514, // 1666 + (float)-0.920318, // 1667 + (float)-0.919114, // 1668 + (float)-0.917901, // 1669 + (float)-0.916679, // 1670 + (float)-0.915449, // 1671 + (float)-0.914210, // 1672 + (float)-0.912962, // 1673 + (float)-0.911706, // 1674 + (float)-0.910441, // 1675 + (float)-0.909168, // 1676 + (float)-0.907886, // 1677 + (float)-0.906596, // 1678 + (float)-0.905297, // 1679 + (float)-0.903989, // 1680 + (float)-0.902673, // 1681 + (float)-0.901349, // 1682 + (float)-0.900016, // 1683 + (float)-0.898674, // 1684 + (float)-0.897325, // 1685 + (float)-0.895966, // 1686 + (float)-0.894599, // 1687 + (float)-0.893224, // 1688 + (float)-0.891841, // 1689 + (float)-0.890449, // 1690 + (float)-0.889048, // 1691 + (float)-0.887640, // 1692 + (float)-0.886223, // 1693 + (float)-0.884797, // 1694 + (float)-0.883363, // 1695 + (float)-0.881921, // 1696 + (float)-0.880471, // 1697 + (float)-0.879012, // 1698 + (float)-0.877545, // 1699 + (float)-0.876070, // 1700 + (float)-0.874587, // 1701 + (float)-0.873095, // 1702 + (float)-0.871595, // 1703 + (float)-0.870087, // 1704 + (float)-0.868571, // 1705 + (float)-0.867046, // 1706 + (float)-0.865514, // 1707 + (float)-0.863973, // 1708 + (float)-0.862424, // 1709 + (float)-0.860867, // 1710 + (float)-0.859302, // 1711 + (float)-0.857729, // 1712 + (float)-0.856147, // 1713 + (float)-0.854558, // 1714 + (float)-0.852961, // 1715 + (float)-0.851355, // 1716 + (float)-0.849742, // 1717 + (float)-0.848120, // 1718 + (float)-0.846491, // 1719 + (float)-0.844854, // 1720 + (float)-0.843208, // 1721 + (float)-0.841555, // 1722 + (float)-0.839894, // 1723 + (float)-0.838225, // 1724 + (float)-0.836548, // 1725 + (float)-0.834863, // 1726 + (float)-0.833170, // 1727 + (float)-0.831470, // 1728 + (float)-0.829761, // 1729 + (float)-0.828045, // 1730 + (float)-0.826321, // 1731 + (float)-0.824589, // 1732 + (float)-0.822850, // 1733 + (float)-0.821103, // 1734 + (float)-0.819348, // 1735 + (float)-0.817585, // 1736 + (float)-0.815814, // 1737 + (float)-0.814036, // 1738 + (float)-0.812251, // 1739 + (float)-0.810457, // 1740 + (float)-0.808656, // 1741 + (float)-0.806848, // 1742 + (float)-0.805031, // 1743 + (float)-0.803208, // 1744 + (float)-0.801376, // 1745 + (float)-0.799537, // 1746 + (float)-0.797691, // 1747 + (float)-0.795837, // 1748 + (float)-0.793975, // 1749 + (float)-0.792107, // 1750 + (float)-0.790230, // 1751 + (float)-0.788346, // 1752 + (float)-0.786455, // 1753 + (float)-0.784557, // 1754 + (float)-0.782651, // 1755 + (float)-0.780737, // 1756 + (float)-0.778817, // 1757 + (float)-0.776888, // 1758 + (float)-0.774953, // 1759 + (float)-0.773010, // 1760 + (float)-0.771061, // 1761 + (float)-0.769103, // 1762 + (float)-0.767139, // 1763 + (float)-0.765167, // 1764 + (float)-0.763188, // 1765 + (float)-0.761202, // 1766 + (float)-0.759209, // 1767 + (float)-0.757209, // 1768 + (float)-0.755201, // 1769 + (float)-0.753187, // 1770 + (float)-0.751165, // 1771 + (float)-0.749136, // 1772 + (float)-0.747101, // 1773 + (float)-0.745058, // 1774 + (float)-0.743008, // 1775 + (float)-0.740951, // 1776 + (float)-0.738887, // 1777 + (float)-0.736817, // 1778 + (float)-0.734739, // 1779 + (float)-0.732654, // 1780 + (float)-0.730563, // 1781 + (float)-0.728464, // 1782 + (float)-0.726359, // 1783 + (float)-0.724247, // 1784 + (float)-0.722128, // 1785 + (float)-0.720003, // 1786 + (float)-0.717870, // 1787 + (float)-0.715731, // 1788 + (float)-0.713585, // 1789 + (float)-0.711432, // 1790 + (float)-0.709273, // 1791 + (float)-0.707107, // 1792 + (float)-0.704934, // 1793 + (float)-0.702755, // 1794 + (float)-0.700569, // 1795 + (float)-0.698376, // 1796 + (float)-0.696177, // 1797 + (float)-0.693971, // 1798 + (float)-0.691759, // 1799 + (float)-0.689541, // 1800 + (float)-0.687315, // 1801 + (float)-0.685084, // 1802 + (float)-0.682846, // 1803 + (float)-0.680601, // 1804 + (float)-0.678350, // 1805 + (float)-0.676093, // 1806 + (float)-0.673829, // 1807 + (float)-0.671559, // 1808 + (float)-0.669283, // 1809 + (float)-0.667000, // 1810 + (float)-0.664711, // 1811 + (float)-0.662416, // 1812 + (float)-0.660114, // 1813 + (float)-0.657807, // 1814 + (float)-0.655493, // 1815 + (float)-0.653173, // 1816 + (float)-0.650847, // 1817 + (float)-0.648514, // 1818 + (float)-0.646176, // 1819 + (float)-0.643832, // 1820 + (float)-0.641481, // 1821 + (float)-0.639124, // 1822 + (float)-0.636762, // 1823 + (float)-0.634393, // 1824 + (float)-0.632019, // 1825 + (float)-0.629638, // 1826 + (float)-0.627252, // 1827 + (float)-0.624859, // 1828 + (float)-0.622461, // 1829 + (float)-0.620057, // 1830 + (float)-0.617647, // 1831 + (float)-0.615232, // 1832 + (float)-0.612810, // 1833 + (float)-0.610383, // 1834 + (float)-0.607950, // 1835 + (float)-0.605511, // 1836 + (float)-0.603067, // 1837 + (float)-0.600616, // 1838 + (float)-0.598161, // 1839 + (float)-0.595699, // 1840 + (float)-0.593232, // 1841 + (float)-0.590760, // 1842 + (float)-0.588282, // 1843 + (float)-0.585798, // 1844 + (float)-0.583309, // 1845 + (float)-0.580814, // 1846 + (float)-0.578314, // 1847 + (float)-0.575808, // 1848 + (float)-0.573297, // 1849 + (float)-0.570781, // 1850 + (float)-0.568259, // 1851 + (float)-0.565732, // 1852 + (float)-0.563199, // 1853 + (float)-0.560662, // 1854 + (float)-0.558119, // 1855 + (float)-0.555570, // 1856 + (float)-0.553017, // 1857 + (float)-0.550458, // 1858 + (float)-0.547894, // 1859 + (float)-0.545325, // 1860 + (float)-0.542751, // 1861 + (float)-0.540171, // 1862 + (float)-0.537587, // 1863 + (float)-0.534998, // 1864 + (float)-0.532403, // 1865 + (float)-0.529804, // 1866 + (float)-0.527199, // 1867 + (float)-0.524590, // 1868 + (float)-0.521975, // 1869 + (float)-0.519356, // 1870 + (float)-0.516732, // 1871 + (float)-0.514103, // 1872 + (float)-0.511469, // 1873 + (float)-0.508830, // 1874 + (float)-0.506187, // 1875 + (float)-0.503538, // 1876 + (float)-0.500885, // 1877 + (float)-0.498228, // 1878 + (float)-0.495565, // 1879 + (float)-0.492898, // 1880 + (float)-0.490226, // 1881 + (float)-0.487550, // 1882 + (float)-0.484869, // 1883 + (float)-0.482184, // 1884 + (float)-0.479494, // 1885 + (float)-0.476799, // 1886 + (float)-0.474100, // 1887 + (float)-0.471397, // 1888 + (float)-0.468689, // 1889 + (float)-0.465976, // 1890 + (float)-0.463260, // 1891 + (float)-0.460539, // 1892 + (float)-0.457813, // 1893 + (float)-0.455084, // 1894 + (float)-0.452350, // 1895 + (float)-0.449611, // 1896 + (float)-0.446869, // 1897 + (float)-0.444122, // 1898 + (float)-0.441371, // 1899 + (float)-0.438616, // 1900 + (float)-0.435857, // 1901 + (float)-0.433094, // 1902 + (float)-0.430326, // 1903 + (float)-0.427555, // 1904 + (float)-0.424780, // 1905 + (float)-0.422000, // 1906 + (float)-0.419217, // 1907 + (float)-0.416430, // 1908 + (float)-0.413638, // 1909 + (float)-0.410843, // 1910 + (float)-0.408044, // 1911 + (float)-0.405241, // 1912 + (float)-0.402435, // 1913 + (float)-0.399624, // 1914 + (float)-0.396810, // 1915 + (float)-0.393992, // 1916 + (float)-0.391170, // 1917 + (float)-0.388345, // 1918 + (float)-0.385516, // 1919 + (float)-0.382683, // 1920 + (float)-0.379847, // 1921 + (float)-0.377007, // 1922 + (float)-0.374164, // 1923 + (float)-0.371317, // 1924 + (float)-0.368467, // 1925 + (float)-0.365613, // 1926 + (float)-0.362756, // 1927 + (float)-0.359895, // 1928 + (float)-0.357031, // 1929 + (float)-0.354164, // 1930 + (float)-0.351293, // 1931 + (float)-0.348419, // 1932 + (float)-0.345541, // 1933 + (float)-0.342661, // 1934 + (float)-0.339777, // 1935 + (float)-0.336890, // 1936 + (float)-0.334000, // 1937 + (float)-0.331106, // 1938 + (float)-0.328210, // 1939 + (float)-0.325310, // 1940 + (float)-0.322408, // 1941 + (float)-0.319502, // 1942 + (float)-0.316593, // 1943 + (float)-0.313682, // 1944 + (float)-0.310767, // 1945 + (float)-0.307850, // 1946 + (float)-0.304929, // 1947 + (float)-0.302006, // 1948 + (float)-0.299080, // 1949 + (float)-0.296151, // 1950 + (float)-0.293219, // 1951 + (float)-0.290285, // 1952 + (float)-0.287347, // 1953 + (float)-0.284408, // 1954 + (float)-0.281465, // 1955 + (float)-0.278520, // 1956 + (float)-0.275572, // 1957 + (float)-0.272621, // 1958 + (float)-0.269668, // 1959 + (float)-0.266713, // 1960 + (float)-0.263755, // 1961 + (float)-0.260794, // 1962 + (float)-0.257831, // 1963 + (float)-0.254866, // 1964 + (float)-0.251898, // 1965 + (float)-0.248928, // 1966 + (float)-0.245955, // 1967 + (float)-0.242980, // 1968 + (float)-0.240003, // 1969 + (float)-0.237024, // 1970 + (float)-0.234042, // 1971 + (float)-0.231058, // 1972 + (float)-0.228072, // 1973 + (float)-0.225084, // 1974 + (float)-0.222094, // 1975 + (float)-0.219101, // 1976 + (float)-0.216107, // 1977 + (float)-0.213110, // 1978 + (float)-0.210112, // 1979 + (float)-0.207111, // 1980 + (float)-0.204109, // 1981 + (float)-0.201105, // 1982 + (float)-0.198098, // 1983 + (float)-0.195090, // 1984 + (float)-0.192080, // 1985 + (float)-0.189069, // 1986 + (float)-0.186055, // 1987 + (float)-0.183040, // 1988 + (float)-0.180023, // 1989 + (float)-0.177004, // 1990 + (float)-0.173984, // 1991 + (float)-0.170962, // 1992 + (float)-0.167938, // 1993 + (float)-0.164913, // 1994 + (float)-0.161886, // 1995 + (float)-0.158858, // 1996 + (float)-0.155828, // 1997 + (float)-0.152797, // 1998 + (float)-0.149765, // 1999 + (float)-0.146730, // 2000 + (float)-0.143695, // 2001 + (float)-0.140658, // 2002 + (float)-0.137620, // 2003 + (float)-0.134581, // 2004 + (float)-0.131540, // 2005 + (float)-0.128498, // 2006 + (float)-0.125455, // 2007 + (float)-0.122411, // 2008 + (float)-0.119365, // 2009 + (float)-0.116319, // 2010 + (float)-0.113271, // 2011 + (float)-0.110222, // 2012 + (float)-0.107172, // 2013 + (float)-0.104122, // 2014 + (float)-0.101070, // 2015 + (float)-0.098017, // 2016 + (float)-0.094963, // 2017 + (float)-0.091909, // 2018 + (float)-0.088854, // 2019 + (float)-0.085797, // 2020 + (float)-0.082740, // 2021 + (float)-0.079682, // 2022 + (float)-0.076624, // 2023 + (float)-0.073565, // 2024 + (float)-0.070505, // 2025 + (float)-0.067444, // 2026 + (float)-0.064383, // 2027 + (float)-0.061321, // 2028 + (float)-0.058258, // 2029 + (float)-0.055195, // 2030 + (float)-0.052132, // 2031 + (float)-0.049068, // 2032 + (float)-0.046003, // 2033 + (float)-0.042938, // 2034 + (float)-0.039873, // 2035 + (float)-0.036807, // 2036 + (float)-0.033741, // 2037 + (float)-0.030675, // 2038 + (float)-0.027608, // 2039 + (float)-0.024541, // 2040 + (float)-0.021474, // 2041 + (float)-0.018407, // 2042 + (float)-0.015339, // 2043 + (float)-0.012272, // 2044 + (float)-0.009204, // 2045 + (float)-0.006136, // 2046 + (float)-0.003068, // 2047 + (float)0.000000, // 0 + (float)0.003068, // 1 + (float)0.006136, // 2 + (float)0.009204, // 3 + (float)0.012272, // 4 + (float)0.015339, // 5 + (float)0.018407, // 6 + (float)0.021474, // 7 + (float)0.024541, // 8 + (float)0.027608, // 9 + (float)0.030675, // 10 + (float)0.033741, // 11 + (float)0.036807, // 12 + (float)0.039873, // 13 + (float)0.042938, // 14 + (float)0.046003, // 15 + (float)0.049068, // 16 + (float)0.052132, // 17 + (float)0.055195, // 18 + (float)0.058258, // 19 + (float)0.061321, // 20 + (float)0.064383, // 21 + (float)0.067444, // 22 + (float)0.070505, // 23 + (float)0.073565, // 24 + (float)0.076624, // 25 + (float)0.079682, // 26 + (float)0.082740, // 27 + (float)0.085797, // 28 + (float)0.088854, // 29 + (float)0.091909, // 30 + (float)0.094963, // 31 + (float)0.098017, // 32 + (float)0.101070, // 33 + (float)0.104122, // 34 + (float)0.107172, // 35 + (float)0.110222, // 36 + (float)0.113271, // 37 + (float)0.116319, // 38 + (float)0.119365, // 39 + (float)0.122411, // 40 + (float)0.125455, // 41 + (float)0.128498, // 42 + (float)0.131540, // 43 + (float)0.134581, // 44 + (float)0.137620, // 45 + (float)0.140658, // 46 + (float)0.143695, // 47 + (float)0.146730, // 48 + (float)0.149765, // 49 + (float)0.152797, // 50 + (float)0.155828, // 51 + (float)0.158858, // 52 + (float)0.161886, // 53 + (float)0.164913, // 54 + (float)0.167938, // 55 + (float)0.170962, // 56 + (float)0.173984, // 57 + (float)0.177004, // 58 + (float)0.180023, // 59 + (float)0.183040, // 60 + (float)0.186055, // 61 + (float)0.189069, // 62 + (float)0.192080, // 63 + (float)0.195090, // 64 + (float)0.198098, // 65 + (float)0.201105, // 66 + (float)0.204109, // 67 + (float)0.207111, // 68 + (float)0.210112, // 69 + (float)0.213110, // 70 + (float)0.216107, // 71 + (float)0.219101, // 72 + (float)0.222094, // 73 + (float)0.225084, // 74 + (float)0.228072, // 75 + (float)0.231058, // 76 + (float)0.234042, // 77 + (float)0.237024, // 78 + (float)0.240003, // 79 + (float)0.242980, // 80 + (float)0.245955, // 81 + (float)0.248928, // 82 + (float)0.251898, // 83 + (float)0.254866, // 84 + (float)0.257831, // 85 + (float)0.260794, // 86 + (float)0.263755, // 87 + (float)0.266713, // 88 + (float)0.269668, // 89 + (float)0.272621, // 90 + (float)0.275572, // 91 + (float)0.278520, // 92 + (float)0.281465, // 93 + (float)0.284408, // 94 + (float)0.287347, // 95 + (float)0.290285, // 96 + (float)0.293219, // 97 + (float)0.296151, // 98 + (float)0.299080, // 99 + (float)0.302006, // 100 + (float)0.304929, // 101 + (float)0.307850, // 102 + (float)0.310767, // 103 + (float)0.313682, // 104 + (float)0.316593, // 105 + (float)0.319502, // 106 + (float)0.322408, // 107 + (float)0.325310, // 108 + (float)0.328210, // 109 + (float)0.331106, // 110 + (float)0.334000, // 111 + (float)0.336890, // 112 + (float)0.339777, // 113 + (float)0.342661, // 114 + (float)0.345541, // 115 + (float)0.348419, // 116 + (float)0.351293, // 117 + (float)0.354164, // 118 + (float)0.357031, // 119 + (float)0.359895, // 120 + (float)0.362756, // 121 + (float)0.365613, // 122 + (float)0.368467, // 123 + (float)0.371317, // 124 + (float)0.374164, // 125 + (float)0.377007, // 126 + (float)0.379847, // 127 + (float)0.382683, // 128 + (float)0.385516, // 129 + (float)0.388345, // 130 + (float)0.391170, // 131 + (float)0.393992, // 132 + (float)0.396810, // 133 + (float)0.399624, // 134 + (float)0.402435, // 135 + (float)0.405241, // 136 + (float)0.408044, // 137 + (float)0.410843, // 138 + (float)0.413638, // 139 + (float)0.416430, // 140 + (float)0.419217, // 141 + (float)0.422000, // 142 + (float)0.424780, // 143 + (float)0.427555, // 144 + (float)0.430326, // 145 + (float)0.433094, // 146 + (float)0.435857, // 147 + (float)0.438616, // 148 + (float)0.441371, // 149 + (float)0.444122, // 150 + (float)0.446869, // 151 + (float)0.449611, // 152 + (float)0.452350, // 153 + (float)0.455084, // 154 + (float)0.457813, // 155 + (float)0.460539, // 156 + (float)0.463260, // 157 + (float)0.465976, // 158 + (float)0.468689, // 159 + (float)0.471397, // 160 + (float)0.474100, // 161 + (float)0.476799, // 162 + (float)0.479494, // 163 + (float)0.482184, // 164 + (float)0.484869, // 165 + (float)0.487550, // 166 + (float)0.490226, // 167 + (float)0.492898, // 168 + (float)0.495565, // 169 + (float)0.498228, // 170 + (float)0.500885, // 171 + (float)0.503538, // 172 + (float)0.506187, // 173 + (float)0.508830, // 174 + (float)0.511469, // 175 + (float)0.514103, // 176 + (float)0.516732, // 177 + (float)0.519356, // 178 + (float)0.521975, // 179 + (float)0.524590, // 180 + (float)0.527199, // 181 + (float)0.529804, // 182 + (float)0.532403, // 183 + (float)0.534998, // 184 + (float)0.537587, // 185 + (float)0.540171, // 186 + (float)0.542751, // 187 + (float)0.545325, // 188 + (float)0.547894, // 189 + (float)0.550458, // 190 + (float)0.553017, // 191 + (float)0.555570, // 192 + (float)0.558119, // 193 + (float)0.560662, // 194 + (float)0.563199, // 195 + (float)0.565732, // 196 + (float)0.568259, // 197 + (float)0.570781, // 198 + (float)0.573297, // 199 + (float)0.575808, // 200 + (float)0.578314, // 201 + (float)0.580814, // 202 + (float)0.583309, // 203 + (float)0.585798, // 204 + (float)0.588282, // 205 + (float)0.590760, // 206 + (float)0.593232, // 207 + (float)0.595699, // 208 + (float)0.598161, // 209 + (float)0.600616, // 210 + (float)0.603067, // 211 + (float)0.605511, // 212 + (float)0.607950, // 213 + (float)0.610383, // 214 + (float)0.612810, // 215 + (float)0.615232, // 216 + (float)0.617647, // 217 + (float)0.620057, // 218 + (float)0.622461, // 219 + (float)0.624859, // 220 + (float)0.627252, // 221 + (float)0.629638, // 222 + (float)0.632019, // 223 + (float)0.634393, // 224 + (float)0.636762, // 225 + (float)0.639124, // 226 + (float)0.641481, // 227 + (float)0.643832, // 228 + (float)0.646176, // 229 + (float)0.648514, // 230 + (float)0.650847, // 231 + (float)0.653173, // 232 + (float)0.655493, // 233 + (float)0.657807, // 234 + (float)0.660114, // 235 + (float)0.662416, // 236 + (float)0.664711, // 237 + (float)0.667000, // 238 + (float)0.669283, // 239 + (float)0.671559, // 240 + (float)0.673829, // 241 + (float)0.676093, // 242 + (float)0.678350, // 243 + (float)0.680601, // 244 + (float)0.682846, // 245 + (float)0.685084, // 246 + (float)0.687315, // 247 + (float)0.689541, // 248 + (float)0.691759, // 249 + (float)0.693971, // 250 + (float)0.696177, // 251 + (float)0.698376, // 252 + (float)0.700569, // 253 + (float)0.702755, // 254 + (float)0.704934, // 255 + (float)0.707107, // 256 + (float)0.709273, // 257 + (float)0.711432, // 258 + (float)0.713585, // 259 + (float)0.715731, // 260 + (float)0.717870, // 261 + (float)0.720003, // 262 + (float)0.722128, // 263 + (float)0.724247, // 264 + (float)0.726359, // 265 + (float)0.728464, // 266 + (float)0.730563, // 267 + (float)0.732654, // 268 + (float)0.734739, // 269 + (float)0.736817, // 270 + (float)0.738887, // 271 + (float)0.740951, // 272 + (float)0.743008, // 273 + (float)0.745058, // 274 + (float)0.747101, // 275 + (float)0.749136, // 276 + (float)0.751165, // 277 + (float)0.753187, // 278 + (float)0.755201, // 279 + (float)0.757209, // 280 + (float)0.759209, // 281 + (float)0.761202, // 282 + (float)0.763188, // 283 + (float)0.765167, // 284 + (float)0.767139, // 285 + (float)0.769103, // 286 + (float)0.771061, // 287 + (float)0.773010, // 288 + (float)0.774953, // 289 + (float)0.776888, // 290 + (float)0.778817, // 291 + (float)0.780737, // 292 + (float)0.782651, // 293 + (float)0.784557, // 294 + (float)0.786455, // 295 + (float)0.788346, // 296 + (float)0.790230, // 297 + (float)0.792107, // 298 + (float)0.793975, // 299 + (float)0.795837, // 300 + (float)0.797691, // 301 + (float)0.799537, // 302 + (float)0.801376, // 303 + (float)0.803208, // 304 + (float)0.805031, // 305 + (float)0.806848, // 306 + (float)0.808656, // 307 + (float)0.810457, // 308 + (float)0.812251, // 309 + (float)0.814036, // 310 + (float)0.815814, // 311 + (float)0.817585, // 312 + (float)0.819348, // 313 + (float)0.821103, // 314 + (float)0.822850, // 315 + (float)0.824589, // 316 + (float)0.826321, // 317 + (float)0.828045, // 318 + (float)0.829761, // 319 + (float)0.831470, // 320 + (float)0.833170, // 321 + (float)0.834863, // 322 + (float)0.836548, // 323 + (float)0.838225, // 324 + (float)0.839894, // 325 + (float)0.841555, // 326 + (float)0.843208, // 327 + (float)0.844854, // 328 + (float)0.846491, // 329 + (float)0.848120, // 330 + (float)0.849742, // 331 + (float)0.851355, // 332 + (float)0.852961, // 333 + (float)0.854558, // 334 + (float)0.856147, // 335 + (float)0.857729, // 336 + (float)0.859302, // 337 + (float)0.860867, // 338 + (float)0.862424, // 339 + (float)0.863973, // 340 + (float)0.865514, // 341 + (float)0.867046, // 342 + (float)0.868571, // 343 + (float)0.870087, // 344 + (float)0.871595, // 345 + (float)0.873095, // 346 + (float)0.874587, // 347 + (float)0.876070, // 348 + (float)0.877545, // 349 + (float)0.879012, // 350 + (float)0.880471, // 351 + (float)0.881921, // 352 + (float)0.883363, // 353 + (float)0.884797, // 354 + (float)0.886223, // 355 + (float)0.887640, // 356 + (float)0.889048, // 357 + (float)0.890449, // 358 + (float)0.891841, // 359 + (float)0.893224, // 360 + (float)0.894599, // 361 + (float)0.895966, // 362 + (float)0.897325, // 363 + (float)0.898674, // 364 + (float)0.900016, // 365 + (float)0.901349, // 366 + (float)0.902673, // 367 + (float)0.903989, // 368 + (float)0.905297, // 369 + (float)0.906596, // 370 + (float)0.907886, // 371 + (float)0.909168, // 372 + (float)0.910441, // 373 + (float)0.911706, // 374 + (float)0.912962, // 375 + (float)0.914210, // 376 + (float)0.915449, // 377 + (float)0.916679, // 378 + (float)0.917901, // 379 + (float)0.919114, // 380 + (float)0.920318, // 381 + (float)0.921514, // 382 + (float)0.922701, // 383 + (float)0.923880, // 384 + (float)0.925049, // 385 + (float)0.926210, // 386 + (float)0.927363, // 387 + (float)0.928506, // 388 + (float)0.929641, // 389 + (float)0.930767, // 390 + (float)0.931884, // 391 + (float)0.932993, // 392 + (float)0.934093, // 393 + (float)0.935184, // 394 + (float)0.936266, // 395 + (float)0.937339, // 396 + (float)0.938404, // 397 + (float)0.939459, // 398 + (float)0.940506, // 399 + (float)0.941544, // 400 + (float)0.942573, // 401 + (float)0.943593, // 402 + (float)0.944605, // 403 + (float)0.945607, // 404 + (float)0.946601, // 405 + (float)0.947586, // 406 + (float)0.948561, // 407 + (float)0.949528, // 408 + (float)0.950486, // 409 + (float)0.951435, // 410 + (float)0.952375, // 411 + (float)0.953306, // 412 + (float)0.954228, // 413 + (float)0.955141, // 414 + (float)0.956045, // 415 + (float)0.956940, // 416 + (float)0.957826, // 417 + (float)0.958703, // 418 + (float)0.959572, // 419 + (float)0.960431, // 420 + (float)0.961280, // 421 + (float)0.962121, // 422 + (float)0.962953, // 423 + (float)0.963776, // 424 + (float)0.964590, // 425 + (float)0.965394, // 426 + (float)0.966190, // 427 + (float)0.966976, // 428 + (float)0.967754, // 429 + (float)0.968522, // 430 + (float)0.969281, // 431 + (float)0.970031, // 432 + (float)0.970772, // 433 + (float)0.971504, // 434 + (float)0.972226, // 435 + (float)0.972940, // 436 + (float)0.973644, // 437 + (float)0.974339, // 438 + (float)0.975025, // 439 + (float)0.975702, // 440 + (float)0.976370, // 441 + (float)0.977028, // 442 + (float)0.977677, // 443 + (float)0.978317, // 444 + (float)0.978948, // 445 + (float)0.979570, // 446 + (float)0.980182, // 447 + (float)0.980785, // 448 + (float)0.981379, // 449 + (float)0.981964, // 450 + (float)0.982539, // 451 + (float)0.983105, // 452 + (float)0.983662, // 453 + (float)0.984210, // 454 + (float)0.984749, // 455 + (float)0.985278, // 456 + (float)0.985798, // 457 + (float)0.986308, // 458 + (float)0.986809, // 459 + (float)0.987301, // 460 + (float)0.987784, // 461 + (float)0.988258, // 462 + (float)0.988722, // 463 + (float)0.989177, // 464 + (float)0.989622, // 465 + (float)0.990058, // 466 + (float)0.990485, // 467 + (float)0.990903, // 468 + (float)0.991311, // 469 + (float)0.991710, // 470 + (float)0.992099, // 471 + (float)0.992480, // 472 + (float)0.992850, // 473 + (float)0.993212, // 474 + (float)0.993564, // 475 + (float)0.993907, // 476 + (float)0.994240, // 477 + (float)0.994565, // 478 + (float)0.994879, // 479 + (float)0.995185, // 480 + (float)0.995481, // 481 + (float)0.995767, // 482 + (float)0.996045, // 483 + (float)0.996313, // 484 + (float)0.996571, // 485 + (float)0.996820, // 486 + (float)0.997060, // 487 + (float)0.997290, // 488 + (float)0.997511, // 489 + (float)0.997723, // 490 + (float)0.997925, // 491 + (float)0.998118, // 492 + (float)0.998302, // 493 + (float)0.998476, // 494 + (float)0.998640, // 495 + (float)0.998795, // 496 + (float)0.998941, // 497 + (float)0.999078, // 498 + (float)0.999205, // 499 + (float)0.999322, // 500 + (float)0.999431, // 501 + (float)0.999529, // 502 + (float)0.999619, // 503 + (float)0.999699, // 504 + (float)0.999769, // 505 + (float)0.999831, // 506 + (float)0.999882, // 507 + (float)0.999925, // 508 + (float)0.999958, // 509 + (float)0.999981, // 510 + (float)0.999995, // 511 +}; + +float *CosTableF = &SinTableF[512]; + +//--------------------------------------------------------------- +SLONG Proportions[] = +{ + 11585, + 11563, + 11540, + 11518, + 11495, + 11473, + 11450, + 11428, + 11406, + 11383, + 11361, + 11339, + 11317, + 11295, + 11273, + 11251, + 11229, + 11207, + 11185, + 11164, + 11142, + 11120, + 11099, + 11077, + 11056, + 11034, + 11013, + 10991, + 10970, + 10949, + 10928, + 10906, + 10885, + 10864, + 10843, + 10822, + 10801, + 10781, + 10760, + 10739, + 10718, + 10698, + 10677, + 10657, + 10636, + 10616, + 10596, + 10575, + 10555, + 10535, + 10515, + 10495, + 10475, + 10455, + 10435, + 10415, + 10396, + 10376, + 10356, + 10337, + 10317, + 10298, + 10279, + 10259, + 10240, + 10221, + 10202, + 10183, + 10164, + 10145, + 10126, + 10107, + 10088, + 10070, + 10051, + 10033, + 10014, + 9996, + 9978, + 9959, + 9941, + 9923, + 9905, + 9887, + 9869, + 9851, + 9834, + 9816, + 9798, + 9781, + 9764, + 9746, + 9729, + 9712, + 9694, + 9677, + 9660, + 9643, + 9627, + 9610, + 9593, + 9577, + 9560, + 9544, + 9527, + 9511, + 9495, + 9479, + 9462, + 9447, + 9431, + 9415, + 9399, + 9383, + 9368, + 9352, + 9337, + 9322, + 9306, + 9291, + 9276, + 9261, + 9246, + 9232, + 9217, + 9202, + 9188, + 9173, + 9159, + 9145, + 9130, + 9116, + 9102, + 9089, + 9075, + 9061, + 9047, + 9034, + 9020, + 9007, + 8994, + 8981, + 8968, + 8955, + 8942, + 8929, + 8916, + 8904, + 8891, + 8879, + 8866, + 8854, + 8842, + 8830, + 8818, + 8807, + 8795, + 8783, + 8772, + 8760, + 8749, + 8738, + 8727, + 8716, + 8705, + 8694, + 8684, + 8673, + 8662, + 8652, + 8642, + 8632, + 8622, + 8612, + 8602, + 8592, + 8583, + 8573, + 8564, + 8555, + 8545, + 8536, + 8527, + 8519, + 8510, + 8501, + 8493, + 8484, + 8476, + 8468, + 8460, + 8452, + 8444, + 8436, + 8429, + 8421, + 8414, + 8407, + 8400, + 8393, + 8386, + 8379, + 8372, + 8366, + 8359, + 8353, + 8347, + 8341, + 8335, + 8329, + 8323, + 8318, + 8312, + 8307, + 8302, + 8296, + 8291, + 8287, + 8282, + 8277, + 8273, + 8268, + 8264, + 8260, + 8256, + 8252, + 8248, + 8244, + 8241, + 8237, + 8234, + 8231, + 8228, + 8225, + 8222, + 8220, + 8217, + 8215, + 8212, + 8210, + 8208, + 8206, + 8204, + 8203, + 8201, + 8200, + 8198, + 8197, + 8196, + 8195, + 8194, + 8194, + 8193, + 8193, + 8192, + 8192, + 8192, + 8192, + 8192, + 8193, + 8193, + 8194, + 8194, + 8195, + 8196, + 8197, + 8198, + 8200, + 8201, + 8203, + 8204, + 8206, + 8208, + 8210, + 8212, + 8215, + 8217, + 8220, + 8222, + 8225, + 8228, + 8231, + 8234, + 8237, + 8241, + 8244, + 8248, + 8252, + 8256, + 8260, + 8264, + 8268, + 8273, + 8277, + 8282, + 8287, + 8291, + 8296, + 8302, + 8307, + 8312, + 8318, + 8323, + 8329, + 8335, + 8341, + 8347, + 8353, + 8359, + 8366, + 8372, + 8379, + 8386, + 8393, + 8400, + 8407, + 8414, + 8421, + 8429, + 8436, + 8444, + 8452, + 8460, + 8468, + 8476, + 8484, + 8493, + 8501, + 8510, + 8519, + 8527, + 8536, + 8545, + 8555, + 8564, + 8573, + 8583, + 8592, + 8602, + 8612, + 8622, + 8632, + 8642, + 8652, + 8662, + 8673, + 8684, + 8694, + 8705, + 8716, + 8727, + 8738, + 8749, + 8760, + 8772, + 8783, + 8795, + 8807, + 8818, + 8830, + 8842, + 8854, + 8866, + 8879, + 8891, + 8904, + 8916, + 8929, + 8942, + 8955, + 8968, + 8981, + 8994, + 9007, + 9020, + 9034, + 9047, + 9061, + 9075, + 9089, + 9102, + 9116, + 9130, + 9145, + 9159, + 9173, + 9188, + 9202, + 9217, + 9232, + 9246, + 9261, + 9276, + 9291, + 9306, + 9322, + 9337, + 9352, + 9368, + 9383, + 9399, + 9415, + 9431, + 9447, + 9462, + 9479, + 9495, + 9511, + 9527, + 9544, + 9560, + 9577, + 9593, + 9610, + 9627, + 9643, + 9660, + 9677, + 9694, + 9712, + 9729, + 9746, + 9764, + 9781, + 9798, + 9816, + 9834, + 9851, + 9869, + 9887, + 9905, + 9923, + 9941, + 9959, + 9978, + 9996, + 10014, + 10033, + 10051, + 10070, + 10088, + 10107, + 10126, + 10145, + 10164, + 10183, + 10202, + 10221, + 10240, + 10259, + 10279, + 10298, + 10317, + 10337, + 10356, + 10376, + 10396, + 10415, + 10435, + 10455, + 10475, + 10495, + 10515, + 10535, + 10555, + 10575, + 10596, + 10616, + 10636, + 10657, + 10677, + 10698, + 10718, + 10739, + 10760, + 10781, + 10801, + 10822, + 10843, + 10864, + 10885, + 10906, + 10928, + 10949, + 10970, + 10991, + 11013, + 11034, + 11056, + 11077, + 11099, + 11120, + 11142, + 11164, + 11185, + 11207, + 11229, + 11251, + 11273, + 11295, + 11317, + 11339, + 11361, + 11383, + 11406, + 11428, + 11450, + 11473, + 11495, + 11518, + 11540, + 11563, + 11585, +}; + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Windows/D3D.cpp b/MFLib1/Source/C/Windows/D3D.cpp new file mode 100644 index 0000000..2061ed2 --- /dev/null +++ b/MFLib1/Source/C/Windows/D3D.cpp @@ -0,0 +1,363 @@ +// Draw3D.cpp - Windows. +// Guy Simmons, 8th May 1997. + + +#define INITGUID + +#include + + +BOOL DeviceFound = FALSE, + GotD3D2 = FALSE, + HasHardware = FALSE; +ULONG RequestFlags = 0; +SLONG DeviceBitDepth; +D3DDEVICEDESC d3d_DeviceDesc; +GUID GUIDDevice; +IDirect3DDevice2 *lp_D3D_Device; +LPDIRECT3D lp_D3D = NULL; +LPDIRECT3D2 lp_D3D_2 = NULL; +LPDIRECTDRAWSURFACE lp_DD_ZBuffer; + +HRESULT WINAPI EnumDeviceCallback(LPGUID,LPTSTR,LPTSTR,LPD3DDEVICEDESC,LPD3DDEVICEDESC,LPVOID); + +//--------------------------------------------------------------- + +void SetupD3D2(void) +{ + HRESULT dd_result; + + + if(!GotD3D2) + { + dd_result = lp_DD->QueryInterface(IID_IDirect3D,(LPVOID*)&lp_D3D); + if(dd_result==DD_OK) + { + dd_result = lp_D3D->QueryInterface(IID_IDirect3D2,(LPVOID*)&lp_D3D_2); + if(dd_result==DD_OK) + { + LogText("D3D2 installed.\n"); + GotD3D2 = TRUE; + } + } + } + return; +} + +//--------------------------------------------------------------- + +void ResetD3D2(void) +{ + HRESULT dd_result; + + + if(lp_DD_ZBuffer) + { + dd_result = lp_DD_ZBuffer->Release(); + if(dd_result!=DD_OK) + { + LogText("error: %ld - Unable to release ZBuffer\n",dd_result&0xff); + } + } + + if(lp_D3D_2) + { + dd_result = lp_D3D_2->Release(); + if(dd_result!=DD_OK) + { + LogText("error: %ld - Unable to release Direct3D2\n",dd_result&0xff); + } + } + if(lp_D3D) + { + dd_result = lp_D3D->Release(); + if(dd_result!=DD_OK) + { + LogText("error: %ld - Unable to release Direct3D\n",dd_result&0xff); + } + } +} + +//--------------------------------------------------------------- + +BOOL ChooseD3DDevice(ULONG flags) +{ + DDSURFACEDESC dd_sd; + HRESULT dd_result; + + + if(GotD3D2) + { + ZeroMemory(&dd_sd,sizeof(dd_sd)); + dd_sd.dwSize = sizeof(dd_sd); + dd_result = lp_DD_FrontSurface->GetSurfaceDesc(&dd_sd); + if(dd_result==DD_OK) + { + switch(dd_sd.ddpfPixelFormat.dwRGBBitCount) + { + case 1: DeviceBitDepth = DDBD_1;break; + case 2: DeviceBitDepth = DDBD_2;break; + case 4: DeviceBitDepth = DDBD_4;break; + case 8: DeviceBitDepth = DDBD_8;break; + case 16: DeviceBitDepth = DDBD_16;break; + case 24: DeviceBitDepth = DDBD_24;break; + case 32: DeviceBitDepth = DDBD_32;break; + default: DeviceBitDepth = 0; + } + DeviceFound = FALSE; + RequestFlags = flags; + dd_result = lp_D3D_2->EnumDevices(EnumDeviceCallback,NULL); + + if(dd_result==D3D_OK && DeviceFound) + { + LogText("Got required device.\n"); + + memset(&dd_sd, 0, sizeof(DDSURFACEDESC)); + + dd_sd.dwSize = sizeof(DDSURFACEDESC); + dd_sd.dwFlags = DDSD_WIDTH | + DDSD_HEIGHT | + DDSD_CAPS | + DDSD_ZBUFFERBITDEPTH; + dd_sd.dwWidth = WorkScreenPixelWidth; + dd_sd.dwHeight = WorkScreenHeight; + + if(HasHardware) + { + LogText("ZBuffer in Video memory\n"); + dd_sd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; + } + else + { + LogText("ZBuffer in System memory\n"); + dd_sd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_SYSTEMMEMORY; + } + + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth & DDBD_32) { dd_sd.dwZBufferBitDepth=32;LogText("32 bit zbuffer\n"); } + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth & DDBD_24) { dd_sd.dwZBufferBitDepth=24;LogText("24 bit zbuffer\n"); } + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth & DDBD_16) { dd_sd.dwZBufferBitDepth=16;LogText("16 bit zbuffer\n"); } + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth & DDBD_8 ) { dd_sd.dwZBufferBitDepth=8;LogText("8 bit zbuffer\n"); } +/* + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth&DDBD_32) { dd_sd.dwZBufferBitDepth=32; } + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth&DDBD_24) { dd_sd.dwZBufferBitDepth=24; } + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth&DDBD_16) { dd_sd.dwZBufferBitDepth=16; } + if(d3d_DeviceDesc.dwDeviceZBufferBitDepth&DDBD_8 ) { dd_sd.dwZBufferBitDepth=8; } +*/ + dd_result = lp_DD->CreateSurface(&dd_sd,&lp_DD_ZBuffer,NULL); + if(dd_result!=DD_OK) + { + LogText("error: %ld - Can't create ZBuffer\n",dd_result&0xffff); + goto exit_false; + } + + dd_result = lp_DD_BackSurface->AddAttachedSurface(lp_DD_ZBuffer); + if(dd_result!=DD_OK) + { + LogText("Can't attach ZBuffer\n"); + goto exit_false; + } + + dd_result = lp_D3D_2->CreateDevice(GUIDDevice,lp_DD_BackSurface,&lp_D3D_Device); + if(dd_result!=DD_OK) + { + LogText("Can't create direct draw device\n"); + goto exit_false; + } + return TRUE; + } + } + } +exit_false: + return FALSE; +} + +//--------------------------------------------------------------- + +HRESULT WINAPI EnumDeviceCallback( + LPGUID lpGUID, + LPTSTR lpszDeviceDesc, + LPTSTR lpszDeviceName, + LPD3DDEVICEDESC lpd3dHWDeviceDesc, + LPD3DDEVICEDESC lpd3dSWDeviceDesc, + LPVOID lpUserArg + ) +{ + LPD3DDEVICEDESC lp_d3d_device_desc; + + + lpUserArg = lpUserArg; + + HasHardware = (lpd3dHWDeviceDesc->dcmColorModel!=0); + + // Do we want hardware & do we have hardware? + if(RequestFlags&D3D_HARDWARE && !HasHardware) + return D3DENUMRET_OK; + + lp_d3d_device_desc = (HasHardware ? lpd3dHWDeviceDesc : lpd3dSWDeviceDesc); + + // Do we want a ramp device & do we have a ramp device? + if(!(RequestFlags&D3D_RAMP) && lp_d3d_device_desc->dcmColorModel==D3DCOLOR_MONO) + return D3DENUMRET_OK; + + // Check the device supports the correct rendering depth. + if(!(lp_d3d_device_desc->dwDeviceRenderBitDepth&DeviceBitDepth)) + return D3DENUMRET_OK; + + // Check the device supports everything we want it to. + if(lp_d3d_device_desc->dcmColorModel==D3DCOLOR_MONO) // Ramp device. + { + if ( + (RequestFlags&D3D_GOURAUD) && + !(lp_d3d_device_desc->dpcTriCaps.dwShadeCaps&D3DPSHADECAPS_COLORGOURAUDMONO) + ) + return D3DENUMRET_OK; // No Ramp gouraud shading. + } + else // RGB device. + { + if ( + (RequestFlags&D3D_GOURAUD) && + !(lp_d3d_device_desc->dpcTriCaps.dwShadeCaps&D3DPSHADECAPS_COLORGOURAUDRGB) + ) + return D3DENUMRET_OK; // No RGB gouraud shading. + } + + DeviceFound = TRUE; + CopyMemory(&GUIDDevice,lpGUID,sizeof(GUID)); +// strcpy(DeviceDesc, lpszDeviceDesc); +// strcpy(DeviceName, lpszDeviceName); + CopyMemory(&d3d_DeviceDesc,lp_d3d_device_desc,sizeof(D3DDEVICEDESC)); + + LogText("DeviceDesc - %s\nDeviceName - %s\n\n",lpszDeviceDesc,lpszDeviceName); + + return D3DENUMRET_CANCEL; +} + +//--------------------------------------------------------------- +/* +HRESULT WINAPI EnumDeviceCallback( + LPGUID lpGUID, + LPTSTR lpszDeviceDesc, + LPTSTR lpszDeviceName, + LPD3DDEVICEDESC lpd3dHWDeviceDesc, + LPD3DDEVICEDESC lpd3dSWDeviceDesc, + LPVOID lpUserArg + ) +{ + LPD3DDEVICEDESC lpd3dDeviceDesc; + + + lpUserArg = lpUserArg; + +#ifdef _DEBUG + HardwareDevice = FALSE; +#else + // If there is no hardware support the color model is zero. + HardwareDevice = (0 != lpd3dHWDeviceDesc->dcmColorModel); +#endif + + lpd3dDeviceDesc = (HardwareDevice ? lpd3dHWDeviceDesc : + lpd3dSWDeviceDesc); + +#ifdef _DEBUG + if(HardwareDevice) + return D3DENUMRET_OK; +#else + if(!HardwareDevice) + return D3DENUMRET_OK; +#endif + + LogText("DeviceDesc - %s\nDeviceName - %s\n\n",lpszDeviceDesc,lpszDeviceName); + + // Does the device render at the depth we want? + if(!(lpd3dDeviceDesc->dwDeviceRenderBitDepth&device_bit_depth)) + { + // If not, skip this device. + + return D3DENUMRET_OK; + } + + // The device must support Gouraud-shaded triangles. + if(D3DCOLOR_MONO == lpd3dDeviceDesc->dcmColorModel) + { + if (!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & + D3DPSHADECAPS_COLORGOURAUDMONO)) + { + // No Gouraud shading. Skip this device. + LogText("No Gouraud shading\n"); + + return D3DENUMRET_OK; + } + } + else + { + if(!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & + D3DPSHADECAPS_COLORGOURAUDRGB)) + { + // No Gouraud shading. Skip this device. + LogText("No Gouraud shading\n"); + + return D3DENUMRET_OK; + } + } +#ifdef _DEBUG + if ( + !HardwareDevice && !DeviceFound && + (D3DCOLOR_RGB == lpd3dDeviceDesc->dcmColorModel) + ) + { + // If this is software RGB and we already have found + // a software monochromatic renderer, we are not + // interested. Skip this device. + +// return D3DENUMRET_OK; + + // This is a device we are interested in. Save the details. + DeviceFound = TRUE; + CopyMemory(&guid_device, lpGUID, sizeof(GUID)); + strcpy(DeviceDesc, lpszDeviceDesc); + strcpy(DeviceName, lpszDeviceName); + + CopyMemory(&d3d_HWDeviceDesc, lpd3dHWDeviceDesc, + sizeof(D3DDEVICEDESC)); + CopyMemory(&d3d_SWDeviceDesc, lpd3dSWDeviceDesc, + sizeof(D3DDEVICEDESC)); + + CopyMemory(&d3d_DeviceDesc, lpd3dDeviceDesc, + sizeof(D3DDEVICEDESC)); + + return D3DENUMRET_CANCEL; + } +#else + // This is a device we are interested in. Save the details. + DeviceFound = TRUE; + CopyMemory(&guid_device, lpGUID, sizeof(GUID)); + strcpy(DeviceDesc, lpszDeviceDesc); + strcpy(DeviceName, lpszDeviceName); + + CopyMemory(&d3d_HWDeviceDesc, lpd3dHWDeviceDesc, + sizeof(D3DDEVICEDESC)); + CopyMemory(&d3d_SWDeviceDesc, lpd3dSWDeviceDesc, + sizeof(D3DDEVICEDESC)); + + CopyMemory(&d3d_DeviceDesc, lpd3dDeviceDesc, + sizeof(D3DDEVICEDESC)); +#endif + +#ifdef _DEBUG +// return D3DENUMRET_CANCEL; + return D3DENUMRET_OK; +#else + // If this is a hardware device, we have found + // what we are looking for. + if(HardwareDevice) + { + LogText("We have a hardware device\n"); + return D3DENUMRET_CANCEL; + } + + // Otherwise, keep looking. + return D3DENUMRET_OK; +#endif +} +*/ +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Windows/Display.cpp b/MFLib1/Source/C/Windows/Display.cpp new file mode 100644 index 0000000..522a317 --- /dev/null +++ b/MFLib1/Source/C/Windows/Display.cpp @@ -0,0 +1,926 @@ +// Display.cpp - Windows. +// Guy Simmons, 1st February 1997. + + +#include + +#define MF_DD2 + + +BOOL EmulateLoRes = FALSE, + Got3DFX = FALSE; +UBYTE DisplayActive = 0, + DisplayState = 0, + *WorkScreen, + WorkScreenDepth; +SLONG DisplayMode = DISPLAY_MODE_NONE, + WorkScreenHeight, + WorkScreenWidth, + WorkScreenPixelWidth; +GUID DevicePrimary, + Device3DFX; +DDSURFACEDESC DD_DisplayDesc; +LPDIRECTDRAW lp_DD = NULL; // Main DirectDraw object +LPDIRECTDRAW2 lp_DD_2 = NULL; // Main DirectDraw2 object +LPDIRECTDRAWCLIPPER lp_DD_Clipper = NULL; +LPDIRECTDRAWSURFACE lp_DD_BackSurface = NULL, + lp_DD_FrontSurface = NULL, + lp_DD_WorkSurface = NULL; + +volatile UBYTE MFShellActive = 0; + + + +SLONG CreateSurfaces(void); +SLONG DestroySurfaces(void); +void RestoreSurfaces(void); +HRESULT CALLBACK DisplayModesCallback(LPDDSURFACEDESC p_dd_sd, LPVOID ignore); + +extern HANDLE hShellThread; +extern HWND hShellWindow; +extern RECT ShellRect; +extern void SetDrawFunctions(ULONG depth); + +BOOL WINAPI EnumDeviceCallback(GUID FAR *lpGUID,LPSTR lpDriverDescription,LPSTR lpDriverName,LPVOID lpContext); + +//--------------------------------------------------------------- + +SLONG OpenDisplay(ULONG width, ULONG height, ULONG depth, ULONG flags) +{ + SLONG result = DisplayCreationError; + HRESULT dd_result; + + + WorkScreenHeight = height; + WorkScreenWidth = width; + WorkScreenPixelWidth = width; + + DisplayActive = 0; + + if(hShellThread) + { + // Create Direct Draw Object. +#ifdef _DEBUG + flags = flags; + dd_result = DirectDrawCreate((GUID*)DDCREATE_EMULATIONONLY,&lp_DD,NULL); +#else + dd_result = DirectDrawEnumerate(EnumDeviceCallback,NULL); + + if(Got3DFX && flags&FLAGS_USE_3DFX) + dd_result = DirectDrawCreate(&Device3DFX,&lp_DD,NULL); + else + dd_result = DirectDrawCreate(NULL,&lp_DD,NULL); +#endif + if(dd_result==DD_OK) + { +#ifdef MF_DD2 + dd_result = lp_DD->QueryInterface(IID_IDirectDraw2,(LPVOID *)&lp_DD_2); +#endif + + if(dd_result==DD_OK) + { + DisplayState |= DS_DIRECT_DRAW_ACTIVE; + +#ifdef _DEBUG + // Normal mode for Debug. + #ifdef MF_DD2 + dd_result = lp_DD_2->SetCooperativeLevel(hShellWindow,DDSCL_NORMAL); + #else + dd_result = lp_DD->SetCooperativeLevel(hShellWindow,DDSCL_NORMAL); + #endif + +#else + // Exclusive mode for Release. + #ifdef MF_DD2 + dd_result = lp_DD_2->SetCooperativeLevel(hShellWindow,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN); //|DDSCL_ALLOWMODEX); + #else + dd_result = lp_DD->SetCooperativeLevel(hShellWindow,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN); //|DDSCL_ALLOWMODEX); + #endif + + // Find all the available display modes. + #ifdef MF_DD2 + lp_DD_2->EnumDisplayModes(0,NULL,0,DisplayModesCallback); + #else + lp_DD->EnumDisplayModes(0,NULL,0,DisplayModesCallback); + #endif + +#endif + InitPalettes(); + + if(SetDisplay(width,height,depth)==NoError) + { + SetupD3D2(); + return NoError; + } + } + } + } + + return result; +} + +//--------------------------------------------------------------- + +SLONG CloseDisplay(void) +{ + HRESULT dd_result; + + +/* + if(DisplayState&DS_THREAD_ACTIVE) + { + SendMessage(hShellWindow,WM_CLOSE,0,0); + WaitForSingleObject(hShellThread,4000); + CloseHandle(hShellThread); + } +*/ + + DestroySurfaces(); + DestroyPalettes(); + + +#ifdef MF_DD2 + if(lp_DD_2) + dd_result = lp_DD_2->SetCooperativeLevel(hShellWindow,DDSCL_NORMAL); +#else + if(lp_DD) + dd_result = lp_DD->SetCooperativeLevel(hShellWindow,DDSCL_NORMAL); +#endif +/* + ResetD3D2(); + + if(lp_DD_2) + { + dd_result = lp_DD_2->Release(); + if(dd_result!=DD_OK) + { + LogText("error: %ld - Unable to release DirectDraw2\n",dd_result&0xff); + } + else + lp_DD_2 = NULL; + } +*/ + if(lp_DD) + { + dd_result = lp_DD->Release(); + if(dd_result!=DD_OK) + { + LogText("error: %ld - Unable to release DirectDraw\n",dd_result&0xff); + } + else + lp_DD = NULL; + } + return NoError; +} + +//--------------------------------------------------------------- + +SLONG SetDisplay(ULONG width,ULONG height,ULONG depth) +{ + SLONG mode = DISPLAY_MODE_NONE; + HRESULT dd_result; + + + if(DisplayState&DS_SCREEN_LOCKED) + { + ERROR_MSG(0,"Screen Locked"); + } + if(DisplayState&DS_DIRECT_DRAW_ACTIVE) + { + mode = DisplayModeAvailable(width,height,depth); + if(mode) + { + // Clear away the old display stuff. + DestroySurfaces(); + DestroyPalettes(); + + // Initially force + WorkScreenHeight = height; + WorkScreenWidth = width; + WorkScreenPixelWidth = width; + WorkScreenDepth = depth; + + // Set display size. +#ifdef _RELEASE + if(EmulateLoRes) + { + #ifdef MF_DD2 + dd_result = lp_DD_2->SetDisplayMode(640,480,8,0,0); + #else + dd_result = lp_DD->SetDisplayMode(640,480,8); + #endif + } + else + { + #ifdef MF_DD2 + dd_result = lp_DD_2->SetDisplayMode(width,height,depth,0,0); + #else + dd_result = lp_DD->SetDisplayMode(width,height,depth); + #endif + } +#else + DWORD dw_style; + RECT temp_rect; + + + dw_style = GetWindowStyle(hShellWindow); + dw_style &= ~WS_POPUP; + dw_style |= WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME|WS_MINIMIZEBOX; + SetWindowLong(hShellWindow,GWL_STYLE,dw_style); + + SetRect(&temp_rect,0,0,width,height); + AdjustWindowRectEx ( + &temp_rect, + GetWindowStyle(hShellWindow), + GetMenu(hShellWindow) != NULL, + GetWindowExStyle(hShellWindow) + ); + SetWindowPos( + hShellWindow, + NULL, + 0,0, + temp_rect.right-temp_rect.left, + temp_rect.bottom-temp_rect.top, + SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE + ); + dd_result = DD_OK; +#endif + + if(dd_result==DD_OK) + { + // Create the new display stuff. + DisplayState |= DS_DISPLAY_MODE_SET; + DisplayMode = mode; +#ifdef _DEBUG + dd_result = lp_DD_2->GetDisplayMode(&DD_DisplayDesc); +#else + DD_DisplayDesc = DisplayModes[DisplayMode].DD_ModeDesc; +#endif + CreateSurfaces(); + CreatePalettes(); + + SetWorkWindowBounds(0,0,width,height); + SetDrawFunctions(depth); + + return NoError; + } + else + { + LogText("Unable to set display mode. Error: %ld\n",dd_result&0xffff); +// ERROR_MSG((dd_result==DD_OK),"Unable to set display mode."); + } + } + else + { + LogText("\nDisplay Mode not available\n"); +// ERROR_MSG((dd_result==DD_OK),"Display mode unavailable."); + } + } + return -1; +} + +//--------------------------------------------------------------- + +SLONG CreateSurfaces(void) +{ +#ifdef _RELEASE + DDSCAPS dd_scaps; +#endif + DDSURFACEDESC dd_sd; + HRESULT dd_result; + + + + ZeroMemory(&dd_sd,sizeof(dd_sd)); + dd_sd.dwSize = sizeof(dd_sd); +#ifdef _DEBUG + if(lp_DD_FrontSurface==NULL) + { + // Create DEBUG front surface. + dd_sd.dwFlags = DDSD_CAPS; + dd_sd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + #ifdef MF_DD2 + dd_result = lp_DD_2->CreateSurface(&dd_sd,&lp_DD_FrontSurface,NULL); + #else + dd_result = lp_DD->CreateSurface(&dd_sd,&lp_DD_FrontSurface,NULL); + #endif + ERROR_MSG((dd_result==DD_OK),"Can't create lp_DD_FrontSurface"); + } + + if(lp_DD_BackSurface==NULL) + { + // Create DEBUG back surface. + dd_sd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH; + dd_sd.dwHeight = WorkScreenHeight; + dd_sd.dwWidth = WorkScreenWidth; + dd_sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_3DDEVICE; //|DDSCAPS_SYSTEMMEMORY; + #ifdef MF_DD2 + dd_result = lp_DD_2->CreateSurface(&dd_sd,&lp_DD_BackSurface,NULL); + #else + dd_result = lp_DD->CreateSurface(&dd_sd,&lp_DD_BackSurface,NULL); + #endif + ERROR_MSG((dd_result==DD_OK),"Can't create lp_DD_BackSurface"); + } + + if(lp_DD_Clipper==NULL) + { + // Create DEBUG clipper. + #ifdef DD2 + dd_result = lp_DD_2->CreateClipper(0,&lp_DD_Clipper,NULL); + #else + dd_result = lp_DD->CreateClipper(0,&lp_DD_Clipper,NULL); + #endif + ERROR_MSG((dd_result==DD_OK),"Can't create lp_DD_Clipper"); + + // Set clipper window handle. + dd_result = lp_DD_Clipper->SetHWnd(0,hShellWindow); + ERROR_MSG((dd_result==DD_OK),"Can't set lp_DD_Clipper window handle"); + + // Attach clipper to front surface. + lp_DD_FrontSurface->SetClipper(lp_DD_Clipper); + ERROR_MSG((dd_result==DD_OK),"Can't attach lp_DD_Clipper to lp_DD_FrontSurface"); + } +#else + if(lp_DD_FrontSurface==NULL) + { + // Create RELEASE front & back Surfaces. + dd_sd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT; + dd_sd.ddsCaps.dwCaps = DDSCAPS_COMPLEX|DDSCAPS_FLIP|DDSCAPS_PRIMARYSURFACE|DDSCAPS_3DDEVICE; + dd_sd.dwBackBufferCount = 1; + #ifdef MF_DD2 + dd_result = lp_DD_2->CreateSurface(&dd_sd,&lp_DD_FrontSurface,NULL); + #else + dd_result = lp_DD->CreateSurface(&dd_sd,&lp_DD_FrontSurface,NULL); + #endif + ERROR_MSG((dd_result==DD_OK),"Can't create lp_DD_FrontSurface"); + + // Extract RELEASE Back surface. + dd_scaps.dwCaps = DDSCAPS_BACKBUFFER; + dd_result = lp_DD_FrontSurface->GetAttachedSurface(&dd_scaps,&lp_DD_BackSurface); + ERROR_MSG((dd_result==DD_OK),"Can't extract lp_DD_BackSurface"); + } +#endif + if(lp_DD_WorkSurface==NULL) + { + // Create work surface. + dd_sd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH; + dd_sd.dwHeight = WorkScreenHeight; + dd_sd.dwWidth = WorkScreenWidth; + dd_sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY; +#ifdef MF_DD2 + dd_result = lp_DD_2->CreateSurface(&dd_sd,&lp_DD_WorkSurface,NULL); +#else + dd_result = lp_DD->CreateSurface(&dd_sd,&lp_DD_WorkSurface,NULL); +#endif + ERROR_MSG((dd_result==DD_OK),"Can't create lp_DD_WorkSurface"); + } + + DisplayState |= DS_CREATED_SURFACES; + + return NoError; +} + +//--------------------------------------------------------------- + +SLONG DestroySurfaces(void) +{ + HRESULT dd_result; + + +#ifdef _DEBUG + if(lp_DD_Clipper) + { + lp_DD_Clipper->Release(); + lp_DD_Clipper = NULL; + } + if(lp_DD_BackSurface) + { + dd_result = lp_DD_BackSurface->Release(); +// if(dd_result!=DD_OK) +// LogText("error: %ld - Unable to release lp_DD_BackSurface\n",dd_result&0xffff); + } +#endif + if(lp_DD_FrontSurface) + { + dd_result = lp_DD_FrontSurface->Release(); + if(dd_result!=DD_OK) + LogText("error: %ld - Unable to release lp_DD_FrontSurface\n",dd_result&0xffff); + lp_DD_FrontSurface = NULL; + lp_DD_BackSurface = NULL; + } + if(lp_DD_WorkSurface) + { + dd_result = lp_DD_WorkSurface->Release(); + if(dd_result!=DD_OK) + LogText("error: %ld - Unable to release lp_DD_WorkSurface\n",dd_result&0xffff); + lp_DD_WorkSurface = NULL; + } + DisplayState &= ~(DS_CREATED_SURFACES); + + return NoError; +} + +//--------------------------------------------------------------- + +void ClearDisplay(void) +{ + DDBLTFX dd_bltfx; + HRESULT dd_result; + + + dd_bltfx.dwSize = sizeof(dd_bltfx); + dd_bltfx.dwFillColor = 0; + dd_result = lp_DD_FrontSurface->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT,&dd_bltfx); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + lp_DD_FrontSurface->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT,&dd_bltfx); + break; + } +} + +//--------------------------------------------------------------- + +void FadeDisplay(UBYTE mode) +{ + switch(mode) + { + case FADE_IN: + break; + case FADE_OUT: + break; + } +} + +//--------------------------------------------------------------- + +void *LockWorkScreen(void) +{ + DDSURFACEDESC dd_sd; + HRESULT dd_result; + + + if(lp_DD_WorkSurface) + { + dd_sd.dwSize = sizeof(dd_sd); + dd_result = lp_DD_WorkSurface->Lock(NULL,&dd_sd,DDLOCK_WAIT,NULL); + switch(dd_result) + { + case DD_OK: + WorkScreenWidth = dd_sd.lPitch; + WorkScreen = (UBYTE*)dd_sd.lpSurface; + SetWorkWindow(); + DisplayState |= DS_SCREEN_LOCKED; + return dd_sd.lpSurface; + case DDERR_SURFACELOST: + RestoreSurfaces(); + return 0; + } + } + return 0; +} + +//--------------------------------------------------------------- + +void UnlockWorkScreen(void) +{ + HRESULT dd_result; + + + if(lp_DD_WorkSurface) + { + dd_result = lp_DD_WorkSurface->Unlock(NULL); + switch(dd_result) + { + case DD_OK: + DisplayState &= ~(DS_SCREEN_LOCKED); + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + } + } +} + +//--------------------------------------------------------------- + +void ShowWorkScreen(ULONG flags) +{ + HRESULT dd_result; + + + if(lp_DD_WorkSurface==NULL) + return; + + // Apparently Blt is better than BltFst for System to Display blits. + + if(flags&DS_WAIT_VBI) + { +#ifdef MF_DD2 + dd_result = lp_DD_2->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#else + dd_result = lp_DD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#endif + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); +#ifdef MF_DD2 + lp_DD_2->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#else + lp_DD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#endif + break; + } + } + + if(flags&DS_DO_FLIP) + { +#ifdef _DEBUG + dd_result = lp_DD_BackSurface->Blt ( + &ShellRect, + lp_DD_WorkSurface, + NULL, + DDBLT_WAIT, + NULL + ); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Blt failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +/* + dd_result = lp_DD_FrontSurface->Blt ( + &ShellRect, + lp_DD_BackSurface, + NULL, + DDBLT_WAIT, + NULL + ); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Flip failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +*/ +#else + dd_result = lp_DD_BackSurface->Blt ( + NULL, + lp_DD_WorkSurface, + NULL, + DDBLT_WAIT, + NULL + ); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Blt failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +/* + dd_result = lp_DD_FrontSurface->Flip(NULL, DDFLIP_WAIT); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Flip failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +*/ +#endif + } + else + { +#ifdef _DEBUG + dd_result = lp_DD_FrontSurface->Blt ( + &ShellRect, + lp_DD_WorkSurface, + NULL, + DDBLT_WAIT, + NULL + ); +#else + dd_result = lp_DD_FrontSurface->Blt ( + NULL, + lp_DD_WorkSurface, + NULL, + DDBLT_WAIT, + NULL + ); +#endif + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Blt failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } + } +} + +//--------------------------------------------------------------- + +void ShowWorkWindow(ULONG flags) +{ + HRESULT dd_result; + RECT ww_source_rect; +#ifdef _DEBUG + SLONG x_scale, + y_scale; + RECT ww_dest_rect; +#endif + + + if(lp_DD_WorkSurface==NULL) + return; + + ww_source_rect.left = WorkWindowRect.Left; + ww_source_rect.top = WorkWindowRect.Top; + ww_source_rect.right = WorkWindowRect.Right; + ww_source_rect.bottom = WorkWindowRect.Bottom; + + // Apparently Blt is better than BltFst for System to Display blits. + + if(flags&DS_WAIT_VBI) + { +#ifdef MF_DD2 + dd_result = lp_DD_2->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#else + dd_result = lp_DD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#endif + switch(dd_result) + { + case DD_OK: + break; + case DDERR_WASSTILLDRAWING: + while(lp_DD_WorkSurface->GetBltStatus(DDGBS_ISBLTDONE)==DDERR_WASSTILLDRAWING); + while(lp_DD_BackSurface->GetBltStatus(DDGBS_ISBLTDONE)==DDERR_WASSTILLDRAWING); + while(lp_DD_FrontSurface->GetBltStatus(DDGBS_ISBLTDONE)==DDERR_WASSTILLDRAWING); +#ifdef MF_DD2 + lp_DD_2->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#else + lp_DD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL); +#endif + break; + } + } + + if(flags&DS_DO_FLIP) + { +#ifdef _DEBUG + x_scale = ((ShellRect.right-ShellRect.left)<<16)/WorkScreenPixelWidth; + y_scale = ((ShellRect.bottom-ShellRect.top)<<16)/WorkScreenHeight; + ww_dest_rect.left = ShellRect.left+ww_source_rect.left; + ww_dest_rect.top = ShellRect.top+ww_source_rect.top; + ww_dest_rect.right = ww_dest_rect.left+((WorkWindowWidth*x_scale)>>16); + ww_dest_rect.bottom = ww_dest_rect.top+((WorkWindowHeight*y_scale)>>16); + + dd_result = lp_DD_BackSurface->Blt ( + &ww_source_rect, + lp_DD_WorkSurface, + &ww_source_rect, + DDBLT_WAIT, + NULL + ); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Blt failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +/* + dd_result = lp_DD_FrontSurface->Blt ( + &ww_dest_rect, + lp_DD_BackSurface, + &ShellRect, + DDBLT_WAIT, + NULL + ); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Flip failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +*/ +#else + dd_result = lp_DD_BackSurface->Blt ( + &ww_source_rect, + lp_DD_WorkSurface, + &ww_source_rect, + DDBLT_WAIT, + NULL + ); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Blt failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +/* + dd_result = lp_DD_FrontSurface->Flip(NULL, DDFLIP_WAIT); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Flip failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } +*/ +#endif + } + else + { +#ifdef _DEBUG + x_scale = ((ShellRect.right-ShellRect.left)<<16)/WorkScreenPixelWidth; + y_scale = ((ShellRect.bottom-ShellRect.top)<<16)/WorkScreenHeight; + ww_dest_rect.left = ShellRect.left+ww_source_rect.left; + ww_dest_rect.top = ShellRect.top+ww_source_rect.top; + ww_dest_rect.right = ww_dest_rect.left+((WorkWindowWidth*x_scale)>>16); + ww_dest_rect.bottom = ww_dest_rect.top+((WorkWindowHeight*y_scale)>>16); + + dd_result = lp_DD_FrontSurface->Blt ( + &ww_dest_rect, + lp_DD_WorkSurface, + &ww_source_rect, + DDBLT_WAIT, + NULL + ); +#else + dd_result = lp_DD_FrontSurface->Blt ( + &ww_source_rect, + lp_DD_WorkSurface, + &ww_source_rect, + DDBLT_WAIT, + NULL + ); +#endif + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + break; + default: + LogText("Blt failed in ShowWorkScreen. Error: %ld\n",dd_result&0xffff); + } + } +} + +//--------------------------------------------------------------- + +void ClearWorkScreen(UBYTE colour) +{ + DDBLTFX dd_bltfx; + HRESULT dd_result; + + + if(lp_DD_WorkSurface) + { + dd_bltfx.dwSize = sizeof(dd_bltfx); + dd_bltfx.dwFillColor = colour; + dd_result = lp_DD_WorkSurface->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT,&dd_bltfx); + switch(dd_result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + RestoreSurfaces(); + lp_DD_WorkSurface->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT,&dd_bltfx); + break; + } + } +} + +//--------------------------------------------------------------- + +void RestoreSurfaces(void) +{ + if(lp_DD_FrontSurface) + { + if(lp_DD_FrontSurface->IsLost() == DDERR_SURFACELOST) + { + lp_DD_FrontSurface->Restore(); + RestorePalettes(); + } + + } +#ifdef _DEBUG + if(lp_DD_BackSurface) + { + if(lp_DD_BackSurface->IsLost() == DDERR_SURFACELOST) + { + lp_DD_BackSurface->Restore(); + } + + } +#endif + if(lp_DD_WorkSurface) + { + if(lp_DD_WorkSurface->IsLost() == DDERR_SURFACELOST) + { + lp_DD_WorkSurface->Restore(); + } + + } + +} + +//--------------------------------------------------------------- + +HRESULT CALLBACK DisplayModesCallback(LPDDSURFACEDESC p_dd_sd, LPVOID ignore) +{ + ULONG c0; + + + ignore = ignore; // Stop the compiler whinging. + + for(c0=1;c0dwWidth && + DisplayModes[c0].Height==p_dd_sd->dwHeight && + DisplayModes[c0].Depth==p_dd_sd->ddpfPixelFormat.dwRGBBitCount + ) + { + DisplayModes[c0].DD_ModeDesc = *p_dd_sd; + DisplayModes[c0].Availability = TRUE; + break; + } + } + return DDENUMRET_OK; +} + +//--------------------------------------------------------------- + +BOOL WINAPI EnumDeviceCallback( + GUID FAR *lpGUID, + LPSTR lpDriverDescription, + LPSTR lpDriverName, + LPVOID lpContext + ) +{ + CBYTE *str_ptr = lpDriverDescription; + + + lpDriverName = lpDriverName; + lpContext = lpContext; + + while(*str_ptr!=0) + { + if(*str_ptr=='3') + { + if((*(str_ptr+1)=='D'||*(str_ptr+1)=='d') && (*(str_ptr+2)=='F'||*(str_ptr+2)=='f') && (*(str_ptr+3)=='X'||*(str_ptr+3)=='x')) + { + Device3DFX = *lpGUID; + Got3DFX = TRUE; + return DDENUMRET_CANCEL; + } + } + str_ptr++; + } + return DDENUMRET_OK; +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Windows/File.cpp b/MFLib1/Source/C/Windows/File.cpp new file mode 100644 index 0000000..26a03f4 --- /dev/null +++ b/MFLib1/Source/C/Windows/File.cpp @@ -0,0 +1,176 @@ +// File.cpp +// Guy Simmons, 10th February 1997. + +#include + + +//--------------------------------------------------------------- + +BOOL FileExists(CBYTE *file_name) +{ + if(GetFileAttributes(file_name)==0xffffffff) + return FALSE; + else + return TRUE; +} + +//--------------------------------------------------------------- + +MFFileHandle FileOpen(CBYTE *file_name) +{ + MFFileHandle result = FILE_OPEN_ERROR; + + + if(FileExists(file_name)) + { + result = CreateFile ( + file_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if(result==INVALID_HANDLE_VALUE) + result = FILE_OPEN_ERROR; + } + return result; +} + +//--------------------------------------------------------------- + +void FileClose(MFFileHandle file_handle) +{ + CloseHandle(file_handle); +} + +//--------------------------------------------------------------- + +MFFileHandle FileCreate(CBYTE *file_name,BOOL overwrite) +{ + DWORD creation_mode; + MFFileHandle result; + + + if(overwrite) + { + creation_mode = CREATE_ALWAYS; + } + else + { + creation_mode = CREATE_NEW; + } + result = CreateFile ( + file_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + creation_mode, + 0, + NULL + ); + if(result==INVALID_HANDLE_VALUE) + result = FILE_CREATION_ERROR; + + return result; +} + +//--------------------------------------------------------------- + +void FileDelete(CBYTE *file_name) +{ + DeleteFile(file_name); +} + +//--------------------------------------------------------------- + +SLONG FileSize(MFFileHandle file_handle) +{ + DWORD result; + + + result = GetFileSize(file_handle,NULL); + if(result==0xffffffff) + return FILE_SIZE_ERROR; + else + return (SLONG)result; +} + +//--------------------------------------------------------------- + +SLONG FileRead(MFFileHandle file_handle,void *buffer,ULONG size) +{ + SLONG bytes_read; + + + if(ReadFile(file_handle,buffer,size,(LPDWORD)&bytes_read,NULL)==FALSE) + return FILE_READ_ERROR; + else + return bytes_read; +} + +//--------------------------------------------------------------- + +SLONG FileWrite(MFFileHandle file_handle,void *buffer,ULONG size) +{ + SLONG bytes_written; + + + if(WriteFile(file_handle,buffer,size,(LPDWORD)&bytes_written,NULL)==FALSE) + return FILE_WRITE_ERROR; + else + return bytes_written; +} + +//--------------------------------------------------------------- + +SLONG FileSeek(MFFileHandle file_handle,enum SeekModes mode,SLONG offset) +{ + DWORD method; + + + switch(mode) + { + case SEEK_MODE_BEGINNING: + method = FILE_BEGIN; + break; + case SEEK_MODE_CURRENT: + method = FILE_CURRENT; + break; + case SEEK_MODE_END: + method = FILE_END; + break; + } + if(SetFilePointer(file_handle,offset,NULL,method)==0xffffffff) + return FILE_SEEK_ERROR; + else + return 0; +} + +//--------------------------------------------------------------- + +SLONG FileLoadAt(CBYTE *file_name,void *buffer) +{ + SLONG size; + MFFileHandle handle; + + + handle = FileOpen(file_name); + if(handle!=FILE_OPEN_ERROR) + { + size = FileSize(handle); + if(size>0) + { + if(FileRead(handle,buffer,size)==size) + { + FileClose(handle); + return size; + } + } + FileClose(handle); + } + return FILE_LOAD_AT_ERROR; +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Windows/Keyboard.cpp b/MFLib1/Source/C/Windows/Keyboard.cpp new file mode 100644 index 0000000..7442666 --- /dev/null +++ b/MFLib1/Source/C/Windows/Keyboard.cpp @@ -0,0 +1,117 @@ +// Keyboard.cpp +// Guy Simmons, 11th February 1997. + + +#include + +volatile UBYTE AltFlag, + ControlFlag, + ShiftFlag; +volatile UBYTE Keys[256], + LastKey; +HHOOK KeyboardHook; + +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam); + +//--------------------------------------------------------------- + +BOOL SetupKeyboard(void) +{ + AltFlag = 0; + ControlFlag = 0; + ShiftFlag = 0; + LastKey = 0; + memset((char*)&Keys[0],0,256); + +#ifdef _RELEASE + KeyboardHook = NULL; +/* + KeyboardHook = SetWindowsHookEx( + WH_KEYBOARD, + (HOOKPROC)KeyboardProc, + NULL, + 0 + ); + ERROR_MSG(KeyboardHook,"Can't setup the keyboard.") + if(KeyboardHook==NULL) + { + // Unable to set up keyboard. + return FALSE; + } +*/ +#endif + return TRUE; +} + +//--------------------------------------------------------------- + +void ResetKeyboard(void) +{ +#ifdef _RELEASE + if(KeyboardHook) + UnhookWindowsHookEx(KeyboardHook); +#endif +} + +//--------------------------------------------------------------- + +#define KEYMASK_REPEAT (0x0000ffff) +#define KEYMASK_SCAN (0x00ff0000) +#define KEYMASK_EXTENDED (0x01000000) +#define KEYMASK_RESERVED (0x1e000000) +#define KEYMASK_CONTEXT (0x20000000) +#define KEYMASK_PSTATE (0x40000000) +#define KEYMASK_TSTATE (0x80000000) + +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) +{ + UBYTE key_code; + ULONG virtual_keycode = wParam; + + + if(code<0) + { + return CallNextHookEx(KeyboardHook,code,wParam,lParam); + } + + // Get key scan code. + key_code = (UBYTE)((lParam&KEYMASK_SCAN)>>16); + + // Extended key press? + if(lParam&KEYMASK_EXTENDED) + { + key_code += 0x80; + } + + // Key up? + if(lParam&KEYMASK_TSTATE) + { + Keys[key_code] = 0; + } + // No ,down. + else + { + Keys[key_code] = 1; + LastKey = key_code; + } + + if(Keys[KB_LALT] || Keys[KB_RALT]) + AltFlag = 1; + else + AltFlag = 0; + + if(Keys[KB_LCONTROL] || Keys[KB_RCONTROL]) + ControlFlag = 1; + else + ControlFlag = 0; + + if(Keys[KB_LSHIFT] || Keys[KB_RSHIFT]) + ShiftFlag = 1; + else + ShiftFlag = 0; + + return FALSE; +} + +//--------------------------------------------------------------- + diff --git a/MFLib1/Source/C/Windows/MFHost.cpp b/MFLib1/Source/C/Windows/MFHost.cpp new file mode 100644 index 0000000..d150af6 --- /dev/null +++ b/MFLib1/Source/C/Windows/MFHost.cpp @@ -0,0 +1,449 @@ +// MFHost.cpp - Windows. +// Guy Simmons, 1st February 1997. + + +#include + +#define SHELL_NAME "Mucky Foot Shell" + +int iGlobalCmdShow; +HANDLE hShellThread = NULL; +HINSTANCE hGlobalInstance, + hGlobalPrevInstance; +HWND hShellWindow = NULL; +LPSTR szGlobalCmdLine; +MFFileHandle log_handle = NULL; +WNDCLASS wnd_class; +RECT ShellRect; + +static UWORD argc; +static LPTSTR argv[MAX_PATH]; + +LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam); +ULONG ShellThread(ULONG arg); +SLONG CreateShellWindow(void); + +extern UBYTE DisplayState; + +//--------------------------------------------------------------- + +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR szCmdLine, int iCmdShow) +{ + +#ifdef TARGET_DC + + // DC doesn't have command-lines. + TCHAR *argv[2]; + argv[0] = TEXT("BogusName"); + argv[1] = TEXT(""); + return MF_main(1,argv); + +#else //#ifdef TARGET_DC + + LPSTR lp_str; + + szGlobalCmdLine = szCmdLine; + iGlobalCmdShow = iCmdShow; + hGlobalInstance = hInstance; + hGlobalPrevInstance = hPrevInstance; + + argc = 1; + lp_str = szCmdLine; + while(*lp_str!=0) + { + while(*lp_str=='\t'||*lp_str==' ') + { + lp_str++; + } + if(*lp_str!=0) + { + argv[argc++] = lp_str; + while(*lp_str!='\t'&&*lp_str!=' '&&*lp_str!=0) + { + lp_str++; + } + if(*lp_str!=0) + { + *lp_str = 0; + lp_str++; + } + } + } + + return MF_main(argc,argv); + +#endif //#else //#ifdef TARGET_DC + +} + +//--------------------------------------------------------------- + +BOOL SetupHost(ULONG flags) +{ + DWORD id; + + + if(!SetupMemory()) + return FALSE; + if(!SetupKeyboard()) + return FALSE; + + if(flags&H_CREATE_LOG) + { + log_handle = FileCreate("debug.log",1); + if(log_handle==FILE_CREATION_ERROR) + log_handle = NULL; + } + +#ifndef TARGET_DC + + // Set up shell window. + wnd_class.style = 0; //CS_HREDRAW|CS_VREDRAW; + wnd_class.lpfnWndProc = WndProc; + wnd_class.cbClsExtra = 0; + wnd_class.cbWndExtra = 0; + wnd_class.hInstance = hGlobalInstance; + wnd_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW); + wnd_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wnd_class.lpszMenuName = NULL; + wnd_class.lpszClassName = SHELL_NAME; + +#else //#ifndef TARGET_DC + + // Set up shell window. + wnd_class.style = 0; + wnd_class.lpfnWndProc = WndProc; + wnd_class.cbClsExtra = 0; + wnd_class.cbWndExtra = 0; + wnd_class.hInstance = hGlobalInstance; + wnd_class.hIcon = NULL; + wnd_class.hCursor = NULL; + wnd_class.hbrBackground = NULL; + wnd_class.lpszMenuName = NULL; + wnd_class.lpszClassName = TEXT(SHELL_NAME); + +#endif //#else //#ifndef TARGET_DC + + RegisterClass(&wnd_class); + + hShellThread = CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)ShellThread, + 0, + 0, + &id + ); + ERROR_MSG(hShellThread,"Can't create the shell thread.") + if(hShellThread) + { + // Wait for shell to activate. + // This could potentially cause a problem if the shell window couldn't be created. + while(!DisplayActive) + { +#ifdef TARGET_DC + Sleep(100); +#else + SleepEx(100,FALSE); +#endif + } + } + + return TRUE; +} + +//--------------------------------------------------------------- + +void ResetHost(void) +{ + if(log_handle) + FileClose(log_handle); + ResetKeyboard(); + ResetMemory(); +} + +//--------------------------------------------------------------- + +LRESULT CALLBACK WndProc(HWND h_window,UINT i_message,WPARAM w_param,LPARAM l_param) +{ + switch (i_message) + { +#ifndef TARGET_DC + case WM_SIZE: + case WM_MOVE: +// LogText("WM_SIZE or WM_MOVE\n"); + if (IsIconic(h_window)) + { + // Shell is minimized, maybe set Pause flag? + } +#ifdef _DEBUG + GetClientRect(h_window, &ShellRect); + ClientToScreen(h_window, (LPPOINT)&ShellRect); + ClientToScreen(h_window, (LPPOINT)&ShellRect+1); + +#else + SetRect(&ShellRect,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN)); +#endif + if(lp_DD_FrontSurface) + ClearDisplay(); + break; + case WM_QUERYNEWPALETTE: +// LogText("WM_QUERYNEWPALETTE\n"); + RestorePalettes(); + break; + case WM_PALETTECHANGED: +// LogText("WM_PALETTECHANGED\n"); + RestorePalettes(); + break; + case WM_MOUSEMOVE: +// LogText("WM_MOUSEMOVE:\n"); + MouseX = LOWORD(l_param); + MouseY = HIWORD(l_param); + MousePoint.X = MouseX; + MousePoint.Y = MouseY; + MouseMoved = 1; + break; +#endif //#ifndef TARGET_DC + case WM_RBUTTONUP: +// LogText("WM_RBUTTONUP\n"); + RightButton = 0; + break; + case WM_RBUTTONDOWN: +// LogText("WM_RBUTTONDOWN\n"); + RightButton = 1; + if(!RightMouse.ButtonState) + { + RightMouse.ButtonState = 1; + RightMouse.MouseX = LOWORD(l_param); + RightMouse.MouseY = HIWORD(l_param); + RightMouse.MousePoint.X = LOWORD(l_param); + RightMouse.MousePoint.Y = HIWORD(l_param); + } + break; + case WM_RBUTTONDBLCLK: + break; + case WM_LBUTTONUP: + LogText("WM_LBUTTONUP\n"); + LeftButton = 0; + break; + case WM_LBUTTONDOWN: +// LogText("WM_LBUTTONDOWN\n"); + LeftButton = 1; + if(!LeftMouse.ButtonState) + { + LeftMouse.ButtonState = 1; + LeftMouse.MouseX = LOWORD(l_param); + LeftMouse.MouseY = HIWORD(l_param); + LeftMouse.MousePoint.X = LOWORD(l_param); + LeftMouse.MousePoint.Y = HIWORD(l_param); + } + break; + case WM_LBUTTONDBLCLK: + break; + case WM_MBUTTONUP: + MiddleButton = 0; + break; + case WM_MBUTTONDOWN: +// LogText("WM_MBUTTONDOWN\n"); + MiddleButton = 1; + if(!MiddleMouse.ButtonState) + { + MiddleMouse.ButtonState = 1; + MiddleMouse.MouseX = LOWORD(l_param); + MiddleMouse.MouseY = HIWORD(l_param); + MiddleMouse.MousePoint.X= LOWORD(l_param); + MiddleMouse.MousePoint.Y= HIWORD(l_param); + } + break; + case WM_MBUTTONDBLCLK: + break; + +//#ifdef _DEBUG +extern LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam); + case WM_KEYDOWN: + case WM_KEYUP: +// LogText("WM_KEYDOWN or WM_KEYUP\n"); + KeyboardProc( 0, 0, l_param); + break; +//#endif + + case WM_CLOSE: +// LogText("WM_CLOSE\n"); + DisplayActive = 0; + break; + case WM_DESTROY: +// LogText("WM_DESTROY\n"); + PostQuitMessage(0); + DisplayState &= ~(DS_SHELL_WINDOW_OPEN); + break; +// default: +// LogText("Unknown event - %ld\n",i_message); + } + return DefWindowProc(h_window,i_message,w_param,l_param); +} + +//--------------------------------------------------------------- + +ULONG ShellThread(ULONG arg) +{ + SLONG result; + MSG msg; + + + arg = arg; + + DisplayState |= DS_THREAD_ACTIVE; + result = CreateShellWindow(); + + if(result==NoError) + { +/* + while(1) + { + if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) + { +// if(!GetMessage(&msg,NULL,0,0)) +// break; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + // make sure we go to sleep if we have nothing else to do + WaitMessage(); + } + } +*/ + while(GetMessage(&msg,NULL,0,0) && (DisplayState&DS_SHELL_WINDOW_OPEN)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +#ifdef TARGET_DC + Sleep(100); +#else + SleepEx(100,FALSE); +#endif + DisplayActive = 0; + MFShellActive = 0; + + DisplayState &= ~(DS_THREAD_ACTIVE); + return EXIT_SUCCESS; +} + +//--------------------------------------------------------------- + +SLONG CreateShellWindow(void) +{ + hShellWindow = CreateWindowExA ( + 0, + SHELL_NAME, + SHELL_NAME, + WS_POPUP|WS_VISIBLE|WS_SYSMENU, +#ifdef _DEBUG + 0,0, + 640, + 480, +#else + 0,0, + GetSystemMetrics(SM_CXSCREEN), + GetSystemMetrics(SM_CYSCREEN), +#endif + NULL, + NULL, + hGlobalInstance, + NULL + ); + ERROR_MSG(hShellWindow,"Can't create the shell window.") + + if(hShellWindow) + { + DisplayState |= DS_SHELL_WINDOW_OPEN; + DisplayActive = 1; + MFShellActive = 1; + +// ShowWindow(hShellWindow,SW_SHOWNORMAL); +// UpdateWindow(hShellWindow); + return NoError; + } + else + { + return -1; + } +} + +//--------------------------------------------------------------- + +void LogText(CBYTE *error, ...) +{ + CBYTE buf[512]; + va_list argptr; + + if(log_handle) + { + va_start(argptr,error); + vsprintf(buf, error,argptr); + va_end(argptr); + + FileWrite(log_handle,buf,strlen(buf)); + } +} + +//--------------------------------------------------------------- +extern HWND hShellWindow; + +int MFMessage(const char *pMessage, const char *pFile, ULONG dwLine) +{ +#ifndef TARGET_DC + char buff1[512]; + char buff2[512]; + ULONG flag; + + + LogText("Mucky Foot Message\n %s\nIn : %s\nLine : %u",pMessage,pFile,dwLine); + + sprintf( buff1, "Something strange has happened!"); + sprintf( buff2, "%s\n\n%s\n\nIn : %s\nline : %u", buff1, pMessage, pFile, dwLine); + strcat(buff2, "\n\nAbort=Kill Application, Retry=Debug, Ignore=Continue"); + flag = MB_ABORTRETRYIGNORE|MB_ICONSTOP|MB_DEFBUTTON3; + + switch(MessageBox(hShellWindow, buff2, "Mucky Foot Message", flag)) + { + case IDABORT: + case IDCANCEL: + exit(1); + break; + + case IDRETRY: + return TRUE; + + } +#else //#ifndef TARGET_DC + LogText("Mucky Foot Message\n %s\nIn : %s\nLine : %u",pMessage,pFile,dwLine); +#endif //#else //#ifndef TARGET_DC + return FALSE; + +} + +//--------------------------------------------------------------- + +void Time(struct MFTime *the_time) +{ + SYSTEMTIME new_time; + + + GetLocalTime(&new_time); + the_time->Hours = new_time.wHour; + the_time->Minutes = new_time.wMinute; + the_time->Seconds = new_time.wSecond; + the_time->MSeconds = new_time.wMilliseconds; + the_time->DayOfWeek = new_time.wDayOfWeek; + the_time->Day = new_time.wDay; + the_time->Month = new_time.wMonth; + the_time->Year = new_time.wYear; + the_time->Ticks = GetTickCount(); +} + +//--------------------------------------------------------------- diff --git a/MFLib1/Source/C/Windows/Mem.cpp b/MFLib1/Source/C/Windows/Mem.cpp new file mode 100644 index 0000000..b07099b --- /dev/null +++ b/MFLib1/Source/C/Windows/Mem.cpp @@ -0,0 +1,67 @@ +// Mem.cpp +// Guy Simmons, 10th February 1997. + + +#include + +#define INITIAL_HEAP_SIZE (18*1024*1024) +#define MAXIMUM_HEAP_SIZE (24*1024*1024) + +HANDLE MFHeap = NULL; + +//--------------------------------------------------------------- + +BOOL SetupMemory(void) +{ + if(MFHeap==NULL) + { + MFHeap = HeapCreate(0,INITIAL_HEAP_SIZE,MAXIMUM_HEAP_SIZE); + } + ERROR_MSG(MFHeap,"Can't setup memory.") + if(MFHeap) + return TRUE; + else + return FALSE; +} + +//--------------------------------------------------------------- + +void ResetMemory(void) +{ + if(MFHeap) + { + HeapDestroy(MFHeap); + MFHeap = NULL; + } +} + +//--------------------------------------------------------------- + +void *MemAlloc(ULONG size) +{ + size = (size+3)&0xfffffffc; + return (void*)HeapAlloc(MFHeap,HEAP_ZERO_MEMORY,size); +} + +//--------------------------------------------------------------- + +void MemFree(void *mem_ptr) +{ + HeapFree(MFHeap,0,mem_ptr); +} + +//--------------------------------------------------------------- + +void MemClear(void *mem_ptr,ULONG size) +{ +/* + ULONG c0; + + for(c0=0;c0 + + + +volatile UBYTE MouseMoved = 0, + LeftButton = 0, + MiddleButton = 0, + RightButton = 0; +volatile SLONG MouseX, + MouseY; +volatile LastMouse LeftMouse = { 0,0,0,{ 0,0 } }, + MiddleMouse = { 0,0,0,{ 0,0 } }, + RightMouse = { 0,0,0,{ 0,0 } }; +volatile MFPoint MousePoint = { 0,0 }; diff --git a/MFLib1/Source/C/Windows/Palette.cpp b/MFLib1/Source/C/Windows/Palette.cpp new file mode 100644 index 0000000..2e71d28 --- /dev/null +++ b/MFLib1/Source/C/Windows/Palette.cpp @@ -0,0 +1,245 @@ +// Palette.cpp +// Guy Simmons, 11th February 1997. + + +#include + +UBYTE CurrentPalette[256*3]; +LPDIRECTDRAWPALETTE lp_DD_Palette = NULL; +PALETTEENTRY ThePalette[256]; + +//--------------------------------------------------------------- + + +void InitPalettes(void) +{ +#if defined(_DEBUG) && !defined(TARGET_DC) + ULONG c0; + + + // First set up the Windows static entries. + for(c0=0;c0<10;c0++) + { + // The first 10 static entries: + ThePalette[c0].peFlags = PC_EXPLICIT; + ThePalette[c0].peRed = (UBYTE)c0; + ThePalette[c0].peGreen = 0; + ThePalette[c0].peBlue = 0; + + // The last 10 static entries: + ThePalette[c0+246].peFlags = PC_EXPLICIT; + ThePalette[c0+246].peRed = (UBYTE)(c0+246); + ThePalette[c0+246].peGreen = 0; + ThePalette[c0+246].peBlue = 0; + } + + // Set up private entries. Initialise to black. + for(c0=10;c0<246;c0++) + { + ThePalette[c0].peFlags = PC_NOCOLLAPSE|PC_RESERVED; + ThePalette[c0].peRed = 0; + ThePalette[c0].peGreen = 0; + ThePalette[c0].peBlue = 0; + } +#else + // Initialise palette to black. + memset(ThePalette,0,sizeof(ThePalette)); +#endif +} + + +//--------------------------------------------------------------- + +SLONG CreatePalettes(void) +{ + HRESULT dd_result; + + + if(lp_DD_Palette==NULL ) + { +#ifdef _DEBUG + dd_result = lp_DD->CreatePalette( + DDPCAPS_8BIT, + ThePalette, + &lp_DD_Palette, + NULL + ); +#else + dd_result = lp_DD->CreatePalette( + DDPCAPS_8BIT|DDPCAPS_ALLOW256, + ThePalette, + &lp_DD_Palette, + NULL + ); +#endif + if(dd_result!=DD_OK) + { + return -1; + } + + dd_result = lp_DD_FrontSurface->SetPalette(lp_DD_Palette); + if(dd_result!=DD_OK) + { + LogText(" Unable to attach palette to lp_DD_FrontSurface\n"); + return -1; + } +/* + if(dd_result!=DD_OK) dd_result = lp_DD_BackSurface->SetPalette(lp_DD_Palette); + + { + LogText(" Unable to attach palette to lp_DD_BackSurface\n"); + return -1; + } +*/ + } + + return NoError; +} + +//--------------------------------------------------------------- + +void DestroyPalettes(void) +{ + HRESULT dd_result; + + + if(lp_DD_Palette) + { + dd_result = lp_DD_Palette->Release(); + if(dd_result==DD_OK) + { + lp_DD_Palette = NULL; + } + else + { +// CBYTE text[256]; +// sprintf(text,"Unable to Release Palette. Error: %ld",dd_result&0xffff); +// ERROR_MSG(0,text) + } + } +} + +//--------------------------------------------------------------- + +void RestorePalettes(void) +{ + if(lp_DD_Palette && lp_DD_FrontSurface) + { + lp_DD_FrontSurface->SetPalette(lp_DD_Palette); + } +} + +//--------------------------------------------------------------- + +void SetPalette(UBYTE *the_palette) +{ +#ifndef TARGET_DC + ULONG c0; + HRESULT dd_result; + + +#ifdef _DEBUG + // First set up the Windows static entries. + for(c0=0;c0<10;c0++) + { + // The first 10 static entries: + ThePalette[c0].peFlags = PC_EXPLICIT; + ThePalette[c0].peRed = (UBYTE)c0; + ThePalette[c0].peGreen = 0; + ThePalette[c0].peBlue = 0; + + // The last 10 static entries: + ThePalette[c0+246].peFlags = PC_EXPLICIT; + ThePalette[c0+246].peRed = (UBYTE)(c0+246); + ThePalette[c0+246].peGreen = 0; + ThePalette[c0+246].peBlue = 0; + } + + // Set up private entries. + for(c0=10;c0<246;c0++) + { + ThePalette[c0].peFlags = PC_NOCOLLAPSE|PC_RESERVED; + ThePalette[c0].peRed = (UBYTE)(the_palette[(c0*3)+0]); + ThePalette[c0].peGreen = (UBYTE)(the_palette[(c0*3)+1]); + ThePalette[c0].peBlue = (UBYTE)(the_palette[(c0*3)+2]); + } +#else + // Set up all entries. + for(c0=0;c0<256;c0++) + { + ThePalette[c0].peRed = (UBYTE)(the_palette[(c0*3)+0]); + ThePalette[c0].peGreen = (UBYTE)(the_palette[(c0*3)+1]); + ThePalette[c0].peBlue = (UBYTE)(the_palette[(c0*3)+2]); + } +#endif + for(c0=0;c0<256;c0++) + { + CurrentPalette[c0*3+0]=ThePalette[c0].peRed; + CurrentPalette[c0*3+1]=ThePalette[c0].peGreen; + CurrentPalette[c0*3+2]=ThePalette[c0].peBlue; + } + if(lp_DD_Palette) + dd_result = lp_DD_Palette->SetEntries(0,0,256,ThePalette); +#endif +} + +//--------------------------------------------------------------- + +SLONG FindColour(UBYTE *the_palette,SLONG r,SLONG g,SLONG b) +{ + SLONG found = -1; + + if(r>255) + r=255; + if(g>255) + g=255; + if(b>255) + b=255; + + switch(WorkScreenDepth) + { + case 1: + { + + SLONG dist = 0x7fffffff, + c0, + dist2, + tr, + tg, + tb; + + + for(c0=0;c0<256;c0++) + { + tr = *the_palette++; + tg = *the_palette++; + tb = *the_palette++; + + tr -= r; + tg -= g; + tb -= b; + + dist2= abs(tr*tr)+abs(tg*tg)+abs(tb*tb); + if(dist2>3)<<11)|((g>>2)<<5)|(b>>3)); + break; + case 4: + found=((r<<16)|(g<<8)|(b)); + break; + + } + return(found); +} + +//--------------------------------------------------------------- diff --git a/MFStdLib/Headers/MFStdLib.h b/MFStdLib/Headers/MFStdLib.h new file mode 100644 index 0000000..4132dc2 --- /dev/null +++ b/MFStdLib/Headers/MFStdLib.h @@ -0,0 +1,312 @@ + +// MFStdLib.h +// Guy Simmons, 18th December 1997. + +#ifndef MF_STD_LIB_H +#define MF_STD_LIB_H + +//--------------------------------------------------------------- + +// Standard 'C' includes. +#if !defined(TARGET_DC) +#include +#include +#endif +#include +#include +#include +#include + +// Library defines. +#define _MF_WINDOWS + +#ifndef _WIN32 + #define _WIN32 +#endif + +#ifndef WIN32 + #define WIN32 +#endif + +// Specific Windows includes. +#define D3D_OVERLOADS +#include +#include +#include +#include +#ifndef TARGET_DC +// For the DX8 headers, you need to define this to get old interfaces. +#ifndef DIRECTINPUT_VERSION +#define DIRECTINPUT_VERSION 0x0700 +#endif +#endif +#include +#include +#include +#include + +#ifdef TARGET_DC +#include "target.h" +#endif + +//--------------------------------------------------------------- + +#define TRUE 1 +#define FALSE 0 + +typedef unsigned char UBYTE; +typedef signed char SBYTE; +typedef char CBYTE; +typedef unsigned short UWORD; +typedef signed short SWORD; +typedef unsigned long ULONG; +typedef signed long SLONG; + + +typedef struct +{ + SLONG X, + Y; +}MFPoint; + +typedef struct +{ + SLONG Left, + Top, + Right, + Bottom, + Width, + Height; +}MFRect; + +//--------------------------------------------------------------- +// MF Standard includes. + +#include "StdFile.h" +#include "StdKeybd.h" +#include "StdMaths.h" +#include "StdMem.h" +#include "StdMouse.h" + +//--------------------------------------------------------------- +// Display + +#define FLAGS_USE_3DFX (1<<0) +#define FLAGS_USE_3D (1<<1) +#define FLAGS_USE_WORKSCREEN (1<<2) + +extern UBYTE WorkScreenDepth, + *WorkScreen; +extern SLONG WorkScreenHeight, + WorkScreenPixelWidth, + WorkScreenWidth; +extern SLONG DisplayWidth, + DisplayHeight, + DisplayBPP; + +SLONG OpenDisplay(ULONG width, ULONG height, ULONG depth, ULONG flags); +SLONG SetDisplay(ULONG width,ULONG height,ULONG depth); +SLONG CloseDisplay(void); +SLONG ClearDisplay(UBYTE r,UBYTE g,UBYTE b); +void FadeDisplay(UBYTE mode); +void *LockWorkScreen(void); +void UnlockWorkScreen(void); +void ShowWorkScreen(ULONG flags); +void ClearWorkScreen(UBYTE colour); + +//--------------------------------------------------------------- +// Host + +#define SHELL_NAME "Mucky Foot Shell\0" +#define H_CREATE_LOG (1<<0) +#define SHELL_ACTIVE (LibShellActive()) +#define SHELL_CHANGED (LibShellChanged()) + +#define main(ac,av) MF_main(ac,av) + +struct MFTime +{ + SLONG Hours, + Minutes, + Seconds, + MSeconds; + SLONG DayOfWeek, // 0 - 6; Sunday = 0 + Day, + Month, // 1 - 12; January = 1 + Year; + SLONG Ticks; // Number of ticks(milliseconds) since windows started. +}; + +SLONG main(UWORD argc, TCHAR** argv); +BOOL SetupHost(ULONG flags); +void ResetHost(void); +//void TraceText(CBYTE *error, ...); +void TraceText(char *error, ...); +BOOL LibShellActive(void); +BOOL LibShellChanged(void); +BOOL LibShellMessage(const char *pMessage, const char *pFile, ULONG dwLine); + +#define NoError 0 + + +#ifndef NDEBUG + +void DebugText(CBYTE *error, ...); +#define TRACE TraceText +#define LogText DebugText +#define MFMessage LibShellMessage +#define ERROR_MSG(e,m) {if(!(e)) {LibShellMessage(m,__FILE__,__LINE__);}} +//#define ASSERT(e) {if (!(e)) { _asm{int 3} }else{/*TRACE("file %s line %d \n",__FILE__,__LINE__);*/}} +#ifndef ASSERT +#define ASSERT(e) ERROR_MSG(e,"ASSERT TRIGGERED"); +#endif + +#else + +#define DebugText +#define TRACE +#define LogText +#define MFMessage +#define ERROR_MSG(e,m) {} +#ifndef ASSERT +#define ASSERT(e) {} +#endif + +#endif + +//--------------------------------------------------------------- +// Input. + +#define MOUSE DIDEVTYPE_MOUSE +#define KEYBOARD DIDEVTYPE_KEYBOARD +#define JOYSTICK DIDEVTYPE_JOYSTICK + + +#if 0 +BOOL GetInputDevice(UBYTE type,UBYTE sub_type); +BOOL ReadInputDevice(void); +#endif + +//--------------------------------------------------------------- +// Sound. + +#define SAMPLE_VOL_MIN DSBVOLUME_MIN +#define SAMPLE_VOL_MAX DSBVOLUME_MAX + +#define SAMPLE_PAN_LEFT DSBPAN_LEFT +#define SAMPLE_PAN_RIGHT DSBPAN_RIGHT +#define SAMPLE_PAN_CENTER DSBPAN_CENTER + +#define SAMPLE_FREQ_MIN DSBFREQUENCY_MIN +#define SAMPLE_FREQ_MAX DSBFREQUENCY_MAX +#define SAMPLE_FREQ_ORIG DSBFREQUENCY_ORIGINAL + + +void LoadSampleList(CBYTE *sample_file); +void PlaySample(SLONG ref,SWORD sample_no,SLONG vol,SLONG pan,SLONG freq,SLONG pri); + +//--------------------------------------------------------------- +// New Sound + + +#define WAVE_STEREO (1<<0) +#define WAVE_POLAR (1<<1) +#define WAVE_CARTESIAN (1<<2) +#define WAVE_PAN_RATE (1<<3) +#define WAVE_DISTANCE_MAPPING (1<<4) +#define WAVE_LOOP (1<<5) +#define WAVE_SET_LOOP_POINTS (1<<6) + +#define WAVE_TYPE_MASK (WAVE_STEREO|WAVE_POLAR|WAVE_CARTESIAN) + +#define WAVE_PLAY_INTERUPT 0 +#define WAVE_PLAY_NO_INTERUPT 1 +#define WAVE_PLAY_OVERLAP 2 +#define WAVE_PLAY_QUEUE 3 + +struct WaveParams +{ + ULONG Flags, + LoopStart, + LoopEnd, + Priority; + union + { + // Stereo. + struct + { + SLONG Pan, + Volume; + }Stereo; + + // Polar. + struct + { + SLONG Azimuth, + Elevation, + Range; + }Polar; + + // Cartesian. + struct + { + SLONG Scale, + X, + Y, + Z; + }Cartesian; + }Mode; +}; +void LoadWaveList(CBYTE *path,CBYTE *file); +void FreeWaveList(void); +void PlayWave(SLONG ref,SLONG wave_id,SLONG play_type,WaveParams *the_params); +void StopWave(SLONG ref,SLONG wave_id); +void SetListenerPosition(SLONG x,SLONG y,SLONG z,SLONG scale); + + +//--------------------------------------------------------------- +// Standard macros. + +#define sgn(a) (((a)<0) ? -1 : 1) +#define swap(a,b) {a^=b;b^=a;a^=b;} + +#define in_range(a,min,max) {if(a>(max))a=(max);else if(a<(min))a=(min);} +#ifndef min +#define min(a,b) (((a)<(b)) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) (((a)>(b)) ? (a) : (b)) +#endif + +//--------------------------------------------------------------- + +// +// Stuff put in by Mark... +// + +#define INFINITY 0x7fffffff +#define PI (3.14159265F) +#define WITHIN(x,a,b) ((x) >= (a) && (x) <= (b)) +#define SATURATE(x,a,b) {if ((x) < (a)) {(x) = (a);} else if ((x) > (b)) {(x) = (b);}} +#define SWAP(a,b) {SLONG temp; temp = (a); (a) = (b); (b) = temp;} +#define SWAP_FL(a,b) {float temp; temp = (a); (a) = (b); (b) = temp;} +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define SIGN(x) (((x)) ? (((x) > 0) ? +1 : -1) : 0) + +// +// Some maths stuff by mike +// + + +#define QDIST3(x,y,z) ((x)>(y) ? ((x)>(z) ? (x)+((y)>>2)+((z)>>2) : (z)+((x)>>2)+((y)>>2)) : ((y)>(z) ? ((y)+((x)>>2)+((z)>>2)) : (z)+((x)>>2)+((y)>>2) )) +#define QDIST2(x,y) ((x)>(y) ? ((x)+((y)>>1) ):((y)+((x)>>1) )) + +#define SDIST3(x,y,z) (((x)*(x))+((y)*(y))+((z)*(z))) +#define SDIST2(x,y) (((x)*(x))+((y)*(y))) + + + +#endif + diff --git a/MFStdLib/Headers/StdFile.h b/MFStdLib/Headers/StdFile.h new file mode 100644 index 0000000..e92ce61 --- /dev/null +++ b/MFStdLib/Headers/StdFile.h @@ -0,0 +1,48 @@ +// StdFile.h +// Guy Simmons, 18th December 1997. + +#ifndef STD_FILE_H +#define STD_FILE_H + +//--------------------------------------------------------------- + +typedef HANDLE MFFileHandle; + +#define FILE_OPEN_ERROR ((MFFileHandle)-100) +#define FILE_CLOSE_ERROR ((MFFileHandle)-101) +#define FILE_CREATION_ERROR ((MFFileHandle)-102) +#define FILE_SIZE_ERROR ((SLONG)-103) +#define FILE_READ_ERROR ((SLONG)-104) +#define FILE_WRITE_ERROR ((SLONG)-105) +#define FILE_SEEK_ERROR ((SLONG)-106) +#define FILE_LOAD_AT_ERROR ((SLONG)-107) + +#define SEEK_MODE_BEGINNING 0 +#define SEEK_MODE_CURRENT 1 +#define SEEK_MODE_END 2 + +BOOL FileExists(CBYTE *file_name); +MFFileHandle FileOpen(CBYTE *file_name); +void FileClose(MFFileHandle file_handle); +MFFileHandle FileCreate(CBYTE *file_name,BOOL overwrite); +void FileDelete(CBYTE *file_name); +SLONG FileSize(MFFileHandle file_handle); +SLONG FileRead(MFFileHandle file_handle,void *buffer,ULONG size); +SLONG FileWrite(MFFileHandle file_handle,void *buffer,ULONG size); +SLONG FileSeek(MFFileHandle file_handle,const int mode,SLONG offset); +SLONG FileLoadAt(CBYTE *file_name,void *buffer); +void FileSetBasePath(CBYTE *path_name); + + + +// Plug'n'play replacements for fopen/fclose. +// Except they do something cunning on the DC. +// These can be used with sscanf() and so on, +// whereas the above can't. +FILE *MF_Fopen ( const char *file_name, const char *mode ); +int MF_Fclose( FILE *stream ); + + +//--------------------------------------------------------------- + +#endif diff --git a/MFStdLib/Headers/StdKeybd.h b/MFStdLib/Headers/StdKeybd.h new file mode 100644 index 0000000..7ec0cbe --- /dev/null +++ b/MFStdLib/Headers/StdKeybd.h @@ -0,0 +1,152 @@ +// StdKeybd.h +// Guy Simmons, 18th December 1997. + +#ifndef STD_KEYBD_H +#define STD_KEYBD_H + +//--------------------------------------------------------------- + +// Row1 +#define KB_ESC 0x01 +#define KB_1 0x02 +#define KB_2 0x03 +#define KB_3 0x04 +#define KB_4 0x05 +#define KB_5 0x06 +#define KB_6 0x07 +#define KB_7 0x08 +#define KB_8 0x09 +#define KB_9 0x0a +#define KB_0 0x0b +#define KB_MINUS 0x0c +#define KB_PLUS 0x0d +#define KB_BS 0x0e + +// Row2 +#define KB_TAB 0x0f +#define KB_Q 0x10 +#define KB_W 0x11 +#define KB_E 0x12 +#define KB_R 0x13 +#define KB_T 0x14 +#define KB_Y 0x15 +#define KB_U 0x16 +#define KB_I 0x17 +#define KB_O 0x18 +#define KB_P 0x19 +#define KB_LBRACE 0x1a +#define KB_RBRACE 0x1b +#define KB_ENTER 0x1c + +// Row3 +#define KB_LCONTROL 0x1d +#define KB_CAPSLOCK 0x3a +#define KB_A 0x1e +#define KB_S 0x1f +#define KB_D 0x20 +#define KB_F 0x21 +#define KB_G 0x22 +#define KB_H 0x23 +#define KB_J 0x24 +#define KB_K 0x25 +#define KB_L 0x26 +#define KB_COLON 0x27 +#define KB_QUOTE 0x28 +#define KB_TILD 0x29 + +// Row4 +#define KB_LSHIFT 0x2a +#define KB_BACKSLASH 0x2b +#define KB_Z 0x2c +#define KB_X 0x2d +#define KB_C 0x2e +#define KB_V 0x2f +#define KB_B 0x30 +#define KB_N 0x31 +#define KB_M 0x32 +#define KB_COMMA 0x33 +#define KB_POINT 0x34 +#define KB_FORESLASH 0x35 +#define KB_RSHIFT 0x36 +#define KB_LALT 0x38 +#define KB_SPACE 0x39 +#define KB_RALT (0x38+0x80) +#define KB_RCONTROL (0x1d+0x80) + +// Function key row. +#define KB_F1 0x3b +#define KB_F2 0x3c +#define KB_F3 0x3d +#define KB_F4 0x3e + +#define KB_F5 0x3f +#define KB_F6 0x40 +#define KB_F7 0x41 +#define KB_F8 0x42 + +#define KB_F9 0x43 +#define KB_F10 0x44 +#define KB_F11 0x57 +#define KB_F12 0x58 + +#define KB_PRTSC (0x37+0x80) +#define KB_SCROLLLOCK 0x46 +//#define KB_PAUSE ???? + +// Edit pad. +#define KB_INS (0x52+0x80) +#define KB_HOME (0x47+0x80) +#define KB_PGUP (0x49+0x80) +#define KB_DEL (0x53+0x80) +#define KB_END (0x4f+0x80) +#define KB_PGDN (0x51+0x80) + +// Cursor pad. +#define KB_LEFT (0x4b+0x80) +#define KB_UP (0x48+0x80) +#define KB_RIGHT (0x4d+0x80) +#define KB_DOWN (0x50+0x80) + +// Key pad. +#define KB_NUMLOCK 0x45 +#define KB_PSLASH (0x35+0x80) +#define KB_ASTERISK 0x37 +#define KB_PMINUS 0x4a +#define KB_P7 0x47 +#define KB_P8 0x48 +#define KB_P9 0x49 +#define KB_PPLUS 0x4e +#define KB_P4 0x4b +#define KB_P5 0x4c +#define KB_P6 0x4d +#define KB_P1 0x4f +#define KB_P2 0x50 +#define KB_P3 0x51 +#define KB_PENTER (0x1c+0x80) +#define KB_P0 0x52 +#define KB_PPOINT 0x53 + + + + +#ifdef TARGET_DC +// On the Dreamcast, these don't exist. +#define AltFlag 0 +#define ControlFlag 0 +#define ShiftFlag 0 + +// These don't either, but we'll leave them for now. +extern volatile UBYTE Keys[256], + LastKey; + +#else +extern volatile UBYTE AltFlag, + ControlFlag, + ShiftFlag; +extern volatile UBYTE Keys[256], + LastKey; +#endif + +//--------------------------------------------------------------- + +#endif diff --git a/MFStdLib/Headers/StdMaths.h b/MFStdLib/Headers/StdMaths.h new file mode 100644 index 0000000..006db3d --- /dev/null +++ b/MFStdLib/Headers/StdMaths.h @@ -0,0 +1,44 @@ +// StdMaths.h +// Guy Simmons, 18th December 1997 + +#ifndef STD_MATHS_H +#define STD_MATHS_H + +//--------------------------------------------------------------- + +#define SIN(a) SinTable[a] +#define COS(a) CosTable[a] + +#define SIN_F(a) SinTableF[a] +#define COS_F(a) CosTableF[a] + +#define PROPTABLE_SIZE 256 +#define PROP(x) Proportions[(x)+PROPTABLE_SIZE] + +extern float *CosTableF, + SinTableF[]; +extern SWORD AtanTable[]; +extern SLONG *CosTable, + SinTable[]; +extern SLONG Proportions[]; + +SLONG Arctan(SLONG X,SLONG Y); +SLONG Root(SLONG square); + +static inline SLONG Hypotenuse(SLONG x,SLONG y) +{ + x = abs(x); + y = abs(y); + if(x>y) + return((PROP((y<<8)/x)*x)>>13); + else + if(y) + return((PROP((x<<8)/y)*y)>>13); + else + return(0); +} + + +//--------------------------------------------------------------- + +#endif diff --git a/MFStdLib/Headers/StdMem.h b/MFStdLib/Headers/StdMem.h new file mode 100644 index 0000000..715020b --- /dev/null +++ b/MFStdLib/Headers/StdMem.h @@ -0,0 +1,42 @@ +// StdMem.h +// Guy Simmons, 18th December 1997 + +#ifndef STD_MEM_H +#define STD_MEM_H + +//--------------------------------------------------------------- + +BOOL SetupMemory(void); +void ResetMemory(void); +void *MemAlloc(ULONG size); +void MemFree(void *mem_ptr); + + + +#ifdef DEBUG +void MFnewTrace ( void *pvAddr, size_t size ); +void MFdeleteTrace ( void *pvAddr ); +#endif + + +// Some templated new and delete stand-ins. +template T *MFnew ( void ) +{ + T *ptr = new T; +#ifdef DEBUG + MFnewTrace ( ptr, sizeof ( ptr ) ); +#endif + return ptr; +} + +template void MFdelete(T *thing) +{ +#ifdef DEBUG + MFdeleteTrace ( thing ); +#endif + delete thing; +} + +//--------------------------------------------------------------- + +#endif diff --git a/MFStdLib/Headers/StdMouse.h b/MFStdLib/Headers/StdMouse.h new file mode 100644 index 0000000..7f1de02 --- /dev/null +++ b/MFStdLib/Headers/StdMouse.h @@ -0,0 +1,31 @@ +// StdMouse.h +// Guy Simmons, 18th December 1997. + +#ifndef STD_MOUSE_H +#define STD_MOUSE_H + +//--------------------------------------------------------------- + +struct LastMouse +{ + SLONG ButtonState, + MouseX, + MouseY; + MFPoint MousePoint; +}; + + +extern volatile UBYTE MouseMoved, + LeftButton, + MiddleButton, + RightButton; +extern volatile SLONG MouseX, + MouseY; +extern volatile LastMouse LeftMouse, + MiddleMouse, + RightMouse; +extern volatile MFPoint MousePoint; + +//--------------------------------------------------------------- + +#endif diff --git a/MFStdLib/Source/StdLib/StdFile.cpp b/MFStdLib/Source/StdLib/StdFile.cpp new file mode 100644 index 0000000..f345a2c --- /dev/null +++ b/MFStdLib/Source/StdLib/StdFile.cpp @@ -0,0 +1,346 @@ +// StdFile.cpp +// Guy Simmons, 18th December 1997. + +#include + +#define MAX_LENGTH_OF_BASE_PATH 64 +CBYTE cBasePath[MAX_LENGTH_OF_BASE_PATH+1]; + +#ifdef DEBUG +int m_iNumOpenFiles_FileOpen = 0; +int m_iNumOpenFiles_MF_Fopen = 0; +char pcPrevFilenameOpened[256]; +#endif + +//--------------------------------------------------------------- + +#define MAX_LENGTH_OF_FULL_NAME (MAX_LENGTH_OF_BASE_PATH+128) +CBYTE cTempFilename[MAX_LENGTH_OF_FULL_NAME+1]; + +CBYTE *MakeFullPathName ( const CBYTE *cFilename ) +{ + strcpy ( cTempFilename, cBasePath ); + ASSERT ( strlen ( cFilename ) < ( MAX_LENGTH_OF_FULL_NAME - MAX_LENGTH_OF_BASE_PATH ) ); + strcat ( cTempFilename, cFilename ); + return ( cTempFilename ); +} + +//--------------------------------------------------------------- + +BOOL FileExists( CBYTE *file_name) +{ + file_name = MakeFullPathName ( file_name ); + + if(GetFileAttributes(file_name)==0xffffffff) + return FALSE; + else + return TRUE; +} + +//--------------------------------------------------------------- + +MFFileHandle FileOpen(CBYTE *file_name) +{ + MFFileHandle result = FILE_OPEN_ERROR; + + if(FileExists(file_name)) + { + file_name = MakeFullPathName ( file_name ); + + result = CreateFile ( + file_name, + (GENERIC_READ), + (FILE_SHARE_READ), + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if(result==INVALID_HANDLE_VALUE) + { + result = FILE_OPEN_ERROR; + } + else + { +#ifdef DEBUG + m_iNumOpenFiles_FileOpen++; + if ( m_iNumOpenFiles_FileOpen > 1 ) + { + TRACE ( "FileOpen nested %i\n", m_iNumOpenFiles_FileOpen ); + } + strncpy ( pcPrevFilenameOpened, file_name, 256 ); +#endif + } + } + return result; +} + +//--------------------------------------------------------------- + +void FileClose(MFFileHandle file_handle) +{ +#ifdef DEBUG + if ( m_iNumOpenFiles_FileOpen > 1 ) + { + TRACE ( "FileClose nested %i\n", m_iNumOpenFiles_FileOpen ); + } + m_iNumOpenFiles_FileOpen--; +#endif + CloseHandle(file_handle); +} + +//--------------------------------------------------------------- + +MFFileHandle FileCreate(CBYTE *file_name,BOOL overwrite) +{ + DWORD creation_mode; + MFFileHandle result; + + file_name = MakeFullPathName ( file_name ); + + if(overwrite) + { + creation_mode = CREATE_ALWAYS; + } + else + { + creation_mode = CREATE_NEW; + } + result = CreateFile ( + file_name, + (GENERIC_READ|GENERIC_WRITE), + 0,//(FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + creation_mode, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if(result==INVALID_HANDLE_VALUE) + result = FILE_CREATION_ERROR; + + return result; +} + +//--------------------------------------------------------------- + +void FileDelete(CBYTE *file_name) +{ + file_name = MakeFullPathName ( file_name ); + DeleteFile(file_name); +} + +//--------------------------------------------------------------- + +SLONG FileSize(MFFileHandle file_handle) +{ + DWORD result; + + + result = GetFileSize(file_handle,NULL); + if(result==0xffffffff) + return FILE_SIZE_ERROR; + else + return (SLONG)result; +} + +//--------------------------------------------------------------- + +SLONG FileRead(MFFileHandle file_handle,void *buffer,ULONG size) +{ + SLONG bytes_read; + + + if(ReadFile(file_handle,buffer,size,(LPDWORD)&bytes_read,NULL)==FALSE) + return FILE_READ_ERROR; + else + return bytes_read; +} + +//--------------------------------------------------------------- + +SLONG FileWrite(MFFileHandle file_handle,void *buffer,ULONG size) +{ + SLONG bytes_written; + + + if(WriteFile(file_handle,buffer,size,(LPDWORD)&bytes_written,NULL)==FALSE) + return FILE_WRITE_ERROR; + else + return bytes_written; +} + +//--------------------------------------------------------------- + +SLONG FileSeek(MFFileHandle file_handle,const int mode,SLONG offset) +{ + DWORD method; + + + switch(mode) + { + case SEEK_MODE_BEGINNING: + method = FILE_BEGIN; + break; + case SEEK_MODE_CURRENT: + method = FILE_CURRENT; + break; + case SEEK_MODE_END: + method = FILE_END; + break; + } + if(SetFilePointer(file_handle,offset,NULL,method)==0xffffffff) + return FILE_SEEK_ERROR; + else + return 0; +} + +//--------------------------------------------------------------- + +SLONG FileLoadAt(CBYTE *file_name,void *buffer) +{ + SLONG size; + MFFileHandle handle; + + handle = FileOpen(file_name); + if(handle!=FILE_OPEN_ERROR) + { + size = FileSize(handle); + if(size>0) + { + if(FileRead(handle,buffer,size)==size) + { + FileClose(handle); + return size; + } + } + FileClose(handle); + } + return FILE_LOAD_AT_ERROR; +} + +//--------------------------------------------------------------- + + +void TraceText(CBYTE *fmt, ...) +{ + // + // Work out the real message. + // + + CBYTE message[512]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + OutputDebugString(message); +} + +//--------------------------------------------------------------- + +void FileSetBasePath(CBYTE *path_name) +{ + ASSERT ( strlen ( path_name ) < MAX_LENGTH_OF_BASE_PATH - 1 ); + strncpy ( cBasePath, path_name, MAX_LENGTH_OF_BASE_PATH - 1 ); + // Add a trailing slash if need be. + CBYTE *pch = cBasePath; + if ( *pch != '\0' ) + { + while ( *++pch != '\0' ){} + pch--; + if ( *pch != '\\' ) + { + *pch++ = '\\'; + *pch = '\0'; + } + } +} + +//--------------------------------------------------------------- + +// Do NOT mix and match MF_FOpen/MF_FClose with the above - they don't mingle. +#ifdef TARGET_DC +static TCHAR pchTcharVersion[100]; +//static TCHAR pchTcharMode[5]; +#endif +FILE *MF_Fopen ( const char *file_name, const char *mode ) +{ + if ( !FileExists ( (char *)file_name ) ) + { + return NULL; + } + file_name = MakeFullPathName ( file_name ); +#ifdef TARGET_DC + + // Apparently fopen causes a memory leak. + +#if 1 + ASSERT ( mode[0] == 'r' ); + ASSERT ( mode[2] == '\0' ); + TCHAR *pchTcharMode; + if ( mode[1] == 't' ) + { + pchTcharMode = TEXT("rt"); + } + else + { + ASSERT ( mode[1] == 'b' ); + pchTcharMode = TEXT("rb"); + } +#else + pc1 = mode; + ASSERT ( strlen ( mode) < 3 ); + pc2 = pchTcharMode; + while ( *pc1 != '\0' ) + { + *pc2++ = (TCHAR)( *pc1++ ); + } + *pc2++ = TEXT('\0'); +#endif + + const char *pc1 = file_name; + ASSERT ( strlen ( file_name) < 80 ); + TCHAR *pc2 = pchTcharVersion; + while ( *pc1 != '\0' ) + { + *pc2++ = (TCHAR)( *pc1++ ); + } + *pc2++ = TEXT('\0'); + + FILE *res = _wfopen ( pchTcharVersion, pchTcharMode ); +#ifdef DEBUG + if ( res != NULL ) + { + m_iNumOpenFiles_MF_Fopen++; + if ( m_iNumOpenFiles_MF_Fopen > 1 ) + { + TRACE ( "MF_Fopen nested %i\n", m_iNumOpenFiles_MF_Fopen ); + } + strncpy ( pcPrevFilenameOpened, file_name, 256 ); + } +#endif + return ( res ); +#else + return ( fopen ( (char *)file_name, (char *)mode ) ); +#endif +} + +//--------------------------------------------------------------- + +int MF_Fclose( FILE *stream ) +{ +#ifdef DEBUG + if ( m_iNumOpenFiles_MF_Fopen > 1 ) + { + TRACE ( "MF_Fclose nested %i\n", m_iNumOpenFiles_MF_Fopen ); + } + m_iNumOpenFiles_MF_Fopen--; +#endif + return ( fclose ( stream ) ); +} + +//--------------------------------------------------------------- + + + diff --git a/MFStdLib/Source/StdLib/StdMaths.cpp b/MFStdLib/Source/StdLib/StdMaths.cpp new file mode 100644 index 0000000..5b9e547 --- /dev/null +++ b/MFStdLib/Source/StdLib/StdMaths.cpp @@ -0,0 +1,6058 @@ +// StdMaths.cpp +// Guy Simmons, 18th December 1997. + +#include +#ifdef TARGET_DC +#include +#endif + +//--------------------------------------------------------------- + +#define LookUp ax = AtanTable[(ax<<8)/bx]; +#define xchg(a,b) {a^=b;b^=a;a^=b;} + + +SLONG Arctan(SLONG X,SLONG Y) +{ + register SLONG ax,bx; + + ax = X; + if(ax) + goto just_do_it; + bx = Y; + if(bx) + goto done_it; + return 0; +just_do_it: + bx = Y; +done_it: + if(ax < 0) + goto xneg; + +// x positive + if(bx < 0) + goto xposyneg; + +// x positive, y positive + if(ax < bx) + goto ppyprimary; + +// ppxprimary + xchg(ax,bx) + LookUp + return ax+512; +ppyprimary: + LookUp + return (-ax)+1024; +xposyneg: //******************************************************************* + bx = -bx; + if(ax < bx) + goto pnyprimary; + +// pnxprimary + xchg(ax,bx) + LookUp + return (-ax)+512; +pnyprimary: + LookUp + return ax; +xneg: + ax = -ax; + if(bx < 0) + goto xnegyneg; +// x negative, y positive + if(ax < bx) + goto npyprimary; + +// npxprimary + xchg(ax,bx) + LookUp + return (-ax)+1536; +npyprimary: + LookUp + return ax+1024; + +// x negative, y negative +xnegyneg: + bx = -bx; + if(ax < bx) + goto nnyprimary; + +// nnxprimary + xchg(ax,bx) + LookUp + return ax+1536; +nnyprimary: + LookUp + return (-ax)+2048; +} + +//--------------------------------------------------------------- + +#ifndef TARGET_DC + +UWORD ini_table[] = +{ + 1, 2, 2, 4, + 5, 8, 11, 16, + 22, 32, 45, 64, + 90, 128, 181, 256, + 362, 512, 724, 1024, + 1448, 2048, 2896, 4096, + 5792, 8192, 11585, 16384, + 23170, 32768, 46340, 65535 +}; + +SLONG Root(SLONG square) +{ + __asm + { + xor ebx,ebx + mov ecx,square + bsr eax,ecx + je done_it + movzx ebx,ini_table[eax*2] +do_it: + mov eax,ecx + xor edx,edx + div ebx + cmp eax,ebx + jge done_it + add ebx,eax + shr ebx,1 + jmp do_it +done_it: + mov eax,ebx + } +} + +#else //#ifndef TARGET_DC + +// Just use the standard rout for the moment - it uses a fast path anyway. +SLONG Root ( SLONG square ) +{ + return ( (int) sqrtf ( (float)square ) ); +} + +#endif //#else //#ifndef TARGET_DC + + + +//--------------------------------------------------------------- + +SWORD AtanTable[] = +{ + 2048L*0/131072L, + 2048L*81/131072L, + 2048L*162/131072L, + 2048L*244/131072L, + 2048L*325/131072L, + 2048L*407/131072L, + 2048L*488/131072L, + 2048L*570/131072L, + 2048L*651/131072L, + 2048L*733/131072L, + 2048L*814/131072L, + 2048L*895/131072L, + 2048L*977/131072L, + 2048L*1058/131072L, + 2048L*1139/131072L, + 2048L*1220/131072L, + 2048L*1302/131072L, + 2048L*1383/131072L, + 2048L*1464/131072L, + 2048L*1545/131072L, + 2048L*1626/131072L, + 2048L*1707/131072L, + 2048L*1788/131072L, + 2048L*1869/131072L, + 2048L*1949/131072L, + 2048L*2030/131072L, + 2048L*2111/131072L, + 2048L*2192/131072L, + 2048L*2272/131072L, + 2048L*2353/131072L, + 2048L*2433/131072L, + 2048L*2513/131072L, + 2048L*2594/131072L, + 2048L*2674/131072L, + 2048L*2754/131072L, + 2048L*2834/131072L, + 2048L*2914/131072L, + 2048L*2994/131072L, + 2048L*3074/131072L, + 2048L*3153/131072L, + 2048L*3233/131072L, + 2048L*3312/131072L, + 2048L*3392/131072L, + 2048L*3471/131072L, + 2048L*3550/131072L, + 2048L*3629/131072L, + 2048L*3708/131072L, + 2048L*3787/131072L, + 2048L*3866/131072L, + 2048L*3945/131072L, + 2048L*4023/131072L, + 2048L*4102/131072L, + 2048L*4180/131072L, + 2048L*4258/131072L, + 2048L*4336/131072L, + 2048L*4414/131072L, + 2048L*4492/131072L, + 2048L*4570/131072L, + 2048L*4647/131072L, + 2048L*4725/131072L, + 2048L*4802/131072L, + 2048L*4879/131072L, + 2048L*4956/131072L, + 2048L*5033/131072L, + 2048L*5110/131072L, + 2048L*5187/131072L, + 2048L*5263/131072L, + 2048L*5339/131072L, + 2048L*5416/131072L, + 2048L*5492/131072L, + 2048L*5568/131072L, + 2048L*5643/131072L, + 2048L*5719/131072L, + 2048L*5794/131072L, + 2048L*5870/131072L, + 2048L*5945/131072L, + 2048L*6020/131072L, + 2048L*6094/131072L, + 2048L*6169/131072L, + 2048L*6244/131072L, + 2048L*6318/131072L, + 2048L*6392/131072L, + 2048L*6466/131072L, + 2048L*6540/131072L, + 2048L*6614/131072L, + 2048L*6687/131072L, + 2048L*6760/131072L, + 2048L*6833/131072L, + 2048L*6906/131072L, + 2048L*6979/131072L, + 2048L*7052/131072L, + 2048L*7124/131072L, + 2048L*7197/131072L, + 2048L*7269/131072L, + 2048L*7340/131072L, + 2048L*7412/131072L, + 2048L*7484/131072L, + 2048L*7555/131072L, + 2048L*7626/131072L, + 2048L*7697/131072L, + 2048L*7768/131072L, + 2048L*7839/131072L, + 2048L*7909/131072L, + 2048L*7979/131072L, + 2048L*8049/131072L, + 2048L*8119/131072L, + 2048L*8189/131072L, + 2048L*8258/131072L, + 2048L*8328/131072L, + 2048L*8397/131072L, + 2048L*8466/131072L, + 2048L*8534/131072L, + 2048L*8603/131072L, + 2048L*8671/131072L, + 2048L*8739/131072L, + 2048L*8807/131072L, + 2048L*8875/131072L, + 2048L*8942/131072L, + 2048L*9010/131072L, + 2048L*9077/131072L, + 2048L*9144/131072L, + 2048L*9210/131072L, + 2048L*9277/131072L, + 2048L*9343/131072L, + 2048L*9409/131072L, + 2048L*9475/131072L, + 2048L*9541/131072L, + 2048L*9606/131072L, + 2048L*9672/131072L, + 2048L*9737/131072L, + 2048L*9802/131072L, + 2048L*9866/131072L, + 2048L*9931/131072L, + 2048L*9995/131072L, + 2048L*10059/131072L, + 2048L*10123/131072L, + 2048L*10187/131072L, + 2048L*10250/131072L, + 2048L*10313/131072L, + 2048L*10376/131072L, + 2048L*10439/131072L, + 2048L*10502/131072L, + 2048L*10564/131072L, + 2048L*10626/131072L, + 2048L*10688/131072L, + 2048L*10750/131072L, + 2048L*10812/131072L, + 2048L*10873/131072L, + 2048L*10934/131072L, + 2048L*10995/131072L, + 2048L*11056/131072L, + 2048L*11117/131072L, + 2048L*11177/131072L, + 2048L*11237/131072L, + 2048L*11297/131072L, + 2048L*11357/131072L, + 2048L*11416/131072L, + 2048L*11476/131072L, + 2048L*11535/131072L, + 2048L*11594/131072L, + 2048L*11652/131072L, + 2048L*11711/131072L, + 2048L*11769/131072L, + 2048L*11827/131072L, + 2048L*11885/131072L, + 2048L*11943/131072L, + 2048L*12000/131072L, + 2048L*12057/131072L, + 2048L*12115/131072L, + 2048L*12171/131072L, + 2048L*12228/131072L, + 2048L*12284/131072L, + 2048L*12341/131072L, + 2048L*12397/131072L, + 2048L*12453/131072L, + 2048L*12508/131072L, + 2048L*12564/131072L, + 2048L*12619/131072L, + 2048L*12674/131072L, + 2048L*12729/131072L, + 2048L*12783/131072L, + 2048L*12838/131072L, + 2048L*12892/131072L, + 2048L*12946/131072L, + 2048L*13000/131072L, + 2048L*13054/131072L, + 2048L*13107/131072L, + 2048L*13160/131072L, + 2048L*13213/131072L, + 2048L*13266/131072L, + 2048L*13319/131072L, + 2048L*13371/131072L, + 2048L*13423/131072L, + 2048L*13475/131072L, + 2048L*13527/131072L, + 2048L*13579/131072L, + 2048L*13630/131072L, + 2048L*13682/131072L, + 2048L*13733/131072L, + 2048L*13784/131072L, + 2048L*13834/131072L, + 2048L*13885/131072L, + 2048L*13935/131072L, + 2048L*13985/131072L, + 2048L*14035/131072L, + 2048L*14085/131072L, + 2048L*14135/131072L, + 2048L*14184/131072L, + 2048L*14233/131072L, + 2048L*14282/131072L, + 2048L*14331/131072L, + 2048L*14380/131072L, + 2048L*14428/131072L, + 2048L*14476/131072L, + 2048L*14524/131072L, + 2048L*14572/131072L, + 2048L*14620/131072L, + 2048L*14667/131072L, + 2048L*14715/131072L, + 2048L*14762/131072L, + 2048L*14809/131072L, + 2048L*14856/131072L, + 2048L*14902/131072L, + 2048L*14949/131072L, + 2048L*14995/131072L, + 2048L*15041/131072L, + 2048L*15087/131072L, + 2048L*15132/131072L, + 2048L*15178/131072L, + 2048L*15223/131072L, + 2048L*15269/131072L, + 2048L*15314/131072L, + 2048L*15358/131072L, + 2048L*15403/131072L, + 2048L*15448/131072L, + 2048L*15492/131072L, + 2048L*15536/131072L, + 2048L*15580/131072L, + 2048L*15624/131072L, + 2048L*15667/131072L, + 2048L*15711/131072L, + 2048L*15754/131072L, + 2048L*15797/131072L, + 2048L*15840/131072L, + 2048L*15883/131072L, + 2048L*15926/131072L, + 2048L*15968/131072L, + 2048L*16010/131072L, + 2048L*16052/131072L, + 2048L*16094/131072L, + 2048L*16136/131072L, + 2048L*16178/131072L, + 2048L*16219/131072L, + 2048L*16261/131072L, + 2048L*16302/131072L, + 2048L*16343/131072L, + 2048L*16384/131072L +}; + +//--------------------------------------------------------------- + +SLONG SinTable[]= +{ + 0, // 0 0.00 0.000000 + 201, // 1 0.18 0.003068 + 402, // 2 0.35 0.006136 + 603, // 3 0.53 0.009204 + 804, // 4 0.70 0.012272 + 1005, // 5 0.88 0.015340 + 1206, // 6 1.05 0.018408 + 1407, // 7 1.23 0.021476 + 1608, // 8 1.41 0.024544 + 1809, // 9 1.58 0.027612 + 2010, // 10 1.76 0.030680 + 2211, // 11 1.93 0.033748 + 2412, // 12 2.11 0.036816 + 2613, // 13 2.29 0.039884 + 2814, // 14 2.46 0.042951 + 3014, // 15 2.64 0.046019 + 3215, // 16 2.81 0.049087 + 3416, // 17 2.99 0.052155 + 3617, // 18 3.16 0.055223 + 3818, // 19 3.34 0.058291 + 4018, // 20 3.52 0.061359 + 4219, // 21 3.69 0.064427 + 4420, // 22 3.87 0.067495 + 4620, // 23 4.04 0.070563 + 4821, // 24 4.22 0.073631 + 5021, // 25 4.39 0.076699 + 5222, // 26 4.57 0.079767 + 5422, // 27 4.75 0.082835 + 5622, // 28 4.92 0.085903 + 5823, // 29 5.10 0.088971 + 6023, // 30 5.27 0.092039 + 6223, // 31 5.45 0.095107 + 6423, // 32 5.62 0.098175 + 6623, // 33 5.80 0.101243 + 6823, // 34 5.98 0.104311 + 7023, // 35 6.15 0.107379 + 7223, // 36 6.33 0.110447 + 7423, // 37 6.50 0.113515 + 7623, // 38 6.68 0.116583 + 7822, // 39 6.86 0.119651 + 8022, // 40 7.03 0.122718 + 8221, // 41 7.21 0.125786 + 8421, // 42 7.38 0.128854 + 8620, // 43 7.56 0.131922 + 8819, // 44 7.73 0.134990 + 9019, // 45 7.91 0.138058 + 9218, // 46 8.09 0.141126 + 9417, // 47 8.26 0.144194 + 9616, // 48 8.44 0.147262 + 9814, // 49 8.61 0.150330 + 10013, // 50 8.79 0.153398 + 10212, // 51 8.96 0.156466 + 10410, // 52 9.14 0.159534 + 10609, // 53 9.32 0.162602 + 10807, // 54 9.49 0.165670 + 11006, // 55 9.67 0.168738 + 11204, // 56 9.84 0.171806 + 11402, // 57 10.02 0.174874 + 11600, // 58 10.20 0.177942 + 11797, // 59 10.37 0.181010 + 11995, // 60 10.55 0.184078 + 12193, // 61 10.72 0.187146 + 12390, // 62 10.90 0.190214 + 12588, // 63 11.07 0.193282 + 12785, // 64 11.25 0.196350 + 12982, // 65 11.43 0.199418 + 13179, // 66 11.60 0.202485 + 13376, // 67 11.78 0.205553 + 13573, // 68 11.95 0.208621 + 13769, // 69 12.13 0.211689 + 13966, // 70 12.30 0.214757 + 14162, // 71 12.48 0.217825 + 14359, // 72 12.66 0.220893 + 14555, // 73 12.83 0.223961 + 14751, // 74 13.01 0.227029 + 14946, // 75 13.18 0.230097 + 15142, // 76 13.36 0.233165 + 15338, // 77 13.54 0.236233 + 15533, // 78 13.71 0.239301 + 15728, // 79 13.89 0.242369 + 15923, // 80 14.06 0.245437 + 16118, // 81 14.24 0.248505 + 16313, // 82 14.41 0.251573 + 16508, // 83 14.59 0.254641 + 16702, // 84 14.77 0.257709 + 16897, // 85 14.94 0.260777 + 17091, // 86 15.12 0.263845 + 17285, // 87 15.29 0.266913 + 17479, // 88 15.47 0.269981 + 17672, // 89 15.64 0.273049 + 17866, // 90 15.82 0.276117 + 18059, // 91 16.00 0.279185 + 18253, // 92 16.17 0.282252 + 18446, // 93 16.35 0.285320 + 18638, // 94 16.52 0.288388 + 18831, // 95 16.70 0.291456 + 19024, // 96 16.88 0.294524 + 19216, // 97 17.05 0.297592 + 19408, // 98 17.23 0.300660 + 19600, // 99 17.40 0.303728 + 19792, // 100 17.58 0.306796 + 19983, // 101 17.75 0.309864 + 20175, // 102 17.93 0.312932 + 20366, // 103 18.11 0.316000 + 20557, // 104 18.28 0.319068 + 20748, // 105 18.46 0.322136 + 20938, // 106 18.63 0.325204 + 21129, // 107 18.81 0.328272 + 21319, // 108 18.98 0.331340 + 21509, // 109 19.16 0.334408 + 21699, // 110 19.34 0.337476 + 21889, // 111 19.51 0.340544 + 22078, // 112 19.69 0.343612 + 22267, // 113 19.86 0.346680 + 22456, // 114 20.04 0.349748 + 22645, // 115 20.21 0.352816 + 22833, // 116 20.39 0.355884 + 23022, // 117 20.57 0.358952 + 23210, // 118 20.74 0.362019 + 23398, // 119 20.92 0.365087 + 23586, // 120 21.09 0.368155 + 23773, // 121 21.27 0.371223 + 23960, // 122 21.45 0.374291 + 24147, // 123 21.62 0.377359 + 24334, // 124 21.80 0.380427 + 24521, // 125 21.97 0.383495 + 24707, // 126 22.15 0.386563 + 24893, // 127 22.32 0.389631 + 25079, // 128 22.50 0.392699 + 25265, // 129 22.68 0.395767 + 25450, // 130 22.85 0.398835 + 25635, // 131 23.03 0.401903 + 25820, // 132 23.20 0.404971 + 26005, // 133 23.38 0.408039 + 26189, // 134 23.55 0.411107 + 26373, // 135 23.73 0.414175 + 26557, // 136 23.91 0.417243 + 26741, // 137 24.08 0.420311 + 26925, // 138 24.26 0.423379 + 27108, // 139 24.43 0.426447 + 27291, // 140 24.61 0.429515 + 27473, // 141 24.79 0.432583 + 27656, // 142 24.96 0.435651 + 27838, // 143 25.14 0.438719 + 28020, // 144 25.31 0.441786 + 28201, // 145 25.49 0.444854 + 28383, // 146 25.66 0.447922 + 28564, // 147 25.84 0.450990 + 28745, // 148 26.02 0.454058 + 28925, // 149 26.19 0.457126 + 29105, // 150 26.37 0.460194 + 29285, // 151 26.54 0.463262 + 29465, // 152 26.72 0.466330 + 29645, // 153 26.89 0.469398 + 29824, // 154 27.07 0.472466 + 30003, // 155 27.25 0.475534 + 30181, // 156 27.42 0.478602 + 30360, // 157 27.60 0.481670 + 30538, // 158 27.77 0.484738 + 30715, // 159 27.95 0.487806 + 30893, // 160 28.12 0.490874 + 31070, // 161 28.30 0.493942 + 31247, // 162 28.48 0.497010 + 31424, // 163 28.65 0.500078 + 31600, // 164 28.83 0.503146 + 31776, // 165 29.00 0.506214 + 31952, // 166 29.18 0.509282 + 32127, // 167 29.36 0.512350 + 32302, // 168 29.53 0.515418 + 32477, // 169 29.71 0.518486 + 32651, // 170 29.88 0.521553 + 32826, // 171 30.06 0.524621 + 32999, // 172 30.23 0.527689 + 33173, // 173 30.41 0.530757 + 33346, // 174 30.59 0.533825 + 33519, // 175 30.76 0.536893 + 33692, // 176 30.94 0.539961 + 33864, // 177 31.11 0.543029 + 34036, // 178 31.29 0.546097 + 34208, // 179 31.46 0.549165 + 34379, // 180 31.64 0.552233 + 34550, // 181 31.82 0.555301 + 34721, // 182 31.99 0.558369 + 34891, // 183 32.17 0.561437 + 35061, // 184 32.34 0.564505 + 35231, // 185 32.52 0.567573 + 35400, // 186 32.70 0.570641 + 35569, // 187 32.87 0.573709 + 35738, // 188 33.05 0.576777 + 35906, // 189 33.22 0.579845 + 36074, // 190 33.40 0.582913 + 36242, // 191 33.57 0.585981 + 36409, // 192 33.75 0.589049 + 36576, // 193 33.93 0.592117 + 36743, // 194 34.10 0.595185 + 36909, // 195 34.28 0.598253 + 37075, // 196 34.45 0.601320 + 37241, // 197 34.63 0.604388 + 37406, // 198 34.80 0.607456 + 37571, // 199 34.98 0.610524 + 37736, // 200 35.16 0.613592 + 37900, // 201 35.33 0.616660 + 38064, // 202 35.51 0.619728 + 38227, // 203 35.68 0.622796 + 38390, // 204 35.86 0.625864 + 38553, // 205 36.04 0.628932 + 38716, // 206 36.21 0.632000 + 38878, // 207 36.39 0.635068 + 39039, // 208 36.56 0.638136 + 39201, // 209 36.74 0.641204 + 39362, // 210 36.91 0.644272 + 39522, // 211 37.09 0.647340 + 39682, // 212 37.27 0.650408 + 39842, // 213 37.44 0.653476 + 40002, // 214 37.62 0.656544 + 40161, // 215 37.79 0.659612 + 40319, // 216 37.97 0.662680 + 40478, // 217 38.14 0.665748 + 40636, // 218 38.32 0.668816 + 40793, // 219 38.50 0.671884 + 40950, // 220 38.67 0.674952 + 41107, // 221 38.85 0.678020 + 41263, // 222 39.02 0.681087 + 41419, // 223 39.20 0.684155 + 41575, // 224 39.38 0.687223 + 41730, // 225 39.55 0.690291 + 41885, // 226 39.73 0.693359 + 42040, // 227 39.90 0.696427 + 42194, // 228 40.08 0.699495 + 42347, // 229 40.25 0.702563 + 42501, // 230 40.43 0.705631 + 42653, // 231 40.61 0.708699 + 42806, // 232 40.78 0.711767 + 42958, // 233 40.96 0.714835 + 43110, // 234 41.13 0.717903 + 43261, // 235 41.31 0.720971 + 43412, // 236 41.48 0.724039 + 43562, // 237 41.66 0.727107 + 43712, // 238 41.84 0.730175 + 43862, // 239 42.01 0.733243 + 44011, // 240 42.19 0.736311 + 44160, // 241 42.36 0.739379 + 44308, // 242 42.54 0.742447 + 44456, // 243 42.71 0.745515 + 44603, // 244 42.89 0.748583 + 44750, // 245 43.07 0.751651 + 44897, // 246 43.24 0.754719 + 45043, // 247 43.42 0.757787 + 45189, // 248 43.59 0.760854 + 45335, // 249 43.77 0.763922 + 45480, // 250 43.95 0.766990 + 45624, // 251 44.12 0.770058 + 45768, // 252 44.30 0.773126 + 45912, // 253 44.47 0.776194 + 46055, // 254 44.65 0.779262 + 46198, // 255 44.82 0.782330 + 46340, // 256 45.00 0.785398 + 46482, // 257 45.18 0.788466 + 46624, // 258 45.35 0.791534 + 46765, // 259 45.53 0.794602 + 46906, // 260 45.70 0.797670 + 47046, // 261 45.88 0.800738 + 47186, // 262 46.05 0.803806 + 47325, // 263 46.23 0.806874 + 47464, // 264 46.41 0.809942 + 47602, // 265 46.58 0.813010 + 47740, // 266 46.76 0.816078 + 47878, // 267 46.93 0.819146 + 48015, // 268 47.11 0.822214 + 48151, // 269 47.29 0.825282 + 48288, // 270 47.46 0.828350 + 48423, // 271 47.64 0.831418 + 48558, // 272 47.81 0.834486 + 48693, // 273 47.99 0.837554 + 48828, // 274 48.16 0.840621 + 48961, // 275 48.34 0.843689 + 49095, // 276 48.52 0.846757 + 49228, // 277 48.69 0.849825 + 49360, // 278 48.87 0.852893 + 49492, // 279 49.04 0.855961 + 49624, // 280 49.22 0.859029 + 49755, // 281 49.39 0.862097 + 49886, // 282 49.57 0.865165 + 50016, // 283 49.75 0.868233 + 50146, // 284 49.92 0.871301 + 50275, // 285 50.10 0.874369 + 50403, // 286 50.27 0.877437 + 50532, // 287 50.45 0.880505 + 50660, // 288 50.62 0.883573 + 50787, // 289 50.80 0.886641 + 50914, // 290 50.98 0.889709 + 51040, // 291 51.15 0.892777 + 51166, // 292 51.33 0.895845 + 51291, // 293 51.50 0.898913 + 51416, // 294 51.68 0.901981 + 51541, // 295 51.86 0.905049 + 51665, // 296 52.03 0.908117 + 51788, // 297 52.21 0.911185 + 51911, // 298 52.38 0.914253 + 52033, // 299 52.56 0.917321 + 52155, // 300 52.73 0.920388 + 52277, // 301 52.91 0.923456 + 52398, // 302 53.09 0.926524 + 52518, // 303 53.26 0.929592 + 52639, // 304 53.44 0.932660 + 52758, // 305 53.61 0.935728 + 52877, // 306 53.79 0.938796 + 52996, // 307 53.96 0.941864 + 53114, // 308 54.14 0.944932 + 53231, // 309 54.32 0.948000 + 53348, // 310 54.49 0.951068 + 53465, // 311 54.67 0.954136 + 53581, // 312 54.84 0.957204 + 53696, // 313 55.02 0.960272 + 53811, // 314 55.20 0.963340 + 53926, // 315 55.37 0.966408 + 54040, // 316 55.55 0.969476 + 54153, // 317 55.72 0.972544 + 54266, // 318 55.90 0.975612 + 54379, // 319 56.07 0.978680 + 54491, // 320 56.25 0.981748 + 54602, // 321 56.43 0.984816 + 54713, // 322 56.60 0.987884 + 54823, // 323 56.78 0.990952 + 54933, // 324 56.95 0.994020 + 55043, // 325 57.13 0.997088 + 55152, // 326 57.30 1.000155 + 55260, // 327 57.48 1.003223 + 55368, // 328 57.66 1.006291 + 55475, // 329 57.83 1.009359 + 55582, // 330 58.01 1.012427 + 55688, // 331 58.18 1.015495 + 55794, // 332 58.36 1.018563 + 55899, // 333 58.54 1.021631 + 56004, // 334 58.71 1.024699 + 56108, // 335 58.89 1.027767 + 56212, // 336 59.06 1.030835 + 56315, // 337 59.24 1.033903 + 56417, // 338 59.41 1.036971 + 56519, // 339 59.59 1.040039 + 56621, // 340 59.77 1.043107 + 56722, // 341 59.94 1.046175 + 56822, // 342 60.12 1.049243 + 56922, // 343 60.29 1.052311 + 57022, // 344 60.47 1.055379 + 57120, // 345 60.64 1.058447 + 57219, // 346 60.82 1.061515 + 57316, // 347 61.00 1.064583 + 57414, // 348 61.17 1.067651 + 57510, // 349 61.35 1.070719 + 57606, // 350 61.52 1.073787 + 57702, // 351 61.70 1.076855 + 57797, // 352 61.88 1.079922 + 57892, // 353 62.05 1.082990 + 57986, // 354 62.23 1.086058 + 58079, // 355 62.40 1.089126 + 58172, // 356 62.58 1.092194 + 58264, // 357 62.75 1.095262 + 58356, // 358 62.93 1.098330 + 58447, // 359 63.11 1.101398 + 58538, // 360 63.28 1.104466 + 58628, // 361 63.46 1.107534 + 58718, // 362 63.63 1.110602 + 58807, // 363 63.81 1.113670 + 58895, // 364 63.98 1.116738 + 58983, // 365 64.16 1.119806 + 59070, // 366 64.34 1.122874 + 59157, // 367 64.51 1.125942 + 59243, // 368 64.69 1.129010 + 59329, // 369 64.86 1.132078 + 59414, // 370 65.04 1.135146 + 59499, // 371 65.21 1.138214 + 59583, // 372 65.39 1.141282 + 59666, // 373 65.57 1.144350 + 59749, // 374 65.74 1.147418 + 59831, // 375 65.92 1.150486 + 59913, // 376 66.09 1.153554 + 59994, // 377 66.27 1.156622 + 60075, // 378 66.45 1.159689 + 60155, // 379 66.62 1.162757 + 60235, // 380 66.80 1.165825 + 60313, // 381 66.97 1.168893 + 60392, // 382 67.15 1.171961 + 60470, // 383 67.32 1.175029 + 60547, // 384 67.50 1.178097 + 60624, // 385 67.68 1.181165 + 60700, // 386 67.85 1.184233 + 60775, // 387 68.03 1.187301 + 60850, // 388 68.20 1.190369 + 60924, // 389 68.38 1.193437 + 60998, // 390 68.55 1.196505 + 61071, // 391 68.73 1.199573 + 61144, // 392 68.91 1.202641 + 61216, // 393 69.08 1.205709 + 61288, // 394 69.26 1.208777 + 61359, // 395 69.43 1.211845 + 61429, // 396 69.61 1.214913 + 61499, // 397 69.79 1.217981 + 61568, // 398 69.96 1.221049 + 61637, // 399 70.14 1.224117 + 61705, // 400 70.31 1.227185 + 61772, // 401 70.49 1.230253 + 61839, // 402 70.66 1.233321 + 61905, // 403 70.84 1.236389 + 61971, // 404 71.02 1.239456 + 62036, // 405 71.19 1.242524 + 62100, // 406 71.37 1.245592 + 62164, // 407 71.54 1.248660 + 62228, // 408 71.72 1.251728 + 62291, // 409 71.89 1.254796 + 62353, // 410 72.07 1.257864 + 62414, // 411 72.25 1.260932 + 62475, // 412 72.42 1.264000 + 62536, // 413 72.60 1.267068 + 62596, // 414 72.77 1.270136 + 62655, // 415 72.95 1.273204 + 62714, // 416 73.12 1.276272 + 62772, // 417 73.30 1.279340 + 62829, // 418 73.48 1.282408 + 62886, // 419 73.65 1.285476 + 62942, // 420 73.83 1.288544 + 62998, // 421 74.00 1.291612 + 63053, // 422 74.18 1.294680 + 63108, // 423 74.36 1.297748 + 63162, // 424 74.53 1.300816 + 63215, // 425 74.71 1.303884 + 63268, // 426 74.88 1.306952 + 63320, // 427 75.06 1.310020 + 63371, // 428 75.23 1.313088 + 63422, // 429 75.41 1.316156 + 63473, // 430 75.59 1.319223 + 63522, // 431 75.76 1.322291 + 63571, // 432 75.94 1.325359 + 63620, // 433 76.11 1.328427 + 63668, // 434 76.29 1.331495 + 63715, // 435 76.46 1.334563 + 63762, // 436 76.64 1.337631 + 63808, // 437 76.82 1.340699 + 63854, // 438 76.99 1.343767 + 63899, // 439 77.17 1.346835 + 63943, // 440 77.34 1.349903 + 63987, // 441 77.52 1.352971 + 64030, // 442 77.70 1.356039 + 64073, // 443 77.87 1.359107 + 64115, // 444 78.05 1.362175 + 64156, // 445 78.22 1.365243 + 64197, // 446 78.40 1.368311 + 64237, // 447 78.57 1.371379 + 64276, // 448 78.75 1.374447 + 64315, // 449 78.93 1.377515 + 64353, // 450 79.10 1.380583 + 64391, // 451 79.28 1.383651 + 64428, // 452 79.45 1.386719 + 64465, // 453 79.63 1.389787 + 64501, // 454 79.80 1.392855 + 64536, // 455 79.98 1.395923 + 64571, // 456 80.16 1.398990 + 64605, // 457 80.33 1.402058 + 64638, // 458 80.51 1.405126 + 64671, // 459 80.68 1.408194 + 64703, // 460 80.86 1.411262 + 64735, // 461 81.04 1.414330 + 64766, // 462 81.21 1.417398 + 64796, // 463 81.39 1.420466 + 64826, // 464 81.56 1.423534 + 64855, // 465 81.74 1.426602 + 64884, // 466 81.91 1.429670 + 64912, // 467 82.09 1.432738 + 64939, // 468 82.27 1.435806 + 64966, // 469 82.44 1.438874 + 64992, // 470 82.62 1.441942 + 65018, // 471 82.79 1.445010 + 65043, // 472 82.97 1.448078 + 65067, // 473 83.14 1.451146 + 65091, // 474 83.32 1.454214 + 65114, // 475 83.50 1.457282 + 65136, // 476 83.67 1.460350 + 65158, // 477 83.85 1.463418 + 65179, // 478 84.02 1.466486 + 65200, // 479 84.20 1.469554 + 65220, // 480 84.38 1.472622 + 65239, // 481 84.55 1.475690 + 65258, // 482 84.73 1.478757 + 65276, // 483 84.90 1.481825 + 65294, // 484 85.08 1.484893 + 65311, // 485 85.25 1.487961 + 65327, // 486 85.43 1.491029 + 65343, // 487 85.61 1.494097 + 65358, // 488 85.78 1.497165 + 65372, // 489 85.96 1.500233 + 65386, // 490 86.13 1.503301 + 65400, // 491 86.31 1.506369 + 65412, // 492 86.48 1.509437 + 65424, // 493 86.66 1.512505 + 65436, // 494 86.84 1.515573 + 65446, // 495 87.01 1.518641 + 65457, // 496 87.19 1.521709 + 65466, // 497 87.36 1.524777 + 65475, // 498 87.54 1.527845 + 65483, // 499 87.71 1.530913 + 65491, // 500 87.89 1.533981 + 65498, // 501 88.07 1.537049 + 65505, // 502 88.24 1.540117 + 65511, // 503 88.42 1.543185 + 65516, // 504 88.59 1.546253 + 65520, // 505 88.77 1.549321 + 65524, // 506 88.95 1.552389 + 65528, // 507 89.12 1.555457 + 65531, // 508 89.30 1.558524 + 65533, // 509 89.47 1.561592 + 65534, // 510 89.65 1.564660 + 65535, // 511 89.82 1.567728 + 65536, // 512 90.00 1.570796 + 65535, // 513 90.18 1.573864 + 65534, // 514 90.35 1.576932 + 65533, // 515 90.53 1.580000 + 65531, // 516 90.70 1.583068 + 65528, // 517 90.88 1.586136 + 65524, // 518 91.05 1.589204 + 65520, // 519 91.23 1.592272 + 65516, // 520 91.41 1.595340 + 65511, // 521 91.58 1.598408 + 65505, // 522 91.76 1.601476 + 65498, // 523 91.93 1.604544 + 65491, // 524 92.11 1.607612 + 65483, // 525 92.29 1.610680 + 65475, // 526 92.46 1.613748 + 65466, // 527 92.64 1.616816 + 65457, // 528 92.81 1.619884 + 65446, // 529 92.99 1.622952 + 65436, // 530 93.16 1.626020 + 65424, // 531 93.34 1.629088 + 65412, // 532 93.52 1.632156 + 65400, // 533 93.69 1.635224 + 65386, // 534 93.87 1.638291 + 65372, // 535 94.04 1.641359 + 65358, // 536 94.22 1.644427 + 65343, // 537 94.39 1.647495 + 65327, // 538 94.57 1.650563 + 65311, // 539 94.75 1.653631 + 65294, // 540 94.92 1.656699 + 65276, // 541 95.10 1.659767 + 65258, // 542 95.27 1.662835 + 65239, // 543 95.45 1.665903 + 65220, // 544 95.62 1.668971 + 65200, // 545 95.80 1.672039 + 65179, // 546 95.98 1.675107 + 65158, // 547 96.15 1.678175 + 65136, // 548 96.33 1.681243 + 65114, // 549 96.50 1.684311 + 65091, // 550 96.68 1.687379 + 65067, // 551 96.86 1.690447 + 65043, // 552 97.03 1.693515 + 65018, // 553 97.21 1.696583 + 64992, // 554 97.38 1.699651 + 64966, // 555 97.56 1.702719 + 64939, // 556 97.73 1.705787 + 64912, // 557 97.91 1.708855 + 64884, // 558 98.09 1.711923 + 64855, // 559 98.26 1.714991 + 64826, // 560 98.44 1.718058 + 64796, // 561 98.61 1.721126 + 64766, // 562 98.79 1.724194 + 64735, // 563 98.96 1.727262 + 64703, // 564 99.14 1.730330 + 64671, // 565 99.32 1.733398 + 64638, // 566 99.49 1.736466 + 64605, // 567 99.67 1.739534 + 64571, // 568 99.84 1.742602 + 64536, // 569 100.02 1.745670 + 64501, // 570 100.20 1.748738 + 64465, // 571 100.37 1.751806 + 64428, // 572 100.55 1.754874 + 64391, // 573 100.72 1.757942 + 64353, // 574 100.90 1.761010 + 64315, // 575 101.07 1.764078 + 64276, // 576 101.25 1.767146 + 64237, // 577 101.43 1.770214 + 64197, // 578 101.60 1.773282 + 64156, // 579 101.78 1.776350 + 64115, // 580 101.95 1.779418 + 64073, // 581 102.13 1.782486 + 64030, // 582 102.30 1.785554 + 63987, // 583 102.48 1.788622 + 63943, // 584 102.66 1.791690 + 63899, // 585 102.83 1.794758 + 63854, // 586 103.01 1.797825 + 63808, // 587 103.18 1.800893 + 63762, // 588 103.36 1.803961 + 63715, // 589 103.54 1.807029 + 63668, // 590 103.71 1.810097 + 63620, // 591 103.89 1.813165 + 63571, // 592 104.06 1.816233 + 63522, // 593 104.24 1.819301 + 63473, // 594 104.41 1.822369 + 63422, // 595 104.59 1.825437 + 63371, // 596 104.77 1.828505 + 63320, // 597 104.94 1.831573 + 63268, // 598 105.12 1.834641 + 63215, // 599 105.29 1.837709 + 63162, // 600 105.47 1.840777 + 63108, // 601 105.64 1.843845 + 63053, // 602 105.82 1.846913 + 62998, // 603 106.00 1.849981 + 62942, // 604 106.17 1.853049 + 62886, // 605 106.35 1.856117 + 62829, // 606 106.52 1.859185 + 62772, // 607 106.70 1.862253 + 62714, // 608 106.88 1.865321 + 62655, // 609 107.05 1.868389 + 62596, // 610 107.23 1.871457 + 62536, // 611 107.40 1.874525 + 62475, // 612 107.58 1.877592 + 62414, // 613 107.75 1.880660 + 62353, // 614 107.93 1.883728 + 62291, // 615 108.11 1.886796 + 62228, // 616 108.28 1.889864 + 62164, // 617 108.46 1.892932 + 62100, // 618 108.63 1.896000 + 62036, // 619 108.81 1.899068 + 61971, // 620 108.98 1.902136 + 61905, // 621 109.16 1.905204 + 61839, // 622 109.34 1.908272 + 61772, // 623 109.51 1.911340 + 61705, // 624 109.69 1.914408 + 61637, // 625 109.86 1.917476 + 61568, // 626 110.04 1.920544 + 61499, // 627 110.21 1.923612 + 61429, // 628 110.39 1.926680 + 61359, // 629 110.57 1.929748 + 61288, // 630 110.74 1.932816 + 61216, // 631 110.92 1.935884 + 61144, // 632 111.09 1.938952 + 61071, // 633 111.27 1.942020 + 60998, // 634 111.45 1.945088 + 60924, // 635 111.62 1.948156 + 60850, // 636 111.80 1.951224 + 60775, // 637 111.97 1.954292 + 60700, // 638 112.15 1.957359 + 60624, // 639 112.32 1.960427 + 60547, // 640 112.50 1.963495 + 60470, // 641 112.68 1.966563 + 60392, // 642 112.85 1.969631 + 60313, // 643 113.03 1.972699 + 60235, // 644 113.20 1.975767 + 60155, // 645 113.38 1.978835 + 60075, // 646 113.55 1.981903 + 59994, // 647 113.73 1.984971 + 59913, // 648 113.91 1.988039 + 59831, // 649 114.08 1.991107 + 59749, // 650 114.26 1.994175 + 59666, // 651 114.43 1.997243 + 59583, // 652 114.61 2.000311 + 59499, // 653 114.79 2.003379 + 59414, // 654 114.96 2.006447 + 59329, // 655 115.14 2.009515 + 59243, // 656 115.31 2.012583 + 59157, // 657 115.49 2.015651 + 59070, // 658 115.66 2.018719 + 58983, // 659 115.84 2.021787 + 58895, // 660 116.02 2.024855 + 58807, // 661 116.19 2.027923 + 58718, // 662 116.37 2.030991 + 58628, // 663 116.54 2.034059 + 58538, // 664 116.72 2.037126 + 58447, // 665 116.89 2.040194 + 58356, // 666 117.07 2.043262 + 58264, // 667 117.25 2.046330 + 58172, // 668 117.42 2.049398 + 58079, // 669 117.60 2.052466 + 57986, // 670 117.77 2.055534 + 57892, // 671 117.95 2.058602 + 57797, // 672 118.12 2.061670 + 57702, // 673 118.30 2.064738 + 57606, // 674 118.48 2.067806 + 57510, // 675 118.65 2.070874 + 57414, // 676 118.83 2.073942 + 57316, // 677 119.00 2.077010 + 57219, // 678 119.18 2.080078 + 57120, // 679 119.36 2.083146 + 57022, // 680 119.53 2.086214 + 56922, // 681 119.71 2.089282 + 56822, // 682 119.88 2.092350 + 56722, // 683 120.06 2.095418 + 56621, // 684 120.23 2.098486 + 56519, // 685 120.41 2.101554 + 56417, // 686 120.59 2.104622 + 56315, // 687 120.76 2.107690 + 56212, // 688 120.94 2.110758 + 56108, // 689 121.11 2.113826 + 56004, // 690 121.29 2.116893 + 55899, // 691 121.46 2.119961 + 55794, // 692 121.64 2.123029 + 55688, // 693 121.82 2.126097 + 55582, // 694 121.99 2.129165 + 55475, // 695 122.17 2.132233 + 55368, // 696 122.34 2.135301 + 55260, // 697 122.52 2.138369 + 55152, // 698 122.70 2.141437 + 55043, // 699 122.87 2.144505 + 54933, // 700 123.05 2.147573 + 54823, // 701 123.22 2.150641 + 54713, // 702 123.40 2.153709 + 54602, // 703 123.57 2.156777 + 54491, // 704 123.75 2.159845 + 54379, // 705 123.93 2.162913 + 54266, // 706 124.10 2.165981 + 54153, // 707 124.28 2.169049 + 54040, // 708 124.45 2.172117 + 53926, // 709 124.63 2.175185 + 53811, // 710 124.80 2.178253 + 53696, // 711 124.98 2.181321 + 53581, // 712 125.16 2.184389 + 53465, // 713 125.33 2.187457 + 53348, // 714 125.51 2.190525 + 53231, // 715 125.68 2.193593 + 53114, // 716 125.86 2.196660 + 52996, // 717 126.04 2.199728 + 52877, // 718 126.21 2.202796 + 52758, // 719 126.39 2.205864 + 52639, // 720 126.56 2.208932 + 52518, // 721 126.74 2.212000 + 52398, // 722 126.91 2.215068 + 52277, // 723 127.09 2.218136 + 52155, // 724 127.27 2.221204 + 52033, // 725 127.44 2.224272 + 51911, // 726 127.62 2.227340 + 51788, // 727 127.79 2.230408 + 51665, // 728 127.97 2.233476 + 51541, // 729 128.14 2.236544 + 51416, // 730 128.32 2.239612 + 51291, // 731 128.50 2.242680 + 51166, // 732 128.67 2.245748 + 51040, // 733 128.85 2.248816 + 50914, // 734 129.02 2.251884 + 50787, // 735 129.20 2.254952 + 50660, // 736 129.38 2.258020 + 50532, // 737 129.55 2.261088 + 50403, // 738 129.73 2.264156 + 50275, // 739 129.90 2.267224 + 50146, // 740 130.08 2.270292 + 50016, // 741 130.25 2.273360 + 49886, // 742 130.43 2.276427 + 49755, // 743 130.61 2.279495 + 49624, // 744 130.78 2.282563 + 49492, // 745 130.96 2.285631 + 49360, // 746 131.13 2.288699 + 49228, // 747 131.31 2.291767 + 49095, // 748 131.48 2.294835 + 48961, // 749 131.66 2.297903 + 48828, // 750 131.84 2.300971 + 48693, // 751 132.01 2.304039 + 48558, // 752 132.19 2.307107 + 48423, // 753 132.36 2.310175 + 48288, // 754 132.54 2.313243 + 48151, // 755 132.71 2.316311 + 48015, // 756 132.89 2.319379 + 47878, // 757 133.07 2.322447 + 47740, // 758 133.24 2.325515 + 47602, // 759 133.42 2.328583 + 47464, // 760 133.59 2.331651 + 47325, // 761 133.77 2.334719 + 47186, // 762 133.95 2.337787 + 47046, // 763 134.12 2.340855 + 46906, // 764 134.30 2.343923 + 46765, // 765 134.47 2.346991 + 46624, // 766 134.65 2.350059 + 46482, // 767 134.82 2.353127 + 46340, // 768 135.00 2.356194 + 46198, // 769 135.18 2.359262 + 46055, // 770 135.35 2.362330 + 45912, // 771 135.53 2.365398 + 45768, // 772 135.70 2.368466 + 45624, // 773 135.88 2.371534 + 45480, // 774 136.05 2.374602 + 45335, // 775 136.23 2.377670 + 45189, // 776 136.41 2.380738 + 45043, // 777 136.58 2.383806 + 44897, // 778 136.76 2.386874 + 44750, // 779 136.93 2.389942 + 44603, // 780 137.11 2.393010 + 44456, // 781 137.29 2.396078 + 44308, // 782 137.46 2.399146 + 44160, // 783 137.64 2.402214 + 44011, // 784 137.81 2.405282 + 43862, // 785 137.99 2.408350 + 43712, // 786 138.16 2.411418 + 43562, // 787 138.34 2.414486 + 43412, // 788 138.52 2.417554 + 43261, // 789 138.69 2.420622 + 43110, // 790 138.87 2.423690 + 42958, // 791 139.04 2.426758 + 42806, // 792 139.22 2.429826 + 42653, // 793 139.39 2.432894 + 42501, // 794 139.57 2.435961 + 42347, // 795 139.75 2.439029 + 42194, // 796 139.92 2.442097 + 42040, // 797 140.10 2.445165 + 41885, // 798 140.27 2.448233 + 41730, // 799 140.45 2.451301 + 41575, // 800 140.62 2.454369 + 41419, // 801 140.80 2.457437 + 41263, // 802 140.98 2.460505 + 41107, // 803 141.15 2.463573 + 40950, // 804 141.33 2.466641 + 40793, // 805 141.50 2.469709 + 40636, // 806 141.68 2.472777 + 40478, // 807 141.86 2.475845 + 40319, // 808 142.03 2.478913 + 40161, // 809 142.21 2.481981 + 40002, // 810 142.38 2.485049 + 39842, // 811 142.56 2.488117 + 39682, // 812 142.73 2.491185 + 39522, // 813 142.91 2.494253 + 39362, // 814 143.09 2.497321 + 39201, // 815 143.26 2.500389 + 39039, // 816 143.44 2.503457 + 38878, // 817 143.61 2.506525 + 38716, // 818 143.79 2.509593 + 38553, // 819 143.96 2.512661 + 38390, // 820 144.14 2.515728 + 38227, // 821 144.32 2.518796 + 38064, // 822 144.49 2.521864 + 37900, // 823 144.67 2.524932 + 37736, // 824 144.84 2.528000 + 37571, // 825 145.02 2.531068 + 37406, // 826 145.20 2.534136 + 37241, // 827 145.37 2.537204 + 37075, // 828 145.55 2.540272 + 36909, // 829 145.72 2.543340 + 36743, // 830 145.90 2.546408 + 36576, // 831 146.07 2.549476 + 36409, // 832 146.25 2.552544 + 36242, // 833 146.43 2.555612 + 36074, // 834 146.60 2.558680 + 35906, // 835 146.78 2.561748 + 35738, // 836 146.95 2.564816 + 35569, // 837 147.13 2.567884 + 35400, // 838 147.30 2.570952 + 35231, // 839 147.48 2.574020 + 35061, // 840 147.66 2.577088 + 34891, // 841 147.83 2.580156 + 34721, // 842 148.01 2.583224 + 34550, // 843 148.18 2.586292 + 34379, // 844 148.36 2.589360 + 34208, // 845 148.54 2.592428 + 34036, // 846 148.71 2.595495 + 33864, // 847 148.89 2.598563 + 33692, // 848 149.06 2.601631 + 33519, // 849 149.24 2.604699 + 33346, // 850 149.41 2.607767 + 33173, // 851 149.59 2.610835 + 32999, // 852 149.77 2.613903 + 32826, // 853 149.94 2.616971 + 32651, // 854 150.12 2.620039 + 32477, // 855 150.29 2.623107 + 32302, // 856 150.47 2.626175 + 32127, // 857 150.64 2.629243 + 31952, // 858 150.82 2.632311 + 31776, // 859 151.00 2.635379 + 31600, // 860 151.17 2.638447 + 31424, // 861 151.35 2.641515 + 31247, // 862 151.52 2.644583 + 31070, // 863 151.70 2.647651 + 30893, // 864 151.88 2.650719 + 30715, // 865 152.05 2.653787 + 30538, // 866 152.23 2.656855 + 30360, // 867 152.40 2.659923 + 30181, // 868 152.58 2.662991 + 30003, // 869 152.75 2.666059 + 29824, // 870 152.93 2.669127 + 29645, // 871 153.11 2.672195 + 29465, // 872 153.28 2.675262 + 29285, // 873 153.46 2.678330 + 29105, // 874 153.63 2.681398 + 28925, // 875 153.81 2.684466 + 28745, // 876 153.98 2.687534 + 28564, // 877 154.16 2.690602 + 28383, // 878 154.34 2.693670 + 28201, // 879 154.51 2.696738 + 28020, // 880 154.69 2.699806 + 27838, // 881 154.86 2.702874 + 27656, // 882 155.04 2.705942 + 27473, // 883 155.21 2.709010 + 27291, // 884 155.39 2.712078 + 27108, // 885 155.57 2.715146 + 26925, // 886 155.74 2.718214 + 26741, // 887 155.92 2.721282 + 26557, // 888 156.09 2.724350 + 26373, // 889 156.27 2.727418 + 26189, // 890 156.45 2.730486 + 26005, // 891 156.62 2.733554 + 25820, // 892 156.80 2.736622 + 25635, // 893 156.97 2.739690 + 25450, // 894 157.15 2.742758 + 25265, // 895 157.32 2.745826 + 25079, // 896 157.50 2.748894 + 24893, // 897 157.68 2.751962 + 24707, // 898 157.85 2.755029 + 24521, // 899 158.03 2.758097 + 24334, // 900 158.20 2.761165 + 24147, // 901 158.38 2.764233 + 23960, // 902 158.55 2.767301 + 23773, // 903 158.73 2.770369 + 23586, // 904 158.91 2.773437 + 23398, // 905 159.08 2.776505 + 23210, // 906 159.26 2.779573 + 23022, // 907 159.43 2.782641 + 22833, // 908 159.61 2.785709 + 22645, // 909 159.79 2.788777 + 22456, // 910 159.96 2.791845 + 22267, // 911 160.14 2.794913 + 22078, // 912 160.31 2.797981 + 21889, // 913 160.49 2.801049 + 21699, // 914 160.66 2.804117 + 21509, // 915 160.84 2.807185 + 21319, // 916 161.02 2.810253 + 21129, // 917 161.19 2.813321 + 20938, // 918 161.37 2.816389 + 20748, // 919 161.54 2.819457 + 20557, // 920 161.72 2.822525 + 20366, // 921 161.89 2.825593 + 20175, // 922 162.07 2.828661 + 19983, // 923 162.25 2.831729 + 19792, // 924 162.42 2.834796 + 19600, // 925 162.60 2.837864 + 19408, // 926 162.77 2.840932 + 19216, // 927 162.95 2.844000 + 19024, // 928 163.12 2.847068 + 18831, // 929 163.30 2.850136 + 18638, // 930 163.48 2.853204 + 18446, // 931 163.65 2.856272 + 18253, // 932 163.83 2.859340 + 18059, // 933 164.00 2.862408 + 17866, // 934 164.18 2.865476 + 17672, // 935 164.36 2.868544 + 17479, // 936 164.53 2.871612 + 17285, // 937 164.71 2.874680 + 17091, // 938 164.88 2.877748 + 16897, // 939 165.06 2.880816 + 16702, // 940 165.23 2.883884 + 16508, // 941 165.41 2.886952 + 16313, // 942 165.59 2.890020 + 16118, // 943 165.76 2.893088 + 15923, // 944 165.94 2.896156 + 15728, // 945 166.11 2.899224 + 15533, // 946 166.29 2.902292 + 15338, // 947 166.46 2.905360 + 15142, // 948 166.64 2.908428 + 14946, // 949 166.82 2.911496 + 14751, // 950 166.99 2.914563 + 14555, // 951 167.17 2.917631 + 14359, // 952 167.34 2.920699 + 14162, // 953 167.52 2.923767 + 13966, // 954 167.70 2.926835 + 13769, // 955 167.87 2.929903 + 13573, // 956 168.05 2.932971 + 13376, // 957 168.22 2.936039 + 13179, // 958 168.40 2.939107 + 12982, // 959 168.57 2.942175 + 12785, // 960 168.75 2.945243 + 12588, // 961 168.93 2.948311 + 12390, // 962 169.10 2.951379 + 12193, // 963 169.28 2.954447 + 11995, // 964 169.45 2.957515 + 11797, // 965 169.63 2.960583 + 11600, // 966 169.80 2.963651 + 11402, // 967 169.98 2.966719 + 11204, // 968 170.16 2.969787 + 11006, // 969 170.33 2.972855 + 10807, // 970 170.51 2.975923 + 10609, // 971 170.68 2.978991 + 10410, // 972 170.86 2.982059 + 10212, // 973 171.04 2.985127 + 10013, // 974 171.21 2.988195 + 9814, // 975 171.39 2.991263 + 9616, // 976 171.56 2.994330 + 9417, // 977 171.74 2.997398 + 9218, // 978 171.91 3.000466 + 9019, // 979 172.09 3.003534 + 8819, // 980 172.27 3.006602 + 8620, // 981 172.44 3.009670 + 8421, // 982 172.62 3.012738 + 8221, // 983 172.79 3.015806 + 8022, // 984 172.97 3.018874 + 7822, // 985 173.14 3.021942 + 7623, // 986 173.32 3.025010 + 7423, // 987 173.50 3.028078 + 7223, // 988 173.67 3.031146 + 7023, // 989 173.85 3.034214 + 6823, // 990 174.02 3.037282 + 6623, // 991 174.20 3.040350 + 6423, // 992 174.38 3.043418 + 6223, // 993 174.55 3.046486 + 6023, // 994 174.73 3.049554 + 5823, // 995 174.90 3.052622 + 5622, // 996 175.08 3.055690 + 5422, // 997 175.25 3.058758 + 5222, // 998 175.43 3.061826 + 5021, // 999 175.61 3.064894 + 4821, // 1000 175.78 3.067962 + 4620, // 1001 175.96 3.071030 + 4420, // 1002 176.13 3.074097 + 4219, // 1003 176.31 3.077165 + 4018, // 1004 176.48 3.080233 + 3818, // 1005 176.66 3.083301 + 3617, // 1006 176.84 3.086369 + 3416, // 1007 177.01 3.089437 + 3215, // 1008 177.19 3.092505 + 3014, // 1009 177.36 3.095573 + 2814, // 1010 177.54 3.098641 + 2613, // 1011 177.71 3.101709 + 2412, // 1012 177.89 3.104777 + 2211, // 1013 178.07 3.107845 + 2010, // 1014 178.24 3.110913 + 1809, // 1015 178.42 3.113981 + 1608, // 1016 178.59 3.117049 + 1407, // 1017 178.77 3.120117 + 1206, // 1018 178.95 3.123185 + 1005, // 1019 179.12 3.126253 + 804, // 1020 179.30 3.129321 + 603, // 1021 179.47 3.132389 + 402, // 1022 179.65 3.135457 + 201, // 1023 179.82 3.138525 + 0, // 1024 180.00 3.141593 + -201, // 1025 180.18 3.144661 + -402, // 1026 180.35 3.147729 + -603, // 1027 180.53 3.150797 + -804, // 1028 180.70 3.153865 + -1005, // 1029 180.88 3.156932 + -1206, // 1030 181.05 3.160000 + -1407, // 1031 181.23 3.163068 + -1608, // 1032 181.41 3.166136 + -1809, // 1033 181.58 3.169204 + -2010, // 1034 181.76 3.172272 + -2211, // 1035 181.93 3.175340 + -2412, // 1036 182.11 3.178408 + -2613, // 1037 182.29 3.181476 + -2814, // 1038 182.46 3.184544 + -3014, // 1039 182.64 3.187612 + -3215, // 1040 182.81 3.190680 + -3416, // 1041 182.99 3.193748 + -3617, // 1042 183.16 3.196816 + -3818, // 1043 183.34 3.199884 + -4018, // 1044 183.52 3.202952 + -4219, // 1045 183.69 3.206020 + -4420, // 1046 183.87 3.209088 + -4620, // 1047 184.04 3.212156 + -4821, // 1048 184.22 3.215224 + -5021, // 1049 184.39 3.218292 + -5222, // 1050 184.57 3.221360 + -5422, // 1051 184.75 3.224428 + -5622, // 1052 184.92 3.227496 + -5823, // 1053 185.10 3.230564 + -6023, // 1054 185.27 3.233632 + -6223, // 1055 185.45 3.236699 + -6423, // 1056 185.62 3.239767 + -6623, // 1057 185.80 3.242835 + -6823, // 1058 185.98 3.245903 + -7023, // 1059 186.15 3.248971 + -7223, // 1060 186.33 3.252039 + -7423, // 1061 186.50 3.255107 + -7623, // 1062 186.68 3.258175 + -7822, // 1063 186.86 3.261243 + -8022, // 1064 187.03 3.264311 + -8221, // 1065 187.21 3.267379 + -8421, // 1066 187.38 3.270447 + -8620, // 1067 187.56 3.273515 + -8819, // 1068 187.73 3.276583 + -9019, // 1069 187.91 3.279651 + -9218, // 1070 188.09 3.282719 + -9417, // 1071 188.26 3.285787 + -9616, // 1072 188.44 3.288855 + -9814, // 1073 188.61 3.291923 + -10013, // 1074 188.79 3.294991 + -10212, // 1075 188.96 3.298059 + -10410, // 1076 189.14 3.301127 + -10609, // 1077 189.32 3.304195 + -10807, // 1078 189.49 3.307263 + -11006, // 1079 189.67 3.310331 + -11204, // 1080 189.84 3.313399 + -11402, // 1081 190.02 3.316466 + -11600, // 1082 190.20 3.319534 + -11797, // 1083 190.37 3.322602 + -11995, // 1084 190.55 3.325670 + -12193, // 1085 190.72 3.328738 + -12390, // 1086 190.90 3.331806 + -12588, // 1087 191.07 3.334874 + -12785, // 1088 191.25 3.337942 + -12982, // 1089 191.43 3.341010 + -13179, // 1090 191.60 3.344078 + -13376, // 1091 191.78 3.347146 + -13573, // 1092 191.95 3.350214 + -13769, // 1093 192.13 3.353282 + -13966, // 1094 192.30 3.356350 + -14162, // 1095 192.48 3.359418 + -14359, // 1096 192.66 3.362486 + -14555, // 1097 192.83 3.365554 + -14751, // 1098 193.01 3.368622 + -14946, // 1099 193.18 3.371690 + -15142, // 1100 193.36 3.374758 + -15338, // 1101 193.54 3.377826 + -15533, // 1102 193.71 3.380894 + -15728, // 1103 193.89 3.383962 + -15923, // 1104 194.06 3.387030 + -16118, // 1105 194.24 3.390098 + -16313, // 1106 194.41 3.393166 + -16508, // 1107 194.59 3.396233 + -16702, // 1108 194.77 3.399301 + -16897, // 1109 194.94 3.402369 + -17091, // 1110 195.12 3.405437 + -17285, // 1111 195.29 3.408505 + -17479, // 1112 195.47 3.411573 + -17672, // 1113 195.64 3.414641 + -17866, // 1114 195.82 3.417709 + -18059, // 1115 196.00 3.420777 + -18253, // 1116 196.17 3.423845 + -18446, // 1117 196.35 3.426913 + -18638, // 1118 196.52 3.429981 + -18831, // 1119 196.70 3.433049 + -19024, // 1120 196.88 3.436117 + -19216, // 1121 197.05 3.439185 + -19408, // 1122 197.23 3.442253 + -19600, // 1123 197.40 3.445321 + -19792, // 1124 197.58 3.448389 + -19983, // 1125 197.75 3.451457 + -20175, // 1126 197.93 3.454525 + -20366, // 1127 198.11 3.457593 + -20557, // 1128 198.28 3.460661 + -20748, // 1129 198.46 3.463729 + -20938, // 1130 198.63 3.466797 + -21129, // 1131 198.81 3.469865 + -21319, // 1132 198.98 3.472933 + -21509, // 1133 199.16 3.476000 + -21699, // 1134 199.34 3.479068 + -21889, // 1135 199.51 3.482136 + -22078, // 1136 199.69 3.485204 + -22267, // 1137 199.86 3.488272 + -22456, // 1138 200.04 3.491340 + -22645, // 1139 200.21 3.494408 + -22833, // 1140 200.39 3.497476 + -23022, // 1141 200.57 3.500544 + -23210, // 1142 200.74 3.503612 + -23398, // 1143 200.92 3.506680 + -23586, // 1144 201.09 3.509748 + -23773, // 1145 201.27 3.512816 + -23960, // 1146 201.45 3.515884 + -24147, // 1147 201.62 3.518952 + -24334, // 1148 201.80 3.522020 + -24521, // 1149 201.97 3.525088 + -24707, // 1150 202.15 3.528156 + -24893, // 1151 202.32 3.531224 + -25079, // 1152 202.50 3.534292 + -25265, // 1153 202.68 3.537360 + -25450, // 1154 202.85 3.540428 + -25635, // 1155 203.03 3.543496 + -25820, // 1156 203.20 3.546564 + -26005, // 1157 203.38 3.549632 + -26189, // 1158 203.55 3.552700 + -26373, // 1159 203.73 3.555767 + -26557, // 1160 203.91 3.558835 + -26741, // 1161 204.08 3.561903 + -26925, // 1162 204.26 3.564971 + -27108, // 1163 204.43 3.568039 + -27291, // 1164 204.61 3.571107 + -27473, // 1165 204.79 3.574175 + -27656, // 1166 204.96 3.577243 + -27838, // 1167 205.14 3.580311 + -28020, // 1168 205.31 3.583379 + -28201, // 1169 205.49 3.586447 + -28383, // 1170 205.66 3.589515 + -28564, // 1171 205.84 3.592583 + -28745, // 1172 206.02 3.595651 + -28925, // 1173 206.19 3.598719 + -29105, // 1174 206.37 3.601787 + -29285, // 1175 206.54 3.604855 + -29465, // 1176 206.72 3.607923 + -29645, // 1177 206.89 3.610991 + -29824, // 1178 207.07 3.614059 + -30003, // 1179 207.25 3.617127 + -30181, // 1180 207.42 3.620195 + -30360, // 1181 207.60 3.623263 + -30538, // 1182 207.77 3.626331 + -30715, // 1183 207.95 3.629399 + -30893, // 1184 208.12 3.632467 + -31070, // 1185 208.30 3.635534 + -31247, // 1186 208.48 3.638602 + -31424, // 1187 208.65 3.641670 + -31600, // 1188 208.83 3.644738 + -31776, // 1189 209.00 3.647806 + -31952, // 1190 209.18 3.650874 + -32127, // 1191 209.36 3.653942 + -32302, // 1192 209.53 3.657010 + -32477, // 1193 209.71 3.660078 + -32651, // 1194 209.88 3.663146 + -32826, // 1195 210.06 3.666214 + -32999, // 1196 210.23 3.669282 + -33173, // 1197 210.41 3.672350 + -33346, // 1198 210.59 3.675418 + -33519, // 1199 210.76 3.678486 + -33692, // 1200 210.94 3.681554 + -33864, // 1201 211.11 3.684622 + -34036, // 1202 211.29 3.687690 + -34208, // 1203 211.46 3.690758 + -34379, // 1204 211.64 3.693826 + -34550, // 1205 211.82 3.696894 + -34721, // 1206 211.99 3.699962 + -34891, // 1207 212.17 3.703030 + -35061, // 1208 212.34 3.706098 + -35231, // 1209 212.52 3.709166 + -35400, // 1210 212.70 3.712234 + -35569, // 1211 212.87 3.715301 + -35738, // 1212 213.05 3.718369 + -35906, // 1213 213.22 3.721437 + -36074, // 1214 213.40 3.724505 + -36242, // 1215 213.57 3.727573 + -36409, // 1216 213.75 3.730641 + -36576, // 1217 213.93 3.733709 + -36743, // 1218 214.10 3.736777 + -36909, // 1219 214.28 3.739845 + -37075, // 1220 214.45 3.742913 + -37241, // 1221 214.63 3.745981 + -37406, // 1222 214.80 3.749049 + -37571, // 1223 214.98 3.752117 + -37736, // 1224 215.16 3.755185 + -37900, // 1225 215.33 3.758253 + -38064, // 1226 215.51 3.761321 + -38227, // 1227 215.68 3.764389 + -38390, // 1228 215.86 3.767457 + -38553, // 1229 216.04 3.770525 + -38716, // 1230 216.21 3.773593 + -38878, // 1231 216.39 3.776661 + -39039, // 1232 216.56 3.779729 + -39201, // 1233 216.74 3.782797 + -39362, // 1234 216.91 3.785865 + -39522, // 1235 217.09 3.788933 + -39682, // 1236 217.27 3.792001 + -39842, // 1237 217.44 3.795068 + -40002, // 1238 217.62 3.798136 + -40161, // 1239 217.79 3.801204 + -40319, // 1240 217.97 3.804272 + -40478, // 1241 218.14 3.807340 + -40636, // 1242 218.32 3.810408 + -40793, // 1243 218.50 3.813476 + -40950, // 1244 218.67 3.816544 + -41107, // 1245 218.85 3.819612 + -41263, // 1246 219.02 3.822680 + -41419, // 1247 219.20 3.825748 + -41575, // 1248 219.38 3.828816 + -41730, // 1249 219.55 3.831884 + -41885, // 1250 219.73 3.834952 + -42040, // 1251 219.90 3.838020 + -42194, // 1252 220.08 3.841088 + -42347, // 1253 220.25 3.844156 + -42501, // 1254 220.43 3.847224 + -42653, // 1255 220.61 3.850292 + -42806, // 1256 220.78 3.853360 + -42958, // 1257 220.96 3.856428 + -43110, // 1258 221.13 3.859496 + -43261, // 1259 221.31 3.862564 + -43412, // 1260 221.48 3.865632 + -43562, // 1261 221.66 3.868700 + -43712, // 1262 221.84 3.871768 + -43862, // 1263 222.01 3.874835 + -44011, // 1264 222.19 3.877903 + -44160, // 1265 222.36 3.880971 + -44308, // 1266 222.54 3.884039 + -44456, // 1267 222.71 3.887107 + -44603, // 1268 222.89 3.890175 + -44750, // 1269 223.07 3.893243 + -44897, // 1270 223.24 3.896311 + -45043, // 1271 223.42 3.899379 + -45189, // 1272 223.59 3.902447 + -45335, // 1273 223.77 3.905515 + -45480, // 1274 223.95 3.908583 + -45624, // 1275 224.12 3.911651 + -45768, // 1276 224.30 3.914719 + -45912, // 1277 224.47 3.917787 + -46055, // 1278 224.65 3.920855 + -46198, // 1279 224.82 3.923923 + -46340, // 1280 225.00 3.926991 + -46482, // 1281 225.18 3.930059 + -46624, // 1282 225.35 3.933127 + -46765, // 1283 225.53 3.936195 + -46906, // 1284 225.70 3.939263 + -47046, // 1285 225.88 3.942331 + -47186, // 1286 226.05 3.945399 + -47325, // 1287 226.23 3.948467 + -47464, // 1288 226.41 3.951535 + -47602, // 1289 226.58 3.954602 + -47740, // 1290 226.76 3.957670 + -47878, // 1291 226.93 3.960738 + -48015, // 1292 227.11 3.963806 + -48151, // 1293 227.29 3.966874 + -48288, // 1294 227.46 3.969942 + -48423, // 1295 227.64 3.973010 + -48558, // 1296 227.81 3.976078 + -48693, // 1297 227.99 3.979146 + -48828, // 1298 228.16 3.982214 + -48961, // 1299 228.34 3.985282 + -49095, // 1300 228.52 3.988350 + -49228, // 1301 228.69 3.991418 + -49360, // 1302 228.87 3.994486 + -49492, // 1303 229.04 3.997554 + -49624, // 1304 229.22 4.000622 + -49755, // 1305 229.39 4.003690 + -49886, // 1306 229.57 4.006758 + -50016, // 1307 229.75 4.009826 + -50146, // 1308 229.92 4.012894 + -50275, // 1309 230.10 4.015962 + -50403, // 1310 230.27 4.019030 + -50532, // 1311 230.45 4.022098 + -50660, // 1312 230.62 4.025166 + -50787, // 1313 230.80 4.028234 + -50914, // 1314 230.98 4.031302 + -51040, // 1315 231.15 4.034369 + -51166, // 1316 231.33 4.037437 + -51291, // 1317 231.50 4.040505 + -51416, // 1318 231.68 4.043573 + -51541, // 1319 231.86 4.046641 + -51665, // 1320 232.03 4.049709 + -51788, // 1321 232.21 4.052777 + -51911, // 1322 232.38 4.055845 + -52033, // 1323 232.56 4.058913 + -52155, // 1324 232.73 4.061981 + -52277, // 1325 232.91 4.065049 + -52398, // 1326 233.09 4.068117 + -52518, // 1327 233.26 4.071185 + -52639, // 1328 233.44 4.074253 + -52758, // 1329 233.61 4.077321 + -52877, // 1330 233.79 4.080389 + -52996, // 1331 233.96 4.083457 + -53114, // 1332 234.14 4.086525 + -53231, // 1333 234.32 4.089593 + -53348, // 1334 234.49 4.092661 + -53465, // 1335 234.67 4.095729 + -53581, // 1336 234.84 4.098797 + -53696, // 1337 235.02 4.101865 + -53811, // 1338 235.20 4.104933 + -53926, // 1339 235.37 4.108001 + -54040, // 1340 235.55 4.111069 + -54153, // 1341 235.72 4.114136 + -54266, // 1342 235.90 4.117204 + -54379, // 1343 236.07 4.120272 + -54491, // 1344 236.25 4.123340 + -54602, // 1345 236.43 4.126408 + -54713, // 1346 236.60 4.129476 + -54823, // 1347 236.78 4.132544 + -54933, // 1348 236.95 4.135612 + -55043, // 1349 237.13 4.138680 + -55152, // 1350 237.30 4.141748 + -55260, // 1351 237.48 4.144816 + -55368, // 1352 237.66 4.147884 + -55475, // 1353 237.83 4.150952 + -55582, // 1354 238.01 4.154020 + -55688, // 1355 238.18 4.157088 + -55794, // 1356 238.36 4.160156 + -55899, // 1357 238.54 4.163224 + -56004, // 1358 238.71 4.166292 + -56108, // 1359 238.89 4.169360 + -56212, // 1360 239.06 4.172428 + -56315, // 1361 239.24 4.175496 + -56417, // 1362 239.41 4.178564 + -56519, // 1363 239.59 4.181632 + -56621, // 1364 239.77 4.184700 + -56722, // 1365 239.94 4.187768 + -56822, // 1366 240.12 4.190836 + -56922, // 1367 240.29 4.193903 + -57022, // 1368 240.47 4.196971 + -57120, // 1369 240.64 4.200039 + -57219, // 1370 240.82 4.203107 + -57316, // 1371 241.00 4.206175 + -57414, // 1372 241.17 4.209243 + -57510, // 1373 241.35 4.212311 + -57606, // 1374 241.52 4.215379 + -57702, // 1375 241.70 4.218447 + -57797, // 1376 241.88 4.221515 + -57892, // 1377 242.05 4.224583 + -57986, // 1378 242.23 4.227651 + -58079, // 1379 242.40 4.230719 + -58172, // 1380 242.58 4.233787 + -58264, // 1381 242.75 4.236855 + -58356, // 1382 242.93 4.239923 + -58447, // 1383 243.11 4.242991 + -58538, // 1384 243.28 4.246059 + -58628, // 1385 243.46 4.249127 + -58718, // 1386 243.63 4.252195 + -58807, // 1387 243.81 4.255263 + -58895, // 1388 243.98 4.258331 + -58983, // 1389 244.16 4.261399 + -59070, // 1390 244.34 4.264467 + -59157, // 1391 244.51 4.267535 + -59243, // 1392 244.69 4.270603 + -59329, // 1393 244.86 4.273670 + -59414, // 1394 245.04 4.276738 + -59499, // 1395 245.21 4.279806 + -59583, // 1396 245.39 4.282874 + -59666, // 1397 245.57 4.285942 + -59749, // 1398 245.74 4.289010 + -59831, // 1399 245.92 4.292078 + -59913, // 1400 246.09 4.295146 + -59994, // 1401 246.27 4.298214 + -60075, // 1402 246.45 4.301282 + -60155, // 1403 246.62 4.304350 + -60235, // 1404 246.80 4.307418 + -60313, // 1405 246.97 4.310486 + -60392, // 1406 247.15 4.313554 + -60470, // 1407 247.32 4.316622 + -60547, // 1408 247.50 4.319690 + -60624, // 1409 247.68 4.322758 + -60700, // 1410 247.85 4.325826 + -60775, // 1411 248.03 4.328894 + -60850, // 1412 248.20 4.331962 + -60924, // 1413 248.38 4.335030 + -60998, // 1414 248.55 4.338098 + -61071, // 1415 248.73 4.341166 + -61144, // 1416 248.91 4.344234 + -61216, // 1417 249.08 4.347302 + -61288, // 1418 249.26 4.350370 + -61359, // 1419 249.43 4.353437 + -61429, // 1420 249.61 4.356505 + -61499, // 1421 249.79 4.359573 + -61568, // 1422 249.96 4.362641 + -61637, // 1423 250.14 4.365709 + -61705, // 1424 250.31 4.368777 + -61772, // 1425 250.49 4.371845 + -61839, // 1426 250.66 4.374913 + -61905, // 1427 250.84 4.377981 + -61971, // 1428 251.02 4.381049 + -62036, // 1429 251.19 4.384117 + -62100, // 1430 251.37 4.387185 + -62164, // 1431 251.54 4.390253 + -62228, // 1432 251.72 4.393321 + -62291, // 1433 251.89 4.396389 + -62353, // 1434 252.07 4.399457 + -62414, // 1435 252.25 4.402525 + -62475, // 1436 252.42 4.405593 + -62536, // 1437 252.60 4.408661 + -62596, // 1438 252.77 4.411729 + -62655, // 1439 252.95 4.414797 + -62714, // 1440 253.12 4.417865 + -62772, // 1441 253.30 4.420933 + -62829, // 1442 253.48 4.424001 + -62886, // 1443 253.65 4.427069 + -62942, // 1444 253.83 4.430137 + -62998, // 1445 254.00 4.433204 + -63053, // 1446 254.18 4.436272 + -63108, // 1447 254.36 4.439340 + -63162, // 1448 254.53 4.442408 + -63215, // 1449 254.71 4.445476 + -63268, // 1450 254.88 4.448544 + -63320, // 1451 255.06 4.451612 + -63371, // 1452 255.23 4.454680 + -63422, // 1453 255.41 4.457748 + -63473, // 1454 255.59 4.460816 + -63522, // 1455 255.76 4.463884 + -63571, // 1456 255.94 4.466952 + -63620, // 1457 256.11 4.470020 + -63668, // 1458 256.29 4.473088 + -63715, // 1459 256.46 4.476156 + -63762, // 1460 256.64 4.479224 + -63808, // 1461 256.82 4.482292 + -63854, // 1462 256.99 4.485360 + -63899, // 1463 257.17 4.488428 + -63943, // 1464 257.34 4.491496 + -63987, // 1465 257.52 4.494564 + -64030, // 1466 257.70 4.497632 + -64073, // 1467 257.87 4.500700 + -64115, // 1468 258.05 4.503768 + -64156, // 1469 258.22 4.506836 + -64197, // 1470 258.40 4.509904 + -64237, // 1471 258.57 4.512971 + -64276, // 1472 258.75 4.516039 + -64315, // 1473 258.93 4.519107 + -64353, // 1474 259.10 4.522175 + -64391, // 1475 259.28 4.525243 + -64428, // 1476 259.45 4.528311 + -64465, // 1477 259.63 4.531379 + -64501, // 1478 259.80 4.534447 + -64536, // 1479 259.98 4.537515 + -64571, // 1480 260.16 4.540583 + -64605, // 1481 260.33 4.543651 + -64638, // 1482 260.51 4.546719 + -64671, // 1483 260.68 4.549787 + -64703, // 1484 260.86 4.552855 + -64735, // 1485 261.04 4.555923 + -64766, // 1486 261.21 4.558991 + -64796, // 1487 261.39 4.562059 + -64826, // 1488 261.56 4.565127 + -64855, // 1489 261.74 4.568195 + -64884, // 1490 261.91 4.571263 + -64912, // 1491 262.09 4.574331 + -64939, // 1492 262.27 4.577399 + -64966, // 1493 262.44 4.580467 + -64992, // 1494 262.62 4.583535 + -65018, // 1495 262.79 4.586603 + -65043, // 1496 262.97 4.589671 + -65067, // 1497 263.14 4.592738 + -65091, // 1498 263.32 4.595806 + -65114, // 1499 263.50 4.598874 + -65136, // 1500 263.67 4.601942 + -65158, // 1501 263.85 4.605010 + -65179, // 1502 264.02 4.608078 + -65200, // 1503 264.20 4.611146 + -65220, // 1504 264.38 4.614214 + -65239, // 1505 264.55 4.617282 + -65258, // 1506 264.73 4.620350 + -65276, // 1507 264.90 4.623418 + -65294, // 1508 265.08 4.626486 + -65311, // 1509 265.25 4.629554 + -65327, // 1510 265.43 4.632622 + -65343, // 1511 265.61 4.635690 + -65358, // 1512 265.78 4.638758 + -65372, // 1513 265.96 4.641826 + -65386, // 1514 266.13 4.644894 + -65400, // 1515 266.31 4.647962 + -65412, // 1516 266.48 4.651030 + -65424, // 1517 266.66 4.654098 + -65436, // 1518 266.84 4.657166 + -65446, // 1519 267.01 4.660234 + -65457, // 1520 267.19 4.663302 + -65466, // 1521 267.36 4.666370 + -65475, // 1522 267.54 4.669438 + -65483, // 1523 267.71 4.672505 + -65491, // 1524 267.89 4.675573 + -65498, // 1525 268.07 4.678641 + -65505, // 1526 268.24 4.681709 + -65511, // 1527 268.42 4.684777 + -65516, // 1528 268.59 4.687845 + -65520, // 1529 268.77 4.690913 + -65524, // 1530 268.95 4.693981 + -65528, // 1531 269.12 4.697049 + -65531, // 1532 269.30 4.700117 + -65533, // 1533 269.47 4.703185 + -65534, // 1534 269.65 4.706253 + -65535, // 1535 269.82 4.709321 + -65536, // 1536 270.00 4.712389 + -65535, // 1537 270.18 4.715457 + -65534, // 1538 270.35 4.718525 + -65533, // 1539 270.53 4.721593 + -65531, // 1540 270.70 4.724661 + -65528, // 1541 270.88 4.727729 + -65524, // 1542 271.05 4.730797 + -65520, // 1543 271.23 4.733865 + -65516, // 1544 271.41 4.736933 + -65511, // 1545 271.58 4.740001 + -65505, // 1546 271.76 4.743069 + -65498, // 1547 271.93 4.746137 + -65491, // 1548 272.11 4.749205 + -65483, // 1549 272.29 4.752272 + -65475, // 1550 272.46 4.755340 + -65466, // 1551 272.64 4.758408 + -65457, // 1552 272.81 4.761476 + -65446, // 1553 272.99 4.764544 + -65436, // 1554 273.16 4.767612 + -65424, // 1555 273.34 4.770680 + -65412, // 1556 273.52 4.773748 + -65400, // 1557 273.69 4.776816 + -65386, // 1558 273.87 4.779884 + -65372, // 1559 274.04 4.782952 + -65358, // 1560 274.22 4.786020 + -65343, // 1561 274.39 4.789088 + -65327, // 1562 274.57 4.792156 + -65311, // 1563 274.75 4.795224 + -65294, // 1564 274.92 4.798292 + -65276, // 1565 275.10 4.801360 + -65258, // 1566 275.27 4.804428 + -65239, // 1567 275.45 4.807496 + -65220, // 1568 275.62 4.810564 + -65200, // 1569 275.80 4.813632 + -65179, // 1570 275.98 4.816700 + -65158, // 1571 276.15 4.819768 + -65136, // 1572 276.33 4.822836 + -65114, // 1573 276.50 4.825904 + -65091, // 1574 276.68 4.828972 + -65067, // 1575 276.86 4.832039 + -65043, // 1576 277.03 4.835107 + -65018, // 1577 277.21 4.838175 + -64992, // 1578 277.38 4.841243 + -64966, // 1579 277.56 4.844311 + -64939, // 1580 277.73 4.847379 + -64912, // 1581 277.91 4.850447 + -64884, // 1582 278.09 4.853515 + -64855, // 1583 278.26 4.856583 + -64826, // 1584 278.44 4.859651 + -64796, // 1585 278.61 4.862719 + -64766, // 1586 278.79 4.865787 + -64735, // 1587 278.96 4.868855 + -64703, // 1588 279.14 4.871923 + -64671, // 1589 279.32 4.874991 + -64638, // 1590 279.49 4.878059 + -64605, // 1591 279.67 4.881127 + -64571, // 1592 279.84 4.884195 + -64536, // 1593 280.02 4.887263 + -64501, // 1594 280.20 4.890331 + -64465, // 1595 280.37 4.893399 + -64428, // 1596 280.55 4.896467 + -64391, // 1597 280.72 4.899535 + -64353, // 1598 280.90 4.902603 + -64315, // 1599 281.07 4.905671 + -64276, // 1600 281.25 4.908739 + -64237, // 1601 281.43 4.911806 + -64197, // 1602 281.60 4.914874 + -64156, // 1603 281.78 4.917942 + -64115, // 1604 281.95 4.921010 + -64073, // 1605 282.13 4.924078 + -64030, // 1606 282.30 4.927146 + -63987, // 1607 282.48 4.930214 + -63943, // 1608 282.66 4.933282 + -63899, // 1609 282.83 4.936350 + -63854, // 1610 283.01 4.939418 + -63808, // 1611 283.18 4.942486 + -63762, // 1612 283.36 4.945554 + -63715, // 1613 283.54 4.948622 + -63668, // 1614 283.71 4.951690 + -63620, // 1615 283.89 4.954758 + -63571, // 1616 284.06 4.957826 + -63522, // 1617 284.24 4.960894 + -63473, // 1618 284.41 4.963962 + -63422, // 1619 284.59 4.967030 + -63371, // 1620 284.77 4.970098 + -63320, // 1621 284.94 4.973166 + -63268, // 1622 285.12 4.976234 + -63215, // 1623 285.29 4.979302 + -63162, // 1624 285.47 4.982370 + -63108, // 1625 285.64 4.985438 + -63053, // 1626 285.82 4.988506 + -62998, // 1627 286.00 4.991573 + -62942, // 1628 286.17 4.994641 + -62886, // 1629 286.35 4.997709 + -62829, // 1630 286.52 5.000777 + -62772, // 1631 286.70 5.003845 + -62714, // 1632 286.88 5.006913 + -62655, // 1633 287.05 5.009981 + -62596, // 1634 287.23 5.013049 + -62536, // 1635 287.40 5.016117 + -62475, // 1636 287.58 5.019185 + -62414, // 1637 287.75 5.022253 + -62353, // 1638 287.93 5.025321 + -62291, // 1639 288.11 5.028389 + -62228, // 1640 288.28 5.031457 + -62164, // 1641 288.46 5.034525 + -62100, // 1642 288.63 5.037593 + -62036, // 1643 288.81 5.040661 + -61971, // 1644 288.98 5.043729 + -61905, // 1645 289.16 5.046797 + -61839, // 1646 289.34 5.049865 + -61772, // 1647 289.51 5.052933 + -61705, // 1648 289.69 5.056001 + -61637, // 1649 289.86 5.059069 + -61568, // 1650 290.04 5.062137 + -61499, // 1651 290.21 5.065205 + -61429, // 1652 290.39 5.068273 + -61359, // 1653 290.57 5.071340 + -61288, // 1654 290.74 5.074408 + -61216, // 1655 290.92 5.077476 + -61144, // 1656 291.09 5.080544 + -61071, // 1657 291.27 5.083612 + -60998, // 1658 291.45 5.086680 + -60924, // 1659 291.62 5.089748 + -60850, // 1660 291.80 5.092816 + -60775, // 1661 291.97 5.095884 + -60700, // 1662 292.15 5.098952 + -60624, // 1663 292.32 5.102020 + -60547, // 1664 292.50 5.105088 + -60470, // 1665 292.68 5.108156 + -60392, // 1666 292.85 5.111224 + -60313, // 1667 293.03 5.114292 + -60235, // 1668 293.20 5.117360 + -60155, // 1669 293.38 5.120428 + -60075, // 1670 293.55 5.123496 + -59994, // 1671 293.73 5.126564 + -59913, // 1672 293.91 5.129632 + -59831, // 1673 294.08 5.132700 + -59749, // 1674 294.26 5.135768 + -59666, // 1675 294.43 5.138836 + -59583, // 1676 294.61 5.141904 + -59499, // 1677 294.79 5.144972 + -59414, // 1678 294.96 5.148040 + -59329, // 1679 295.14 5.151107 + -59243, // 1680 295.31 5.154175 + -59157, // 1681 295.49 5.157243 + -59070, // 1682 295.66 5.160311 + -58983, // 1683 295.84 5.163379 + -58895, // 1684 296.02 5.166447 + -58807, // 1685 296.19 5.169515 + -58718, // 1686 296.37 5.172583 + -58628, // 1687 296.54 5.175651 + -58538, // 1688 296.72 5.178719 + -58447, // 1689 296.89 5.181787 + -58356, // 1690 297.07 5.184855 + -58264, // 1691 297.25 5.187923 + -58172, // 1692 297.42 5.190991 + -58079, // 1693 297.60 5.194059 + -57986, // 1694 297.77 5.197127 + -57892, // 1695 297.95 5.200195 + -57797, // 1696 298.12 5.203263 + -57702, // 1697 298.30 5.206331 + -57606, // 1698 298.48 5.209399 + -57510, // 1699 298.65 5.212467 + -57414, // 1700 298.83 5.215535 + -57316, // 1701 299.00 5.218603 + -57219, // 1702 299.18 5.221671 + -57120, // 1703 299.36 5.224739 + -57022, // 1704 299.53 5.227807 + -56922, // 1705 299.71 5.230874 + -56822, // 1706 299.88 5.233942 + -56722, // 1707 300.06 5.237010 + -56621, // 1708 300.23 5.240078 + -56519, // 1709 300.41 5.243146 + -56417, // 1710 300.59 5.246214 + -56315, // 1711 300.76 5.249282 + -56212, // 1712 300.94 5.252350 + -56108, // 1713 301.11 5.255418 + -56004, // 1714 301.29 5.258486 + -55899, // 1715 301.46 5.261554 + -55794, // 1716 301.64 5.264622 + -55688, // 1717 301.82 5.267690 + -55582, // 1718 301.99 5.270758 + -55475, // 1719 302.17 5.273826 + -55368, // 1720 302.34 5.276894 + -55260, // 1721 302.52 5.279962 + -55152, // 1722 302.70 5.283030 + -55043, // 1723 302.87 5.286098 + -54933, // 1724 303.05 5.289166 + -54823, // 1725 303.22 5.292234 + -54713, // 1726 303.40 5.295302 + -54602, // 1727 303.57 5.298370 + -54491, // 1728 303.75 5.301438 + -54379, // 1729 303.93 5.304506 + -54266, // 1730 304.10 5.307574 + -54153, // 1731 304.28 5.310641 + -54040, // 1732 304.45 5.313709 + -53926, // 1733 304.63 5.316777 + -53811, // 1734 304.80 5.319845 + -53696, // 1735 304.98 5.322913 + -53581, // 1736 305.16 5.325981 + -53465, // 1737 305.33 5.329049 + -53348, // 1738 305.51 5.332117 + -53231, // 1739 305.68 5.335185 + -53114, // 1740 305.86 5.338253 + -52996, // 1741 306.04 5.341321 + -52877, // 1742 306.21 5.344389 + -52758, // 1743 306.39 5.347457 + -52639, // 1744 306.56 5.350525 + -52518, // 1745 306.74 5.353593 + -52398, // 1746 306.91 5.356661 + -52277, // 1747 307.09 5.359729 + -52155, // 1748 307.27 5.362797 + -52033, // 1749 307.44 5.365865 + -51911, // 1750 307.62 5.368933 + -51788, // 1751 307.79 5.372001 + -51665, // 1752 307.97 5.375069 + -51541, // 1753 308.14 5.378137 + -51416, // 1754 308.32 5.381205 + -51291, // 1755 308.50 5.384273 + -51166, // 1756 308.67 5.387341 + -51040, // 1757 308.85 5.390408 + -50914, // 1758 309.02 5.393476 + -50787, // 1759 309.20 5.396544 + -50660, // 1760 309.38 5.399612 + -50532, // 1761 309.55 5.402680 + -50403, // 1762 309.73 5.405748 + -50275, // 1763 309.90 5.408816 + -50146, // 1764 310.08 5.411884 + -50016, // 1765 310.25 5.414952 + -49886, // 1766 310.43 5.418020 + -49755, // 1767 310.61 5.421088 + -49624, // 1768 310.78 5.424156 + -49492, // 1769 310.96 5.427224 + -49360, // 1770 311.13 5.430292 + -49228, // 1771 311.31 5.433360 + -49095, // 1772 311.48 5.436428 + -48961, // 1773 311.66 5.439496 + -48828, // 1774 311.84 5.442564 + -48693, // 1775 312.01 5.445632 + -48558, // 1776 312.19 5.448700 + -48423, // 1777 312.36 5.451768 + -48288, // 1778 312.54 5.454836 + -48151, // 1779 312.71 5.457904 + -48015, // 1780 312.89 5.460972 + -47878, // 1781 313.07 5.464040 + -47740, // 1782 313.24 5.467108 + -47602, // 1783 313.42 5.470175 + -47464, // 1784 313.59 5.473243 + -47325, // 1785 313.77 5.476311 + -47186, // 1786 313.95 5.479379 + -47046, // 1787 314.12 5.482447 + -46906, // 1788 314.30 5.485515 + -46765, // 1789 314.47 5.488583 + -46624, // 1790 314.65 5.491651 + -46482, // 1791 314.82 5.494719 + -46340, // 1792 315.00 5.497787 + -46198, // 1793 315.18 5.500855 + -46055, // 1794 315.35 5.503923 + -45912, // 1795 315.53 5.506991 + -45768, // 1796 315.70 5.510059 + -45624, // 1797 315.88 5.513127 + -45480, // 1798 316.05 5.516195 + -45335, // 1799 316.23 5.519263 + -45189, // 1800 316.41 5.522331 + -45043, // 1801 316.58 5.525399 + -44897, // 1802 316.76 5.528467 + -44750, // 1803 316.93 5.531535 + -44603, // 1804 317.11 5.534603 + -44456, // 1805 317.29 5.537671 + -44308, // 1806 317.46 5.540739 + -44160, // 1807 317.64 5.543807 + -44011, // 1808 317.81 5.546875 + -43862, // 1809 317.99 5.549942 + -43712, // 1810 318.16 5.553010 + -43562, // 1811 318.34 5.556078 + -43412, // 1812 318.52 5.559146 + -43261, // 1813 318.69 5.562214 + -43110, // 1814 318.87 5.565282 + -42958, // 1815 319.04 5.568350 + -42806, // 1816 319.22 5.571418 + -42653, // 1817 319.39 5.574486 + -42501, // 1818 319.57 5.577554 + -42347, // 1819 319.75 5.580622 + -42194, // 1820 319.92 5.583690 + -42040, // 1821 320.10 5.586758 + -41885, // 1822 320.27 5.589826 + -41730, // 1823 320.45 5.592894 + -41575, // 1824 320.62 5.595962 + -41419, // 1825 320.80 5.599030 + -41263, // 1826 320.98 5.602098 + -41107, // 1827 321.15 5.605166 + -40950, // 1828 321.33 5.608234 + -40793, // 1829 321.50 5.611302 + -40636, // 1830 321.68 5.614370 + -40478, // 1831 321.86 5.617438 + -40319, // 1832 322.03 5.620506 + -40161, // 1833 322.21 5.623574 + -40002, // 1834 322.38 5.626642 + -39842, // 1835 322.56 5.629709 + -39682, // 1836 322.73 5.632777 + -39522, // 1837 322.91 5.635845 + -39362, // 1838 323.09 5.638913 + -39201, // 1839 323.26 5.641981 + -39039, // 1840 323.44 5.645049 + -38878, // 1841 323.61 5.648117 + -38716, // 1842 323.79 5.651185 + -38553, // 1843 323.96 5.654253 + -38390, // 1844 324.14 5.657321 + -38227, // 1845 324.32 5.660389 + -38064, // 1846 324.49 5.663457 + -37900, // 1847 324.67 5.666525 + -37736, // 1848 324.84 5.669593 + -37571, // 1849 325.02 5.672661 + -37406, // 1850 325.20 5.675729 + -37241, // 1851 325.37 5.678797 + -37075, // 1852 325.55 5.681865 + -36909, // 1853 325.72 5.684933 + -36743, // 1854 325.90 5.688001 + -36576, // 1855 326.07 5.691069 + -36409, // 1856 326.25 5.694137 + -36242, // 1857 326.43 5.697205 + -36074, // 1858 326.60 5.700273 + -35906, // 1859 326.78 5.703341 + -35738, // 1860 326.95 5.706409 + -35569, // 1861 327.13 5.709476 + -35400, // 1862 327.30 5.712544 + -35231, // 1863 327.48 5.715612 + -35061, // 1864 327.66 5.718680 + -34891, // 1865 327.83 5.721748 + -34721, // 1866 328.01 5.724816 + -34550, // 1867 328.18 5.727884 + -34379, // 1868 328.36 5.730952 + -34208, // 1869 328.54 5.734020 + -34036, // 1870 328.71 5.737088 + -33864, // 1871 328.89 5.740156 + -33692, // 1872 329.06 5.743224 + -33519, // 1873 329.24 5.746292 + -33346, // 1874 329.41 5.749360 + -33173, // 1875 329.59 5.752428 + -32999, // 1876 329.77 5.755496 + -32826, // 1877 329.94 5.758564 + -32651, // 1878 330.12 5.761632 + -32477, // 1879 330.29 5.764700 + -32302, // 1880 330.47 5.767768 + -32127, // 1881 330.64 5.770836 + -31952, // 1882 330.82 5.773904 + -31776, // 1883 331.00 5.776972 + -31600, // 1884 331.17 5.780040 + -31424, // 1885 331.35 5.783108 + -31247, // 1886 331.52 5.786176 + -31070, // 1887 331.70 5.789243 + -30893, // 1888 331.88 5.792311 + -30715, // 1889 332.05 5.795379 + -30538, // 1890 332.23 5.798447 + -30360, // 1891 332.40 5.801515 + -30181, // 1892 332.58 5.804583 + -30003, // 1893 332.75 5.807651 + -29824, // 1894 332.93 5.810719 + -29645, // 1895 333.11 5.813787 + -29465, // 1896 333.28 5.816855 + -29285, // 1897 333.46 5.819923 + -29105, // 1898 333.63 5.822991 + -28925, // 1899 333.81 5.826059 + -28745, // 1900 333.98 5.829127 + -28564, // 1901 334.16 5.832195 + -28383, // 1902 334.34 5.835263 + -28201, // 1903 334.51 5.838331 + -28020, // 1904 334.69 5.841399 + -27838, // 1905 334.86 5.844467 + -27656, // 1906 335.04 5.847535 + -27473, // 1907 335.21 5.850603 + -27291, // 1908 335.39 5.853671 + -27108, // 1909 335.57 5.856739 + -26925, // 1910 335.74 5.859807 + -26741, // 1911 335.92 5.862875 + -26557, // 1912 336.09 5.865943 + -26373, // 1913 336.27 5.869010 + -26189, // 1914 336.45 5.872078 + -26005, // 1915 336.62 5.875146 + -25820, // 1916 336.80 5.878214 + -25635, // 1917 336.97 5.881282 + -25450, // 1918 337.15 5.884350 + -25265, // 1919 337.32 5.887418 + -25079, // 1920 337.50 5.890486 + -24893, // 1921 337.68 5.893554 + -24707, // 1922 337.85 5.896622 + -24521, // 1923 338.03 5.899690 + -24334, // 1924 338.20 5.902758 + -24147, // 1925 338.38 5.905826 + -23960, // 1926 338.55 5.908894 + -23773, // 1927 338.73 5.911962 + -23586, // 1928 338.91 5.915030 + -23398, // 1929 339.08 5.918098 + -23210, // 1930 339.26 5.921166 + -23022, // 1931 339.43 5.924234 + -22833, // 1932 339.61 5.927302 + -22645, // 1933 339.79 5.930370 + -22456, // 1934 339.96 5.933438 + -22267, // 1935 340.14 5.936506 + -22078, // 1936 340.31 5.939574 + -21889, // 1937 340.49 5.942642 + -21699, // 1938 340.66 5.945710 + -21509, // 1939 340.84 5.948777 + -21319, // 1940 341.02 5.951845 + -21129, // 1941 341.19 5.954913 + -20938, // 1942 341.37 5.957981 + -20748, // 1943 341.54 5.961049 + -20557, // 1944 341.72 5.964117 + -20366, // 1945 341.89 5.967185 + -20175, // 1946 342.07 5.970253 + -19983, // 1947 342.25 5.973321 + -19792, // 1948 342.42 5.976389 + -19600, // 1949 342.60 5.979457 + -19408, // 1950 342.77 5.982525 + -19216, // 1951 342.95 5.985593 + -19024, // 1952 343.12 5.988661 + -18831, // 1953 343.30 5.991729 + -18638, // 1954 343.48 5.994797 + -18446, // 1955 343.65 5.997865 + -18253, // 1956 343.83 6.000933 + -18059, // 1957 344.00 6.004001 + -17866, // 1958 344.18 6.007069 + -17672, // 1959 344.36 6.010137 + -17479, // 1960 344.53 6.013205 + -17285, // 1961 344.71 6.016273 + -17091, // 1962 344.88 6.019341 + -16897, // 1963 345.06 6.022409 + -16702, // 1964 345.23 6.025477 + -16508, // 1965 345.41 6.028544 + -16313, // 1966 345.59 6.031612 + -16118, // 1967 345.76 6.034680 + -15923, // 1968 345.94 6.037748 + -15728, // 1969 346.11 6.040816 + -15533, // 1970 346.29 6.043884 + -15338, // 1971 346.46 6.046952 + -15142, // 1972 346.64 6.050020 + -14946, // 1973 346.82 6.053088 + -14751, // 1974 346.99 6.056156 + -14555, // 1975 347.17 6.059224 + -14359, // 1976 347.34 6.062292 + -14162, // 1977 347.52 6.065360 + -13966, // 1978 347.70 6.068428 + -13769, // 1979 347.87 6.071496 + -13573, // 1980 348.05 6.074564 + -13376, // 1981 348.22 6.077632 + -13179, // 1982 348.40 6.080700 + -12982, // 1983 348.57 6.083768 + -12785, // 1984 348.75 6.086836 + -12588, // 1985 348.93 6.089904 + -12390, // 1986 349.10 6.092972 + -12193, // 1987 349.28 6.096040 + -11995, // 1988 349.45 6.099108 + -11797, // 1989 349.63 6.102176 + -11600, // 1990 349.80 6.105244 + -11402, // 1991 349.98 6.108311 + -11204, // 1992 350.16 6.111379 + -11006, // 1993 350.33 6.114447 + -10807, // 1994 350.51 6.117515 + -10609, // 1995 350.68 6.120583 + -10410, // 1996 350.86 6.123651 + -10212, // 1997 351.04 6.126719 + -10013, // 1998 351.21 6.129787 + -9814, // 1999 351.39 6.132855 + -9616, // 2000 351.56 6.135923 + -9417, // 2001 351.74 6.138991 + -9218, // 2002 351.91 6.142059 + -9019, // 2003 352.09 6.145127 + -8819, // 2004 352.27 6.148195 + -8620, // 2005 352.44 6.151263 + -8421, // 2006 352.62 6.154331 + -8221, // 2007 352.79 6.157399 + -8022, // 2008 352.97 6.160467 + -7822, // 2009 353.14 6.163535 + -7623, // 2010 353.32 6.166603 + -7423, // 2011 353.50 6.169671 + -7223, // 2012 353.67 6.172739 + -7023, // 2013 353.85 6.175807 + -6823, // 2014 354.02 6.178875 + -6623, // 2015 354.20 6.181943 + -6423, // 2016 354.38 6.185011 + -6223, // 2017 354.55 6.188078 + -6023, // 2018 354.73 6.191146 + -5823, // 2019 354.90 6.194214 + -5622, // 2020 355.08 6.197282 + -5422, // 2021 355.25 6.200350 + -5222, // 2022 355.43 6.203418 + -5021, // 2023 355.61 6.206486 + -4821, // 2024 355.78 6.209554 + -4620, // 2025 355.96 6.212622 + -4420, // 2026 356.13 6.215690 + -4219, // 2027 356.31 6.218758 + -4018, // 2028 356.48 6.221826 + -3818, // 2029 356.66 6.224894 + -3617, // 2030 356.84 6.227962 + -3416, // 2031 357.01 6.231030 + -3215, // 2032 357.19 6.234098 + -3014, // 2033 357.36 6.237166 + -2814, // 2034 357.54 6.240234 + -2613, // 2035 357.71 6.243302 + -2412, // 2036 357.89 6.246370 + -2211, // 2037 358.07 6.249438 + -2010, // 2038 358.24 6.252506 + -1809, // 2039 358.42 6.255574 + -1608, // 2040 358.59 6.258642 + -1407, // 2041 358.77 6.261710 + -1206, // 2042 358.95 6.264778 + -1005, // 2043 359.12 6.267846 + -804, // 2044 359.30 6.270913 + -603, // 2045 359.47 6.273981 + -402, // 2046 359.65 6.277049 + -201, // 2047 359.82 6.280117 + 0, // 2048 360.00 6.283185 + 201, // 2049 360.18 6.286253 + 402, // 2050 360.35 6.289321 + 603, // 2051 360.53 6.292389 + 804, // 2052 360.70 6.295457 + 1005, // 2053 360.88 6.298525 + 1206, // 2054 361.05 6.301593 + 1407, // 2055 361.23 6.304661 + 1608, // 2056 361.41 6.307729 + 1809, // 2057 361.58 6.310797 + 2010, // 2058 361.76 6.313865 + 2211, // 2059 361.93 6.316933 + 2412, // 2060 362.11 6.320001 + 2613, // 2061 362.29 6.323069 + 2814, // 2062 362.46 6.326137 + 3014, // 2063 362.64 6.329205 + 3215, // 2064 362.81 6.332273 + 3416, // 2065 362.99 6.335341 + 3617, // 2066 363.16 6.338409 + 3818, // 2067 363.34 6.341477 + 4018, // 2068 363.52 6.344545 + 4219, // 2069 363.69 6.347613 + 4420, // 2070 363.87 6.350680 + 4620, // 2071 364.04 6.353748 + 4821, // 2072 364.22 6.356816 + 5021, // 2073 364.39 6.359884 + 5222, // 2074 364.57 6.362952 + 5422, // 2075 364.75 6.366020 + 5622, // 2076 364.92 6.369088 + 5823, // 2077 365.10 6.372156 + 6023, // 2078 365.27 6.375224 + 6223, // 2079 365.45 6.378292 + 6423, // 2080 365.62 6.381360 + 6623, // 2081 365.80 6.384428 + 6823, // 2082 365.98 6.387496 + 7023, // 2083 366.15 6.390564 + 7223, // 2084 366.33 6.393632 + 7423, // 2085 366.50 6.396700 + 7623, // 2086 366.68 6.399768 + 7822, // 2087 366.86 6.402836 + 8022, // 2088 367.03 6.405904 + 8221, // 2089 367.21 6.408972 + 8421, // 2090 367.38 6.412040 + 8620, // 2091 367.56 6.415108 + 8819, // 2092 367.73 6.418176 + 9019, // 2093 367.91 6.421244 + 9218, // 2094 368.09 6.424312 + 9417, // 2095 368.26 6.427380 + 9616, // 2096 368.44 6.430447 + 9814, // 2097 368.61 6.433515 + 10013, // 2098 368.79 6.436583 + 10212, // 2099 368.96 6.439651 + 10410, // 2100 369.14 6.442719 + 10609, // 2101 369.32 6.445787 + 10807, // 2102 369.49 6.448855 + 11006, // 2103 369.67 6.451923 + 11204, // 2104 369.84 6.454991 + 11402, // 2105 370.02 6.458059 + 11600, // 2106 370.20 6.461127 + 11797, // 2107 370.37 6.464195 + 11995, // 2108 370.55 6.467263 + 12193, // 2109 370.72 6.470331 + 12390, // 2110 370.90 6.473399 + 12588, // 2111 371.07 6.476467 + 12785, // 2112 371.25 6.479535 + 12982, // 2113 371.43 6.482603 + 13179, // 2114 371.60 6.485671 + 13376, // 2115 371.78 6.488739 + 13573, // 2116 371.95 6.491807 + 13769, // 2117 372.13 6.494875 + 13966, // 2118 372.30 6.497943 + 14162, // 2119 372.48 6.501011 + 14359, // 2120 372.66 6.504079 + 14555, // 2121 372.83 6.507147 + 14751, // 2122 373.01 6.510214 + 14946, // 2123 373.18 6.513282 + 15142, // 2124 373.36 6.516350 + 15338, // 2125 373.54 6.519418 + 15533, // 2126 373.71 6.522486 + 15728, // 2127 373.89 6.525554 + 15923, // 2128 374.06 6.528622 + 16118, // 2129 374.24 6.531690 + 16313, // 2130 374.41 6.534758 + 16508, // 2131 374.59 6.537826 + 16702, // 2132 374.77 6.540894 + 16897, // 2133 374.94 6.543962 + 17091, // 2134 375.12 6.547030 + 17285, // 2135 375.29 6.550098 + 17479, // 2136 375.47 6.553166 + 17672, // 2137 375.64 6.556234 + 17866, // 2138 375.82 6.559302 + 18059, // 2139 376.00 6.562370 + 18253, // 2140 376.17 6.565438 + 18446, // 2141 376.35 6.568506 + 18638, // 2142 376.52 6.571574 + 18831, // 2143 376.70 6.574642 + 19024, // 2144 376.88 6.577710 + 19216, // 2145 377.05 6.580778 + 19408, // 2146 377.23 6.583846 + 19600, // 2147 377.40 6.586914 + 19792, // 2148 377.58 6.589981 + 19983, // 2149 377.75 6.593049 + 20175, // 2150 377.93 6.596117 + 20366, // 2151 378.11 6.599185 + 20557, // 2152 378.28 6.602253 + 20748, // 2153 378.46 6.605321 + 20938, // 2154 378.63 6.608389 + 21129, // 2155 378.81 6.611457 + 21319, // 2156 378.98 6.614525 + 21509, // 2157 379.16 6.617593 + 21699, // 2158 379.34 6.620661 + 21889, // 2159 379.51 6.623729 + 22078, // 2160 379.69 6.626797 + 22267, // 2161 379.86 6.629865 + 22456, // 2162 380.04 6.632933 + 22645, // 2163 380.21 6.636001 + 22833, // 2164 380.39 6.639069 + 23022, // 2165 380.57 6.642137 + 23210, // 2166 380.74 6.645205 + 23398, // 2167 380.92 6.648273 + 23586, // 2168 381.09 6.651341 + 23773, // 2169 381.27 6.654409 + 23960, // 2170 381.45 6.657477 + 24147, // 2171 381.62 6.660545 + 24334, // 2172 381.80 6.663613 + 24521, // 2173 381.97 6.666681 + 24707, // 2174 382.15 6.669748 + 24893, // 2175 382.32 6.672816 + 25079, // 2176 382.50 6.675884 + 25265, // 2177 382.68 6.678952 + 25450, // 2178 382.85 6.682020 + 25635, // 2179 383.03 6.685088 + 25820, // 2180 383.20 6.688156 + 26005, // 2181 383.38 6.691224 + 26189, // 2182 383.55 6.694292 + 26373, // 2183 383.73 6.697360 + 26557, // 2184 383.91 6.700428 + 26741, // 2185 384.08 6.703496 + 26925, // 2186 384.26 6.706564 + 27108, // 2187 384.43 6.709632 + 27291, // 2188 384.61 6.712700 + 27473, // 2189 384.79 6.715768 + 27656, // 2190 384.96 6.718836 + 27838, // 2191 385.14 6.721904 + 28020, // 2192 385.31 6.724972 + 28201, // 2193 385.49 6.728040 + 28383, // 2194 385.66 6.731108 + 28564, // 2195 385.84 6.734176 + 28745, // 2196 386.02 6.737244 + 28925, // 2197 386.19 6.740312 + 29105, // 2198 386.37 6.743380 + 29285, // 2199 386.54 6.746448 + 29465, // 2200 386.72 6.749515 + 29645, // 2201 386.89 6.752583 + 29824, // 2202 387.07 6.755651 + 30003, // 2203 387.25 6.758719 + 30181, // 2204 387.42 6.761787 + 30360, // 2205 387.60 6.764855 + 30538, // 2206 387.77 6.767923 + 30715, // 2207 387.95 6.770991 + 30893, // 2208 388.12 6.774059 + 31070, // 2209 388.30 6.777127 + 31247, // 2210 388.48 6.780195 + 31424, // 2211 388.65 6.783263 + 31600, // 2212 388.83 6.786331 + 31776, // 2213 389.00 6.789399 + 31952, // 2214 389.18 6.792467 + 32127, // 2215 389.36 6.795535 + 32302, // 2216 389.53 6.798603 + 32477, // 2217 389.71 6.801671 + 32651, // 2218 389.88 6.804739 + 32826, // 2219 390.06 6.807807 + 32999, // 2220 390.23 6.810875 + 33173, // 2221 390.41 6.813943 + 33346, // 2222 390.59 6.817011 + 33519, // 2223 390.76 6.820079 + 33692, // 2224 390.94 6.823147 + 33864, // 2225 391.11 6.826215 + 34036, // 2226 391.29 6.829282 + 34208, // 2227 391.46 6.832350 + 34379, // 2228 391.64 6.835418 + 34550, // 2229 391.82 6.838486 + 34721, // 2230 391.99 6.841554 + 34891, // 2231 392.17 6.844622 + 35061, // 2232 392.34 6.847690 + 35231, // 2233 392.52 6.850758 + 35400, // 2234 392.70 6.853826 + 35569, // 2235 392.87 6.856894 + 35738, // 2236 393.05 6.859962 + 35906, // 2237 393.22 6.863030 + 36074, // 2238 393.40 6.866098 + 36242, // 2239 393.57 6.869166 + 36409, // 2240 393.75 6.872234 + 36576, // 2241 393.93 6.875302 + 36743, // 2242 394.10 6.878370 + 36909, // 2243 394.28 6.881438 + 37075, // 2244 394.45 6.884506 + 37241, // 2245 394.63 6.887574 + 37406, // 2246 394.80 6.890642 + 37571, // 2247 394.98 6.893710 + 37736, // 2248 395.16 6.896778 + 37900, // 2249 395.33 6.899846 + 38064, // 2250 395.51 6.902914 + 38227, // 2251 395.68 6.905982 + 38390, // 2252 395.86 6.909049 + 38553, // 2253 396.04 6.912117 + 38716, // 2254 396.21 6.915185 + 38878, // 2255 396.39 6.918253 + 39039, // 2256 396.56 6.921321 + 39201, // 2257 396.74 6.924389 + 39362, // 2258 396.91 6.927457 + 39522, // 2259 397.09 6.930525 + 39682, // 2260 397.27 6.933593 + 39842, // 2261 397.44 6.936661 + 40002, // 2262 397.62 6.939729 + 40161, // 2263 397.79 6.942797 + 40319, // 2264 397.97 6.945865 + 40478, // 2265 398.14 6.948933 + 40636, // 2266 398.32 6.952001 + 40793, // 2267 398.50 6.955069 + 40950, // 2268 398.67 6.958137 + 41107, // 2269 398.85 6.961205 + 41263, // 2270 399.02 6.964273 + 41419, // 2271 399.20 6.967341 + 41575, // 2272 399.38 6.970409 + 41730, // 2273 399.55 6.973477 + 41885, // 2274 399.73 6.976545 + 42040, // 2275 399.90 6.979613 + 42194, // 2276 400.08 6.982681 + 42347, // 2277 400.25 6.985749 + 42501, // 2278 400.43 6.988816 + 42653, // 2279 400.61 6.991884 + 42806, // 2280 400.78 6.994952 + 42958, // 2281 400.96 6.998020 + 43110, // 2282 401.13 7.001088 + 43261, // 2283 401.31 7.004156 + 43412, // 2284 401.48 7.007224 + 43562, // 2285 401.66 7.010292 + 43712, // 2286 401.84 7.013360 + 43862, // 2287 402.01 7.016428 + 44011, // 2288 402.19 7.019496 + 44160, // 2289 402.36 7.022564 + 44308, // 2290 402.54 7.025632 + 44456, // 2291 402.71 7.028700 + 44603, // 2292 402.89 7.031768 + 44750, // 2293 403.07 7.034836 + 44897, // 2294 403.24 7.037904 + 45043, // 2295 403.42 7.040972 + 45189, // 2296 403.59 7.044040 + 45335, // 2297 403.77 7.047108 + 45480, // 2298 403.95 7.050176 + 45624, // 2299 404.12 7.053244 + 45768, // 2300 404.30 7.056312 + 45912, // 2301 404.47 7.059380 + 46055, // 2302 404.65 7.062448 + 46198, // 2303 404.82 7.065516 + 46340, // 2304 405.00 7.068583 + 46482, // 2305 405.18 7.071651 + 46624, // 2306 405.35 7.074719 + 46765, // 2307 405.53 7.077787 + 46906, // 2308 405.70 7.080855 + 47046, // 2309 405.88 7.083923 + 47186, // 2310 406.05 7.086991 + 47325, // 2311 406.23 7.090059 + 47464, // 2312 406.41 7.093127 + 47602, // 2313 406.58 7.096195 + 47740, // 2314 406.76 7.099263 + 47878, // 2315 406.93 7.102331 + 48015, // 2316 407.11 7.105399 + 48151, // 2317 407.29 7.108467 + 48288, // 2318 407.46 7.111535 + 48423, // 2319 407.64 7.114603 + 48558, // 2320 407.81 7.117671 + 48693, // 2321 407.99 7.120739 + 48828, // 2322 408.16 7.123807 + 48961, // 2323 408.34 7.126875 + 49095, // 2324 408.52 7.129943 + 49228, // 2325 408.69 7.133011 + 49360, // 2326 408.87 7.136079 + 49492, // 2327 409.04 7.139147 + 49624, // 2328 409.22 7.142215 + 49755, // 2329 409.39 7.145283 + 49886, // 2330 409.57 7.148350 + 50016, // 2331 409.75 7.151418 + 50146, // 2332 409.92 7.154486 + 50275, // 2333 410.10 7.157554 + 50403, // 2334 410.27 7.160622 + 50532, // 2335 410.45 7.163690 + 50660, // 2336 410.62 7.166758 + 50787, // 2337 410.80 7.169826 + 50914, // 2338 410.98 7.172894 + 51040, // 2339 411.15 7.175962 + 51166, // 2340 411.33 7.179030 + 51291, // 2341 411.50 7.182098 + 51416, // 2342 411.68 7.185166 + 51541, // 2343 411.86 7.188234 + 51665, // 2344 412.03 7.191302 + 51788, // 2345 412.21 7.194370 + 51911, // 2346 412.38 7.197438 + 52033, // 2347 412.56 7.200506 + 52155, // 2348 412.73 7.203574 + 52277, // 2349 412.91 7.206642 + 52398, // 2350 413.09 7.209710 + 52518, // 2351 413.26 7.212778 + 52639, // 2352 413.44 7.215846 + 52758, // 2353 413.61 7.218914 + 52877, // 2354 413.79 7.221982 + 52996, // 2355 413.96 7.225050 + 53114, // 2356 414.14 7.228117 + 53231, // 2357 414.32 7.231185 + 53348, // 2358 414.49 7.234253 + 53465, // 2359 414.67 7.237321 + 53581, // 2360 414.84 7.240389 + 53696, // 2361 415.02 7.243457 + 53811, // 2362 415.20 7.246525 + 53926, // 2363 415.37 7.249593 + 54040, // 2364 415.55 7.252661 + 54153, // 2365 415.72 7.255729 + 54266, // 2366 415.90 7.258797 + 54379, // 2367 416.07 7.261865 + 54491, // 2368 416.25 7.264933 + 54602, // 2369 416.43 7.268001 + 54713, // 2370 416.60 7.271069 + 54823, // 2371 416.78 7.274137 + 54933, // 2372 416.95 7.277205 + 55043, // 2373 417.13 7.280273 + 55152, // 2374 417.30 7.283341 + 55260, // 2375 417.48 7.286409 + 55368, // 2376 417.66 7.289477 + 55475, // 2377 417.83 7.292545 + 55582, // 2378 418.01 7.295613 + 55688, // 2379 418.18 7.298681 + 55794, // 2380 418.36 7.301749 + 55899, // 2381 418.54 7.304817 + 56004, // 2382 418.71 7.307884 + 56108, // 2383 418.89 7.310952 + 56212, // 2384 419.06 7.314020 + 56315, // 2385 419.24 7.317088 + 56417, // 2386 419.41 7.320156 + 56519, // 2387 419.59 7.323224 + 56621, // 2388 419.77 7.326292 + 56722, // 2389 419.94 7.329360 + 56822, // 2390 420.12 7.332428 + 56922, // 2391 420.29 7.335496 + 57022, // 2392 420.47 7.338564 + 57120, // 2393 420.64 7.341632 + 57219, // 2394 420.82 7.344700 + 57316, // 2395 421.00 7.347768 + 57414, // 2396 421.17 7.350836 + 57510, // 2397 421.35 7.353904 + 57606, // 2398 421.52 7.356972 + 57702, // 2399 421.70 7.360040 + 57797, // 2400 421.88 7.363108 + 57892, // 2401 422.05 7.366176 + 57986, // 2402 422.23 7.369244 + 58079, // 2403 422.40 7.372312 + 58172, // 2404 422.58 7.375380 + 58264, // 2405 422.75 7.378448 + 58356, // 2406 422.93 7.381516 + 58447, // 2407 423.11 7.384584 + 58538, // 2408 423.28 7.387651 + 58628, // 2409 423.46 7.390719 + 58718, // 2410 423.63 7.393787 + 58807, // 2411 423.81 7.396855 + 58895, // 2412 423.98 7.399923 + 58983, // 2413 424.16 7.402991 + 59070, // 2414 424.34 7.406059 + 59157, // 2415 424.51 7.409127 + 59243, // 2416 424.69 7.412195 + 59329, // 2417 424.86 7.415263 + 59414, // 2418 425.04 7.418331 + 59499, // 2419 425.21 7.421399 + 59583, // 2420 425.39 7.424467 + 59666, // 2421 425.57 7.427535 + 59749, // 2422 425.74 7.430603 + 59831, // 2423 425.92 7.433671 + 59913, // 2424 426.09 7.436739 + 59994, // 2425 426.27 7.439807 + 60075, // 2426 426.45 7.442875 + 60155, // 2427 426.62 7.445943 + 60235, // 2428 426.80 7.449011 + 60313, // 2429 426.97 7.452079 + 60392, // 2430 427.15 7.455147 + 60470, // 2431 427.32 7.458215 + 60547, // 2432 427.50 7.461283 + 60624, // 2433 427.68 7.464351 + 60700, // 2434 427.85 7.467418 + 60775, // 2435 428.03 7.470486 + 60850, // 2436 428.20 7.473554 + 60924, // 2437 428.38 7.476622 + 60998, // 2438 428.55 7.479690 + 61071, // 2439 428.73 7.482758 + 61144, // 2440 428.91 7.485826 + 61216, // 2441 429.08 7.488894 + 61288, // 2442 429.26 7.491962 + 61359, // 2443 429.43 7.495030 + 61429, // 2444 429.61 7.498098 + 61499, // 2445 429.79 7.501166 + 61568, // 2446 429.96 7.504234 + 61637, // 2447 430.14 7.507302 + 61705, // 2448 430.31 7.510370 + 61772, // 2449 430.49 7.513438 + 61839, // 2450 430.66 7.516506 + 61905, // 2451 430.84 7.519574 + 61971, // 2452 431.02 7.522642 + 62036, // 2453 431.19 7.525710 + 62100, // 2454 431.37 7.528778 + 62164, // 2455 431.54 7.531846 + 62228, // 2456 431.72 7.534914 + 62291, // 2457 431.89 7.537982 + 62353, // 2458 432.07 7.541050 + 62414, // 2459 432.25 7.544118 + 62475, // 2460 432.42 7.547185 + 62536, // 2461 432.60 7.550253 + 62596, // 2462 432.77 7.553321 + 62655, // 2463 432.95 7.556389 + 62714, // 2464 433.12 7.559457 + 62772, // 2465 433.30 7.562525 + 62829, // 2466 433.48 7.565593 + 62886, // 2467 433.65 7.568661 + 62942, // 2468 433.83 7.571729 + 62998, // 2469 434.00 7.574797 + 63053, // 2470 434.18 7.577865 + 63108, // 2471 434.36 7.580933 + 63162, // 2472 434.53 7.584001 + 63215, // 2473 434.71 7.587069 + 63268, // 2474 434.88 7.590137 + 63320, // 2475 435.06 7.593205 + 63371, // 2476 435.23 7.596273 + 63422, // 2477 435.41 7.599341 + 63473, // 2478 435.59 7.602409 + 63522, // 2479 435.76 7.605477 + 63571, // 2480 435.94 7.608545 + 63620, // 2481 436.11 7.611613 + 63668, // 2482 436.29 7.614681 + 63715, // 2483 436.46 7.617749 + 63762, // 2484 436.64 7.620817 + 63808, // 2485 436.82 7.623885 + 63854, // 2486 436.99 7.626952 + 63899, // 2487 437.17 7.630020 + 63943, // 2488 437.34 7.633088 + 63987, // 2489 437.52 7.636156 + 64030, // 2490 437.70 7.639224 + 64073, // 2491 437.87 7.642292 + 64115, // 2492 438.05 7.645360 + 64156, // 2493 438.22 7.648428 + 64197, // 2494 438.40 7.651496 + 64237, // 2495 438.57 7.654564 + 64276, // 2496 438.75 7.657632 + 64315, // 2497 438.93 7.660700 + 64353, // 2498 439.10 7.663768 + 64391, // 2499 439.28 7.666836 + 64428, // 2500 439.45 7.669904 + 64465, // 2501 439.63 7.672972 + 64501, // 2502 439.80 7.676040 + 64536, // 2503 439.98 7.679108 + 64571, // 2504 440.16 7.682176 + 64605, // 2505 440.33 7.685244 + 64638, // 2506 440.51 7.688312 + 64671, // 2507 440.68 7.691380 + 64703, // 2508 440.86 7.694448 + 64735, // 2509 441.04 7.697516 + 64766, // 2510 441.21 7.700584 + 64796, // 2511 441.39 7.703652 + 64826, // 2512 441.56 7.706719 + 64855, // 2513 441.74 7.709787 + 64884, // 2514 441.91 7.712855 + 64912, // 2515 442.09 7.715923 + 64939, // 2516 442.27 7.718991 + 64966, // 2517 442.44 7.722059 + 64992, // 2518 442.62 7.725127 + 65018, // 2519 442.79 7.728195 + 65043, // 2520 442.97 7.731263 + 65067, // 2521 443.14 7.734331 + 65091, // 2522 443.32 7.737399 + 65114, // 2523 443.50 7.740467 + 65136, // 2524 443.67 7.743535 + 65158, // 2525 443.85 7.746603 + 65179, // 2526 444.02 7.749671 + 65200, // 2527 444.20 7.752739 + 65220, // 2528 444.38 7.755807 + 65239, // 2529 444.55 7.758875 + 65258, // 2530 444.73 7.761943 + 65276, // 2531 444.90 7.765011 + 65294, // 2532 445.08 7.768079 + 65311, // 2533 445.25 7.771147 + 65327, // 2534 445.43 7.774215 + 65343, // 2535 445.61 7.777283 + 65358, // 2536 445.78 7.780351 + 65372, // 2537 445.96 7.783419 + 65386, // 2538 446.13 7.786486 + 65400, // 2539 446.31 7.789554 + 65412, // 2540 446.48 7.792622 + 65424, // 2541 446.66 7.795690 + 65436, // 2542 446.84 7.798758 + 65446, // 2543 447.01 7.801826 + 65457, // 2544 447.19 7.804894 + 65466, // 2545 447.36 7.807962 + 65475, // 2546 447.54 7.811030 + 65483, // 2547 447.71 7.814098 + 65491, // 2548 447.89 7.817166 + 65498, // 2549 448.07 7.820234 + 65505, // 2550 448.24 7.823302 + 65511, // 2551 448.42 7.826370 + 65516, // 2552 448.59 7.829438 + 65520, // 2553 448.77 7.832506 + 65524, // 2554 448.95 7.835574 + 65528, // 2555 449.12 7.838642 + 65531, // 2556 449.30 7.841710 + 65533, // 2557 449.47 7.844778 + 65534, // 2558 449.65 7.847846 + 65535, // 2559 449.82 7.850914 +}; + +SLONG *CosTable = &SinTable[512]; + +//--------------------------------------------------------------- + +float SinTableF[] = +{ + (float)0.000000, // 0 + (float)0.003068, // 1 + (float)0.006136, // 2 + (float)0.009204, // 3 + (float)0.012272, // 4 + (float)0.015339, // 5 + (float)0.018407, // 6 + (float)0.021474, // 7 + (float)0.024541, // 8 + (float)0.027608, // 9 + (float)0.030675, // 10 + (float)0.033741, // 11 + (float)0.036807, // 12 + (float)0.039873, // 13 + (float)0.042938, // 14 + (float)0.046003, // 15 + (float)0.049068, // 16 + (float)0.052132, // 17 + (float)0.055195, // 18 + (float)0.058258, // 19 + (float)0.061321, // 20 + (float)0.064383, // 21 + (float)0.067444, // 22 + (float)0.070505, // 23 + (float)0.073565, // 24 + (float)0.076624, // 25 + (float)0.079682, // 26 + (float)0.082740, // 27 + (float)0.085797, // 28 + (float)0.088854, // 29 + (float)0.091909, // 30 + (float)0.094963, // 31 + (float)0.098017, // 32 + (float)0.101070, // 33 + (float)0.104122, // 34 + (float)0.107172, // 35 + (float)0.110222, // 36 + (float)0.113271, // 37 + (float)0.116319, // 38 + (float)0.119365, // 39 + (float)0.122411, // 40 + (float)0.125455, // 41 + (float)0.128498, // 42 + (float)0.131540, // 43 + (float)0.134581, // 44 + (float)0.137620, // 45 + (float)0.140658, // 46 + (float)0.143695, // 47 + (float)0.146730, // 48 + (float)0.149765, // 49 + (float)0.152797, // 50 + (float)0.155828, // 51 + (float)0.158858, // 52 + (float)0.161886, // 53 + (float)0.164913, // 54 + (float)0.167938, // 55 + (float)0.170962, // 56 + (float)0.173984, // 57 + (float)0.177004, // 58 + (float)0.180023, // 59 + (float)0.183040, // 60 + (float)0.186055, // 61 + (float)0.189069, // 62 + (float)0.192080, // 63 + (float)0.195090, // 64 + (float)0.198098, // 65 + (float)0.201105, // 66 + (float)0.204109, // 67 + (float)0.207111, // 68 + (float)0.210112, // 69 + (float)0.213110, // 70 + (float)0.216107, // 71 + (float)0.219101, // 72 + (float)0.222094, // 73 + (float)0.225084, // 74 + (float)0.228072, // 75 + (float)0.231058, // 76 + (float)0.234042, // 77 + (float)0.237024, // 78 + (float)0.240003, // 79 + (float)0.242980, // 80 + (float)0.245955, // 81 + (float)0.248928, // 82 + (float)0.251898, // 83 + (float)0.254866, // 84 + (float)0.257831, // 85 + (float)0.260794, // 86 + (float)0.263755, // 87 + (float)0.266713, // 88 + (float)0.269668, // 89 + (float)0.272621, // 90 + (float)0.275572, // 91 + (float)0.278520, // 92 + (float)0.281465, // 93 + (float)0.284408, // 94 + (float)0.287347, // 95 + (float)0.290285, // 96 + (float)0.293219, // 97 + (float)0.296151, // 98 + (float)0.299080, // 99 + (float)0.302006, // 100 + (float)0.304929, // 101 + (float)0.307850, // 102 + (float)0.310767, // 103 + (float)0.313682, // 104 + (float)0.316593, // 105 + (float)0.319502, // 106 + (float)0.322408, // 107 + (float)0.325310, // 108 + (float)0.328210, // 109 + (float)0.331106, // 110 + (float)0.334000, // 111 + (float)0.336890, // 112 + (float)0.339777, // 113 + (float)0.342661, // 114 + (float)0.345541, // 115 + (float)0.348419, // 116 + (float)0.351293, // 117 + (float)0.354164, // 118 + (float)0.357031, // 119 + (float)0.359895, // 120 + (float)0.362756, // 121 + (float)0.365613, // 122 + (float)0.368467, // 123 + (float)0.371317, // 124 + (float)0.374164, // 125 + (float)0.377007, // 126 + (float)0.379847, // 127 + (float)0.382683, // 128 + (float)0.385516, // 129 + (float)0.388345, // 130 + (float)0.391170, // 131 + (float)0.393992, // 132 + (float)0.396810, // 133 + (float)0.399624, // 134 + (float)0.402435, // 135 + (float)0.405241, // 136 + (float)0.408044, // 137 + (float)0.410843, // 138 + (float)0.413638, // 139 + (float)0.416430, // 140 + (float)0.419217, // 141 + (float)0.422000, // 142 + (float)0.424780, // 143 + (float)0.427555, // 144 + (float)0.430326, // 145 + (float)0.433094, // 146 + (float)0.435857, // 147 + (float)0.438616, // 148 + (float)0.441371, // 149 + (float)0.444122, // 150 + (float)0.446869, // 151 + (float)0.449611, // 152 + (float)0.452350, // 153 + (float)0.455084, // 154 + (float)0.457813, // 155 + (float)0.460539, // 156 + (float)0.463260, // 157 + (float)0.465976, // 158 + (float)0.468689, // 159 + (float)0.471397, // 160 + (float)0.474100, // 161 + (float)0.476799, // 162 + (float)0.479494, // 163 + (float)0.482184, // 164 + (float)0.484869, // 165 + (float)0.487550, // 166 + (float)0.490226, // 167 + (float)0.492898, // 168 + (float)0.495565, // 169 + (float)0.498228, // 170 + (float)0.500885, // 171 + (float)0.503538, // 172 + (float)0.506187, // 173 + (float)0.508830, // 174 + (float)0.511469, // 175 + (float)0.514103, // 176 + (float)0.516732, // 177 + (float)0.519356, // 178 + (float)0.521975, // 179 + (float)0.524590, // 180 + (float)0.527199, // 181 + (float)0.529804, // 182 + (float)0.532403, // 183 + (float)0.534998, // 184 + (float)0.537587, // 185 + (float)0.540171, // 186 + (float)0.542751, // 187 + (float)0.545325, // 188 + (float)0.547894, // 189 + (float)0.550458, // 190 + (float)0.553017, // 191 + (float)0.555570, // 192 + (float)0.558119, // 193 + (float)0.560662, // 194 + (float)0.563199, // 195 + (float)0.565732, // 196 + (float)0.568259, // 197 + (float)0.570781, // 198 + (float)0.573297, // 199 + (float)0.575808, // 200 + (float)0.578314, // 201 + (float)0.580814, // 202 + (float)0.583309, // 203 + (float)0.585798, // 204 + (float)0.588282, // 205 + (float)0.590760, // 206 + (float)0.593232, // 207 + (float)0.595699, // 208 + (float)0.598161, // 209 + (float)0.600616, // 210 + (float)0.603067, // 211 + (float)0.605511, // 212 + (float)0.607950, // 213 + (float)0.610383, // 214 + (float)0.612810, // 215 + (float)0.615232, // 216 + (float)0.617647, // 217 + (float)0.620057, // 218 + (float)0.622461, // 219 + (float)0.624859, // 220 + (float)0.627252, // 221 + (float)0.629638, // 222 + (float)0.632019, // 223 + (float)0.634393, // 224 + (float)0.636762, // 225 + (float)0.639124, // 226 + (float)0.641481, // 227 + (float)0.643832, // 228 + (float)0.646176, // 229 + (float)0.648514, // 230 + (float)0.650847, // 231 + (float)0.653173, // 232 + (float)0.655493, // 233 + (float)0.657807, // 234 + (float)0.660114, // 235 + (float)0.662416, // 236 + (float)0.664711, // 237 + (float)0.667000, // 238 + (float)0.669283, // 239 + (float)0.671559, // 240 + (float)0.673829, // 241 + (float)0.676093, // 242 + (float)0.678350, // 243 + (float)0.680601, // 244 + (float)0.682846, // 245 + (float)0.685084, // 246 + (float)0.687315, // 247 + (float)0.689541, // 248 + (float)0.691759, // 249 + (float)0.693971, // 250 + (float)0.696177, // 251 + (float)0.698376, // 252 + (float)0.700569, // 253 + (float)0.702755, // 254 + (float)0.704934, // 255 + (float)0.707107, // 256 + (float)0.709273, // 257 + (float)0.711432, // 258 + (float)0.713585, // 259 + (float)0.715731, // 260 + (float)0.717870, // 261 + (float)0.720003, // 262 + (float)0.722128, // 263 + (float)0.724247, // 264 + (float)0.726359, // 265 + (float)0.728464, // 266 + (float)0.730563, // 267 + (float)0.732654, // 268 + (float)0.734739, // 269 + (float)0.736817, // 270 + (float)0.738887, // 271 + (float)0.740951, // 272 + (float)0.743008, // 273 + (float)0.745058, // 274 + (float)0.747101, // 275 + (float)0.749136, // 276 + (float)0.751165, // 277 + (float)0.753187, // 278 + (float)0.755201, // 279 + (float)0.757209, // 280 + (float)0.759209, // 281 + (float)0.761202, // 282 + (float)0.763188, // 283 + (float)0.765167, // 284 + (float)0.767139, // 285 + (float)0.769103, // 286 + (float)0.771061, // 287 + (float)0.773010, // 288 + (float)0.774953, // 289 + (float)0.776888, // 290 + (float)0.778817, // 291 + (float)0.780737, // 292 + (float)0.782651, // 293 + (float)0.784557, // 294 + (float)0.786455, // 295 + (float)0.788346, // 296 + (float)0.790230, // 297 + (float)0.792107, // 298 + (float)0.793975, // 299 + (float)0.795837, // 300 + (float)0.797691, // 301 + (float)0.799537, // 302 + (float)0.801376, // 303 + (float)0.803208, // 304 + (float)0.805031, // 305 + (float)0.806848, // 306 + (float)0.808656, // 307 + (float)0.810457, // 308 + (float)0.812251, // 309 + (float)0.814036, // 310 + (float)0.815814, // 311 + (float)0.817585, // 312 + (float)0.819348, // 313 + (float)0.821103, // 314 + (float)0.822850, // 315 + (float)0.824589, // 316 + (float)0.826321, // 317 + (float)0.828045, // 318 + (float)0.829761, // 319 + (float)0.831470, // 320 + (float)0.833170, // 321 + (float)0.834863, // 322 + (float)0.836548, // 323 + (float)0.838225, // 324 + (float)0.839894, // 325 + (float)0.841555, // 326 + (float)0.843208, // 327 + (float)0.844854, // 328 + (float)0.846491, // 329 + (float)0.848120, // 330 + (float)0.849742, // 331 + (float)0.851355, // 332 + (float)0.852961, // 333 + (float)0.854558, // 334 + (float)0.856147, // 335 + (float)0.857729, // 336 + (float)0.859302, // 337 + (float)0.860867, // 338 + (float)0.862424, // 339 + (float)0.863973, // 340 + (float)0.865514, // 341 + (float)0.867046, // 342 + (float)0.868571, // 343 + (float)0.870087, // 344 + (float)0.871595, // 345 + (float)0.873095, // 346 + (float)0.874587, // 347 + (float)0.876070, // 348 + (float)0.877545, // 349 + (float)0.879012, // 350 + (float)0.880471, // 351 + (float)0.881921, // 352 + (float)0.883363, // 353 + (float)0.884797, // 354 + (float)0.886223, // 355 + (float)0.887640, // 356 + (float)0.889048, // 357 + (float)0.890449, // 358 + (float)0.891841, // 359 + (float)0.893224, // 360 + (float)0.894599, // 361 + (float)0.895966, // 362 + (float)0.897325, // 363 + (float)0.898674, // 364 + (float)0.900016, // 365 + (float)0.901349, // 366 + (float)0.902673, // 367 + (float)0.903989, // 368 + (float)0.905297, // 369 + (float)0.906596, // 370 + (float)0.907886, // 371 + (float)0.909168, // 372 + (float)0.910441, // 373 + (float)0.911706, // 374 + (float)0.912962, // 375 + (float)0.914210, // 376 + (float)0.915449, // 377 + (float)0.916679, // 378 + (float)0.917901, // 379 + (float)0.919114, // 380 + (float)0.920318, // 381 + (float)0.921514, // 382 + (float)0.922701, // 383 + (float)0.923880, // 384 + (float)0.925049, // 385 + (float)0.926210, // 386 + (float)0.927363, // 387 + (float)0.928506, // 388 + (float)0.929641, // 389 + (float)0.930767, // 390 + (float)0.931884, // 391 + (float)0.932993, // 392 + (float)0.934093, // 393 + (float)0.935184, // 394 + (float)0.936266, // 395 + (float)0.937339, // 396 + (float)0.938404, // 397 + (float)0.939459, // 398 + (float)0.940506, // 399 + (float)0.941544, // 400 + (float)0.942573, // 401 + (float)0.943593, // 402 + (float)0.944605, // 403 + (float)0.945607, // 404 + (float)0.946601, // 405 + (float)0.947586, // 406 + (float)0.948561, // 407 + (float)0.949528, // 408 + (float)0.950486, // 409 + (float)0.951435, // 410 + (float)0.952375, // 411 + (float)0.953306, // 412 + (float)0.954228, // 413 + (float)0.955141, // 414 + (float)0.956045, // 415 + (float)0.956940, // 416 + (float)0.957826, // 417 + (float)0.958703, // 418 + (float)0.959572, // 419 + (float)0.960431, // 420 + (float)0.961280, // 421 + (float)0.962121, // 422 + (float)0.962953, // 423 + (float)0.963776, // 424 + (float)0.964590, // 425 + (float)0.965394, // 426 + (float)0.966190, // 427 + (float)0.966976, // 428 + (float)0.967754, // 429 + (float)0.968522, // 430 + (float)0.969281, // 431 + (float)0.970031, // 432 + (float)0.970772, // 433 + (float)0.971504, // 434 + (float)0.972226, // 435 + (float)0.972940, // 436 + (float)0.973644, // 437 + (float)0.974339, // 438 + (float)0.975025, // 439 + (float)0.975702, // 440 + (float)0.976370, // 441 + (float)0.977028, // 442 + (float)0.977677, // 443 + (float)0.978317, // 444 + (float)0.978948, // 445 + (float)0.979570, // 446 + (float)0.980182, // 447 + (float)0.980785, // 448 + (float)0.981379, // 449 + (float)0.981964, // 450 + (float)0.982539, // 451 + (float)0.983105, // 452 + (float)0.983662, // 453 + (float)0.984210, // 454 + (float)0.984749, // 455 + (float)0.985278, // 456 + (float)0.985798, // 457 + (float)0.986308, // 458 + (float)0.986809, // 459 + (float)0.987301, // 460 + (float)0.987784, // 461 + (float)0.988258, // 462 + (float)0.988722, // 463 + (float)0.989177, // 464 + (float)0.989622, // 465 + (float)0.990058, // 466 + (float)0.990485, // 467 + (float)0.990903, // 468 + (float)0.991311, // 469 + (float)0.991710, // 470 + (float)0.992099, // 471 + (float)0.992480, // 472 + (float)0.992850, // 473 + (float)0.993212, // 474 + (float)0.993564, // 475 + (float)0.993907, // 476 + (float)0.994240, // 477 + (float)0.994565, // 478 + (float)0.994879, // 479 + (float)0.995185, // 480 + (float)0.995481, // 481 + (float)0.995767, // 482 + (float)0.996045, // 483 + (float)0.996313, // 484 + (float)0.996571, // 485 + (float)0.996820, // 486 + (float)0.997060, // 487 + (float)0.997290, // 488 + (float)0.997511, // 489 + (float)0.997723, // 490 + (float)0.997925, // 491 + (float)0.998118, // 492 + (float)0.998302, // 493 + (float)0.998476, // 494 + (float)0.998640, // 495 + (float)0.998795, // 496 + (float)0.998941, // 497 + (float)0.999078, // 498 + (float)0.999205, // 499 + (float)0.999322, // 500 + (float)0.999431, // 501 + (float)0.999529, // 502 + (float)0.999619, // 503 + (float)0.999699, // 504 + (float)0.999769, // 505 + (float)0.999831, // 506 + (float)0.999882, // 507 + (float)0.999925, // 508 + (float)0.999958, // 509 + (float)0.999981, // 510 + (float)0.999995, // 511 + (float)1.000000, // 512 + (float)0.999995, // 513 + (float)0.999981, // 514 + (float)0.999958, // 515 + (float)0.999925, // 516 + (float)0.999882, // 517 + (float)0.999831, // 518 + (float)0.999769, // 519 + (float)0.999699, // 520 + (float)0.999619, // 521 + (float)0.999529, // 522 + (float)0.999431, // 523 + (float)0.999322, // 524 + (float)0.999205, // 525 + (float)0.999078, // 526 + (float)0.998941, // 527 + (float)0.998795, // 528 + (float)0.998640, // 529 + (float)0.998476, // 530 + (float)0.998302, // 531 + (float)0.998118, // 532 + (float)0.997925, // 533 + (float)0.997723, // 534 + (float)0.997511, // 535 + (float)0.997290, // 536 + (float)0.997060, // 537 + (float)0.996820, // 538 + (float)0.996571, // 539 + (float)0.996313, // 540 + (float)0.996045, // 541 + (float)0.995767, // 542 + (float)0.995481, // 543 + (float)0.995185, // 544 + (float)0.994879, // 545 + (float)0.994565, // 546 + (float)0.994240, // 547 + (float)0.993907, // 548 + (float)0.993564, // 549 + (float)0.993212, // 550 + (float)0.992850, // 551 + (float)0.992480, // 552 + (float)0.992099, // 553 + (float)0.991710, // 554 + (float)0.991311, // 555 + (float)0.990903, // 556 + (float)0.990485, // 557 + (float)0.990058, // 558 + (float)0.989622, // 559 + (float)0.989177, // 560 + (float)0.988722, // 561 + (float)0.988258, // 562 + (float)0.987784, // 563 + (float)0.987301, // 564 + (float)0.986809, // 565 + (float)0.986308, // 566 + (float)0.985798, // 567 + (float)0.985278, // 568 + (float)0.984749, // 569 + (float)0.984210, // 570 + (float)0.983662, // 571 + (float)0.983105, // 572 + (float)0.982539, // 573 + (float)0.981964, // 574 + (float)0.981379, // 575 + (float)0.980785, // 576 + (float)0.980182, // 577 + (float)0.979570, // 578 + (float)0.978948, // 579 + (float)0.978317, // 580 + (float)0.977677, // 581 + (float)0.977028, // 582 + (float)0.976370, // 583 + (float)0.975702, // 584 + (float)0.975025, // 585 + (float)0.974339, // 586 + (float)0.973644, // 587 + (float)0.972940, // 588 + (float)0.972226, // 589 + (float)0.971504, // 590 + (float)0.970772, // 591 + (float)0.970031, // 592 + (float)0.969281, // 593 + (float)0.968522, // 594 + (float)0.967754, // 595 + (float)0.966976, // 596 + (float)0.966190, // 597 + (float)0.965394, // 598 + (float)0.964590, // 599 + (float)0.963776, // 600 + (float)0.962953, // 601 + (float)0.962121, // 602 + (float)0.961280, // 603 + (float)0.960431, // 604 + (float)0.959572, // 605 + (float)0.958703, // 606 + (float)0.957826, // 607 + (float)0.956940, // 608 + (float)0.956045, // 609 + (float)0.955141, // 610 + (float)0.954228, // 611 + (float)0.953306, // 612 + (float)0.952375, // 613 + (float)0.951435, // 614 + (float)0.950486, // 615 + (float)0.949528, // 616 + (float)0.948561, // 617 + (float)0.947586, // 618 + (float)0.946601, // 619 + (float)0.945607, // 620 + (float)0.944605, // 621 + (float)0.943593, // 622 + (float)0.942573, // 623 + (float)0.941544, // 624 + (float)0.940506, // 625 + (float)0.939459, // 626 + (float)0.938404, // 627 + (float)0.937339, // 628 + (float)0.936266, // 629 + (float)0.935184, // 630 + (float)0.934093, // 631 + (float)0.932993, // 632 + (float)0.931884, // 633 + (float)0.930767, // 634 + (float)0.929641, // 635 + (float)0.928506, // 636 + (float)0.927363, // 637 + (float)0.926210, // 638 + (float)0.925049, // 639 + (float)0.923880, // 640 + (float)0.922701, // 641 + (float)0.921514, // 642 + (float)0.920318, // 643 + (float)0.919114, // 644 + (float)0.917901, // 645 + (float)0.916679, // 646 + (float)0.915449, // 647 + (float)0.914210, // 648 + (float)0.912962, // 649 + (float)0.911706, // 650 + (float)0.910441, // 651 + (float)0.909168, // 652 + (float)0.907886, // 653 + (float)0.906596, // 654 + (float)0.905297, // 655 + (float)0.903989, // 656 + (float)0.902673, // 657 + (float)0.901349, // 658 + (float)0.900016, // 659 + (float)0.898674, // 660 + (float)0.897325, // 661 + (float)0.895966, // 662 + (float)0.894599, // 663 + (float)0.893224, // 664 + (float)0.891841, // 665 + (float)0.890449, // 666 + (float)0.889048, // 667 + (float)0.887640, // 668 + (float)0.886223, // 669 + (float)0.884797, // 670 + (float)0.883363, // 671 + (float)0.881921, // 672 + (float)0.880471, // 673 + (float)0.879012, // 674 + (float)0.877545, // 675 + (float)0.876070, // 676 + (float)0.874587, // 677 + (float)0.873095, // 678 + (float)0.871595, // 679 + (float)0.870087, // 680 + (float)0.868571, // 681 + (float)0.867046, // 682 + (float)0.865514, // 683 + (float)0.863973, // 684 + (float)0.862424, // 685 + (float)0.860867, // 686 + (float)0.859302, // 687 + (float)0.857729, // 688 + (float)0.856147, // 689 + (float)0.854558, // 690 + (float)0.852961, // 691 + (float)0.851355, // 692 + (float)0.849742, // 693 + (float)0.848120, // 694 + (float)0.846491, // 695 + (float)0.844854, // 696 + (float)0.843208, // 697 + (float)0.841555, // 698 + (float)0.839894, // 699 + (float)0.838225, // 700 + (float)0.836548, // 701 + (float)0.834863, // 702 + (float)0.833170, // 703 + (float)0.831470, // 704 + (float)0.829761, // 705 + (float)0.828045, // 706 + (float)0.826321, // 707 + (float)0.824589, // 708 + (float)0.822850, // 709 + (float)0.821103, // 710 + (float)0.819348, // 711 + (float)0.817585, // 712 + (float)0.815814, // 713 + (float)0.814036, // 714 + (float)0.812251, // 715 + (float)0.810457, // 716 + (float)0.808656, // 717 + (float)0.806848, // 718 + (float)0.805031, // 719 + (float)0.803208, // 720 + (float)0.801376, // 721 + (float)0.799537, // 722 + (float)0.797691, // 723 + (float)0.795837, // 724 + (float)0.793975, // 725 + (float)0.792107, // 726 + (float)0.790230, // 727 + (float)0.788346, // 728 + (float)0.786455, // 729 + (float)0.784557, // 730 + (float)0.782651, // 731 + (float)0.780737, // 732 + (float)0.778817, // 733 + (float)0.776888, // 734 + (float)0.774953, // 735 + (float)0.773010, // 736 + (float)0.771061, // 737 + (float)0.769103, // 738 + (float)0.767139, // 739 + (float)0.765167, // 740 + (float)0.763188, // 741 + (float)0.761202, // 742 + (float)0.759209, // 743 + (float)0.757209, // 744 + (float)0.755201, // 745 + (float)0.753187, // 746 + (float)0.751165, // 747 + (float)0.749136, // 748 + (float)0.747101, // 749 + (float)0.745058, // 750 + (float)0.743008, // 751 + (float)0.740951, // 752 + (float)0.738887, // 753 + (float)0.736817, // 754 + (float)0.734739, // 755 + (float)0.732654, // 756 + (float)0.730563, // 757 + (float)0.728464, // 758 + (float)0.726359, // 759 + (float)0.724247, // 760 + (float)0.722128, // 761 + (float)0.720003, // 762 + (float)0.717870, // 763 + (float)0.715731, // 764 + (float)0.713585, // 765 + (float)0.711432, // 766 + (float)0.709273, // 767 + (float)0.707107, // 768 + (float)0.704934, // 769 + (float)0.702755, // 770 + (float)0.700569, // 771 + (float)0.698376, // 772 + (float)0.696177, // 773 + (float)0.693971, // 774 + (float)0.691759, // 775 + (float)0.689541, // 776 + (float)0.687315, // 777 + (float)0.685084, // 778 + (float)0.682846, // 779 + (float)0.680601, // 780 + (float)0.678350, // 781 + (float)0.676093, // 782 + (float)0.673829, // 783 + (float)0.671559, // 784 + (float)0.669283, // 785 + (float)0.667000, // 786 + (float)0.664711, // 787 + (float)0.662416, // 788 + (float)0.660114, // 789 + (float)0.657807, // 790 + (float)0.655493, // 791 + (float)0.653173, // 792 + (float)0.650847, // 793 + (float)0.648514, // 794 + (float)0.646176, // 795 + (float)0.643832, // 796 + (float)0.641481, // 797 + (float)0.639124, // 798 + (float)0.636762, // 799 + (float)0.634393, // 800 + (float)0.632019, // 801 + (float)0.629638, // 802 + (float)0.627252, // 803 + (float)0.624859, // 804 + (float)0.622461, // 805 + (float)0.620057, // 806 + (float)0.617647, // 807 + (float)0.615232, // 808 + (float)0.612810, // 809 + (float)0.610383, // 810 + (float)0.607950, // 811 + (float)0.605511, // 812 + (float)0.603067, // 813 + (float)0.600616, // 814 + (float)0.598161, // 815 + (float)0.595699, // 816 + (float)0.593232, // 817 + (float)0.590760, // 818 + (float)0.588282, // 819 + (float)0.585798, // 820 + (float)0.583309, // 821 + (float)0.580814, // 822 + (float)0.578314, // 823 + (float)0.575808, // 824 + (float)0.573297, // 825 + (float)0.570781, // 826 + (float)0.568259, // 827 + (float)0.565732, // 828 + (float)0.563199, // 829 + (float)0.560662, // 830 + (float)0.558119, // 831 + (float)0.555570, // 832 + (float)0.553017, // 833 + (float)0.550458, // 834 + (float)0.547894, // 835 + (float)0.545325, // 836 + (float)0.542751, // 837 + (float)0.540171, // 838 + (float)0.537587, // 839 + (float)0.534998, // 840 + (float)0.532403, // 841 + (float)0.529804, // 842 + (float)0.527199, // 843 + (float)0.524590, // 844 + (float)0.521975, // 845 + (float)0.519356, // 846 + (float)0.516732, // 847 + (float)0.514103, // 848 + (float)0.511469, // 849 + (float)0.508830, // 850 + (float)0.506187, // 851 + (float)0.503538, // 852 + (float)0.500885, // 853 + (float)0.498228, // 854 + (float)0.495565, // 855 + (float)0.492898, // 856 + (float)0.490226, // 857 + (float)0.487550, // 858 + (float)0.484869, // 859 + (float)0.482184, // 860 + (float)0.479494, // 861 + (float)0.476799, // 862 + (float)0.474100, // 863 + (float)0.471397, // 864 + (float)0.468689, // 865 + (float)0.465976, // 866 + (float)0.463260, // 867 + (float)0.460539, // 868 + (float)0.457813, // 869 + (float)0.455084, // 870 + (float)0.452350, // 871 + (float)0.449611, // 872 + (float)0.446869, // 873 + (float)0.444122, // 874 + (float)0.441371, // 875 + (float)0.438616, // 876 + (float)0.435857, // 877 + (float)0.433094, // 878 + (float)0.430326, // 879 + (float)0.427555, // 880 + (float)0.424780, // 881 + (float)0.422000, // 882 + (float)0.419217, // 883 + (float)0.416430, // 884 + (float)0.413638, // 885 + (float)0.410843, // 886 + (float)0.408044, // 887 + (float)0.405241, // 888 + (float)0.402435, // 889 + (float)0.399624, // 890 + (float)0.396810, // 891 + (float)0.393992, // 892 + (float)0.391170, // 893 + (float)0.388345, // 894 + (float)0.385516, // 895 + (float)0.382683, // 896 + (float)0.379847, // 897 + (float)0.377007, // 898 + (float)0.374164, // 899 + (float)0.371317, // 900 + (float)0.368467, // 901 + (float)0.365613, // 902 + (float)0.362756, // 903 + (float)0.359895, // 904 + (float)0.357031, // 905 + (float)0.354164, // 906 + (float)0.351293, // 907 + (float)0.348419, // 908 + (float)0.345541, // 909 + (float)0.342661, // 910 + (float)0.339777, // 911 + (float)0.336890, // 912 + (float)0.334000, // 913 + (float)0.331106, // 914 + (float)0.328210, // 915 + (float)0.325310, // 916 + (float)0.322408, // 917 + (float)0.319502, // 918 + (float)0.316593, // 919 + (float)0.313682, // 920 + (float)0.310767, // 921 + (float)0.307850, // 922 + (float)0.304929, // 923 + (float)0.302006, // 924 + (float)0.299080, // 925 + (float)0.296151, // 926 + (float)0.293219, // 927 + (float)0.290285, // 928 + (float)0.287347, // 929 + (float)0.284408, // 930 + (float)0.281465, // 931 + (float)0.278520, // 932 + (float)0.275572, // 933 + (float)0.272621, // 934 + (float)0.269668, // 935 + (float)0.266713, // 936 + (float)0.263755, // 937 + (float)0.260794, // 938 + (float)0.257831, // 939 + (float)0.254866, // 940 + (float)0.251898, // 941 + (float)0.248928, // 942 + (float)0.245955, // 943 + (float)0.242980, // 944 + (float)0.240003, // 945 + (float)0.237024, // 946 + (float)0.234042, // 947 + (float)0.231058, // 948 + (float)0.228072, // 949 + (float)0.225084, // 950 + (float)0.222094, // 951 + (float)0.219101, // 952 + (float)0.216107, // 953 + (float)0.213110, // 954 + (float)0.210112, // 955 + (float)0.207111, // 956 + (float)0.204109, // 957 + (float)0.201105, // 958 + (float)0.198098, // 959 + (float)0.195090, // 960 + (float)0.192080, // 961 + (float)0.189069, // 962 + (float)0.186055, // 963 + (float)0.183040, // 964 + (float)0.180023, // 965 + (float)0.177004, // 966 + (float)0.173984, // 967 + (float)0.170962, // 968 + (float)0.167938, // 969 + (float)0.164913, // 970 + (float)0.161886, // 971 + (float)0.158858, // 972 + (float)0.155828, // 973 + (float)0.152797, // 974 + (float)0.149765, // 975 + (float)0.146730, // 976 + (float)0.143695, // 977 + (float)0.140658, // 978 + (float)0.137620, // 979 + (float)0.134581, // 980 + (float)0.131540, // 981 + (float)0.128498, // 982 + (float)0.125455, // 983 + (float)0.122411, // 984 + (float)0.119365, // 985 + (float)0.116319, // 986 + (float)0.113271, // 987 + (float)0.110222, // 988 + (float)0.107172, // 989 + (float)0.104122, // 990 + (float)0.101070, // 991 + (float)0.098017, // 992 + (float)0.094963, // 993 + (float)0.091909, // 994 + (float)0.088854, // 995 + (float)0.085797, // 996 + (float)0.082740, // 997 + (float)0.079682, // 998 + (float)0.076624, // 999 + (float)0.073565, // 1000 + (float)0.070505, // 1001 + (float)0.067444, // 1002 + (float)0.064383, // 1003 + (float)0.061321, // 1004 + (float)0.058258, // 1005 + (float)0.055195, // 1006 + (float)0.052132, // 1007 + (float)0.049068, // 1008 + (float)0.046003, // 1009 + (float)0.042938, // 1010 + (float)0.039873, // 1011 + (float)0.036807, // 1012 + (float)0.033741, // 1013 + (float)0.030675, // 1014 + (float)0.027608, // 1015 + (float)0.024541, // 1016 + (float)0.021474, // 1017 + (float)0.018407, // 1018 + (float)0.015339, // 1019 + (float)0.012272, // 1020 + (float)0.009204, // 1021 + (float)0.006136, // 1022 + (float)0.003068, // 1023 + (float)-0.000000, // 1024 + (float)-0.003068, // 1025 + (float)-0.006136, // 1026 + (float)-0.009204, // 1027 + (float)-0.012272, // 1028 + (float)-0.015339, // 1029 + (float)-0.018407, // 1030 + (float)-0.021474, // 1031 + (float)-0.024541, // 1032 + (float)-0.027608, // 1033 + (float)-0.030675, // 1034 + (float)-0.033741, // 1035 + (float)-0.036807, // 1036 + (float)-0.039873, // 1037 + (float)-0.042938, // 1038 + (float)-0.046003, // 1039 + (float)-0.049068, // 1040 + (float)-0.052132, // 1041 + (float)-0.055195, // 1042 + (float)-0.058258, // 1043 + (float)-0.061321, // 1044 + (float)-0.064383, // 1045 + (float)-0.067444, // 1046 + (float)-0.070505, // 1047 + (float)-0.073565, // 1048 + (float)-0.076624, // 1049 + (float)-0.079682, // 1050 + (float)-0.082740, // 1051 + (float)-0.085797, // 1052 + (float)-0.088854, // 1053 + (float)-0.091909, // 1054 + (float)-0.094963, // 1055 + (float)-0.098017, // 1056 + (float)-0.101070, // 1057 + (float)-0.104122, // 1058 + (float)-0.107172, // 1059 + (float)-0.110222, // 1060 + (float)-0.113271, // 1061 + (float)-0.116319, // 1062 + (float)-0.119365, // 1063 + (float)-0.122411, // 1064 + (float)-0.125455, // 1065 + (float)-0.128498, // 1066 + (float)-0.131540, // 1067 + (float)-0.134581, // 1068 + (float)-0.137620, // 1069 + (float)-0.140658, // 1070 + (float)-0.143695, // 1071 + (float)-0.146730, // 1072 + (float)-0.149765, // 1073 + (float)-0.152797, // 1074 + (float)-0.155828, // 1075 + (float)-0.158858, // 1076 + (float)-0.161886, // 1077 + (float)-0.164913, // 1078 + (float)-0.167938, // 1079 + (float)-0.170962, // 1080 + (float)-0.173984, // 1081 + (float)-0.177004, // 1082 + (float)-0.180023, // 1083 + (float)-0.183040, // 1084 + (float)-0.186055, // 1085 + (float)-0.189069, // 1086 + (float)-0.192080, // 1087 + (float)-0.195090, // 1088 + (float)-0.198098, // 1089 + (float)-0.201105, // 1090 + (float)-0.204109, // 1091 + (float)-0.207111, // 1092 + (float)-0.210112, // 1093 + (float)-0.213110, // 1094 + (float)-0.216107, // 1095 + (float)-0.219101, // 1096 + (float)-0.222094, // 1097 + (float)-0.225084, // 1098 + (float)-0.228072, // 1099 + (float)-0.231058, // 1100 + (float)-0.234042, // 1101 + (float)-0.237024, // 1102 + (float)-0.240003, // 1103 + (float)-0.242980, // 1104 + (float)-0.245955, // 1105 + (float)-0.248928, // 1106 + (float)-0.251898, // 1107 + (float)-0.254866, // 1108 + (float)-0.257831, // 1109 + (float)-0.260794, // 1110 + (float)-0.263755, // 1111 + (float)-0.266713, // 1112 + (float)-0.269668, // 1113 + (float)-0.272621, // 1114 + (float)-0.275572, // 1115 + (float)-0.278520, // 1116 + (float)-0.281465, // 1117 + (float)-0.284408, // 1118 + (float)-0.287347, // 1119 + (float)-0.290285, // 1120 + (float)-0.293219, // 1121 + (float)-0.296151, // 1122 + (float)-0.299080, // 1123 + (float)-0.302006, // 1124 + (float)-0.304929, // 1125 + (float)-0.307850, // 1126 + (float)-0.310767, // 1127 + (float)-0.313682, // 1128 + (float)-0.316593, // 1129 + (float)-0.319502, // 1130 + (float)-0.322408, // 1131 + (float)-0.325310, // 1132 + (float)-0.328210, // 1133 + (float)-0.331106, // 1134 + (float)-0.334000, // 1135 + (float)-0.336890, // 1136 + (float)-0.339777, // 1137 + (float)-0.342661, // 1138 + (float)-0.345541, // 1139 + (float)-0.348419, // 1140 + (float)-0.351293, // 1141 + (float)-0.354164, // 1142 + (float)-0.357031, // 1143 + (float)-0.359895, // 1144 + (float)-0.362756, // 1145 + (float)-0.365613, // 1146 + (float)-0.368467, // 1147 + (float)-0.371317, // 1148 + (float)-0.374164, // 1149 + (float)-0.377007, // 1150 + (float)-0.379847, // 1151 + (float)-0.382683, // 1152 + (float)-0.385516, // 1153 + (float)-0.388345, // 1154 + (float)-0.391170, // 1155 + (float)-0.393992, // 1156 + (float)-0.396810, // 1157 + (float)-0.399624, // 1158 + (float)-0.402435, // 1159 + (float)-0.405241, // 1160 + (float)-0.408044, // 1161 + (float)-0.410843, // 1162 + (float)-0.413638, // 1163 + (float)-0.416430, // 1164 + (float)-0.419217, // 1165 + (float)-0.422000, // 1166 + (float)-0.424780, // 1167 + (float)-0.427555, // 1168 + (float)-0.430326, // 1169 + (float)-0.433094, // 1170 + (float)-0.435857, // 1171 + (float)-0.438616, // 1172 + (float)-0.441371, // 1173 + (float)-0.444122, // 1174 + (float)-0.446869, // 1175 + (float)-0.449611, // 1176 + (float)-0.452350, // 1177 + (float)-0.455084, // 1178 + (float)-0.457813, // 1179 + (float)-0.460539, // 1180 + (float)-0.463260, // 1181 + (float)-0.465976, // 1182 + (float)-0.468689, // 1183 + (float)-0.471397, // 1184 + (float)-0.474100, // 1185 + (float)-0.476799, // 1186 + (float)-0.479494, // 1187 + (float)-0.482184, // 1188 + (float)-0.484869, // 1189 + (float)-0.487550, // 1190 + (float)-0.490226, // 1191 + (float)-0.492898, // 1192 + (float)-0.495565, // 1193 + (float)-0.498228, // 1194 + (float)-0.500885, // 1195 + (float)-0.503538, // 1196 + (float)-0.506187, // 1197 + (float)-0.508830, // 1198 + (float)-0.511469, // 1199 + (float)-0.514103, // 1200 + (float)-0.516732, // 1201 + (float)-0.519356, // 1202 + (float)-0.521975, // 1203 + (float)-0.524590, // 1204 + (float)-0.527199, // 1205 + (float)-0.529804, // 1206 + (float)-0.532403, // 1207 + (float)-0.534998, // 1208 + (float)-0.537587, // 1209 + (float)-0.540171, // 1210 + (float)-0.542751, // 1211 + (float)-0.545325, // 1212 + (float)-0.547894, // 1213 + (float)-0.550458, // 1214 + (float)-0.553017, // 1215 + (float)-0.555570, // 1216 + (float)-0.558119, // 1217 + (float)-0.560662, // 1218 + (float)-0.563199, // 1219 + (float)-0.565732, // 1220 + (float)-0.568259, // 1221 + (float)-0.570781, // 1222 + (float)-0.573297, // 1223 + (float)-0.575808, // 1224 + (float)-0.578314, // 1225 + (float)-0.580814, // 1226 + (float)-0.583309, // 1227 + (float)-0.585798, // 1228 + (float)-0.588282, // 1229 + (float)-0.590760, // 1230 + (float)-0.593232, // 1231 + (float)-0.595699, // 1232 + (float)-0.598161, // 1233 + (float)-0.600616, // 1234 + (float)-0.603067, // 1235 + (float)-0.605511, // 1236 + (float)-0.607950, // 1237 + (float)-0.610383, // 1238 + (float)-0.612810, // 1239 + (float)-0.615232, // 1240 + (float)-0.617647, // 1241 + (float)-0.620057, // 1242 + (float)-0.622461, // 1243 + (float)-0.624859, // 1244 + (float)-0.627252, // 1245 + (float)-0.629638, // 1246 + (float)-0.632019, // 1247 + (float)-0.634393, // 1248 + (float)-0.636762, // 1249 + (float)-0.639124, // 1250 + (float)-0.641481, // 1251 + (float)-0.643832, // 1252 + (float)-0.646176, // 1253 + (float)-0.648514, // 1254 + (float)-0.650847, // 1255 + (float)-0.653173, // 1256 + (float)-0.655493, // 1257 + (float)-0.657807, // 1258 + (float)-0.660114, // 1259 + (float)-0.662416, // 1260 + (float)-0.664711, // 1261 + (float)-0.667000, // 1262 + (float)-0.669283, // 1263 + (float)-0.671559, // 1264 + (float)-0.673829, // 1265 + (float)-0.676093, // 1266 + (float)-0.678350, // 1267 + (float)-0.680601, // 1268 + (float)-0.682846, // 1269 + (float)-0.685084, // 1270 + (float)-0.687315, // 1271 + (float)-0.689541, // 1272 + (float)-0.691759, // 1273 + (float)-0.693971, // 1274 + (float)-0.696177, // 1275 + (float)-0.698376, // 1276 + (float)-0.700569, // 1277 + (float)-0.702755, // 1278 + (float)-0.704934, // 1279 + (float)-0.707107, // 1280 + (float)-0.709273, // 1281 + (float)-0.711432, // 1282 + (float)-0.713585, // 1283 + (float)-0.715731, // 1284 + (float)-0.717870, // 1285 + (float)-0.720003, // 1286 + (float)-0.722128, // 1287 + (float)-0.724247, // 1288 + (float)-0.726359, // 1289 + (float)-0.728464, // 1290 + (float)-0.730563, // 1291 + (float)-0.732654, // 1292 + (float)-0.734739, // 1293 + (float)-0.736817, // 1294 + (float)-0.738887, // 1295 + (float)-0.740951, // 1296 + (float)-0.743008, // 1297 + (float)-0.745058, // 1298 + (float)-0.747101, // 1299 + (float)-0.749136, // 1300 + (float)-0.751165, // 1301 + (float)-0.753187, // 1302 + (float)-0.755201, // 1303 + (float)-0.757209, // 1304 + (float)-0.759209, // 1305 + (float)-0.761202, // 1306 + (float)-0.763188, // 1307 + (float)-0.765167, // 1308 + (float)-0.767139, // 1309 + (float)-0.769103, // 1310 + (float)-0.771061, // 1311 + (float)-0.773010, // 1312 + (float)-0.774953, // 1313 + (float)-0.776888, // 1314 + (float)-0.778817, // 1315 + (float)-0.780737, // 1316 + (float)-0.782651, // 1317 + (float)-0.784557, // 1318 + (float)-0.786455, // 1319 + (float)-0.788346, // 1320 + (float)-0.790230, // 1321 + (float)-0.792107, // 1322 + (float)-0.793975, // 1323 + (float)-0.795837, // 1324 + (float)-0.797691, // 1325 + (float)-0.799537, // 1326 + (float)-0.801376, // 1327 + (float)-0.803208, // 1328 + (float)-0.805031, // 1329 + (float)-0.806848, // 1330 + (float)-0.808656, // 1331 + (float)-0.810457, // 1332 + (float)-0.812251, // 1333 + (float)-0.814036, // 1334 + (float)-0.815814, // 1335 + (float)-0.817585, // 1336 + (float)-0.819348, // 1337 + (float)-0.821103, // 1338 + (float)-0.822850, // 1339 + (float)-0.824589, // 1340 + (float)-0.826321, // 1341 + (float)-0.828045, // 1342 + (float)-0.829761, // 1343 + (float)-0.831470, // 1344 + (float)-0.833170, // 1345 + (float)-0.834863, // 1346 + (float)-0.836548, // 1347 + (float)-0.838225, // 1348 + (float)-0.839894, // 1349 + (float)-0.841555, // 1350 + (float)-0.843208, // 1351 + (float)-0.844854, // 1352 + (float)-0.846491, // 1353 + (float)-0.848120, // 1354 + (float)-0.849742, // 1355 + (float)-0.851355, // 1356 + (float)-0.852961, // 1357 + (float)-0.854558, // 1358 + (float)-0.856147, // 1359 + (float)-0.857729, // 1360 + (float)-0.859302, // 1361 + (float)-0.860867, // 1362 + (float)-0.862424, // 1363 + (float)-0.863973, // 1364 + (float)-0.865514, // 1365 + (float)-0.867046, // 1366 + (float)-0.868571, // 1367 + (float)-0.870087, // 1368 + (float)-0.871595, // 1369 + (float)-0.873095, // 1370 + (float)-0.874587, // 1371 + (float)-0.876070, // 1372 + (float)-0.877545, // 1373 + (float)-0.879012, // 1374 + (float)-0.880471, // 1375 + (float)-0.881921, // 1376 + (float)-0.883363, // 1377 + (float)-0.884797, // 1378 + (float)-0.886223, // 1379 + (float)-0.887640, // 1380 + (float)-0.889048, // 1381 + (float)-0.890449, // 1382 + (float)-0.891841, // 1383 + (float)-0.893224, // 1384 + (float)-0.894599, // 1385 + (float)-0.895966, // 1386 + (float)-0.897325, // 1387 + (float)-0.898674, // 1388 + (float)-0.900016, // 1389 + (float)-0.901349, // 1390 + (float)-0.902673, // 1391 + (float)-0.903989, // 1392 + (float)-0.905297, // 1393 + (float)-0.906596, // 1394 + (float)-0.907886, // 1395 + (float)-0.909168, // 1396 + (float)-0.910441, // 1397 + (float)-0.911706, // 1398 + (float)-0.912962, // 1399 + (float)-0.914210, // 1400 + (float)-0.915449, // 1401 + (float)-0.916679, // 1402 + (float)-0.917901, // 1403 + (float)-0.919114, // 1404 + (float)-0.920318, // 1405 + (float)-0.921514, // 1406 + (float)-0.922701, // 1407 + (float)-0.923880, // 1408 + (float)-0.925049, // 1409 + (float)-0.926210, // 1410 + (float)-0.927363, // 1411 + (float)-0.928506, // 1412 + (float)-0.929641, // 1413 + (float)-0.930767, // 1414 + (float)-0.931884, // 1415 + (float)-0.932993, // 1416 + (float)-0.934093, // 1417 + (float)-0.935184, // 1418 + (float)-0.936266, // 1419 + (float)-0.937339, // 1420 + (float)-0.938404, // 1421 + (float)-0.939459, // 1422 + (float)-0.940506, // 1423 + (float)-0.941544, // 1424 + (float)-0.942573, // 1425 + (float)-0.943593, // 1426 + (float)-0.944605, // 1427 + (float)-0.945607, // 1428 + (float)-0.946601, // 1429 + (float)-0.947586, // 1430 + (float)-0.948561, // 1431 + (float)-0.949528, // 1432 + (float)-0.950486, // 1433 + (float)-0.951435, // 1434 + (float)-0.952375, // 1435 + (float)-0.953306, // 1436 + (float)-0.954228, // 1437 + (float)-0.955141, // 1438 + (float)-0.956045, // 1439 + (float)-0.956940, // 1440 + (float)-0.957826, // 1441 + (float)-0.958703, // 1442 + (float)-0.959572, // 1443 + (float)-0.960431, // 1444 + (float)-0.961280, // 1445 + (float)-0.962121, // 1446 + (float)-0.962953, // 1447 + (float)-0.963776, // 1448 + (float)-0.964590, // 1449 + (float)-0.965394, // 1450 + (float)-0.966190, // 1451 + (float)-0.966976, // 1452 + (float)-0.967754, // 1453 + (float)-0.968522, // 1454 + (float)-0.969281, // 1455 + (float)-0.970031, // 1456 + (float)-0.970772, // 1457 + (float)-0.971504, // 1458 + (float)-0.972226, // 1459 + (float)-0.972940, // 1460 + (float)-0.973644, // 1461 + (float)-0.974339, // 1462 + (float)-0.975025, // 1463 + (float)-0.975702, // 1464 + (float)-0.976370, // 1465 + (float)-0.977028, // 1466 + (float)-0.977677, // 1467 + (float)-0.978317, // 1468 + (float)-0.978948, // 1469 + (float)-0.979570, // 1470 + (float)-0.980182, // 1471 + (float)-0.980785, // 1472 + (float)-0.981379, // 1473 + (float)-0.981964, // 1474 + (float)-0.982539, // 1475 + (float)-0.983105, // 1476 + (float)-0.983662, // 1477 + (float)-0.984210, // 1478 + (float)-0.984749, // 1479 + (float)-0.985278, // 1480 + (float)-0.985798, // 1481 + (float)-0.986308, // 1482 + (float)-0.986809, // 1483 + (float)-0.987301, // 1484 + (float)-0.987784, // 1485 + (float)-0.988258, // 1486 + (float)-0.988722, // 1487 + (float)-0.989177, // 1488 + (float)-0.989622, // 1489 + (float)-0.990058, // 1490 + (float)-0.990485, // 1491 + (float)-0.990903, // 1492 + (float)-0.991311, // 1493 + (float)-0.991710, // 1494 + (float)-0.992099, // 1495 + (float)-0.992480, // 1496 + (float)-0.992850, // 1497 + (float)-0.993212, // 1498 + (float)-0.993564, // 1499 + (float)-0.993907, // 1500 + (float)-0.994240, // 1501 + (float)-0.994565, // 1502 + (float)-0.994879, // 1503 + (float)-0.995185, // 1504 + (float)-0.995481, // 1505 + (float)-0.995767, // 1506 + (float)-0.996045, // 1507 + (float)-0.996313, // 1508 + (float)-0.996571, // 1509 + (float)-0.996820, // 1510 + (float)-0.997060, // 1511 + (float)-0.997290, // 1512 + (float)-0.997511, // 1513 + (float)-0.997723, // 1514 + (float)-0.997925, // 1515 + (float)-0.998118, // 1516 + (float)-0.998302, // 1517 + (float)-0.998476, // 1518 + (float)-0.998640, // 1519 + (float)-0.998795, // 1520 + (float)-0.998941, // 1521 + (float)-0.999078, // 1522 + (float)-0.999205, // 1523 + (float)-0.999322, // 1524 + (float)-0.999431, // 1525 + (float)-0.999529, // 1526 + (float)-0.999619, // 1527 + (float)-0.999699, // 1528 + (float)-0.999769, // 1529 + (float)-0.999831, // 1530 + (float)-0.999882, // 1531 + (float)-0.999925, // 1532 + (float)-0.999958, // 1533 + (float)-0.999981, // 1534 + (float)-0.999995, // 1535 + (float)-1.000000, // 1536 + (float)-0.999995, // 1537 + (float)-0.999981, // 1538 + (float)-0.999958, // 1539 + (float)-0.999925, // 1540 + (float)-0.999882, // 1541 + (float)-0.999831, // 1542 + (float)-0.999769, // 1543 + (float)-0.999699, // 1544 + (float)-0.999619, // 1545 + (float)-0.999529, // 1546 + (float)-0.999431, // 1547 + (float)-0.999322, // 1548 + (float)-0.999205, // 1549 + (float)-0.999078, // 1550 + (float)-0.998941, // 1551 + (float)-0.998795, // 1552 + (float)-0.998640, // 1553 + (float)-0.998476, // 1554 + (float)-0.998302, // 1555 + (float)-0.998118, // 1556 + (float)-0.997925, // 1557 + (float)-0.997723, // 1558 + (float)-0.997511, // 1559 + (float)-0.997290, // 1560 + (float)-0.997060, // 1561 + (float)-0.996820, // 1562 + (float)-0.996571, // 1563 + (float)-0.996313, // 1564 + (float)-0.996045, // 1565 + (float)-0.995767, // 1566 + (float)-0.995481, // 1567 + (float)-0.995185, // 1568 + (float)-0.994879, // 1569 + (float)-0.994565, // 1570 + (float)-0.994240, // 1571 + (float)-0.993907, // 1572 + (float)-0.993564, // 1573 + (float)-0.993212, // 1574 + (float)-0.992850, // 1575 + (float)-0.992480, // 1576 + (float)-0.992099, // 1577 + (float)-0.991710, // 1578 + (float)-0.991311, // 1579 + (float)-0.990903, // 1580 + (float)-0.990485, // 1581 + (float)-0.990058, // 1582 + (float)-0.989622, // 1583 + (float)-0.989177, // 1584 + (float)-0.988722, // 1585 + (float)-0.988258, // 1586 + (float)-0.987784, // 1587 + (float)-0.987301, // 1588 + (float)-0.986809, // 1589 + (float)-0.986308, // 1590 + (float)-0.985798, // 1591 + (float)-0.985278, // 1592 + (float)-0.984749, // 1593 + (float)-0.984210, // 1594 + (float)-0.983662, // 1595 + (float)-0.983105, // 1596 + (float)-0.982539, // 1597 + (float)-0.981964, // 1598 + (float)-0.981379, // 1599 + (float)-0.980785, // 1600 + (float)-0.980182, // 1601 + (float)-0.979570, // 1602 + (float)-0.978948, // 1603 + (float)-0.978317, // 1604 + (float)-0.977677, // 1605 + (float)-0.977028, // 1606 + (float)-0.976370, // 1607 + (float)-0.975702, // 1608 + (float)-0.975025, // 1609 + (float)-0.974339, // 1610 + (float)-0.973644, // 1611 + (float)-0.972940, // 1612 + (float)-0.972226, // 1613 + (float)-0.971504, // 1614 + (float)-0.970772, // 1615 + (float)-0.970031, // 1616 + (float)-0.969281, // 1617 + (float)-0.968522, // 1618 + (float)-0.967754, // 1619 + (float)-0.966976, // 1620 + (float)-0.966190, // 1621 + (float)-0.965394, // 1622 + (float)-0.964590, // 1623 + (float)-0.963776, // 1624 + (float)-0.962953, // 1625 + (float)-0.962121, // 1626 + (float)-0.961280, // 1627 + (float)-0.960431, // 1628 + (float)-0.959572, // 1629 + (float)-0.958703, // 1630 + (float)-0.957826, // 1631 + (float)-0.956940, // 1632 + (float)-0.956045, // 1633 + (float)-0.955141, // 1634 + (float)-0.954228, // 1635 + (float)-0.953306, // 1636 + (float)-0.952375, // 1637 + (float)-0.951435, // 1638 + (float)-0.950486, // 1639 + (float)-0.949528, // 1640 + (float)-0.948561, // 1641 + (float)-0.947586, // 1642 + (float)-0.946601, // 1643 + (float)-0.945607, // 1644 + (float)-0.944605, // 1645 + (float)-0.943593, // 1646 + (float)-0.942573, // 1647 + (float)-0.941544, // 1648 + (float)-0.940506, // 1649 + (float)-0.939459, // 1650 + (float)-0.938404, // 1651 + (float)-0.937339, // 1652 + (float)-0.936266, // 1653 + (float)-0.935184, // 1654 + (float)-0.934093, // 1655 + (float)-0.932993, // 1656 + (float)-0.931884, // 1657 + (float)-0.930767, // 1658 + (float)-0.929641, // 1659 + (float)-0.928506, // 1660 + (float)-0.927363, // 1661 + (float)-0.926210, // 1662 + (float)-0.925049, // 1663 + (float)-0.923880, // 1664 + (float)-0.922701, // 1665 + (float)-0.921514, // 1666 + (float)-0.920318, // 1667 + (float)-0.919114, // 1668 + (float)-0.917901, // 1669 + (float)-0.916679, // 1670 + (float)-0.915449, // 1671 + (float)-0.914210, // 1672 + (float)-0.912962, // 1673 + (float)-0.911706, // 1674 + (float)-0.910441, // 1675 + (float)-0.909168, // 1676 + (float)-0.907886, // 1677 + (float)-0.906596, // 1678 + (float)-0.905297, // 1679 + (float)-0.903989, // 1680 + (float)-0.902673, // 1681 + (float)-0.901349, // 1682 + (float)-0.900016, // 1683 + (float)-0.898674, // 1684 + (float)-0.897325, // 1685 + (float)-0.895966, // 1686 + (float)-0.894599, // 1687 + (float)-0.893224, // 1688 + (float)-0.891841, // 1689 + (float)-0.890449, // 1690 + (float)-0.889048, // 1691 + (float)-0.887640, // 1692 + (float)-0.886223, // 1693 + (float)-0.884797, // 1694 + (float)-0.883363, // 1695 + (float)-0.881921, // 1696 + (float)-0.880471, // 1697 + (float)-0.879012, // 1698 + (float)-0.877545, // 1699 + (float)-0.876070, // 1700 + (float)-0.874587, // 1701 + (float)-0.873095, // 1702 + (float)-0.871595, // 1703 + (float)-0.870087, // 1704 + (float)-0.868571, // 1705 + (float)-0.867046, // 1706 + (float)-0.865514, // 1707 + (float)-0.863973, // 1708 + (float)-0.862424, // 1709 + (float)-0.860867, // 1710 + (float)-0.859302, // 1711 + (float)-0.857729, // 1712 + (float)-0.856147, // 1713 + (float)-0.854558, // 1714 + (float)-0.852961, // 1715 + (float)-0.851355, // 1716 + (float)-0.849742, // 1717 + (float)-0.848120, // 1718 + (float)-0.846491, // 1719 + (float)-0.844854, // 1720 + (float)-0.843208, // 1721 + (float)-0.841555, // 1722 + (float)-0.839894, // 1723 + (float)-0.838225, // 1724 + (float)-0.836548, // 1725 + (float)-0.834863, // 1726 + (float)-0.833170, // 1727 + (float)-0.831470, // 1728 + (float)-0.829761, // 1729 + (float)-0.828045, // 1730 + (float)-0.826321, // 1731 + (float)-0.824589, // 1732 + (float)-0.822850, // 1733 + (float)-0.821103, // 1734 + (float)-0.819348, // 1735 + (float)-0.817585, // 1736 + (float)-0.815814, // 1737 + (float)-0.814036, // 1738 + (float)-0.812251, // 1739 + (float)-0.810457, // 1740 + (float)-0.808656, // 1741 + (float)-0.806848, // 1742 + (float)-0.805031, // 1743 + (float)-0.803208, // 1744 + (float)-0.801376, // 1745 + (float)-0.799537, // 1746 + (float)-0.797691, // 1747 + (float)-0.795837, // 1748 + (float)-0.793975, // 1749 + (float)-0.792107, // 1750 + (float)-0.790230, // 1751 + (float)-0.788346, // 1752 + (float)-0.786455, // 1753 + (float)-0.784557, // 1754 + (float)-0.782651, // 1755 + (float)-0.780737, // 1756 + (float)-0.778817, // 1757 + (float)-0.776888, // 1758 + (float)-0.774953, // 1759 + (float)-0.773010, // 1760 + (float)-0.771061, // 1761 + (float)-0.769103, // 1762 + (float)-0.767139, // 1763 + (float)-0.765167, // 1764 + (float)-0.763188, // 1765 + (float)-0.761202, // 1766 + (float)-0.759209, // 1767 + (float)-0.757209, // 1768 + (float)-0.755201, // 1769 + (float)-0.753187, // 1770 + (float)-0.751165, // 1771 + (float)-0.749136, // 1772 + (float)-0.747101, // 1773 + (float)-0.745058, // 1774 + (float)-0.743008, // 1775 + (float)-0.740951, // 1776 + (float)-0.738887, // 1777 + (float)-0.736817, // 1778 + (float)-0.734739, // 1779 + (float)-0.732654, // 1780 + (float)-0.730563, // 1781 + (float)-0.728464, // 1782 + (float)-0.726359, // 1783 + (float)-0.724247, // 1784 + (float)-0.722128, // 1785 + (float)-0.720003, // 1786 + (float)-0.717870, // 1787 + (float)-0.715731, // 1788 + (float)-0.713585, // 1789 + (float)-0.711432, // 1790 + (float)-0.709273, // 1791 + (float)-0.707107, // 1792 + (float)-0.704934, // 1793 + (float)-0.702755, // 1794 + (float)-0.700569, // 1795 + (float)-0.698376, // 1796 + (float)-0.696177, // 1797 + (float)-0.693971, // 1798 + (float)-0.691759, // 1799 + (float)-0.689541, // 1800 + (float)-0.687315, // 1801 + (float)-0.685084, // 1802 + (float)-0.682846, // 1803 + (float)-0.680601, // 1804 + (float)-0.678350, // 1805 + (float)-0.676093, // 1806 + (float)-0.673829, // 1807 + (float)-0.671559, // 1808 + (float)-0.669283, // 1809 + (float)-0.667000, // 1810 + (float)-0.664711, // 1811 + (float)-0.662416, // 1812 + (float)-0.660114, // 1813 + (float)-0.657807, // 1814 + (float)-0.655493, // 1815 + (float)-0.653173, // 1816 + (float)-0.650847, // 1817 + (float)-0.648514, // 1818 + (float)-0.646176, // 1819 + (float)-0.643832, // 1820 + (float)-0.641481, // 1821 + (float)-0.639124, // 1822 + (float)-0.636762, // 1823 + (float)-0.634393, // 1824 + (float)-0.632019, // 1825 + (float)-0.629638, // 1826 + (float)-0.627252, // 1827 + (float)-0.624859, // 1828 + (float)-0.622461, // 1829 + (float)-0.620057, // 1830 + (float)-0.617647, // 1831 + (float)-0.615232, // 1832 + (float)-0.612810, // 1833 + (float)-0.610383, // 1834 + (float)-0.607950, // 1835 + (float)-0.605511, // 1836 + (float)-0.603067, // 1837 + (float)-0.600616, // 1838 + (float)-0.598161, // 1839 + (float)-0.595699, // 1840 + (float)-0.593232, // 1841 + (float)-0.590760, // 1842 + (float)-0.588282, // 1843 + (float)-0.585798, // 1844 + (float)-0.583309, // 1845 + (float)-0.580814, // 1846 + (float)-0.578314, // 1847 + (float)-0.575808, // 1848 + (float)-0.573297, // 1849 + (float)-0.570781, // 1850 + (float)-0.568259, // 1851 + (float)-0.565732, // 1852 + (float)-0.563199, // 1853 + (float)-0.560662, // 1854 + (float)-0.558119, // 1855 + (float)-0.555570, // 1856 + (float)-0.553017, // 1857 + (float)-0.550458, // 1858 + (float)-0.547894, // 1859 + (float)-0.545325, // 1860 + (float)-0.542751, // 1861 + (float)-0.540171, // 1862 + (float)-0.537587, // 1863 + (float)-0.534998, // 1864 + (float)-0.532403, // 1865 + (float)-0.529804, // 1866 + (float)-0.527199, // 1867 + (float)-0.524590, // 1868 + (float)-0.521975, // 1869 + (float)-0.519356, // 1870 + (float)-0.516732, // 1871 + (float)-0.514103, // 1872 + (float)-0.511469, // 1873 + (float)-0.508830, // 1874 + (float)-0.506187, // 1875 + (float)-0.503538, // 1876 + (float)-0.500885, // 1877 + (float)-0.498228, // 1878 + (float)-0.495565, // 1879 + (float)-0.492898, // 1880 + (float)-0.490226, // 1881 + (float)-0.487550, // 1882 + (float)-0.484869, // 1883 + (float)-0.482184, // 1884 + (float)-0.479494, // 1885 + (float)-0.476799, // 1886 + (float)-0.474100, // 1887 + (float)-0.471397, // 1888 + (float)-0.468689, // 1889 + (float)-0.465976, // 1890 + (float)-0.463260, // 1891 + (float)-0.460539, // 1892 + (float)-0.457813, // 1893 + (float)-0.455084, // 1894 + (float)-0.452350, // 1895 + (float)-0.449611, // 1896 + (float)-0.446869, // 1897 + (float)-0.444122, // 1898 + (float)-0.441371, // 1899 + (float)-0.438616, // 1900 + (float)-0.435857, // 1901 + (float)-0.433094, // 1902 + (float)-0.430326, // 1903 + (float)-0.427555, // 1904 + (float)-0.424780, // 1905 + (float)-0.422000, // 1906 + (float)-0.419217, // 1907 + (float)-0.416430, // 1908 + (float)-0.413638, // 1909 + (float)-0.410843, // 1910 + (float)-0.408044, // 1911 + (float)-0.405241, // 1912 + (float)-0.402435, // 1913 + (float)-0.399624, // 1914 + (float)-0.396810, // 1915 + (float)-0.393992, // 1916 + (float)-0.391170, // 1917 + (float)-0.388345, // 1918 + (float)-0.385516, // 1919 + (float)-0.382683, // 1920 + (float)-0.379847, // 1921 + (float)-0.377007, // 1922 + (float)-0.374164, // 1923 + (float)-0.371317, // 1924 + (float)-0.368467, // 1925 + (float)-0.365613, // 1926 + (float)-0.362756, // 1927 + (float)-0.359895, // 1928 + (float)-0.357031, // 1929 + (float)-0.354164, // 1930 + (float)-0.351293, // 1931 + (float)-0.348419, // 1932 + (float)-0.345541, // 1933 + (float)-0.342661, // 1934 + (float)-0.339777, // 1935 + (float)-0.336890, // 1936 + (float)-0.334000, // 1937 + (float)-0.331106, // 1938 + (float)-0.328210, // 1939 + (float)-0.325310, // 1940 + (float)-0.322408, // 1941 + (float)-0.319502, // 1942 + (float)-0.316593, // 1943 + (float)-0.313682, // 1944 + (float)-0.310767, // 1945 + (float)-0.307850, // 1946 + (float)-0.304929, // 1947 + (float)-0.302006, // 1948 + (float)-0.299080, // 1949 + (float)-0.296151, // 1950 + (float)-0.293219, // 1951 + (float)-0.290285, // 1952 + (float)-0.287347, // 1953 + (float)-0.284408, // 1954 + (float)-0.281465, // 1955 + (float)-0.278520, // 1956 + (float)-0.275572, // 1957 + (float)-0.272621, // 1958 + (float)-0.269668, // 1959 + (float)-0.266713, // 1960 + (float)-0.263755, // 1961 + (float)-0.260794, // 1962 + (float)-0.257831, // 1963 + (float)-0.254866, // 1964 + (float)-0.251898, // 1965 + (float)-0.248928, // 1966 + (float)-0.245955, // 1967 + (float)-0.242980, // 1968 + (float)-0.240003, // 1969 + (float)-0.237024, // 1970 + (float)-0.234042, // 1971 + (float)-0.231058, // 1972 + (float)-0.228072, // 1973 + (float)-0.225084, // 1974 + (float)-0.222094, // 1975 + (float)-0.219101, // 1976 + (float)-0.216107, // 1977 + (float)-0.213110, // 1978 + (float)-0.210112, // 1979 + (float)-0.207111, // 1980 + (float)-0.204109, // 1981 + (float)-0.201105, // 1982 + (float)-0.198098, // 1983 + (float)-0.195090, // 1984 + (float)-0.192080, // 1985 + (float)-0.189069, // 1986 + (float)-0.186055, // 1987 + (float)-0.183040, // 1988 + (float)-0.180023, // 1989 + (float)-0.177004, // 1990 + (float)-0.173984, // 1991 + (float)-0.170962, // 1992 + (float)-0.167938, // 1993 + (float)-0.164913, // 1994 + (float)-0.161886, // 1995 + (float)-0.158858, // 1996 + (float)-0.155828, // 1997 + (float)-0.152797, // 1998 + (float)-0.149765, // 1999 + (float)-0.146730, // 2000 + (float)-0.143695, // 2001 + (float)-0.140658, // 2002 + (float)-0.137620, // 2003 + (float)-0.134581, // 2004 + (float)-0.131540, // 2005 + (float)-0.128498, // 2006 + (float)-0.125455, // 2007 + (float)-0.122411, // 2008 + (float)-0.119365, // 2009 + (float)-0.116319, // 2010 + (float)-0.113271, // 2011 + (float)-0.110222, // 2012 + (float)-0.107172, // 2013 + (float)-0.104122, // 2014 + (float)-0.101070, // 2015 + (float)-0.098017, // 2016 + (float)-0.094963, // 2017 + (float)-0.091909, // 2018 + (float)-0.088854, // 2019 + (float)-0.085797, // 2020 + (float)-0.082740, // 2021 + (float)-0.079682, // 2022 + (float)-0.076624, // 2023 + (float)-0.073565, // 2024 + (float)-0.070505, // 2025 + (float)-0.067444, // 2026 + (float)-0.064383, // 2027 + (float)-0.061321, // 2028 + (float)-0.058258, // 2029 + (float)-0.055195, // 2030 + (float)-0.052132, // 2031 + (float)-0.049068, // 2032 + (float)-0.046003, // 2033 + (float)-0.042938, // 2034 + (float)-0.039873, // 2035 + (float)-0.036807, // 2036 + (float)-0.033741, // 2037 + (float)-0.030675, // 2038 + (float)-0.027608, // 2039 + (float)-0.024541, // 2040 + (float)-0.021474, // 2041 + (float)-0.018407, // 2042 + (float)-0.015339, // 2043 + (float)-0.012272, // 2044 + (float)-0.009204, // 2045 + (float)-0.006136, // 2046 + (float)-0.003068, // 2047 + (float)0.000000, // 0 + (float)0.003068, // 1 + (float)0.006136, // 2 + (float)0.009204, // 3 + (float)0.012272, // 4 + (float)0.015339, // 5 + (float)0.018407, // 6 + (float)0.021474, // 7 + (float)0.024541, // 8 + (float)0.027608, // 9 + (float)0.030675, // 10 + (float)0.033741, // 11 + (float)0.036807, // 12 + (float)0.039873, // 13 + (float)0.042938, // 14 + (float)0.046003, // 15 + (float)0.049068, // 16 + (float)0.052132, // 17 + (float)0.055195, // 18 + (float)0.058258, // 19 + (float)0.061321, // 20 + (float)0.064383, // 21 + (float)0.067444, // 22 + (float)0.070505, // 23 + (float)0.073565, // 24 + (float)0.076624, // 25 + (float)0.079682, // 26 + (float)0.082740, // 27 + (float)0.085797, // 28 + (float)0.088854, // 29 + (float)0.091909, // 30 + (float)0.094963, // 31 + (float)0.098017, // 32 + (float)0.101070, // 33 + (float)0.104122, // 34 + (float)0.107172, // 35 + (float)0.110222, // 36 + (float)0.113271, // 37 + (float)0.116319, // 38 + (float)0.119365, // 39 + (float)0.122411, // 40 + (float)0.125455, // 41 + (float)0.128498, // 42 + (float)0.131540, // 43 + (float)0.134581, // 44 + (float)0.137620, // 45 + (float)0.140658, // 46 + (float)0.143695, // 47 + (float)0.146730, // 48 + (float)0.149765, // 49 + (float)0.152797, // 50 + (float)0.155828, // 51 + (float)0.158858, // 52 + (float)0.161886, // 53 + (float)0.164913, // 54 + (float)0.167938, // 55 + (float)0.170962, // 56 + (float)0.173984, // 57 + (float)0.177004, // 58 + (float)0.180023, // 59 + (float)0.183040, // 60 + (float)0.186055, // 61 + (float)0.189069, // 62 + (float)0.192080, // 63 + (float)0.195090, // 64 + (float)0.198098, // 65 + (float)0.201105, // 66 + (float)0.204109, // 67 + (float)0.207111, // 68 + (float)0.210112, // 69 + (float)0.213110, // 70 + (float)0.216107, // 71 + (float)0.219101, // 72 + (float)0.222094, // 73 + (float)0.225084, // 74 + (float)0.228072, // 75 + (float)0.231058, // 76 + (float)0.234042, // 77 + (float)0.237024, // 78 + (float)0.240003, // 79 + (float)0.242980, // 80 + (float)0.245955, // 81 + (float)0.248928, // 82 + (float)0.251898, // 83 + (float)0.254866, // 84 + (float)0.257831, // 85 + (float)0.260794, // 86 + (float)0.263755, // 87 + (float)0.266713, // 88 + (float)0.269668, // 89 + (float)0.272621, // 90 + (float)0.275572, // 91 + (float)0.278520, // 92 + (float)0.281465, // 93 + (float)0.284408, // 94 + (float)0.287347, // 95 + (float)0.290285, // 96 + (float)0.293219, // 97 + (float)0.296151, // 98 + (float)0.299080, // 99 + (float)0.302006, // 100 + (float)0.304929, // 101 + (float)0.307850, // 102 + (float)0.310767, // 103 + (float)0.313682, // 104 + (float)0.316593, // 105 + (float)0.319502, // 106 + (float)0.322408, // 107 + (float)0.325310, // 108 + (float)0.328210, // 109 + (float)0.331106, // 110 + (float)0.334000, // 111 + (float)0.336890, // 112 + (float)0.339777, // 113 + (float)0.342661, // 114 + (float)0.345541, // 115 + (float)0.348419, // 116 + (float)0.351293, // 117 + (float)0.354164, // 118 + (float)0.357031, // 119 + (float)0.359895, // 120 + (float)0.362756, // 121 + (float)0.365613, // 122 + (float)0.368467, // 123 + (float)0.371317, // 124 + (float)0.374164, // 125 + (float)0.377007, // 126 + (float)0.379847, // 127 + (float)0.382683, // 128 + (float)0.385516, // 129 + (float)0.388345, // 130 + (float)0.391170, // 131 + (float)0.393992, // 132 + (float)0.396810, // 133 + (float)0.399624, // 134 + (float)0.402435, // 135 + (float)0.405241, // 136 + (float)0.408044, // 137 + (float)0.410843, // 138 + (float)0.413638, // 139 + (float)0.416430, // 140 + (float)0.419217, // 141 + (float)0.422000, // 142 + (float)0.424780, // 143 + (float)0.427555, // 144 + (float)0.430326, // 145 + (float)0.433094, // 146 + (float)0.435857, // 147 + (float)0.438616, // 148 + (float)0.441371, // 149 + (float)0.444122, // 150 + (float)0.446869, // 151 + (float)0.449611, // 152 + (float)0.452350, // 153 + (float)0.455084, // 154 + (float)0.457813, // 155 + (float)0.460539, // 156 + (float)0.463260, // 157 + (float)0.465976, // 158 + (float)0.468689, // 159 + (float)0.471397, // 160 + (float)0.474100, // 161 + (float)0.476799, // 162 + (float)0.479494, // 163 + (float)0.482184, // 164 + (float)0.484869, // 165 + (float)0.487550, // 166 + (float)0.490226, // 167 + (float)0.492898, // 168 + (float)0.495565, // 169 + (float)0.498228, // 170 + (float)0.500885, // 171 + (float)0.503538, // 172 + (float)0.506187, // 173 + (float)0.508830, // 174 + (float)0.511469, // 175 + (float)0.514103, // 176 + (float)0.516732, // 177 + (float)0.519356, // 178 + (float)0.521975, // 179 + (float)0.524590, // 180 + (float)0.527199, // 181 + (float)0.529804, // 182 + (float)0.532403, // 183 + (float)0.534998, // 184 + (float)0.537587, // 185 + (float)0.540171, // 186 + (float)0.542751, // 187 + (float)0.545325, // 188 + (float)0.547894, // 189 + (float)0.550458, // 190 + (float)0.553017, // 191 + (float)0.555570, // 192 + (float)0.558119, // 193 + (float)0.560662, // 194 + (float)0.563199, // 195 + (float)0.565732, // 196 + (float)0.568259, // 197 + (float)0.570781, // 198 + (float)0.573297, // 199 + (float)0.575808, // 200 + (float)0.578314, // 201 + (float)0.580814, // 202 + (float)0.583309, // 203 + (float)0.585798, // 204 + (float)0.588282, // 205 + (float)0.590760, // 206 + (float)0.593232, // 207 + (float)0.595699, // 208 + (float)0.598161, // 209 + (float)0.600616, // 210 + (float)0.603067, // 211 + (float)0.605511, // 212 + (float)0.607950, // 213 + (float)0.610383, // 214 + (float)0.612810, // 215 + (float)0.615232, // 216 + (float)0.617647, // 217 + (float)0.620057, // 218 + (float)0.622461, // 219 + (float)0.624859, // 220 + (float)0.627252, // 221 + (float)0.629638, // 222 + (float)0.632019, // 223 + (float)0.634393, // 224 + (float)0.636762, // 225 + (float)0.639124, // 226 + (float)0.641481, // 227 + (float)0.643832, // 228 + (float)0.646176, // 229 + (float)0.648514, // 230 + (float)0.650847, // 231 + (float)0.653173, // 232 + (float)0.655493, // 233 + (float)0.657807, // 234 + (float)0.660114, // 235 + (float)0.662416, // 236 + (float)0.664711, // 237 + (float)0.667000, // 238 + (float)0.669283, // 239 + (float)0.671559, // 240 + (float)0.673829, // 241 + (float)0.676093, // 242 + (float)0.678350, // 243 + (float)0.680601, // 244 + (float)0.682846, // 245 + (float)0.685084, // 246 + (float)0.687315, // 247 + (float)0.689541, // 248 + (float)0.691759, // 249 + (float)0.693971, // 250 + (float)0.696177, // 251 + (float)0.698376, // 252 + (float)0.700569, // 253 + (float)0.702755, // 254 + (float)0.704934, // 255 + (float)0.707107, // 256 + (float)0.709273, // 257 + (float)0.711432, // 258 + (float)0.713585, // 259 + (float)0.715731, // 260 + (float)0.717870, // 261 + (float)0.720003, // 262 + (float)0.722128, // 263 + (float)0.724247, // 264 + (float)0.726359, // 265 + (float)0.728464, // 266 + (float)0.730563, // 267 + (float)0.732654, // 268 + (float)0.734739, // 269 + (float)0.736817, // 270 + (float)0.738887, // 271 + (float)0.740951, // 272 + (float)0.743008, // 273 + (float)0.745058, // 274 + (float)0.747101, // 275 + (float)0.749136, // 276 + (float)0.751165, // 277 + (float)0.753187, // 278 + (float)0.755201, // 279 + (float)0.757209, // 280 + (float)0.759209, // 281 + (float)0.761202, // 282 + (float)0.763188, // 283 + (float)0.765167, // 284 + (float)0.767139, // 285 + (float)0.769103, // 286 + (float)0.771061, // 287 + (float)0.773010, // 288 + (float)0.774953, // 289 + (float)0.776888, // 290 + (float)0.778817, // 291 + (float)0.780737, // 292 + (float)0.782651, // 293 + (float)0.784557, // 294 + (float)0.786455, // 295 + (float)0.788346, // 296 + (float)0.790230, // 297 + (float)0.792107, // 298 + (float)0.793975, // 299 + (float)0.795837, // 300 + (float)0.797691, // 301 + (float)0.799537, // 302 + (float)0.801376, // 303 + (float)0.803208, // 304 + (float)0.805031, // 305 + (float)0.806848, // 306 + (float)0.808656, // 307 + (float)0.810457, // 308 + (float)0.812251, // 309 + (float)0.814036, // 310 + (float)0.815814, // 311 + (float)0.817585, // 312 + (float)0.819348, // 313 + (float)0.821103, // 314 + (float)0.822850, // 315 + (float)0.824589, // 316 + (float)0.826321, // 317 + (float)0.828045, // 318 + (float)0.829761, // 319 + (float)0.831470, // 320 + (float)0.833170, // 321 + (float)0.834863, // 322 + (float)0.836548, // 323 + (float)0.838225, // 324 + (float)0.839894, // 325 + (float)0.841555, // 326 + (float)0.843208, // 327 + (float)0.844854, // 328 + (float)0.846491, // 329 + (float)0.848120, // 330 + (float)0.849742, // 331 + (float)0.851355, // 332 + (float)0.852961, // 333 + (float)0.854558, // 334 + (float)0.856147, // 335 + (float)0.857729, // 336 + (float)0.859302, // 337 + (float)0.860867, // 338 + (float)0.862424, // 339 + (float)0.863973, // 340 + (float)0.865514, // 341 + (float)0.867046, // 342 + (float)0.868571, // 343 + (float)0.870087, // 344 + (float)0.871595, // 345 + (float)0.873095, // 346 + (float)0.874587, // 347 + (float)0.876070, // 348 + (float)0.877545, // 349 + (float)0.879012, // 350 + (float)0.880471, // 351 + (float)0.881921, // 352 + (float)0.883363, // 353 + (float)0.884797, // 354 + (float)0.886223, // 355 + (float)0.887640, // 356 + (float)0.889048, // 357 + (float)0.890449, // 358 + (float)0.891841, // 359 + (float)0.893224, // 360 + (float)0.894599, // 361 + (float)0.895966, // 362 + (float)0.897325, // 363 + (float)0.898674, // 364 + (float)0.900016, // 365 + (float)0.901349, // 366 + (float)0.902673, // 367 + (float)0.903989, // 368 + (float)0.905297, // 369 + (float)0.906596, // 370 + (float)0.907886, // 371 + (float)0.909168, // 372 + (float)0.910441, // 373 + (float)0.911706, // 374 + (float)0.912962, // 375 + (float)0.914210, // 376 + (float)0.915449, // 377 + (float)0.916679, // 378 + (float)0.917901, // 379 + (float)0.919114, // 380 + (float)0.920318, // 381 + (float)0.921514, // 382 + (float)0.922701, // 383 + (float)0.923880, // 384 + (float)0.925049, // 385 + (float)0.926210, // 386 + (float)0.927363, // 387 + (float)0.928506, // 388 + (float)0.929641, // 389 + (float)0.930767, // 390 + (float)0.931884, // 391 + (float)0.932993, // 392 + (float)0.934093, // 393 + (float)0.935184, // 394 + (float)0.936266, // 395 + (float)0.937339, // 396 + (float)0.938404, // 397 + (float)0.939459, // 398 + (float)0.940506, // 399 + (float)0.941544, // 400 + (float)0.942573, // 401 + (float)0.943593, // 402 + (float)0.944605, // 403 + (float)0.945607, // 404 + (float)0.946601, // 405 + (float)0.947586, // 406 + (float)0.948561, // 407 + (float)0.949528, // 408 + (float)0.950486, // 409 + (float)0.951435, // 410 + (float)0.952375, // 411 + (float)0.953306, // 412 + (float)0.954228, // 413 + (float)0.955141, // 414 + (float)0.956045, // 415 + (float)0.956940, // 416 + (float)0.957826, // 417 + (float)0.958703, // 418 + (float)0.959572, // 419 + (float)0.960431, // 420 + (float)0.961280, // 421 + (float)0.962121, // 422 + (float)0.962953, // 423 + (float)0.963776, // 424 + (float)0.964590, // 425 + (float)0.965394, // 426 + (float)0.966190, // 427 + (float)0.966976, // 428 + (float)0.967754, // 429 + (float)0.968522, // 430 + (float)0.969281, // 431 + (float)0.970031, // 432 + (float)0.970772, // 433 + (float)0.971504, // 434 + (float)0.972226, // 435 + (float)0.972940, // 436 + (float)0.973644, // 437 + (float)0.974339, // 438 + (float)0.975025, // 439 + (float)0.975702, // 440 + (float)0.976370, // 441 + (float)0.977028, // 442 + (float)0.977677, // 443 + (float)0.978317, // 444 + (float)0.978948, // 445 + (float)0.979570, // 446 + (float)0.980182, // 447 + (float)0.980785, // 448 + (float)0.981379, // 449 + (float)0.981964, // 450 + (float)0.982539, // 451 + (float)0.983105, // 452 + (float)0.983662, // 453 + (float)0.984210, // 454 + (float)0.984749, // 455 + (float)0.985278, // 456 + (float)0.985798, // 457 + (float)0.986308, // 458 + (float)0.986809, // 459 + (float)0.987301, // 460 + (float)0.987784, // 461 + (float)0.988258, // 462 + (float)0.988722, // 463 + (float)0.989177, // 464 + (float)0.989622, // 465 + (float)0.990058, // 466 + (float)0.990485, // 467 + (float)0.990903, // 468 + (float)0.991311, // 469 + (float)0.991710, // 470 + (float)0.992099, // 471 + (float)0.992480, // 472 + (float)0.992850, // 473 + (float)0.993212, // 474 + (float)0.993564, // 475 + (float)0.993907, // 476 + (float)0.994240, // 477 + (float)0.994565, // 478 + (float)0.994879, // 479 + (float)0.995185, // 480 + (float)0.995481, // 481 + (float)0.995767, // 482 + (float)0.996045, // 483 + (float)0.996313, // 484 + (float)0.996571, // 485 + (float)0.996820, // 486 + (float)0.997060, // 487 + (float)0.997290, // 488 + (float)0.997511, // 489 + (float)0.997723, // 490 + (float)0.997925, // 491 + (float)0.998118, // 492 + (float)0.998302, // 493 + (float)0.998476, // 494 + (float)0.998640, // 495 + (float)0.998795, // 496 + (float)0.998941, // 497 + (float)0.999078, // 498 + (float)0.999205, // 499 + (float)0.999322, // 500 + (float)0.999431, // 501 + (float)0.999529, // 502 + (float)0.999619, // 503 + (float)0.999699, // 504 + (float)0.999769, // 505 + (float)0.999831, // 506 + (float)0.999882, // 507 + (float)0.999925, // 508 + (float)0.999958, // 509 + (float)0.999981, // 510 + (float)0.999995, // 511 +}; + +float *CosTableF = &SinTableF[512]; + +//--------------------------------------------------------------- +SLONG Proportions[] = +{ + 11585, + 11563, + 11540, + 11518, + 11495, + 11473, + 11450, + 11428, + 11406, + 11383, + 11361, + 11339, + 11317, + 11295, + 11273, + 11251, + 11229, + 11207, + 11185, + 11164, + 11142, + 11120, + 11099, + 11077, + 11056, + 11034, + 11013, + 10991, + 10970, + 10949, + 10928, + 10906, + 10885, + 10864, + 10843, + 10822, + 10801, + 10781, + 10760, + 10739, + 10718, + 10698, + 10677, + 10657, + 10636, + 10616, + 10596, + 10575, + 10555, + 10535, + 10515, + 10495, + 10475, + 10455, + 10435, + 10415, + 10396, + 10376, + 10356, + 10337, + 10317, + 10298, + 10279, + 10259, + 10240, + 10221, + 10202, + 10183, + 10164, + 10145, + 10126, + 10107, + 10088, + 10070, + 10051, + 10033, + 10014, + 9996, + 9978, + 9959, + 9941, + 9923, + 9905, + 9887, + 9869, + 9851, + 9834, + 9816, + 9798, + 9781, + 9764, + 9746, + 9729, + 9712, + 9694, + 9677, + 9660, + 9643, + 9627, + 9610, + 9593, + 9577, + 9560, + 9544, + 9527, + 9511, + 9495, + 9479, + 9462, + 9447, + 9431, + 9415, + 9399, + 9383, + 9368, + 9352, + 9337, + 9322, + 9306, + 9291, + 9276, + 9261, + 9246, + 9232, + 9217, + 9202, + 9188, + 9173, + 9159, + 9145, + 9130, + 9116, + 9102, + 9089, + 9075, + 9061, + 9047, + 9034, + 9020, + 9007, + 8994, + 8981, + 8968, + 8955, + 8942, + 8929, + 8916, + 8904, + 8891, + 8879, + 8866, + 8854, + 8842, + 8830, + 8818, + 8807, + 8795, + 8783, + 8772, + 8760, + 8749, + 8738, + 8727, + 8716, + 8705, + 8694, + 8684, + 8673, + 8662, + 8652, + 8642, + 8632, + 8622, + 8612, + 8602, + 8592, + 8583, + 8573, + 8564, + 8555, + 8545, + 8536, + 8527, + 8519, + 8510, + 8501, + 8493, + 8484, + 8476, + 8468, + 8460, + 8452, + 8444, + 8436, + 8429, + 8421, + 8414, + 8407, + 8400, + 8393, + 8386, + 8379, + 8372, + 8366, + 8359, + 8353, + 8347, + 8341, + 8335, + 8329, + 8323, + 8318, + 8312, + 8307, + 8302, + 8296, + 8291, + 8287, + 8282, + 8277, + 8273, + 8268, + 8264, + 8260, + 8256, + 8252, + 8248, + 8244, + 8241, + 8237, + 8234, + 8231, + 8228, + 8225, + 8222, + 8220, + 8217, + 8215, + 8212, + 8210, + 8208, + 8206, + 8204, + 8203, + 8201, + 8200, + 8198, + 8197, + 8196, + 8195, + 8194, + 8194, + 8193, + 8193, + 8192, + 8192, + 8192, + 8192, + 8192, + 8193, + 8193, + 8194, + 8194, + 8195, + 8196, + 8197, + 8198, + 8200, + 8201, + 8203, + 8204, + 8206, + 8208, + 8210, + 8212, + 8215, + 8217, + 8220, + 8222, + 8225, + 8228, + 8231, + 8234, + 8237, + 8241, + 8244, + 8248, + 8252, + 8256, + 8260, + 8264, + 8268, + 8273, + 8277, + 8282, + 8287, + 8291, + 8296, + 8302, + 8307, + 8312, + 8318, + 8323, + 8329, + 8335, + 8341, + 8347, + 8353, + 8359, + 8366, + 8372, + 8379, + 8386, + 8393, + 8400, + 8407, + 8414, + 8421, + 8429, + 8436, + 8444, + 8452, + 8460, + 8468, + 8476, + 8484, + 8493, + 8501, + 8510, + 8519, + 8527, + 8536, + 8545, + 8555, + 8564, + 8573, + 8583, + 8592, + 8602, + 8612, + 8622, + 8632, + 8642, + 8652, + 8662, + 8673, + 8684, + 8694, + 8705, + 8716, + 8727, + 8738, + 8749, + 8760, + 8772, + 8783, + 8795, + 8807, + 8818, + 8830, + 8842, + 8854, + 8866, + 8879, + 8891, + 8904, + 8916, + 8929, + 8942, + 8955, + 8968, + 8981, + 8994, + 9007, + 9020, + 9034, + 9047, + 9061, + 9075, + 9089, + 9102, + 9116, + 9130, + 9145, + 9159, + 9173, + 9188, + 9202, + 9217, + 9232, + 9246, + 9261, + 9276, + 9291, + 9306, + 9322, + 9337, + 9352, + 9368, + 9383, + 9399, + 9415, + 9431, + 9447, + 9462, + 9479, + 9495, + 9511, + 9527, + 9544, + 9560, + 9577, + 9593, + 9610, + 9627, + 9643, + 9660, + 9677, + 9694, + 9712, + 9729, + 9746, + 9764, + 9781, + 9798, + 9816, + 9834, + 9851, + 9869, + 9887, + 9905, + 9923, + 9941, + 9959, + 9978, + 9996, + 10014, + 10033, + 10051, + 10070, + 10088, + 10107, + 10126, + 10145, + 10164, + 10183, + 10202, + 10221, + 10240, + 10259, + 10279, + 10298, + 10317, + 10337, + 10356, + 10376, + 10396, + 10415, + 10435, + 10455, + 10475, + 10495, + 10515, + 10535, + 10555, + 10575, + 10596, + 10616, + 10636, + 10657, + 10677, + 10698, + 10718, + 10739, + 10760, + 10781, + 10801, + 10822, + 10843, + 10864, + 10885, + 10906, + 10928, + 10949, + 10970, + 10991, + 11013, + 11034, + 11056, + 11077, + 11099, + 11120, + 11142, + 11164, + 11185, + 11207, + 11229, + 11251, + 11273, + 11295, + 11317, + 11339, + 11361, + 11383, + 11406, + 11428, + 11450, + 11473, + 11495, + 11518, + 11540, + 11563, + 11585, +}; + +//--------------------------------------------------------------- diff --git a/MFStdLib/Source/StdLib/StdMem.cpp b/MFStdLib/Source/StdLib/StdMem.cpp new file mode 100644 index 0000000..4186946 --- /dev/null +++ b/MFStdLib/Source/StdLib/StdMem.cpp @@ -0,0 +1,254 @@ +// StdMem.cpp +// Guy Simmons, 18th December 1997 + +#include + +#define INITIAL_HEAP_SIZE (8*1024*1024) +#define MAXIMUM_HEAP_SIZE 0 + +#ifdef DEBUG +// Allows heap debugging - logs interesting info, e.g. for memory leak tracking. +//#define HEAP_DEBUGGING_PLEASE_BOB defined +#endif + + +HANDLE MFHeap = NULL; + +#ifdef HEAP_DEBUGGING_PLEASE_BOB +struct HeapDebugInfo +{ + HeapDebugInfo *pPrev; + HeapDebugInfo *pNext; + ULONG ulSize; // The size of this alloc. + ULONG ulSeqNum; // The malloc number. +}; + +#define MAX_NUM_DELNEW_TRACES 2000 + +int iNumNewDelTraces = 0; + +struct newdeltrace +{ + void *pvAddr; + ULONG ulsize; + ULONG ulSequenceNumber; +} ndtList[MAX_NUM_DELNEW_TRACES]; + + + +HeapDebugInfo *pFirst = NULL; +ULONG ulCurrentSequenceNumber = 0; + +// Set this to 1 in a debugger to dump the info. +volatile bool bDumpDebug = FALSE; +// Set this to an ID you want to track in the debugger. +volatile ULONG ulSpotted = -1; + + +void DumpDebug ( void ) +{ + bDumpDebug = FALSE; + + TRACE ( "\nMemory debug dump\n" ); + + HeapDebugInfo *phdi = pFirst; + while ( phdi != NULL ) + { + TRACE ( "ID<0x%x> size<0x%x> \n", phdi->ulSeqNum, phdi->ulSize ); + + phdi = phdi->pNext; + } + + TRACE ( "NewDel debug bump\n" ); + for ( int i = 0; i < iNumNewDelTraces; i++ ) + { + TRACE ( "ID<0x%x> size<0x%x> \n", ndtList[i].ulSequenceNumber, ndtList[i].ulsize ); + } + + TRACE ( "\n" ); + +} + + +#endif + +//--------------------------------------------------------------- + +BOOL SetupMemory(void) +{ +#ifdef HEAP_DEBUGGING_PLEASE_BOB + pFirst = NULL; + ulCurrentSequenceNumber = 0; +#endif + if(MFHeap==NULL) + { + MFHeap = HeapCreate(0,INITIAL_HEAP_SIZE,MAXIMUM_HEAP_SIZE); + } + if(MFHeap) + return TRUE; + else + return FALSE; +} + +//--------------------------------------------------------------- + +void ResetMemory(void) +{ + if(MFHeap) + { + HeapDestroy(MFHeap); + MFHeap = NULL; + } +#ifdef HEAP_DEBUGGING_PLEASE_BOB + pFirst = NULL; + // Sequence number is not reset. +#endif +} + +//--------------------------------------------------------------- + +void *MemAlloc(ULONG size) +{ +#ifdef HEAP_DEBUGGING_PLEASE_BOB + if ( bDumpDebug ) + { + DumpDebug(); + } + + // Set up ulSpotted in a debugger to track interesting items. + ASSERT ( ulSpotted != ulCurrentSequenceNumber ); + + ULONG ulOriginalSize = size; + size += sizeof ( HeapDebugInfo ); +#endif + size = (size+3)&0xfffffffc; + void *ptr = (void*)HeapAlloc(MFHeap,HEAP_ZERO_MEMORY,size); + ASSERT ( ptr != NULL ); + +#ifdef HEAP_DEBUGGING_PLEASE_BOB + HeapDebugInfo *phdi = (HeapDebugInfo *)ptr; + ptr = (void*)( (char*)ptr + sizeof ( HeapDebugInfo ) ); + + phdi->ulSeqNum = ulCurrentSequenceNumber++; + phdi->ulSize = ulOriginalSize; + phdi->pNext = pFirst; + phdi->pPrev = NULL; + if ( pFirst != NULL ) + { + ASSERT ( pFirst->pPrev == NULL ); + pFirst->pPrev = phdi; + } + pFirst = phdi; +#endif + + return ptr; +} + +//--------------------------------------------------------------- + +void MemFree(void *mem_ptr) +{ +#ifdef HEAP_DEBUGGING_PLEASE_BOB + if ( bDumpDebug ) + { + DumpDebug(); + } + + mem_ptr = (void*)( (char*)mem_ptr - sizeof ( HeapDebugInfo ) ); + HeapDebugInfo *phdi = (HeapDebugInfo *)mem_ptr; + + // Set up ulSpotted in a debugger to track interesting items. + ASSERT ( ulSpotted != phdi->ulSeqNum ); + + if ( phdi->pPrev != NULL ) + { + ASSERT ( phdi->pPrev->pNext == phdi ); + phdi->pPrev->pNext = phdi->pNext; + } + else + { + ASSERT ( pFirst == phdi ); + pFirst = phdi->pNext; + } + if ( phdi->pNext != NULL ) + { + ASSERT ( phdi->pNext->pPrev == phdi ); + phdi->pNext->pPrev = phdi->pPrev; + } +#endif + + HeapFree(MFHeap,0,mem_ptr); +} + +//--------------------------------------------------------------- + +/* +void MemClear(void *mem_ptr,ULONG size) +{ +} +*/ + +//--------------------------------------------------------------- + + +#ifdef DEBUG +// Support for MFnew and MFdelete +#ifndef HEAP_DEBUGGING_PLEASE_BOB + +// Do nothing. +void MFnewTrace ( void *pvAddr, size_t size ) +{ +} + +void MFdeleteTrace ( void *pvAddr ) +{ +} + +#else //#ifndef HEAP_DEBUGGING_PLEASE_BOB + +void MFnewTrace ( void *pvAddr, size_t size ) +{ + if ( bDumpDebug ) + { + DumpDebug(); + } + + ASSERT ( iNumNewDelTraces < MAX_NUM_DELNEW_TRACES - 1 ); + + ndtList[iNumNewDelTraces].pvAddr = pvAddr; + ndtList[iNumNewDelTraces].ulsize = (ULONG)size; + ndtList[iNumNewDelTraces].ulSequenceNumber = ulCurrentSequenceNumber++; + iNumNewDelTraces++; +} + +void MFdeleteTrace ( void *pvAddr ) +{ + if ( bDumpDebug ) + { + DumpDebug(); + } + + // Search for this entry. + bool bFound = FALSE; + for ( int i = 0; i < iNumNewDelTraces; i++ ) + { + if ( ndtList[i].pvAddr == pvAddr ) + { + iNumNewDelTraces--; + ndtList[i] = ndtList[iNumNewDelTraces]; + bFound = TRUE; + break; + } + } + ASSERT ( bFound ); +} + +#endif //#else //#ifndef HEAP_DEBUGGING_PLEASE_BOB + + +#endif + + + + + diff --git a/MuckyBasic/Always.h b/MuckyBasic/Always.h new file mode 100644 index 0000000..08d2f3e --- /dev/null +++ b/MuckyBasic/Always.h @@ -0,0 +1,414 @@ +#ifndef _ALWAYS_ +#define _ALWAYS_ + +// +// Turn off the warning about [] arrays at the end of structures. +// + +#pragma warning( disable : 4200 ) + + +typedef signed long SLONG; +typedef unsigned long ULONG; +typedef signed short int SWORD; +typedef unsigned short int UWORD; +typedef signed char SBYTE; +typedef unsigned char UBYTE; +typedef char CBYTE; + + +// +// Standard libraries most often used. +// + +#include +#include +#include +#include +#include +#include +#include + +// +// Constants. +// + +#define PI (3.14159265F) +#define ROOT2 (1.41421356F) +#define INFINITY (0x7fffffff) + + +// +// Useful defines. +// + +#define MIN(mnx,mny) (((mnx) < (mny)) ? (mnx) : (mny)) +#define MAX(mnx,mny) (((mnx) > (mny)) ? (mnx) : (mny)) +#define MAX3(mnx,mny,mnz) (((mnx) > (mny)) ? MAX(mnx,mnz) : MAX(mny,mnz)) +#define MIN3(mnx,mny,mnz) (((mnx) < (mny)) ? MIN(mnx,mnz) : MIN(mny,mnz)) +#define MIN4(a,b,c,d) (MIN(MIN(a,b), MIN(c,d))) +#define MAX4(a,b,c,d) (MAX(MAX(a,b), MAX(c,d))) +#define SWAP(x,y) {SLONG SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_UB(x,y) {UBYTE SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_UW(x,y) {UWORD SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_FL(x,y) {float SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_DB(x,y) {double SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_HF(x,y) {Pointhf SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_P3(x,y) {Point3d SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_VD(x,y) {void *SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_UWP(x,y) {UWORD *SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define SWAP_UBP(x,y) {UBYTE *SWAP_spare; SWAP_spare = x; x = y; y = SWAP_spare;} +#define WITHIN(x,a,b) ((x) >= (a) && (x) <= (b)) +#define SATURATE(x,a,b) {if ((x) < (a)) (x) = (a); if ((x) > (b)) (x) = (b);} +#define SIGN(x) (((x)) ? (((x) > 0) ? 1 : -1) : 0) +#define QLEN(x,y) (((x) > (y)) ? (x) + ((y) >> 1) : (y) + ((x) >> 1)) +#define XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) +#define SQRT16(x) ((sqrt((double) (x)) * 256)) +#define SHOW(a) {TRACE(#a" = %d\n", (a));} +#define SHOW_X(a) {TRACE(#a" = 0x%x\n", (a));} +#define SHOW_FL(a) {TRACE(#a" = %f\n", (a));} + + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +// +// Error checking macros +// + +#ifndef NDEBUG + +void OS_string(CBYTE *fmt, ...); + +#define ASSERT(x) {assert(x);} +#define TRACE OS_string +#define VERIFY(x) ASSERT(x) +#else +#define ASSERT(x) {__assume(x);} +#define TRACE +#define VERIFY(x) x + +// +// In release build, get rid of the x == 1; warning message otherwise +// VERIFY generates it all the time! +// + +#pragma warning( disable : 4553 ) +#endif + + +// +// Assembler fixed point thingies from T.A.C. +// + +static inline SLONG DIV16(SLONG a, SLONG b) +{ + SLONG v; + _asm + { + mov edx,a + mov ebx,b + mov eax,edx + shl eax,16 + sar edx,16 + idiv ebx + mov v,eax + } + return v; +} + +#pragma warning( disable : 4035 ) +// stop warning of no return value : eax is valid +static inline SLONG MUL16(SLONG a, SLONG b) +// MSVC++ version, params:ecx,edx, return:eax +// this is as fast on 486/Pentium as the old version +// and 2.5* faster on Pentium Pro +{ + __asm + { + mov eax, a + imul b // result in edx:eax + shl edx,16 + shr eax,16 + or eax,edx + // return in eax + } +} +#pragma warning( default : 4035 ) + + +// +// Sets the precision of the floating point unit. +// + +#define FPP_SINGLE 0x00 // 32-bits +#define FPP_DOUBLE 0x20 // 53-bits +#define FPP_EXTENDED 0x30 // 64-bits + +static inline void fpp_set(UWORD precision) +{ + short control; + + __asm + { + wait + fnstcw control + wait + mov ax, control + and ax, 0xfcff + or ax, precision + mov control, ax + fldcw control + } +} + + + +// +// For doing fast floating-point to long conversion... +// + +// +// Sets the rounding to truncate automatically. +// + +static inline void ftol_init(void) +{ + short control; + + __asm + { + wait + fnstcw control + wait + mov ax, control + or ah, 0Ch + mov control, ax + fldcw control + } +} + +// +// Converts a float to an int using the current rounding. For normal +// C-style rounding, make sure you call ftol_init() at the start +// of your program. +// + +static inline int ftol(float f) +{ + int ans; + + __asm + { + fld f + fistp ans + } + + return ans; +} + + + +// +// Finds the sign of the cross product x1y2 - x2y1 also from T.A.C. +// + +static inline SBYTE CROSS_PROD_SIGN(SLONG x1, SLONG y1, SLONG x2, SLONG y2) +{ + SBYTE ans; + + __asm + { + mov eax, x1 + mov ebx, y1 + mov ecx, x2 + mov edx, y2 + + imul edx + xchg eax,ebx + xchg edx,ecx + imul edx + sub ebx,eax + setnz al + sbb ecx,edx + jz done + setl ah + setg al + sub al,ah + done: + + mov ans, al + } + + return ans; +} + + +// +// Returns the number of the first bit set in the given value. Returns +// -1 if there is no bit set. +// + +static inline first_bit(SLONG search) +{ + SLONG ans; + + __asm + { + mov eax, search + mov ebx, 0ffffffffh + bsf ebx, eax + mov ans, ebx + } + + return ans; +} + + +// +// Returns the number of the last bit set in the given value. Returns +// -1 if there is no bit set. +// + +static inline last_bit(SLONG search) +{ + SLONG ans; + + __asm + { + mov eax, search + mov ebx, 0ffffffffh + bsr ebx, eax + mov ans, ebx + } + + return ans; +} + + +// +// Find the cross product. +// + +#define CROSS_PROD(x1,y1,x2,y2) (((x1)*(y2)) - ((x2)*(y1))) + + +// +// Globally useful structures. +// + +typedef struct {float x, y, z;} Point3d; +typedef struct {float x, y; } Point2d; +typedef struct {float x, z; } Pointhf; +typedef struct {float u, v; } Pointuv; + +typedef struct +{ + float yaw; + float pitch; + float roll; + +} Direction; + +typedef struct +{ + UBYTE r; + UBYTE g; + UBYTE b; + +} Colour; + +// +// Fast approximation to sqrt(x*x + y*y) +// + +static inline float qdist2(float x, float y) +{ + float ans; + + ASSERT(x >= 0.0F); + ASSERT(y >= 0.0F); + + if (x > y) + { + ans = x + y * 0.5F; + } + else + { + ans = y + x * 0.5F; + } + + return ans; +} + + +// +// Fast approximation to sqrt(x*x + y*y + z*z), x,y and z must +// be positive. +// + +static inline float qdist3(float x, float y, float z) +{ + float ans; + + ASSERT(x >= 0.0F); + ASSERT(y >= 0.0F); + ASSERT(z >= 0.0F); + + if (x > y) + { + if (x > z) + { + // + // x is the biggeset. + // + + ans = x + (y + z) * 0.2941F; + + return ans; + } + } + else + { + if (y > z) + { + // + // y is the biggeset. + // + + ans = y + (x + z) * 0.2941F; + + return ans; + } + } + + // + // z is the biggeset. + // + + ans = z + (x + y) * 0.2941F; + + return ans; +} + + +// +// A floating point number between 0 and 1.0F +// + +static inline float frand(void) +{ + SLONG irand = rand(); + float ans = float(irand) * (1.0F / float(RAND_MAX)); + + return ans; +} + + + +#endif diff --git a/MuckyBasic/Key.h b/MuckyBasic/Key.h new file mode 100644 index 0000000..a01250e --- /dev/null +++ b/MuckyBasic/Key.h @@ -0,0 +1,133 @@ +// +// Keyboard handling. +// + +#ifndef _KEY_ +#define _KEY_ + + +// +// Every key has a byte flag to say whether it is on or off. +// + +extern volatile UBYTE KEY_on[256]; +extern volatile SLONG KEY_inkey; // The ASCII value of the last key pressed. +extern volatile SLONG KEY_shift; + +// +// KEY shift can have the following bits set. +// + +#define KEY_SHIFT (1 << 0) +#define KEY_ALT (1 << 1) +#define KEY_CONTROL (1 << 2) + +// +// The scancodes of all the keys... +// + +#define KEY_ESCAPE 0x01 +#define KEY_1 0x02 +#define KEY_2 0x03 +#define KEY_3 0x04 +#define KEY_4 0x05 +#define KEY_5 0x06 +#define KEY_6 0x07 +#define KEY_7 0x08 +#define KEY_8 0x09 +#define KEY_9 0x0a +#define KEY_0 0x0b +#define KEY_MINUS 0x0c +#define KEY_EQUAL 0x0d +#define KEY_BACKSPACE 0x0e +#define KEY_TAB 0x0f +#define KEY_Q 0x010 +#define KEY_W 0x011 +#define KEY_E 0x012 +#define KEY_R 0x013 +#define KEY_T 0x014 +#define KEY_Y 0x015 +#define KEY_U 0x016 +#define KEY_I 0x017 +#define KEY_O 0x018 +#define KEY_P 0x019 +#define KEY_LSBRACKET 0x01a +#define KEY_RSBRACKET 0x01b +#define KEY_RETURN 0x01c +#define KEY_LCONTROL 0x01d +#define KEY_RCONTROL (0x01d + 0x80) +#define KEY_A 0x01e +#define KEY_S 0x01f +#define KEY_D 0x020 +#define KEY_F 0x021 +#define KEY_G 0x022 +#define KEY_H 0x023 +#define KEY_J 0x024 +#define KEY_K 0x025 +#define KEY_L 0x026 +#define KEY_COLON 0x027 +#define KEY_QUOTE 0x028 +#define KEY_QUOTE2 0x029 +#define KEY_LSHIFT 0x02a +#define KEY_HASH 0x02b +#define KEY_BACKSLASH 0x056 +#define KEY_Z 0x02c +#define KEY_X 0x02d +#define KEY_C 0x02e +#define KEY_V 0x02f +#define KEY_B 0x030 +#define KEY_N 0x031 +#define KEY_M 0x032 +#define KEY_COMMA 0x033 +#define KEY_POINT 0x034 +#define KEY_SLASH 0x035 +#define KEY_RSHIFT 0x036 +#define KEY_LALT 0x038 +#define KEY_RALT (0x038 + 0x80) +#define KEY_SPACE 0x039 +#define KEY_CAPS 0x03a +#define KEY_F1 0x03b +#define KEY_F2 0x03c +#define KEY_F3 0x03d +#define KEY_F4 0x03e +#define KEY_F5 0x03f +#define KEY_F6 0x040 +#define KEY_F7 0x041 +#define KEY_F8 0x042 +#define KEY_F9 0x043 +#define KEY_F10 0x044 +#define KEY_F11 0x057 +#define KEY_F12 0x058 + +#define KEY_HOME (0x47 + 0x80) +#define KEY_UP (0x48 + 0x80) +#define KEY_PAGEUP (0x49 + 0x80) +#define KEY_LEFT (0x4b + 0x80) +#define KEY_RIGHT (0x4d + 0x80) +#define KEY_END (0x4f + 0x80) +#define KEY_DOWN (0x50 + 0x80) +#define KEY_PAGEDOWN (0x51 + 0x80) +#define KEY_INSERT (0x52 + 0x80) +#define KEY_DELETE (0x53 + 0x80) + +#define KEY_NUM_LOCK 0x045 +#define KEY_PMINUS 0x04a +#define KEY_PADD 0x04e +#define KEY_PSLASH (0x035 + 0x80) +#define KEY_ASTERISK 0x037 +#define KEY_PDOT 0x053 +#define KEY_ENTER (0x01c + 0x80) + +#define KEY_P7 0x047 +#define KEY_P8 0x048 +#define KEY_P9 0x049 +#define KEY_P4 0x04b +#define KEY_P5 0x04c +#define KEY_P6 0x04d +#define KEY_P1 0x04f +#define KEY_P2 0x050 +#define KEY_P3 0x051 +#define KEY_P0 0x052 + + +#endif \ No newline at end of file diff --git a/MuckyBasic/Matrix.cpp b/MuckyBasic/Matrix.cpp new file mode 100644 index 0000000..8dad09b --- /dev/null +++ b/MuckyBasic/Matrix.cpp @@ -0,0 +1,450 @@ +#include "always.h" +#include "matrix.h" + + + +// +// OPTIMISE THIS AT SOME POINT MARK! 'roll' AND 'pitch' ARE NEARLY ALWAYS 0! +// + +void MATRIX_calc(float matrix[9], float yaw, float pitch, float roll) +{ + float cy, cp, cr; + float sy, sp, sr; + + sy = sinf(yaw); + sp = sinf(pitch); + sr = sinf(roll); + + cy = cosf(yaw); + cp = cosf(pitch); + cr = cosf(roll); + + // + // Jan I trust you... but only becuase I've already seen it working! + // + + matrix[0] = cy * cr + sy * sp * sr; + matrix[3] = cy * sr - sy * sp * cr; + matrix[6] = sy * cp; + matrix[1] = -cp * sr; + matrix[4] = cp * cr; + matrix[7] = sp; + matrix[2] = -sy * cr + cy * sp * sr; + matrix[5] = -sy * sr - cy * sp * cr; + matrix[8] = cy * cp; +} + +void MATRIX_calc_arb( + float matrix[9], + float ux, + float uy, + float uz, + float angle) +{ + float sa = sinf(angle); + float ca = cosf(angle); + + float ux2 = ux*ux; + float uy2 = uy*uy; + float uz2 = uz*uz; + + float uxuy = ux*uy; + float uxuz = ux*uz; + float uyuz = uy*uz; + + matrix[0] = ux2 + ca*(1 - ux2); + + matrix[1] = uxuy*(1 - ca) - uz*sa; + + matrix[2] = uxuz*(1 - ca) + uy*sa; + + matrix[3] = uxuy*(1 - ca) + uz*sa; + + matrix[4] = uy2 + ca*(1 - uy2); + + matrix[5] = uyuz*(1 - ca) - ux*sa; + + matrix[6] = uxuz*(1 - ca) - uy*sa; + + matrix[7] = uy*uz*(1 - ca) + ux*sa; + + matrix[8] = uz2 + ca*(1 - uz2); + +} + + +void MATRIX_vector(float vector[3], float yaw, float pitch) +{ + float cy, cp; + float sy, sp; + + sy = sin(yaw); + sp = sin(pitch); + + cy = cos(yaw); + cp = cos(pitch); + + vector[0] = sy * cp; + vector[1] = sp; + vector[2] = cy * cp; +} + +void MATRIX_skew(float matrix[9], float skew, float zoom, float scale) +{ + // + // Squish up the matrix according to the aspect ratio of the screen. + // + + matrix[0] = matrix[0] * skew; + matrix[1] = matrix[1] * skew; + matrix[2] = matrix[2] * skew; + + // + // Create a lens by multiplying the x and y rows by the zoom factor... + // + + matrix[0] = zoom * matrix[0]; + matrix[1] = zoom * matrix[1]; + matrix[2] = zoom * matrix[2]; + + matrix[3] = zoom * matrix[3]; + matrix[4] = zoom * matrix[4]; + matrix[5] = zoom * matrix[5]; + + // + // Scale the whole matrix. + // + + matrix[0] *= scale; + matrix[1] *= scale; + matrix[2] *= scale; + matrix[3] *= scale; + matrix[4] *= scale; + matrix[5] *= scale; + matrix[6] *= scale; + matrix[7] *= scale; + matrix[8] *= scale; +} + + +void MATRIX_3x3mul(float a[9], float m[9], float n[9]) +{ + float result[9]; + + result[0] = m[0] * n[0] + m[1] * n[3] + m[2] * n[6]; + result[1] = m[0] * n[1] + m[1] * n[4] + m[2] * n[7]; + result[2] = m[0] * n[2] + m[1] * n[5] + m[2] * n[8]; + + result[3] = m[3] * n[0] + m[4] * n[3] + m[5] * n[6]; + result[4] = m[3] * n[1] + m[4] * n[4] + m[5] * n[7]; + result[5] = m[3] * n[2] + m[4] * n[5] + m[5] * n[8]; + + result[6] = m[6] * n[0] + m[7] * n[3] + m[8] * n[6]; + result[7] = m[6] * n[1] + m[7] * n[4] + m[8] * n[7]; + result[8] = m[6] * n[2] + m[7] * n[5] + m[8] * n[8]; + + a[0] = result[0]; + a[1] = result[1]; + a[2] = result[2]; + + a[3] = result[3]; + a[4] = result[4]; + a[5] = result[5]; + + a[6] = result[6]; + a[7] = result[7]; + a[8] = result[8]; +} + + +// +// Rotates the matrix by angle. You don't have to pass the 3rd row of the +// matrix, because it will be unchanged. +// + +#define MATRIX_ROTATE_ABOUT_Z(ax, ay, az, bx, by, bz, cx, cy, cz, angle) \ +{ \ + float c = cos(angle); \ + float s = sin(angle); \ + \ + float px; \ + float py; \ + float pz; \ + \ + float qx; \ + float qy; \ + float qz; \ + \ + if (angle) \ + { \ + px = c * (ax) + s * (bx); \ + py = c * (ay) + s * (by); \ + pz = c * (az) + s * (bz); \ + \ + qx = -s * (ax) + c * (bx); \ + qy = -s * (ay) + c * (by); \ + qz = -s * (az) + c * (bz); \ + \ + (ax) = px; (ay) = py; (az) = pz; \ + (bx) = qx; (by) = qy; (bz) = qz; \ + } \ +} + + + +void MATRIX_rotate_about_its_x(float *matrix, float angle) +{ + MATRIX_ROTATE_ABOUT_Z( + matrix[1], matrix[4], matrix[7], + matrix[2], matrix[5], matrix[8], + matrix[0], matrix[3], matrix[6], + -angle); +} + + +void MATRIX_rotate_about_its_y(float *matrix, float angle) +{ + MATRIX_ROTATE_ABOUT_Z( + matrix[2], matrix[5], matrix[8], + matrix[0], matrix[3], matrix[6], + matrix[1], matrix[4], matrix[7], + -angle); +} + + +void MATRIX_rotate_about_its_z(float *matrix, float angle) +{ + MATRIX_ROTATE_ABOUT_Z( + matrix[0], matrix[3], matrix[6], + matrix[1], matrix[4], matrix[7], + matrix[2], matrix[5], matrix[8], + -angle); +} + + +#define MATRIX_FA_VECTOR_TOO_SMALL (0.001F) +#define MATRIX_FA_ANGLE_TOO_SMALL (PI * 2.0F / 180.0F) + +Direction MATRIX_find_angles_old(float matrix[9]) +{ + float x; + float y; + float z; + float xz; + + Direction ans; + + // + // Look from above at the z-vector to work out the yaw. + // + + x = matrix[6]; + y = matrix[7]; + z = matrix[8]; + + if (fabsf(x) + fabsf(z) < MATRIX_FA_VECTOR_TOO_SMALL) + { + // + // Try using the x-vector instead. + // + + float x1 = matrix[0]; + float y1 = matrix[1]; + float z1 = matrix[2]; + + ans.yaw = atan2f(-z1, x1); + + //ans.yaw = 0.0F; + } + else + { + ans.yaw = atan2f(x, z); + } + + // + // Look down the x vector to at the z-vector to work out the pitch. + // + + xz = sqrtf(x*x + z*z); + + if (fabsf(xz) + fabsf(y) < MATRIX_FA_VECTOR_TOO_SMALL) + { + if (y < 0) {ans.pitch = -PI;} else {ans.pitch = +PI;} + } + else + { + ans.pitch = atan2(y, xz); + } + + // + // Now... matrix[4] = cos(pitch) * cos(roll) + // matrix[1] = -cos(pitch) * sin(roll) + // + // so... cos(roll) = matrix[4] / cos(pitch) + // sin(roll) = matrix[1] / -cos(pitch) + // + + float cos_roll; + float sin_roll; + float cos_pitch; + + cos_pitch = cosf(ans.pitch); + + if (fabsf(cos_pitch) < MATRIX_FA_ANGLE_TOO_SMALL) + { + ans.roll = 0.0F; + } + else + { + cos_roll = matrix[4] / cos_pitch; + sin_roll = matrix[1] / -cos_pitch; + + ans.roll = atan2f(sin_roll, cos_roll); + } + + return ans; +} + + + +Direction MATRIX_find_angles(float matrix[9]) +{ + Direction ans; + + // + // matrix[7] is the sin(pitch) + // + + ans.pitch = asinf(matrix[7]); + + // + // Work out yaw differently depending on how much we are looking + // down or up. + // + + if (fabsf(ans.pitch) > (PI / 4.0F)) + { + if (fabsf(matrix[0]) + fabsf(matrix[2]) < 0.1F) + { + } + + ans.yaw = atan2f(matrix[0], matrix[2]) - (PI / 2.0F); + } + else + { + ans.yaw = atan2f(matrix[6], matrix[8]); + } + + // + // Now... matrix[4] = cos(pitch) * cos(roll) + // matrix[1] = -cos(pitch) * sin(roll) + // + // so... cos(roll) = matrix[4] / cos(pitch) + // sin(roll) = matrix[1] / -cos(pitch) + // + + float cos_roll; + float sin_roll; + float cos_pitch; + + cos_pitch = cosf(ans.pitch); + + if (fabsf(cos_pitch) < 0.0001F) + { + ans.roll = 0.0F; + } + else + { + cos_roll = matrix[4] / cos_pitch; + sin_roll = matrix[1] / -cos_pitch; + + ans.roll = atan2f(sin_roll, cos_roll); + } + + return ans; +} + + +void MATRIX_scale(float matrix[9], float mulby) +{ + matrix[0] *= mulby; + matrix[1] *= mulby; + matrix[2] *= mulby; + matrix[3] *= mulby; + matrix[4] *= mulby; + matrix[5] *= mulby; + matrix[6] *= mulby; + matrix[7] *= mulby; + matrix[8] *= mulby; +} + + +void MATRIX_construct(float matrix[9], float dx, float dy, float dz) +{ + float cx; + float cy; + float cz; + float len; + float overlen; + + len = sqrtf(dx*dx + dy*dy + dz*dz); + overlen = 1.0F / len; + + dx *= overlen; + dy *= overlen; + dz *= overlen; + + // + // We've got the z-row of the matrix now. + // + + matrix[6] = dx; + matrix[7] = dy; + matrix[8] = dz; + + cx = 0.0F; + cy = 1.0F; + cz = 0.0F; + + matrix[0] = cy*dz - cz*dy; + matrix[1] = cz*dx - cx*dz; + matrix[2] = cx*dy - cy*dx; + + len = + matrix[0]*matrix[0] + + matrix[1]*matrix[1] + + matrix[2]*matrix[2]; + + if (len < 0.001F) + { + // + // Oh dear... too small! + // + + MATRIX_calc( + matrix, + 0.0F, + -PI * 0.5F, + 0.0F); + + return; + } + + MATRIX_NORMALISE( + matrix[0], + matrix[1], + matrix[2]); + + matrix[3] = -matrix[1]*matrix[8] + matrix[2]*matrix[7]; + matrix[4] = -matrix[2]*matrix[6] + matrix[0]*matrix[8]; + matrix[5] = -matrix[0]*matrix[7] + matrix[1]*matrix[6]; + + MATRIX_NORMALISE( + matrix[3], + matrix[4], + matrix[5]); + + +} + diff --git a/MuckyBasic/Matrix.h b/MuckyBasic/Matrix.h new file mode 100644 index 0000000..f7f813b --- /dev/null +++ b/MuckyBasic/Matrix.h @@ -0,0 +1,167 @@ +// +// Matrix stuff... +// + +#ifndef _MATRIX_ +#define _MATRIX_ + +// +// ALL ANGLES ARE IN RADIANS. +// + +// +// Fills in the matrix appropriately given the three angles (yaw, pitch, roll) +// for the eye along the z-axis. +// + +void MATRIX_calc(float matrix[9], float yaw, float pitch, float roll); + +// +// Makes a rotation matrix that rotates 'angle' radians about thie given unit vector +// + +void MATRIX_calc_arb( + float matrix[9], + float ux, + float uy, + float uz, + float angle); + +// +// Calculates a vector from yaw and pitch... +// + +void MATRIX_vector(float vector[3], float yaw, float pitch); + +// +// Skews the view matrix so that it is correct for 3d clipping. +// +// The skew value should be one over the horizontal view-window resolution +// divided by the vertical view-window resolution. +// +// The x and y vectors are multiplied by the zoom. +// +// The whole matrix is scaled by scale. +// + +void MATRIX_skew(float matrix[9], float skew, float zoom, float scale); + + +// +// Normalises the vector. +// + +#define MATRIX_NORMALISE(x,y,z) \ +{ \ + float len2; \ + float len; \ + float overlen; \ + \ + len2 = (x)*(x) + (y)*(y) + (z)*(z); \ + len = sqrtf(len2); \ + overlen = 1.0F / len; \ + \ + (x) *= overlen; \ + (y) *= overlen; \ + (z) *= overlen; \ +} + + +// +// Multiplies points x,y,z by matrix m. +// + +#define MATRIX_MUL(m,x,y,z) \ +{ \ + float xnew, ynew, znew; \ + \ + xnew = (x) * (m)[0]; \ + ynew = (x) * (m)[3]; \ + znew = (x) * (m)[6]; \ + \ + xnew += (y) * (m)[1]; \ + ynew += (y) * (m)[4]; \ + znew += (y) * (m)[7]; \ + \ + xnew += (z) * (m)[2]; \ + ynew += (z) * (m)[5]; \ + znew += (z) * (m)[8]; \ + \ + (x) = xnew; (y) = ynew; (z) = znew; \ +} + + +// +// Multiplies points x,y,z by the transpose of matrix m. +// + +#define MATRIX_MUL_BY_TRANSPOSE(m,x,y,z) \ +{ \ + float xnew, ynew, znew; \ + \ + xnew = (x) * (m)[0]; \ + ynew = (x) * (m)[1]; \ + znew = (x) * (m)[2]; \ + \ + xnew += (y) * (m)[3]; \ + ynew += (y) * (m)[4]; \ + znew += (y) * (m)[5]; \ + \ + xnew += (z) * (m)[6]; \ + ynew += (z) * (m)[7]; \ + znew += (z) * (m)[8]; \ + \ + (x) = xnew; (y) = ynew; (z) = znew; \ +} + +// +// Multiplies two 3x3 together. A = MN. +// + +void MATRIX_3x3mul(float a[9], float m[9], float n[9]); + +// +// Transposes the matrix m. +// + +#define MATRIX_TRANSPOSE(m) {SWAP_FL(m[1], m[3]); SWAP_FL(m[2], m[6]); SWAP_FL(m[5], m[7]);} + +// +// Rotates a matrix about its x,y or z vector. +// + +void MATRIX_rotate_about_its_x(float *matrix, float angle); +void MATRIX_rotate_about_its_y(float *matrix, float angle); +void MATRIX_rotate_about_its_z(float *matrix, float angle); + +// +// Convert a matrix into its equivalent yaw, pitch and roll. +// + +Direction MATRIX_find_angles(float matrix[9]); + + +// +// Scales the given vector. +// + +void MATRIX_scale(float matrix[9], float mulby); + + +// +// Constructs an orthonormal matrix from a vector whose [6][7][8] is the normalised +// vector (dx,dy,dz). It return a matrix without any 'roll'. (dx,dy,dz) does not +// have to be normalised. +// + +void MATRIX_construct(float matrix[9], float dx, float dy, float dz); + + +#endif + + + + + + + diff --git a/MuckyBasic/Tga.cpp b/MuckyBasic/Tga.cpp new file mode 100644 index 0000000..97107b3 --- /dev/null +++ b/MuckyBasic/Tga.cpp @@ -0,0 +1,343 @@ +// +// Loads in 32-bit RGBA uncompressed TGAs. +// + +#include "always.h" +#include "tga.h" + + + +TGA_Info TGA_load( + const CBYTE *file, + SLONG max_width, + SLONG max_height, + TGA_Pixel *data) +{ + SLONG i; + SLONG j; + + UBYTE red; + UBYTE green; + UBYTE blue; + + SLONG tga_width; + SLONG tga_height; + SLONG tga_pixel_depth; + SLONG tga_image_type; + SLONG tga_id_length; + + UBYTE header[18]; + UBYTE rubbish; + UBYTE no_alpha; + + FILE *handle; + + TGA_Info ans; + + // + // Open the file. + // + + handle = fopen(file, "rb"); + + if (handle == NULL) + { + TRACE("Could not open TGA file %s", file); + ans.valid = FALSE; + return ans; + } + + // + // Read the header. + // + + if (fread(header, sizeof(UBYTE), 18, handle) != 18) goto file_error; + + // + // Extract info from the header. + // + + tga_id_length = header[0x0]; + tga_image_type = header[0x2]; + tga_width = header[0xc] + header[0xd] * 256; + tga_height = header[0xe] + header[0xf] * 256; + tga_pixel_depth = header[0x10]; + + // + // Is this a valid tga file? + // + + ans.valid = FALSE; + ans.width = tga_width; + ans.height = tga_height; + ans.flag = 0; + + if (tga_image_type != 2) + { + TRACE("Tga must be true colour and uncompressed.\n"); + fclose(handle); + return ans; + } + + if (tga_pixel_depth != 32 && tga_pixel_depth != 24) + { + TRACE("Tga must be 32-bit or 24-bit (24-bit + 8-bit alpha channel)\n"); + fclose(handle); + return ans; + } + + if (tga_width > max_width || + tga_height > max_height) + { + TRACE("Invalid dimensions:\n\tWanted <= %d x %d\n\tGot %d x %d\n", max_width, max_height, tga_width, tga_height); + fclose(handle); + return ans; + } + + // + // The tga file is valid... + // + + ans.valid = TRUE; + + // + // Skip past the image identification field. + // + + for (i = 0; i < tga_id_length; i++) + { + if (fread(&rubbish, sizeof(UBYTE), 1, handle) != 1) goto file_error; + } + + // + // Load in the data upside down (because the TGA's themselves are stored upside down!) + // + + if (tga_pixel_depth == 32) + { + for (i = tga_height - 1; i >= 0; i--) + { + if (fread(data + tga_width * i, sizeof(TGA_Pixel), tga_width, handle) != tga_width) goto file_error; + } + + no_alpha = FALSE; + } + else + { + // + // We have to load a pixel in at a time to add the NULL alpha channel. + // + + for (i = tga_height - 1; i >= 0; i--) + { + for (j = 0; j < tga_width; j++) + { + if (fread(&blue, sizeof(UBYTE), 1, handle) != 1) goto file_error; + if (fread(&green, sizeof(UBYTE), 1, handle) != 1) goto file_error; + if (fread(&red, sizeof(UBYTE), 1, handle) != 1) goto file_error; + + data[i * tga_width + j].red = red; + data[i * tga_width + j].green = green; + data[i * tga_width + j].blue = blue; + data[i * tga_width + j].alpha = 255; + } + } + + no_alpha = TRUE; + } + + fclose(handle); + + // + // Loaded in the tga. Sets the flags- is it grayscale? + // + + if (!no_alpha) + { + ans.flag |= TGA_FLAG_ONE_BIT_ALPHA; + + for (i = 0; i < tga_width * tga_height; i++) + { + if (data[i].alpha != 255) + { + // + // Found alpha channel data. + // + + ans.flag |= TGA_FLAG_CONTAINS_ALPHA; + + if (ans.flag != 0) + { + ans.flag &= ~TGA_FLAG_ONE_BIT_ALPHA; + + break; + } + } + } + + if (!(ans.flag & TGA_FLAG_CONTAINS_ALPHA)) + { + ans.flag &= ~TGA_FLAG_ONE_BIT_ALPHA; + } + } + + // + // Is it grayscale? + // + + ans.flag |= TGA_FLAG_GRAYSCALE; + + for (i = 0; i < tga_width * tga_height; i++) + { + if (data[i].red != data[i].green || + data[i].red != data[i].blue || + data[i].green != data[i].blue) + { + ans.flag &= ~TGA_FLAG_GRAYSCALE; + + break; + } + } + + return ans; + + file_error:; + + // + // Error! + // + + TRACE("File error loading TGA file %s\n", file); + fclose(handle); + ans.valid = FALSE; + + return ans; +} + + + + + + + + +UBYTE TGA_header[18] = +{ + 0, 0, 2, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 1, // Width LSB:MSB + 0, 1, // Height LSB:MSB + 24, // Pixel depth + 0 +}; + +void TGA_save( + const CBYTE *file, + SLONG width, + SLONG height, + TGA_Pixel *data, + SLONG contains_alpha) +{ + SLONG x; + SLONG y; + + SLONG num_pixels; + UBYTE header[18]; + SLONG bpp; + + FILE *handle; + + handle = fopen(file, "wb"); + + if (handle == NULL) + { + TRACE("Cannot open TGA file %s\n", file); + + return; + } + + // + // Create the header. + // + + SLONG i; + + for (i = 0; i < 18; i++) + { + header[i] = TGA_header[i]; + } + + header[0xc] = width & 0xff; + header[0xd] = width >> 8; + header[0xe] = height & 0xff; + header[0xf] = height >> 8; + + header[0x10] = (contains_alpha) ? 32 : 24; + + // + // Write out the header. + // + + fwrite(&header, sizeof(UBYTE), 18, handle); + + // + // Write out the pixel data. + // + + for (y = height - 1; y >= 0; y--) + for (x = 0; x < width; x++) + { + if (contains_alpha) + { + fwrite(&data[x + y * width].alpha, sizeof(UBYTE), 1, handle); + } + + fwrite(&data[x + y * width].blue, sizeof(UBYTE), 1, handle); + fwrite(&data[x + y * width].green, sizeof(UBYTE), 1, handle); + fwrite(&data[x + y * width].red, sizeof(UBYTE), 1, handle); + } + + fclose(handle); +} + + +SLONG TGA_colour(TGA_Pixel tp) +{ + if (abs(tp.red - tp.green) < 24 && + abs(tp.red - tp.blue ) < 24 && + abs(tp.green - tp.blue ) < 24) + { + // + // All the colours are roughly in the same proportions. + // The colour is a shade of grey. + // + + if (tp.red < 64) {return TGA_COLOUR_BLACK;} + if (tp.red < 192) {return TGA_COLOUR_GREY ;} + + return TGA_COLOUR_WHITE; + } + + if (tp.red > tp.green && tp.green > tp.blue && tp.blue < (tp.red >> 1)) + { + // + // Red green blue in descending order and not much blue. + // This must be a brown pixel. + // + + return TGA_COLOUR_BROWN; + } + + if (tp.red > (tp.green << 1) && tp.red > (tp.blue << 1)) + { + return TGA_COLOUR_RED; + } + + if (tp.green > (tp.red << 1) && tp.red > (tp.blue << 1)) + { + return TGA_COLOUR_GREEN; + } + + return TGA_COLOUR_DONTKNOW; +} diff --git a/MuckyBasic/Tga.h b/MuckyBasic/Tga.h new file mode 100644 index 0000000..8361167 --- /dev/null +++ b/MuckyBasic/Tga.h @@ -0,0 +1,80 @@ +// +// Loads in 32-bit RGBA uncompressed TGAs. +// + +#ifndef _TGA_ +#define _TGA_ + + +// +// The format of a TGA pixel. +// + +typedef struct +{ + UBYTE blue; + UBYTE green; + UBYTE red; + UBYTE alpha; + +} TGA_Pixel; + +// +// Info describing the tga. +// + +#define TGA_FLAG_CONTAINS_ALPHA (1 << 0) +#define TGA_FLAG_ONE_BIT_ALPHA (1 << 1) // Alpha is only 255 or 0 +#define TGA_FLAG_GRAYSCALE (1 << 2) // For all pixels r == g == b. + +typedef struct +{ + SLONG valid; + SLONG width; + SLONG height; + ULONG flag; + +} TGA_Info; + +// +// If the width and height of the tga exceed the maximums, then the tga is not loaded. +// + +TGA_Info TGA_load( + const CBYTE *file, + SLONG max_width, + SLONG max_height, + TGA_Pixel *data); + + +// +// Saves out a tga. +// + +void TGA_save( + const CBYTE *file, + SLONG width, + SLONG height, + TGA_Pixel *data, + SLONG contains_alpha); // FALSE => Save without the alpha data. + + + +// +// Returns the colour of the given pixel. +// + +#define TGA_COLOUR_DONTKNOW 0 +#define TGA_COLOUR_BLACK 1 +#define TGA_COLOUR_GREEN 2 +#define TGA_COLOUR_BROWN 3 +#define TGA_COLOUR_WHITE 4 +#define TGA_COLOUR_RED 5 +#define TGA_COLOUR_GREY 6 + +SLONG TGA_colour(TGA_Pixel tp); + + + + +#endif diff --git a/MuckyBasic/cg.cpp b/MuckyBasic/cg.cpp new file mode 100644 index 0000000..4470e29 --- /dev/null +++ b/MuckyBasic/cg.cpp @@ -0,0 +1,2727 @@ +// +// The code generator. Converts the output of the parse into +// an executable. +// + +#include "always.h" +#include "cg.h" +#include "lex.h" +#include "link.h" +#include "ml.h" +#include "parse.h" +#include "sysvar.h" +#include "st.h" + + + +// +// The result of code generation. +// + +CBYTE *CG_output; +SLONG CG_num_errors; +SLONG CG_num_warnings; + +// +// The instructions +// + +#define CG_MAX_INSTRUCTIONS 65536 + +SLONG CG_instruction[CG_MAX_INSTRUCTIONS]; +SLONG CG_instruction_upto; + + +// +// The line we are currently generating code for. +// + +SLONG CG_generating_line; + + + + +// +// The functions. +// + +typedef struct +{ + CBYTE *name; // The function name... + SLONG debug_name; // Index into the debug data. + SLONG num_args; + SLONG arg_upto; + SLONG line; // The entrypoint of the function. + SLONG endline; // The last line of the function. + SLONG num_locals; // How many of the args are actually locals! + +} CG_Func; + +#define CG_MAX_FUNCS 4096 + +CG_Func CG_func[CG_MAX_FUNCS]; +SLONG CG_func_upto; + + + +// +// For each line of code. +// + +typedef struct +{ + SLONG code; // Index into the instruction array. Where each line's code is. + +} CG_Line; + +#define CG_MAX_LINES 16384 + +CG_Line CG_line[CG_MAX_LINES]; +SLONG CG_line_upto; + + +// +// Line numbers that must be converted to instruction +// indices. +// + +#define CG_FORWARD_GOTO_TYPE_GOTO 0 +#define CG_FORWARD_GOTO_TYPE_GOSUB 1 +#define CG_FORWARD_GOTO_TYPE_CALL 2 + +typedef struct +{ + SLONG type; + SLONG instruction; + +} CG_Forward_goto; + +#define CG_MAX_FORWARD_GOTOS 4096 + +CG_Forward_goto CG_forward_goto[CG_MAX_FORWARD_GOTOS]; +SLONG CG_forward_goto_upto; + + +// +// Single-line IF statements. +// + +typedef struct +{ + SLONG ifcode; + SLONG instruction; // The instruction containing the forward jump of the IF condition that jumps over the THEN statement code. + +} CG_If; + +#define CG_MAX_IFS_PER_LINE 256 + +CG_If CG_if[CG_MAX_IFS_PER_LINE]; +SLONG CG_if_upto; + +// +// Multi-line IF statements. +// + +#define CG_MIF_FLAG_FOUND_MELSE (1 << 0) +#define CG_MIF_FLAG_FOUND_MENDIF (1 << 1) + +typedef struct +{ + ULONG flag; + SLONG iffalsejump; + SLONG afterthenjump; + +} CG_Mif; + +#define CG_MAX_MIFS 4096 + +CG_Mif CG_mif[CG_MAX_MIFS]; +SLONG CG_mif_upto; + + + +// +// All the FOR-NEXT loops... +// + +#define CG_FOR_TYPE_ANON 0 // No lvalue associated with this FOR-NEXT loop. +#define CG_FOR_TYPE_LVALUE 1 + +typedef struct +{ + SLONG type; + PARSE_Node *lvalue; // The lvalue that this FOR-NEXT loop is acting on + SLONG loopto; // The instruction that corresponding NEXT statements should jump to. + SLONG overstep; // The instruction which should contain the address of the instruction after the STEP statement. + SLONG forcode; // The unique code identifying this FOR loop. + SLONG afternext; // The instruction which should contain the address of the instruction after the NEXT statement. + +} CG_For; + +#define CG_MAX_FORS 4096 + +CG_For CG_for[CG_MAX_FORS]; +SLONG CG_for_upto; + +// +// The while loops. +// + +#define CG_WHILE_FLAG_FOUND_LOOP (1 << 0) + +typedef struct +{ + SLONG flag; + SLONG iffalsejump; + SLONG whilecode; + SLONG loopto; + +} CG_While; + +#define CG_MAX_WHILES 4096 + +CG_While CG_while[CG_MAX_WHILES]; +SLONG CG_while_upto; + +// +// The number of globals used by the program. +// + +SLONG CG_global_upto; + +// +// The number of field_ids used so far. +// + +SLONG CG_field_id_upto; + + +// +// The string table. +// + +SLONG CG_data_table_max; +UBYTE *CG_data_table; +SLONG CG_data_table_upto; + +// +// The function we are currently generating code for. +// + +SLONG CG_in_function; + + +// +// Every jump instruction's target address. +// + +typedef struct +{ + SLONG instruction; + +} CG_Jump; + +#define CG_MAX_JUMPS 16384 + +CG_Jump CG_jump[CG_MAX_JUMPS]; +SLONG CG_jump_upto; + + +// +// Every reference to a global. +// + +typedef struct +{ + SLONG instruction; + +} CG_Globalref; + +#define CG_MAX_GLOBALREFS 16384 + +CG_Globalref CG_globalref[CG_MAX_GLOBALREFS]; +SLONG CG_globalref_upto; + + +// +// Every refrence to a field. +// + +typedef struct +{ + SLONG instruction; + +} CG_Fieldref; + +#define CG_MAX_FIELDREFS 16384 + +CG_Fieldref CG_fieldref[CG_MAX_FIELDREFS]; +SLONG CG_fieldref_upto; + + +// +// Every reference to an undefined function. +// + +typedef struct +{ + SLONG name; // Index into the debug data array. + SLONG instruction; + +} CG_Undefref; + +#define CG_MAX_UNDEFREFS 16384 + +CG_Undefref CG_undefref[CG_MAX_UNDEFREFS]; +SLONG CG_undefref_upto; + + + +// +// Every reference into the data table. +// + +typedef struct +{ + SLONG instruction; + +} CG_Datatableref; + +#define CG_MAX_DATATABLEREFS 16384 + +CG_Datatableref CG_datatableref[CG_MAX_DATATABLEREFS]; +SLONG CG_datatableref_upto; + + +// +// Debug data. +// + +#define CG_MAX_DEBUG_DATA 65536 + +CBYTE CG_debug_data[CG_MAX_DEBUG_DATA]; +SLONG CG_debug_data_upto; + + + + +// +// Adds a string to the debug data and returns +// an index to it. +// + +SLONG CG_add_string_to_debug_data(CBYTE *string) +{ + SLONG length = strlen(string) + 1; // + 1 to include the terminating NULL + + if (CG_debug_data_upto + length > CG_MAX_DEBUG_DATA) + { + // + // ERROR! + // + + ASSERT(0); + } + + SLONG ans = CG_debug_data_upto; + + strcpy(CG_debug_data + CG_debug_data_upto, string); + + CG_debug_data_upto += length; + + return ans; + +} + + + + + + +// +// Adds a string to the string table and returns the index +// into the string table for where it was stored. +// + +SLONG CG_add_string(CBYTE *string) +{ + SLONG length = strlen(string) + 1; // + 1 to include the terminating NULL. + + if (CG_data_table_upto + length > CG_data_table_max) + { + CG_data_table_max *= 2; + CG_data_table = (UBYTE *) realloc(CG_data_table, sizeof(UBYTE) * CG_data_table_max); + } + + SLONG ans = CG_data_table_upto; + + strcpy(((CBYTE *) CG_data_table) + CG_data_table_upto, string); + + CG_data_table_upto += length; + + return ans; +} + + + +// +// The callback function for adding labels and variables to the +// symbol table. +// + +SLONG CG_callback_add_labels_and_variables(PARSE_Node *pn) +{ + switch(pn->type) + { + case PARSE_NODE_TYPE_LABEL: + + if (ST_find(pn->label)) + { + // + // ERROR! + // + + ASSERT(0); + + return FALSE; + } + else + { + ST_add(ST_TABLE_GLOBAL, pn->label, CG_generating_line, 0); + } + + break; + + case PARSE_NODE_TYPE_VAR_ADDRESS: + case PARSE_NODE_TYPE_VAR_VALUE: + + if (ST_find(pn->variable)) + { + // + // We've already added this variable to the symbol table + // and assigned it a 'global' memory number. + // + } + else + { + ST_add(ST_TABLE_GLOBAL, pn->variable, CG_global_upto++, 0); + } + + break; + + case PARSE_NODE_TYPE_FIELD: + + if (ST_find(pn->field)) + { + // + // Already assigned this structure field a field_id. + // + } + else + { + ST_add(ST_TABLE_GLOBAL, pn->field, CG_field_id_upto++, 0); + } + + break; + + case PARSE_NODE_TYPE_FUNCTION: + + if (CG_in_function) + { + // + // ERROR! Two function definitions in a row without an ENDFUNC. + // + + ASSERT(0); + } + + CG_in_function = CG_func_upto; + + // + // Allocate a new function structure. + // + + ASSERT(WITHIN(CG_func_upto, 1, CG_MAX_FUNCS - 1)); + + CG_func[CG_func_upto].name = pn->variable; + CG_func[CG_func_upto].num_args = 0; + CG_func[CG_func_upto].line = CG_generating_line; + + // + // Add the function to the string table. + // + + ST_add(ST_TABLE_GLOBAL, pn->variable, CG_func_upto, 0); + + CG_func_upto += 1; + + break; + + case PARSE_NODE_TYPE_ARGUMENT: + + // + // We must be inside a function! + // + + if (!CG_in_function) + { + // + // ERROR! + // + + ASSERT(0); + } + + ASSERT(CG_in_function == CG_func_upto - 1); + + // + // Add this argument to the local variables for this function. + // + + if (ST_find(pn->variable)) + { + if (ST_found_table != ST_TABLE_LOCAL) + { + // + // Add this variable to the local symbol table. + // + + ST_add(ST_TABLE_LOCAL, pn->variable, 0, 0); + + CG_func[CG_in_function].num_args += 1; + } + else + if (ST_found_table == ST_TABLE_LOCAL) + { + // + // ERROR! Mutliple defined arguements! + // + + ASSERT(0); + } + } + else + { + // + // Add this variable to the local symbol table. + // + + ST_add(ST_TABLE_LOCAL, pn->variable, 0, 0); + + CG_func[CG_in_function].num_args += 1; + } + + break; + + case PARSE_NODE_TYPE_ENDFUNC: + + // + // Remember the line where this function ends. + // + + ASSERT(WITHIN(CG_in_function, 1, CG_MAX_FUNCS - 1)); + + CG_func[CG_in_function].endline = CG_generating_line; + + // + // Not in a function any more. + // + + CG_in_function = FALSE; + + // + // We've lost all the symbols in the local symbol table. + // + + ST_clear(ST_TABLE_LOCAL); + + break; + + case PARSE_NODE_TYPE_EXPORT: + + // + // Add this variable (manged with a "->" on the front) to + // the symbol, to denote that it should be exported in the + // object file. + // + + { + CBYTE export[LEX_MAX_STRING_LENGTH + 2]; + + sprintf(export, "->%s", pn->variable); + + ST_add(ST_TABLE_GLOBAL, export, 0, 0); + } + + break; + + case PARSE_NODE_TYPE_LOCAL: + + if (CG_in_function) + { + // + // Add this local to the function. + // + + ASSERT(WITHIN(CG_in_function, 1, CG_MAX_FUNCS - 1)); + + if (ST_find(pn->variable)) + { + if (ST_found_table == ST_TABLE_LOCAL) + { + // + // ERROR! Multiply defined locals/args + // + + ASSERT(0); + } + else + { + // + // Add this local to the funcion. + // + + CG_func[CG_in_function].num_args += 1; + CG_func[CG_in_function].num_locals += 1; + + // + // Add this variable to the local symbol table. + // + + ST_add(ST_TABLE_LOCAL, pn->variable, 0, 0); + } + } + else + { + // + // Add this local to the funcion. + // + + CG_func[CG_in_function].num_args += 1; + CG_func[CG_in_function].num_locals += 1; + + // + // Add this variable to the local symbol table. + // + + ST_add(ST_TABLE_LOCAL, pn->variable, 0, 0); + } + } + else + { + // + // A local declaration outside of a function + // means that the variable is local to the file. + // Add it to the symbol table with "<-" on the front + // if it. + // + + CBYTE local[LEX_MAX_STRING_LENGTH + 2]; + + sprintf(local, "<-%s", pn->variable); + + ST_add(ST_TABLE_GLOBAL, local, 0, 0); + } + + break; + + default: + break; + } + + return TRUE; +} + + +// +// The code generation callback function. +// + +SLONG CG_callback_generate_code(PARSE_Node *pn) +{ + // + // Always make sure we have 3 SLONGS worth of instructions spare. + // + + if (!WITHIN(CG_instruction_upto, 0, CG_MAX_INSTRUCTIONS - 3)) + { + // + // Out of memory! + // + + return FALSE; + } + + switch(pn->type) + { + case PARSE_NODE_TYPE_NOP: + break; + + case PARSE_NODE_TYPE_EQUALS: + CG_instruction[CG_instruction_upto++] = ML_DO_EQUALS; + break; + + case PARSE_NODE_TYPE_PLUS: + CG_instruction[CG_instruction_upto++] = ML_DO_ADD; + break; + + case PARSE_NODE_TYPE_MINUS: + CG_instruction[CG_instruction_upto++] = ML_DO_MINUS; + break; + + case PARSE_NODE_TYPE_UMINUS: + CG_instruction[CG_instruction_upto++] = ML_DO_UMINUS; + break; + + case PARSE_NODE_TYPE_TIMES: + CG_instruction[CG_instruction_upto++] = ML_DO_TIMES; + break; + + case PARSE_NODE_TYPE_DIVIDE: + CG_instruction[CG_instruction_upto++] = ML_DO_DIVIDE; + break; + + case PARSE_NODE_TYPE_MOD: + CG_instruction[CG_instruction_upto++] = ML_DO_MOD; + break; + + case PARSE_NODE_TYPE_SLUMBER: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_SLUMBER; + CG_instruction[CG_instruction_upto++] = pn->slumber; + break; + + case PARSE_NODE_TYPE_FLUMBER: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_FLUMBER; + ((float *) CG_instruction)[CG_instruction_upto++] = pn->flumber; + break; + + case PARSE_NODE_TYPE_STRING: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_STRCONST; + CG_instruction[CG_instruction_upto++] = CG_add_string(pn->string); + + // + // Remember the reference into the data table. + // + + ASSERT(WITHIN(CG_datatableref_upto, 0, CG_MAX_DATATABLEREFS - 1)); + + CG_datatableref[CG_datatableref_upto++].instruction = CG_instruction_upto - 1; + + break; + + case PARSE_NODE_TYPE_VAR_VALUE: + + if (!ST_find(pn->variable)) + { + ASSERT(0); + } + else + { + SLONG local = (ST_found_table == ST_TABLE_LOCAL); + SLONG quick = (pn->flag & PARSE_NODE_FLAG_EXTRACT); + SLONG instruction; + + // + // Can't be both these types... + // + + if (local) + { + if (quick) + { + instruction = ML_DO_PUSH_LOCAL_QUICK; + } + else + { + instruction = ML_DO_PUSH_LOCAL_VALUE; + } + } + else + { + if (quick) + { + instruction = ML_DO_PUSH_GLOBAL_QUICK; + } + else + { + instruction = ML_DO_PUSH_GLOBAL_VALUE; + } + + // + // Remember the reference to the global. + // + + ASSERT(WITHIN(CG_globalref_upto, 0, CG_MAX_GLOBALREFS - 1)); + + CG_globalref[CG_globalref_upto++].instruction = CG_instruction_upto + 1; + } + + CG_instruction[CG_instruction_upto++] = instruction; + CG_instruction[CG_instruction_upto++] = ST_found_value; + } + + break; + + case PARSE_NODE_TYPE_IF: + + // + // Store where this if instruction is so we can set the + // if condition goto to be after the 'then' code. + // + + ASSERT(WITHIN(CG_if_upto, 0, CG_MAX_IFS_PER_LINE - 1)); + + CG_if[CG_if_upto].ifcode = pn->ifcode; + CG_if[CG_if_upto].instruction = CG_instruction_upto + 1; + + CG_if_upto++; + + CG_instruction[CG_instruction_upto++] = ML_DO_IF_FALSE_GOTO; + CG_instruction[CG_instruction_upto++] = 0; // To be filled in when we get the corresponding PARSE_NODE_TYPE_FAKE_THEN node. + + // + // Remember the jump instruction. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + break; + + case PARSE_NODE_TYPE_FAKE_THEN: + + // + // Look for the corresponding IF. + // + + { + SLONG i; + + for (i = 0; i < CG_if_upto; i++) + { + if (CG_if[i].ifcode == pn->ifcode) + { + // + // Found it! Make the IF_FALSE_GOTO point to the current instruction. + // + + ASSERT(WITHIN(CG_if[i].instruction, 0, CG_instruction_upto - 1)); + + CG_instruction[CG_if[i].instruction] = CG_instruction_upto; + + break; + } + } + + // + // THEN found without matching IF? + // + + ASSERT(i != CG_if_upto); + } + + break; + + case PARSE_NODE_TYPE_FAKE_ELSE: + + // + // Look for the corresponding IF. + // + + { + SLONG i; + + for (i = 0; i < CG_if_upto; i++) + { + if (CG_if[i].ifcode == pn->ifcode) + { + // + // Found it! This IF_FALSE_GOTO instruction must + // jump an instruction further to skip over the + // goto we are just about to put in... + // + + ASSERT(WITHIN(CG_if[i].instruction, 0, CG_instruction_upto - 1)); + + CG_instruction[CG_if[i].instruction] = CG_instruction_upto + 2; + + // + // Insert a GOTO so that the THEN code doesn't + // leak into the ELSE code. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOTO; + CG_instruction[CG_instruction_upto++] = 0; // To be filled in when we get the corresponding PARSE_NODE_TYPE_FAKE_ENDIF node. + + CG_if[i].instruction = CG_instruction_upto - 1; + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + break; + } + } + + // + // ELSE found without matching IF? + // + + ASSERT(i != CG_if_upto); + } + + break; + + case PARSE_NODE_TYPE_FAKE_END_ELSE: + + // + // Look for the corresponding IF. + // + + { + SLONG i; + + for (i = 0; i < CG_if_upto; i++) + { + if (CG_if[i].ifcode == pn->ifcode) + { + // + // Found it! Make the GOTO after the 'THEN' code point to the current instruction. + // + + ASSERT(WITHIN(CG_if[i].instruction, 0, CG_instruction_upto - 1)); + + CG_instruction[CG_if[i].instruction] = CG_instruction_upto; + + break; + } + } + + // + // ENDELSE found without matching IF? + // + + ASSERT(i != CG_if_upto); + + } + + break; + + case PARSE_NODE_TYPE_GOTO: + case PARSE_NODE_TYPE_GOSUB: + + if (!ST_find(pn->label)) + { + // + // ERROR! + // + + ASSERT(0); + + return FALSE; + } + else + { + switch(pn->type) + { + case PARSE_NODE_TYPE_GOTO: CG_instruction[CG_instruction_upto++] = ML_DO_GOTO; break; + case PARSE_NODE_TYPE_GOSUB: CG_instruction[CG_instruction_upto++] = ML_DO_GOSUB; break; + + default: + ASSERT(0); + break; + } + + // + // If this is a backwards goto or gosub then we can put the instruction + // index here. + // + + if (ST_found_value <= CG_generating_line) + { + CG_instruction[CG_instruction_upto++] = CG_line[ST_found_value].code; + } + else + { + // + // The line number to be converted to instruction after code generation. + // + + CG_instruction[CG_instruction_upto++] = ST_found_value; + + // + // Remember all the line numbers we must convert. + // + + ASSERT(WITHIN(CG_forward_goto_upto, 0, CG_MAX_FORWARD_GOTOS - 1)); + + CG_forward_goto[CG_forward_goto_upto].instruction = CG_instruction_upto - 1; + + switch(pn->type) + { + case PARSE_NODE_TYPE_GOTO: CG_forward_goto[CG_forward_goto_upto].type = CG_FORWARD_GOTO_TYPE_GOTO; break; + case PARSE_NODE_TYPE_GOSUB: CG_forward_goto[CG_forward_goto_upto].type = CG_FORWARD_GOTO_TYPE_GOSUB; break; + + default: + ASSERT(0); + break; + } + + CG_forward_goto_upto++; + } + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + } + + break; + + case PARSE_NODE_TYPE_LABEL: + break; + + case PARSE_NODE_TYPE_GT: + CG_instruction[CG_instruction_upto++] = ML_DO_GT; + break; + + case PARSE_NODE_TYPE_LT: + CG_instruction[CG_instruction_upto++] = ML_DO_LT; + break; + + case PARSE_NODE_TYPE_GTEQ: + CG_instruction[CG_instruction_upto++] = ML_DO_GTEQ; + break; + + case PARSE_NODE_TYPE_LTEQ: + CG_instruction[CG_instruction_upto++] = ML_DO_LTEQ; + break; + + case PARSE_NODE_TYPE_AND: + CG_instruction[CG_instruction_upto++] = ML_DO_AND; + break; + + case PARSE_NODE_TYPE_OR: + CG_instruction[CG_instruction_upto++] = ML_DO_OR; + break; + + case PARSE_NODE_TYPE_NOT: + CG_instruction[CG_instruction_upto++] = ML_DO_NOT; + break; + + case PARSE_NODE_TYPE_DOT: + break; + + case PARSE_NODE_TYPE_LOCAL: + + // + // LOCAL statement outside of functions have already been + // handled (they've added their variable with "<-" at the start + // to the symbol table). + // + + if (CG_in_function) + { + // + // There shouldn't already be a local with this name. + // + + ASSERT(!(ST_find(pn->variable) && ST_found_table == ST_TABLE_LOCAL)); + + // + // Add the local to the symbol table. + // + + ST_add(ST_TABLE_LOCAL, pn->variable, CG_func[CG_in_function].arg_upto, 0); + + CG_func[CG_in_function].arg_upto += 1; + } + + break; + + case PARSE_NODE_TYPE_PRINT: + CG_instruction[CG_instruction_upto++] = ML_DO_PRINT; + break; + + case PARSE_NODE_TYPE_ASSIGN: + CG_instruction[CG_instruction_upto++] = ML_DO_ASSIGN; + break; + + case PARSE_NODE_TYPE_VAR_ADDRESS: + + if (!ST_find(pn->variable)) + { + ASSERT(0); + } + else + { + CG_instruction[CG_instruction_upto++] = (ST_found_table == ST_TABLE_LOCAL) ? ML_DO_PUSH_LOCAL_ADDRESS : ML_DO_PUSH_GLOBAL_ADDRESS; + CG_instruction[CG_instruction_upto++] = ST_found_value; + + if (ST_found_table != ST_TABLE_LOCAL) + { + // + // Remember the reference to the global. + // + + ASSERT(WITHIN(CG_globalref_upto, 0, CG_MAX_GLOBALREFS - 1)); + + CG_globalref[CG_globalref_upto++].instruction = CG_instruction_upto - 1; + } + } + + break; + + case PARSE_NODE_TYPE_BOOLEAN: + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_BOOLEAN; + CG_instruction[CG_instruction_upto++] = pn->boolean; + + break; + + case PARSE_NODE_TYPE_SQRT: + CG_instruction[CG_instruction_upto++] = ML_DO_SQRT; + break; + + case PARSE_NODE_TYPE_NEWLINE: + CG_instruction[CG_instruction_upto++] = ML_DO_NEWLINE; + break; + + case PARSE_NODE_TYPE_ABS: + CG_instruction[CG_instruction_upto++] = ML_DO_ABS; + break; + + case PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_FIELD_ADDRESS; + break; + + case PARSE_NODE_TYPE_FIELD: + + if (!ST_find(pn->field)) + { + ASSERT(0); + } + else + { + CG_instruction[CG_instruction_upto++] = ST_found_value; + + // + // Remember the reference to the field. + // + + ASSERT(WITHIN(CG_fieldref_upto, 0, CG_MAX_FIELDREFS - 1)); + + CG_fieldref[CG_fieldref_upto++].instruction = CG_instruction_upto - 1; + } + + break; + + case PARSE_NODE_TYPE_PUSH_FIELD_VALUE: + + if (pn->flag & PARSE_NODE_FLAG_EXTRACT) + { + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_FIELD_QUICK; + } + else + { + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_FIELD_VALUE; + } + + break; + + case PARSE_NODE_TYPE_EXP_LIST: + break; + + case PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_ARRAY_ADDRESS; + CG_instruction[CG_instruction_upto++] = pn->dimensions; + break; + + case PARSE_NODE_TYPE_PUSH_ARRAY_VALUE: + + if (pn->flag & PARSE_NODE_FLAG_EXTRACT) + { + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_ARRAY_QUICK; + } + else + { + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_ARRAY_VALUE; + } + + CG_instruction[CG_instruction_upto++] = pn->dimensions; + + break; + + case PARSE_NODE_TYPE_INPUT: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_INPUT; + break; + + case PARSE_NODE_TYPE_UNDEFINED: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_UNDEFINED; + CG_instruction[CG_instruction_upto++] = 0; + break; + + case PARSE_NODE_TYPE_STATEMENT_LIST: + break; + + case PARSE_NODE_TYPE_EXIT: + CG_instruction[CG_instruction_upto++] = ML_DO_EXIT; + break; + + case PARSE_NODE_TYPE_RETURN: + + if (CG_in_function) + { + ASSERT(WITHIN(CG_in_function, 0, CG_func_upto - 1)); + + if (pn->child1 == NULL) + { + // + // The function doesn't return anything. Make it + // return UNDEFINED. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_UNDEFINED; + CG_instruction[CG_instruction_upto++] = 0; + } + + // + // A return from function rather than a simple GOSUB. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_ENDFUNC; + CG_instruction[CG_instruction_upto++] = CG_func[CG_in_function].num_args; + } + else + { + CG_instruction[CG_instruction_upto++] = ML_DO_RETURN; + + if (pn->child1) + { + // + // ERROR! Only RETURNs inside functions can return values. + // + + ASSERT(0); + } + } + + break; + + case PARSE_NODE_TYPE_XOR: + CG_instruction[CG_instruction_upto++] = ML_DO_XOR; + break; + + case PARSE_NODE_TYPE_FOR: + + // + // This is a forward goto so we skip over the STEP code. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOTO; + CG_instruction[CG_instruction_upto++] = 0; // To be filled in later by the FAKE_ENDFOR parse node. + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + // + // This is where we GOTO to for another iteration. + // + + ASSERT(WITHIN(CG_for_upto, 0, CG_MAX_FORS - 1)); + + CG_for[CG_for_upto].type = CG_FOR_TYPE_ANON; + CG_for[CG_for_upto].lvalue = NULL; + CG_for[CG_for_upto].loopto = CG_instruction_upto; + CG_for[CG_for_upto].overstep = CG_instruction_upto - 1; + CG_for[CG_for_upto].forcode = pn->forcode; + + if (pn->lvalue) + { + CG_for[CG_for_upto].type = CG_FOR_TYPE_LVALUE; + CG_for[CG_for_upto].lvalue = pn->lvalue; + } + + CG_for_upto += 1; + + break; + + case PARSE_NODE_TYPE_FAKE_END_FOR: + + // + // Find the FOR statement corresponding to this ENDFOR node. + // + + { + SLONG i; + + for (i = CG_for_upto - 1; i >= 0; i--) + { + if (CG_for[i].forcode == pn->forcode) + { + ASSERT(WITHIN(CG_for[i].overstep, 0, CG_instruction_upto - 1)); + + CG_instruction[CG_for[i].overstep] = CG_instruction_upto; + + goto found_corresponding_for; + } + } + + ASSERT(0); + + found_corresponding_for:; + } + + break; + + case PARSE_NODE_TYPE_NEXT: + + { + SLONG i; + + for (i = CG_for_upto - 1; i >= 0; i--) + { + if (CG_for[i].forcode == 0) + { + // + // This FOR has alreay been matched by a next... + // + + continue; + } + + if (pn->lvalue == NULL) + { + // + // Match this FOR loop... + // + } + else + { + // + // Only match a FOR loop with the correct variable. + // + + if (CG_for[i].type == CG_FOR_TYPE_LVALUE && PARSE_trees_the_same(CG_for[i].lvalue, pn->lvalue)) + { + // + // This is our FOR loop! + // + } + else + { + // + // This is not our FOR loop. + // + + continue; + } + } + + // + // This is the FOR-LOOP to match up with- free it up. + // + + CG_for[i].forcode = 0; + + // + // Loop back to the increment and condition. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOTO; + CG_instruction[CG_instruction_upto++] = CG_for[i].loopto; + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + // + // Fill in the jump for the condition. + // + + ASSERT(WITHIN(CG_for[i].afternext, 0, CG_instruction_upto - 1)); + + CG_instruction[CG_for[i].afternext] = CG_instruction_upto; + + // + // Get rid of the lvalue node so the tree traversal doesn't + // generate code for it. + // + + pn->lvalue = NULL; + + goto found_matching_for; + } + + // + // ERROR! No matching FOR loop for the NEXT statement. + // + + ASSERT(0); + + found_matching_for:; + } + + break; + + case PARSE_NODE_TYPE_FAKE_FOR_COND: + + // + // Find the FOR statement corresponding to this FOR_COND node. + // + + { + SLONG i; + + for (i = CG_for_upto - 1; i >= 0; i--) + { + if (CG_for[i].forcode == pn->forcode) + { + // + // Generate code to jump to after the NEXT in the + // condition is TRUE. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_IF_TRUE_GOTO; + CG_instruction[CG_instruction_upto++] = 0; + + CG_for[i].afternext = CG_instruction_upto - 1; + + // + // Remember the jump instruction. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + goto found_the_for; + } + } + + // + // ERROR! No matching FOR loop for the NEXT statement. + // + + ASSERT(0); + + found_the_for:; + } + + break; + + case PARSE_NODE_TYPE_NOTEQUAL: + CG_instruction[CG_instruction_upto++] = ML_DO_NOTEQUAL; + break; + + case PARSE_NODE_TYPE_RANDOM: + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_RANDOM_SLUMBER; + break; + + case PARSE_NODE_TYPE_SWAP: + CG_instruction[CG_instruction_upto++] = ML_DO_SWAP; + break; + + case PARSE_NODE_TYPE_MIF: + + // + // Create code to jump over the THEN code if the condition + // code evaluates to FALSE. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_IF_FALSE_GOTO; + CG_instruction[CG_instruction_upto++] = 0; // To be filled in later when we get the MELSE or MENDIF node. + + // + // Remember the jump instruction. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + // + // Create a new entry in the multi-line IF array. + // + + ASSERT(WITHIN(CG_mif_upto, 0, CG_MAX_MIFS - 1)); + + CG_mif[CG_mif_upto].flag = 0; + CG_mif[CG_mif_upto].iffalsejump = CG_instruction_upto - 1; + CG_mif[CG_mif_upto].afterthenjump = 0; + + CG_mif_upto += 1; + + break; + + case PARSE_NODE_TYPE_MELSE: + + // + // An ELSE instruction in a multi-line IF. Match it up with + // the nearest MIF. + // + + { + SLONG i; + + for (i = CG_mif_upto - 1; i >= 0; i--) + { + if (CG_mif[i].flag & CG_MIF_FLAG_FOUND_MENDIF) + { + // + // This MIF has already been matched with an ENDIF. + // + } + else + { + // + // This is our MIF instruction. + // + + if (CG_mif[i].flag & CG_MIF_FLAG_FOUND_MELSE) + { + // + // ERROR! Badly formed, nested multi-line ifs... + // + + ASSERT(0); + } + + // + // Add instructions to jump over the ELSE code to + // the end of the THEN code. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOTO; + CG_instruction[CG_instruction_upto++] = 0; // To be filled in later when we get the MENDIF node. + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + // + // Update the multiline-if structure now we have found the else. + // + + CG_mif[i].flag |= CG_MIF_FLAG_FOUND_MELSE; + CG_mif[i].afterthenjump = CG_instruction_upto - 1; + + // + // Set the target of the IF_FALSE_GOTO jump instruction + // inserted by the MIF node. + // + + ASSERT(WITHIN(CG_mif[i].iffalsejump, 0, CG_instruction_upto - 2)); + + CG_instruction[CG_mif[i].iffalsejump] = CG_instruction_upto; + + goto found_mif_for_melse; + } + } + + // + // ERROR! + // + + ASSERT(0); + + found_mif_for_melse:; + } + + break; + + case PARSE_NODE_TYPE_MENDIF: + + // + // An ENDIF instruction in a multi-line IF. Match it up with + // the nearest MIF. + // + + { + SLONG i; + + for (i = CG_mif_upto - 1; i >= 0; i--) + { + if (CG_mif[i].flag & CG_MIF_FLAG_FOUND_MENDIF) + { + // + // This MIF has already been matched with an ENDIF. + // + } + else + { + CG_mif[i].flag |= CG_MIF_FLAG_FOUND_MENDIF; + + if (CG_mif[i].flag & CG_MIF_FLAG_FOUND_MELSE) + { + // + // Set the target of the jump put in by the MELSE node. + // + + ASSERT(WITHIN(CG_mif[i].afterthenjump, 0, CG_instruction_upto - 2)); + + CG_instruction[CG_mif[i].afterthenjump] = CG_instruction_upto; + } + else + { + // + // Set the target of the jump put in by the MIF node. + // + + ASSERT(WITHIN(CG_mif[i].iffalsejump, 0, CG_instruction_upto - 2)); + + CG_instruction[CG_mif[i].iffalsejump] = CG_instruction_upto; + } + + goto found_mif_for_endif; + } + } + + // + // ERROR! + // + + ASSERT(0); + + found_mif_for_endif:; + } + + break; + + case PARSE_NODE_TYPE_WHILE: + + // + // Create a new entry in the while array. + // + + ASSERT(WITHIN(CG_while_upto, 0, CG_MAX_WHILES - 1)); + + CG_while[CG_while_upto].flag = 0; + CG_while[CG_while_upto].iffalsejump = 0; + CG_while[CG_while_upto].whilecode = pn->whilecode; + CG_while[CG_while_upto].loopto = CG_instruction_upto; + + CG_while_upto += 1; + + break; + + case PARSE_NODE_TYPE_FAKE_WHILE_COND: + + // + // Create code to jump over the body of the While-loop if the condition + // code evaluates to FALSE. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_IF_FALSE_GOTO; + CG_instruction[CG_instruction_upto++] = 0; // To be filled in later when we LOOP node. + + // + // Remember the jump instruction. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + // + // Find our while loop. + // + + { + SLONG i; + + for (i = CG_while_upto - 1; i >= 0; i--) + { + if (CG_while[i].whilecode == pn->whilecode) + { + // + // Found our while loop! + // + + CG_while[i].iffalsejump = CG_instruction_upto - 1; + + goto found_our_while_loop; + } + } + + // + // Oh dear... + // + + ASSERT(0); + + found_our_while_loop:; + } + + break; + + case PARSE_NODE_TYPE_LOOP: + + // + // Look for the nearest unmatched while loop. + // + + { + SLONG i; + + for (i = CG_while_upto - 1; i >= 0; i--) + { + if (CG_while[i].flag & CG_WHILE_FLAG_FOUND_LOOP) + { + // + // Already been matched up. + // + } + else + { + ASSERT(WITHIN(CG_while[i].loopto , 0, CG_instruction_upto - 1)); + ASSERT(WITHIN(CG_while[i].iffalsejump, 0, CG_instruction_upto - 1)); + + CG_while[i].flag |= CG_WHILE_FLAG_FOUND_LOOP; + + // + // Loop back to the beginning of the while loop. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOTO; + CG_instruction[CG_instruction_upto++] = CG_while[i].loopto; + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + // + // Set the target of the jump put in by the WHILE node. + // + + CG_instruction[CG_while[i].iffalsejump] = CG_instruction_upto; + + goto found_while; + } + } + + // + // ERROR! + // + + ASSERT(0); + + found_while:; + } + + break; + + case PARSE_NODE_TYPE_FUNCTION: + + if (CG_in_function) + { + // + // ERROR! + // + + ASSERT(0); + } + else + { + // + // Find our function. + // + + if (!ST_find(pn->variable)) + { + // + // ERROR! + // + + ASSERT(0); + } + else + { + CG_in_function = ST_found_value; + + ASSERT(WITHIN(CG_in_function, 0, CG_func_upto - 1)); + ASSERT(strcmp(CG_func[CG_in_function].name, pn->variable) == 0); + + // + // Code to jump over the body of the function if execution + // leaks down to the function. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOTO; + CG_instruction[CG_instruction_upto++] = CG_func[CG_in_function].endline + 1; + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + + // + // This is a forward goto.. + // + + ASSERT(WITHIN(CG_forward_goto_upto, 0, CG_MAX_FORWARD_GOTOS - 1)); + + CG_forward_goto[CG_forward_goto_upto].type = CG_FORWARD_GOTO_TYPE_GOTO; + CG_forward_goto[CG_forward_goto_upto].instruction = CG_instruction_upto - 1; + + CG_forward_goto_upto++; + + // + // The numbering of our arugments and local variables + // + + CG_func[CG_in_function].arg_upto = 0; + + // + // Enter the function. Easy! + // + + CG_instruction[CG_instruction_upto++] = ML_DO_ENTERFUNC; + CG_instruction[CG_instruction_upto++] = CG_func[CG_in_function].num_args; + } + } + + break; + + case PARSE_NODE_TYPE_ARGUMENT: + + // + // We must be inside a function! + // + + if (!CG_in_function) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // There shouldn't already be a local with this name. + // + + ASSERT(!(ST_find(pn->variable) && ST_found_table == ST_TABLE_LOCAL)); + + // + // Add this argument to the local variables for this function. + // + + ST_add(ST_TABLE_LOCAL, pn->variable, CG_func[CG_in_function].arg_upto, 0); + + CG_func[CG_in_function].arg_upto += 1; + + break; + + case PARSE_NODE_TYPE_ENDFUNC: + + // + // The function doesn't return anything. Make it + // return UNDEFINED. + // + + ASSERT(WITHIN(CG_in_function, 0, CG_func_upto - 1)); + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_UNDEFINED; + CG_instruction[CG_instruction_upto++] = 0; + + CG_instruction[CG_instruction_upto++] = ML_DO_ENDFUNC; + CG_instruction[CG_instruction_upto++] = CG_func[CG_in_function].num_args; + + // + // Not in a function any more. + // + + CG_in_function = FALSE; + + // + // We've lost all the symbols in the local symbol table. + // + + ST_clear(ST_TABLE_LOCAL); + + break; + + case PARSE_NODE_TYPE_CALL: + + // + // Push the number of arguments in the function call onto the stack. + // The function will check for the correct number and insert + // extra UNDEFINED locals as required. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_NUM_ARGS; + CG_instruction[CG_instruction_upto++] = pn->args; + + if (!ST_find(pn->variable)) + { + // + // This is an undeclared function. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOSUB; + CG_instruction[CG_instruction_upto++] = 0; + + // + // Remember where the reference to the function is. + // + + ASSERT(WITHIN(CG_undefref_upto, 0, CG_MAX_UNDEFREFS - 1)); + + CG_undefref[CG_undefref_upto].name = CG_add_string_to_debug_data(pn->variable); + CG_undefref[CG_undefref_upto].instruction = CG_instruction_upto - 1; + + CG_undefref_upto += 1; + } + else + { + ASSERT(WITHIN(ST_found_value, 0, CG_func_upto - 1)); + ASSERT(strcmp(CG_func[ST_found_value].name, pn->variable) == 0); + + if (CG_generating_line > CG_func[ST_found_value].line) + { + // + // This is a backwards goto so we can fill in the instruction + // right away. We add 2 to the instruction to jump over the GOTO + // over the function... + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOSUB; + CG_instruction[CG_instruction_upto++] = CG_line[CG_func[ST_found_value].line].code + 2; + } + else + { + // + // This is a forward goto. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_GOSUB; + CG_instruction[CG_instruction_upto++] = CG_func[ST_found_value].line; + + ASSERT(WITHIN(CG_forward_goto_upto, 0, CG_MAX_FORWARD_GOTOS - 1)); + + CG_forward_goto[CG_forward_goto_upto].type = CG_FORWARD_GOTO_TYPE_CALL; + CG_forward_goto[CG_forward_goto_upto].instruction = CG_instruction_upto - 1; + + CG_forward_goto_upto++; + } + + // + // Remember where the jump instruction is. + // + + ASSERT(WITHIN(CG_jump_upto, 0, CG_MAX_JUMPS - 1)); + + CG_jump[CG_jump_upto++].instruction = CG_instruction_upto - 1; + } + + if (!(pn->flag & PARSE_NODE_FLAG_EXPRESSION)) + { + // + // If this function call isn't part of an expression, the + // return value isn't needed. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_POP; + } + + break; + + case PARSE_NODE_TYPE_TEXTURE: + case PARSE_NODE_TYPE_BUFFER: + case PARSE_NODE_TYPE_DRAW: + case PARSE_NODE_TYPE_CLS: + + { + SLONG num_args; + SLONG func_code; + + // + // How many arguments do we want and what is the function code? + // + + switch(pn->type) + { + case PARSE_NODE_TYPE_TEXTURE: num_args = 2; func_code = ML_DO_TEXTURE; break; + case PARSE_NODE_TYPE_BUFFER: num_args = 4; func_code = ML_DO_BUFFER; break; + case PARSE_NODE_TYPE_DRAW: num_args = 3; func_code = ML_DO_DRAW; break; + case PARSE_NODE_TYPE_CLS: num_args = 2; func_code = ML_DO_CLS; break; + + default: + ASSERT(0); + break; + } + + // + // Do we have the right number of arguments for the function? + // + + if (num_args == pn->args) + { + // + // The right number of arguements! + // + } + else + if (num_args > pn->args) + { + // + // Need to push some undefined members onto the stack. + // + + SLONG i; + + for (i = pn->args; i < num_args; i++) + { + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_UNDEFINED; + CG_instruction[CG_instruction_upto++] = 0; + } + } + else + { + // + // ERROR! More arguments than the function needs?! + // + + ASSERT(0); + } + + // + // The function code. + // + + CG_instruction[CG_instruction_upto++] = func_code; + } + + break; + + case PARSE_NODE_TYPE_FLIP: + CG_instruction[CG_instruction_upto++] = ML_DO_FLIP; + break; + + case PARSE_NODE_TYPE_KEY_VALUE: + CG_instruction[CG_instruction_upto++] = ML_DO_KEY_VALUE; + break; + + case PARSE_NODE_TYPE_KEY_ASSIGN: + CG_instruction[CG_instruction_upto++] = ML_DO_KEY_ASSIGN; + break; + + case PARSE_NODE_TYPE_INKEY_VALUE: + CG_instruction[CG_instruction_upto++] = ML_DO_INKEY_VALUE; + break; + + case PARSE_NODE_TYPE_INKEY_ASSIGN: + CG_instruction[CG_instruction_upto++] = ML_DO_INKEY_ASSIGN; + break; + + case PARSE_NODE_TYPE_TIMER: + CG_instruction[CG_instruction_upto++] = ML_DO_TIMER; + break; + + case PARSE_NODE_TYPE_SIN: + CG_instruction[CG_instruction_upto++] = ML_DO_SIN; + break; + + case PARSE_NODE_TYPE_COS: + CG_instruction[CG_instruction_upto++] = ML_DO_COS; + break; + + case PARSE_NODE_TYPE_TAN: + CG_instruction[CG_instruction_upto++] = ML_DO_TAN; + break; + + case PARSE_NODE_TYPE_ASIN: + CG_instruction[CG_instruction_upto++] = ML_DO_ASIN; + break; + + case PARSE_NODE_TYPE_ACOS: + CG_instruction[CG_instruction_upto++] = ML_DO_ACOS; + break; + + case PARSE_NODE_TYPE_ATAN: + CG_instruction[CG_instruction_upto++] = ML_DO_ATAN; + break; + + case PARSE_NODE_TYPE_ATAN2: + CG_instruction[CG_instruction_upto++] = ML_DO_ATAN2; + break; + + case PARSE_NODE_TYPE_EXPORT: + break; + + case PARSE_NODE_TYPE_LEFT: + + if (pn->child2 == NULL) + { + // + // This is a one-argument version. Push the constant 1 onto the stack. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_SLUMBER; + CG_instruction[CG_instruction_upto++] = 1; + } + + CG_instruction[CG_instruction_upto++] = ML_DO_LEFT; + + break; + + case PARSE_NODE_TYPE_RIGHT: + + if (pn->child2 == NULL) + { + // + // This is a one-argument version. Push the constant 1 onto the stack. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_SLUMBER; + CG_instruction[CG_instruction_upto++] = 1; + } + + CG_instruction[CG_instruction_upto++] = ML_DO_RIGHT; + + break; + + case PARSE_NODE_TYPE_MID: + + if (pn->child3 == NULL) + { + // + // This is a two-argument version. Push the constant 1 onto the stack. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_CONSTANT; + CG_instruction[CG_instruction_upto++] = ML_TYPE_SLUMBER; + CG_instruction[CG_instruction_upto++] = 1; + } + + CG_instruction[CG_instruction_upto++] = ML_DO_MID; + + break; + + case PARSE_NODE_TYPE_LEN: + CG_instruction[CG_instruction_upto++] = ML_DO_LEN; + break; + + case PARSE_NODE_TYPE_MATRIX: + + if (pn->child1) + { + // + // Constructing a matrix from three vectors. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_MATRIX; + } + else + { + // + // The identity matrix. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_IDENTITY_MATRIX; + } + + break; + + case PARSE_NODE_TYPE_VECTOR: + + if (pn->child1) + { + // + // Constructing a vector from three numbers. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_VECTOR; + } + else + { + // + // The zero vector. + // + + CG_instruction[CG_instruction_upto++] = ML_DO_PUSH_ZERO_VECTOR; + } + + break; + + default: + ASSERT(0); + break; + } + + return TRUE; +} + + + +SLONG CG_do(CBYTE *fname, SLONG output) +{ + SLONG i; + + PARSE_Node *pn; + FILE *handle; + ML_Header mh; + LINK_Header lh; + CG_Func *cf; + LINK_Global *lg; + LINK_Function lf; + LINK_Field *ld; + + CBYTE export_string [LEX_MAX_STRING_LENGTH + 2]; + CBYTE local_string [LEX_MAX_STRING_LENGTH + 2]; + CBYTE string_backup [LEX_MAX_STRING_LENGTH + 2]; + SLONG value_backup; + SLONG export; + SLONG local; + + #ifdef _DEBUG + SLONG globals_found; + SLONG fields_found; + #endif + + // + // Clear symbol tables and add the system variables. + // + + ST_clear_all(); + SYSVAR_init(); + + // + // Initialise output. + // + + CG_output = NULL; + CG_num_errors = 0; + CG_num_warnings = 0; + + memset(CG_instruction, 0, sizeof(CG_instruction )); + memset(CG_line, 0, sizeof(CG_line )); + memset(CG_func, 0, sizeof(CG_func )); + memset(CG_for, 0, sizeof(CG_for )); + memset(CG_forward_goto, 0, sizeof(CG_forward_goto)); + memset(CG_if, 0, sizeof(CG_if )); + memset(CG_mif, 0, sizeof(CG_mif )); + memset(CG_while, 0, sizeof(CG_while )); + + memset(CG_jump, 0, sizeof(CG_jump )); + memset(CG_globalref, 0, sizeof(CG_globalref )); + memset(CG_fieldref, 0, sizeof(CG_fieldref )); + memset(CG_undefref, 0, sizeof(CG_undefref )); + memset(CG_datatableref, 0, sizeof(CG_datatableref)); + memset(CG_debug_data, 0, sizeof(CG_debug_data )); + + CG_instruction_upto = 0; + CG_line_upto = 0; + CG_field_id_upto = SYSVAR_FIELD_NUMBER; + CG_for_upto = 0; + CG_mif_upto = 0; + CG_while_upto = 0; + CG_func_upto = 1; // 0 func => top level code. + CG_forward_goto_upto = 0; + + CG_generating_line = 0; + CG_global_upto = 0; + + CG_jump_upto = 0; + CG_globalref_upto = 0; + CG_fieldref_upto = 0; + CG_undefref_upto = 0; + CG_datatableref_upto = 0; + CG_debug_data_upto = 0; + + // + // The string table. + // + + CG_data_table_max = 512; + CG_data_table = (UBYTE *) malloc(sizeof(UBYTE) * CG_data_table_max); + CG_data_table_upto = 0; + + // + // Go through the PARSE tree adding all labels and variables + // to the symbol table and finding our functions. + // + + CG_in_function = FALSE; // Not in a function when we start... + + for (i = 0; i < PARSE_line_upto; i++) + { + pn = PARSE_line[i]; + + CG_generating_line = i; + + PARSE_traverse(pn, CG_callback_add_labels_and_variables); + } + + // + // Generate code! + // + + CG_in_function = FALSE; // Not in a function when we start... + + for (i = 0; i < PARSE_line_upto; i++) + { + pn = PARSE_line[i]; + + // + // Each line knows where it's instructions are. + // + + ASSERT(WITHIN(i, 0, CG_MAX_LINES - 1)); + + CG_line[i].code = CG_instruction_upto; + CG_line_upto = i + 1; + + // + // Clear the Ifs-per-line array. + // + + CG_if_upto = 0; + + // + // Generate code for this line. + // + + CG_generating_line = i; + + PARSE_traverse(pn, CG_callback_generate_code); + } + + // + // The pretend last line that holds the EXIT instruction. + // + + ASSERT(WITHIN(CG_line_upto, 0, CG_MAX_LINES - 1)); + + CG_line[CG_line_upto++].code = CG_instruction_upto; + + // + // And write out an EXIT instruction. + // + + if (!(WITHIN(CG_instruction_upto, 0, CG_MAX_INSTRUCTIONS - 1))) + { + // + // This is a bit unlucky! ERROR! + // + + ASSERT(0); + + return FALSE; + } + + CG_instruction[CG_instruction_upto++] = ML_DO_EXIT; + + // + // Replace all GOTO addresses with the instruction index rather + // than the line number. + // + + for (i = 0; i < CG_forward_goto_upto; i++) + { + ASSERT(WITHIN(CG_forward_goto[i].instruction, 0, CG_instruction_upto - 1)); + ASSERT(WITHIN(CG_instruction[CG_forward_goto[i].instruction], 0, CG_line_upto - 1)); + + CG_instruction[CG_forward_goto[i].instruction] = CG_line[CG_instruction[CG_forward_goto[i].instruction]].code; + + if (CG_forward_goto[i].type == CG_FORWARD_GOTO_TYPE_CALL) + { + // + // The first couple of instructions of a function are + // a GOTO over the body of the function- incase the + // functions are defined at the top of the file. So + // when we call the function, we must jump to a couple + // of instructions ahead. + // + + CG_instruction[CG_forward_goto[i].instruction] += 2; + } + } + + // + // Open our output filename. + // + + handle = fopen(fname, "wb"); + + if (!handle) + { + // + // ERROR! + // + + ASSERT(0); + + return FALSE; + } + + // + // Write out the file type. + // + + if (output & CG_OUTPUT_EXECUTABLE) + { + if (CG_undefref_upto != 0) + { + // + // ERROR! You can't have undefined functions when you + // output an executable. + // + + ASSERT(0); + } + + // + // The header of an executable. + // + + mh.version = ML_VERSION_NUMBER; + mh.instructions_memory_in_bytes = CG_instruction_upto * sizeof(SLONG); + mh.data_table_length_in_bytes = CG_data_table_upto; + mh.num_globals = CG_global_upto; + + if (fwrite(&mh, sizeof(mh), 1, handle) != 1) goto file_error; + + // + // The instructions. + // + + if (fwrite(CG_instruction, sizeof(SLONG), CG_instruction_upto, handle) != CG_instruction_upto) goto file_error; + + // + // The string table. + // + + if (fwrite(CG_data_table, sizeof(UBYTE), CG_data_table_upto, handle) != CG_data_table_upto) goto file_error; + + fclose(handle); + + // + // Find all our symbols. + // + + ST_find_all_start(); + + while(ST_find_all_next()) + { + OS_string("Symbol \"%s\" = %d\n", ST_found_string, ST_found_value); + } + + return TRUE; + } + else + { + // + // Writing out the magic number after each block. + // + + SLONG magic = 12345678; + + #define CG_WRITE_MAGIC() {if (fwrite(&magic, sizeof(SLONG), 1, handle) != 1) goto file_error;} + + // + // The header of the object file. + // + + lh.version = 1; + lh.num_instructions = CG_instruction_upto; + lh.data_table_length_in_bytes = CG_data_table_upto; + lh.num_globals = CG_global_upto; + lh.num_functions = CG_func_upto - 1; // Function 0 is not used + lh.num_lines = CG_line_upto; + lh.num_jumps = CG_jump_upto; + lh.num_fields = CG_field_id_upto; + lh.num_global_refs = CG_globalref_upto; + lh.num_undef_refs = CG_undefref_upto; + lh.num_field_refs = CG_fieldref_upto; + lh.num_data_table_refs = CG_datatableref_upto; + + if (fwrite(&lh, sizeof(lh), 1, handle) != 1) goto file_error; + + // + // Each block of data. + // + + if (fwrite(CG_instruction, sizeof(SLONG), CG_instruction_upto, handle) != CG_instruction_upto) goto file_error; CG_WRITE_MAGIC(); + if (fwrite(CG_data_table, sizeof(UBYTE), CG_data_table_upto, handle) != CG_data_table_upto ) goto file_error; CG_WRITE_MAGIC(); + + // + // Write out the globals sorted by their global_id. + // + + { + lg = (LINK_Global *) malloc(sizeof(LINK_Global) * CG_global_upto); + + + #ifdef _DEBUG + globals_found = 0; + #endif + + ST_find_all_start(); + + while(ST_find_all_next()) + { + if (ST_found_string[0] == '.') + { + // + // This is a field. + // + } + else + if (ST_found_string[0] == '(') + { + // + // This is a function. + // + } + else + if (ST_found_string[0] == '-') + { + // + // This is an export directive. + // + } + else + if (ST_found_string[0] == '<') + { + // + // This is a local directive. + // + } + else + { + // + // This must be a global. Backup ST_found_string and + // ST_found_value because we are going to access the + // symbol table again to find out if this global + // should be exported or not. + // + + strcpy(string_backup, ST_found_string); + + value_backup = ST_found_value; + + // + // Should we export it? + // + + sprintf(export_string, "->%s", string_backup); + + export = ST_find(export_string); + + // + // Should it be a local? + // + + sprintf(local_string, "<-%s", string_backup); + + local = ST_find(local_string); + + // + // Can't be both local and exported! + // + + ASSERT(!(local && export)); + + // + // Write out the global. + // + + ASSERT(WITHIN(value_backup, 0, CG_global_upto - 1)); + + lg[value_backup].export = export; + lg[value_backup].local = local; + lg[value_backup].index = value_backup; + lg[value_backup].name = CG_add_string_to_debug_data(string_backup); + + #ifdef _DEBUG + globals_found += 1; + #endif + } + } + + ASSERT(globals_found == CG_global_upto); + + // + // Write out the global array. + // + + if (fwrite(lg, sizeof(LINK_Global), CG_global_upto, handle) != CG_global_upto) goto file_error; CG_WRITE_MAGIC(); + + // + // Free memory. + // + + free(lg); + } + + // + // Write out all the defined functions. + // + + for (i = 1; i < CG_func_upto; i++) + { + cf = &CG_func[i]; + + // + // Is this function exported? + // + + sprintf(export_string, "->%s", cf->name + 2); // + 2 skips over the () at the beginning of the function name. + + export = ST_find(export_string); + + // + // Write out the function. + // + + lf.name = CG_add_string_to_debug_data(cf->name); + lf.line_start = cf->line; + lf.line_end = cf->endline; + lf.num_args = cf->num_args; + lf.export = export; + + if (fwrite(&lf, sizeof(lf), 1, handle) != 1) goto file_error; + } + + CG_WRITE_MAGIC(); + + // + // Write out each line and each jump. + // + + if (fwrite(CG_line, sizeof(CG_Line), CG_line_upto, handle) != CG_line_upto) goto file_error; CG_WRITE_MAGIC(); + if (fwrite(CG_jump, sizeof(CG_Jump), CG_jump_upto, handle) != CG_jump_upto) goto file_error; CG_WRITE_MAGIC(); + + // + // Write out all the fields sorted by their field_id + // + + { + ld = (LINK_Field *) malloc(sizeof(LINK_Field) * CG_field_id_upto); + + #ifdef _DEBUG + fields_found = 0; + #endif + + ST_find_all_start(); + + while(ST_find_all_next()) + { + if (ST_found_string[0] == '.') + { + ASSERT(WITHIN(ST_found_value, 0, CG_field_id_upto - 1)); + + // + // This is a field. + // + + ld[ST_found_value].index = ST_found_value; + ld[ST_found_value].name = CG_add_string_to_debug_data(ST_found_string); + + #ifdef _DEBUG + fields_found += 1; + #endif + } + } + + ASSERT(fields_found == CG_field_id_upto); + + // + // Write out all the fields. + // + + if (fwrite(ld, sizeof(LINK_Field), CG_field_id_upto, handle) != CG_field_id_upto) goto file_error; CG_WRITE_MAGIC(); + + // + // Free memory. + // + + free(ld); + } + + // + // The references to each global, the undefined function references + // and the field references. + // + + ASSERT(sizeof(CG_Globalref) == sizeof(LINK_Globalref)); + ASSERT(sizeof(CG_Undefref ) == sizeof(LINK_Undefref )); + ASSERT(sizeof(CG_Fieldref ) == sizeof(LINK_Fieldref )); + + if (fwrite(CG_globalref, sizeof(CG_Globalref ), CG_globalref_upto, handle) != CG_globalref_upto ) goto file_error; CG_WRITE_MAGIC(); + if (fwrite(CG_undefref, sizeof(CG_Undefref ), CG_undefref_upto, handle) != CG_undefref_upto ) goto file_error; CG_WRITE_MAGIC(); + if (fwrite(CG_fieldref, sizeof(CG_Fieldref ), CG_fieldref_upto, handle) != CG_fieldref_upto ) goto file_error; CG_WRITE_MAGIC(); + if (fwrite(CG_datatableref, sizeof(CG_Datatableref), CG_datatableref_upto, handle) != CG_datatableref_upto) goto file_error; CG_WRITE_MAGIC(); + + // + // The debug data. + // + + if (fwrite(&CG_debug_data_upto, sizeof(SLONG), 1, handle) != 1 ) goto file_error; + if (fwrite( CG_debug_data, sizeof(CBYTE), CG_debug_data_upto, handle) != CG_debug_data_upto) goto file_error; + + // + // All done. + // + + fclose(handle); + + return TRUE; + } + + file_error:; + + // + // ERROR! + // + + ASSERT(0); + + fclose(handle); + + return FALSE; +} + + diff --git a/MuckyBasic/cg.h b/MuckyBasic/cg.h new file mode 100644 index 0000000..5e3d492 --- /dev/null +++ b/MuckyBasic/cg.h @@ -0,0 +1,32 @@ +// +// The code generator and linker. Converts the output of the parse into +// an executable. +// + +#ifndef _CG_ +#define _CG_ + + + +// +// Takes the output of the PARSE module and spews out +// code to the given filename. Returns FALSE on failure. +// CG_output[] hold the errors/warnings/status of the +// code generation phase. +// + +extern CBYTE *CG_output; +extern SLONG CG_num_errors; +extern SLONG CG_num_warnings; + +#define CG_OUTPUT_EXECUTABLE (1 << 0) +#define CG_OUTPUT_OBJECT_FILE (1 << 1) +#define CG_OUTPUT_DEBUG_INFO (1 << 2) + +SLONG CG_do(CBYTE *fname, SLONG output = CG_OUTPUT_EXECUTABLE); + + + + + +#endif diff --git a/MuckyBasic/clip.cpp b/MuckyBasic/clip.cpp new file mode 100644 index 0000000..db4555f --- /dev/null +++ b/MuckyBasic/clip.cpp @@ -0,0 +1,155 @@ +// +// A general clipper. +// + +#include "always.h" + + + +// +// The buffer in which we create new points. +// + +#define CLIP_BUFFER_SIZE 2048 + +UBYTE CLIP_buffer[CLIP_BUFFER_SIZE]; +UBYTE *CLIP_buffer_upto = CLIP_buffer; + + +// +// Returns the address of a block of memory of the +// given size. +// + +inline void *CLIP_malloc(ULONG size) +{ + void *ans; + + ASSERT(size < CLIP_BUFFER_SIZE); + + if (CLIP_buffer_upto + size * 2 > &CLIP_buffer[CLIP_BUFFER_SIZE]) + { + CLIP_buffer_upto = CLIP_buffer; + } + + ans = CLIP_buffer_upto; + CLIP_buffer_upto += size * 2; + + return ans; +} + + + +void CLIP_do( + void ***polygon, + SLONG *polygon_num_points, + SLONG sizeof_polygon_point, + void (*interpolate)(void *new_point, void *point1, void *point2, float amount_along_from_1_to_2), + float (*signed_distance_from_edge)(void *point)) +{ + + SLONG i; + + SLONG i_p1; + SLONG i_p2; + + void *p1; + void *p2; + + float along; + + // + // The output buffer. + // + + void **output = (void **) CLIP_malloc(2 * sizeof(void *) * *polygon_num_points); + SLONG output_upto = 0; + + // + // Work out the signed distance of each point from the edge. + // + + float *distance = (float *) CLIP_malloc(sizeof(float) * *polygon_num_points); + + for (i = 0; i < *polygon_num_points; i++) + { + distance[i] = signed_distance_from_edge((*polygon)[i]); + } + + // + // Go through the lines of the poly and build up the output polygon. + // + + for (i = 0; i < *polygon_num_points; i++) + { + // + // The two points of the line. + // + + i_p1 = i + 0; + i_p2 = i + 1; + + if (i_p2 == *polygon_num_points) + { + i_p2 = 0; + } + + p1 = (*polygon)[i_p1]; + p2 = (*polygon)[i_p2]; + + if (distance[i_p1] >= 0) + { + // + // This point is on the 'good' positive side of the line... add + // it to the output polygon. + // + + output[output_upto++] = p1; + + if (distance[i_p2] >= 0) + { + // + // The other end of the line is also on the right side of the line... + // no need to create a clipped point. + // + + continue; + } + } + else + { + if (distance[i_p2] < 0) + { + // + // Both points are offscreen, so don't create a clipped point between them. + // + + continue; + } + } + + along = distance[i_p1] / (distance[i_p1] - distance[i_p2]); + + // + // Create a clipped point 'along' the way from point 1 to point 2. + // + + output[output_upto] = CLIP_malloc(sizeof_polygon_point); + + interpolate( + output[output_upto], + p1, + p2, + along); + + output_upto += 1; + } + + // + // Return the new polygon. + // + + *polygon = output; + *polygon_num_points = output_upto; +} + diff --git a/MuckyBasic/clip.h b/MuckyBasic/clip.h new file mode 100644 index 0000000..8c6c745 --- /dev/null +++ b/MuckyBasic/clip.h @@ -0,0 +1,22 @@ +// +// A general clipper. +// + +#ifndef _CLIP_ +#define _CLIP_ + + +// +// Clips a polygon against an edge. On exit *polygon is an array of points and +// *polygon_num_points gives the length of the array. +// + +void CLIP_do( + void ***polygon, // Points to an array of (point *)s of length (*polygon_num_points) + SLONG *polygon_num_points, + SLONG sizeof_polygon_point, + void (*interpolate)(void *new_point, void *point1, void *point2, float amount_along_from_1_to_2), + float signed_distance_from_edge(void *point)); // +'ve => On the good side of the edge. + + +#endif diff --git a/MuckyBasic/comp.cpp b/MuckyBasic/comp.cpp new file mode 100644 index 0000000..900e8eb --- /dev/null +++ b/MuckyBasic/comp.cpp @@ -0,0 +1,62 @@ +#include "always.h" +#include "cg.h" +#include "lex.h" +#include "parse.h" +#include "st.h" +#include "vm.h" + +#define COMP_MAX_PROGRAM (512 * 1024) // Huge buffer! + +CBYTE COMP_program[COMP_MAX_PROGRAM]; + +SLONG COMP_do(CBYTE *fname_input, CBYTE *fname_output) +{ + // + // Load program. + // + + FILE *handle = fopen(fname_input, "rb"); + + if (!handle) + { + // + // Could not open input file. + // + + return FALSE; + } + + // + // Load in the source. + // + + SLONG bytes_read; + + bytes_read = fread(COMP_program, sizeof(CBYTE), COMP_MAX_PROGRAM, handle); + + if (bytes_read == 0) + { + // + // No data read? + // + + return FALSE; + } + + if (bytes_read >= COMP_MAX_PROGRAM) + { + // + // Our source buffer isn't large enough! + // + + return FALSE; + } + + ST_init(); + + PARSE_do(COMP_program); + + CG_do(fname_output); + + return TRUE; +} diff --git a/MuckyBasic/comp.h b/MuckyBasic/comp.h new file mode 100644 index 0000000..eecfa6c --- /dev/null +++ b/MuckyBasic/comp.h @@ -0,0 +1,18 @@ +// +// The compiler. +// + +#ifndef _COMP_ +#define _COMP_ + + + +// +// Compiles the input file to produce the output file. +// + +SLONG COMP_do(CBYTE *fname_input, CBYTE *fname_output); + + + +#endif diff --git a/MuckyBasic/console.cpp b/MuckyBasic/console.cpp new file mode 100644 index 0000000..5e29d40 --- /dev/null +++ b/MuckyBasic/console.cpp @@ -0,0 +1,300 @@ +// +// Provides a PRINT and INPUT for our graphical display. +// Uses the FONT module and takes control of the display. +// + +#include "always.h" +#include "console.h" +#include "font.h" +#include "key.h" +#include "os.h" + + + +// +// Each line of text. +// + +#define CONSOLE_MAX_TEXT_PER_LINE 512 + +typedef struct +{ + CBYTE text[CONSOLE_MAX_TEXT_PER_LINE]; + SLONG cursor; + +} CONSOLE_Line; + +#define CONSOLE_MAX_LINES 35 + +CONSOLE_Line CONSOLE_line[CONSOLE_MAX_LINES]; +SLONG CONSOLE_line_upto; // Just keeps going up beyond CONSOLE_MAX_LINES... + + + +// +// Line height... +// + +#define CONSOLE_LINE_HEIGHT (1.0F / (CONSOLE_MAX_LINES + 1)) + + + +void CONSOLE_init() +{ + memset(CONSOLE_line, 0, sizeof(CONSOLE_line)); + + CONSOLE_line_upto = 0; +} + + + +// +// Draws the current console. +// + +void CONSOLE_draw() +{ + SLONG i; + SLONG first; + SLONG last; + SLONG num; + float ypos; + + OS_clear_screen(); + + if (CONSOLE_line_upto <= CONSOLE_MAX_LINES) + { + first = 0; + last = CONSOLE_line_upto - 1; + } + else + { + first = CONSOLE_line_upto - CONSOLE_MAX_LINES; + last = CONSOLE_line_upto - 1; + } + + num = last - first + 1; + ypos = 0.009F + (num - 1) * CONSOLE_LINE_HEIGHT; + + for (i = last; i >= first; i--) + { + FONT_draw( + 0.013F, + ypos, + 0xffffff, + FONT_FLAG_JUSTIFY_LEFT, + 1.0F, + CONSOLE_line[i % CONSOLE_MAX_LINES].cursor, + CONSOLE_line[i % CONSOLE_MAX_LINES].text); + + ypos -= CONSOLE_LINE_HEIGHT; + } + + OS_show(); +} + + + + +void CONSOLE_print(CBYTE *fmt, ...) +{ + // + // Work out the real message. + // + + CBYTE message[2048]; // Real long... just in case! + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + // + // Create a new line on the console. + // + + CONSOLE_Line *cl; + + cl = &CONSOLE_line[CONSOLE_line_upto++ % CONSOLE_MAX_LINES]; + + memcpy(cl->text, message, CONSOLE_MAX_TEXT_PER_LINE - 1); + + cl->cursor = -1; + + // + // Draw the console. + // + + CONSOLE_draw(); +} + + +CBYTE *CONSOLE_input() +{ + CBYTE *ch; + CONSOLE_Line *cl; + + SLONG flash = OS_ticks(); + SLONG draw = TRUE; + SLONG cursor = 0; + + // + // Create a new line on the console that we will use as our input. + // + + cl = &CONSOLE_line[CONSOLE_line_upto++ % CONSOLE_MAX_LINES]; + + memset(cl->text, 0, sizeof(cl->text)); + + cl->cursor = -1; + + // + // Process keyboard input... + // + + KEY_inkey = 0; + + while(1) + { + if (KEY_on[KEY_BACKSPACE]) + { + KEY_on[KEY_BACKSPACE] = 0; + + if (cursor > 0) + { + cursor -= 1; + + ch = &cl->text[cursor]; + + while(1) + { + ch[0] = ch[1]; + + if (ch[0] == '\000') + { + break; + } + + ch++; + } + } + + flash = OS_ticks(); + draw = TRUE; + } + + if (KEY_on[KEY_DELETE]) + { + KEY_on[KEY_DELETE] = 0; + + } + + if (KEY_on[KEY_RETURN]) + { + KEY_on[KEY_RETURN] = 0; + + cl->cursor = -1; + + return cl->text; + } + + if (KEY_on[KEY_LEFT]) + { + KEY_on[KEY_LEFT] = 0; + + if (cursor > 0) + { + cursor -= 1; + } + + flash = OS_ticks(); + draw = TRUE; + } + + if (KEY_on[KEY_RIGHT]) + { + KEY_on[KEY_RIGHT] = 0; + + if (cl->text[cursor]) + { + cursor += 1; + } + + flash = OS_ticks(); + draw = TRUE; + } + + if (KEY_on[KEY_END]) + { + KEY_on[KEY_END] = 0; + + while(cl->text[cursor]) + { + cursor++; + } + + flash = OS_ticks(); + draw = TRUE; + } + + if (KEY_on[KEY_HOME]) + { + KEY_on[KEY_HOME] = 0; + + cursor = 0; + + flash = OS_ticks(); + draw = TRUE; + } + + if (KEY_inkey) + { + if (isprint(KEY_inkey)) + { + if (WITHIN(cursor, 0, CONSOLE_MAX_TEXT_PER_LINE - 2)) + { + // + // Insert a character at the cursor position. + // + + for (ch = &cl->text[cursor]; *ch; ch++); + + while(ch > &cl->text[cursor]) + { + ch[0] = ch[-1]; + + ch--; + } + + cl->text[cursor] = KEY_inkey; + + cl->text[CONSOLE_MAX_TEXT_PER_LINE - 1] = '\000'; + + cursor += 1; + } + } + + flash = OS_ticks(); + draw = TRUE; + + KEY_inkey = 0; + } + + if (OS_ticks() > flash + 500) + { + flash = OS_ticks(); + draw ^= TRUE; + } + + if (draw) + { + cl->cursor = cursor; + } + else + { + cl->cursor = -1; + } + + CONSOLE_draw(); + } +} diff --git a/MuckyBasic/console.h b/MuckyBasic/console.h new file mode 100644 index 0000000..9d80b9c --- /dev/null +++ b/MuckyBasic/console.h @@ -0,0 +1,33 @@ +// +// Provides a PRINT and INPUT for our graphical display. +// Uses the FONT module and takes control of the display. +// + +#ifndef _CONSOLE_ +#define _CONSOLE_ + + + +// +// Iniailises the CONSOLE output. +// + +void CONSOLE_init(void); + + + +// +// Prints the text. +// + +void CONSOLE_print(CBYTE *fmt, ...); + +// +// Gets a line of input from the user. +// + +CBYTE *CONSOLE_input(void); + + + +#endif diff --git a/MuckyBasic/d3denum.cpp b/MuckyBasic/d3denum.cpp new file mode 100644 index 0000000..1dcc3ca --- /dev/null +++ b/MuckyBasic/d3denum.cpp @@ -0,0 +1,643 @@ +//----------------------------------------------------------------------------- +// File: D3DEnum.cpp +// +// Desc: Class enumerate through the DirectDraw drivers, Direct3D devices, +// and the display modes available to each device. +// +// +// Copyright (c) 1997-1998 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#define STRICT +#include + +// HACK!!!!! +#include +#ifndef SM_CMONITORS +#define SM_CMONITORS +DECLARE_HANDLE(HMONITOR); +#define HMONITOR_DECLARED +#endif + +#include "D3DEnum.h" +#include "D3DUtil.h" + + + + +//----------------------------------------------------------------------------- +// Constants and function prototypes for the user select driver dialog +//----------------------------------------------------------------------------- +DLGTEMPLATE* _BuildDriverSelectTemplate(); +BOOL CALLBACK _DriverSelectProc( HWND, UINT, WPARAM, LPARAM ); + + + + +//----------------------------------------------------------------------------- +// Global data for the enumerator functions +//----------------------------------------------------------------------------- +static LPDIRECTDRAW4 g_pDD = NULL; // Used for callbacks +static BOOL g_bRefRastEnumerated = FALSE; // For the reference rast +static BOOL g_bDevicesEnumerated = FALSE; // Used during enumeration + +D3DEnum_DriverInfo* g_pFirstDriver = NULL; // List of DD drivers +D3DEnum_DriverInfo* g_pDefaultDriver = NULL; // Default driver +D3DEnum_DriverInfo* g_pCurrentDriver = NULL; // The selected DD driver + +static HRESULT (*g_fnAppConfirmFn)(DDCAPS*, D3DDEVICEDESC*) = NULL; + + + + +//----------------------------------------------------------------------------- +// Local callback functions used during enumeration +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Name: EnumDisplayModesCallback() +// Desc: Callback function called for each display mode. Each available +// display mode is added to a list for further choosing from the app. +//----------------------------------------------------------------------------- +static HRESULT WINAPI EnumDisplayModesCallback( DDSURFACEDESC2* pddsd, + VOID* pvContext ) +{ + // Check parameters + if( NULL==pddsd || NULL==pvContext ) + return DDENUMRET_CANCEL; + + D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pvContext; + D3DEnum_ModeInfo* pNewMode; + DWORD dwBitDepth = pDevice->ddDesc.dwDeviceRenderBitDepth; + DWORD dwModeDepth = pddsd->ddpfPixelFormat.dwRGBBitCount; + + // Check mode for compatability with device. Skip 8-bit modes. + if( (32==dwModeDepth) && (0==(dwBitDepth&DDBD_32)) ) return DDENUMRET_OK; + if( (24==dwModeDepth) && (0==(dwBitDepth&DDBD_24)) ) return DDENUMRET_OK; + if( (16==dwModeDepth) && (0==(dwBitDepth&DDBD_16)) ) return DDENUMRET_OK; + if( ( 8==dwModeDepth) ) return DDENUMRET_OK; + + // Create a new mode structure + if( NULL == ( pNewMode = new D3DEnum_ModeInfo ) ) + return DDENUMRET_CANCEL; + + // Initialize the new mode structure + ZeroMemory( pNewMode, sizeof(D3DEnum_ModeInfo) ); + memcpy( &pNewMode->ddsd, pddsd, sizeof(DDSURFACEDESC2) ); + sprintf( pNewMode->strDesc, TEXT("%ld x %ld x %ld"), pddsd->dwWidth, + pddsd->dwHeight, dwModeDepth ); + + // Link the new mode struct in the list of other display modes + D3DEnum_ModeInfo** pMode = &pDevice->pFirstMode; + while( *pMode ) + pMode = &((*pMode)->pNext); + (*pMode) = pNewMode; + + // If this is a 640x480x16 mode, save it as the default mode + if( ( 640 == pddsd->dwWidth ) && ( 480 == pddsd->dwHeight ) && + ( 16 == pddsd->ddpfPixelFormat.dwRGBBitCount ) ) + pDevice->pCurrentMode = pNewMode; + + if( NULL == pDevice->pCurrentMode ) + pDevice->pCurrentMode = pNewMode; + + return DDENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: Enum3DDevicesCallback() +// Desc: Callback function called for each DirectX 3D device. The driver's +// attributes are added to the list of available drivers. +//----------------------------------------------------------------------------- +static HRESULT WINAPI Enum3DDevicesCallback( GUID* pGUID, LPSTR strDesc, + LPSTR strName, LPD3DDEVICEDESC pHALDesc, + LPD3DDEVICEDESC pHELDesc, LPVOID pvContext ) +{ + D3DEnum_DriverInfo* pDriver = (D3DEnum_DriverInfo*)pvContext; + D3DEnum_DeviceInfo* pNewDevice; + + // Check params + if( NULL==pGUID || NULL==pHALDesc || NULL==pHELDesc || NULL==pDriver ) + return D3DENUMRET_CANCEL; + + // Handle specific device GUIDs. NullDevice renders nothing + if( IsEqualGUID( *pGUID, IID_IDirect3DNullDevice ) ) + return D3DENUMRET_OK; + + // Set a flag so we know enumeration is working. This is just a feature to + // help return more informative return codes later on. + g_bDevicesEnumerated = TRUE; + + // Get info about this device. + BOOL bIsHardware = ( 0 != pHALDesc->dwFlags ); + D3DDEVICEDESC* pDesc = bIsHardware ? pHALDesc : pHELDesc; + + // Only enumerate software rasterizers for the primary device (which has + // a NULL GUID). This is to avoid duplicates + if( pDriver->pGUID != NULL ) + if( FALSE == bIsHardware ) + return D3DENUMRET_OK; + + + // Give the app a chance to accept or reject this device, based on + // what feature set it supports + if( g_fnAppConfirmFn ) + if( FAILED( g_fnAppConfirmFn( &pDriver->ddDriverCaps, pDesc ) ) ) + return D3DENUMRET_OK; + + // Create a new D3D Driver struct + if( NULL == ( pNewDevice = new D3DEnum_DeviceInfo ) ) + return D3DENUMRET_CANCEL; + ZeroMemory( pNewDevice, sizeof(D3DEnum_DeviceInfo) ); + + // Copy remaining device attributes + memcpy( &pNewDevice->guid, pGUID, sizeof(GUID) ); + pNewDevice->pGUID = &pNewDevice->guid; + strncpy( pNewDevice->strName, strName, 39 ); + memcpy( &pNewDevice->ddDesc, pDesc, sizeof(D3DDEVICEDESC) ); + pNewDevice->bIsHardware = bIsHardware; + + if( pNewDevice->bIsHardware ) + pDriver->pCurrentDevice = pNewDevice; + else + { + if( NULL == pDriver->pCurrentDevice ) + if( D3DCOLOR_RGB & pHELDesc->dcmColorModel ) + pDriver->pCurrentDevice = pNewDevice; + } + + // Enumerate the display modes + g_pDD->EnumDisplayModes( 0, NULL, pNewDevice, EnumDisplayModesCallback ); + + // Get the display mode's depth + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(DDSURFACEDESC2); + g_pDD->GetDisplayMode( &ddsd ); + DWORD dwDisplayBPP = ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Set the initial bWindowed flag if the device can render in a window and + // supports the current display mode + if( pDriver->ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED ) + { + for( D3DEnum_ModeInfo* pMode=pNewDevice->pFirstMode; pMode; + pMode = pMode->pNext ) + { + if( pMode->ddsd.ddpfPixelFormat.dwRGBBitCount == dwDisplayBPP ) + { + pNewDevice->bCompatbileWithDesktop = TRUE; + if( NULL == pDriver->pGUID ) + pNewDevice->bWindowed = TRUE; + } + } + } + + if( pNewDevice->pFirstMode ) + { + // Link it with the other D3D drivers in the DD Driver struct + D3DEnum_DeviceInfo** pDevice = &pDriver->pFirstDevice; + while( *pDevice ) + pDevice = &((*pDevice)->pNext); + (*pDevice) = pNewDevice; + } + else + // Device has no modes, so delete it + delete pNewDevice; + + if( IsEqualGUID( *pGUID, IID_IDirect3DRefDevice ) ) + g_bRefRastEnumerated = TRUE; + + return D3DENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: DirectDrawEnumCallbackEx() +// Desc: Callback function called for each DirectDraw driver. Unless we have +// multimon or a type of card which uses a separate 2D card in +// conjunction with the 3D card, this is only done once. +//----------------------------------------------------------------------------- +static BOOL WINAPI DirectDrawEnumCallbackEx( GUID FAR* pGUID, LPSTR strDesc, + LPSTR strName, VOID*, + HMONITOR hMonitor ) +{ + // Use the GUID to create the DirectDraw object, so that information + // can be extracted from it. + LPDIRECTDRAW pDD; + if( FAILED( DirectDrawCreate( pGUID, &pDD, 0L ) ) ) + { + DEBUG_MSG( TEXT("Can't create DDraw during enumeration!") ); + return D3DENUMRET_OK; + } + + // Query the DirectDraw driver for access to Direct3D. + if( FAILED( pDD->QueryInterface( IID_IDirectDraw4, (VOID**)&g_pDD ) ) ) + { + DEBUG_MSG( TEXT("Can't query IDirectDraw4 during enumeration!") ); + pDD->Release(); + return D3DENUMRET_OK; + } + pDD->Release(); + + // Query the DirectDraw driver for access to Direct3D. + LPDIRECT3D3 pD3D; + if( FAILED( g_pDD->QueryInterface( IID_IDirect3D3, (VOID**)&pD3D ) ) ) + { + DEBUG_MSG( TEXT("Can't query IDirect3D3 during enumeration!") ); + g_pDD->Release(); + return D3DENUMRET_OK; + } + + // Copy the DDDriver info into a new DriverInfo struct + D3DEnum_DriverInfo* pNewDriver = new D3DEnum_DriverInfo; + if( NULL == pNewDriver ) + return D3DENUMRET_CANCEL; + + ZeroMemory( pNewDriver, sizeof(D3DEnum_DriverInfo) ); + + // Copy the GUID (if specified) and the driver name + if( NULL != pGUID ) + { + memcpy( &pNewDriver->guid, pGUID, sizeof(GUID) ); + pNewDriver->pGUID = &pNewDriver->guid; + } + strncpy( pNewDriver->strDesc, strDesc, 39 ); + strncpy( pNewDriver->strName, strName, 39 ); + pNewDriver->hMonitor = hMonitor; + + // Get the caps bits for the driver + pNewDriver->ddDriverCaps.dwSize = sizeof(DDCAPS); + pNewDriver->ddHELCaps.dwSize = sizeof(DDCAPS); + g_pDD->GetCaps( &pNewDriver->ddDriverCaps, &pNewDriver->ddHELCaps ); + + // Now, enumerate all the 3D devices + pD3D->EnumDevices( Enum3DDevicesCallback, pNewDriver ); + + if( pNewDriver->pFirstDevice ) + { + // Link the new DDDriver with the global list + D3DEnum_DriverInfo** pDriver = &g_pFirstDriver; + while( *pDriver ) + pDriver = &((*pDriver)->pNext); + (*pDriver) = pNewDriver; + + // Decide if this is a good default driver + if( NULL == pGUID ) + g_pCurrentDriver = pNewDriver; + } + else + // Driver has no devices, so delete it + delete pNewDriver; + + pD3D->Release(); + g_pDD->Release(); + return DDENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: DirectDrawEnumCallback() +// Desc: Non-mulitmon version of the ddraw enumeration callback +//----------------------------------------------------------------------------- +static BOOL WINAPI DirectDrawEnumCallback( GUID FAR* pGUID, LPSTR strDesc, + LPSTR strName, VOID* ) +{ + return DirectDrawEnumCallbackEx( pGUID, strDesc, strName, NULL, NULL ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_FreeResources() +// Desc: Frees all resources used for driver enumeration +//----------------------------------------------------------------------------- +VOID D3DEnum_FreeResources() +{ + // Loop through each driver, and delete everything + while( g_pFirstDriver ) + { + D3DEnum_DriverInfo* pDriverVictim = g_pFirstDriver; + g_pFirstDriver = g_pFirstDriver->pNext; + + while( pDriverVictim->pFirstDevice ) + { + D3DEnum_DeviceInfo* pDeviceVictim = pDriverVictim->pFirstDevice; + pDriverVictim->pFirstDevice = pDeviceVictim->pNext; + + while( pDeviceVictim->pFirstMode ) + { + D3DEnum_ModeInfo* pModeVictim = pDeviceVictim->pFirstMode; + pDeviceVictim->pFirstMode = pModeVictim->pNext; + delete pModeVictim; + } + delete pDeviceVictim; + } + delete pDriverVictim; + } +} + + + + +//----------------------------------------------------------------------------- +// Name: RefreshListForDesktopCompatibility() +// Desc: Loops through list of devices, and marks a flag for whether the device +// is compatible with the desktop bit depth. +//----------------------------------------------------------------------------- +static VOID RefreshListForDesktopCompatibility() +{ + // Get the currect display mode description + LPDIRECTDRAW pDD; + DDSURFACEDESC ddsd; + if( FAILED( DirectDrawCreate( NULL, &pDD, NULL ) ) ) + return; + ddsd.dwSize = sizeof(DDSURFACEDESC); + pDD->GetDisplayMode( &ddsd ); + pDD->Release(); + + // Get the display mode's depth + DWORD dwDisplayBPP = ddsd.ddpfPixelFormat.dwRGBBitCount; + + // Loop through the devices, and check if any modes works with the current + // display setting + for( D3DEnum_DriverInfo* pDriver = g_pFirstDriver; pDriver; + pDriver = pDriver->pNext ) + { + for( D3DEnum_DeviceInfo* pDevice=pDriver->pFirstDevice; pDevice; + pDevice = pDevice->pNext ) + { + pDevice->bCompatbileWithDesktop = FALSE; + + for( D3DEnum_ModeInfo* pMode=pDevice->pFirstMode; pMode; + pMode = pMode->pNext ) + { + if( pMode->ddsd.ddpfPixelFormat.dwRGBBitCount == dwDisplayBPP ) + pDevice->bCompatbileWithDesktop = TRUE; + } + } + } +} + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_EnumerateDevices() +// Desc: Enumerates all drivers, devices, and modes. The optional app-supplied +// callback is called for each enumerated device, to confirm that the +// device supports the feature set required by the app. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_EnumerateDevices( + HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC*) ) +{ + g_fnAppConfirmFn = AppConfirmFn; + g_bRefRastEnumerated = FALSE; + + // We need to manually get the procedure address for the DDrawEnumEx() + // function. + HMODULE hDDrawDLL = GetModuleHandle("DDRAW.DLL"); + if( NULL == hDDrawDLL ) + { + DEBUG_MSG( TEXT("Can't load DDRAW.DLL!") ); + return D3DENUMERR_NODIRECTDRAW; + } + + // Find the DDraw enumeration function, and call it + LPDIRECTDRAWENUMERATEEX pDDrawEnumFn = (LPDIRECTDRAWENUMERATEEX) + GetProcAddress( hDDrawDLL, "DirectDrawEnumerateExA" ); + + if( pDDrawEnumFn ) + pDDrawEnumFn( DirectDrawEnumCallbackEx, NULL, + DDENUM_ATTACHEDSECONDARYDEVICES | + DDENUM_DETACHEDSECONDARYDEVICES | + DDENUM_NONDISPLAYDEVICES ); + else + DirectDrawEnumerate( DirectDrawEnumCallback, NULL ); + + // Select a driver. Ask for a hardware device that renders in a window + return D3DEnum_SelectDefaultDriver( NULL ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_SelectDefaultDriver() +// Desc: Picks a default driver according to the passed in flags. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_SelectDefaultDriver( DWORD dwFlags ) +{ + // Refresh the list of devices to mark which devices (if any) are + // compatible with the current desktop (ie. can render in a window). + RefreshListForDesktopCompatibility(); + + // If a specific driver was requested, perform that search here + if( dwFlags & 0x0000003c ) + { + for( D3DEnum_DriverInfo* pDriver = g_pFirstDriver; pDriver; + pDriver = pDriver->pNext ) + { + for( D3DEnum_DeviceInfo* pDevice = pDriver->pFirstDevice; pDevice; + pDevice = pDevice->pNext ) + { + BOOL bFound = FALSE; + + if( IsEqualGUID( *pDevice->pGUID, IID_IDirect3DRGBDevice ) ) + { + if( dwFlags & D3DENUM_RGBEMULATION ) + bFound = TRUE; + } + else if( IsEqualGUID( *pDevice->pGUID, IID_IDirect3DRefDevice ) ) + { + if( dwFlags & D3DENUM_REFERENCERAST ) + bFound = TRUE; + } + else + { + if( dwFlags & D3DENUM_PRIMARYHAL ) + if( pDriver == g_pFirstDriver ) + bFound = TRUE; + if( dwFlags & D3DENUM_SECONDARYHAL ) + if( pDriver != g_pFirstDriver ) + bFound = TRUE; + } + + if( bFound ) + { + g_pCurrentDriver = pDriver; + g_pCurrentDriver->pCurrentDevice = pDevice; + return S_OK; + } + } + } + return D3DENUMERR_NOTFOUND; + } + + // Do 4 passes, looping through drivers, devices and modes. The 1st pass + // searches for hardware. The 2nd pass looks for software devices. The + // final two passes allow fullscreen modes. + for( WORD pass=0; pass<4; pass++ ) + { + BOOL bSeekHardware = ( pass & 0x1 ) ? FALSE : TRUE; + BOOL bSeekWindowed = ( pass & 0x2 ) ? FALSE : TRUE; + + // Skip the passes we aren't allowing + if( (TRUE==bSeekHardware) && (dwFlags&D3DENUM_SOFTWAREONLY) ) + continue; + if( (TRUE==bSeekWindowed) && (dwFlags&D3DENUM_FULLSCREENONLY) ) + continue; + + for( D3DEnum_DriverInfo* pDriver = g_pFirstDriver; pDriver; + pDriver = pDriver->pNext ) + { + DDCAPS* pCaps = &pDriver->ddDriverCaps; + + if( bSeekWindowed ) + if( 0 == ( pCaps->dwCaps2 & DDCAPS2_CANRENDERWINDOWED ) ) + continue; + + for( D3DEnum_DeviceInfo* pDevice = pDriver->pFirstDevice; pDevice; + pDevice = pDevice->pNext ) + { + if( bSeekHardware != pDevice->bIsHardware ) + continue; + if( bSeekWindowed && FALSE == pDevice->bCompatbileWithDesktop ) + continue; + + pDevice->bWindowed = bSeekWindowed; + g_pCurrentDriver = pDriver; + g_pCurrentDriver->pCurrentDevice = pDevice; + + return S_OK; + } + } + } + + // No compatible devices were found. Return an error code + if( FALSE == g_bDevicesEnumerated ) + return D3DENUMERR_ENUMERATIONFAILED; // Enumeration really did fail + if( FALSE == g_bRefRastEnumerated ) + return D3DENUMERR_SUGGESTREFRAST; // Suggest enabling the RefRast + + return D3DENUMERR_NOCOMPATIBLEDEVICES; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_UserDlgSelectDriver() +// Desc: Displays a dialog box for the user to select a driver/device/mode. +// The return values are akin to the Windows DialogBox() function. +//----------------------------------------------------------------------------- +INT D3DEnum_UserDlgSelectDriver( HWND hwndParent, BOOL bCurrentlyWindowed ) +{ + INT nResult = -1; + + // Check in case drivers weren't properly enumerated beforehand. + if( NULL == g_pCurrentDriver ) + return -1; + + // Refresh the list of devices to mark which devices (if any) are + // compatible with the current desktop (ie. can render in a window). + RefreshListForDesktopCompatibility(); + + // Match the current windowed-vs-fullscreen state + g_pCurrentDriver->pCurrentDevice->bWindowed = bCurrentlyWindowed; + + // Pop up a dialog box for the user's choice of driver/device/mode + HINSTANCE hInstance = (HINSTANCE)GetWindowLong( hwndParent, + GWL_HINSTANCE ); + + // Create dynamic dialog template + DLGTEMPLATE* pDlgSelect = _BuildDriverSelectTemplate(); + if( pDlgSelect ) + { + // Create dialog box from template + nResult = DialogBoxIndirectParam( hInstance, pDlgSelect, hwndParent, + (DLGPROC)_DriverSelectProc, 0L ); + delete pDlgSelect; + } + + return nResult; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_GetSelectedDriver() +// Desc: Returns the currently selected driver, device, and display mode +//----------------------------------------------------------------------------- +HRESULT D3DEnum_GetSelectedDriver( LPGUID* ppDriverGUID, LPGUID* ppDeviceGUID, + LPDDSURFACEDESC2* ppddsd, BOOL* pbWindowed, + BOOL* pbIsHardware ) + +{ + // Check parans + if( (!ppDriverGUID) || (!ppDeviceGUID) ) + return E_INVALIDARG; + + // Abort if things weren't setup correctly + if( NULL == g_pCurrentDriver ) + return D3DENUMERR_ENUMERATIONFAILED; + + // Copy the driver and device GUID ptrs + (*ppDriverGUID) = g_pCurrentDriver->pGUID; + (*ppDeviceGUID) = g_pCurrentDriver->pCurrentDevice->pGUID; + + if( ppddsd ) + (*ppddsd) = &g_pCurrentDriver->pCurrentDevice->pCurrentMode->ddsd; + if( pbWindowed ) + (*pbWindowed) = g_pCurrentDriver->pCurrentDevice->bWindowed; + if( pbIsHardware ) + (*pbIsHardware) = g_pCurrentDriver->pCurrentDevice->bIsHardware; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_GetSelectedDriver() +// Desc: Returns the currently selected driver, device, and display mode +//----------------------------------------------------------------------------- +HRESULT D3DEnum_GetSelectedDriver( D3DEnum_DriverInfo** ppDriverInfo, + D3DEnum_DeviceInfo** ppDeviceInfo ) + +{ + // Abort if things weren't setup correctly + if( NULL == g_pCurrentDriver ) + return D3DENUMERR_ENUMERATIONFAILED; + + // Copy the driver and device info ptrs + if( ppDriverInfo ) *ppDriverInfo = g_pCurrentDriver; + if( ppDeviceInfo ) *ppDeviceInfo = g_pCurrentDriver->pCurrentDevice; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_GetFirstDriver() +// Desc: Returns a ptr to the first DriverInfo structure in the list. +//----------------------------------------------------------------------------- +D3DEnum_DriverInfo* D3DEnum_GetFirstDriver() +{ + return g_pFirstDriver; +} + + + + + diff --git a/MuckyBasic/d3denum.h b/MuckyBasic/d3denum.h new file mode 100644 index 0000000..63b71a7 --- /dev/null +++ b/MuckyBasic/d3denum.h @@ -0,0 +1,180 @@ +//----------------------------------------------------------------------------- +// File: D3DEnum.h +// +// Desc: Functions which enumerate through the DirectDraw drivers, Direct3D +// devices, and the display modes available to each device. +// +// +// Copyright (C) 1997 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + + +#ifndef D3DENUM_H +#define D3DENUM_H + +#include +#include + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_ModeInfo +// Desc: Linked-list structure to hold information about a display mode. This +// info is stored as a width, height, bpp, and pixelformat within a +// DDSURFACEDESC2. +//----------------------------------------------------------------------------- +struct D3DEnum_ModeInfo +{ + DDSURFACEDESC2 ddsd; + CHAR strDesc[40]; + D3DEnum_ModeInfo* pNext; +}; + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_DeviceInfo +// Desc: Linked-list structure to hold information about a Direct3D device. The +// primary information recorded here is the D3DDEVICEDESC and a ptr to a +// linked-list of valid display modes. +//----------------------------------------------------------------------------- +struct D3DEnum_DeviceInfo +{ + GUID guid; + GUID* pGUID; + CHAR strName[40]; + D3DDEVICEDESC ddDesc; + BOOL bIsHardware; + BOOL bCompatbileWithDesktop; + BOOL bWindowed; + + D3DEnum_ModeInfo* pCurrentMode; + D3DEnum_ModeInfo* pFirstMode; + D3DEnum_DeviceInfo* pNext; +}; + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_DriverInfo +// Desc: Linked-list structure to hold information about a DirectX driver. The +// info stored is the capability bits for the driver plus a linked-list +// of valid Direct3D devices for the driver. Note: most systems will only +// have one driver. The exception are multi-monitor systems, and systems +// with non-GDI 3D video cards. +//----------------------------------------------------------------------------- +struct D3DEnum_DriverInfo +{ + GUID guid; + GUID* pGUID; + CHAR strDesc[40]; + CHAR strName[40]; + DDCAPS ddDriverCaps; + DDCAPS ddHELCaps; + HANDLE hMonitor; + + D3DEnum_DeviceInfo* pCurrentDevice; + D3DEnum_DeviceInfo* pFirstDevice; + D3DEnum_DriverInfo* pNext; +}; + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_EnumerateDevices() +// Desc: Enumerates all drivers, devices, and modes. The optional app-supplied +// callback is called for each enumerated device, to confirm that the +// device supports the feature set required by the app. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_EnumerateDevices( + HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC*) ); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_FreeResources() +// Desc: Frees all resources used for driver enumeration +//----------------------------------------------------------------------------- +VOID D3DEnum_FreeResources(); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_SelectDefaultDriver() +// Desc: Picks a driver based on a set of passed in criteria. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_SelectDefaultDriver( DWORD dwFlags ); + +#define D3DENUM_SOFTWAREONLY 0x00000001 +#define D3DENUM_FULLSCREENONLY 0x00000002 +#define D3DENUM_RGBEMULATION 0x00000004 +#define D3DENUM_REFERENCERAST 0x00000008 +#define D3DENUM_PRIMARYHAL 0x00000010 +#define D3DENUM_SECONDARYHAL 0x00000020 + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_UserDlgSelectDriver() +// Desc: Prompts the user with a dialog box, from which to choose a DD driver, +// D3D device, and compatible display mode. The function will return +// IDOK if a new driver/device/mode was selected, or IDCANCEL if not. +// Any error will result in a -1 for a return code. +//----------------------------------------------------------------------------- +INT D3DEnum_UserDlgSelectDriver( HWND hwndParent, BOOL bCurrentlyWindowed ); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_GetSelectedDriver() +// Desc: Returns the currently selected driver, device, and display mode. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_GetSelectedDriver( LPGUID* ppDriverGUID, LPGUID* ppDeviceGuid, + LPDDSURFACEDESC2* pddsdDisplayMode = NULL, + BOOL* pbWindowed = NULL, + BOOL* pbIsHardware = NULL ); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_GetSelectedDriver() +// Desc: Returns the currently selected driver, device, and display mode. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_GetSelectedDriver( D3DEnum_DriverInfo** ppDriverInfo, + D3DEnum_DeviceInfo** ppDeviceInfo ); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_GetFirstDriver() +// Desc: Returns a ptr to the first DriverInfo structure in the tree holding +// the device/driver/mode enumeration information. +//----------------------------------------------------------------------------- +D3DEnum_DriverInfo* D3DEnum_GetFirstDriver(); + + + + +//----------------------------------------------------------------------------- +// Error codes +//----------------------------------------------------------------------------- +#define D3DENUMERR_ENUMERATIONFAILED 0x81000001 // Enumeration failed +#define D3DENUMERR_SUGGESTREFRAST 0x81000002 // Suggest using the RefRast +#define D3DENUMERR_NOCOMPATIBLEDEVICES 0x81000003 // No devices were found that + // meet the app's desired + // capabilities +#define D3DENUMERR_NODIRECTDRAW 0x81000004 // DDraw couldn't initialize +#define D3DENUMERR_NOTFOUND 0x81000005 // Requested device not found + +#endif // D3DENUM_H + diff --git a/MuckyBasic/d3dframe.cpp b/MuckyBasic/d3dframe.cpp new file mode 100644 index 0000000..ab50919 --- /dev/null +++ b/MuckyBasic/d3dframe.cpp @@ -0,0 +1,755 @@ +//----------------------------------------------------------------------------- +// File: D3DFrame.cpp +// +// Desc: Class to manage the Direct3D environment objects such as buffers, +// viewports, and 3D devices. +// +// The class is initialized with the Initialize() function, after which +// the Get????() functions can be used to access the objects needed for +// rendering. If the device or display needs to be changed, the +// ChangeDevice() function can be called. If the display window is moved +// the changes need to be reported with the Move() function. +// +// After rendering a frame, the ShowFrame() function filps or blits the +// backbuffer contents to the primary. If surfaces are lost, they can be +// restored with the RestoreSurfaces() function. Finally, if normal +// Windows output is needed, the FlipToGDISurface() provides a GDI +// surface to draw on. +// +// +// Copyright (c) 1995-1998 by Microsoft, all rights reserved +//----------------------------------------------------------------------------- + +#define STRICT +#include +#include "D3DFrame.h" +#include "D3DUtil.h" + + + + +//----------------------------------------------------------------------------- +// 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; +} + + + + +//----------------------------------------------------------------------------- +// Name: CD3DFramework() +// Desc: The constructor. Clears static variables +//----------------------------------------------------------------------------- +CD3DFramework::CD3DFramework() +{ + m_hWnd = NULL; + m_bIsFullscreen = FALSE; + m_dwRenderWidth = 0L; + m_dwRenderHeight = 0L; + m_pddsFrontBuffer = NULL; + m_pddsBackBuffer = NULL; + m_pddsRenderTarget = NULL; + m_pddsZBuffer = NULL; + m_pd3dDevice = NULL; + m_pvViewport = NULL; + m_pDD = NULL; + m_pD3D = NULL; + m_dwDeviceMemType = NULL; +} + + + + +//----------------------------------------------------------------------------- +// Name: ~CD3DFramework() +// Desc: The destructor. Deletes all objects +//----------------------------------------------------------------------------- +CD3DFramework::~CD3DFramework() +{ + DestroyObjects(); +} + + + + +//----------------------------------------------------------------------------- +// Name: DestroyObjects() +// Desc: Cleans everything up upon deletion. This code returns an error +// if any of the objects have remaining reference counts. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::DestroyObjects() +{ + LONG nDD = 0L; // Number of outstanding DDraw references + LONG nD3D = 0L; // Number of outstanding D3DDevice references + + SAFE_RELEASE( m_pvViewport ); + + // Do a safe check for releasing the D3DDEVICE. RefCount must be zero. + if( m_pd3dDevice ) + if( 0 < ( nD3D = m_pd3dDevice->Release() ) ) + DEBUG_MSG( TEXT("Error: D3DDevice object is still referenced!") ); + m_pd3dDevice = NULL; + + // In windowed mode, release the explicity created backbuffer. + if( FALSE == m_bIsFullscreen ) + SAFE_RELEASE( m_pddsBackBuffer ); + SAFE_RELEASE( m_pddsRenderTarget ); //Note: release before frontbuffer + SAFE_RELEASE( m_pddsZBuffer ); + SAFE_RELEASE( m_pddsFrontBuffer ); + SAFE_RELEASE( m_pD3D ); + + // Do a safe check for releasing DDRAW. RefCount must be zero. + if( m_pDD ) + { + m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ); + + if( 0 < ( nDD = m_pDD->Release() ) ) + DEBUG_MSG( TEXT("Error: DDraw object is still referenced!") ); + } + m_pDD = NULL; + + // Return successful, unless there are outstanding DD or D3DDevice refs. + return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT; +} + + + + +//----------------------------------------------------------------------------- +// Name: Initialize() +// Desc: Creates the internal objects for the framework +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::Initialize( HWND hWnd, GUID* pDriverGUID, + GUID* pDeviceGUID, DDSURFACEDESC2* pMode, + DWORD dwFlags ) +{ + HRESULT hr; + + // Check params. A NULL mode is valid for windowed modes only. A NULL + // device GUID is legal for apps that only want 2D support. + if( NULL==hWnd || ( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) ) + return E_INVALIDARG; + + // Setup state for windowed/fullscreen mode + m_hWnd = hWnd; + m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? TRUE : FALSE; + + // Create the D3D rendering environment (surfaces, device, viewport, etc.) + if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode, + dwFlags ) ) ) + { + DestroyObjects(); + if( E_FAIL == hr ) + hr = D3DFWERR_INITIALIZATIONFAILED; + } + return hr; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateEnvironment() +// Desc: Creates the internal objects for the framework +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID, + DDSURFACEDESC2* pMode, DWORD dwFlags ) +{ + HRESULT hr; + + // Create the DDraw object + if( FAILED( hr = CreateDirectDraw( pDriverGUID, dwFlags ) ) ) + return hr; + + // Create the Direct3D object + if( pDeviceGUID ) + if( FAILED( hr = CreateDirect3D( pDeviceGUID, dwFlags ) ) ) + return hr; + + // Create the front and back buffers, and attach a clipper + if( FAILED( hr = CreateBuffers( pMode, dwFlags ) ) ) + return hr; + + // If there is no device GUID, then the app only wants 2D, so we're done + if( NULL == pDeviceGUID ) + return S_OK; + + // Create and attach the zbuffer + if( dwFlags & D3DFW_ZBUFFER ) + if( FAILED( hr = CreateZBuffer() ) ) + return hr; + + // Query the render buffer for the 3ddevice + if( FAILED( hr = Create3DDevice( pDeviceGUID ) ) ) + return hr; + + // Create and set the viewport + if( FAILED( hr = CreateViewport() ) ) + return hr; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateDirectDraw() +// Desc: Create the DirectDraw interface +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags ) +{ + // Create the DirectDraw interface, and query for the DD4 interface + LPDIRECTDRAW pDD; + if( FAILED( DirectDrawCreate( pDriverGUID, &pDD, NULL ) ) ) + { + DEBUG_MSG( TEXT("Could not create DirectDraw") ); + return D3DFWERR_NODIRECTDRAW; + } + + if( FAILED( pDD->QueryInterface( IID_IDirectDraw4, (VOID**)&m_pDD ) ) ) + { + pDD->Release(); + DEBUG_MSG( TEXT("Couldn't query for DirectDraw4") ); + return D3DFWERR_NODIRECTDRAW; + } + pDD->Release(); + + // Set the Windows cooperative level + DWORD dwCoopFlags = DDSCL_NORMAL; + if( m_bIsFullscreen ) + dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN; + + // By defualt, set the flag to allow D3D to optimize floating point calcs + if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) ) + dwCoopFlags |= DDSCL_FPUSETUP; + + if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) ) + { + DEBUG_MSG( TEXT("Couldn't set coop level") ); + return D3DFWERR_COULDNTSETCOOPLEVEL; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateDirect3D() +// Desc: Create the Direct3D interface +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::CreateDirect3D( GUID* pDeviceGUID, DWORD dwFlags ) +{ + // Query DirectDraw for access to Direct3D + if( FAILED( m_pDD->QueryInterface( IID_IDirect3D3, (VOID**)&m_pD3D ) ) ) + { + DEBUG_MSG( TEXT("Couldn't query the Direct3D interface") ); + return D3DFWERR_NODIRECT3D; + } + + // Use the FindDevice() method to test if the requested device + // exists, and if so, take note of what memory type it takes. + D3DFINDDEVICERESULT devResult; + D3DFINDDEVICESEARCH devSearch; + ZeroMemory( &devResult, sizeof(D3DFINDDEVICERESULT) ); + ZeroMemory( &devSearch, sizeof(D3DFINDDEVICESEARCH) ); + devResult.dwSize = sizeof(D3DFINDDEVICERESULT); + devSearch.dwSize = sizeof(D3DFINDDEVICESEARCH); + devSearch.dwFlags = D3DFDS_GUID; + CopyMemory( &devSearch.guid, pDeviceGUID, sizeof(GUID) ); + + if( FAILED( m_pD3D->FindDevice( &devSearch, &devResult ) ) ) + { + DEBUG_MSG( TEXT("Couldn't find the specified device") ); + return D3DFWERR_NODIRECT3D; + } + + // Whether device is SW or HW, get the devicedesc, and the defualt memtype + if( 0L == devResult.ddHwDesc.dwFlags ) + { + m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY; + memcpy( &m_ddDeviceDesc, &devResult.ddSwDesc, sizeof(D3DDEVICEDESC) ); + } + else + { + m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY; + memcpy( &m_ddDeviceDesc, &devResult.ddHwDesc, sizeof(D3DDEVICEDESC) ); + } + + // Using the device GUID, let's enumerate a format for our z-buffer, in + // case we later decide to create one. + ZeroMemory( &m_ddpfZBuffer, sizeof(DDPIXELFORMAT) ); + + if( dwFlags & D3DFW_STENCILBUFFER ) + m_ddpfZBuffer.dwFlags = DDPF_ZBUFFER | DDPF_STENCILBUFFER; + else + m_ddpfZBuffer.dwFlags = DDPF_ZBUFFER; + + // Get an appropiate pixel format from enumeration of the formats. + m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, + (VOID*)&m_ddpfZBuffer ); + + if( sizeof(DDPIXELFORMAT) != m_ddpfZBuffer.dwSize ) + { + DEBUG_MSG( TEXT("Device doesn't support requested zbuffer format") ); + return D3DFWERR_NOZBUFFER; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateBuffers() +// Desc: Creates the primary and (optional) backbuffer for rendering. +// Windowed mode and fullscreen mode are handled differently. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::CreateBuffers( DDSURFACEDESC2* pddsd, DWORD dwFlags ) +{ + HRESULT hr; + + if( dwFlags & D3DFW_FULLSCREEN ) + { + // Get the dimensions of the viewport and screen bounds + // Store the rectangle which contains the renderer + SetRect( &m_rcViewportRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight ); + memcpy( &m_rcScreenRect, &m_rcViewportRect, sizeof(RECT) ); + m_dwRenderWidth = m_rcViewportRect.right; + m_dwRenderHeight = m_rcViewportRect.bottom; + + // Set the display mode to the requested dimensions. Check for + // 320x200x8 modes, and set flag to avoid using ModeX + DWORD dwModeFlags = 0; + + if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) && + (8==pddsd->ddpfPixelFormat.dwRGBBitCount) ) + dwModeFlags |= DDSDM_STANDARDVGAMODE; + + if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight, + pddsd->ddpfPixelFormat.dwRGBBitCount, + pddsd->dwRefreshRate, dwModeFlags ) ) ) + { + DEBUG_MSG( TEXT("Can't set display mode") ); + return D3DFWERR_BADDISPLAYMODE; + } + + // Create the primary surface + DDSURFACEDESC2 ddsd; + D3DUtil_InitSurfaceDesc( ddsd, DDSD_CAPS ); + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; + + // With no backbuffer, the primary becomes the render target + if( dwFlags & D3DFW_BACKBUFFER ) + { + ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + } + + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) + { + DEBUG_MSG( TEXT("Error: Can't create primary surface") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOPRIMARY; + DEBUG_MSG( TEXT("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + // Get the backbuffer. For fullscreen mode, the backbuffer was created + // along with the primary, but windowed mode still needs to create one. + if( dwFlags & D3DFW_BACKBUFFER ) + { + // Get a ptr to the back buffer, which will be our render target + DDSCAPS2 ddscaps; + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps, + &m_pddsBackBuffer ) ) ) + { + DEBUG_MSG( TEXT("Error: Can't get/create the backbuffer") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOBACKBUFFER; + DEBUG_MSG( TEXT("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + } + } + else // Set up buffers for windowed rendering + { + // Get the dimensions of the viewport and screen bounds + GetClientRect( m_hWnd, &m_rcViewportRect ); + GetClientRect( m_hWnd, &m_rcScreenRect ); + ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left ); + ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right ); + m_dwRenderWidth = m_rcViewportRect.right; + m_dwRenderHeight = m_rcViewportRect.bottom; + + // Create the primary surface + DDSURFACEDESC2 ddsd; + D3DUtil_InitSurfaceDesc( ddsd, DDSD_CAPS ); + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + // With no backbuffer, the primary becomes the render target + if( 0L == ( dwFlags & D3DFW_BACKBUFFER ) ) + ddsd.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE; + + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) + { + DEBUG_MSG( TEXT("Error: Can't create primary surface") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOPRIMARY; + DEBUG_MSG( TEXT("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + // If in windowed-mode, create a clipper object + LPDIRECTDRAWCLIPPER pcClipper; + if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't create clipper") ); + return D3DFWERR_NOCLIPPER; + } + + // Associate the clipper with the window + pcClipper->SetHWnd( 0, m_hWnd ); + m_pddsFrontBuffer->SetClipper( pcClipper ); + SAFE_RELEASE( pcClipper ); + + // Get the backbuffer. For fullscreen mode, the backbuffer was created + // along with the primary, but windowed mode still needs to create one. + if( dwFlags & D3DFW_BACKBUFFER ) + { + // Create the back buffer (the render target) + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwWidth = m_dwRenderWidth; + ddsd.dwHeight = m_dwRenderHeight; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't create the backbuffer") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOBACKBUFFER; + DEBUG_MSG( TEXT("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + } + else // For rendering without a backbuffer + { + ClientToScreen( m_hWnd, (POINT*)&m_rcViewportRect.left ); + ClientToScreen( m_hWnd, (POINT*)&m_rcViewportRect.right ); + } + } + + // Set up backbuffer ptr and ref counts + if( dwFlags & D3DFW_BACKBUFFER ) + m_pddsRenderTarget = m_pddsBackBuffer; + else + m_pddsRenderTarget = m_pddsFrontBuffer; + m_pddsRenderTarget->AddRef(); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateZBuffer() +// Desc: Internal function called by Create() to make and attach a zbuffer +// to the renderer +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::CreateZBuffer() +{ + HRESULT hr; + + // Check if the device supports z-bufferless hidden surface removal. If so, + // we don't really need a z-buffer + DWORD dwRasterCaps = m_ddDeviceDesc.dpcTriCaps.dwRasterCaps; + if( dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR ) + return S_OK; + + // Get z-buffer dimensions from the render target + // Setup the surface desc for the z-buffer. + DDSURFACEDESC2 ddsd; + D3DUtil_InitSurfaceDesc( ddsd, DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | + DDSD_PIXELFORMAT ); + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | m_dwDeviceMemType; + ddsd.dwWidth = m_dwRenderWidth; + ddsd.dwHeight = m_dwRenderHeight; + memcpy( &ddsd.ddpfPixelFormat, &m_ddpfZBuffer, sizeof(DDPIXELFORMAT) ); + + // Create and attach a z-buffer + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsZBuffer, NULL ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't create a ZBuffer surface") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOZBUFFER; + DEBUG_MSG( TEXT("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + if( FAILED( m_pddsRenderTarget->AddAttachedSurface( m_pddsZBuffer ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't attach zbuffer to render surface") ); + return D3DFWERR_NOZBUFFER; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: Create3DDevice() +// Desc: Creates the 3D device for the render target +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::Create3DDevice( GUID* pDeviceGUID ) +{ + // Check that we are NOT in a palettized display. That case will fail, + // since the framework doesn't use palettes. + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(DDSURFACEDESC2); + m_pDD->GetDisplayMode( &ddsd ); + if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 ) + return D3DFWERR_INVALIDMODE; + + // Create the device + if( FAILED( m_pD3D->CreateDevice( *pDeviceGUID, m_pddsRenderTarget, + &m_pd3dDevice, NULL ) ) ) + { + DEBUG_MSG( TEXT("Couldn't create the D3DDevice") ); + return D3DFWERR_NO3DDEVICE; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateViewport() +// Desc: Create the D3D viewport used by the renderer. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::CreateViewport() +{ + // Set up the viewport data parameters + HRESULT hr; + D3DVIEWPORT2 vdData; + D3DUtil_InitViewport( vdData, m_dwRenderWidth, m_dwRenderHeight ); + + // Create the viewport + if( FAILED( m_pD3D->CreateViewport( &m_pvViewport, NULL ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't create a viewport") ); + return D3DFWERR_NOVIEWPORT; + } + + // Associate the viewport with the D3DDEVICE object + if( FAILED( hr = m_pd3dDevice->AddViewport( m_pvViewport ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't add the viewport") ); + return D3DFWERR_NOVIEWPORT; + } + + // Set the parameters to the new viewport + if( FAILED( m_pvViewport->SetViewport2( &vdData ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't set the viewport data") ); + return D3DFWERR_NOVIEWPORT; + } + + // Finally, set the current viewport for the current device + if( FAILED( m_pd3dDevice->SetCurrentViewport( m_pvViewport ) ) ) + { + DEBUG_MSG( TEXT("Error: Couldn't set current viewport to device") ); + return D3DFWERR_NOVIEWPORT; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: ShowFrame() +// Desc: Show the frame on the primary surface, via a blt or a flip. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::ShowFrame() +{ + if( NULL == m_pddsFrontBuffer ) + return D3DFWERR_NOTINITIALIZED; + + // Check for a backbuffer. If no backbuffer exists, then we have nothing to + // do. However, to be consistent let's check for lost surfaces + if( NULL == m_pddsBackBuffer ) + return m_pddsFrontBuffer->IsLost(); + + // If we are in fullscreen mode perform a flip. + if( m_bIsFullscreen ) + return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT ); + + // Else, we are in windowed mode, so perform a blit. + return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer, + &m_rcViewportRect, DDBLT_WAIT, NULL ); +} + + + + +//----------------------------------------------------------------------------- +// Name: FlipToGDISurface() +// Desc: Puts the GDI surface in front of the primary, so that dialog +// boxes and other windows drawing funcs may happen. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::FlipToGDISurface( BOOL bDrawFrame ) +{ + if( m_pDD && m_bIsFullscreen ) + { + m_pDD->FlipToGDISurface(); + + if( bDrawFrame ) + { + DrawMenuBar( m_hWnd ); + RedrawWindow( m_hWnd, NULL, NULL, RDW_FRAME ); + } + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: RestoreSurfaces() +// Desc: Checks for lost surfaces and restores them if lost. Note: Don't +// restore render surface, since it's just a duplicate ptr. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::RestoreSurfaces() +{ + // Check/restore the primary surface + if( m_pddsFrontBuffer ) + if( m_pddsFrontBuffer->IsLost() ) + m_pddsFrontBuffer->Restore(); + + // Check/restore the back buffer + if( m_pddsBackBuffer ) + if( m_pddsBackBuffer->IsLost() ) + m_pddsBackBuffer->Restore(); + + // Check/restore the z-buffer surface + if( m_pddsZBuffer ) + if( m_pddsZBuffer->IsLost() ) + m_pddsZBuffer->Restore(); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: Move() +// Desc: Moves the screen rect for windowed renderers +//----------------------------------------------------------------------------- +VOID CD3DFramework::Move( INT x, INT y ) +{ + if( FALSE == m_bIsFullscreen ) + { + SetRect( &m_rcScreenRect, x, y, + x + m_dwRenderWidth, y + m_dwRenderHeight ); + + // If we have no backbuffer, then update viewport rect as well + if( NULL == m_pddsBackBuffer ) + CopyMemory( &m_rcViewportRect, &m_rcScreenRect, sizeof(RECT) ); + } +} + + + + +//----------------------------------------------------------------------------- +// Name: ChangeRenderTarget() +// Desc: Wrapper for the IDirect3DDevice::SetRenderTarget() function, which +// adds functionality to handle an attached z-buffer. Note that this +// function does NOT alter the current viewport +//----------------------------------------------------------------------------- +HRESULT CD3DFramework::ChangeRenderTarget( LPDIRECTDRAWSURFACE4 pddsNewTarget ) +{ + if( NULL == pddsNewTarget ) + return E_INVALIDARG; + + // Get the new render target dimensions + DDSURFACEDESC2 ddsd; + D3DUtil_InitSurfaceDesc( ddsd ); + pddsNewTarget->GetSurfaceDesc( &ddsd ); + m_dwRenderWidth = ddsd.dwWidth; + m_dwRenderHeight = ddsd.dwHeight; + + // If a z-buffer is attached, delete and recreate it + if( NULL != m_pddsZBuffer ) + { + // Remove the old z-buffer + m_pddsRenderTarget->DeleteAttachedSurface( 0, m_pddsZBuffer ); + SAFE_RELEASE( m_pddsZBuffer ); + + // Keep track of reference counts + SAFE_RELEASE( m_pddsRenderTarget ); + m_pddsRenderTarget = pddsNewTarget; + m_pddsRenderTarget->AddRef(); + + // Create the new z-buffer + if( FAILED( CreateZBuffer() ) ) + { + DEBUG_MSG( TEXT("ChangeRenderTarget() - zbuffer create failed") ); + return D3DFWERR_NOZBUFFER; + } + } + else + { + // With no z-buffer, we just do accounting on the reference counts + SAFE_RELEASE( m_pddsRenderTarget ); + m_pddsRenderTarget = pddsNewTarget; + m_pddsRenderTarget->AddRef(); + } + + // Finally, perform the set render target call + if( FAILED( m_pd3dDevice->SetRenderTarget( m_pddsRenderTarget, 0 ) ) ) + { + return D3DFWERR_NORENDERTARGET; + } + + return S_OK; +} + + + + + diff --git a/MuckyBasic/d3dframe.h b/MuckyBasic/d3dframe.h new file mode 100644 index 0000000..fdbb26d --- /dev/null +++ b/MuckyBasic/d3dframe.h @@ -0,0 +1,135 @@ +//----------------------------------------------------------------------------- +// File: D3DFrame.h +// +// Desc: Class to manage the Direct3D environment objects such as buffers, +// viewports, and 3D devices. +// +// The class is initialized with the Initialize() function, after which +// the Get????() functions can be used to access the objects needed for +// rendering. If the device or display needs to be changed, the +// ChangeDevice() function can be called. If the display window is moved +// the changes need to be reported with the Move() function. +// +// After rendering a frame, the ShowFrame() function filps or blits the +// backbuffer contents to the primary. If surfaces are lost, they can be +// restored with the RestoreSurfaces() function. Finally, if normal +// Windows output is needed, the FlipToGDISurface() provides a GDI +// surface to draw on. +// +// +// Copyright (C) 1997 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + + +#ifndef D3DFRAME_H +#define D3DFRAME_H + +#include +#include + + + + +//----------------------------------------------------------------------------- +// Name: CD3DFramework +// Desc: The Direct3D sample framework class. Maintains the D3D surfaces, +// device, and viewport used for 3D rendering. +//----------------------------------------------------------------------------- +class CD3DFramework +{ + // Internal variables for the framework class + HWND m_hWnd; // The window object + BOOL m_bIsFullscreen; // Fullscreen vs. windowed + DWORD m_dwRenderWidth; // Dimensions of the render target + DWORD m_dwRenderHeight; + RECT m_rcScreenRect; // Screen rect for window + RECT m_rcViewportRect; // Offscreen rect for VPort + LPDIRECTDRAWSURFACE4 m_pddsFrontBuffer; // The primary surface + LPDIRECTDRAWSURFACE4 m_pddsBackBuffer; // The backbuffer surface + LPDIRECTDRAWSURFACE4 m_pddsRenderTarget; // The render target surface + LPDIRECTDRAWSURFACE4 m_pddsZBuffer; // The zbuffer surface + LPDIRECT3DDEVICE3 m_pd3dDevice; // The D3D device + LPDIRECT3DVIEWPORT3 m_pvViewport; // The D3D viewport + LPDIRECTDRAW4 m_pDD; // The DirectDraw object + LPDIRECT3D3 m_pD3D; // The Direct3D object + D3DDEVICEDESC m_ddDeviceDesc; + DWORD m_dwDeviceMemType; + DDPIXELFORMAT m_ddpfZBuffer; // Enumerated zbuffer format + + // Internal functions for the framework class + HRESULT CreateViewport(); + HRESULT Create3DDevice( GUID* ); + HRESULT CreateZBuffer(); + HRESULT CreateBuffers( DDSURFACEDESC2*, DWORD ); + HRESULT CreateDirectDraw( GUID*, DWORD ); + HRESULT CreateDirect3D( GUID*, DWORD ); + HRESULT CreateEnvironment( GUID*, GUID*, DDSURFACEDESC2*, DWORD ); + +public: + // Access functions for DirectX objects + LPDIRECTDRAW4 GetDirectDraw() { return m_pDD; } + LPDIRECT3D3 GetDirect3D() { return m_pD3D; } + LPDIRECT3DDEVICE3 GetD3DDevice() { return m_pd3dDevice; } + LPDIRECT3DVIEWPORT3 GetViewport() { return m_pvViewport; } + LPDIRECTDRAWSURFACE4 GetFrontBuffer() { return m_pddsFrontBuffer; } + LPDIRECTDRAWSURFACE4 GetBackBuffer() { return m_pddsBackBuffer; } + LPDIRECTDRAWSURFACE4 GetRenderSurface() { return m_pddsRenderTarget; } + + // Functions to aid rendering + HRESULT RestoreSurfaces(); + HRESULT ShowFrame(); + HRESULT FlipToGDISurface( BOOL bDrawFrame ); + + // Functions for managing screen and viewport bounds + BOOL IsFullscreen() { return m_bIsFullscreen; } + RECT* GetViewportRect() { return &m_rcViewportRect; } + VOID Move( INT x, INT y ); + + // Functions to support sprite-based rendering + HRESULT ChangeRenderTarget( LPDIRECTDRAWSURFACE4 pddsNewTarget ); + + // Creates the Framework + HRESULT Initialize( HWND hWnd, GUID* pDriverGUID, GUID* pDeviceGUID, + DDSURFACEDESC2* pddsd, DWORD dwFlags ); + HRESULT DestroyObjects(); + + CD3DFramework(); + ~CD3DFramework(); +}; + + + + +//----------------------------------------------------------------------------- +// Flags used for the Initialize() method of a CD3DFramework object +//----------------------------------------------------------------------------- +#define D3DFW_FULLSCREEN 0x00000001 // Use fullscreen mode +#define D3DFW_BACKBUFFER 0x00000002 // Create and use a backbuffer +#define D3DFW_ZBUFFER 0x00000004 // Create and use a zbuffer +#define D3DFW_STENCILBUFFER 0x00000008 // Use a z-buffer w/stenciling +#define D3DFW_NO_FPUSETUP 0x00000010 // Don't use default DDSCL_FPUSETUP flag + + + +//----------------------------------------------------------------------------- +// Errors that the Initialize() and ChangeDriver() calls may return +//----------------------------------------------------------------------------- +#define D3DFWERR_INITIALIZATIONFAILED 0x82000000 +#define D3DFWERR_NODIRECTDRAW 0x82000001 +#define D3DFWERR_COULDNTSETCOOPLEVEL 0x82000002 +#define D3DFWERR_NODIRECT3D 0x82000003 +#define D3DFWERR_NO3DDEVICE 0x82000004 +#define D3DFWERR_NOZBUFFER 0x82000005 +#define D3DFWERR_NOVIEWPORT 0x82000006 +#define D3DFWERR_NOPRIMARY 0x82000007 +#define D3DFWERR_NOCLIPPER 0x82000008 +#define D3DFWERR_BADDISPLAYMODE 0x82000009 +#define D3DFWERR_NOBACKBUFFER 0x8200000a +#define D3DFWERR_NONZEROREFCOUNT 0x8200000b +#define D3DFWERR_NORENDERTARGET 0x8200000c +#define D3DFWERR_INVALIDMODE 0x8200000d +#define D3DFWERR_NOTINITIALIZED 0x8200000e + + +#endif // D3DFRAME_H + diff --git a/MuckyBasic/d3dutil.cpp b/MuckyBasic/d3dutil.cpp new file mode 100644 index 0000000..93d669f --- /dev/null +++ b/MuckyBasic/d3dutil.cpp @@ -0,0 +1,394 @@ +//----------------------------------------------------------------------------- +// File: D3DUtil.cpp +// +// Desc: Shortcut macros and functions for using DX objects +// +// +// Copyright (c) 1997-1998 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#define D3D_OVERLOADS +#define STRICT +#include +#include +#include "D3DUtil.h" + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitDeviceDesc() +// Desc: Helper function called to initialize a D3DDEVICEDESC structure, +//----------------------------------------------------------------------------- +VOID D3DUtil_InitDeviceDesc( D3DDEVICEDESC& ddDevDesc ) +{ + ZeroMemory( &ddDevDesc, sizeof(D3DDEVICEDESC) ); + ddDevDesc.dwSize = sizeof(D3DDEVICEDESC); + ddDevDesc.dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS); + ddDevDesc.dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS); + ddDevDesc.dpcLineCaps.dwSize = sizeof(D3DPRIMCAPS); + ddDevDesc.dpcTriCaps.dwSize = sizeof(D3DPRIMCAPS); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitSurfaceDesc() +// Desc: Helper function called to build a DDSURFACEDESC2 structure, +// typically before calling CreateSurface() or GetSurfaceDesc() +//----------------------------------------------------------------------------- +VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags, + DWORD dwCaps ) +{ + ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) ); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = dwFlags; + ddsd.ddsCaps.dwCaps = dwCaps; + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitViewport() +// Desc: Helper function called to build a D3DVIEWPORT3 structure +//----------------------------------------------------------------------------- +VOID D3DUtil_InitViewport( D3DVIEWPORT2& vp, DWORD dwWidth, DWORD dwHeight ) +{ + ZeroMemory( &vp, sizeof(D3DVIEWPORT2) ); + vp.dwSize = sizeof(D3DVIEWPORT2); + + vp.dwX = 0; + vp.dwY = 0; + vp.dwWidth = dwWidth; + vp.dwHeight = dwHeight; + vp.dvMaxZ = 1.0f; + + vp.dvClipX = -1.0f; + vp.dvClipWidth = 2.0f; + vp.dvClipY = 1.0f; + vp.dvClipHeight = 2.0f; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitMaterial() +// Desc: Helper function called to build a D3DMATERIAL structure +//----------------------------------------------------------------------------- +VOID D3DUtil_InitMaterial( D3DMATERIAL& mtrl, FLOAT r, FLOAT g, FLOAT b ) +{ + ZeroMemory( &mtrl, sizeof(D3DMATERIAL) ); + mtrl.dwSize = sizeof(D3DMATERIAL); + mtrl.dcvDiffuse.r = mtrl.dcvAmbient.r = r; + mtrl.dcvDiffuse.g = mtrl.dcvAmbient.g = g; + mtrl.dcvDiffuse.b = mtrl.dcvAmbient.b = b; + mtrl.dwRampSize = 16L; // A default ramp size +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitLight() +// Desc: Initializes a D3DLIGHT structure +//----------------------------------------------------------------------------- +VOID D3DUtil_InitLight( D3DLIGHT& light, D3DLIGHTTYPE ltType, + FLOAT x, FLOAT y, FLOAT z ) +{ + ZeroMemory( &light, sizeof(D3DLIGHT) ); + light.dwSize = sizeof(D3DLIGHT); + light.dltType = ltType; + light.dcvColor.r = 1.0f; + light.dcvColor.g = 1.0f; + light.dcvColor.b = 1.0f; + light.dvPosition.x = light.dvDirection.x = x; + light.dvPosition.y = light.dvDirection.y = y; + light.dvPosition.z = light.dvDirection.z = z; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_GetDirectDrawFromDevice() +// Desc: Get the DDraw interface from a D3DDevice. +//----------------------------------------------------------------------------- +LPDIRECTDRAW4 D3DUtil_GetDirectDrawFromDevice( LPDIRECT3DDEVICE3 pd3dDevice ) +{ + LPDIRECTDRAW4 pDD = NULL; + LPDIRECTDRAWSURFACE4 pddsRender; + + if( pd3dDevice ) + { + // Get the current render target + if( SUCCEEDED( pd3dDevice->GetRenderTarget( &pddsRender ) ) ) + { + // Get the DDraw4 interface from the render target + pddsRender->GetDDInterface( (VOID**)&pDD ); + pddsRender->Release(); + } + } + return pDD; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_GetDeviceMemoryType() +// Desc: Retreives the default memory type used for the device. +//----------------------------------------------------------------------------- +DWORD D3DUtil_GetDeviceMemoryType( LPDIRECT3DDEVICE3 pd3dDevice ) +{ + D3DDEVICEDESC ddHwDesc, ddSwDesc; + ddHwDesc.dwSize = sizeof(D3DDEVICEDESC); + ddSwDesc.dwSize = sizeof(D3DDEVICEDESC); + if( FAILED( pd3dDevice->GetCaps( &ddHwDesc, &ddSwDesc ) ) ) + return 0L; + + if( ddHwDesc.dwFlags ) + return DDSCAPS_VIDEOMEMORY; + + return DDSCAPS_SYSTEMMEMORY; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetViewMatrix() +// Desc: Given an eye point, a lookat point, and an up vector, this +// function builds a 4x4 view matrix. +//----------------------------------------------------------------------------- +HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, + D3DVECTOR& vAt, D3DVECTOR& vWorldUp ) +{ + // Get the z basis vector, which points straight ahead. This is the + // difference from the eyepoint to the lookat point. + D3DVECTOR vView = vAt - vFrom; + + FLOAT fLength = Magnitude( vView ); + if( fLength < 1e-6f ) + return E_INVALIDARG; + + // Normalize the z basis vector + vView /= fLength; + + // Get the dot product, and calculate the projection of the z basis + // vector onto the up vector. The projection is the y basis vector. + FLOAT fDotProduct = DotProduct( vWorldUp, vView ); + + D3DVECTOR vUp = vWorldUp - fDotProduct * vView; + + // If this vector has near-zero length because the input specified a + // bogus up vector, let's try a default up vector + if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) + { + vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView; + + // If we still have near-zero length, resort to a different axis. + if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) + { + vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView; + + if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) + return E_INVALIDARG; + } + } + + // Normalize the y basis vector + vUp /= fLength; + + // The x basis vector is found simply with the cross product of the y + // and z basis vectors + D3DVECTOR vRight = CrossProduct( vUp, vView ); + + // Start building the matrix. The first three rows contains the basis + // vectors used to rotate the view to point at the lookat point + D3DUtil_SetIdentityMatrix( mat ); + mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x; + mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y; + mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z; + + // Do the translation values (rotations are still about the eyepoint) + mat._41 = - DotProduct( vFrom, vRight ); + mat._42 = - DotProduct( vFrom, vUp ); + mat._43 = - DotProduct( vFrom, vView ); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetProjectionMatrix() +// Desc: Sets the passed in 4x4 matrix to a perpsective projection matrix built +// from the field-of-view (fov, in y), aspect ratio, near plane (D), +// and far plane (F). Note that the projection matrix is normalized for +// element [3][4] to be 1.0. This is performed so that W-based range fog +// will work correctly. +//----------------------------------------------------------------------------- +HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV, FLOAT fAspect, + FLOAT fNearPlane, FLOAT fFarPlane ) +{ + if( fabs(fFarPlane-fNearPlane) < 0.01f ) + return E_INVALIDARG; + if( fabs(sin(fFOV/2)) < 0.01f ) + return E_INVALIDARG; + + FLOAT w = fAspect * (FLOAT)( cos(fFOV/2)/sin(fFOV/2) ); + FLOAT h = 1.0f * (FLOAT)( cos(fFOV/2)/sin(fFOV/2) ); + FLOAT Q = fFarPlane / ( fFarPlane - fNearPlane ); + + ZeroMemory( &mat, sizeof(D3DMATRIX) ); + mat._11 = w; + mat._22 = h; + mat._33 = Q; + mat._34 = 1.0f; + mat._43 = -Q*fNearPlane; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotateXMatrix() +// Desc: Create Rotation matrix about X axis +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads ) +{ + D3DUtil_SetIdentityMatrix( mat ); + mat._22 = (FLOAT)cos( fRads ); + mat._23 = (FLOAT)sin( fRads ); + mat._32 = -(FLOAT)sin( fRads ); + mat._33 = (FLOAT)cos( fRads ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotateYMatrix() +// Desc: Create Rotation matrix about Y axis +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads ) +{ + D3DUtil_SetIdentityMatrix( mat ); + mat._11 = (FLOAT)cos( fRads ); + mat._13 = -(FLOAT)sin( fRads ); + mat._31 = (FLOAT)sin( fRads ); + mat._33 = (FLOAT)cos( fRads ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotateZMatrix() +// Desc: Create Rotation matrix about Z axis +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads ) +{ + D3DUtil_SetIdentityMatrix( mat ); + mat._11 = (FLOAT)cos( fRads ); + mat._12 = (FLOAT)sin( fRads ); + mat._21 = -(FLOAT)sin( fRads ); + mat._22 = (FLOAT)cos( fRads ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotationMatrix +// Desc: Create a Rotation matrix about vector direction +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, FLOAT fRads ) +{ + FLOAT fCos = (FLOAT)cos( fRads ); + FLOAT fSin = (FLOAT)sin( fRads ); + D3DVECTOR v = Normalize( vDir ); + + mat._11 = ( v.x * v.x ) * ( 1.0f - fCos ) + fCos; + mat._12 = ( v.x * v.y ) * ( 1.0f - fCos ) - (v.z * fSin); + mat._13 = ( v.x * v.z ) * ( 1.0f - fCos ) + (v.y * fSin); + + mat._21 = ( v.y * v.x ) * ( 1.0f - fCos ) + (v.z * fSin); + mat._22 = ( v.y * v.y ) * ( 1.0f - fCos ) + fCos ; + mat._23 = ( v.y * v.z ) * ( 1.0f - fCos ) - (v.x * fSin); + + mat._31 = ( v.z * v.x ) * ( 1.0f - fCos ) - (v.y * fSin); + mat._32 = ( v.z * v.y ) * ( 1.0f - fCos ) + (v.x * fSin); + mat._33 = ( v.z * v.z ) * ( 1.0f - fCos ) + fCos; + + mat._14 = mat._24 = mat._34 = 0.0f; + mat._41 = mat._42 = mat._43 = 0.0f; + mat._44 = 1.0f; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_GetDisplayDepth() +// Desc: Returns the depth of the current display mode. +//----------------------------------------------------------------------------- +DWORD D3DUtil_GetDisplayDepth( LPDIRECTDRAW4 pDD4 ) +{ + // If the caller did not supply a DDraw object, just create a temp one. + if( NULL == pDD4 ) + { + LPDIRECTDRAW pDD1; + if( FAILED( DirectDrawCreate( NULL, &pDD1, NULL ) ) ) + return 0L; + + HRESULT hr = pDD1->QueryInterface( IID_IDirectDraw4, (VOID**)&pDD4 ); + pDD1->Release(); + if( FAILED(hr) ) + return 0L; + } + else + pDD4->AddRef(); + + // Get the display mode description + DDSURFACEDESC2 ddsd; + ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) ); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + pDD4->GetDisplayMode( &ddsd ); + pDD4->Release(); + + // Return the display mode's depth + return ddsd.ddpfPixelFormat.dwRGBBitCount; +} + + + + +//----------------------------------------------------------------------------- +// Name: _DbgOut() +// Desc: Outputs a message to the debug stream +//----------------------------------------------------------------------------- +HRESULT _DbgOut( TCHAR* strFile, DWORD dwLine, HRESULT hr, TCHAR* strMsg ) +{ + TCHAR buffer[256]; + sprintf( buffer, "%s(%ld): ", strFile, dwLine ); + OutputDebugString( buffer ); + OutputDebugString( strMsg ); + + if( hr ) + { + sprintf( buffer, "(hr=%08lx)\n", hr ); + OutputDebugString( buffer ); + } + + OutputDebugString( "\n" ); + + return hr; +} + diff --git a/MuckyBasic/d3dutil.h b/MuckyBasic/d3dutil.h new file mode 100644 index 0000000..f26a6ce --- /dev/null +++ b/MuckyBasic/d3dutil.h @@ -0,0 +1,110 @@ +//----------------------------------------------------------------------------- +// File: D3DUtil.h +// +// Desc: Helper functions and typing shortcuts for Direct3D programming. +// +// +// Copyright (C) 1997 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#ifndef D3DUTIL_H +#define D3DUTIL_H + +#include +#include + + +//----------------------------------------------------------------------------- +// Typing shortcuts for deleting and freeing objects. +//----------------------------------------------------------------------------- +#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } + + + + +//----------------------------------------------------------------------------- +// Short cut functions for creating and using DX structures +//----------------------------------------------------------------------------- +VOID D3DUtil_InitDeviceDesc( D3DDEVICEDESC& ddDevDesc ); +VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags=0, + DWORD dwCaps=0 ); +VOID D3DUtil_InitViewport( D3DVIEWPORT2& vdViewData, DWORD dwWidth=0, + DWORD dwHeight=0 ); +VOID D3DUtil_InitMaterial( D3DMATERIAL& mdMtrlData, FLOAT r=0.0f, FLOAT g=0.0f, + FLOAT b=0.0f ); +VOID D3DUtil_InitLight( D3DLIGHT& ldLightData, D3DLIGHTTYPE ltType, + FLOAT x=0.0f, FLOAT y=0.0f, FLOAT z=0.0f ); + + + + +//----------------------------------------------------------------------------- +// Miscellaneous helper functions +//----------------------------------------------------------------------------- +LPDIRECTDRAW4 D3DUtil_GetDirectDrawFromDevice( LPDIRECT3DDEVICE3 pd3dDevice ); +DWORD D3DUtil_GetDeviceMemoryType( LPDIRECT3DDEVICE3 pd3dDevice ); +DWORD D3DUtil_GetDisplayDepth( LPDIRECTDRAW4 pDD4=NULL ); + + + + +//----------------------------------------------------------------------------- +// D3D Matrix functions. For performance reasons, some functions are inline. +//----------------------------------------------------------------------------- +HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, + D3DVECTOR& vAt, D3DVECTOR& vUp ); +HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV = 1.570795f, + FLOAT fAspect = 1.0f, + FLOAT fNearPlane = 1.0f, + FLOAT fFarPlane = 1000.0f ); + +inline VOID D3DUtil_SetIdentityMatrix( D3DMATRIX& m ) +{ + m._12 = m._13 = m._14 = m._21 = m._23 = m._24 = 0.0f; + m._31 = m._32 = m._34 = m._41 = m._42 = m._43 = 0.0f; + m._11 = m._22 = m._33 = m._44 = 1.0f; +} + +inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, FLOAT tx, FLOAT ty, + FLOAT tz ) +{ D3DUtil_SetIdentityMatrix( m ); m._41 = tx; m._42 = ty; m._43 = tz; } + +inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, D3DVECTOR& v ) +{ D3DUtil_SetTranslateMatrix( m, v.x, v.y, v.z ); } + +inline VOID D3DUtil_SetScaleMatrix( D3DMATRIX& m, FLOAT sx, FLOAT sy, + FLOAT sz ) +{ D3DUtil_SetIdentityMatrix( m ); m._11 = sx; m._22 = sy; m._33 = sz; } + +inline VOID SetScaleMatrix( D3DMATRIX& m, D3DVECTOR& v ) +{ D3DUtil_SetScaleMatrix( m, v.x, v.y, v.z ); } + +VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads ); +VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads ); +VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads ); +VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, + FLOAT fRads ); + + + + +//----------------------------------------------------------------------------- +// Debug printing support +//----------------------------------------------------------------------------- + +HRESULT _DbgOut( TCHAR*, DWORD, HRESULT, TCHAR* ); + +#if defined(DEBUG) | defined(_DEBUG) + #define DEBUG_MSG(str) _DbgOut( __FILE__, (DWORD)__LINE__, 0, str ) + #define DEBUG_ERR(hr,str) _DbgOut( __FILE__, (DWORD)__LINE__, hr, str ) +#else + #define DEBUG_MSG(str) (0L) + #define DEBUG_ERR(hr,str) (hr) +#endif + + + + +#endif // D3DUTIL_H + diff --git a/MuckyBasic/font.cpp b/MuckyBasic/font.cpp new file mode 100644 index 0000000..8c3dae1 --- /dev/null +++ b/MuckyBasic/font.cpp @@ -0,0 +1,480 @@ +// +// A font! That's all there is to it. +// + +#include "always.h" +#include "font.h" +#include "os.h" +#include "tga.h" + + +// +// Each of the letters +// + +typedef struct +{ + float u; + float v; + float uwidth; + +} FONT_Letter; + +#define FONT_LETTER_HEIGHT 20 + +#define FONT_LOWERCASE 0 +#define FONT_UPPERCASE 26 +#define FONT_NUMBERS 52 +#define FONT_PUNCT_PLING 62 +#define FONT_PUNCT_DQUOTE 63 +#define FONT_PUNCT_POUND 64 +#define FONT_PUNCT_DOLLAR 65 +#define FONT_PUNCT_PERCENT 66 +#define FONT_PUNCT_POWER 67 +#define FONT_PUNCT_AMPERSAND 68 +#define FONT_PUNCT_ASTERISK 69 +#define FONT_PUNCT_OPEN 70 +#define FONT_PUNCT_CLOSE 71 +#define FONT_PUNCT_COPEN 72 +#define FONT_PUNCT_CCLOSE 73 +#define FONT_PUNCT_SOPEN 74 +#define FONT_PUNCT_SCLOSE 75 +#define FONT_PUNCT_LT 76 +#define FONT_PUNCT_GT 77 +#define FONT_PUNCT_BSLASH 78 +#define FONT_PUNCT_FSLASH 79 +#define FONT_PUNCT_SEMICOLON 80 +#define FONT_PUNCT_COLON 81 +#define FONT_PUNCT_QUOTE 82 +#define FONT_PUNCT_AT 83 +#define FONT_PUNCT_HASH 84 +#define FONT_PUNCT_TILDE 85 +#define FONT_PUNCT_QMARK 86 +#define FONT_PUNCT_MINUS 87 +#define FONT_PUNCT_EQUALS 88 +#define FONT_PUNCT_PLUS 89 +#define FONT_PUNCT_DOT 90 +#define FONT_PUNCT_COMMA 91 +#define FONT_PUNCT_UNDERSCORE 92 +#define FONT_NUM_FOREIGN 66 +#define FONT_NUM_LETTERS (93 + FONT_NUM_FOREIGN) + +FONT_Letter FONT_letter[FONT_NUM_LETTERS]; + +// +// This is the order the punctuation characters come in. +// + +CBYTE FONT_punct[] = +{ + "!\"£$%^&*(){}[]<>\\/;:'@#~?-=+.,_" + + "©ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüüýþÿ" +}; + + +// +// The texture and another place where we store the font data +// apart from the texture! +// + +OS_Texture *FONT_ot; +TGA_Pixel FONT_data[256][256]; + + + +// +// Returns TRUE if it finds pixel data at (x,y) +// + +SLONG FONT_found_data(SLONG x, SLONG y) +{ + SLONG dy; + + SLONG px; + SLONG py; + + ASSERT(WITHIN(x, 0, 255)); + + for (dy = -15; dy <= 4; dy++) + { + px = x; + py = y + dy; + + if (WITHIN(py, 0, 255)) + { + if (FONT_data[py][px].alpha) + { + return TRUE; + } + } + } + + return FALSE; +} + + + +void FONT_init() +{ + SLONG i; + SLONG y; + SLONG x; + SLONG line; + + FONT_Letter *fl; + + // + // Load the texture. + // + + FONT_ot = OS_texture_create("font_system.tga"); + + // + // Load in the font bitmap. + // + + TGA_Info ti; + + ti = TGA_load( + "Textures\\System\\Fonts\\font_system.tga", + 256, + 256, + &FONT_data[0][0]); + + ASSERT(ti.valid); + ASSERT(ti.width == 256); + ASSERT(ti.height == 256); + + // + // Work out the position of each of the letters. + // + + x = 0; + y = 19; + line = 0; + + for (i = 0; i < FONT_NUM_LETTERS; i++) + { + fl = &FONT_letter[i]; + + // + // Look for the start of the letter. + // + + while(!FONT_found_data(x,y)) + { + x += 1; + + if (x >= 256) + { + x = 0; + line += 1; + y += 22; + + if (y > 256) + { + return; + } + } + } + + fl->u = float(x); + fl->v = float(y); + + // + // Look for the end of the letter. + // + + x += 3; + + while(FONT_found_data(x,y)) + { + x += 1; + } + + fl->uwidth = (x - fl->u) * (1.0F / 256.0F); + + // + // Convert the (u,v)s + // + + fl->u *= 1.0F / 256.0F; + fl->v *= 1.0F / 256.0F; + + fl->v -= 16.0F / 256.0F; + } +} + + +// +// Returns the index of the given character +// + +SLONG FONT_get_index(CBYTE chr) +{ + SLONG letter; + + // + // Find our letter index. + // + + if (WITHIN(chr, 'a', 'z')) + { + letter = FONT_LOWERCASE + chr - 'a'; + } + else + if (WITHIN(chr, 'A', 'Z')) + { + letter = FONT_UPPERCASE + chr - 'A'; + } + else + if (WITHIN(chr, '0', '9')) + { + letter = FONT_NUMBERS + chr - '0'; + } + else + { + // + // Look for the punctuation letter. + // + + letter = FONT_PUNCT_PLING; + + for (CBYTE *ch = FONT_punct; *ch && *ch != chr; ch++, letter++); + } + + if (!WITHIN(letter, 0, FONT_NUM_LETTERS - 1)) + { + letter = FONT_PUNCT_QMARK; + } + + return letter; +} + + +SLONG FONT_char_is_valid(CBYTE ch) +{ + if (FONT_get_index(ch) == FONT_PUNCT_QMARK && ch != '?') + { + return FALSE; + } + else + { + return TRUE; + } +} + + + +float FONT_get_letter_width(CBYTE chr) +{ + SLONG letter; + + if (chr == ' ') + { + return 8.0F / 256.0F; + } + + letter = FONT_get_index(chr); + + ASSERT(WITHIN(letter, 0, FONT_NUM_LETTERS - 1)); + + return FONT_letter[letter].uwidth + (1.0F / 256.0F); +} + + + +float FONT_draw_letter( + OS_Buffer *ob, + CBYTE chr, + float x, + float y, + ULONG colour = 0xffffffff, + ULONG flag = 0, + float scale = 1.0F) +{ + SLONG letter; + float width; + + FONT_Letter *fl; + + if (flag & FONT_FLAG_DROP_SHADOW) + { + FONT_draw_letter( + ob, + chr, + x + 0.008F * scale, + y + 0.008F * scale, + (~colour) | (colour & 0xff000000), + flag & ~FONT_FLAG_DROP_SHADOW, + scale); + } + + // + // Space is a special case! + // + + if (chr == ' ') + { + width = (8.0F / 256.0F) * scale; + } + else + { + letter = FONT_get_index(chr); + + ASSERT(WITHIN(letter, 0, FONT_NUM_LETTERS - 1)); + + fl = &FONT_letter[letter]; + + width = fl->uwidth; + + OS_buffer_add_sprite( + ob, + x, + y, + x + fl->uwidth * scale, + y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + fl->u, + fl->v, + fl->u + fl->uwidth, + fl->v + (FONT_LETTER_HEIGHT / 256.0F), + 0.0F, + colour); + } + + return (width + 1.0F / 256.0F) * scale; +} + +// +// Returns the width of the given string. +// + +float FONT_get_width(CBYTE *str, float scale) +{ + float ans = 0.0F; + + for (CBYTE *ch = str; *ch; ch++) + { + ans += FONT_get_letter_width(*ch) * scale; + } + + return ans; +} + + + + + +void FONT_draw(float start_x, float start_y, ULONG colour, ULONG flag, float scale, SLONG cursor, CBYTE *fmt, ...) +{ + CBYTE message[4096]; + va_list ap; + + if (fmt == NULL) + { + sprintf(message, ""); + } + else + { + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + } + + // + // So that a scale of 1.0F is normal size. + // + + scale *= 0.26F; + + // + // The buffer we use to hold the sprites. + // + + OS_Buffer *ob = OS_buffer_new(); + + // + // Make sure the colour component has alpha- otherwise the + // font will be invisible! + // + + colour |= 0xff000000; + + float x = start_x; + float y = start_y; + + if (flag & FONT_FLAG_JUSTIFY_CENTRE) + { + x -= FONT_get_width(message, scale) * 0.5F; + } + else + if (flag & FONT_FLAG_JUSTIFY_RIGHT) + { + x -= FONT_get_width(message, scale); + } + + CBYTE *ch = message; + + while(*ch) + { + if (iscntrl(*ch)) + { + if (*ch == '\n') + { + x = start_x; + y += (FONT_LETTER_HEIGHT * 1.4F / 256.0F) * scale; + } + } + else + { + if (cursor-- == 0) + { + // + // Draw a cursor here. + // + + { + OS_Buffer *ob = OS_buffer_new(); + + OS_buffer_add_sprite( + ob, + x, y, x + 0.01F * scale, y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + 0.0F, 0.0F, + 1.0F, 1.0F, + 0.0F, + 0xeeeeeff); + + OS_buffer_draw(ob, NULL, NULL, OS_DRAW_DOUBLESIDED | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE); + } + } + + x += FONT_draw_letter(ob, *ch, x, y, colour, flag, scale); + } + + ch += 1; + } + + if (cursor-- == 0) + { + // + // Draw a cursor here. + // + + { + OS_Buffer *ob = OS_buffer_new(); + + OS_buffer_add_sprite( + ob, + x, y, x + 0.01F * scale, y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + 0.0F, 0.0F, + 1.0F, 1.0F, + 0.0F, + 0xeeeeeff); + + OS_buffer_draw(ob, NULL, NULL, OS_DRAW_DOUBLESIDED | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE); + } + } + + OS_buffer_draw(ob, FONT_ot, NULL, OS_DRAW_DOUBLESIDED | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE | OS_DRAW_ALPHABLEND); +} diff --git a/MuckyBasic/font.h b/MuckyBasic/font.h new file mode 100644 index 0000000..7ca3993 --- /dev/null +++ b/MuckyBasic/font.h @@ -0,0 +1,37 @@ +// +// A font! That's all there is to it. +// + +#ifndef _FONT_ +#define _FONT_ + + +// +// Loads in the font texture and calculates the uv's of the letters. +// + +void FONT_init(void); + + + +// +// Returns TRUE if the FONT module can draw the ASCII character. +// + +SLONG FONT_char_is_valid(CBYTE ch); + + +// +// Draws some text. A scale of 1.0F is normal! If cursor is >= 0, then a cursor +// draw after the 'cursor'th character. +// + +#define FONT_FLAG_JUSTIFY_LEFT (1 << 0) +#define FONT_FLAG_JUSTIFY_CENTRE (1 << 1) +#define FONT_FLAG_JUSTIFY_RIGHT (1 << 2) +#define FONT_FLAG_DROP_SHADOW (1 << 3) + +void FONT_draw(float start_x, float start_y, ULONG colour, ULONG flag, float scale, SLONG cursor, CBYTE *fmt, ...); + + +#endif diff --git a/MuckyBasic/icon1.ico b/MuckyBasic/icon1.ico new file mode 100644 index 0000000000000000000000000000000000000000..f0f989e67b044277f5020a2b31d118fdcac5e593 GIT binary patch literal 3310 zcmc(hze{9C9KgSud*J$5Sknjr2^*`k9thZpgj9;xSldl~omT|zRkphl5T?5#2}zO0 zzhDbV5eMwFiIv3#3ETSmoc^Zha3?`OU<@1aOTUP!02BHI4` zLgZV0gQLa?h<2T7Kem$?2hc_-V4*?;FO`DeNCS?(tLj^9f5 zw#qcjF@BQ-h~HsO`_%xs#d>tBT1@ul#39wIJ67cSb%%LLUC%B@_lBFIvYtcTkY|q1 z&B^1`c|xE-@W$upnp^Mr3cW+G?|H?1ajUrFSSs$f4*FyAoO_x+-gHYqGw+E*l#gvcJDCySuxxy}d1)o10So5aiXXAV12bgnzvJarr?m-@ljM zZ@-hl&@J83d5u&wJPbO6&Zv%Wjk;L$mWf4g(OdMo%%OMa9fCve&@+ff@6mho9)(9A zkOOk?DHTsca6=%&BE$DBrsrW`FfbSx3=9zo1_OhE!N6c(h?p=K7z_*s1_MJxhrz&L zU@$Nk7)(G1hk?T=2j5btB8BB?VX?4SSmKspu_U)7vIMoT#4=#COe`!GmRJ@zEF2aN z3x|axmI@9FgN4Duprx~LSQsn}K7QGKDj|8&4>^`ss{<9e9e%OYjts zM(!+5T|xw(Yp|Q}u6vC4BvRrI0 zLnvc^wtW;^@#y+wAB9lN#vkSlU}whqQH-H`kNdCpm+Y(^5kr;PKD&P2&Q@bf>nHoK z*T-0R': + + if (LEX_stream_upto[1] == '=') + { + LEX_stream_upto += 2; + LEX_top.type = LEX_TOKEN_TYPE_GTEQ; + } + else + { + LEX_stream_upto += 1; + LEX_top.type = LEX_TOKEN_TYPE_GT; + } + + return; + + case '<': + + if (LEX_stream_upto[1] == '=') + { + LEX_stream_upto += 2; + LEX_top.type = LEX_TOKEN_TYPE_LTEQ; + } + else + if (LEX_stream_upto[1] == '>') + { + LEX_stream_upto += 2; + LEX_top.type = LEX_TOKEN_TYPE_NOTEQUAL; + } + else + { + LEX_stream_upto += 1; + LEX_top.type = LEX_TOKEN_TYPE_LT; + } + + return; + + case '!': + + if (LEX_stream_upto[1] == '=') + { + LEX_stream_upto += 2; + LEX_top.type = LEX_TOKEN_TYPE_NOTEQUAL; + + return; + } + + break; + + case '.': + + if (isdigit(LEX_stream_upto[1])) + { + // + // This dot is part of a number. + // + + break; + } + else + { + LEX_stream_upto += 1; + LEX_top.type = LEX_TOKEN_TYPE_DOT; + + return; + } + + case '"': + + LEX_stream_upto += 1; + dest = LEX_string_buffer; + + while(1) + { + if (!WITHIN(dest, LEX_string_buffer, LEX_string_buffer + LEX_MAX_STRING_LENGTH - 1)) + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "String constant is too long"; + + return; + } + + if (*LEX_stream_upto == '"') + { + *dest = '\000'; + LEX_stream_upto += 1; + LEX_top.type = LEX_TOKEN_TYPE_STRING; + LEX_top.string = LEX_string_buffer; + + return; + } + else + if (*LEX_stream_upto == '\n') + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "Newline in string constant (did you miss out a close quote on a string!)"; + + return; + } + else + if (*LEX_stream_upto == '\000') + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "End of file found during string constant (did you miss out a close quote on a string!)"; + + return; + } + else + { + *dest++ = *LEX_stream_upto++; + } + } + + // + // Never gets here... + // + + ASSERT(0); + + case '\'': + + // + // Character constant? + // + + LEX_stream_upto += 1; + + if (iscntrl(*LEX_stream_upto)) + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "Bad character in character constant"; + + return; + } + + LEX_top.type = LEX_TOKEN_TYPE_SLUMBER; + LEX_top.slumber = *LEX_stream_upto++; + + if (*LEX_stream_upto != '\'') + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "Character constant isn't terminated with an end quote"; + + return; + } + + LEX_stream_upto++; + + break; + + default: + break; + } + + // + // Number constant? + // + + if (LEX_stream_upto[0] == '0' && (LEX_stream_upto[1] == 'x' || LEX_stream_upto[1] == 'X')) + { + // + // This is a HEX number. + // + + SLONG number = 0; + SLONG num_digits = 0; + + LEX_stream_upto += 2; + + if (!isxdigit(*LEX_stream_upto)) + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "Unfinished hexadecimal constant"; + + return; + } + + while(1) + { + if (isxdigit(*LEX_stream_upto)) + { + number <<= 4; + + if (isdigit(*LEX_stream_upto)) + { + number |= *LEX_stream_upto - '0'; + } + else + { + if (isupper(*LEX_stream_upto)) + { + number |= *LEX_stream_upto - 'A' + 10; + } + else + { + number |= *LEX_stream_upto - 'a' + 10; + } + } + + num_digits += 1; + LEX_stream_upto += 1; + } + else + { + break; + } + } + + if (num_digits > 8) + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "Too many digits in hexadecimal constant"; + + return; + } + + LEX_top.type = LEX_TOKEN_TYPE_SLUMBER; + LEX_top.slumber = number; + + return; + } + else + if (isdigit(*LEX_stream_upto) || *LEX_stream_upto == '.') + { + SLONG doing_fraction = FALSE; + + double number = 0.0F; + double frac = 0.1F; + + while(1) + { + if (isdigit(*LEX_stream_upto)) + { + if (doing_fraction) + { + // + // We are doing the fractional part of a floating point number. + // + + number += float(*LEX_stream_upto - '0') * frac; + frac *= 0.1F; + } + else + { + // + // We are doing the integer part. + // + + number *= 10.0F; + number += float(*LEX_stream_upto - '0'); + } + } + else + if (*LEX_stream_upto == '.') + { + // + // A floating point number. + // + + if (doing_fraction) + { + // + // We've already come across one decimal point! + // + + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "Found two decimal points in a floating point number!"; + + return; + } + else + { + doing_fraction = TRUE; + } + } + else + { + if (doing_fraction) + { + LEX_top.type = LEX_TOKEN_TYPE_FLUMBER; + LEX_top.flumber = (float) number; + } + else + { + LEX_top.type = LEX_TOKEN_TYPE_SLUMBER; + LEX_top.slumber = (SLONG) number; + } + + return; + } + + LEX_stream_upto += 1; + } + } + + // + // A word of some sort? + // + + if (isalpha(*LEX_stream_upto)) + { + // + // Copy the variable into the string buffer. + // + + dest = LEX_string_buffer; + + while(1) + { + if (!WITHIN(dest, LEX_string_buffer, LEX_string_buffer + LEX_MAX_STRING_LENGTH - 1)) + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "Variable name or label is too long"; + + return; + } + + if (isalnum(*LEX_stream_upto) || *LEX_stream_upto == '_') + { + *dest++ = *LEX_stream_upto++; + } + else + { + *dest = '\000'; + + break; + } + } + + // + // Have we found a keyword? + // + + struct + { + CBYTE *keyword; + SLONG token; + + } keyword[] = + { + {"IF", LEX_TOKEN_TYPE_IF }, + {"THEN", LEX_TOKEN_TYPE_THEN }, + {"GOTO", LEX_TOKEN_TYPE_GOTO }, + {"AND", LEX_TOKEN_TYPE_AND }, + {"OR", LEX_TOKEN_TYPE_OR }, + {"NOT", LEX_TOKEN_TYPE_NOT }, + {"REM", NULL }, // This is a special case, LEX removes the rest of the line + {"CALL", LEX_TOKEN_TYPE_CALL }, + {"FUNC", LEX_TOKEN_TYPE_FUNC }, + {"LOCAL", LEX_TOKEN_TYPE_LOCAL }, + {"PRINT", LEX_TOKEN_TYPE_PRINT }, + {"ELSE", LEX_TOKEN_TYPE_ELSE }, + {"TRUE", LEX_TOKEN_TYPE_TRUE }, + {"FALSE", LEX_TOKEN_TYPE_FALSE }, + {"SQRT", LEX_TOKEN_TYPE_SQRT }, + {"ABS", LEX_TOKEN_TYPE_ABS }, + {"INPUT", LEX_TOKEN_TYPE_INPUT }, + {"UNDEFINED", LEX_TOKEN_TYPE_UNDEFINED}, + {"EXIT", LEX_TOKEN_TYPE_EXIT }, + {"GOSUB", LEX_TOKEN_TYPE_GOSUB }, + {"RETURN", LEX_TOKEN_TYPE_RETURN }, + {"XOR", LEX_TOKEN_TYPE_XOR }, + {"FOR", LEX_TOKEN_TYPE_FOR }, + {"TO", LEX_TOKEN_TYPE_TO }, + {"STEP", LEX_TOKEN_TYPE_STEP }, + {"NEXT", LEX_TOKEN_TYPE_NEXT }, + {"RANDOM", LEX_TOKEN_TYPE_RANDOM }, + {"SWAP", LEX_TOKEN_TYPE_SWAP }, + {"MOD", LEX_TOKEN_TYPE_MOD }, + {"ENDIF", LEX_TOKEN_TYPE_ENDIF }, + {"WHILE", LEX_TOKEN_TYPE_WHILE }, + {"LOOP", LEX_TOKEN_TYPE_LOOP }, + {"FUNCTION", LEX_TOKEN_TYPE_FUNCTION }, + {"ENDFUNC", LEX_TOKEN_TYPE_ENDFUNC }, + {"TEXTURE", LEX_TOKEN_TYPE_TEXTURE }, + {"BUFFER", LEX_TOKEN_TYPE_BUFFER }, + {"DRAW", LEX_TOKEN_TYPE_DRAW }, + {"CLS", LEX_TOKEN_TYPE_CLS }, + {"FLIP", LEX_TOKEN_TYPE_FLIP }, + {"KEY", LEX_TOKEN_TYPE_KEY }, + {"INKEY", LEX_TOKEN_TYPE_INKEY }, + {"TIMER", LEX_TOKEN_TYPE_TIMER }, + {"SIN", LEX_TOKEN_TYPE_SIN }, + {"COS", LEX_TOKEN_TYPE_COS }, + {"TAN", LEX_TOKEN_TYPE_TAN }, + {"ASIN", LEX_TOKEN_TYPE_ASIN }, + {"ACOS", LEX_TOKEN_TYPE_ACOS }, + {"ATAN", LEX_TOKEN_TYPE_ATAN }, + {"ATAN2", LEX_TOKEN_TYPE_ATAN2 }, + {"EXPORT", LEX_TOKEN_TYPE_EXPORT }, + {"LEFT", LEX_TOKEN_TYPE_LEFT }, + {"MID", LEX_TOKEN_TYPE_MID }, + {"RIGHT", LEX_TOKEN_TYPE_RIGHT }, + {"LEN", LEX_TOKEN_TYPE_LEN }, + {"!"} + }; + + for (i = 0; keyword[i].keyword[0] != '!'; i++) + { + if (strcmp(keyword[i].keyword, LEX_string_buffer) == 0) + { + if (strcmp(keyword[i].keyword, "REM") == 0) + { + // + // This is a REM statement. Skip to the end of the line + // and return a NEWLINE. + // + + while(1) + { + if (*LEX_stream_upto == '\n') + { + LEX_stream_upto++; + LEX_top.type = LEX_TOKEN_TYPE_NEWLINE; + + LEX_last_token_newline = TRUE; + + return; + } + + if (*LEX_stream_upto == '\000') + { + LEX_top.type = LEX_TOKEN_TYPE_NEWLINE; + + LEX_last_token_newline = TRUE; + + return; + } + + LEX_stream_upto++; + } + + // + // Never gets here + // + + ASSERT(0); + } + + if (LEX_last_token_newline) + { + // + // If the next character is a ':', then it's an error because + // you can't have a keyword as a label. + // + + if (*LEX_stream_upto == ':') + { + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = "You can't have a keyword as a label"; + + return; + } + } + + LEX_top.type = keyword[i].token; + + return; + } + } + + // + // Is this a label? Is the next character a ':'? + // + + if (*LEX_stream_upto == ':') + { + if (LEX_last_token_newline) + { + // + // Labels only at the beginning of a line. + // + + strcat(LEX_string_buffer, ":"); + + LEX_stream_upto += 1; + LEX_top.type = LEX_TOKEN_TYPE_LABEL; + LEX_top.label = LEX_string_buffer; + + return; + } + else + { + // + // Otherwise it's a variable followed by a COLON separator. + // + } + } + + // + // Must be a variable. + // + + LEX_top.type = LEX_TOKEN_TYPE_VARIABLE; + LEX_top.variable = LEX_string_buffer; + + return; + } + + // + // Strange character. + // + + sprintf(LEX_string_buffer, "Found a strange character: '%c'", *LEX_stream_upto); + + LEX_top.type = LEX_TOKEN_TYPE_ERROR; + LEX_top.error = LEX_string_buffer; + + return; +} + + + + +void LEX_start(CBYTE *string) +{ + LEX_stream_buffer = string; + LEX_stream_upto = string; + + LEX_top_valid = FALSE; + LEX_last_token_newline = FALSE; +} + +LEX_Token LEX_get() +{ + if (!LEX_top_valid) + { + LEX_find_next_token(); + } + + return LEX_top; +} + +LEX_Token LEX_pop() +{ + LEX_Token ans; + + if (!LEX_top_valid) + { + LEX_find_next_token(); + } + + LEX_top_valid = FALSE; + ans = LEX_top; + + if (LEX_stack_valid) + { + LEX_stack_valid = FALSE; + LEX_top_valid = TRUE; + LEX_top = LEX_stack; + } + + return ans; +} + +void LEX_push(LEX_Token lt) +{ + if (LEX_top_valid) + { + ASSERT(!LEX_stack_valid); + + LEX_stack_valid = TRUE; + LEX_stack = LEX_top; + LEX_top = lt; + } + else + { + LEX_top_valid = TRUE; + LEX_top = lt; + } +} + + +void LEX_next_line() +{ + LEX_Token lt; + + while(1) + { + lt = LEX_pop(); + + if (lt.type == LEX_TOKEN_TYPE_NEWLINE) + { + return; + } + + if (lt.type == LEX_TOKEN_TYPE_EOF) + { + // + // Push the token back on the stack... + // + + LEX_top_valid = TRUE; + + return; + } + } +} diff --git a/MuckyBasic/lex.h b/MuckyBasic/lex.h new file mode 100644 index 0000000..ecf6672 --- /dev/null +++ b/MuckyBasic/lex.h @@ -0,0 +1,161 @@ +// +// A lexical analyser +// + +#ifndef _LEX_ +#define _LEX_ + + +#define LEX_TOKEN_TYPE_EQUALS 0 +#define LEX_TOKEN_TYPE_PLUS 1 +#define LEX_TOKEN_TYPE_MINUS 2 +#define LEX_TOKEN_TYPE_TIMES 3 +#define LEX_TOKEN_TYPE_DIVIDE 4 +#define LEX_TOKEN_TYPE_SLUMBER 5 +#define LEX_TOKEN_TYPE_FLUMBER 6 +#define LEX_TOKEN_TYPE_STRING 7 +#define LEX_TOKEN_TYPE_VARIABLE 8 +#define LEX_TOKEN_TYPE_IF 9 +#define LEX_TOKEN_TYPE_THEN 10 +#define LEX_TOKEN_TYPE_GOTO 11 +#define LEX_TOKEN_TYPE_LABEL 12 +#define LEX_TOKEN_TYPE_ERROR 13 +#define LEX_TOKEN_TYPE_NEWLINE 14 +#define LEX_TOKEN_TYPE_EOF 15 +#define LEX_TOKEN_TYPE_GT 16 +#define LEX_TOKEN_TYPE_LT 17 +#define LEX_TOKEN_TYPE_GTEQ 18 +#define LEX_TOKEN_TYPE_LTEQ 19 +#define LEX_TOKEN_TYPE_AND 20 +#define LEX_TOKEN_TYPE_OR 21 +#define LEX_TOKEN_TYPE_NOT 22 +#define LEX_TOKEN_TYPE_DOT 23 +#define LEX_TOKEN_TYPE_OPEN 24 +#define LEX_TOKEN_TYPE_CLOSE 25 +#define LEX_TOKEN_TYPE_CALL 26 +#define LEX_TOKEN_TYPE_FUNC 27 +#define LEX_TOKEN_TYPE_LOCAL 28 +#define LEX_TOKEN_TYPE_OSQUARE 29 // Open square bracket [ +#define LEX_TOKEN_TYPE_CSQUARE 30 // Close square bracket ] +#define LEX_TOKEN_TYPE_PRINT 31 +#define LEX_TOKEN_TYPE_MOD 32 +#define LEX_TOKEN_TYPE_ELSE 33 +#define LEX_TOKEN_TYPE_TRUE 34 +#define LEX_TOKEN_TYPE_FALSE 35 +#define LEX_TOKEN_TYPE_SQRT 36 +#define LEX_TOKEN_TYPE_ABS 37 +#define LEX_TOKEN_TYPE_COMMA 38 +#define LEX_TOKEN_TYPE_INPUT 39 +#define LEX_TOKEN_TYPE_UNDEFINED 40 // The actual word "UNDEFINED" +#define LEX_TOKEN_TYPE_COLON 41 +#define LEX_TOKEN_TYPE_EXIT 42 +#define LEX_TOKEN_TYPE_GOSUB 43 +#define LEX_TOKEN_TYPE_RETURN 44 +#define LEX_TOKEN_TYPE_XOR 45 +#define LEX_TOKEN_TYPE_FOR 46 +#define LEX_TOKEN_TYPE_TO 47 +#define LEX_TOKEN_TYPE_STEP 48 +#define LEX_TOKEN_TYPE_NEXT 49 +#define LEX_TOKEN_TYPE_NOTEQUAL 50 +#define LEX_TOKEN_TYPE_RANDOM 51 +#define LEX_TOKEN_TYPE_SWAP 52 +#define LEX_TOKEN_TYPE_ENDIF 53 +#define LEX_TOKEN_TYPE_WHILE 54 +#define LEX_TOKEN_TYPE_LOOP 55 +#define LEX_TOKEN_TYPE_FUNCTION 56 +#define LEX_TOKEN_TYPE_ENDFUNC 57 +#define LEX_TOKEN_TYPE_TEXTURE 58 +#define LEX_TOKEN_TYPE_BUFFER 59 +#define LEX_TOKEN_TYPE_DRAW 60 +#define LEX_TOKEN_TYPE_CLS 61 +#define LEX_TOKEN_TYPE_FLIP 62 +#define LEX_TOKEN_TYPE_KEY 63 +#define LEX_TOKEN_TYPE_INKEY 64 +#define LEX_TOKEN_TYPE_TIMER 65 +#define LEX_TOKEN_TYPE_SIN 66 +#define LEX_TOKEN_TYPE_COS 67 +#define LEX_TOKEN_TYPE_TAN 68 +#define LEX_TOKEN_TYPE_ASIN 69 +#define LEX_TOKEN_TYPE_ACOS 70 +#define LEX_TOKEN_TYPE_ATAN 71 +#define LEX_TOKEN_TYPE_ATAN2 72 +#define LEX_TOKEN_TYPE_EXPORT 73 +#define LEX_TOKEN_TYPE_LEFT 74 +#define LEX_TOKEN_TYPE_MID 75 +#define LEX_TOKEN_TYPE_RIGHT 76 +#define LEX_TOKEN_TYPE_LEN 77 +#define LEX_TOKEN_TYPE_MATRIX 78 +#define LEX_TOKEN_TYPE_VECTOR 79 +#define LEX_TOKEN_TYPE_DPROD 80 +#define LEX_TOKEN_TYPE_CPROD 81 +#define LEX_TOKEN_TYPE_NORMALISE 82 +#define LEX_TOKEN_TYPE_TRANSPOSE 83 + + + +typedef struct +{ + SLONG type; + SLONG line; + + union + { + SLONG slumber; + float flumber; + CBYTE *string; + CBYTE *variable; + CBYTE *label; + CBYTE *error; + }; + +} LEX_Token; + + +// +// The maximum length of a string constant, variable name or label. +// + +#define LEX_MAX_STRING_LENGTH 1024 + + + + +// +// Starts reading token from the given string. +// + +void LEX_start(CBYTE *string); + + +// +// Returns the next token in the input stream without +// taking it out of the stream. +// + +LEX_Token LEX_get(void); + +// +// Pops the next token from the input stream. +// + +LEX_Token LEX_pop(void); + + +// +// Pushes the given token back onto the input stream. +// + +void LEX_push(LEX_Token lt); + + +// +// Skips to the next line and eats up all the input. Helpful +// for error recovery. +// + +void LEX_next_line(void); + + + + +#endif diff --git a/MuckyBasic/link.cpp b/MuckyBasic/link.cpp new file mode 100644 index 0000000..c99dee3 --- /dev/null +++ b/MuckyBasic/link.cpp @@ -0,0 +1,975 @@ +// +// The linker +// + +#include "always.h" +#include "ml.h" +#include "link.h" +#include "sysvar.h" +#include "st.h" + + + + + + +// +// The data we accumulate as we link. +// + +SLONG *LINK_instruction; +SLONG LINK_instruction_max; +SLONG LINK_instruction_upto; + +CBYTE *LINK_table_data; +SLONG LINK_table_data_max; +SLONG LINK_table_data_upto; + +LINK_Global *LINK_global; +SLONG LINK_global_max; +SLONG LINK_global_upto; + +LINK_Function *LINK_function; +SLONG LINK_function_max; +SLONG LINK_function_upto; + +LINK_Line *LINK_line; +SLONG LINK_line_max; +SLONG LINK_line_upto; + +LINK_Jump *LINK_jump; +SLONG LINK_jump_max; +SLONG LINK_jump_upto; + +LINK_Field *LINK_field; +SLONG LINK_field_max; +SLONG LINK_field_upto; + +LINK_Globalref *LINK_global_ref; +SLONG LINK_global_ref_max; +SLONG LINK_global_ref_upto; + +LINK_Undefref *LINK_undef_ref; +SLONG LINK_undef_ref_max; +SLONG LINK_undef_ref_upto; + +LINK_Fieldref *LINK_field_ref; +SLONG LINK_field_ref_max; +SLONG LINK_field_ref_upto; + +LINK_Datatableref *LINK_data_table_ref; +SLONG LINK_data_table_ref_max; +SLONG LINK_data_table_ref_upto; + +CBYTE *LINK_debug_data; +SLONG LINK_debug_data_max; +SLONG LINK_debug_data_upto; + +// +// Each file. +// + +typedef struct +{ + SLONG first_instruction; + SLONG num_instructions; + + SLONG first_table_datum; + SLONG num_table_data; + + SLONG first_global; + SLONG num_globals; + + SLONG first_function; + SLONG num_functions; + + SLONG first_line; + SLONG num_lines; + + SLONG first_jump; + SLONG num_jumps; + + SLONG first_field; + SLONG num_fields; + + SLONG first_global_ref; + SLONG num_global_refs; + + SLONG first_undef_ref; + SLONG num_undef_refs; + + SLONG first_field_ref; + SLONG num_field_refs; + + SLONG first_data_table_ref; + SLONG num_data_table_refs; + + SLONG first_debug_datum; + SLONG num_debug_data; + +} LINK_File; + +LINK_File *LINK_file; +SLONG LINK_file_max; +SLONG LINK_file_upto; + + + +// +// The number of globals and fields in the executable. +// + +SLONG LINK_global_id_upto; +SLONG LINK_field_id_upto; + + + + + + + + +// +// Allocates initial memory. +// + +void LINK_allocate_memory(void) +{ + LINK_instruction_max = 1; + LINK_instruction_upto = 0; + LINK_instruction = (SLONG *) malloc(sizeof(SLONG) * LINK_instruction_max); + + LINK_table_data_max = 1; + LINK_table_data_upto = 0; + LINK_table_data = (CBYTE *) malloc(sizeof(CBYTE) * LINK_table_data_max); + + LINK_global_max = 1; + LINK_global_upto = 0; + LINK_global = (LINK_Global *) malloc(sizeof(LINK_Global) * LINK_global_max); + + LINK_function_max = 1; + LINK_function_upto = 0; + LINK_function = (LINK_Function *) malloc(sizeof(LINK_Function) * LINK_function_max); + + LINK_line_max = 1; + LINK_line_upto = 0; + LINK_line = (LINK_Line *) malloc(sizeof(LINK_Line) * LINK_line_max); + + LINK_jump_max = 1; + LINK_jump_upto = 0; + LINK_jump = (LINK_Jump *) malloc(sizeof(LINK_Jump) * LINK_jump_max); + + LINK_field_max = 1; + LINK_field_upto = 0; + LINK_field = (LINK_Field *) malloc(sizeof(LINK_Field) * LINK_field_max); + + LINK_global_ref_max = 1; + LINK_global_ref_upto = 0; + LINK_global_ref = (LINK_Globalref *) malloc(sizeof(LINK_Globalref) * LINK_global_ref_max); + + LINK_undef_ref_max = 1; + LINK_undef_ref_upto = 0; + LINK_undef_ref = (LINK_Undefref *) malloc(sizeof(LINK_Undefref) * LINK_undef_ref_max); + + LINK_field_ref_max = 1; + LINK_field_ref_upto = 0; + LINK_field_ref = (LINK_Fieldref *) malloc(sizeof(LINK_Fieldref) * LINK_field_ref_max); + + LINK_data_table_ref_max = 1; + LINK_data_table_ref_upto = 0; + LINK_data_table_ref = (LINK_Datatableref *) malloc(sizeof(LINK_Datatableref) * LINK_data_table_ref_max); + + LINK_debug_data_max = 1; + LINK_debug_data_upto = 0; + LINK_debug_data = (CBYTE *) malloc(sizeof(CBYTE) * LINK_debug_data_max); + + LINK_file_max = 1; + LINK_file_upto = 0; + LINK_file = (LINK_File *) malloc(sizeof(LINK_File) * LINK_file_max); + +} + + +// +// Frees all memory. +// + +void LINK_free_memory(void) +{ + free(LINK_instruction ); + free(LINK_table_data ); + free(LINK_global ); + free(LINK_function ); + free(LINK_line ); + free(LINK_jump ); + free(LINK_field ); + free(LINK_global_ref ); + free(LINK_undef_ref ); + free(LINK_field_ref ); + free(LINK_data_table_ref); + free(LINK_debug_data ); + free(LINK_file ); + + LINK_instruction = NULL; + LINK_table_data = NULL; + LINK_global = NULL; + LINK_function = NULL; + LINK_line = NULL; + LINK_jump = NULL; + LINK_field = NULL; + LINK_global_ref = NULL; + LINK_undef_ref = NULL; + LINK_field_ref = NULL; + LINK_data_table_ref = NULL; + LINK_debug_data = NULL; + LINK_file = NULL; +} + + + + + + + + +SLONG LINK_do(CBYTE *object_fname[], SLONG num_object_files, CBYTE *exec_fname) +{ + SLONG i; + SLONG j; + SLONG instruction; + SLONG magic; + + LINK_Header lh; + LINK_File *lf; + LINK_Function *lc; + LINK_Jump *lj; + LINK_Global *lg; + LINK_Field *ld; + LINK_Undefref *lu; + LINK_Datatableref *lt; + FILE *handle; + + #define LINK_MAGIC_CHECK() {if (fread(&magic, sizeof(SLONG), 1, handle) != 1) goto file_error; ASSERT(magic == 12345678);} + + // + // Initialise all data. + // + + LINK_allocate_memory(); + + // + // Load in each file. + // + + for (i = 0; i < num_object_files; i++) + { + // + // Open the file. + // + + handle = fopen(object_fname[i], "rb"); + + if (handle == NULL) + { + // + // ERROR! Can't open object file... + // + + goto file_error; + } + + // + // Load in the header. + // + + if (fread(&lh, sizeof(LINK_Header), 1, handle) != 1) goto file_error; + + // + // Correct version number? + // + + if (lh.version != 1) + { + // + // ERROR! + // + } + + // + // Get another LINK_File. + // + + if (LINK_file_upto >= LINK_file_max) + { + LINK_file_max *= 2; + LINK_file = (LINK_File *) realloc(LINK_file, sizeof(LINK_File) * LINK_file_max); + } + + lf = &LINK_file[LINK_file_upto++]; + + // + // Initialise. + // + + memset(lf, 0, sizeof(LINK_File)); + + // + // Instructions. + // + + lf->first_instruction = LINK_instruction_upto; + lf->num_instructions = lh.num_instructions; + + while(LINK_instruction_upto + lh.num_instructions > LINK_instruction_max) + { + LINK_instruction_max *= 2; + LINK_instruction = (SLONG *) realloc(LINK_instruction, sizeof(SLONG) * LINK_instruction_max); + } + + if (fread(LINK_instruction + LINK_instruction_upto, sizeof(SLONG), lh.num_instructions, handle) != lh.num_instructions) goto file_error; + + LINK_instruction_upto += lh.num_instructions; + + LINK_MAGIC_CHECK(); + + // + // The data table. + // + + lf->first_table_datum = LINK_table_data_upto; + lf->num_table_data = lh.data_table_length_in_bytes; + + while(LINK_table_data_upto + lh.data_table_length_in_bytes > LINK_table_data_max) + { + LINK_table_data_max *= 2; + LINK_table_data = (CBYTE *) realloc(LINK_table_data, sizeof(CBYTE) * LINK_table_data_max); + } + + if (fread(LINK_table_data + LINK_table_data_upto, sizeof(CBYTE), lh.data_table_length_in_bytes, handle) != lh.data_table_length_in_bytes) goto file_error; + + LINK_table_data_upto += lh.data_table_length_in_bytes; + + LINK_MAGIC_CHECK(); + + // + // Globals. + // + + lf->first_global = LINK_global_upto; + lf->num_globals = lh.num_globals; + + while(LINK_global_upto + lh.num_globals > LINK_global_max) + { + LINK_global_max *= 2; + LINK_global = (LINK_Global *) realloc(LINK_global, sizeof(LINK_Global) * LINK_global_max); + } + + if (fread(LINK_global + LINK_global_upto, sizeof(LINK_Global), lh.num_globals, handle) != lh.num_globals) goto file_error; + + LINK_global_upto += lh.num_globals; + + LINK_MAGIC_CHECK(); + + // + // Functions. + // + + lf->first_function = LINK_function_upto; + lf->num_functions = lh.num_functions; + + while(LINK_function_upto + lh.num_functions > LINK_function_max) + { + LINK_function_max *= 2; + LINK_function = (LINK_Function *) realloc(LINK_function, sizeof(LINK_Function) * LINK_function_max); + } + + if (fread(LINK_function + LINK_function_upto, sizeof(LINK_Function), lh.num_functions, handle) != lh.num_functions) goto file_error; + + LINK_function_upto += lh.num_functions; + + LINK_MAGIC_CHECK(); + + // + // Lines. + // + + lf->first_line = LINK_line_upto; + lf->num_lines = lh.num_lines; + + while(LINK_line_upto + lh.num_lines > LINK_line_max) + { + LINK_line_max *= 2; + LINK_line = (LINK_Line *) realloc(LINK_line, sizeof(LINK_Line) * LINK_line_max); + } + + if (fread(LINK_line + LINK_line_upto, sizeof(LINK_Line), lh.num_lines, handle) != lh.num_lines) goto file_error; + + LINK_line_upto += lh.num_lines; + + LINK_MAGIC_CHECK(); + + // + // Jumps. + // + + lf->first_jump = LINK_jump_upto; + lf->num_jumps = lh.num_jumps; + + while(LINK_jump_upto + lh.num_jumps > LINK_jump_max) + { + LINK_jump_max *= 2; + LINK_jump = (LINK_Jump *) realloc(LINK_jump, sizeof(LINK_Jump) * LINK_jump_max); + } + + if (fread(LINK_jump + LINK_jump_upto, sizeof(LINK_Jump), lh.num_jumps, handle) != lh.num_jumps) goto file_error; + + LINK_jump_upto += lh.num_jumps; + + LINK_MAGIC_CHECK(); + + // + // Fields. + // + + lf->first_field = LINK_field_upto; + lf->num_fields = lh.num_fields; + + while(LINK_field_upto + lh.num_fields > LINK_field_max) + { + LINK_field_max *= 2; + LINK_field = (LINK_Field *) realloc(LINK_field, sizeof(LINK_Field) * LINK_field_max); + } + + if (fread(LINK_field + LINK_field_upto, sizeof(LINK_Field), lh.num_fields, handle) != lh.num_fields) goto file_error; + + LINK_field_upto += lh.num_fields; + + LINK_MAGIC_CHECK(); + + // + // Globalrefs. + // + + lf->first_global_ref = LINK_global_ref_upto; + lf->num_global_refs = lh.num_global_refs; + + while(LINK_global_ref_upto + lh.num_global_refs > LINK_global_ref_max) + { + LINK_global_ref_max *= 2; + LINK_global_ref = (LINK_Globalref *) realloc(LINK_global_ref, sizeof(LINK_Globalref) * LINK_global_ref_max); + } + + if (fread(LINK_global_ref + LINK_global_ref_upto, sizeof(LINK_Globalref), lh.num_global_refs, handle) != lh.num_global_refs) goto file_error; + + LINK_global_ref_upto += lh.num_global_refs; + + LINK_MAGIC_CHECK(); + + // + // Undefined function references. + // + + lf->first_undef_ref = LINK_undef_ref_upto; + lf->num_undef_refs = lh.num_undef_refs; + + while(LINK_undef_ref_upto + lh.num_undef_refs > LINK_undef_ref_max) + { + LINK_undef_ref_max *= 2; + LINK_undef_ref = (LINK_Undefref *) realloc(LINK_undef_ref, sizeof(LINK_Undefref) * LINK_undef_ref_max); + } + + if (fread(LINK_undef_ref + LINK_undef_ref_upto, sizeof(LINK_Undefref), lh.num_undef_refs, handle) != lh.num_undef_refs) goto file_error; + + LINK_undef_ref_upto += lh.num_undef_refs; + + LINK_MAGIC_CHECK(); + + // + // Fieldrefs. + // + + lf->first_field_ref = LINK_field_ref_upto; + lf->num_field_refs = lh.num_field_refs; + + while(LINK_field_ref_upto + lh.num_field_refs > LINK_field_ref_max) + { + LINK_field_ref_max *= 2; + LINK_field_ref = (LINK_Fieldref *) realloc(LINK_field_ref, sizeof(LINK_Fieldref) * LINK_field_ref_max); + } + + if (fread(LINK_field_ref + LINK_field_ref_upto, sizeof(LINK_Fieldref), lh.num_field_refs, handle) != lh.num_field_refs) goto file_error; + + LINK_field_ref_upto += lh.num_field_refs; + + LINK_MAGIC_CHECK(); + + // + // Data table refs. + // + + lf->first_data_table_ref = LINK_data_table_ref_upto; + lf->num_data_table_refs = lh.num_data_table_refs; + + while(LINK_data_table_ref_upto + lh.num_data_table_refs > LINK_data_table_ref_max) + { + LINK_data_table_ref_max *= 2; + LINK_data_table_ref = (LINK_Datatableref *) realloc(LINK_data_table_ref, sizeof(LINK_Datatableref) * LINK_data_table_ref_max); + } + + if (fread(LINK_data_table_ref + LINK_data_table_ref_upto, sizeof(LINK_Datatableref), lh.num_data_table_refs, handle) != lh.num_data_table_refs) goto file_error; + + LINK_data_table_ref_upto += lh.num_data_table_refs; + + LINK_MAGIC_CHECK(); + + // + // Load in the debug data. + // + + lf->first_debug_datum = LINK_debug_data_upto; + + if (fread(&lf->num_debug_data, sizeof(SLONG), 1, handle) != 1) goto file_error; + + while(LINK_debug_data_upto + lf->num_debug_data > LINK_debug_data_max) + { + LINK_debug_data_max *= 2; + LINK_debug_data = (CBYTE *) realloc(LINK_debug_data, sizeof(CBYTE) * LINK_debug_data_max); + } + + if (fread(LINK_debug_data + LINK_debug_data_upto, sizeof(CBYTE), lf->num_debug_data, handle) != lf->num_debug_data) goto file_error; + + LINK_debug_data_upto += lf->num_debug_data; + + // + // Finished. We should have read the entire file. + // + + #ifdef _DEBUG + + // + // Make sure there is no file left! + // + + { + UBYTE junk[1024]; + SLONG read; + + read = fread(junk, 1, 1024, handle); + + ASSERT(read == 0); + } + + #endif + + // + // Finished reading the file. + // + + fclose(handle); + } + + // + // Add all exported globals, fields and exported functions + // to the symbol table. This helps us allocate global_ids + // and field_ids and resolve calls to functions across files. + // + + ST_clear_all(); + SYSVAR_init(); + + LINK_global_id_upto = 0; + LINK_field_id_upto = SYSVAR_FIELD_NUMBER; + + for (i = 0; i < LINK_file_upto; i++) + { + lf = &LINK_file[i]; + + // + // Overwrite each global's index field with the new global_id. + // + + for (j = 0; j < lf->num_globals; j++) + { + lg = &LINK_global[lf->first_global + j]; + + if (lg->export) + { + ASSERT(WITHIN(lg->name + lf->first_debug_datum, 0, LINK_debug_data_upto - 1)); + + // + // Is this global already in the symbol table? + // + + if (ST_find(LINK_debug_data + lg->name + lf->first_debug_datum)) + { + // + // ERROR! Multiply defined exported global. + // + + ASSERT(0); + } + else + { + // + // The global wasn't found. Allocate a new global_id and add + // this global to the symbol table. + // + + lg->index = LINK_global_id_upto++; + + ST_add(ST_TABLE_GLOBAL, LINK_debug_data + lg->name + lf->first_debug_datum, lg->index, 0); + } + } + else + { + ASSERT(WITHIN(lg->name + lf->first_debug_datum, 0, LINK_debug_data_upto - 1)); + + if (lg->local) + { + // + // This global is local for sure, so it needs it's own ID. + // + + lg->index = LINK_global_id_upto++; + } + else + { + // + // Is this global already in the symbol table? + // + + if (ST_find(LINK_debug_data + lg->name + lf->first_debug_datum)) + { + // + // Use the same global id. + // + + lg->index = ST_found_value; + } + else + { + // + // Allocate a new global_id. + // + + lg->index = LINK_global_id_upto++; + } + } + } + } + + // + // Overwrite each field's index field with the new field_id. + // + + for (j = 0; j < lf->num_fields; j++) + { + ld = &LINK_field[lf->first_field + j]; + + ASSERT(WITHIN(ld->name + lf->first_debug_datum, 0, LINK_debug_data_upto - 1)); + + // + // Is this field already in the symbol table? + // + + if (ST_find(LINK_debug_data + ld->name + lf->first_debug_datum)) + { + // + // Use the same field_id. + // + + ld->index = ST_found_value; + } + else + { + // + // Allocate a new field_id and add it to the symbol table. + // + + ld->index = LINK_field_id_upto++; + + ST_add(ST_TABLE_GLOBAL, LINK_debug_data + ld->name + lf->first_debug_datum, ld->index, 0); + } + } + + // + // Add all the exported functions to the symbol table. + // + + for (j = 0; j < lf->num_functions; j++) + { + lc = &LINK_function[lf->first_function + j]; + + if (lc->export) + { + ASSERT(WITHIN(lc->name + lf->first_debug_datum, 0, LINK_debug_data_upto - 1)); + + // + // The value associated with the function is the first instruction + // of the function body. + // + + if (ST_find(LINK_debug_data + lc->name + lf->first_debug_datum)) + { + // + // ERROR! Multiply defined function! + // + + ASSERT(0); + } + else + { + // + // What is the first instruction of the function body? + // + + ASSERT(WITHIN(lc->line_start, 0, lf->num_lines - 1)); + ASSERT(WITHIN(lc->line_start + lf->first_line, 0, LINK_line_upto - 1)); + + instruction = LINK_line[lf->first_line + lc->line_start].instruction; + + ASSERT(WITHIN(instruction, 0, lf->num_instructions - 1)); + + instruction += lf->first_instruction; + + ASSERT(WITHIN(instruction, 0, LINK_instruction_upto - 1)); + + // + // The first two instructions of a function are a GOTO to the + // end of the funciton. This is so that execution will jump + // over the function instead of leaking into it accidentally. + // + + instruction += 2; + + // + // Add the function to the symbol table. + // + + ST_add( + ST_TABLE_GLOBAL, + LINK_debug_data + lc->name + lf->first_debug_datum, + instruction, + 0); + } + } + } + } + + // + // Do the actual linking. + // + + for (i = 0; i < LINK_file_upto; i++) + { + lf = &LINK_file[i]; + + // + // Fix instructions that refer to globals. + // + + for (j = 0; j < lf->num_global_refs; j++) + { + ASSERT(WITHIN(lf->first_global_ref + j, 0, LINK_global_ref_upto - 1)); + + instruction = LINK_global_ref[lf->first_global_ref + j].instruction; + instruction += lf->first_instruction; + + ASSERT(WITHIN(instruction, 0, LINK_instruction_upto - 1)); + + // + // We have the instruction that contains the old global_id. + // Overwrite it with the new one. + // + + ASSERT(WITHIN(LINK_instruction[instruction], 0, lf->num_globals - 1)); + + LINK_instruction[instruction] = LINK_global[lf->first_global + LINK_instruction[instruction]].index; + } + + // + // Fix instructions that refer to fields. + // + + for (j = 0; j < lf->num_field_refs; j++) + { + ASSERT(WITHIN(lf->first_field_ref + j, 0, LINK_field_ref_upto - 1)); + + instruction = LINK_field_ref[lf->first_field_ref + j].instruction; + instruction += lf->first_instruction; + + ASSERT(WITHIN(instruction, 0, LINK_instruction_upto - 1)); + + // + // We have the instruction that contains the old field_id. + // Overwrite it with the new one. + // + + ASSERT(WITHIN(LINK_instruction[instruction], 0, lf->num_fields - 1)); + + LINK_instruction[instruction] = LINK_field[lf->first_field + LINK_instruction[instruction]].index; + } + + // + // Fix calls to functions across files. + // + + for (j = 0; j < lf->num_undef_refs; j++) + { + ASSERT(WITHIN(lf->first_undef_ref + j, 0, LINK_undef_ref_upto - 1)); + + lu = &LINK_undef_ref[lf->first_undef_ref + j]; + + // + // Look for this undefined function in the symbol table. + // + + ASSERT(WITHIN(lu->name + lf->first_debug_datum, 0, LINK_debug_data_upto - 1)); + + if (!ST_find(LINK_debug_data + lu->name + lf->first_debug_datum)) + { + // + // ERROR! Undefined function. + // + + ASSERT(0); + } + else + { + // + // Write the address of the function into the instructions. + // + + ASSERT(WITHIN(lu->instruction, 0, lf->num_instructions - 1)); + ASSERT(WITHIN(lf->first_instruction + lu->instruction, 0, LINK_instruction_upto - 1)); + ASSERT(WITHIN(ST_found_value, 0, LINK_instruction_upto - 1)); + + LINK_instruction[lf->first_instruction + lu->instruction] = ST_found_value; + } + } + + // + // Fix jumps. + // + + for (j = 0; j < lf->num_jumps; j++) + { + ASSERT(WITHIN(lf->first_jump + j, 0, LINK_jump_upto - 1)); + + lj = &LINK_jump[lf->first_jump + j]; + + ASSERT(WITHIN(lj->instruction, 0, lf->num_instructions - 1)); + ASSERT(WITHIN(lj->instruction + lf->first_instruction, 0, LINK_instruction_upto - 1)); + + LINK_instruction[lf->first_instruction + lj->instruction] += lf->first_instruction; + } + + // + // Fix references into the data table. + // + + for (j = 0; j < lf->num_data_table_refs; j++) + { + ASSERT(WITHIN(lf->first_data_table_ref + j, 0, LINK_data_table_ref_upto - 1)); + + lt = &LINK_data_table_ref[lf->first_data_table_ref + j]; + + ASSERT(WITHIN(lt->instruction, 0, lf->num_instructions - 1)); + ASSERT(WITHIN(lt->instruction + lf->first_instruction, 0, LINK_instruction_upto - 1)); + ASSERT(WITHIN(LINK_instruction[lt->instruction + lf->first_instruction], 0, lf->num_table_data - 1)); + + LINK_instruction[lt->instruction + lf->first_instruction] += lf->first_table_datum; + + ASSERT(WITHIN(LINK_instruction[lt->instruction + lf->first_instruction], 0, LINK_table_data_upto - 1)); + } + + // + // The last instruction of any file is an EXIT. Replace all these + // EXIT instrucitons with NOPs except for the last one. + // + + if (i == LINK_file_upto - 1) + { + // + // This is the last file. + // + } + else + { + ASSERT(WITHIN(lf->first_instruction + lf->num_instructions - 1, 0, LINK_instruction_upto - 1)); + ASSERT(LINK_instruction[lf->first_instruction + lf->num_instructions - 1] == ML_DO_EXIT); + + LINK_instruction[lf->first_instruction + lf->num_instructions - 1] = ML_DO_NOP; + } + } + + // + // Ready to write out the executable now. Create the + // header of an executable. + // + + ML_Header mh; + + mh.version = ML_VERSION_NUMBER; + mh.instructions_memory_in_bytes = LINK_instruction_upto * sizeof(SLONG); + mh.data_table_length_in_bytes = LINK_table_data_upto; + mh.num_globals = LINK_global_upto; + + // + // Open the executable file. + // + + handle = fopen(exec_fname, "wb"); + + if (handle == NULL) + { + // + // ERROR! + // + + goto file_error; + } + + if (fwrite(&mh, sizeof(mh), 1, handle) != 1) goto file_error; + + // + // The instructions. + // + + if (fwrite(LINK_instruction, sizeof(SLONG), LINK_instruction_upto, handle) != LINK_instruction_upto) goto file_error; + + // + // The string table. + // + + if (fwrite(LINK_table_data, sizeof(UBYTE), LINK_table_data_upto, handle) != LINK_table_data_upto) goto file_error; + + fclose(handle); + + // + // All done. + // + + LINK_free_memory(); + + return TRUE; + + file_error:; + + // + // ERROR! + // + + if (handle) + { + fclose(handle); + } + + LINK_free_memory(); + + return FALSE; +} + + + + diff --git a/MuckyBasic/link.h b/MuckyBasic/link.h new file mode 100644 index 0000000..b54a280 --- /dev/null +++ b/MuckyBasic/link.h @@ -0,0 +1,139 @@ +// +// The linker +// + +#ifndef _LINK_ +#define _LINK_ + + +// ======================================================== +// +// STRUCTURES IN THE OBJECT FILE. +// +// ======================================================== + +typedef struct +{ + UWORD index; // This is the number of the global. + UBYTE export; // TRUE => This global is exported + UBYTE local; // TRUE => This global is local to the file. + SLONG name; // Index into the debug data + +} LINK_Global; + +typedef struct +{ + SLONG name; + SLONG export; // TRUE => this function is exported. + SLONG line_start; // The first and last line of the function body + SLONG line_end; + SLONG num_args; // The number of arguments to the function + +} LINK_Function; + +typedef struct +{ + SLONG instruction; // The first instruction generated for this line of code. + +} LINK_Line; + +typedef struct +{ + SLONG instruction; // Index into instruction memory (SLONG *..) that contains a jump address. + +} LINK_Jump; + +typedef struct +{ + SLONG index; // This is the number of the field. + SLONG name; // Index into the debug data. + +} LINK_Field; + +typedef struct +{ + SLONG instruction; // Index into instruction memory that contains a global index. + +} LINK_Globalref; + +typedef struct +{ + SLONG name; // Index into debug data for the name of the undefined function. + SLONG instruction; // Index into instruction memory that should contain the GOSUB jump to the function. + +} LINK_Undefref; + +typedef struct +{ + SLONG instruction; // Index into the instruction memory for which field. + +} LINK_Fieldref; + +typedef struct +{ + SLONG instruction; + +} LINK_Datatableref; + +typedef struct +{ + SLONG version; + SLONG num_instructions; // Each instruction is a SLONG + SLONG data_table_length_in_bytes; + SLONG num_globals; + SLONG num_functions; + SLONG num_lines; + SLONG num_jumps; + SLONG num_fields; + SLONG num_global_refs; + SLONG num_undef_refs; + SLONG num_field_refs; + SLONG num_data_table_refs; + +} LINK_Header; + + +// ======================================================== +// +// THE FORMAT OF THE OBJECT FILE. +// +// ======================================================== + +// +// LINK_Header lh +// +// SLONG Instructions [lh.num_instructions ] Followed by MAGIC SLONG(12345678) +// CBYTE Data table [lh.data_table_length_in_bytes] Followed by MAGIC SLONG(12345678) +// LINK_Global Globals [lh.num_globals ] Followed by MAGIC SLONG(12345678) +// LINK_Function Functions [lh.num_functions ] Followed by MAGIC SLONG(12345678) +// LINK_Line Lines [lh.num_lines ] Followed by MAGIC SLONG(12345678) +// LINK_Jump Jumps [lh.num_jumps ] Followed by MAGIC SLONG(12345678) +// LINK_Field Fields [lh.num_fields ] Followed by MAGIC SLONG(12345678) +// LINK_Globalref Gobal refs [lh.num_global_refs ] Followed by MAGIC SLONG(12345678) +// LINK_Undefref Undefined function refs[lh.num_undefined_funcion_refs] Followed by MAGIC SLONG(12345678) +// LINK_Fieldref Field refs [lh.num_field_refs ] Followed by MAGIC SLONG(12345678) +// LINK_Datatableref Data table refs [lh.num_data_table_refs ] Followed by MAGIC SLONG(12345678) +// +// SLONG debug_data_length_in_bytes +// CBYTE debug data[debug_data_length_in_bytes] +// + + + + +// ======================================================== +// +// THE LINKER +// +// ======================================================== + +// +// Links all the object files into an executable. Returns FALSE on failure. +// + +SLONG LINK_do(CBYTE *object_fname[], SLONG num_object_files, CBYTE *exec_fname); + + + + +#endif diff --git a/MuckyBasic/ll.cpp b/MuckyBasic/ll.cpp new file mode 100644 index 0000000..c3b48a4 --- /dev/null +++ b/MuckyBasic/ll.cpp @@ -0,0 +1,405 @@ +// +// An interface between the low level D3D drawing and +// the virtual machine. +// + +#include "always.h" +#include "ll.h" +#include "mem.h" +#include "os.h" + + + + + +// +// All the textures. +// + +#define LL_MAX_TEXTURES 4096 + +LL_Texture *LL_texture[LL_MAX_TEXTURES]; + + + +// +// All the sounds. +// + +#define LL_MAX_SOUNDS 4096 + +LL_Sound *LL_sound[LL_MAX_SOUNDS]; + + + + + + + + + + +LL_Texture *LL_create_texture(CBYTE *fname) +{ + SLONG i; + + // + // Create the OS texture. + // + + OS_Texture *ot = OS_texture_create(fname); + + // + // Do we already have this texture? + // + + for (i = 0; i < LL_MAX_TEXTURES; i++) + { + if (LL_texture[i] && LL_texture[i]->ot == ot) + { + // + // We already have this texture! + // + + LL_texture[i]->ref_count += 1; + + return LL_texture[i]; + } + } + + // + // Create a new texture. + // + + LL_Texture *lt; + + lt = (LL_Texture *) MEM_alloc(sizeof(LL_Texture)); + lt->ot = ot; + lt->width = OS_texture_width (ot); + lt->height = OS_texture_height(ot); + lt->ref_count = 1; + + // + // Add it to our list of textures. + // + + for (i = 0; i < LL_MAX_TEXTURES; i++) + { + if (LL_texture[i] == NULL) + { + LL_texture[i] = lt; + + return lt; + } + } + + // + // No more textures! + // + + ASSERT(0); + + return NULL; +} + + +void LL_free_texture(LL_Texture *lt) +{ + // + // Free everything! We can't free OS_Textures! + // + + MEM_free(lt); + + // + // Get rid of the reference in the LL_texture[] array. + // + + SLONG i; + + for (i = 0; i < LL_MAX_TEXTURES; i++) + { + if (LL_texture[i] == lt) + { + LL_texture[i] = NULL; + + return; + } + } + + ASSERT(0); +} + + + + + + + +LL_Sound *LL_create_sound(CBYTE *fname) +{ + SLONG i; + + // + // Create the OS sound. + // + + OS_Sound *os = OS_sound_create(fname, OS_SOUND_TYPE_2D); + + // + // Do we already have this sound? + // + + for (i = 0; i < LL_MAX_SOUNDS; i++) + { + if (LL_sound[i] && LL_sound[i]->os == os) + { + // + // We already have this sound! + // + + LL_sound[i]->ref_count += 1; + + return LL_sound[i]; + } + } + + // + // Create a new sound. + // + + LL_Sound *ls; + + ls = (LL_Sound *) MEM_alloc(sizeof(LL_Sound)); + ls->os = os; + ls->ref_count = 1; + + // + // Add it to our list of sounds. + // + + for (i = 0; i < LL_MAX_SOUNDS; i++) + { + if (LL_sound[i] == NULL) + { + LL_sound[i] = ls; + + return ls; + } + } + + // + // No more sounds! + // + + ASSERT(0); + + return NULL; +} + + +void LL_free_sound(LL_Sound *ls) +{ + // + // Free everything! We can't free OS_Sounds! + // + + MEM_free(ls); + + // + // Get rid of the reference in the LL_sound[] array. + // + + SLONG i; + + for (i = 0; i < LL_MAX_SOUNDS; i++) + { + if (LL_sound[i] == ls) + { + LL_sound[i] = NULL; + + return; + } + } + + ASSERT(0); +} + + + + + + + +LL_Buffer *LL_create_buffer( + SLONG type, + void *vert, + SLONG num_verts, + UWORD *index, + SLONG num_indices) +{ + ASSERT( + type == LL_BUFFER_TYPE_TLV || + type == LL_BUFFER_TYPE_LV); + + // + // Create a new buffer. + // + + LL_Buffer *lb = (LL_Buffer *) MEM_alloc(sizeof(LL_Buffer)); + + lb->type = type; + lb->vert_data = vert; + lb->index = index; + lb->num_verts = num_verts; + lb->num_indices = num_indices; + lb->ref_count = 1; + + return lb; +} + + + +void LL_free_buffer(LL_Buffer *lb) +{ + // + // Free up data. + // + + MEM_free(lb->vert); + + if (lb->index) + { + MEM_free(lb->index); + } + + // + // Now free up the actual buffer. + // + + MEM_free(lb); +} + + + + + +// +// Draws a buffer +// + +OS_Vert LL_vert[OS_MAX_TRANS]; + +void LL_draw_buffer( + LL_Buffer *lb, + LL_Texture *lt, // NULL => Draw untextured + ULONG rs) // The LL_RS_* renderstates ORed together. +{ + SLONG i; + + OS_Buffer *ob; + OS_Trans *ot; + OS_Vert *ov; + LL_Tlvert *tl; + + ob = OS_buffer_new(); + + // + // Are there too many points in this buffer? + // + + ASSERT(lb->num_verts <= OS_MAX_TRANS); + + // + // Build the OS_trans and OS_vert buffers. + // + + switch(lb->type) + { + case LL_BUFFER_TYPE_TLV: + + // + // These are already transformed, so we can write + // directly into the OS_trans[] array. + // + + for (i = 0; i < lb->num_verts; i++) + { + ot = &OS_trans [i]; + ov = &LL_vert [i]; + tl = &lb->vert_tl[i]; + + ot->X = tl->x; + ot->Y = tl->y; + ot->Z = tl->rhw; + ot->z = tl->z; + ot->clip = OS_CLIP_TRANSFORMED; + + ov->trans = i; + ov->index = 0; + ov->colour = tl->colour; + ov->specular = tl->specular; + ov->u1 = tl->u; + ov->v1 = tl->v; + ov->u2 = 0.0F; + ov->v2 = 0.0F; + } + + if (lb->index) + { + ASSERT(lb->num_indices % 3 == 0); + + for (i = 0; i < lb->num_indices; i += 3) + { + OS_buffer_add_triangle( + ob, + &LL_vert[lb->index[i + 0]], + &LL_vert[lb->index[i + 1]], + &LL_vert[lb->index[i + 2]]); + } + } + else + { + for (i = 0; i < lb->num_verts; i += 3) + { + OS_buffer_add_triangle( + ob, + &LL_vert[i + 0], + &LL_vert[i + 1], + &LL_vert[i + 2]); + } + } + + break; + + default: + ASSERT(0); + break; + } + + // + // Now draw the buffer. + // + + OS_buffer_draw(ob, (lt) ? lt->ot : NULL, NULL, rs | OS_DRAW_DOUBLESIDED | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE); +} + + + +void LL_cls(ULONG colour, float z) +{ + SLONG r = (colour >> 16) & 0xff; + SLONG g = (colour >> 8) & 0xff; + SLONG b = (colour >> 0) & 0xff; + + ASSERT(WITHIN(z, 0.0F, 1.0F)); + + OS_clear_screen(r,g,b,z); +} + + +void LL_flip() +{ + OS_show(); +} + diff --git a/MuckyBasic/ll.h b/MuckyBasic/ll.h new file mode 100644 index 0000000..cd658fc --- /dev/null +++ b/MuckyBasic/ll.h @@ -0,0 +1,220 @@ +// +// An interface between the low level D3D drawing and +// the virtual machine. +// + +#ifndef _LL_ +#define _LL_ + +#include "os.h" + + + + + +// +// A texture. +// + +typedef struct +{ + OS_Texture *ot; + SLONG width; + SLONG height; + SLONG ref_count; // This is up to you! It is set to 1 when you create the texture. + +} LL_Texture; + + + +// +// The different types of points we can pass to LL_create_buffer. +// + +typedef struct +{ + float x; + float y; + float z; + float rhw; + ULONG colour; + ULONG specular; + float u; + float v; + +} LL_Tlvert; + +typedef struct +{ + float x; + float y; + float z; + ULONG reserved; + ULONG colour; + ULONG specular; + float u; + float v; + +} LL_Lvert; + +typedef struct +{ + float x; + float y; + float z; + float nx; + float ny; + float nz; + float u; + float v; + +} LL_Vert; + + + +// +// A buffer. +// + +#define LL_BUFFER_TYPE_TLV 0 // Transformed and lit +#define LL_BUFFER_TYPE_LV 0 // Just lit +#define LL_BUFFER_TYPE_V 0 // Neither lit nor transformed + +typedef struct +{ + SLONG type; + + union + { + void *vert_data; + LL_Tlvert *vert_tl; + LL_Lvert *vert_l; + LL_Vert *vert; + }; + + UWORD *index; + SLONG num_verts; + SLONG num_indices; + SLONG ref_count; // This is up to you! It is set to 1 when you create the buffer. + +} LL_Buffer; + + +// +// A sound +// + +typedef struct +{ + OS_Sound *os; + SLONG ref_count; + +} LL_Sound; + + + + +// +// Creates a texture from a file. Returns NULL on failure. +// + +LL_Texture *LL_create_texture(CBYTE *fname); + + +// +// Deletes the texture. +// + +void LL_free_texture(LL_Texture *lt); + + + +// +// Loads a sound from a file. Returns NULL on failure. +// + +LL_Sound *LL_create_sound(CBYTE *fname); + +// +// Deletes the sound. +// + +void LL_free_sound(LL_Sound *ls); + + + + + +// +// Creates a buffer. The vertex and index memory should be +// allocated with the MEM module. +// + +LL_Buffer *LL_create_buffer( + SLONG type, + void *vert, + SLONG num_verts, + UWORD *index, // If NULL then this is a LIST buffer rather than an INDEXED buffer. + SLONG num_indices); + +// +// Deletes the buffer. +// + +void LL_free_buffer(LL_Buffer *lb); + + + + +// +// The renderstates you can OR together. +// + +#define LL_RS_NORMAL OS_DRAW_NORMAL +#define LL_RS_ADD OS_DRAW_ADD +#define LL_RS_MULTIPLY OS_DRAW_MULTIPLY +#define LL_RS_CLAMP OS_DRAW_CLAMP +#define LL_RS_DECAL OS_DRAW_DECAL +#define LL_RS_TRANSPARENT OS_DRAW_TRANSPARENT +#define LL_RS_DOUBLESIDED OS_DRAW_DOUBLESIDED +#define LL_RS_NOZWRITE OS_DRAW_NOZWRITE +#define LL_RS_ALPHAREF OS_DRAW_ALPHAREF +#define LL_RS_ZREVERSE OS_DRAW_ZREVERSE +#define LL_RS_ZALWAYS OS_DRAW_ZALWAYS +#define LL_RS_CULLREVERSE OS_DRAW_CULLREVERSE +#define LL_RS_NODITHER OS_DRAW_NODITHER +#define LL_RS_ALPHABLEND OS_DRAW_ALPHABLEND +#define LL_RS_TEX_NONE OS_DRAW_TEX_NONE +#define LL_RS_NOFILTER OS_DRAW_NOFILTER +#define LL_RS_MULBYONE OS_DRAW_MULBYONE + + + + +// +// Draws a buffer +// + +void LL_draw_buffer( + LL_Buffer *lb, + LL_Texture *lt, // NULL => Draw untextured + ULONG rs); // The LL_RS_* renderstates ORed together. + + + +void LL_cls(ULONG colour, float z); + + + + +// +// Flips the screen- actually does a blit or a FLIP depending +// on whether we are running in a window or not. +// + +void LL_flip(void); + + + + +#endif diff --git a/MuckyBasic/main.cpp b/MuckyBasic/main.cpp new file mode 100644 index 0000000..8e179c3 --- /dev/null +++ b/MuckyBasic/main.cpp @@ -0,0 +1,113 @@ +// +// The entrypoint for muckyBASIC +// + +#include "always.h" +#include "cg.h" +#include "console.h" +#include "font.h" +#include "key.h" +#include "link.h" +#include "mem.h" +#include "parse.h" +#include "os.h" +#include "st.h" +#include "sysvar.h" +#include "vm.h" + + + + + + + + + +// +// Compiles the given file. Returns TRUE on success. +// + +SLONG MAIN_compile(CBYTE *input, CBYTE *output) +{ + FILE *handle; + + PARSE_do(input); + + if (PARSE_error_upto) + { + // + // There are errors! + // + + SLONG i; + + for (i = 0; i < PARSE_error_upto; i++) + { + OS_string("%s\n", PARSE_error[i]); + } + + return FALSE; + } + + CG_do(output, CG_OUTPUT_OBJECT_FILE); + + return TRUE; +} + + + + + + + + + + + +void MAIN_main() +{ + FONT_init(); + ST_init(); + + // + // Compile. + // + + if (!MAIN_compile("test.mbs", "MuckyBASIC objects\\test.mbo" )) return; + if (!MAIN_compile("test2.mbs", "MuckyBASIC objects\\test2.mbo")) return; + + // + // Link. + // + + CBYTE *link[] = + { + "MuckyBASIC objects\\test.mbo", + "MuckyBASIC objects\\test2.mbo", + }; + + LINK_do(link, 2, "MuckyBASIC executables\\test.mbe"); + + // + // Run. + // + + VM_run("MuckyBASIC executables\\test.mbe"); + + // + // Wait for a key... + // + + while(1) + { + if (KEY_on[KEY_ESCAPE]) + { + KEY_on[KEY_ESCAPE] = 0; + + break; + } + } + +} + + diff --git a/MuckyBasic/mem.cpp b/MuckyBasic/mem.cpp new file mode 100644 index 0000000..86d8277 --- /dev/null +++ b/MuckyBasic/mem.cpp @@ -0,0 +1,55 @@ +// +// Memory allocation for the virtual machine. +// + +#include "always.h" +#include "mem.h" +#include + + +// +// The number of bytes of memory allocated by malloc() - not +// neccessarily the same number as that passed to MEM_alloc() +// + +SLONG MEM_bytes_used; + + +void *MEM_alloc(SLONG num_bytes) +{ + void *ans; + + ans = malloc(num_bytes); + + ASSERT(ans); + + MEM_bytes_used += _msize(ans); + + return ans; +} + + +void MEM_free(void *memory) +{ + ASSERT(memory); + + MEM_bytes_used -= _msize(memory); + + free(memory); +} + + + + +SLONG MEM_block_size(void *memory) +{ + ASSERT(memory); + + return _msize(memory); +} + + +SLONG MEM_total_bytes_allocated() +{ + return MEM_bytes_used; +} diff --git a/MuckyBasic/mem.h b/MuckyBasic/mem.h new file mode 100644 index 0000000..18a3d88 --- /dev/null +++ b/MuckyBasic/mem.h @@ -0,0 +1,40 @@ +// +// Memory allocation for the virtual machine. +// + +#ifndef _MEM_ +#define _MEM_ + + +// +// Allocates an area of memory. +// + +void *MEM_alloc(SLONG num_bytes); + + +// +// Frees an area of memory allocated with MEM_alloc(); +// + +void MEM_free(void *memory); + + +// +// Returns the length in bytes of the given block. +// + +SLONG MEM_block_size(void *memory); + + + +// +// Returns the total amount of memory allocated in bytes. +// + +SLONG MEM_total_bytes_allocated(void); + + + + +#endif diff --git a/MuckyBasic/ml.h b/MuckyBasic/ml.h new file mode 100644 index 0000000..e1be552 --- /dev/null +++ b/MuckyBasic/ml.h @@ -0,0 +1,243 @@ +// +// The language of our virtual machine and the executable +// file format. +// + +#ifndef _ML_ +#define _ML_ + +#include "ll.h" + + +// +// A memory location in the machine is 8-bytes long and contains +// an ML_Data. There is main memory where globals are held and a +// stack where computations are peformed and local variables are stored. +// There is also a string table (CBYTE[]) where string constants are +// stored. When an ML_Data must store a variable that is more than an +// SLONG it just malloc()s the required memory and then stores a pointer +// to it. +// + +// +// Each instruction... +// + +#define ML_DO_PUSH_CONSTANT 0 // Followed by an 8-byte constant. +#define ML_DO_ADD 1 // Adds the last two items on the stack and replaces them with the answer. +#define ML_DO_PRINT 2 // Pops the last item of the stack and prints it. +#define ML_DO_EXIT 3 // Exits. +#define ML_DO_GOTO 4 // Followed by the instruction to go to. In SLONGs from the beginning of the program. +#define ML_DO_UMINUS 5 // 'Minuses' the last item on the stack. +#define ML_DO_PUSH_GLOBAL_VALUE 6 // Followed by the number of the global to push. +#define ML_DO_MINUS 7 // Does stack[-2] = stack[-2] - stack[-1]; stack -= 1... +#define ML_DO_TIMES 8 // Does stack[-2] = stack[-2] * stack[-1]; stack -= 1... +#define ML_DO_DIVIDE 9 // Does stack[-2] = stack[-2] / stack[-1]; stack -= 1... +#define ML_DO_MOD 10 // Does stack[-2] = stack[-2] % stack[-1]; stack -= 1... +#define ML_DO_IF_FALSE_GOTO 11 // Pops the stack. If it is FALSE then it does a GOTO (next instruction holds address) +#define ML_DO_AND 12 // etc...! +#define ML_DO_OR 13 +#define ML_DO_EQUALS 14 +#define ML_DO_GT 15 +#define ML_DO_LT 16 +#define ML_DO_GTEQ 17 +#define ML_DO_LTEQ 18 +#define ML_DO_NOT 19 +#define ML_DO_SQRT 20 +#define ML_DO_NEWLINE 21 // A PRINT without anything produces a NEWLINE instruction... +#define ML_DO_ABS 22 +#define ML_DO_PUSH_GLOBAL_ADDRESS 23 // Pushes an 'ML_TYPE_POINTER' onto the stack containing the address of the given global. +#define ML_DO_ASSIGN 24 // stack[-2] is a value, stack[-1] is a pointer. Assigns the value to the ML_Data pointed to by stack[-1] +#define ML_DO_PUSH_FIELD_ADDRESS 25 // The next instruction contains the field_id. This function pops off a pointer to a data and pushes on the address of the given field of that bit of data. +#define ML_DO_PUSH_FIELD_VALUE 26 +#define ML_DO_PUSH_ARRAY_ADDRESS 27 // The next instruction contains the dimensions of the array and the indices will already be on the stack +#define ML_DO_PUSH_ARRAY_VALUE 28 +#define ML_DO_PUSH_INPUT 29 // Gets user input as a string and pushes it onto the stack +#define ML_DO_GOSUB 30 +#define ML_DO_RETURN 31 +#define ML_DO_XOR 32 +#define ML_DO_PUSH_GLOBAL_QUICK 33 +#define ML_DO_PUSH_FIELD_QUICK 34 // Pushes the actual field onto the stack- not a copy of it. +#define ML_DO_PUSH_ARRAY_QUICK 35 // Pushes the actual array onto the stack- not a copy of it. +#define ML_DO_NOTEQUAL 36 +#define ML_DO_IF_TRUE_GOTO 37 +#define ML_DO_PUSH_RANDOM_SLUMBER 38 // Pushes a random SLUMBER onto the stack. +#define ML_DO_SWAP 39 // Swaps the contents of the last two ML_TYPE_POINTERs on the stack. +#define ML_DO_ENTERFUNC 40 // Followed by the number of arguments passed to the function. +#define ML_DO_ENDFUNC 41 // Followed by the number of arguments passed to the function. +#define ML_DO_POP 42 // Throws away the value at the top of the stack. +#define ML_DO_PUSH_LOCAL_VALUE 43 +#define ML_DO_PUSH_LOCAL_ADDRESS 44 +#define ML_DO_PUSH_LOCAL_QUICK 45 +#define ML_DO_JNEQ_POP_1 46 // For switch statements. Compares two values on the stack. If not equal it pops one value and jumps otherwise it pops both values. The next SLONG hold where to jump to. +#define ML_DO_TEXTURE 47 +#define ML_DO_BUFFER 48 +#define ML_DO_DRAW 49 +#define ML_DO_CLS 50 +#define ML_DO_FLIP 51 +#define ML_DO_KEY_VALUE 52 +#define ML_DO_KEY_ASSIGN 53 +#define ML_DO_INKEY_VALUE 54 +#define ML_DO_INKEY_ASSIGN 55 +#define ML_DO_TIMER 56 +#define ML_DO_SIN 57 +#define ML_DO_COS 58 +#define ML_DO_TAN 59 +#define ML_DO_ASIN 60 +#define ML_DO_ACOS 61 +#define ML_DO_ATAN 62 +#define ML_DO_ATAN2 63 +#define ML_DO_NOP 64 +#define ML_DO_LEFT 65 +#define ML_DO_MID 66 +#define ML_DO_RIGHT 67 +#define ML_DO_LEN 68 +#define ML_DO_PUSH_IDENTITY_MATRIX 69 // Pushes an identity matrix onto the stack +#define ML_DO_PUSH_ZERO_VECTOR 70 // Pushes a zero vector onto the stack +#define ML_DO_MATRIX 71 // Constructs a matrix from three vectors on the stack +#define ML_DO_VECTOR 72 // Constructs a vector from three numbers on the stack +#define ML_DO_PUSH_UP 73 // Push vector ( 0,+1, 0) +#define ML_DO_PUSH_DOWN 74 // Push vector ( 0,-1, 0) +#define ML_DO_PUSH_LEFT 75 // Push vector (-1, 0, 0) +#define ML_DO_PUSH_RIGHT 76 // Push vector (+1, 0, 0) +#define ML_DO_PUSH_FORWARDS 77 // Push vector ( 0, 0,+1) +#define ML_DO_PUSH_BACKWARDS 78 // Push vector ( 0, 0,-1) +#define ML_DO_DOT 79 // The dot product of two vectors on the stack +#define ML_DO_CROSS 80 // The cross product of two vectors on the stack + +// +// The basic types. +// + +#define ML_TYPE_UNDEFINED 0 +#define ML_TYPE_SLUMBER 1 +#define ML_TYPE_FLUMBER 2 +#define ML_TYPE_STRCONST 3 // A string constant located in the string data segment. +#define ML_TYPE_STRVAR 4 +#define ML_TYPE_BOOLEAN 5 +#define ML_TYPE_POINTER 6 // Pointer to an ML_Data in the 'data' field. +#define ML_TYPE_STRUCTURE 7 // Pointer to an ML_Structure on the heap. +#define ML_TYPE_ARRAY 8 // Pointer to an ML_Array on the heap. +#define ML_TYPE_CODE_POINTER 9 // Instruction address +#define ML_TYPE_STACK_BASE 10 // The previous stack frame base pointer. +#define ML_TYPE_TEXTURE 11 +#define ML_TYPE_BUFFER 12 +#define ML_TYPE_NUM_ARGS 13 // The number of argument passed in a function call. +#define ML_TYPE_MATRIX 14 +#define ML_TYPE_VECTOR 15 +#define ML_TYPE_FLOINTER 16 // A pointer to a float inside a vector +#define ML_TYPE_VOINTER 17 // A pointer to a vector + +// +// A memory location. +// + +typedef struct ml_data ML_Data; +typedef struct ml_structure ML_Structure; +typedef struct ml_array ML_Array; +typedef struct ml_vector ML_Vector; +typedef struct ml_matrix ML_Matrix; + +typedef struct ml_data +{ + SLONG type; + + union + { + SLONG value; + SLONG slumber; + float flumber; + SLONG strconst; // Index into the data table. + SLONG local; // Index into the current stackframe. + CBYTE *strvar; // Pointer to some MEM_alloc()ed memory. + SLONG boolean; + ML_Data *data; // Pointer to an ML_Data. + ML_Structure *structure; // Pointer to an ML_Structure on the heap. + ML_Array *array; + SLONG *code_pointer; // Index into instruction memory. + ML_Data *stack_base; + LL_Texture *lt; + LL_Buffer *lb; + CBYTE character; + SLONG args; + ML_Vector *vector; + ML_Matrix *matrix; + float *flointer; + }; + +} ML_Data; + +typedef struct +{ + SLONG field_id; + ML_Data data; + +} ML_Field; + +typedef struct ml_structure +{ + SLONG num_fields; + ML_Field field[]; + +} ML_Structure; + +typedef struct +{ + SLONG size; + SLONG stride; // How many ML_Datas between two array members with consecutive indices in this dimension. + +} ML_Dimension; + +typedef struct ml_array +{ + SLONG length; // Total number of ML_Datas in the data[] array. + SLONG num_dimensions; + ML_Data *data; // The actual data on the heap. + ML_Dimension dimension[]; + +} ML_Array; + +typedef struct ml_vector +{ + float x; + float y; + float z; + +} ML_Vector; + +typedef struct ml_matrix +{ + ML_Vector vector[3]; + +} ML_Matrix; + + + +// +// This is the header for the executable file. +// + +#define ML_VERSION_NUMBER 1 + +typedef struct +{ + SLONG version; + SLONG instructions_memory_in_bytes; + SLONG data_table_length_in_bytes; + SLONG num_globals; + + // + // The instructions... + // + + // + // The data table... + // + +} ML_Header; + + + + + +#endif diff --git a/MuckyBasic/muckyBASIC.dsp b/MuckyBasic/muckyBASIC.dsp new file mode 100644 index 0000000..b7b4a13 --- /dev/null +++ b/MuckyBasic/muckyBASIC.dsp @@ -0,0 +1,291 @@ +# Microsoft Developer Studio Project File - Name="muckyBASIC" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=muckyBASIC - 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 "muckyBASIC.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 "muckyBASIC.mak" CFG="muckyBASIC - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "muckyBASIC - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "muckyBASIC - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/muckyBASIC", XXDAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "muckyBASIC - 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" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W2 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /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 /subsystem:windows /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 ddraw.lib d3d8.lib dinput.lib dxguid.lib dsound.lib winmm.lib msacm32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "muckyBASIC - 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" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W2 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /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 /subsystem:windows /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 ddraw.lib d3d8.lib dinput.lib dxguid.lib dsound.lib winmm.lib msacm32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "muckyBASIC - Win32 Release" +# Name "muckyBASIC - Win32 Debug" +# Begin Group "D3DFrame" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\d3denum.cpp +# End Source File +# Begin Source File + +SOURCE=.\d3denum.h +# End Source File +# Begin Source File + +SOURCE=.\d3dframe.cpp +# End Source File +# Begin Source File + +SOURCE=.\d3dframe.h +# End Source File +# Begin Source File + +SOURCE=.\d3dutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\d3dutil.h +# End Source File +# Begin Source File + +SOURCE=.\userdlg.cpp +# End Source File +# Begin Source File + +SOURCE=.\wave.c +# End Source File +# Begin Source File + +SOURCE=.\wave.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Always.h +# End Source File +# Begin Source File + +SOURCE=.\cg.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg.h +# End Source File +# Begin Source File + +SOURCE=.\clip.cpp +# End Source File +# Begin Source File + +SOURCE=.\clip.h +# End Source File +# Begin Source File + +SOURCE=.\comp.cpp +# End Source File +# Begin Source File + +SOURCE=.\comp.h +# End Source File +# Begin Source File + +SOURCE=.\console.cpp +# End Source File +# Begin Source File + +SOURCE=.\console.h +# End Source File +# Begin Source File + +SOURCE=.\font.cpp +# End Source File +# Begin Source File + +SOURCE=.\font.h +# End Source File +# Begin Source File + +SOURCE=.\icon1.ico +# End Source File +# Begin Source File + +SOURCE=.\Key.h +# End Source File +# Begin Source File + +SOURCE=.\lex.cpp +# End Source File +# Begin Source File + +SOURCE=.\lex.h +# End Source File +# Begin Source File + +SOURCE=.\link.cpp +# End Source File +# Begin Source File + +SOURCE=.\link.h +# End Source File +# Begin Source File + +SOURCE=.\ll.cpp +# End Source File +# Begin Source File + +SOURCE=.\ll.h +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\Matrix.cpp +# End Source File +# Begin Source File + +SOURCE=.\Matrix.h +# End Source File +# Begin Source File + +SOURCE=.\mem.cpp +# End Source File +# Begin Source File + +SOURCE=.\mem.h +# End Source File +# Begin Source File + +SOURCE=.\ml.h +# End Source File +# Begin Source File + +SOURCE=.\muckyBASIC.rc +# End Source File +# Begin Source File + +SOURCE=.\os.cpp +# End Source File +# Begin Source File + +SOURCE=.\os.h +# End Source File +# Begin Source File + +SOURCE=.\parse.cpp +# End Source File +# Begin Source File + +SOURCE=.\parse.h +# End Source File +# Begin Source File + +SOURCE=.\st.cpp +# End Source File +# Begin Source File + +SOURCE=.\st.h +# End Source File +# Begin Source File + +SOURCE=.\sysvar.cpp +# End Source File +# Begin Source File + +SOURCE=.\sysvar.h +# End Source File +# Begin Source File + +SOURCE=.\test.mbs +# End Source File +# Begin Source File + +SOURCE=.\test2.mbs +# End Source File +# Begin Source File + +SOURCE=.\Tga.cpp +# End Source File +# Begin Source File + +SOURCE=.\Tga.h +# End Source File +# Begin Source File + +SOURCE=.\vm.cpp +# End Source File +# Begin Source File + +SOURCE=.\vm.h +# End Source File +# End Target +# End Project diff --git a/MuckyBasic/muckyBASIC.dsw b/MuckyBasic/muckyBASIC.dsw new file mode 100644 index 0000000..0874a04 --- /dev/null +++ b/MuckyBasic/muckyBASIC.dsw @@ -0,0 +1,37 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "muckyBASIC"=.\muckyBASIC.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/muckyBASIC", XXDAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ + begin source code control + "$/muckyBASIC", XXDAAAAA + . + end source code control +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/MuckyBasic/muckyBASIC.rc b/MuckyBasic/muckyBASIC.rc new file mode 100644 index 0000000..6fe212c --- /dev/null +++ b/MuckyBasic/muckyBASIC.rc @@ -0,0 +1,116 @@ +//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 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DRIVERS DIALOG DISCARDABLE 0, 0, 208, 111 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "muckyBASIC Virtual Machine" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Start",IDOK,50,86,50,16 + PUSHBUTTON "Exit",IDCANCEL,105,86,50,16 + LTEXT "Driver",IDC_STATIC,8,24,32,8 + COMBOBOX IDC_COMBO_DRIVER,40,24,160,88,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Mode",IDC_STATIC,8,48,32,8 + COMBOBOX IDC_COMBO_MODE,40,48,160,77,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Choose your driver and screen mode...",IDC_STATIC,8,8, + 192,8 + CTEXT "(Detected a 166MHz processor)",IDC_PROCESSOR,5,70,194, + 10,SS_CENTERIMAGE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DRIVERS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 201 + TOPMARGIN, 7 + BOTTOMMARGIN, 104 + END +END +#endif // APSTUDIO_INVOKED + + +#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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon1.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/MuckyBasic/os.cpp b/MuckyBasic/os.cpp new file mode 100644 index 0000000..545e874 --- /dev/null +++ b/MuckyBasic/os.cpp @@ -0,0 +1,5945 @@ +#define _OS_CPP_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "d3denum.h" // Direct 3D sample library +#include "d3dframe.h" + +#include "resource.h" + +#include "always.h" +#include "clip.h" +#include "key.h" +#include "os.h" +#include "tga.h" +#include "matrix.h" +#include "wave.h" + +#include +#include + +// +// The entrypoint into the actual game. +// + +extern void MAIN_main(void); + +HINSTANCE OS_this_instance; +HINSTANCE OS_last_instance; +LPSTR OS_command_line; +int OS_start_show_state; + +CBYTE *OS_application_name = "muckyBASIC Virtual Machine"; + +// +// Our window class. +// + +WNDCLASSEX OS_wcl; + +// +// Our window handle and menu handle. +// + +HWND OS_window_handle; + +// +// The DirectX 6 framework library class. +// + +UBYTE OS_frame_is_fullscreen; +UBYTE OS_frame_is_hardware; + +CD3DFramework OS_frame; + + +// +// The number of poly's drawn last frame. +// + +SLONG OS_poly_count_transformed; +SLONG OS_poly_count_drawn; + + +// ======================================================== +// +// THE SCREEN +// +// ======================================================== + +float OS_screen_width; +float OS_screen_height; + + +// ======================================================== +// +// KEY HANDLING STUFF +// +// ======================================================== + +// +// The keys that are held down. +// + +volatile UBYTE KEY_on[256]; +volatile SLONG KEY_inkey; +volatile SLONG KEY_shift; + + +// ======================================================== +// +// JOYSTICK STUFF +// +// ======================================================== + +IDirectInput *OS_joy_direct_input; +IDirectInputDevice *OS_joy_input_device; +IDirectInputDevice2 *OS_joy_input_device2; // We need this newer interface to poll the joystick. + +float OS_joy_x; +float OS_joy_y; +SLONG OS_joy_x_range_min; +SLONG OS_joy_x_range_max; +SLONG OS_joy_y_range_min; +SLONG OS_joy_y_range_max; +ULONG OS_joy_button; // The buttons that are currently down +ULONG OS_joy_button_down; // The buttons that have just been pressed +ULONG OS_joy_button_up; // The buttons that have just been released + + +// +// The callback function for enumerating joysticks. +// + +BOOL CALLBACK OS_joy_enum( + LPCDIDEVICEINSTANCE instance, + LPVOID context ) +{ + HRESULT hr; + LPDIRECTINPUTDEVICE pDevice; + + // + // Get an interface to the joystick. + // + + hr = OS_joy_direct_input->CreateDevice( + instance->guidInstance, + &OS_joy_input_device, + NULL); + + if (FAILED(hr)) + { + // + // Cant use this joystick for some reason! + // + + OS_joy_input_device = NULL; + OS_joy_input_device2 = NULL; + + return DIENUM_CONTINUE; + } + + // + // Query for the IDirectInputDevice2 interface. + // We need this to poll the joystick. + // + + OS_joy_input_device->QueryInterface( + IID_IDirectInputDevice2, + (LPVOID *) &OS_joy_input_device2); + + // + // No need to find another joystick! + // + + return DIENUM_STOP; +} + +// +// Initialises the joystick. +// + +void OS_joy_init(void) +{ + HRESULT hr; + + // + // Initialise everything. + // + + OS_joy_direct_input = NULL; + OS_joy_input_device = NULL; + OS_joy_input_device2 = NULL; + + // + // Create the direct input object. + // + + CoInitialize(NULL); + + CoCreateInstance( + CLSID_DirectInput8, + NULL, + CLSCTX_INPROC_SERVER, + IID_IDirectInput8W, + (void **) &OS_joy_direct_input); + + hr = OS_joy_direct_input->Initialize(OS_this_instance, DIRECTINPUT_VERSION); + + if (hr != DI_OK) + { + if (hr == DIERR_BETADIRECTINPUTVERSION) + { + return; + } + + if (hr == DIERR_OLDDIRECTINPUTVERSION) + { + return; + } + + return; + } + + /* + + hr = DirectInputCreateEx( + OS_this_instance, + DIRECTINPUT_VERSION, + &OS_joy_direct_input, + NULL); + + if (FAILED(hr)) + { + // + // No direct input! + // + + return; + } + + */ + + // + // Find a joystick. + // + + hr = OS_joy_direct_input->EnumDevices( + DI8DEVTYPE_JOYSTICK, + OS_joy_enum, + NULL, + DIEDFL_ATTACHEDONLY); + + if (OS_joy_input_device == NULL || + OS_joy_input_device2 == NULL) + { + // + // The joystick wasn't properly found. + // + + OS_joy_input_device = NULL; + OS_joy_input_device2 = NULL; + + return; + } + + // + // So we can get the nice 'n' simple joystick data format. + // + + OS_joy_input_device->SetDataFormat(&c_dfDIJoystick); + + // + // Grab the joystick exclusively when our window in the foreground. + // + + OS_joy_input_device->SetCooperativeLevel( + OS_window_handle, + DISCL_EXCLUSIVE | DISCL_FOREGROUND); + + // + // What is the range of the joystick? + // + + DIPROPRANGE diprg; + + // + // In x... + // + + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.diph.dwObj = DIJOFS_X; + diprg.lMin = 0; + diprg.lMax = 0; + + OS_joy_input_device->GetProperty( + DIPROP_RANGE, + &diprg.diph); + + OS_joy_x_range_min = diprg.lMin; + OS_joy_x_range_max = diprg.lMax; + + // + // In y... + // + + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.diph.dwObj = DIJOFS_Y; + diprg.lMin = 0; + diprg.lMax = 0; + + OS_joy_input_device->GetProperty( + DIPROP_RANGE, + &diprg.diph); + + OS_joy_y_range_min = diprg.lMin; + OS_joy_y_range_max = diprg.lMax; + +} + +// +// Polls the joystick. +// + +void OS_joy_poll(void) +{ + HRESULT hr; + + if (OS_joy_direct_input == NULL || + OS_joy_input_device == NULL || + OS_joy_input_device2 == NULL) + { + // + // No joystick detected. + // + + OS_joy_x = 0.0F; + OS_joy_y = 0.0F; + OS_joy_button = 0; + OS_joy_button_down = 0; + OS_joy_button_up = 0; + + return; + } + + SLONG acquired_already = FALSE; + + try_again_after_acquiring:; + + { + DIJOYSTATE js; + + // + // We acquired the joystick okay. Poll the joystick to + // update its state. + // + + OS_joy_input_device2->Poll(); + + // + // Finally get the state of the joystick. + // + + hr = OS_joy_input_device->GetDeviceState(sizeof(js), &js); + + if (hr == DIERR_NOTACQUIRED || + hr == DIERR_INPUTLOST) + { + if (acquired_already) + { + // + // Oh dear! + // + + OS_joy_x = 0.0F; + OS_joy_y = 0.0F; + OS_joy_button = 0; + OS_joy_button_down = 0; + OS_joy_button_up = 0; + + return; + } + else + { + hr = OS_joy_input_device->Acquire(); + + if (hr == DI_OK) + { + acquired_already = TRUE; + + goto try_again_after_acquiring; + } + else + { + OS_joy_x = 0.0F; + OS_joy_y = 0.0F; + OS_joy_button = 0; + OS_joy_button_down = 0; + OS_joy_button_up = 0; + + return; + } + } + } + + if (!FAILED(hr)) + { + // + // Axis movment normalised to between -1.0F and +1.0F + // + + SLONG dx = OS_joy_x_range_max - OS_joy_x_range_min; + SLONG dy = OS_joy_y_range_max - OS_joy_y_range_min; + + OS_joy_x = 0.0F; + OS_joy_y = 0.0F; + + if (dx) {OS_joy_x = float(js.lX - OS_joy_x_range_min) * 2.0F / float(dx) - 1.0F;} + if (dy) {OS_joy_y = float(js.lY - OS_joy_y_range_min) * 2.0F / float(dy) - 1.0F;} + + // + // The buttons. + // + + SLONG i; + + ULONG last = OS_joy_button; + ULONG now = 0; + + for (i = 0; i < 32; i++) + { + if (js.rgbButtons[i] & 0x80) + { + now |= 1 << i; + } + } + + OS_joy_button = now; + OS_joy_button_down = now & ~last; + OS_joy_button_up = last & ~now; + } + } +} + + +// ======================================================== +// +// WAVEFORM CONVERSION +// +// ======================================================== + +// +// Returns the converted memory, allocated with malloc(). +// + +void OS_decompress_sound( + WAVEFORMATEX *source_format, + void *source_data, + SLONG source_num_bytes, + WAVEFORMATEX *dest_format, + void **dest_data, + ULONG *dest_num_bytes) +{ + // + // Open the conversion stream. + // + + HACMSTREAM has; + + switch(acmStreamOpen( + &has, + NULL, + source_format, + dest_format, + NULL, + NULL, + 0, + ACM_STREAMOPENF_NONREALTIME)) + { + case ACMERR_NOTPOSSIBLE: TRACE("The requested operation cannot be performed.\n"); break; + case MMSYSERR_INVALFLAG: TRACE("At least one flag is invalid. \n"); break; + case MMSYSERR_INVALHANDLE: TRACE("The specified handle is invalid. \n"); break; + case MMSYSERR_INVALPARAM: TRACE("At least one parameter is invalid. \n"); break; + case MMSYSERR_NOMEM: TRACE("The system is unable to allocate resources. \n"); break; + } + + // + // Work out how many bytes we need. + // + + if (acmStreamSize( + has, + source_num_bytes, + dest_num_bytes, + ACM_STREAMSIZEF_SOURCE)) + { + return; + } + + // + // Allocate the memory. + // + + *dest_data = (void *) malloc(*dest_num_bytes); + + if (!*dest_data) + { + return; + } + + memset(*dest_data, 0, *dest_num_bytes); + + // + // Prepare the source and destination buffers. + // + + ACMSTREAMHEADER ash; + + memset(&ash, 0, sizeof(ash)); + + ash.cbStruct = sizeof(ash); + ash.pbSrc = (LPBYTE) source_data; + ash.cbSrcLength = source_num_bytes; + ash.pbDst = (LPBYTE) *dest_data; + ash.cbDstLength = *dest_num_bytes; + + if (acmStreamPrepareHeader( + has, + &ash, + 0)) + { + return; + } + + // + // Do the conversion. + // + + if (acmStreamConvert( + has, + &ash, + 0)) + { + return; + } + + // + // Unprepare the header and close the stream. + // + + if (acmStreamUnprepareHeader( + has, + &ash, + 0)) + { + return; + } + + *dest_num_bytes = ash.cbDstLengthUsed; + + if (acmStreamClose(has, 0)) + { + return; + } +} + + + + + +// ======================================================== +// +// SOUND STUFF +// +// ======================================================== + +// +// Dsound globals. +// + +SLONG OS_sound_valid; +LPDIRECTSOUND OS_sound_dsound; +LPDIRECTSOUNDBUFFER OS_sound_primary; +LPDIRECTSOUND3DLISTENER OS_sound_listener; +SLONG OS_sound_changed; // TRUE => we need to commit deferred settings. + + +// +// Each dsound sound. +// + +typedef struct os_sound +{ + SLONG type; + CBYTE fname[256]; + LPDIRECTSOUNDBUFFER buffer; + LPDIRECTSOUND3DBUFFER buffer3d; + +} OS_Sound; + +#define OS_MAX_SOUNDS 256 + +OS_Sound OS_sound[OS_MAX_SOUNDS]; + + +void OS_sound_init(void) +{ + // + // Create direct sound. + // + + if (DirectSoundCreate(NULL, &OS_sound_dsound, NULL) != DS_OK) + { + return; + } + + // + // Set a co-op level. + // + + if (OS_sound_dsound->SetCooperativeLevel(OS_window_handle, DSSCL_PRIORITY) != DS_OK) + { + return; + } + + // + // Get our primary buffer. + // + + DSBUFFERDESC dsbd; + + memset(&dsbd, 0, sizeof(dsbd)); + + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D; + + if (OS_sound_dsound->CreateSoundBuffer(&dsbd, &OS_sound_primary, NULL) != DS_OK) + { + return; + } + + // + // Setup the format to 16-bit 22khz. + // + + WAVEFORMATEX wfx; + + memset(&wfx, 0, sizeof(wfx)); + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 2; + wfx.nSamplesPerSec = 22050; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + + if (OS_sound_primary->SetFormat(&wfx) != DS_OK) + { + return; + } + + // + // Create the listener for 3D sounds. + // + + if (OS_sound_primary->QueryInterface(IID_IDirectSound3DListener, (void ** ) &OS_sound_listener) != DS_OK) + { + return; + } + + // + // Set listener defaults... + // + + OS_sound_listener->SetDopplerFactor(2.0F, DS3D_DEFERRED); + OS_sound_listener->SetRolloffFactor(2.0F, DS3D_DEFERRED); + + OS_sound_changed = TRUE; + + // + // Make sure that the primary buffer is always active. That way we don't + // get nasty clicks when we go in or out of silence. + // + + OS_sound_primary->Play(0, 0, DSBPLAY_LOOPING); + + // + // DSound is initialised ok. + // + + OS_sound_valid = TRUE; +} + + +OS_Sound *OS_sound_create(CBYTE *fname, SLONG type) +{ + SLONG i; + + unsigned int bytes_read; + + OS_Sound *os; + + WAVEFORMATEX *pwfx; // Wave format info + HMMIO hmmio; // File handle + MMCKINFO mmckinfoData; // Chunk info + MMCKINFO mmckinfoParent; // Parent chunk info + + if (!OS_sound_valid) + { + return NULL; + } + + // + // Do we already have this sound? + // + + for (i = 0; i < OS_MAX_SOUNDS; i++) + { + os = &OS_sound[i]; + + if (stricmp(fname, os->fname) == 0) + { + // + // Return this sound! + // + + return os; + } + } + + + // + // Get a new sample structure. + // + + for (i = 0; i < OS_MAX_SOUNDS; i++) + { + os = &OS_sound[i]; + + if (os->type == OS_SOUND_TYPE_UNUSED) + { + goto found_spare_sound; + } + } + + // + // No more sounds available. + // + + return NULL; + + found_spare_sound:; + + strcpy(os->fname, fname); + os->type = type; + + // + // Open the wave file. + // + + if (WaveOpenFile(fname, &hmmio, &pwfx, &mmckinfoParent) != 0) + { + return NULL; + } + + if (WaveStartDataRead(&hmmio, &mmckinfoData, &mmckinfoParent) != 0) + { + WaveCloseReadFile(&hmmio, &pwfx); + + return NULL; + } + + // + // If the format is not PCM, then convert to PCM format. + // + + if (pwfx->wFormatTag != WAVE_FORMAT_PCM) + { + SLONG num_source_bytes = mmckinfoData.cksize; + + // + // Read the data into a temporary buffer. + // + + void *src = (void *) malloc(mmckinfoData.cksize); + + if (WaveReadFile( + hmmio, // file handle + mmckinfoData.cksize,// no. of bytes to read + (UBYTE *) src, // destination + &mmckinfoData, // file chunk info + &bytes_read)) // actual no. of bytes read + { + WaveCloseReadFile(&hmmio, &pwfx); + + return NULL; + } + + // + // Convert! + // + + WAVEFORMATEX destwfx; + + destwfx.wFormatTag = WAVE_FORMAT_PCM; + destwfx.wBitsPerSample = 16; + destwfx.nChannels = pwfx->nChannels; + destwfx.nSamplesPerSec = pwfx->nSamplesPerSec; + destwfx.nBlockAlign = destwfx.wBitsPerSample / 8 * destwfx.nChannels; + destwfx.nAvgBytesPerSec = destwfx.nSamplesPerSec * destwfx.nBlockAlign; + destwfx.cbSize = 0; + + void *dest_data = NULL; + ULONG dest_num_bytes; + + OS_decompress_sound( + pwfx, + src, + num_source_bytes, + &destwfx, + &dest_data, + &dest_num_bytes); + + if (!dest_data) + { + return NULL; + } + + // + // Create the sound buffer with the destination format. + // + + DSBUFFERDESC dsbdesc; + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE; + dsbdesc.dwBufferBytes = dest_num_bytes; + dsbdesc.lpwfxFormat = &destwfx; + + switch(type) + { + case OS_SOUND_TYPE_2D: + dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; + break; + + case OS_SOUND_TYPE_3D: + dsbdesc.dwFlags |= DSBCAPS_CTRL3D; + dsbdesc.dwFlags |= DSBCAPS_MUTE3DATMAXDISTANCE; + break; + + default: + ASSERT(0); + break; + } + + if (OS_sound_dsound->CreateSoundBuffer(&dsbdesc, &os->buffer, NULL) != DS_OK) + { + WaveCloseReadFile(&hmmio, &pwfx); + + return NULL; + } + + // + // Lock the sound buffer. + // + + void *data; + ULONG num_bytes; + + if (os->buffer->Lock( + 0, // Offset of lock start + 0, // Size of lock; ignored in this case + &data, // Address of lock start + &num_bytes, // Number of bytes locked + NULL, // Wraparound start; not used + NULL, // Wraparound size; not used + DSBLOCK_ENTIREBUFFER) != DS_OK) + { + WaveCloseReadFile(&hmmio, &pwfx); + + return NULL; + } + + ASSERT(num_bytes == dest_num_bytes); + + // + // Copy over the converted data. + // + + memcpy(data, dest_data, dest_num_bytes); + + // + // Free up memory. + // + + free(src); + free(dest_data); + + // + // Unlock the buffer and close the wave file. + // + + os->buffer->Unlock(data, num_bytes, NULL, 0); + + WaveCloseReadFile(&hmmio, &pwfx); + + } + else + { + // + // Create a sound buffer- now that we know the format of the wave. + // + + DSBUFFERDESC dsbdesc; + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_STATIC; + dsbdesc.dwBufferBytes = mmckinfoData.cksize; + dsbdesc.lpwfxFormat = pwfx; + + switch(type) + { + case OS_SOUND_TYPE_2D: + dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; + break; + + case OS_SOUND_TYPE_3D: + dsbdesc.dwFlags |= DSBCAPS_CTRL3D; + dsbdesc.dwFlags |= DSBCAPS_MUTE3DATMAXDISTANCE; + break; + + default: + ASSERT(0); + break; + } + + if (OS_sound_dsound->CreateSoundBuffer(&dsbdesc, &os->buffer, NULL) != DS_OK) + { + WaveCloseReadFile(&hmmio, &pwfx); + + return NULL; + } + + // + // Lock the sound buffer. + // + + void *data; + ULONG num_bytes; + + if (os->buffer->Lock( + 0, // Offset of lock start + 0, // Size of lock; ignored in this case + &data, // Address of lock start + &num_bytes, // Number of bytes locked + NULL, // Wraparound start; not used + NULL, // Wraparound size; not used + DSBLOCK_ENTIREBUFFER) != DS_OK) + { + WaveCloseReadFile(&hmmio, &pwfx); + + return NULL; + } + + // + // Read in the sound data. + // + + if (WaveReadFile( + hmmio, // file handle + num_bytes, // no. of bytes to read + (UBYTE *) data, // destination + &mmckinfoData, // file chunk info + &bytes_read)) // actual no. of bytes read + { + WaveCloseReadFile(&hmmio, &pwfx); + + return NULL; + } + + // + // Unlock the buffer and close the wave file. + // + + os->buffer->Unlock(data, num_bytes, NULL, 0); + + WaveCloseReadFile(&hmmio, &pwfx); + } + + // + // If this buffer is 3D, then get the 3D interface. + // + + os->buffer3d = NULL; + + if (os->type == OS_SOUND_TYPE_3D) + { + if (FAILED(os->buffer->QueryInterface(IID_IDirectSound3DBuffer, (void **) &os->buffer3d))) + { + return NULL; + } + + os->buffer3d->SetMinDistance(4.0F, DS3D_DEFERRED); + } + + return os; +} + +OS_Sound *OS_sound_create(UWORD *data, SLONG num_samples, SLONG type) +{ + SLONG i; + + OS_Sound *os; + + if (!OS_sound_valid) + { + return NULL; + } + + // + // Get a new sample structure. + // + + for (i = 0; i < OS_MAX_SOUNDS; i++) + { + os = &OS_sound[i]; + + if (os->type == OS_SOUND_TYPE_UNUSED) + { + goto found_spare_sound; + } + } + + // + // No more sounds available. + // + + return NULL; + + found_spare_sound:; + + strcpy(os->fname, "Generated"); + + os->type = OS_SOUND_TYPE_2D; + + // + // Create a sound buffer. + // + + DSBUFFERDESC dsbdesc; + WAVEFORMATEX pwfx; // Wave format info + + // + // Setup the wave format + // + + memset(&pwfx, 0, sizeof(pwfx)); + + pwfx.cbSize = sizeof(pwfx); + pwfx.wFormatTag = WAVE_FORMAT_PCM; + pwfx.nChannels = 1; + pwfx.nSamplesPerSec = 22050; + pwfx.nAvgBytesPerSec = 22050 * sizeof(UWORD); + pwfx.nBlockAlign = 2; + pwfx.wBitsPerSample = 16; + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_STATIC; + dsbdesc.dwBufferBytes = num_samples * sizeof(UWORD); + dsbdesc.lpwfxFormat = &pwfx; + + switch(type) + { + case OS_SOUND_TYPE_2D: + dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; + break; + + case OS_SOUND_TYPE_3D: + dsbdesc.dwFlags |= DSBCAPS_CTRL3D; + dsbdesc.dwFlags |= DSBCAPS_MUTE3DATMAXDISTANCE; + break; + + default: + ASSERT(0); + break; + } + + if (OS_sound_dsound->CreateSoundBuffer(&dsbdesc, &os->buffer, NULL) != DS_OK) + { + return NULL; + } + + // + // Lock the sound buffer. + // + + void *locked_data; + ULONG locked_bytes; + + if (os->buffer->Lock( + 0, // Offset of lock start + 0, // Size of lock; ignored in this case + &locked_data, // Address of lock start + &locked_bytes, // Number of bytes locked + NULL, // Wraparound start; not used + NULL, // Wraparound size; not used + DSBLOCK_ENTIREBUFFER) != DS_OK) + { + return NULL; + } + + // + // Copy over the sound data. + // + + memcpy(locked_data, data, locked_bytes); + + // + // Unlock the buffer and close the wave file. + // + + os->buffer->Unlock(locked_data, locked_bytes, NULL, 0); + + // + // If this buffer is 3D, then get the 3D interface. + // + + os->buffer3d = NULL; + + if (os->type == OS_SOUND_TYPE_3D) + { + if (FAILED(os->buffer->QueryInterface(IID_IDirectSound3DBuffer, (void **) &os->buffer3d))) + { + return NULL; + } + + os->buffer3d->SetMinDistance(4.0F, DS3D_DEFERRED); + } + + return os; +} + + + +void OS_sound_play(OS_Sound *os, SLONG flag) +{ + if (!OS_sound_valid || os == NULL || os->buffer == NULL) + { + return; + } + + // + // What's this buffer doing now? + // + + ULONG status; + + os->buffer->GetStatus(&status); + + if (status == DSBSTATUS_PLAYING || + status == DSBSTATUS_LOOPING) + { + if (flag & OS_SOUND_FLAG_INTERRUPT) + { + os->buffer->SetCurrentPosition(0); + } + } + else + { + os->buffer->Play(0, 0, (flag & OS_SOUND_FLAG_LOOP) ? DSBPLAY_LOOPING : 0); + } +} + + +void OS_sound_stop(OS_Sound *os) +{ + if (!OS_sound_valid || os == NULL || os->buffer == NULL) + { + return; + } + + os->buffer->Stop(); +} + +void OS_sound_finish() +{ +} + +void OS_sound_2d_set_volume(OS_Sound *os, float volume) +{ + if (!OS_sound_valid || os == NULL || os->buffer == NULL) + { + return; + } + + volume = sqrt(volume); + volume = sqrt(volume); + volume = sqrt(volume); + volume = sqrt(volume); + + SLONG long_volume = SLONG(DSBVOLUME_MIN + volume * (DSBVOLUME_MAX - DSBVOLUME_MIN)); + + os->buffer->SetVolume(long_volume); +} + + +void OS_sound_3d_set_range(OS_Sound *os, float min, float max) +{ + if (!OS_sound_valid || os == NULL || os->buffer == NULL) + { + return; + } + + os->buffer3d->SetMinDistance(min, DS3D_DEFERRED); + os->buffer3d->SetMaxDistance(max, DS3D_DEFERRED); + + OS_sound_changed = TRUE; +} + +void OS_sound_3d_set_position( + OS_Sound *os, + float x, + float y, + float z, + float dx, + float dy, + float dz) +{ + if (!OS_sound_valid || os == NULL || os->buffer == NULL) + { + return; + } + + os->buffer3d->SetPosition( x, y, z, DS3D_DEFERRED); + os->buffer3d->SetVelocity(dx,dy,dz, DS3D_DEFERRED); + + OS_sound_changed = TRUE; +} + + + +void OS_sound_listener_set( + float x, + float y, + float z, + float dx, + float dy, + float dz, + float yaw, + float pitch, + float roll) +{ + float matrix[9]; + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + OS_sound_listener->SetPosition( x, y, z, DS3D_DEFERRED); + OS_sound_listener->SetVelocity(dx, dy, dz, DS3D_DEFERRED); + + OS_sound_listener->SetOrientation( + matrix[6], + matrix[7], + matrix[8], + matrix[3], + matrix[4], + matrix[5], + DS3D_DEFERRED); + + OS_sound_changed = TRUE; +} + + + +void OS_sound_update_changes() +{ + if (OS_sound_changed) + { + OS_sound_listener->CommitDeferredSettings(); + + OS_sound_changed = FALSE; + } +} + + + + + +// ======================================================== +// +// TEXTURE STUFF +// +// ======================================================== + +// +// The directories where we load textures from. +// + +#define OS_MAX_TEXPATHS 256 + +CBYTE OS_texpath[OS_MAX_TEXPATHS][64]; +SLONG OS_texpath_upto; +SLONG OS_texpath_last; // The last texture path we used successfully. + + +// +// All the textures available and the path we found them in. +// + +typedef struct +{ + SLONG path; // -1 => Not used. + CBYTE fname[28]; + +} OS_Texname; + +#define OS_MAX_TEXNAMES 1024 + +OS_Texname OS_texname[OS_MAX_TEXNAMES]; +SLONG OS_texname_upto; + + + +// +// The pixel formats for each of our OS_TEXTURE_FORMATs +// + +typedef struct +{ + SLONG valid; + + DDPIXELFORMAT ddpf; + + SLONG mask_r; + SLONG mask_g; + SLONG mask_b; + SLONG mask_a; + + SLONG shift_r; + SLONG shift_g; + SLONG shift_b; + SLONG shift_a; + +} OS_Tformat; + +OS_Tformat OS_tformat[OS_TEXTURE_FORMAT_NUMBER]; + + +// +// Our texture pages. +// + +typedef struct os_texture +{ + CBYTE name[_MAX_PATH]; + UBYTE format; + UBYTE inverted; + UWORD padding; + UWORD width; + UWORD height; + + DDSURFACEDESC2 ddsd; + LPDIRECTDRAWSURFACE4 ddsurface; + LPDIRECT3DTEXTURE2 ddtx; + + OS_Texture *next; + +} OS_Texture; + +// +// They are stored in a linked list and dynamically allocated. +// + +OS_Texture *OS_texture_head; + + + +// +// Fills in the texture path info from the given file. +// + +#define OS_BASE_TEXTURE_PATH "Textures\\" + +void OS_init_texpaths() +{ + SLONG i; + + WIN32_FIND_DATA fd; + HANDLE handle; + CBYTE search_path[256]; + OS_Texname *otn; + CBYTE *ch; + + // + // We always have "Textures\\" in our path. + // + + strcpy(OS_texpath[0], OS_BASE_TEXTURE_PATH); + + OS_texpath_upto = 1; + + // + // Use any additional directories inside the base directory. + // + + for (i = 0; i < OS_texpath_upto; i++) + { + sprintf(search_path, "%s*.*", OS_texpath[i]); + + handle = FindFirstFile( + search_path, + &fd); + + if (handle != INVALID_HANDLE_VALUE) + { + while(1) + { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + // + // Found another directory. + // + + if (fd.cFileName[0] == '.') + { + // + // Ignore the crappy "." and ".." directories + // + } + else + { + ASSERT(WITHIN(OS_texpath_upto, 0, OS_MAX_TEXPATHS - 1)); + + sprintf(OS_texpath[OS_texpath_upto], "%s%s\\", OS_texpath[i], fd.cFileName); + + OS_texpath_upto += 1; + } + } + + if (!FindNextFile(handle, &fd)) + { + // + // Nothing more in the "Textures\\" directory. + // + + FindClose(handle); + + break; + } + } + } + } + + // + // Find all the texture filenames. + // + + for (i = 0; i < OS_texpath_upto; i++) + { + sprintf(search_path, "%s\\*.tga", OS_texpath[i]); + + handle = FindFirstFile(search_path, &fd); + + if (handle != INVALID_HANDLE_VALUE) + { + while(1) + { + ASSERT(WITHIN(OS_texname_upto, 0, OS_MAX_TEXNAMES - 1)); + + otn = &OS_texname[OS_texname_upto++]; + + otn->path = i; + + // + // Copy over just the filename. + // + + strncpy(otn->fname, fd.cFileName, 27); + + if (!FindNextFile(handle, &fd)) + { + // + // Nothing more in this path. + // + + FindClose(handle); + + break; + } + } + } + } +} + + + +// +// Returns the number of bits set in 'mask' with a rather cunning algorithm. +// + +SLONG OS_bit_count(ULONG mask) +{ + SLONG ans; + + for (ans = 0; mask; mask &= mask - 1, ans += 1); + + return ans; +} + + +// +// The texture enumeration function. +// + +HRESULT CALLBACK OS_texture_enumerate_pixel_formats( + LPDDPIXELFORMAT lpddpf, + LPVOID context) +{ + SLONG format; + + OS_Tformat *otf = (OS_Tformat *) malloc(sizeof(OS_Tformat)); + + if (otf == NULL) + { + // + // Oh dear! + // + + return D3DENUMRET_CANCEL; + } + + // + // Is this one of the formats we are interested in? + // + + if (lpddpf->dwFlags & DDPF_RGB) + { + // + // We are only interested in 16-bpp RGB modes. + // + + if (lpddpf->dwRGBBitCount == 16) + { + if (lpddpf->dwFlags & DDPF_ALPHAPIXELS) + { + SLONG alphabits; + + // + // Could be 1555 or 4444 + // + + alphabits = OS_bit_count(lpddpf->dwRGBAlphaBitMask); + + if (alphabits == 1) + { + // + // Must be 1555 + // + + OS_tformat[OS_TEXTURE_FORMAT_1555].valid = TRUE; + OS_tformat[OS_TEXTURE_FORMAT_1555].ddpf = *lpddpf; + } + else + if (alphabits == 4) + { + // + // Must be 4444 + // + + OS_tformat[OS_TEXTURE_FORMAT_4444].valid = TRUE; + OS_tformat[OS_TEXTURE_FORMAT_4444].ddpf = *lpddpf; + } + } + else + { + // + // This is a good RGB pixel format. + // + + OS_tformat[OS_TEXTURE_FORMAT_RGB].valid = TRUE; + OS_tformat[OS_TEXTURE_FORMAT_RGB].ddpf = *lpddpf; + } + } + } + else + if (lpddpf->dwFlags & DDPF_LUMINANCE) + { + if (lpddpf->dwFlags & DDPF_ALPHAPIXELS) + { + // + // We only want luminance- not luminance and alpha. + // + } + else + { + if (lpddpf->dwLuminanceBitCount == 8) + { + // + // This is what we want. An 8-bit luminance format. + // + + OS_tformat[OS_TEXTURE_FORMAT_8].valid = TRUE; + OS_tformat[OS_TEXTURE_FORMAT_8].ddpf = *lpddpf; + } + } + } + + // + // Ask for another texture format. + // + + return D3DENUMRET_OK; +} + + +// +// Given the bitmask for a colour in a pixel format, it calculates the mask and +// shift so that you can construct a pixel in pixel format given its RGB values. +// The formula is... +// +// PIXEL(r,g,b) = ((r >> mask) << shift) | ((g >> mask) << shift) | ((b >> mask) << shift); +// +// THIS ASSUMES that r,g,b are 8-bit values. +// + +void OS_calculate_mask_and_shift( + ULONG bitmask, + SLONG *mask, + SLONG *shift) +{ + SLONG i; + SLONG b; + SLONG num_bits = 0; + SLONG first_bit = -1; + + for (i = 0, b = 1; i < 32; i++, b <<= 1) + { + if (bitmask & b) + { + num_bits += 1; + + if (first_bit == -1) + { + // + // We have found the first bit. + // + + first_bit = i; + } + } + } + + ASSERT(first_bit != -1 && num_bits != 0); + + *mask = 8 - num_bits; + *shift = first_bit; + + if (*mask < 0) + { + // + // More than 8 bits per colour component? May + // as well support it! + // + + *shift -= *mask; + *mask = 0; + } +} + + +CBYTE *OS_texture_full_path(CBYTE *fname) +{ + SLONG i; + + static CBYTE fullpath[MAX_PATH]; + + + //sprintf(fullpath, "Textures\\qmark.tga"); + + //return fullpath; + + for (i = 0; i < OS_texname_upto; i++) + { + if (_stricmp(OS_texname[i].fname, fname) == 0) + { + // + // Found the texture! + // + + sprintf(fullpath, "%s\\%s", OS_texpath[OS_texname[i].path], fname); + + return fullpath; + } + } + + // + // No such texture. + // + + return NULL; +} + +// +// The buffer we use to load TGAs into. +// + +TGA_Pixel OS_texture_tga[OS_TEXTURE_MAX_SIZE * OS_TEXTURE_MAX_SIZE]; + +OS_Texture *OS_texture_create(CBYTE *fname, SLONG invert) +{ + SLONG format; + OS_Texture *ot; + OS_Tformat *best_otf; + TGA_Info ti; + CBYTE *fullpath; + + // + // Do we already have this texture? + // + + for (ot = OS_texture_head; ot; ot = ot->next) + { + if (strcmp(fname, ot->name) == 0) + { + if (ot->inverted == invert) + { + return ot; + } + } + } + + // + // Find the filename. + // + + fullpath = OS_texture_full_path(fname); + + if (!fullpath) + { + OS_error("Could not find the texture file: \"%s\"\nanywhere inside the Textures directory.\nUsing texture \"qmark.tga\" instead.", fname); + + fullpath = OS_BASE_TEXTURE_PATH"qmark.tga"; + } + + // + // Try to load in the TGA. + // + + ti = TGA_load(fullpath, OS_TEXTURE_MAX_SIZE, OS_TEXTURE_MAX_SIZE, OS_texture_tga); + + if (!ti.valid || + OS_bit_count(ti.width) != 1 || + OS_bit_count(ti.height) != 1) + { + if (!ti.valid) + { + OS_error("Error loading tga file \"%s\".\n", fname); + } + else + { + OS_error("Cannot load \"%s\"\nBoth the width and height of a texture must be a power of 2.\ni.e. 64,128,256,512,...\nUsing qmark.tga instead.", fname); + } + + fullpath = OS_BASE_TEXTURE_PATH"qmark.tga"; + + ti = TGA_load(fullpath, OS_TEXTURE_MAX_SIZE, OS_TEXTURE_MAX_SIZE, OS_texture_tga); + + if (!ti.valid || + OS_bit_count(ti.width) != 1 || + OS_bit_count(ti.height) != 1) + { + // + // Error loading qmark.tga! + // + + return NULL; + } + } + + // + // Find the best texture format. + // + + if (ti.flag & TGA_FLAG_CONTAINS_ALPHA) + { + if (ti.flag & TGA_FLAG_ONE_BIT_ALPHA) + { + format = OS_TEXTURE_FORMAT_1555; + } + else + { + format = OS_TEXTURE_FORMAT_4444; + } + } + else + if (ti.flag & TGA_FLAG_GRAYSCALE) + { + if (OS_tformat[OS_TEXTURE_FORMAT_8].valid) + { + // + // This card has a luminance only texture format. + // + + format = OS_TEXTURE_FORMAT_8; + } + else + { + // + // Use the RGB format as the next-best thing. + // + + format = OS_TEXTURE_FORMAT_RGB; + } + } + else + { + // + // A normal RGB texture + // + + format = OS_TEXTURE_FORMAT_RGB; + } + + best_otf = &OS_tformat[format]; + + if (!best_otf->valid) + { + // + // No good texture format. + // + + return NULL; + } + + // + // Create a new texture. + // + + ot = (OS_Texture *) malloc(sizeof(OS_Texture)); + + if (ot == NULL) + { + // + // It's really not worth checking for this... but anyway! + // + + return NULL; + } + + strncpy(ot->name, fname, _MAX_PATH); + + ot->format = format; + ot->inverted = invert; + + // + // Create a managed texture surface. + // + + memset(&ot->ddsd, 0, sizeof(ot->ddsd)); + + ot->ddsd.dwSize = sizeof(DDSURFACEDESC2); + ot->ddsd.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_MIPMAPCOUNT | + DDSD_PIXELFORMAT; + ot->ddsd.dwWidth = ti.width; + ot->ddsd.dwHeight = ti.height; + ot->ddsd.dwMipMapCount = 1; + ot->ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX; + ot->ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTSTATIC; + ot->ddsd.ddpfPixelFormat = best_otf->ddpf; + + VERIFY(OS_frame.GetDirectDraw()->CreateSurface( + &ot->ddsd, + &ot->ddsurface, + NULL) == DD_OK); + + if (invert) + { + SLONG i; + SLONG j; + + TGA_Pixel *tp; + + // + // Invert the texture. + // + + tp = OS_texture_tga; + + for (i = 0; i < ti.width; i++) + { + for (j = 0; j < ti.height; j++) + { + tp->alpha = 255 - tp->alpha; + tp->red = 255 - tp->red; + tp->green = 255 - tp->green; + tp->blue = 255 - tp->blue; + + tp += 1; + } + } + } + + // + // Lock the surface. + // + + DDSURFACEDESC2 ddsd; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + VERIFY(ot->ddsurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK); + + // + // Copy the tga data into the surface. + // + + if (format != OS_TEXTURE_FORMAT_8) + { + SLONG i; + SLONG j; + UWORD pixel_our; + TGA_Pixel pixel_tga; + UWORD *wscreen = (UWORD *) ddsd.lpSurface; + + // + // 16 bits per pixel. + // + + for (i = 0; i < ti.width; i++) + { + for (j = 0; j < ti.height; j++) + { + pixel_tga = OS_texture_tga[i + j * ti.width]; + pixel_our = 0; + + pixel_our |= (pixel_tga.red >> best_otf->mask_r) << best_otf->shift_r; + pixel_our |= (pixel_tga.green >> best_otf->mask_g) << best_otf->shift_g; + pixel_our |= (pixel_tga.blue >> best_otf->mask_b) << best_otf->shift_b; + + if (best_otf->ddpf.dwFlags & DDPF_ALPHAPIXELS) + { + pixel_our |= (pixel_tga.alpha >> best_otf->mask_a) << best_otf->shift_a; + } + + wscreen[i + j * (ddsd.lPitch >> 1)] = pixel_our; + } + } + } + else + { + SLONG i; + SLONG j; + UBYTE *wscreen = (UBYTE *) ddsd.lpSurface; + + // + // 8 bits per pixel. + // + + for (i = 0; i < ti.width; i++) + { + for (j = 0; j < ti.height; j++) + { + wscreen[i + j * ddsd.lPitch] = OS_texture_tga[i + j * ti.width].red; + } + } + } + + // + // Unlock the surface. + // + + ot->ddsurface->Unlock(NULL); + + // + // Query the texture interface from the surface. + // + + VERIFY(ot->ddsurface->QueryInterface(IID_IDirect3DTexture2, (void **) &ot->ddtx) == DD_OK); + + // + // Insert this texture into the array. + // + + ot->next = OS_texture_head; + OS_texture_head = ot; + + // + // Remember the size! + // + + ot->width = ti.width; + ot->height = ti.height; + + return ot; +} + + +OS_Texture *OS_texture_create(SLONG width, SLONG height, SLONG format) +{ + OS_Texture *ot; + OS_Tformat *otf; + + // + // Powers of two? + // + + if (OS_bit_count(width ) > 1 || + OS_bit_count(height) > 1) + { + return NULL; + } + + // + // Make sure this texture is not too big. + // + + { + D3DDEVICEDESC dh; + D3DDEVICEDESC ds; + + memset(&dh, 0, sizeof(dh)); + memset(&ds, 0, sizeof(ds)); + + dh.dwSize = sizeof(dh); + ds.dwSize = sizeof(ds); + + VERIFY(OS_frame.GetD3DDevice()->GetCaps(&dh, &ds) == D3D_OK); + + if (width > dh.dwMaxTextureWidth || + height > dh.dwMaxTextureHeight) + { + return NULL; + } + } + + if (!OS_tformat[format].valid) + { + // + // The requested texture format does not exist. Is there + // another one we can try? + // + + switch(format) + { + case OS_TEXTURE_FORMAT_8: format = OS_TEXTURE_FORMAT_RGB; break; + case OS_TEXTURE_FORMAT_1555: format = OS_TEXTURE_FORMAT_4444; break; + case OS_TEXTURE_FORMAT_4444: format = OS_TEXTURE_FORMAT_1555; break; + } + + if (!OS_tformat[format].valid) + { + // + // We have no suitable texture format. + // + + return NULL; + } + } + + // + // The texture format we are going to use. + // + + otf = &OS_tformat[format]; + + // + // Create a new texture. + // + + ot = (OS_Texture *) malloc(sizeof(OS_Texture)); + + if (ot == NULL) + { + // + // It's really not worth checking for this... but anyway! + // + + return NULL; + } + + sprintf(ot->name, "Generated"); + + ot->format = format; + ot->width = width; + ot->height = height; + + // + // Create a managed texture surface. + // + + memset(&ot->ddsd, 0, sizeof(ot->ddsd)); + + ot->ddsd.dwSize = sizeof(DDSURFACEDESC2); + ot->ddsd.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_MIPMAPCOUNT | + DDSD_PIXELFORMAT; + ot->ddsd.dwWidth = width; + ot->ddsd.dwHeight = height; + ot->ddsd.dwMipMapCount = 1; + ot->ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX; + ot->ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTDYNAMIC; + ot->ddsd.ddpfPixelFormat = otf->ddpf; + + if (OS_frame.GetDirectDraw()->CreateSurface( + &ot->ddsd, + &ot->ddsurface, + NULL) != DD_OK) + { + // + // Oh dear... + // + + free(ot); + + return NULL; + } + + + // + // The surface probably contains junk... + // + + // + // Query the texture interface from the surface. + // + + VERIFY(ot->ddsurface->QueryInterface(IID_IDirect3DTexture2, (void **) &ot->ddtx) == DD_OK); + + // + // Insert this texture into the array. + // + + ot->next = OS_texture_head; + OS_texture_head = ot; + + return ot; +} + + + +void OS_texture_finished_creating() +{ + /* + + SLONG i; + + OS_Texture *ot; + OS_Point op; + UWORD index[3]; + + // + // Go through all the textures and draw something with them. + // + + OS_scene_begin(); + OS_init_renderstates(); + + for (ot = OS_texture_head; ot; ot = ot->next) + { + OS_page_lock(ot); + + for (i = 0; i < 3; i++) + { + op.x = frand() * OS_screen_width; + op.y = frand() * OS_screen_height; + op.z = 0.5F; + op.rhw = 0.5F; + op.clip = OS_CLIP_TRANSFORMED; + + index[i] = OS_page_add_point(ot, &op, 0x00000000, 0x00000000, frand(), frand(), 0.0F); + } + + OS_page_add_triangle(ot, index[0], index[1], index[2]); + OS_page_unlock(ot); + OS_page_draw(ot, OS_TEXTURE_TYPE_DOUBLESIDED | OS_TEXTURE_TYPE_ZALWAYS); + } + + OS_scene_end(); + OS_show(); + + */ +} + + +SLONG OS_texture_width(OS_Texture *ot) +{ + if (ot == NULL) + { + return 0; + } + + return ot->width; +} + +SLONG OS_texture_height(OS_Texture *ot) +{ + if (ot == NULL) + { + return 0; + } + + return ot->height; +} + + + +SLONG OS_bitmap_format; // OS_TEXTURE_FORMAT_* +UWORD *OS_bitmap_uword_screen; // For 16-bit formats. +SLONG OS_bitmap_uword_pitch; // Pitch in UWORDS +UBYTE *OS_bitmap_ubyte_screen; // For the grayscale format. +SLONG OS_bitmap_ubyte_pitch; // Pitch in UBYTES +SLONG OS_bitmap_width; +SLONG OS_bitmap_height; +SLONG OS_bitmap_mask_r; +SLONG OS_bitmap_mask_g; +SLONG OS_bitmap_mask_b; +SLONG OS_bitmap_mask_a; +SLONG OS_bitmap_shift_r; +SLONG OS_bitmap_shift_g; +SLONG OS_bitmap_shift_b; +SLONG OS_bitmap_shift_a; + +void OS_texture_lock(OS_Texture *ot) +{ + OS_Tformat *otf; + + HRESULT res; + + DDSURFACEDESC2 ddsd; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + VERIFY((res = ot->ddsurface->Lock( + NULL, + &ddsd, + DDLOCK_WAIT | + DDLOCK_WRITEONLY | + DDLOCK_NOSYSLOCK, + NULL)) == DD_OK); + + ASSERT(WITHIN(ot->format, 0, OS_TEXTURE_FORMAT_NUMBER - 1)); + + otf = &OS_tformat[ot->format]; + + if (ot->format == OS_TEXTURE_FORMAT_8) + { + // + // 8-bits per pixel. + // + + OS_bitmap_ubyte_screen = (UBYTE *) ddsd.lpSurface; + OS_bitmap_ubyte_pitch = ddsd.lPitch; + + OS_bitmap_uword_screen = NULL; + OS_bitmap_uword_pitch = 0; + } + else + { + OS_bitmap_ubyte_screen = NULL; + OS_bitmap_ubyte_pitch = 0; + + OS_bitmap_uword_screen = (UWORD *) ddsd.lpSurface; + OS_bitmap_uword_pitch = ddsd.lPitch >> 1; + } + + OS_bitmap_format = ot->format; + OS_bitmap_width = ddsd.dwWidth; + OS_bitmap_height = ddsd.dwHeight; + OS_bitmap_mask_r = otf->mask_r; + OS_bitmap_mask_g = otf->mask_g; + OS_bitmap_mask_b = otf->mask_b; + OS_bitmap_mask_a = otf->mask_a; + OS_bitmap_shift_r = otf->shift_r; + OS_bitmap_shift_g = otf->shift_g; + OS_bitmap_shift_b = otf->shift_b; + OS_bitmap_shift_a = otf->shift_a; +} + +void OS_texture_unlock(OS_Texture *ot) +{ + // + // Unlock the surface. + // + + ot->ddsurface->Unlock(NULL); +} + + +SLONG OS_texture_blit_from_backbuffer(OS_Texture *ot, SLONG x, SLONG y) +{ + RECT src_rect; + + src_rect.top = y; + src_rect.left = x; + src_rect.bottom = y + ot->height; + src_rect.right = x + ot->width; + + if (ot->ddsurface->Blt(NULL, OS_frame.GetBackBuffer(), &src_rect, DDBLT_WAIT, NULL) == DD_OK) + { + return TRUE; + } + else + { + return FALSE; + } +} + + + + +// ======================================================== +// +// PIPELINE SETUP AND VALIDATION +// +// ======================================================== + + + +void OS_init_renderstates() +{ + LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice(); + + // + // Setup renderstates. + // + + d3d->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); + d3d->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_SUBPIXEL, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL); + d3d->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW); + d3d->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE); + d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); + d3d->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE); + + if (KEY_on[KEY_A]) + { + d3d->SetRenderState(D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_SORTINDEPENDENT); + } + else + { + d3d->SetRenderState(D3DRENDERSTATE_ANTIALIAS, D3DANTIALIAS_NONE); + } + + // + // Setup pipeline for one-texture gouraud shaded. + // + + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + d3d->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + + d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + d3d->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); + + d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); + + d3d->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_LINEAR); + d3d->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + d3d->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + + d3d->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFG_LINEAR); + d3d->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + d3d->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + + // + // No alpha. + // + + d3d->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + d3d->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + d3d->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE); +} + + + +// +// Works out how to setup the pipeline for additive and multiplicitive +// multi-texturing. +// + +#define OS_METHOD_NUMBER_MUL 2 + +SLONG OS_pipeline_method_mul; + +void OS_pipeline_calculate() +{ + ULONG num_passes; + + LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice(); + + OS_pipeline_method_mul = 0; + + OS_Texture *ot1 = OS_texture_create(32, 32, OS_TEXTURE_FORMAT_RGB); + OS_Texture *ot2 = OS_texture_create(32, 32, OS_TEXTURE_FORMAT_RGB); + + while(1) + { + OS_init_renderstates(); + + d3d->SetTexture(0, ot1->ddtx); + d3d->SetTexture(1, ot2->ddtx); + + switch(OS_pipeline_method_mul) + { + case 1: + + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + + break; + + case 0: + + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + + d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + + d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + d3d->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_CURRENT); + + break; + + default: + + // + // Didn't find any way to do mulitexturing! + // + + break; + } + + if (OS_pipeline_method_mul == OS_METHOD_NUMBER_MUL) + { + // + // No multitexturing! :( + // + + break; + } + + if (d3d->ValidateDevice(&num_passes) == D3D_OK) + { + if (num_passes != 0) + { + // + // Found a methed for doing additive multi-texturing. + // + + OS_string("Validated %d with %d passes\n", OS_pipeline_method_mul, num_passes); + + break; + } + } + + OS_pipeline_method_mul += 1; + } + + OS_string("Multitexture method %d\n", OS_pipeline_method_mul); +} + + +void OS_change_renderstate_for_type(ULONG draw) +{ + LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice(); + + if (draw & OS_DRAW_ADD) + { + d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE); + d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); + } + + if (draw & OS_DRAW_MULTIPLY) + { + d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_DESTCOLOR); + d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_SRCCOLOR); + } + + if (draw & OS_DRAW_MULBYONE) + { + d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_DESTCOLOR); + d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO); + } + + if (draw & OS_DRAW_CLAMP) + { + d3d->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + } + + if (draw & OS_DRAW_DECAL) + { + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + } + + if (draw & OS_DRAW_TRANSPARENT) + { + d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ZERO); + d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); + } + + if (draw & OS_DRAW_DOUBLESIDED) + { + d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + } + + if (draw & OS_DRAW_NOZWRITE) + { + d3d->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE); + } + + if (draw & OS_DRAW_ALPHAREF) + { + d3d->SetRenderState(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL); + d3d->SetRenderState(D3DRENDERSTATE_ALPHAREF,0); + d3d->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE,TRUE); + + // + // Make sure the alpha from the texture gets through. + // + + d3d->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + } + + if (draw & OS_DRAW_ZREVERSE) + { + d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL); + } + + if (draw & OS_DRAW_ZALWAYS) + { + d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS); + } + + if (draw & OS_DRAW_CULLREVERSE) + { + d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CW); + } + + if (draw & OS_DRAW_NODITHER) + { + d3d->SetRenderState(D3DRENDERSTATE_DITHERENABLE, FALSE); + } + + if (draw & OS_DRAW_ALPHABLEND) + { + d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); + d3d->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); + + d3d->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + d3d->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + } + + if (draw & OS_DRAW_TEX_NONE) + { + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + } + + if (draw & OS_DRAW_TEX_MUL) + { + switch(OS_pipeline_method_mul) + { + case 1: + + if (draw & OS_DRAW_DECAL) + { + // + // Don't multiply by diffuse colour... + // + + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + } + else + { + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + } + + d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + + break; + + case 0: + + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + + d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + + if (draw & OS_DRAW_DECAL) + { + // + // Don't multiply by diffuse colour... + // + } + else + { + d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + d3d->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_CURRENT); + } + + break; + + default: + break; + } + } + + if (draw & OS_DRAW_NOFILTER) + { + d3d->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_POINT); + d3d->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT); + + d3d->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFG_POINT); + d3d->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_POINT); + } +} + + +void OS_undo_renderstate_type_changes(void) +{ + LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice(); + + d3d->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + d3d->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3d->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + + d3d->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); + + d3d->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + + d3d->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); + d3d->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW); + d3d->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE); + d3d->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL); + d3d->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE); + d3d->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); + + d3d->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_LINEAR); + d3d->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + + d3d->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFG_LINEAR); + d3d->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); +} + +// ======================================================== +// +// WINDOWS STUFF +// +// ======================================================== + +void OS_string(CBYTE *fmt, ...) +{ + // + // Work out the real message. + // + + CBYTE message[512]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + OutputDebugString(message); +} + + +SLONG OS_game_start_tick_count; + +SLONG OS_ticks(void) +{ + return GetTickCount() - OS_game_start_tick_count; +} + +void OS_ticks_reset() +{ + OS_game_start_tick_count = GetTickCount(); +} + + +SLONG OS_mhz; + +// +// Returns TRUE if the processor has support for the RDTSC instruction. +// + +SLONG OS_has_rdtsc(void) +{ + SLONG res; + + _asm + { + mov eax, 0 + cpuid + mov res, eax + } + + if (res == 0) + { + // + // This is an old 486! + // + + return FALSE; + } + + // + // Check the processor feature info. + // + + _asm + { + mov eax, 1 + cpuid + mov res, edx + } + + if (res & (1 << 4)) + { + return TRUE; + } + else + { + return FALSE; + } +} + +// +// Returns the number of processor ticks since the processor was reset / 65536 +// + +ULONG OS_rdtsc(void) +{ + ULONG hi; + ULONG lo; + + _asm + { + rdtsc + mov hi, edx + mov lo, eax + } + + ULONG ans; + + ans = lo >> 16; + ans |= hi << 16; + + return ans; +} + + +void OS_work_out_mhz(void) +{ + if (OS_has_rdtsc()) + { + SLONG tick; + ULONG tsc1 = OS_rdtsc(); + + // + // Wait a second. + // + + tick = OS_ticks(); + + while(OS_ticks() < tick + 1000); + + ULONG tsc2 = OS_rdtsc(); + + float persec = float(tsc2 - tsc1); + + persec *= 65536.0F / 1000000.0F; + + OS_mhz = SLONG(persec + 0.5F); + } + else + { + // + // It must be a 486... lets say its 66Mhz and be hopeful. + // + + OS_mhz = 66; + } +} + +SLONG OS_processor_mhz(void) +{ + return OS_mhz; +} + + +void OS_error(CBYTE *fmt, ...) +{ + if (!OS_frame_is_fullscreen) + { + // + // Work out the real message. + // + + CBYTE message[512]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + MessageBox( + OS_window_handle, + message, + "Error", + MB_ICONERROR | MB_OK); + + } +} + + +SLONG OS_is_archive_bit_set(CBYTE *fname) +{ + SLONG attribs; + + attribs = GetFileAttributes(fname); + + if (attribs == -1) + { + // + // Error! + // + + return FALSE; + } + else + { + if (attribs & FILE_ATTRIBUTE_ARCHIVE) + { + return TRUE; + } + else + { + return FALSE; + } + } +} + +void OS_clear_archive_bit(CBYTE *fname) +{ + SLONG attribs; + + attribs = GetFileAttributes(fname); + + if (attribs == -1) + { + // + // Error! + // + + return; + } + else + { + attribs &= ~FILE_ATTRIBUTE_ARCHIVE; + + SetFileAttributes(fname, attribs); + } +} + + + + +// ======================================================== +// +// MOUSE STUFF +// +// ======================================================== + +void OS_mouse_get(SLONG *x, SLONG *y) +{ + POINT point; + + GetCursorPos(&point); + + if (!OS_frame_is_fullscreen) + { + RECT rect; + + // + // (point.x,point.y) is in screen coordinates. We want it to + // be relative to the client rectangle of our window. + // + + ScreenToClient( + OS_window_handle, + &point); + } + + *x = point.x; + *y = point.y; +} + +void OS_mouse_set(SLONG x, SLONG y) +{ + if (!OS_frame_is_fullscreen) + { + POINT point; + + point.x = x; + point.y = y; + + // + // (x,y) is in relative to the client rectangle of our window + // but SetCurorPos wandt screen coordinates. + // + + ClientToScreen( + OS_window_handle, + &point); + } + + SetCursorPos(x, y); +} + +SLONG OS_message_handler_request_quit; + +LRESULT CALLBACK OS_message_handler( + HWND window_handle, + UINT message_type, + WPARAM param_w, + LPARAM param_l) +{ + UBYTE scancode; + + switch(message_type) + { + case WM_PAINT: + + // + // The user callback function does all the screen drawing. + // Do enough to appease windows. + // + + HDC device_context_handle; + PAINTSTRUCT paintstruct; + + device_context_handle = BeginPaint(window_handle, &paintstruct); + EndPaint(window_handle, &paintstruct); + + return 0; + + case WM_CHAR: + KEY_inkey = param_w; + break; + + case WM_KEYDOWN: + case WM_KEYUP: + + // + // Keyboard stuff. + // + + scancode = (param_l >> 16) & 0xff; + scancode |= (param_l >> 17) & 0x80; + + if (message_type == WM_KEYDOWN) + { + KEY_on[scancode] = 1; + } + else + { + KEY_on[scancode] = 0; + } + + // + // Alt keys don't work. + // + + KEY_on[KEY_LALT] = 0; + KEY_on[KEY_RALT] = 0; + + // + // Check for shift/alt/control keys. + // + + KEY_shift = 0; + + if (KEY_on[KEY_LSHIFT ] || KEY_on[KEY_RSHIFT ]) KEY_shift |= KEY_SHIFT; + if (KEY_on[KEY_LCONTROL] || KEY_on[KEY_RCONTROL]) KEY_shift |= KEY_CONTROL; + if (KEY_on[KEY_LALT ] || KEY_on[KEY_RALT ]) KEY_shift |= KEY_ALT; + + if (KEY_on[KEY_ESCAPE]) + { + OS_message_handler_request_quit = TRUE; + } + + break; + + case WM_MOVE: + + // + // Tell the frame about the new position of the window. + // + + OS_frame.Move(LOWORD(param_l),HIWORD(param_l)); + + // + // Fall through to the default handling. + // + + break; + + case WM_CLOSE: + OS_message_handler_request_quit = TRUE; + return 0; + + default: + break; + } + + + // + // Just let windows do its normal thing. + // + + return DefWindowProc( + window_handle, + message_type, + param_w, + param_l); + +} + + +void OS_process_messages() +{ + MSG msg; + int ret; + + while(1) + { + // + // Poll the joystick. + // + + OS_joy_poll(); + + // + // Activate the changes made to the direct sound settings... + // + + OS_sound_update_changes(); + + // + // Wait for a message to be available. + // + + WaitMessage(); + + while(PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) + { + ret = GetMessage(&msg, NULL, 0, 0); + + if (ret == 0 || ret == -1) + { + // + // Kill the game! + // + + return; + } + + TranslateMessage(&msg); + DispatchMessage (&msg); + } + + if (OS_message_handler_request_quit) + { + OS_message_handler_request_quit = FALSE; + + // + // The window has been told to close! + // + + return; + } + } +} + +// +// Valid devices. +// + +typedef struct +{ + D3DEnum_DriverInfo *driver; + D3DEnum_DeviceInfo *device; + D3DEnum_ModeInfo *mode; // NULL => Use windowed mode. + +} OS_Mode; + +#define OS_MAX_MODES 16 + +OS_Mode OS_mode[OS_MAX_MODES]; +SLONG OS_mode_upto; +SLONG OS_mode_sel; + +// +// Finds the valid devices from the D3DEnumerated choice and set +// the OS_mode_sel to the default. +// + +void OS_mode_init() +{ + SLONG i; + + D3DEnum_DriverInfo *vi; + D3DEnum_DeviceInfo *ci; + D3DEnum_ModeInfo *mi; // NULL => Use windowed mode. + + OS_mode_upto = 0; + OS_mode_sel = 0; + + SLONG lookfor640x480; + SLONG lookfor512x384; + + // + // Find all valid modes. + // + + for (vi = D3DEnum_GetFirstDriver(); vi; vi = vi->pNext) + { + for (ci = vi->pFirstDevice; ci; ci = ci->pNext) + { + if (ci->bIsHardware) + { + // + // Found a hardware device. + // + + if (WITHIN(OS_mode_upto, 0, OS_MAX_MODES - 1)) + { + OS_mode[OS_mode_upto].driver = vi; + OS_mode[OS_mode_upto].device = ci; + OS_mode[OS_mode_upto].mode = NULL; + + #ifdef NDEBUG + + lookfor512x384 = FALSE; + lookfor640x480 = TRUE; + + #else + + lookfor512x384 = FALSE; + lookfor640x480 = !ci->bWindowed; + + #endif + + if (lookfor512x384) + { + // + // Look for the first 512x384 mode. + // + + for (mi = ci->pFirstMode; mi; mi = mi->pNext) + { + if (mi->ddsd.dwWidth == 512 && + mi->ddsd.dwHeight == 384) + { + OS_mode[OS_mode_upto].mode = mi; + + // + // We already have our mode. + // + + lookfor640x480 = FALSE; + + break; + } + } + } + + if (lookfor640x480) + { + // + // Look for the first 640x480 mode. + // + + for (mi = ci->pFirstMode; mi; mi = mi->pNext) + { + if (mi->ddsd.dwWidth == 640 && + mi->ddsd.dwHeight == 480) + { + OS_mode[OS_mode_upto].mode = mi; + + break; + } + } + } + + if (OS_mode[OS_mode_upto].mode == NULL) + { + // + // Make sure this device support windowed mode! + // + + if (OS_mode[OS_mode_upto].device->bWindowed) + { + // + // We are ok. + // + } + else + { + // + // Use the first available mode. + // + + OS_mode[OS_mode_upto].mode = OS_mode[OS_mode_upto].device->pFirstMode; + } + } + + OS_mode_upto += 1; + } + } + } + } + + #ifndef NDEBUG + + // + // In debug build choose the first windowed mode. + // + + for (i = 0; i < OS_mode_upto; i++) + { + if (OS_mode[i].device->bWindowed) + { + OS_mode_sel = i; + } + } + + #else + + // + // In release build choose the last mode. + // + + OS_mode_sel = OS_mode_upto - 1; + + #endif +} + + +// +// Adds the modes for the current selection to the combo box. +// + +void OS_mydemo_setup_mode_combo(HWND combo_handle, SLONG mode) +{ + SLONG index; + + ASSERT(WITHIN(mode, 0, OS_mode_upto - 1)); + + // + // Clear all old modes. + // + + SendMessage(combo_handle, CB_RESETCONTENT, 0, 0); + + // + // Add each mode. + // + + D3DEnum_ModeInfo *mi; + + if (OS_mode[mode].device->bWindowed) + { + index = SendMessage(combo_handle, CB_ADDSTRING, 0, (LPARAM) "In a window"); + + SendMessage(combo_handle, CB_SETITEMDATA, (WPARAM) index, (LPARAM) NULL); + + if (NULL == OS_mode[mode].mode) + { + // + // This is the current selection. + // + + SendMessage(combo_handle, CB_SETCURSEL, index, 0); + } + } + + for (mi = OS_mode[mode].device->pFirstMode; mi; mi = mi->pNext) + { + index = SendMessage(combo_handle, CB_ADDSTRING, 0, (LPARAM) mi->strDesc); + + SendMessage(combo_handle, CB_SETITEMDATA, (WPARAM) index, (LPARAM) mi); + + if (mi == OS_mode[mode].mode) + { + // + // This is the current selection. + // + + SendMessage(combo_handle, CB_SETCURSEL, index, 0); + } + } +} + + + +// +// The callback function for the MyDemo dialog box. +// + +#define OS_MYDEMO_RUN 1 +#define OS_MYDEMO_EXIT 2 + +BOOL CALLBACK OS_mydemo_proc( + HWND dialog_handle, + UINT message_type, + WPARAM param_w, + LPARAM param_l) +{ + SLONG i; + SLONG d; + SLONG res; + SLONG index; + + RECT rect; + + HWND combo_handle; + + D3DEnum_DriverInfo *vi; + D3DEnum_DeviceInfo *ci; + + switch(message_type) + { + case WM_INITDIALOG: + + // + // Fill out the list boxes with the correct values. First find + // all compatible + // + + combo_handle = GetDlgItem(dialog_handle, IDC_COMBO_DRIVER); + + for (i = 0; i < OS_mode_upto; i++) + { + SendMessage(combo_handle, CB_ADDSTRING, 0, (LPARAM) OS_mode[i].driver->strDesc); + } + + // + // Set the current selection. + // + + SendMessage(combo_handle, CB_SETCURSEL, OS_mode_sel, 0); + + // + // Add the modes for the current selection. + // + + combo_handle = GetDlgItem(dialog_handle, IDC_COMBO_MODE); + + OS_mydemo_setup_mode_combo(combo_handle, OS_mode_sel); + + { + CBYTE mhz[64]; + + sprintf(mhz, "Detected a %dMhz processor", OS_mhz); + + // + // What speed processor have we detected? + // + + SetWindowText(GetDlgItem(dialog_handle, IDC_PROCESSOR), mhz); + } + + // + // Run the egg physics by default. + // + + CheckDlgButton(dialog_handle, IDC_RUN_PATCH_TEST, BST_CHECKED); + + return TRUE; + + case WM_COMMAND: + + switch(LOWORD(param_w)) + { + case IDOK: + EndDialog(dialog_handle, OS_MYDEMO_RUN); + return TRUE; + + case IDCANCEL: + EndDialog(dialog_handle, OS_MYDEMO_EXIT); + return TRUE; + + case IDC_COMBO_DRIVER: + + switch(HIWORD(param_w)) + { + case CBN_SELCHANGE: + + // + // Change the list of modes. + // + + OS_mode_sel = SendMessage((HWND) param_l, CB_GETCURSEL, 0, 0); + + ASSERT(WITHIN(OS_mode_sel, 0, OS_mode_upto - 1)); + + OS_mydemo_setup_mode_combo( + GetDlgItem(dialog_handle, IDC_COMBO_MODE), + OS_mode_sel); + + break; + } + + break; + + case IDC_COMBO_MODE: + + switch(HIWORD(param_w)) + { + case CBN_SELCHANGE: + + // + // Update the current mode. + // + + index = SendMessage((HWND) param_l, CB_GETCURSEL, 0, 0); + + ASSERT(WITHIN(OS_mode_sel, 0, OS_mode_upto - 1)); + + OS_mode[OS_mode_sel].mode = (D3DEnum_ModeInfo * /* We hope */) SendMessage((HWND) param_l, CB_GETITEMDATA, (WPARAM) index, 0); + + break; + } + + break; + } + + break; + + case WM_CLOSE: + EndDialog(dialog_handle, OS_MYDEMO_EXIT); + return TRUE; + } + + return FALSE; +} + + +// +// The game thread's function and HANDLE. +// + +HANDLE OS_game_thread_handle; +DWORD OS_game_thread_id; + +DWORD WINAPI OS_game_thread_function(void *data) +{ + MAIN_main(); + + OS_message_handler_request_quit = TRUE; + OS_game_thread_handle = FALSE; + OS_game_thread_id = FALSE; + + // + // Send a windows message to our window to wake it up so it'll exit. + // + + PostMessage(OS_window_handle, WM_CLOSE, 0, 0); + + return 0; +} + + + + +// +// The entry point of the program. +// + +int WINAPI WinMain( + HINSTANCE this_instance, + HINSTANCE last_instance, + LPSTR command_line, + int start_show_state) +{ + HRESULT res; + + // + // Remember the arguments passed to this function. + // + + OS_this_instance = this_instance; + OS_last_instance = last_instance; + OS_command_line = command_line; + OS_start_show_state = start_show_state; + + OS_wcl.hInstance = this_instance; + OS_wcl.lpszClassName = OS_application_name; + OS_wcl.lpfnWndProc = OS_message_handler; + OS_wcl.style = 0; + OS_wcl.cbSize = sizeof(WNDCLASSEX); + OS_wcl.cbClsExtra = 0; + OS_wcl.cbWndExtra = 0; + OS_wcl.lpszMenuName = NULL; + OS_wcl.hIcon = LoadIcon(this_instance, MAKEINTRESOURCE(IDI_ICON1)); + OS_wcl.hIconSm = NULL;//LoadIcon(this_instance, MAKEINTRESOURCE(IDI_ICON1)); + OS_wcl.hCursor = LoadCursor(NULL, IDC_ARROW); + OS_wcl.hbrBackground = (HBRUSH) GetStockObject(NULL_BRUSH); + + // + // Register the window class. + // + + if (RegisterClassEx(&OS_wcl) == 0) + { + // + // Could not register the window class! + // + + return 0; + } + + // + // The window size in windowed mode. + // + + #define OS_WINDOW_WIDTH 640 + #define OS_WINDOW_HEIGHT 480 + + // + // Create a window + // + + RECT rect; + + rect.left = 100 + 0; + rect.right = 100 + OS_WINDOW_WIDTH; + rect.top = 100 + 0; + rect.bottom = 100 + OS_WINDOW_HEIGHT; + + AdjustWindowRect( + &rect, + WS_CAPTION, + FALSE); + + OS_window_handle = CreateWindow( + OS_application_name, + OS_application_name, + WS_CAPTION | WS_SYSMENU, + 50, + 50, + rect.right - rect.left, + rect.bottom - rect.top, + NULL, + NULL, + this_instance, + NULL); + + // + // Make sure it worked. + // + + if (OS_window_handle == 0) + { + return 0; + } + + // + // Initialise joystick control. + // + + OS_joy_init(); + + // + // Find out the speed of the machine we are running on. + // + + OS_work_out_mhz(); + + // + // Enumerate the devices. + // + + D3DEnum_EnumerateDevices(NULL); + + D3DEnum_DriverInfo *di = D3DEnum_GetFirstDriver(); + + // + // Find valid modes. + // + + OS_mode_init(); + + if (OS_mode_upto == 0) + { + // + // No valid screen mode! + // + + MessageBox( + OS_window_handle, + "Could not find a 3d accelerator card. Make sure that you have DirectX 6.0 or higher installed.", "Beat", MB_ICONERROR | MB_OK); + + exit(1); + } + + have_another_go:; + + // + // Promt the user to choose a mode. + // + + switch(DialogBox( + OS_this_instance, + MAKEINTRESOURCE(IDD_DRIVERS), + OS_window_handle, + OS_mydemo_proc)) + { + case OS_MYDEMO_RUN: + break; + + case OS_MYDEMO_EXIT: + + // + // Close gracefully... + // + + D3DEnum_FreeResources(); + + return 0; + + default: + exit(1); + break; + } + + { + GUID *driver; + GUID *device; + DDSURFACEDESC2 *display_mode; + BOOL is_windowed; + BOOL is_hardware; + + #if WE_USE_THE_DEFAULT_DIALOG_BOX + + // + // Prompt the user for a device and a driver. + // + + INT ret = D3DEnum_UserDlgSelectDriver(OS_window_handle, TRUE); + + D3DEnum_GetSelectedDriver( + &driver, + &device, + &display_mode, + &is_windowed, + &is_hardware); + + OS_frame_is_fullscreen = !is_windowed; + OS_frame_is_hardware = is_hardware; + + #else + + driver = OS_mode[OS_mode_sel].driver->pGUID; + device = OS_mode[OS_mode_sel].device->pGUID; + + if (OS_mode[OS_mode_sel].mode) + { + display_mode = &OS_mode[OS_mode_sel].mode->ddsd; + + OS_frame_is_fullscreen = TRUE; + OS_frame_is_hardware = TRUE; + } + else + { + display_mode = NULL; + + OS_frame_is_fullscreen = FALSE; + OS_frame_is_hardware = TRUE; + } + + #endif + + // + // Initialise the framework. + // + + DWORD flags; + + flags = 0; + flags |= D3DFW_BACKBUFFER; + flags |= D3DFW_ZBUFFER; + + if (OS_frame_is_fullscreen) + { + flags |= D3DFW_FULLSCREEN; + } + + if (OS_frame_is_fullscreen) + { + // + // Hide the mouse. + // + + ShowCursor(FALSE); + + // + // Makes the window not redraw itself when we go fullscreen. + // + + SetWindowLong(OS_window_handle, GWL_STYLE, WS_POPUP); + } + + res = OS_frame.Initialize( + OS_window_handle, + driver, + device, + display_mode, + flags); + + if (res == S_OK) + { + if (!OS_frame_is_fullscreen) + { + // + // Show our window! + // + + ShowWindow(OS_window_handle, SW_SHOW); + } + + // + // Enumerate texture formats. + // + + { + int i; + + OS_Tformat *otf; + + // + // Find the texture formats. + // + + OS_frame.GetD3DDevice()->EnumTextureFormats(OS_texture_enumerate_pixel_formats, NULL); + + // + // The pixel format of the screen. + // + + { + DDSURFACEDESC2 ddsd; + + memset(&ddsd, 0, sizeof(ddsd)); + + ddsd.dwSize = sizeof(ddsd); + + if (OS_frame.GetBackBuffer()->GetSurfaceDesc(&ddsd) == DD_OK) + { + OS_tformat[OS_TEXTURE_FORMAT_SCREEN].valid = TRUE; + OS_tformat[OS_TEXTURE_FORMAT_SCREEN].ddpf = ddsd.ddpfPixelFormat; + } + } + + // + // Set the masks and shifts for each texture format. + // + + for (i = 0; i < OS_TEXTURE_FORMAT_NUMBER; i++) + { + otf = &OS_tformat[i]; + + if (i == OS_TEXTURE_FORMAT_8) + { + // + // We don't have to set the masks and shifts for grayscale textures. + // + + continue; + } + + if (otf->valid) + { + // + // Calculate the masks and shifts. + // + + OS_calculate_mask_and_shift(otf->ddpf.dwRBitMask, &otf->mask_r, &otf->shift_r); + OS_calculate_mask_and_shift(otf->ddpf.dwGBitMask, &otf->mask_g, &otf->shift_g); + OS_calculate_mask_and_shift(otf->ddpf.dwBBitMask, &otf->mask_b, &otf->shift_b); + + if (otf->ddpf.dwFlags & DDPF_ALPHAPIXELS) + { + OS_calculate_mask_and_shift(otf->ddpf.dwRGBAlphaBitMask, &otf->mask_a, &otf->shift_a); + } + } + } + } + + // + // What is the screen-res? + // + + RECT *dimensions = OS_frame.GetViewportRect(); + + OS_screen_width = float(dimensions->right); + OS_screen_height = float(dimensions->bottom); + + // + // Work out how to multi-texture, find all the texture directories, + // initailise the sound system and setup the floating point unit. + // + + ftol_init(); + OS_pipeline_calculate(); + OS_init_texpaths(); + OS_sound_init(); + + // + // Time relative to the beginning of the program. + // + + OS_game_start_tick_count = GetTickCount(); + + // + // Start the game. + // + + OS_game_thread_handle = CreateThread( + NULL, + 0, + OS_game_thread_function, + NULL, + 0, + &OS_game_thread_id); + + if (OS_game_thread_handle) + { + // + // Make the thread get less time than the message loop! + // + + SetThreadPriority( + OS_game_thread_handle, + THREAD_PRIORITY_BELOW_NORMAL); + + // + // This thread processes messages while the game + // thread runs the game. + // + + OS_process_messages(); + + if (OS_game_thread_handle) + { + // + // Exit the game thread. + // + + TerminateThread( + OS_game_thread_handle, + 0); + } + } + + // + // Clean up. + // + + OS_frame.DestroyObjects(); + + OS_sound_finish(); + } + else + { + if (OS_frame_is_fullscreen) + { + // + // Show the mouse. + // + + ShowCursor(TRUE); + } + + // + // Could not set that mode! + // + + CBYTE *err; + + if (res == D3DFWERR_NOZBUFFER) + { + err = "There was not enough memory to create the zbuffer. Try using a lower resolution mode."; + + } + else + { + err = "Could not setup the display using those settings. Try changing driver or using another mode."; + } + + MessageBox( + OS_window_handle, + err, + "Beat", + MB_ICONERROR | MB_OK); + + // + // Have another go... + // + + goto have_another_go; + } + } + + // + // Free all enumeration resources. + // + + D3DEnum_FreeResources(); + + return 0; +} + + +// ======================================================== +// +// ROTATING POINTS +// +// ======================================================== + +// +// The camera and the screen. +// + +float OS_cam_x; +float OS_cam_y; +float OS_cam_z; +float OS_cam_aspect; +float OS_cam_lens; +float OS_cam_view_dist; +float OS_cam_over_view_dist; +float OS_cam_matrix[9]; +float OS_cam_view_matrix[9]; +float OS_cam_view_matrix_plus_local_rot[9]; + +float OS_cam_screen_x1; +float OS_cam_screen_y1; +float OS_cam_screen_x2; +float OS_cam_screen_y2; + +float OS_cam_screen_width; +float OS_cam_screen_height; +float OS_cam_screen_mid_x; +float OS_cam_screen_mid_y; +float OS_cam_screen_mul_x; +float OS_cam_screen_mul_y; + +void OS_camera_set( + float world_x, + float world_y, + float world_z, + float view_dist, + float yaw, + float pitch, + float roll, + float lens, + float screen_x1, + float screen_y1, + float screen_x2, + float screen_y2) +{ + float matrix[9]; + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + OS_camera_set( + world_x, + world_y, + world_z, + view_dist, + matrix, + lens, + screen_x1, + screen_y1, + screen_x2, + screen_y2); +} + +void OS_camera_set( + float world_x, + float world_y, + float world_z, + float view_dist, + float matrix[9], + float lens, + float screen_x1, + float screen_y1, + float screen_x2, + float screen_y2) +{ + OS_cam_screen_x1 = screen_x1 * OS_screen_width; + OS_cam_screen_y1 = screen_y1 * OS_screen_height; + OS_cam_screen_x2 = screen_x2 * OS_screen_width; + OS_cam_screen_y2 = screen_y2 * OS_screen_height; + + OS_cam_screen_width = OS_cam_screen_x2 - OS_cam_screen_x1; + OS_cam_screen_height = OS_cam_screen_y2 - OS_cam_screen_y1; + OS_cam_screen_mid_x = OS_cam_screen_x1 + OS_cam_screen_width * 0.5F; + OS_cam_screen_mid_y = OS_cam_screen_y1 + OS_cam_screen_height * 0.5F; + OS_cam_screen_mul_x = OS_cam_screen_width * 0.5F / OS_ZCLIP_PLANE; + OS_cam_screen_mul_y = OS_cam_screen_height * 0.5F / OS_ZCLIP_PLANE; + + OS_cam_x = world_x; + OS_cam_y = world_y; + OS_cam_z = world_z; + + OS_cam_lens = lens; + OS_cam_view_dist = view_dist; + OS_cam_over_view_dist = 1.0F / view_dist; + OS_cam_aspect = OS_cam_screen_height / OS_cam_screen_width; + + memcpy(OS_cam_matrix, matrix, sizeof(OS_cam_matrix)); + memcpy(OS_cam_view_matrix, matrix, sizeof(OS_cam_matrix)); + + MATRIX_skew( + OS_cam_matrix, + OS_cam_aspect, + OS_cam_lens, + OS_cam_over_view_dist); // Shrink the matrix down so the furthest point has a view distance z of 1.0F +} + + + +OS_Trans OS_trans[OS_MAX_TRANS]; +SLONG OS_trans_upto; + +void OS_transform( + float world_x, + float world_y, + float world_z, + OS_Trans *os) +{ + os->x = world_x - OS_cam_x; + os->y = world_y - OS_cam_y; + os->z = world_z - OS_cam_z; + + MATRIX_MUL( + OS_cam_matrix, + os->x, + os->y, + os->z); + + os->clip = OS_CLIP_ROTATED; + + if (os->z < OS_ZCLIP_PLANE) + { + os->clip |= OS_CLIP_NEAR; + + return; + } + else + if (os->z > 1.0F) + { + os->clip |= OS_CLIP_FAR; + + return; + } + else + { + // + // The z-range of the point is okay. + // + + os->Z = OS_ZCLIP_PLANE / os->z; + + os->X = OS_cam_screen_mid_x + OS_cam_screen_mul_x * os->x * os->Z; + os->Y = OS_cam_screen_mid_y - OS_cam_screen_mul_y * os->y * os->Z; + + // + // Set the clipping flags. + // + + os->clip |= OS_CLIP_TRANSFORMED; + + if (os->X < 0.0F ) {os->clip |= OS_CLIP_LEFT;} + else if (os->X > OS_screen_width) {os->clip |= OS_CLIP_RIGHT;} + + if (os->Y < 0.0F ) {os->clip |= OS_CLIP_TOP;} + else if (os->Y > OS_screen_height) {os->clip |= OS_CLIP_BOTTOM;} + + return; + } +} + +float OS_local_world_x; +float OS_local_world_y; +float OS_local_world_z; +float OS_local_world_matrix[9]; +float OS_local_view_x; +float OS_local_view_y; +float OS_local_view_z; +float OS_local_matrix_plus_camera[9]; + +void OS_local_position_and_rotation( + float world_x, + float world_y, + float world_z, + float local_rotation_matrix[9]) +{ + // + // Store the local rotation and position. + // + + OS_local_world_x = world_x; + OS_local_world_y = world_y; + OS_local_world_z = world_z; + + memcpy(OS_local_world_matrix, local_rotation_matrix, sizeof(OS_local_world_matrix)); + + MATRIX_TRANSPOSE(OS_local_world_matrix); + + // + // Premultiply this matrix by the camera matrix. + // + + MATRIX_3x3mul(OS_local_matrix_plus_camera, OS_cam_matrix, OS_local_world_matrix); + MATRIX_3x3mul(OS_cam_view_matrix_plus_local_rot, OS_cam_view_matrix, OS_local_world_matrix); + + // + // Put the centre of the object into viewspace. + // + + OS_local_view_x = world_x - OS_cam_x; + OS_local_view_y = world_y - OS_cam_y; + OS_local_view_z = world_z - OS_cam_z; + + MATRIX_MUL( + OS_cam_matrix, + OS_local_view_x, + OS_local_view_y, + OS_local_view_z); +} + +void OS_transform_local( + float local_x, + float local_y, + float local_z, + OS_Trans *os) +{ + // + // Work out the posiiton of this point in viewspace. + // + + MATRIX_MUL( + OS_local_matrix_plus_camera, + local_x, + local_y, + local_z); + + os->x = local_x + OS_local_view_x; + os->y = local_y + OS_local_view_y; + os->z = local_z + OS_local_view_z; + + os->clip = OS_CLIP_ROTATED; + + if (os->z < OS_ZCLIP_PLANE) + { + os->clip |= OS_CLIP_NEAR; + + return; + } + else + if (os->z > 1.0F) + { + os->clip |= OS_CLIP_FAR; + + return; + } + else + { + // + // The z-range of the point is okay. + // + + os->Z = OS_ZCLIP_PLANE / os->z; + + os->X = OS_cam_screen_mid_x + OS_cam_screen_mul_x * os->x * os->Z; + os->Y = OS_cam_screen_mid_y - OS_cam_screen_mul_y * os->y * os->Z; + + // + // Set the clipping flags. + // + + os->clip |= OS_CLIP_TRANSFORMED; + + if (os->X < 0.0F ) {os->clip |= OS_CLIP_LEFT;} + else if (os->X > OS_screen_width) {os->clip |= OS_CLIP_RIGHT;} + + if (os->Y < 0.0F ) {os->clip |= OS_CLIP_TOP;} + else if (os->Y > OS_screen_height) {os->clip |= OS_CLIP_BOTTOM;} + + return; + } +} + + + + +// ======================================================== +// +// DRAWING STUFF +// +// ======================================================== + +void OS_clear_screen(UBYTE r, UBYTE g, UBYTE b, float z) +{ + ULONG colour = (r << 16) | (g << 8) | (b << 0); + + HRESULT ret = OS_frame.GetViewport()->Clear2( + 1, + (D3DRECT *) OS_frame.GetViewportRect(), + D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + colour, + z, + 0); +} + + + +SLONG OS_in_scene; + +void OS_scene_begin() +{ + ASSERT(!OS_in_scene); + + OS_frame.GetD3DDevice()->BeginScene(); + + OS_in_scene = TRUE; + + // + // Set the render states to their default values. + // + + OS_init_renderstates(); +} + +void OS_scene_end() +{ + ASSERT(OS_in_scene); + + OS_frame.GetD3DDevice()->EndScene(); + + OS_in_scene = FALSE; +} + + +SLONG OS_fps; +SLONG OS_last_time; +SLONG OS_last_frame_count; +SLONG OS_frame_count; + +SLONG OS_fps_get() +{ + SLONG now; + + now = OS_ticks(); + OS_frame_count += 1; + + if (now >= OS_last_time + 1000) + { + OS_fps = OS_frame_count - OS_last_frame_count; + OS_last_frame_count = OS_frame_count; + OS_last_time = now; + } + + return OS_fps; +} + +void OS_fps_draw() +{ + SLONG i; + + float x1; + float y1; + float x2; + float y2; + + float tick; + + SLONG now; + + now = OS_ticks(); + OS_frame_count += 1; + + if (now >= OS_last_time + 1000) + { + OS_fps = OS_frame_count - OS_last_frame_count; + OS_last_frame_count = OS_frame_count; + OS_last_time = now; + } + + OS_Buffer *ob = OS_buffer_new(); + + for (i = 0; i < OS_fps; i++) + { + switch((i + 1) % 10) + { + case 0: + tick = 8.0F; + break; + + case 5: + tick = 5.0F; + break; + + default: + tick = 3.0F; + break; + } + + + x1 = 5.0F + i * 2.0F; + y1 = 5.0F; + x2 = 5.0F + i * 2.0F + 1.0F; + y2 = 5.0F + tick; + + x1 /= OS_screen_width; + y1 /= OS_screen_height; + x2 /= OS_screen_width; + y2 /= OS_screen_height; + + OS_buffer_add_sprite( + ob, + x1, + y1, + x2, + y2, + 0.0F, 1.0F, + 0.0F, 1.0F, + 0.0F, + 0x00ffffff, + 0x00000000, + OS_FADE_BOTTOM); + } + + OS_buffer_draw(ob, NULL); +} + + +void OS_show() +{ + if (OS_in_scene) + { + OS_scene_end(); + } + + if (OS_frame_is_fullscreen) + { + // + // Do we blit or do we flip? + // + + if (1) + { + // + // Flip. + // + + OS_frame.ShowFrame(); + } + else + { + // + // Blit. + // + + LPDIRECTDRAWSURFACE4 fb = OS_frame.GetFrontBuffer(); + LPDIRECTDRAWSURFACE4 bb = OS_frame.GetBackBuffer(); + + fb->Blt(NULL, bb, NULL, DDBLT_WAIT, NULL); + } + } + else + { + OS_frame.ShowFrame(); + } + + OS_poly_count_drawn = 0; + OS_poly_count_transformed = 0; +} + +// +// Our flexible vertex format. +// + +typedef struct +{ + float sx; + float sy; + float sz; + float rhw; + ULONG colour; + ULONG specular; + float tu1; + float tv1; + float tu2; + float tv2; + +} OS_Flert; + +#define OS_FLERT_FORMAT (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2) + +// ======================================================== +// +// BUFFER STUFF +// +// ======================================================== + +typedef struct os_buffer +{ + SLONG num_flerts; + SLONG num_indices; + + SLONG max_flerts; + SLONG max_indices; + + OS_Flert *flert; + UWORD *index; + + OS_Buffer *next; + +} OS_Buffer; + +OS_Buffer *OS_buffer_free; + + +// +// Creates a new buffer. +// + +OS_Buffer *OS_buffer_create(void) +{ + // + // Allocate the buffer. + // + + OS_Buffer *ob = (OS_Buffer *) malloc(sizeof(OS_Buffer)); + + // + // Initialise the buffer. + // + + ob->max_flerts = 256; + ob->max_indices = 1024; + + ob->num_flerts = 0; + ob->num_indices = 1; + + ob->flert = (OS_Flert *) malloc(sizeof(OS_Flert) * ob->max_flerts ); + ob->index = (UWORD *) malloc(sizeof(UWORD ) * ob->max_indices); + + memset(ob->flert, 0, sizeof(OS_Flert) * ob->max_flerts ); + memset(ob->index, 0, sizeof(UWORD ) * ob->max_indices); + + ob->next = NULL; + + return ob; +} + +// +// Gets a buffer from the linked list of free buffers. If the free list is empty, +// it creates a new one. +// + +OS_Buffer *OS_buffer_get(void) +{ + OS_Buffer *ans; + + if (OS_buffer_free) + { + ans = OS_buffer_free; + OS_buffer_free = OS_buffer_free->next; + ans->next = NULL; + } + else + { + ans = OS_buffer_create(); + } + + return ans; +} + +// +// Returns a buffer to the free list. +// + +void OS_buffer_give(OS_Buffer *ob) +{ + ob->next = OS_buffer_free; + OS_buffer_free = ob; +} + +OS_Buffer *OS_buffer_new(void) +{ + OS_Buffer *ob = OS_buffer_get(); + + ob->num_indices = 0; + ob->num_flerts = 1; + + return ob; +} + +// +// Grows the size of the flert array. +// + +void OS_buffer_grow_flerts(OS_Buffer *ob) +{ + ob->max_flerts *= 2; + + ob->flert = (OS_Flert *) realloc(ob->flert, ob->max_flerts * sizeof(OS_Flert)); +} + +void OS_buffer_grow_indices(OS_Buffer *ob) +{ + ob->max_indices *= 2; + + ob->index = (UWORD *) realloc(ob->index, ob->max_indices * sizeof(UWORD)); +} + +void OS_buffer_add_vert(OS_Buffer *ob, OS_Vert *ov) +{ + OS_Trans *ot; + OS_Flert *of; + + // + // Make sure we've got enough room for another vertex. + // + + if (ob->num_flerts >= ob->max_flerts) + { + // + // We need a bigger buffer. + // + + OS_buffer_grow_flerts(ob); + } + + ASSERT(WITHIN(ov->trans, 0, OS_MAX_TRANS - 1)); + + of = &ob->flert[ob->num_flerts]; + ot = &OS_trans [ov->trans]; + + // + // Create the new tlvertex. + // + + of->sx = ot->X; + of->sy = ot->Y; + of->sz = 1.0F - ot->Z; //ot->z; + of->rhw = ot->Z; + of->colour = ov->colour; + of->specular = ov->specular; + of->tu1 = ov->u1; + of->tv1 = ov->v1; + of->tu2 = ov->u2; + of->tv2 = ov->v2; + + // + // Store the index of the flert inside the vertex. + // + + ov->index = ob->num_flerts++; +} + + +// +// Returns the colour 'v' along from colour1 to colour2 where 0.0 <= v <= 1.0 +// + +ULONG OS_interpolate_colour(float v, ULONG colour1, ULONG colour2) +{ + SLONG rb1, rb2, drb, rba; + SLONG ga1, ga2, dga, gaa; + + union + { + float vfloat; + ULONG vfixed8; + }; + + SLONG answer; + + // + // Early outs. + // + + if (colour1 == colour2) {return colour1;} + + if (v < 0.01F) {return colour1;} + if (v > 0.99F) {return colour2;} + + // + // Work out how much to interpolate along in fixed point 8. + // + + vfloat = 32768.0F + v; + vfixed8 &= 0xff; + + // + // Red and blue. + // + + rb1 = colour1 & (0x00ff00ff); + rb2 = colour2 & (0x00ff00ff); + + if (rb1 != rb2) + { + // + // Do interpolation of red and blue simultaneously. + // + + drb = rb2 - rb1; + drb *= vfixed8; + drb >>= 8; + rba = rb1 + drb; + rba &= 0x00ff00ff; + } + else + { + // + // No need to interpolated red and blue. + // + + rba = rb1; + } + + // + // Green and alpha. + // + + ga1 = colour1 >> 8; + ga2 = colour2 >> 8; + + ga1 &= 0x00ff00ff; + ga2 &= 0x00ff00ff; + + if (ga1 != ga2) + { + // + // Do interpolationg of red and blue simultaneously. + // + + dga = ga2 - ga1; + dga *= vfixed8; + gaa = (ga1 << 8) + dga; + gaa &= 0xff00ff00; + } + else + { + // + // No need to interpolate green and alpha. + // + + gaa = ga1 << 8; + } + + answer = rba | gaa; + + return answer; +} + + + +// ======================================================== +// +// Functions to pass the the CLIP module. +// + +void OS_clip_helper_interpolate(void *new_point, void *point1, void *point2, float along) +{ + OS_Vert *ov1 = (OS_Vert *) point1; + OS_Vert *ov2 = (OS_Vert *) point2; + OS_Vert *ovn = (OS_Vert *) new_point; + + ASSERT(WITHIN(ov1->trans, 0, OS_trans_upto - 1)); + ASSERT(WITHIN(ov2->trans, 0, OS_trans_upto - 1)); + + OS_Trans *ot1 = &OS_trans[ov1->trans]; + OS_Trans *ot2 = &OS_trans[ov2->trans]; + + // + // We need a new OS_Trans for the new point. + // + + ASSERT(WITHIN(OS_trans_upto, 0, OS_MAX_TRANS - 1)); + + OS_Trans *otn = &OS_trans[OS_trans_upto]; + + otn->x = ot1->x + along * (ot2->x - ot1->x); + otn->y = ot1->y + along * (ot2->y - ot1->y); + otn->z = OS_ZCLIP_PLANE; + otn->Z = 1.0F; + otn->X = OS_cam_screen_mid_x + OS_cam_screen_mul_x * otn->x; + otn->Y = OS_cam_screen_mid_y - OS_cam_screen_mul_y * otn->y; + + otn->clip = OS_CLIP_TRANSFORMED | OS_CLIP_ROTATED; + + if (otn->X < 0.0F ) {otn->clip |= OS_CLIP_LEFT;} + else if (otn->X > OS_screen_width) {otn->clip |= OS_CLIP_RIGHT;} + + if (otn->Y < 0.0F ) {otn->clip |= OS_CLIP_TOP;} + else if (otn->Y > OS_screen_height) {otn->clip |= OS_CLIP_BOTTOM;} + + // + // Now build the new OS_Vert. + // + + ovn->colour = OS_interpolate_colour(along, ov1->colour, ov2->colour ); + ovn->specular = OS_interpolate_colour(along, ov1->specular, ov2->specular); + ovn->index = NULL; + ovn->trans = OS_trans_upto; + ovn->u1 = ov1->u1 + along * (ov2->u1 - ov1->u1); + ovn->v1 = ov1->v1 + along * (ov2->v1 - ov1->v1); + ovn->u2 = ov1->u2 + along * (ov2->u2 - ov1->u2); + ovn->v2 = ov1->v2 + along * (ov2->v2 - ov1->v2); + + OS_trans_upto += 1; +} + +float OS_clip_helper_signed_distance(void *point) +{ + OS_Vert *ov; + OS_Trans *ot; + + ov = (OS_Vert *) point; + + ASSERT(WITHIN(ov->trans, 0, OS_MAX_TRANS - 1)); + + ot = &OS_trans[ov->trans]; + + return ot->z - OS_ZCLIP_PLANE; +} + +// +// ======================================================== + + + +void OS_buffer_add_triangle( + OS_Buffer *ob, + OS_Vert *ov1, + OS_Vert *ov2, + OS_Vert *ov3) +{ + OS_poly_count_transformed += 1; + + ULONG clip_and = + OS_trans[ov1->trans].clip & + OS_trans[ov2->trans].clip & + OS_trans[ov3->trans].clip; + + if (clip_and & OS_CLIP_TRANSFORMED) + { + if (clip_and & OS_CLIP_OFFSCREEN) + { + // + // The triangle is completely off-screen. + // + + return; + } + else + { + if (ov1->index == NULL) {OS_buffer_add_vert(ob, ov1);} + if (ov2->index == NULL) {OS_buffer_add_vert(ob, ov2);} + if (ov3->index == NULL) {OS_buffer_add_vert(ob, ov3);} + + // + // Add this triangle. All the points are transformed and at least + // one is on screen. + // + + if (ob->num_indices + 3 > ob->max_indices) + { + // + // Need a bigger buffer. + // + + OS_buffer_grow_indices(ob); + } + + ob->index[ob->num_indices++] = ov1->index; + ob->index[ob->num_indices++] = ov2->index; + ob->index[ob->num_indices++] = ov3->index; + + return; + } + } + else + { + ULONG clip_or = + OS_trans[ov1->trans].clip | + OS_trans[ov2->trans].clip | + OS_trans[ov3->trans].clip; + + if (clip_or & OS_CLIP_TRANSFORMED) + { + // + // This triangle needs to be zclipped. + // + + if (clip_or & OS_CLIP_FAR) + { + // + // Reject triangles on the far clip plane. + // + } + else + { + void *clip_tri[3]; + void **clip_ans; + SLONG clip_num; + + clip_tri[0] = ov1; + clip_tri[1] = ov2; + clip_tri[2] = ov3; + + clip_ans = clip_tri; + clip_num = 3; + + CLIP_do( + &clip_ans, + &clip_num, + sizeof(OS_Vert), + OS_clip_helper_interpolate, + OS_clip_helper_signed_distance); + + ASSERT( + clip_num == 3 || + clip_num == 4); + + // + // Recurse... lazily! + // + + ov1 = (OS_Vert *) ((clip_ans)[0]); + ov2 = (OS_Vert *) ((clip_ans)[1]); + ov3 = (OS_Vert *) ((clip_ans)[2]); + + ASSERT(WITHIN(ov1->trans, 0, OS_trans_upto - 1)); + ASSERT(WITHIN(ov2->trans, 0, OS_trans_upto - 1)); + ASSERT(WITHIN(ov3->trans, 0, OS_trans_upto - 1)); + + { + SLONG i; + + for (i = 0; i < clip_num; i++) + { + OS_Vert *ov = (OS_Vert *) (clip_ans[i]); + OS_Trans *ot = &OS_trans[ov->trans]; + + ASSERT(ot->clip & OS_CLIP_TRANSFORMED); + ASSERT(ot->z >= OS_ZCLIP_PLANE); + } + } + + clip_and = + OS_trans[ov1->trans].clip & + OS_trans[ov2->trans].clip & + OS_trans[ov3->trans].clip; + + if (clip_and & OS_CLIP_OFFSCREEN) + { + // + // The triangle is completely off-screen. + // + } + else + { + if (ov1->index == NULL) {OS_buffer_add_vert(ob, ov1);} + if (ov2->index == NULL) {OS_buffer_add_vert(ob, ov2);} + if (ov3->index == NULL) {OS_buffer_add_vert(ob, ov3);} + + // + // Add this triangle. All the points are transformed and at least + // one is on screen. + // + + if (ob->num_indices + 3 > ob->max_indices) + { + // + // Need a bigger buffer. + // + + OS_buffer_grow_indices(ob); + } + + ob->index[ob->num_indices++] = ov1->index; + ob->index[ob->num_indices++] = ov2->index; + ob->index[ob->num_indices++] = ov3->index; + } + + if (clip_num == 4) + { + ov2 = (OS_Vert *) ((clip_ans)[2]); + ov3 = (OS_Vert *) ((clip_ans)[3]); + + clip_and = + OS_trans[ov1->trans].clip & + OS_trans[ov2->trans].clip & + OS_trans[ov3->trans].clip; + + if (clip_and & OS_CLIP_OFFSCREEN) + { + // + // The triangle is completely off-screen. + // + } + else + { + if (ov1->index == NULL) {OS_buffer_add_vert(ob, ov1);} + if (ov2->index == NULL) {OS_buffer_add_vert(ob, ov2);} + if (ov3->index == NULL) {OS_buffer_add_vert(ob, ov3);} + + // + // Add this triangle. All the points are transformed and at least + // one is on screen. + // + + if (ob->num_indices + 3 > ob->max_indices) + { + // + // Need a bigger buffer. + // + + OS_buffer_grow_indices(ob); + } + + ob->index[ob->num_indices++] = ov1->index; + ob->index[ob->num_indices++] = ov2->index; + ob->index[ob->num_indices++] = ov3->index; + } + } + } + + return; + } + else + { + // + // The whole triangle is zclipped one way or another. We assume that + // a single triangle is not going to span both the near and far zclip + // planes... + // + + return; + } + } +} + + +void OS_buffer_add_sprite( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float u1, float v1, + float u2, float v2, + float z, + ULONG colour, + ULONG specular, + ULONG fade) +{ + SLONG i; + + OS_Flert *of; + + // + // Enough room in our buffer? + // + + if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);} + if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);} + + // + // Add four vertices. + // + + for (i = 0; i < 4; i++) + { + of = &ob->flert[ob->num_flerts + i]; + + of->sx = ((i & 1) ? x1 : x2) * OS_screen_width; + of->sy = ((i & 2) ? y1 : y2) * OS_screen_height; + of->sz = z; + of->rhw = 0.5F; + of->colour = colour; + of->specular = specular; + of->tu1 = ((i & 1) ? u1 : u2); + of->tv1 = ((i & 2) ? v1 : v2); + of->tu2 = ((i & 1) ? u1 : u2); + of->tv2 = ((i & 2) ? v1 : v2); + } + + if (fade) + { + if (fade & OS_FADE_TOP) + { + ob->flert[ob->num_flerts + 2].colour = 0x00000000; + ob->flert[ob->num_flerts + 3].colour = 0x00000000; + } + + if (fade & OS_FADE_BOTTOM) + { + ob->flert[ob->num_flerts + 0].colour = 0x00000000; + ob->flert[ob->num_flerts + 1].colour = 0x00000000; + } + + if (fade & OS_FADE_LEFT) + { + ob->flert[ob->num_flerts + 1].colour = 0x00000000; + ob->flert[ob->num_flerts + 3].colour = 0x00000000; + } + + if (fade & OS_FADE_RIGHT) + { + ob->flert[ob->num_flerts + 0].colour = 0x00000000; + ob->flert[ob->num_flerts + 2].colour = 0x00000000; + } + } + + // + // Add two triangles. + // + + ob->index[ob->num_indices + 0] = ob->num_flerts + 0; + ob->index[ob->num_indices + 1] = ob->num_flerts + 1; + ob->index[ob->num_indices + 2] = ob->num_flerts + 3; + + ob->index[ob->num_indices + 3] = ob->num_flerts + 0; + ob->index[ob->num_indices + 4] = ob->num_flerts + 3; + ob->index[ob->num_indices + 5] = ob->num_flerts + 2; + + ob->num_indices += 6; + ob->num_flerts += 4; +} + + + +void OS_buffer_add_multitex_sprite( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float u11, float v11, + float u12, float v12, + float u21, float v21, + float u22, float v22, + float z, + ULONG colour, + ULONG specular, + ULONG fade) +{ + SLONG i; + + OS_Flert *of; + + // + // Enough room in our buffer? + // + + if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);} + if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);} + + // + // Add four vertices. + // + + for (i = 0; i < 4; i++) + { + of = &ob->flert[ob->num_flerts + i]; + + of->sx = ((i & 1) ? x1 : x2) * OS_screen_width; + of->sy = ((i & 2) ? y1 : y2) * OS_screen_height; + of->sz = z; + of->rhw = 0.5F; + of->colour = colour; + of->specular = specular; + of->tu1 = ((i & 1) ? u11 : u12); + of->tv1 = ((i & 2) ? v11 : v12); + of->tu2 = ((i & 1) ? u21 : u22); + of->tv2 = ((i & 2) ? v21 : v22); + } + + if (fade) + { + if (fade & OS_FADE_TOP) + { + ob->flert[ob->num_flerts + 2].colour = 0x00000000; + ob->flert[ob->num_flerts + 3].colour = 0x00000000; + } + + if (fade & OS_FADE_BOTTOM) + { + ob->flert[ob->num_flerts + 0].colour = 0x00000000; + ob->flert[ob->num_flerts + 1].colour = 0x00000000; + } + + if (fade & OS_FADE_LEFT) + { + ob->flert[ob->num_flerts + 1].colour = 0x00000000; + ob->flert[ob->num_flerts + 3].colour = 0x00000000; + } + + if (fade & OS_FADE_RIGHT) + { + ob->flert[ob->num_flerts + 0].colour = 0x00000000; + ob->flert[ob->num_flerts + 2].colour = 0x00000000; + } + } + + // + // Add two triangles. + // + + ob->index[ob->num_indices + 0] = ob->num_flerts + 0; + ob->index[ob->num_indices + 1] = ob->num_flerts + 1; + ob->index[ob->num_indices + 2] = ob->num_flerts + 3; + + ob->index[ob->num_indices + 3] = ob->num_flerts + 0; + ob->index[ob->num_indices + 4] = ob->num_flerts + 3; + ob->index[ob->num_indices + 5] = ob->num_flerts + 2; + + ob->num_indices += 6; + ob->num_flerts += 4; +} + + + +void OS_buffer_add_sprite_rot( + OS_Buffer *ob, + float x_mid, + float y_mid, + float size, // As a percentage of the width of the screen. + float angle, + float u1, float v1, + float u2, float v2, + float z, + ULONG colour, + ULONG specular, + float tu1, float tv1, + float tu2, float tv2) +{ + SLONG i; + + OS_Flert *of; + + float dx = sin(angle) * size; + float dy = cos(angle) * size; + + float x; + float y; + + x_mid *= OS_screen_width; + y_mid *= OS_screen_height; + + // + // Enough room in our buffer? + // + + if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);} + if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);} + + // + // Add four vertices. + // + + for (i = 0; i < 4; i++) + { + of = &ob->flert[ob->num_flerts + i]; + + x = 0.0F; + y = 0.0F; + + if (i & 1) + { + x += dx; + y += dy; + } + else + { + x -= dx; + y -= dy; + } + + if (i & 2) + { + x += -dy; + y += +dx; + } + else + { + x -= -dy; + y -= +dx; + } + + x *= OS_screen_width; + y *= OS_screen_height * 1.33F; + + x += x_mid; + y += y_mid; + + of->sx = x; + of->sy = y; + of->sz = z; + of->rhw = 0.5F; + of->colour = colour; + of->specular = specular; + of->tu1 = ((i & 1) ? u1 : u2); + of->tv1 = ((i & 2) ? v1 : v2); + of->tu2 = ((i & 1) ? tu1 : tu2); + of->tv2 = ((i & 2) ? tv1 : tv2); + } + + // + // Add two triangles. + // + + ob->index[ob->num_indices + 0] = ob->num_flerts + 0; + ob->index[ob->num_indices + 1] = ob->num_flerts + 1; + ob->index[ob->num_indices + 2] = ob->num_flerts + 3; + + ob->index[ob->num_indices + 3] = ob->num_flerts + 0; + ob->index[ob->num_indices + 4] = ob->num_flerts + 3; + ob->index[ob->num_indices + 5] = ob->num_flerts + 2; + + ob->num_indices += 6; + ob->num_flerts += 4; +} + + +void OS_buffer_add_sprite_arbitrary( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float x3, // Normalised to 0.0F - 1.0F + float y3, // Normalised to 0.0F - 1.0F + float x4, // Normalised to 0.0F - 1.0F + float y4, // Normalised to 0.0F - 1.0F + float u1, float v1, + float u2, float v2, + float u3, float v3, + float u4, float v4, + float z, + ULONG colour, + ULONG specular) +{ + OS_buffer_add_sprite_arbitrary( + ob, + x1, y1, + x2, y2, + x3, y3, + x4, y4, + u1, v1, + u2, v2, + u3, v3, + u4, v4, + z,z,z,z, + colour, + specular); +} + + +void OS_buffer_add_sprite_arbitrary( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float x3, // Normalised to 0.0F - 1.0F + float y3, // Normalised to 0.0F - 1.0F + float x4, // Normalised to 0.0F - 1.0F + float y4, // Normalised to 0.0F - 1.0F + float u1, float v1, + float u2, float v2, + float u3, float v3, + float u4, float v4, + float z1, + float z2, + float z3, + float z4, + ULONG colour, + ULONG specular) +{ + SLONG i; + + float x; + float y; + float u; + float v; + float z; + + OS_Flert *of; + + // + // Enough room in our buffer? + // + + if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);} + if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);} + + // + // Add four vertices. + // + + for (i = 0; i < 4; i++) + { + of = &ob->flert[ob->num_flerts + i]; + + switch(i) + { + case 0: + x = x1; + y = y1; + u = u1; + v = v1; + z = z1; + break; + + case 1: + x = x2; + y = y2; + u = u2; + v = v2; + z = z2; + break; + + case 2: + x = x3; + y = y3; + u = u3; + v = v3; + z = z3; + break; + + case 3: + x = x4; + y = y4; + u = u4; + v = v4; + z = z4; + break; + + default: + ASSERT(0); + break; + } + + x *= OS_screen_width; + y *= OS_screen_height; + + of->sx = x; + of->sy = y; + of->sz = z; + of->rhw = 0.5F; + of->colour = colour; + of->specular = specular; + of->tu1 = u; + of->tv1 = v; + of->tu2 = u; + of->tv2 = v; + } + + // + // Add two triangles. + // + + ob->index[ob->num_indices + 0] = ob->num_flerts + 0; + ob->index[ob->num_indices + 1] = ob->num_flerts + 1; + ob->index[ob->num_indices + 2] = ob->num_flerts + 3; + + ob->index[ob->num_indices + 3] = ob->num_flerts + 0; + ob->index[ob->num_indices + 4] = ob->num_flerts + 3; + ob->index[ob->num_indices + 5] = ob->num_flerts + 2; + + ob->num_indices += 6; + ob->num_flerts += 4; +} + + +void OS_buffer_add_line_3d( + OS_Buffer *ob, + float X1, + float Y1, + float X2, + float Y2, + float width, + float u1, float v1, + float u2, float v2, + float z1, + float z2, + ULONG colour, + ULONG specular) +{ + SLONG i; + + OS_Flert *of; + + float dx; + float dy; + float len; + float overlen; + + float x; + float y; + + // + // Enough room in our buffer? + // + + if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);} + if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);} + + // + // The width of the line. + // + + dx = X2 - X1; + dy = Y2 - Y1; + + len = qdist2(fabs(dx),fabs(dy)); + overlen = width * OS_screen_width / len; + + dx *= overlen; + dy *= overlen; + + // + // Add four vertices. + // + + for (i = 0; i < 4; i++) + { + of = &ob->flert[ob->num_flerts + i]; + + x = 0.0F; + y = 0.0F; + + if (i & 1) + { + x += -dy; + y += +dx; + } + else + { + x -= -dy; + y -= +dx; + } + + if (i & 2) + { + x += X1; + y += Y1; + } + else + { + x += X2; + y += Y2; + } + + of->sx = x; + of->sy = y; + of->sz = ((i & 2) ? z1 : z2); + of->rhw = 0.5F; + of->colour = colour; + of->specular = specular; + of->tu1 = ((i & 1) ? u1 : u2); + of->tv1 = ((i & 2) ? v1 : v2); + of->tu2 = ((i & 1) ? u1 : u2); + of->tv2 = ((i & 2) ? v1 : v2); + } + + // + // Add two triangles. + // + + ob->index[ob->num_indices + 0] = ob->num_flerts + 0; + ob->index[ob->num_indices + 1] = ob->num_flerts + 1; + ob->index[ob->num_indices + 2] = ob->num_flerts + 3; + + ob->index[ob->num_indices + 3] = ob->num_flerts + 0; + ob->index[ob->num_indices + 4] = ob->num_flerts + 3; + ob->index[ob->num_indices + 5] = ob->num_flerts + 2; + + ob->num_indices += 6; + ob->num_flerts += 4; +} + + + + +void OS_buffer_add_line_2d( + OS_Buffer *ob, + float x1, + float y1, + float x2, + float y2, + float width, + float u1, float v1, + float u2, float v2, + float z, + ULONG colour, + ULONG specular) +{ + SLONG i; + + OS_Flert *of; + + float dx; + float dy; + float len; + float overlen; + + float x; + float y; + + // + // Enough room in our buffer? + // + + if (ob->num_indices + 6 > ob->max_indices) {OS_buffer_grow_indices(ob);} + if (ob->num_flerts + 4 > ob->max_flerts ) {OS_buffer_grow_flerts (ob);} + + // + // The width of the line. + // + + x1 *= OS_screen_width; + y1 *= OS_screen_height; + + x2 *= OS_screen_width; + y2 *= OS_screen_height; + + dx = x2 - x1; + dy = y2 - y1; + + len = qdist2(fabs(dx),fabs(dy)); + overlen = width * OS_screen_width / len; + + dx *= overlen; + dy *= overlen; + + // + // Add four vertices. + // + + for (i = 0; i < 4; i++) + { + of = &ob->flert[ob->num_flerts + i]; + + x = 0.0F; + y = 0.0F; + + if (i & 1) + { + x += -dy; + y += +dx; + } + else + { + x -= -dy; + y -= +dx; + } + + if (i & 2) + { + x += x1; + y += y1; + } + else + { + x += x2; + y += y2; + } + + of->sx = x; + of->sy = y; + of->sz = z; + of->rhw = 0.5F; + of->colour = colour; + of->specular = specular; + of->tu1 = ((i & 1) ? u1 : u2); + of->tv1 = ((i & 2) ? v1 : v2); + of->tu2 = ((i & 1) ? u1 : u2); + of->tv2 = ((i & 2) ? v1 : v2); + } + + // + // Add two triangles. + // + + ob->index[ob->num_indices + 0] = ob->num_flerts + 0; + ob->index[ob->num_indices + 1] = ob->num_flerts + 1; + ob->index[ob->num_indices + 2] = ob->num_flerts + 3; + + ob->index[ob->num_indices + 3] = ob->num_flerts + 0; + ob->index[ob->num_indices + 4] = ob->num_flerts + 3; + ob->index[ob->num_indices + 5] = ob->num_flerts + 2; + + ob->num_indices += 6; + ob->num_flerts += 4; +} + + + +void OS_buffer_draw( + OS_Buffer *ob, + OS_Texture *ot1, + OS_Texture *ot2, + ULONG draw) +{ + LPDIRECT3DDEVICE3 d3d = OS_frame.GetD3DDevice(); + + if (ob->num_flerts == 0) + { + // + // Empty buffer! + // + + OS_buffer_give(ob); + + return; + } + + if (!OS_in_scene) + { + OS_scene_begin(); + } + + if (ot1 == NULL) + { + // + // No texturing. + // + + draw |= OS_DRAW_TEX_NONE; + } + else + { + // + // Make this texture the input into the pipeline. + // + + d3d->SetTexture(0, ot1->ddtx); + } + + if (ot2) + { + // + // Make this texture the input into the second stage of the pipeline. + // + + d3d->SetTexture(1, ot2->ddtx); + } + + // + // Update renderstates. + // + + if (draw != OS_DRAW_NORMAL) + { + OS_change_renderstate_for_type(draw); + } + + { + // + // Check that this will be okay. + // + + ULONG num_passes; + + if (d3d->ValidateDevice(&num_passes) != D3D_OK) + { + OS_string("Validation failed: draw = 0x%x\n", draw); + } + } + + // + // The number of polys actually drawn. + // + + OS_poly_count_drawn += ob->num_indices / 3; + + // + // Draw the triangles. + // + + d3d->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + OS_FLERT_FORMAT, + ob->flert, + ob->num_flerts, + ob->index, + ob->num_indices, + D3DDP_DONOTUPDATEEXTENTS); + + // + // Put state back to normal. + // + + if (draw != OS_DRAW_NORMAL) + { + OS_undo_renderstate_type_changes(); + } + + // + // Returns the buffer to the free list. + // + + OS_buffer_give(ob); +} + + +void OS_screenshot(CBYTE *fname) +{ + SLONG r; + SLONG g; + SLONG b; + + SLONG x; + SLONG y; + + ULONG pixel; + UWORD *u_screen; + SLONG pitch; + ULONG *l_screen; + + CBYTE ourname[128]; + + SLONG width = ftol(OS_screen_width ); + SLONG height = ftol(OS_screen_height); + + TGA_Pixel *tga; + + DDSURFACEDESC2 ddsd; + + tga = (TGA_Pixel *) malloc(sizeof(TGA_Pixel) * width * height); + + if (!tga) + { + return; + } + + // + // Lock the backbuffer. + // + + memset(&ddsd, 0, sizeof(ddsd)); + + ddsd.dwSize = sizeof(ddsd); + + OS_frame.GetBackBuffer()->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + + // + // Screen format. + // + + SLONG mask_r; + SLONG mask_g; + SLONG mask_b; + + SLONG shift_r; + SLONG shift_g; + SLONG shift_b; + + OS_calculate_mask_and_shift(ddsd.ddpfPixelFormat.dwRBitMask, &mask_r, &shift_r); + OS_calculate_mask_and_shift(ddsd.ddpfPixelFormat.dwGBitMask, &mask_g, &shift_g); + OS_calculate_mask_and_shift(ddsd.ddpfPixelFormat.dwBBitMask, &mask_b, &shift_b); + + // + // How many bpp? + // + + if (ddsd.ddpfPixelFormat.dwRGBBitCount == 16) + { + u_screen = (UWORD *) ddsd.lpSurface; + l_screen = NULL; + pitch = ddsd.lPitch >> 1; + } + else + if (ddsd.ddpfPixelFormat.dwRGBBitCount == 32) + { + u_screen = NULL; + l_screen = (ULONG *) ddsd.lpSurface; + pitch = ddsd.lPitch >> 2; + } + else + { + return; + } + + // + // Transfer pixels to buffer. + // + + for (x = 0; x < width; x++) + for (y = 0; y < height; y++) + { + if (u_screen) + { + pixel = u_screen[x + y * pitch]; + } + else + { + pixel = l_screen[x + y * pitch]; + } + + r = ((pixel >> shift_r) << mask_r) & 0xff; + g = ((pixel >> shift_g) << mask_g) & 0xff; + b = ((pixel >> shift_b) << mask_b) & 0xff; + + tga[x + y * width].red = r; + tga[x + y * width].green = g; + tga[x + y * width].blue = b; + tga[x + y * width].alpha = 0; + } + + // + // Unlock screen. + // + + OS_frame.GetBackBuffer()->Unlock(NULL); + + // + // Get the filename. + // + + if (!fname) + { + SLONG i; + + for (i = 1; i < 1000; i++) + { + sprintf(ourname, "ScreenShot\\shot%03d.tga", i); + + if (fopen(ourname, "rb") == NULL) + { + // + // Found an unused filename. + // + + fname = ourname; + + goto found_name; + } + } + + // + // Could not get a filename. + // + + return; + + found_name:; + } + + TGA_save( + fname, + width, + height, + tga, + FALSE); + + // + // Free up tga memory. + // + + free(tga); +} + + + + + + diff --git a/MuckyBasic/os.h b/MuckyBasic/os.h new file mode 100644 index 0000000..a358644 --- /dev/null +++ b/MuckyBasic/os.h @@ -0,0 +1,664 @@ +// +// Interface to all the OS functions. +// + +#ifndef _OS_ +#define _OS_ + + +// ======================================================== +// +// WINDOWS AND MISCELLANEOUS STUFF +// +// ======================================================== + +// +// The command line passed to the program. +// + +extern CBYTE *OS_command_line; + +// +// Outputs a debug string. +// Returns the number of milliseconds since MAIN_main was called. It is very accurate. +// Resets OS_ticks() +// Returns the Mhz of the current processor. +// + +void OS_string (CBYTE *fmt, ...); +void OS_reset_ticks (void); +SLONG OS_ticks (void); +void OS_ticks_reset (void); +SLONG OS_processor_mhz(void); + +// +// In windowed mode it puts up an error message. In release build or +// fullscreen mode, it return and does nothing. +// + +void OS_error(CBYTE *fmt, ...); + + +// +// Returns TRUE if the given file has its archive bit set. Returns +// FALSE if the file is not found. +// + +SLONG OS_is_archive_bit_set(CBYTE *fname); +void OS_clear_archive_bit (CBYTE *fname); + + +// ======================================================== +// +// TEXTURE STUFF +// +// ======================================================== + +typedef struct os_texture OS_Texture; + +// +// You can create a texture either from a TGA file or just by +// specifying a size and format. If the file could not be loaded +// then a blank texture is used instead. If you try and create +// a texture from the same TGA file twice, the same pointer will +// be returned both times. +// +// It looks for the file in the "Textures\" directory and then +// in any directory its find in it's texture path. It loads +// additional texture paths from the "data\texurepaths.txt" file +// + +#define OS_TEXTURE_FORMAT_RGB 0 // RGB +#define OS_TEXTURE_FORMAT_1555 1 // ARGB +#define OS_TEXTURE_FORMAT_4444 2 // ARGB +#define OS_TEXTURE_FORMAT_8 3 // Grayscale +#define OS_TEXTURE_FORMAT_SCREEN 4 // The same format that the back buffer is in. +#define OS_TEXTURE_FORMAT_NUMBER 5 + +#define OS_TEXTURE_MAX_SIZE 512 + +OS_Texture *OS_texture_create(CBYTE *fname, SLONG invert = FALSE); +OS_Texture *OS_texture_create(SLONG width, SLONG height, SLONG format); + +// +// Call this function once you have loaded all textures. It ensures that +// as many of the textures as possible start off on the card instead of +// only in the texture cache in system memory. +// + +void OS_texture_finished_creating(void); + +// +// Returns the size of the texture. +// + +SLONG OS_texture_width (OS_Texture *ot); +SLONG OS_texture_height(OS_Texture *ot); + +// +// To updating a texture yourself, lock the texture and write +// into the bitmap. When you unlock it, the new texture will +// be blitted to the hardware. +// +// You're not allowed to READ from the texture! Only write. +// +// On success one of OS_bitmap_uword_screen or OS_bitmap_ubyte_screen will +// point to the screen memory. +// + +void OS_texture_lock (OS_Texture *ot); // OS_bitmap_screen == NULL => lock failed. +void OS_texture_unlock(OS_Texture *ot); + +// +// The bitmap returned by OS_texture_lock. To create a pixel, use the masks and +// shifts like this: +// +// pixel = (r >> mask_r) << shift_r; +// pixel |= (g >> mask_g) << shift_g; +// pixel |= (b >> mask_b) << shift_b; +// +// Include alpha only if the original texture had alpha. +// + +extern SLONG OS_bitmap_format; // OS_TEXTURE_FORMAT_* +extern UWORD *OS_bitmap_uword_screen; // For 16-bit formats. +extern SLONG OS_bitmap_uword_pitch; // Pitch in UWORDS +extern UBYTE *OS_bitmap_ubyte_screen; // For the grayscale format. +extern SLONG OS_bitmap_ubyte_pitch; // Pitch in UBYTES +extern SLONG OS_bitmap_width; +extern SLONG OS_bitmap_height; +extern SLONG OS_bitmap_mask_r; +extern SLONG OS_bitmap_mask_g; +extern SLONG OS_bitmap_mask_b; +extern SLONG OS_bitmap_mask_a; +extern SLONG OS_bitmap_shift_r; +extern SLONG OS_bitmap_shift_g; +extern SLONG OS_bitmap_shift_b; +extern SLONG OS_bitmap_shift_a; + +// +// Writes a pixel to a 16-bit bitmap. +// + +#define OS_BITMAP_UWORD_PIXEL(x,y) (OS_bitmap_uword_screen + (x) + (y) * OS_bitmap_uword_pitch) +#define OS_BITMAP_UWORD_COLOUR(r,g,b) ((((r) >> OS_bitmap_mask_r) << OS_bitmap_shift_r) | (((g) >> OS_bitmap_mask_g) << OS_bitmap_shift_g) | (((b) >> OS_bitmap_mask_b) << OS_bitmap_shift_b)) +#define OS_BITMAP_UWORD_PLOT(x,y,r,g,b) {*OS_BITMAP_UWORD_PIXEL(x,y) = OS_BITMAP_UWORD_COLOUR(r,g,b);} + +// +// Write a pixel to an 8-bit bitmap +// + +#define OS_BITMAP_UBYTE_PIXEL(x,y) (OS_bitmap_ubyte_screen + (x) + (y) * OS_bitmap_ubyte_pitch) +#define OS_BITMAP_UBYTE_PLOT(x,y,c) {*OS_BITMAP_UBYTE_PIXEL(x,y) = (c);} + +// +// Blitting a portion of the backbuffer onto the texture. +// This will fail if the backbuffer and the texture are in +// different formats. Returns TRUE on success. +// +// The (x,y) is the upper left hand corner of the texture and +// the size of the region is given by the size of the texture. +// +// The texture can't be locked! +// + +SLONG OS_texture_blit_from_backbuffer(OS_Texture *ot, SLONG x, SLONG y); + + +// +// Searches the "Textures\\" directory for the given file and returns +// the fullpath name. Returns the address from inside the same static +// array each time it is called. Returns NULL if it can't find the +// file inside the "Textures\\" directory. +// + +CBYTE *OS_texture_full_path(CBYTE *fname); + + + +// ======================================================== +// +// THE CAMERA +// +// ======================================================== + +// +// Sets up the camera used to transform points added to the OS_Buffers. +// + +void OS_camera_set( + float world_x, + float world_y, + float world_z, + float view_dist, + float yaw, + float pitch, + float roll, + float lens, + float screen_x1 = 0.0F, + float screen_y1 = 0.0F, + float screen_x2 = 1.0F, + float screen_y2 = 1.0F); + +void OS_camera_set( + float world_x, + float world_y, + float world_z, + float view_dist, + float matrix[9], + float lens, + float screen_x1 = 0.0F, + float screen_y1 = 0.0F, + float screen_x2 = 1.0F, + float screen_y2 = 1.0F); + +extern float OS_cam_x; // For reference only! Use the function above to set the camera +extern float OS_cam_y; +extern float OS_cam_z; +extern float OS_cam_lens; +extern float OS_cam_view_matrix [9]; +extern float OS_cam_view_matrix_plus_local_rot[9]; // For when using OS_transform_local() + +// +// The clipping flags. +// + +#define OS_CLIP_TOP (1 << 0) +#define OS_CLIP_BOTTOM (1 << 1) +#define OS_CLIP_LEFT (1 << 2) +#define OS_CLIP_RIGHT (1 << 3) + +#define OS_CLIP_FAR (1 << 4) +#define OS_CLIP_NEAR (1 << 5) +#define OS_CLIP_ROTATED (1 << 6) +#define OS_CLIP_TRANSFORMED (1 << 7) + +#define OS_CLIP_OFFSCREEN (OS_CLIP_TOP|OS_CLIP_BOTTOM|OS_CLIP_LEFT|OS_CLIP_RIGHT) +#define OS_ZCLIP_PLANE (128.0F / 65536.0F) + +// +// Transformed points. +// + +typedef struct +{ + float x; + float y; + float z; + + float X; + float Y; + float Z; + + ULONG clip; + +} OS_Trans; + +#define OS_MAX_TRANS 16384 + +extern OS_Trans OS_trans[OS_MAX_TRANS]; +extern SLONG OS_trans_upto; + +// +// Transforming points. +// + +void OS_transform( + float world_x, + float world_y, + float world_z, + OS_Trans *os); + +// +// Sets the local position and orientation for OS_transform_local(). +// + +void OS_local_position_and_rotation( + float world_x, + float world_y, + float world_z, + float local_rotation_matrix[9]); + +// +// Transforms a point, but first puts it through the local rotation +// and position given by OS_local_position_and_rotation(). +// + +void OS_transform_local( + float local_x, + float local_y, + float local_z, + OS_Trans *os); + + +// ======================================================== +// +// BUFFERS FOR COLLECTING TOGETHER POINTS AND TRIANGLES +// +// ======================================================== + +typedef struct os_buffer OS_Buffer; + +typedef struct +{ + UWORD trans; // Index into the OS_trans array for the transformed point. + UWORD index; // Before you add any OS_Verts to a buffer make sure they all have this field set to NULL + float u1; + float v1; + float u2; // For multitexturing. + float v2; + ULONG colour; + ULONG specular; + +} OS_Vert; + +// +// The number of poly's drawn last frame. +// + +extern SLONG OS_poly_count_transformed; +extern SLONG OS_poly_count_drawn; + +// +// Returns a new buffer to which you can add triangles. +// + +OS_Buffer *OS_buffer_new(void); + +// +// Adds a triangle to the buffer. The triangle is given by three vertices +// into an OS_Vert array whose tlvert field is all set to zero. +// + +void OS_buffer_add_triangle( + OS_Buffer *ob, + OS_Vert *ov1, + OS_Vert *ov2, + OS_Vert *ov3); + +// +// Adds a 2D sprite to the buffer. +// + +#define OS_FADE_TOP (1 << 0) +#define OS_FADE_BOTTOM (1 << 1) +#define OS_FADE_LEFT (1 << 2) +#define OS_FADE_RIGHT (1 << 3) + +void OS_buffer_add_sprite( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float u1 = 0.0F, float v1 = 0.0F, + float u2 = 1.0F, float v2 = 1.0F, + float z = 0.0F, + ULONG colour = 0xffffffff, + ULONG specular = 0x00000000, + ULONG fade = 0); + +void OS_buffer_add_multitex_sprite( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float u11 = 0.0F, float v11 = 0.0F, + float u12 = 1.0F, float v12 = 1.0F, + float u21 = 0.0F, float v21 = 0.0F, + float u22 = 1.0F, float v22 = 1.0F, + float z = 0.0F, + ULONG colour = 0xffffffff, + ULONG specular = 0x00000000, + ULONG fade = 0); + +// +// Adds a rotated 2D sprite to the buffer. +// + +void OS_buffer_add_sprite_rot( + OS_Buffer *ob, + float x_mid, + float y_mid, + float radius, // As a percentage of the width of the screen. + float angle, + float u1 = 0.0F, float v1 = 0.0F, + float u2 = 1.0F, float v2 = 1.0F, + float z = 0.0F, + ULONG colour = 0xffffffff, + ULONG specular = 0x00000000, + float tu1 = 0.0F, float tv1 = 0.0F, // For the second pass... + float tu2 = 1.0F, float tv2 = 1.0F); + +// +// Adds an arbitrary-shaped sprite to the buffer. The points are +// given in this order. +// +// 0-------1 +// / \ +// 2-----------3 + +void OS_buffer_add_sprite_arbitrary( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float x3, // Normalised to 0.0F - 1.0F + float y3, // Normalised to 0.0F - 1.0F + float x4, // Normalised to 0.0F - 1.0F + float y4, // Normalised to 0.0F - 1.0F + float u1 = 0.0F, float v0 = 0.0F, + float u2 = 1.0F, float v2 = 0.0F, + float u3 = 0.0F, float v3 = 1.0F, + float u4 = 1.0F, float v4 = 1.0F, + float z = 0.0F, + ULONG colour = 0xffffffff, + ULONG specular = 0x00000000); + + +void OS_buffer_add_sprite_arbitrary( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float x3, // Normalised to 0.0F - 1.0F + float y3, // Normalised to 0.0F - 1.0F + float x4, // Normalised to 0.0F - 1.0F + float y4, // Normalised to 0.0F - 1.0F + float u1 = 0.0F, float v0 = 0.0F, + float u2 = 1.0F, float v2 = 0.0F, + float u3 = 0.0F, float v3 = 1.0F, + float u4 = 1.0F, float v4 = 1.0F, + float z1 = 0.0F, + float z2 = 0.0F, + float z3 = 0.0F, + float z4 = 0.0F, + ULONG colour = 0xffffffff, + ULONG specular = 0x00000000); + + +// +// Adds a line. +// + +void OS_buffer_add_line_2d( + OS_Buffer *ob, + float x1, // Normalised to 0.0F - 1.0F + float y1, // Normalised to 0.0F - 1.0F + float x2, // Normalised to 0.0F - 1.0F + float y2, // Normalised to 0.0F - 1.0F + float width = 0.01F, // As a percentage of the width of the screen. + float u1 = 0.0F, float v1 = 0.0F, + float u2 = 1.0F, float v2 = 1.0F, + float z = 0.0F, + ULONG colour = 0xffffffff, + ULONG specular = 0x00000000); + +void OS_buffer_add_line_3d( + OS_Buffer *ob, + float X1, // These are in REAL SCREEN COORDINATES! + float Y1, // These are in REAL SCREEN COORDINATES! + float X2, // These are in REAL SCREEN COORDINATES! + float Y2, // These are in REAL SCREEN COORDINATES! + float width = 0.01F, // As a percentage of the width of the screen. + float u1 = 0.0F, float v1 = 0.0F, + float u2 = 1.0F, float v2 = 1.0F, + float z1 = 0.0F, + float z2 = 0.0F, + ULONG colour = 0xffffffff, + ULONG specular = 0x00000000); + + + + +// +// Draws the buffer in the way defined by the OS_DRAW_* flags and the texture. After +// drawing a buffer it becomes invalid. You can't add triangles to it anymore. +// + +#define OS_DRAW_NORMAL 0 // Normal zbuffered gouraud textured triangle +#define OS_DRAW_ADD (1 << 0) // Pixel = source + dest +#define OS_DRAW_MULTIPLY (1 << 1) // Pixel = source * dest * 2 +#define OS_DRAW_CLAMP (1 << 2) // No texture wrapping +#define OS_DRAW_DECAL (1 << 3) // No gouraud +#define OS_DRAW_TRANSPARENT (1 << 4) // Just the zbuffer written to (Pixel = dest) +#define OS_DRAW_DOUBLESIDED (1 << 5) // Don't backface cull +#define OS_DRAW_NOZWRITE (1 << 6) // Don't write to the zbuffer +#define OS_DRAW_ALPHAREF (1 << 7) // Don't draw if alpha channel is zero +#define OS_DRAW_ZREVERSE (1 << 8) // Reverses the order or the zbuffer +#define OS_DRAW_ZALWAYS (1 << 9) // Never z-reject. +#define OS_DRAW_CULLREVERSE (1 << 10) // Flip the direction of backface culling +#define OS_DRAW_NODITHER (1 << 11) // Turn of gouraud-shade dithering +#define OS_DRAW_ALPHABLEND (1 << 12) // Alphablending +#define OS_DRAW_TEX_NONE (1 << 13) // No texture mapping +#define OS_DRAW_TEX_MUL (1 << 14) // Two textures multiplied together +#define OS_DRAW_NOFILTER (1 << 15) // No filtering +#define OS_DRAW_MULBYONE (1 << 16) // Pixel = source * dest * 1 + +void OS_buffer_draw( + OS_Buffer *ob, + OS_Texture *ot1, // NULL => No texture mapping + OS_Texture *ot2 = NULL, + ULONG draw = OS_DRAW_NORMAL); + + +// ======================================================== +// +// RENDER LOOP STUFF +// +// ======================================================== + +// +// A couple of BOOLs to tell you how the screen is setup. +// + +extern UBYTE OS_frame_is_fullscreen; +extern UBYTE OS_frame_is_hardware; + +extern float OS_screen_width; +extern float OS_screen_height; + +// +// Clears the screen. +// + +void OS_clear_screen( + UBYTE r = 0, + UBYTE g = 0, + UBYTE b = 0, + float z = 1.0F); + +// +// Draws the FPS onto the screen. Call ONCE a frame! +// + +void OS_fps_draw(void); +SLONG OS_fps_get (void); + +// +// Flips the screen. +// + +void OS_show(void); + +// +// Saves out a screenshot. If the filename is NULL then +// it saves out shot.tga where n is the lowest available +// number. +// + +void OS_screenshot(CBYTE *fname = NULL); + + +// ======================================================== +// +// MOUSE STUFF +// +// ======================================================== + +void OS_mouse_get(SLONG *x, SLONG *y); +void OS_mouse_set(SLONG x, SLONG y); + +// ======================================================== +// +// SOUND STUFF +// +// ======================================================== + +// +// A sound identifier, so you can change a sounds attributes. +// + +typedef struct os_sound OS_Sound; + +// +// Creates a new sound. +// + +#define OS_SOUND_TYPE_UNUSED 0 +#define OS_SOUND_TYPE_2D 1 +#define OS_SOUND_TYPE_3D 2 + +OS_Sound *OS_sound_create(CBYTE *fname, SLONG type); + +// +// Assumes the sound to be mono at 22050 samples per second. +// + +OS_Sound *OS_sound_create(UWORD *data, SLONG num_samples, SLONG type); + + +// +// Plays a sound. If OS_SOUND_FLAG_LOOP then the sound will play until +// it is stopped with OS_sound_stop(). +// + +#define OS_SOUND_FLAG_INTERRUPT (1 << 0) // If this sample is already playing- it will start again. +#define OS_SOUND_FLAG_LOOP (1 << 1) // Continue playing until OS_sound_stop() is called. + +void OS_sound_play(OS_Sound *sound, SLONG flag = 0); +void OS_sound_stop(OS_Sound *sound); + + +// +// For 2D sounds. +// + +void OS_sound_2d_set_volume(OS_Sound *sound, float volume); // volume is between 0.0F and 1.0F + +// +// For 3D sounds. The new setting take effect from the next +// time you call OS_process_messages(). +// + +void OS_sound_3d_set_range (OS_Sound *sound, float min, float max); +void OS_sound_3d_set_position( + OS_Sound *sound, + float x, + float y, + float z, + float dx = 0.0F, + float dy = 0.0F, + float dz = 0.0F); + + +// +// Setup the listener for 3D sounds. +// + +void OS_sound_listener_set( + float x, + float y, + float z, + float dx = 0.0F, + float dy = 0.0F, + float dz = 0.0F, + float yaw = 0.0F, + float pitch = 0.0F, + float roll = 0.0F); + + + + +// ======================================================== +// +// JOYSTICK INPUT +// +// ======================================================== + +// +// These values are updated after each call to OS_process_messages() +// + +extern float OS_joy_x; // -1.0F to +1.0F +extern float OS_joy_y; // -1.0F to +1.0F +extern ULONG OS_joy_button; // The buttons that are currently down +extern ULONG OS_joy_button_down; // The buttons that have just been pressed +extern ULONG OS_joy_button_up; // The buttons that have just been released + + +#endif + diff --git a/MuckyBasic/parse.cpp b/MuckyBasic/parse.cpp new file mode 100644 index 0000000..f3048a1 --- /dev/null +++ b/MuckyBasic/parse.cpp @@ -0,0 +1,3994 @@ +#include "always.h" +#include "lex.h" +#include "parse.h" + +#include + + +// +// The nodes. +// + +#define PARSE_MAX_NODES 65536 + +PARSE_Node PARSE_node[PARSE_MAX_NODES]; +SLONG PARSE_node_upto; + +PARSE_Node *PARSE_get_node() +{ + ASSERT(WITHIN(PARSE_node_upto, 0, PARSE_MAX_NODES - 1)); + + return &PARSE_node[PARSE_node_upto++]; +} + + + +// +// Output variables and others... +// + +#define PARSE_MAX_LINES 16384 +#define PARSE_MAX_STRING_TABLE_SIZE 65536 +#define PARSE_MAX_ERRORS 256 + +PARSE_Node *PARSE_line[PARSE_MAX_LINES]; // NULL value means that line was blank. +SLONG PARSE_line_upto; +CBYTE PARSE_string_table[PARSE_MAX_STRING_TABLE_SIZE]; +SLONG PARSE_string_table_upto; +CBYTE *PARSE_error[PARSE_MAX_ERRORS]; +SLONG PARSE_error_upto; +SLONG PARSE_ifcode; // This gets incremented every time we parse an IF statement... +SLONG PARSE_forcode; // This gets incremented every time we parse a FOR statement... +SLONG PARSE_whilecode; // This gets incremented every time we parse a WHILE statement... + +// +// The error buffer. +// + +#define PARSE_MAX_ERRBUF 32768 + +CBYTE PARSE_errbuf[PARSE_MAX_ERRBUF]; +SLONG PARSE_errbuf_upto; + +// +// Adds the given error. If it has run out of room, it +// returns FALSE. +// + +SLONG PARSE_add_error(CBYTE *fmt, ...) +{ + if (PARSE_error_upto >= PARSE_MAX_ERRORS) + { + return FALSE; + } + + // + // Work out the real error. + // + + CBYTE error[512]; + va_list ap; + + va_start(ap, fmt); + vsprintf(error, fmt, ap); + va_end (ap); + + // + // Put it into the buffer. + // + + SLONG len = strlen(error) + 1; // + 1 to include terminating NULL. + + if (PARSE_errbuf_upto + len > PARSE_MAX_ERRBUF) + { + return FALSE; + } + + strcpy(PARSE_errbuf + PARSE_errbuf_upto, error); + + PARSE_error[PARSE_error_upto] = PARSE_errbuf + PARSE_errbuf_upto; + + PARSE_error_upto += 1; + PARSE_errbuf_upto += len; + + return TRUE; +} + +// +// Where to longjmp on an error. +// + +jmp_buf PARSE_error_jmp; + + +// +// The reason the parser jumped to PARSE_error_jmp; +// + +CBYTE *PARSE_error_type; + + + +// +// Throws up an error. +// + +void PARSE_throw(CBYTE *error = "Parse error") +{ + PARSE_error_type = error; + + longjmp(PARSE_error_jmp, 1); +} + + + + + +// +// Adds the string to PARSE_string_table and return the address +// where it was copied. +// + +CBYTE *PARSE_add_string(CBYTE *string) +{ + SLONG length = strlen(string) + 1; // + 1 to include the terminating NULL + + if (PARSE_string_table_upto + length > PARSE_MAX_STRING_TABLE_SIZE) + { + // + // ERROR! + // + + PARSE_throw("No more string constant memory"); + } + + CBYTE *ans = PARSE_string_table + PARSE_string_table_upto; + + strcpy(ans, string); + + PARSE_string_table_upto += length; + + return ans; +} + + +// +// Sets the PARSE_NODE_FLAG_CONDITIONAL flag in the given node. +// + +SLONG PARSE_set_conditional_flag(PARSE_Node *pn) +{ + pn->flag |= PARSE_NODE_FLAG_CONDITIONAL; + + return TRUE; +} + + +// +// Sets the PARSE_NODE_FLAG_EXPRESSION flag in the given node. +// + +SLONG PARSE_set_expression_flag(PARSE_Node *pn) +{ + pn->flag |= PARSE_NODE_FLAG_EXPRESSION; + + return TRUE; +} + + + +// +// Returns TRUE if the given expression is sure to return +// a BOOLEAN value. +// + +SLONG PARSE_expression_is_boolean(PARSE_Node *exp) +{ + switch(exp->type) + { + case PARSE_NODE_TYPE_EQUALS: + case PARSE_NODE_TYPE_GT: + case PARSE_NODE_TYPE_LT: + case PARSE_NODE_TYPE_GTEQ: + case PARSE_NODE_TYPE_LTEQ: + case PARSE_NODE_TYPE_AND: + case PARSE_NODE_TYPE_OR: + case PARSE_NODE_TYPE_NOT: + case PARSE_NODE_TYPE_BOOLEAN: + case PARSE_NODE_TYPE_XOR: + case PARSE_NODE_TYPE_KEY_VALUE: + return TRUE; + + case PARSE_NODE_TYPE_NOP: + case PARSE_NODE_TYPE_PLUS: + case PARSE_NODE_TYPE_MINUS: + case PARSE_NODE_TYPE_UMINUS: + case PARSE_NODE_TYPE_TIMES: + case PARSE_NODE_TYPE_DIVIDE: + case PARSE_NODE_TYPE_SLUMBER: + case PARSE_NODE_TYPE_FLUMBER: + case PARSE_NODE_TYPE_STRING: + case PARSE_NODE_TYPE_VAR_VALUE: + case PARSE_NODE_TYPE_IF: + case PARSE_NODE_TYPE_GOTO: + case PARSE_NODE_TYPE_LABEL: + case PARSE_NODE_TYPE_DOT: + case PARSE_NODE_TYPE_CALL: + case PARSE_NODE_TYPE_LOCAL: + case PARSE_NODE_TYPE_PRINT: + case PARSE_NODE_TYPE_ASSIGN: + case PARSE_NODE_TYPE_VAR_ADDRESS: + case PARSE_NODE_TYPE_MOD: + case PARSE_NODE_TYPE_SQRT: + case PARSE_NODE_TYPE_NEWLINE: + case PARSE_NODE_TYPE_ABS: + case PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS: + case PARSE_NODE_TYPE_FIELD: + case PARSE_NODE_TYPE_PUSH_FIELD_VALUE: + case PARSE_NODE_TYPE_EXP_LIST: + case PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS: + case PARSE_NODE_TYPE_PUSH_ARRAY_VALUE: + case PARSE_NODE_TYPE_INPUT: + case PARSE_NODE_TYPE_UNDEFINED: + case PARSE_NODE_TYPE_STATEMENT_LIST: + case PARSE_NODE_TYPE_EXIT: + case PARSE_NODE_TYPE_RETURN: + case PARSE_NODE_TYPE_GOSUB: + case PARSE_NODE_TYPE_FOR: + case PARSE_NODE_TYPE_NEXT: + case PARSE_NODE_TYPE_NOTEQUAL: + case PARSE_NODE_TYPE_RANDOM: + case PARSE_NODE_TYPE_SWAP: + case PARSE_NODE_TYPE_MIF: + case PARSE_NODE_TYPE_MELSE: + case PARSE_NODE_TYPE_MENDIF: + case PARSE_NODE_TYPE_WHILE: + case PARSE_NODE_TYPE_LOOP: + case PARSE_NODE_TYPE_FUNCTION: + case PARSE_NODE_TYPE_ARGUMENT: + case PARSE_NODE_TYPE_ENDFUNC: + case PARSE_NODE_TYPE_TEXTURE: + case PARSE_NODE_TYPE_BUFFER: + case PARSE_NODE_TYPE_DRAW: + case PARSE_NODE_TYPE_CLS: + case PARSE_NODE_TYPE_FLIP: + case PARSE_NODE_TYPE_KEY_ASSIGN: + case PARSE_NODE_TYPE_INKEY_VALUE: + case PARSE_NODE_TYPE_INKEY_ASSIGN: + case PARSE_NODE_TYPE_TIMER: + case PARSE_NODE_TYPE_SIN: + case PARSE_NODE_TYPE_COS: + case PARSE_NODE_TYPE_TAN: + case PARSE_NODE_TYPE_ASIN: + case PARSE_NODE_TYPE_ACOS: + case PARSE_NODE_TYPE_ATAN: + case PARSE_NODE_TYPE_ATAN2: + case PARSE_NODE_TYPE_EXPORT: + case PARSE_NODE_TYPE_LEFT: + case PARSE_NODE_TYPE_MID: + case PARSE_NODE_TYPE_RIGHT: + case PARSE_NODE_TYPE_MATRIX: + case PARSE_NODE_TYPE_VECTOR: + return FALSE; + + default: + ASSERT(0); + break; + } + + return FALSE; +} + + +// +// Returns a copy of the parse tree. +// + +PARSE_Node *PARSE_copy_tree(PARSE_Node *tree) +{ + PARSE_Node *ans = PARSE_get_node(); + + *ans = *tree; + + if (ans->child1) {ans->child1 = PARSE_copy_tree(ans->child1);} + if (ans->child2) {ans->child2 = PARSE_copy_tree(ans->child2);} + if (ans->child3) {ans->child3 = PARSE_copy_tree(ans->child3);} + + return ans; +} + +// +// Converts an lvalue to an rvalue. +// + +PARSE_Node *PARSE_convert_lvalue_to_rvalue(PARSE_Node *lv) +{ + PARSE_Node *ans = PARSE_get_node(); + + *ans = *lv; + + switch(lv->type) + { + case PARSE_NODE_TYPE_VAR_ADDRESS: + ans->type = PARSE_NODE_TYPE_VAR_VALUE; + break; + + case PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS: + + ans->type = PARSE_NODE_TYPE_PUSH_FIELD_VALUE; + ans->child1 = PARSE_convert_lvalue_to_rvalue(ans->child1); + ans->child2 = PARSE_copy_tree(ans->child2); + + // + // We need a 'QUICK' copy from the child + // + + ans->child1->flag |= PARSE_NODE_FLAG_EXTRACT; + + break; + + case PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS: + ans->type = PARSE_NODE_TYPE_PUSH_ARRAY_VALUE; + ans->child1 = PARSE_convert_lvalue_to_rvalue(ans->child1); + ans->child2 = PARSE_copy_tree(ans->child2); + + // + // We need a 'QUICK' copy from the child + // + + ans->child1->flag |= PARSE_NODE_FLAG_EXTRACT; + + break; + + default: + ASSERT(0); + break; + } + + return ans; +} + +// +// Converts an rvalue to an lvalue. Only work on certain nodes... of course! +// + +void PARSE_convert_rvalue_to_lvalue(PARSE_Node *rv) +{ + switch(rv->type) + { + case PARSE_NODE_TYPE_VAR_VALUE: + rv->type = PARSE_NODE_TYPE_VAR_ADDRESS; + break; + + case PARSE_NODE_TYPE_PUSH_FIELD_VALUE: + + rv->type = PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS; + + PARSE_convert_rvalue_to_lvalue(rv->child1); + + break; + + case PARSE_NODE_TYPE_PUSH_ARRAY_VALUE: + + rv->type = PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS; + + PARSE_convert_rvalue_to_lvalue(rv->child1); + + break; + + default: + ASSERT(0); + break; + } +} + + +// +// Call this function on all top-level nodes that are in argument +// lists to function-calls. It makes sure that all variables are +// passed by reference. +// + +void PARSE_convert_rvalue_to_argument(PARSE_Node *arg) +{ + // + // Sometimes we must change the type of the node's children. + // + + switch(arg->type) + { + case PARSE_NODE_TYPE_VAR_VALUE: + case PARSE_NODE_TYPE_PUSH_FIELD_VALUE: + case PARSE_NODE_TYPE_PUSH_ARRAY_VALUE: + PARSE_convert_rvalue_to_lvalue(arg); + break; + + default: + break; + } +} + + + + +SLONG PARSE_trees_the_same(PARSE_Node *tree1, PARSE_Node *tree2) +{ + // + // Make sure both tree have the same type. + // + + if (tree1->type != tree2->type) + { + return FALSE; + } + + // + // For nodes with data, make sure the data is the same. + // + + switch(tree1->type) + { + case PARSE_NODE_TYPE_SLUMBER: + if (tree1->slumber != tree2->slumber) return FALSE; + break; + + case PARSE_NODE_TYPE_FLUMBER: + if (tree1->flumber != tree2->flumber) return FALSE; + break; + + case PARSE_NODE_TYPE_STRING: + if (strcmp(tree1->string, tree2->string) != 0) return FALSE; + break; + + case PARSE_NODE_TYPE_VAR_VALUE: + case PARSE_NODE_TYPE_VAR_ADDRESS: + case PARSE_NODE_TYPE_CALL: + case PARSE_NODE_TYPE_FUNCTION: + case PARSE_NODE_TYPE_FIELD: + case PARSE_NODE_TYPE_ARGUMENT: + case PARSE_NODE_TYPE_LOCAL: + case PARSE_NODE_TYPE_EXPORT: + if (strcmp(tree1->variable, tree2->variable) != 0) return FALSE; + break; + + case PARSE_NODE_TYPE_GOTO: + case PARSE_NODE_TYPE_LABEL: + case PARSE_NODE_TYPE_GOSUB: + if (strcmp(tree1->label, tree2->label) != 0) return FALSE; + break; + + case PARSE_NODE_TYPE_BOOLEAN: + if (tree1->boolean != tree2->boolean) return FALSE; + break; + + case PARSE_NODE_TYPE_NOP: + case PARSE_NODE_TYPE_EQUALS: + case PARSE_NODE_TYPE_PLUS: + case PARSE_NODE_TYPE_MINUS: + case PARSE_NODE_TYPE_UMINUS: + case PARSE_NODE_TYPE_TIMES: + case PARSE_NODE_TYPE_DIVIDE: + case PARSE_NODE_TYPE_IF: + case PARSE_NODE_TYPE_GT: + case PARSE_NODE_TYPE_LT: + case PARSE_NODE_TYPE_GTEQ: + case PARSE_NODE_TYPE_LTEQ: + case PARSE_NODE_TYPE_AND: + case PARSE_NODE_TYPE_OR: + case PARSE_NODE_TYPE_NOT: + case PARSE_NODE_TYPE_DOT: + case PARSE_NODE_TYPE_PRINT: + case PARSE_NODE_TYPE_ASSIGN: + case PARSE_NODE_TYPE_MOD: + case PARSE_NODE_TYPE_SQRT: + case PARSE_NODE_TYPE_NEWLINE: + case PARSE_NODE_TYPE_ABS: + case PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS: + case PARSE_NODE_TYPE_PUSH_FIELD_VALUE: + case PARSE_NODE_TYPE_EXP_LIST: + case PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS: + case PARSE_NODE_TYPE_PUSH_ARRAY_VALUE: + case PARSE_NODE_TYPE_INPUT: + case PARSE_NODE_TYPE_UNDEFINED: + case PARSE_NODE_TYPE_STATEMENT_LIST: + case PARSE_NODE_TYPE_EXIT: + case PARSE_NODE_TYPE_RETURN: + case PARSE_NODE_TYPE_XOR: + case PARSE_NODE_TYPE_FOR: + case PARSE_NODE_TYPE_NEXT: + case PARSE_NODE_TYPE_NOTEQUAL: + case PARSE_NODE_TYPE_RANDOM: + case PARSE_NODE_TYPE_SWAP: + case PARSE_NODE_TYPE_MIF: + case PARSE_NODE_TYPE_MELSE: + case PARSE_NODE_TYPE_MENDIF: + case PARSE_NODE_TYPE_WHILE: + case PARSE_NODE_TYPE_LOOP: + case PARSE_NODE_TYPE_ENDFUNC: + case PARSE_NODE_TYPE_TEXTURE: + case PARSE_NODE_TYPE_BUFFER: + case PARSE_NODE_TYPE_DRAW: + case PARSE_NODE_TYPE_CLS: + case PARSE_NODE_TYPE_FLIP: + case PARSE_NODE_TYPE_KEY_ASSIGN: + case PARSE_NODE_TYPE_KEY_VALUE: + case PARSE_NODE_TYPE_INKEY_ASSIGN: + case PARSE_NODE_TYPE_INKEY_VALUE: + case PARSE_NODE_TYPE_TIMER: + case PARSE_NODE_TYPE_SIN: + case PARSE_NODE_TYPE_COS: + case PARSE_NODE_TYPE_TAN: + case PARSE_NODE_TYPE_ASIN: + case PARSE_NODE_TYPE_ACOS: + case PARSE_NODE_TYPE_ATAN: + case PARSE_NODE_TYPE_ATAN2: + case PARSE_NODE_TYPE_LEFT: + case PARSE_NODE_TYPE_MID: + case PARSE_NODE_TYPE_RIGHT: + case PARSE_NODE_TYPE_MATRIX: + case PARSE_NODE_TYPE_VECTOR: + break; + + default: + ASSERT(0); + break; + } + + // + // Make sure both trees have the same number of children. + // + + if ( tree1->child1 && !tree2->child1) return FALSE; + if (!tree1->child1 && tree2->child1) return FALSE; + + if ( tree1->child2 && !tree2->child2) return FALSE; + if (!tree1->child2 && tree2->child2) return FALSE; + + if ( tree1->child3 && !tree2->child3) return FALSE; + if (!tree1->child3 && tree2->child3) return FALSE; + + // + // The children must be the same too. + // + + if (tree1->child1 && !PARSE_trees_the_same(tree1->child1, tree2->child1)) return FALSE; + if (tree1->child2 && !PARSE_trees_the_same(tree1->child2, tree2->child2)) return FALSE; + if (tree1->child3 && !PARSE_trees_the_same(tree1->child3, tree2->child3)) return FALSE; + + // + // All fine! + // + + return TRUE; +} + + + + + +// +// Our parsing functions........ +// + +PARSE_Node *PARSE_labelled_statement_list(); +PARSE_Node *PARSE_statement_list(); +PARSE_Node *PARSE_statement(); +PARSE_Node *PARSE_expression(); +PARSE_Node *PARSE_expression_list(); +PARSE_Node *PARSE_p1exp(); +PARSE_Node *PARSE_p2exp(); +PARSE_Node *PARSE_p3exp(); +PARSE_Node *PARSE_p4exp(); +PARSE_Node *PARSE_p5exp(); +PARSE_Node *PARSE_primary(); +PARSE_Node *PARSE_function_call(); +PARSE_Node *PARSE_lvalue(); +PARSE_Node *PARSE_var(); +PARSE_Node *PARSE_struct(); +PARSE_Node *PARSE_argument_definition(); + +SLONG PARSE_expression_list_depth(PARSE_Node *explist); + + + +// +// Recursive descent parsing... +// + +PARSE_Node *PARSE_function_call() +{ + PARSE_Node *ans; + + LEX_Token lt; + + // + // A function call. + // + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_VARIABLE) + { + // + // ERROR! What function are we calling? + // + + PARSE_throw("Expected a function name"); + } + + LEX_pop(); + + // + // Put "()" onto the front of the function name so + // we know that it's a function. + // + + CBYTE name[LEX_MAX_STRING_LENGTH + 32]; + + sprintf(name, "()%s", lt.variable); + + // + // The start of an argument list? + // + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + PARSE_throw("Expected an open bracket after the function name"); + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + // + // No argments to the function. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_CALL; + ans->child1 = NULL; + ans->args = 0; + ans->variable = PARSE_add_string(name); + + return ans; + } + + // + // This function call has an argument list. + // + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_CALL; + ans->child1 = PARSE_expression_list(); + ans->args = PARSE_expression_list_depth(ans->child1); + ans->variable = PARSE_add_string(name); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("No close bracket after the list of arguments"); + } + + LEX_pop(); + + // + // Descend the expression list and convert each rvalue to an arguement. + // + + PARSE_Node *arg = ans->child1; + + while(1) + { + if (arg->type == PARSE_NODE_TYPE_EXP_LIST) + { + PARSE_convert_rvalue_to_argument(arg->child1); + + arg = arg->child2; + } + else + { + PARSE_convert_rvalue_to_argument(arg); + + break; + } + } + + return ans; + +} + + + +PARSE_Node *PARSE_primary() +{ + PARSE_Node *ans; + + LEX_Token lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_MINUS: + + // + // A unary minus! + // + + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_UMINUS; + ans->child1 = PARSE_primary(); + + return ans; + + case LEX_TOKEN_TYPE_SLUMBER: + + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_SLUMBER; + ans->slumber = lt.slumber; + + return ans; + + case LEX_TOKEN_TYPE_FLUMBER: + + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_FLUMBER; + ans->flumber = lt.flumber; + + return ans; + + case LEX_TOKEN_TYPE_VARIABLE: + + { + CBYTE *varname = PARSE_add_string(lt.variable); + + // + // This could be a function call. + // + + LEX_pop(); + + LEX_Token lookahead = LEX_get(); + + if (lookahead.type == LEX_TOKEN_TYPE_OPEN) + { + // + // This is a function call! + // + + LEX_push(lt); + + ans = PARSE_function_call(); + + return ans; + } + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_VAR_VALUE; + ans->variable = varname; + + return ans; + } + + case LEX_TOKEN_TYPE_OPEN: + + LEX_pop(); + + ans = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("No matching close bracket found"); + } + else + { + LEX_pop(); + + return ans; + } + + case LEX_TOKEN_TYPE_TRUE: + + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_BOOLEAN; + ans->boolean = TRUE; + + return ans; + + case LEX_TOKEN_TYPE_FALSE: + + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_BOOLEAN; + ans->boolean = FALSE; + + return ans; + + case LEX_TOKEN_TYPE_NOT: + + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_NOT; + ans->child1 = PARSE_primary(); + + return ans; + + case LEX_TOKEN_TYPE_STRING: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_STRING; + ans->string = PARSE_add_string(lt.string); + + return ans; + + case LEX_TOKEN_TYPE_INPUT: + + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_INPUT; + + return ans; + + case LEX_TOKEN_TYPE_UNDEFINED: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_UNDEFINED; + + return ans; + + case LEX_TOKEN_TYPE_RANDOM: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_RANDOM; + + return ans; + + case LEX_TOKEN_TYPE_CALL: + + LEX_pop(); + + ans = PARSE_function_call(); + + return ans; + + case LEX_TOKEN_TYPE_TEXTURE: + case LEX_TOKEN_TYPE_BUFFER: + + // + // Creation of a texture or a buffer. + // + + LEX_pop(); + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_TEXTURE: ans->type = PARSE_NODE_TYPE_TEXTURE; break; + case LEX_TOKEN_TYPE_BUFFER: ans->type = PARSE_NODE_TYPE_BUFFER; break; + + default: + ASSERT(0); + break; + } + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + switch(ans->type) + { + case PARSE_NODE_TYPE_TEXTURE: PARSE_throw("No open bracket after the keyword TEXTURE"); break; + case PARSE_NODE_TYPE_BUFFER: PARSE_throw("No open bracket after the keyword BUFFER"); break; + + default: + ASSERT(0); + } + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + // + // No arguments + // + + LEX_pop(); + + ans->child1 = NULL; + ans->args = 0; + } + else + { + // + // An argument list. + // + + ans->child1 = PARSE_expression_list(); + ans->args = PARSE_expression_list_depth(ans->child1); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + switch(ans->type) + { + case PARSE_NODE_TYPE_TEXTURE: PARSE_throw("No close bracket after the keyword TEXTURE"); break; + case PARSE_NODE_TYPE_BUFFER: PARSE_throw("No close bracket after the keyword BUFFER"); break; + + default: + ASSERT(0); + } + } + + LEX_pop(); + } + + return ans; + + + case LEX_TOKEN_TYPE_KEY: + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OSQUARE) + { + // + // ERROR! + // + + PARSE_throw("KEY must be accessed like an array, e.g. KEY[50] or KEY[x]"); + } + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_KEY_VALUE; + ans->child1 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CSQUARE) + { + // + // ERROR! + // + + PARSE_throw("Missing close bracket for the KEY keyword"); + } + + LEX_pop(); + + return ans; + + case LEX_TOKEN_TYPE_INKEY: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_INKEY_VALUE; + + return ans; + + case LEX_TOKEN_TYPE_TIMER: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_TIMER; + + return ans; + + case LEX_TOKEN_TYPE_SQRT: + case LEX_TOKEN_TYPE_ABS: + case LEX_TOKEN_TYPE_SIN: + case LEX_TOKEN_TYPE_COS: + case LEX_TOKEN_TYPE_TAN: + case LEX_TOKEN_TYPE_ASIN: + case LEX_TOKEN_TYPE_ACOS: + case LEX_TOKEN_TYPE_ATAN: + case LEX_TOKEN_TYPE_LEN: + + LEX_pop(); + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_SQRT: ans->type = PARSE_NODE_TYPE_SQRT; break; + case LEX_TOKEN_TYPE_ABS: ans->type = PARSE_NODE_TYPE_ABS; break; + case LEX_TOKEN_TYPE_SIN: ans->type = PARSE_NODE_TYPE_SIN; break; + case LEX_TOKEN_TYPE_COS: ans->type = PARSE_NODE_TYPE_COS; break; + case LEX_TOKEN_TYPE_TAN: ans->type = PARSE_NODE_TYPE_TAN; break; + case LEX_TOKEN_TYPE_ASIN: ans->type = PARSE_NODE_TYPE_ASIN; break; + case LEX_TOKEN_TYPE_ACOS: ans->type = PARSE_NODE_TYPE_ACOS; break; + case LEX_TOKEN_TYPE_ATAN: ans->type = PARSE_NODE_TYPE_ATAN; break; + case LEX_TOKEN_TYPE_LEN: ans->type = PARSE_NODE_TYPE_LEN; break; + + default: + ASSERT(0); + break; + } + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + switch(ans->type) + { + case PARSE_NODE_TYPE_SQRT: PARSE_throw("Missing open bracket after SQRT"); break; + case PARSE_NODE_TYPE_ABS: PARSE_throw("Missing open bracket after ABS"); break; + case PARSE_NODE_TYPE_SIN: PARSE_throw("Missing open bracket after SIN"); break; + case PARSE_NODE_TYPE_COS: PARSE_throw("Missing open bracket after COS"); break; + case PARSE_NODE_TYPE_TAN: PARSE_throw("Missing open bracket after TAN"); break; + case PARSE_NODE_TYPE_ASIN: PARSE_throw("Missing open bracket after ASIN"); break; + case PARSE_NODE_TYPE_ACOS: PARSE_throw("Missing open bracket after ACOS"); break; + case PARSE_NODE_TYPE_ATAN: PARSE_throw("Missing open bracket after ATAN"); break; + case PARSE_NODE_TYPE_LEN: PARSE_throw("Missing open bracket after LEN"); break; + + default: + ASSERT(0); + break; + } + } + + LEX_pop(); + + ans->child1 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + switch(ans->type) + { + case PARSE_NODE_TYPE_SQRT: PARSE_throw("Missing close bracket after SQRT"); break; + case PARSE_NODE_TYPE_ABS: PARSE_throw("Missing close bracket after ABS"); break; + case PARSE_NODE_TYPE_SIN: PARSE_throw("Missing close bracket after SIN"); break; + case PARSE_NODE_TYPE_COS: PARSE_throw("Missing close bracket after COS"); break; + case PARSE_NODE_TYPE_TAN: PARSE_throw("Missing close bracket after TAN"); break; + case PARSE_NODE_TYPE_ASIN: PARSE_throw("Missing close bracket after ASIN"); break; + case PARSE_NODE_TYPE_ACOS: PARSE_throw("Missing close bracket after ACOS"); break; + case PARSE_NODE_TYPE_ATAN: PARSE_throw("Missing close bracket after ATAN"); break; + case PARSE_NODE_TYPE_LEN: PARSE_throw("Missing close bracket after LEN"); break; + + default: + ASSERT(0); + break; + } + } + + LEX_pop(); + + return ans; + + case LEX_TOKEN_TYPE_ATAN2: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_ATAN2; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + PARSE_throw("Missing open bracket after ATAN2"); + } + + LEX_pop(); + + ans->child1 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_COMMA) + { + // + // ERROR! + // + + PARSE_throw("Expected a comma separating the two arguments to ATAN2"); + } + + LEX_pop(); + + ans->child2 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("Missing close bracket after ATAN2"); + } + + LEX_pop(); + + return ans; + + case LEX_TOKEN_TYPE_LEFT: + case LEX_TOKEN_TYPE_RIGHT: + + // + // These functions take either one or two arguments. + // + + LEX_pop(); + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_LEFT: ans->type = PARSE_NODE_TYPE_LEFT; break; + case LEX_TOKEN_TYPE_RIGHT: ans->type = PARSE_NODE_TYPE_RIGHT; break; + + default: + ASSERT(0); + break; + } + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + switch(ans->type) + { + case PARSE_NODE_TYPE_LEFT: PARSE_throw("Missing open bracket after LEFT"); break; + case PARSE_NODE_TYPE_RIGHT: PARSE_throw("Missing open bracket after RIGHT"); break; + + default: + ASSERT(0); + break; + } + } + + LEX_pop(); + + ans->child1 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + LEX_pop(); + + // + // This is a one-argugment version. + // + + ans->child2 = NULL; + + return ans; + } + else + if (lt.type != LEX_TOKEN_TYPE_COMMA) + { + // + // ERROR! + // + + switch(ans->type) + { + case PARSE_NODE_TYPE_LEFT: PARSE_throw("Expected a comma or a close bracket after the first argument to LEFT"); break; + case PARSE_NODE_TYPE_RIGHT: PARSE_throw("Expected a comma or a close bracket after the first argument to RIGHT"); break; + + default: + ASSERT(0); + break; + } + } + + LEX_pop(); + + ans->child2 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + switch(ans->type) + { + case PARSE_NODE_TYPE_LEFT: PARSE_throw("Expected a close bracket after LEFT"); break; + case PARSE_NODE_TYPE_RIGHT: PARSE_throw("Expected a close bracket after RIGHT"); break; + + default: + ASSERT(0); + break; + } + } + + LEX_pop(); + + return ans; + + case LEX_TOKEN_TYPE_MID: + + // + // A two or three arguement function. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_MID; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + PARSE_throw("Expected an open bracket after MID"); + } + + LEX_pop(); + + ans->child1 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_COMMA) + { + // + // ERROR! + // + + PARSE_throw("Expected a comma after the first argument to MID"); + } + + LEX_pop(); + + ans->child2 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + LEX_pop(); + + // + // This is a two-argument version. + // + + ans->child3 = NULL; + + return ans; + } + else + if (lt.type != LEX_TOKEN_TYPE_COMMA) + { + // + // ERROR! + // + + PARSE_throw("Expected a comma or close bracket after the second argument to MID"); + } + + LEX_pop(); + + ans->child3 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("Expected a close bracket after the third argument to MID"); + } + + LEX_pop(); + + return ans; + + case LEX_TOKEN_TYPE_MATRIX: + + // + // A matrix constant. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_MATRIX; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + PARSE_throw("Expected an open bracket after MATRIX"); + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + // + // This is the identity matrix. + // + + ans->child1 = NULL; + } + else + { + // + // There must be an expression list. + // + + ans->child1 = PARSE_expression_list(); + ans->args = PARSE_expression_list_depth(ans->child1); + + // + // Right number of arguments? 3 args that must all be vectors, + // + + if (ans-> args != 3) + { + // + // ERROR! + // + + PARSE_throw("MATRIX wants three vector arguments"); + } + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("Expected a close bracket after the argument list to MATRIX"); + } + + LEX_pop(); + } + + return ans; + + case LEX_TOKEN_TYPE_VECTOR: + + // + // A matrix constant. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_VECTOR; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + PARSE_throw("Expected an open bracket after VECTOR"); + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + // + // This is the zero vector (0,0,0). + // + + ans->child1 = NULL; + } + else + { + // + // There must be an expression list. + // + + ans->child1 = PARSE_expression_list(); + ans->args = PARSE_expression_list_depth(ans->child1); + + // + // Right number of arguments? + // + + if (ans->args != 3) + { + // + // ERROR! + // + + PARSE_throw("The VECTOR command expects either 3 arguments or an empty argument list"); + } + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("Expected a close bracket after the argument list to VECTOR"); + } + + LEX_pop(); + } + + return ans; + + default: + + // + // ERROR! + // + + PARSE_throw(); + + return NULL; + } +} + + + +PARSE_Node *PARSE_p6exp() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_primary(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_DOT: + + LEX_pop(); + + rhs = PARSE_struct(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_PUSH_FIELD_VALUE; + ans->child1 = lhs; + ans->child2 = rhs; + + lhs->flag |= PARSE_NODE_FLAG_EXTRACT; + + // + // Now carry on... + // + + lhs = ans; + + break; + + case LEX_TOKEN_TYPE_OSQUARE: + + LEX_pop(); + + rhs = PARSE_expression_list(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_PUSH_ARRAY_VALUE; + ans->dimensions = PARSE_expression_list_depth(rhs); + ans->child1 = lhs; + ans->child2 = rhs; + + lhs->flag |= PARSE_NODE_FLAG_EXTRACT; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CSQUARE) + { + // + // ERROR! + // + + PARSE_throw("Missing close square bracket in an array access"); + } + + LEX_pop(); + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + return lhs; + } + } +} + + + + +PARSE_Node *PARSE_p5exp() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_p6exp(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_TIMES: + case LEX_TOKEN_TYPE_DIVIDE: + case LEX_TOKEN_TYPE_MOD: + case LEX_TOKEN_TYPE_CPROD: + + LEX_pop(); + + rhs = PARSE_p6exp(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_TIMES: ans->type = PARSE_NODE_TYPE_TIMES; break; + case LEX_TOKEN_TYPE_DIVIDE: ans->type = PARSE_NODE_TYPE_DIVIDE; break; + case LEX_TOKEN_TYPE_MOD: ans->type = PARSE_NODE_TYPE_MOD; break; + + default: + ASSERT(0); + break; + } + + ans->child1 = lhs; + ans->child2 = rhs; + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + return lhs; + } + } +} + + + +PARSE_Node *PARSE_p4exp() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_p5exp(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_PLUS: + case LEX_TOKEN_TYPE_MINUS: + + LEX_pop(); + + rhs = PARSE_p5exp(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_PLUS: ans->type = PARSE_NODE_TYPE_PLUS; break; + case LEX_TOKEN_TYPE_MINUS: ans->type = PARSE_NODE_TYPE_MINUS; break; + + default: + ASSERT(0); + break; + } + + ans->child1 = lhs; + ans->child2 = rhs; + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + return lhs; + } + } +} + +PARSE_Node *PARSE_p3exp() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_p4exp(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_LT: + case LEX_TOKEN_TYPE_GT: + case LEX_TOKEN_TYPE_LTEQ: + case LEX_TOKEN_TYPE_GTEQ: + + LEX_pop(); + + rhs = PARSE_p4exp(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_LT: ans->type = PARSE_NODE_TYPE_LT; break; + case LEX_TOKEN_TYPE_GT: ans->type = PARSE_NODE_TYPE_GT; break; + case LEX_TOKEN_TYPE_LTEQ: ans->type = PARSE_NODE_TYPE_LTEQ; break; + case LEX_TOKEN_TYPE_GTEQ: ans->type = PARSE_NODE_TYPE_GTEQ; break; + + default: + ASSERT(0); + break; + } + + ans->child1 = lhs; + ans->child2 = rhs; + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + return lhs; + } + } +} + + + + +PARSE_Node *PARSE_p2exp() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_p3exp(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_EQUALS: + case LEX_TOKEN_TYPE_NOTEQUAL: + + LEX_pop(); + + rhs = PARSE_p3exp(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_EQUALS: ans->type = PARSE_NODE_TYPE_EQUALS; break; + case LEX_TOKEN_TYPE_NOTEQUAL: ans->type = PARSE_NODE_TYPE_NOTEQUAL; break; + + default: + ASSERT(0); + break; + } + + ans->child1 = lhs; + ans->child2 = rhs; + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + return lhs; + } + } +} + + + +PARSE_Node *PARSE_p1exp() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_p2exp(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_AND: + + LEX_pop(); + + rhs = PARSE_p2exp(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_AND; + ans->child1 = lhs; + ans->child2 = rhs; + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + return lhs; + } + } +} + + + + +PARSE_Node *PARSE_expression() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_p1exp(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_OR: + case LEX_TOKEN_TYPE_XOR: + + LEX_pop(); + + rhs = PARSE_p1exp(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_OR: ans->type = PARSE_NODE_TYPE_OR; break; + case LEX_TOKEN_TYPE_XOR: ans->type = PARSE_NODE_TYPE_XOR; break; + + default: + ASSERT(0); + break; + } + + ans->child1 = lhs; + ans->child2 = rhs; + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + + // + // Make this whole tree as belonging to an expression. + // + + PARSE_traverse(lhs, PARSE_set_expression_flag); + + return lhs; + } + } +} + + +PARSE_Node *PARSE_expression_list() +{ + LEX_Token lt; + + PARSE_Node *exp; + PARSE_Node *ans; + + exp = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_COMMA) + { + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_EXP_LIST; + ans->child1 = exp; + ans->child2 = PARSE_expression_list(); + + return ans; + } + else + { + return exp; + } +} + +// +// Returns the depth of an expressionlist. +// + +SLONG PARSE_expression_list_depth(PARSE_Node *explist) +{ + if (explist->type != PARSE_NODE_TYPE_EXP_LIST) + { + return 1; + } + else + { + return 1 + PARSE_expression_list_depth(explist->child2); + } +} + + + +PARSE_Node *PARSE_var() +{ + // + // No arrays for now! + // + + PARSE_Node *ans; + + LEX_Token lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_VARIABLE) + { + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_VAR_ADDRESS; + ans->variable = PARSE_add_string(lt.variable); + + return ans; + } + + // + // ERROR! + // + + PARSE_throw(); + + return NULL; +} + +PARSE_Node *PARSE_struct() +{ + // + // No arrays for now! + // + + PARSE_Node *ans; + + LEX_Token lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_VARIABLE) + { + LEX_pop(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_FIELD; + + { + // + // Build the field name (insert a '.' at the beginning) + // + + CBYTE field[LEX_MAX_STRING_LENGTH + 32]; + + sprintf(field, ".%s", lt.variable); + + ans->field = PARSE_add_string(field); + } + + return ans; + } + + // + // ERROR! + // + + PARSE_throw(); + + return NULL; +} + + + + +PARSE_Node *PARSE_lvalue() +{ + LEX_Token lt; + + PARSE_Node *lhs; + PARSE_Node *rhs; + PARSE_Node *ans; + + lhs = PARSE_var(); + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_DOT: + + LEX_pop(); + + rhs = PARSE_struct(); + + // + // Build a little tree... + // + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS; + ans->child1 = lhs; + ans->child2 = rhs; + + // + // Now carry on... + // + + lhs = ans; + + break; + + case LEX_TOKEN_TYPE_OSQUARE: + + LEX_pop(); + + // + // Get a list of numbers... + // + + rhs = PARSE_expression_list(); + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS; + ans->dimensions = PARSE_expression_list_depth(rhs); + ans->child1 = lhs; + ans->child2 = rhs; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CSQUARE) + { + // + // ERROR! + // + + PARSE_throw("Missing close square bracket in array access"); + } + + LEX_pop(); + + // + // Now carry on... + // + + lhs = ans; + + break; + + default: + return lhs; + } + } +} + + +PARSE_Node *PARSE_argument_definition() +{ + LEX_Token lt; + + // + // Initailise our answer. + // + + PARSE_Node *ans = NULL; + PARSE_Node *arg = NULL; + PARSE_Node *last = NULL; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // No arguements? + // + + return NULL; + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + LEX_pop(); + + // + // An empty argument call... + // + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_NOP; + + return ans; + } + + while(1) + { + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_VARIABLE: + + LEX_pop(); + + // + // Create another argument. + // + + arg = PARSE_get_node(); + + arg->type = PARSE_NODE_TYPE_ARGUMENT; + arg->variable = PARSE_add_string(lt.variable); + arg->child1 = NULL; + + // + // Is this the first argument? + // + + if (ans == NULL) + { + ans = arg; + } + + // + // Do we have to put this onto the end of existing tree + // of arguments? + // + + if (last) + { + last->child1 = arg; + } + + last = arg; + + // + // End of the list or is there another one? + // + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_COMMA) + { + // + // Another variable... + // + + LEX_pop(); + } + else + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + // + // End of the list. + // + + LEX_pop(); + + return ans; + } + else + { + // + // ERROR! + // + + PARSE_throw("Expected a comma or close bracket in argument list"); + } + + break; + + default: + + // + // ERROR! + // + + PARSE_throw("Something odd in the argument list - only variables allowed!"); + } + } +} + + + + + +PARSE_Node *PARSE_statement() +{ + PARSE_Node *ans; + + LEX_Token lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_PRINT: + + LEX_pop(); + + ans = PARSE_get_node(); + + if (LEX_get().type == LEX_TOKEN_TYPE_NEWLINE || + LEX_get().type == LEX_TOKEN_TYPE_COLON) + { + ans->type = PARSE_NODE_TYPE_NEWLINE; + } + else + { + ans->type = PARSE_NODE_TYPE_PRINT; + ans->child1 = PARSE_expression(); + } + + return ans; + + case LEX_TOKEN_TYPE_GOTO: + case LEX_TOKEN_TYPE_GOSUB: + + LEX_pop(); + + ans = PARSE_get_node(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_GOTO: ans->type = PARSE_NODE_TYPE_GOTO; break; + case LEX_TOKEN_TYPE_GOSUB: ans->type = PARSE_NODE_TYPE_GOSUB; break; + + default: + ASSERT(0); + break; + } + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_SLUMBER) + { + LEX_pop(); + + CBYTE label[32]; + CBYTE *ch; + + itoa(lt.slumber, label, 10); + + for (ch = label; *ch; ch++); + + ch[0] = ':'; + ch[1] = '\000'; + + ans->label = PARSE_add_string(label); + } + else + if (lt.type == LEX_TOKEN_TYPE_VARIABLE) + { + LEX_pop(); + + strcat(lt.variable, ":"); + + ans->label = PARSE_add_string(lt.variable); + } + else + { + // + // ERROR! + // + + PARSE_throw("You can only GOTO labels or line numbers"); + } + + return ans; + + case LEX_TOKEN_TYPE_VARIABLE: + + { + CBYTE *varname = PARSE_add_string(lt.variable); + + // + // This could be a function call. + // + + LEX_pop(); + + LEX_Token lookahead = LEX_get(); + + if (lookahead.type == LEX_TOKEN_TYPE_OPEN) + { + // + // This is a function call! + // + + LEX_push(lt); + + ans = PARSE_function_call(); + + return ans; + } + + // + // The 'variable' part could have been + // overwritten by the LEX_get()... + // + + lt.variable = varname; + + LEX_push(lt); + + // + // Variable assignement... + // + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_ASSIGN; + ans->child1 = PARSE_lvalue(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_EQUALS) + { + // + // ERROR! + // + + PARSE_throw("Missing equals after a variable (assuming you wanted to assign a value!)"); + } + + LEX_pop(); + + ans->child2 = PARSE_expression(); + + return ans; + } + + case LEX_TOKEN_TYPE_IF: + + // + // IF THEN (ELSE) statement. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_IF; + ans->child1 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_NEWLINE) + { + // + // This must be a multi-line if. + // + + ans->type = PARSE_NODE_TYPE_MIF; + ans->child2 = NULL; + ans->child3 = NULL; + + return ans; + } + + if (lt.type != LEX_TOKEN_TYPE_THEN) + { + // + // ERROR! + // + + PARSE_throw("Missing THEN after an IF statement"); + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_NEWLINE) + { + // + // This must be a multi-line if. + // + + ans->type = PARSE_NODE_TYPE_MIF; + ans->child2 = NULL; + ans->child3 = NULL; + + return ans; + } + + ans->child2 = PARSE_statement_list(); + + // + // Tell the THEN statements they are part of a conditional. + // + + PARSE_traverse(ans->child2, PARSE_set_conditional_flag); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_ELSE) + { + // + // This IF statement has an ELSE bit! + // + + LEX_pop(); + + ans->child3 = PARSE_statement_list(); + + // + // Tell the ELSE statements they are part of a conditional. + // + + PARSE_traverse(ans->child3, PARSE_set_conditional_flag); + } + else + { + // + // IF and THEN without an ELSE. + // + + ans->child3 = NULL; + } + + return ans; + + case LEX_TOKEN_TYPE_NEWLINE: + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_NOP; + return ans; + + case LEX_TOKEN_TYPE_EXIT: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_EXIT; + + return ans; + + case LEX_TOKEN_TYPE_FOR: + + { + LEX_pop(); + + PARSE_forcode++; + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_FOR; + ans->forcode = PARSE_forcode; + + // + // The initialisation. + // + + ans->child1 = PARSE_statement_list(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_TO) + { + // + // ERROR! + // + + PARSE_throw("Missing TO in the FOR statement"); + } + + LEX_pop(); + + // + // Find the variable by which the FOR loop is recognised. + // + + { + PARSE_Node *init; + + if (ans->child1->type == PARSE_NODE_TYPE_STATEMENT_LIST) + { + init = ans->child1->child1; + } + else + { + init = ans->child1; + } + + if (init->type == PARSE_NODE_TYPE_ASSIGN) + { + // + // Store the lvalue the FOR loop is initialising. + // + + ans->lvalue = init->child1; + } + else + { + // + // This is an anonymous FOR loop. + // + + ans->lvalue = NULL; + } + } + + // + // Now parse the end condition. + // + + ans->child2 = PARSE_expression(); + + if (PARSE_expression_is_boolean(ans->child2)) + { + // + // We don't have to create a boolean expression. + // + } + else + { + // + // Replace the expression with the condition that + // this FOR loop's lvalue > the expression. + // + + if (ans->lvalue == NULL) + { + // + // ERROR! + // + + PARSE_throw("Cannot establish a condition for terminating the FOR loop. Try making the TO part of the FOR loop a BOOLEAN expression"); + } + + PARSE_Node *cond = PARSE_get_node(); + + cond->type = PARSE_NODE_TYPE_GT; + cond->child1 = PARSE_convert_lvalue_to_rvalue(ans->lvalue); + cond->child2 = ans->child2; + + ans->child2 = cond; + } + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_STEP) + { + if (ans->lvalue == NULL) + { + // + // ERROR! Can't build a default STEP for an anonymous FOR loop. + // + + PARSE_throw( "Cannot create a default STEP for the FOR loop. You must specify a STEP instruction"); + } + + // + // Build a parse tree to increment this variable. + // + + PARSE_Node *assign; + PARSE_Node *varaddress; + PARSE_Node *varvalue; + PARSE_Node *one; + PARSE_Node *add; + + varaddress = PARSE_copy_tree(ans->lvalue); + varvalue = PARSE_convert_lvalue_to_rvalue(ans->lvalue); + + one = PARSE_get_node(); + one->type = PARSE_NODE_TYPE_SLUMBER; + one->slumber = 1; + + add = PARSE_get_node(); + add->type = PARSE_NODE_TYPE_PLUS; + add->child1 = varvalue; + add->child2 = one; + + assign = PARSE_get_node(); + assign->type = PARSE_NODE_TYPE_ASSIGN; + assign->child1 = varaddress; + assign->child2 = add; + + // + // And make this our STEP instruction. + // + + ans->child3 = assign; + } + else + { + LEX_pop(); + + // + // We have a STEP statement! + // + + ans->child3 = PARSE_statement_list(); + } + } + + return ans; + + case LEX_TOKEN_TYPE_NEXT: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_NEXT; + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_VARIABLE) + { + // + // The NEXT statement that knows which FOR loop it belongs to. + // + + ans->lvalue = PARSE_lvalue(); + } + else + { + // + // An anonymous NEXT. + // + + ans->lvalue = NULL; + } + + return ans; + + case LEX_TOKEN_TYPE_SWAP: + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_SWAP; + ans->child1 = PARSE_lvalue(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_AND) + { + // + // ERROR! + // + + PARSE_throw("The two things to swap must be separated by an AND with a SWAP statment. e.g. SWAP x AND w"); + } + + LEX_pop(); + + ans->child2 = PARSE_lvalue(); + + return ans; + + case LEX_TOKEN_TYPE_ELSE: + + // + // This must be the ELSE instruction of a multi-line IF. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_MELSE; + + return ans; + + case LEX_TOKEN_TYPE_ENDIF: + + // + // This must be the ELSE instruction of a multi-line IF. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_MENDIF; + + return ans; + + case LEX_TOKEN_TYPE_WHILE: + + // + // The start of a WHILE loop. + // + + LEX_pop(); + + PARSE_whilecode += 1; + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_WHILE; + ans->whilecode = PARSE_whilecode; + ans->child1 = PARSE_expression(); + + return ans; + + case LEX_TOKEN_TYPE_LOOP: + + // + // The end of a while loop. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_LOOP; + + return ans; + + case LEX_TOKEN_TYPE_FUNCTION: + + // + // A function definition! + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_FUNCTION; + + // + // Name of the function... + // + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_VARIABLE) + { + // + // ERROR! + // + + PARSE_throw("Expected the name of the function after the FUNCTION keyword"); + } + + LEX_pop(); + + { + // + // Put "()" onto the front of the function name so + // we know that it's a function. + // + + CBYTE name[LEX_MAX_STRING_LENGTH + 32]; + + sprintf(name, "()%s", lt.variable); + + ans->variable = PARSE_add_string(name); + } + + // + // Argument declaration. + // + + ans->child1 = PARSE_argument_definition(); + + return ans; + + case LEX_TOKEN_TYPE_RETURN: + + // + // Return from a function or subroutine. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_RETURN; + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_ELSE || + lt.type == LEX_TOKEN_TYPE_ENDIF || + lt.type == LEX_TOKEN_TYPE_COLON || + lt.type == LEX_TOKEN_TYPE_NEWLINE) + { + // + // No argument to return... + // + + ans->child1 = NULL; + } + else + { + // + // The expression to be returned + // + + ans->child1 = PARSE_expression(); + } + + return ans; + + case LEX_TOKEN_TYPE_ENDFUNC: + + // + // The end of a function declaration... + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_ENDFUNC; + + return ans; + + case LEX_TOKEN_TYPE_CALL: + + LEX_pop(); + + ans = PARSE_function_call(); + + return ans; + + case LEX_TOKEN_TYPE_DRAW: + + // + // Drawing something! + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_DRAW; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // ERROR! + // + + PARSE_throw("Missing open bracket after DRAW"); + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + // + // No arguments + // + + LEX_pop(); + + ans->child1 = NULL; + ans->args = 0; + } + else + { + // + // An argument list. + // + + ans->child1 = PARSE_expression_list(); + ans->args = PARSE_expression_list_depth(ans->child1); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("Missing close bracket after DRAW"); + } + + LEX_pop(); + } + + return ans; + + case LEX_TOKEN_TYPE_CLS: + + // + // Clear the screen. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_CLS; + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OPEN) + { + // + // A CLS without an argument list. + // + + ans->child1 = NULL; + ans->args = 0; + } + else + { + LEX_pop(); + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_CLOSE) + { + // + // No arguments + // + + LEX_pop(); + + ans->child1 = NULL; + ans->args = 0; + } + else + { + // + // An argument list. + // + + ans->child1 = PARSE_expression_list(); + ans->args = PARSE_expression_list_depth(ans->child1); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CLOSE) + { + // + // ERROR! + // + + PARSE_throw("Missing close bracket after CLS"); + } + + LEX_pop(); + } + } + + return ans; + + case LEX_TOKEN_TYPE_FLIP: + + // + // A FLIP statement. + // + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_FLIP; + + return ans; + + case LEX_TOKEN_TYPE_KEY: + + // + // Assiging to the KEY array. + // + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_OSQUARE) + { + // + // ERROR! + // + + PARSE_throw("Expected an open square bracket after KEY"); + } + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_KEY_ASSIGN; + ans->child1 = PARSE_expression(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_CSQUARE) + { + // + // ERROR! + // + + PARSE_throw("Expected a close square bracket after KEY"); + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_EQUALS) + { + // + // ERROR! + // + + PARSE_throw("Expected an equals after KEY[...]"); + } + + LEX_pop(); + + ans->child2 = PARSE_expression(); + + return ans; + + case LEX_TOKEN_TYPE_INKEY: + + // + // Assigning to INKEY + // + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_EQUALS) + { + // + // ERROR! + // + + PARSE_throw("Expected an equals after INKEY"); + } + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_INKEY_ASSIGN; + ans->child1 = PARSE_expression(); + + return ans; + + case LEX_TOKEN_TYPE_EXPORT: + + // + // Exporting a global or function. + // + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_VARIABLE) + { + // + // ERROR! + // + + PARSE_throw("Expected a variable list after EXPORT"); + } + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_EXPORT; + ans->variable = PARSE_add_string(lt.variable); + + { + PARSE_Node *higher = ans; + PARSE_Node *lower; + + // + // We can have a whole long list of exports. + // + + while(1) + { + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_COMMA) + { + break; + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_VARIABLE) + { + // + // ERROR! + // + + PARSE_throw("Expected a variable after the comma in the EXPORT statement"); + } + + LEX_pop(); + + // + // Create a new node. + // + + lower = PARSE_get_node(); + lower->type = PARSE_NODE_TYPE_EXPORT; + lower->variable = PARSE_add_string(lt.variable); + + higher->child1 = lower; + higher = lower; + } + } + + return ans; + + case LEX_TOKEN_TYPE_LOCAL: + + // + // Declaring a variable to be a local. + // + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_VARIABLE) + { + // + // ERROR! + // + + PARSE_throw("Expected a variable list after LOCAL"); + } + + LEX_pop(); + + ans = PARSE_get_node(); + ans->type = PARSE_NODE_TYPE_LOCAL; + ans->variable = PARSE_add_string(lt.variable); + + { + PARSE_Node *higher = ans; + PARSE_Node *lower; + + // + // We can have a whole long list of locals. + // + + while(1) + { + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_COMMA) + { + break; + } + + LEX_pop(); + + lt = LEX_get(); + + if (lt.type != LEX_TOKEN_TYPE_VARIABLE) + { + // + // ERROR! + // + + PARSE_throw("Expected a variable after the comma in the LOCAL statement"); + } + + LEX_pop(); + + // + // Create a new node. + // + + lower = PARSE_get_node(); + lower->type = PARSE_NODE_TYPE_LOCAL; + lower->variable = PARSE_add_string(lt.variable); + + higher->child1 = lower; + higher = lower; + } + } + + return ans; + + default: + + // + // ERROR! + // + + PARSE_throw(); + + return NULL; // To stop the compiler complaining that not all control paths return a value. + } +} + + + +PARSE_Node *PARSE_statement_list() +{ + LEX_Token lt; + + PARSE_Node *statement; + + statement = PARSE_statement(); + + // + // Should we continue to PARSE another statement? + // + + SLONG another_statement = FALSE; + + lt = LEX_get(); + + switch(lt.type) + { + case LEX_TOKEN_TYPE_COLON: + + // + // We've found a colon separator. + // + + LEX_pop(); + + another_statement = TRUE; + + break; + + case LEX_TOKEN_TYPE_ENDIF: + + // + // We don't need a colon before an ENDIF instruction... + // + + another_statement = TRUE; + + break; + + case LEX_TOKEN_TYPE_NEWLINE: + break; + + default: + + if (statement->type == PARSE_NODE_TYPE_MELSE) + { + // + // We dont need a COLON before the next statement. + // + + another_statement = TRUE; + } + + break; + } + + if (another_statement) + { + PARSE_Node *ans; + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_STATEMENT_LIST; + ans->child1 = statement; + ans->child2 = PARSE_statement_list(); + + return ans; + } + + return statement; +} + + + +PARSE_Node *PARSE_labelled_statement_list() +{ + PARSE_Node *ans; + + LEX_Token lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_FLUMBER) + { + // + // ERROR! Labelling a line with a floating point number? + // + + PARSE_throw("You can't label a line with a floating point number"); + } + + if (lt.type == LEX_TOKEN_TYPE_SLUMBER) + { + LEX_pop(); + + // + // This line is labelled with a number. + // + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_LABEL; + + CBYTE label[32]; + CBYTE *ch; + + itoa(lt.slumber, label, 10); + + for (ch = label; *ch; ch++); + + ch[0] = ':'; + ch[1] = '\000'; + + ans->label = PARSE_add_string(label); + ans->child1 = PARSE_statement(); + } + else if (lt.type == LEX_TOKEN_TYPE_LABEL) + { + LEX_pop(); + + // + // This line is labelled with a proper label. + // + + ans = PARSE_get_node(); + + ans->type = PARSE_NODE_TYPE_LABEL; + ans->label = PARSE_add_string(lt.label); + ans->child1 = PARSE_statement(); + } + else + { + // + // No label... + // + + ans = PARSE_statement_list(); + } + + lt = LEX_pop(); + + if (lt.type != LEX_TOKEN_TYPE_NEWLINE) + { + // + // ERROR! + // + + PARSE_throw("Expected the end of the line but there was extra stuff"); + } + + return ans; +} + + + +// +// The maximum length of a source file in bytes. This is pants! +// + + +CBYTE *PARSE_program; +SLONG PARSE_program_upto; +SLONG PARSE_program_max; + + + +void PARSE_do(CBYTE *fname) +{ + SLONG want_to_read; + SLONG bytes_read; + LEX_Token lt; + PARSE_Node *nop; + + // + // Initialise... + // + + PARSE_node_upto = 0; + PARSE_string_table_upto = 0; + PARSE_line_upto = 0; + PARSE_error_upto = 0; + PARSE_errbuf_upto = 0; + + memset(PARSE_node, 0, sizeof(PARSE_node)); + + if (PARSE_program_max == 0) + { + // + // Allocate memory for the file. + // + + PARSE_program_max = 16; + PARSE_program = (CBYTE *) malloc(sizeof(CBYTE) * PARSE_program_max); + + memset(PARSE_program, 0, sizeof(CBYTE) * PARSE_program_max); + } + + // + // Load the file. + // + + FILE *handle = fopen(fname, "rb"); + + if (!handle) + { + PARSE_add_error("Could not open source file \"%s\"", fname); + + return; + } + + PARSE_program_upto = 0; + + while(1) + { + // + // How many bytes till the end of our buffer? + // + + want_to_read = PARSE_program_max - PARSE_program_upto; + + // + // Try and load in that many bytes. + // + + bytes_read = fread( + PARSE_program + PARSE_program_upto, + sizeof(CBYTE), + want_to_read, + handle); + + PARSE_program_upto += bytes_read; + + if (bytes_read == want_to_read) + { + // + // More data to read, so allocate a bigger buffer. + // + + PARSE_program_max *= 2; + PARSE_program = (CBYTE *) realloc(PARSE_program, sizeof(CBYTE) * PARSE_program_max); + + // + // Zero out newly allocated memory. + // + + memset(PARSE_program + (PARSE_program_max / 2), 0, sizeof(CBYTE) * PARSE_program_max / 2); + } + else + { + // + // Finished reading program. + // + + break; + } + } + + // + // Give the input to the lexical analyser. + // + + LEX_start(PARSE_program); + + // + // This is where we pop back to when we get an error! + // + + if (setjmp(PARSE_error_jmp) == 0) + { + // + // This is the first call... + // + + ASSERT(PARSE_line_upto == 0); + } + else + { + // + // An error has occurred. + // + + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_ERROR) + { + // + // Override the parse error with the lexical error. + // + + PARSE_error_type = lt.error; + } + + if (!PARSE_add_error("ERROR in %s line %d : %s", fname, PARSE_line_upto, PARSE_error_type)) + { + // + // Too many errors! ABORT! + // + + return; + } + + // + // Try and recover. Go onto the next line. + // + + LEX_next_line(); + + // + // Mark this line as blank. + // + + nop = PARSE_get_node(); + nop->type = PARSE_NODE_TYPE_NOP; + + PARSE_line[PARSE_line_upto++] = nop; + } + + while(1) + { + lt = LEX_get(); + + if (lt.type == LEX_TOKEN_TYPE_EOF) + { + // + // Parsing complete! + // + + break; + } + + ASSERT(WITHIN(PARSE_line_upto, 0, PARSE_MAX_LINES - 1)); + + PARSE_line[PARSE_line_upto++] = PARSE_labelled_statement_list(); + } +} + + +void PARSE_traverse_do(PARSE_Node *pn, SLONG (*user_function)(PARSE_Node *pn)) +{ + switch(pn->type) + { + case PARSE_NODE_TYPE_NOP: + case PARSE_NODE_TYPE_SLUMBER: + case PARSE_NODE_TYPE_FLUMBER: + case PARSE_NODE_TYPE_STRING: + case PARSE_NODE_TYPE_VAR_VALUE: + case PARSE_NODE_TYPE_VAR_ADDRESS: + case PARSE_NODE_TYPE_GOTO: + case PARSE_NODE_TYPE_BOOLEAN: + case PARSE_NODE_TYPE_NEWLINE: + case PARSE_NODE_TYPE_FIELD: + case PARSE_NODE_TYPE_INPUT: + case PARSE_NODE_TYPE_UNDEFINED: + case PARSE_NODE_TYPE_EXIT: + case PARSE_NODE_TYPE_GOSUB: + case PARSE_NODE_TYPE_NEXT: + case PARSE_NODE_TYPE_RANDOM: + case PARSE_NODE_TYPE_MELSE: + case PARSE_NODE_TYPE_MENDIF: + case PARSE_NODE_TYPE_LOOP: + case PARSE_NODE_TYPE_ENDFUNC: + case PARSE_NODE_TYPE_FLIP: + case PARSE_NODE_TYPE_INKEY_VALUE: + case PARSE_NODE_TYPE_TIMER: + case PARSE_NODE_TYPE_EXPORT: + + // + // No children. + // + + user_function(pn); + + break; + + case PARSE_NODE_TYPE_LABEL: + case PARSE_NODE_TYPE_UMINUS: + case PARSE_NODE_TYPE_NOT: + case PARSE_NODE_TYPE_PRINT: + case PARSE_NODE_TYPE_SQRT: + case PARSE_NODE_TYPE_ABS: + case PARSE_NODE_TYPE_MIF: + case PARSE_NODE_TYPE_INKEY_ASSIGN: + case PARSE_NODE_TYPE_KEY_VALUE: + case PARSE_NODE_TYPE_SIN: + case PARSE_NODE_TYPE_COS: + case PARSE_NODE_TYPE_TAN: + case PARSE_NODE_TYPE_ASIN: + case PARSE_NODE_TYPE_ACOS: + case PARSE_NODE_TYPE_ATAN: + case PARSE_NODE_TYPE_LEN: + + // + // One child. + // + + PARSE_traverse_do(pn->child1, user_function); + + user_function(pn); + + break; + + case PARSE_NODE_TYPE_EQUALS: + case PARSE_NODE_TYPE_PLUS: + case PARSE_NODE_TYPE_MINUS: + case PARSE_NODE_TYPE_TIMES: + case PARSE_NODE_TYPE_DIVIDE: + case PARSE_NODE_TYPE_GT: + case PARSE_NODE_TYPE_LT: + case PARSE_NODE_TYPE_GTEQ: + case PARSE_NODE_TYPE_LTEQ: + case PARSE_NODE_TYPE_AND: + case PARSE_NODE_TYPE_OR: + case PARSE_NODE_TYPE_XOR: + case PARSE_NODE_TYPE_DOT: + case PARSE_NODE_TYPE_MOD: + case PARSE_NODE_TYPE_EXP_LIST: + case PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS: + case PARSE_NODE_TYPE_PUSH_ARRAY_VALUE: + case PARSE_NODE_TYPE_STATEMENT_LIST: + case PARSE_NODE_TYPE_NOTEQUAL: + case PARSE_NODE_TYPE_SWAP: + case PARSE_NODE_TYPE_ATAN2: + + // + // Two children. + // + + PARSE_traverse_do(pn->child1, user_function); + PARSE_traverse_do(pn->child2, user_function); + + user_function(pn); + + break; + + case PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS: + case PARSE_NODE_TYPE_PUSH_FIELD_VALUE: + + // + // Two children- strange order of traversal! + // + + PARSE_traverse_do(pn->child1, user_function); + user_function(pn); + PARSE_traverse_do(pn->child2, user_function); + + break; + + case PARSE_NODE_TYPE_IF: + + { + // + // Special case order of traversal including + // putting in fake nodes to help out the CG module! + // + + PARSE_Node fake_then; + PARSE_Node fake_else; + PARSE_Node fake_end_else; + + memset(&fake_then, 0, sizeof(fake_then )); + memset(&fake_else, 0, sizeof(fake_else )); + memset(&fake_end_else, 0, sizeof(fake_end_else)); + + pn->ifcode = PARSE_ifcode; + + fake_then.type = PARSE_NODE_TYPE_FAKE_THEN; + fake_then.ifcode = PARSE_ifcode; + + fake_else.type = PARSE_NODE_TYPE_FAKE_ELSE; + fake_else.ifcode = PARSE_ifcode; + + fake_end_else.type = PARSE_NODE_TYPE_FAKE_END_ELSE; + fake_end_else.ifcode = PARSE_ifcode; + + PARSE_ifcode += 1; + + PARSE_traverse_do(pn->child1, user_function); // Condition + user_function(pn); // IF node ... + + PARSE_traverse_do(pn->child2, user_function); // 'THEN' statement + user_function(&fake_then); // The fake THEN node. + + if (pn->child3) + { + // + // This IF statement has an ELSE. + // + + user_function(&fake_else); // The fake ELSE node. + PARSE_traverse_do(pn->child3, user_function); // 'ELSE' statement + user_function(&fake_end_else); // The fake END_ELSE node. + } + } + + break; + + case PARSE_NODE_TYPE_ASSIGN: + case PARSE_NODE_TYPE_KEY_ASSIGN: + + // + // Special case order of traversal. + // + + PARSE_traverse_do(pn->child2, user_function); + PARSE_traverse_do(pn->child1, user_function); + + user_function(pn); + + break; + + case PARSE_NODE_TYPE_FOR: + + { + PARSE_Node fake_end_for; + PARSE_Node fake_for_cond; + + memset(&fake_end_for, 0, sizeof(fake_end_for )); + memset(&fake_for_cond, 0, sizeof(fake_for_cond)); + + fake_end_for.type = PARSE_NODE_TYPE_FAKE_END_FOR; + fake_end_for.forcode = pn->forcode; + + fake_for_cond.type = PARSE_NODE_TYPE_FAKE_FOR_COND; + fake_for_cond.forcode = pn->forcode; + + // + // Initialisation. + // + + PARSE_traverse_do(pn->child1, user_function); + + // + // The FOR... + // + + user_function(pn); + + // + // The STEP code. + // + + PARSE_traverse_do(pn->child3, user_function); + + // + // The END_FOR code... + // + + user_function(&fake_end_for); + + // + // The condition. + // + + PARSE_traverse_do(pn->child2, user_function); + + // + // THE FOR_COND node... + // + + user_function(&fake_for_cond); + } + + break; + + case PARSE_NODE_TYPE_WHILE: + + { + // + // Build a FAKE_WHILE_COND node. + // + + PARSE_Node fake_while_cond; + + memset(&fake_while_cond, 0, sizeof(fake_while_cond)); + + fake_while_cond.type = PARSE_NODE_TYPE_FAKE_WHILE_COND; + fake_while_cond.whilecode = pn->whilecode; + + // + // Mark the beginning of the while loop. + // + + user_function(pn); + + // + // The condition. + // + + PARSE_traverse_do(pn->child1, user_function); + + // + // Mark the end of the condition. + // + + user_function(&fake_while_cond); + } + + break; + + case PARSE_NODE_TYPE_FUNCTION: + case PARSE_NODE_TYPE_ARGUMENT: + case PARSE_NODE_TYPE_LOCAL: + + user_function(pn); + + if (pn->child1) + { + PARSE_traverse_do(pn->child1, user_function); + } + + break; + + case PARSE_NODE_TYPE_CALL: + case PARSE_NODE_TYPE_TEXTURE: + case PARSE_NODE_TYPE_BUFFER: + case PARSE_NODE_TYPE_DRAW: + case PARSE_NODE_TYPE_CLS: + case PARSE_NODE_TYPE_RETURN: + case PARSE_NODE_TYPE_MATRIX: + case PARSE_NODE_TYPE_VECTOR: + + // + // Possibly one child. + // + + if (pn->child1) + { + PARSE_traverse_do(pn->child1, user_function); + } + + user_function(pn); + + break; + + case PARSE_NODE_TYPE_LEFT: + case PARSE_NODE_TYPE_RIGHT: + + // + // One or two kids... + // + + PARSE_traverse_do(pn->child1, user_function); + + if (pn->child2) + { + PARSE_traverse_do(pn->child2, user_function); + } + + user_function(pn); + + break; + + case PARSE_NODE_TYPE_MID: + + // + // Two or three kids... + // + + PARSE_traverse_do(pn->child1, user_function); + PARSE_traverse_do(pn->child2, user_function); + + if (pn->child3) + { + PARSE_traverse_do(pn->child3, user_function); + } + + user_function(pn); + + break; + + default: + ASSERT(0); + break; + } + + return; +} + + +void PARSE_traverse(PARSE_Node *pn, SLONG (*user_function)(PARSE_Node *pn)) +{ + // + // Store stack info... + // + + PARSE_traverse_do(pn, user_function); +} diff --git a/MuckyBasic/parse.h b/MuckyBasic/parse.h new file mode 100644 index 0000000..d9fb034 --- /dev/null +++ b/MuckyBasic/parse.h @@ -0,0 +1,196 @@ +// +// A recursive descent parser. +// + +#ifndef _PARSE_ +#define _PARSE_ + + + +// +// Each line produces a node. A node is a tree structure. +// + +#define PARSE_NODE_TYPE_NOP 0 // For a blank line +#define PARSE_NODE_TYPE_EQUALS 1 +#define PARSE_NODE_TYPE_PLUS 2 +#define PARSE_NODE_TYPE_MINUS 3 +#define PARSE_NODE_TYPE_UMINUS 4 // Unary minus +#define PARSE_NODE_TYPE_TIMES 5 +#define PARSE_NODE_TYPE_DIVIDE 6 +#define PARSE_NODE_TYPE_SLUMBER 7 +#define PARSE_NODE_TYPE_FLUMBER 8 +#define PARSE_NODE_TYPE_STRING 9 +#define PARSE_NODE_TYPE_VAR_VALUE 10 +#define PARSE_NODE_TYPE_IF 11 +#define PARSE_NODE_TYPE_GOTO 12 +#define PARSE_NODE_TYPE_LABEL 13 // Child1 is the rest of the statement for the line +#define PARSE_NODE_TYPE_GT 14 +#define PARSE_NODE_TYPE_LT 15 +#define PARSE_NODE_TYPE_GTEQ 16 +#define PARSE_NODE_TYPE_LTEQ 17 +#define PARSE_NODE_TYPE_AND 18 +#define PARSE_NODE_TYPE_OR 19 +#define PARSE_NODE_TYPE_NOT 20 +#define PARSE_NODE_TYPE_DOT 21 // A fullstop that isn't part of a number +#define PARSE_NODE_TYPE_CALL 22 +#define PARSE_NODE_TYPE_LOCAL 23 // Child1 may point to another local node... +#define PARSE_NODE_TYPE_PRINT 24 +#define PARSE_NODE_TYPE_ASSIGN 25 // Equals := , assignment... +#define PARSE_NODE_TYPE_VAR_ADDRESS 26 +#define PARSE_NODE_TYPE_MOD 27 +#define PARSE_NODE_TYPE_BOOLEAN 28 +#define PARSE_NODE_TYPE_SQRT 29 +#define PARSE_NODE_TYPE_NEWLINE 30 // A PRINT without anything else... +#define PARSE_NODE_TYPE_ABS 31 +#define PARSE_NODE_TYPE_PUSH_FIELD_ADDRESS 32 +#define PARSE_NODE_TYPE_FIELD 33 +#define PARSE_NODE_TYPE_PUSH_FIELD_VALUE 34 +#define PARSE_NODE_TYPE_EXP_LIST 35 +#define PARSE_NODE_TYPE_PUSH_ARRAY_ADDRESS 36 +#define PARSE_NODE_TYPE_PUSH_ARRAY_VALUE 37 +#define PARSE_NODE_TYPE_INPUT 38 +#define PARSE_NODE_TYPE_UNDEFINED 39 // The constant value +#define PARSE_NODE_TYPE_STATEMENT_LIST 40 +#define PARSE_NODE_TYPE_EXIT 41 +#define PARSE_NODE_TYPE_RETURN 42 +#define PARSE_NODE_TYPE_GOSUB 43 +#define PARSE_NODE_TYPE_XOR 44 +#define PARSE_NODE_TYPE_FOR 45 +#define PARSE_NODE_TYPE_NEXT 46 +#define PARSE_NODE_TYPE_NOTEQUAL 47 +#define PARSE_NODE_TYPE_RANDOM 48 +#define PARSE_NODE_TYPE_SWAP 49 +#define PARSE_NODE_TYPE_MIF 50 // A multi-line IF +#define PARSE_NODE_TYPE_MELSE 51 // The ELSE of a multi-line IF +#define PARSE_NODE_TYPE_MENDIF 52 // THE ENDIF of a multi-line IF +#define PARSE_NODE_TYPE_WHILE 53 +#define PARSE_NODE_TYPE_LOOP 54 +#define PARSE_NODE_TYPE_FUNCTION 55 +#define PARSE_NODE_TYPE_ARGUMENT 56 +#define PARSE_NODE_TYPE_ENDFUNC 57 +#define PARSE_NODE_TYPE_TEXTURE 58 +#define PARSE_NODE_TYPE_BUFFER 59 +#define PARSE_NODE_TYPE_DRAW 60 +#define PARSE_NODE_TYPE_CLS 61 +#define PARSE_NODE_TYPE_FLIP 62 +#define PARSE_NODE_TYPE_KEY_ASSIGN 63 +#define PARSE_NODE_TYPE_KEY_VALUE 64 +#define PARSE_NODE_TYPE_INKEY_ASSIGN 65 +#define PARSE_NODE_TYPE_INKEY_VALUE 66 +#define PARSE_NODE_TYPE_TIMER 67 +#define PARSE_NODE_TYPE_SIN 68 +#define PARSE_NODE_TYPE_COS 69 +#define PARSE_NODE_TYPE_TAN 70 +#define PARSE_NODE_TYPE_ASIN 71 +#define PARSE_NODE_TYPE_ACOS 72 +#define PARSE_NODE_TYPE_ATAN 73 +#define PARSE_NODE_TYPE_ATAN2 74 +#define PARSE_NODE_TYPE_EXPORT 75 +#define PARSE_NODE_TYPE_LEFT 76 +#define PARSE_NODE_TYPE_MID 77 +#define PARSE_NODE_TYPE_RIGHT 78 +#define PARSE_NODE_TYPE_LEN 79 +#define PARSE_NODE_TYPE_MATRIX 80 // Child1 is an expression list or NULL +#define PARSE_NODE_TYPE_VECTOR 81 // Child1 is an expression list or NULL +#define PARSE_NODE_TYPE_DPROD 82 +#define PARSE_NODE_TYPE_CPROD 83 +#define PARSE_NODE_TYPE_NORMALISE 84 +#define PARSE_NODE_TYPE_TRANSPOSE 85 + + + +#define PARSE_NODE_FLAG_EXTRACT (1 << 0) // If this node is the 'child1' of a PUSH_ARRAY_VALUE, PUSH_FIELD_VALUE, PUSH_ARRAY_ADDRESS or PUSH_FIELD_ADDRESS node. +#define PARSE_NODE_FLAG_CONDITIONAL (1 << 1) // This node is in the THEN or ELSE part of an IF statement. +#define PARSE_NODE_FLAG_EXPRESSION (1 << 2) // This node is part of an expression. + +typedef struct parse_node PARSE_Node; + +typedef struct parse_node +{ + UWORD type; + UWORD flag; + + union + { + SLONG slumber; + float flumber; + CBYTE *string; + CBYTE *label; + CBYTE *variable; + SLONG boolean; + CBYTE *field; // A string whose first character is '.' to indicate this is a field. + SLONG dimensions; // For a PUSHARRAYADDRESS or PUSHARRAYVALUE node, this gives the number of dimensions + PARSE_Node *lvalue; // A FOR node has the lvalue by which it is recognised in here. + CBYTE character; // For a CHAR_CONST + }; + + union + { + SLONG forcode; // A unique, non-zero, random code that pairs up FOR parse nodes with corresponding FAKE_ENDFOR nodes. + SLONG ifcode; // IF nodes have a unique, non-zero random code. This code is used by the 'pretend' node types in PARSE_traverse()... + SLONG whilecode; // Unique, non-zero and random. Matched up while nodes with corresponding FAKE_WHILE_COND nodes. + SLONG args; // The number of arguments in a PARSE_NODE_TYPE_CALL node (depth of child1) or the number of initialisers to a MATRIX or VECTOR + }; + + struct parse_node *child1; + struct parse_node *child2; + struct parse_node *child3; + +} PARSE_Node; + + + +// +// Returns an array of PARSE_Nodes that describes the program. +// It also returns a string table that contains all the strings +// and labels used in the program. Errors/warnings/status are +// returned in the PARSE_output variable. +// + +extern PARSE_Node *PARSE_line[]; // NULL value means that line was blank. +extern SLONG PARSE_line_upto; +extern SLONG PARSE_string_table_upto; +extern CBYTE PARSE_string_table[]; +extern CBYTE *PARSE_error[]; +extern SLONG PARSE_error_upto; + +void PARSE_do(CBYTE *fname); + + + + +// +// Traverses the given parse tree and called the user_function on +// each node of the tree. It traverses through the tree in a +// cunning order- to help out the CG module. It also inserts +// the pretend nodes... +// + +#define PARSE_NODE_TYPE_FAKE_THEN 10000 +#define PARSE_NODE_TYPE_FAKE_ELSE 10001 +#define PARSE_NODE_TYPE_FAKE_END_ELSE 10002 +#define PARSE_NODE_TYPE_FAKE_END_FOR 10003 +#define PARSE_NODE_TYPE_FAKE_FOR_COND 10004 +#define PARSE_NODE_TYPE_FAKE_WHILE_COND 10005 + +// That have their 'ifcode' field set to the IF instruction +// that they correspond to. The function should return FALSE +// to abort. +// + +void PARSE_traverse(PARSE_Node *pn, SLONG (*user_function)(PARSE_Node *pn)); + + + + +// +// Returns TRUE if the two PARSE trees are the same. +// + +SLONG PARSE_trees_the_same(PARSE_Node *tree1, PARSE_Node *tree2); + + + + +#endif diff --git a/MuckyBasic/resource.h b/MuckyBasic/resource.h new file mode 100644 index 0000000..2467cd4 --- /dev/null +++ b/MuckyBasic/resource.h @@ -0,0 +1,85 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by muckyBASIC.rc +// +#define IDD_DRIVERS 101 +#define IDI_ICON1 103 +#define IDR_MAIN_MENU 106 +#define IDR_POPUPS 110 +#define IDC_COMBO1 1000 +#define IDC_COMBO_DRIVER 1000 +#define IDC_COMBO2 1001 +#define IDC_COMBO_MODE 1001 +#define IDC_BUTTON1 1002 +#define IDC_MINFRAMERATE 1006 +#define IDC_CONSTRES 1018 +#define IDC_PROCESSOR 1022 +#define IDC_RUN_DRIVING_GAME 1030 +#define IDC_RUN_MY_GAME 1031 +#define IDC_RUN_MIKES_GAME 1032 +#define IDC_RUN_LIQUID_METAL 1033 +#define IDC_RUN_ANIMATION_TEST 1034 +#define IDC_RUN_TOON_TEST 1064 +#define IDC_RUN_EGG_PHYSICS 1065 +#define IDC_RUN_PATCH_TEST 1066 +#define ID_MODE_BRUSH 40003 +#define ID_BRUSH_TREE 40005 +#define ID_MODE_SELECT 40009 +#define ID_CAMERA_FOLLOWCAR 40010 +#define ID_CAMERA_LOCKEDAROUNDPOINT 40011 +#define ID_CAMERA_RESET 40013 +#define ID_BRUSH_GRASS 40014 +#define ID_BRUSH_OB 40015 +#define ID_FILE_RESET 40016 +#define ID_FILE_OPENMAP 40017 +#define ID_FILE_SAVEMAP 40018 +#define ID_FILE_SAVEMAPAS 40019 +#define ID_FILE_LOADTRACKMESH 40020 +#define ID_BRUSH_CAR 40024 +#define ID_EDIT_DELETE 40027 +#define ID_CAMERA_1STPERSON 40028 +#define ID_CAMERA_DIFFERENTCAR 40030 +#define ID_DRAW_TRACK 40031 +#define ID_DRAW_OBS 40032 +#define ID_DRAW_LINES 40033 +#define ID_DRAW_CARS 40034 +#define ID_CAR_MOVETO_POLEPOSITION 40044 +#define ID_CAR_MOVETO_2NDPLACE 40046 +#define ID_CAR_MOVETO_3RDPLACE 40047 +#define ID_CAR_MOVETO_4THPLACE 40048 +#define ID_CAR_MOVETO_5THPLACE 40049 +#define ID_CAR_MOVETO_6THPLACE 40050 +#define ID_SPLINE_STARTINGLINE 40051 +#define ID_SPLINE_TRACKSEGMENT_1 40053 +#define ID_SPLINE_TRACKSEGMENT_2 40054 +#define ID_SPLINE_TRACKSEGMENT_3 40055 +#define ID_SPLINE_TRACKSEGMENT_4 40056 +#define ID_SPLINE_TRACKSEGMENT_5 40057 +#define ID_SPLINE_TRACKSEGMENT_6 40058 +#define ID_SPLINE_TRACKSEGMENT_7 40059 +#define ID_SPLINE_TRACKSEGMENT_8 40060 +#define ID_SPLINE_TRACKSEGMENT_9 40061 +#define ID_SPLINE_TRACKSEGMENT_10 40062 +#define ID_SPLINE_TRACKSEGMENT_11 40063 +#define ID_SPLINE_TRACKSEGMENT_12 40064 +#define ID_SPLINE_TRACKSEGMENT_13 40065 +#define ID_SPLINE_TRACKSEGMENT_14 40066 +#define ID_SPLINE_TRACKSEGMENT_15 40067 +#define ID_SPLINE_TRACKSEGMENT_16 40068 +#define ID_CAR_DEF_POLEPOSITION 40069 +#define ID_CAR_DEF_2NDPLACE 40070 +#define ID_CAR_DEF_3RDPLACE 40071 +#define ID_CAR_DEF_4THPLACE 40072 +#define ID_CAR_DEF_5THPLACE 40073 +#define ID_CAR_DEF_6THPLACE 40074 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 112 +#define _APS_NEXT_COMMAND_VALUE 40075 +#define _APS_NEXT_CONTROL_VALUE 1066 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/MuckyBasic/st.cpp b/MuckyBasic/st.cpp new file mode 100644 index 0000000..8a5e6b5 --- /dev/null +++ b/MuckyBasic/st.cpp @@ -0,0 +1,400 @@ +// +// A symbol table. +// + +#include "always.h" +#include "st.h" + + + + +// +// A symbol. +// + +typedef struct +{ + ULONG hash; + SLONG value; + SLONG flag; + UWORD string; // Offset into the buffer + UWORD next; + +} ST_Symbol; + + +// +// A symbol table. +// + +typedef struct +{ + // + // Where we store strings. + // + + CBYTE *buffer; + SLONG buffer_upto; + SLONG buffer_max; + + // + // Where we store symbols. + // + + ST_Symbol *symbol; + SLONG symbol_upto; + SLONG symbol_max; + + // + // A hash table. Each entry is the start of a linked list. + // + + #define ST_HASH_SIZE 512 + + UWORD hash[ST_HASH_SIZE]; + +} ST_Table; + +ST_Table ST_table[ST_TABLE_NUMBER]; + + + +// +// Computes the hash value of a string. +// + +ULONG ST_hash_value(CBYTE *string) +{ + ULONG ans = 0; + SLONG rot = 0; + + CBYTE *ch; + + for (ch = string; *ch; ch++) + { + ans ^= _lrotl(*ch, rot); + + rot += 7; + } + + ans ^= ans >> 16; // So more letters count... + + return ans; +} + +void ST_init() +{ + SLONG i; + + ST_Table *st; + + // + // Clear all data. + // + + memset(ST_table, 0, sizeof(ST_table)); + + // + // Initialise each table. + // + + for (i = 0; i < ST_TABLE_NUMBER; i++) + { + st = &ST_table[i]; + + st->buffer_max = 8192; + st->buffer_upto = 0; + st->buffer = (CBYTE *) malloc(sizeof(CBYTE) * st->buffer_max); + + st->symbol_max = 1024; + st->symbol_upto = 1; // The 0th element is the NULL index... + st->symbol = (ST_Symbol *) malloc(sizeof(ST_Symbol) * st->symbol_max); + } +} + + + +void ST_add(SLONG table, CBYTE *string, SLONG value, SLONG flag) +{ + ST_Table *st; + ST_Symbol *ss; + + SLONG symbol; + + ASSERT(WITHIN(table, 0, ST_TABLE_NUMBER - 1)); + + st = &ST_table[table]; + + // + // Compute the hash value. + // + + ULONG hash = ST_hash_value(string); + + #ifdef _DEBUG + + // + // Do we already have this symbol? + // + + #endif + + // + // Get a new symbol. Is there enough room? + // + + if (st->symbol_upto >= st->symbol_max) + { + st->symbol_max *= 2; + st->symbol = (ST_Symbol *) realloc(st->symbol, sizeof(ST_Symbol) * st->symbol_max); + } + + // + // The index of our new symbol. + // + + symbol = st->symbol_upto++; + + // + // Initialise the symbol. + // + + ss = &st->symbol[symbol]; + + ss->hash = hash; + ss->value = value; + ss->flag = flag; + ss->string = (UWORD) st->buffer_upto; + ss->next = NULL; + + // + // Enough room to add the string? + // + + SLONG length = strlen(string) + 1; // + 1 to include the terminating NULL. + + if (st->buffer_upto + length > st->buffer_max) + { + // + // Must allocate a bigger string buffer. + // + + st->buffer_max *= 2; + st->buffer = (CBYTE *) realloc(st->buffer, sizeof(CBYTE) * st->buffer_max); + } + + // + // Add the string to the buffer. + // + + strcpy(st->buffer + st->buffer_upto, string); + + st->buffer_upto += length; + + // + // Insert the symbol into the hash table. + // + + ss->next = st->hash[ss->hash & (ST_HASH_SIZE - 1)]; + st->hash[ss->hash & (ST_HASH_SIZE - 1)] = (UWORD) symbol; +} + + + +// +// Looks for the string in the given table. Returns TRUE if it +// finds one. Sets the ST_found_table and ST_found_value variables +// if it finds the string. +// + +SLONG ST_found_table; +SLONG ST_found_value; +SLONG ST_found_flag; +CBYTE *ST_found_string; +ST_Symbol *ST_found_ss; + +SLONG ST_find_in_table(SLONG table, CBYTE *string) +{ + ST_Table *st; + ST_Symbol *ss; + + SLONG symbol; + + ASSERT(WITHIN(table, 0, ST_TABLE_NUMBER - 1)); + + st = &ST_table[table]; + + // + // Compute the hash value. + // + + ULONG hash = ST_hash_value(string); + + for (symbol = st->hash[hash & (ST_HASH_SIZE - 1)]; symbol; symbol = ss->next) + { + ASSERT(WITHIN(symbol, 1, st->symbol_upto - 1)); + + ss = &st->symbol[symbol]; + + if (ss->hash == hash) + { + // + // This is probably our symbol. We have to check though. + // + + if (strcmp(st->buffer + ss->string, string) == 0) + { + // + // This is our symbol. + // + + ST_found_table = table; + ST_found_value = ss->value; + ST_found_flag = ss->flag; + ST_found_ss = ss; + ST_found_string = string; + + return TRUE; + } + } + } + + return FALSE; +} + + + + +SLONG ST_find(CBYTE *string) +{ + SLONG table; + + // + // Look in the tables. + // + + for (table = ST_TABLE_NUMBER - 1; table >= 0; table--) + { + if (ST_find_in_table( + table, + string)) + { + return TRUE; + } + } + + return FALSE; +} + + +void ST_update_flag(CBYTE *string, SLONG new_flag) +{ + SLONG table; + + // + // Look in the tables. + // + + for (table = ST_TABLE_NUMBER - 1; table >= 0; table--) + { + if (ST_find_in_table( + table, + string)) + { + ST_found_ss->flag = new_flag; + + return; + } + } + + // + // Symbol not found! + // + + ASSERT(0); + + return; +} + + + +SLONG ST_find_all_table; +SLONG ST_find_all_symbol; + + +void ST_find_all_start() +{ + ST_find_all_table = 0; + ST_find_all_symbol = 1; +} + +SLONG ST_find_all_next() +{ + ST_Table *st; + ST_Symbol *ss; + + while(1) + { + ASSERT(WITHIN(ST_find_all_table, 0, ST_TABLE_NUMBER - 1)); + + st = &ST_table[ST_find_all_table]; + + if (ST_find_all_symbol >= st->symbol_upto) + { + ST_find_all_table += 1; + ST_find_all_symbol = 1; + + if (ST_find_all_table >= ST_TABLE_NUMBER) + { + return FALSE; + } + } + else + { + ASSERT(WITHIN(ST_find_all_symbol, 0, st->symbol_upto - 1)); + + ss = &st->symbol[ST_find_all_symbol++]; + + ASSERT(WITHIN(ss->string, 0, st->buffer_upto - 2)); + + ST_found_string = &st->buffer[ss->string]; + ST_found_table = ST_find_all_table; + ST_found_value = ss->value; + ST_found_flag = ss->flag; + + return TRUE; + } + } +} + + + +void ST_clear(SLONG table) +{ + ST_Table *st; + + ASSERT(WITHIN(table, 0, ST_TABLE_NUMBER - 1)); + + st = &ST_table[table]; + + // + // Zero length the arrays and clear the hash table. + // + + st->symbol_upto = 1; // 1 because the 0'th index is reserved for NULL. + st->buffer_upto = 0; + + memset(st->hash, 0, sizeof(st->hash)); +} + + +void ST_clear_all() +{ + SLONG i; + + for (i = 0; i < ST_TABLE_NUMBER; i++) + { + ST_clear(i); + } +} + diff --git a/MuckyBasic/st.h b/MuckyBasic/st.h new file mode 100644 index 0000000..fbbde1a --- /dev/null +++ b/MuckyBasic/st.h @@ -0,0 +1,85 @@ +// +// A symbol table. +// + +#ifndef _ST_ +#define _ST_ + + +// +// There is a stack of symbol tables. The bottom one contains +// system defined variables and doesn't change. The next one +// contains variables from the libraries that you the program +// uses. The one above that contains globals and all the others +// above that are for function definitions. +// + +#define ST_TABLE_SYSTEM 0 +#define ST_TABLE_LIBRARY 1 +#define ST_TABLE_GLOBAL 2 +#define ST_TABLE_LOCAL 3 +#define ST_TABLE_NUMBER 4 // The number of symbol tables in the stack. + + +// +// Initialises all the symbol tables. Call once at the start +// of the whole program. +// + +void ST_init(void); + + + +// +// Adds a symbol value pair to the given symbol table. +// +// DONT ADD THE SAME SYMBOL TWICE TO THE SAME TABLE! +// + +void ST_add(SLONG table, CBYTE *string, SLONG value, SLONG flag); + + +// +// Finds the symbol. It checks the CALL,LOCAL,GLOBAL,LIBRRARY,SYSTEM +// symbol tables in that order. Returns TRUE if it found the symbol. +// + +extern SLONG ST_found_table; // The table the symbol was in. +extern SLONG ST_found_value; // The value associated with that symbol. +extern SLONG ST_found_flag; +extern CBYTE *ST_found_string; + +SLONG ST_find(CBYTE *string); + + +// +// Changes the flag variable associated with the given string. +// It is an error if the symbol is not found. +// + +void ST_update_flag(CBYTE *string, SLONG new_flag); + + + +// +// Finds everything in the symbol tables. Call ST_find_all_start(), +// then every call to ST_find_all_next() that returns TRUE fills in +// the ST_found_* variables. When a call to ST_find_all_next() returns +// FALSE there is nothing left to find. +// + +void ST_find_all_start(void); +SLONG ST_find_all_next (void); + + + +// +// Clears all the symbols tables or a particular one. +// + +void ST_clear (SLONG table); +void ST_clear_all(void); + + + +#endif diff --git a/MuckyBasic/sysvar.cpp b/MuckyBasic/sysvar.cpp new file mode 100644 index 0000000..90ff74b --- /dev/null +++ b/MuckyBasic/sysvar.cpp @@ -0,0 +1,37 @@ +// +// System variables. +// + +#include "always.h" +#include "mem.h" +#include "ml.h" +#include "st.h" +#include "sysvar.h" +#include "vm.h" + +// +// The names of the system fields. +// + +CBYTE *SYSVAR_field[SYSVAR_FIELD_NUMBER] = +{ + ".x", + ".y", + ".z", + ".rhw", + ".colour", + ".specular", + ".u", + ".v" +}; + +void SYSVAR_init() +{ + SLONG i; + + for (i = 0; i < SYSVAR_FIELD_NUMBER; i++) + { + ST_add(ST_TABLE_SYSTEM, SYSVAR_field[i], i, 0); + } +} + diff --git a/MuckyBasic/sysvar.h b/MuckyBasic/sysvar.h new file mode 100644 index 0000000..35ff93e --- /dev/null +++ b/MuckyBasic/sysvar.h @@ -0,0 +1,33 @@ +// +// System variables. +// + +#ifndef _SYSVAR_ +#define _SYSVAR_ + + +// +// The fields that are used by the system and therefore constants. +// + +#define SYSVAR_FIELD_X 0 +#define SYSVAR_FIELD_Y 1 +#define SYSVAR_FIELD_Z 2 +#define SYSVAR_FIELD_RHW 3 +#define SYSVAR_FIELD_COLOUR 4 +#define SYSVAR_FIELD_SPECULAR 5 +#define SYSVAR_FIELD_U 6 +#define SYSVAR_FIELD_V 7 +#define SYSVAR_FIELD_NUMBER 8 + + +// +// Adds all the system variables to the SYSTEM symbol table. +// Call this function after calling ST_init() +// + +void SYSVAR_init(void); + + + +#endif diff --git a/MuckyBasic/test.mbs b/MuckyBasic/test.mbs new file mode 100644 index 0000000..39c186f --- /dev/null +++ b/MuckyBasic/test.mbs @@ -0,0 +1,23 @@ +// +// TODO next is the get . working for MATRIXes and VECTORs +// There are already ML_TYPE_* for floats and vectors... +// +// +// +// +// +// + + + right = VECTOR(1,0,0) + up = VECTOR(0,1,0) + forwards = VECTOR(0,0,1) + + direction = MATRIX(right,up,forwards) + + + pos = right * 2 + + PRINT pos.x + + diff --git a/MuckyBasic/test2.mbs b/MuckyBasic/test2.mbs new file mode 100644 index 0000000..8d1bab0 --- /dev/null +++ b/MuckyBasic/test2.mbs @@ -0,0 +1,32 @@ + + LOCAL x + + + FUNCTION isprime(n) + + LOCAL i,j + + FOR i = 2 TO SQRT(n) + IF n MOD i = 0 THEN RETURN FALSE + NEXT i + + j = 55 + + RETURN TRUE + + ENDFUNC + + + i = 100 + + PRINT "i = " + i + PRINT "j = " + j + + + PRINT "127 is prime ? " + isprime(127) + + PRINT "i = " + i + PRINT "j = " + j + + + PRINT "x = " + x \ No newline at end of file diff --git a/MuckyBasic/userdlg.cpp b/MuckyBasic/userdlg.cpp new file mode 100644 index 0000000..307b242 --- /dev/null +++ b/MuckyBasic/userdlg.cpp @@ -0,0 +1,384 @@ +//----------------------------------------------------------------------------- +// File: UserDlg.cpp +// +// Desc: Support functions for the user select driver dialog. + +// Note: Since this code is destined for a static link library, the +// dialog dox is constructed manually. Otherwise, we would use a resource +// and save many lines of code. Manually constructing dialog boxes is not +// trivial and there are many issues (unicode, dword alignment, etc.) +// involved. +// +// +// Copyright (c) 1997-1998 Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- + +#define STRICT +#include +#include "D3DEnum.h" +#include +#include "d3dutil.h" + + + +//----------------------------------------------------------------------------- +// Constants and function prototypes for the user select driver dialog +//----------------------------------------------------------------------------- +#define IDC_STATIC 0xffff +#define IDC_DRIVER_COMBO 1000 +#define IDC_DEVICE_COMBO 1001 +#define IDC_MODE_COMBO 1002 + + + + +//----------------------------------------------------------------------------- +// External variables (declared in the D3DEnum.cpp file) +//----------------------------------------------------------------------------- +extern D3DEnum_DriverInfo* g_pCurrentDriver; // The selected DD driver + + + + +//----------------------------------------------------------------------------- +// Name: CopyToWideChar +//----------------------------------------------------------------------------- +static VOID CopyToWideChar( WCHAR** pstrOut, LPTSTR strIn ) +{ + DWORD dwLen = lstrlen( strIn ); + WCHAR* strOut = *pstrOut; + +#ifdef UNICODE // Copy Unicode to Unicode + _wcsncpy( strOut, strIn, dwLen ); + strOut[dwLen] = L'\0'; +#else // Copy Ansi to Unicode + dwLen = MultiByteToWideChar( CP_ACP, 0, strIn, dwLen, strOut, dwLen ); + strOut[dwLen++] = L'\0'; // Add the null terminator +#endif + *pstrOut += dwLen; +} + + + + +//----------------------------------------------------------------------------- +// Name: AddDialogControl() +// Desc: Internal function to help build the user select dialog +//----------------------------------------------------------------------------- +static VOID AddDialogControl( WORD** pp, DWORD dwStyle, SHORT x, SHORT y, + SHORT cx, SHORT cy, WORD id, + LPTSTR strClassName, LPTSTR strTitle ) +{ + // DWORD align the current ptr + DLGITEMTEMPLATE* p = (DLGITEMTEMPLATE*)(((((ULONG)(*pp))+3)>>2)<<2); + + p->style = dwStyle | WS_CHILD | WS_VISIBLE; + p->dwExtendedStyle = 0L; + p->x = x; + p->y = y; + p->cx = cx; + p->cy = cy; + p->id = id; + + *pp = (WORD*)(++p); // Advance ptr + + CopyToWideChar( (WCHAR**)pp, strClassName ); // Set Class name + CopyToWideChar( (WCHAR**)pp, strTitle ); // Set Title + + (*pp)++; // Skip Extra Stuff +} + + + + +//----------------------------------------------------------------------------- +// Name: _BuildUserSelectDialog() +// Desc: Internal function to build the user select dialog +//----------------------------------------------------------------------------- +DLGTEMPLATE* _BuildDriverSelectTemplate() +{ + // Allocate ample memory for building the template + DLGTEMPLATE* pDlgTemplate = new DLGTEMPLATE[50]; + if( NULL == pDlgTemplate ) + return NULL; + ZeroMemory( pDlgTemplate, 50*sizeof(DLGTEMPLATE) ); + + // Fill in the DLGTEMPLATE info + DLGTEMPLATE* pdt = pDlgTemplate; + pdt->style = DS_MODALFRAME | DS_NOIDLEMSG | DS_SETFOREGROUND | + DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU | DS_SETFONT; + pdt->dwExtendedStyle = 0L; + pdt->cdit = 8; + pdt->x = 0; + pdt->y = 0; + pdt->cx = 179; + pdt->cy = 84; + + // Add menu array, class array, dlg title, font size and font name + WORD* pw = (WORD*)(++pdt); + *pw++ = L'\0'; // Set Menu array to nothing + *pw++ = L'\0'; // Set Class array to nothing + CopyToWideChar( (WCHAR**)&pw, TEXT( "Select New Direct3D Driver" ) ); // Dlg title + *pw++ = 8; // Font Size + CopyToWideChar( (WCHAR**)&pw, TEXT("Arial") ); // Font Name + + // Add the okay button + AddDialogControl( &pw, BS_PUSHBUTTON | WS_TABSTOP, 65, 65, 51, 14, + IDOK, TEXT("BUTTON"), TEXT("OK") ); + + // Add the cancel button + AddDialogControl( &pw, BS_PUSHBUTTON | WS_TABSTOP, 123, 65, 51, 14, + IDCANCEL, TEXT("BUTTON"), TEXT("Cancel") ); + + // Add the driver select combobox + AddDialogControl( &pw, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP, + 36, 5, 138, 45, + IDC_DRIVER_COMBO, TEXT("COMBOBOX"), TEXT("") ); + + // Add the device select combobox + AddDialogControl( &pw, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP, + 36, 24, 138, 45, + IDC_DEVICE_COMBO, TEXT("COMBOBOX"), TEXT("") ); + + // Add the mode select combobox + AddDialogControl( &pw, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP, + 36, 44, 138, 45, + IDC_MODE_COMBO, TEXT("COMBOBOX"), TEXT("") ); + + // Add the "Driver:" text + AddDialogControl( &pw, SS_LEFT, 5, 5, 22, 13, + IDC_STATIC, TEXT("STATIC"), TEXT("Driver:") ); + + // Add the "Device:" text + AddDialogControl( &pw, SS_LEFT, 5, 24, 25, 13, + IDC_STATIC, TEXT("STATIC"), TEXT("Device:") ); + + // Add the "Mode:" text + AddDialogControl( &pw, SS_LEFT, 5, 44, 22, 13, + IDC_STATIC, TEXT("STATIC"), TEXT("Mode:") ); + + return pDlgTemplate; +} + + + + +//----------------------------------------------------------------------------- +// Name: UpdateComboBoxesContent() +// Desc: Builds the list of drivers, devices and modes for the combo boxes +// in the driver select dialog box. +//----------------------------------------------------------------------------- +static VOID UpdateComboBoxesContent( HWND hDlg, + D3DEnum_DriverInfo** ppCurrentDriver, + D3DEnum_DeviceInfo** ppCurrentDevice, + D3DEnum_ModeInfo** ppCurrentMode, + BOOL bWindowed ) +{ + // Check the parameters + if( (NULL==ppCurrentDriver) || (NULL==ppCurrentDevice) || + (NULL==ppCurrentMode) ) + return; + + // If the specified driver is NULL, use the first one in the list + if( NULL == *ppCurrentDriver) + (*ppCurrentDriver) = D3DEnum_GetFirstDriver(); + + // If the specified device is NULL, use the first one in the list + if( NULL == *ppCurrentDevice) + (*ppCurrentDevice) = (*ppCurrentDriver)->pFirstDevice; + + // Reset the content in each of the combo boxes + SendDlgItemMessage( hDlg, IDC_DRIVER_COMBO, CB_RESETCONTENT, 0, 0 ); + SendDlgItemMessage( hDlg, IDC_DEVICE_COMBO, CB_RESETCONTENT, 0, 0 ); + SendDlgItemMessage( hDlg, IDC_MODE_COMBO, CB_RESETCONTENT, 0, 0 ); + + // Build the list of drivers for the combo box + for( D3DEnum_DriverInfo* pDriver = D3DEnum_GetFirstDriver(); pDriver; + pDriver = pDriver->pNext ) + { + // Add driver desc to the combo box + DWORD dwItem = SendDlgItemMessage( hDlg, IDC_DRIVER_COMBO, + CB_ADDSTRING, 0, (LPARAM)pDriver->strDesc ); + + // Associate DriverInfo ptr with the item in the combo box + SendDlgItemMessage( hDlg, IDC_DRIVER_COMBO, CB_SETITEMDATA, + (WPARAM)dwItem, (LPARAM)pDriver ); + + // If this is the current driver, set is as the current selection + if( pDriver == (*ppCurrentDriver) ) + SendDlgItemMessage( hDlg, IDC_DRIVER_COMBO, CB_SETCURSEL, + (WPARAM)dwItem, 0L ); + } + + // Build the list of devices for the combo box + for( D3DEnum_DeviceInfo* pDevice = (*ppCurrentDriver)->pFirstDevice; pDevice; + pDevice = pDevice->pNext ) + { + // Add device name to the combo box + DWORD dwItem = SendDlgItemMessage( hDlg, IDC_DEVICE_COMBO, + CB_ADDSTRING, 0, (LPARAM)pDevice->strName ); + + // Associate DeviceInfo ptr with the item in the combo box + SendDlgItemMessage( hDlg, IDC_DEVICE_COMBO, CB_SETITEMDATA, + (WPARAM)dwItem, (LPARAM)pDevice ); + + // If this is the current device, set this as the current selection + if( pDevice == (*ppCurrentDevice) ) + SendDlgItemMessage( hDlg, IDC_DEVICE_COMBO, CB_SETCURSEL, + (WPARAM)dwItem, 0L ); + } + + if( (*ppCurrentDriver)->ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED + && ( NULL == (*ppCurrentDriver)->pGUID ) + && (*ppCurrentDevice)->bCompatbileWithDesktop ) + { + // Add windowed mode to the combo box of available modes + DWORD dwItem = SendDlgItemMessage( hDlg, IDC_MODE_COMBO, + CB_ADDSTRING, 0, (LPARAM)TEXT("Windowed mode") ); + + // Associate ModeInfo ptr with the item in the combo box + SendDlgItemMessage( hDlg, IDC_MODE_COMBO, CB_SETITEMDATA, + (WPARAM)dwItem, (LPARAM)NULL ); + + // If the current device is windowed, set this as current + if( bWindowed ) + SendDlgItemMessage( hDlg, IDC_MODE_COMBO, CB_SETCURSEL, + (WPARAM)dwItem, 0L ); + } + + // Build the list of modes for the combo box + for( D3DEnum_ModeInfo* pMode = (*ppCurrentDevice)->pFirstMode; pMode; + pMode = pMode->pNext ) + { + // Add mode desc to the combo box + DWORD dwItem = SendDlgItemMessage( hDlg, IDC_MODE_COMBO, + CB_ADDSTRING, 0, + (LPARAM)pMode->strDesc ); + + // Associate ModeInfo ptr with the item in the combo box + SendDlgItemMessage( hDlg, IDC_MODE_COMBO, CB_SETITEMDATA, + (WPARAM)dwItem, (LPARAM)pMode ); + + // If this is the current mode, set is as the current selection + if( !bWindowed && ( pMode == (*ppCurrentMode) ) ) + SendDlgItemMessage( hDlg, IDC_MODE_COMBO, CB_SETCURSEL, + (WPARAM)dwItem, 0L ); + } +} + + + + +//----------------------------------------------------------------------------- +// Name: _DriverSelectProc() +// Desc: Windows message handling function for the driver select dialog +//----------------------------------------------------------------------------- +BOOL CALLBACK _DriverSelectProc( HWND hDlg, UINT uiMsg, WPARAM wParam, + LPARAM lParam ) +{ + static D3DEnum_DriverInfo *pOldDriver, *pNewDriver; + static D3DEnum_DeviceInfo *pOldDevice, *pNewDevice; + static D3DEnum_ModeInfo *pOldMode, *pNewMode; + static BOOL bOldWindowed, bNewWindowed; + + // Handle the initialization message + if( WM_INITDIALOG == uiMsg ) + { + // Setup temp storage pointers for dialog + pNewDriver = pOldDriver = g_pCurrentDriver; + pNewDevice = pOldDevice = pOldDriver->pCurrentDevice; + pNewMode = pOldMode = pOldDevice->pCurrentMode; + bNewWindowed = bOldWindowed = pOldDevice->bWindowed; + + UpdateComboBoxesContent( hDlg, &pOldDriver, &pOldDevice, + &pOldMode, bOldWindowed ); + return TRUE; + } + + if( WM_COMMAND == uiMsg ) + { + // Handle the case when the user hits the OK button + if( IDOK == LOWORD(wParam) ) + { + // Check if any of the options were changed + if( ( pOldDriver != pNewDriver ) || ( pOldDevice != pNewDevice ) || + ( pOldMode != pNewMode ) || ( bOldWindowed != bNewWindowed ) ) + { + // Set actual ptrs from the temp ptrs used for the dialog + g_pCurrentDriver = pNewDriver; + g_pCurrentDriver->pCurrentDevice = pNewDevice; + g_pCurrentDriver->pCurrentDevice->pCurrentMode = pNewMode; + g_pCurrentDriver->pCurrentDevice->bWindowed = bNewWindowed; + + EndDialog( hDlg, IDOK ); + return TRUE; + } + else + { + EndDialog( hDlg, IDCANCEL ); + return TRUE; + } + } + + // Handle the case when the user hits the Cancel button + else if( IDCANCEL == LOWORD(wParam) ) + { + EndDialog( hDlg, IDCANCEL ); + return TRUE; + } + + // Handle the case when the user chooses an item in the combo boxes. + else if( CBN_SELENDOK == HIWORD(wParam) ) + { + DWORD dwIndex = SendMessage( (HWND)lParam, CB_GETCURSEL, + 0, 0 ); + LONG pNewObject = SendMessage( (HWND)lParam, CB_GETITEMDATA, + dwIndex, 0 ); + + if( (CB_ERR==dwIndex) ) + return TRUE; + + // Handle the case where one of these may have changed. The + // combo boxes will need to be updated to reflect the changes. + switch( LOWORD( wParam ) ) + { + case IDC_DRIVER_COMBO: + if( pNewObject && pNewObject != (LONG)pNewDriver ) + { + pNewDriver = (D3DEnum_DriverInfo*)pNewObject; + pNewDevice = pNewDriver->pCurrentDevice;; + pNewMode = pNewDevice->pCurrentMode; + bNewWindowed = pNewDevice->bWindowed; + } + break; + case IDC_DEVICE_COMBO: + if( pNewObject && pNewObject != (LONG)pNewDevice ) + { + pNewDevice = (D3DEnum_DeviceInfo*)pNewObject; + pNewMode = pNewDevice->pCurrentMode; + bNewWindowed = pNewDevice->bWindowed; + } + break; + case IDC_MODE_COMBO: + if( pNewObject ) + { + pNewMode = (D3DEnum_ModeInfo*)pNewObject; + bNewWindowed = FALSE; + } + else + bNewWindowed = TRUE; + break; + } + + UpdateComboBoxesContent( hDlg, &pNewDriver, &pNewDevice, + &pNewMode, bNewWindowed ); + + return TRUE; + } + } + return FALSE; +} + + + diff --git a/MuckyBasic/vm.cpp b/MuckyBasic/vm.cpp new file mode 100644 index 0000000..4662582 --- /dev/null +++ b/MuckyBasic/vm.cpp @@ -0,0 +1,4435 @@ +// +// The virtual machine to run our basic programs. +// + +#include "always.h" +#include "console.h" +#include "key.h" +#include "mem.h" +#include "ml.h" +#include "sysvar.h" + + + +// +// Instruction memory. +// + +SLONG *VM_code; +SLONG VM_code_max; +SLONG VM_code_upto; +SLONG *VM_code_pointer; // The instruction we are executing... + + + +// +// The stack. +// + +ML_Data *VM_stack; +SLONG VM_stack_max; +ML_Data *VM_stack_top; // The top of the stack +ML_Data *VM_stack_base; // The current stack frame + + +// +// The globals. +// + +ML_Data *VM_global; +SLONG VM_global_max; + + +// +// The static data table. +// + +UBYTE *VM_data; +SLONG VM_data_max; + + + + +// +// Extra globals we add onto the end of the program. +// + +#define VM_EXTRA_GLOBAL_KEY(key) (VM_global_extra + (key)) +#define VM_EXTRA_GLOBAL_INKEY (VM_global_extra + 256) +#define VM_EXTRA_GLOBAL_NUMBER 257 + +SLONG VM_global_extra; // The index of the first extra global. + + + +// +// OS_ticks() the last time we did a flip. +// + +SLONG VM_flip_tick; + + +// +// Checks for sufficient stack space to push on another +// item of data. +// + +#define VM_CHECK_STACK_PUSH() {ASSERT(WITHIN(VM_stack_top, VM_stack, VM_stack + VM_stack_max - 1));} + +// +// Pops two items off the stack (just decreases the stack pointer!) +// + +#define VM_POP_STACK(n) {VM_stack_top -= (n); ASSERT(WITHIN(VM_stack_top, VM_stack, VM_stack + VM_stack_max - 1));} + + + + + + +// +// Frees memory used by the given bit of data. +// + +void VM_data_free(ML_Data md) +{ + SLONG i; + + switch(md.type) + { + case ML_TYPE_STRVAR: + MEM_free(md.strvar); + break; + + case ML_TYPE_STRUCTURE: + + // + // Free all the fields. + // + + for (i = 0; i < md.structure->num_fields; i++) + { + VM_data_free(md.structure->field[i].data); + } + + // + // Now free the structure. + // + + MEM_free(md.structure); + + break; + + case ML_TYPE_ARRAY: + + // + // Free all the elements of the array. + // + + for (i = 0; i < md.array->length; i++) + { + VM_data_free(md.array->data[i]); + } + + MEM_free(md.array->data); + + // + // Now free the array. + // + + MEM_free(md.array); + + break; + + case ML_TYPE_TEXTURE: + + md.lt->ref_count -= 1; + + if (md.lt->ref_count == 0) + { + // + // Free the texture. + // + + LL_free_texture(md.lt); + } + + break; + + + case ML_TYPE_BUFFER: + + md.lb->ref_count -= 1; + + if (md.lb->ref_count == 0) + { + // + // Free the buffer. + // + + LL_free_buffer(md.lb); + } + + break; + + case ML_TYPE_MATRIX: + MEM_free(md.matrix); + break; + + case ML_TYPE_VECTOR: + MEM_free(md.vector); + break; + + default: + break; + } +} + + +// +// Creates a copy of the given bit of data. +// + +ML_Data VM_data_copy(ML_Data original) +{ + ML_Data ans; + + switch(original.type) + { + // + // Types that need extra allocation. + // + + case ML_TYPE_STRVAR: + + { + SLONG length = MEM_block_size(original.strvar); + + ans.type = ML_TYPE_STRVAR; + ans.strvar = (CBYTE *) MEM_alloc(length); + + memcpy(ans.strvar, original.strvar, length); + } + + return ans; + + case ML_TYPE_STRUCTURE: + + { + // + // Create another copy of the structure. + // + + SLONG length = sizeof(ML_Structure) + original.structure->num_fields * sizeof(ML_Field); + + ans.type = ML_TYPE_STRUCTURE; + ans.structure = (ML_Structure *) MEM_alloc(length); + + SLONG i; + + ans.structure->num_fields = original.structure->num_fields; + + for (i = 0; i < ans.structure->num_fields; i++) + { + ans.structure->field[i].field_id = original.structure->field[i].field_id; + ans.structure->field[i].data = VM_data_copy(original.structure->field[i].data); + } + } + + return ans; + + case ML_TYPE_ARRAY: + + { + // + // Create another copy of the array. + // + + SLONG length = sizeof(ML_Array) + original.array->num_dimensions * sizeof(ML_Dimension); + + ans.type = ML_TYPE_ARRAY; + ans.array = (ML_Array *) MEM_alloc(length); + + ans.array->data = (ML_Data *) MEM_alloc(sizeof(ML_Data) * original.array->length); + ans.array->length = original.array->length; + ans.array->num_dimensions = original.array->num_dimensions; + + SLONG i; + + for (i = 0; i < original.array->num_dimensions; i++) + { + ans.array->dimension[i] = original.array->dimension[i]; + } + + for (i = 0; i < original.array->length; i++) + { + ans.array->data[i] = VM_data_copy(original.array->data[i]); + } + } + + return ans; + + case ML_TYPE_TEXTURE: + + // + // Increase the reference count of the texture. + // + + original.lt->ref_count += 1; + + return original; + + case ML_TYPE_BUFFER: + + // + // Increase the reference count of the buffer. + // + + original.lb->ref_count += 1; + + return original; + + case ML_TYPE_POINTER: + + // + // Push on the derefenced value. + // + + return VM_data_copy(*original.data); + + case ML_TYPE_MATRIX: + + ans.type = ML_TYPE_MATRIX; + ans.matrix = (ML_Matrix *) MEM_alloc(sizeof(ML_Matrix)); + *(ans.matrix) = *original.matrix; + + return ans; + + case ML_TYPE_VECTOR: + + ans.type = ML_TYPE_VECTOR; + ans.vector = (ML_Vector *) MEM_alloc(sizeof(ML_Vector)); + *(ans.vector) = *original.vector; + + return ans; + + // + // Simple types. + // + + default: + return original; + } +} + + + + + +// +// Convert the given bit of data to a string. If the input is a +// string variable or string constant then the original is returned, +// not a copy. +// + +void VM_convert_to_string(ML_Data *original) +{ + ML_Data ans; + + ans.type = ML_TYPE_STRVAR; + + switch(original->type) + { + case ML_TYPE_UNDEFINED: + ans.strvar = (CBYTE *) MEM_alloc(16); // Enough to hold the string "" + memcpy(ans.strvar, "", 12); + break; + + case ML_TYPE_SLUMBER: + ans.strvar = (CBYTE *) MEM_alloc(16); // Enough to hold the number -2 ^ 32 and a NULL. + sprintf(ans.strvar, "%d", original->slumber); + break; + + case ML_TYPE_FLUMBER: + ans.strvar = (CBYTE *) MEM_alloc(32); // Enough to hold the number -2 ^ 32 and a NULL. + sprintf(ans.strvar, "%f", original->flumber); + break; + + case ML_TYPE_STRCONST: + case ML_TYPE_STRVAR: + + // + // Should we be calling this function? + // + + return; + + case ML_TYPE_BOOLEAN: + + ans.strvar = (CBYTE *) MEM_alloc(6); // Enough to hold the string "TRUE" or "FALSE" + + if (original->boolean) + { + memcpy(ans.strvar, "TRUE", 5); + } + else + { + memcpy(ans.strvar, "FALSE", 6); + } + + break; + + default: + ASSERT(0); + break; + } + + *original = ans; + + return; +} + +// +// Returns the string held by the given string variable. +// + +CBYTE *VM_get_string(ML_Data string) +{ + switch(string.type) + { + case ML_TYPE_STRCONST: + ASSERT(WITHIN(string.strconst, 0, VM_data_max - 2)); + return (CBYTE *) (VM_data + string.strconst); + + case ML_TYPE_STRVAR: + return string.strvar; + + default: + ASSERT(0); + return NULL; + } +} + + +// +// Makes VM_stack_top[0] and VM_stack_top[1] have the same type. +// VM_stack_top[0] must be a FLUMBER or a SLUMBER. +// + +void VM_convert_stack_top_to_same_numerical_type() +{ + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: + + if (VM_stack_top[1].type == ML_TYPE_FLUMBER) + { + // + // Convert first argument to a float. + // + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = float(VM_stack_top[0].slumber); + } + + break; + + case ML_TYPE_FLUMBER: + + if (VM_stack_top[1].type == ML_TYPE_SLUMBER) + { + // + // Convert second argument to a float. + // + + VM_stack_top[1].type = ML_TYPE_FLUMBER; + VM_stack_top[1].flumber = float(VM_stack_top[1].slumber); + } + + break; + + default: + ASSERT(0); + break; + } +} + + + +// +// Makes sure the array is big enough to for the indices +// given in the md[] array (an array of SLUMBERs) +// + +void VM_grow_array(ML_Array *ma, ML_Data *md) +{ + SLONG i; + SLONG j; + SLONG bigger_index; + SLONG bigger_length; + + #define VM_MAX_DIMENSIONS 64 + + ASSERT(WITHIN(ma->num_dimensions, 1, VM_MAX_DIMENSIONS)); + + SLONG bigger_size [VM_MAX_DIMENSIONS]; + SLONG bigger_stride[VM_MAX_DIMENSIONS]; + SLONG index [VM_MAX_DIMENSIONS]; + + // + // Build the array of the new sizes of each dimension. + // + + for (i = 0; i < ma->num_dimensions; i++) + { + if (md[i].slumber > ma->dimension[i].size) + { + // + // Double the dimension of the array. + // + + bigger_size[i] = ma->dimension[i].size * 2; + + if (md[i].slumber > bigger_size[i]) + { + // + // Doubling wasn't good enough! Make it as big as need be. + // + + bigger_size[i] = md[i].slumber; + } + } + else + { + bigger_size[i] = ma->dimension[i].size; + } + } + + // + // The new stride in each dimension. + // + + for (i = 0; i < ma->num_dimensions; i++) + { + bigger_stride[i] = 1; + + for (j = i + 1; j < ma->num_dimensions; j++) + { + bigger_stride[i] *= bigger_size[j]; + } + } + + // + // How long is the new array? + // + + bigger_length = bigger_size[0]; + + for (i = 1; i < ma->num_dimensions; i++) + { + bigger_length *= bigger_size[1]; + } + + // + // Allocate a new area of memory. + // + + ML_Data *bigger_data = (ML_Data *) MEM_alloc(sizeof(ML_Data) * bigger_length); + + if (ma->num_dimensions == 1) + { + // + // Easy to copy over data... + // + + memcpy(bigger_data, ma->data, sizeof(ML_Data) * ma->length); + memset(bigger_data + ma->length, 0, sizeof(ML_Data) * (bigger_length - ma->length)); + } + else + { + // + // Nightmare to copy over data. Initialise new memory to + // + + memset(bigger_data, 0, sizeof(ML_Data) * bigger_length); + + // + // Clear the index array. + // + + for (i = 0; i < ma->num_dimensions; i++) + { + index[i] = 0; + } + + // + // Copy over all old data in a horribly inefficient manner. + // + + for (i = 0; i < ma->length; i++) + { + // + // What's the new index of this element? + // + + bigger_index = 0; + + for (j = 0; j < ma->num_dimensions; j++) + { + bigger_index += bigger_stride[j] * index[j]; + } + + // + // Copy over this element. + // + + bigger_data[bigger_index] = ma->data[i]; + + // + // Update our indices... + // + + for (j = ma->num_dimensions - 1; j >= 1; j--) + { + index[j] += 1; + + if (index[j] >= ma->dimension[j].size) + { + // + // Roll-over. + // + + index[j ] = 0; + index[j - 1] += 1; + } + } + } + } + + // + // Free old memory. + // + + MEM_free(ma->data); + + ma->data = bigger_data; + ma->length = bigger_length; + + for (i = 0; i < ma->num_dimensions; i++) + { + ma->dimension[i].size = bigger_size[i]; + ma->dimension[i].stride = bigger_stride[i]; + } +} + + +// +// Complicated instructions that needn't be fast +// get their own function. +// + + +void VM_do_texture() +{ + VM_POP_STACK(2); + + // + // We don't support USER textures now, so the + // first argument must be the filename and the + // second should be UNDEFINED. + // + + if (VM_stack_top[0].type != ML_TYPE_STRCONST && + VM_stack_top[0].type != ML_TYPE_STRVAR) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[1].type != ML_TYPE_UNDEFINED) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Create the texture. + // + + ML_Data texture; + + texture.type = ML_TYPE_TEXTURE; + texture.lt = LL_create_texture(VM_get_string(VM_stack_top[0])); + + // + // Free the arguments. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + + VM_stack_top[0] = texture; + + VM_stack_top += 1; +} + +void VM_do_buffer() +{ + SLONG i; + SLONG j; + SLONG num_verts; + SLONG num_indices; + ULONG found; + SLONG slumber; + float flumber; + + ML_Data *vert_array; + ML_Structure *vert_struct; + ML_Field *field; + ML_Data *index_array; + LL_Tlvert *tl; + UWORD *index; + + VM_POP_STACK(4); + + // + // The first argument should be an 1d array of structures! + // + + if (VM_stack_top[0].type != ML_TYPE_ARRAY) + { + // + // ERROR! + // + + ASSERT(0); + } + else + if (VM_stack_top[0].array->num_dimensions != 1) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // The next argument should be the number of vertices. + // + + if (VM_stack_top[1].type == ML_TYPE_SLUMBER) + { + num_verts = VM_stack_top[1].slumber; + } + else + if (VM_stack_top[1].type == ML_TYPE_FLUMBER) + { + float integer; + float fraction; + + fraction = modff(VM_stack_top[1].flumber, &integer); + + if (fraction != 0.0F) + { + // + // ERROR! A fractional number of verts? + // + + ASSERT(0); + } + + num_verts = ftol(integer); + } + + // + // The next two arguments are optional depending on whether + // this is a triangle list or an indexed list. + // + + if (VM_stack_top[3].type == ML_TYPE_UNDEFINED) + { + // + // Ok... just means no indices. + // + + num_indices = 0; + } + else + if (VM_stack_top[3].type == ML_TYPE_SLUMBER) + { + num_indices = VM_stack_top[3].slumber; + } + else + if (VM_stack_top[3].type == ML_TYPE_FLUMBER) + { + float integer; + float fraction; + + fraction = modff(VM_stack_top[1].flumber, &integer); + + if (fraction != 0.0F) + { + // + // ERROR! Oh dear! A fractional number of indices! + // + + ASSERT(0); + } + + num_indices = ftol(integer); + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[2].type == ML_TYPE_ARRAY) + { + // + // Should be an 1d array of numbers. + // + + if (VM_stack_top[2].array->num_dimensions != 1) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (num_indices == 0 || num_indices % 3 != 0) + { + // + // ERROR! + // + + ASSERT(0); + } + } + else + if (VM_stack_top[2].type == ML_TYPE_UNDEFINED) + { + // + // Can't have indices without an array. + // + + if (num_indices != 0) + { + // + // ERROR! + // + + ASSERT(0); + } + } + + // + // Is our vert array big enough? + // + + if (num_verts > VM_stack_top[0].array->length) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Create the vert buffer. + // + + tl = (LL_Tlvert *) MEM_alloc(num_verts * sizeof(LL_Tlvert)); + + vert_array = VM_stack_top[0].array->data; + + for (i = 0; i < num_verts; i++) + { + if (vert_array[i].type != ML_TYPE_STRUCTURE) + { + // + // ERROR! + // + + ASSERT(0); + } + + vert_struct = vert_array[i].structure; + + // + // Extract the various components of the LL_Tlvert. + // + + found = 0; + + for (j = 0; j < vert_struct->num_fields; j++) + { + field = &vert_struct->field[j]; + + if (field->field_id < SYSVAR_FIELD_NUMBER) + { + // + // This is a system field so it could be part of our + // Tlvert structure. Type check the data if it is. + // + + switch(field->field_id) + { + case SYSVAR_FIELD_X: + case SYSVAR_FIELD_Y: + case SYSVAR_FIELD_U: + case SYSVAR_FIELD_V: + + // + // Must be numbers. + // + + if (field->data.type == ML_TYPE_SLUMBER) + { + flumber = float(field->data.slumber); + } + else + if (field->data.type == ML_TYPE_FLUMBER) + { + flumber = field->data.flumber; + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + break; + + + case SYSVAR_FIELD_Z: + case SYSVAR_FIELD_RHW: + + // + // Must be floating point numbers between 0 and 1. + // + + if (field->data.type == ML_TYPE_SLUMBER) + { + flumber = float(field->data.slumber); + } + else + if (field->data.type == ML_TYPE_FLUMBER) + { + flumber = field->data.flumber; + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + if (!WITHIN(flumber, 0.0F, 1.0F)) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (field->field_id == SYSVAR_FIELD_RHW) + { + // + // If RHW is too small it fucks up... in general! + // + + if (flumber < 1.0F / 1024.0F) + { + flumber = 1.0F / 1024.0F; + } + } + + break; + + case SYSVAR_FIELD_COLOUR: + case SYSVAR_FIELD_SPECULAR: + + // + // Must be numbers... or maybe string colours?! + // + + if (field->data.type == ML_TYPE_SLUMBER) + { + slumber = field->data.slumber; + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + break; + + default: + + // + // Not a field we are interested in. + // + + continue; + } + + // + // This is one of our fields. + // + + found |= 1 << field->field_id; + + switch(field->field_id) + { + case SYSVAR_FIELD_X: tl[i].x = flumber; break; + case SYSVAR_FIELD_Y: tl[i].y = flumber; break; + case SYSVAR_FIELD_Z: tl[i].z = flumber; break; + case SYSVAR_FIELD_RHW: tl[i].x = flumber; break; + case SYSVAR_FIELD_U: tl[i].u = flumber; break; + case SYSVAR_FIELD_V: tl[i].v = flumber; break; + case SYSVAR_FIELD_COLOUR: tl[i].colour = slumber; break; + case SYSVAR_FIELD_SPECULAR: tl[i].specular = slumber; break; + + default: + ASSERT(0); + break; + } + } + } + + // + // Fill in missing fields with default values. + // + + if (!(found & (1 << SYSVAR_FIELD_Z ))) {tl[i].z = 0.0F; found |= 1 << SYSVAR_FIELD_Z; } + if (!(found & (1 << SYSVAR_FIELD_RHW ))) {tl[i].rhw = 0.5F; found |= 1 << SYSVAR_FIELD_RHW; } + if (!(found & (1 << SYSVAR_FIELD_U ))) {tl[i].u = 0.0F; found |= 1 << SYSVAR_FIELD_U; } + if (!(found & (1 << SYSVAR_FIELD_V ))) {tl[i].v = 0.0F; found |= 1 << SYSVAR_FIELD_V; } + if (!(found & (1 << SYSVAR_FIELD_COLOUR ))) {tl[i].colour = 0xffffffff; found |= 1 << SYSVAR_FIELD_COLOUR; } + if (!(found & (1 << SYSVAR_FIELD_SPECULAR))) {tl[i].specular = 0xff000000; found |= 1 << SYSVAR_FIELD_SPECULAR;} + + // + // Make sure we have initialised every member. + // + + const SLONG found_every_tlvert_field = + (1 << SYSVAR_FIELD_X ) | + (1 << SYSVAR_FIELD_Y ) | + (1 << SYSVAR_FIELD_Z ) | + (1 << SYSVAR_FIELD_RHW ) | + (1 << SYSVAR_FIELD_U ) | + (1 << SYSVAR_FIELD_V ) | + (1 << SYSVAR_FIELD_COLOUR ) | + (1 << SYSVAR_FIELD_SPECULAR); + + if (found != found_every_tlvert_field) + { + // + // ERROR! + // + + ASSERT(0); + } + } + + // + // Now create the index buffer. + // + + if (num_indices == 0) + { + index = NULL; + } + else + { + // + // Is our index array big enough? + // + + if (num_indices > VM_stack_top[2].array->length) + { + // + // ERROR! + // + + ASSERT(0); + } + + index = (UWORD *) MEM_alloc(num_indices * sizeof(UWORD)); + index_array = VM_stack_top[2].array->data; + + for (i = 0; i < num_indices; i++) + { + if (index_array[i].type == ML_TYPE_SLUMBER) + { + slumber = index_array[i].slumber; + } + else + if (index_array[i].type == ML_TYPE_FLUMBER) + { + float integer; + float fraction; + + fraction = modff(index_array[i].flumber, &integer); + + if (fraction != 0.0F) + { + // + // ERROR! Oh dear! A fractional number of indices! + // + + ASSERT(0); + } + + slumber = ftol(integer); + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + if (!WITHIN(slumber, 1, num_verts)) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Convert from 1-based indexing to 0-based indexing. + // + + index[i] = slumber - 1; + } + } + + // + // Free the arguments. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + VM_data_free(VM_stack_top[2]); + VM_data_free(VM_stack_top[3]); + + VM_stack_top[0].type = ML_TYPE_BUFFER; + VM_stack_top[0].lb = LL_create_buffer( + LL_BUFFER_TYPE_TLV, + tl, + num_verts, + index, + num_indices); + + VM_stack_top += 1; +} + + +void VM_do_draw() +{ + VM_POP_STACK(3); + + LL_Buffer *lb; + LL_Texture *lt; + ULONG rs; + + // + // We should have a buffer then a texture and a renderstate. + // + + if (VM_stack_top[0].type == ML_TYPE_BUFFER) + { + lb = VM_stack_top[0].lb; + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[1].type == ML_TYPE_TEXTURE) + { + lt = VM_stack_top[1].lt; + } + else + if (VM_stack_top[1].type == ML_TYPE_UNDEFINED) + { + // + // Undefined => draw untextured. + // + + lt = NULL; + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[2].type == ML_TYPE_SLUMBER) + { + rs = VM_stack_top[2].slumber; + } + else + if (VM_stack_top[2].type == ML_TYPE_UNDEFINED) + { + // + // Default renderstate. + // + + rs = LL_RS_NORMAL; + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Do the draw! + // + + LL_draw_buffer(lb,lt,rs); + + // + // Free the arguments. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + VM_data_free(VM_stack_top[2]); +} + + +void VM_do_cls() +{ + ULONG colour; + float zsort; + + VM_POP_STACK(2); + + // + // The colour. + // + + if (VM_stack_top[0].type == ML_TYPE_SLUMBER) + { + colour = VM_stack_top[0].slumber; + } + else + if (VM_stack_top[0].type == ML_TYPE_UNDEFINED) + { + colour = 0; + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // The z-value. + // + + if (VM_stack_top[1].type == ML_TYPE_SLUMBER) + { + zsort = float(VM_stack_top[1].slumber); + } + else + if (VM_stack_top[1].type == ML_TYPE_FLUMBER) + { + zsort = VM_stack_top[1].flumber; + } + else + if (VM_stack_top[1].type == ML_TYPE_UNDEFINED) + { + zsort = 1.0F; + } + + if (!WITHIN(zsort, 0.0F, 1.0F)) + { + // + // ERROR! + // + + ASSERT(0); + } + + LL_cls(colour, zsort); +} + + + + +// +// Executes the program! +// + +void VM_execute() +{ + while(1) + { + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + + switch(*VM_code_pointer++) + { + case ML_DO_PUSH_CONSTANT: + + VM_CHECK_STACK_PUSH(); + + ASSERT(WITHIN(VM_code_pointer + 1, VM_code, VM_code + VM_code_upto - 1)); + + VM_stack_top->type = *VM_code_pointer++; + VM_stack_top->value = *VM_code_pointer++; + + VM_stack_top += 1; + + break; + + case ML_DO_ADD: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do type conversion... + // + + switch(VM_stack_top[0].type) + { + case ML_TYPE_BOOLEAN: + + if (VM_stack_top[1].type == ML_TYPE_STRVAR || + VM_stack_top[1].type == ML_TYPE_STRCONST) + { + // + // Convert first argument to a string. + // + + VM_convert_to_string(&VM_stack_top[0]); + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + break; + + case ML_TYPE_SLUMBER: + + if (VM_stack_top[1].type == ML_TYPE_FLUMBER) + { + // + // Convert first argument to a float. + // + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = float(VM_stack_top[0].slumber); + } + else + if (VM_stack_top[1].type == ML_TYPE_STRVAR || + VM_stack_top[1].type == ML_TYPE_STRCONST) + { + // + // Convert first argument to a string. + // + + VM_convert_to_string(&VM_stack_top[0]); + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + break; + + case ML_TYPE_FLUMBER: + + if (VM_stack_top[1].type == ML_TYPE_SLUMBER) + { + // + // Convert second argument to a float. + // + + VM_stack_top[1].type = ML_TYPE_FLUMBER; + VM_stack_top[1].flumber = float(VM_stack_top[1].slumber); + } + else + if (VM_stack_top[1].type == ML_TYPE_STRVAR || + VM_stack_top[1].type == ML_TYPE_STRCONST) + { + // + // Convert first argument to a string. + // + + VM_convert_to_string(&VM_stack_top[0]); + } + else + { + // + // ERROR! + // + + ASSERT(0); + } + + break; + + case ML_TYPE_STRVAR: + case ML_TYPE_STRCONST: + + // + // Converts to a string representing the data. + // + + VM_convert_to_string(&VM_stack_top[1]); + + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: + VM_stack_top[0].slumber = VM_stack_top[0].slumber + VM_stack_top[1].slumber; + break; + + case ML_TYPE_FLUMBER: + VM_stack_top[0].flumber = VM_stack_top[0].flumber + VM_stack_top[1].flumber; + break; + + case ML_TYPE_STRVAR: + case ML_TYPE_STRCONST: + + { + ML_Data result; + SLONG length; + CBYTE *str1; + CBYTE *str2; + + + // + // How long is the resulting string? + // + + str1 = VM_get_string(VM_stack_top[0]); + str2 = VM_get_string(VM_stack_top[1]); + + length = strlen(str1) + strlen(str2) + 1; // + 1 for the terminating NULL. + + // + // Build the result. + // + + result.type = ML_TYPE_STRVAR; + result.strvar = (CBYTE *) MEM_alloc(length); + + strcpy(result.strvar, str1); + strcat(result.strvar, str2); + + // + // Free memory. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + + // + // Put new data on the stack. + // + + VM_stack_top[0] = result; + } + + break; + + case ML_TYPE_VECTOR: + + VM_stack_top[0].vector->x += VM_stack_top[1].vector->x; + VM_stack_top[0].vector->y += VM_stack_top[1].vector->y; + VM_stack_top[0].vector->z += VM_stack_top[1].vector->z; + + VM_data_free(VM_stack_top[1]); + + break; + + default: + ASSERT(0); + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_PRINT: + + VM_POP_STACK(1); + + VM_convert_to_string(&VM_stack_top[0]); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_STRVAR: + + CONSOLE_print(VM_stack_top[0].strvar); + + VM_data_free(VM_stack_top[0]); + + break; + + case ML_TYPE_STRCONST: + + ASSERT(WITHIN(VM_stack_top[0].strconst, 0, VM_data_max - 2)); + + CONSOLE_print((CBYTE *) (VM_data + VM_stack_top[0].strconst)); + + break; + + default: + ASSERT(0); + break; + } + + break; + + case ML_DO_EXIT: + + // + // Free memory. + // + + { + SLONG i; + + for (i = 0; i < VM_global_max; i++) + { + VM_data_free(VM_global[i]); + } + + ASSERT(MEM_total_bytes_allocated() == 0); + } + + return; + + case ML_DO_GOTO: + + // + // Valid address? + // + + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_code_upto - 1)); + + VM_code_pointer = &VM_code[VM_code_pointer[0]]; + + break; + + case ML_DO_UMINUS: + + VM_POP_STACK(1); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: + VM_stack_top[0].slumber = -VM_stack_top[0].slumber; + break; + + case ML_TYPE_FLUMBER: + VM_stack_top[0].flumber = -VM_stack_top[0].flumber; + break; + + case ML_TYPE_VECTOR: + VM_stack_top[0].vector->x = -VM_stack_top[0].vector->x; + VM_stack_top[0].vector->y = -VM_stack_top[0].vector->y; + VM_stack_top[0].vector->z = -VM_stack_top[0].vector->z; + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_PUSH_GLOBAL_VALUE: + + VM_CHECK_STACK_PUSH(); + + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_global_max - 1)); + + // + // Push a copy of the global onto the stack. Any memory allocated + // by the original will be duplicated. + // + + *VM_stack_top++ = VM_data_copy(VM_global[*VM_code_pointer++]); + + break; + + case ML_DO_PUSH_GLOBAL_QUICK: + + VM_CHECK_STACK_PUSH(); + + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_global_max - 1)); + + // + // Push a copy of the global onto the stack - don't copy data. + // + + *VM_stack_top++ = VM_global[*VM_code_pointer++]; + + break; + + case ML_DO_MINUS: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do type conversion... + // + + VM_convert_stack_top_to_same_numerical_type(); + } + + ASSERT(VM_stack_top[0].type == VM_stack_top[1].type); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: + VM_stack_top[0].slumber = VM_stack_top[0].slumber - VM_stack_top[1].slumber; + break; + + case ML_TYPE_FLUMBER: + VM_stack_top[0].flumber = VM_stack_top[0].flumber - VM_stack_top[1].flumber; + break; + + case ML_TYPE_VECTOR: + + VM_stack_top[0].vector->x -= VM_stack_top[1].vector->x; + VM_stack_top[0].vector->y -= VM_stack_top[1].vector->y; + VM_stack_top[0].vector->z -= VM_stack_top[1].vector->z; + + VM_data_free(VM_stack_top[1]); + + break; + + default: + ASSERT(0); + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_TIMES: + + VM_POP_STACK(2); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: + + switch(VM_stack_top[1].type) + { + case ML_TYPE_SLUMBER: + VM_stack_top[0].slumber *= VM_stack_top[1].slumber; + break; + + case ML_TYPE_FLUMBER: + + // + // Answer becomes a float. + // + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = float(VM_stack_top[0].slumber) * VM_stack_top[1].flumber; + + break; + + case ML_TYPE_VECTOR: + + { + float fmul = float(VM_stack_top[0].slumber); + + VM_stack_top[0] = VM_stack_top[1]; + + VM_stack_top[0].vector->x *= fmul; + VM_stack_top[0].vector->y *= fmul; + VM_stack_top[0].vector->z *= fmul; + } + + break; + + case ML_TYPE_MATRIX: + + { + float fmul = float(VM_stack_top[0].slumber); + + VM_stack_top[0] = VM_stack_top[1]; + + VM_stack_top[0].matrix->vector[0].x *= fmul; + VM_stack_top[0].matrix->vector[0].y *= fmul; + VM_stack_top[0].matrix->vector[0].z *= fmul; + + VM_stack_top[0].matrix->vector[1].x *= fmul; + VM_stack_top[0].matrix->vector[1].y *= fmul; + VM_stack_top[0].matrix->vector[1].z *= fmul; + + VM_stack_top[0].matrix->vector[2].x *= fmul; + VM_stack_top[0].matrix->vector[2].y *= fmul; + VM_stack_top[0].matrix->vector[2].z *= fmul; + } + + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + break; + + case ML_TYPE_FLUMBER: + + switch(VM_stack_top[1].type) + { + case ML_TYPE_SLUMBER: + VM_stack_top[0].flumber *= (float) VM_stack_top[1].slumber; + break; + + case ML_TYPE_FLUMBER: + VM_stack_top[0].flumber *= VM_stack_top[1].flumber; + + break; + + case ML_TYPE_VECTOR: + + { + float fmul = VM_stack_top[0].flumber; + + VM_stack_top[0] = VM_stack_top[1]; + + VM_stack_top[0].vector->x *= fmul; + VM_stack_top[0].vector->y *= fmul; + VM_stack_top[0].vector->z *= fmul; + } + + break; + + case ML_TYPE_MATRIX: + + { + float fmul = VM_stack_top[0].flumber; + + VM_stack_top[0] = VM_stack_top[1]; + + VM_stack_top[0].matrix->vector[0].x *= fmul; + VM_stack_top[0].matrix->vector[0].y *= fmul; + VM_stack_top[0].matrix->vector[0].z *= fmul; + + VM_stack_top[0].matrix->vector[1].x *= fmul; + VM_stack_top[0].matrix->vector[1].y *= fmul; + VM_stack_top[0].matrix->vector[1].z *= fmul; + + VM_stack_top[0].matrix->vector[2].x *= fmul; + VM_stack_top[0].matrix->vector[2].y *= fmul; + VM_stack_top[0].matrix->vector[2].z *= fmul; + } + + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + break; + + case ML_TYPE_MATRIX: + + switch(VM_stack_top[1].type) + { + case ML_TYPE_MATRIX: + + // + // Matrix multiplication. + // + + { + ML_Matrix ans; + ML_Matrix *a = VM_stack_top[0].matrix; + ML_Matrix *b = VM_stack_top[1].matrix; + + ans.vector[0].x = a->vector[0].x * b->vector[0].x + a->vector[0].y * b->vector[1].x + a->vector[0].z * b->vector[2].x; + ans.vector[0].y = a->vector[0].x * b->vector[0].y + a->vector[0].y * b->vector[1].y + a->vector[0].z * b->vector[2].y; + ans.vector[0].z = a->vector[0].x * b->vector[0].z + a->vector[0].y * b->vector[1].z + a->vector[0].z * b->vector[2].z; + + ans.vector[1].x = a->vector[1].x * b->vector[0].x + a->vector[1].y * b->vector[1].x + a->vector[1].z * b->vector[2].x; + ans.vector[1].y = a->vector[1].x * b->vector[0].y + a->vector[1].y * b->vector[1].y + a->vector[1].z * b->vector[2].y; + ans.vector[1].z = a->vector[1].x * b->vector[0].z + a->vector[1].y * b->vector[1].z + a->vector[1].z * b->vector[2].z; + + ans.vector[2].x = a->vector[2].x * b->vector[0].x + a->vector[2].y * b->vector[1].x + a->vector[2].z * b->vector[2].x; + ans.vector[2].y = a->vector[2].x * b->vector[0].y + a->vector[2].y * b->vector[1].y + a->vector[2].z * b->vector[2].y; + ans.vector[2].z = a->vector[2].x * b->vector[0].z + a->vector[2].y * b->vector[1].z + a->vector[2].z * b->vector[2].z; + + *VM_stack_top[0].matrix = ans; + + // + // Don't need the second matrix any more. + // + + VM_data_free(VM_stack_top[1]); + } + + break; + + case ML_TYPE_VECTOR: + + // + // Matrix * vector. + // + + { + ML_Vector ans; + + ans.x = VM_stack_top[0].matrix->vector[0].x * VM_stack_top[1].vector->x + VM_stack_top[0].matrix->vector[0].y * VM_stack_top[1].vector->y + VM_stack_top[0].matrix->vector[0].z * VM_stack_top[1].vector->z; + ans.y = VM_stack_top[0].matrix->vector[1].x * VM_stack_top[1].vector->x + VM_stack_top[0].matrix->vector[1].y * VM_stack_top[1].vector->y + VM_stack_top[0].matrix->vector[1].z * VM_stack_top[1].vector->z; + ans.z = VM_stack_top[0].matrix->vector[2].x * VM_stack_top[1].vector->x + VM_stack_top[0].matrix->vector[2].y * VM_stack_top[1].vector->y + VM_stack_top[0].matrix->vector[2].z * VM_stack_top[1].vector->z; + + VM_data_free(VM_stack_top[0]); + + VM_stack_top[0] = VM_stack_top[1]; + VM_stack_top[0].vector->x = ans.x; + VM_stack_top[0].vector->y = ans.y; + VM_stack_top[0].vector->z = ans.z; + } + + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + break; + + case ML_TYPE_VECTOR: + + switch(VM_stack_top[1].type) + { + case ML_TYPE_SLUMBER: + + { + float fmul = float(VM_stack_top[1].slumber); + + VM_stack_top[0].vector->x *= fmul; + VM_stack_top[0].vector->y *= fmul; + VM_stack_top[0].vector->z *= fmul; + } + + break; + + case ML_TYPE_FLUMBER: + + { + float fmul = VM_stack_top[1].flumber; + + VM_stack_top[0].vector->x *= fmul; + VM_stack_top[0].vector->y *= fmul; + VM_stack_top[0].vector->z *= fmul; + } + + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_DIVIDE: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do type conversion... + // + + VM_convert_stack_top_to_same_numerical_type(); + } + + ASSERT(VM_stack_top[0].type == VM_stack_top[1].type); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: + VM_stack_top[0].slumber = VM_stack_top[0].slumber / VM_stack_top[1].slumber; + break; + + case ML_TYPE_FLUMBER: + VM_stack_top[0].flumber = VM_stack_top[0].flumber / VM_stack_top[1].flumber; + break; + + default: + ASSERT(0); + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_MOD: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do type conversion... + // + + VM_convert_stack_top_to_same_numerical_type(); + } + + ASSERT(VM_stack_top[0].type == VM_stack_top[1].type); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: + VM_stack_top[0].slumber = VM_stack_top[0].slumber % VM_stack_top[1].slumber; + break; + + case ML_TYPE_FLUMBER: + VM_stack_top[0].flumber = fmodf(VM_stack_top[0].flumber,VM_stack_top[1].flumber); + break; + + default: + ASSERT(0); + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_IF_FALSE_GOTO: + + VM_POP_STACK(1); + + if (VM_stack_top[0].type != ML_TYPE_BOOLEAN) + { + // + // ERROR! Or maybe type conversion? What if there is a string + // that says "YES", for instance? + // + + ASSERT(0); + } + + if (!VM_stack_top[0].boolean) + { + // + // Valid address? + // + + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_code_upto - 1)); + + VM_code_pointer = &VM_code[VM_code_pointer[0]]; + } + else + { + // + // Skip over the address instruction. + // + + VM_code_pointer++; + } + + break; + + case ML_DO_AND: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // ERROR! AND only works on the same values! + // + + ASSERT(0); + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_BOOLEAN: VM_stack_top[0].boolean = VM_stack_top[0].boolean && VM_stack_top[1].boolean; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top++; + + break; + + case ML_DO_OR: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // ERROR! AND only works on the same values! + // + + ASSERT(0); + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_BOOLEAN: VM_stack_top[0].boolean = VM_stack_top[0].boolean || VM_stack_top[1].boolean; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top++; + + break; + + case ML_DO_EQUALS: + case ML_DO_NOTEQUAL: + case ML_DO_JNEQ_POP_1: + + { + SLONG are_equal = FALSE; + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do some type conversion??? + // + + if ((VM_stack_top[0].type == ML_TYPE_STRVAR || VM_stack_top[0].type == ML_TYPE_STRCONST) && + (VM_stack_top[1].type == ML_TYPE_STRVAR || VM_stack_top[1].type == ML_TYPE_STRCONST)) + { + // + // Both are strings... + // + } + else + { + // + // Different types aren't equal. + // + + are_equal = FALSE; + + goto found_out_equality; + } + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_BOOLEAN: are_equal = VM_stack_top[0].boolean == VM_stack_top[1].boolean; break; + case ML_TYPE_SLUMBER: are_equal = VM_stack_top[0].slumber == VM_stack_top[1].slumber; break; + case ML_TYPE_FLUMBER: are_equal = VM_stack_top[0].flumber == VM_stack_top[1].flumber; break; + + case ML_TYPE_STRCONST: + case ML_TYPE_STRVAR: + + { + if (strcmp( + VM_get_string(VM_stack_top[0]), + VM_get_string(VM_stack_top[1])) == 0) + { + are_equal = TRUE; + } + else + { + are_equal = FALSE; + } + } + + break; + + case ML_TYPE_UNDEFINED: + are_equal = TRUE; + break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + found_out_equality:; + + switch(VM_code_pointer[-1]) + { + case ML_DO_NOTEQUAL: + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + + VM_stack_top[0].type = ML_TYPE_BOOLEAN; + VM_stack_top[0].boolean = !are_equal; + + VM_stack_top++; + + break; + + case ML_DO_JNEQ_POP_1: + + if (VM_stack_top[0].boolean) + { + // + // Pop both values. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + + // + // Step over the jump address. + // + + VM_code_pointer += 1; + } + else + { + // + // Pop just one value and jump. + // + + VM_data_free(VM_stack_top[1]); + + VM_stack_top++; + + // + // Valid address? + // + + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_code_upto - 1)); + + VM_code_pointer = &VM_code[VM_code_pointer[0]]; + } + + break; + + case ML_DO_EQUALS: + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + + VM_stack_top[0].type = ML_TYPE_BOOLEAN; + VM_stack_top[0].boolean = are_equal; + + VM_stack_top++; + + break; + + default: + ASSERT(0); + break; + } + } + + break; + + case ML_DO_GT: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do some type conversion. + // + + VM_convert_stack_top_to_same_numerical_type(); + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].slumber > VM_stack_top[1].slumber; break; + case ML_TYPE_FLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].flumber > VM_stack_top[1].flumber; break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top[0].type = ML_TYPE_BOOLEAN; + VM_stack_top++; + + break; + + case ML_DO_LT: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do some type conversion. + // + + VM_convert_stack_top_to_same_numerical_type(); + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].slumber < VM_stack_top[1].slumber; break; + case ML_TYPE_FLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].flumber < VM_stack_top[1].flumber; break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top[0].type = ML_TYPE_BOOLEAN; + VM_stack_top++; + + break; + + case ML_DO_GTEQ: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do some type conversion. + // + + VM_convert_stack_top_to_same_numerical_type(); + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].slumber >= VM_stack_top[1].slumber; break; + case ML_TYPE_FLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].flumber >= VM_stack_top[1].flumber; break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top[0].type = ML_TYPE_BOOLEAN; + VM_stack_top++; + + break; + + case ML_DO_LTEQ: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // Must do some type conversion. + // + + VM_convert_stack_top_to_same_numerical_type(); + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].slumber <= VM_stack_top[1].slumber; break; + case ML_TYPE_FLUMBER: VM_stack_top[0].boolean = VM_stack_top[0].flumber <= VM_stack_top[1].flumber; break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top[0].type = ML_TYPE_BOOLEAN; + VM_stack_top++; + + break; + + case ML_DO_NOT: + + VM_POP_STACK(1); + + switch (VM_stack_top[0].type) + { + case ML_TYPE_BOOLEAN: VM_stack_top[0].boolean = !VM_stack_top[0].boolean; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top++; + + break; + + case ML_DO_SQRT: + + VM_POP_STACK(1); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: VM_stack_top[0].slumber = (SLONG) sqrtf(float(VM_stack_top[0].slumber)); break; + case ML_TYPE_FLUMBER: VM_stack_top[0].flumber = sqrtf(float(VM_stack_top[0].flumber)); break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_NEWLINE: + CONSOLE_print(""); + break; + + case ML_DO_ABS: + + VM_POP_STACK(1); + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: VM_stack_top[0].slumber = abs (VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: VM_stack_top[0].flumber = fabsf(VM_stack_top[0].flumber); break; + + default: + + // + // ERROR! + // + + ASSERT(0); + + break; + } + + VM_stack_top += 1; + + break; + + case ML_DO_PUSH_GLOBAL_ADDRESS: + + VM_CHECK_STACK_PUSH(); + + ASSERT(WITHIN(VM_code_pointer + 1, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_global_max - 1)); + + VM_stack_top[0].type = ML_TYPE_POINTER; + VM_stack_top[0].data = &VM_global[*VM_code_pointer++]; + + VM_stack_top++; + + break; + + case ML_DO_ASSIGN: + + VM_POP_STACK(2); + + ASSERT(VM_stack_top[1].type == ML_TYPE_POINTER); + + // + // Free any memory used by the current variable. + // + + VM_data_free(*VM_stack_top[1].data); + + // + // Overwrite old value. + // + + *VM_stack_top[1].data = VM_stack_top[0]; + + break; + + case ML_DO_PUSH_FIELD_ADDRESS: + + VM_POP_STACK(1); + + ASSERT(WITHIN(VM_code_pointer + 1, VM_code, VM_code + VM_code_upto - 1)); + + if (VM_stack_top[0].type == ML_TYPE_POINTER) + { + SLONG field_id; + ML_Data *data; + + field_id = *VM_code_pointer++; + data = VM_stack_top[0].data; + + switch(data->type) + { + case ML_TYPE_STRUCTURE: + + // + // Does this variable already have this field? + // + + SLONG i; + + for (i = 0; i < data->structure->num_fields; i++) + { + if (data->structure->field[i].field_id == field_id) + { + // + // Found our field. Push the address onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_POINTER; + VM_stack_top[0].data = &data->structure->field[i].data; + + VM_stack_top++; + + break; + } + } + + // + // Must add another field. + // + + ML_Structure *ms; + + ms = (ML_Structure *) MEM_alloc(sizeof(ML_Structure) + (data->structure->num_fields + 1) * sizeof(ML_Field)); + + memcpy(ms, data->structure, sizeof(ML_Structure) + data->structure->num_fields * sizeof(ML_Field)); + + ms->field[ms->num_fields].field_id = field_id; + ms->field[ms->num_fields].data.type = ML_TYPE_UNDEFINED; + + // + // Push address onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_POINTER; + VM_stack_top[0].data = &ms->field[ms->num_fields].data; + + VM_stack_top++; + + ms->num_fields += 1; + + // + // Get rid of old memory- point to new memory. + // + + MEM_free(data->structure); + + data->structure = ms; + + break; + + case ML_TYPE_MATRIX: + + // + // Can only access fields (x,y,z) + // + + if (!WITHIN(field_id, SYSVAR_FIELD_X, SYSVAR_FIELD_Z)) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Push address onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_VOINTER; + VM_stack_top[0].vector = &data->matrix->vector[field_id]; + + VM_stack_top++; + + break; + + case ML_TYPE_VECTOR: + + // + // Can only access fields (x,y,z) + // + + if (!WITHIN(field_id, SYSVAR_FIELD_X, SYSVAR_FIELD_Z)) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Push address onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_FLOINTER; + VM_stack_top[0].flointer = &(&data->vector->x)[field_id]; + + VM_stack_top++; + + break; + + default: + + // + // Create a struture with just one field marked as undefined. + // + + VM_data_free(*data); + + data->type = ML_TYPE_STRUCTURE; + data->structure = (ML_Structure *) MEM_alloc(sizeof(ML_Structure) + sizeof(ML_Field) * 1); + data->structure->num_fields = 1; + data->structure->field[0].field_id = field_id; + data->structure->field[0].data.type = ML_TYPE_UNDEFINED; + + // + // Push the address of this field onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_POINTER; + VM_stack_top[0].data = &data->structure->field[0].data; + + VM_stack_top++; + + break; + } + } + else + if (VM_stack_top[0].type == ML_TYPE_VOINTER) + { + SLONG field_id; + ML_Data *data; + + field_id = *VM_code_pointer++; + + // + // Can only access fields (x,y,z) + // + + if (!WITHIN(field_id, SYSVAR_FIELD_X, SYSVAR_FIELD_Z)) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Push address onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_FLOINTER; + VM_stack_top[0].flointer = &(&VM_stack_top[0].vector->x)[field_id]; + + VM_stack_top++; + } + else + if (VM_stack_top[0].type == ML_TYPE_FLOINTER) + { + // + // ERROR! + // + + ASSERT(0); + } + else + { + // + // ERROR! This is an internal error - not a real error. + // + + ASSERT(0); + } + + break; + + case ML_DO_PUSH_FIELD_VALUE: + case ML_DO_PUSH_FIELD_QUICK: + + VM_POP_STACK(1); + + ASSERT(WITHIN(VM_code_pointer + 1, VM_code, VM_code + VM_code_upto - 1)); + + { + SLONG field_id; + + field_id = *VM_code_pointer++; + + // + // Is this variable already a structure? + // + + if (VM_stack_top[0].type != ML_TYPE_STRUCTURE) + { + if (VM_stack_top[0].type == ML_TYPE_MATRIX) + { + if (WITHIN(field_id, SYSVAR_FIELD_X, SYSVAR_FIELD_Z)) + { + ML_Data ans; + + if (VM_code_pointer[-2] == ML_DO_PUSH_FIELD_QUICK) + { + // + // Point to the same data as the matrix. + // + + ans.type = ML_TYPE_VECTOR; + ans.vector = &VM_stack_top[0].matrix->vector[field_id]; + } + else + { + // + // Copy the matrix data to create a new vector. + // + + ans.type = ML_TYPE_VECTOR; + ans.vector = (ML_Vector *) MEM_alloc(sizeof(ML_Vector)); + *(ans.vector) = VM_stack_top[0].matrix->vector[field_id]; + + VM_stack_top[0] = ans; + VM_stack_top++; + } + } + else + { + // + // No such field... push onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + + VM_stack_top++; + } + } + else + if (VM_stack_top[0].type == ML_TYPE_VECTOR) + { + if (WITHIN(field_id, SYSVAR_FIELD_X, SYSVAR_FIELD_Z)) + { + ML_Data ans; + + // + // Point to the same data as the matrix. + // + + ans.type = ML_TYPE_FLUMBER; + ans.flumber = (&VM_stack_top[0].vector->x)[field_id]; + + VM_stack_top[0] = ans; + VM_stack_top++; + } + else + { + // + // No such field... push onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + + VM_stack_top++; + } + } + else + { + // + // No such field... push onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + + VM_stack_top++; + } + } + else + { + // + // Does this variable already have this field? + // + + SLONG i; + + for (i = 0; i < VM_stack_top[0].structure->num_fields; i++) + { + if (VM_stack_top[0].structure->field[i].field_id == field_id) + { + // + // Found our field. Push a copy of the value onto the stack. + // + + if (VM_code_pointer[-2] == ML_DO_PUSH_FIELD_QUICK) + { + // + // Push on the actual data rather than a copy. + // + + VM_stack_top[0] = VM_stack_top[0].structure->field[i].data; + } + else + { + // + // Push on a copy of the data. + // + + VM_stack_top[0] = VM_data_copy(VM_stack_top[0].structure->field[i].data); + } + + VM_stack_top++; + + goto pushed_field_value; + } + } + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + + VM_stack_top++; + + pushed_field_value:; + } + } + + break; + + case ML_DO_PUSH_ARRAY_ADDRESS: + + { + SLONG i; + SLONG j; + SLONG array_length; + SLONG num_dimensions; + + ASSERT(WITHIN(VM_code_pointer + 1, VM_code, VM_code + VM_code_upto - 1)); + + num_dimensions = *VM_code_pointer++; + + VM_POP_STACK(num_dimensions + 1); + + // + // Make sure all the indices are given by integers! + // + + for (i = 0; i < num_dimensions; i++) + { + if (VM_stack_top[i + 1].type != ML_TYPE_SLUMBER) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[i + 1].slumber <= 0) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[i + 1].slumber >= 1024 * 1024 * 2 / 8) + { + // + // ERROR! Limit to 2meg arrays to guard against ridiculous memory usage? + // + + ASSERT(0); + } + } + + // + // Make sure we have a pointer on the stack. + // + + if (VM_stack_top[0].type != ML_TYPE_POINTER) + { + // + // ERROR! + // + + ASSERT(0); + } + + ML_Data *data = VM_stack_top[0].data; + + // + // Do we already have an array on the stack of the correct + // dimensions? + // + + if (data->type != ML_TYPE_ARRAY || data->array->num_dimensions != num_dimensions) + { + // + // Free old value. + // + + VM_data_free(*data); + + // + // How long should the array be? + // + + array_length = VM_stack_top[1].slumber; + + for (i = 1; i < num_dimensions; i++) + { + array_length *= VM_stack_top[i + 1].slumber; + } + + // + // Create the array. + // + + data->type = ML_TYPE_ARRAY; + data->array = (ML_Array *) MEM_alloc(sizeof(ML_Array) + sizeof(ML_Dimension) * num_dimensions); + data->array->length = array_length; + data->array->num_dimensions = num_dimensions; + data->array->data = (ML_Data *) MEM_alloc(sizeof(ML_Data) * array_length); + + for (i = 0; i < num_dimensions; i++) + { + data->array->dimension[i].size = VM_stack_top[i + 1].slumber; + data->array->dimension[i].stride = 1; + + for (j = i + 1; j < num_dimensions; j++) + { + data->array->dimension[i].stride *= VM_stack_top[j + 1].slumber; + } + } + + // + // Make all elements of the array undefined. + // + + memset(data->array->data, 0, sizeof(ML_Data) * array_length); + } + + // + // Should have a compatible data type by now... + // + + ASSERT(data->type == ML_TYPE_ARRAY); + ASSERT(data->array->num_dimensions == num_dimensions); + + // + // Is this array big enough? + // + + for (i = 0; i < num_dimensions; i++) + { + if (VM_stack_top[i + 1].slumber > data->array->dimension[i].size) + { + VM_grow_array(data->array, VM_stack_top + 1); + + goto grown_array; + } + } + + grown_array:; + + // + // What's this index of this element into the array? + // + + SLONG index = 0; + + for (i = 0; i < num_dimensions; i++) + { + index += data->array->dimension[i].stride * (VM_stack_top[i + 1].slumber - 1); + } + + ASSERT(WITHIN(index, 0, data->array->length - 1)); + + // + // Push the address of the element onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_POINTER; + VM_stack_top[0].data = data->array->data + index; + + VM_stack_top++; + } + + break; + + case ML_DO_PUSH_ARRAY_VALUE: + case ML_DO_PUSH_ARRAY_QUICK: + + { + SLONG i; + SLONG index; + SLONG num_dimensions; + + ASSERT(WITHIN(VM_code_pointer + 1, VM_code, VM_code + VM_code_upto - 1)); + + num_dimensions = *VM_code_pointer++; + + VM_POP_STACK(num_dimensions + 1); + + // + // Make sure all the indices are given by integers! + // + + for (i = 0; i < num_dimensions; i++) + { + if (VM_stack_top[i + 1].type != ML_TYPE_SLUMBER) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[i + 1].slumber <= 0) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[i + 1].slumber >= 1024 * 1024 * 2 / 8) + { + // + // ERROR! Limit to 2meg arrays to guard against ridiculous memory usage? + // + + ASSERT(0); + } + } + + if (VM_stack_top[0].type != ML_TYPE_ARRAY || VM_stack_top[0].array->num_dimensions != num_dimensions) + { + // + // Incompatible data type- push + // + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + + VM_stack_top++; + } + else + { + // + // Are all indices in range? + // + + for (i = 0; i < num_dimensions; i++) + { + if (VM_stack_top[i + 1].slumber > VM_stack_top[0].array->dimension[i].size) + { + // + // Referencing outside the array. + // + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + + VM_stack_top++; + + goto outside_the_array; + } + } + + // + // What's this index of this element into the array? + // + + index = 0; + + for (i = 0; i < num_dimensions; i++) + { + index += VM_stack_top[0].array->dimension[i].stride * (VM_stack_top[i + 1].slumber - 1); + } + + // + // Push a copy of this element onto the stack. + // + + ASSERT(WITHIN(index, 0, VM_stack_top[0].array->length - 1)); + + if (VM_code_pointer[-2] == ML_DO_PUSH_ARRAY_QUICK) + { + // + // Push the actual value rather than a copy. + // + + VM_stack_top[0] = VM_stack_top[0].array->data[index]; + } + else + { + // + // Push a copy of the data. + // + + VM_stack_top[0] = VM_data_copy(VM_stack_top[0].array->data[index]); + } + + VM_stack_top++; + + outside_the_array:; + } + } + + break; + + case ML_DO_PUSH_INPUT: + + { + CBYTE *string; + + // + // Get user input! + // + + string = CONSOLE_input(); + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_STRVAR; + VM_stack_top[0].strvar = (CBYTE *) MEM_alloc(strlen(string) + 1); + + strcpy(VM_stack_top[0].strvar, string); + + VM_stack_top++; + } + + break; + + case ML_DO_GOSUB: + + VM_CHECK_STACK_PUSH(); + + // + // Push the return address onto the stack. + // + + VM_stack_top[0].type = ML_TYPE_CODE_POINTER; + VM_stack_top[0].code_pointer = VM_code_pointer + 1; + + VM_stack_top++; + + // + // Valid address? + // + + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_code_upto - 1)); + + VM_code_pointer = &VM_code[VM_code_pointer[0]]; + + break; + + case ML_DO_RETURN: + + VM_POP_STACK(1); + + ASSERT(VM_stack_top[0].type == ML_TYPE_CODE_POINTER); + ASSERT(WITHIN(VM_stack_top[0].code_pointer, VM_code, VM_code + VM_code_upto - 1)); + + VM_code_pointer = VM_stack_top[0].code_pointer; + + break; + + case ML_DO_XOR: + + VM_POP_STACK(2); + + if (VM_stack_top[0].type != VM_stack_top[1].type) + { + // + // ERROR! AND only works on the same values! + // + + ASSERT(0); + } + + switch(VM_stack_top[0].type) + { + case ML_TYPE_BOOLEAN: VM_stack_top[0].boolean = VM_stack_top[0].boolean ^ VM_stack_top[1].boolean; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top++; + + break; + + case ML_DO_IF_TRUE_GOTO: + + VM_POP_STACK(1); + + if (VM_stack_top[0].type != ML_TYPE_BOOLEAN) + { + // + // ERROR! Or maybe type conversion? What if there is a string + // that says "YES", for instance? + // + + ASSERT(0); + } + + if (VM_stack_top[0].boolean) + { + // + // Valid address? + // + + ASSERT(WITHIN(VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(VM_code_pointer[0], 0, VM_code_upto - 1)); + + VM_code_pointer = &VM_code[VM_code_pointer[0]]; + } + else + { + // + // Skip over the address instruction. + // + + VM_code_pointer++; + } + + break; + + case ML_DO_PUSH_RANDOM_SLUMBER: + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_SLUMBER; + VM_stack_top[0].slumber = rand(); + + VM_stack_top++; + + break; + + case ML_DO_SWAP: + + VM_POP_STACK(2); + + ASSERT(VM_stack_top[0].type == ML_TYPE_POINTER); + ASSERT(VM_stack_top[1].type == ML_TYPE_POINTER); + + { + ML_Data swap_spare; + + swap_spare = *VM_stack_top[0].data; + *VM_stack_top[0].data = *VM_stack_top[1].data; + *VM_stack_top[1].data = swap_spare; + } + + break; + + case ML_DO_ENTERFUNC: + + { + SLONG i; + + // + // Do we have the right number of arguments? + // + + ASSERT(VM_stack_top[-2].type == ML_TYPE_NUM_ARGS ); // Num args to functions + ASSERT(VM_stack_top[-1].type == ML_TYPE_CODE_POINTER); // Return address + + SLONG args_to_function = VM_stack_top[-2].args; + + if (args_to_function == *VM_code_pointer) + { + // + // Get rid of the number of args to the function. + // + + VM_POP_STACK(1); + + VM_stack_top[-1] = VM_stack_top[0]; + } + else + { + if (args_to_function > *VM_code_pointer) + { + // + // ERROR! Too many argument passed to the function! + // + + ASSERT(0); + } + else + { + // + // Remember the code pointer so we wont overwrite it. + // + + SLONG *code_pointer = VM_stack_top[-1].code_pointer; + + // + // Must insert extra undefined arguments. + // + + VM_POP_STACK(2); + + for (i = args_to_function; i < *VM_code_pointer; i++) + { + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + VM_stack_top[0].value = 0; // Not required. + + VM_stack_top++; + } + + // + // Now push the return address. + // + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_CODE_POINTER; + VM_stack_top[0].code_pointer = code_pointer; + + VM_stack_top++; + } + } + } + + // + // Push the old base pointer. + // + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_STACK_BASE; + VM_stack_top[0].stack_base = VM_stack_base; + + VM_stack_top++; + + // + // Work out the new stack base. + // + + ASSERT(WITHIN( VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(*VM_code_pointer, 0, 256)); // Sensible numbers of arguments? + + // + // Minus 2 to skip over the return address and the old stack base. + // + + VM_stack_base = VM_stack_top - *VM_code_pointer++ - 2; + + break; + + case ML_DO_ENDFUNC: + + { + // + // On the stack there should be the return value of the function, + // the old base pointer and the return address. + // + + VM_POP_STACK(3); + + ASSERT(VM_stack_top[0].type == ML_TYPE_CODE_POINTER); + ASSERT(VM_stack_top[1].type == ML_TYPE_STACK_BASE ); + + SLONG *return_instruction = VM_stack_top[0].code_pointer; + + // + // Pop the locals off the stack. + // + + ASSERT(WITHIN( VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(*VM_code_pointer, 0, 256)); // Sensible numbers of arguments? + + VM_POP_STACK(*VM_code_pointer); + + // + // Free all the locals. + // + + SLONG i; + + for (i = 0; i < *VM_code_pointer; i++) + { + VM_data_free(VM_stack_top[i]); + } + + // + // Push the return value onto the bottom of the stack. + // + + VM_stack_top[0] = VM_stack_top[*VM_code_pointer + 2]; + + VM_stack_top++; + + // + // Continue execution from the return address. + // + + VM_code_pointer = return_instruction; + } + + break; + + case ML_DO_POP: + VM_POP_STACK(1); + break; + + case ML_DO_PUSH_LOCAL_VALUE: + + VM_CHECK_STACK_PUSH(); + + ASSERT(WITHIN( VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(*VM_code_pointer, 0, 256)); // Sensible local index? + + ASSERT(VM_stack_base); + ASSERT(VM_stack_base + *VM_code_pointer <= VM_stack_top - 2); + + ASSERT(VM_stack_base[*VM_code_pointer].type != ML_TYPE_CODE_POINTER); + ASSERT(VM_stack_base[*VM_code_pointer].type != ML_TYPE_STACK_BASE); + + // + // Push a copy of the local onto the stack. Any memory allocated + // by the original will be duplicated. + // + + *VM_stack_top++ = VM_data_copy(VM_stack_base[*VM_code_pointer++]); + + break; + + case ML_DO_PUSH_LOCAL_ADDRESS: + + VM_CHECK_STACK_PUSH(); + + ASSERT(WITHIN( VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(*VM_code_pointer, 0, 256)); // Sensible local index? + + ASSERT(VM_stack_base); + ASSERT(VM_stack_base + *VM_code_pointer < VM_stack_top - 2); + + ASSERT(VM_stack_base[*VM_code_pointer].type != ML_TYPE_CODE_POINTER); + ASSERT(VM_stack_base[*VM_code_pointer].type != ML_TYPE_STACK_BASE); + + if (VM_stack_base[*VM_code_pointer].type == ML_TYPE_POINTER) + { + // + // This local is already a pointer, just push on + // it's current value. + // + + VM_stack_top[0] = VM_stack_base[*VM_code_pointer++]; + } + else + { + // + // Push on the address of this local. + // + + VM_stack_top[0].type = ML_TYPE_POINTER; + VM_stack_top[0].data = VM_stack_base + *VM_code_pointer++; + } + + VM_stack_top++; + + break; + + case ML_DO_PUSH_LOCAL_QUICK: + + VM_CHECK_STACK_PUSH(); + + ASSERT(WITHIN( VM_code_pointer, VM_code, VM_code + VM_code_upto - 1)); + ASSERT(WITHIN(*VM_code_pointer, 0, 256)); // Sensible local index? + + ASSERT(VM_stack_base); + ASSERT(VM_stack_base + *VM_code_pointer < VM_stack_top - 2); + + ASSERT(VM_stack_base[*VM_code_pointer].type != ML_TYPE_CODE_POINTER); + ASSERT(VM_stack_base[*VM_code_pointer].type != ML_TYPE_STACK_BASE); + + // + // Push a copy of the local onto the stack - don't copy data. + // + + *VM_stack_top++ = VM_stack_base[*VM_code_pointer++]; + + break; + + case ML_DO_TEXTURE: VM_do_texture(); break; + case ML_DO_BUFFER: VM_do_buffer(); break; + case ML_DO_DRAW: VM_do_draw(); break; + case ML_DO_CLS: VM_do_cls(); break; + + case ML_DO_FLIP: + + // + // Less than 10 milliseconds since our last FLIP? + // + + while(VM_flip_tick > OS_ticks() - 10); + + LL_flip(); + + VM_flip_tick = OS_ticks(); + + break; + + case ML_DO_KEY_VALUE: + + VM_POP_STACK(1); + + if (VM_stack_top[0].type != ML_TYPE_SLUMBER) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (!WITHIN(VM_stack_top[0].slumber, 1, 255)) + { + // + // Outside the array... + // + + VM_stack_top[0].type = ML_TYPE_UNDEFINED; + } + else + { + if (KEY_on[VM_stack_top[0].slumber] == 0 || + KEY_on[VM_stack_top[0].slumber] == 1) + { + // + // This key has been pressed since the last time + // it was assigned to. Free the current key value. + // + + VM_data_free(VM_global[VM_EXTRA_GLOBAL_KEY(VM_stack_top[0].slumber)]); + + // + // Create a new value. + // + + VM_global[VM_EXTRA_GLOBAL_KEY(VM_stack_top[0].slumber)].type = ML_TYPE_BOOLEAN; + VM_global[VM_EXTRA_GLOBAL_KEY(VM_stack_top[0].slumber)].boolean = KEY_on[VM_stack_top[0].slumber]; + + // + // Push it onto the stack. + // + + VM_stack_top[0] = VM_data_copy(VM_global[VM_EXTRA_GLOBAL_KEY(VM_stack_top[0].slumber)]); + } + else + { + // + // Use the value the user wrote to the KEY[] array... + // + + VM_stack_top[0] = VM_data_copy(VM_global[VM_EXTRA_GLOBAL_KEY(VM_stack_top[0].slumber)]); + } + } + + VM_stack_top++; + + break; + + case ML_DO_KEY_ASSIGN: + + VM_POP_STACK(2); + + if (VM_stack_top[1].type != ML_TYPE_SLUMBER) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (!WITHIN(VM_stack_top[1].slumber, 1, 255)) + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // Free the current value. + // + + VM_data_free(VM_global[VM_EXTRA_GLOBAL_KEY(VM_stack_top[1].slumber)]); + + // + // Assign the new number. + // + + VM_global[VM_EXTRA_GLOBAL_KEY(VM_stack_top[1].slumber)] = VM_stack_top[0]; + + // + // Overwrite the real KEY_on array with a special value so we know + // if the key has been pressed or release since it was assigned to... + // + + KEY_on[VM_stack_top[1].slumber] = 42; + + break; + + case ML_DO_INKEY_VALUE: + + VM_CHECK_STACK_PUSH(); + + if (KEY_inkey) + { + VM_data_free(VM_global[VM_EXTRA_GLOBAL_INKEY]); + + VM_global[VM_EXTRA_GLOBAL_INKEY].type = ML_TYPE_SLUMBER; + VM_global[VM_EXTRA_GLOBAL_INKEY].slumber = KEY_inkey; + + KEY_inkey = 0; + } + + VM_stack_top[0] = VM_data_copy(VM_global[VM_EXTRA_GLOBAL_INKEY]); + + VM_stack_top++; + + break; + + case ML_DO_INKEY_ASSIGN: + + VM_POP_STACK(1); + + // + // Free memory used by the current inkey variable. + // + + VM_data_free(VM_global[VM_EXTRA_GLOBAL_INKEY]); + + // + // Assign the new value. + // + + VM_global[VM_EXTRA_GLOBAL_INKEY] = VM_stack_top[0]; + + // + // Overwrite the real inkey too! + // + + KEY_inkey = 0; + + break; + + case ML_DO_TIMER: + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = float(OS_ticks()) * 0.001F; + + VM_stack_top++; + + break; + + case ML_DO_SIN: + + VM_POP_STACK(1); + + { + float val; + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: val = float(VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: val = VM_stack_top[0].flumber; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = sinf(val); + } + + VM_stack_top++; + + break; + + case ML_DO_COS: + + VM_POP_STACK(1); + + { + float val; + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: val = float(VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: val = VM_stack_top[0].flumber; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = cosf(val); + } + + VM_stack_top++; + + break; + + case ML_DO_TAN: + + VM_POP_STACK(1); + + { + float val; + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: val = float(VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: val = VM_stack_top[0].flumber; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = tanf(val); + } + + VM_stack_top++; + + break; + + case ML_DO_ASIN: + + VM_POP_STACK(1); + + { + float val; + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: val = float(VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: val = VM_stack_top[0].flumber; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = asinf(val); + } + + VM_stack_top++; + + break; + + case ML_DO_ACOS: + + VM_POP_STACK(1); + + { + float val; + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: val = float(VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: val = VM_stack_top[0].flumber; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = acosf(val); + } + + VM_stack_top++; + + break; + + case ML_DO_ATAN: + + VM_POP_STACK(1); + + { + float val; + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: val = float(VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: val = VM_stack_top[0].flumber; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = atanf(val); + } + + VM_stack_top++; + + break; + + case ML_DO_ATAN2: + + VM_POP_STACK(2); + + { + float val1; + float val2; + + switch(VM_stack_top[0].type) + { + case ML_TYPE_SLUMBER: val1 = float(VM_stack_top[0].slumber); break; + case ML_TYPE_FLUMBER: val1 = VM_stack_top[0].flumber; break; + + default: + ASSERT(0); + break; + } + + switch(VM_stack_top[1].type) + { + case ML_TYPE_SLUMBER: val2 = float(VM_stack_top[1].slumber); break; + case ML_TYPE_FLUMBER: val2 = VM_stack_top[1].flumber; break; + + default: + ASSERT(0); + break; + } + + VM_stack_top[0].type = ML_TYPE_FLUMBER; + VM_stack_top[0].flumber = atan2f(val1,val2); + } + + VM_stack_top++; + + break; + + case ML_DO_NOP: + break; + + case ML_DO_LEFT: + + VM_POP_STACK(2); + + // + // Check types. + // + + if (VM_stack_top[0].type != ML_TYPE_STRVAR && + VM_stack_top[0].type != ML_TYPE_STRCONST) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[1].type != ML_TYPE_SLUMBER) + { + // + // ERROR! + // + + ASSERT(0); + } + + { + ML_Data ans; + + CBYTE *input = VM_get_string(VM_stack_top[0]); + SLONG left = VM_stack_top[1].slumber; + + if (left < 0) + { + // + // ERROR! + // + + ASSERT(0); + } + + ans.type = ML_TYPE_STRVAR; + ans.strvar = (CBYTE *) MEM_alloc(left + 1); + + CBYTE *src = input; + CBYTE *dst = ans.strvar; + + while(left > 0) + { + if (*src == '\000') + { + break; + } + + *dst++ = *src++; + + left--; + } + + *dst = '\000'; + + // + // Free args. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + + // + // Push answer onto the stack. + // + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0] = ans; + VM_stack_top++; + } + + break; + + case ML_DO_MID: + + VM_POP_STACK(3); + + // + // Check types. + // + + if (VM_stack_top[0].type != ML_TYPE_STRVAR && + VM_stack_top[0].type != ML_TYPE_STRCONST) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[1].type != ML_TYPE_SLUMBER || + VM_stack_top[2].type != ML_TYPE_SLUMBER) + { + // + // ERROR! + // + + ASSERT(0); + } + + { + ML_Data ans; + + CBYTE *input = VM_get_string(VM_stack_top[0]); + SLONG in = VM_stack_top[1].slumber - 1; // - 1 because BASIC is 1-based not zero based. + SLONG num = VM_stack_top[2].slumber; + SLONG len = strlen(input); + + if (num < 0) + { + // + // ERROR! Bad number of characters. + // + + ASSERT(0); + } + + ans.type = ML_TYPE_STRVAR; + ans.strvar = (CBYTE *) MEM_alloc(num + 1); + + if (!WITHIN(in, 0, len - 1)) + { + ans.strvar[0] = '\000'; + } + else + { + CBYTE *src = input + in; + CBYTE *dst = ans.strvar; + + while(num > 0) + { + if (*src == '\000') + { + break; + } + + *dst++ = *src++; + + num--; + } + + *dst = '\000'; + } + + // + // Free args. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + VM_data_free(VM_stack_top[2]); + + // + // Push answer onto the stack. + // + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0] = ans; + VM_stack_top++; + } + + break; + + case ML_DO_RIGHT: + + VM_POP_STACK(2); + + // + // Check types. + // + + if (VM_stack_top[0].type != ML_TYPE_STRVAR && + VM_stack_top[0].type != ML_TYPE_STRCONST) + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[1].type != ML_TYPE_SLUMBER) + { + // + // ERROR! + // + + ASSERT(0); + } + + { + ML_Data ans; + + CBYTE *input = VM_get_string(VM_stack_top[0]); + SLONG len = VM_stack_top[1].slumber; + + ans.type = ML_TYPE_STRVAR; + ans.strvar = (CBYTE *) MEM_alloc(len + 1); + + CBYTE *src = input; + CBYTE *dst = ans.strvar; + + while(*src) {src++;} + + src -= len; + + if (src < input) + { + // + // We want a segment that is bigger that the string! + // + + src = input; + } + + while(len > 0) + { + if (*src == '\000') + { + break; + } + + *dst++ = *src++; + + len--; + } + + *dst = '\000'; + + // + // Free args. + // + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + + // + // Push answer onto the stack. + // + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0] = ans; + VM_stack_top++; + } + + break; + + case ML_DO_LEN: + + VM_POP_STACK(1); + + if (VM_stack_top[0].type != ML_TYPE_STRVAR && + VM_stack_top[0].type != ML_TYPE_STRCONST) + { + // + // ERROR! + // + + ASSERT(0); + } + else + { + SLONG len = strlen(VM_get_string(VM_stack_top[0])); + + VM_data_free(VM_stack_top[0]); + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_SLUMBER; + VM_stack_top[0].slumber = len; + + VM_stack_top++; + } + + break; + + case ML_DO_PUSH_IDENTITY_MATRIX: + + { + const ML_Vector right = {1.0F, 0.0F, 0.0F}; + const ML_Vector up = {0.0F, 1.0F, 0.0F}; + const ML_Vector forwards = {0.0F, 0.0F, 1.0F}; + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_MATRIX; + VM_stack_top[0].matrix = (ML_Matrix *) MEM_alloc(sizeof(ML_Matrix)); + + VM_stack_top[0].matrix->vector[0] = right; + VM_stack_top[0].matrix->vector[1] = up; + VM_stack_top[0].matrix->vector[2] = forwards; + + VM_stack_top++; + } + + break; + + case ML_DO_PUSH_ZERO_VECTOR: + + VM_CHECK_STACK_PUSH(); + + VM_stack_top[0].type = ML_TYPE_VECTOR; + VM_stack_top[0].vector = (ML_Vector *) MEM_alloc(sizeof(ML_Vector)); + + VM_stack_top[0].vector->x = 0.0F; + VM_stack_top[0].vector->y = 0.0F; + VM_stack_top[0].vector->z = 0.0F; + + break; + + case ML_DO_MATRIX: + + VM_POP_STACK(3); + + // + // Make sure all the arguments are vectors. + // + + if (VM_stack_top[0].type != ML_TYPE_VECTOR || + VM_stack_top[1].type != ML_TYPE_VECTOR || + VM_stack_top[2].type != ML_TYPE_VECTOR) + { + // + // ERROR! + // + + ASSERT(0); + } + + { + ML_Data res; + + res.type = ML_TYPE_MATRIX; + res.matrix = (ML_Matrix *) MEM_alloc(sizeof(ML_Matrix)); + + res.matrix->vector[0] = *VM_stack_top[0].vector; + res.matrix->vector[1] = *VM_stack_top[1].vector; + res.matrix->vector[2] = *VM_stack_top[2].vector; + + VM_data_free(VM_stack_top[0]); + VM_data_free(VM_stack_top[1]); + VM_data_free(VM_stack_top[2]); + + VM_stack_top[0] = res; + + VM_stack_top++; + } + + break; + + case ML_DO_VECTOR: + + VM_POP_STACK(3); + + { + ML_Data res; + + res.type = ML_TYPE_VECTOR; + res.vector = (ML_Vector *) MEM_alloc(sizeof(ML_Vector)); + + if (VM_stack_top[0].type == ML_TYPE_FLUMBER) {res.vector->x = VM_stack_top[0].flumber;} + else if (VM_stack_top[0].type == ML_TYPE_SLUMBER) {res.vector->x = (float) VM_stack_top[0].slumber;} + else + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[1].type == ML_TYPE_FLUMBER) {res.vector->y = VM_stack_top[1].flumber;} + else if (VM_stack_top[1].type == ML_TYPE_SLUMBER) {res.vector->y = (float) VM_stack_top[1].slumber;} + else + { + // + // ERROR! + // + + ASSERT(0); + } + + if (VM_stack_top[2].type == ML_TYPE_FLUMBER) {res.vector->z = VM_stack_top[2].flumber;} + else if (VM_stack_top[2].type == ML_TYPE_SLUMBER) {res.vector->z = (float) VM_stack_top[2].slumber;} + else + { + // + // ERROR! + // + + ASSERT(0); + } + + // + // No need to free the arguments... they are all just numbers. + // + + VM_stack_top[0] = res; + + VM_stack_top++; + } + + break; + + default: + ASSERT(0); + break; + } + } +} + + + + + + + + + + + +void VM_run(CBYTE *fname) +{ + SLONG i; + + FILE *handle; + + handle = fopen(fname, "rb"); + + if (handle == NULL) + { + fprintf(stderr, "Unable to open file \"%s\"\n", fname); + + return; + } + + // + // Load in the file header. + // + + ML_Header mh; + + if (fread(&mh, sizeof(mh), 1, handle) != 1) {goto file_error;} + + // + // Valid file? + // + + if (mh.version != ML_VERSION_NUMBER) + { + // + // This is an old file. + // + + fprintf(stderr, "File \"%s\" has an old version number.\n", fname); + + fclose(handle); + + return; + } + + // + // Allocate instruction memory and read in the instructions + // from the file. + // + + ASSERT(mh.instructions_memory_in_bytes % sizeof(SLONG) == 0); + + VM_code_max = (mh.instructions_memory_in_bytes + 32) / sizeof(SLONG); + VM_code = (SLONG *) malloc(sizeof(SLONG) * VM_code_max); + VM_code_upto = mh.instructions_memory_in_bytes / sizeof(SLONG); + VM_code_pointer = VM_code; + + if (fread(VM_code, sizeof(UBYTE), mh.instructions_memory_in_bytes, handle) != mh.instructions_memory_in_bytes) goto file_error; + + // + // Allocate static data and read in data from the file. + // + + VM_data_max = mh.data_table_length_in_bytes; + VM_data = (UBYTE *) malloc(sizeof(UBYTE) * mh.data_table_length_in_bytes); + + if (fread(VM_data, sizeof(UBYTE), mh.data_table_length_in_bytes, handle) != mh.data_table_length_in_bytes) goto file_error; + + // + // Allocate the stack. + // + + VM_stack_max = 2048; + VM_stack = (ML_Data *) malloc(sizeof(ML_Data) * VM_stack_max); + VM_stack_top = VM_stack; + VM_stack_base = NULL; + + // + // Allocate the globals and initialise all of them to undefined. + // + + VM_global_max = mh.num_globals + VM_EXTRA_GLOBAL_NUMBER; + VM_global_extra = mh.num_globals; + VM_global = (ML_Data *) malloc(sizeof(ML_Data) * VM_global_max); + + memset(VM_global, 0, sizeof(ML_Data) * VM_global_max); + + // + // Initialise the KEY[] array to FALSE. + // + + for (i = 0; i < 256; i++) + { + VM_global[VM_EXTRA_GLOBAL_KEY(i)].type = ML_TYPE_BOOLEAN; + VM_global[VM_EXTRA_GLOBAL_KEY(i)].boolean = FALSE; + } + + // + // Initialise the flip tick. + // + + VM_flip_tick = 0; + + // + // Start execution! + // + + VM_execute(); + + return; + + file_error:; + + fclose(handle); + + if (VM_code) {free(VM_code); VM_code = NULL;} + if (VM_stack) {free(VM_stack); VM_stack = NULL;} + + return; +} diff --git a/MuckyBasic/vm.h b/MuckyBasic/vm.h new file mode 100644 index 0000000..867deec --- /dev/null +++ b/MuckyBasic/vm.h @@ -0,0 +1,17 @@ +// +// The virtual machine to run our basic programs. +// + +#ifndef _VM_ +#define _VM_ + + +// +// Loads the given MuckyBASIC program into memory and runs it! +// + +void VM_run(CBYTE *fname); + + + +#endif diff --git a/MuckyBasic/wave.c b/MuckyBasic/wave.c new file mode 100644 index 0000000..af87819 --- /dev/null +++ b/MuckyBasic/wave.c @@ -0,0 +1,896 @@ +/*========================================================================== + * + * Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved. + * + * File: wave.c + * Content: Wave library routines. + * This file is used for loading/saving waves, and reading and + * writing waves in smaller blocks. + * Uses WaveOpenFile, WaveReadFile and WaveCloseReadFile for + * single block access to reading wave files. + * Uses WaveCreateFile, WaveWriteFile, WaveCloseWriteFile for + * single block access for writing wave files. + * Uses WaveLoadFile to load a whole wave file into memory. + * Uses WaveSaveFile to save a whole wave file into memory. + * + ***************************************************************************/ + +/* PROTOTYPES */ +#include +#include +#include "wave.h" +//#include "debug.h" +#include "windowsx.h" + +#define ASSERT(x) + +/* ROUTINES */ +/* -------------------------------------------------------*/ + +/* This function will open a wave input file and prepare it for reading, + * so the data can be easily + * read with WaveReadFile. Returns 0 if successful, the error code if not. + * pszFileName - Input filename to load. + * phmmioIn - Pointer to handle which will be used + * for further mmio routines. + * ppwfxInfo - Ptr to ptr to WaveFormatEx structure + * with all info about the file. + * +*/ +int WaveOpenFile( + TCHAR*pszFileName, // (IN) + HMMIO *phmmioIn, // (OUT) + WAVEFORMATEX **ppwfxInfo, // (OUT) + MMCKINFO *pckInRIFF // (OUT) + ) +{ + HMMIO hmmioIn; + MMCKINFO ckIn; // chunk info. for general use. + PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. + WORD cbExtraAlloc; // Extra bytes for waveformatex + int nError; // Return value. + + + // Initialization... + *ppwfxInfo = NULL; + nError = 0; + hmmioIn = NULL; + + if ((hmmioIn = mmioOpen(pszFileName, NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL) + { + nError = ER_CANNOTOPEN; + goto ERROR_READING_WAVE; + } + + if ((nError = (int)mmioDescend(hmmioIn, pckInRIFF, NULL, 0)) != 0) + { + goto ERROR_READING_WAVE; + } + + + if ((pckInRIFF->ckid != FOURCC_RIFF) || (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E'))) + { + nError = ER_NOTWAVEFILE; + goto ERROR_READING_WAVE; + } + + /* Search the input file for for the 'fmt ' chunk. */ + ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); + if ((nError = (int)mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK)) != 0) + { + goto ERROR_READING_WAVE; + } + + /* Expect the 'fmt' chunk to be at least as large as ; + * if there are extra parameters at the end, we'll ignore them */ + + if (ckIn.cksize < (long) sizeof(PCMWAVEFORMAT)) + { + nError = ER_NOTWAVEFILE; + goto ERROR_READING_WAVE; + } + + /* Read the 'fmt ' chunk into .*/ + if (mmioRead(hmmioIn, (HPSTR) &pcmWaveFormat, (long) sizeof(pcmWaveFormat)) != (long) sizeof(pcmWaveFormat)) + { + nError = ER_CANNOTREAD; + goto ERROR_READING_WAVE; + } + + + // Ok, allocate the waveformatex, but if its not pcm + // format, read the next word, and thats how many extra + // bytes to allocate. + if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) + cbExtraAlloc = 0; + + else + { + // Read in length of extra bytes. + if (mmioRead(hmmioIn, (LPTSTR) &cbExtraAlloc, + (long) sizeof(cbExtraAlloc)) != (long) sizeof(cbExtraAlloc)) + { + nError = ER_CANNOTREAD; + goto ERROR_READING_WAVE; + } + + } + + // Ok, now allocate that waveformatex structure. + if ((*ppwfxInfo = GlobalAlloc(GMEM_FIXED, sizeof(WAVEFORMATEX)+cbExtraAlloc)) == NULL) + { + nError = ER_MEM; + goto ERROR_READING_WAVE; + } + + // Copy the bytes from the pcm structure to the waveformatex structure + memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat)); + (*ppwfxInfo)->cbSize = cbExtraAlloc; + + // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. + if (cbExtraAlloc != 0) + { + if (mmioRead(hmmioIn, (LPTSTR) (((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(cbExtraAlloc)), + (long) (cbExtraAlloc)) != (long) (cbExtraAlloc)) + { + nError = ER_NOTWAVEFILE; + goto ERROR_READING_WAVE; + } + } + + /* Ascend the input file out of the 'fmt ' chunk. */ + if ((nError = mmioAscend(hmmioIn, &ckIn, 0)) != 0) + { + goto ERROR_READING_WAVE; + + } + + + goto TEMPCLEANUP; + +ERROR_READING_WAVE: + if (*ppwfxInfo != NULL) + { + GlobalFree(*ppwfxInfo); + *ppwfxInfo = NULL; + } + + if (hmmioIn != NULL) + { + mmioClose(hmmioIn, 0); + hmmioIn = NULL; + } + +TEMPCLEANUP: + *phmmioIn = hmmioIn; + + return(nError); + +} + +/* This routine has to be called before WaveReadFile as it searchs for the chunk to descend into for + reading, that is, the 'data' chunk. For simplicity, this used to be in the open routine, but was + taken out and moved to a separate routine so there was more control on the chunks that are before + the data chunk, such as 'fact', etc... */ + +int WaveStartDataRead( + HMMIO *phmmioIn, + MMCKINFO *pckIn, + MMCKINFO *pckInRIFF + ) +{ + int nError; + + nError = 0; + + // Do a nice little seek... + if ((nError = mmioSeek(*phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC), SEEK_SET)) == -1) + { + ASSERT(FALSE); + } + + nError = 0; + // Search the input file for for the 'data' chunk. + pckIn->ckid = mmioFOURCC('d', 'a', 't', 'a'); + if ((nError = mmioDescend(*phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK)) != 0) + { + goto ERROR_READING_WAVE; + } + + goto CLEANUP; + +ERROR_READING_WAVE: + +CLEANUP: + return(nError); +} + + +/* This will read wave data from the wave file. Makre sure we're descended into + the data chunk, else this will fail bigtime! + hmmioIn - Handle to mmio. + cbRead - # of bytes to read. + pbDest - Destination buffer to put bytes. + cbActualRead- # of bytes actually read. + + + +*/ + + +int WaveReadFile( + HMMIO hmmioIn, // IN + UINT cbRead, // IN + BYTE *pbDest, // IN + MMCKINFO *pckIn, // IN. + UINT *cbActualRead // OUT. + + ) +{ + + MMIOINFO mmioinfoIn; // current status of + int nError; + UINT cT, cbDataIn; + + nError = 0; + + if (nError = mmioGetInfo(hmmioIn, &mmioinfoIn, 0) != 0) + { + goto ERROR_CANNOT_READ; + } + + cbDataIn = cbRead; + if (cbDataIn > pckIn->cksize) + cbDataIn = pckIn->cksize; + + pckIn->cksize -= cbDataIn; + + for (cT = 0; cT < cbDataIn; cT++) + { + /* Copy the bytes from the io to the buffer. */ + if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) + { + if ((nError = mmioAdvance(hmmioIn, &mmioinfoIn, MMIO_READ)) != 0) + { + goto ERROR_CANNOT_READ; + } + if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) + { + nError = ER_CORRUPTWAVEFILE; + goto ERROR_CANNOT_READ; + } + } + + // Actual copy. + *((BYTE*)pbDest+cT) = *((BYTE*)mmioinfoIn.pchNext)++; + } + + if ((nError = mmioSetInfo(hmmioIn, &mmioinfoIn, 0)) != 0) + { + goto ERROR_CANNOT_READ; + } + + *cbActualRead = cbDataIn; + goto FINISHED_READING; + +ERROR_CANNOT_READ: + *cbActualRead = 0; + +FINISHED_READING: + return(nError); + +} + +/* This will close the wave file openned with WaveOpenFile. + phmmioIn - Pointer to the handle to input MMIO. + ppwfxSrc - Pointer to pointer to WaveFormatEx structure. + + Returns 0 if successful, non-zero if there was a warning. + +*/ +int WaveCloseReadFile( + HMMIO *phmmio, // IN + WAVEFORMATEX **ppwfxSrc // IN + ) +{ + + if (*ppwfxSrc != NULL) + { + GlobalFree(*ppwfxSrc); + *ppwfxSrc = NULL; + } + + if (*phmmio != NULL) + { + mmioClose(*phmmio, 0); + *phmmio = NULL; + } + + return(0); + +} + +/* This routine will create a wave file for writing. This will automatically overwrite any + existing file with the same name, so be careful and check before hand!!! + pszFileName - Pointer to filename to write. + phmmioOut - Pointer to HMMIO handle that is used for further writes + pwfxDest - Valid waveformatex destination structure. + pckOut - Pointer to be set with the MMCKINFO. + pckOutRIFF - Pointer to be set with the RIFF info. + +*/ +int WaveCreateFile( + TCHAR*pszFileName, // (IN) + HMMIO *phmmioOut, // (OUT) + WAVEFORMATEX *pwfxDest, // (IN) + MMCKINFO *pckOut, // (OUT) + MMCKINFO *pckOutRIFF // (OUT) + + ) +{ + + int nError; // Return value. + DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile. + MMCKINFO ckOut1; + + dwFactChunk = (DWORD)-1; + nError = 0; + + *phmmioOut = mmioOpen(pszFileName, NULL, + MMIO_ALLOCBUF | MMIO_READWRITE|MMIO_CREATE); + + if (*phmmioOut == NULL) + { + nError = ER_CANNOTWRITE; + goto ERROR_CANNOT_WRITE; // cannot save WAVE file + } + + /* Create the output file RIFF chunk of form type 'WAVE'. + */ + pckOutRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E'); + pckOutRIFF->cksize = 0; + if ((nError = mmioCreateChunk(*phmmioOut, pckOutRIFF, MMIO_CREATERIFF)) != 0) + { + goto ERROR_CANNOT_WRITE; // cannot write file, probably + } + + /* We are now descended into the 'RIFF' chunk we just created. + * Now create the 'fmt ' chunk. Since we know the size of this chunk, + * specify it in the MMCKINFO structure so MMIO doesn't have to seek + * back and set the chunk size after ascending from the chunk. + */ + pckOut->ckid = mmioFOURCC('f', 'm', 't', ' '); + pckOut->cksize = sizeof(PCMWAVEFORMAT); // we know the size of this ck. + if ((nError = mmioCreateChunk(*phmmioOut, pckOut, 0)) != 0) + { + goto ERROR_CANNOT_WRITE; // cannot write file, probably + } + + /* Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type. */ + if (pwfxDest->wFormatTag == WAVE_FORMAT_PCM) + { + if (mmioWrite(*phmmioOut, (HPSTR) pwfxDest, sizeof(PCMWAVEFORMAT)) + != sizeof(PCMWAVEFORMAT)) + { + nError = ER_CANNOTWRITE; + goto ERROR_CANNOT_WRITE; // cannot write file, probably + } + } + + else + { + // Write the variable length size. + if ((UINT)mmioWrite(*phmmioOut, (HPSTR) pwfxDest, sizeof(*pwfxDest)+pwfxDest->cbSize) + != (sizeof(*pwfxDest)+pwfxDest->cbSize)) + { + nError = ER_CANNOTWRITE; + goto ERROR_CANNOT_WRITE; // cannot write file, probably + } + + } + + /* Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk. + */ + if ((nError = mmioAscend(*phmmioOut, pckOut, 0)) != 0) + { + goto ERROR_CANNOT_WRITE; // cannot write file, probably + } + + // Now create the fact chunk, not required for PCM but nice to have. This is filled + // in when the close routine is called. + ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't'); + ckOut1.cksize = 0; + if ((nError = mmioCreateChunk(*phmmioOut, &ckOut1, 0)) != 0) + { + goto ERROR_CANNOT_WRITE; // cannot write file, probably + } + + if (mmioWrite(*phmmioOut, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) != sizeof(dwFactChunk)) + { + nError = ER_CANNOTWRITE; + goto ERROR_CANNOT_WRITE; + } + + // Now ascend out of the fact chunk... + if ((nError = mmioAscend(*phmmioOut, &ckOut1, 0)) != 0) + { + nError = ER_CANNOTWRITE; // cannot write file, probably + goto ERROR_CANNOT_WRITE; + } + + + + goto DONE_CREATE; + +ERROR_CANNOT_WRITE: + // Maybe delete the half-written file? Ah forget it for now, its good to leave the + // file there for debugging... + +DONE_CREATE: + return(nError); + +} + +/* This routine has to be called before any data is written to the wave output file, via wavewritefile. This + sets up the data to write, and creates the data chunk. +*/ + +int WaveStartDataWrite( + HMMIO *phmmioOut, // (IN) + MMCKINFO *pckOut, // (IN) + MMIOINFO *pmmioinfoOut // (OUT) + ) +{ + + int nError; + + nError = 0; + /* Create the 'data' chunk that holds the waveform samples. */ + pckOut->ckid = mmioFOURCC('d', 'a', 't', 'a'); + pckOut->cksize = 0; + if ((nError = mmioCreateChunk(*phmmioOut, pckOut, 0)) != 0) + { + goto ERROR_CANNOT_WRITE; // cannot write file, probably + } + + if ((nError = mmioGetInfo(*phmmioOut, pmmioinfoOut, 0)) != 0) + { + goto ERROR_CANNOT_WRITE; + } + + goto CLEANUP; +ERROR_CANNOT_WRITE: + +CLEANUP: + return(nError); +} + +/* This routine will write out data to a wave file. + hmmioOut - Handle to hmmioOut filled by WaveCreateFile + cbWrite - # of bytes to write out. + pbSrc - Pointer to source. + pckOut - pointer to ckOut filled by WaveCreateFile + cbActualWrite - # of actual bytes written. + pmmioinfoOut - Pointer to mmioinfoOut filled by WaveCreateFile. + + Returns 0 if successful, else the error code. + + */ + + +int WaveWriteFile( + HMMIO hmmioOut, // (IN) + UINT cbWrite, // (IN) + BYTE *pbSrc, // (IN) + MMCKINFO *pckOut, // (IN) + UINT *cbActualWrite, // (OUT) + MMIOINFO *pmmioinfoOut // (IN) + ) +{ + + + int nError; + UINT cT; + + nError = 0; + + *cbActualWrite = 0; + + for (cT=0; cT < cbWrite; cT++) + { + if (pmmioinfoOut->pchNext == pmmioinfoOut->pchEndWrite) + { + pmmioinfoOut->dwFlags |= MMIO_DIRTY; + if ((nError = mmioAdvance(hmmioOut, pmmioinfoOut, MMIO_WRITE)) != 0) + { + goto ERROR_CANNOT_WRITE; + } + } + *((BYTE*)pmmioinfoOut->pchNext)++ = *((BYTE*)pbSrc+cT); + (*cbActualWrite)++; + } + + +ERROR_CANNOT_WRITE: + // What to do here? Well, for now, nothing, just return that error. (maybe delete the + // file later? + + return(nError); + +} + + + +/* This routine will close a wave file used for writing. Returns 0 if successful, else + the error code. + phmmioOut - Pointer to mmio handle for saving. + pckOut - Pointer to the MMCKINFO for saving. + pckOutRiff - Pointer to the riff MMCKINFO for saving. + pmmioinfoOut- Pointer to mmioinfo for saving. + cSamples - # of samples saved, for the fact chunk. For PCM, this isn't used but + will be written anyway, so this can be zero as long as programs ignore + this field when they load PCM formats. + + + +*/ +int WaveCloseWriteFile( + HMMIO *phmmioOut, // (IN) + MMCKINFO *pckOut, // (IN) + MMCKINFO *pckOutRIFF, // (IN) + MMIOINFO *pmmioinfoOut, // (IN) + DWORD cSamples // (IN) + ) +{ + + int nError; + + nError = 0; + + if (*phmmioOut == NULL) + return(0); + + pmmioinfoOut->dwFlags |= MMIO_DIRTY; + if ((nError = mmioSetInfo(*phmmioOut, pmmioinfoOut, 0)) != 0) + { + // cannot flush, probably... + goto ERROR_CANNOT_WRITE; + } + + /* Ascend the output file out of the 'data' chunk -- this will cause + * the chunk size of the 'data' chunk to be written. + */ + if ((nError = mmioAscend(*phmmioOut, pckOut, 0)) != 0) + goto ERROR_CANNOT_WRITE; // cannot write file, probably + + + // Do this here instead... + if ((nError = mmioAscend(*phmmioOut, pckOutRIFF, 0)) != 0) + goto ERROR_CANNOT_WRITE; // cannot write file, probably + + + nError = mmioSeek(*phmmioOut, 0, SEEK_SET); + if ((nError = (int)mmioDescend(*phmmioOut, pckOutRIFF, NULL, 0)) != 0) + { + goto ERROR_CANNOT_WRITE; + } + + nError = 0; + pckOut->ckid = mmioFOURCC('f', 'a', 'c', 't'); + if ((nError = mmioDescend(*phmmioOut, pckOut, pckOutRIFF, MMIO_FINDCHUNK)) == 0) + { + // If it didn't fail, write the fact chunk out, if it failed, not critical, just + // assert (below). + nError = mmioWrite(*phmmioOut, (HPSTR)&cSamples, sizeof(DWORD)); + nError = mmioAscend(*phmmioOut, pckOut, 0); + nError = 0; + } + else + { + nError = 0; + ASSERT(FALSE); + } + +// CANTWRITEFACT: + /* Ascend the output file out of the 'RIFF' chunk -- this will cause + * the chunk size of the 'RIFF' chunk to be written. + */ + if ((nError = mmioAscend(*phmmioOut, pckOutRIFF, 0)) != 0) + goto ERROR_CANNOT_WRITE; // cannot write file, probably + + + +ERROR_CANNOT_WRITE: + if (*phmmioOut != NULL) + { + mmioClose(*phmmioOut, 0); + *phmmioOut = NULL; + } + + return(nError); + +} + +/* This routine will copy from a source wave file to a destination wave file all those useless chunks + (well, the ones useless to conversions, etc --> apparently people use them!). The source will be + seeked to the begining, but the destination has to be at a current pointer to put the new chunks. + This will also seek back to the start of the wave riff header at the end of the routine. + + phmmioIn - Pointer to input mmio file handle. + pckIn - Pointer to a nice ckIn to use. + pckInRiff - Pointer to the main riff. + phmmioOut - Pointer to output mmio file handle. + pckOut - Pointer to nice ckOut to use. + pckOutRiff - Pointer to the main riff. + + + Returns 0 if successful, else the error code. If this routine fails, it still attemps to seek back to + the start of the wave riff header, though this too could be unsuccessful. +*/ + +int WaveCopyUselessChunks( + HMMIO *phmmioIn, + MMCKINFO *pckIn, + MMCKINFO *pckInRiff, + HMMIO *phmmioOut, + MMCKINFO *pckOut, + MMCKINFO *pckOutRiff) +{ + + int nError; + + nError = 0; + // First seek to the stinking start of the file, not including the riff header... + if ((nError = mmioSeek(*phmmioIn, pckInRiff->dwDataOffset + sizeof(FOURCC), SEEK_SET)) == -1) + { + nError = ER_CANNOTREAD; + goto ERROR_IN_PROC; + } + + nError = 0; + + while (mmioDescend(*phmmioIn, pckIn, pckInRiff, 0) == 0) + { + + // quickly check for corrupt RIFF file--don't ascend past end! + if ((pckIn->dwDataOffset + pckIn->cksize) > (pckInRiff->dwDataOffset + pckInRiff->cksize)) + goto ERROR_IN_PROC; + + switch (pckIn->ckid) + { + // explicitly skip these... + case mmioFOURCC('f', 'm', 't', ' '): + break; + + case mmioFOURCC('d', 'a', 't', 'a'): + break; + + case mmioFOURCC('f', 'a', 'c', 't'): + break; + + case mmioFOURCC('J', 'U', 'N', 'K'): + break; + + case mmioFOURCC('P', 'A', 'D', ' '): + break; + + case mmioFOURCC('c', 'u', 'e', ' '): + break; + + // copy chunks that are OK to copy + case mmioFOURCC('p', 'l', 's', 't'): + // although without the 'cue' chunk, it doesn't make much sense + riffCopyChunk(*phmmioIn, *phmmioOut, pckIn); + break; + + case mmioFOURCC('D', 'I', 'S', 'P'): + riffCopyChunk(*phmmioIn, *phmmioOut, pckIn); + break; + + + // don't copy unknown chunks + default: + break; + } + + + // step up to prepare for next chunk.. + mmioAscend(*phmmioIn, pckIn, 0); + } + +ERROR_IN_PROC: + { + int nErrorT; + // Seek back to riff header + nErrorT = mmioSeek(*phmmioIn, pckInRiff->dwDataOffset + sizeof(FOURCC), SEEK_SET); + } + + return(nError); +} + +/** BOOL RIFFAPI riffCopyChunk(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck) + * + * DESCRIPTION: + * + * + * ARGUMENTS: + * (LPWAVECONVCB lpwc, LPMMCKINFO lpck) + * + * RETURN (BOOL NEAR PASCAL): + * + * + * NOTES: + * + ** */ + +BOOL riffCopyChunk(HMMIO hmmioSrc, HMMIO hmmioDst, const LPMMCKINFO lpck) +{ + MMCKINFO ck; + HPSTR hpBuf; + + // + // + // + hpBuf = (HPSTR)GlobalAllocPtr(GHND, lpck->cksize); + if (!hpBuf) + return (FALSE); + + ck.ckid = lpck->ckid; + ck.cksize = lpck->cksize; + if (mmioCreateChunk(hmmioDst, &ck, 0)) + goto rscc_Error; + + if (mmioRead(hmmioSrc, hpBuf, lpck->cksize) != (LONG)lpck->cksize) + goto rscc_Error; + + if (mmioWrite(hmmioDst, hpBuf, lpck->cksize) != (LONG)lpck->cksize) + goto rscc_Error; + + if (mmioAscend(hmmioDst, &ck, 0)) + goto rscc_Error; + + if (hpBuf) + GlobalFreePtr(hpBuf); + + return (TRUE); + +rscc_Error: + + if (hpBuf) + GlobalFreePtr(hpBuf); + + return (FALSE); +} /* RIFFSupCopyChunk() */ + + + +/* This routine loads a full wave file into memory. Be careful, wave files can get + pretty big these days :). + szFileName - sz Filename + cbSize - Size of loaded wave (returned) + cSamples - # of samples loaded. + ppwfxInfo - Pointer to pointer to waveformatex structure. The wfx structure + IS ALLOCATED by this routine! Make sure to free it! + ppbData - Pointer to a byte pointer (globalalloc) which is allocated by this + routine. Make sure to free it! + + Returns 0 if successful, else the error code. +*/ + +int WaveLoadFile( + TCHAR*pszFileName, // (IN) + UINT *cbSize, // (OUT) + WAVEFORMATEX **ppwfxInfo, // (OUT) + BYTE **ppbData // (OUT) + ) +{ + + HMMIO hmmioIn; + MMCKINFO ckInRiff; + MMCKINFO ckIn; + int nError; + UINT cbActualRead; + + *ppbData = NULL; + *ppwfxInfo = NULL; + *cbSize = 0; + + if ((nError = WaveOpenFile(pszFileName, &hmmioIn, ppwfxInfo, &ckInRiff)) != 0) + { + goto ERROR_LOADING; + } + + if ((nError = WaveStartDataRead(&hmmioIn, &ckIn, &ckInRiff)) != 0) + { + goto ERROR_LOADING; + } + + // Ok, size of wave data is in ckIn, allocate that buffer. + if ((*ppbData = (BYTE *)GlobalAlloc(GMEM_FIXED, ckIn.cksize)) == NULL) + { + nError = ER_MEM; + goto ERROR_LOADING; + } + + if ((nError = WaveReadFile(hmmioIn, ckIn.cksize, *ppbData, &ckIn, &cbActualRead)) != 0) + { + goto ERROR_LOADING; + } + + *cbSize = cbActualRead; + goto DONE_LOADING; + +ERROR_LOADING: + if (*ppbData != NULL) + { + GlobalFree(*ppbData); + *ppbData = NULL; + } + if (*ppwfxInfo != NULL) + { + GlobalFree(*ppwfxInfo); + *ppwfxInfo = NULL; + } + +DONE_LOADING: + // Close the wave file. + if (hmmioIn != NULL) + { + mmioClose(hmmioIn, 0); + hmmioIn = NULL; + } + + return(nError); + +} + +/* This routine saves a wave file in currently in memory. + pszFileName - FileName to save to. Automatically overwritten, be careful! + cbSize - Size in bytes to write. + cSamples - # of samples to write, used to make the fact chunk. (if !PCM) + pwfxDest - Pointer to waveformatex structure. + pbData - Pointer to the data. +*/ + +int WaveSaveFile( + TCHAR*pszFileName, // (IN) + UINT cbSize, // (IN) + DWORD cSamples, // (IN) + WAVEFORMATEX *pwfxDest, // (IN) + BYTE *pbData // (IN) + ) +{ + + HMMIO hmmioOut; + MMCKINFO ckOut; + MMCKINFO ckOutRIFF; + MMIOINFO mmioinfoOut; + UINT cbActualWrite; + int nError; + + if ((nError = WaveCreateFile(pszFileName, &hmmioOut, pwfxDest, &ckOut, &ckOutRIFF)) != 0) + { + goto ERROR_SAVING; + } + + if ((nError = WaveStartDataWrite(&hmmioOut, &ckOut, &mmioinfoOut)) != 0) + { + goto ERROR_SAVING; + } + + if ((nError = WaveWriteFile(hmmioOut, cbSize, pbData, &ckOut, &cbActualWrite, &mmioinfoOut)) != 0) + { + goto ERROR_SAVING; + } + + if ((nError = WaveCloseWriteFile(&hmmioOut, &ckOut, &ckOutRIFF, &mmioinfoOut, cSamples)) != 0) + { + goto ERROR_SAVING; + } + +ERROR_SAVING: + + return(nError); + +} + diff --git a/MuckyBasic/wave.h b/MuckyBasic/wave.h new file mode 100644 index 0000000..8d71853 --- /dev/null +++ b/MuckyBasic/wave.h @@ -0,0 +1,68 @@ +/*========================================================================== + * + * Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved. + * + * File: wave.h + * Content: wave header + * + ***************************************************************************/ +#ifndef __WAVE_INCLUDED__ +#define __WAVE_INCLUDED__ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WAVEVERSION 1 + +#ifndef ER_MEM +#define ER_MEM 0xe000 +#endif + +#ifndef ER_CANNOTOPEN +#define ER_CANNOTOPEN 0xe100 +#endif + +#ifndef ER_NOTWAVEFILE +#define ER_NOTWAVEFILE 0xe101 +#endif + +#ifndef ER_CANNOTREAD +#define ER_CANNOTREAD 0xe102 +#endif + +#ifndef ER_CORRUPTWAVEFILE +#define ER_CORRUPTWAVEFILE 0xe103 +#endif + +#ifndef ER_CANNOTWRITE +#define ER_CANNOTWRITE 0xe104 +#endif + + + +int WaveOpenFile(TCHAR*, HMMIO *, WAVEFORMATEX **, MMCKINFO *); +int WaveStartDataRead(HMMIO *, MMCKINFO *, MMCKINFO *); +int WaveReadFile(HMMIO, UINT, BYTE *, MMCKINFO *, UINT *); +int WaveCloseReadFile(HMMIO *, WAVEFORMATEX **); + +int WaveCreateFile(TCHAR*, HMMIO *, WAVEFORMATEX *, MMCKINFO *, MMCKINFO *); +int WaveStartDataWrite(HMMIO *, MMCKINFO *, MMIOINFO *); +int WaveWriteFile(HMMIO, UINT, BYTE *, MMCKINFO *, UINT *, MMIOINFO *); +int WaveCloseWriteFile(HMMIO *, MMCKINFO *, MMCKINFO *, MMIOINFO *, DWORD); + +int WaveLoadFile(TCHAR*, UINT *, WAVEFORMATEX **, BYTE **); +int WaveSaveFile(TCHAR*, UINT, DWORD, WAVEFORMATEX *, BYTE *); + +int WaveCopyUselessChunks(HMMIO *, MMCKINFO *, MMCKINFO *, HMMIO *, MMCKINFO *, MMCKINFO *); +BOOL riffCopyChunk(HMMIO, HMMIO, const LPMMCKINFO); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/fallen/AutoRun/AutoRun.cpp b/fallen/AutoRun/AutoRun.cpp new file mode 100644 index 0000000..7cb5385 --- /dev/null +++ b/fallen/AutoRun/AutoRun.cpp @@ -0,0 +1,626 @@ +// AutoRun.cpp +// +// Defines the entry point for the application + +#include "AutoRun.h" + +// defines + +#define WINCLASS "AUTORUN" + +// globals + +HINSTANCE hInst; // current instance +TCHAR szLanguage[MAX_PATH]; // the user's language +TCHAR szAutorunDir[MAX_PATH]; // the autorun directory +Director* pDirector; // the director structure +HCURSOR hNormalCursor; // the pointer +HCURSOR hSelectCursor; // the hand cursor + +Menu* pMenu; // current menu +Menu* pLastMenu; // last menu +MenuItem* pMenuItem; // current item +HBITMAP hBackground; // background bitmap +BITMAP bmBackground; // bitmap info +HFONT hMenuFont; // menu font + +// statics + +static ATOM MyRegisterClass(HINSTANCE hInstance); +static void GetLanguageData(void); +static Director* LoadMenuData(void); +static BOOL InitInstance(HINSTANCE, int); +static void OpenMenu(HWND hWnd, Menu* menu); +static void CloseMenu(); +static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +static void OnPaint(HWND hWnd); +static void OnMouseMove(HWND hWnd, int x, int y); +static void OnLButtonDown(HWND hWnd, int x, int y); +static bool MacroReplace(TCHAR* cmd, TCHAR* buffer, UINT blen); + +// WinMain +// +// entry point + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + // try and create an event + // this always succeeds + // if event existed before (still succeeds) and ERROR_ALREADY_EXISTS is returned, so die + // note the event is automatically deleted by the system when the app exits (even if it crashes) + HANDLE hEvent = CreateEventA(NULL, FALSE, FALSE, "AutoRunExclusionZone"); + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + return FALSE; + } + + // get the autorun directory + if (!GetCurrentDirectory(MAX_PATH, szAutorunDir)) + { + return FALSE; + } + + // remove trailing \ if present + int len = strlen(szAutorunDir); + if (szAutorunDir[len - 1] == '\\') szAutorunDir[len - 1] = '\0'; + + // go into AUTORUN directory + if (!SetCurrentDirectory("AUTORUN")) + { + return FALSE; + } + + // register window class + MyRegisterClass(hInstance); + + // get user's language info + GetLanguageData(); + + // load menu data + pDirector = LoadMenuData(); + + if (!pDirector) + { + return FALSE; + } + + // go back up + SetCurrentDirectory(".."); + + // init application instance + if (!InitInstance(hInstance, nCmdShow)) + { + delete pDirector; + return FALSE; + } + + // load accelerators + HACCEL hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_AUTORUN); + + // Main message loop: + MSG msg; + + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + delete pDirector; + + return msg.wParam; +} + +// MyRegisterClass +// +// register the window class + +static ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_CLASSDC; // keep a class DC for speed + wcex.lpfnWndProc = (WNDPROC)WndProc; // window proc + wcex.cbClsExtra = 0; // no class extra data + wcex.cbWndExtra = 0; // no window extra data + wcex.hInstance = hInstance; // us + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_AUTORUN); // icon + wcex.hCursor = NULL; // cursor + wcex.hbrBackground = NULL; // don't redraw background + wcex.lpszMenuName = NULL; // no menu + wcex.lpszClassName = WINCLASS; // class name from resource file + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_AUTORUN); // small icon + + return RegisterClassEx(&wcex); +} + +// GetLanguageData +// +// obtain user's language + +static void GetLanguageData(void) +{ + // get locale ID + LCID lcid = GetUserDefaultLCID(); + + // read language name (in English) + if (!GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, szLanguage, MAX_PATH)) + { + // copy default language name (English) + strcpy(szLanguage, "English"); + } +} + +// LoadMenuData +// +// load menu data + +static Director* LoadMenuData(void) +{ + FILE* fd; + TCHAR filename[MAX_PATH]; + + // first try to find .txt + sprintf(filename, "%s.txt", szLanguage); + fd = fopen(filename, "r"); + + if (!fd) + { + // try English.txt + strcpy(filename, "English.txt"); + fd = fopen(filename, "r"); + } + + if (!fd) return NULL; + + Director* obj = new Director(fd); + + fclose(fd); + + return obj; +} + +// InitInstance +// +// get system information +// create main window + +static BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + // store instance handle + hInst = hInstance; + + // load cursors + hNormalCursor = LoadCursor(NULL, (LPCTSTR)IDC_ARROW); + hSelectCursor = LoadCursor(hInstance, (LPCTSTR)IDC_SELECTCURSOR); + + // create window + hWnd = CreateWindow(WINCLASS, + pDirector->WindowTitle, + WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + NULL, NULL, hInstance, NULL); + + if (!hWnd) + { + return FALSE; + } + + // modify window menu + HMENU hMenu = GetSystemMenu(hWnd, FALSE); + + RemoveMenu(hMenu, SC_RESTORE, MF_BYCOMMAND); + RemoveMenu(hMenu, SC_SIZE, MF_BYCOMMAND); + RemoveMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND); + + // open the initial menu + OpenMenu(hWnd, pDirector->Active); + + // show the window + ShowWindow(hWnd, SW_SHOW); + UpdateWindow(hWnd); + + return TRUE; +} + +// OpenMenu +// +// open the given menu + +static void OpenMenu(HWND hWnd, Menu* menu) +{ + if (pMenu == menu) return; // no change + + if (pMenu) + { + CloseMenu(); + } + + // save menu pointer + pMenu = menu; + + // load bitmap + SetCurrentDirectory("AUTORUN"); + + hBackground = (HBITMAP)LoadImage(NULL, pMenu->Bitmap, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + + SetCurrentDirectory(".."); + + // get bitmap info + GetObject(hBackground, sizeof(BITMAP), &bmBackground); + + // get window rects, resize and centre + RECT winsize; + RECT clientsize; + RECT scrsize; + HWND hScreen; + + hScreen = GetDesktopWindow(); + + GetWindowRect(hWnd, &winsize); + GetClientRect(hWnd, &clientsize); + GetClientRect(hScreen, &scrsize); + + int width = (winsize.right - winsize.left) - (clientsize.right - clientsize.left) + bmBackground.bmWidth; + int height = (winsize.bottom - winsize.top) - (clientsize.bottom - clientsize.top) + bmBackground.bmHeight; + int xoff = ((scrsize.right - scrsize.left) - width) / 2; + int yoff = ((scrsize.bottom - scrsize.top) - height) / 2; + + SetWindowPos(hWnd, NULL, xoff, yoff, width, height, SWP_NOZORDER); + + // create font + hMenuFont = CreateFont(pMenu->FontSize, 0, 0, 0, pMenu->FontWeight, + FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + pMenu->FontName); + + // measure the menu strings + HDC hdc = GetDC(hWnd); + HFONT hOldFont = (HFONT)SelectObject(hdc, hMenuFont); + MenuItem* item = pMenu->Item; + ULONG y = pMenu->TopBorder; + + while (item) + { + SIZE sz; + + GetTextExtentPoint(hdc, item->Text, strlen(item->Text), &sz); + + item->Area.left = pMenu->LeftBorder; + item->Area.right = pMenu->LeftBorder + sz.cx; + item->Area.top = y; + item->Area.bottom = y + sz.cy; + + y += pMenu->LineSpacing * (1 + item->Spacing); + + item = item->Next; + } + + SelectObject(hdc, hOldFont); + ReleaseDC(hWnd, hdc); + + // refresh + InvalidateRect(hWnd, NULL, FALSE); + UpdateWindow(hWnd); + + // set normal cursor + SetCursor(hNormalCursor); +} + +// CloseMenu +// +// close the menu + +static void CloseMenu() +{ + pMenu = NULL; + pMenuItem = NULL; + + if (hBackground) DeleteObject(hBackground); + hBackground = NULL; + + if (hMenuFont) DeleteObject(hMenuFont); + hMenuFont = NULL; +} + +// WndProc +// +// the window procedure + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_PAINT: + OnPaint(hWnd); + break; + + case WM_MOUSEMOVE: + OnMouseMove(hWnd, LOWORD(lParam), HIWORD(lParam)); + break; + + case WM_LBUTTONDOWN: + OnLButtonDown(hWnd, LOWORD(lParam), HIWORD(lParam)); + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return 0; +} + +// OnPaint +// +// WM_PAINT handler + +static void OnPaint(HWND hWnd) +{ + PAINTSTRUCT ps; + + HDC hdc = BeginPaint(hWnd, &ps); + + // draw background bitmap + HDC hdcMem = CreateCompatibleDC(hdc); + SelectObject(hdcMem, hBackground); + + BitBlt(hdc, 0, 0, bmBackground.bmWidth, bmBackground.bmHeight, hdcMem, 0, 0, SRCCOPY); + + DeleteDC(hdcMem); + + // draw menu items + HFONT hFontOld = (HFONT)SelectObject(hdc, hMenuFont); + MenuItem* item = pMenu->Item; + SetBkMode(hdc, TRANSPARENT); + + while (item) + { + SetTextColor(hdc, pMenuItem == item ? pMenu->ColourSelected : pMenu->ColourNormal); + DrawTextEx(hdc, item->Text, -1, &item->Area, DT_SINGLELINE | DT_LEFT | DT_TOP, NULL); + item = item->Next; + } + + SelectObject(hdc, hFontOld); + + EndPaint(hWnd, &ps); +} + +// OnMouseMove +// +// WM_MOUSEMOVE handler + +static void OnMouseMove(HWND hWnd, int x, int y) +{ + MenuItem* over = NULL; + + MenuItem* item = pMenu->Item; + while (item) + { + if ((x >= item->Area.left) && (x <= item->Area.right) && + (y >= item->Area.top) && (y <= item->Area.bottom)) + { + over = item; + break; + } + item = item->Next; + } + + if (over == pMenuItem) return; // nothing to do + + HDC hdc = GetDC(hWnd); + HFONT hFontOld = (HFONT)SelectObject(hdc, hMenuFont); + SetBkMode(hdc, TRANSPARENT); + + // draw old menu item unselected + if (pMenuItem) + { + SetTextColor(hdc, pMenu->ColourNormal); + DrawTextEx(hdc, pMenuItem->Text, -1, &pMenuItem->Area, DT_SINGLELINE | DT_LEFT | DT_TOP, NULL); + } + + // draw new item selected + if (over) + { + SetTextColor(hdc, pMenu->ColourSelected); + DrawTextEx(hdc, over->Text, -1, &over->Area, DT_SINGLELINE | DT_LEFT | DT_TOP, NULL); + } + + SelectObject(hdc, hFontOld); + ReleaseDC(hWnd, hdc); + + pMenuItem = over; + SetCursor(pMenuItem ? hSelectCursor : hNormalCursor); +} + +// OnLButtonDown +// +// WM_LBUTTONDOWN handler + +static void OnLButtonDown(HWND hWnd, int x, int y) +{ + OnMouseMove(hWnd, x, y); + + if (!pMenuItem) return; + + // decode command + TCHAR* verb = pMenuItem->Verb; + TCHAR* doc = pMenuItem->Document; + TCHAR* dir = pMenuItem->Directory; + + // set defaults + if (!dir[0]) dir = "$SRC$"; + + bool bExit = false; + + if (verb[0] == '@') + { + bExit = true; + verb++; + } + + // run special verbs + if (!stricmp(verb, "uninstall")) + { + // uninstall - run the uninstall string + verb = "run"; + doc = pDirector->UninstallString; + bExit = true; + if (!doc[0]) + { + ReportError("Product is not installed"); + return; + } + } + else if (!stricmp(verb, "back")) + { + // back - go to the last menu + if (pLastMenu) + { + OpenMenu(hWnd, pLastMenu); + pLastMenu = NULL; + } + else + { + ReportError("'back' command in top-level menu"); + } + return; + } + else if (!stricmp(verb, "menu")) + { + // menu - go to a different menu + Menu* menu = pDirector->FindMenu(doc); + + if (menu) + { + pLastMenu = pMenu; + OpenMenu(hWnd, menu); + } + else + { + ReportError("No such submenu"); + } + return; + } + + // macro-replace the document and directory fields + TCHAR document[MAX_PATH]; + TCHAR directory[MAX_PATH]; + + if (!MacroReplace(doc, document, MAX_PATH)) return; + if (!MacroReplace(dir, directory, MAX_PATH)) return; + + // now run the verb + if (!stricmp(verb, "run")) + { + // run - use CreateProcess + STARTUPINFO sinfo; + + memset(&sinfo, 0, sizeof(sinfo)); + sinfo.cb = sizeof(sinfo); + + PROCESS_INFORMATION pinfo; + + if (!CreateProcess(NULL, document, NULL, NULL, FALSE, 0, NULL, directory, &sinfo, &pinfo)) + { + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, 0, NULL); + + ReportError((LPCTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + + return; + } + } + else if (verb[0]) + { + // other verb - use ShellExecute + ShellExecute(hWnd, verb, document, NULL, directory, SW_SHOWNORMAL); + } + + if (bExit) + { + PostQuitMessage(0); + } +} + +// MacroReplace +// +// copy cmd to buffer and perform macro replacement + +static bool MacroReplace(TCHAR* cmd, TCHAR* buffer, UINT blen) +{ + while (*cmd) + { + if (*cmd == '$') + { + cmd++; + + TCHAR* cptr = cmd; + + while (*cptr && (*cptr != '$')) cptr++; + + if (!*cptr) + { + ReportError("Illegal macro in command"); + return false; + } + + TCHAR* replace = NULL; + + if (!strnicmp(cmd, "src", cptr - cmd)) replace = szAutorunDir; + else if (!strnicmp(cmd, "dst", cptr - cmd)) replace = pDirector->AppPath; + + if (!replace || !replace[0]) + { + ReportError("No such macro"); + return false; + } + + if (blen < strlen(replace) + 1) + { + ReportError("Command is too long"); + return false; + } + + strcpy(buffer, replace); + buffer += strlen(replace); + blen -= strlen(replace); + cmd = cptr + 1; + } + else + { + if (blen < 2) + { + ReportError("Command is too long"); + return false; + } + else + { + *buffer++ = *cmd++; + blen--; + } + } + } + + *buffer++ = '\0'; + return true; +} diff --git a/fallen/AutoRun/AutoRun.cur b/fallen/AutoRun/AutoRun.cur new file mode 100644 index 0000000000000000000000000000000000000000..614403a0b640c99f740671b5753c4cfd05e53791 GIT binary patch literal 326 zcma*hF%AJi6oBD>2wSd-(w0h{lG`|f(jIM(AvBJ#B_YN?vm{~@F_Z7T%*(tt0|Nq8 z1tVY?U}|2-5*r0~T6K>75M%5Ye^iEdNQy_NG?$K;Yo?WU+TLJ%(oqLBa_%=v_=msN fCB*pF+LfHMeQfB|W?m-de9ykN&|1Fq>FW6jKVf?T literal 0 HcmV?d00001 diff --git a/fallen/AutoRun/AutoRun.dsp b/fallen/AutoRun/AutoRun.dsp new file mode 100644 index 0000000..f7850fc --- /dev/null +++ b/fallen/AutoRun/AutoRun.dsp @@ -0,0 +1,163 @@ +# Microsoft Developer Studio Project File - Name="AutoRun" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=AutoRun - 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 "AutoRun.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 "AutoRun.mak" CFG="AutoRun - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "AutoRun - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "AutoRun - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Fallen/AutoRun", UNCAAAAA" +# PROP Scc_LocalPath "." +CPP=xicl6.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "AutoRun - 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.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 advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "AutoRun - 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 /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.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 advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "AutoRun - Win32 Release" +# Name "AutoRun - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\AutoRun.cpp +# End Source File +# Begin Source File + +SOURCE=.\AutoRun.rc +# End Source File +# Begin Source File + +SOURCE=.\Director.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\AutoRun.h +# End Source File +# Begin Source File + +SOURCE=.\Director.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.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" +# Begin Source File + +SOURCE=.\AutoRun.cur +# End Source File +# Begin Source File + +SOURCE=.\AutoRun.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Autorun\English.txt +# End Source File +# Begin Source File + +SOURCE=.\Autorun\French.txt +# End Source File +# Begin Source File + +SOURCE=.\Autorun\German.txt +# End Source File +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# Begin Source File + +SOURCE=.\Autorun\Spanish.txt +# End Source File +# End Target +# End Project diff --git a/fallen/AutoRun/AutoRun.h b/fallen/AutoRun/AutoRun.h new file mode 100644 index 0000000..b330fb4 --- /dev/null +++ b/fallen/AutoRun/AutoRun.h @@ -0,0 +1,12 @@ +// AutoRun.h +// +// main header file for AutoRun + +// standard pre-compiled crap +#include "stdafx.h" + +// our stuff +#include "Director.h" + +// error reporting +inline void ReportError(const TCHAR* error) { MessageBox(NULL, error, "Error", MB_OK | MB_ICONINFORMATION); } diff --git a/fallen/AutoRun/AutoRun.ico b/fallen/AutoRun/AutoRun.ico new file mode 100644 index 0000000000000000000000000000000000000000..dd6d6c5c3be6fac295ec5d2558f2df6494f9a721 GIT binary patch literal 1078 zcmbtSF>b>!45Z=$=~U(i@l@m&>DGtz0nKJ_QYLxxmkgv2$;F+(?FnC5-`7R}Nb~bKq!JBQ7^!f5nzDX}Z|W0XVP~FSsM}BwQ}G z!i|-LTL4F&?Y_GiW6SCR^+?yFZC9LIpPLINN!m84R}W`x0;=#)IY!CImC*t;qwODdq>A{<+s9S1lJAif zqlbg)eqUbwjCf!_^T`E&s)lWT{anlYd42R}1}_KWw~uOYp&Ez^2T0_=1d|K<$^|#> zAIG=nOtd}`ZPj7)zDpm~=6nUN!SkFC(C<^gP{V?`E&?mm-_1EQnk!Uw6KUXhW-Eg13B(O1poj5 literal 0 HcmV?d00001 diff --git a/fallen/AutoRun/AutoRun.rc b/fallen/AutoRun/AutoRun.rc new file mode 100644 index 0000000..9e44261 --- /dev/null +++ b/fallen/AutoRun/AutoRun.rc @@ -0,0 +1,106 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "resource.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 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_AUTORUN ICON DISCARDABLE "AutoRun.ICO" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +IDC_SELECTCURSOR CURSOR DISCARDABLE "AutoRun.cur" +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/fallen/AutoRun/Autorun/English.txt b/fallen/AutoRun/Autorun/English.txt new file mode 100644 index 0000000..08ad763 --- /dev/null +++ b/fallen/AutoRun/Autorun/English.txt @@ -0,0 +1,57 @@ +"Urban Chaos CD-ROM" +"Urban Chaos" +"fallen.exe" +4 + +PREINSTALL +"background.bmp" +"Arial",18,700 +0,255,0 +255,255,0 +22,103,31 +"About Urban Chaos","open","readme.htm","",0 +"Install Urban Chaos","@open","setup.exe","",0 +"Install DirectX 6.1","open","dxinstall.exe","",0 +"Check System Requirements","","","",0 +"Websites...","menu","WEBLINKS","",0 +"EidosNet...","menu","EIDOSNET","",0 +"Explore this CD","explore","$SRC$","",1 +"Exit","@","","",-1 + +POSTINSTALL +"background.bmp" +"Arial",18,700 +0,255,0 +255,255,0 +22,103,31 +"About Urban Chaos","open","readme.htm","",0 +"Run Urban Chaos","open","$DST$\fallen.exe","$DST$",0 +"Reinstall Urban Chaos","open","setup.exe","",0 +"Uninstall Urban Chaos","uninstall","","",0 +"Install DirectX 6.1","open","dxinstall.exe","",0 +"Websites...","menu","WEBLINKS","",0 +"EidosNet...","menu","EIDOSNET","",0 +"Explore this CD","explore","$SRC$","",1 +"Exit","@","","",-1 + +WEBLINKS +"background.bmp" +"Arial",18,700 +0,255,0 +255,255,0 +22,103,31 +"Mucky Foot Productions Ltd","open","http://www.muckyfoot.com","",0 +"Eidos Interactive","open","http://www.eidos.com","",0 +"Technical Support","open","http://www.eidos.co.uk/support.html","",0 +"Warranty Information","open","http://www.eidos.co.uk/warranty.html","",1 +"Back","back","","",-1 + +EIDOSNET +"background.bmp" +"Arial",18,700 +0,255,0 +255,255,0 +22,103,31 +"Install EidosNet Software","open","$SRC$\eidosnet\setup.exe","$SRC$\eidosnet",0 +"Explore EidosNet Website","open","http://www.eidos.co.uk/eidosnet.html","",1 +"Back","back","","",-1 diff --git a/fallen/AutoRun/Autorun/French.txt b/fallen/AutoRun/Autorun/French.txt new file mode 100644 index 0000000..c47c6fd --- /dev/null +++ b/fallen/AutoRun/Autorun/French.txt @@ -0,0 +1,45 @@ +"Urban Chaos CD-ROM " +"URBAN CHAOS" +"FALLEN.EXE" +3 + +PREINSTALL +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Consulter le fichier Lisezmoi","OPEN","README.HTM","",0 +"Installer Urban Chaos","@OPEN","SETUP.EXE","",0 +"Installer DirectX 6.1","OPEN","DXINSTALL.EXE","",0 +"Vérifier la compatibilité matérielle","","","",0 +"Liens vers des sites Internet","MENU","WEBLINKS","",0 +"Ouvrir le CD-ROM","EXPLORE","$SRC$","",1 +"Quitter","@","","",-1 + +POSTINSTALL +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Consulter le fichier Lisezmoi","OPEN","README.HTM","",0 +"Jouer à Urban Chaos","OPEN","$DST$\FALLEN.EXE","$DST$",0 +"Réinstaller Urban Chaos","OPEN","SETUP.EXE","",0 +"Désinstaller Urban Chaos","UNINSTALL","","",0 +"Installer DirectX 6.1","OPEN","DXINSTALL.EXE","",0 +"Liens vers des sites Internet","MENU","WEBLINKS","",0 +"Ouvrir le CD-ROM","EXPLORE","$SRC$","",1 +"Quitter","@","","",-1 + +WEBLINKS +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Mucky Foot Productions Ltd","OPEN","http://www.muckyfoot.com","",0 +"Eidos Interactive","OPEN","http://www.eidos.com","",0 +"Assistance technique","OPEN","http://www.eidos.co.uk/support.html","",0 +"Garanties et informations contractuelles","OPEN","http://www.eidos.co.uk/warranty.html","",1 +"Précédent","back","","",-1 diff --git a/fallen/AutoRun/Autorun/German.txt b/fallen/AutoRun/Autorun/German.txt new file mode 100644 index 0000000..97cdabf --- /dev/null +++ b/fallen/AutoRun/Autorun/German.txt @@ -0,0 +1,45 @@ +"Urban Chaos CD-ROM" +"URBAN CHAOS" +"FALLEN.EXE" +3 + +PREINSTALL +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Zu Urban Chaos","OPEN","README.HTM","",0 +"Urban Chaos installieren","@OPEN","SETUP.EXE","",0 +"DirectX 6.1 installieren","OPEN","DXINSTALL.EXE","",0 +"Systemanforderungen prüfen","","","",0 +"Websites...","MENU","WEBLINKS","",0 +"Diese CD untersuchen","EXPLORE","$SRC$","",1 +"Beenden","@","","",-1 + +POSTINSTALL +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Zu Urban Chaos","OPEN","README.HTM","",0 +"Urban Chaos spielen","OPEN","$DST$\FALLEN.EXE","$DST$",0 +"Urban Chaos neu installieren","OPEN","SETUP.EXE","",0 +"Urban Chaos deinstallieren","UNINSTALL","","",0 +"DirectX 6.1 installieren","OPEN","DXINSTALL.EXE","",0 +"Websites...","MENU","WEBLINKS","",0 +"Diese CD untersuchen","EXPLORE","$SRC$","",1 +"Beenden","@","","",-1 + +WEBLINKS +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Mucky Foot Productions Ltd","OPEN","http://www.muckyfoot.com","",0 +"Eidos Interactive","OPEN","http://www.eidos.com","",0 +"Technischer Support","OPEN","http://www.eidos.co.uk/support.html","",0 +"Hinweise zur Gewährleistung","OPEN","http://www.eidos.co.uk/warranty.html","",1 +"Zurück","back","","",-1 diff --git a/fallen/AutoRun/Autorun/Spanish.txt b/fallen/AutoRun/Autorun/Spanish.txt new file mode 100644 index 0000000..6d29c32 --- /dev/null +++ b/fallen/AutoRun/Autorun/Spanish.txt @@ -0,0 +1,45 @@ +"Urban Chaos CD-ROM" +"URBAN CHAOS" +"FALLEN.EXE" +3 + +PREINSTALL +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Acerca de Urban Chaos","OPEN","README.HTM","",0 +"Instalar Urban Chaos","@OPEN","SETUP.EXE","",0 +"Instalar DirectX 6.1","OPEN","DXINSTALL.EXE","",0 +"Comprobar los requisitos del sistema","","","",0 +"Páginas web...","MENU","WEBLINKS","",0 +"Explorar este CD","EXPLORE","$SRC$","",1 +"Salir","@","","",-1 + +POSTINSTALL +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Acerca de Urban Chaos","OPEN","README.HTM","",0 +"Ejecutar Urban Chaos","OPEN","$DST$\FALLEN.EXE","$DST$",0 +"Volver a instalar Urban Chaos","OPEN","SETUP.EXE","",0 +"Desinstalar Urban Chaos","UNINSTALL","","",0 +"Instalar DirectX 6.1","OPEN","DXINSTALL.EXE","",0 +"Páginas web...","MENU","WEBLINKS","",0 +"Explorar este CD","EXPLORE","$SRC$","",1 +"Salir","@","","",-1 + +WEBLINKS +"BACKGROUND.BMP" +"ARIAL",18,700 +0,255,0 +255,255,0 +22,103,31 +"Mucky Foot Productions Ltd","OPEN","http://www.muckyfoot.com","",0 +"Eidos Interactive","OPEN","http://www.eidos.com","",0 +"Servicio técnico","OPEN","http://www.eidos.co.uk/support.html","",0 +"Información sobre la garantía","OPEN","http://www.eidos.co.uk/warranty.html","",1 +"Atrás","back","","",-1 diff --git a/fallen/AutoRun/Director.cpp b/fallen/AutoRun/Director.cpp new file mode 100644 index 0000000..095c703 --- /dev/null +++ b/fallen/AutoRun/Director.cpp @@ -0,0 +1,289 @@ +// Director.cpp +// +// director object + +#include "AutoRun.h" + +static TCHAR* ReadString(FILE* fd); +static ULONG ReadNumber(FILE* fd); +static COLORREF ReadRGB(FILE* fd); + +// Menu +// +// construct from file +// +// syntax: +// +// PREINSTALL menu name - PREINSTALL and POSTINSTALL must exist +// "menubackground.bmp" bitmap name +// "Arial",11,1 font name,size,bold flag +// 0,255,0 RGB colour for normal text +// 255,255,0 RGB colour for selected text +// 16,80,20 left border, top border, line seperation, in pixels +// "Install Urban Chaos","open","setup.exe","",1 for each item ,,,, +// ,-1 for line seperation is the menu terminator +// +// see readme.txt for details of command format + +Menu::Menu(FILE* fd) +{ + strcpy(Name, ReadString(fd)); + + strcpy(Bitmap, ReadString(fd)); + + strcpy(FontName, ReadString(fd)); + FontSize = ReadNumber(fd); + FontWeight = ReadNumber(fd); + + ColourNormal = ReadRGB(fd); + ColourSelected = ReadRGB(fd); + + LeftBorder = ReadNumber(fd); + TopBorder = ReadNumber(fd); + LineSpacing = ReadNumber(fd); + + MenuItem* last = NULL; + + for (;;) + { + MenuItem* item = new MenuItem; + + strcpy(item->Text, ReadString(fd)); + + strcpy(item->Verb, ReadString(fd)); + strcpy(item->Document, ReadString(fd)); + strcpy(item->Directory, ReadString(fd)); + + item->Spacing = ReadNumber(fd); + item->Next = NULL; + + if (last) last->Next = item; + else Item = item; + + last = item; + + if (item->Spacing & 0x80000000) break; + } + + Next = NULL; +} + +// ~Menu +// +// destructor + +Menu::~Menu() +{ + while (Item) + { + MenuItem* item = Item; + Item = item->Next; + + delete item; + } +} + +// Director(fd) +// +// construct from file +// +// syntax: +// +// "Urban Chaos CD-ROM" window title +// "Urban Chaos" app name in Uninstall part of registry +// "fallen.exe" program name in App Paths part of registry +// 2 number of menus +// +// [menus] + +Director::Director(FILE* fd) +{ + strcpy(WindowTitle, ReadString(fd)); + strcpy(AppName, ReadString(fd)); + strcpy(ExeName, ReadString(fd)); + + ULONG menus = ReadNumber(fd); + + Menu* last = NULL; + + for (ULONG ii = 0; ii < menus; ii++) + { + Menu* menu = new Menu(fd); + + if (last) last->Next = menu; + else MenuList = menu; + + last = menu; + } + + PreInstall = FindMenu("PREINSTALL"); + PostInstall = FindMenu("POSTINSTALL"); + + LoadRegistryStrings(); +} + +// ~Director +// +// destructor + +Director::~Director() +{ + while (MenuList) + { + Menu* menu = MenuList; + MenuList = menu->Next; + delete menu; + } +} + +// LoadRegistryStrings +// +// load strings from the registry + +void Director::LoadRegistryStrings() +{ + strcpy(UninstallString, ""); + strcpy(AppPath, ""); + + HKEY hCurrentVersion; + + if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &hCurrentVersion)) + { + HKEY hUninstall; + + if (!RegOpenKeyEx(hCurrentVersion, "Uninstall", 0, KEY_READ, &hUninstall)) + { + HKEY hOurUninstall; + + if (!RegOpenKeyEx(hUninstall, AppName, 0, KEY_READ, &hOurUninstall)) + { + DWORD len = MAX_PATH; + + RegQueryValueEx(hOurUninstall, "UninstallString", NULL, NULL, (unsigned char*)UninstallString, &len); + + RegCloseKey(hOurUninstall); + } + + RegCloseKey(hUninstall); + } + + HKEY hAppPaths; + + if (!RegOpenKeyEx(hCurrentVersion, "App Paths", 0, KEY_READ, &hAppPaths)) + { + HKEY hOurAppPath; + + if (!RegOpenKeyEx(hAppPaths, ExeName, 0, KEY_READ, &hOurAppPath)) + { + DWORD len = MAX_PATH; + + RegQueryValueEx(hOurAppPath, "Path", NULL, NULL, (unsigned char*)AppPath, &len); + if ((len >= 2) && (AppPath[len - 2] == '\\')) AppPath[len - 2] = '\0'; + + RegCloseKey(hOurAppPath); + } + + RegCloseKey(hAppPaths); + } + + RegCloseKey(hCurrentVersion); + } + + + + if (UninstallString[0] && AppPath[0]) Active = PostInstall; + else Active = PreInstall; +} + +// FindMenu +// +// find a named menu + +Menu* Director::FindMenu(TCHAR* name) +{ + Menu* menu = MenuList; + + while (menu) + { + if (!stricmp(menu->Name, name)) break; + menu = menu->Next; + } + + return menu; +} + +// +// file reading utilities +// + +static TCHAR szBuffer[MAX_PATH]; + +// ReadString +// +// read to the next terminator (, or newline) +// skips "" so e.g. "Eddie, Matt","Mike, Mark" gives two strings +// \" is accepted as a quoted " +// +// note that no overflow checks are made - don't put huge strings into the definition files, please! + +static TCHAR* ReadString(FILE* fd) +{ + TCHAR* wptr = szBuffer; + bool quoted = false; + bool wasquoted = false; + + for (;;) + { + int ch = fgetc(fd); + + if ((ch == '\n') || (ch == EOF) || ((ch == ',') && !quoted)) + { + if ((wptr != szBuffer) || (ch == EOF)) + { + *wptr = '\0'; + return szBuffer; + } + if ((wptr == szBuffer) && wasquoted) + { + *wptr = '\0'; + return szBuffer; + } + // otherwise continue + } + else if (ch == '\"') + { + quoted = !quoted; + wasquoted = true; + } + else if (ch == ' ') + { + if (quoted) *wptr++ = ' '; + } + else + { + *wptr++ = ch; + } + } +} + +// ReadNumber +// +// read a number + +static ULONG ReadNumber(FILE* fd) +{ + return ULONG(atoi(ReadString(fd))); +} + +// ReadRGB +// +// read an RGB value + +static COLORREF ReadRGB(FILE* fd) +{ + int r = ReadNumber(fd); + int g = ReadNumber(fd); + int b = ReadNumber(fd); + + return RGB(r,g,b); +} diff --git a/fallen/AutoRun/Director.h b/fallen/AutoRun/Director.h new file mode 100644 index 0000000..4ddc02e --- /dev/null +++ b/fallen/AutoRun/Director.h @@ -0,0 +1,72 @@ +// Director.h +// +// Director object + +// MenuItem +// +// a menu item + +struct MenuItem +{ + TCHAR Text[MAX_PATH]; // text for menu + + TCHAR Verb[MAX_PATH]; // verb for command - open, explore, menu, uninstall, back + TCHAR Document[MAX_PATH]; // document/executable for command + TCHAR Directory[MAX_PATH]; // directory for command + + ULONG Spacing; // number of extra lines after menu item + MenuItem* Next; // next item in menu + RECT Area; // area of menu item in window +}; + +// Menu +// +// a menu + +struct Menu +{ + TCHAR Name[MAX_PATH]; // name of menu + TCHAR Bitmap[MAX_PATH]; // name of bitmap for menu + TCHAR FontName[MAX_PATH]; // font name for menu text + ULONG FontSize; // font size (pixels) + ULONG FontWeight; // font weight + COLORREF ColourNormal; // normal colour (0x00BBGGRR) + COLORREF ColourSelected; // selected colour (0x00BBGGRR) + ULONG LeftBorder; // x of left border (pixels) + ULONG TopBorder; // y of top border (pixels) + ULONG LineSpacing; // spacing between lines (pixels) + MenuItem* Item; // first item in menu + Menu* Next; // next menu in list + + Menu(); // set defaults + Menu(FILE* fd); // load from file + ~Menu(); // delete +}; + +// Director +// +// top-level control + +struct Director +{ + // data loaded from file + TCHAR WindowTitle[MAX_PATH]; // title for main window + TCHAR AppName[MAX_PATH]; // app name in registry + TCHAR ExeName[MAX_PATH]; // executable name in registry + + TCHAR UninstallString[MAX_PATH]; // uninstall string + TCHAR AppPath[MAX_PATH]; // application path + + Menu* MenuList; // list of menus + Menu* PreInstall; // preinstall menu + Menu* PostInstall; // postinstall menu + Menu* Active; // active menu + + Director(); // create default menus + Director(FILE* fd); // load from file + ~Director(); // delete + + void LoadRegistryStrings(); // load UninstallString[] and RunString[] from the registry + + Menu* FindMenu(TCHAR* name); // find a named menu +}; diff --git a/fallen/AutoRun/ReadMe.txt b/fallen/AutoRun/ReadMe.txt new file mode 100644 index 0000000..96ab919 --- /dev/null +++ b/fallen/AutoRun/ReadMe.txt @@ -0,0 +1,134 @@ +AutoRun +------- + +AutoRun is a simple CD front-end. It supports internationalization (Western alphabets only), 2-level +menus and automatic detection of the installation of a product. The executable is fully configurable +via text files and bitmaps. + +Basic Behaviour +--------------- + +AutoRun must be in the root directory of the CD, and there must be an AUTORUN directory containing at +least one background bitmap and one menu file called English.txt. + +When AutoRun is started (via Autorun.inf) it first finds the language name for the user's machine e.g +English, French, Italian etc. It then looks in AUTORUN for a file called .txt. If this +file does not exist AutoRun loads English.txt as the default (if this is not found, AutoRun exits). + +The file is then loaded and parsed. This yields a set of Menu Definitions as well as global data - +the window title, the registry key for uninstallation and the registry key for the application. + +If these registry keys exist, then the menu called POSTINSTALL is displayed, else the menu called +PREINSTALL is displayed. + +Displaying a Menu +----------------- + +Each menu can have its own background bitmap, font size, colours, etc. The bitmap must be in the +AUTORUN subdirectory of the CD, along with the menu definition files. + +The window is resized to fit the bitmap, and centred on the screen. The menu strings are displayed +starting at specified top,left coordinates, and each line is a specified number of pixels below the +last. + +When the user points to an item, it changes colour. Clicking once invokes that item. + +Registry Keys +------------- + +Some standard registry keys are used: + +HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\ + +has value UninstallString which is the command line to run to uninstall the game. The is +the normal name (with spaces) of the game e.g. "Urban Chaos" + +HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\ + +has values (Default) which is the command line to run to execute the game, and Path which is the +directory to enter when running the game. The is the actual name of the executable +e.g. "fallen.exe" Only Path is used by AutoRun.exe. + +File Format +----------- + +The file is a simple text file. Fields are seperated by commas or newline. Fields should be either +single words or numbers, or strings in quotes (""). The first 4 lines of the file define the global +data: + +"Urban Chaos CD-ROM" This is the title displayed in the AutoRun window +"Urban Chaos" This is the name of the registry key containing uninstall info +"fallen.exe" This is the name of the registry key containing run info +4 The number of menus in the file + +This header is followed by the menu data. Each menu is independent. + +Menu Data +--------- + +The menu data consists of a header, followed by a series of menu items. The header format is as +follows: + +PREINSTALL The menu name - this can be anything but PREINSTALL and + POSTINSTALL are the root menus +"background.bmp" The name of the bitmap used as a background (in AUTORUN\) +"Arial",18,700 The font name, size and weight to be used for the menu +0,255,0 The RGB colour to be used for unselected items +255,255,0 The RGB colour to be used for selected items +22,103,31 Left border, top border and line seperation, in pixels + +This header is followed by menu items. Each item takes the form: + +,,,, + + the menu text which will be printed on-screen. You should use ... at the end of the + line if the menu opens a submenu + the verb to be executed (see below) + the document, executable or command-line + the directory in which to execute the verb + the number of extra lines to leave after this line - if -1, this is the last menu item + +Verbs +----- + +If a verb starts with @ then after executing it, AutoRun quits. You should use @ before running +the setup program, then the setup program should re-run AutoRun so it can check the registry +again. @ alone can be used for an "exit" menu item + +open used in 90% of cases - opens the document, folder or executable specified +run runs the specified command-line - this allows you to specify additional arguments +menu opens the submenu specified - only one level of submenu depth is supported +back returns to the top-level menu +uninstall runs the uninstaller (using the command-line from the registry) + +Macros +------ + +The and are macro-expanded before being used. The following macros are +replaced: + +$SRC$ replaced with the source directory (containing AutoRun.exe) i.e. D: or similar +$DST$ replaced with the destination directory, if installed i.e. C:\Urban Chaos or similar + +If is "" then it defaults to "$SRC$" + +Examples +-------- + +"open","readme.htm","" opens "\readme.htm" in a web browser + +"@open","setup.exe","" runs "\setup.exe" then quits + +"menu","WEBLINKS","" opens the WEBLINKS submenu + +"open","$SRC$","" opens in explorer + +"@","","" exits the program + +"open","http://www.muckyfoot.com" opens http://www.muckyfoot.com in a web browser + +"open","$SRC$\eidosnet\setup.exe","$SRC$\eidosnet" + + runs "\eidosnet\setup.exe" in "\eidosnet" + +"open","$DST$\fallen.exe","$DST$" runs fallen.exe in the installation directory diff --git a/fallen/AutoRun/StdAfx.cpp b/fallen/AutoRun/StdAfx.cpp new file mode 100644 index 0000000..5d38d54 --- /dev/null +++ b/fallen/AutoRun/StdAfx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : source file that includes just the standard includes +// AutoRun.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/fallen/AutoRun/StdAfx.h b/fallen/AutoRun/StdAfx.h new file mode 100644 index 0000000..b609d04 --- /dev/null +++ b/fallen/AutoRun/StdAfx.h @@ -0,0 +1,22 @@ +// stdafx.h +// +// standard crap + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +// windows +#include +#include + +// C stuff +#include +#include +#include +#include +#include + +// NLS stuff +#include + +// resources +#include "resource.h" diff --git a/fallen/AutoRun/resource.h b/fallen/AutoRun/resource.h new file mode 100644 index 0000000..4afdc6c --- /dev/null +++ b/fallen/AutoRun/resource.h @@ -0,0 +1,28 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by AutoRun.rc +// +#define IDC_MYICON 2 +#define IDD_AUTORUN_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDS_APP_TITLE 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDS_HELLO 106 +#define IDI_AUTORUN 107 +#define IDI_SMALL 108 +#define IDC_AUTORUN 109 +#define IDR_MAINFRAME 128 +#define IDC_SELECTCURSOR 130 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 131 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/fallen/DDEngine/Headers/BreakTimer.h b/fallen/DDEngine/Headers/BreakTimer.h new file mode 100644 index 0000000..c2a9756 --- /dev/null +++ b/fallen/DDEngine/Headers/BreakTimer.h @@ -0,0 +1,34 @@ +// BreakTimer.h +// +// break timer + +// Interface: +// +// Simply call BreakTime(name) at each breakpoint and BreakFrame() after the screen flip call +// Call BreakStart() and BreakEnd() at start/end of game replay code +// +// The library reports on the times between frames and breakpoints +// by storing peak times (min and max) and average time between points + +//#define BREAKTIMER + +#ifdef BREAKTIMER + +extern void BreakStart(); +extern void BreakEnd(const char* filename); +extern void BreakTime(const char* name); +extern void BreakFacets(ULONG facets); +extern void BreakFrame(); + +#else + +#define BreakStart() 0 +#define BreakEnd(X) 0 +#define BreakTime(X) 0 +#define BreakFacets(N) 0 +#define BreakFrame() 0 + +#endif + +extern void StartStopwatch(); +extern float StopStopwatch(); diff --git a/fallen/DDEngine/Headers/Bucket.h b/fallen/DDEngine/Headers/Bucket.h new file mode 100644 index 0000000..14e4e68 --- /dev/null +++ b/fallen/DDEngine/Headers/Bucket.h @@ -0,0 +1,178 @@ +// Bucket.h +// Guy Simmons, 24th October 1997. + +#ifndef BUCKET_H +#define BUCKET_H + +//--------------------------------------------------------------- + +#define MAX_LISTS 24 +#define MAX_BUCKETS 1024 +#define BUCKET_POOL_SIZE (512*1024) + +#define TEXTURE_LIST_1 0 +#define TEXTURE_LIST_2 1 +#define TEXTURE_LIST_3 2 +#define TEXTURE_LIST_4 3 +#define TEXTURE_LIST_5 4 +#define TEXTURE_LIST_6 5 + +#define LAST_NORMAL_PAGE (MAX_LISTS-8) + +#define SKY_LIST_2 (MAX_LISTS-7) +#define SKY_LIST_1 (MAX_LISTS-6) +#define MASK_LIST_1 (MAX_LISTS-5) +#define COLOUR_LIST_1 (MAX_LISTS-4) +#define WATER_LIST_1 (MAX_LISTS-3) +#define ALPHA_LIST_1 (MAX_LISTS-2) +#define FOG_LIST_1 (MAX_LISTS-1) + +#define BUCKET_NONE 0 +#define BUCKET_QUAD 1 +#define BUCKET_TRI 2 +#define BUCKET_LINE 3 +#define BUCKET_POINT 4 + +#define GET_BUCKET(s) (s*)e_buckets;e_buckets+=sizeof(s) +#define BUCKETS_FULL (e_buckets>=e_end_buckets) + +struct BucketHead +{ + BucketHead *NextBucket; + ULONG BucketType; +}; + +struct BucketQuad +{ + BucketHead BucketHeader; + UWORD P[4]; +}; + +struct BucketTri +{ + BucketHead BucketHeader; + UWORD P[4]; +}; + +struct BucketLine +{ + BucketHead BucketHeader; + UWORD P[2]; +}; + +struct BucketPoint +{ + BucketHead BucketHeader; + UWORD P[2]; +}; + +extern UBYTE e_bucket_pool[BUCKET_POOL_SIZE], + *e_buckets, + *e_end_buckets; +extern BucketHead *bucket_lists[MAX_LISTS][MAX_BUCKETS+1]; + +//--------------------------------------------------------------- + +inline void reset_buckets(void) +{ + e_buckets = e_bucket_pool; + e_end_buckets = &e_bucket_pool[BUCKET_POOL_SIZE]; +} + +//--------------------------------------------------------------- + +inline SLONG check_vertex(D3DTLVERTEX *v) +{ + if(v->sz<0.0 || v->sz>1.0 || v->rhw<0.0 || v->rhw>1.0) + return(1); + else + return(0); + +} +extern D3DTLVERTEX vertex_pool[]; + +inline void add_bucket(BucketHead *header,UBYTE bucket_type,SLONG list_index,SLONG z) +{ + SLONG c0; + BucketQuad *the_quad; + BucketTri *the_tri; + BucketLine *the_line; + D3DTLVERTEX *vertex; + +/* + SLONG index; + + + if(z>0) + index = MAX_BUCKETS/z; + else if(z==0) + index = MAX_BUCKETS; + else + index = 0; + + header->BucketType = bucket_type; + header->NextBucket = bucket_lists[list_index][index]; + bucket_lists[list_index][index] = header; +*/ + header->BucketType = bucket_type; + header->NextBucket = bucket_lists[list_index][z]; + bucket_lists[list_index][z] = header; +/* + switch(bucket_type) + { + case BUCKET_QUAD: + the_quad=(struct BucketQuad*)header; + for(c0=0;c0<4;c0++) + { + SLONG p0; + vertex=&vertex_pool[the_quad->P[c0]]; + + if(check_vertex(vertex)) + { + ASSERT(0); + } + } + + break; + case BUCKET_TRI: + the_tri=(struct BucketTri*)header; + for(c0=0;c0<3;c0++) + { + SLONG p0; + vertex=&vertex_pool[the_tri->P[c0]]; + + if(check_vertex(vertex)) + { + ASSERT(0); + } + } + break; + case BUCKET_LINE: + the_line = (BucketLine*)header; + for(c0=0;c0<2;c0++) + { + SLONG p0; + vertex=&vertex_pool[the_line->P[c0]]; + + if(check_vertex(vertex)) + { + ASSERT(0); + } + } + break; + + } +*/ + +} + +//--------------------------------------------------------------- + +void init_buckets(void); + +//--------------------------------------------------------------- + +#endif + + + diff --git a/fallen/DDEngine/Headers/Crinkle.h b/fallen/DDEngine/Headers/Crinkle.h new file mode 100644 index 0000000..85292a6 --- /dev/null +++ b/fallen/DDEngine/Headers/Crinkle.h @@ -0,0 +1,75 @@ +// +// Crinkles! +// + +#ifndef CRINKLE_H +#define CRINKLE_H + + +#include "aeng.h" +#include "poly.h" +#include "fileclump.h" + + +typedef UWORD CRINKLE_Handle; + + +// +// Clears out all the crinkles and invalidates all the handles. +// + +void CRINKLE_init(void); + + +// +// Loads the given crinkle in and returns its handle. Returns +// CRINKLE_NULL if it could not load the crinkle. +// + +CRINKLE_Handle CRINKLE_load(CBYTE *sex_filename); +CRINKLE_Handle CRINKLE_read_bin(FileClump* tclump, int id); + +void CRINKLE_write_bin(FileClump* tclump, CRINKLE_Handle hnd, int id); + +// +// Sets the view-space light vector. +// + +void CRINKLE_light(float dx, float dy, float dz); + + +// +// Tells the crinkle module how view-space is skewed. +// + +void CRINKLE_skew(float aspect, float lens); + + + +// +// Draws a crinkle extruded by 'amount' from 0.0 to 1.0 between +// the four points. +// + +void CRINKLE_do( + CRINKLE_Handle crinkle, + SLONG page, + float amount, + POLY_Point *pp[4], + SLONG flip); + + +// +// Projects an SMAP shadow over the crinkle. +// + +void CRINKLE_project( + CRINKLE_Handle crinkle, + float amount, + SVector_F poly[4], + SLONG flip); + + + + +#endif diff --git a/fallen/DDEngine/Headers/DCback.h b/fallen/DDEngine/Headers/DCback.h new file mode 100644 index 0000000..f5c0c3b --- /dev/null +++ b/fallen/DDEngine/Headers/DCback.h @@ -0,0 +1,26 @@ +// +// The background... +// + +#ifndef _BACK_ +#define _BACK_ + + + +// +// Loads the textures. +// + +void BACK_init(void); + + +// +// Draws the background polys- it clears both the screen and +// the z-buffer. +// + +void BACK_draw(void); + + + +#endif diff --git a/fallen/DDEngine/Headers/DCcredits.h b/fallen/DDEngine/Headers/DCcredits.h new file mode 100644 index 0000000..9fd0901 --- /dev/null +++ b/fallen/DDEngine/Headers/DCcredits.h @@ -0,0 +1,14 @@ +// +// Draws the credits +// + +#ifndef _CREDITS_ +#define _CREDITS_ + +// +// Do the credits... +// + +void CREDITS_do(void); + +#endif diff --git a/fallen/DDEngine/Headers/DCfont.h b/fallen/DDEngine/Headers/DCfont.h new file mode 100644 index 0000000..84cef4f --- /dev/null +++ b/fallen/DDEngine/Headers/DCfont.h @@ -0,0 +1,56 @@ +// +// A font! That's all there is to it. +// + +#ifndef _FONT_ +#define _FONT_ + + +// +// Loads in the font texture and calculates the uv's of the letters. +// + +void FONT_init(void); + + + +// +// Returns TRUE if the FONT module can draw the ASCII character. +// + +SLONG FONT_char_is_valid(CBYTE ch); + + + +// +// Draws some text. When you shimmer the text, it gets drawn more transparent too... +// + +#define FONT_FLAG_JUSTIFY_LEFT 0 // Default... +#define FONT_FLAG_JUSTIFY_CENTRE (1 << 0) +#define FONT_FLAG_JUSTIFY_RIGHT (1 << 1) +#define FONT_FLAG_ITALIC (1 << 2) + +// +// After the function returns these values say where the next character +// would have been drawn. +// + +extern float FONT_end_x; +extern float FONT_end_y; + +void FONT_draw( + SLONG flag, + float start_x, + float start_y, + ULONG colour, + float scale, // 1.0F => Normal scale + SLONG cursor, // If cursor is >= 0, then a cursor is drawn after the 'cursor'th character + float shimmer, // How much to shimmer. 0.0F => no shimmering, 1.0F => maximum shimmering. + CBYTE *fmt, ...); + + + + + +#endif diff --git a/fallen/DDEngine/Headers/DCos.h b/fallen/DDEngine/Headers/DCos.h new file mode 100644 index 0000000..5d15144 --- /dev/null +++ b/fallen/DDEngine/Headers/DCos.h @@ -0,0 +1,47 @@ +// +// Sprite drawing routines for the DC credits sequence. +// + +#ifndef _DCOS_ +#define _DCOS_ + + + +// +// A new buffer. +// + +typedef struct dcos_buffer DCOS_Buffer; + +DCOS_Buffer *DCOS_buffer_new(void); + + +// +// Add sprites to the buffer. +// + +void DCOS_buffer_add_sprite( + DCOS_Buffer *ob, + float x1, float y1, + float x2, float y2, + float u1 = 0.0F, float v1 = 0.0F, + float u2 = 1.0F, float v2 = 1.0F, + float z = 0.0F, + ULONG colour = 0x00ffffff, + ULONG specular = 0x00000000, + ULONG fade = 0); + + +// +// Draws the given buffer. +// + +#define DCOS_DRAW_NORMAL 0 +#define DCOS_DRAW_ADD 1 + +void DCOS_buffer_draw(OS_Buffer *ob, D3DTexture *texture, ULONG draw = DCOS_DRAW_NORMAL); + + + + +#endif diff --git a/fallen/DDEngine/Headers/DrawXtra.h b/fallen/DDEngine/Headers/DrawXtra.h new file mode 100644 index 0000000..3ec754d --- /dev/null +++ b/fallen/DDEngine/Headers/DrawXtra.h @@ -0,0 +1,66 @@ +// +// DrawXtra.h +// Matthew Rosenfeld 12 October 1998 +// +// In order to make fallen more PSX-friendly, the various Really Gnasty Hacks scattered +// throughout the game code to draw "special" objects are being collected together in +// drawxtra.cpp -- stuff like the van, helicopter, footprints, etc. +// + +#ifndef _DRAWXTRA_H_ +#define _DRAWXTRA_H_ + +#include "MFStdLib.h" +#include "game.h" +#include "thing.h" +#include "ribbon.h" + +#define BLOOM_GLOW_ALWAYS 1 +#define BLOOM_LENSFLARE 2 +#define BLOOM_BEAM 4 +#define BLOOM_FAINT 8 +#define BLOOM_NOGLOW 16 +#define BLOOM_RAISE_LOS 32 // raise LOS point by 16 units + +#define BLOOM_FLENSFLARE (BLOOM_LENSFLARE|BLOOM_FAINT) + +void CHOPPER_draw_chopper(Thing *p_chopper); +void TRACKS_DrawTrack(Thing *p_thing); +void PARTICLE_Draw(); +void PYRO_draw_pyro(Thing *p_pyro); +void RIBBON_draw_ribbon(Ribbon *ribbon); +void BLOOM_draw(SLONG x, SLONG y, SLONG z, SLONG dx, SLONG dy, SLONG dz, SLONG col, UBYTE opts=BLOOM_LENSFLARE|BLOOM_BEAM); +void BLOOM_flare_draw(SLONG x, SLONG y, SLONG z, SLONG str); +void DRAWXTRA_Special(Thing *p_thing); +void ANIMAL_draw(Thing *p_thing); + +void DRAW2D_Box(SLONG x, SLONG y, SLONG ox, SLONG oy, SLONG rgb, UBYTE flag, UBYTE depth=128); +#ifndef PSX +void DRAW2D_Box_Page(SLONG x, SLONG y, SLONG ox, SLONG oy, SLONG rgb, SLONG page, UBYTE depth=128); +#endif +void DRAW2D_Tri(SLONG x, SLONG y, SLONG ox, SLONG oy, SLONG tx, SLONG ty, SLONG rgb, UBYTE flag); +void DRAW2D_Sprite(SLONG x, SLONG y, SLONG ox, SLONG oy, float u, float v, float ou, float ov, SLONG page, SLONG rgb); + +// +// Draws the final glowwy thing for the Guardian of Baalrog. A fade of 0 means transparent +// 255 is completely faded in. +// + +void DRAWXTRA_final_glow(SLONG x, SLONG y, SLONG z, UBYTE fade); +void DRAWXTRA_MIB_destruct(Thing *p_thing); + + +// Do this to throttle effects down to sensible levels. + +// Called with how many sprites are wanted. +// Returns the number it can have. +int IWouldLikeSomePyroSpritesHowManyCanIHave ( int iIWantThisMany ); +// If the rout can't change how many it uses, at least call this to warn the pyro system that they will be used. +void IHaveToHaveSomePyroSprites( int iINeedThisMany ); + + +// Just call this once a frame, would you? Ta. +void Pyros_EndOfFrameMarker ( void ); + + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Headers/Engine.h b/fallen/DDEngine/Headers/Engine.h new file mode 100644 index 0000000..e51d144 --- /dev/null +++ b/fallen/DDEngine/Headers/Engine.h @@ -0,0 +1,383 @@ +// Engine.h +// Guy Simmons, 18th October 1997 + +#ifndef ENGINE_H +#define ENGINE_H + +#include "Game.h" +#include "DDLib.h" + +#include "Gamut.h" +#include "Bucket.h" +#include "Message.h" +#include + +void DebugText(CBYTE *error, ...); + + +// +// This is the palette used by the gouraud-shaded +// faces. Their 'Col' field is an index into this +// array. +// + + +// +// Loads the palette +// + +//void ENGINE_load_palette(CBYTE *palette); + + +// +// Given a ULONG packed d3d colour or specalar value, it +// returns the ULONG multiplied by (r,g,b). r, g and b should +// be from 0 - 255 +// + +inline ULONG ENGINE_multiply_colour(ULONG colour, SLONG r, SLONG g, SLONG b) +{ + ULONG ans; + + SLONG cr = (colour >> 8) & 0xff; + SLONG cg = (colour >> 16) & 0xff; + SLONG cb = (colour >> 24) & 0xff; + + cr *= r; + cg *= g; + cb *= b; + + cr >>= 8; + cg >>= 8; + cb >>= 8; + + ans = (cr << 0) | (cg << 8) | (cb << 16); +#ifdef TARGET_DC + ans |= 0xff000000; +#endif + + return ans; +} + + + +//--------------------------------------------------------------- +// Engine Maths stuff. + +struct M31 +{ + float R[3]; +}; + +typedef struct M31 M31; + +#define UV_X R[0] +#define UV_Y R[1] +#define UV_Z R[2] + +#define SET_M31(v,x,y,z) (v)->UV_X=x;(v)->UV_Y=y;(v)->UV_Z=z; +#define VECTOR_LENGTH_SQUARED(v) (float)(((v)->UV_X*(v)->UV_X)+((v)->UV_Y*(v)->UV_Y)+((v)->UV_Z*(v)->UV_Z)) +#define VECTOR_LENGTH(v) (float)sqrt(VECTOR_LENGTH_SQUARED(v)) +#define DOT_PRODUCT(v,w) ((v)->UV_X*(w)->UV_X)+((v)->UV_Y*(w)->UV_Y)+((v)->UV_Z*(w)->UV_Z) +#define CROSS_PRODUCT(r,v,w) (r)->UV_X=(((v)->UV_Y*(w)->UV_Z)-((v)->UV_Z*(w)->UV_Y)); \ + (r)->UV_Y=(((v)->UV_Z*(w)->UV_X)-((v)->UV_X*(w)->UV_Z)); \ + (r)->UV_Z=(((v)->UV_X*(w)->UV_Y)-((v)->UV_Y*(w)->UV_X)); + +inline float approx_vector_length(M31 *v) +{ + float max = (float)fabs((v->UV_X)), + med = (float)fabs((v->UV_Y)), + min = (float)fabs((v->UV_Z)), + temp; + + + if(maxUV_X = (v->UV_X)*length; + v->UV_Y = (v->UV_Y)*length; + v->UV_Z = (v->UV_Z)*length; +} + +//--------------------------------------------------------------- + +struct M33 +{ + M31 R0, + R1, + R2; +}; + +typedef struct M33 M33; + +#define UV_XX R0.R[0] +#define UV_YX R0.R[1] +#define UV_ZX R0.R[2] + +#define UV_XY R1.R[0] +#define UV_YY R1.R[1] +#define UV_ZY R1.R[2] + +#define UV_XZ R2.R[0] +#define UV_YZ R2.R[1] +#define UV_ZZ R2.R[2] + + +inline void init_M33(M33 *m) { m->UV_XX=(float)1.0;m->UV_XY=(float)0.0;m->UV_XZ=(float)0.0; + m->UV_YX=(float)0.0;m->UV_YY=(float)1.0;m->UV_YZ=(float)0.0; + m->UV_ZX=(float)0.0;m->UV_ZY=(float)0.0;m->UV_ZZ=(float)1.0; + } + +inline void rotate_on_x(SLONG angle,M33 *matrix) +{ + float sin = SIN_F(angle & 2047), + cos = COS_F(angle & 2047); + float t10 = matrix->UV_XY, + t11 = matrix->UV_YY, + t12 = matrix->UV_ZY, + t20 = matrix->UV_XZ, + t21 = matrix->UV_YZ, + t22 = matrix->UV_ZZ; + + matrix->UV_XY = ((cos*t10) + (-sin*t20)); + matrix->UV_YY = ((cos*t11) + (-sin*t21)); + matrix->UV_ZY = ((cos*t12) + (-sin*t22)); + matrix->UV_XZ = ((sin*t10) + (cos*t20)); + matrix->UV_YZ = ((sin*t11) + (cos*t21)); + matrix->UV_ZZ = ((sin*t12) + (cos*t22)); +} + +inline void rotate_on_y(SLONG angle,M33 *matrix) +{ + float sin = SIN_F(angle & 2047), + cos = COS_F(angle & 2047); + float t00 = matrix->UV_XX, + t01 = matrix->UV_YX, + t02 = matrix->UV_ZX, + t20 = matrix->UV_XZ, + t21 = matrix->UV_YZ, + t22 = matrix->UV_ZZ; + + matrix->UV_XX = ((cos*t00) + (sin*t20)); + matrix->UV_YX = ((cos*t01) + (sin*t21)); + matrix->UV_ZX = ((cos*t02) + (sin*t22)); + matrix->UV_XZ = ((-sin*t00) + (cos*t20)); + matrix->UV_YZ = ((-sin*t01) + (cos*t21)); + matrix->UV_ZZ = ((-sin*t02) + (cos*t22)); +} + +inline void rotate_on_z(SLONG angle,M33 *matrix) +{ + float sin = SIN_F(angle & 2047), + cos = COS_F(angle & 2047); + float t00 = matrix->UV_XX, + t01 = matrix->UV_YX, + t02 = matrix->UV_ZX, + t10 = matrix->UV_XY, + t11 = matrix->UV_YY, + t12 = matrix->UV_ZY; + + matrix->UV_XX = ((cos*t00) + (-sin*t10)); + matrix->UV_YX = ((cos*t01) + (-sin*t11)); + matrix->UV_ZX = ((cos*t02) + (-sin*t12)); + matrix->UV_XY = ((sin*t00) + (cos*t10)); + matrix->UV_YY = ((sin*t01) + (cos*t11)); + matrix->UV_ZY = ((sin*t02) + (cos*t12)); +} + +inline void angle_vector(SLONG angle, M31 *matrix) +{ + float sin = SIN_F(angle), + cos = COS_F(angle); + float t_x = matrix->UV_X, + t_z = matrix->UV_Z; + + + matrix->UV_X = ((cos*t_x) + (sin*t_z)); + matrix->UV_Z = ((-sin*t_x) + (cos*t_z)); +} + +inline void roll_vector(SLONG roll, M31 *matrix) +{ + float sin = SIN_F(roll), + cos = COS_F(roll); + float t_x = matrix->UV_X, + t_y = matrix->UV_Y; + + + matrix->UV_X = ((cos*t_x) + (sin*t_y)); + matrix->UV_Y = ((-sin*t_x) + (cos*t_y)); +} + +inline void tilt_vector(SLONG tilt, M31 *matrix) +{ + float sin = SIN_F(tilt), + cos = COS_F(tilt); + float t_y = matrix->UV_Y, + t_z = matrix->UV_Z; + + + matrix->UV_Y = ((cos*t_y) + (sin*t_z)); + matrix->UV_Z = ((-sin*t_y) + (cos*t_z)); +} + +//--------------------------------------------------------------- +// Engine defines. + +#define EF_OFF_LEFT (1<<0) +#define EF_OFF_RIGHT (1<<1) +#define EF_OFF_TOP (1<<2) +#define EF_OFF_BOTTOM (1<<3) +#define EF_FAR_OUT (1<<4) +#define EF_BEHIND_YOU (1<<5) +#define EF_TRANSLATED (1<<6) +#define EF_TOO_BIG (1<<7) + +#define EF_CLIPFLAGS (EF_OFF_LEFT+EF_OFF_RIGHT+EF_OFF_TOP+EF_OFF_BOTTOM) +#define EF_CLIPZFLAGS (EF_FAR_OUT+EF_BEHIND_YOU+EF_TOO_BIG) + +//--------------------------------------------------------------- + +typedef struct +{ + float X, + Y, + Z; + + float RotX; // The view-space coordinates. + float RotY; + float RotZ; + +}SVECTOR_F; + + +typedef struct +{ + float X, + Y, + Z; +}Coord; + +//--------------------------------------------------------------- + +typedef struct +{ + float CameraX, + CameraY, + CameraZ; + SLONG CameraAngle, + CameraRoll, + CameraTilt; +}Camera; + + +//--------------------------------------------------------------- + +typedef struct +{ + float HalfViewHeight, + HalfViewWidth, + OriginX, + OriginY, + OriginZ, + ViewHeight, + ViewWidth, + Lens; + SLONG BucketSize; + M33 CameraMatrix; + Coord CameraPos; + +}Engine; + +extern Engine the_engine; + +//--------------------------------------------------------------- + +typedef struct +{ + float Distance, + ScrX, + ScrY, + ScrZ; + +}DDEnginePoint; + + +struct EnginePointF +{ + float ScrX, + ScrY, + ScrZ, + X, + Y, + Z; +}; + +//--------------------------------------------------------------- + +#define MAX_VERTICES (32000) +#define ELE_SHIFT (8) +#define ELE_SHIFT_F (1.0f/(float)(ELE_SIZE)) +#define ELE_SIZE (1<>16; (y) = ynew>>16; (z) = znew>>16; \ +} + +// +// Multiplies points x,y,z by the transpose of matrix m. +// + +#define MATRIX_MUL_BY_TRANSPOSE(m,x,y,z) \ +{ \ + float xnew, ynew, znew; \ + \ + xnew = (x) * (m)[0]; \ + ynew = (x) * (m)[1]; \ + znew = (x) * (m)[2]; \ + \ + xnew += (y) * (m)[3]; \ + ynew += (y) * (m)[4]; \ + znew += (y) * (m)[5]; \ + \ + xnew += (z) * (m)[6]; \ + ynew += (z) * (m)[7]; \ + znew += (z) * (m)[8]; \ + \ + (x) = xnew; (y) = ynew; (z) = znew; \ +} + +// +// Multiplies two 3x3 together. A = MN. +// + +void MATRIX_3x3mul(float a[9], float m[9], float n[9]); + +// +// Transposes the matrix m. +// + +#define MATRIX_TRANSPOSE(m) {SWAP_FL(m[1], m[3]); SWAP_FL(m[2], m[6]); SWAP_FL(m[5], m[7]);} + +// +// Rotates a matrix about its x,y or z vector. +// + +void MATRIX_rotate_about_its_x(float *matrix, float angle); +void MATRIX_rotate_about_its_y(float *matrix, float angle); +void MATRIX_rotate_about_its_z(float *matrix, float angle); + +// +// Convert a matrix into its equivalent yaw, pitch and roll. +// + +typedef struct +{ + float yaw; + float pitch; + float roll; + +} Direction; + +Direction MATRIX_find_angles(float matrix[9]); + + +#endif + diff --git a/fallen/DDEngine/Headers/Message.h b/fallen/DDEngine/Headers/Message.h new file mode 100644 index 0000000..ec4d02a --- /dev/null +++ b/fallen/DDEngine/Headers/Message.h @@ -0,0 +1,37 @@ +// +// Message passing to the user. +// + + +#ifndef _MSG_ +#define _MSG_ + + + +// +// Clears all current messages. You don't have to call this at the +// start of the program. +// + +void MSG_clear(void); + +// +// Adds the current to the list of messages displayed to the user. The string is +// copied to a non-volatile area of memory, so you can use a local string to pass +// the message if you like. +// +// If you add the same message more than once, only one copy will appear. +// + +//void MSG_add(CBYTE *message, ...); + + +// +// Draws the messages onto the screen. It expects the screen to be locked. +// + +void MSG_draw(void); + + + +#endif diff --git a/fallen/DDEngine/Headers/NGamut.h b/fallen/DDEngine/Headers/NGamut.h new file mode 100644 index 0000000..511ffa4 --- /dev/null +++ b/fallen/DDEngine/Headers/NGamut.h @@ -0,0 +1,88 @@ +// +// Gamut calculations of polygons. +// + +#ifndef _NGAMUT_ +#define _NGAMUT_ + + +// +// The size of the gamut mapwho. +// + +#define NGAMUT_SIZE 128 +#define NGAMUT_SIZE_LO 32 + +// +// The gamut for squares. +// + +typedef struct +{ + SLONG xmin; + SLONG xmax; + +} NGAMUT_Gamut; + +extern NGAMUT_Gamut NGAMUT_gamut[NGAMUT_SIZE]; +extern SLONG NGAMUT_xmin; +extern SLONG NGAMUT_zmin; +extern SLONG NGAMUT_zmax; + +// +// Function to work out a gamut. +// +// Initialises the gamut. +// Pushes out the gamut along the line. The line can go off the gamut mapwho, but +// the gamut always stays within the gamut mapwho. +// + +void NGAMUT_init (void); +void NGAMUT_add_line( + float px1, + float pz1, + float px2, + float pz2); + +// +// Works out a square gamut of the given radius centered at (x,z) +// + +void NGAMUT_view_square(float mid_x, float mid_z, float radius); + + +// +// Once you've worked out the gamut for squares, this function works +// out the gamut for points. +// + +extern NGAMUT_Gamut NGAMUT_point_gamut[NGAMUT_SIZE]; +extern SLONG NGAMUT_point_zmin; +extern SLONG NGAMUT_point_zmax; + +void NGAMUT_calculate_point_gamut(void); + +// +// This is the square gamut expanded by one in each direction. +// + +extern NGAMUT_Gamut NGAMUT_out_gamut[NGAMUT_SIZE]; +extern SLONG NGAMUT_out_zmin; +extern SLONG NGAMUT_out_zmax; + +void NGAMUT_calculate_out_gamut(void); + +// +// This is a lower-res gamut. It is guaranteed to encompass all the +// squares in the point gamut. It is calculated from the out gamut, so +// make sure you have calculated that one already. +// + +extern NGAMUT_Gamut NGAMUT_lo_gamut[NGAMUT_SIZE_LO]; +extern SLONG NGAMUT_lo_zmin; +extern SLONG NGAMUT_lo_zmax; + +void NGAMUT_calculate_lo_gamut(void); + + +#endif diff --git a/fallen/DDEngine/Headers/Quaternion.h b/fallen/DDEngine/Headers/Quaternion.h new file mode 100644 index 0000000..a2507b6 --- /dev/null +++ b/fallen/DDEngine/Headers/Quaternion.h @@ -0,0 +1,20 @@ +#ifndef QUATERNION_H +#define QUATERNION_H + +class FloatMatrix +{ +public: + float M[3][3]; +}; + +class CQuaternion +{ +public: + + float w; + float x, y, z; + + static void BuildTween(struct Matrix33 *dest,struct CMatrix33 *cm1,struct CMatrix33 *cm2,SLONG tween); +}; + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Headers/Text.h b/fallen/DDEngine/Headers/Text.h new file mode 100644 index 0000000..6836b00 --- /dev/null +++ b/fallen/DDEngine/Headers/Text.h @@ -0,0 +1,21 @@ +// Text.h +// Guy Simmons, 17th May 1998. + +#ifndef TEXT_H +#define TEXT_H + +//--------------------------------------------------------------- +extern BOOL text_fudge; +extern ULONG text_colour; + + +SLONG text_width(CBYTE *message,SLONG font_id,SLONG *char_count); +SLONG text_height(CBYTE *message,SLONG font_id,SLONG *char_count); +void draw_text_at(float x,float y,CBYTE *message,SLONG font_id); +void draw_centre_text_at(float x,float y,CBYTE *message,SLONG font_id,SLONG flag); +void show_text(void); + +//--------------------------------------------------------------- + +#endif + diff --git a/fallen/DDEngine/Headers/aa.h b/fallen/DDEngine/Headers/aa.h new file mode 100644 index 0000000..aa5eb11 --- /dev/null +++ b/fallen/DDEngine/Headers/aa.h @@ -0,0 +1,27 @@ +// +// An anti-aliased triangle draw. +// + +#ifndef _AA_ +#define _AA_ + + +// +// The value generated for each pixel is the percentage area of +// that pixel covered by the triangle. This value is added with +// saturate to the value already in the pixel. +// +// The points must be given in clockwise order. +// + +void AA_draw( + UBYTE *bitmap, + UBYTE x_res, + UBYTE y_res, + SLONG pitch, + SLONG p1x, SLONG p1y, // 16-bit fixed point. + SLONG p2x, SLONG p2y, + SLONG p3x, SLONG p3y); + + +#endif diff --git a/fallen/DDEngine/Headers/aeng.h b/fallen/DDEngine/Headers/aeng.h new file mode 100644 index 0000000..06d98da --- /dev/null +++ b/fallen/DDEngine/Headers/aeng.h @@ -0,0 +1,493 @@ +// +// Another engine. +// + +#ifndef _AENG_ +#define _AENG_ + +// +// defines +// + +#define KERB_HEIGHT 32.0F +#define KERB_HEIGHTI ((SLONG)(KERB_HEIGHT)) + + + + +// Set this to 1 to enable TomF's new D3D-friendly engine. +// 0 enables the old engine again. +// NOTE! There are other versions of this define dotted around in other header +// files! Make sure they all agree or you'll have grief. +#ifdef TARGET_DC +#define USE_TOMS_ENGINE_PLEASE_BOB 1 +#else +#define USE_TOMS_ENGINE_PLEASE_BOB 1 +#endif + + + +// +// Call once at the start of the whole program. +// + +void AENG_init(void); + + + +// +// Chooses the texture set to use. If the current texture set is +// different from the new one, then all the textures are released. +// + +void TEXTURE_choose_set(SLONG number); + + +// +// Loads only the textures that are used in the prim faces and the current map. +// + +// iStartCompletionBar = where it is now. +// iEndCompletionBar = where it needs to get to. +// iNumberTexturesProbablyLoaded = roughly how many textures will be loaded. +void TEXTURE_load_needed(CBYTE* fname_level, + int iStartCompletionBar = 0, + int iEndCompletionBar = 0, + int iNumberTexturesProbablyLoaded = 0 + ); + +// +// Loads the textures needed for the given prim object. +// + +void TEXTURE_load_needed_object(SLONG prim_object); + + +// +// This function makes a local copy of the prim points for +// the engine's own use. +// + +typedef struct +{ + float X; + float Y; + float Z; + +} SVector_F; + +extern SVector_F AENG_dx_prim_points[]; + +void AENG_create_dx_prim_points(void); + +// +// After you have loaded all the prims, call this function. It +// fixes the texture coordinates of the prims if the engine has +// fiddled with the texture pages. +// + +void TEXTURE_fix_texture_styles(void); +void TEXTURE_fix_prim_textures (void); + +// +// Given a texture square coordinate on a page, it returns the +// page and texture square coordinates of the fiddled position. +// +// 'square_u' and 'square_v' should be between 0 and 7, and the +// fiddled position are returned. +// + +SLONG TEXTURE_get_fiddled_position( + SLONG square_u, + SLONG square_v, + SLONG page, + float *u, + float *v); + +// +// Initialises a new frame. +// Draws the engine. +// + +void AENG_set_camera( + SLONG world_x, + SLONG world_y, + SLONG world_z, + SLONG yaw, + SLONG pitch, + SLONG roll); + +void AENG_set_camera_radians( + SLONG world_x, + SLONG world_y, + SLONG world_z, + float yaw, + float pitch, + float roll); + +// +// Get/set draw distance +// + +void AENG_set_draw_distance(SLONG dist); +SLONG AENG_get_draw_distance(); + +// +// Draws world lines. +// + +// Just for debugging please! +void AENG_world_line( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + SLONG sort_to_front); + +// For lines that aren't debug. +void AENG_world_line_nondebug ( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + SLONG sort_to_front); + + +// +// Draws the line as a series of smaller lines so you can draw lines. +// with endpoints out of the view frustrum. +// + +void AENG_world_line_infinite( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + SLONG sort_to_front); + +void AENG_draw_col_tri(SLONG x0,SLONG y0,SLONG col0,SLONG x1,SLONG y1,SLONG col1,SLONG x2,SLONG z2,SLONG col2,SLONG layer); + + +// +// Older engine compatability. +// + +void AENG_e_draw_3d_line (SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2); +void AENG_e_draw_3d_line_dir (SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2); +void AENG_e_draw_3d_line_col (SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b); +void AENG_e_draw_3d_line_col_sorted(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b); +void AENG_e_draw_3d_mapwho (SLONG x1,SLONG z1); +void AENG_e_draw_3d_mapwho_y (SLONG x1,SLONG y1,SLONG z1); + +void AENG_draw_rect(SLONG x,SLONG y,SLONG w,SLONG h,SLONG col,SLONG layer,SLONG page); + +#define e_draw_3d_line AENG_e_draw_3d_line +#define e_draw_3d_line_dir AENG_e_draw_3d_line_dir +#define e_draw_3d_line_col AENG_e_draw_3d_line_col +#define e_draw_3d_line_col_sorted AENG_e_draw_3d_line_col_sorted +#define e_draw_3d_mapwho AENG_e_draw_3d_mapwho +#define e_draw_3d_mapwho_y AENG_e_draw_3d_mapwho_y + +// +// Sets the type of sky to use. +// + +void AENG_set_sky_nighttime(void); +void AENG_set_sky_daytime (ULONG bottom_colour, ULONG top_colour); + +// +// The new engines- you don't have to call these- just call +// AENG_draw() and it will take care of everything for you. +// + +void AENG_draw_city (void); +void AENG_draw_inside(void); +void AENG_draw_sewer (void); +void AENG_draw_ns (void); + +// +// Draw the correct engine given the current gamestate. If +// (draw_3d) then it draws the scene red/blue for use with +// 3d glasses. Make sure that the textures are all greyscale. +// + +void AENG_draw(SLONG draw_3d); + +// +// Clear the viewport (moved to just after flip for concurrency) +// + +void AENG_clear_viewport(); + +// +// The scanner. +// + +void AENG_draw_scanner( + SLONG screen_x1, + SLONG screen_y1, + SLONG screen_x2, + SLONG screen_y2, + SLONG map_x, + SLONG map_z, + SLONG map_zoom, // The number of pixels per mapsquare in fixed-point 8. + SLONG map_angle); + + +void AENG_draw_power(SLONG x,SLONG y,SLONG w,SLONG h,SLONG val,SLONG max); + +// +// Draws the messages and the FPS stuff to the screen. +// + +void AENG_draw_FPS(void); +void AENG_draw_messages(void); + +// +// Fades in from black via the MF logo. +// Fades out to the mucky foot logo. +// + +void AENG_fade_in (UBYTE amount); +void AENG_fade_out(UBYTE amount); + + +// +// Flips/blits the back-buffer. +// + +void AENG_flip(void); +void AENG_blit(void); + +// +// Adds a message to the message system. +// + +void MSG_add(CBYTE *message, ...); +//#define MSG_add + +// +// Drawing stuff straight to the screen... +// + +void AENG_clear_screen(void); +SLONG AENG_lock(void); +SLONG FONT_draw(SLONG x, SLONG y, CBYTE *text, ...); +void AENG_unlock(void); + + +// +// Call once at the end of the whole program. +// + +void AENG_fini(void); + + +// ======================================================== +// +// EDITOR SUPPORT FUNCTIONS +// +// ======================================================== + +// +// Returns the position of the ray going through the +// given screen pixel. Return FALSE if no intersection +// happened! +// + +SLONG AENG_raytraced_position( + SLONG sx, + SLONG sy, + SLONG *world_x, + SLONG *world_y, + SLONG *world_z, + SLONG indoors=0); + +// +// Returns the position of the point above (wx,wz) in +// the world whose screeny coordinate is the same as +// the given point. +// + +void AENG_raytraced_y_position( + SLONG sy, + SLONG wx, + SLONG wz, + SLONG *world_y); + + +// +// Draws a light. Returns bitfield to say if the given screen coord +// is over any part of the light. +// + +#define AENG_MOUSE_OVER_LIGHT_BOT (1 << 0) +#define AENG_MOUSE_OVER_LIGHT_TOP (1 << 1) + +ULONG AENG_light_draw( + SLONG sx, + SLONG sy, + SLONG lx, + SLONG ly, + SLONG lz, + ULONG colour, + UBYTE highlight); // How much to expand the light ball by... + + +// +// Draws the editor mode of the sewer editor. +// + +void AENG_draw_sewer_editor( + SLONG cam_x, + SLONG cam_y, + SLONG cam_z, + SLONG cam_yaw, + SLONG cam_pitch, + SLONG cam_roll, + SLONG mouse_x, + SLONG mouse_y, + SLONG *mouse_over_valid, + SLONG *mouse_over_x, + SLONG *mouse_over_y, + SLONG *mouse_over_z, + SLONG draw_prim_at_mouse, + SLONG prim_object, + SLONG prim_yaw); + + +// +// Draws text at the given point by calling FONT_buffer_add(). +// So remember to call FONT_buffer_draw() before you flip the screen. +// + +void AENG_world_text( + SLONG x, + SLONG y, + SLONG z, + UBYTE red, + UBYTE blue, + UBYTE green, + UBYTE shadowed_or_not, + CBYTE *fmt, ...); + + + +//--------------------------------------------------------------- +// GUY. +//--------------------------------------------------------------- + +#define AENG_MOUSE_OVER_WAYPOINT (1 << 0) + +ULONG AENG_waypoint_draw( + SLONG mx, + SLONG my, + SLONG lx, + SLONG ly, + SLONG lz, + ULONG colour, + UBYTE highlight); + +ULONG AENG_rad_trigger_draw( + SLONG mx, + SLONG my, + SLONG lx, + SLONG ly, + SLONG lz, + ULONG rad, + ULONG colour, + UBYTE highlight); + +//--------------------------------------------------------------- +// CANIS. +//--------------------------------------------------------------- + +void AENG_groundsquare_draw( + SLONG lx, + SLONG ly, + SLONG lz, + ULONG colour, + UBYTE polyinit); + +//--------------------------------------------------------------- + +// +// Drawing buffered up text anywhere on the screen. +// + +#include "font.h" +#include "console.h" + + +// +// panel stuff +// +extern void PANEL_draw_health_bar(SLONG x,SLONG y,SLONG percentage); +extern void PANEL_draw_timer(SLONG time_in_hundreths, SLONG x, SLONG y); +extern void PANEL_draw_buffered(void); // Actually draws the timers.... +extern void PANEL_finish(void); + +// +// detail level stuff +// + +// read detail levels from disc +void AENG_read_detail_levels(); + + +#ifdef TARGET_DC +// get the prevaling settings +void AENG_get_detail_levels(//int* stars, + int* shadows, + //int* moon_reflection, + //int* people_reflection, + int* puddles, + int* dirt, + int* mist, + int* rain, + int* skyline, + //int* filter, + //int* perspective, + int* crinkles); + +// change the prevaling settings +void AENG_set_detail_levels(//int stars, + int shadows, + //int moon_reflection, + //int people_reflection, + int puddles, + int dirt, + int mist, + int rain, + int skyline, + //int filter, + //int perspective, + int crinkles); + + +#else +// get the prevaling settings +void AENG_get_detail_levels(int* stars, + int* shadows, + int* moon_reflection, + int* people_reflection, + int* puddles, + int* dirt, + int* mist, + int* rain, + int* skyline, + int* filter, + int* perspective, + int* crinkles); + +// change the prevaling settings +void AENG_set_detail_levels(int stars, + int shadows, + int moon_reflection, + int people_reflection, + int puddles, + int dirt, + int mist, + int rain, + int skyline, + int filter, + int perspective, + int crinkles); + +#endif + +#endif diff --git a/fallen/DDEngine/Headers/build.h b/fallen/DDEngine/Headers/build.h new file mode 100644 index 0000000..6ccdbba --- /dev/null +++ b/fallen/DDEngine/Headers/build.h @@ -0,0 +1,24 @@ +// +// Draws buildings. +// + +#ifndef _BUILD_ +#define _BUILD_ + + +// +// This function uses the POLY module, and assumes +// that all the camera stuff has already been set up. +// + +void BUILD_draw(Thing *building); + +// +// Draws a building you are inside. +// + +void BUILD_draw_inside(void); + + + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Headers/comp.h b/fallen/DDEngine/Headers/comp.h new file mode 100644 index 0000000..77480f3 --- /dev/null +++ b/fallen/DDEngine/Headers/comp.h @@ -0,0 +1,68 @@ +// +// Movie compression routines. +// + +#ifndef _COMP_ +#define _COMP_ + + +#include "tga.h" + + +// +// The dimensions of the compressed frames. +// + +#define COMP_SIZE 64 +#define COMP_SNUM 8 +#define COMP_SSIZE (COMP_SIZE / COMP_SNUM) + + +// +// Our types. +// + +typedef struct +{ + TGA_Pixel p[COMP_SIZE][COMP_SIZE]; // Access (y,x)! + +} COMP_Frame; + +typedef struct +{ + SLONG size; + UBYTE data[]; + +} COMP_Delta; + + +// +// Loads a frame in from a .TGA file. Returns TRUE on success. +// + +#define COMP_TGA_MAX_WIDTH 640 +#define COMP_TGA_MAX_HEIGHT 480 + +SLONG COMP_load(CBYTE *filename, COMP_Frame *cf); + +// +// Calculates a structure that maps one frame onto the next. +// It returns the COMP_Delta in the same block of memory each time! +// i.e. subsequent calls overwrite previous answers. Returns the +// compressed frame. +// + +COMP_Delta *COMP_calc(COMP_Frame *f1, COMP_Frame *f2, COMP_Frame *ans); + +// +// Calculates one frame from the next, using a delta calculated with +// COMP_calc(). +// + +void COMP_decomp( + COMP_Frame *base, + COMP_Delta *delta, + COMP_Frame *result); + + +#endif diff --git a/fallen/DDEngine/Headers/cone.h b/fallen/DDEngine/Headers/cone.h new file mode 100644 index 0000000..06de5a5 --- /dev/null +++ b/fallen/DDEngine/Headers/cone.h @@ -0,0 +1,65 @@ +// +// Cones clipped by planar polygons. +// + +#ifndef _CONE_ +#define _CONE_ + + +// +// Creates a new cone. (dx,dy,dz) need not be normalised. +// + +void CONE_create( + float x, + float y, + float z, + float dx, + float dy, + float dz, + float length, + float radius, + ULONG colour_start, + ULONG colour_end, + SLONG detail); // A value between 0 and 256 + + +// +// Clips the last created cone with the given planar polygon. +// + +typedef struct +{ + float x; + float y; + float z; + +} CONE_Poly; + +void CONE_clip( + CONE_Poly p[], + SLONG num_points); + + +// +// Goes through the map looking for walls to intersect the cone with. +// + +void CONE_intersect_with_map(void); + + + +// +// Annoyingly, you can optimise the above call a lot if the poly is paralell to +// the x, y or z axis. Nearly all the polygons will be. +// + +// +// Draws the current cone. +// + +void CONE_draw(void); + + + +#endif diff --git a/fallen/DDEngine/Headers/console.h b/fallen/DDEngine/Headers/console.h new file mode 100644 index 0000000..2190339 --- /dev/null +++ b/fallen/DDEngine/Headers/console.h @@ -0,0 +1,33 @@ +/************************************************************ + * + * console.h + * a crude message console for queuing and writing + * messages to the user + * + */ + + +#ifndef _CONSOLE_ +#define _CONSOLE_ + +#include "MFStdLib.h" + +void CONSOLE_font(CBYTE *fontpath, float scale=1.0); +void CONSOLE_draw(); +void CONSOLE_text(CBYTE *text, SLONG delay = 4000); // Delay in milliseconds +void CONSOLE_clear(); +void CONSOLE_scroll(); + +// +// Messages that appear at specific points on the screen- If you place +// a message at the same place as an older message, the new message +// replaces that older one. +// + +void CONSOLE_text_at( + SLONG x, + SLONG y, + SLONG delay, + CBYTE *fmt, ...); + +#endif diff --git a/fallen/DDEngine/Headers/facet.h b/fallen/DDEngine/Headers/facet.h new file mode 100644 index 0000000..b561c1c --- /dev/null +++ b/fallen/DDEngine/Headers/facet.h @@ -0,0 +1,55 @@ +// +// Facet drawing functions. +// + +#ifndef _FACET_ +#define _FACET_ + + + +// +// Draws the given facet. +// + +void FACET_draw(SLONG facet,UBYTE alpha); + + +// +// Draws all the walkable faces for the given building. +// + +void FACET_draw_walkable(SLONG building); + + + +// +// Projects a shadow onto the crinkled facet. When it has made a +// properly crinkled polygon, it calls AENG_add_projected_shadow_poly(). +// +// Only call this function on NORMAL facets! +// + +void FACET_project_crinkled_shadow(SLONG facet); + + + + +// +// NOT USED ANY MORE! +// + +// +// Draws a sewer ladder. All coordinates and the height are +// in hi-res mapsquares +// + +void FACET_draw_ns_ladder( + SLONG x1, + SLONG z1, + SLONG x2, + SLONG z2, + SLONG height); + + + +#endif diff --git a/fallen/DDEngine/Headers/fall.h b/fallen/DDEngine/Headers/fall.h new file mode 100644 index 0000000..d190c56 --- /dev/null +++ b/fallen/DDEngine/Headers/fall.h @@ -0,0 +1,55 @@ +// +// Poly-modelled animating waterfalls. +// + +#ifndef _FALL_ +#define _FALL_ + + + +// +// Initialises all the waterfalls. +// + +void FALL_init(void); + + +// +// Creates a new waterfall. NULL => Couldn't create one. +// + +UBYTE FALL_create( + float x1, float z1, float u, float v, + float x2, float z2, float u, float v, + float dx, + float dz, + float du, + float dv, + float top_y, + float bot_y); + +// +// Destroys the given waterfall. +// + +void FALL_destroy(void); + +// +// Processes all the waterfalls. +// + +void FALL_process(void); + +// +// Draws them all. +// + +void FALL_draw(void); + + + +#endif + + + + diff --git a/fallen/DDEngine/Headers/farfacet.h b/fallen/DDEngine/Headers/farfacet.h new file mode 100644 index 0000000..40060b7 --- /dev/null +++ b/fallen/DDEngine/Headers/farfacet.h @@ -0,0 +1,42 @@ +// +// Faster far-facets... +// + +#ifndef _FARFACET_ +#define _FARFACET_ + + + +// +// Creates optimised data for drawing farfacets. +// Call after all facets have been loaded. +// + +void FARFACET_init(void); + + +// +// Draws the far facets that can be seen from this view. +// + +void FARFACET_draw( + float x, + float y, + float z, + float yaw, + float pitch, + float roll, + float draw_dist, + float lens); + +// +// Frees up memory. +// + +void FARFACET_fini(void); + + + + + +#endif diff --git a/fallen/DDEngine/Headers/fastprim.h b/fallen/DDEngine/Headers/fastprim.h new file mode 100644 index 0000000..46a873d --- /dev/null +++ b/fallen/DDEngine/Headers/fastprim.h @@ -0,0 +1,48 @@ +// +// Draws prims super-fast! +// + +#ifndef _FASTPRIM_ +#define _FASTPRIM_ + +#include "night.h" + + +// +// Initialises memory. +// + +void FASTPRIM_init(void); + + +// +// Draws a prim fastly. Return TRUE if it did it okay. +// + +SLONG FASTPRIM_draw( + SLONG prim, + float x, + float y, + float z, + float matrix[9], + NIGHT_Colour *lpc); + + +// +// Frees up memory. +// + +void FASTPRIM_fini(void); + + + +#endif + + + + + + + + + diff --git a/fallen/DDEngine/Headers/figure.h b/fallen/DDEngine/Headers/figure.h new file mode 100644 index 0000000..bc4199b --- /dev/null +++ b/fallen/DDEngine/Headers/figure.h @@ -0,0 +1,50 @@ +// +// Draws a person. +// + +#ifndef _FIGURE_ +#define _FIGURE_ + + +// +// This function uses the POLY module, and assumes +// that all the camera stuff has already been set up. +// + +void FIGURE_draw(Thing *person); + +extern SLONG FIGURE_alpha; + + +// +// Draws a reflection of the person about the plane, y = height. It fills in +// the bounding box of the object on screen. The bounding box isn't necessarily +// on screen! +// + +extern SLONG FIGURE_reflect_x1; +extern SLONG FIGURE_reflect_y1; +extern SLONG FIGURE_reflect_x2; +extern SLONG FIGURE_reflect_y2; + +void FIGURE_draw_reflection(Thing *person, SLONG height); + + +// +// What's this doing in figure.h? +// Don't ask me. I was just told to dump it here... +// + +void init_flames(); + + +// +// Draws an animating prim. +// + +void ANIM_obj_draw(Thing *p_thing, DrawTween *dt); + + + + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Headers/flamengine.h b/fallen/DDEngine/Headers/flamengine.h new file mode 100644 index 0000000..e47b246 --- /dev/null +++ b/fallen/DDEngine/Headers/flamengine.h @@ -0,0 +1,82 @@ +/************************************************************ + * + * flamengine.h + * 2D flame (and other fx) engine + * + */ + +#ifndef _FLAMENGINE_ +#define _FLAMENGINE_ + +#include + +struct FlameXY2 { + UBYTE x,y; +}; + +union FlameXY { + FlameXY2 loc; + UWORD ofs; +}; + +#ifdef TARGET_DC +// Properly aligned! +struct FlameParticle { + FlameXY pos; + UBYTE jx,jy; // Jitter range + UBYTE ex,ey; // Emitter position + UBYTE life; // could be ttl but is just on/off flag + UBYTE prate; // speed of pulsing + UBYTE pmode; // kind of pulse (ramp/cycle) + UBYTE wmode; // walk mode + SWORD pulse; // particles pulsing in and out + ULONG pstart; // start of pulse range; + ULONG pend; // end of pulse range; +}; +#else +struct FlameParticle { + FlameXY pos; + UBYTE jx,jy; // Jitter range + UBYTE ex,ey; // Emitter position + UBYTE life; // could be ttl but is just on/off flag + SWORD pulse; // particles pulsing in and out + UBYTE prate; // speed of pulsing + UBYTE pmode; // kind of pulse (ramp/cycle) + UBYTE wmode; // walk mode + ULONG pstart; // start of pulse range; + ULONG pend; // end of pulse range; +}; +#endif + +struct FlameParams { + UBYTE blur, dark, convec; + UBYTE palette[768]; + UWORD free, posn; + UBYTE randomize;// extra random stuff for flames + FlameParticle particles[2000]; +}; + +class Flamengine { + private: + UBYTE data[256*256*2]; + UBYTE work[256*256*2]; + void AddParticles(); // Sparkly bits + void AddParticles2(); // Sparkly bits + void Feedback(); // Funky feedback; must be used BEFORE any other screen draw + void ConvectionBlur(); // Straightforward blur box filter but offset one line + void ConvectionBlur2(); // H@X0R'd version + void Darkening(); // Moves and/or darkens the image + void UpdateTexture(); // Locks, pokes, unlocks and updates a texture with the fire data + void ReadHeader(MFFileHandle handle); + void ReadParts(MFFileHandle handle); + void BlitOffset(); // Blit the texture, skewed for feedback, onto the backbuffer + public: + FlameParams params; + Flamengine(char *name); + ~Flamengine(); + void Run(); // Update the animation one frame + void Blit(); // Blit the texture, suitably alpha'd, onto the backbuffer + void BlitHalf(CBYTE side); // Same, but half only (for seperate left + right) +}; + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Headers/font2d.h b/fallen/DDEngine/Headers/font2d.h new file mode 100644 index 0000000..422a9e8 --- /dev/null +++ b/fallen/DDEngine/Headers/font2d.h @@ -0,0 +1,99 @@ +/************************************************************ + * + * font2d.h + * 2D text writer + * + */ + +#ifndef _FONT_2D_H_ +#define _FONT_2D_H_ + +#include "MFStdLib.h" +#include "poly.h" + + + +void FONT2D_init(SLONG font_id); + + + + +typedef struct +{ + float u; + float v; + SLONG width; // Width is in pixels. Divide by 256.0F to get width in texture coords. + +} FONT2D_Letter; + + + +// +// Draws the letter and returns the width of the letter in pixels. +// + +SLONG FONT2D_DrawLetter(CBYTE chr, SLONG x, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0); + +// +// Returns the width of the given letter in pixels. +// + +SLONG FONT2D_GetLetterWidth(CBYTE chr); + + +// +// Draws the string. +// + +void FONT2D_DrawString(CBYTE*chr, SLONG x, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0); + +// +// Draws text that won't go off the screen. Returns the y coordinate of the line it finished on. +// Sets FONT2D_rightmost_x to be the the coordinate after the rightmost character it drew. +// + +extern SLONG FONT2D_rightmost_x; +extern SLONG FONT2D_leftmost_x; // For right justify! + +SLONG FONT2D_DrawStringWrapTo(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade, SWORD span); + +#ifdef TARGET_DC +// Um.... guys. +inline SLONG FONT2D_DrawStringWrap(CBYTE*chr, SLONG x, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0) +{ + return FONT2D_DrawStringWrapTo ( chr, x, y, rgb, scale, page, fade, 600 ); +} +#else +SLONG FONT2D_DrawStringWrap(CBYTE*chr, SLONG x, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0); +#endif + +// +// The text is right-justified and it wraps. The function returns the y coordinate of the +// line it finished on. +// + +SLONG FONT2D_DrawStringRightJustify(CBYTE*chr, SLONG x, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0, bool bDontDraw=FALSE); + +SLONG FONT2D_DrawStringRightJustifyNoWrap(CBYTE*chr, SLONG x, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0); + + + +// +// Draws a centre-justified string. +// + +void FONT2D_DrawStringCentred(CBYTE*chr, SLONG x, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0); + + + +// +// Draws a strikethrough. +// + +//void FONT2D_DrawStrikethrough(SLONG x1, SLONG x2, SLONG y, ULONG rgb=0xffffff, SLONG scale=256, SLONG page=POLY_PAGE_FONT2D, SLONG fade=0); +void FONT2D_DrawStrikethrough(SLONG x1, SLONG x2, SLONG y, ULONG rgb, SLONG scale, SLONG page, SLONG fade, bool bUseLastOffset=FALSE); + + + +#endif + diff --git a/fallen/DDEngine/Headers/font3d.h b/fallen/DDEngine/Headers/font3d.h new file mode 100644 index 0000000..b6dd12d --- /dev/null +++ b/fallen/DDEngine/Headers/font3d.h @@ -0,0 +1,68 @@ + +// THIS IS PANTS! + +#if 0 + +/************************************************************ + * + * font3d.h + * 3D text writer + * + */ + +#ifndef _FONT_3D_H_ +#define _FONT_3D_H_ + +// #include + +// why does the above line toast it? +// oh well... set up manually then... + +#define TRUE 1 +#define FALSE 0 +#define PI (3.14159265F) +typedef unsigned char UBYTE; +typedef signed char SBYTE; +typedef char CBYTE; +typedef unsigned short UWORD; +typedef signed short SWORD; +typedef unsigned long ULONG; +typedef signed long SLONG; + + +struct FontVec { + float x,y,z; // vertex pos + float tx,ty,tz; // translated vertex pos + float nx,ny,nz; // normal pos + float tnx,tny,tnz; // translated normal pos +}; + +struct FontFace { + FontVec *a, *b, *c, norm; +}; + +struct FontData { + ULONG numpts, numfaces; + FontVec *pts; + FontFace *faces; + UWORD width; +}; + +class Font3D { + private: + FontData data[100]; + ULONG nextchar; + ULONG LetterWidth(CBYTE chr); + float fontscale; + public: + void ClearLetters(); + void AddLetter(CBYTE *fn); + void DrawLetter(CBYTE chr, ULONG x, ULONG y, ULONG rgb=0xffffff, float yaw=0, float roll=0, float pitch=0, float scale=3.5); + void DrawString(CBYTE *str, ULONG x, ULONG y, ULONG rgb=0xffffff, float scale=3.5, CBYTE wibble=0, UWORD zoom=0); + Font3D(char *path, float scale=1.0); + ~Font3D(); +}; + +#endif + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Headers/ic.h b/fallen/DDEngine/Headers/ic.h new file mode 100644 index 0000000..b1dfb92 --- /dev/null +++ b/fallen/DDEngine/Headers/ic.h @@ -0,0 +1,54 @@ +// +// Image compression. +// + +#ifndef _IC_ +#define _IC_ + +#include "tga.h" + + +// +// Compresses the given 4x4 block of a TGA using the mad S3 texture compression +// system. Ignores the alpha channel of course! +// + +typedef struct +{ + UWORD colour1; // 5:6:5 + UWORD colour2; // 5:6:5 + ULONG bit; + +} IC_Packet; + +IC_Packet IC_pack( + TGA_Pixel *tga, + SLONG tga_width, + SLONG tga_height, + SLONG px, + SLONG py); + + +// +// Fills in a 4x4 block of the given tga with the colour data +// from a compressed IC packet. +// + +void IC_unpack( + IC_Packet ip, + TGA_Pixel *tga, + SLONG tga_width, + SLONG tga_height, + SLONG px, + SLONG py); + + + +// +// Debug test... +// + +void IC_test(void); + + +#endif diff --git a/fallen/DDEngine/Headers/map.h b/fallen/DDEngine/Headers/map.h new file mode 100644 index 0000000..7022169 --- /dev/null +++ b/fallen/DDEngine/Headers/map.h @@ -0,0 +1,52 @@ +// +// The new map screen +// + + +#ifndef _MAP_ +#define _MAP_ + + + +// +// Initialises the map (gets rid of nav beacons... sets up view) +// + +void MAP_init(void); + + +// +// Draws the map. +// + +void MAP_draw(void); + + + +// +// Adds a NAV beacon to the map. +// Removes a beacon from the map. +// + +UBYTE MAP_beacon_create(SLONG x, SLONG z, SLONG index, THING_INDEX track_my_position); +void MAP_beacon_remove(UBYTE beacon); + + +// +// Processes the map. +// + +void MAP_process(void); + + + +// +// Draws the quick on-screen map beacon direction indicator. +// + +void MAP_draw_onscreen_beacons(void); + + + +#endif + diff --git a/fallen/DDEngine/Headers/menufont.h b/fallen/DDEngine/Headers/menufont.h new file mode 100644 index 0000000..a0a5702 --- /dev/null +++ b/fallen/DDEngine/Headers/menufont.h @@ -0,0 +1,84 @@ +/************************************************************ + * + * menufont.h + * 2D proportional-font text writer with poncey afterfx + * + */ + +#ifndef _MENUFONT_H_ +#define _MENUFONT_H_ + +#include "MFStdlib.h" + +#define MENUFONT_FUTZING (1) +#define MENUFONT_HALOED (2) +#define MENUFONT_GLIMMER (4) +#define MENUFONT_CENTRED (8) +#define MENUFONT_FLANGED (16) +#define MENUFONT_SINED (32) +#define MENUFONT_ONLY (64) +#define MENUFONT_RIGHTALIGN (128) +#define MENUFONT_HSCALEONLY (256) +#define MENUFONT_SUPER_YCTR (512) +#define MENUFONT_SHAKE (1024) + +void MENUFONT_Load(CBYTE *fn, SLONG page, CBYTE *fontlist); +void MENUFONT_Page(SLONG page); +void MENUFONT_Draw(SWORD x, SWORD y, UWORD scale, CBYTE *msg, SLONG rgb, UWORD flags, SWORD max=-1); +void MENUFONT_Draw_floats(float x, float y, UWORD scale, CBYTE *msg, SLONG rgb, UWORD flags); +void MENUFONT_Free(); +void MENUFONT_Dimensions(CBYTE *fn, SLONG &x, SLONG &y, SWORD max=-1, SWORD scale=256); +SLONG MENUFONT_CharFit(CBYTE *fn, SLONG x, UWORD scale=256); +SLONG MENUFONT_CharWidth(CBYTE fn, UWORD scale=256); +#ifdef TARGET_DC +void MENUFONT_Draw_Selection_Box(SWORD x, SWORD y, UWORD scale, CBYTE *msg, SLONG rgb, UWORD flags, SWORD max=-1); +#endif + + + +struct CharData { + float x,y,ox,oy; // fractional texture coordinates. live with it. + UBYTE width, height; + UBYTE xofs, yofs; // offsets, hm. +}; + + +extern CharData FontInfo[256]; + + +#ifdef TARGET_DC +// The Yanks call them VMUs, Europeans call them VMs. Madness. +// Set this to TRUE if you're a European. +extern bool bWriteVMInsteadOfVMU; +#endif + + +// ======================================================== +// +// Cool line-fade-in text. +// +// ======================================================== + +// +// Clears any old fadein data. +// + +void MENUFONT_fadein_init(void); + +// +// Sets the x pixel fadein position. Text will only appear to the left of this +// line. +// + +void MENUFONT_fadein_line(SLONG x); // x is in 8-bit fixed point + +// +// Draws centred text where a fade 255 is opaque and 0 is transparent. +// + +void MENUFONT_fadein_draw(SLONG x, SLONG y, UBYTE fade, CBYTE *msg); + + + + +#endif diff --git a/fallen/DDEngine/Headers/mesh.h b/fallen/DDEngine/Headers/mesh.h new file mode 100644 index 0000000..b65f177 --- /dev/null +++ b/fallen/DDEngine/Headers/mesh.h @@ -0,0 +1,124 @@ +// +// Drawing rotating prims. +// + +#ifndef MESH_H +#define MESH_H + + +#include "night.h" + + +// +// If a prim face has its FACE_FLAG_TINTED flag set, then +// the colours the face is drawn with is ANDED with this +// value +// + +extern ULONG MESH_colour_and; + +// +// Call once at the start of the whole game. Calculates the +// crumple look-up tables. +// + +void MESH_init(void); + + +// +// Draws a mesh using the POLY module. If 'lpc' is NULL then, the ambient +// light colour is used. Returns the address of after the end of the lpc array. +// + +NIGHT_Colour *MESH_draw_poly( + SLONG prim, + SLONG at_x, + SLONG at_y, + SLONG at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll, + NIGHT_Colour *lpc, + UBYTE fade, + SLONG crumple = 0); + +// +// Sets car crumple parameters before a call to MESH_draw_poly(..., -1) +// + +void MESH_set_crumple(UBYTE* assignments, UBYTE* crumples); + +// +// Draws an environment map over this given prim. +// + +void MESH_draw_envmap( + SLONG prim, + SLONG at_x, + SLONG at_y, + SLONG at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll); + + +// +// This version uses a flipped matrix compares to MESH_draw_poly +// It's useful for helicopters. Trust me. I'm a programmer. +// + +NIGHT_Colour *MESH_draw_poly_inv_matrix( + SLONG prim, + SLONG at_x, + SLONG at_y, + SLONG at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll, + NIGHT_Colour *lpc); + +// +// The relfections are calculated once and then reused. The init() function clears +// all old reflection data. +// + +void MESH_init_reflections(void); + +// +// Draws the reflection of the given object. The reflection is always +// at the bottom of the prim. +// + +void MESH_draw_reflection( + SLONG prim, + SLONG at_x, + SLONG at_y, + SLONG at_z, + SLONG at_yaw, + NIGHT_Colour *lpc); + + +// +// Draws a mesh using the faces and textures from the given prim, but the +// points from the two given morphs. +// + +void MESH_draw_morph( + SLONG prim, + UBYTE morph1, + UBYTE morph2, + UWORD tween, // 0 - 256 + SLONG at_x, + SLONG at_y, + SLONG at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll, + NIGHT_Colour *lpc); + + + + +#endif + + diff --git a/fallen/DDEngine/Headers/oval.h b/fallen/DDEngine/Headers/oval.h new file mode 100644 index 0000000..84cbfe6 --- /dev/null +++ b/fallen/DDEngine/Headers/oval.h @@ -0,0 +1,28 @@ +// +// Simple ovals underneath people, barrels etc... +// + +#ifndef _OVAL_ +#define _OVAL_ + + + +// +// Creates an oval elongated in a given direction... +// + +#define OVAL_TYPE_OVAL 0 +#define OVAL_TYPE_SQUARE 1 + +void OVAL_add( + SLONG x, // 8 bits per mapsquare + SLONG y, + SLONG z, + SLONG size, + float elongate = 1.0F, + float angle = 0.0F, + SLONG type = OVAL_TYPE_OVAL); + + + +#endif diff --git a/fallen/DDEngine/Headers/pack.h b/fallen/DDEngine/Headers/pack.h new file mode 100644 index 0000000..d30161f --- /dev/null +++ b/fallen/DDEngine/Headers/pack.h @@ -0,0 +1,17 @@ +// +// Looks at all the textures loaded and packs similar ones +// onto 256x256s... +// + +#ifndef _PACK_ +#define _PACK_ + + +// +// Does the packing... +// + +void PACK_do(void); + + +#endif diff --git a/fallen/DDEngine/Headers/panel.h b/fallen/DDEngine/Headers/panel.h new file mode 100644 index 0000000..2da7c91 --- /dev/null +++ b/fallen/DDEngine/Headers/panel.h @@ -0,0 +1,138 @@ +#ifndef AENG_PANEL_HPP + +#define AENG_PANEL_HPP + + +extern UBYTE PANEL_scanner_poo; // sets whether you want a poo scanner or not + +extern void PANEL_start(void); +extern void PANEL_draw_gun_sight(SLONG x,SLONG y,SLONG z,SLONG radius,SLONG scale); +extern void PANEL_draw_timer(SLONG time_in_hundreths, SLONG x, SLONG y); +extern void PANEL_draw_buffered(void); // Actually draws the timers.... +extern void PANEL_draw_health_bar(SLONG x,SLONG y,SLONG percentage); +#if 0 +// Never used! +extern void PANEL_draw_angelic_status(SLONG x, SLONG y, SLONG size, SLONG am_i_an_angel); +extern void PANEL_draw_press_button(SLONG x, SLONG y, SLONG size, SLONG frame); // Even/odd frame +#endif +extern void PANEL_finish(void); +extern void PANEL_inventory(Thing *darci, Thing *player); + + +// +// The new funky panel! +// +#ifdef PSX +void PANEL_new_funky(void); +#endif + +// +// Clears all new text messages. +// + +void PANEL_new_text_init(void); + +// +// The new funky messages-from-people system. +// + +void PANEL_new_text(Thing *who, SLONG delay, CBYTE *fmt, ...); + + +// +// Help system messages. +// + +void PANEL_new_help_message(CBYTE *fmt, ...); + + + +// +// Messages that give you info. They go where the beacon text +// normally goes. +// + +void PANEL_new_info_message(CBYTE *fmt, ...); + + +// +// Flashes up a sign on the screen for the next few second. +// + +#define PANEL_SIGN_WHICH_UTURN 0 +#define PANEL_SIGN_WHICH_TURN_RIGHT 1 +#define PANEL_SIGN_WHICH_DONT_TAKE_RIGHT_TURN 2 +#define PANEL_SIGN_WHICH_STOP 3 + +#define PANEL_SIGN_FLIP_LEFT_AND_RIGHT (1 << 0) +#define PANEL_SIGN_FLIP_TOP_AND_BOTTOM (1 << 1) + +void PANEL_flash_sign(SLONG which, SLONG flip); + + +// +// Darkens the screen where x goes from 0 to 640. +// + +void PANEL_darken_screen(SLONG x); + + +// +// How to fade out the screen. +// + +void PANEL_fadeout_init (void); +void PANEL_fadeout_start (void); // Only starts if the fadeout is not already going... +void PANEL_fadeout_draw (void); +SLONG PANEL_fadeout_finished(void); + + + + +// +// The last panel for Urban Chaos (with a bit of luck). +// + +void PANEL_last(void); + + + +// +// Where completion goes from 0 to 256 +// + +void PANEL_draw_completion_bar(SLONG completion); + + + +// Returns a value to use for RHW that says "this is on top". +// Use 1.0f - this for a Z value. +// Each time this is called, it increases a little to help +// with cards that depth buffer oddly. +float PANEL_GetNextDepthBodge ( void ); + +// Call at the start of each frame. +void PANEL_ResetDepthBodge ( void ); + + +// Screensaver stuff. +void PANEL_enable_screensaver ( void ); +void PANEL_disable_screensaver ( bool bImmediately=FALSE ); +void PANEL_screensaver_draw ( void ); + + + +void PANEL_draw_quad( + float left, + float top, + float right, + float bottom, + SLONG page, + ULONG colour = 0xffffffff, + float u1 = 0.0F, + float v1 = 0.0F, + float u2 = 1.0F, + float v2 = 1.0F); + + +#endif diff --git a/fallen/DDEngine/Headers/planmap.h b/fallen/DDEngine/Headers/planmap.h new file mode 100644 index 0000000..372854b --- /dev/null +++ b/fallen/DDEngine/Headers/planmap.h @@ -0,0 +1,35 @@ +// +// The map draw. +// + +#ifndef _PLANMAP_ +#define _PLANMAP_ + + + +// +// Draws the plan view of the city. +// + +void plan_view_shot(SLONG wx,SLONG wz,SLONG pixelw,SLONG sx,SLONG sy,SLONG w,SLONG h,UBYTE *mem); + + +// +// Draws a dot on the map. +// + +#define BEACON_FLAG_BEACON (1 << 0) // This is a beacon +#define BEACON_FLAG_POINTY (1 << 1) // This is a player- takes direction from 'dir' + +void map_beacon_draw( + SLONG x, + SLONG z, + ULONG col, + ULONG flags, + UWORD dir); + + + + + +#endif diff --git a/fallen/DDEngine/Headers/poly.h b/fallen/DDEngine/Headers/poly.h new file mode 100644 index 0000000..496e68e --- /dev/null +++ b/fallen/DDEngine/Headers/poly.h @@ -0,0 +1,736 @@ +// +// Drawing polygons with D3D +// + +#ifndef _POLY_ +#define _POLY_ + + +#ifdef TARGET_DC +// Fade the diffuse and specular, rather than using D3D fog, which doesn't work on DC yet. +// It does now!!!!! +//#define FAKE_UP_VERTEX_FOG_PLEASE_BOB defined + +// If using D3D fog, use W-based table fog, rather than vertex fogging. +// (which is faked up by the driver on DC). Doesn't work yet, +#define USE_W_FOG_PLEASE_BOB defined + +#endif + + + + +#if defined(TARGET_DC) + +static inline int ftol(float f) +{ + return ( (int)f ); +} + + +#else //#if defined(TARGET_DC) + +#ifndef PSX +static inline int ftol(float f) +{ + int ans; + + __asm + { + mov eax,f + fld f + fistp ans + } + + return ans; +} +#endif + +#endif //#else //#if defined(TARGET_DC) + + +// +// Only points further than 1/64'th of the draw range are drawn. +// + +#define POLY_ZCLIP_PLANE (1.0F / 64.0F) + +// +// Call once at the start of the whole program. +// + +void POLY_init(void); + + +#ifndef TARGET_DC +void calc_global_cloud(SLONG x,SLONG y,SLONG z); +void apply_cloud(SLONG x,SLONG y,SLONG z,ULONG *col); +void use_global_cloud(ULONG *col); +#endif + + +// +// Clears all the texture flags. +// Loads texture flags from the given file. The 'offset' is added onto the +// page numbers in the file. +// + +void POLY_init_texture_flags(void); +void POLY_load_texture_flags(CBYTE *fname, SLONG offset = 0); + +// reset renderstates + +void POLY_reset_render_states(); + + +// ======================================================== +// +// TRANSFORMING POINTS +// +// ======================================================== + +// +// Sets the position of the camera. You can clip all the polygons +// to the top or bottom half of the screen. +// + +#define POLY_SPLITSCREEN_NONE 0 +#define POLY_SPLITSCREEN_TOP 1 +#define POLY_SPLITSCREEN_BOTTOM 2 + +extern float POLY_cam_x; +extern float POLY_cam_y; +extern float POLY_cam_z; +extern float POLY_cam_matrix[9]; + +void POLY_camera_set( + float x, + float y, + float z, + float yaw, + float pitch, + float roll, + float view_dist, // The maximum distance a point should be from the camera. + float lens, // Normally around 1.5F... the higher it is the more zoom you get. + SLONG splitscreen = POLY_SPLITSCREEN_NONE); + +// +// These are set by calling camera_set() +// + +extern float POLY_screen_width; +extern float POLY_screen_height; + +// +// Given three points in world space, this function fills in +// the 3d view space coordinates of the point. If the point +// is not 'behind' the camera, then it is transformed. If it +// is transformed then the 2d points and clipping flags are +// calculated. +// + +#define POLY_CLIP_LEFT (1 << 0) // point is to left of screen, implies POLY_CLIP_TRANSFORMED +#define POLY_CLIP_RIGHT (1 << 1) // point is to right of screen, implies POLY_CLIP_TRANSFORMED +#define POLY_CLIP_TOP (1 << 2) // point is above screen, implies POLY_CLIP_TRANSFORMED +#define POLY_CLIP_BOTTOM (1 << 3) // point is below screen, implies POLY_CLIP_TRANSFORMED +#define POLY_CLIP_TRANSFORMED (1 << 4) // point has been rotated into camera coordinates and projected onto the screen +#define POLY_CLIP_FAR (1 << 5) // point is behind farplane, implies !POLY_CLIP_TRANSFORMED +#define POLY_CLIP_NEAR (1 << 6) // point is in front of nearplane, implies !POLY_CLIP_TRANSFORMED + +// any one of these flags set => point is off screen +#define POLY_CLIP_OFFSCREEN (POLY_CLIP_LEFT | POLY_CLIP_RIGHT | POLY_CLIP_TOP | POLY_CLIP_BOTTOM | POLY_CLIP_FAR | POLY_CLIP_NEAR) + +typedef struct +{ + float x; // + float y; // 3D points... + float z; // + + float X; // + float Y; // 2D points... + float Z; // + + UWORD clip; + UWORD user; // For your use! + + float u; + float v; + ULONG colour; // xxRRGGBB + ULONG specular; // xxRRGGBB + + // IsValid - point has been rotated & projected; screen coords OK + inline bool IsValid() { return ((clip & POLY_CLIP_TRANSFORMED) != 0); } + // MaybeValid - point has been rotated, but may be in front of the nearplane; screen coords not necessarily OK + inline bool MaybeValid() { return ((clip & (POLY_CLIP_TRANSFORMED | POLY_CLIP_NEAR)) != 0); } + // NearClip - point is in front of the nearplane + inline bool NearClip() { return ((clip & POLY_CLIP_NEAR) != 0); } + +} POLY_Point; + + +#ifdef TARGET_DC + +void POLY_flush_local_rot ( void ); + +void POLY_transform_c( + float world_x, + float world_y, + float world_z, + POLY_Point *pt, + bool bResetTheFTRV = FALSE); + +#define POLY_transform POLY_transform_c + +#else //#ifdef TARGET_DC + +// Does nothing on PC. +inline void POLY_flush_local_rot ( void ) +{ +} + +void POLY_transform( + float world_x, + float world_y, + float world_z, + POLY_Point *pt, + bool bUnused = FALSE); + +void POLY_transform_c( + float world_x, + float world_y, + float world_z, + POLY_Point *pt, + bool bUnused = FALSE); + + +#endif //#else //#ifdef TARGET_DC + + +void POLY_set_local_rotation_none ( void ); + +void POLY_transform_abs( + float world_x, + float world_y, + float world_z, + POLY_Point *pt); + +void POLY_transform_c_saturate_z( + float world_x, + float world_y, + float world_z, + POLY_Point *pt); + + + +// +// Transformation function that takes points already rotated +// into view space (whose x,y,z,u,v,colour,specular have valid +// values and calculates the X,Y,Z and clip values. +// + +void POLY_transform_from_view_space(POLY_Point *pt); + +// +// Returns the screen coordinates if the point is not +// zclipped. Returns TRUE on success. This transformation +// function does not care about the z-range. +// + +SLONG POLY_get_screen_pos( + float world_x, + float world_y, + float world_z, + float *screen_x, + float *screen_y); + +// +// Applies the perspective transform to a POLY_Point already +// in viewspace. Viewspace x and y go from -1 to +1 and viewspace +// z goes from POLY_ZCLIP_PLANE to 1 +// + +void POLY_perspective(POLY_Point *pt, UBYTE wibble_key = 0); + +// +// sets clipping flags for a point - DON'T just set pt->clip to TRANSFORMED!!! +// + +void POLY_setclip(POLY_Point* pt); + +// +// Converts a length in world space to a width on the screen. +// + +float POLY_world_length_to_screen(float world_length); + +// +// Get approximate length of a 2D line +// + +float POLY_approx_len(float dx, float dy); + +// +// Gives the screen position and approximate screen radius of +// the circle corresponding to the given sphere in world space. +// Returns FALSE if the sphere is behind you. +// + +SLONG POLY_get_sphere_circle( + float world_x, + float world_y, + float world_z, + float world_radius, + SLONG *screen_x, + SLONG *screen_y, + SLONG *screen_radius); + +// +// Sets the wibble values to use. +// + +void POLY_set_wibble( + UBYTE wibble_y1, + UBYTE wibble_y2, + UBYTE wibble_g1, + UBYTE wibble_g2, + UBYTE wibble_s1, + UBYTE wibble_s2); + +// +// Sets an additional matrix to be applied to the world point before +// it is transformed. +// + +void POLY_set_local_rotation( + float off_x, + float off_y, + float off_z, + float matrix[9]); + + +#ifdef TARGET_DC + +void POLY_transform_using_local_rotation_c( + float local_x, + float local_y, + float local_z, + POLY_Point *pt); + +#define POLY_transform_using_local_rotation POLY_transform_using_local_rotation_c + +#else //#ifdef TARGET_DC + +void POLY_transform_using_local_rotation( + float local_x, + float local_y, + float local_z, + POLY_Point *pt); + +#endif //#else //#ifdef TARGET_DC + + +void POLY_transform_using_local_rotation_and_wibble( + float local_x, + float local_y, + float local_z, + POLY_Point *pt, + UBYTE wibble_key); + +// +// Returns true if the given sphere in world space is visible +// on screen. 'radius' should be given as a fraction of the viewdist passed +// to POLY_camera_set. radius = world_radius / view_dist. +// + +SLONG POLY_sphere_visible( + float world_x, + float world_y, + float world_z, + float radius); + +// +// Returns TRUE if the given texture page is drawn two-pass with the +// next higher-numbered texture page over the top of it. +// + +SLONG POLY_page_is_masked_self_illuminating(SLONG page); + +// +// Handy buffers for rotating objects +// + +#ifdef TARGET_DC +// Gatecrasher seems to give the biggest high-water-mark, during the intro cutscene. +#define POLY_BUFFER_SIZE 768 +#define POLY_SHADOW_SIZE 512 +#else +#define POLY_BUFFER_SIZE 8192 +#define POLY_SHADOW_SIZE 8192 +#endif + +extern POLY_Point POLY_buffer[POLY_BUFFER_SIZE]; +extern SLONG POLY_buffer_upto; + +extern POLY_Point POLY_shadow[POLY_SHADOW_SIZE]; +extern SLONG POLY_shadow_upto; + + +// ======================================================== +// +// GLOBALS EFFECTING POLY DRAW AND POINT FADEOUT. +// +// ======================================================== + +// +// All colours are ANDed with ~POLY_colour_restrict. +// + +extern ULONG POLY_colour_restrict; // NOTted then ANDed with all colours +extern ULONG POLY_force_additive_alpha; // Everything is drawn with additive alpha. + +// +// The fade-out range of the points. +// + +#define POLY_FADEOUT_START (0.60F) +#define POLY_FADEOUT_END (0.95F) + + +//#define POLY_FADEOUT_START (0.60F/3.0F) +//#define POLY_FADEOUT_END (0.95F/3.0F) + +// +// Applies fade out to the given point. +// Applies fade out to all the points in the POLY_buffer array. +// + +SLONG fade_point_more(POLY_Point *pp); + +static void inline POLY_fadeout_point(POLY_Point *pp) +{ + +#ifdef USE_W_FOG_PLEASE_BOB + // Not much to do apart from colour masking. + pp->colour &= ~POLY_colour_restrict; + pp->specular &= ~POLY_colour_restrict; +#else //#ifdef USE_W_FOG_PLEASE_BOB + + + // Mark, you can't just rip out the fog and replace it with nothing else ya twonk, + // even if you are on a Quest For Speed (but gave up after a week, having not found any). + //return; + +// if (pp->z > POLY_FADEOUT_START) + { + SLONG multi = 255 - ftol((pp->z - POLY_FADEOUT_START) * (256.0F / (POLY_FADEOUT_END - POLY_FADEOUT_START))); +#ifdef TARGET_DC + //multi = 255 - multi; +#endif + +// multi=fade_point_more(pp); + + + if(multi>255) + { + multi=255; + } + + if (multi < 0) + { + multi = 0; + } + + pp->specular &= 0x00ffffff; +#ifndef FAKE_UP_VERTEX_FOG_PLEASE_BOB + + // Use D3D fog. + pp->specular |= multi << 24; + +#else + + SLONG red; + SLONG green; + SLONG blue; + + { + red = ((pp->colour >> 16) & 0xff) * multi >> 8; + green = ((pp->colour >> 8) & 0xff) * multi >> 8; + blue = ((pp->colour >> 0) & 0xff) * multi >> 8; + +#ifdef TARGET_DC + // Force the alpha channel on. + //pp->colour = 0xff000000; + pp->colour = multi << 24; + //pp->colour &= 0xff000000; +#else + pp->colour &= 0xff000000; +#endif + pp->colour |= red << 16; + pp->colour |= green << 8; + pp->colour |= blue << 0; + + if (pp->specular) + { + red = ((pp->specular >> 16) & 0xff) * multi >> 8; + green = ((pp->specular >> 8) & 0xff) * multi >> 8; + blue = ((pp->specular >> 0) & 0xff) * multi >> 8; + + pp->specular = 0; + pp->specular |= red << 16; + pp->specular |= green << 8; + pp->specular |= blue << 0; + } + } +#endif + + } +/* + else + { + pp->specular |= 0xff000000; + } +*/ + + pp->colour &= ~POLY_colour_restrict; + pp->specular &= ~POLY_colour_restrict; + +#endif //#else //#ifdef USE_W_FOG_PLEASE_BOB + +} + +void POLY_fadeout_buffer(void); + +// ======================================================== +// +// ADDING TRIANGLES / QUADS / LINES +// +// ======================================================== + +// +// NB There is no vertex sharing except in a quad. +// +// While adding triangles to a page, if there are enough triangles using the same +// texture, then they are drawn immediately. The exeption to this is the shadow +// page which is only draw with a call to POLY_frame_draw(TRUE). +// + +// +// The 'page' argument should either be one of the TEXTURE module's +// texture pages or one of these defines. +// + +#ifdef TARGET_DC +#define POLY_NUM_PAGES (22*64+124) +#else +#define POLY_NUM_PAGES (22*64+111) // 1508 +#endif + +#ifdef TARGET_DC +#define POLY_PAGE_BACKGROUND_IMAGE (POLY_NUM_PAGES - 124) +#define POLY_PAGE_BACKGROUND_IMAGE2 (POLY_NUM_PAGES - 123) + +#define POLY_PAGE_JOYPAD_A (POLY_NUM_PAGES - 122) +#define POLY_PAGE_JOYPAD_B (POLY_NUM_PAGES - 121) +#define POLY_PAGE_JOYPAD_C (POLY_NUM_PAGES - 120) +#define POLY_PAGE_JOYPAD_X (POLY_NUM_PAGES - 119) +#define POLY_PAGE_JOYPAD_Y (POLY_NUM_PAGES - 118) +#define POLY_PAGE_JOYPAD_Z (POLY_NUM_PAGES - 117) +#define POLY_PAGE_JOYPAD_L (POLY_NUM_PAGES - 116) +#define POLY_PAGE_JOYPAD_R (POLY_NUM_PAGES - 115) +#define POLY_PAGE_JOYPAD_PAD_L (POLY_NUM_PAGES - 114) +#define POLY_PAGE_JOYPAD_PAD_R (POLY_NUM_PAGES - 113) +#define POLY_PAGE_JOYPAD_PAD_D (POLY_NUM_PAGES - 112) +#define POLY_PAGE_JOYPAD_PAD_U (POLY_NUM_PAGES - 111) +#endif + +#define POLY_PAGE_FADE_MF (POLY_NUM_PAGES - 110) +#define POLY_PAGE_SNOWFLAKE (POLY_NUM_PAGES - 109) +#define POLY_PAGE_SPLASH (POLY_NUM_PAGES - 108) +#define POLY_PAGE_METEOR (POLY_NUM_PAGES - 107) +#define POLY_PAGE_LITE_BOLT (POLY_NUM_PAGES - 106) +#define POLY_PAGE_LADSHAD (POLY_NUM_PAGES - 105) +#define POLY_PAGE_LASTPANEL_ALPHA (POLY_NUM_PAGES - 104) +#define POLY_PAGE_LASTPANEL_SUB (POLY_NUM_PAGES - 103) +#define POLY_PAGE_LASTPANEL2_SUB (POLY_NUM_PAGES - 102) +#define POLY_PAGE_LASTPANEL2_ADDALPHA (POLY_NUM_PAGES - 101) +#define POLY_PAGE_LASTPANEL_ADDALPHA (POLY_NUM_PAGES - 100) +#define POLY_PAGE_LASTPANEL2_ALPHA (POLY_NUM_PAGES - 99) +#define POLY_PAGE_LASTPANEL2_ADD (POLY_NUM_PAGES - 98) +#define POLY_PAGE_EXPLODE2_ADDITIVE (POLY_NUM_PAGES - 97) +#define POLY_PAGE_EXPLODE1_ADDITIVE (POLY_NUM_PAGES - 96) +#define POLY_PAGE_SHADOW_SQUARE (POLY_NUM_PAGES - 95) +#define POLY_PAGE_PCFLAMER (POLY_NUM_PAGES - 94) +#define POLY_PAGE_SIGN (POLY_NUM_PAGES - 93) +#define POLY_PAGE_LASTPANEL_ADD (POLY_NUM_PAGES - 92) +#define POLY_PAGE_LEAF (POLY_NUM_PAGES - 90) +#define POLY_PAGE_RUBBISH (POLY_NUM_PAGES - 89) +#define POLY_PAGE_FADECAT (POLY_NUM_PAGES - 88) +#define POLY_PAGE_LADDER (POLY_NUM_PAGES - 87) +#define POLY_PAGE_SMOKECLOUD2 (POLY_NUM_PAGES - 86) +#define POLY_PAGE_SMOKECLOUD (POLY_NUM_PAGES - 85) +#define POLY_PAGE_TINY_BUTTONS (POLY_NUM_PAGES - 84) +#define POLY_PAGE_FINALGLOW (POLY_NUM_PAGES - 83) +#define POLY_PAGE_BIG_LEAF (POLY_NUM_PAGES - 82) +#define POLY_PAGE_BIG_RAIN (POLY_NUM_PAGES - 81) +#define POLY_PAGE_BIG_BUTTONS (POLY_NUM_PAGES - 80) +#define POLY_PAGE_COLOUR_WITH_FOG (POLY_NUM_PAGES - 79) +#define POLY_PAGE_ALPHA_OVERLAY (POLY_NUM_PAGES - 78) +#define POLY_PAGE_TYRESKID (POLY_NUM_PAGES - 77) +#define POLY_PAGE_COLOUR (POLY_NUM_PAGES - 76) +#define POLY_PAGE_POLAROID (POLY_NUM_PAGES - 75) +#define POLY_PAGE_MENULOGO (POLY_NUM_PAGES - 74) +#define POLY_PAGE_SUBTRACTIVEALPHA (POLY_NUM_PAGES - 73) +#define POLY_PAGE_NEWFONT_INVERSE (POLY_NUM_PAGES - 72) +#define POLY_PAGE_IC_NORMAL (POLY_NUM_PAGES - 71) +#define POLY_PAGE_IC2_NORMAL (POLY_NUM_PAGES - 70) +#define POLY_PAGE_IC_ALPHA (POLY_NUM_PAGES - 69) +#define POLY_PAGE_IC2_ALPHA (POLY_NUM_PAGES - 68) +#define POLY_PAGE_IC_ADDITIVE (POLY_NUM_PAGES - 67) +#define POLY_PAGE_IC2_ADDITIVE (POLY_NUM_PAGES - 66) +#define POLY_PAGE_IC_ALPHA_END (POLY_NUM_PAGES - 65) +#define POLY_PAGE_IC2_ALPHA_END (POLY_NUM_PAGES - 64) +#define POLY_PAGE_PRESS1 (POLY_NUM_PAGES - 63) +#define POLY_PAGE_PRESS2 (POLY_NUM_PAGES - 62) +#define POLY_PAGE_NEWFONT (POLY_NUM_PAGES - 61) +#define POLY_PAGE_TARGET (POLY_NUM_PAGES - 60) +#define POLY_PAGE_SMOKER (POLY_NUM_PAGES - 59) +#define POLY_PAGE_DEVIL (POLY_NUM_PAGES - 58) +#define POLY_PAGE_ANGEL (POLY_NUM_PAGES - 57) +#define POLY_PAGE_ADDITIVEALPHA (POLY_NUM_PAGES - 56) +#define POLY_PAGE_TYRETRACK (POLY_NUM_PAGES - 55) +#define POLY_PAGE_WINMAP (POLY_NUM_PAGES - 54) +#define POLY_PAGE_LENSFLARE (POLY_NUM_PAGES - 53) +#define POLY_PAGE_HITSPANG (POLY_NUM_PAGES - 52) +#define POLY_PAGE_BLOOM2 (POLY_NUM_PAGES - 51) +#define POLY_PAGE_BLOOM1 (POLY_NUM_PAGES - 50) +#define POLY_PAGE_BLOODSPLAT (POLY_NUM_PAGES - 49) +#define POLY_PAGE_FLAMES3 (POLY_NUM_PAGES - 48) +#define POLY_PAGE_DUSTWAVE (POLY_NUM_PAGES - 47) +#define POLY_PAGE_BIGBANG (POLY_NUM_PAGES - 46) +#define POLY_PAGE_FACE1 (POLY_NUM_PAGES - 45) +#define POLY_PAGE_FACE2 (POLY_NUM_PAGES - 44) +#define POLY_PAGE_FACE3 (POLY_NUM_PAGES - 43) +#define POLY_PAGE_FACE4 (POLY_NUM_PAGES - 42) +#define POLY_PAGE_FACE5 (POLY_NUM_PAGES - 41) +#define POLY_PAGE_FACE6 (POLY_NUM_PAGES - 40) +#define POLY_PAGE_FONT2D (POLY_NUM_PAGES - 39) +#define POLY_PAGE_FOOTPRINT (POLY_NUM_PAGES - 38) +#define POLY_PAGE_BARBWIRE (POLY_NUM_PAGES - 37) +#define POLY_PAGE_MENUPASS (POLY_NUM_PAGES - 36) +#define POLY_PAGE_MENUTEXT (POLY_NUM_PAGES - 35) +#define POLY_PAGE_MENUFLAME (POLY_NUM_PAGES - 34) +#define POLY_PAGE_FLAMES2 (POLY_NUM_PAGES - 33) +#define POLY_PAGE_SMOKE (POLY_NUM_PAGES - 32) // 1476 // this is OK to have a "bad alpha blend mode" message +#define POLY_PAGE_FLAMES (POLY_NUM_PAGES - 31) +#define POLY_PAGE_SEWATER (POLY_NUM_PAGES - 28) +#define POLY_PAGE_SKY (POLY_NUM_PAGES - 27) +#define POLY_PAGE_SHADOW (POLY_NUM_PAGES - 26) // 1482 // this is OK to have a "bad alpha blend mode" message +#define POLY_PAGE_SHADOW_OVAL (POLY_NUM_PAGES - 25) +#define POLY_PAGE_PUDDLE (POLY_NUM_PAGES - 24) +#define POLY_PAGE_CLOUDS (POLY_NUM_PAGES - 23) +#define POLY_PAGE_ALPHA (POLY_NUM_PAGES - 22) +#define POLY_PAGE_ADDITIVE (POLY_NUM_PAGES - 21) +#define POLY_PAGE_MOON (POLY_NUM_PAGES - 20) +#define POLY_PAGE_MANONMOON (POLY_NUM_PAGES - 19) +#define POLY_PAGE_MASKED (POLY_NUM_PAGES - 18) +#define POLY_PAGE_ENVMAP (POLY_NUM_PAGES - 17) +#define POLY_PAGE_WATER (POLY_NUM_PAGES - 16) +#define POLY_PAGE_DRIP (POLY_NUM_PAGES - 15) +#define POLY_PAGE_FOG (POLY_NUM_PAGES - 14) +#define POLY_PAGE_STEAM (POLY_NUM_PAGES - 13) +#define POLY_PAGE_BANG (POLY_NUM_PAGES - 11) +#define POLY_PAGE_TEXT (POLY_NUM_PAGES - 10) +#define POLY_PAGE_LOGO (POLY_NUM_PAGES - 9) +#define POLY_PAGE_DROPLET (POLY_NUM_PAGES - 8) +#define POLY_PAGE_RAINDROP (POLY_NUM_PAGES - 7) +#define POLY_PAGE_SPARKLE (POLY_NUM_PAGES - 6) +#define POLY_PAGE_EXPLODE2 (POLY_NUM_PAGES - 5) +#define POLY_PAGE_EXPLODE1 (POLY_NUM_PAGES - 4) +#define POLY_PAGE_COLOUR_ALPHA (POLY_NUM_PAGES - 1) + +#define POLY_PAGE_TEST_SHADOWMAP (POLY_NUM_PAGES - 2) + +// +// Clears all buffers, ready for a new frame. +// Checks the clipflags and backface culling of the triangle and returns TRUE if it should be drawn. +// Adds a triangle and a quad. +// Adds a line. The widths are given in world-space sizes. if (sort_to_front) then lines will be drawn last with no z-buffer. +// Sets the box against which clip-lines are clipped. +// Adds a line clipped against the clip box. +// Draws all the triangles and quads. +// + +void POLY_frame_init (SLONG keep_shadow_page, SLONG keep_text_page); // TRUE => doesn't delete the shadow polygons. +SLONG POLY_valid_triangle(POLY_Point *p[3]); +SLONG POLY_valid_quad (POLY_Point *p[4]); +SLONG POLY_valid_line (POLY_Point *p1, POLY_Point *p2); +void POLY_add_poly (POLY_Point** poly, SLONG poly_points, SLONG page); +void POLY_add_triangle (POLY_Point *p[3], SLONG page, SLONG shall_i_backface_cull, SLONG generate_clip_flags = FALSE); +void POLY_add_quad (POLY_Point *p[4], SLONG page, SLONG shall_i_backface_cull, SLONG generate_clip_flags = FALSE); +void POLY_add_quad_split2(POLY_Point *pp[4], SLONG page, SLONG backface_cull); +void POLY_create_cylinder_points(POLY_Point* p1, POLY_Point* p2, float width, POLY_Point* pout); +void POLY_add_line (POLY_Point *p1, POLY_Point *p2, float width1, float width2, SLONG page, UBYTE sort_to_front); +void POLY_add_line_tex (POLY_Point *p1, POLY_Point *p2, float width1, float width2, SLONG page, UBYTE sort_to_front); +void POLY_add_line_2d (float sx1, float sy1, float sx2, float sy2, ULONG colour); +void POLY_clip_line_box (float sx1, float sy1, float sx2, float sy2); +void POLY_clip_line_add (float sx1, float sy1, float sx2, float sy2, ULONG colour); +void POLY_frame_draw (SLONG draw_shadow_page, SLONG draw_text_page); // FALSE => Doens't draw the shadow polygons. + +void POLY_sort_sewater_page(void); // Sorts the sewater page polys in order of distance from the eye. + +void POLY_frame_draw_odd(void); // Only draws normal textures with blend mode MODULATEALHPA +void POLY_frame_draw_puddles(void); // Only draws the puddle page. +void POLY_frame_draw_sewater(void); // Only draws the sewer water page. + +ULONG POLY_interpolate_colour(float v, ULONG colour1, ULONG colour2); + +// +// Draws the frame focused on the focal point. +// + +void POLY_frame_draw_focused(float focus); + +// +// To share points among a group of faces all using the same texture +// page. Calling any other add functions on that page will cock this up. +// + +void POLY_add_shared_start(SLONG page); +void POLY_add_shared_point(POLY_Point *pp); +void POLY_add_shared_tri (UWORD p1, UWORD p2, UWORD p3); // 0 => The first shared point added. + +// +// Returns TRUE if the given screen coordinate is inside the quad. +// If it is, then it returns the amount along the two vectors 0-1, 0-2 +// that the point lies. +// +// ASSUMES that the QUAD is a PARALELLAGRAM +// + +SLONG POLY_inside_quad( + float screen_x, + float screen_y, + POLY_Point *quad[3], + float *along_01, + float *along_02); + +// +// Flags for each standard texture page. +// + +#define POLY_PAGE_FLAG_TRANSPARENT (1 << 0) +#define POLY_PAGE_FLAG_WRAP (1 << 1) +#define POLY_PAGE_FLAG_ADD_ALPHA (1 << 2) +#define POLY_PAGE_FLAG_2PASS (1 << 3) +#define POLY_PAGE_FLAG_SELF_ILLUM (1 << 4) +#define POLY_PAGE_FLAG_NO_FOG (1 << 5) +#define POLY_PAGE_FLAG_WINDOW (1 << 6) +#define POLY_PAGE_FLAG_WINDOW_2ND (1 << 7) +#define POLY_PAGE_FLAG_ALPHA (1 << 8) + +extern SLONG draw_3d; +extern UWORD POLY_page_flag[POLY_NUM_PAGES]; + +extern void POLY_init_render_states(); + +#endif diff --git a/fallen/DDEngine/Headers/polypage.h b/fallen/DDEngine/Headers/polypage.h new file mode 100644 index 0000000..4a72a90 --- /dev/null +++ b/fallen/DDEngine/Headers/polypage.h @@ -0,0 +1,313 @@ +// polypage.h +// +// PolyPage class - main low-level rendering + +#ifndef TARGET_DC + +// PC + +// this makes absolutely fuck-all difference to speed (tested) +//#define TEX_EMBED // must be set the same in D3DTexture.h +// Do need to sort, and so need polybuffers +#define WE_NEED_POLYBUFFERS_PLEASE_BOB 1 + +#else + +// DREAMCAST + +// But it makes the VQ much more efficient, so do it! +#define TEX_EMBED // must be set the same in D3DTexture.h +// Don't need to sort, and so don't need polybuffers +#define WE_NEED_POLYBUFFERS_PLEASE_BOB 0 + +#endif + +#ifndef _POLYPAGE_ +#define _POLYPAGE_ + +#include "renderstate.h" +#include "vertexbuffer.h" +#include "polypoint.h" + +class PolyPage; + +// PolyPoly +// +// a polygon in a PolyPage + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB +struct PolyPoly +{ + float sort_z; // z-value to sort on + UWORD first_vertex; // first vertex # + UWORD num_vertices; // number of vertices; if top bit set, draw as wireframe + PolyPage* page; // page for polygon (only when in a bucket) + PolyPoly* next; // next polygon (only when in a bucket) +}; + +inline bool operator<(const PolyPoly& arg1, const PolyPoly& arg2) { return arg1.sort_z < arg2.sort_z; } +inline bool operator<=(const PolyPoly& arg1, const PolyPoly& arg2) { return arg1.sort_z <= arg2.sort_z; } +inline bool operator>(const PolyPoly& arg1, const PolyPoly& arg2) { return !(arg1 <= arg2); } +inline bool operator>=(const PolyPoly& arg1, const PolyPoly& arg2) { return !(arg1 < arg2); } + +#endif //#if WE_NEED_POLYBUFFERS_PLEASE_BOB + +// PolyPage +// +// a polygon page + +#pragma pack( push, 4 ) +class PolyPage +{ +public: + PolyPage(ULONG logsize = 6); + ~PolyPage(); + +#ifdef TEX_EMBED + // texture embedding + + PolyPage *pTheRealPolyPage; // The poly page you actually need to add tris to. + // This is never NULL, but may point back to this one. + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + void SetTexOffset ( D3DTexture *src ); +#else + void SetTexEmbed(float u_scale, float u_offset, float v_scale, float v_offset); +#endif + void SetTexOffset(UBYTE offset); // 0 for (0,0)-(1,1) else 128 + (0-15) for the subtexture +#endif + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + // fan submission + void AddFan(POLY_Point** pts, ULONG num_vertices); + void AddWirePoly(POLY_Point** pts, ULONG num_vertices); +#endif + + // set greenscreen + static void SetGreenScreen(bool enabled = true); + + // set scaling for different screen sizes + static void SetScaling(float xmul, float ymul); + +#ifdef TARGET_DC + // DC does all our sorting for us. + static void EnableAlphaSort() {} + static void DisableAlphaSort() {} + static bool AlphaSortEnabled() { return FALSE; } +#else + + // sort polygons in approx. Z order + void SortBackFirst(); + + // sort enabling + static void EnableAlphaSort() { s_AlphaSort = true; } + static void DisableAlphaSort() { s_AlphaSort = false; } + static bool AlphaSortEnabled() { return s_AlphaSort; } +#endif + + // render polygons to card +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + bool NeedsRendering() { return m_PolyBufUsed > 0; } +#else + bool NeedsRendering() { return m_VBUsed > 0; } +#endif + void Render(IDirect3DDevice3* dev); + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + // render polygons using bucket sort + void AddToBuckets(PolyPoly* buckets[], int count); + void DrawSinglePoly(PolyPoly* poly, IDirect3DDevice3* dev); +#endif + + // clear without rendering + void Clear(); + + // render state for the page + RenderState RS; + + + // static members +#ifndef TARGET_DC + static bool s_AlphaSort; // alpha sort enabled flag +#endif + static ULONG s_ColourMask; // colour mask for green-screen monitor FX + static float s_XScale; // X scale for screen vertices + static float s_YScale; // Y scale for screen vertices + + + PolyPoint2D* PointAlloc(ULONG num_points); // allocate some points - DONT USE. + PolyPoint2D* FanAlloc(ULONG num_points); // Allocate a fan polygon. + // You just fill in the data, the indices are handled magically. + + +#ifdef TEX_EMBED + float m_UScale; + float m_UOffset; + float m_VScale; + float m_VOffset; +#endif + + + +//private: + + // member variables + VertexBuffer* m_VertexBuffer; // vertex buffer + PolyPoint2D* m_VertexPtr; // pointer to vertices in buffer + ULONG m_VBLogSize; // log2 of buffer size + ULONG m_VBUsed; // number of vertices used + ULONG GetVBSize() { return 1 << m_VBLogSize; } + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + PolyPoly* m_PolyBuffer; // polygon buffer + ULONG m_PolyBufSize; // size of polygon buffer + ULONG m_PolyBufUsed; // number of polygons used + + PolyPoly* m_PolySortBuffer; // polygon sort buffer + ULONG m_PolySortBufSize; // size of polygon sort buffer +#else + // Index buffer. + WORD *m_pwIndexBuffer; // The list of indices. + ULONG m_iNumIndicesAlloc; // How many indices are allocated. + ULONG m_iNumIndicesUsed; // How many indices are used. +#endif + + +#if USE_D3D_VBUF + IDirect3DVertexBuffer* m_VB; // vertex buffer pointer, only used in bucket sort +#endif + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + // SortBackFirst iteration + void MergeSortIteration(ULONG sort_len); +#endif + + // submission helpers +// PolyPoint2D* PointAlloc(ULONG num_points); // allocate some points + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + PolyPoly* PolyBufAlloc(); // allocate a polygon +#endif + + + // massage vertices according to RS.GetEffect() + void MassageVertices(); +}; +#pragma pack( pop ) + +extern PolyPage POLY_Page[POLY_NUM_PAGES]; + +#endif + + + +// A routine to emulate the DC's DrawPrimtiveMM call on the PC, so +// that people can use it when developing on the PC. + + +// An actual function. + + + +// Notes: +// +// No front-plane clipping is performed - do it yourself, or use the old AddTri routs. +// Side-band clipping is done by the hardware. +// Only D3D_VERTEX and D3D_LVERTEX types supported. +// No alpha-blended/alpha-tested polys allowed - solid only. +// Lighting is complex - yell at TomF if you want to do lighting. I'm not going to address it in this header file. + +// The 12th byte of the vertex data holds the index +// of the matrix it uses for transformation. This byte is the least-significant +// part of the mantissa for N.X - it makes no difference to the lighting at all. +// You can set it easily using this macro: +//#define SET_MM_INDEX(v,i) (((unsigned char*) &v)[12] = (unsigned char)i) +// Remember to do this AFTER copying in all the standard data :-) + +// The indices are not actually in list order - they are in strip order, but +// an index of -1 (0xFFFF) starts a new strip. So the order +// The number of indices supplied MUST include the final FFFF. Also, when +// allocating the indices, make sure you allocate one more. Doesn't matter what's in it, +// but it must be valid memory. A small bug in the MS driver means this word is read, +// then discarded, and it doesn't cause a problem except when the index falls off the +// end of an allocated page and causes a page fault. Took me ages to find that bug. +// I will be checking that it is 0x1234 for debugging purposes, unless you give +// me a good reason not to (e.g. you're storing index lists right next to each other). +// +// On this strips-with-termination thing, the index list 0,1,2,3,4,-1,5,6,7,-1,2,4,8,-1 gives you: +// +// 1---3 5---6 +// |\ |\ | / +// | \ | \ | / +// | \| \ |/ +// 0---2---4 7 +// | / +// | / +// |/ +// 8 +// +// If you want to generate optimal strips from random indexed list data, I have +// some utility routs that will do it for you. Yell - TomF. + +// The matrices are generated in a slightly odd way. The easiest way to do this +// is to call this function to generate them: +// If mWorldMatrix == NULL, then the rout will get it from the standard camera setup. +extern void GenerateMMMatrixFromStandardD3DOnes ( D3DMATRIX *mOutput, + const D3DMATRIX *mProjectionMatrix, + const D3DMATRIX *mWorldMatrix, + const D3DVIEWPORT2 *d3dvpt ); + +// You can usually get the standard data from these globals - I keep them +// all current, and update g_matWorld when you call POLY_set_local_rotation +// and similar calls. You can use a different matrix of course and not call +// POLY_set_local_rotation, which is probably slightly faster. +extern D3DMATRIX g_matProjection; +// Actually, don't use g_matWorld, just pass in NULL. +extern D3DMATRIX g_matWorld; +extern D3DVIEWPORT2 g_viewData; + + + +#ifdef TARGET_DC + +// Just a straight alias. +#define DrawIndPrimMM(dev,type,d3dmm,numvert,pwind,numind) dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,type,(void*)d3dmm,numvert,pwind,numind,D3DDP_MULTIMATRIX) + + +#else + + +// This is already defined by DX in a DC build. +struct D3DMULTIMATRIX +{ + LPVOID lpvVertices; // Pointer to the vertex data. MUST be 32-byte aligned. + LPD3DMATRIX lpd3dMatrices; // Pointer to the array of matrices. MUST be 32-byte aligned. + LPVOID lpvLightDirs; // Pointer to the array of light vectors (NULL if not lighting). MUST be 8-byte aligned. + LPD3DCOLOR lpLightTable; // Pointer to the fade table (NULL if not lighting). MUST be 4-byte aligned. +}; + +// Also in the DC/DX headers, +#define SET_MM_INDEX(v,i) (((unsigned char*) &v)[12] = (unsigned char)i) + + +// dwFVFType must be D3DFVF_VERTEX or D3DFVF_LVERTEX. +// d3dmm is the multimatrix info block: +extern HRESULT DrawIndPrimMM ( LPDIRECT3DDEVICE3 lpDevice, + DWORD dwFVFType, + D3DMULTIMATRIX *d3dmm, + WORD wNumVertices, + WORD *pwIndices, + DWORD dwNumIndices ); + +#endif + + +// Useful. +#define GET_MM_INDEX(v) (((unsigned char*)&v)[12]) + + + + + + + diff --git a/fallen/DDEngine/Headers/polypoint.h b/fallen/DDEngine/Headers/polypoint.h new file mode 100644 index 0000000..8443876 --- /dev/null +++ b/fallen/DDEngine/Headers/polypoint.h @@ -0,0 +1,112 @@ +// polypoint.h +// +// PolyPoint class, encapsulating a D3DTLVERTEX + +// PolyPoint2D +// +// really a D3DTLVERTEX with helper functions +// +// the coordinates are stored as (x/z,y/z,1-1/z,1/z) + +#ifndef _POLYPOINT_ +#define _POLYPOINT_ + +// we copy U,V using int copies; this is because u,v are uninitialized in +// a lot of cases. we can only hope that the driver doesn't read U,V into +// the FPU because it's not practical to check every single point where a +// POLY_Point is initialized ... +#ifdef TARGET_DC +#define INT_COPY_FLOAT(DST,SRC) ((DST)=(SRC)) +#else +#define INT_COPY_FLOAT(DST,SRC) *((int*)&(DST)) = *((int*)&(SRC)) +#endif + +class PolyPoint2D : private D3DTLVERTEX // don't even *think* about making this a public base-class +{ +public: + // Helper functions for setup: + + void SetSC(float sx, float sy, float sz = 0); // Set Screen coordinates + + void SetUV(float& u, float& v); // Set u,v + void SetUV2(float u, float v); // Set u,v + + static ULONG MakeD3DColour(UBYTE r, UBYTE g, UBYTE b, UBYTE a); // make D3D colour value + static ULONG ModulateD3DColours(ULONG c1, ULONG c2); // modulate 2 D3D colour values + + void SetColour(ULONG d3d_col); // Set colour + void SetColour(UBYTE r, UBYTE g, UBYTE b, UBYTE a = 0xFF); + + void SetSpecular(ULONG d3d_col); // Set specular colour + void SetSpecular(UBYTE r, UBYTE g, UBYTE b, UBYTE a = 0xFF); + + /* + D3DTLVERTEX *GetTLVert ( void ) + { + return ( (D3DTLVERTEX *)this ); + } + */ +}; + +inline void PolyPoint2D::SetSC(float _sx, float _sy, float _sz) +{ + sx = _sx; + sy = _sy; + sz = _sz; + rhw = 1.0F - _sz; +} + +inline void PolyPoint2D::SetUV(float& u, float& v) +{ + INT_COPY_FLOAT(tu, u); + INT_COPY_FLOAT(tv, v); +} + +inline void PolyPoint2D::SetUV2(float u, float v) +{ + INT_COPY_FLOAT(tu, u); + INT_COPY_FLOAT(tv, v); +} + +inline ULONG PolyPoint2D::MakeD3DColour(UBYTE r, UBYTE g, UBYTE b, UBYTE a) +{ + return (ULONG(a) << 24) | (ULONG(r) << 16) | (ULONG(g) << 8) | ULONG(b); +} + +inline void PolyPoint2D::SetColour(ULONG d3d_col) +{ + color = d3d_col; +} + +inline void PolyPoint2D::SetColour(UBYTE r, UBYTE g, UBYTE b, UBYTE a) +{ + SetColour(MakeD3DColour(r,g,b,a)); +} + +inline void PolyPoint2D::SetSpecular(ULONG d3d_col) +{ + specular = d3d_col; +} + +inline void PolyPoint2D::SetSpecular(UBYTE r, UBYTE g, UBYTE b, UBYTE a) +{ + SetSpecular(MakeD3DColour(r,g,b,a)); +} + +// NOTE: doesn't round properly, doesn't modulate alpha + +inline ULONG PolyPoint2D::ModulateD3DColours(ULONG c1, ULONG c2) +{ + ULONG res; + + res = ((c1 & 0xFF) * (c2 & 0xFF)) >> 8; + c1 >>= 8; c2 >>= 8; + res |= ((c1 & 0xFF) * (c2 & 0xFF)) & 0xFF00; + c1 >>= 8; c2 >>= 8; + res |= (((c1 & 0xFF) * (c2 & 0xFF)) & 0xFF00) << 8; + res |= (c1 & 0xFF00) << 16; + + return res; +} + +#endif diff --git a/fallen/DDEngine/Headers/qeng.h b/fallen/DDEngine/Headers/qeng.h new file mode 100644 index 0000000..c9f6482 --- /dev/null +++ b/fallen/DDEngine/Headers/qeng.h @@ -0,0 +1,87 @@ +// +// An engine for the qmap. +// + +#ifndef _QENG_ +#define _QENG_ + + +#include "c:\fallen\headers\qmap.h" + + +// +// Once at the start of the whole program. +// + +void QENG_init(void); + + +// +// Debug messages drawn to the screen. +// + +void MSG_add(CBYTE *message, ...); + + +// +// Where everything is drawn from. +// + +void QENG_set_camera( + float world_x, + float world_y, + float world_z, + float yaw, + float pitch, + float roll); + +// +// Clears the screen. +// + +void QENG_clear_screen(void); + + +// +// Draws a line in the world. Sets QENG_mouse_over and QENG_mouse_pos if the +// mouse is over the line. +// + +extern SLONG QENG_mouse_over; +extern float QENG_mouse_pos_x; // Position in the world +extern float QENG_mouse_pos_y; +extern float QENG_mouse_pos_z; + +void QENG_world_line( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + bool sort_to_front); + +// +// Draws a QMAP_Draw structure. +// + +void QENG_draw(QMAP_Draw *qd); + +// +// Draws everything. +// + +void QENG_render(void); + + +// +// Flips in the backbuffer. +// + +void QENG_flip(void); + + +// +// Once at the end of the whole program. +// + +void QENG_fini(void); + + +#endif diff --git a/fallen/DDEngine/Headers/ray.h b/fallen/DDEngine/Headers/ray.h new file mode 100644 index 0000000..45cb785 --- /dev/null +++ b/fallen/DDEngine/Headers/ray.h @@ -0,0 +1,19 @@ +// +// Realtime raytracing on the PC! +// + +#ifndef _RAY_ +#define _RAY_ + + + +// +// Loops the raytracing demo... +// + +void RAY_do(void); + + + +#endif + diff --git a/fallen/DDEngine/Headers/renderstate.h b/fallen/DDEngine/Headers/renderstate.h new file mode 100644 index 0000000..6c7ff23 --- /dev/null +++ b/fallen/DDEngine/Headers/renderstate.h @@ -0,0 +1,105 @@ +// renderstate.h +// +// render state class; encapsulates a state of the renderer + +#ifndef _RENDERSTATE_ +#define _RENDERSTATE_ + +enum SpecialEffect +{ + RS_None, // no special effect + RS_AlphaPremult, // premultiply vertex colours by alpha and set alpha to 0 + RS_BlackWithAlpha, // set vertex R,G,B to (0,0,0) + RS_InvAlphaPremult, // premultiply vertex colours by 1-alpha and set alpha to 0 + RS_DecalMode // set vertex A,R,G,B to (255,255,255,255) +}; + +#pragma pack( push, 4 ) +struct RenderState +{ + RenderState(DWORD mag_filter = D3DFILTER_LINEAR, DWORD min_filter = D3DFILTER_NEAREST); + + void SetTexture(LPDIRECT3DTEXTURE2 texture); + void SetRenderState(DWORD index, DWORD value); + void SetEffect(DWORD effect); + +#ifndef TARGET_DC + void SetTempTransparent(); + void ResetTempTransparent(); +#endif + + LPDIRECT3DTEXTURE2 GetTexture() { return TextureMap; } + DWORD GetEffect() { return Effect; } + + void InitScene(DWORD fog_colour); + + void SetChanged(); // set changed members + +#ifdef TARGET_DC + bool NeedsSorting() { return FALSE; } +#else + bool NeedsSorting() { return !ZWriteEnable; } +#endif + DWORD ZLift() { return ZBias; } + + void WrapJustOnce() {WrapOnce = true;} // Temporarily sets the state to wrapping just for one call to SetChanged() + +#ifdef _DEBUG + char* Validate(); // returns a string error if not OK +#endif + + bool IsSameRenderState ( RenderState *pRS ); + + + static RenderState s_State; + +#ifdef EDITOR + static bool AllowFadeOut; +#endif + + bool IsAlphaBlendEnabled() { return ( AlphaBlendEnable != FALSE );} + +private: + LPDIRECT3DTEXTURE2 TextureMap; + DWORD TextureAddress; + DWORD TextureMag; + DWORD TextureMin; + DWORD TextureMapBlend; + +#ifndef TARGET_DC + DWORD ZEnable; + DWORD ZWriteEnable; +#endif + DWORD AlphaTestEnable; + DWORD SrcBlend; + DWORD DestBlend; +#ifndef TARGET_DC + DWORD ZFunc; +#endif + DWORD AlphaBlendEnable; + DWORD FogEnable; +#ifndef TARGET_DC + DWORD ColorKeyEnable; +#endif + DWORD CullMode; + DWORD ZBias; + DWORD Effect; + bool WrapOnce; + +#ifndef TARGET_DC + bool TempTransparent; + DWORD TempSrcBlend; + DWORD TempDestBlend; + DWORD TempAlphaBlendEnable; + DWORD TempZWriteEnable; + DWORD TempTextureMapBlend; + DWORD TempEffect; +#endif +}; +#pragma pack( pop ) + +void RS_read_config(); +void RS_get_config(int* fix_directx); +void RS_set_config(int fix_directx); + +#endif diff --git a/fallen/DDEngine/Headers/shape.h b/fallen/DDEngine/Headers/shape.h new file mode 100644 index 0000000..69ec667 --- /dev/null +++ b/fallen/DDEngine/Headers/shape.h @@ -0,0 +1,161 @@ +// +// Primitive shapes... +// + +#ifndef _SHAPE_ +#define _SHAPE_ + + +#include "ob.h" + + +// +// Draws a semi-sphere whose edge is black and whose colour in the +// middle is given. It is drawn with additive-alpha. +// + +void SHAPE_semisphere( + SLONG x, + SLONG y, + SLONG z, + SLONG dx, // Gives the direction of the semi-sphere (256 long) + SLONG dy, + SLONG dz, + SLONG radius, + SLONG page, + UBYTE red, + UBYTE green, + UBYTE blue); + +void SHAPE_semisphere_textured( + SLONG x, + SLONG y, + SLONG z, + SLONG dx, // Gives the direction of the semi-sphere (256 long) + SLONG dy, + SLONG dz, + SLONG radius, + float u_mid, + float v_mid, + float uv_radius, + SLONG page, + UBYTE red, + UBYTE green, + UBYTE blue); + +// +// Draws a sphere. +// + +void SHAPE_sphere( + SLONG x, + SLONG y, + SLONG z, + SLONG radius, + ULONG colour); + +// +// Draws an alpha sphere. +// + +void SHAPE_alpha_sphere( + SLONG x, + SLONG y, + SLONG z, + SLONG radius, + ULONG colour, + ULONG alpha); + + +// +// Draws a sparky line. +// + +#define SHAPE_MAX_SPARKY_POINTS 16 + +void SHAPE_sparky_line( + SLONG num_points, + SLONG px[], + SLONG py[], + SLONG pz[], + ULONG colour, + float width); + + +// +// Draws a bit of glitter. +// + +void SHAPE_glitter( + SLONG x1, + SLONG y1, + SLONG z1, + SLONG x2, + SLONG y2, + SLONG z2, + ULONG colour); + +// +// Draws a trip-wire. +// + +void SHAPE_tripwire( + SLONG x1, + SLONG y1, + SLONG z1, + SLONG x2, + SLONG y2, + SLONG z2, + SLONG width, + ULONG colour, + UWORD counter, // A frame animation counter. + UBYTE along); // How far along the line the tripwire goes. + +// +// Draws a waterfall. +// + +void SHAPE_waterfall( + SLONG map_x, + SLONG map_z, + SLONG map_dx, + SLONG map_dz, + SLONG top, + SLONG bot); + + +// +// Draws a droplet of water. +// + +void SHAPE_droplet( + SLONG x, + SLONG y, + SLONG z, + SLONG dx, + SLONG dy, + SLONG dz, + ULONG colour, + SLONG page); + +// +// Draws a shadow for the given prim. +// + +void SHAPE_prim_shadow(OB_Info *oi); + + +// +// Draws a balloon. +// + +void SHAPE_draw_balloon(SLONG balloon); + + + +#endif + + + + + diff --git a/fallen/DDEngine/Headers/sky.h b/fallen/DDEngine/Headers/sky.h new file mode 100644 index 0000000..da736a5 --- /dev/null +++ b/fallen/DDEngine/Headers/sky.h @@ -0,0 +1,88 @@ +// +// Sky. +// + +#ifndef SKY_H +#define SKY_H + + +// +// Needs the screen to have been initialised. +// if 'star_file' is NULL, then stars are placed randomly, otherwise +// it should be an ascii file of the form... +// +// +// # These are comment lines +// # The values are Yaw, Pitch, Brightness +// # Yaw and Pitch are in degrees and brightness goes from 0 to 255. +// +// Star: 230, 45, 205 +// Star: 125, 70, 100 +// + +void SKY_init(CBYTE *star_file); + + + +// ======================================================== +// +// THE SKY AT NIGHT +// +// ======================================================== + +// +// Draws the stars to a LOCKED screen! +// This should be done before drawing any polys. +// + +void SKY_draw_stars( + float world_camera_x, + float world_camera_y, + float world_camera_z, + float max_dist); + +void SKY_draw_poly_clouds( + float world_camera_x, + float world_camera_y, + float world_camera_z, + float max_dist); + +void SKY_draw_poly_moon( + float world_camera_x, + float world_camera_y, + float world_camera_z, + float max_dist); + +// +// Draws the reflection of the moon and returns its bounding box on screen. +// Returns FALSE if the moon was off-screen. +// + +SLONG SKY_draw_moon_reflection( + float world_camera_x, + float world_camera_y, + float world_camera_z, + float max_dist, + float *moon_screen_x1, + float *moon_screen_y1, + float *moon_screen_x2, + float *moon_screen_y2); + + +// ======================================================== +// +// THE SKY DURING THE DAY. +// +// ======================================================== + +void SKY_draw_poly_sky( + float world_camera_x, + float world_camera_y, + float world_camera_z, + float world_camera_yaw, + float max_dist, + ULONG bot_colour, + ULONG top_colour); + + +#endif diff --git a/fallen/DDEngine/Headers/smap.h b/fallen/DDEngine/Headers/smap.h new file mode 100644 index 0000000..3458e09 --- /dev/null +++ b/fallen/DDEngine/Headers/smap.h @@ -0,0 +1,62 @@ +// +// Shadow maps. +// + +#ifndef _SMAP_ +#define _SMAP_ + + + +// +// Creates a shadow map of the given person. +// + +void SMAP_person( + Thing *person, + UBYTE *bitmap, // 0 => transparent 255 => opaque + UBYTE u_res, + UBYTE v_res, + SLONG light_dx, // This vector need not be normalised + SLONG light_dy, + SLONG light_dz); + +void SMAP_bike( + Thing *person, + UBYTE *bitmap, // 0 => transparent 255 => opaque + UBYTE u_res, + UBYTE v_res, + SLONG light_dx, // This vector need not be normalised + SLONG light_dy, + SLONG light_dz); + + +// +// Projects the last shadow map created onto a poly in world-space. The poly +// should be given in clockwise order. This function returns NULL if the poly +// is facing away from the light, or if the poly is on the 'wrong side' of +// the shadow map. The polygon linked list is valid until the next call +// to the function. +// +// This is not a circular data structure. The last point of the poly has a NULL +// pointer. There is not a copy of the first point at the end of the linked list. +// + +typedef struct smap_link +{ + float wx; + float wy; + float wz; + float u; + float v; + + struct smap_link *next; + + ULONG clip; // Private! + +} SMAP_Link; + +SMAP_Link *SMAP_project_onto_poly(SVector_F poly[], SLONG num_points); // poly must be planar. + + + +#endif diff --git a/fallen/DDEngine/Headers/sprite.h b/fallen/DDEngine/Headers/sprite.h new file mode 100644 index 0000000..ba009c3 --- /dev/null +++ b/fallen/DDEngine/Headers/sprite.h @@ -0,0 +1,72 @@ +// +// Drawing sprites... +// + +#ifndef _SPRITE_ +#define _SPRITE_ + + + +#define SPRITE_SORT_NORMAL 1 +#define SPRITE_SORT_FRONT 2 + +void SPRITE_draw( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + SLONG sort); + +void SPRITE_draw_tex( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + float u,float v,float w,float h, + SLONG sort); + + +#ifdef TARGET_DC + +// Need to slim down the number of parameters. +struct SPRITE_draw_tex_distorted_params +{ + float u, v, w, h; + float wx1, wy1, wx2, wy2, wx3, wy3, wx4, wy4; +}; + +void SPRITE_draw_tex_distorted( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + SLONG sort, + SPRITE_draw_tex_distorted_params *pParams); + +#else //#ifdef TARGET_DC + +void SPRITE_draw_tex_distorted( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + float u,float v,float w,float h, + float wx1, float wy1, float wx2, float wy2, float wx3, float wy3, float wx4, float wy4, + SLONG sort); + +#endif //#else //#ifdef TARGET_DC + +#endif + diff --git a/fallen/DDEngine/Headers/supercrinkle.h b/fallen/DDEngine/Headers/supercrinkle.h new file mode 100644 index 0000000..4ee1782 --- /dev/null +++ b/fallen/DDEngine/Headers/supercrinkle.h @@ -0,0 +1,57 @@ +// +// SUPERCRINKLES! +// + +#ifndef _SUPERCRINKLE_ +#define _SUPERCRINKLE_ + + +// Set to 0 to remove all crinkle stuff. +#define SUPERCRINKLES_ENABLED 0 + + + + +#if SUPERCRINKLES_ENABLED + +// +// Loads all the crinkles for the current level and creates +// their lighting textures. +// + +void SUPERCRINKLE_init(void); + + +// +// Does this page have a crinkle? +// + +extern UBYTE SUPERCRINKLE_is_crinkled[512]; + +#define SUPERCRINKLE_IS_CRINKLED(num) SUPERCRINKLE_is_crinkled[num] + + +// +// Draws the given crinkle. It assumes the POLY_local_rotation +// has been setup properly already. Returns TRUE if it drew +// a SUPERCRINKLE. +// + +SLONG SUPERCRINKLE_draw(SLONG page, ULONG colour[4], ULONG specular[4]); + + +#else //#if SUPERCRINKLES_ENABLED + + +// Dummy routs. +inline void SUPERCRINKLE_init(void) {} + +#define SUPERCRINKLE_IS_CRINKLED(num) FALSE + +inline SLONG SUPERCRINKLE_draw(SLONG page, ULONG colour[4], ULONG specular[4]){ return FALSE; } + + +#endif //#else //#if SUPERCRINKLES_ENABLED + + +#endif diff --git a/fallen/DDEngine/Headers/superfacet.h b/fallen/DDEngine/Headers/superfacet.h new file mode 100644 index 0000000..56517da --- /dev/null +++ b/fallen/DDEngine/Headers/superfacet.h @@ -0,0 +1,43 @@ +// +// Converts facets to draw indexed primitive calls... +// + +#ifndef _SUPERFACET_ +#define _SUPERFACET_ + + + +// +// Call at the start of the game_loop()- after everything has +// been loaded. Sets up memory. +// + +void SUPERFACET_init(void); + + +// +// Sets up the frame for drawing SUPERFACET +// + +void SUPERFACET_start_frame(void); + + + +// +// Draws a super-fast facet if it can, otherwise returns FALSE! +// + +SLONG SUPERFACET_draw(SLONG facet); + + + +// +// Call at the end of the game_loop()- frees up memory. +// + +void SUPERFACET_fini(void); + + + + +#endif diff --git a/fallen/DDEngine/Headers/sw.h b/fallen/DDEngine/Headers/sw.h new file mode 100644 index 0000000..3b35565 --- /dev/null +++ b/fallen/DDEngine/Headers/sw.h @@ -0,0 +1,84 @@ +// +// Sofware renderer hacked in! +// + +#ifndef _SW_ +#define _SW_ + + +// +// The maximum software screen dimensions. +// + +#define SW_MAX_WIDTH 640 +#define SW_MAX_HEIGHT 480 + +extern ULONG *SW_buffer; + +#ifndef TARGET_DC + +// +// Reloads all textures. Looks at the D3D Texture system and +// loads a copy of each texture. +// + +void SW_reload_textures(void); + + +// +// Initialises a new frame and clears the SW_buffer. +// + +void SW_init( + SLONG width, + SLONG height); + + +// +// Sets the way each page is drawn. +// + +#define SW_PAGE_IGNORE 0 // This page is not drawn. +#define SW_PAGE_NORMAL 1 +#define SW_PAGE_MASKED 2 +#define SW_PAGE_ALPHA 3 +#define SW_PAGE_ADDITIVE 4 + +void SW_set_page(SLONG page, SLONG type); + + + + +// +// Adds a triangle. (x,y) are given in 8-bit fixed point and z +// is a value from 1 to 65535. +// + +void SW_add_triangle( + SLONG x1, SLONG y1, SLONG z1, SLONG r1, SLONG g1, SLONG b1, SLONG u1, SLONG v1, + SLONG x2, SLONG y2, SLONG z2, SLONG r2, SLONG g2, SLONG b2, SLONG u2, SLONG v2, + SLONG x3, SLONG y3, SLONG z3, SLONG r3, SLONG g3, SLONG b3, SLONG u3, SLONG v3, + SLONG page, + SLONG alpha = 255); // Only for certain pages... + +// +// Copies the SW_buffer onto the back buffer. +// + +void SW_copy_to_bb(void); + + +#else //#ifndef TARGET_DC + +// Not used - it just shuts the compiler up. +#define SW_PAGE_IGNORE 0 // This page is not drawn. +#define SW_PAGE_NORMAL 1 +#define SW_PAGE_MASKED 2 +#define SW_PAGE_ALPHA 3 +#define SW_PAGE_ADDITIVE 4 + +#endif //#else //#ifndef TARGET_DC + + + +#endif diff --git a/fallen/DDEngine/Headers/texture.h b/fallen/DDEngine/Headers/texture.h new file mode 100644 index 0000000..b4fdf63 --- /dev/null +++ b/fallen/DDEngine/Headers/texture.h @@ -0,0 +1,288 @@ +// +// Texture handling is wierd! +// + +#ifndef TEXTURE_H +#define TEXTURE_H + + +#include "crinkle.h" + + +// +// The shadow texture page is generated by you! This is its size. +// The is the texture page for video playback. +// + +#define TEXTURE_SHADOW_SIZE 64 +#define TEXTURE_VIDEO_SIZE 64 + +#define FACE_PAGE_OFFSET (8*64) + +// +// Chooses the texture set to use. If the current texture set is +// different from the new one, then all the textures are released. +// + +void TEXTURE_choose_set(SLONG number); + + + +// +// Fixed prims to work with the individual texture pages. Call this function BEFORE +// you load the textures! It works out which pages are needed. +// + +void TEXTURE_fix_prim_textures(SLONG flag); +void TEXTURE_fix_texture_styles(void); + +// +// The number of standard texture pages. +// + +extern SLONG TEXTURE_page_num_standard; + +#ifdef TARGET_DC +extern SLONG TEXTURE_page_background_use_instead; +extern SLONG TEXTURE_page_background_use_instead2; + +extern SLONG TEXTURE_page_joypad_a; +extern SLONG TEXTURE_page_joypad_b; +extern SLONG TEXTURE_page_joypad_c; +extern SLONG TEXTURE_page_joypad_x; +extern SLONG TEXTURE_page_joypad_y; +extern SLONG TEXTURE_page_joypad_z; +extern SLONG TEXTURE_page_joypad_l; +extern SLONG TEXTURE_page_joypad_r; +extern SLONG TEXTURE_page_joypad_pad_l; +extern SLONG TEXTURE_page_joypad_pad_r; +extern SLONG TEXTURE_page_joypad_pad_d; +extern SLONG TEXTURE_page_joypad_pad_u; +#endif + +extern SLONG TEXTURE_page_snowflake; +extern SLONG TEXTURE_page_sparkle; +extern SLONG TEXTURE_page_explode2; +extern SLONG TEXTURE_page_explode1; +extern SLONG TEXTURE_page_bigbang; +extern SLONG TEXTURE_page_face1; +extern SLONG TEXTURE_page_face2; +extern SLONG TEXTURE_page_face3; +extern SLONG TEXTURE_page_face4; +extern SLONG TEXTURE_page_face5; +extern SLONG TEXTURE_page_face6; +extern SLONG TEXTURE_page_fog; +extern SLONG TEXTURE_page_moon; +extern SLONG TEXTURE_page_clouds; +extern SLONG TEXTURE_page_water; +extern SLONG TEXTURE_page_puddle; +extern SLONG TEXTURE_page_drip; +extern SLONG TEXTURE_page_shadow; +extern SLONG TEXTURE_page_bang; +extern SLONG TEXTURE_page_font; +extern SLONG TEXTURE_page_logo; +extern SLONG TEXTURE_page_sky; +extern SLONG TEXTURE_page_flames; +extern SLONG TEXTURE_page_smoke; +extern SLONG TEXTURE_page_flame2; +extern SLONG TEXTURE_page_steam; +extern SLONG TEXTURE_page_menuflame; +extern SLONG TEXTURE_page_barbwire; +extern SLONG TEXTURE_page_font2d; +extern SLONG TEXTURE_page_dustwave; +extern SLONG TEXTURE_page_flames3; +extern SLONG TEXTURE_page_bloodsplat; +extern SLONG TEXTURE_page_bloom1; +extern SLONG TEXTURE_page_bloom2; +extern SLONG TEXTURE_page_hitspang; +extern SLONG TEXTURE_page_lensflare; +extern SLONG TEXTURE_page_tyretrack; +extern SLONG TEXTURE_page_envmap; // The environment map on metal +extern SLONG TEXTURE_page_winmap; // The environment map on windows +extern SLONG TEXTURE_page_leaf; +extern SLONG TEXTURE_page_raindrop; +extern SLONG TEXTURE_page_footprint; +extern SLONG TEXTURE_page_angel; +extern SLONG TEXTURE_page_devil; +extern SLONG TEXTURE_page_smoker; +extern SLONG TEXTURE_page_target; +extern SLONG TEXTURE_page_newfont; +extern SLONG TEXTURE_page_droplet; +extern SLONG TEXTURE_page_press1; +extern SLONG TEXTURE_page_press2; +extern SLONG TEXTURE_page_ic; +extern SLONG TEXTURE_page_ic2; +extern SLONG TEXTURE_page_lcdfont; +extern SLONG TEXTURE_page_smokecloud; +extern SLONG TEXTURE_page_menulogo; +extern SLONG TEXTURE_page_polaroid; +extern SLONG TEXTURE_page_bigbutton; +extern SLONG TEXTURE_page_bigleaf; +extern SLONG TEXTURE_page_bigrain; +extern SLONG TEXTURE_page_finalglow; +extern SLONG TEXTURE_page_tinybutt; +extern SLONG TEXTURE_page_lcdfont_alpha; +extern SLONG TEXTURE_page_flames_alpha; +extern SLONG TEXTURE_page_tyretrack_alpha; +extern SLONG TEXTURE_page_people3; +extern SLONG TEXTURE_page_ladder; +extern SLONG TEXTURE_page_fadecat; +extern SLONG TEXTURE_page_fade_MF; +extern SLONG TEXTURE_page_shadowoval; +extern SLONG TEXTURE_page_rubbish; +extern SLONG TEXTURE_page_lastpanel; +extern SLONG TEXTURE_page_lastpanel2; +extern SLONG TEXTURE_page_sign; +extern SLONG TEXTURE_page_pcflamer; +extern SLONG TEXTURE_page_shadowsquare; +extern SLONG TEXTURE_page_litebolt; +extern SLONG TEXTURE_page_ladshad; +extern SLONG TEXTURE_page_meteor; +extern SLONG TEXTURE_page_splash; + +extern SLONG TEXTURE_num_textures; // The total number of pages. + +// +// Returns the texture handle of the given page. +// DX6: returns a D3DTexture ptr to give to SET_TEXTURE macro +// + +//D3DTEXTUREHANDLE TEXTURE_get_handle(SLONG page); +LPDIRECT3DTEXTURE2 TEXTURE_get_handle(SLONG page); + + +#ifdef TEX_EMBED +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +D3DTexture *TEXTURE_get_D3DTexture(SLONG page); +#else +UBYTE TEXTURE_get_offset(SLONG page); +#endif +#endif + + + +// +// The handle of each crinkle. NULL => No crinkle for that page. +// + +extern CRINKLE_Handle TEXTURE_crinkle[22 * 64]; + + + + +// +// To update the shadow texture page, first lock it, then +// write into it, then unlock it, then update it... phew! +// + +// +// These are only valid after a successful lock. +// + +extern UWORD *TEXTURE_shadow_bitmap; +extern SLONG TEXTURE_shadow_pitch; // In bytes! +extern SLONG TEXTURE_shadow_mask_red; +extern SLONG TEXTURE_shadow_mask_green; +extern SLONG TEXTURE_shadow_mask_blue; +extern SLONG TEXTURE_shadow_mask_alpha; +extern SLONG TEXTURE_shadow_shift_red; +extern SLONG TEXTURE_shadow_shift_green; +extern SLONG TEXTURE_shadow_shift_blue; +extern SLONG TEXTURE_shadow_shift_alpha; + +SLONG TEXTURE_shadow_lock (void); // False on failure. +void TEXTURE_shadow_unlock(void); +void TEXTURE_shadow_update(void); + +SLONG TEXTURE_86_lock (void); // False on failure. +void TEXTURE_86_unlock(void); +void TEXTURE_86_update(void); + + + +// +// Returns the four texture coordinates of the given MiniTextureBits structure +// + +void TEXTURE_get_minitexturebits_uvs( + UWORD texture, + SLONG *page, + float *u0, + float *v0, + float *u1, + float *v1, + float *u2, + float *v2, + float *u3, + float *v3); + +// +// Gives the uv of the top left of the given texture square and +// returns the page. +// + +SLONG TEXTURE_get_fiddled_position( + SLONG square_u, + SLONG square_v, + SLONG page, + float *u, + float *v); + +// +// Makes black the colour key for the given texture. +// + +#ifndef TARGET_DC +void TEXTURE_set_colour_key(SLONG page); +#endif + + +// +// Makes all the textures greyscale. +// + +void TEXTURE_set_greyscale(SLONG is_greyscale); + +// +// Change a specific texture to a different tga +// + +void TEXTURE_set_tga(SLONG page, CBYTE *fn); + +// +// Frees all the texture pages. +// + +void TEXTURE_free(void); + +// Frees all the non-frontend texture pages. +void TEXTURE_free_unneeded ( void ); + +// +// Returns what sort it thinks the given page looks like. +// + +#define TEXTURE_LOOK_ROAD 0 +#define TEXTURE_LOOK_GRASS 1 +#define TEXTURE_LOOK_DIRT 2 +#define TEXTURE_LOOK_SLIPPERY 3 + +extern SLONG TEXTURE_liney; +extern SLONG TEXTURE_av_r; +extern SLONG TEXTURE_av_g; +extern SLONG TEXTURE_av_b; + +SLONG TEXTURE_looks_like(SLONG page); + + +#endif + + + + + + + + + + diff --git a/fallen/DDEngine/Headers/truetype.h b/fallen/DDEngine/Headers/truetype.h new file mode 100644 index 0000000..0d65096 --- /dev/null +++ b/fallen/DDEngine/Headers/truetype.h @@ -0,0 +1,81 @@ +// truetype.h +// +// TrueType font handling + +#include "texture.h" + +// if this is defined, we use TrueType fonts, otherwise we use normal fonts +//#define TRUETYPE + +// TextCommand +// +// a text command + +#define MAX_TT_TEXT (2048 - 48) + +struct TextCommand +{ + char data[MAX_TT_TEXT]; // data for the command + int nbytes; // number of bytes of data + int nchars; // number of chars of data + int x,y; // origin x,y + int rx; // right x margin + int scale; // scale (256 = x1) + ULONG rgb; // RGB colour + int command; // command type + int validity; // validity + bool in_cache; // in cache? + int lines; // number of lines + int fwidth; // formatted width +}; + +enum TextCommands +{ + LeftJustify = 0, // left-justify and word-wrap + RightJustify, // right-justify and word-wrap + Centred, // centre and word-wrap +}; + +enum Validity +{ + Free = 0, // command slot is free + Current, // command is current + Pending, // command is pending free +}; + +// CacheLine +// +// a line of texture, 256 x in size +// one per line of allocated texture RAM + +struct CacheLine +{ + TextCommand* owner; // owning TextCommand, or NULL if free + int sx,sy; // screen x,y to render to + int width; // width used + int height; // height used + + D3DTexture* texture; // mapped texture + int y; // mapped y coordinate +}; + +// +// API +// + +// init library + +extern void TT_Init(); +extern void TT_Term(); + +// call before flipping the screen + +extern void PreFlipTT(); + +// draw text + +extern int DrawTextTT(char* string, int x, int y, int rx, int scale, ULONG rgb, int command, long* width = NULL); + +// get height + +extern int GetTextHeightTT(); \ No newline at end of file diff --git a/fallen/DDEngine/Headers/vertexbuffer.h b/fallen/DDEngine/Headers/vertexbuffer.h new file mode 100644 index 0000000..3aefb47 --- /dev/null +++ b/fallen/DDEngine/Headers/vertexbuffer.h @@ -0,0 +1,94 @@ +// vertexbuffer.h +// +// Vertex buffer stuff (DX6) + +#ifndef _VERTEXBUFFER_ +#define _VERTEXBUFFER_ + +#ifndef TARGET_DC +// tried and it is about 33% faster than not using D3D vertex buffers +#define USE_D3D_VBUF 0 // set to 0 to revert to malloc'd vertex buffers + +#else +// DC doesn't have (or need) them +#define USE_D3D_VBUF 0 +#endif + +extern void VB_Init(); +extern void VB_Term(); + +// VertexBuffer +// +// a D3D vertex buffer + +class VertexBuffer +{ +public: + ~VertexBuffer(); + + D3DTLVERTEX* GetPtr() { ASSERT(m_LockedPtr); return m_LockedPtr; } + ULONG GetSize() { return 1 << m_LogSize; } + ULONG GetLogSize() { return m_LogSize; } + +private: + friend class VertexBufferPool; + + VertexBuffer(); + + // create the buffer + HRESULT Create(IDirect3D3* d3d, bool force_system, ULONG logsize = 6); + + D3DTLVERTEX* Lock(); // lock the buffer + void Unlock(); // unlock the buffer + + ULONG m_LogSize; // log2 of size + D3DTLVERTEX* m_LockedPtr; // ptr to memory iff locked + VertexBuffer* m_Prev; // prev in chain + VertexBuffer* m_Next; // next in chain + +#if USE_D3D_VBUF + IDirect3DVertexBuffer* m_TheBuffer; +#endif +}; + +// VertexBufferPool +// +// vertex buffer pool + +class VertexBufferPool +{ +public: + VertexBufferPool(); + ~VertexBufferPool(); + + void Create(IDirect3D3* d3d, bool force_system); // create pool and preallocate some buffers + + VertexBuffer* GetBuffer(ULONG logsize = 6); // get a new buffer + void ReleaseBuffer(VertexBuffer* buffer); // release a buffer + + VertexBuffer* ExpandBuffer(VertexBuffer* buffer); // expand a buffer +#if USE_D3D_VBUF + IDirect3DVertexBuffer* PrepareBuffer(VertexBuffer* buffer); // prepare a buffer for rendering +#endif + +#ifndef TARGET_DC + void DumpInfo(FILE* fd); // dump info out +#endif + + void ReclaimBuffers(); // try to reclaim any free buffers + +private: + IDirect3D3* m_D3D; // D3D object + bool m_SysMem; // use system memory? + VertexBuffer* m_FreeList[16]; // free vertex buffers (locked) + VertexBuffer* m_BusyListLRU[16]; // busy vertex buffers, least recent end = head + VertexBuffer* m_BusyListMRU[16]; // busy vertex buffers, most recent end = tail + ULONG m_Count[16]; // total number of buffers + + void CreateBuffer(ULONG logsize); // create a buffer of the given size + void CheckBuffers(ULONG logsize, bool time_critical); // check busy buffers +}; + +extern VertexBufferPool* TheVPool; + +#endif diff --git a/fallen/DDEngine/Headers/wibble.h b/fallen/DDEngine/Headers/wibble.h new file mode 100644 index 0000000..88a13ce --- /dev/null +++ b/fallen/DDEngine/Headers/wibble.h @@ -0,0 +1,28 @@ +// +// Wibbles the given bit of screen. +// + +#ifndef _WIBBLE_ +#define _WIBBLE_ + + + +// +// ALL THESE FUNCTIONS MUST ONLY BE CALLED WHEN THE SCREEN IS LOCKED. +// +// Make sure the bounding boxes are all well on screen! +// + +void WIBBLE_simple( + SLONG x1, SLONG y1, + SLONG x2, SLONG y2, + UBYTE wibble_y1, + UBYTE wibble_y2, + UBYTE wibble_g1, + UBYTE wibble_g2, + UBYTE wibble_s1, + UBYTE wibble_s2); + + + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Source/Attract.cpp b/fallen/DDEngine/Source/Attract.cpp new file mode 100644 index 0000000..2c6cacc --- /dev/null +++ b/fallen/DDEngine/Source/Attract.cpp @@ -0,0 +1,40 @@ +// Attract.cpp +// Guy Simmons, 20th November 1997. + +#include "Engine.h" +#include "font.h" + +//--------------------------------------------------------------- + +void engine_attract(void) +{ + static count=0; + count++; + if (the_display.screen_lock()) + { + CBYTE str[100]; + sprintf(str,"%d",count); + FONT_draw_coloured_text(220,5,128,128,128,str); + the_display.screen_unlock(); + } + + FLIP(NULL,DDFLIP_WAIT); + return; +} + +//--------------------------------------------------------------- + +extern Camera test_view; +void game_engine(Camera *the_view); + +void engine_win_level(void) +{ +} + +//--------------------------------------------------------------- + +void engine_lose_level(void) +{ +} + +//--------------------------------------------------------------- diff --git a/fallen/DDEngine/Source/BreakTimer.cpp b/fallen/DDEngine/Source/BreakTimer.cpp new file mode 100644 index 0000000..75a5abf --- /dev/null +++ b/fallen/DDEngine/Source/BreakTimer.cpp @@ -0,0 +1,223 @@ +// BreakTimer.cpp +// +// break timer for timing portions of code + +#include +#if !defined(TARGET_DC) +#include +#endif +#include "BreakTimer.h" + +// Windows timer access functions + +static inline ULONG GetFineTimerFreq() +{ + LARGE_INTEGER freq; + + QueryPerformanceFrequency(&freq); + + return ULONG(freq.u.LowPart); +} + +static inline ULONG GetFineTimerValue() +{ + LARGE_INTEGER time; + + QueryPerformanceCounter(&time); + + return ULONG(time.u.LowPart); +} + +// basic timing + +static ULONG stopwatch_start; + +void StartStopwatch() +{ + stopwatch_start = GetFineTimerValue(); +} + +float StopStopwatch() +{ + ULONG time = GetFineTimerValue() - stopwatch_start; + + float secs = float(time) / float(GetFineTimerFreq()); + + return secs; +} + +#ifdef BREAKTIMER + +const size_t MAX_BREAK = 64; + +static size_t next_break; +static size_t max_break; +static ULONG time_base; +static bool enabled = false; + +static ULONG total_dfacets; + +struct BreakPoint +{ + const char* name; // name of breakpoint + ULONG time; // last measured breaktime + float min_sec; // minimum seconds since last breakpoint + float max_sec; // maximum seconds since last breakpoint + float tot_sec; // total seconds measured between this and last breakpoint + float tot_secsq; // total seconds measured between this and last breakpoint, squared + ULONG tot_cnt; // total number of measurements +} breakpoint[MAX_BREAK + 1]; + +// BreakStart +// +// start break timing + +void BreakStart() +{ + time_base = GetFineTimerFreq(); + for (size_t ii = 0; ii <= MAX_BREAK; ii++) + { + breakpoint[ii].name = NULL; + breakpoint[ii].time = 0; + breakpoint[ii].min_sec = 1000000; + breakpoint[ii].max_sec = 0; + breakpoint[ii].tot_sec = 0; + breakpoint[ii].tot_cnt = 0; + } + breakpoint[0].name = "Frame Start"; + breakpoint[0].time = GetFineTimerValue(); + enabled = true; + next_break = 1; + max_break = 0; + total_dfacets = 0; +} + +void BreakTime(const char* name) +{ + if (enabled) + { + ASSERT(next_break < MAX_BREAK); + breakpoint[next_break].name = name; + breakpoint[next_break++].time = GetFineTimerValue(); + } +} + +void BreakFacets(ULONG dfacets) +{ + total_dfacets += dfacets; +} + +void BreakFrame() +{ + if (enabled) + { + breakpoint[next_break].name = "Frame End"; + breakpoint[next_break].time = GetFineTimerValue(); + + if (!max_break) max_break = next_break; + else ASSERT(max_break == next_break); + + // get break times + for (size_t ii = 1; ii <= next_break; ii++) + { + ULONG dtime = breakpoint[ii].time - breakpoint[ii-1].time; + float dsec = float(dtime) / float(time_base); + + if (dsec < breakpoint[ii].min_sec) breakpoint[ii].min_sec = dsec; + if (dsec > breakpoint[ii].max_sec) breakpoint[ii].max_sec = dsec; + breakpoint[ii].tot_sec += dsec; + breakpoint[ii].tot_secsq += dsec * dsec; + breakpoint[ii].tot_cnt++; + } + + // get frame time + ULONG dtime = breakpoint[next_break].time - breakpoint[0].time; + float dsec = float(dtime) / float(time_base); + + if (dsec < breakpoint[0].min_sec) breakpoint[0].min_sec = dsec; + if (dsec > breakpoint[0].max_sec) breakpoint[0].max_sec = dsec; + breakpoint[0].tot_sec += dsec; + breakpoint[0].tot_secsq += dsec * dsec; + breakpoint[0].tot_cnt++; + + // restart + breakpoint[0].time = GetFineTimerValue(); + next_break = 1; + } +} + +void BreakEnd(const char* filename) +{ + if (!enabled) return; + + FILE* fd = MF_Fopen(filename, "w"); + + if (fd) + { + float fps = float(breakpoint[0].tot_cnt) / breakpoint[0].tot_sec; + float facets = float(total_dfacets) / float(breakpoint[0].tot_cnt); + + fprintf(fd, "%d frames in %d seconds = %d fps\n\n", breakpoint[0].tot_cnt, int(floor(breakpoint[0].tot_sec + 0.5)), int(floor(fps + 0.5))); + fprintf(fd, "Average %d facets\n\n", int(floor(facets + 0.5))); + + float eX = breakpoint[0].tot_sec / breakpoint[0].tot_cnt; + float eXsq = breakpoint[0].tot_secsq / breakpoint[0].tot_cnt; + float variance = eXsq - eX*eX; // var = E[X^2] - E[X]^2 + float stddev = float(sqrt(variance)); + + ULONG min = ULONG(floor(breakpoint[0].min_sec * 1000000 + 0.5)); + ULONG max = ULONG(floor(breakpoint[0].max_sec * 1000000 + 0.5)); + ULONG av = ULONG(floor(eX * 1000000 + 0.5)); + ULONG sd = ULONG(floor(stddev * 1000000 + 0.5)); + + if (0) + { + fprintf(fd, "Whole frame:\n"); + fprintf(fd, " Range: %d - %d us\n Avg: %d us, Dev: %d us\n\n", min, max, av, sd); + } + + for (size_t ii = 1; ii <= max_break; ii++) + { + float eX = breakpoint[ii].tot_sec / breakpoint[ii].tot_cnt; + float eXsq = breakpoint[ii].tot_secsq / breakpoint[ii].tot_cnt; + float variance = eXsq - eX*eX; // var = E[X^2] - E[X]^2 + float stddev = float(sqrt(variance)); + + ULONG min = ULONG(floor(breakpoint[ii].min_sec * 1000000 + 0.5)); + ULONG max = ULONG(floor(breakpoint[ii].max_sec * 1000000 + 0.5)); + ULONG av = ULONG(floor(eX * 1000000 + 0.5)); + ULONG sd = ULONG(floor(stddev * 1000000 + 0.5)); +// ULONG apc = ULONG(floor(breakpoint[ii].tot_sec * 100 / breakpoint[0].tot_sec + 0.5)); + ULONG apc = ULONG(floor(eX * 1000000 / 333 + 0.5)); + + if (0) + { + fprintf(fd, "\"%s\" to \"%s\":\n", breakpoint[ii-1].name, breakpoint[ii].name); + fprintf(fd, " Range: %d - %d us\n Avg: %d us (%d%%), Dev: %d us\n\n", min, max, av, apc, sd); + } + else + { + fprintf(fd, "%s", breakpoint[ii].name); + for (size_t jj = strlen(breakpoint[ii].name); jj < 32; jj++) + { + fprintf(fd, " "); + } + fprintf(fd, "%d tms ", apc); + if (apc < 10) fprintf(fd, " "); + for (jj = 0; jj < apc; jj++) + { + fprintf(fd, "X"); + } + fprintf(fd, "\n"); + } + } + + + MF_Fclose(fd); + } + + enabled = false; +} + +#endif // BREAKTIMER + diff --git a/fallen/DDEngine/Source/Bucket.cpp b/fallen/DDEngine/Source/Bucket.cpp new file mode 100644 index 0000000..41304b0 --- /dev/null +++ b/fallen/DDEngine/Source/Bucket.cpp @@ -0,0 +1,20 @@ +// Bucket.cpp +// Guy Simmons, 24th October 1997. + +#include "Engine.h" + + +UBYTE e_bucket_pool[BUCKET_POOL_SIZE], + *e_buckets, + *e_end_buckets; +BucketHead *bucket_lists[MAX_LISTS][MAX_BUCKETS+1]; + +//--------------------------------------------------------------- + +void init_buckets(void) +{ + memset(bucket_lists,0,sizeof(bucket_lists)); + reset_buckets(); +} + +//--------------------------------------------------------------- diff --git a/fallen/DDEngine/Source/Crinkle.cpp b/fallen/DDEngine/Source/Crinkle.cpp new file mode 100644 index 0000000..aabae0a --- /dev/null +++ b/fallen/DDEngine/Source/Crinkle.cpp @@ -0,0 +1,984 @@ +// +// Crinkles! +// + +#include "game.h" +#include "poly.h" +#include "crinkle.h" + +#include + +#ifdef TARGET_DC +// intrinsic maths +#include +#endif + + +// +// Temporary storage for transformed crinkle points. +// + +#ifdef TARGET_DC +// Only temporary - got no memory for them. +#define DISABLE_CRINKLES 1 +#else +#define DISABLE_CRINKLES 0 +#endif + + +#if DISABLE_CRINKLES +#define CRINKLE_MAX_POINTS_PER_CRINKLE 1 +#else +#define CRINKLE_MAX_POINTS_PER_CRINKLE 700 +#endif + +POLY_Point CRINKLE_pp[CRINKLE_MAX_POINTS_PER_CRINKLE]; + + + + +// Bogus rout - just needs to be out of the way somewhere. +// Just stops the compiler optimising out entire loops! +void DontDoAnythingWithThis ( DWORD blibble ) +{ + // Don't do anything. +} + + + +// +// The points. +// + +typedef struct +{ + float vec1; // From point 0 to point 1 + float vec2; // From point 0 to point 2 + float vec3; // 0-1 cross 0-2 + UBYTE c[4]; // How much of each points corner's colour this point takes. + +} CRINKLE_Point; + +#if DISABLE_CRINKLES +#define CRINKLE_MAX_POINTS 1 +#else +#define CRINKLE_MAX_POINTS 8192 +#endif + +CRINKLE_Point CRINKLE_point[CRINKLE_MAX_POINTS]; +SLONG CRINKLE_point_upto; + +// +// The faces. +// + +typedef struct +{ + UWORD point[3]; // Index in the CRINKLE_point array + +} CRINKLE_Face; + +#ifdef TARGET_DC +#define CRINKLE_MAX_FACES 1 +#else +#define CRINKLE_MAX_FACES 8192 +#endif + +CRINKLE_Face CRINKLE_face[CRINKLE_MAX_FACES]; +SLONG CRINKLE_face_upto; + +// +// The crinkles. +// + +typedef struct +{ + SLONG num_points; + SLONG num_faces; + + CRINKLE_Point *point; + CRINKLE_Face *face; + +} CRINKLE_Crinkle; + +#ifdef TARGET_DC +#define CRINKLE_MAX_CRINKLES 1 +#else +#define CRINKLE_MAX_CRINKLES 256 +#endif + +CRINKLE_Crinkle CRINKLE_crinkle[CRINKLE_MAX_CRINKLES]; +SLONG CRINKLE_crinkle_upto; + + + +void CRINKLE_init(void) +{ + CRINKLE_crinkle_upto = 1; + CRINKLE_point_upto = 0; + CRINKLE_face_upto = 0; +} + + + +// +// The longest a line will be in an asc... +// + +#define CRINKLE_MAX_LINE 256 + +CRINKLE_Handle CRINKLE_load(CBYTE *asc_filename) +{ + SLONG i; + + SLONG o; + SLONG f; + + float x; + float y; + float z; + + float dx; + float dy; + float dz; + + float size; + float oversize; + + SLONG a; + SLONG b; + SLONG c; + + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG match; + SLONG index; + + CBYTE line[CRINKLE_MAX_LINE]; + + CRINKLE_Handle ans; + CRINKLE_Crinkle *cc; + + FILE *handle; + + // + // Open the file. + // + + return NULL; + + +#if DISABLE_CRINKLES + return NULL; +#endif + + handle = MF_Fopen(asc_filename, "rb"); + + if (!handle) + { + TRACE("Could not open crinkle file \"%s\"\n", asc_filename); + + return NULL; + } + else + { + TRACE("crinkle = %s\n", asc_filename); + } + + ASSERT(WITHIN(CRINKLE_crinkle_upto, 1, CRINKLE_MAX_CRINKLES - 1)); + + // + // The new crinkle. + // + + ans = CRINKLE_crinkle_upto; + cc = &CRINKLE_crinkle[CRINKLE_crinkle_upto++]; + + cc->num_points = 0; + cc->num_faces = 0; + cc->point = &CRINKLE_point[CRINKLE_point_upto]; + cc->face = &CRINKLE_face [CRINKLE_face_upto]; + + index = 0; + + // + // Load the asc. Put the points into the buffer and the faces + // into the CRINKLE_face array. + // + + while(fgets(line, CRINKLE_MAX_LINE, handle)) + { + match = sscanf(line, "Vertex: (%f, %f, %f)", &x, &y, &z); + + if (match == 3) + { + ASSERT(WITHIN(CRINKLE_point_upto, 0, CRINKLE_MAX_POINTS - 1)); + + // + // Found a point. Add it to the buffer. + // + + SWAP_FL(y, z); + x = -x; + + CRINKLE_point[CRINKLE_point_upto].vec1 = x; + CRINKLE_point[CRINKLE_point_upto].vec2 = y; + CRINKLE_point[CRINKLE_point_upto].vec3 = z; + + CRINKLE_point_upto += 1; + cc->num_points += 1; + + continue; + } + + match = sscanf(line, "Face: Material %d xyz (%d, %d, %d)", &f, &a, &b, &c); + + if (match == 4) + { + ASSERT(WITHIN(CRINKLE_face_upto, 0, CRINKLE_MAX_FACES - 1)); + + cc->face[cc->num_faces].point[0] = a; + cc->face[cc->num_faces].point[1] = b; + cc->face[cc->num_faces].point[2] = c; + + cc->num_faces += 1; + CRINKLE_face_upto += 1; + + continue; + } + } + + // + // Finished with the file. + // + + MF_Fclose(handle); + + // + // What is the bounding rectangle? + // + + float minx = +float(INFINITY); + float miny = +float(INFINITY); + float minz = +float(INFINITY); + + float maxx = -float(INFINITY); + float maxy = -float(INFINITY); + float maxz = -float(INFINITY); + + for (i = 0; i < cc->num_points; i++) + { + if (cc->point[i].vec1 < minx) {minx = cc->point[i].vec1;} + if (cc->point[i].vec2 < miny) {miny = cc->point[i].vec2;} + if (cc->point[i].vec3 < minz) {minz = cc->point[i].vec3;} + + if (cc->point[i].vec1 > maxx) {maxx = cc->point[i].vec1;} + if (cc->point[i].vec2 > maxy) {maxy = cc->point[i].vec2;} + if (cc->point[i].vec3 > maxz) {maxz = cc->point[i].vec3;} + } + + float sizex = maxx - minx; + float sizey = maxy - miny; + float sizez = maxz - minz; + + if (sizey < sizex && sizey < sizez) + { + // + // This is a ground crinkle. + // + + for (i = 0; i < cc->num_points; i++) + { + x = cc->point[i].vec1; + y = cc->point[i].vec2; + z = cc->point[i].vec3; + + x -= minx; + z -= minz; + + x *= 1.0F / 100.0F; + y *= 1.0F / 100.0F; + z *= 1.0F / 100.0F; + + SATURATE(x, 0.0F, 1.0F); + SATURATE(z, 0.0F, 1.0F); + + cc->point[i].vec1 = x; + cc->point[i].vec2 = z; + cc->point[i].vec3 = y; // y is the extrusion coordinate... + } + } + else + { + // + // This is a wall crinkle. + // + + for (i = 0; i < cc->num_points; i++) + { + x = cc->point[i].vec1; + y = cc->point[i].vec2; + z = cc->point[i].vec3; + + x -= minx; + y -= miny; + + x *= 1.0F / 100.0F; + y *= 1.0F / 100.0F; + z *= 1.0F / 100.0F; + + SATURATE(x, 0.0F, 1.0F); + SATURATE(y, 0.0F, 1.0F); + + cc->point[i].vec1 = 1.0F - x; // They are flipped in x and y apparently! + cc->point[i].vec2 = 1.0F - y; + cc->point[i].vec3 = z; // z is the extrusion coordinate... + } + } + + // + // Set the colour interpolations. + // + + float v[4]; + + for (i = 0; i < cc->num_points; i++) + { + v[0] = (1.0F - cc->point[i].vec1) * (1.0F - cc->point[i].vec2); + v[1] = ( cc->point[i].vec1) * (1.0F - cc->point[i].vec2); + v[2] = (1.0F - cc->point[i].vec1) * ( cc->point[i].vec2); + v[3] = ( cc->point[i].vec1) * ( cc->point[i].vec2); + + ASSERT(WITHIN(v[0] + v[1] + v[2] + v[3], 0.9F, 1.1F)); + + cc->point[i].c[0] = v[0] * 128.0F; + cc->point[i].c[1] = v[1] * 128.0F; + cc->point[i].c[2] = v[2] * 128.0F; + cc->point[i].c[3] = v[3] * 128.0F; + } + + return ans; +} + +CRINKLE_Handle CRINKLE_read_bin(FileClump* tclump, int id) +{ + int ii; + + // read data + + UBYTE* buffer = tclump->Read(id); + if (!buffer) return NULL; + + UBYTE* bptr = buffer; + + ASSERT(WITHIN(CRINKLE_crinkle_upto, 1, CRINKLE_MAX_CRINKLES - 1)); + + // + // The new crinkle. + // + + CRINKLE_Handle ans = CRINKLE_crinkle_upto; + CRINKLE_Crinkle* cc = &CRINKLE_crinkle[CRINKLE_crinkle_upto]; + CRINKLE_crinkle_upto++; + + // do the header + memcpy(cc, bptr, sizeof(*cc)); + bptr += sizeof(*cc); + + CRINKLE_Point* cp = &CRINKLE_point[CRINKLE_point_upto]; + CRINKLE_Face* cf = &CRINKLE_face [CRINKLE_face_upto]; + + cc->point = cp; + cc->face = cf; + + CRINKLE_point_upto += cc->num_points; + CRINKLE_face_upto += cc->num_faces; + + for (ii = 0; ii < cc->num_points; ii++) + { + memcpy(cp, bptr, sizeof(*cp)); + cp++; + bptr += sizeof(*cp); + } + + for (ii = 0; ii < cc->num_faces; ii++) + { + memcpy(cf, bptr, sizeof(*cf)); + cf++; + bptr += sizeof(*cf); + } + + return ans; +} + + +#ifndef TARGET_DC +void CRINKLE_write_bin(FileClump* tclump, CRINKLE_Handle hnd, int id) +{ + CRINKLE_Crinkle* cc = &CRINKLE_crinkle[hnd]; + + int size = sizeof(CRINKLE_Crinkle) + cc->num_points * sizeof(CRINKLE_Point) + cc->num_faces * sizeof(CRINKLE_Face); + + UBYTE* buffer = new UBYTE[size]; + ASSERT(buffer); + UBYTE* bptr = buffer; + + memcpy(bptr, cc, sizeof(*cc)); + bptr += sizeof(*cc); + + CRINKLE_Point* cp = cc->point; + CRINKLE_Face* cf = cc->face; + + for (int ii = 0; ii < cc->num_points; ii++) + { + memcpy(bptr, cp, sizeof(*cp)); + cp++; + bptr += sizeof(*cp); + } + + for (ii = 0; ii < cc->num_faces; ii++) + { + memcpy(bptr, cf, sizeof(*cf)); + cf++; + bptr += sizeof(*cf); + } + + ASSERT(bptr - buffer == size); + + tclump->Write(buffer, size, id); +} +#endif //#ifndef TARGET_DC + + +float CRINKLE_light_x; +float CRINKLE_light_y; +float CRINKLE_light_z; + +float CRINKLE_mul_x; +float CRINKLE_mul_y; +float CRINKLE_mul_recip_x; +float CRINKLE_mul_recip_y; + +void CRINKLE_skew(float aspect, float lens) +{ + CRINKLE_mul_x = aspect * lens; + CRINKLE_mul_y = lens; + CRINKLE_mul_recip_x = 1.0F / CRINKLE_mul_x; + CRINKLE_mul_recip_y = 1.0F / CRINKLE_mul_y; +} + +void CRINKLE_light(float dx, float dy, float dz) +{ +#ifdef TARGET_DC + // USe the intrinsic one. + float len = dx*dx + dy*dy + dz*dz; + float overlen = _InvSqrtA(len); +#else + float len = sqrt(dx*dx + dy*dy + dz*dz); + float overlen = 1.0F / len; +#endif + + dx *= overlen; + dy *= overlen; + dz *= overlen; + + CRINKLE_light_x = dx; + CRINKLE_light_y = dy; + CRINKLE_light_z = dz; +} + + +void CRINKLE_do( + CRINKLE_Handle crinkle, + SLONG page, + float extrude, + POLY_Point *pp[4], + SLONG flip) +{ + SLONG i; + + CRINKLE_Crinkle *cc; + + ASSERT(WITHIN(crinkle, 0, CRINKLE_crinkle_upto - 1)); + + cc = &CRINKLE_crinkle[crinkle]; +#ifndef FINAL +#ifndef TARGET_DC + if (Keys[KB_RSHIFT]) + { + flip = TRUE; + } +#endif +#endif + if (flip) + { + #define PPSWAP(a,b) {POLY_Point *pp_spare = (a); (a) = (b); (b) = pp_spare;} + + PPSWAP(pp[0],pp[1]); + PPSWAP(pp[2],pp[3]); + } + + // + // Un-warp viewspace... + // + + pp[0]->x *= CRINKLE_mul_recip_x; + pp[1]->x *= CRINKLE_mul_recip_x; + pp[2]->x *= CRINKLE_mul_recip_x; + pp[3]->x *= CRINKLE_mul_recip_x; + + pp[0]->y *= CRINKLE_mul_recip_y; + pp[1]->y *= CRINKLE_mul_recip_y; + pp[2]->y *= CRINKLE_mul_recip_y; + pp[3]->y *= CRINKLE_mul_recip_y; + + // + // The base vectors of the crinkle. + // + + float ox = pp[0]->x; + float oy = pp[0]->y; + float oz = pp[0]->z; + float ou = pp[0]->u; + float ov = pp[0]->v; + + float ax = pp[1]->x - ox; + float ay = pp[1]->y - oy; + float az = pp[1]->z - oz; + float au = pp[1]->u - ou; + float av = pp[1]->v - ov; + + float bx = pp[2]->x - ox; + float by = pp[2]->y - oy; + float bz = pp[2]->z - oz; + float bu = pp[2]->u - ou; + float bv = pp[2]->v - ov; + + float cx = (ay*bz - az*by) * (1.0F / 256.0F); + float cy = (az*bx - ax*bz) * (1.0F / 256.0F); + float cz = (ax*by - ay*bx) * (1.0F / 256.0F); + +#ifdef TARGET_DC + float len = (cx*cx + cy*cy + cz*cz); + float overlen = 0.05F * _InvSqrtA ( len ); +#else + float len = sqrt(cx*cx + cy*cy + cz*cz); + float overlen = 0.05F / len; +#endif + + if (flip) + { + overlen = -overlen; + } + + SLONG pr[4]; + SLONG pg[4]; + SLONG pb[4]; + SLONG pa[4]; + + for (i = 0; i < 4; i++) + { + pa[i] = (pp[i]->colour >> 24) & 0xff; + pr[i] = (pp[i]->colour >> 16) & 0xff; + pg[i] = (pp[i]->colour >> 8) & 0xff; + pb[i] = (pp[i]->colour >> 0) & 0xff; + } + + cx *= overlen; + cy *= overlen; + cz *= overlen; + + // + // Warp viewspace again... + // + + pp[0]->x *= CRINKLE_mul_x; + pp[1]->x *= CRINKLE_mul_x; + pp[2]->x *= CRINKLE_mul_x; + pp[3]->x *= CRINKLE_mul_x; + + pp[0]->y *= CRINKLE_mul_y; + pp[1]->y *= CRINKLE_mul_y; + pp[2]->y *= CRINKLE_mul_y; + pp[3]->y *= CRINKLE_mul_y; + + // + // Transform the points. + // + + float x; + float y; + float z; + + float u; + float v; + + SLONG r; + SLONG g; + SLONG b; + SLONG a; + + CRINKLE_Point *cp; + POLY_Point *pt; + + ASSERT(WITHIN(cc->num_points, 4, CRINKLE_MAX_POINTS_PER_CRINKLE)); + + for (i = 0; i < cc->num_points; i++) + { + cp = &cc->point[i]; + pt = &CRINKLE_pp[i]; + + pt->x = ox + cp->vec1 * ax + cp->vec2 * bx + cp->vec3 * cx * extrude; + pt->y = oy + cp->vec1 * ay + cp->vec2 * by + cp->vec3 * cy * extrude; + pt->z = oz + cp->vec1 * az + cp->vec2 * bz + cp->vec3 * cz * extrude; + pt->u = ou + cp->vec1 * au + cp->vec2 * bu; + pt->v = ov + cp->vec1 * av + cp->vec2 * bv; + + r = pr[0] * cp->c[0] + pr[1] * cp->c[1] + pr[2] * cp->c[2] + pr[3] * cp->c[3] >> 7; + g = pg[0] * cp->c[0] + pg[1] * cp->c[1] + pg[2] * cp->c[2] + pg[3] * cp->c[3] >> 7; + b = pb[0] * cp->c[0] + pb[1] * cp->c[1] + pb[2] * cp->c[2] + pb[3] * cp->c[3] >> 7; + a = pa[0] * cp->c[0] + pa[1] * cp->c[1] + pa[2] * cp->c[2] + pa[3] * cp->c[3] >> 7; + + ASSERT(WITHIN(r, 0, 255)); + ASSERT(WITHIN(g, 0, 255)); + ASSERT(WITHIN(b, 0, 255)); + ASSERT(WITHIN(a, 0, 255)); + +#ifdef TARGET_DC + pt->specular = 0x00000000; + pt->colour = 0xff000000 | (r << 16) | (g << 8) | (b << 0); +#else + pt->colour = (a << 24) | (r << 16) | (g << 8) | (b << 0); + pt->specular = 0xff000000; +#endif + + + // Warp viewspace... + + pt->x *= CRINKLE_mul_x; + pt->y *= CRINKLE_mul_y; + + POLY_transform_from_view_space(pt); + } + + // + // The faces. + // + + POLY_Point *tri[3]; + CRINKLE_Face *cf; + + for (i = 0; i < cc->num_faces; i++) + { + cf = &cc->face[i]; + + if (flip) + { + tri[0] = &CRINKLE_pp[cf->point[0]]; + tri[1] = &CRINKLE_pp[cf->point[2]]; + tri[2] = &CRINKLE_pp[cf->point[1]]; + } + else + { + tri[0] = &CRINKLE_pp[cf->point[0]]; + tri[1] = &CRINKLE_pp[cf->point[1]]; + tri[2] = &CRINKLE_pp[cf->point[2]]; + } + + if (POLY_valid_triangle(tri)) + { + // + // A face that isn't extruded doesn't have it lighting changed... + // + + if (fabsf(cc->point[cf->point[0]].vec3) + fabsf(cc->point[cf->point[1]].vec3) + fabsf(cc->point[cf->point[2]].vec3) > 0.001F) + { + // + // Find the normal :( + // + + float ax = tri[1]->x - tri[0]->x; + float ay = tri[1]->y - tri[0]->y; + float az = tri[1]->z - tri[0]->z; + + float bx = tri[2]->x - tri[0]->x; + float by = tri[2]->y - tri[0]->y; + float bz = tri[2]->z - tri[0]->z; + + float nx = ay*bz - az*by; + float ny = az*bx - ax*bz; + float nz = ax*by - ay*bx; + +#ifdef TARGET_DC + float len = (nx*nx + ny*ny + nz*nz); + float overlen = _InvSqrtA ( len ); +#else + float len = sqrt(nx*nx + ny*ny + nz*nz); + float overlen = 1.0F / len; +#endif + + nx *= overlen; + ny *= overlen; + nz *= overlen; + + // + // Work out how we vary the lighting of the crinkle because of + // the light vector. + // + + float dprod = nx*CRINKLE_light_x + ny*CRINKLE_light_y + nz*CRINKLE_light_z; + float dbright = dprod * extrude; + SLONG drgb = dbright * 64.0F; + + // + // Backup the old lighting. + // + + ULONG c0 = tri[0]->colour; + ULONG c1 = tri[1]->colour; + ULONG c2 = tri[2]->colour; + + SLONG r; + SLONG g; + SLONG b; + SLONG a; + + // + // Each colour in turn... + // + + r = ((c0 >> 16) & 0xff) + drgb; + g = ((c0 >> 8) & 0xff) + drgb; + b = ((c0 >> 0) & 0xff) + drgb; + a = ((c0 >> 24) & 0xff) + drgb; + + SATURATE(r, 0, 255); + SATURATE(g, 0, 255); + SATURATE(b, 0, 255); + SATURATE(a, 0, 255); + +#ifdef TARGET_DC + tri[0]->colour = (0xff << 24) | (r << 16) | (g << 8) | (b << 0); +#else + tri[0]->colour = (a << 24) | (r << 16) | (g << 8) | (b << 0); +#endif + + r = ((c1 >> 16) & 0xff) + drgb; + g = ((c1 >> 8) & 0xff) + drgb; + b = ((c1 >> 0) & 0xff) + drgb; + a = ((c1 >> 24) & 0xff) + drgb; + + SATURATE(r, 0, 255); + SATURATE(g, 0, 255); + SATURATE(b, 0, 255); + SATURATE(a, 0, 255); + +#ifdef TARGET_DC + tri[1]->colour = (0xff << 24) | (r << 16) | (g << 8) | (b << 0); +#else + tri[1]->colour = (a << 24) | (r << 16) | (g << 8) | (b << 0); +#endif + + r = ((c2 >> 16) & 0xff) + drgb; + g = ((c2 >> 8) & 0xff) + drgb; + b = ((c2 >> 0) & 0xff) + drgb; + a = ((c2 >> 24) & 0xff) + drgb; + + SATURATE(r, 0, 255); + SATURATE(g, 0, 255); + SATURATE(b, 0, 255); + SATURATE(a, 0, 255); + +#ifdef TARGET_DC + tri[2]->colour = (0xff << 24) | (r << 16) | (g << 8) | (b << 0); +#else + tri[2]->colour = (a << 24) | (r << 16) | (g << 8) | (b << 0); +#endif + + // + // Draw the triangle. + // + + POLY_add_triangle(tri, page, TRUE); + + // + // Restore the old colours. + // + + tri[0]->colour = c0; + tri[1]->colour = c1; + tri[2]->colour = c2; + } + else + { + POLY_add_triangle(tri, page, TRUE); + } + } + } +} + + +void CRINKLE_project( + CRINKLE_Handle crinkle, + float extrude, + SVector_F pp[4], + SLONG flip) +{ + SLONG i; + + CRINKLE_Crinkle *cc; + + ASSERT(WITHIN(crinkle, 0, CRINKLE_crinkle_upto - 1)); + + cc = &CRINKLE_crinkle[crinkle]; + +#ifndef TARGET_DC + if (Keys[KB_RSHIFT]) + { + flip = TRUE; + } +#endif + + if (flip) + { + #define SVSWAP(a,b) {SVector_F sv_spare = (a); (a) = (b); (b) = sv_spare;} + + SVSWAP(pp[0],pp[1]); + SVSWAP(pp[2],pp[3]); + } + + // + // The base vectors of the crinkle. + // + + float ox = pp[0].X; + float oy = pp[0].Y; + float oz = pp[0].Z; + + float ax = pp[1].X - ox; + float ay = pp[1].Y - oy; + float az = pp[1].Z - oz; + + float bx = pp[2].X - ox; + float by = pp[2].Y - oy; + float bz = pp[2].Z - oz; + + float cx = (ay*bz - az*by) * (1.0F / 256.0F); + float cy = (az*bx - ax*bz) * (1.0F / 256.0F); + float cz = (ax*by - ay*bx) * (1.0F / 256.0F); + +#ifdef TARGET_DC + float len = (cx*cx + cy*cy + cz*cz); + float overlen = 0.05F * _InvSqrtA ( len ); +#else + float len = sqrt(cx*cx + cy*cy + cz*cz); + float overlen = 0.05F / len; +#endif + + if (flip) + { + overlen = -overlen; + } + + cx *= overlen; + cy *= overlen; + cz *= overlen; + + // + // Find the points. + // + + float x; + float y; + float z; + + float u; + float v; + + SLONG r; + SLONG g; + SLONG b; + SLONG a; + + CRINKLE_Point *cp; + POLY_Point *pt; + + ASSERT(WITHIN(cc->num_points, 4, CRINKLE_MAX_POINTS_PER_CRINKLE)); + + for (i = 0; i < cc->num_points; i++) + { + cp = &cc->point[i]; + pt = &CRINKLE_pp[i]; + + pt->x = ox + cp->vec1 * ax + cp->vec2 * bx + cp->vec3 * cx * extrude; + pt->y = oy + cp->vec1 * ay + cp->vec2 * by + cp->vec3 * cy * extrude; + pt->z = oz + cp->vec1 * az + cp->vec2 * bz + cp->vec3 * cz * extrude; + } + + // + // The faces. + // + + POLY_Point *tri[3]; + CRINKLE_Face *cf; + + for (i = 0; i < cc->num_faces; i++) + { + cf = &cc->face[i]; + + if (flip) + { + tri[0] = &CRINKLE_pp[cf->point[0]]; + tri[1] = &CRINKLE_pp[cf->point[2]]; + tri[2] = &CRINKLE_pp[cf->point[1]]; + } + else + { + tri[0] = &CRINKLE_pp[cf->point[0]]; + tri[1] = &CRINKLE_pp[cf->point[1]]; + tri[2] = &CRINKLE_pp[cf->point[2]]; + } + + AENG_world_line( + tri[0]->x, + tri[0]->y, + tri[0]->z, + 4, + 0xffffff, + tri[1]->x, + tri[1]->y, + tri[1]->z, + 3, + 0xffffff, + TRUE); + + AENG_world_line( + tri[1]->x, + tri[1]->y, + tri[1]->z, + 4, + 0xffffff, + tri[2]->x, + tri[2]->y, + tri[2]->z, + 3, + 0xffffff, + TRUE); + + AENG_world_line( + tri[2]->x, + tri[2]->y, + tri[2]->z, + 4, + 0xffffff, + tri[0]->x, + tri[0]->y, + tri[0]->z, + 3, + 0xffffff, + TRUE); + } +} + diff --git a/fallen/DDEngine/Source/DCback.cpp b/fallen/DDEngine/Source/DCback.cpp new file mode 100644 index 0000000..f354ee0 --- /dev/null +++ b/fallen/DDEngine/Source/DCback.cpp @@ -0,0 +1,257 @@ +#if 0 + +// +// The background... +// + +#include +#include "back.h" + + + + + +D3DTexture BACK_ot_roper; +D3DTexture BACK_ot_darci; +D3DTexture BACK_ot_mib; +D3DTexture BACK_ot_line; +D3DTexture BACK_ot_logo; + +SLONG BACK_starttime; + +void BACK_init() +{ + BACK_ot_roper.LoadTextureTGA("RoperEdgeNail.tga", -1); + BACK_ot_darci.LoadTextureTGA("GunshotNail.tga", -1); + BACK_ot_mib .LoadTextureTGA("ThreeAmigos4.tga", -1); + BACK_ot_line .LoadTextureTGA("Bumpyline.tga", -1); + BACK_ot_logo .LoadTextureTGA("uclogo.tga", -1); + + BACK_starttime = GetTickCount(); +} + + + + +void BACK_draw() +{ + ULONG colour; + + OS_Buffer *ob; + + float between = 0.0F; + + D3DTexture *ot1; + D3DTexture *ot2; + + SLONG now = GetTickCount() - BACK_starttime; + + if (now < 2048) + { + // + // Draw nothing for a while... + // + + colour = 0; + } + else + if (now < 4096) + { + // + // Then fade in over the next two seconds... + // + + colour = now - 2048 >> 4; + colour |= colour << 8; + colour |= colour << 8; + } + else + { + now -= 4000; + colour = 0x808080; + } + + switch((now >> 14) % 3) + { + case 0: + ot1 = &BACK_ot_roper; + ot2 = &BACK_ot_darci; + break; + + case 1: + ot1 = &BACK_ot_darci; + ot2 = &BACK_ot_mib; + break; + + case 2: + ot1 = &BACK_ot_mib; + ot2 = &BACK_ot_roper; + break; + + default: + ASSERT(0); + break; + } + + now &= 0x3fff; + + if (now < 6000) + { + between = 0.0F; + } + else + if (now < 10000) + { + between = (now - 6000) * (1.0F / 4000.0F); + } + else + { + between = 1.0F; + } + + if (between < 1.0F) + { + ob = OS_buffer_new(); + + OS_buffer_add_sprite( + ob, + 0.0F, 0.0F, 1.0F - between, 1.0F, + 0.0F, 1.0F, 1.0F - between, 0.0F, + 0.9999F, + colour, + 0x00000000, + OS_FADE_RIGHT); + + OS_buffer_draw(ob, ot1, NULL, OS_DRAW_ZALWAYS); + } + + if (between > 0.0F) + { + ob = OS_buffer_new(); + + OS_buffer_add_sprite( + ob, + 1.0F - between, 0.0F, 1.0F, 1.0F, + 1.0F - between, 1.0F, 1.0F, 0.0F, + 0.9999F, + colour, + 0x00000000, + OS_FADE_RIGHT); + + OS_buffer_draw(ob, ot2, NULL, OS_DRAW_ZALWAYS); + } + + if (between > 0.0F && between < 1.0F) + { + ob = OS_buffer_new(); + + OS_buffer_add_line_2d( + ob, + 1.0F - between, 0.0F, + 1.0F - between, 1.0F, + 0.04F * frand(), + 0.0F, 0.0F - frand(), + 1.0F, 2.0F + frand(), + 0.0F, + ftol((1.0F - between) * 255) | 0x5522ff); + + OS_buffer_draw(ob, BACK_ot_line, NULL, OS_DRAW_ADD | OS_DRAW_NOZWRITE | OS_DRAW_ZALWAYS); + } + + // + // Draw the UC logo. + // + + static SLONG start = 2000; + static SLONG fade = 2100; + static SLONG end = 9000; + static SLONG which = 0; + static float v1 = 1.0F - 0.00F; + static float v2 = 1.0F - 0.22F; + + if (OS_ticks() < start) + { + // + // Do nothing... + // + } + else + if (OS_ticks() < fade || OS_ticks() > end) + { + SLONG i; + ULONG colour = 0x404040; + + ob = OS_buffer_new(); + + for (i = 0; i < 4; i++) + { + OS_buffer_add_sprite( + ob, + 0.70F + frand() * 0.02F - 0.01F, 0.9F + frand() * 0.02F - 0.01F - (v1 - v2) * 0.17F, + 0.96F + frand() * 0.02F - 0.01F, 0.9F + frand() * 0.02F - 0.01F + (v1 - v2) * 0.17F, + 0.0F, v1, + 1.0F, v2, + 0.0F, + colour); + } + + OS_buffer_draw(ob, BACK_ot_logo, NULL, OS_DRAW_ADD | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE); + + if (OS_ticks() > end + 100) + { + // + // Start again! + // + + start = end + 5000; + fade = start + 100; + end = fade + 5000; + + which += 1; + + if (which == 3) + { + which = 0; + } + + switch(which) + { + case 0: + v1 = 1.0F - 0.57F; + v2 = 1.0F - 1.00F; + break; + + case 1: + v1 = 1.0F - 63.0F / 256.0F; + v2 = 1.0F - 142.0F / 256.0F; + break; + + case 2: + v1 = 1.0F - 0.00F; + v2 = 1.0F - 0.22F; + break; + + default: + ASSERT(0); + break; + } + } + } + else + { + ob = OS_buffer_new(); + + OS_buffer_add_sprite( + ob, + 0.70F, 0.9F - (v1 - v2) * 0.17F, + 0.96F, 0.9F + (v1 - v2) * 0.17F, + 0.0F, v1, + 1.0F, v2, + 0.0F, + 0xffffff); + + OS_buffer_draw(ob, BACK_ot_logo, NULL, OS_DRAW_ADD | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE); + } +} + +#endif diff --git a/fallen/DDEngine/Source/DCcredits.cpp b/fallen/DDEngine/Source/DCcredits.cpp new file mode 100644 index 0000000..9462916 --- /dev/null +++ b/fallen/DDEngine/Source/DCcredits.cpp @@ -0,0 +1,660 @@ +#if 0 + +// +// Draws the credits +// + +#include "always.h" +#include "key.h" +#include "font.h" +#include "os.h" + + + + +// +// The credits for each section. +// + +CBYTE *CREDITS_muckyfoot[] = +{ + "Mucky Foot are Ashley Hampton, Barry Meade, Chris Knott, Eddie", + "Edwards, Fin McGechie, Gary Carr, Guy Simmons, James 'Dudley'", + "Watson, Jan Svarovsky, John Steels, Junior Walker, Justin Amore,", + "Mark Smart, Mark Adami, Martin Oliver, Matthew Rosenfeld, Mike", + "Burnham, Mike Diskett, Ollie Shaw, Richard Franke, Simon 'Grimmy'", + "Keating, Stuart Black, Tom Forsyth, Tom Ireland and Wayne Imlach.", + NULL, + "Here's an effort to divide up what we did to make Urban Chaos!", + NULL, + + "~BProgramming", + "\tMike Diskett", + "\tMark Adami", + "\tMatthew Rosenfeld", + "\tJames 'Dudley' Watson", + "\tEddie Edwards", + "\tGuy Simmons", + "\tTom Forsyth", + "~I\tAdditional programming", + "\t\tJeremy Longley", + NULL, + + "~BArt Direction", + "\tFin McGechie", + NULL, + + "~BArt", + "\tStuart Black", + "\tRichard Franke", + "\tOllie Shaw", + "\tFin McGechie", + "\tJunior Walker", + "\tChris Knott", + "\tGary Carr", + "~I\tAdditional art", + "\t\tTerry Catrell", + "\t\tJoe Rider", + "\t\tSteve Brown", + NULL, + + "~BAnimation", + "\tOllie Shaw", + "\tJunior Walker", + "\tChris Knott", + NULL, + + "~BLevel Design", + "\tSimon 'Grimmy' Keating", + "\tBarry Meade", + NULL, + + "~BSound and Music", + "\tMartin Oliver", + NULL, + + "~BScripting", + "\tBarry Meade", + "\tSimon 'Grimmy' Keating", + "\tFin McGechie", + NULL, + + "~BTesting", + "\tJustin (mucky)hands Amore", + "~I\tAdditional testing", + "\t\tSean Lamacraft", + "\t\tMarie Colwell", + "\t\tMark Rose", + "\t\tDavid Harlow", + "~I\tFurther testing", + "\t\tChristopher Absolom", + "\t\tMark Baker", + "\t\tAlex Blackwood", + "\t\tDahman Coombes", + "\t\tTom Everard", + "\t\tEamon Meadows", + "\t\tAnthony Nicholson", + "\t\tTom Patterson", + "\t\tLawrence Phillips", + "\t\tDaniel Purvis", + "\t\tGary Reed", + "\t\tAmy Ross", + "\t\tPeter Ruscoe", + "\t\tKraig Stone", + "\t\tLorne Tietjen", + "\t\tDavid Walker", + "\t\tDavid Wright", + NULL, + "\tMichael Burnham", + "\tTom Forsyth", + "\tGary Carr", + "\tJohn Steels", + "\tTom Ireland", + "\tJan Svarovsky", + "\tand everyone at MuckyFoot", + NULL, + + "~BIT and Mucky Website", + "\tMichael Burnham", + NULL, + + "~BPR", + "\tCathy Campos at PanachePR", + NULL, + + "~BFurry Friends", + "\tSam", + "\tLisa", + "\tBarney", + NULL, + + "Special thanks to Glenn Corpes and a big mucky \"Thank You\" from", + "Mucky Foot to everyone at Eidos. Hello to the Wednesday night", + "footballers!", + "!" +}; + +CBYTE *CREDITS_eidos_uk[] = +{ + "~BSenior Producer", + "\tDarren Hedges", + NULL, + "~BLocalisation Team", + "\tHolly Andrews", + "\tFlavia Timiani", + NULL, + + "~BMarketing", + "\tKaren Ridley", + "\tLorna Evans", + NULL, + + "~BPR", + "\tJonathan Rosenblatt", + "\tSteve Starvis", + NULL, + + "~BCreative Services", + "\tCaroline Simon", + NULL, + + "~BLocalisation QA", + "\tMichael Weissmuller", + "\tAlex Lepoureau", + "\tAlessandro Mantelli", + NULL, + + "~BQA Manager", + "\tTony Bourne", + NULL, + + "~BLead QA", + "\tJean Duret", + NULL, + + "~BQA", + "\tLinus Dominique (Assistant Lead)", + "\tJason Walker (Hardware Specialist)", + "\tMichael Hanley", + "\tAndrew Christopher", + "\tAnthony Fretwell", + "\tBJ Samuel Kil", + "\tChris Ince", + "\tClint Nembhard", + "\tEsmond Ferns", + "\tGuy Cooper", + "\tLouis Farnham", + "\tMarlon Grant", + "\tNoel Cowan", + "\tPatrick Cowan", + "\tTyrone O'Neil", + NULL, + + "~BWith thanks for the last leg", + "\tIain McNeil", + "\tGrant Dean", + "!" +}; + + + +CBYTE *CREDITS_eidos_usa[] = +{ + "~BAssociate Producer", + "\tEric Adams", + NULL, + + "~BQA Manager", + "\tMike McHale", + NULL, + + "~BProduct Manager", + "\tJennifer Fitzsimmons", + NULL, + + "~BMarketing Manager", + "\tSusan Boshkoff", + NULL, + + "~BPR", + "\tBrian Kemp", + "\tGreg Rizzer", + NULL, + + "~BTesting", + "\tCorey Fong", + "\tKjell Vistad", + "\tRalph Ortiz", + "\tJohn Arvay", + "!" +}; + +CBYTE *CREDITS_eidos_france[] = +{ + "~BChef de produit", + "\tOlivier Salomon", + NULL, + + "~BResponsable localisation", + "\tStéphan Gonizzi", // This has got an accent + NULL, + + "~BResponsable RP", + "\tPriscille Demoly", + NULL, + + "~BTesteur de la VF", + "\tGuillaume Mahouin", + NULL, + + "~BTraduction", + "\tAround the Word, Paris", + NULL, + + "~BEnregistrement des voix françaises", // This has got an accent in it! + "\tLe Lotus Rose, Paris", + "!" +}; + +/* + +// +// The Translated version... +// + +{ + "~BMarketing Manager", + "\tOlivier Salomon", + NULL, + + "~BLocalisation Manager", + "\tStéphan Gonizzi", + NULL, + + "~BPR Manager", + "\tPriscille Demoly", + NULL, + + "~BLocalisation Testing", + "\tGuillaume Mahouin", + "!" +}; + +*/ + +CBYTE *CREDITS_eidos_germany[] = +{ + "~BLeiter Produktentwicklung", + "\tBeco Mulderij", + NULL, + + "~BProdukt-Manager", + "\tLars Wittkuhn", + NULL, + + "~BLeiter Marketing", + "\tKnut-Jochen Bergel", + NULL, + + "~BPR-Manager", + "\tSascha Denise Green-Kaiser", + NULL, + + "~BLokalisierungs-Manager", + "\tHeidi Maria Kohne", + NULL, + + "~BQA-Manager", + "Sören Winterfeldt", // Accent! + NULL, + + "~BÜbersetzung", // Accent! + "\tViolet Media, Isabel Sterner", + NULL, + + "~BAudio", + "\tHastings International Audio Network", + NULL, + + "~BTonmeister", + "\tCedric Hopf", + "!" + +}; + + + + + +CBYTE *CREDITS_voice_production[] = +{ + "~BCasting", + "\tPhil Morris at AllintheGame", + NULL, + + "~BVoice Production", + "\tBarry Meade", + "\tMartin Oliver", + "\tChris O'Saughanessy", + "\tPhil Morris", + NULL, + + "~BVoice Actors", + "\tJohnnie Fiori", + "\tDan Russell", + "\tSharon Holm", + "\tKerry Shale", + "\tJulienne Davis", + "\tColin McFarlane", + "\tTed Maynard", + "\tBrad Lavelle", + "\tTogo Igawa", + NULL, + + "~BTranslation", + "\tAround the Word, Paris", + NULL, + + "~BFrench Voices", + "\tLe Lotus Rose, Paris", + "!" +}; + + + +CBYTE *CREDITS_bands[] = +{ + "Way Out West - Urban Chaos", + "The 3 Jays - Feeling it too", + "Tour De Force ", + "Asian Dub Foundation and Audioactive - Psycho Buds", + "Infidels - Everything", + "Infidels - Ooma Gabba", + "Special Forces 'Something Else... The bleep tune' courtesy of Photek Productions", + NULL, + "Many Thanks to Miles Jacobson at Anglo.", + "!" +}; + + + +// +// The credits grouped into sections. +// + +typedef struct +{ + CBYTE *title; + CBYTE **line; + +} CREDITS_Section; + +#define CREDITS_NUM_SECTIONS 7 + +CREDITS_Section CREDITS_section[CREDITS_NUM_SECTIONS] = +{ + { + "MUCKYFOOT", + CREDITS_muckyfoot + }, + + { + "EIDOS UK", + CREDITS_eidos_uk + }, + + { + "EIDOS USA", + CREDITS_eidos_usa + }, + + { + "EIDOS FRANCE", + CREDITS_eidos_france + }, + + { + "EIDOS GERMANY", + CREDITS_eidos_germany + }, + + { + "VOICE PRODUCTION", + CREDITS_voice_production + }, + + { + "ORIGINAL CD MUSIC", + CREDITS_bands + } +}; + + + +// +// The current section and y-offset. +// + +SLONG CREDITS_current_section; +float CREDITS_current_y; +float CREDITS_current_end_y; + + + + +void CREDITS_init() +{ + CREDITS_current_section = 0; + CREDITS_current_y = 1.0F; +} + + + + + +void CREDITS_draw() +{ + SLONG i; + SLONG dont_draw; + SLONG flag; + float x; + float y; + float shimmer; + float scale; + + CREDITS_Section *cs; + + static SLONG last; + static SLONG now; + + now = OS_ticks(); + + // + // Never be more than 1/2 a second behind... + // + + if (last < now - 500) + { + last = now - 500; + } + + if (KEY_on[KEY_S]) + { + last -= 200; + } + + // + // Scroll upwards... + // + + CREDITS_current_y -= (now - last) * 0.00005F; + + // + // Draw the title of the section. + // + + ASSERT(WITHIN(CREDITS_current_section, 0, CREDITS_NUM_SECTIONS - 1)); + + cs = &CREDITS_section[CREDITS_current_section]; + + // + // Draw the title. + // + + if (CREDITS_current_y > 0.6F) + { + shimmer = 1.0F - (1.0F - CREDITS_current_y) * (1.0F / 0.4F); + } + else + if (CREDITS_current_end_y < 0.50F) + { + shimmer = 1.0F - (CREDITS_current_end_y - 0.10F) * (1.0F / 0.4F); + } + + SATURATE(shimmer, 0.0F, 1.0F); + + FONT_draw( + FONT_FLAG_JUSTIFY_LEFT, + 0.03F, 0.05F, + 0xffffff, + 1.5F, + -1, + shimmer, + cs->title); + + // + // Draw all the text in the current section. + // + + y = CREDITS_current_y; + + for (i = 0; cs->line[i] == NULL || cs->line[i][0] != '!'; i++) + { + flag = FONT_FLAG_JUSTIFY_LEFT; + scale = 0.6F; + dont_draw = FALSE; + + if (cs->line[i] == NULL) + { + // + // Blank line. + // + + dont_draw = TRUE; + } + else + if (y < 0.10F) + { + // + // Dont draw... + // + + dont_draw = TRUE; + } + else + if (y < 0.30F) + { + shimmer = 1.0F - (y - 0.10F) * (1.0F / 0.2F); + } + else + if (y < 0.75F) + { + shimmer = 0.0F; + } + else + if (y < 0.95F) + { + shimmer = (y - 0.75F) * (1.0F / 0.2F); + } + else + { + // + // Don't draw... + // + + dont_draw = TRUE; + } + + if (cs->line[i]) + { + CBYTE *text = cs->line[i]; + + // + // What style do we draw the text? + // + + if (text[0] == '~') + { + switch(text[1]) + { + case 'B': + scale = 1.0F; + break; + + case 'I': + flag |= FONT_FLAG_ITALIC; + break; + + default: + ASSERT(0); + break; + } + + text += 2; + } + + // + // Whats the tabbing? + // + + x = 0.06F; + + while(*text == '\t') + { + text += 1; + x += 0.03F; + } + + if (!dont_draw) + { + // + // Draw the text! + // + + FONT_draw( + flag, + x, y, + 0xffffff, + scale, + -1, + shimmer, + text); + } + } + + y += 0.05F * scale; + } + + CREDITS_current_end_y = y; + + if (y < 0.10F) + { + // + // Time to move onto the next set of credits! + // + + CREDITS_current_section += 1; + CREDITS_current_y = 1.0F; + + if (CREDITS_current_section >= CREDITS_NUM_SECTIONS) + { + CREDITS_current_section = 0; + } + } + + last = now; +} + + + +#endif diff --git a/fallen/DDEngine/Source/DCfont.cpp b/fallen/DDEngine/Source/DCfont.cpp new file mode 100644 index 0000000..84dca00 --- /dev/null +++ b/fallen/DDEngine/Source/DCfont.cpp @@ -0,0 +1,575 @@ +#if 0 + +// +// A font! That's all there is to it. +// + +#include "always.h" +#include "font.h" +#include "os.h" +#include "tga.h" + + +// +// Each of the letters +// + +typedef struct +{ + float u; + float v; + float uwidth; + +} FONT_Letter; + +#define FONT_LETTER_HEIGHT 21 + +#define FONT_LOWERCASE 0 +#define FONT_UPPERCASE 26 +#define FONT_NUMBERS 52 +#define FONT_PUNCT_PLING 62 +#define FONT_PUNCT_DQUOTE 63 +#define FONT_PUNCT_POUND 64 +#define FONT_PUNCT_DOLLAR 65 +#define FONT_PUNCT_PERCENT 66 +#define FONT_PUNCT_POWER 67 +#define FONT_PUNCT_AMPERSAND 68 +#define FONT_PUNCT_ASTERISK 69 +#define FONT_PUNCT_OPEN 70 +#define FONT_PUNCT_CLOSE 71 +#define FONT_PUNCT_COPEN 72 +#define FONT_PUNCT_CCLOSE 73 +#define FONT_PUNCT_SOPEN 74 +#define FONT_PUNCT_SCLOSE 75 +#define FONT_PUNCT_LT 76 +#define FONT_PUNCT_GT 77 +#define FONT_PUNCT_BSLASH 78 +#define FONT_PUNCT_FSLASH 79 +#define FONT_PUNCT_COLON 80 +#define FONT_PUNCT_SEMICOLON 81 +#define FONT_PUNCT_QUOTE 82 +#define FONT_PUNCT_AT 83 +#define FONT_PUNCT_HASH 84 +#define FONT_PUNCT_TILDE 85 +#define FONT_PUNCT_QMARK 86 +#define FONT_PUNCT_MINUS 87 +#define FONT_PUNCT_EQUALS 88 +#define FONT_PUNCT_PLUS 89 +#define FONT_PUNCT_DOT 90 +#define FONT_PUNCT_COMMA 91 +#define FONT_NUM_FOREIGN 66 +#define FONT_NUM_LETTERS (92 + FONT_NUM_FOREIGN) + +FONT_Letter FONT_letter[FONT_NUM_LETTERS]; + +// +// This is the order the punctuation characters come in. +// + +CBYTE FONT_punct[] = +{ + "!\"£$%^&*(){}[]<>\\/:;'@#~?-=+.," + + "©ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüüýþÿ" +}; + + +// +// The texture and another place where we store the font data +// apart from the texture! +// + +OS_Texture *FONT_ot; +TGA_Pixel FONT_data[256][256]; + + +// +// Where the next character would have been drawn. +// + +float FONT_end_x; +float FONT_end_y; + + + +// +// Returns TRUE if it finds pixel data at (x,y) +// + +SLONG FONT_found_data(SLONG x, SLONG y) +{ + SLONG dy; + + SLONG px; + SLONG py; + + ASSERT(WITHIN(x, 0, 255)); + + for (dy = -16; dy <= 4; dy++) + { + px = x; + py = y + dy; + + if (WITHIN(py, 0, 255)) + { + if (FONT_data[255- py][px].alpha) + { + return TRUE; + } + } + } + + return FALSE; +} + + + +void FONT_init() +{ + SLONG i; + SLONG y; + SLONG x; + SLONG line; + + FONT_Letter *fl; + + // + // Load the texture. + // + + FONT_ot = OS_texture_create("font.tga"); + + // + // Load in the font bitmap. + // + + TGA_Info ti; + + ti = TGA_load( + "Textures\\font.tga", + 256, + 256, + &FONT_data[0][0]); + + ASSERT(ti.valid); + ASSERT(ti.width == 256); + ASSERT(ti.height == 256); + + // + // Work out the position of each of the letters. + // + + x = 0; + y = 19; + line = 0; + + for (i = 0; i < FONT_NUM_LETTERS; i++) + { + fl = &FONT_letter[i]; + + // + // Look for the start of the letter. + // + + while(!FONT_found_data(x,y)) + { + x += 1; + + if (x >= 256) + { + x = 0; + line += 1; + y += 22; + + if (y > 256) + { + return; + } + } + } + + fl->u = float(x); + fl->v = float(y); + + // + // Look for the end of the letter. + // + + x += 3; + + while(FONT_found_data(x,y)) + { + x += 1; + } + + fl->uwidth = (x - fl->u) * (1.0F / 256.0F); + + // + // Convert the (u,v)s + // + + fl->u *= 1.0F / 256.0F; + fl->v *= 1.0F / 256.0F; + + fl->v -= 16.0F / 256.0F; + } +} + + +// +// Returns the index of the given character +// + +SLONG FONT_get_index(CBYTE chr) +{ + SLONG letter; + + // + // Find our letter index. + // + + if (WITHIN(chr, 'a', 'z')) + { + letter = FONT_LOWERCASE + chr - 'a'; + } + else + if (WITHIN(chr, 'A', 'Z')) + { + letter = FONT_UPPERCASE + chr - 'A'; + } + else + if (WITHIN(chr, '0', '9')) + { + letter = FONT_NUMBERS + chr - '0'; + } + else + { + // + // Look for the punctuation letter. + // + + letter = FONT_PUNCT_PLING; + + for (CBYTE *ch = FONT_punct; *ch && *ch != chr; ch++, letter++); + } + + if (!WITHIN(letter, 0, FONT_NUM_LETTERS - 1)) + { + letter = FONT_PUNCT_QMARK; + } + + return letter; +} + + +SLONG FONT_char_is_valid(CBYTE ch) +{ + if (FONT_get_index(ch) == FONT_PUNCT_QMARK && ch != '?') + { + return FALSE; + } + else + { + return TRUE; + } +} + + + +float FONT_get_letter_width(CBYTE chr) +{ + SLONG letter; + + if (chr == ' ') + { + return 8.0F / 256.0F; + } + + letter = FONT_get_index(chr); + + ASSERT(WITHIN(letter, 0, FONT_NUM_LETTERS - 1)); + + return FONT_letter[letter].uwidth + (1.0F / 256.0F); +} + + + +float FONT_draw_letter( + OS_Buffer *ob, + CBYTE chr, + float x, + float y, + ULONG colour = 0xffffffff, + float scale = 1.0F, + float shimmer = 0.0F, + SLONG italic = FALSE) +{ + SLONG letter; + float width; + float lean; + + FONT_Letter *fl; + + // + // How much the character leans... + // + + lean = (italic) ? scale * 0.02F : 0.0F; + + // + // Space is a special case! + // + + if (chr == ' ') + { + width = (10.0F / 256.0F) * scale; + } + else + { + letter = FONT_get_index(chr); + + ASSERT(WITHIN(letter, 0, FONT_NUM_LETTERS - 1)); + + fl = &FONT_letter[letter]; + + width = fl->uwidth; + + if (shimmer == 0.0F) + { + /* + + OS_buffer_add_sprite( + ob, + x, + y, + x + fl->uwidth * scale, + y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + fl->u, + 1.0F - (fl->v), + fl->u + fl->uwidth, + 1.0F - (fl->v + (FONT_LETTER_HEIGHT / 256.0F)), + 0.0F, + colour); + */ + + OS_buffer_add_sprite_arbitrary( + ob, + x + lean, y, + x + lean + fl->uwidth * scale, y, + x, + y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + x + fl->uwidth * scale, + y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + fl->u, + 1.0F - (fl->v), + fl->u + fl->uwidth, + 1.0F - (fl->v), + fl->u, + 1.0F - (fl->v + (FONT_LETTER_HEIGHT / 256.0F)), + fl->u + fl->uwidth, + 1.0F - (fl->v + (FONT_LETTER_HEIGHT / 256.0F)), + 0.0F, + colour); + } + else + { + SLONG i; + + #define FONT_SHIMMER_SEGS 12 + #define FONT_SHIMMER_DANGLE 0.8F + #define FONT_SHIMMER_AMOUNT 0.01F + + float dx_last; + float dx_now; + float v = fl->v; + float dy = (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale / FONT_SHIMMER_SEGS; + float dv = (FONT_LETTER_HEIGHT * 1.00F / 256.0F) / FONT_SHIMMER_SEGS; + float angle = OS_ticks() * 0.004F; + float dlean = lean * (1.0F / FONT_SHIMMER_SEGS); + + // + // Scale the amount we shimmer by... + // + + shimmer *= scale; + shimmer *= FONT_SHIMMER_AMOUNT; + + // + // Draw in horizontal strips... + // + + dx_last = sin(angle - FONT_SHIMMER_DANGLE) * shimmer + lean; + + for (i = 0; i < FONT_SHIMMER_SEGS; i++) + { + lean -= dlean; + dx_now = sin(angle) * shimmer + lean; + + OS_buffer_add_sprite_arbitrary( + ob, + x + dx_last, y, x + fl->uwidth * scale + dx_last, y, + x + dx_now, y + dy, x + fl->uwidth * scale + dx_now , y + dy, + fl->u, 1.0F - v, + fl->u + fl->uwidth, 1.0F - v, + fl->u, 1.0F - (v + dv), + fl->u + fl->uwidth, 1.0F - (v + dv), + 0.0F, + colour); + + y += dy; + v += dv; + dx_last = dx_now; + angle += FONT_SHIMMER_DANGLE; + } + } + } + + return (width + 1.0F / 256.0F) * scale; +} + +// +// Returns the width of the given string. +// + +float FONT_get_width(CBYTE *str, float scale) +{ + float ans = 0.0F; + + for (CBYTE *ch = str; *ch; ch++) + { + ans += FONT_get_letter_width(*ch) * scale; + } + + return ans; +} + + + + + + + +void FONT_draw(SLONG flag, float start_x, float start_y, ULONG colour, float scale, SLONG cursor, float shimmer, CBYTE *fmt, ...) +{ + CBYTE message[4096]; + va_list ap; + + if (fmt == NULL) + { + sprintf(message, ""); + } + else + { + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + } + + // + // So that a scale of 1.0F is normal size. + // + + scale *= 0.55F; + + // + // The buffer we use to hold the sprites. + // + + OS_Buffer *ob = OS_buffer_new(); + + // + // Make sure the colour component has alpha- otherwise the + // font will be invisible! + // + + SLONG alpha; + + SATURATE(shimmer, 0.0F, 1.0F); + + alpha = ftol(255.0F * (1.0F - shimmer)); + colour |= alpha << 24; + + float x = start_x; + float y = start_y; + + if (flag & FONT_FLAG_JUSTIFY_CENTRE) + { + x -= FONT_get_width(message, scale) * 0.5F; + } + else + if (flag & FONT_FLAG_JUSTIFY_RIGHT) + { + x -= FONT_get_width(message, scale); + } + + CBYTE *ch = message; + + while(*ch) + { + if (*ch == '\n') + { + x = start_x; + y += (FONT_LETTER_HEIGHT + 2.0F) * scale; + } + else + { + if (cursor-- == 0) + { + // + // Draw a cursor here. + // + + { + OS_Buffer *ob = OS_buffer_new(); + + OS_buffer_add_sprite( + ob, + x, y, x + 0.01F * scale, y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + 0.0F, 0.0F, + 1.0F, 1.0F, + 0.0F, + 0xeeeeeff); + + OS_buffer_draw(ob, NULL, NULL); + } + } + + x += FONT_draw_letter(ob, *ch, x, y, colour, scale, shimmer, flag & FONT_FLAG_ITALIC); + } + + ch += 1; + } + + if (cursor-- == 0) + { + // + // Draw a cursor here. + // + + { + OS_Buffer *ob = OS_buffer_new(); + + OS_buffer_add_sprite( + ob, + x, y, x + 0.01F * scale, y + (FONT_LETTER_HEIGHT * 1.33F / 256.0F) * scale, + 0.0F, 0.0F, + 1.0F, 1.0F, + 0.0F, + 0xeeeeeff); + + OS_buffer_draw(ob, NULL, NULL); + } + } + + OS_buffer_draw(ob, FONT_ot, NULL, OS_DRAW_DOUBLESIDED | OS_DRAW_ZALWAYS | OS_DRAW_NOZWRITE | OS_DRAW_ALPHABLEND); + + // + // Where the next character would have been drawn. + // + + FONT_end_x = x; + FONT_end_y = y; +} + + +#endif diff --git a/fallen/DDEngine/Source/DCos.cpp b/fallen/DDEngine/Source/DCos.cpp new file mode 100644 index 0000000..b402368 --- /dev/null +++ b/fallen/DDEngine/Source/DCos.cpp @@ -0,0 +1,47 @@ +#if 0 + +// +// Sprite drawing routines for the DC credits sequence. +// + +#include + + +typedef struct dcos_buffer +{ + + + +} DCOS_Buffer; + + +// +// Add sprites to the buffer. +// + +void DCOS_buffer_add_sprite( + DCOS_Buffer *ob, + float x1, float y1, + float x2, float y2, + float u1 = 0.0F, float v1 = 0.0F, + float u2 = 1.0F, float v2 = 1.0F, + float z = 0.0F, + ULONG colour = 0x00ffffff, + ULONG specular = 0x00000000, + ULONG fade = 0); + + +// +// Draws the given buffer. +// + +#define DCOS_DRAW_NORMAL 0 +#define DCOS_DRAW_ADD 1 + +void DCOS_buffer_draw(OS_Buffer *ob, D3DTexture *texture, ULONG draw = DCOS_DRAW_NORMAL); + + + + +#endif + diff --git a/fallen/DDEngine/Source/Font.cpp b/fallen/DDEngine/Source/Font.cpp new file mode 100644 index 0000000..bc64c69 --- /dev/null +++ b/fallen/DDEngine/Source/Font.cpp @@ -0,0 +1,1848 @@ +// +// Cheapo font stuff... +// + +#include +#include +#include "font.h" +#include + +#define _____ 0x00 +#define ____x 0x01 +#define ___x_ 0x02 +#define ___xx 0x03 +#define __x__ 0x04 +#define __x_x 0x05 +#define __xx_ 0x06 +#define __xxx 0x07 +#define _x___ 0x08 +#define _x__x 0x09 +#define _x_x_ 0x0a +#define _x_xx 0x0b +#define _xx__ 0x0c +#define _xx_x 0x0d +#define _xxx_ 0x0e +#define _xxxx 0x0f +#define x____ 0x10 +#define x___x 0x11 +#define x__x_ 0x12 +#define x__xx 0x13 +#define x_x__ 0x14 +#define x_x_x 0x15 +#define x_xx_ 0x16 +#define x_xxx 0x17 +#define xx___ 0x18 +#define xx__x 0x19 +#define xx_x_ 0x1a +#define xx_xx 0x1b +#define xxx__ 0x1c +#define xxx_x 0x1d +#define xxxx_ 0x1e +#define xxxxx 0x1f + +typedef struct +{ + UBYTE bit[FONT_HEIGHT]; + UBYTE width; + +} FONT_Char; + +// +// Capital letters. +// + +FONT_Char FONT_upper[26] = +{ + { + { + _xx__, + x__x_, + x__x_, + x__x_, + xxxx_, + x__x_, + x__x_, + _____, + _____ + }, + 4 + }, + + { + { + xxx__, + x__x_, + x__x_, + xxx__, + x__x_, + x__x_, + xxx__, + _____, + _____ + }, + 4 + }, + + { + { + _xxx_, + x____, + x____, + x____, + x____, + x____, + _xxx_, + _____, + _____ + }, + 4 + }, + + { + { + xxx__, + x__x_, + x__x_, + x__x_, + x__x_, + x__x_, + xxx__, + _____, + _____ + }, + 4 + }, + + { + { + xxxx_, + x____, + x____, + xxx__, + x____, + x____, + xxxx_, + _____, + _____ + }, + 4 + }, + + { + { + xxxx_, + x____, + x____, + xxx__, + x____, + x____, + x____, + _____, + _____ + }, + 4 + }, + + { + { + _xxx_, + x____, + x____, + x____, + x_xx_, + x__x_, + _xxx_, + _____, + _____ + }, + 4 + }, + + { + { + x__x_, + x__x_, + x__x_, + xxxx_, + x__x_, + x__x_, + x__x_, + _____, + _____ + }, + 4 + }, + + { + { + xxx__, + _x___, + _x___, + _x___, + _x___, + _x___, + xxx__, + _____, + _____ + }, + 3 + }, + + { + { + xxxx_, + ___x_, + ___x_, + ___x_, + ___x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + x____, + x__x_, + x_x__, + xx___, + xx___, + x_x__, + x__x_, + _____, + _____ + }, + 4 + }, + + { + { + x____, + x____, + x____, + x____, + x____, + x____, + xxxx_, + _____, + _____ + }, + 4 + }, + + { + { + x___x, + xx_xx, + x_x_x, + x___x, + x___x, + x___x, + x___x, + _____, + _____ + }, + 5 + }, + + { + { + x___x, + x___x, + xx__x, + x_x_x, + x__xx, + x___x, + x___x, + _____, + _____ + }, + 5 + }, + + { + { + _xx__, + x__x_, + x__x_, + x__x_, + x__x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + xxx__, + x__x_, + x__x_, + x__x_, + xxx__, + x____, + x____, + _____, + _____ + }, + 4 + }, + + { + { + _xx__, + x__x_, + x__x_, + x__x_, + x__x_, + x_xx_, + _xx__, + ___x_, + _____ + }, + 4 + }, + + { + { + xxx__, + x__x_, + x__x_, + x__x_, + xxx__, + x_x__, + x__x_, + _____, + _____ + }, + 4 + }, + + { + { + _xx__, + x__x_, + x____, + _x___, + __x__, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + xxx__, + _x___, + _x___, + _x___, + _x___, + _x___, + _x___, + _____, + _____ + }, + 3 + }, + + { + { + x__x_, + x__x_, + x__x_, + x__x_, + x__x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + x__x_, + x__x_, + x__x_, + x__x_, + x__x_, + _x_x_, + __xx_, + _____, + _____ + }, + 4 + }, + + { + { + x___x, + x___x, + x___x, + x___x, + x_x_x, + xx_xx, + x___x, + _____, + _____ + }, + 5 + }, + + { + { + x___x, + x___x, + _x_x_, + __x__, + _x_x_, + x___x, + x___x, + _____, + _____ + }, + 5 + }, + + { + { + x__x_, + x__x_, + x__x_, + _x_x_, + __xx_, + __x__, + xx___, + _____, + _____ + }, + 4 + }, + + { + { + xxxx_, + ___x_, + ___x_, + __x__, + _x___, + x____, + xxxx_, + _____, + _____ + }, + 4 + } +}; + +// +// Lowercase +// + +FONT_Char FONT_lower[26] = +{ + { + { + _____, + _____, + _xx__, + ___x_, + _xxx_, + x__x_, + _xxx_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + x____, + xxx__, + x__x_, + x__x_, + x__x_, + xxx__, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + _xx__, + x____, + x____, + x____, + _xx__, + _____, + _____ + }, + 3 + }, + + { + { + _____, + ___x_, + _xxx_, + x__x_, + x__x_, + x__x_, + _xxx_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + _xx__, + x__x_, + xxxx_, + x____, + _xxx_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _xx__, + x____, + x____, + xx___, + x____, + x____, + _____, + _____ + }, + 3 + }, + + { + { + _____, + _____, + _xxx_, + x__x_, + x__x_, + x__x_, + _xxx_, + ___x_, + _xx__ + }, + 4 + }, + + { + { + _____, + x____, + x____, + xxx__, + x__x_, + x__x_, + x__x_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _x___, + _____, + xx___, + _x___, + _x___, + _x___, + _____, + _____ + }, + 2 + }, + + { + { + _____, + _x___, + _____, + xx___, + _x___, + _x___, + _x___, + _x___, + x____ + }, + 2 + }, + + { + { + _____, + x____, + x____, + x____, + x_x__, + xx___, + x_x__, + _____, + _____ + }, + 3 + }, + + { + { + _____, + xx___, + _x___, + _x___, + _x___, + _x___, + _x___, + _____, + _____ + }, + 2 + }, + + { + { + _____, + _____, + xx_x_, + x_x_x, + x___x, + x___x, + x___x, + _____, + _____ + }, + 5 + }, + + { + { + _____, + _____, + xxx__, + x__x_, + x__x_, + x__x_, + x__x_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + _xx__, + x__x_, + x__x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + xxx__, + x__x_, + x__x_, + x__x_, + xxx__, + x____, + x____ + }, + 4 + }, + + { + { + _____, + _____, + _xxx_, + x__x_, + x__x_, + x__x_, + _xxx_, + ___xx, + ___x_ + }, + 4 + }, + + { + { + _____, + _____, + x_xx_, + xx___, + x____, + x____, + x____, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + _xxx_, + x____, + _xx__, + ___x_, + xxx__, + _____, + _____ + }, + 4 + }, + + { + { + _____, + x____, + x____, + xxx__, + x____, + x____, + _xx__, + _____, + _____ + }, + 3 + }, + + { + { + _____, + _____, + x__x_, + x__x_, + x__x_, + x__x_, + _xxx_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + x__x_, + x__x_, + x__x_, + _x_x_, + __xx_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + x___x, + x___x, + x___x, + x_x_x, + _x_x_, + _____, + _____ + }, + 5 + }, + + { + { + _____, + _____, + x___x, + _x_x_, + __x__, + _x_x_, + x___x, + _____, + _____ + }, + 5 + }, + + { + { + _____, + _____, + x__x_, + x__x_, + x__x_, + x__x_, + _xxx_, + ___x_, + _xx__ + }, + 4 + }, + + { + { + _____, + _____, + xxxx_, + ___x_, + __x__, + _x___, + xxxx_, + _____, + _____ + }, + 4 + } +}; + +// +// The numbers... +// + +FONT_Char FONT_number[10] = +{ + + { + { + _xx__, + x__x_, + x_xx_, + xx_x_, + x__x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + _x___, + xx___, + _x___, + _x___, + _x___, + _x___, + xxx__, + _____, + _____ + }, + 3 + }, + + { + { + _xx__, + x__x_, + ___x_, + __x__, + _x___, + x____, + xxxx_, + _____, + _____ + }, + 4 + }, + + { + { + _xx__, + x__x_, + ___x_, + __x__, + ___x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + __x__, + _xx__, + x_x__, + x_x__, + xxxx_, + __x__, + __x__, + _____, + _____ + }, + 4 + }, + + { + { + xxxx_, + x____, + x____, + xxx__, + ___x_, + ___x_, + xxx__, + _____, + _____ + }, + 4 + }, + + { + { + __x__, + _x___, + x____, + xxx__, + x__x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + xxxx_, + ___x_, + ___x_, + __x__, + _x___, + _x___, + _x___, + _____, + _____ + }, + 4 + }, + + { + { + _xx__, + x__x_, + x__x_, + _xx__, + x__x_, + x__x_, + _xx__, + _____, + _____ + }, + 4 + }, + + { + { + _xx__, + x__x_, + x__x_, + _xxx_, + ___x_, + ___x_, + _xx__, + _____, + _____ + }, + 4 + } +}; + +// +// Various punctuation... +// + +#define FONT_PUNCT_DOT 0 +#define FONT_PUNCT_COMMA 1 +#define FONT_PUNCT_QMARK 2 +#define FONT_PUNCT_PLING 3 +#define FONT_PUNCT_QUOTES 4 +#define FONT_PUNCT_OPEN 5 +#define FONT_PUNCT_CLOSE 6 +#define FONT_PUNCT_PLUS 7 +#define FONT_PUNCT_MINUS 8 +#define FONT_PUNCT_EQUAL 9 +#define FONT_PUNCT_HASH 10 +#define FONT_PUNCT_PCENT 11 +#define FONT_PUNCT_STAR 12 +#define FONT_PUNCT_BSLASH 13 +#define FONT_PUNCT_FSLASH 14 +#define FONT_PUNCT_COLON 15 +#define FONT_PUNCT_SCOLON 16 +#define FONT_PUNCT_APOST 17 +#define FONT_PUNCT_AMPER 18 +#define FONT_PUNCT_POUND 19 +#define FONT_PUNCT_DOLLAR 20 +#define FONT_PUNCT_LT 21 +#define FONT_PUNCT_GT 22 +#define FONT_PUNCT_AT 23 +#define FONT_PUNCT_UNDER 24 +#define FONT_PUNCT_NUMBER 25 + +FONT_Char FONT_punct[FONT_PUNCT_NUMBER] = +{ + { + { + _____, + _____, + _____, + _____, + _____, + _____, + x____, + _____, + _____ + }, + 1 + }, + + { + { + _____, + _____, + _____, + _____, + _____, + _____, + x____, + x____, + _____ + }, + 2 + }, + + { + { + _xx__, + x__x_, + ___x_, + _xx__, + _x___, + _____, + _x___, + _____, + _____ + }, + 4 + }, + + { + { + x____, + x____, + x____, + x____, + x____, + _____, + x____, + _____, + _____ + }, + 1 + }, + + { + { + x_x__, + x_x__, + _____, + _____, + _____, + _____, + _____, + _____, + _____ + }, + 3 + }, + + { + { + _____, + _x___, + x____, + x____, + x____, + x____, + _x___, + _____, + _____ + }, + 2 + }, + + { + { + _____, + x____, + _x___, + _x___, + _x___, + _x___, + x____, + _____, + _____ + }, + 2 + }, + + { + { + _____, + _____, + __x__, + __x__, + xxxxx, + __x__, + __x__, + _____, + _____ + }, + 5 + }, + + { + { + _____, + _____, + _____, + _____, + xxxxx, + _____, + _____, + _____, + _____ + }, + 5 + }, + + { + { + _____, + _____, + _____, + xxxxx, + _____, + xxxxx, + _____, + _____, + _____ + }, + 5 + }, + + { + { + _____, + _____, + _x_x_, + xxxxx, + _x_x_, + xxxxx, + _x_x_, + _____, + _____ + }, + 5 + }, + + { + { + _____, + _____, + xx__x, + x__x_, + __x__, + _x__x, + x__xx, + _____, + _____ + }, + 5 + }, + + { + { + _____, + __x__, + x_x_x, + _xxx_, + xxxxx, + _xxx_, + x_x_x, + __x__, + _____ + }, + 5 + }, + + { + { + x____, + x____, + _x___, + _x___, + __x__, + __x__, + ___x_, + ___x_, + _____ + }, + 4 + }, + + { + { + ___x_, + ___x_, + __x__, + __x__, + _x___, + _x___, + x____, + x____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + _____, + x____, + _____, + x____, + _____, + _____, + _____ + }, + 1 + }, + + { + { + _____, + _____, + _____, + x____, + _____, + x____, + x____, + _____, + _____ + }, + 1 + }, + + { + { + _____, + x____, + x____, + _____, + _____, + _____, + _____, + _____, + _____ + }, + 1 + }, + + { + { + _xx__, + x__x_, + x_x__, + _x___, + x_x_x, + x__x_, + _xx_x, + _____, + _____ + }, + 5 + }, + + { + { + _xx__, + x__x_, + x____, + _x___, + xxx__, + _x___, + xxxx_, + _____, + _____ + }, + 4 + }, + + { + { + _____, + __x__, + _xxx_, + x_x__, + _xxx_, + __x_x, + _xxx_, + __x__, + _____ + }, + 5 + }, + + { + { + _____, + ___x_, + __x__, + _x___, + x____, + _x___, + __x__, + ___x_, + _____ + }, + 4 + }, + + { + { + _____, + x____, + _x___, + __x__, + ___x_, + __x__, + _x___, + x____, + _____ + }, + 4 + }, + + { + { + _____, + _____, + _xxx_, + x___x, + x_xxx, + x_xx_, + x____, + _xxxx, + _____ + }, + 5 + }, + + { + { + _____, + _____, + _____, + _____, + _____, + _____, + _____, + xxxx_, + _____ + }, + 4 + } +}; + +/* + { + { + _____, + _____, + _____, + _____, + _____, + _____, + _____, + _____, + _____ + }, + 4 + }, + +*/ + + +// +// Draws a character with the given RGB at (x,y). +// + +SLONG FONT_draw_coloured_char( + SLONG sx, + SLONG sy, + UBYTE red, + UBYTE green, + UBYTE blue, + CBYTE ch) +{ + SLONG b; + SLONG x; + SLONG y; + + FONT_Char *fc; + + if (ch == ' ') + { + return 3; + } + if (ch >= 'A' && ch <= 'Z') + { + fc = &FONT_upper[ch - 'A']; + } + else + if (ch >= 'a' && ch <= 'z') + { + fc = &FONT_lower[ch - 'a']; + } + else + if (ch >= '0' && ch <= '9') + { + fc = &FONT_number[ch - '0']; + } + else + { + switch(ch) + { + case '.': fc = &FONT_punct[FONT_PUNCT_DOT ]; break; + case ',': fc = &FONT_punct[FONT_PUNCT_COMMA ]; break; + case '?': fc = &FONT_punct[FONT_PUNCT_QMARK ]; break; + case '!': fc = &FONT_punct[FONT_PUNCT_PLING ]; break; + case '"': fc = &FONT_punct[FONT_PUNCT_QUOTES]; break; + case '(': fc = &FONT_punct[FONT_PUNCT_OPEN ]; break; + case ')': fc = &FONT_punct[FONT_PUNCT_CLOSE ]; break; + case '+': fc = &FONT_punct[FONT_PUNCT_PLUS ]; break; + case '-': fc = &FONT_punct[FONT_PUNCT_MINUS ]; break; + case '=': fc = &FONT_punct[FONT_PUNCT_EQUAL ]; break; + case '#': fc = &FONT_punct[FONT_PUNCT_HASH ]; break; + case '%': fc = &FONT_punct[FONT_PUNCT_PCENT ]; break; + case '*': fc = &FONT_punct[FONT_PUNCT_STAR ]; break; + case '\\': fc = &FONT_punct[FONT_PUNCT_BSLASH]; break; + case '/': fc = &FONT_punct[FONT_PUNCT_FSLASH]; break; + case ':': fc = &FONT_punct[FONT_PUNCT_COLON ]; break; + case ';': fc = &FONT_punct[FONT_PUNCT_SCOLON]; break; + case '\'': fc = &FONT_punct[FONT_PUNCT_APOST ]; break; + case '&': fc = &FONT_punct[FONT_PUNCT_AMPER ]; break; + case '£': fc = &FONT_punct[FONT_PUNCT_POUND ]; break; + case '$': fc = &FONT_punct[FONT_PUNCT_DOLLAR]; break; + case '<': fc = &FONT_punct[FONT_PUNCT_LT ]; break; + case '>': fc = &FONT_punct[FONT_PUNCT_GT ]; break; + case '@': fc = &FONT_punct[FONT_PUNCT_AT ]; break; + case '_': fc = &FONT_punct[FONT_PUNCT_UNDER ]; break; + + default: fc = &FONT_punct[FONT_PUNCT_QMARK ]; break; + } + } + + if (sy < -FONT_HEIGHT || sy >= the_display.screen_height || + sx < -FONT_WIDTH || sx >= the_display.screen_width) + { + // + // The character is off-screen. + // + } + else + { + for (y = 0; y < FONT_HEIGHT; y++) + { + for (b = 0x10, x = 0; x < 5; x++, b >>= 1) + { + if (fc->bit[y] & b) + { + the_display.PlotPixel(sx + x, sy + y, red, green, blue); + } + } + } + } + + return fc->width; +} +// +// Tab spacing... +// + +#define FONT_TAB 16 + +SLONG FONT_draw_coloured_text( + SLONG x, + SLONG y, + UBYTE red, + UBYTE green, + UBYTE blue, + CBYTE *fmt, ...) +{ + // + // Work out the real message. + // + + CBYTE message[FONT_MAX_LENGTH]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + // + // Draw the message! + // + + CBYTE *ch; + SLONG xstart = x; + + for (ch = message; *ch; ch++) + { + if (*ch == '\t') + { + x += FONT_TAB; + x &= ~(FONT_TAB - 1); + } + else + { + x += FONT_draw_coloured_char(x, y, red, green, blue, *ch) + 1; + } + + } + + return x - xstart; +} + + + +SLONG FONT_draw(SLONG x, SLONG y, CBYTE *fmt, ...) +{ + // + // Work out the real message. + // + + CBYTE message[FONT_MAX_LENGTH]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + // + // Draw the message! + // + + CBYTE *ch; + SLONG xstart = x; + + for (ch = message; *ch; ch++) + { + if (*ch == '\t') + { + x += (FONT_TAB); + x &= ~(FONT_TAB - 1); + } + else + { + FONT_draw_coloured_char(x + 1, y + 1, 255, 0, 0, *ch); + x += FONT_draw_coloured_char(x + 0, y + 0, 255, 255, 0, *ch) + 1; + } + } + + return x - xstart; +} + + + +// +// The buffer. +// + +#define FONT_BUFFER_SIZE (1024 * 8) + +CBYTE FONT_buffer[FONT_BUFFER_SIZE]; +CBYTE *FONT_buffer_upto; + +typedef struct +{ + SLONG x; + SLONG y; + UBYTE r; + UBYTE g; + UBYTE b; + UBYTE s; + CBYTE *m; + +} FONT_Message; + +#define FONT_MAX_MESSAGES 256 + +FONT_Message FONT_message[FONT_MAX_MESSAGES]; +SLONG FONT_message_upto; + + +void FONT_buffer_add( + SLONG x, + SLONG y, + UBYTE r, + UBYTE g, + UBYTE b, + UBYTE s, + CBYTE *fmt, ...) +{ + FONT_Message *fm; + + // + // Work out the real message. + // + + CBYTE message[FONT_MAX_LENGTH]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + // + // So we dont have to have an init() function. + // + + if (FONT_buffer_upto == NULL) + { + FONT_buffer_upto = &FONT_buffer[0]; + } + + if (!WITHIN(FONT_message_upto, 0, FONT_MAX_MESSAGES - 1)) + { + // + // No more messages. + // + + return; + } + + // + // Copy the message to the FONT_buffer. + // + + if (FONT_buffer_upto + strlen(message) + 1 > &FONT_buffer[FONT_BUFFER_SIZE]) + { + // + // Not enough room in the buffer. + // + + return; + } + + strcpy(FONT_buffer_upto, message); + + // + // Build the message. + // + + fm = &FONT_message[FONT_message_upto++]; + + fm->x = x; + fm->y = y; + fm->r = r; + fm->g = g; + fm->b = b; + fm->s = s; + fm->m = FONT_buffer_upto; + + FONT_buffer_upto += strlen(message) + 1; +} + +void FONT_buffer_draw() +{ + SLONG i; + SLONG x; + SLONG y; + + CBYTE *ch; + + FONT_Message *fm; + + if (FONT_message_upto == 0) + { + return; + } + + if (the_display.screen_lock()) + { + for (i = 0; i < FONT_message_upto; i++) + { + fm = &FONT_message[i]; + + x = fm->x; + y = fm->y; + + for (ch = fm->m; *ch; ch++) + { + if (*ch == '\t') + { + x += (FONT_TAB); + x &= ~(FONT_TAB - 1); + } + else + if (*ch == '\n') + { + x = fm->x; + y += 10; + } + else + { + if (fm->s) + { + FONT_draw_coloured_char(x + 1, y + 1, fm->r >> 1, fm->g >> 1, fm->b >> 1, *ch); + x += FONT_draw_coloured_char(x + 0, y + 0, fm->r, fm->g, fm->b, *ch) + 1; + } + else + { + x += FONT_draw_coloured_char(x + 0, y + 0, fm->r, fm->g, fm->b, *ch) + 1; + } + } + } + } + + the_display.screen_unlock(); + } + + FONT_buffer_upto = &FONT_buffer[0]; + FONT_message_upto = 0; +} + + +void FONT_draw_speech_bubble_text( + SLONG x, + SLONG y, + UBYTE red, + UBYTE green, + UBYTE blue, + CBYTE *fmt, ...) +{ + + // + // Work out the real message. + // + + CBYTE message[FONT_MAX_LENGTH]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + // + // How long is the message. + // + + SLONG length = FONT_draw_coloured_text(-100, -100, 0, 0, 0, message); + SLONG width = SLONG(sqrt(float(length) * 13.0F)); + + // + // Draw the message pretend to see how many lines it has. + // + + CBYTE *ch; + SLONG cw; + SLONG w = 0; + SLONG lines = 0; + + for (ch = message; *ch; ch++) + { + w += FONT_draw_coloured_char(-100, -100, 0, 0, 0, *ch) + 1; + + if (w > width) + { + w = 0; + lines += 1; + } + } + + + // + // Work out where we should start drawing the text. + // + + SLONG xstart = x; + SLONG ystart = y - lines * 10; + + // + // Draw the message. + // + + x = xstart; + y = ystart; + + for (ch = message; *ch; ch++) + { + cw = FONT_draw_coloured_char(x, y, red, green, blue, *ch) + 1; + + w += cw; + x += cw; + + if (w > width) + { + w = 0; + x = xstart; + y += 10; + } + } +} diff --git a/fallen/DDEngine/Source/Gamut.cpp b/fallen/DDEngine/Source/Gamut.cpp new file mode 100644 index 0000000..e82fc36 --- /dev/null +++ b/fallen/DDEngine/Source/Gamut.cpp @@ -0,0 +1,100 @@ +// Gamut.cpp +// Guy Simmons, 4th November 1997. + +#include "Engine.h" + + +GamutElement gamut_ele_pool[MAX_GAMUT_RADIUS*4*MAX_GAMUT_RADIUS], + *gamut_ele_ptr[MAX_GAMUT_RADIUS+2]; + +//--------------------------------------------------------------- + +void build_gamut_table(void) +{ + SBYTE *grid; + SLONG actual_radius, + angle, + count, + dx,dz, + old_radius = 0, + radius, + radius_offset, + sum_count = 0; + GamutElement *ele_ptr; + + + ele_ptr = gamut_ele_pool; + + grid = (SBYTE*)MemAlloc((MAX_GAMUT_RADIUS+1)*(MAX_GAMUT_RADIUS+1)*4); + if(grid) + { + for(radius=(MAX_GAMUT_RADIUS<<2);radius>2;radius--) + { + if((radius>>2)!=old_radius) + { + old_radius = radius>>2; + gamut_ele_ptr[radius>>2] = ele_ptr; + } + for(angle=0;angle<2048;angle+=4) + { + for(radius_offset=-4;radius_offset<4;radius_offset++) + { + dx = (SIN(angle)*(radius+radius_offset))>>(16+2); + dz = (COS(angle)*(radius+radius_offset))>>(16+2); + actual_radius = Root((dx*dx)+(dz*dz)); + if(actual_radius==(radius>>2)) + { + if(grid[(dx+MAX_GAMUT_RADIUS)+(dz+MAX_GAMUT_RADIUS)*(MAX_GAMUT_RADIUS*2)]!=-1) + { + grid[(dx+MAX_GAMUT_RADIUS)+(dz+MAX_GAMUT_RADIUS)*(MAX_GAMUT_RADIUS*2)] = -1; + ele_ptr->DX = (SBYTE)dx; + ele_ptr->DZ = (SBYTE)dz; + ele_ptr->Angle = (SWORD)angle; + ele_ptr++; + } + } + } + } + } + gamut_ele_ptr[0] = ele_ptr; + MemFree(grid); + } + for(radius=1;radiusDX+x; + scr_y = ele_ptr->DZ+y; + +// DrawPixel(scr_x,scr_y,0xffff); + + ele_ptr++; + } + } +} + +//--------------------------------------------------------------- diff --git a/fallen/DDEngine/Source/Matrix.cpp b/fallen/DDEngine/Source/Matrix.cpp new file mode 100644 index 0000000..efc61aa --- /dev/null +++ b/fallen/DDEngine/Source/Matrix.cpp @@ -0,0 +1,434 @@ +#include +#include "c:\fallen\ddengine\headers\matrix.h" + +#include + +#ifdef TARGET_DC +#include "target.h" +#endif + +#ifdef TARGET_DC +#include "shsgintr.h" +#endif + + +// +// OPTIMISE THIS AT SOME POINT MARK! 'roll' AND 'pitch' ARE NEARLY ALWAYS 0! +// + +void MATRIX_calc(float matrix[9], float yaw, float pitch, float roll) +{ + + float cy, cp, cr; + float sy, sp, sr; + +#ifdef TARGET_DC + + // Use the fast intrinsics. + // Error is 2e-21 at most. + _SinCosA ( &sy, &cy, yaw ); + _SinCosA ( &sr, &cr, roll ); + _SinCosA ( &sp, &cp, pitch ); + +#else //#ifdef TARGET_DC + + sy = sin(yaw); + sp = sin(pitch); + sr = sin(roll); + + cy = cos(yaw); + cp = cos(pitch); + cr = cos(roll); + +#endif //#else //#ifdef TARGET_DC + + // + // Jan I trust you... but only becuase I've already seen it working! + // + + matrix[0] = cy * cr + sy * sp * sr; + matrix[3] = cy * sr - sy * sp * cr; + matrix[6] = sy * cp; + matrix[1] = -cp * sr; + matrix[4] = cp * cr; + matrix[7] = sp; + matrix[2] = -sy * cr + cy * sp * sr; + matrix[5] = -sy * sr - cy * sp * cr; + matrix[8] = cy * cp; + + +} + + + + +#ifndef TARGET_DC +// +// i'll do this later / miked +// +void MATRIX_calc_int(SLONG matrix[9], SLONG yaw, SLONG pitch, SLONG roll) +{ + float cy, cp, cr; + float sy, sp, sr; + + sy = sin(yaw); + sp = sin(pitch); + sr = sin(roll); + + cy = cos(yaw); + cp = cos(pitch); + cr = cos(roll); + + // + // Jan I trust you... but only becuase I've already seen it working! + // + + matrix[0] = cy * cr + sy * sp * sr; + matrix[3] = cy * sr - sy * sp * cr; + matrix[6] = sy * cp; + matrix[1] = -cp * sr; + matrix[4] = cp * cr; + matrix[7] = sp; + matrix[2] = -sy * cr + cy * sp * sr; + matrix[5] = -sy * sr - cy * sp * cr; + matrix[8] = cy * cp; +} +#endif //#ifndef TARGET_DC + + +void MATRIX_vector(float vector[3], float yaw, float pitch) +{ + float cy, cp; + float sy, sp; + +#ifdef TARGET_DC + + // Use the fast intrinsics. + // Error is 2e-21 at most. + _SinCosA ( &sy, &cy, yaw ); + _SinCosA ( &sp, &cp, pitch ); + +#else + sy = sin(yaw); + sp = sin(pitch); + + cy = cos(yaw); + cp = cos(pitch); +#endif + + vector[0] = sy * cp; + vector[1] = sp; + vector[2] = cy * cp; +} + +void MATRIX_skew(float matrix[9], float skew, float zoom, float scale) +{ + // + // Squish up the matrix according to the aspect ratio of the screen. + // + + matrix[0] = matrix[0] * skew; + matrix[1] = matrix[1] * skew; + matrix[2] = matrix[2] * skew; + + // + // Create a lens by multiplying the x and y rows by the zoom factor... + // + + matrix[0] = zoom * matrix[0]; + matrix[1] = zoom * matrix[1]; + matrix[2] = zoom * matrix[2]; + + matrix[3] = zoom * matrix[3]; + matrix[4] = zoom * matrix[4]; + matrix[5] = zoom * matrix[5]; + + // + // Scale the whole matrix. + // + + matrix[0] *= scale; + matrix[1] *= scale; + matrix[2] *= scale; + matrix[3] *= scale; + matrix[4] *= scale; + matrix[5] *= scale; + matrix[6] *= scale; + matrix[7] *= scale; + matrix[8] *= scale; +} + + +void MATRIX_3x3mul(float a[9], float m[9], float n[9]) +{ + a[0] = m[0] * n[0] + m[1] * n[3] + m[2] * n[6]; + a[1] = m[0] * n[1] + m[1] * n[4] + m[2] * n[7]; + a[2] = m[0] * n[2] + m[1] * n[5] + m[2] * n[8]; + + a[3] = m[3] * n[0] + m[4] * n[3] + m[5] * n[6]; + a[4] = m[3] * n[1] + m[4] * n[4] + m[5] * n[7]; + a[5] = m[3] * n[2] + m[4] * n[5] + m[5] * n[8]; + + a[6] = m[6] * n[0] + m[7] * n[3] + m[8] * n[6]; + a[7] = m[6] * n[1] + m[7] * n[4] + m[8] * n[7]; + a[8] = m[6] * n[2] + m[7] * n[5] + m[8] * n[8]; +} + + +// +// Rotates the matrix by angle. You don't have to pass the 3rd row of the +// matrix, because it will be unchanged. +// + +#ifdef TARGET_DC + +// Use the fast intrinsics. +// Error is 2e-21 at most. + +#define MATRIX_ROTATE_ABOUT_Z(ax, ay, az, bx, by, bz, cx, cy, cz, angle) \ +{ \ + float c; \ + float s; \ + \ + _SinCosA ( &s, &c, angle ); \ + \ + float px; \ + float py; \ + float pz; \ + \ + float qx; \ + float qy; \ + float qz; \ + \ + if (angle) \ + { \ + px = c * (ax) + s * (bx); \ + py = c * (ay) + s * (by); \ + pz = c * (az) + s * (bz); \ + \ + qx = -s * (ax) + c * (bx); \ + qy = -s * (ay) + c * (by); \ + qz = -s * (az) + c * (bz); \ + \ + (ax) = px; (ay) = py; (az) = pz; \ + (bx) = qx; (by) = qy; (bz) = qz; \ + } \ +} + +#else + +#define MATRIX_ROTATE_ABOUT_Z(ax, ay, az, bx, by, bz, cx, cy, cz, angle) \ +{ \ + float c = cos(angle); \ + float s = sin(angle); \ + \ + float px; \ + float py; \ + float pz; \ + \ + float qx; \ + float qy; \ + float qz; \ + \ + if (angle) \ + { \ + px = c * (ax) + s * (bx); \ + py = c * (ay) + s * (by); \ + pz = c * (az) + s * (bz); \ + \ + qx = -s * (ax) + c * (bx); \ + qy = -s * (ay) + c * (by); \ + qz = -s * (az) + c * (bz); \ + \ + (ax) = px; (ay) = py; (az) = pz; \ + (bx) = qx; (by) = qy; (bz) = qz; \ + } \ +} + +#endif + + +void MATRIX_rotate_about_its_x(float *matrix, float angle) +{ + MATRIX_ROTATE_ABOUT_Z( + matrix[1], matrix[4], matrix[7], + matrix[2], matrix[5], matrix[8], + matrix[0], matrix[3], matrix[6], + -angle); +} + + +void MATRIX_rotate_about_its_y(float *matrix, float angle) +{ + MATRIX_ROTATE_ABOUT_Z( + matrix[2], matrix[5], matrix[8], + matrix[0], matrix[3], matrix[6], + matrix[1], matrix[4], matrix[7], + -angle); +} + + +void MATRIX_rotate_about_its_z(float *matrix, float angle) +{ + MATRIX_ROTATE_ABOUT_Z( + matrix[0], matrix[3], matrix[6], + matrix[1], matrix[4], matrix[7], + matrix[2], matrix[5], matrix[8], + -angle); +} + + +#define MATRIX_FA_VECTOR_TOO_SMALL (0.001F) +#define MATRIX_FA_ANGLE_TOO_SMALL (PI * 2.0F / 180.0F) + +#ifndef TARGET_DC +Direction MATRIX_find_angles_old(float matrix[9]) +{ + float x; + float y; + float z; + float xz; + + Direction ans; + + // + // Look from above at the z-vector to work out the yaw. + // + + x = matrix[6]; + y = matrix[7]; + z = matrix[8]; + + if (fabsf(x) + fabsf(z) < MATRIX_FA_VECTOR_TOO_SMALL) + { + // + // Try using the x-vector instead. + // + + float x1 = matrix[0]; + float y1 = matrix[1]; + float z1 = matrix[2]; + + ans.yaw = atan2(-z1, x1); + + //ans.yaw = 0.0F; + } + else + { + ans.yaw = atan2(x, z); + } + + // + // Look down the x vector to at the z-vector to work out the pitch. + // + + xz = sqrt(x*x + z*z); + + if (fabsf(xz) + fabsf(y) < MATRIX_FA_VECTOR_TOO_SMALL) + { + if (y < 0) {ans.pitch = -PI;} else {ans.pitch = +PI;} + } + else + { + ans.pitch = atan2(y, xz); + } + + // + // Now... matrix[4] = cos(pitch) * cos(roll) + // matrix[1] = -cos(pitch) * sin(roll) + // + // so... cos(roll) = matrix[4] / cos(pitch) + // sin(roll) = matrix[1] / -cos(pitch) + // + + float cos_roll; + float sin_roll; + float cos_pitch; + + cos_pitch = cos(ans.pitch); + + if (fabsf(cos_pitch) < MATRIX_FA_ANGLE_TOO_SMALL) + { + ans.roll = 0.0F; + } + else + { + cos_roll = matrix[4] / cos_pitch; + sin_roll = matrix[1] / -cos_pitch; + + ans.roll = atan2(sin_roll, cos_roll); + } + + return ans; +} +#endif + + +Direction MATRIX_find_angles(float matrix[9]) +{ + Direction ans; + + // + // matrix[7] is the sin(pitch) + // + + ans.pitch = (float)asin(matrix[7]); + + // + // Work out yaw differently depending on how much we are looking + // down or up. + // + + if (fabsf(ans.pitch) > (PI / 4.0F)) + { + if (fabsf(matrix[0]) + fabsf(matrix[2]) < 0.1F) + { + } + + ans.yaw = (float)atan2(matrix[0], matrix[2]) - (PI / 2.0F); + } + else + { + ans.yaw = (float)atan2(matrix[6], matrix[8]); + } + + // + // Now... matrix[4] = cos(pitch) * cos(roll) + // matrix[1] = -cos(pitch) * sin(roll) + // + // so... cos(roll) = matrix[4] / cos(pitch) + // sin(roll) = matrix[1] / -cos(pitch) + // + + float cos_roll; + float sin_roll; + float cos_pitch; + + cos_pitch = (float)cos(ans.pitch); + + if (fabsf(cos_pitch) < 0.0001F) + { + ans.roll = 0.0F; + } + else + { + cos_roll = matrix[4] / cos_pitch; + sin_roll = matrix[1] / -cos_pitch; + + ans.roll = (float)atan2(sin_roll, cos_roll); + } + + return ans; +} + + + + + + + + + + + + diff --git a/fallen/DDEngine/Source/Message.cpp b/fallen/DDEngine/Source/Message.cpp new file mode 100644 index 0000000..c1f2419 --- /dev/null +++ b/fallen/DDEngine/Source/Message.cpp @@ -0,0 +1,211 @@ +// +// Message passing to the user. +// + + +#include +#include "font.h" +#include "message.h" + + +#ifdef TARGET_DC +#define MSG_MAX_LENGTH 128 +#define MSG_MAX_MESSAGES 100 +#else +#define MSG_MAX_LENGTH 256 +#define MSG_MAX_MESSAGES 1000 +#endif + +extern BOOL allow_debug_keys; + +// +// The actual messages. +// + +typedef struct +{ + SLONG timer; + CBYTE message[MSG_MAX_LENGTH]; + +} MSG_Message; + +MSG_Message MSG_message[MSG_MAX_MESSAGES]; +SLONG current_message=0; +SLONG message_count=0; +SLONG draw_message_offset=0; + +void MSG_clear() +{ + SLONG i; + + for (i = 0; i < MSG_MAX_MESSAGES; i++) + { + MSG_message[i].timer = 0; + } +} + +// +// How long the messages hang around for. +// + +#define MSG_TIMER 128 + +void MSG_add(CBYTE *fmt, ...) +{ + //SLONG i; + SLONG oldest = 0; + SLONG oldtimer = INFINITY; + + if (!allow_debug_keys) return; + + // + // Work out the real message. + // + + CBYTE message[512]; + va_list ap; +// return; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + if(ControlFlag) + LogText("MSG->%s\n",message); +/* + for (i = 0; i < MSG_MAX_MESSAGES; i++) + { + // + // If we find the same message already present, just make that message + // hang around longer. + // + + if (MSG_message[i].timer) + { + if (strncmp(MSG_message[i].message, message, MSG_MAX_LENGTH - 1) == 0) + { + MSG_message[i].timer = MSG_TIMER; + return; + } + } + + if (MSG_message[i].timer < oldtimer) + { + oldest = i; + oldtimer = MSG_message[i].timer; + } + } +*/ + + + // + // Overwrite the oldest message. + // + + strncpy(MSG_message[current_message].message, message, MSG_MAX_LENGTH - 1); + + MSG_message[current_message].timer = MSG_TIMER; + + current_message++; + if(current_message>MSG_MAX_MESSAGES-2) + current_message=0; + + return; +} + + +#define SCREEN_SIZE 45 + +void MSG_draw() +{ + SLONG i; + SLONG x; + SLONG y; + + UBYTE red; + UBYTE green; + UBYTE blue; + + SLONG pos; + static draw_flag=0; + SLONG size=1; + // + // Go through the messages and draw them. + // + + if (!allow_debug_keys) return; + + pos=current_message-SCREEN_SIZE+draw_message_offset; + if(pos<0) + pos+=MSG_MAX_MESSAGES; + + if(pos>MSG_MAX_MESSAGES) + pos-=MSG_MAX_MESSAGES; + + if(ShiftFlag) + size=20; + + if(Keys[KB_PPLUS]) + draw_message_offset+=size; + + if(Keys[KB_PMINUS]) + draw_message_offset-=size; + + if(Keys[KB_PENTER]) + draw_message_offset=0; + + /* + + if(Keys[KB_PPOINT]) + { + Keys[KB_PPOINT]=0; + if(draw_flag) + draw_flag=0; + else + draw_flag=1; + } + + */ + +// if(draw_flag) + for (i = 0; i < SCREEN_SIZE; i++) + { + + x = 10; + y = 10 + i * 10; + + if (MSG_message[pos].timer) + { + //red = 80 + (MSG_message[i].timer >> 2); + //green = 80 + (MSG_message[i].timer >> 2); + //blue = 80 + (MSG_message[i].timer >> 2); + +// if (MSG_message[i].timer == MSG_TIMER) + { + red = 223; + green = 223; + blue = 223; + } + + FONT_draw_coloured_text( + x + 1, + y + 1, + red, + 0, + blue, + MSG_message[pos].message); + + FONT_draw_coloured_text( + x + 0, + y + 0, + red + 32, + green + 32, + blue + 32, + MSG_message[pos].message); + +// MSG_message[pos].timer -= 1; + } + pos++; + if(pos>MSG_MAX_MESSAGES) + pos=0; + } +} diff --git a/fallen/DDEngine/Source/NGamut.cpp b/fallen/DDEngine/Source/NGamut.cpp new file mode 100644 index 0000000..e9a96e0 --- /dev/null +++ b/fallen/DDEngine/Source/NGamut.cpp @@ -0,0 +1,335 @@ +// +// The gamut. +// + +#include +#include "ngamut.h" + + +NGAMUT_Gamut NGAMUT_gamut[NGAMUT_SIZE]; +SLONG NGAMUT_zmin; +SLONG NGAMUT_zmax; +SLONG NGAMUT_xmin; + +// +// Initialises the gamut. +// + +void NGAMUT_init(void) +{ + SLONG i; + + // + // This could be the first time we have called NGAMUT_init. + // We have to initialise the whole array. + // + + for (i = 0; i < NGAMUT_SIZE; i++) + { + NGAMUT_gamut[i].xmin = INFINITY; + NGAMUT_gamut[i].xmax = -INFINITY; + } + + NGAMUT_xmin = INFINITY; + NGAMUT_zmin = INFINITY; + NGAMUT_zmax = -INFINITY; +} + +// +// Pushes out the gamut so it includes the given square. +// + +inline void NGAMUT_add_square(SLONG x, SLONG z) +{ + if (!WITHIN(z, 0, NGAMUT_SIZE - 2)) + { + // + // The zline is off the map. + // + + return; + } + + // + // Make sure that the x-coord is in range. + // + + SATURATE(x, 0, NGAMUT_SIZE - 2); + + // + // Push out the gamut. + // + + if (z < NGAMUT_zmin) {NGAMUT_zmin = z;} + if (z > NGAMUT_zmax) {NGAMUT_zmax = z;} + + if (x < NGAMUT_xmin) {NGAMUT_xmin = x;} + + if (x < NGAMUT_gamut[z].xmin) {NGAMUT_gamut[z].xmin = x;} + if (x > NGAMUT_gamut[z].xmax) {NGAMUT_gamut[z].xmax = x;} +} + +// +// Pushes out the gamut so it includes the given line. +// + +void NGAMUT_add_line(float p1x, float p1z, float p2x, float p2z) +{ + float x; + SLONG z; + + SLONG m1x; + SLONG m1z; + + SLONG m2x; + SLONG m2z; + + float xfrac; + float zfrac; + + float dx; + float dz; + float dxdz; + + // + // Sort the points by z. + // + + if (p2z < p1z) + { + SWAP_FL(p1x, p2x); + SWAP_FL(p1z, p2z); + } + + // + // Add the end points of the line. + // + + m1x = SLONG(p1x); + m1z = SLONG(p1z); + + NGAMUT_add_square(m1x, m1z); + + m2x = SLONG(p2x); + m2z = SLONG(p2z); + + NGAMUT_add_square(m2x, m2z); + + // + // Go along the line. + // + + dx = p2x - p1x; + dz = p2z - p1z; + + if (dz == 0.0f) + { + // + // No z to traverse. + // + } + else + { + dxdz = dx / dz; + + // + // Move down to the next zline. + // + + zfrac = 1.0F - (p1z - m1z); + xfrac = zfrac * dxdz; + + x = p1x + xfrac; + z = m1z + 1; + + while(z <= m2z) + { + NGAMUT_add_square(SLONG(x), SLONG(z )); + NGAMUT_add_square(SLONG(x), SLONG(z - 1)); + + x += dxdz; + z += 1; + } + } +} + + +void NGAMUT_view_square(float mid_x, float mid_z, float radius) +{ + SLONG i; + SLONG z; + + SLONG zmin; + SLONG zmax; + + SLONG xmin; + SLONG xmax; + + zmin = SLONG(mid_z - radius); + zmax = SLONG(mid_z + radius); + + xmin = SLONG(mid_x - radius); + xmax = SLONG(mid_x + radius); + + SATURATE(zmin, 0, NGAMUT_SIZE - 1); + SATURATE(zmax, 0, NGAMUT_SIZE - 1); + + SATURATE(xmin, 0, NGAMUT_SIZE - 1); + SATURATE(xmax, 0, NGAMUT_SIZE - 1); + + NGAMUT_zmin = zmin; + NGAMUT_zmax = zmax; + + NGAMUT_xmin = xmin; + + // + // Initialise the rest of the gamut... + // + + for (i = 0; i < NGAMUT_SIZE; i++) + { + NGAMUT_gamut[i].xmin = INFINITY; + NGAMUT_gamut[i].xmax = -INFINITY; + } + + // + // Mark the square of the gamut. + // + + for (z = zmin; z <= zmax; z++) + { + NGAMUT_gamut[z].xmin = xmin; + NGAMUT_gamut[z].xmax = xmax; + } +} + + +NGAMUT_Gamut NGAMUT_point_gamut[NGAMUT_SIZE]; +SLONG NGAMUT_point_zmin; +SLONG NGAMUT_point_zmax; + +void NGAMUT_calculate_point_gamut(void) +{ + SLONG i; + + NGAMUT_point_zmin = NGAMUT_zmin; + NGAMUT_point_zmax = NGAMUT_zmax + 1; + + for (i = NGAMUT_zmin + 1; i <= NGAMUT_zmax; i++) + { + NGAMUT_point_gamut[i].xmin = MIN(NGAMUT_gamut[i].xmin, NGAMUT_gamut[i - 1].xmin); + NGAMUT_point_gamut[i].xmax = MAX(NGAMUT_gamut[i].xmax + 1, NGAMUT_gamut[i - 1].xmax + 1); + } + + NGAMUT_point_gamut[NGAMUT_point_zmin].xmin = NGAMUT_gamut[NGAMUT_zmin].xmin; + NGAMUT_point_gamut[NGAMUT_point_zmin].xmax = NGAMUT_gamut[NGAMUT_zmin].xmax + 1; + NGAMUT_point_gamut[NGAMUT_point_zmax].xmin = NGAMUT_gamut[NGAMUT_zmax].xmin; + NGAMUT_point_gamut[NGAMUT_point_zmax].xmax = NGAMUT_gamut[NGAMUT_zmax].xmax + 1; +} + +NGAMUT_Gamut NGAMUT_out_gamut[NGAMUT_SIZE]; +SLONG NGAMUT_out_zmin; +SLONG NGAMUT_out_zmax; + +#ifndef MIN3 +#define MIN3(a,b,c) (MIN(MIN(a,b),c)) +#endif + +#ifndef MAX3 +#define MAX3(a,b,c) (MAX(MAX(a,b,c)) +#endif + +void NGAMUT_calculate_out_gamut(void) +{ + SLONG i; + + SLONG z1; + SLONG z2; + SLONG z3; + + SLONG xmin; + SLONG xmax; + + NGAMUT_out_zmin = NGAMUT_zmin - 1; + NGAMUT_out_zmax = NGAMUT_zmax + 1; + + SATURATE(NGAMUT_out_zmin, 0, NGAMUT_SIZE - 1); + SATURATE(NGAMUT_out_zmax, 0, NGAMUT_SIZE - 1); + + for (i = NGAMUT_out_zmin; i <= NGAMUT_out_zmax; i++) + { + z1 = i - 1; + z2 = i; + z3 = i + 1; + + if (z1 < NGAMUT_zmin) {z1 = NGAMUT_zmin;} + if (z3 > NGAMUT_zmax) {z3 = NGAMUT_zmax;} + + SATURATE(z2, NGAMUT_zmin, NGAMUT_zmax); + + xmin = MIN3(NGAMUT_gamut[z1].xmin - 1, NGAMUT_gamut[z2].xmin - 1, NGAMUT_gamut[z3].xmin - 1); + xmax = MIN3(NGAMUT_gamut[z1].xmax + 1, NGAMUT_gamut[z2].xmax + 1, NGAMUT_gamut[z3].xmax + 1); + + if (xmin < 0) {xmin = 0;} + if (xmax > NGAMUT_SIZE - 1) {xmax = NGAMUT_SIZE - 1;} + + NGAMUT_out_gamut[i].xmin = xmin; + NGAMUT_out_gamut[i].xmax = xmax; + } +} + +NGAMUT_Gamut NGAMUT_lo_gamut[NGAMUT_SIZE_LO]; +SLONG NGAMUT_lo_zmin; +SLONG NGAMUT_lo_zmax; + +void NGAMUT_calculate_lo_gamut() +{ + SLONG i; + SLONG j; + + SLONG z; + + SLONG xmin; + SLONG xmax; + + SLONG out_xmin; + SLONG out_xmax; + + NGAMUT_lo_zmin = (NGAMUT_point_zmin - 1) / (NGAMUT_SIZE / NGAMUT_SIZE_LO); + NGAMUT_lo_zmax = (NGAMUT_point_zmax + 1) / (NGAMUT_SIZE / NGAMUT_SIZE_LO); + + SATURATE(NGAMUT_lo_zmin, 0, NGAMUT_SIZE_LO - 1); + SATURATE(NGAMUT_lo_zmax, 0, NGAMUT_SIZE_LO - 1); + + for (i = NGAMUT_lo_zmin; i <= NGAMUT_lo_zmax; i++) + { + xmin = +INFINITY; + xmax = -INFINITY; + + for (j = 0; j < (NGAMUT_SIZE / NGAMUT_SIZE_LO); j++) + { + z = i * (NGAMUT_SIZE / NGAMUT_SIZE_LO); + z += j; + + if (WITHIN(z, NGAMUT_point_zmin, NGAMUT_point_zmax)) + { + out_xmin = (NGAMUT_point_gamut[z].xmin - 1) / (NGAMUT_SIZE / NGAMUT_SIZE_LO); + out_xmax = (NGAMUT_point_gamut[z].xmax + 1) / (NGAMUT_SIZE / NGAMUT_SIZE_LO); + + if (out_xmin < xmin) {xmin = out_xmin;} + if (out_xmax > xmax) {xmax = out_xmax;} + } + } + ASSERT(xmax>=xmin || (xmin==+INFINITY && xmax==-INFINITY)); + + + SATURATE(xmin, 0, NGAMUT_SIZE_LO - 1); + SATURATE(xmax, 0, NGAMUT_SIZE_LO - 1); + + NGAMUT_lo_gamut[i].xmin = xmin; + NGAMUT_lo_gamut[i].xmax = xmax; + } +} + + + diff --git a/fallen/DDEngine/Source/Quaternion.cpp b/fallen/DDEngine/Source/Quaternion.cpp new file mode 100644 index 0000000..b17e08c --- /dev/null +++ b/fallen/DDEngine/Source/Quaternion.cpp @@ -0,0 +1,621 @@ +#include + +#include "game.h" +#include "Quaternion.h" +#include "c:\fallen\headers\fmatrix.h" + +void QUATERNION_BuildTweenInteger(struct Matrix33 *dest,struct CMatrix33 *cm1,struct CMatrix33 *cm2,SLONG tween); + +// JCL 22/12/98 +// lots of code shamelessly ripped (and then fixed...) from the Gamasutra Web site. + +//*************************************************************************************************** + +#define DELTA 0.05 //! guess???????????? + +void QuatSlerp(CQuaternion *from, CQuaternion *to, float t, CQuaternion *res) +{ + float to1[4]; + double omega, cosom, sinom, scale0, scale1; + + + // calc cosine + cosom = from->x * to->x + from->y * to->y + from->z * to->z + from->w * to->w; + + // adjust signs (if necessary) + if ( cosom <0.0 ) + { + cosom = -cosom; + + to1[0] = - to->x; + to1[1] = - to->y; + to1[2] = - to->z; + to1[3] = - to->w; + } + else + { + to1[0] = to->x; + to1[1] = to->y; + to1[2] = to->z; + to1[3] = to->w; + } + + // calculate coefficients + + if ( (1.0 - cosom) > DELTA ) + { + // standard case (slerp) + omega = acos(cosom); + sinom = sin(omega); + scale0 = sin((1.0 - t) * omega) / sinom; + scale1 = sin(t * omega) / sinom; + + } + else + { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; + } + + // calculate final values + res->x = scale0 * from->x + scale1 * to1[0]; + res->y = scale0 * from->y + scale1 * to1[1]; + res->z = scale0 * from->z + scale1 * to1[2]; + res->w = scale0 * from->w + scale1 * to1[3]; +} + +//*************************************************************************************************** +void QuatMul(CQuaternion *q1, CQuaternion *q2, CQuaternion *res) +{ + float A, B, C, D, E, F, G, H; + + A = (q1->w + q1->x) * (q2->w + q2->x); + B = (q1->z - q1->y) * (q2->y - q2->z); + C = (q1->x - q1->w) * (q2->y - q2->z); + D = (q1->y + q1->z) * (q2->x - q2->w); + E = (q1->x + q1->z) * (q2->x + q2->y); + F = (q1->x - q1->z) * (q2->x - q2->y); + G = (q1->w + q1->y) * (q2->w - q2->z); + H = (q1->w - q1->y) * (q2->w + q2->z); + + res->w = B + (-E - F + G + H) / 2; + res->x = A - ( E + F + G + H) / 2; + res->y = -C + ( E - F + G - H) / 2; + res->z = -D + ( E - F - G + H) / 2; +} + +//*************************************************************************************************** +void EulerToQuat(float roll, float pitch, float yaw, CQuaternion * quat) +{ + float cr, cp, cy, sr, sp, sy, cpcy, spsy; + + // calculate trig identities + cr = cos(roll/2); + cp = cos(pitch/2); + cy = cos(yaw/2); + + sr = sin(roll/2); + sp = sin(pitch/2); + sy = sin(yaw/2); + + cpcy = cp * cy; + spsy = sp * sy; + + quat->w = cr * cpcy + sr * spsy; + quat->x = sr * cpcy - cr * spsy; + quat->y = cr * sp * cy + sr * cp * sy; + quat->z = cr * cp * sy - sr * sp * cy; +} + +//*************************************************************************************************** +void QuatToMatrix(CQuaternion *quat, FloatMatrix *fm) +{ + float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + + // calculate coefficients + x2 = quat->x + quat->x; y2 = quat->y + quat->y; + z2 = quat->z + quat->z; + xx = quat->x * x2; xy = quat->x * y2; xz = quat->x * z2; + yy = quat->y * y2; yz = quat->y * z2; zz = quat->z * z2; + wx = quat->w * x2; wy = quat->w * y2; wz = quat->w * z2; + + fm->M[0][0] = 1.0 - (yy + zz); fm->M[1][0] = xy - wz; + fm->M[2][0] = xz + wy; + + fm->M[0][1] = xy + wz; fm->M[1][1] = 1.0 - (xx + zz); + fm->M[2][1] = yz - wx; + + fm->M[0][2] = xz - wy; fm->M[1][2] = yz + wx; + fm->M[2][2] = 1.0 - (xx + yy); +} + +//*************************************************************************************************** +void MatrixToQuat(FloatMatrix *fm, CQuaternion *quat) +{ + float tr, s, q[4]; + int i, j, k; + + int nxt[3] = {1, 2, 0}; + + tr = fm->M[0][0] + fm->M[1][1] + fm->M[2][2]; + + // check the diagonal +// if (tr > 1.0) //!???!?!?!?!!?!?!??!? + if (tr > 0.0) + { + s = sqrt (tr + 1.0); + quat->w = s / 2.0; + s = 0.5 / s; + quat->x = (fm->M[1][2] - fm->M[2][1]) * s; + quat->y = (fm->M[2][0] - fm->M[0][2]) * s; + quat->z = (fm->M[0][1] - fm->M[1][0]) * s; + } + else + { + // diagonal is negative + i = 0; + if (fm->M[1][1] > fm->M[0][0]) i = 1; + if (fm->M[2][2] > fm->M[i][i]) i = 2; + j = nxt[i]; + k = nxt[j]; + + s = sqrt ((fm->M[i][i] - (fm->M[j][j] + fm->M[k][k])) + 1.0); + + q[i] = s * 0.5; + + if (s != 0.0) s = 0.5 / s; + + q[3] = (fm->M[j][k] - fm->M[k][j]) * s; + q[j] = (fm->M[i][j] + fm->M[j][i]) * s; + q[k] = (fm->M[i][k] + fm->M[k][i]) * s; + + quat->x = q[0]; + quat->y = q[1]; + quat->z = q[2]; + quat->w = q[3]; + } +} + +//*************************************************************************************************** +//*************************************************************************************************** + +// temporary matrix conversion stuff + +void cmat_to_fmat(CMatrix33 *cm, FloatMatrix *fm) +{ + fm->M[0][0] = float(((cm->M[0] & CMAT0_MASK) >> 20)) / 512.f; + fm->M[0][1] = float(((cm->M[0] & CMAT1_MASK) >> 10)) / 512.f; + fm->M[0][2] = float(((cm->M[0] & CMAT2_MASK) >> 00)) / 512.f; + + fm->M[1][0] = float(((cm->M[1] & CMAT0_MASK) >> 20)) / 512.f; + fm->M[1][1] = float(((cm->M[1] & CMAT1_MASK) >> 10)) / 512.f; + fm->M[1][2] = float(((cm->M[1] & CMAT2_MASK) >> 00)) / 512.f; + + fm->M[2][0] = float(((cm->M[2] & CMAT0_MASK) >> 20)) / 512.f; + fm->M[2][1] = float(((cm->M[2] & CMAT1_MASK) >> 10)) / 512.f; + fm->M[2][2] = float(((cm->M[2] & CMAT2_MASK) >> 00)) / 512.f; + + // this is pretty damn shite. + if (fm->M[0][0] >= 1.f) fm->M[0][0] -= 2.f; + if (fm->M[0][1] >= 1.f) fm->M[0][1] -= 2.f; + if (fm->M[0][2] >= 1.f) fm->M[0][2] -= 2.f; + if (fm->M[1][0] >= 1.f) fm->M[1][0] -= 2.f; + if (fm->M[1][1] >= 1.f) fm->M[1][1] -= 2.f; + if (fm->M[1][2] >= 1.f) fm->M[1][2] -= 2.f; + if (fm->M[2][0] >= 1.f) fm->M[2][0] -= 2.f; + if (fm->M[2][1] >= 1.f) fm->M[2][1] -= 2.f; + if (fm->M[2][2] >= 1.f) fm->M[2][2] -= 2.f; +} + +//*************************************************************************************************** +void fmat_to_mat(FloatMatrix *fm, Matrix33 *m) +{ + m->M[0][0] = SLONG(fm->M[0][0] * 32768.f); + m->M[0][1] = SLONG(fm->M[0][1] * 32768.f); + m->M[0][2] = SLONG(fm->M[0][2] * 32768.f); + + m->M[1][0] = SLONG(fm->M[1][0] * 32768.f); + m->M[1][1] = SLONG(fm->M[1][1] * 32768.f); + m->M[1][2] = SLONG(fm->M[1][2] * 32768.f); + + m->M[2][0] = SLONG(fm->M[2][0] * 32768.f); + m->M[2][1] = SLONG(fm->M[2][1] * 32768.f); + m->M[2][2] = SLONG(fm->M[2][2] * 32768.f); +} + + +//*************************************************************************************************** +//*************************************************************************************************** + +BOOL is_unit(float a, float b, float c) +{ + return (fabs(1.0 - (a*a + b*b + c*c)) < 0.01); +} + +BOOL check_isonormal(FloatMatrix &m) +{ + BOOL r = TRUE; + + if ((m.M[0][0] == 0) && (m.M[0][1] == 0) && (m.M[0][2] == 0)) + return TRUE; // void matrix + +#ifdef _DEBUG_POO + // check units + r &= is_unit(m.M[0][0], m.M[0][1], m.M[0][2]); + r &= is_unit(m.M[1][0], m.M[1][1], m.M[1][2]); + r &= is_unit(m.M[2][0], m.M[2][1], m.M[2][2]); + r &= is_unit(m.M[0][0], m.M[1][0], m.M[2][0]); + r &= is_unit(m.M[0][1], m.M[1][1], m.M[2][1]); + r &= is_unit(m.M[0][2], m.M[1][2], m.M[2][2]); + + ASSERT(r); + + // check orthogonality + float a = (m.M[0][0]*m.M[1][0] + m.M[0][1]*m.M[1][1] + m.M[0][2]*m.M[1][2]); + float b = (m.M[0][0]*m.M[2][0] + m.M[0][1]*m.M[2][1] + m.M[0][2]*m.M[2][2]); + float c = (m.M[2][0]*m.M[1][0] + m.M[2][1]*m.M[1][1] + m.M[2][2]*m.M[1][2]); + + ASSERT(fabs(a) < 0.03); + ASSERT(fabs(b) < 0.03); + ASSERT(fabs(c) < 0.03); +#endif + + // check handedness + float x = m.M[0][1] * m.M[1][2] - m.M[0][2] * m.M[1][1]; + float y = m.M[0][2] * m.M[1][0] - m.M[0][0] * m.M[1][2]; + float z = m.M[0][0] * m.M[1][1] - m.M[0][1] * m.M[1][0]; + + if ((fabs(x - m.M[2][0]) > 0.03) || + (fabs(y - m.M[2][1]) > 0.03) || + (fabs(z - m.M[2][2]) > 0.03)) + return FALSE; + + return TRUE; +} + +void build_tween_matrix(struct Matrix33 *mat,struct CMatrix33 *cmat1,struct CMatrix33 *cmat2,SLONG tween); + +// external stuff + +void CQuaternion::BuildTween(struct Matrix33 *dest,struct CMatrix33 *cm1,struct CMatrix33 *cm2,SLONG tween) +{ + // * construct the quaternions from the compressed integer matrices + // * SLERP the quaternions using the tween value + // * construct a non-compressed integer matrix from the resulting quaternion + + //! mmm +// QUATERNION_BuildTweenInteger(dest, cm1, cm2, tween); +// return; + +#ifndef PSX + + FloatMatrix f1, f2, f3; + + cmat_to_fmat(cm1, &f1); + cmat_to_fmat(cm2, &f2); + + BOOL a, b; + a = check_isonormal(f1); + b = check_isonormal(f2); + +// if (b) +// if (1) + + // ok - if handedness is wrong, flip before and afterwards. + // only if both src and dest handedness is the same.. + if (a == b) + { +/* + if (!a) + { + // flip + f1.M[2][0] = -f1.M[2][0]; + f1.M[2][1] = -f1.M[2][1]; + f1.M[2][2] = -f1.M[2][2]; + f2.M[2][0] = -f2.M[2][0]; + f2.M[2][1] = -f2.M[2][1]; + f2.M[2][2] = -f2.M[2][2]; + } +*/ + float t = float(tween) / 256.f; + + CQuaternion q1, q2, q3; + + MatrixToQuat(&f1, &q1); + MatrixToQuat(&f2, &q2); + + QuatSlerp(&q1, &q2, t, &q3); + QuatToMatrix(&q3, &f3); +/* + if (!a) + { + // flip + f3.M[2][0] = -f3.M[2][0]; + f3.M[2][1] = -f3.M[2][1]; + f3.M[2][2] = -f3.M[2][2]; + } +*/ + fmat_to_mat(&f3, dest); + + return; + } +#endif + + // fallback for dodgy matrices and PSX version + build_tween_matrix(dest, cm1, cm2, tween); + normalise_matrix_rows(dest); +} + +//*************************************************************************************************** +//*************************************************************************************************** +//*************************************************************************************************** +//*************************************************************************************************** +//*************************************************************************************************** + +// integer version! + +//*************************************************************************************************** +struct QuatInt +{ + SLONG x, y, z, w; +}; + +//*************************************************************************************************** +void MatrixToQuatInteger(Matrix33 *m, QuatInt *quat) +{ + SLONG tr, s; + SLONG q[4]; + SLONG i, j, k; + + SLONG nxt[3] = {1, 2, 0}; + + tr = m->M[0][0] + m->M[1][1] + m->M[2][2]; + + // check the diagonal + if (tr > 0) + { + s = Root(tr + (1 << 15)) * 181; /// argh.. == << 7.5 ... + quat->w = s / 2; + s = ((1 << (14 + 12)) / s) << 3; // hmph - avoid overflow... + quat->x = ((m->M[1][2] - m->M[2][1]) * s) >> 15; + quat->y = ((m->M[2][0] - m->M[0][2]) * s) >> 15; + quat->z = ((m->M[0][1] - m->M[1][0]) * s) >> 15; + } + else + { + // diagonal is negative + i = 0; + if (m->M[1][1] > m->M[0][0]) i = 1; + if (m->M[2][2] > m->M[i][i]) i = 2; + j = nxt[i]; + k = nxt[j]; + + s = Root((m->M[i][i] - (m->M[j][j] + m->M[k][k])) + (1 << 15)) * 181 ; + + q[i] = s / 2; + + if (s != 0) + s = ((1 << (14 + 12)) / s) << 3; // hmph - avoid overflow... + + q[3] = ((m->M[j][k] - m->M[k][j]) * s) >> 15; + q[j] = ((m->M[i][j] + m->M[j][i]) * s) >> 15; + q[k] = ((m->M[i][k] + m->M[k][i]) * s) >> 15; + + quat->x = q[0]; + quat->y = q[1]; + quat->z = q[2]; + quat->w = q[3]; + } +} + +//*************************************************************************************************** +void QuatToMatrixInteger(QuatInt *quat, Matrix33 *m) +{ + SLONG wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + + // calculate coefficients + x2 = quat->x + quat->x; y2 = quat->y + quat->y; + z2 = quat->z + quat->z; + xx = (quat->x * x2) >> 15; xy = (quat->x * y2) >> 15; xz = (quat->x * z2) >> 15; + yy = (quat->y * y2) >> 15; yz = (quat->y * z2) >> 15; zz = (quat->z * z2) >> 15; + wx = (quat->w * x2) >> 15; wy = (quat->w * y2) >> 15; wz = (quat->w * z2) >> 15; + + m->M[0][0] = (1 << 15) - (yy + zz); m->M[1][0] = xy - wz; + m->M[2][0] = xz + wy; + + m->M[0][1] = xy + wz; m->M[1][1] = (1 << 15) - (xx + zz); + m->M[2][1] = yz - wx; + + m->M[0][2] = xz - wy; m->M[1][2] = yz + wx; + m->M[2][2] = (1 << 15) - (xx + yy); +} + +//*************************************************************************************************** +//! er.. this should be loaded in.... + +SWORD acos_table[1025]; // only half of it! +BOOL acos_table_init = FALSE; + +void BuildACosTable() +{ + SLONG c0; + + for (c0 = 0; c0 < 1025; c0 ++) + { + acos_table[c0] = SLONG(acos(float(c0) / 1025.f) / (2 * 3.1415926) * 2047); + } + + acos_table_init = TRUE; +} + +//*************************************************************************************************** +#define DELTA_INT 1638 + +void QuatSlerpInteger(QuatInt *from, QuatInt *to, SLONG tween, QuatInt *res) +{ + SLONG to1[4]; +// double omega, cosom, sinom; + SLONG omega, cosom, sinom; + SLONG scale0, scale1; + + //! shouldn't be done here... + if (!acos_table_init) + BuildACosTable(); + + // calc cosine + cosom = (from->x * to->x + from->y * to->y + from->z * to->z + from->w * to->w) >> 15; + + // adjust signs (if necessary) + if ( cosom < 0 ) + { + cosom = -cosom; + + to1[0] = -to->x; + to1[1] = -to->y; + to1[2] = -to->z; + to1[3] = -to->w; + } + else + { + to1[0] = to->x; + to1[1] = to->y; + to1[2] = to->z; + to1[3] = to->w; + } + + // calculate coefficients + + if (((1 << 15) - cosom) > DELTA_INT) + { + // standard case (slerp) +// omega = SLONG((acos(float(cosom) / 32768) / (2 * 3.1415926)) * 2047); + + ASSERT(cosom >= 0); + ASSERT(cosom <= 32768); + omega = acos_table[cosom / 32]; + + sinom = SIN(omega); + scale0 = (SIN(((256 - tween) * omega) / 256) * 256) / sinom; + scale1 = (SIN(((tween ) * omega) / 256) * 256) / sinom; + + } + else + { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 256 - tween; + scale1 = tween; + } + + // calculate final values + res->x = (scale0 * from->x + scale1 * to1[0]) >> 8; + res->y = (scale0 * from->y + scale1 * to1[1]) >> 8; + res->z = (scale0 * from->z + scale1 * to1[2]) >> 8; + res->w = (scale0 * from->w + scale1 * to1[3]) >> 8; +} + +//*************************************************************************************************** +void cmat_to_mat(CMatrix33 *cm, Matrix33 *m) +{ + m->M[0][0] = ((cm->M[0] & CMAT0_MASK) >> 20) << 6; + m->M[0][1] = ((cm->M[0] & CMAT1_MASK) >> 10) << 6; + m->M[0][2] = ((cm->M[0] & CMAT2_MASK) >> 00) << 6; + + m->M[1][0] = ((cm->M[1] & CMAT0_MASK) >> 20) << 6; + m->M[1][1] = ((cm->M[1] & CMAT1_MASK) >> 10) << 6; + m->M[1][2] = ((cm->M[1] & CMAT2_MASK) >> 00) << 6; + + m->M[2][0] = ((cm->M[2] & CMAT0_MASK) >> 20) << 6; + m->M[2][1] = ((cm->M[2] & CMAT1_MASK) >> 10) << 6; + m->M[2][2] = ((cm->M[2] & CMAT2_MASK) >> 00) << 6; + + // this is pretty damn shite. + if (m->M[0][0] >= 32768) m->M[0][0] -= 65536; + if (m->M[0][1] >= 32768) m->M[0][1] -= 65536; + if (m->M[0][2] >= 32768) m->M[0][2] -= 65536; + if (m->M[1][0] >= 32768) m->M[1][0] -= 65536; + if (m->M[1][1] >= 32768) m->M[1][1] -= 65536; + if (m->M[1][2] >= 32768) m->M[1][2] -= 65536; + if (m->M[2][0] >= 32768) m->M[2][0] -= 65536; + if (m->M[2][1] >= 32768) m->M[2][1] -= 65536; + if (m->M[2][2] >= 32768) m->M[2][2] -= 65536; +} + +//*************************************************************************************************** +BOOL check_isonormal_integer(Matrix33 &m) +{ + // check handedness + SLONG x = (m.M[0][1] * m.M[1][2] - m.M[0][2] * m.M[1][1]) >> 15; + SLONG y = (m.M[0][2] * m.M[1][0] - m.M[0][0] * m.M[1][2]) >> 15; + SLONG z = (m.M[0][0] * m.M[1][1] - m.M[0][1] * m.M[1][0]) >> 15; + + if ((abs(x - m.M[2][0]) > 1000) || + (abs(y - m.M[2][1]) > 1000) || + (abs(z - m.M[2][2]) > 1000)) + return FALSE; + + return TRUE; +} + +//*************************************************************************************************** +void QUATERNION_BuildTweenInteger(struct Matrix33 *dest,struct CMatrix33 *cm1,struct CMatrix33 *cm2,SLONG tween) +{ + // * construct the quaternions from the compressed integer matrices + // * SLERP the quaternions using the tween value + // * construct a non-compressed integer matrix from the resulting quaternion + + Matrix33 m1, m2; + + cmat_to_mat(cm1, &m1); + cmat_to_mat(cm2, &m2); + + BOOL a, b; + a = check_isonormal_integer(m1); + b = check_isonormal_integer(m2); + + // ok - if handedness is wrong, flip before and afterwards. + // only if both src and dest handedness is the same.. + if (a == b) + { + if (!a) + { + // flip + m1.M[2][0] = -m1.M[2][0]; + m1.M[2][1] = -m1.M[2][1]; + m1.M[2][2] = -m1.M[2][2]; + m2.M[2][0] = -m2.M[2][0]; + m2.M[2][1] = -m2.M[2][1]; + m2.M[2][2] = -m2.M[2][2]; + } + + QuatInt q1, q2, q3; + + MatrixToQuatInteger(&m1, &q1); + MatrixToQuatInteger(&m2, &q2); + + QuatSlerpInteger(&q1, &q2, tween, &q3); + QuatToMatrixInteger(&q3, dest); + +// QuatToMatrixInteger(&q1, dest); + + if (!a) + { + // flip + dest->M[2][0] = -dest->M[2][0]; + dest->M[2][1] = -dest->M[2][1]; + dest->M[2][2] = -dest->M[2][2]; + } + + return; + } + + // fallback for dodgy matrices + build_tween_matrix(dest, cm1, cm2, tween); + normalise_matrix_rows(dest); + +} + +//*************************************************************************************************** +//*************************************************************************************************** diff --git a/fallen/DDEngine/Source/Temp.cpp b/fallen/DDEngine/Source/Temp.cpp new file mode 100644 index 0000000..2f42bf6 --- /dev/null +++ b/fallen/DDEngine/Source/Temp.cpp @@ -0,0 +1,2410 @@ +#ifdef TARGET_DC +#error Why is this included in a DC build? Bad person.... +#endif + + + +#include "Engine.h" +#include "crinkle.h" + +#include "c:\fallen\editor\headers\primativ.hpp" +//#include "c:\fallen\editor\headers\building.hpp" +#include "c:\fallen\editor\headers\Edit.h" +//#include "c:\fallen\editor\headers\Engine.h" +#include "c:\fallen\editor\headers\Map.h" +#include "c:\fallen\editor\headers\prim_draw.h" +#include "c:\fallen\editor\headers\Thing.h" +#include "c:\fallen\headers\interact.h" +#include "c:\fallen\headers\FMatrix.h" +//#include "c:\fallen\editor\headers\collide.hpp" + +#define POLY_FLAG_TEXTURED (1<<1) +#define POLY_FLAG_MASKED (1<<2) +#define POLY_FLAG_DOUBLESIDED (1<<6) + +SVECTOR_F dx_global_res[5560]; //max points per object? + +struct DXMaterial +{ + float R, + G, + B; + +}; + +extern SLONG material_count; +extern DXMaterial dx_materials[200]; +extern SVECTOR_F dx_prim_points[MAX_PRIM_POINTS]; + +#define SHOE_SIZE 8 +//--------------------------------------------------------------- +void matrix_mult33(struct Matrix33* result,struct Matrix33* mat1,struct Matrix33* mat2) +{ + result->M[0][0] = ((mat1->M[0][0]*mat2->M[0][0])+(mat1->M[0][1]*mat2->M[1][0])+(mat1->M[0][2]*mat2->M[2][0]))>>15; + result->M[0][1] = ((mat1->M[0][0]*mat2->M[0][1])+(mat1->M[0][1]*mat2->M[1][1])+(mat1->M[0][2]*mat2->M[2][1]))>>15; + result->M[0][2] = ((mat1->M[0][0]*mat2->M[0][2])+(mat1->M[0][1]*mat2->M[1][2])+(mat1->M[0][2]*mat2->M[2][2]))>>15; + result->M[1][0] = ((mat1->M[1][0]*mat2->M[0][0])+(mat1->M[1][1]*mat2->M[1][0])+(mat1->M[1][2]*mat2->M[2][0]))>>15; + result->M[1][1] = ((mat1->M[1][0]*mat2->M[0][1])+(mat1->M[1][1]*mat2->M[1][1])+(mat1->M[1][2]*mat2->M[2][1]))>>15; + result->M[1][2] = ((mat1->M[1][0]*mat2->M[0][2])+(mat1->M[1][1]*mat2->M[1][2])+(mat1->M[1][2]*mat2->M[2][2]))>>15; + result->M[2][0] = ((mat1->M[2][0]*mat2->M[0][0])+(mat1->M[2][1]*mat2->M[1][0])+(mat1->M[2][2]*mat2->M[2][0]))>>15; + result->M[2][1] = ((mat1->M[2][0]*mat2->M[0][1])+(mat1->M[2][1]*mat2->M[1][1])+(mat1->M[2][2]*mat2->M[2][1]))>>15; + result->M[2][2] = ((mat1->M[2][0]*mat2->M[0][2])+(mat1->M[2][1]*mat2->M[1][2])+(mat1->M[2][2]*mat2->M[2][2]))>>15; +} + +void rotate_obj(SWORD xangle,SWORD yangle,SWORD zangle, Matrix33 *r3) +{ + SLONG sinx, cosx, siny, cosy, sinz, cosz; + SLONG cxcz,sysz,sxsycz,sxsysz,sysx,cxczsy,sxsz,cxsysz,czsx,cxsy,sycz,cxsz; + + sinx = SIN(xangle & (2048-1)) >>1; // 15's + cosx = COS(xangle & (2048-1)) >>1; + siny = SIN(yangle & (2048-1)) >>1; + cosy = COS(yangle & (2048-1)) >>1; + sinz = SIN(zangle & (2048-1)) >>1; + cosz = COS(zangle & (2048-1)) >>1; + + cxsy = (cosx*cosy); // 30's + sycz = (cosy*cosz); + cxcz = (cosx*cosz); + cxsz = (cosx*sinz); + czsx = (cosz*sinx); + sysx = (cosy*sinx); + sysz = (cosy*sinz); + sxsz = (sinx*sinz); + sxsysz = (sxsz>>15)*siny; + cxczsy = (cxcz>>15)*siny; + cxsysz = ((cosx*siny)>>15)*sinz; + sxsycz = (czsx>>15)*siny; + + // Define rotation matrix r3. + + r3->M[0][0] = (sycz)>>15; // 14's + r3->M[0][1] = (-sysz)>>15; + r3->M[0][2] = siny; + r3->M[1][0] = (sxsycz+cxsz)>>15; + r3->M[1][1] = (cxcz-sxsysz)>>15; + r3->M[1][2] = (-sysx)>>15; + r3->M[2][0] = (sxsz-cxczsy)>>15; + r3->M[2][1] = (cxsysz+czsx)>>15; + r3->M[2][2] = (cxsy)>>15; +} + +struct QuickMap +{ + SWORD Prim; + SWORD Texture; + SWORD Bright; + SWORD Thing; +}; + + + + +struct TinyXZ radius_pool[MAX_RADIUS*4*MAX_RADIUS*2]; +struct TinyXZ *radius_ptr[MAX_RADIUS+2]; + +void build_radius_info(void) +{ + SBYTE *grid; + SLONG dx,dz; + struct TinyXZ *ptr_rad; + SLONG actual_radius,radius,radius_offset,old_radius=0; + SLONG angle; + SLONG sum_count=0; + SLONG count=0; + + ptr_rad=radius_pool; + + + grid=(SBYTE*)MemAlloc((MAX_RADIUS+1)*(MAX_RADIUS+1)*4); + if(grid) + { + + for(radius=(MAX_RADIUS<<2);radius>3;radius--) + { + if((radius>>2)!=old_radius) + { + old_radius=radius>>2; +// LogText(" radius %d max_radius %d \n",radius>>2,MAX_RADIUS); + radius_ptr[(radius>>2)]=ptr_rad; + + } + for(angle=0;angle<2048;angle+=4) + { + for(radius_offset=-4;radius_offset<4;radius_offset++) + { + + dx=(SIN(angle)*(radius+radius_offset))>>(16+2); + dz=(COS(angle)*(radius+radius_offset))>>(16+2); + actual_radius=Root(SDIST2(dx,dz)); + if(actual_radius==(radius>>2)) + { + if(grid[(dx+MAX_RADIUS)+(dz+MAX_RADIUS)*(MAX_RADIUS*2)]!=-1) + { + grid[(dx+MAX_RADIUS)+(dz+MAX_RADIUS)*(MAX_RADIUS*2)]=-1; + ptr_rad->Dx=dx; + ptr_rad->Dz=dz; + ptr_rad->Angle=angle; + ptr_rad++; + } + } + } + } + } + radius_ptr[0]=ptr_rad; + MemFree(grid); + } + for(radius=1;radius",radius); + ptr_rad=radius_ptr[radius]; + count=0; + while(ptr_radAngle,ptr_rad->Dx,ptr_rad->Dz); + ptr_rad++; + count++; + } + sum_count+=count; +// LogText("\n"); + } +// LogText("count=%d sum %d\n",count,sum_count); +} + +DXMaterial dx_materials[200]= +{ + {0,0,0} +}; + +void setup_anim_stuff(void) +{ +#ifdef EDITOR +extern SLONG key_frame_count,current_element; + current_element = 0; + key_frame_count = 0; +#endif + if(the_elements) + MemFree(the_elements); + the_elements = (KeyFrameElement*)MemAlloc(MAX_NUMBER_OF_ELEMENTS*sizeof(KeyFrameElement)); +} + +//--------------------------------------------------------------- + +void reset_anim_stuff(void) +{ + //if(test_chunk) + { + test_chunk.MultiObject=0; + test_chunk.ElementCount=0; + } + if(the_elements) + MemFree(the_elements); +} + + +void load_anim(MFFileHandle file_handle,Anim *the_anim,KeyFrameChunk *the_chunk) +{ + CBYTE anim_name[ANIM_NAME_SIZE]; + SLONG anim_flags, + c0, + frame_count, + frame_id, + tween_step; + KeyFrame *the_frame; + SWORD chunk_id; + SWORD fixed=0; + CBYTE version=0; + + + FileRead(file_handle,&version,1); + + if(version==0||version>20) + { + anim_name[0]=version; + FileRead(file_handle,&anim_name[1],ANIM_NAME_SIZE-1); + version=0; + } + else + FileRead(file_handle,anim_name,ANIM_NAME_SIZE); + + + FileRead(file_handle,&anim_flags,sizeof(anim_flags)); + FileRead(file_handle,&frame_count,sizeof(frame_count)); + the_anim->SetAnimName(anim_name); + for(c0=0;c00) + FileRead(file_handle,&fixed,sizeof(fixed)); + + the_frame = &the_chunk->KeyFrames[frame_id]; + the_frame->TweenStep = tween_step; + the_frame->Fixed = fixed; + the_frame->Fight = 0; + if(version>1) + { + struct FightCol *fcol,*fcol_prev=0; + SLONG count,c0; + + FileRead(file_handle,&count,sizeof(count)); +// LogText(" fight count load = %d \n",count); + + for(c0=0;c0Fight=fcol; + } + else + { + fcol_prev->Next=fcol; + } + fcol_prev=fcol; + } + } + } + the_anim->AddKeyFrame(the_frame); + the_frame->Fight=0; + } + the_anim->SetAnimFlags(anim_flags); + if(anim_flags&ANIM_LOOP) + the_anim->StartLooping(); + +} + +//--------------------------------------------------------------- + +//--------------------------------------------------------------- +Anim *current_anim; + +void create_anim(Anim **the_list) +{ + CBYTE text[32]; + Anim *next_anim, + *the_anim; + + + the_anim = MFnew(); + if(the_anim) + { + // anim_count++; + // sprintf(text,"New Anim %d",anim_count); +// the_anim->SetAnimName(text); + if(*the_list) + { + next_anim = *the_list; + while(1) + { + if(next_anim->GetNextAnim()) + next_anim = next_anim->GetNextAnim(); + else + break; + } + next_anim->SetNextAnim(the_anim); + the_anim->SetLastAnim(next_anim); + } + else + { + *the_list = the_anim; + } + current_anim = the_anim; + } +} + +//--------------------------------------------------------------- +void load_body_part_info(MFFileHandle file_handle,SLONG version,KeyFrameChunk *the_chunk) +{ + SLONG c0,c1; + SLONG no_people,no_body_bits,string_len; + + FileRead(file_handle,&no_people,sizeof(SLONG)); + + FileRead(file_handle,&no_body_bits,sizeof(SLONG)); + + FileRead(file_handle,&string_len,sizeof(SLONG)); + + for(c0=0;c0PeopleNames[c0],string_len); + for(c1=0;c1PeopleTypes[c0].BodyPart[c1],sizeof(UBYTE)); + } +} + +void load_all_anims(KeyFrameChunk *the_chunk,Anim **anim_list) +{ +//#ifdef EDITOR + SLONG anim_count,version, + c0; + MFFileHandle file_handle; + + + file_handle = FileOpen(the_chunk->ANMName); + if(file_handle!=FILE_OPEN_ERROR) + { + FileRead(file_handle,&anim_count,sizeof(anim_count)); + if(anim_count<0) + { + version=anim_count; + + FileRead(file_handle,&anim_count,sizeof(anim_count)); + + load_body_part_info(file_handle,version,the_chunk); + } + for(c0=0;c0X; +// dy=l_y-input->Y; +// dz=l_z-input->Z; + + dx=-128; + dy=128; + dz=128; + +extern SLONG calc_height_at(SLONG x,SLONG z); + alt=calc_height_at(input->X,input->Z); + + if(dx) + { + m=(dy<<8)/dx; + + if(abs(m)>65536) + { + m>>=8; + c=input->Y-((m*input->X)); + if(m) + output->X=((alt-c))/m; + } + else + { + c=input->Y-((m*input->X)>>8); + if(m) + output->X=((alt-c)<<8)/m; + } + } + else + { + output->X=input->X; + } + + if(dz) + { + m=(dy<<8)/dz; + + if(abs(m)>65536) + { + m>>=8; + c=input->Y-((m*input->Z)); + if(m) + output->Z=((alt-c))/m; + } + else + { + c=input->Y-((m*input->Z)>>8); + if(m) + output->Z=((alt-c)<<8)/m; + } + } + else + { + output->Z=input->Z; + } + + //output->X=input->X; + //output->Z=input->Z; + + output->Y=calc_height_at(output->X,output->Z); + + return(0); +} + +SLONG points_clockwise(SLONG p0,SLONG p1,SLONG p2) +{ + float res; + float vx,vy,wx,wy,z; + + vx=dx_global_res[p1].X-dx_global_res[p0].X; + wx=dx_global_res[p2].X-dx_global_res[p1].X; + vy=dx_global_res[p1].Y-dx_global_res[p0].Y; + wy=dx_global_res[p2].Y-dx_global_res[p1].Y; + + z=vx*wy-vy*wx; + + if(z>0.0) + return 1; + else + return 0; + +} + +SLONG e_draw_a_facet_at(UWORD building_object, UWORD f_building, UWORD facet, SLONG x,SLONG y,SLONG z) +{ + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + ULONG flag_and,flag_or; + SLONG c0; + struct BuildingFacet *p_facet; + struct FBuilding *p_building; + SLONG sp,ep; + SLONG az; + SLONG col=0,cor=0,cob=0,cot=0,total=0; + SLONG best_z=9999999; + SLONG min_z=9999999,max_z=-9999999; + SLONG first_face=1; + + SLONG facet_flags; + SLONG offset_z=0; + SLONG list; + + float average_z, + f_x,f_y,f_z, + r,g,b, + shade, + *rgb; + BucketQuad *the_quad; + BucketTri *the_tri; + D3DTLVERTEX *the_vertex; + SVECTOR_F temp; + + float max_height; + + p_building = &building_list [f_building]; + p_facet = &building_facets[facet]; + facet_flags = p_facet->FacetFlags; + + UBYTE point_order[4] = {0, 1, 3, 2}; + + /* + + // + // Draw the normals of all the points. + // + + { + SLONG i; + SLONG x1, y1, z1; + SLONG x2, y2, z2; + + for (i = p_facet->StartPoint; i < p_facet->EndPoint; i++) + { + x1 = prim_points[i].X + x; + y1 = prim_points[i].Y + y; + z1 = prim_points[i].Z + z; + + x2 = x1 + (prim_normal[i].X >> 3); + y2 = y1 + (prim_normal[i].Y >> 3); + z2 = z1 + (prim_normal[i].Z >> 3); + + e_draw_3d_line_col_sorted( + x1, y1, z1, + x2, y2, z2, + 128, 130, 150); + } + } + + + + for(c0=p_facet->StartFace4;c0EndFace4;c0++) + { + p_f4 = &prim_faces4[c0]; + + if (p_f4->FaceFlags & FACE_FLAG_WALKABLE) + { + SLONG i; + SLONG p1; + SLONG p2; + + for (i = 0; i < 4; i++) + { + if (p_f4->FaceFlags & (FACE_FLAG_SLIDE_EDGE << i)) + { + p1 = p_f4->Points[point_order[(i + 0) & 0x3]]; + p2 = p_f4->Points[point_order[(i + 1) & 0x3]]; + + e_draw_3d_line( + prim_points[p1].X + x, + prim_points[p1].Y + y, + prim_points[p1].Z + z, + prim_points[p2].X + x, + prim_points[p2].Y + y, + prim_points[p2].Z + z); + } + } + } + } +*/ + + p_f4 = &prim_faces4[p_facet->StartFace4]; + p_f3 = &prim_faces3[p_facet->StartFace3]; + + // + // If we are indoors, then we only draw polys that are lower than + // the storey we are currently in. + // + + if (GAME_FLAGS & GF_INDOORS) + { + // + // Add on a little bit just to make sure! + // + + max_height = (float) INDOORS_HEIGHT_CEILING; + max_height += 128.0F; + + if (p_building->BuildingType == BUILDING_TYPE_CRATE_IN) + { + // + // Always draw all of it. + // + + max_height = (float) INFINITY; + } + else + if (facet_flags & FACET_FLAG_ROOF) + { + // + // Don't draw roofs inside buildings. + // + + return best_z; // Best zed is very far away! + } + else + if (p_building->BuildingType == BUILDING_TYPE_WAREHOUSE) + { + // + // Draw an extra storeys worth outside. + // + + max_height += 256.0F; + } + } + else + { + // + // Draw everything if we are not indoors. + // + + max_height = (float) INFINITY; + } + + if(facet_flags&FACET_FLAG_ROOF) + { + first_face=0; + offset_z=-50; + } + + sp = p_facet->StartPoint; + ep = p_facet->EndPoint; + + f_x = (float)x; + f_y = (float)y; + f_z = (float)z; + +// LogText(" facet sp ep %d %d \n",sp,ep); + for(c0=sp;c0EndFace4) + for(c0=p_facet->StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + if(BUCKETS_FULL) + goto exit; + + p0 = p_f4->Points[0]-sp; + p1 = p_f4->Points[1]-sp; + p2 = p_f4->Points[2]-sp; + p3 = p_f4->Points[3]-sp; + ASSERT(p0>=0&&p0=0&&p1=0&&p2=0&&p3DrawFlags&POLY_FLAG_DOUBLESIDED) || points_clockwise(p0,p1,p2)) + { + + + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]&global_flags[p3]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]|global_flags[p3]; + + if( (!(flag_and & EF_CLIPFLAGS))&&((flag_or&EF_BEHIND_YOU)==0)) + { + the_quad = GET_BUCKET(BucketQuad); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[p0].X; + the_vertex->sy = dx_global_res[p0].Y; + the_vertex->sz = dx_global_res[p0].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + the_vertex++; + the_vertex->sx = dx_global_res[p1].X; + the_vertex->sy = dx_global_res[p1].Y; + the_vertex->sz = dx_global_res[p1].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + the_vertex++; + the_vertex->sx = dx_global_res[p2].X; + the_vertex->sy = dx_global_res[p2].Y; + the_vertex->sz = dx_global_res[p2].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + the_vertex++; + the_vertex->sx = dx_global_res[p3].X; + the_vertex->sy = dx_global_res[p3].Y; + the_vertex->sz = dx_global_res[p3].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + if(p_f4->DrawFlags&POLY_FLAG_MASKED) + { + list = MASK_LIST_1; + vertex_pool[current_vertex+0].tu = p_f4->UV[0][0]*TEXTURE_MUL; + vertex_pool[current_vertex+0].tv = p_f4->UV[0][1]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tu = p_f4->UV[1][0]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tv = p_f4->UV[1][1]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tu = p_f4->UV[2][0]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tv = p_f4->UV[2][1]*TEXTURE_MUL; + vertex_pool[current_vertex+3].tu = p_f4->UV[3][0]*TEXTURE_MUL; + vertex_pool[current_vertex+3].tv = p_f4->UV[3][1]*TEXTURE_MUL; + } + else if(p_f4->DrawFlags&POLY_FLAG_TEXTURED) + { + list = p_f4->TexturePage; + vertex_pool[current_vertex+0].tu = p_f4->UV[0][0]*TEXTURE_MUL; + vertex_pool[current_vertex+0].tv = p_f4->UV[0][1]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tu = p_f4->UV[1][0]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tv = p_f4->UV[1][1]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tu = p_f4->UV[2][0]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tv = p_f4->UV[2][1]*TEXTURE_MUL; + vertex_pool[current_vertex+3].tu = p_f4->UV[3][0]*TEXTURE_MUL; + vertex_pool[current_vertex+3].tv = p_f4->UV[3][1]*TEXTURE_MUL; + + shade = p_f4->Bright[0]*SHADE_MUL; + vertex_pool[current_vertex+0].color = D3DRGB(1.0*shade,1.0*shade,1.0*shade); + shade = p_f4->Bright[1]*SHADE_MUL; + vertex_pool[current_vertex+1].color = D3DRGB(1.0*shade,1.0*shade,1.0*shade); + shade = p_f4->Bright[2]*SHADE_MUL; + vertex_pool[current_vertex+2].color = D3DRGB(1.0*shade,1.0*shade,1.0*shade); + shade = p_f4->Bright[3]*SHADE_MUL; + vertex_pool[current_vertex+3].color = D3DRGB(1.0*shade,1.0*shade,1.0*shade); + } + else + { + list = COLOUR_LIST_1; + r = dx_materials[p_f4->Col].R; + g = dx_materials[p_f4->Col].G; + b = dx_materials[p_f4->Col].B; + shade = p_f4->Bright[0]*SHADE_MUL; + vertex_pool[current_vertex+0].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f4->Bright[1]*SHADE_MUL; + vertex_pool[current_vertex+1].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f4->Bright[2]*SHADE_MUL; + vertex_pool[current_vertex+2].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f4->Bright[3]*SHADE_MUL; + vertex_pool[current_vertex+3].color = D3DRGB(r*shade,g*shade,b*shade); + } + + // + // Draw a crinkle! + // + + if (Keys[KB_Y]) + { + SLONG point[4]; + + point[0] = p0; + point[1] = p1; + point[2] = p2; + point[3] = p3; + + CRINKLE_do(0, 1.0, &vertex_pool[current_vertex], point, list, (SLONG) average_z); + } + else + { + + the_quad->P[0] = current_vertex++; + the_quad->P[1] = current_vertex++; + the_quad->P[2] = current_vertex++; + the_quad->P[3] = current_vertex++; + + average_z = ( + dx_global_res[p0].Z, + dx_global_res[p1].Z, + dx_global_res[p2].Z, + dx_global_res[p3].Z + ) * 256.0f; + + add_bucket(&the_quad->BucketHeader,BUCKET_QUAD,list,(SLONG)average_z); + + if(p_f4->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + the_quad = GET_BUCKET(BucketQuad); + + the_quad->P[0] = current_vertex-2; + the_quad->P[1] = current_vertex-1; + the_quad->P[2] = current_vertex-4; + the_quad->P[3] = current_vertex-3; + + add_bucket(&the_quad->BucketHeader,BUCKET_QUAD,list,(SLONG)average_z); + } + } + } + } + + p_f4++; + } + + if(p_facet->EndFace3) + for(c0=p_facet->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + if(BUCKETS_FULL) + goto exit; + + p0 = p_f3->Points[0]-sp; + p1 = p_f3->Points[1]-sp; + p2 = p_f3->Points[2]-sp; + + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + the_tri = GET_BUCKET(BucketTri); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[p0].X; + the_vertex->sy = dx_global_res[p0].Y; + the_vertex->sz = dx_global_res[p0].Z; +// the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f3->UV[0][0]*TEXTURE_MUL; + the_vertex->tv = p_f3->UV[0][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + the_vertex++; + the_vertex->sx = dx_global_res[p1].X; + the_vertex->sy = dx_global_res[p1].Y; + the_vertex->sz = dx_global_res[p1].Z; +// the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f3->UV[1][0]*TEXTURE_MUL; + the_vertex->tv = p_f3->UV[1][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + the_vertex++; + the_vertex->sx = dx_global_res[p2].X; + the_vertex->sy = dx_global_res[p2].Y; + the_vertex->sz = dx_global_res[p2].Z; +// the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f3->UV[2][0]*TEXTURE_MUL; + the_vertex->tv = p_f3->UV[2][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + if(p_f3->DrawFlags&POLY_FLAG_MASKED) + { + list = MASK_LIST_1; + vertex_pool[current_vertex+0].tu = p_f3->UV[0][0]*TEXTURE_MUL; + vertex_pool[current_vertex+0].tv = p_f3->UV[0][1]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tu = p_f3->UV[1][0]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tv = p_f3->UV[1][1]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tu = p_f3->UV[2][0]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tv = p_f3->UV[2][1]*TEXTURE_MUL; + } + else if(p_f3->DrawFlags&POLY_FLAG_TEXTURED) + { + list = p_f3->TexturePage; + vertex_pool[current_vertex+0].tu = p_f3->UV[0][0]*TEXTURE_MUL; + vertex_pool[current_vertex+0].tv = p_f3->UV[0][1]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tu = p_f3->UV[1][0]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tv = p_f3->UV[1][1]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tu = p_f3->UV[2][0]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tv = p_f3->UV[2][1]*TEXTURE_MUL; + + shade = p_f3->Bright[0]*SHADE_MUL; + vertex_pool[current_vertex+0].color = D3DRGB(1.0*shade,1.0*shade,1.0*shade); + shade = p_f3->Bright[1]*SHADE_MUL; + vertex_pool[current_vertex+1].color = D3DRGB(1.0*shade,1.0*shade,1.0*shade); + shade = p_f3->Bright[2]*SHADE_MUL; + vertex_pool[current_vertex+2].color = D3DRGB(1.0*shade,1.0*shade,1.0*shade); + } + else + { + list = COLOUR_LIST_1; + r = dx_materials[p_f3->Col].R; + g = dx_materials[p_f3->Col].G; + b = dx_materials[p_f3->Col].B; + shade = p_f3->Bright[0]*SHADE_MUL; + vertex_pool[current_vertex+0].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f3->Bright[1]*SHADE_MUL; + vertex_pool[current_vertex+1].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f3->Bright[2]*SHADE_MUL; + vertex_pool[current_vertex+2].color = D3DRGB(r*shade,g*shade,b*shade); + } + + the_tri->P[0] = current_vertex++; + the_tri->P[1] = current_vertex++; + the_tri->P[2] = current_vertex++; + + average_z = ( + dx_global_res[p0].Z, + dx_global_res[p1].Z, + dx_global_res[p2].Z + ) * 341.33f; + + add_bucket(&the_tri->BucketHeader,BUCKET_TRI,list,(SLONG)average_z); + + if(p_f3->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + the_tri = GET_BUCKET(BucketTri); + + the_tri->P[0] = current_vertex-2; + the_tri->P[1] = current_vertex-1; + the_tri->P[2] = current_vertex-3; + + add_bucket(&the_tri->BucketHeader,BUCKET_TRI,list,(SLONG)average_z); + } + } + p_f3++; + } +exit:; + + return(best_z); +} + +//--------------------------------------------------------------- + +void e_draw_a_building_at(UWORD building_o, UWORD building_f,SLONG x,SLONG y,SLONG z) +{ + SLONG index; + SLONG best_z=-999999,az; + + + index = building_objects[building_o].FacetHead; + while(index) + { + az = e_draw_a_facet_at(building_o, building_f, index, x, y, z); + if(best_zStartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + f_x = (float)x; + f_y = (float)y; + f_z = (float)z; + + for(c0=sp;c0EndFace4) + for(c0=p_obj->StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + if(BUCKETS_FULL) + goto exit; + + p0 = p_f4->Points[0]-sp; + p1 = p_f4->Points[1]-sp; + p2 = p_f4->Points[2]-sp; + p3 = p_f4->Points[3]-sp; + + if( (p_f4->DrawFlags&POLY_FLAG_DOUBLESIDED) || points_clockwise(p0,p1,p2)) + { + + + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]&global_flags[p3]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]|global_flags[p3]; + + if( (!(flag_and & EF_CLIPFLAGS))&&((flag_or&EF_BEHIND_YOU)==0)) + { + the_quad = GET_BUCKET(BucketQuad); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[p0].X; + the_vertex->sy = dx_global_res[p0].Y; + the_vertex->sz = dx_global_res[p0].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f4->UV[0][0]*TEXTURE_MUL; + the_vertex->tv = p_f4->UV[0][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + the_vertex++; + the_vertex->sx = dx_global_res[p1].X; + the_vertex->sy = dx_global_res[p1].Y; + the_vertex->sz = dx_global_res[p1].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f4->UV[1][0]*TEXTURE_MUL; + the_vertex->tv = p_f4->UV[1][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + the_vertex++; + the_vertex->sx = dx_global_res[p2].X; + the_vertex->sy = dx_global_res[p2].Y; + the_vertex->sz = dx_global_res[p2].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f4->UV[2][0]*TEXTURE_MUL; + the_vertex->tv = p_f4->UV[2][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + the_vertex++; + the_vertex->sx = dx_global_res[p3].X; + the_vertex->sy = dx_global_res[p3].Y; + the_vertex->sz = dx_global_res[p3].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f4->UV[3][0]*TEXTURE_MUL; + the_vertex->tv = p_f4->UV[3][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + if(p_f4->DrawFlags&POLY_FLAG_TEXTURED) + { + + } + else + { + /* + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->Col + ); + */ + } + the_quad->P[0] = current_vertex++; + the_quad->P[1] = current_vertex++; + the_quad->P[2] = current_vertex++; + the_quad->P[3] = current_vertex++; + + average_z = ( + dx_global_res[p0].Z, + dx_global_res[p1].Z, + dx_global_res[p2].Z, + dx_global_res[p3].Z + ) * 256.0f; + + add_bucket(&the_quad->BucketHeader,BUCKET_QUAD,p_f4->TexturePage,(SLONG)average_z); + + if(p_f4->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + the_quad = GET_BUCKET(BucketQuad); + + the_quad->P[0] = current_vertex-2; + the_quad->P[1] = current_vertex-1; + the_quad->P[2] = current_vertex-4; + the_quad->P[3] = current_vertex-3; + + add_bucket(&the_quad->BucketHeader,BUCKET_QUAD,p_f4->TexturePage,(SLONG)average_z); + } + } + } + + p_f4++; + } + + if(p_obj->EndFace3) + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + if(BUCKETS_FULL) + goto exit; + + p0 = p_f3->Points[0]-sp; + p1 = p_f3->Points[1]-sp; + p2 = p_f3->Points[2]-sp; + + if( (p_f3->DrawFlags&POLY_FLAG_DOUBLESIDED) || points_clockwise(p0,p1,p2)) + { + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + the_tri = GET_BUCKET(BucketTri); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[p0].X; + the_vertex->sy = dx_global_res[p0].Y; + the_vertex->sz = dx_global_res[p0].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f3->UV[0][0]*TEXTURE_MUL; + the_vertex->tv = p_f3->UV[0][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + the_vertex++; + the_vertex->sx = dx_global_res[p1].X; + the_vertex->sy = dx_global_res[p1].Y; + the_vertex->sz = dx_global_res[p1].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f3->UV[1][0]*TEXTURE_MUL; + the_vertex->tv = p_f3->UV[1][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + the_vertex++; + the_vertex->sx = dx_global_res[p2].X; + the_vertex->sy = dx_global_res[p2].Y; + the_vertex->sz = dx_global_res[p2].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->tu = p_f3->UV[2][0]*TEXTURE_MUL; + the_vertex->tv = p_f3->UV[2][1]*TEXTURE_MUL; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + /* + setPolyType3( + current_bucket_pool, + p_f3->DrawFlags + ); + */ + if(p_f3->DrawFlags&POLY_FLAG_TEXTURED) + { + + } + else + { + /* + setCol3 ( + (struct BucketQuad*)current_bucket_pool, + p_f3->Col + ); + */ + } + the_tri->P[0] = current_vertex++; + the_tri->P[1] = current_vertex++; + the_tri->P[2] = current_vertex++; + + average_z = ( + dx_global_res[p0].Z, + dx_global_res[p1].Z, + dx_global_res[p2].Z + ) * 341.33f; + + add_bucket(&the_tri->BucketHeader,BUCKET_TRI,p_f3->TexturePage,(SLONG)average_z); + + if(p_f3->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + the_tri = GET_BUCKET(BucketTri); + + the_tri->P[0] = current_vertex-2; + the_tri->P[1] = current_vertex-1; + the_tri->P[2] = current_vertex-3; + + add_bucket(&the_tri->BucketHeader,BUCKET_TRI,p_f3->TexturePage,(SLONG)average_z); + } + } + } + p_f3++; + } +exit:; +} + +//--------------------------------------------------------------- + +//void e_draw_prim_tween(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next,struct Matrix33 *rot_mat,ULONG shadow); +void e_draw_prim_tween(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct GameKeyFrameElement *anim_info,struct GameKeyFrameElement *anim_info_next,struct Matrix33 *rot_mat,ULONG shadow,SWORD dx,SWORD dy,SWORD dz); +/* +void e_draw_test_bloke(SLONG x,SLONG y,SLONG z,UBYTE anim,SLONG angle) +{ + SLONG c0,c1; + struct Matrix33 r_matrix; + struct MapThing *p_mthing; + + + + +void animate_bloke(void); + if(anim) + animate_bloke(); +extern MapThing man_thing; + p_mthing=&man_thing; + + p_mthing->X = x; + p_mthing->Y = y; + p_mthing->Z = z; + + rotate_obj ( + p_mthing->AngleX, + (p_mthing->AngleY+angle)&2047, + p_mthing->AngleZ, + &r_matrix + ); +extern KeyFrameChunk test_chunk; + if(p_mthing->AnimElements&&p_mthing->NextAnimElements) + { + for(c1=0,c0=prim_multi_objects[test_chunk.MultiObject].StartObject;c0<=prim_multi_objects[test_chunk.MultiObject].EndObject;c0++,c1++) + { + if(c1==1) + { +extern UBYTE store_pos; + store_pos = 1; + } + e_draw_prim_tween ( + c0, + p_mthing->X,p_mthing->Y,p_mthing->Z, + p_mthing->TweenStage, + &p_mthing->AnimElements[c1], + &p_mthing->NextAnimElements[c1], + &r_matrix,0,0,0 + ); + } + } +} +*/ +//--------------------------------------------------------------- + +void e_draw_figure(Thing *p_thing,DrawTween *draw_info,SLONG x,SLONG y,SLONG z) +{ + SLONG c0,c1; + Matrix33 r_matrix; + GameKeyFrameElement *anim_elements, + *next_anim_elements; + + SLONG dx=0,dy=0,dz=0; + SLONG x1,y1,z1,x2,y2,z2; + + // + // Find the lighting context for this thing. The e_draw_prim_tween() function + // calls LIGHT_get_point(). LIGHT_get_point returns the light on the given + // point in this context. + // + + LIGHT_get_context(THING_NUMBER(p_thing)); + + if(draw_info->CurrentFrame==0 || draw_info->NextFrame==0) + { + MSG_add("!!!!!!!!!!!!!!!!!!!!!!!!ERROR e_draw_figure"); + return; + } + + if(draw_info->Locked) + { + MSG_add("Locked animate %d \n",draw_info->Locked); + calc_sub_objects_position_global(draw_info->CurrentFrame,draw_info->NextFrame,0,draw_info->Locked,&x1,&y1,&z1); + calc_sub_objects_position_global(draw_info->CurrentFrame,draw_info->NextFrame,256,draw_info->Locked,&x2,&y2,&z2); + dx=-x2+x1; + dy=-y2+y1; + dz=-z2+z1; +// LogText(" figure start frame %d %d %d \n",x1+p_thing->WorldPos.X,y1+p_thing->WorldPos.Y,z1+p_thing->WorldPos.Z); +// LogText(" figure end frame %d %d %d \n",x2+p_thing->WorldPos.X,y2+p_thing->WorldPos.Y,z2+p_thing->WorldPos.Z); +// LogText(" dx dy dz %d %d %d \n",dx,dy,dz); + + + } + + + +// draw_info->TweenStage = draw_info->AnimTween; + anim_elements = draw_info->CurrentFrame->FirstElement; + if(draw_info->NextFrame) + next_anim_elements = draw_info->NextFrame->FirstElement; + else + next_anim_elements = anim_elements; + + + + rotate_obj ( + draw_info->Tilt, + draw_info->Angle, + draw_info->Roll, + &r_matrix + ); + + if(anim_elements && next_anim_elements) + { + SLONG ele_count,start_object; + + ele_count=draw_info->TheChunk->ElementCount; + start_object=prim_multi_objects[draw_info->TheChunk->MultiObject[0]].StartObject; + for(c1=0;c1TheChunk->PeopleTypes[draw_info->PersonID].BodyPart[c1]; + + e_draw_prim_tween ( + start_object+object_offset, + x,y+SHOE_SIZE,z, + draw_info->AnimTween, + &anim_elements[c1], + &next_anim_elements[c1], + &r_matrix, + draw_info->Flags&FLAGS_DRAW_SHADOW, + dx,dy,dz // funny bodge + ); +// test_draw(start_object+object_offset,AnimOffsetX,AnimOffsetY,100,AnimTween,the_element,the_next_element,&r_matrix); + +// local_object_flags=0; + } + } +} + +//--------------------------------------------------------------- + +#define MAX_POINTS 1560 + +/* +struct SVECTOR +{ + SLONG X,Y,Z; +}; +*/ + +#define MAX_COLOURS 256 + +ULONG d3d_colour [MAX_COLOURS]; +ULONG d3d_specular[MAX_COLOURS]; + +void e_draw_prim_tween(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct GameKeyFrameElement *anim_info,struct GameKeyFrameElement *anim_info_next,struct Matrix33 *rot_mat,ULONG shadow,SWORD off_dx,SWORD off_dy,SWORD off_dz) +{ + float average_z, + bright[MAX_POINTS*3], + r,g,b, +// shade, + *rgb; + ULONG flag_and,flag_or; + SLONG p_index; + SLONG az, + c0, + dx,dy,dz, + flags[MAX_POINTS], + flags_shadow[MAX_POINTS], + i,j, + list, + sp,ep; + BucketQuad *the_quad; + BucketTri *the_tri; + D3DTLVERTEX *the_vertex; + KeyFrame *the_keyframe1, + *the_keyframe2; + M31 normal; + Matrix31 offset; + Matrix33 mat2; + Matrix33 mat_final; + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + SVECTOR temp, + temp_shadow; + SVECTOR_F res_shadow[MAX_POINTS], + temp_f, + temp_f_shadow; + GameCoord pos; + SLONG shade; + + SLONG red; + SLONG green; + SLONG blue; + + +// LogText(" draw prim tween %d \n",prim); + p_obj = &prim_objects[prim]; + p_f4 = &prim_faces4[p_obj->StartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + +// mat = &anim_info->Matrix; +// mat_next = &anim_info_next->Matrix; + + //move object "tweened quantity" , z&y flipped + + //LogText(" ANIMATE *** offset start %d %d %d ofset end %d %d %d, BODGE %d %d %d\n",anim_info->OffsetX,anim_info->OffsetY,anim_info->OffsetZ, + offset.M[0] = (anim_info->OffsetX+(((anim_info_next->OffsetX+off_dx-(anim_info->OffsetX))*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (anim_info->OffsetY+(((anim_info_next->OffsetY+off_dy-(anim_info->OffsetY))*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (anim_info->OffsetZ+(((anim_info_next->OffsetZ+off_dz-(anim_info->OffsetZ))*tween)>>8))>>TWEEN_OFFSET_SHIFT; + +void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x += temp.X; + y += temp.Y; + z += temp.Z; + + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + //create a temporary "tween" matrix between current and next + /* + for(i=0;i<3;i++) + { + for(j=0;j<3;j++) + { + mat2.M[i][j]=mat->M[i][j]+(((mat_next->M[i][j]-mat->M[i][j])*tween)>>8); + } + } + */ + build_tween_matrix(&mat2,&anim_info->CMatrix,&anim_info_next->CMatrix,tween); + normalise_matrix(&mat2); + + //apply local rotation matrix +void matrix_mult33(struct Matrix33* result,struct Matrix33* mat1,struct Matrix33* mat2); + matrix_mult33(&mat_final,rot_mat,&mat2); + + SET_M31 ( + &normal, + 0,-1,0 + ); + +void matrix_transform(struct Matrix31* result, struct Matrix33* trans,struct Matrix31* mat2); +SLONG calc_shadow_co_ord(struct SVECTOR *input,struct SVECTOR *output,SLONG l_x,SLONG l_y,SLONG l_z); + for(c0=sp;c0StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + if(BUCKETS_FULL) + goto exit; + + p0 = p_f4->Points[0]-sp; + p1 = p_f4->Points[1]-sp; + p2 = p_f4->Points[2]-sp; + p3 = p_f4->Points[3]-sp; + + if(shadow) + { + flag_and = flags_shadow[p0]&flags_shadow[p1]&flags_shadow[p2]&flags_shadow[p3]; + flag_or = flags_shadow[p0]|flags_shadow[p1]|flags_shadow[p2]|flags_shadow[p3]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + the_quad = GET_BUCKET(BucketQuad); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = res_shadow[p0].X; + the_vertex->sy = res_shadow[p0].Y; + the_vertex->sz = res_shadow[p0].Z-0.0005f; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = 0; + the_vertex->specular= 0; + + the_vertex++; + the_vertex->sx = res_shadow[p1].X; + the_vertex->sy = res_shadow[p1].Y; + the_vertex->sz = res_shadow[p1].Z-0.0005f; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB(0.0,0.0,0.0); + the_vertex->specular= 0; + + the_vertex++; + the_vertex->sx = res_shadow[p2].X; + the_vertex->sy = res_shadow[p2].Y; + the_vertex->sz = res_shadow[p2].Z-0.0005f; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB(0.0,0.0,0.0); + the_vertex->specular= 0; + + the_vertex++; + the_vertex->sx = res_shadow[p3].X; + the_vertex->sy = res_shadow[p3].Y; + the_vertex->sz = res_shadow[p3].Z-0.0005f; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB(0.0,0.0,0.0); + the_vertex->specular= 0; + + the_quad->P[0] = current_vertex++; + the_quad->P[1] = current_vertex++; + the_quad->P[2] = current_vertex++; + the_quad->P[3] = current_vertex++; + + average_z = ( + res_shadow[p0].Z, + res_shadow[p1].Z, + res_shadow[p2].Z, + res_shadow[p3].Z + ) * 256.0f; + + add_bucket(&the_quad->BucketHeader,BUCKET_QUAD,COLOUR_LIST_1,(SLONG)average_z); + } + } + + if( (p_f4->DrawFlags&POLY_FLAG_DOUBLESIDED) || points_clockwise(p0,p1,p2)) + { + flag_and = flags[p0]&flags[p1]&flags[p2]&flags[p3]; + flag_or = flags[p0]|flags[p1]|flags[p2]|flags[p3]; + + if( (!(flag_and & EF_CLIPFLAGS))&&((flag_or&EF_BEHIND_YOU)==0)) + { + the_quad = GET_BUCKET(BucketQuad); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[p0].X; + the_vertex->sy = dx_global_res[p0].Y; + the_vertex->sz = dx_global_res[p0].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + + the_vertex++; + the_vertex->sx = dx_global_res[p1].X; + the_vertex->sy = dx_global_res[p1].Y; + the_vertex->sz = dx_global_res[p1].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + + the_vertex++; + the_vertex->sx = dx_global_res[p2].X; + the_vertex->sy = dx_global_res[p2].Y; + the_vertex->sz = dx_global_res[p2].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + + the_vertex++; + the_vertex->sx = dx_global_res[p3].X; + the_vertex->sy = dx_global_res[p3].Y; + the_vertex->sz = dx_global_res[p3].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + + if(p_f4->DrawFlags&POLY_FLAG_TEXTURED) + { + list = p_f4->TexturePage; + vertex_pool[current_vertex+0].tu = p_f4->UV[0][0]*TEXTURE_MUL; + vertex_pool[current_vertex+0].tv = p_f4->UV[0][1]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tu = p_f4->UV[1][0]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tv = p_f4->UV[1][1]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tu = p_f4->UV[2][0]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tv = p_f4->UV[2][1]*TEXTURE_MUL; + vertex_pool[current_vertex+3].tu = p_f4->UV[3][0]*TEXTURE_MUL; + vertex_pool[current_vertex+3].tv = p_f4->UV[3][1]*TEXTURE_MUL; + + vertex_pool[current_vertex+0].color = d3d_colour[p0]; + vertex_pool[current_vertex+1].color = d3d_colour[p1]; + vertex_pool[current_vertex+2].color = d3d_colour[p2]; + vertex_pool[current_vertex+3].color = d3d_colour[p3]; + + vertex_pool[current_vertex+0].specular = d3d_specular[p0]; + vertex_pool[current_vertex+1].specular = d3d_specular[p1]; + vertex_pool[current_vertex+2].specular = d3d_specular[p2]; + vertex_pool[current_vertex+3].specular = d3d_specular[p3]; + + + } + else + { + SLONG r,g,b; + list = COLOUR_LIST_1; + + // + // The colour of each point. + // + r = ENGINE_palette[p_f4->Col].red; + g = ENGINE_palette[p_f4->Col].green; + b = ENGINE_palette[p_f4->Col].blue; + +// LogText(" draw fig col %d rgb %d %d %d \n",p_f4->Col,r,g,b); + + + #define P_BRIGHT_L 32 + #define P_BRIGHT 0 + //((32<<16)+(32<<8)+32) + + shade = p_f4->Bright[0]+P_BRIGHT_L;// * 256; + red = (r*shade)>>8; + green = (g*shade)>>8; + blue = (b*shade)>>8; + vertex_pool[current_vertex+0].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f4->Bright[1]+P_BRIGHT_L;// * 256; + red = (r*shade)>>8; + green = (g*shade)>>8; + blue = (b*shade)>>8; + vertex_pool[current_vertex+1].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f4->Bright[2]+P_BRIGHT_L;// * 256; + red = (r*shade)>>8; + green = (g*shade)>>8; + blue = (b*shade)>>8; + vertex_pool[current_vertex+2].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f4->Bright[3]+P_BRIGHT_L;// * 256; + red = (r*shade)>>8; + green = (g*shade)>>8; + blue = (b*shade)>>8; + vertex_pool[current_vertex+3].color = (red << 16) | (green << 8) | (blue << 0); + + vertex_pool[current_vertex+0].specular = P_BRIGHT; //d3d_specular[p0]; + vertex_pool[current_vertex+1].specular = P_BRIGHT; //d3d_specular[p1]; + vertex_pool[current_vertex+2].specular = P_BRIGHT; //d3d_specular[p2]; + vertex_pool[current_vertex+3].specular = P_BRIGHT; //d3d_specular[p3]; + /* + shade = p_f4->Bright[0] * SHADE_MUL * 256; + + red = (SLONG) (dx_materials[p_f4->Col].R * shade); + green = (SLONG) (dx_materials[p_f4->Col].G * shade); + blue = (SLONG) (dx_materials[p_f4->Col].B * shade); + + + + red *= (d3d_colour[p0] >> 0) & 0xff; + green *= (d3d_colour[p0] >> 8) & 0xff; + blue *= (d3d_colour[p0] >> 16) & 0xff; + + red >>= 8; + green >>= 8; + blue >>= 8; + + + vertex_pool[current_vertex+0].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f4->Bright[1] * SHADE_MUL * 256; + + red = (SLONG) (dx_materials[p_f4->Col].R * shade); + green = (SLONG) (dx_materials[p_f4->Col].G * shade); + blue = (SLONG) (dx_materials[p_f4->Col].B * shade); + + red *= (d3d_colour[p1] >> 0) & 0xff; + green *= (d3d_colour[p1] >> 8) & 0xff; + blue *= (d3d_colour[p1] >> 16) & 0xff; + + red >>= 8; + green >>= 8; + blue >>= 8; + + vertex_pool[current_vertex+1].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f4->Bright[2] * SHADE_MUL * 256; + + red = (SLONG) (dx_materials[p_f4->Col].R * shade); + green = (SLONG) (dx_materials[p_f4->Col].G * shade); + blue = (SLONG) (dx_materials[p_f4->Col].B * shade); + + red *= (d3d_colour[p2] >> 0) & 0xff; + green *= (d3d_colour[p2] >> 8) & 0xff; + blue *= (d3d_colour[p2] >> 16) & 0xff; + + red >>= 8; + green >>= 8; + blue >>= 8; + + vertex_pool[current_vertex+2].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f4->Bright[3] * SHADE_MUL * 256; + + red = (SLONG) (dx_materials[p_f4->Col].R * shade); + green = (SLONG) (dx_materials[p_f4->Col].G * shade); + blue = (SLONG) (dx_materials[p_f4->Col].B * shade); + + red *= (d3d_colour[p3] >> 0) & 0xff; + green *= (d3d_colour[p3] >> 8) & 0xff; + blue *= (d3d_colour[p3] >> 16) & 0xff; + + red >>= 8; + green >>= 8; + blue >>= 8; + + vertex_pool[current_vertex+3].color = (red << 16) | (green << 8) | (blue << 0); + + // + // Don't take face colour into account with the specular... + // + + vertex_pool[current_vertex+0].specular = d3d_specular[p0]; + vertex_pool[current_vertex+1].specular = d3d_specular[p1]; + vertex_pool[current_vertex+2].specular = d3d_specular[p2]; + vertex_pool[current_vertex+3].specular = d3d_specular[p3]; + */ + + + + /* + + r = dx_materials[p_f4->Col].R; + g = dx_materials[p_f4->Col].G; + b = dx_materials[p_f4->Col].B; + shade = p_f4->Bright[0]*SHADE_MUL; + vertex_pool[current_vertex+0].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f4->Bright[1]*SHADE_MUL; + vertex_pool[current_vertex+1].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f4->Bright[2]*SHADE_MUL; + vertex_pool[current_vertex+2].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f4->Bright[3]*SHADE_MUL; + vertex_pool[current_vertex+3].color = D3DRGB(r*shade,g*shade,b*shade); + + */ + } + + the_quad->P[0] = current_vertex++; + the_quad->P[1] = current_vertex++; + the_quad->P[2] = current_vertex++; + the_quad->P[3] = current_vertex++; + + average_z = ( + dx_global_res[p0].Z, + dx_global_res[p1].Z, + dx_global_res[p2].Z, + dx_global_res[p3].Z + ) * 256.0f; + + add_bucket(&the_quad->BucketHeader,BUCKET_QUAD,list,(SLONG)average_z); + } + } + p_f4++; + } + + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + if(BUCKETS_FULL) + goto exit; + + p0 = p_f3->Points[0]-sp; + p1 = p_f3->Points[1]-sp; + p2 = p_f3->Points[2]-sp; + + if(shadow) + { + flag_and = flags_shadow[p0]&flags_shadow[p1]&flags_shadow[p2]; + flag_or = flags_shadow[p0]|flags_shadow[p1]|flags_shadow[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + the_tri = GET_BUCKET(BucketTri); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = res_shadow[p0].X; + the_vertex->sy = res_shadow[p0].Y; + the_vertex->sz = res_shadow[p0].Z; +// the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB(0.0,0.0,0.0); + the_vertex->specular= 0; + + the_vertex++; + the_vertex->sx = res_shadow[p1].X; + the_vertex->sy = res_shadow[p1].Y; + the_vertex->sz = res_shadow[p1].Z; +// the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB(0.0,0.0,0.0); + the_vertex->specular= 0; + + the_vertex++; + the_vertex->sx = res_shadow[p2].X; + the_vertex->sy = res_shadow[p2].Y; + the_vertex->sz = res_shadow[p2].Z; +// the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB(0.0,0.0,0.0); + the_vertex->specular= 0; + + the_tri->P[0] = current_vertex++; + the_tri->P[1] = current_vertex++; + the_tri->P[2] = current_vertex++; + + average_z = ( + res_shadow[p0].Z, + res_shadow[p1].Z, + res_shadow[p2].Z + ) * 341.33f; + + add_bucket(&the_tri->BucketHeader,BUCKET_TRI,COLOUR_LIST_1,(SLONG)average_z); + } + } + + if( (p_f3->DrawFlags&POLY_FLAG_DOUBLESIDED) || points_clockwise(p0,p1,p2)) + { + flag_and = flags[p0]&flags[p1]&flags[p2]; + flag_or = flags[p0]|flags[p1]|flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + the_tri = GET_BUCKET(BucketTri); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[p0].X; + the_vertex->sy = dx_global_res[p0].Y; + the_vertex->sz = dx_global_res[p0].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + + the_vertex++; + the_vertex->sx = dx_global_res[p1].X; + the_vertex->sy = dx_global_res[p1].Y; + the_vertex->sz = dx_global_res[p1].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + + the_vertex++; + the_vertex->sx = dx_global_res[p2].X; + the_vertex->sy = dx_global_res[p2].Y; + the_vertex->sz = dx_global_res[p2].Z; + // the_vertex->rhw = 1.0f/the_vertex->sz; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + + if(p_f3->DrawFlags&POLY_FLAG_TEXTURED) + { + list = p_f3->TexturePage; + vertex_pool[current_vertex+0].tu = p_f3->UV[0][0]*TEXTURE_MUL; + vertex_pool[current_vertex+0].tv = p_f3->UV[0][1]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tu = p_f3->UV[1][0]*TEXTURE_MUL; + vertex_pool[current_vertex+1].tv = p_f3->UV[1][1]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tu = p_f3->UV[2][0]*TEXTURE_MUL; + vertex_pool[current_vertex+2].tv = p_f3->UV[2][1]*TEXTURE_MUL; + + + vertex_pool[current_vertex+0].color = d3d_colour[p0]; + vertex_pool[current_vertex+1].color = d3d_colour[p1]; + vertex_pool[current_vertex+2].color = d3d_colour[p2]; + + vertex_pool[current_vertex+0].specular = d3d_specular[p0]; + vertex_pool[current_vertex+1].specular = d3d_specular[p1]; + vertex_pool[current_vertex+2].specular = d3d_specular[p2]; + } + else + { + SLONG r,g,b; + r = ENGINE_palette[p_f3->Col].red; + g = ENGINE_palette[p_f3->Col].green; + b = ENGINE_palette[p_f3->Col].blue; + list = COLOUR_LIST_1; + +// LogText(" draw fig col %d rgb %d %d %d \n",p_f3->Col,r,g,b); + + + // + // The colour of each point. + // + + shade = p_f3->Bright[0]+P_BRIGHT_L;// * 256; + red = (r*shade)>>8; + green = (g*shade)>>8; + blue = (b*shade)>>8; + vertex_pool[current_vertex+0].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f3->Bright[1]+P_BRIGHT_L;// * 256; + red = (r*shade)>>8; + green = (g*shade)>>8; + blue = (b*shade)>>8; + vertex_pool[current_vertex+1].color = (red << 16) | (green << 8) | (blue << 0); + + shade = p_f3->Bright[2]+P_BRIGHT_L;// * 256; + red = (r*shade)>>8; + green = (g*shade)>>8; + blue = (b*shade)>>8; + vertex_pool[current_vertex+2].color = (red << 16) | (green << 8) | (blue << 0); + + vertex_pool[current_vertex+0].specular = P_BRIGHT; //d3d_specular[p0]; + vertex_pool[current_vertex+1].specular = P_BRIGHT; //d3d_specular[p1]; + vertex_pool[current_vertex+2].specular = P_BRIGHT; //d3d_specular[p2]; + + /* + shade = p_f3->Bright[0] * SHADE_MUL * 256; + + red = (SLONG) (dx_materials[p_f3->Col].R * shade); + green = (SLONG) (dx_materials[p_f3->Col].G * shade); + blue = (SLONG) (dx_materials[p_f3->Col].B * shade); + + + red *= (d3d_colour[p0] >> 0) & 0xff; + green *= (d3d_colour[p0] >> 8) & 0xff; + blue *= (d3d_colour[p0] >> 16) & 0xff; + + red >>= 8; + green >>= 8; + blue >>= 8; + + vertex_pool[current_vertex+0].color = (red << 16) | (green << 8) | (blue << 0); + + // + // The colour of each point. + // + + shade = p_f3->Bright[0] * SHADE_MUL * 256; + + red = (SLONG) (dx_materials[p_f3->Col].R * shade); + green = (SLONG) (dx_materials[p_f3->Col].G * shade); + blue = (SLONG) (dx_materials[p_f3->Col].B * shade); + + red *= (d3d_colour[p0] >> 0) & 0xff; + green *= (d3d_colour[p0] >> 8) & 0xff; + blue *= (d3d_colour[p0] >> 16) & 0xff; + + red >>= 8; + green >>= 8; + blue >>= 8; + + vertex_pool[current_vertex+1].color = (red << 16) | (green << 8) | (blue << 0); + + // + // The colour of each point. + // + + shade = p_f3->Bright[0] * SHADE_MUL * 256; + + red = (SLONG) (dx_materials[p_f3->Col].R * shade); + green = (SLONG) (dx_materials[p_f3->Col].G * shade); + blue = (SLONG) (dx_materials[p_f3->Col].B * shade); + + red *= (d3d_colour[p0] >> 0) & 0xff; + green *= (d3d_colour[p0] >> 8) & 0xff; + blue *= (d3d_colour[p0] >> 16) & 0xff; + + red >>= 8; + green >>= 8; + blue >>= 8; + + vertex_pool[current_vertex+2].color = (red << 16) | (green << 8) | (blue << 0); + + // + // Don't take face colour into account with the specular... + // + + vertex_pool[current_vertex+0].specular = d3d_specular[p0]; + vertex_pool[current_vertex+1].specular = d3d_specular[p1]; + vertex_pool[current_vertex+2].specular = d3d_specular[p2]; + */ + + /* + + r = dx_materials[p_f3->Col].R; + g = dx_materials[p_f3->Col].G; + b = dx_materials[p_f3->Col].B; + shade = p_f3->Bright[0]*SHADE_MUL; + vertex_pool[current_vertex+0].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f3->Bright[1]*SHADE_MUL; + vertex_pool[current_vertex+1].color = D3DRGB(r*shade,g*shade,b*shade); + shade = p_f3->Bright[2]*SHADE_MUL; + vertex_pool[current_vertex+2].color = D3DRGB(r*shade,g*shade,b*shade); + + */ + + } + the_tri->P[0] = current_vertex++; + the_tri->P[1] = current_vertex++; + the_tri->P[2] = current_vertex++; + + average_z = ( + dx_global_res[p0].Z, + dx_global_res[p1].Z, + dx_global_res[p2].Z + ) * 341.33f; + + add_bucket(&the_tri->BucketHeader,BUCKET_TRI,list,(SLONG)average_z); + } + } + p_f3++; + } +exit:; +} + + + +void e_draw_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2) +{ + + SVECTOR_F temp; + D3DTLVERTEX *the_vertex; + BucketLine *the_line; + ULONG f1,f2; + + SLONG flag_and; + SLONG flag_or; + +#ifndef _DEBUG +// return; +#endif + + temp.X = (float) x1; + temp.Y = (float) y1; + temp.Z = (float) z1; + + f1 = transform_point(&temp, &dx_global_res[0]); + + temp.X = (float) x2; + temp.Y = (float) y2; + temp.Z = (float) z2; + + f2 = transform_point(&temp, &dx_global_res[1]); + + flag_and = f1 & f2; + flag_or = f1 | f2; + + if ((flag_or & EF_BEHIND_YOU) || (flag_and & EF_CLIPFLAGS)) + { + +// LogText(" not drawn f1 %x f2 %x or %x and %x \n",f1,f2,flag_or,flag_and); + // + // Don't draw the line. + // + } + else + { + the_line = GET_BUCKET(BucketLine); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[0].X; + the_vertex->sy = dx_global_res[0].Y; + the_vertex->sz = SCALE_SZ; //dx_global_res[0].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + the_vertex++; + the_vertex->sx = dx_global_res[1].X; + the_vertex->sy = dx_global_res[1].Y; + the_vertex->sz = SCALE_SZ; //dx_global_res[1].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + 1.0f, + 1.0f, + 1.0f + ); + + + + the_line->P[0] = current_vertex++; + the_line->P[1] = current_vertex++; + + add_bucket(&the_line->BucketHeader,BUCKET_LINE,COLOUR_LIST_1,0); + } + +} + + +void e_draw_3d_line_dir(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2) +{ + SLONG dist; + SLONG nx,ny,nz; + SLONG vx,vy,vz; + SLONG c0; + +#ifndef _DEBUG + return; +#endif + vx=x2-x1; + vy=y2-y1; + vz=z2-z1; + nx=vz; + nz=-vx; + dist=(SLONG)sqrt((float) (nx*nx+nz*nz)); + + if(dist==0) + { + return; + } + + nx=(nx*80)/dist; + nz=(nz*80)/dist; + + vx=(vx*20)/dist; + vy=(vy*20)/dist; + vz=(vz*20)/dist; + + for(c0=1;c0<(dist/20);c0+=8) + { + e_draw_3d_line(x1+vx*c0,y1+vy*c0,z1+vz*c0,x1+vx*(c0-1)+nx,y1+vy*c0,z1+vz*(c0-1)+nz); + e_draw_3d_line(x1+vx*c0,y1+vy*c0,z1+vz*c0,x1+vx*(c0-1)-nx,y1+vy*c0,z1+vz*(c0-1)-nz); + } + + e_draw_3d_line(x1, y1, z1, x2, y2, z2); +} + + + +void e_draw_3d_line_col_sorted(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b) +{ + + SVECTOR_F temp; + D3DTLVERTEX *the_vertex; + BucketLine *the_line; + SLONG flag_and,flag_or; + + ULONG colour; + +#ifndef _DEBUG + return; +#endif + temp.X = (float)x1; + temp.Y = (float)y1; + temp.Z = (float)z1; + + + + global_flags[0] = transform_point(&temp,&dx_global_res[0]); + temp.X = (float)x2; + temp.Y = (float)y2; + temp.Z = (float)z2; + global_flags[1] = transform_point(&temp,&dx_global_res[1]); + + + + flag_and = global_flags[0]&global_flags[1]; + flag_or = global_flags[0]|global_flags[1]; + + if ((flag_or & EF_BEHIND_YOU) || + (flag_and & EF_CLIPFLAGS)) + { + // + // Don't draw the line. + // + } + else + { + + colour = (r << 0) | (g << 8) | (b << 16); + + the_line = GET_BUCKET(BucketLine); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[0].X; + the_vertex->sy = dx_global_res[0].Y; + the_vertex->sz = dx_global_res[0].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = colour; + + the_vertex++; + the_vertex->sx = dx_global_res[1].X; + the_vertex->sy = dx_global_res[1].Y; + the_vertex->sz = dx_global_res[1].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = colour; + + the_line->P[0] = current_vertex++; + the_line->P[1] = current_vertex++; + + add_bucket(&the_line->BucketHeader,BUCKET_LINE,COLOUR_LIST_1,0); + } +} + + +void e_draw_3d_line_col(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b) +{ + + SVECTOR_F temp; + D3DTLVERTEX *the_vertex; + BucketLine *the_line; + SLONG flag_and,flag_or; + +#ifndef _DEBUG + return; +#endif + temp.X = (float)x1; + temp.Y = (float)y1; + temp.Z = (float)z1; + + + + global_flags[0] = transform_point(&temp,&dx_global_res[0]); + temp.X = (float)x2; + temp.Y = (float)y2; + temp.Z = (float)z2; + global_flags[1] = transform_point(&temp,&dx_global_res[1]); + + + + flag_and = global_flags[0]&global_flags[1]; + flag_or = global_flags[0]|global_flags[1]; + + if ((flag_or & EF_BEHIND_YOU) || + (flag_and & EF_CLIPFLAGS)) + { + // + // Don't draw the line. + // + } + else + { + + the_line = GET_BUCKET(BucketLine); + + the_vertex = &vertex_pool[current_vertex]; + the_vertex->sx = dx_global_res[0].X; + the_vertex->sy = dx_global_res[0].Y; + the_vertex->sz = SCALE_SZ; //dx_global_res[0].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + ((float)r)/256.0, + ((float)g)/256.0, + ((float)b)/256.0, + ); + the_vertex++; + the_vertex->sx = dx_global_res[1].X; + the_vertex->sy = dx_global_res[1].Y; + the_vertex->sz = SCALE_SZ; //dx_global_res[1].Z; + the_vertex->rhw = SCALE_SZ/the_vertex->sz; + the_vertex->color = D3DRGB ( + ((float)r)/256.0, + ((float)g)/256.0, + ((float)b)/256.0, + ); + + + + the_line->P[0] = current_vertex++; + the_line->P[1] = current_vertex++; + + add_bucket(&the_line->BucketHeader,BUCKET_LINE,COLOUR_LIST_1,0); + } + +} + +void e_draw_3d_mapwho(SLONG x1,SLONG z1) +{ + x1<<=ELE_SHIFT; + z1<<=ELE_SHIFT; + +#ifdef NDEBUG + return; +#endif + e_draw_3d_line(x1,0,z1,x1+256,0,z1); + e_draw_3d_line(x1+256,0,z1,x1+256,0,z1+256); + e_draw_3d_line(x1+256,0,z1+256,x1,0,z1+256); + e_draw_3d_line(x1,0,z1+256,x1,0,z1); + + +} + + +void e_draw_3d_mapwho_y(SLONG x1,SLONG y1,SLONG z1) +{ + x1<<=ELE_SHIFT; + z1<<=ELE_SHIFT; + +#ifdef NDEBUG + return; +#endif + e_draw_3d_line(x1,y1,z1,x1+256,y1,z1); + e_draw_3d_line(x1+256,y1,z1,x1+256,y1,z1+256); + e_draw_3d_line(x1+256,y1,z1+256,x1,y1,z1+256); + e_draw_3d_line(x1,y1,z1+256,x1,y1,z1); + + +} + +void e_draw_actual_col_vect(UWORD col_vect) +{ + struct SVECTOR points[2]; + struct SVECTOR res[2]; + SLONG flags[2]; + +#ifdef NDEBUG + return; +#endif + points[0].X=col_vects[ col_vect].X[0]; + points[0].Y=col_vects[ col_vect].Y[0]; + points[0].Z=col_vects[ col_vect].Z[0]; + + points[1].X=col_vects[ col_vect].X[1]; + points[1].Y=col_vects[ col_vect].Y[1]; + points[1].Z=col_vects[ col_vect].Z[1]; + +// LogText(" DRAW COL VECT %d (%d,%d,%d)--(%d,%d,%d)\n",points[0].X,points[0].Y,points[0].Z,points[1].X,points[1].Y,points[1].Z); + e_draw_3d_line_dir(points[0].X,points[0].Y,points[0].Z,points[1].X,points[1].Y,points[1].Z); + +} +void e_draw_col_vects(UWORD col_vect_link) +{ +#ifdef NDEBUG + return; +#endif + if (!Keys[KB_8]) + { + return; + } + + while(col_vect_link) + { + e_draw_actual_col_vect(col_vects_links[col_vect_link].VectIndex); + + col_vect_link=col_vects_links[col_vect_link].Next; + } + +} + + + +//--------------------------------------------------------------- diff --git a/fallen/DDEngine/Source/Text.cpp b/fallen/DDEngine/Source/Text.cpp new file mode 100644 index 0000000..dd35c2d --- /dev/null +++ b/fallen/DDEngine/Source/Text.cpp @@ -0,0 +1,325 @@ +// Text.cpp +// Guy Simmons, 17th May 1998. + +#include +#include "poly.h" +#include "texture.h" +#include "vertexbuffer.h" +#include "polypoint.h" +#include "renderstate.h" +#include "polypage.h" + +//--------------------------------------------------------------- +#define TEXTURE_STEP 0.00390625f + +//D3DTexture font_page; + +extern D3DTexture TEXTURE_texture[]; +extern SLONG TEXTURE_page_font; + +#define font_page (TEXTURE_texture[TEXTURE_page_font]) + +//--------------------------------------------------------------- + +SLONG text_width(CBYTE *message,SLONG font_id,SLONG *char_count) +{ + SLONG count = 0, + width = 0; + Char *the_char; + Font *the_font; + + + the_font = font_page.GetFont(font_id); + if(!the_font) + return 0; + + while(*message && *message!='\n' && *message!='\r') + { + if(*message==32) + { + width += 5; + } + else + { + the_char = &the_font->CharSet[*message-33]; + if(the_char) + { + width += the_char->Width+1; + } + } + message++; + count++; + } + + if(char_count) + *char_count = count; + + return width; +} + +//--------------------------------------------------------------- + +SLONG text_height(CBYTE *message,SLONG font_id,SLONG *char_count) +{ + SLONG count = 0, + height = 0; + Char *the_char; + Font *the_font; + + + the_font = font_page.GetFont(font_id); + if(!the_font) + return 0; + + while(*message && *message!='\n' && *message!='\r') + { + the_char = &the_font->CharSet[*message-33]; + if(the_char) + { + if(the_char->Height>height) + height = the_char->Height+1; + } + + message++; + count++; + } + + if(char_count) + *char_count = count; + + return height; +} + +//--------------------------------------------------------------- + +#define TEXT_TOP 280 +#define TEXT_BOT 430 + +BOOL text_fudge = FALSE; +ULONG text_colour; + +void draw_text_at(float x, float y,CBYTE *message,SLONG font_id) +{ + float offset_x, + offset_y; + SLONG b_colour, + t_colour; + Char *the_char; + Font *the_font; + POLY_Point pp[4], + *quad[4]; + + + the_font = font_page.GetFont(font_id); + if(!the_font) + return; + + offset_x = (float)x; + offset_y = (float)y; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + while(*message) + { + switch(*message) + { + case 10: + case 13: + offset_x = (float)x; + offset_y += (float)the_font->CharSet['y'-33].Height+2; + break; + case 32: + offset_x += 5.0f; + break; + + default: + if (WITHIN(*message, 33, 127)) + { + the_char = &the_font->CharSet[*message-33]; + if(the_char) + { + if(text_fudge) + { + if(offset_yHeight)-TEXT_TOP)*20)+255; + if(b_colour>255) + b_colour = 255; + else if(b_colour<0) + b_colour = 0; + b_colour *= 0x00010101; //(b_colour<<24)|0x00ffffff; + } + else if((offset_y+the_char->Height)>TEXT_BOT) + { + b_colour = ((TEXT_BOT-((SLONG)offset_y+the_char->Height))*20)+255; + if(b_colour<0) + b_colour = 0; + b_colour *= 0x00010101; //(b_colour<<24)|0x00ffffff; + + t_colour = ((TEXT_BOT-(SLONG)offset_y)*20)+255; + if(t_colour>255) + t_colour = 255; + else if(t_colour<0) + t_colour = 0; + t_colour *= 0x00010101; //(t_colour<<24)|0x00ffffff; + } + else + { + t_colour = b_colour = 0x00ffffff; + } + } + else + { + t_colour = b_colour = text_colour; + } + + pp[0].X = offset_x; + pp[0].Y = offset_y; + pp[0].Z = 0.5f; + pp[0].u = the_char->X*TEXTURE_STEP; + pp[0].v = the_char->Y*TEXTURE_STEP; + pp[0].colour = t_colour; + pp[0].specular= 0; + + pp[1].X = offset_x+the_char->Width+1; + pp[1].Y = offset_y; + pp[1].Z = 0.5f; + pp[1].u = (the_char->X+the_char->Width+1)*TEXTURE_STEP; + pp[1].v = the_char->Y*TEXTURE_STEP; + pp[1].colour = t_colour; + pp[1].specular = 0; + + pp[2].X = offset_x; + pp[2].Y = offset_y+the_char->Height+1; + pp[2].Z = 0.5f; + pp[2].u = the_char->X*TEXTURE_STEP; + pp[2].v = (the_char->Y+the_char->Height+1)*TEXTURE_STEP; + pp[2].colour = b_colour; + pp[2].specular = 0; + + pp[3].X = offset_x+the_char->Width+1; + pp[3].Y = offset_y+the_char->Height+1; + pp[3].Z = 0.5f; + pp[3].u = (the_char->X+the_char->Width+1)*TEXTURE_STEP; + pp[3].v = (the_char->Y+the_char->Height+1)*TEXTURE_STEP; + pp[3].colour = b_colour; + pp[3].specular = 0; + + POLY_add_quad(quad,POLY_PAGE_TEXT,FALSE,TRUE); + + offset_x += the_char->Width+1.0f; + } + } + + break; + } + + message++; + } +} + +//--------------------------------------------------------------- + +void draw_centre_text_at(float x, float y,CBYTE *message,SLONG font_id,SLONG flag) +{ + CBYTE temp; + SLONG char_count = 0; + float height; + float width; + + height = (float) text_height("y",font_id,NULL); + while(*message) + { + width = (float) text_width(message,font_id,&char_count); +// LogText(" message >%s< len %d \n",message,char_count); + + temp = *(message+char_count); + if(flag) + *(message+char_count) = 0; + +// LogText(" draw text message >%s< width %d \n",message,width); + draw_text_at((640-((SLONG)width))>>1,y,message,font_id); + if(!flag) + break; + + y += height+2; + + *(message+char_count) = temp; + + + message += char_count+1; + } +} + +//--------------------------------------------------------------- + +void show_text(void) +{ + return; + + PolyPage *pa = &POLY_Page[POLY_PAGE_TEXT]; + +#ifndef TARGET_DC + DDCOLORKEY ck; + if (font_page.GetD3DTexture()) + { + ck.dwColorSpaceLowValue = 0; + ck.dwColorSpaceHighValue = 0; + font_page.SetColorKey(DDCKEY_SRCBLT,&ck); + } + else + { +// return; + } +#endif + + + + +#define SET_RENDER_STATE(I,V) pa->RS.SetRenderState(I,V) + + + if (pa->NeedsRendering()) + { + BEGIN_SCENE; + + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); +// SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREHANDLE,texture); + //pa->RS.SetTexture(pa->RS.SetTexture(handle)); + +#ifndef TARGET_DC + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + if(text_fudge) +#endif + { + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + } +#ifndef TARGET_DC + else + { + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE); + } +#endif + + pa->RS.SetChanged(); + pa->Render(the_display.lp_D3D_Device); + + END_SCENE; + } +} + +//--------------------------------------------------------------- + diff --git a/fallen/DDEngine/Source/aa.cpp b/fallen/DDEngine/Source/aa.cpp new file mode 100644 index 0000000..e7ac78e --- /dev/null +++ b/fallen/DDEngine/Source/aa.cpp @@ -0,0 +1,987 @@ +// +// An anti-aliased triangle draw. +// + +#include + +// +// The internal fixed point we used. +// + +#define AA_FIX 10 +#define AA_PIX (1 << AA_FIX) +#define AA_PMN (AA_PIX - 1) + + +// +// The spans. +// + +//#define AA_MAX_SPAN_X 256 +//#define AA_MAX_SPAN_Y 256 +#define AA_MAX_SPAN_X 33 +#define AA_MAX_SPAN_Y 33 + +typedef struct +{ + SLONG rhs_min; + SLONG rhs_max; + + SLONG lhs_min; + SLONG lhs_max; + + SLONG pixel[AA_MAX_SPAN_X]; + +} AA_Span; + +AA_Span AA_span[AA_MAX_SPAN_Y]; + + + +// +// A pixel on the rhs of a triangle filled in by 'frac' amount. +// frac is an AA_FIX-bit fraction. +// + +void AA_pixel_rhs( + SLONG x, + SLONG y, + SLONG frac) +{ + ASSERT(WITHIN(x, 0, AA_MAX_SPAN_X - 1)); + ASSERT(WITHIN(y, 0, AA_MAX_SPAN_Y - 1)); + + frac >>= AA_FIX - 8; + + AA_Span *as = &AA_span[y]; + + if (WITHIN(x, as->rhs_min, as->rhs_max)) + { + as->pixel[x] += frac; + } + else + { + as->pixel[x] = frac; + + if (x < as->rhs_min) {as->rhs_min = x;} + if (x > as->rhs_max) {as->rhs_max = x;} + } +} + +// +// A pixel on the lhs of a triangle where there is frac_left +// free space on the left of the pixel and frac_right filled +// space on the right of the pixel. +// + +void AA_pixel_lhs( + SLONG x, + SLONG y, + SLONG frac_left, + SLONG frac_right) +{ + ASSERT(WITHIN(x, 0, AA_MAX_SPAN_X - 1)); + ASSERT(WITHIN(y, 0, AA_MAX_SPAN_Y - 1)); + + frac_left >>= AA_FIX - 8; + frac_right >>= AA_FIX - 8; + + //ASSERT(WITHIN(frac_left, 0, 256)); + //ASSERT(WITHIN(frac_right, 0, 256)); + + AA_Span *as = &AA_span[y]; + + if (WITHIN(x, as->rhs_min, as->rhs_max)) + { + // + // Take a chunk out of this pixel. + // + + as->pixel[x] -= frac_left; + + if (x < as->lhs_min) {as->lhs_min = x;} + if (x > as->lhs_max) {as->lhs_max = x;} + } + else + { + if (WITHIN(x, as->lhs_min, as->lhs_max)) + { + as->pixel[x] += frac_right; + } + else + { + as->pixel[x] = frac_right; + + if (x < as->lhs_min) {as->lhs_min = x;} + if (x > as->lhs_max) {as->lhs_max = x;} + } + } +} + + +// +// An rhs span on one line. All values are in AA_FIX-bit fixed point. +// + +void AA_span_rhs( + SLONG dydx, + SLONG x1, + SLONG y1, + SLONG x2, + SLONG y2) +{ + SLONG dx; + SLONG dy; + + SLONG xleft; + SLONG xright; + SLONG ytop; + SLONG ybot; + + SLONG frac; + + if (x2 == x1) + { + // + // Ignore dydx! + // + + frac = (x1 & AA_PMN) * (y2 - y1) >> AA_FIX; // Fraction of this pixel covered. + + AA_pixel_rhs( + x1 >> AA_FIX, + y1 >> AA_FIX, + frac); + + return; + } + + if (x2 > x1) + { + xleft = x1; + ytop = y1; + + while(1) + { + xright = xleft + AA_PIX; + xright &= ~AA_PMN; + + if (xright > x2) + { + xright = x2; + } + + dx = xright - xleft; + dy = dx * dydx >> AA_FIX; + ybot = ytop + dy; + + frac = dx * dy >> (AA_FIX + 1); + frac += dx * (y2 - ybot) >> AA_FIX; + + if (xleft & AA_PMN) + { + frac += dy * (xleft & AA_PMN) >> AA_FIX; + frac += (y2 - ybot) * (xleft & AA_PMN) >> AA_FIX; + } + + AA_pixel_rhs( + xleft >> AA_FIX, + y1 >> AA_FIX, + frac); + + if (xright >= x2) + { + return; + } + + xleft = xright; + ytop = ybot; + } + } + else + { + xright = x1; + ytop = y1; + + while(1) + { + xleft = xright - 1; + xleft &= ~AA_PMN; + + if (xleft < x2) + { + xleft = x2; + } + + dx = xright - xleft; + dy = -dx * dydx >> AA_FIX; + ybot = ytop + dy; + + frac = dx * dy >> (AA_FIX + 1); + frac += dx * (ytop - y1) >> AA_FIX; + + if (xleft & AA_PMN) + { + frac += dy * (xleft & AA_PMN) >> AA_FIX; + frac += (ytop - y1) * (xleft & AA_PMN) >> AA_FIX; + } + + AA_pixel_rhs( + xleft >> AA_FIX, + y1 >> AA_FIX, + frac); + + if (xleft <= x2) + { + return; + } + + xright = xleft; + ytop = ybot; + } + } +} + + + + +// +// An lhs span on one line. All values are in AA_FIX-bit fixed point. +// + +void AA_span_lhs( + SLONG dydx, + SLONG x1, + SLONG y1, + SLONG x2, + SLONG y2) +{ + SLONG dx; + SLONG dy; + + SLONG xleft; + SLONG xright; + SLONG xpixel; + SLONG ytop; + SLONG ybot; + + SLONG frac_left; + SLONG frac_right; + + if (x2 == x1) + { + // + // Ignore dydx! + // + + frac_left = (x1 & AA_PMN) * (y2 - y1) >> AA_FIX; + frac_right = (AA_PMN - (x1 & AA_PMN)) * (y2 - y1) >> AA_FIX; + + AA_pixel_lhs( + x1 >> AA_FIX, + y1 >> AA_FIX, + frac_left, + frac_right); + + return; + } + + if (x2 > x1) + { + xleft = x1; + ytop = y1; + + while(1) + { + xright = xleft + AA_PIX; + xright &= ~AA_PMN; + xpixel = xright; + + if (xright > x2) + { + xright = x2; + } + + dx = xright - xleft; + dy = dx * dydx >> AA_FIX; + ybot = ytop + dy; + + frac_right = dx * dy >> (AA_FIX + 1); + frac_right += dx * (ytop - y1) >> AA_FIX; + + if (xpixel - xright) + { + frac_right += dy * (xpixel - xright) >> AA_FIX; + frac_right += (ytop - y1) * (xpixel - xright) >> AA_FIX; + } + + frac_left = dx * dy >> (AA_FIX + 1); + frac_left += dx * (y2 - ybot) >> AA_FIX; + + if (xleft & AA_PMN) + { + frac_left += dy * (xleft & AA_PMN) >> AA_FIX; + frac_left += (y2 - ybot) * (xleft & AA_PMN) >> AA_FIX; + } + + AA_pixel_lhs( + xleft >> AA_FIX, + y1 >> AA_FIX, + frac_left, + frac_right); + + if (xright >= x2) + { + return; + } + + xleft = xright; + ytop = ybot; + } + } + else + { + xright = x1; + ytop = y1; + + while(1) + { + xleft = xright - 1; + xleft &= ~AA_PMN; + xpixel = xleft + AA_PIX; + + if (xleft < x2) + { + xleft = x2; + } + + dx = xright - xleft; + dy = dx * -dydx >> AA_FIX; + ybot = ytop + dy; + + frac_right = dx * dy >> (AA_FIX + 1); + frac_right += dx * (y2 - ybot) >> AA_FIX; + + if (xpixel - xright) + { + frac_right += dy * (xpixel - xright) >> AA_FIX; + frac_right += (y2 - ybot) * (xpixel - xright) >> AA_FIX; + } + + frac_left = dx * dy >> (AA_FIX + 1); + frac_left += dx * (ytop - y1) >> AA_FIX; + frac_left += dy * (xleft & AA_PMN) >> AA_FIX; + frac_left += (ytop - y1) * (xleft & AA_PMN) >> AA_FIX; + + AA_pixel_lhs( + xleft >> AA_FIX, + y1 >> AA_FIX, + frac_left, + frac_right); + + if (xleft <= x2) + { + return; + } + + xright = xleft; + ytop = ybot; + } + } +} + + + + +// +// A line on the rhs of the triangle. py1 <= py2 +// + +void AA_line_rhs(SLONG px1, SLONG py1, SLONG px2, SLONG py2) +{ + if (py1 == py2) + { + return; + } + + SLONG dy; + SLONG dx; + + SLONG dydx; + SLONG dxdy; + + SLONG x1, x2; + SLONG y1, y2; + + dx = px2 - px1; + dy = py2 - py1; + dxdy = (dx << AA_FIX) / dy; + + if (dx) + { + dydx = dy << AA_FIX; + dydx /= dx; + } + else + { + // + // dydx will never be referenced... honest! + // + + dydx = 0; + } + + x1 = px1; + y1 = py1; + + while(1) + { + y2 = y1 + AA_PIX; + y2 &= ~AA_PMN; + + if (y2 > py2) + { + y2 = py2; + } + + dy = y2 - y1; + + if (dy == 0) + { + // + // Hmm... do nowt. + // + } + else + { + x2 = x1 + (dy * dxdy >> AA_FIX); + + AA_span_rhs(dydx, x1, y1, x2, y2); + } + + if (y2 >= py2) + { + return; + } + + x1 = x2; + y1 = y2; + } +} + +// +// A line on the lhs of the triangle py1 <= py2 +// + +void AA_line_lhs(SLONG px1, SLONG py1, SLONG px2, SLONG py2) +{ + if (py1 == py2) + { + return; + } + + SLONG dy; + SLONG dx; + + SLONG dydx; + SLONG dxdy; + + SLONG x1, x2; + SLONG y1, y2; + + dx = px2 - px1; + dy = py2 - py1; + dxdy = (dx << AA_FIX) / dy; + + if (dx) + { + dydx = dy << AA_FIX; + dydx /= dx; + } + else + { + // + // dydx will never be referenced... honest! + // + + dydx = 0; + } + + x1 = px1; + y1 = py1; + + while(1) + { + y2 = y1 + AA_PIX; + y2 &= ~AA_PMN; + + if (y2 > py2) + { + y2 = py2; + } + + dy = y2 - y1; + + if (dy == 0) + { + // + // Hmm... do nowt. + // + } + else + { + x2 = x1 + (dy * dxdy >> AA_FIX); + + AA_span_lhs(dydx, x1, y1, x2, y2); + } + + if (y2 >= py2) + { + return; + } + + y1 = y2; + x1 = x2; + } +} + + + +void AA_draw_do( + UBYTE *bitmap, + UBYTE x_res, + UBYTE y_res, + SLONG pitch, + + // + // In clockwise order. + // + + SLONG px[3], + SLONG py[3]) +{ + SLONG i; + + SLONG miny; + SLONG maxy; + + //SLONG minp; + SLONG p1; + SLONG p2; + + SLONG x; + SLONG y; + + SLONG x1, y1; + SLONG x2, y2; + + SLONG nextp[3] = {1,2,0}; + + SLONG val; + + SLONG fill_top; + SLONG fill_bot; + + SLONG fill; + UBYTE *line; + + // + // The bounds of the triangle. + // + + miny = py[0]; + maxy = py[0]; + + if (py[1] < miny) {miny = py[1];} + if (py[1] > maxy) {maxy = py[1];} + + if (py[2] < miny) {miny = py[2];} + if (py[2] > maxy) {maxy = py[2];} + + fill_top = AA_PIX - (miny & AA_PMN); + fill_bot = ((maxy - 1) & AA_PMN); + + miny >>= AA_FIX; + maxy -= 1; + maxy >>= AA_FIX; + + // + // Initialise these guys. + // + + for (i = miny; i <= maxy; i++) + { + ASSERT(WITHIN(i, 0, AA_MAX_SPAN_Y - 1)); + + AA_span[i].lhs_min = +INFINITY; + AA_span[i].lhs_max = -INFINITY; + + AA_span[i].rhs_min = +INFINITY; + AA_span[i].rhs_max = -INFINITY; + } + + // + // Go through each line. + // + + p1 = 0; + + for (i = 0; i < 3; i++) + { + p2 = nextp[p1]; + + x1 = px[p1]; + y1 = py[p1]; + + x2 = px[p2]; + y2 = py[p2]; + + if (y1 < y2) + { + // + // Running along the RHS of the triangle. + // + + AA_line_rhs(x1, y1, x2, y2); + } + else + { + // + // Running along the LHS of the triangle. + // + + AA_line_lhs(x2, y2, x1, y1); + } + + p1 = p2; + } + + // + // Draw the bitmap from the info in the spans. + // + + fill = fill_top; + + for (y = miny; y <= maxy; y++) + { + if (y == maxy) + { + fill = fill_bot; + } + + ASSERT(WITHIN(y, 0, AA_MAX_SPAN_Y - 1)); + + AA_Span *as = &AA_span[y]; + + line = &bitmap[y * pitch]; + + x = as->lhs_min; + + while(x <= as->lhs_max) + { + ASSERT(WITHIN(x, 0, AA_MAX_SPAN_X - 1)); + + + val = line[x]; + val += as->pixel[x]; + + SATURATE(val, 0, 255); + + line[x] = (UBYTE)val; + + x += 1; + } + + while (x < as->rhs_min) + { + ASSERT(WITHIN(x, 0, x_res - 1)); + + val = line[x]; + val += fill; + + SATURATE(val, 0, 255); + + line[x] = (UBYTE)val; + + x += 1; + } + + while (x <= as->rhs_max) + { + ASSERT(WITHIN(x, 0, AA_MAX_SPAN_X - 1)); + + val = line[x]; + val += as->pixel[x]; + + SATURATE(val, 0, 255); + + line[x] = (UBYTE)val; + + x += 1; + } + + fill = 255; + } + +} + + + + + +// +// The value generate for +// + +void AA_draw( + UBYTE *bitmap, + UBYTE x_res, + UBYTE y_res, + SLONG pitch, + SLONG p1x, SLONG p1y, // 16-bit fixed point. + SLONG p2x, SLONG p2y, + SLONG p3x, SLONG p3y) +{ +#ifndef NDEBUG + SLONG i; +#endif + + //SLONG miny; + //SLONG maxy; + + SLONG minp; + + SLONG p1; + SLONG p2; + SLONG p3; + + //SLONG x; + //SLONG y; + + SLONG px[3]; + SLONG py[3]; + + //SLONG val; + + //SLONG fill_top; + //SLONG fill_bot; + + //UBYTE fill; + //UBYTE *line; + + SLONG nextp[3] = {1,2,0}; + + // + // Work in AA_FIX-bit internally. + // + + px[0] = p1x >> (16 - AA_FIX); + py[0] = p1y >> (16 - AA_FIX); + + px[1] = p2x >> (16 - AA_FIX); + py[1] = p2y >> (16 - AA_FIX); + + px[2] = p3x >> (16 - AA_FIX); + py[2] = p3y >> (16 - AA_FIX); + + // + // Lose the bottom few bits to preserve accuracy in + // the triangle draws... + // + + px[0] &= ~0xf; + py[0] &= ~0xf; + + px[1] &= ~0xf; + py[1] &= ~0xf; + + px[2] &= ~0xf; + py[2] &= ~0xf; + + #ifndef NDEBUG + + for (i = 0; i < 3; i++) + { + ASSERT(WITHIN(px[i], 0, AA_MAX_SPAN_X << AA_FIX)); + ASSERT(WITHIN(py[i], 0, AA_MAX_SPAN_Y << AA_FIX)); + } + + #endif + + // + // The maximum span + // + + if (px[0] == AA_MAX_SPAN_X << AA_FIX) {px[0] -= 1;} + if (px[1] == AA_MAX_SPAN_X << AA_FIX) {px[1] -= 1;} + if (px[2] == AA_MAX_SPAN_X << AA_FIX) {px[2] -= 1;} + + if (py[0] == AA_MAX_SPAN_Y << AA_FIX) {py[0] -= 1;} + if (py[1] == AA_MAX_SPAN_Y << AA_FIX) {py[1] -= 1;} + if (py[2] == AA_MAX_SPAN_Y << AA_FIX) {py[2] -= 1;} + + // + // What is the top point? + // + + minp = 0; + + if (py[1] < py[ 0]) {minp = 1;} + if (py[2] < py[minp]) {minp = 2;} + + p1 = minp; + p2 = nextp[p1]; + p3 = nextp[p2]; + + if (py[0] == py[1] || + py[1] == py[2] || + py[2] == py[0]) + { + // + // This triangle is already flat along one edge! + // + + SLONG tx[3]; + SLONG ty[3]; + + tx[0] = px[p1]; + ty[0] = py[p1]; + + tx[1] = px[p2]; + ty[1] = py[p2]; + + tx[2] = px[p3]; + ty[2] = py[p3]; + + AA_draw_do( + bitmap, + x_res, + y_res, + pitch, + tx, + ty); + } + else + { + if (py[p2] > py[p3]) + { + // + // Pointy left triangle. Find the new point along the edge from p1 to p2. + // + + SLONG dx = px[p2] - px[p1]; + SLONG dy = py[p2] - py[p1]; + + SLONG nx; + SLONG ny; + + nx = px[p1] + (dx * (py[p3] - py[p1])) / dy; + ny = py[p3]; + + // + // Two new triangles. + // + + SLONG tx[3]; + SLONG ty[3]; + + tx[0] = px[p1]; + ty[0] = py[p1]; + + tx[1] = nx; + ty[1] = ny; + + tx[2] = px[p3]; + ty[2] = py[p3]; + + AA_draw_do( + bitmap, + x_res, + y_res, + pitch, + tx, + ty); + + + tx[0] = px[p3]; + ty[0] = py[p3]; + + tx[1] = nx; + ty[1] = ny; + + tx[2] = px[p2]; + ty[2] = py[p2]; + + AA_draw_do( + bitmap, + x_res, + y_res, + pitch, + tx, + ty); + } + else + { + // + // Pointy right triangle. Find the new point along the edge from p1 to p3. + // + + SLONG dx = px[p3] - px[p1]; + SLONG dy = py[p3] - py[p1]; + + SLONG nx; + SLONG ny; + + nx = px[p1] + (dx * (py[p2] - py[p1])) / dy; + ny = py[p2]; + + // + // Two new triangles. + // + + SLONG tx[3]; + SLONG ty[3]; + + tx[0] = px[p1]; + ty[0] = py[p1]; + + tx[1] = px[p2]; + ty[1] = py[p2]; + + tx[2] = nx; + ty[2] = ny; + + AA_draw_do( + bitmap, + x_res, + y_res, + pitch, + tx, + ty); + + tx[0] = nx; + ty[0] = ny; + + tx[1] = px[p2]; + ty[1] = py[p2]; + + tx[2] = px[p3]; + ty[2] = py[p3]; + + AA_draw_do( + bitmap, + x_res, + y_res, + pitch, + tx, + ty); + } + } +} + + + + + + + diff --git a/fallen/DDEngine/Source/aeng.cpp b/fallen/DDEngine/Source/aeng.cpp new file mode 100644 index 0000000..41cd88f --- /dev/null +++ b/fallen/DDEngine/Source/aeng.cpp @@ -0,0 +1,17084 @@ +// +// Another engine. +// + +#include +#include +#include +#include "game.h" +#include "aeng.h" +#include "font.h" +#include "ngamut.h" +#include "poly.h" +#include "texture.h" +#include "matrix.h" +#include "message.h" +#include "font2d.h" +#include "figure.h" +#include "build.h" +#include "mesh.h" +#include "dirt.h" +#include "sky.h" +#include "mist.h" +#include "id.h" +#include "shadow.h" +#include "puddle.h" +#include "az.h" +#include "aa.h" +#include "smap.h" +#include "sewer.h" +#include "drip.h" +#include "wibble.h" +#include "shape.h" +#include "bang.h" +#include "mav.h" +#include "fire.h" +#include "animtmap.h" +#include "sprite.h" +#include "spark.h" +#include "glitter.h" +#include "Text.h" // Guy. +#include "cone.h" +#include "ob.h" +#include "morph.h" +#include "trip.h" +#include "text.h" +#include "pap.h" +#include "night.h" +#include "c:\fallen\headers\supermap.h" +#include "hook.h" +#include "sm.h" +#include "ns.h" +#include "cloth.h" +#include "facet.h" +//#include "c:\fallen\sedit\headers\es.h" +#include "ic.h" +#include "comp.h" +#include "cam.h" +#include "c:\fallen\headers\tracks.h" +#include "pcom.h" +#include "drawxtra.h" +#include "balloon.h" +#include "snipe.h" +#include "c:\fallen\headers\inside2.h" +#include "psystem.h" +#include "fc.h" +#include "memory.h" +#include "ware.h" +#include "statedef.h" +#include "pow.h" +#include "FMatrix.h" +#include "eway.h" +#include "c:\fallen\headers\env.h" +#include "animate.h" +#include "oval.h" +#include "crinkle.h" +#include "sw.h" +#include "c:\fallen\headers\sound.h" + +#include "vertexbuffer.h" + +#include "BreakTimer.h" +#include "polypoint.h" + +#include "grenade.h" +#include "superfacet.h" +#include "farfacet.h" + +#include "interfac.h" + + +#include "polypage.h" +#include "DCLowLevel.h" + +#ifdef TARGET_DC +#include +#else +#define POLY_set_local_rotation_none() {} + +#endif + + +#define AENG_MAX_BBOXES 8 +#define AENG_BBOX_PUSH_IN 16 +#define AENG_BBOX_PUSH_OUT 4 + + + + +//#ifdef DEBUG +#if 0 +#define ANNOYINGSCRIBBLECHECK ScribbleCheck() + +static void ScribbleCheck ( void ) +{ + ASSERT ( prim_faces4[1].Points[0] >= 48 ); + ASSERT ( prim_faces4[1].Points[0] < 62 ); + ASSERT ( prim_faces4[1].Points[1] >= 48 ); + ASSERT ( prim_faces4[1].Points[1] < 62 ); + ASSERT ( prim_faces4[1].Points[2] >= 48 ); + ASSERT ( prim_faces4[1].Points[2] < 62 ); + ASSERT ( prim_faces4[1].Points[3] >= 48 ); + ASSERT ( prim_faces4[1].Points[3] < 62 ); +} + +#else +#define ANNOYINGSCRIBBLECHECK +#endif + + + +#ifndef TARGET_DC + +#define LOG_ENTER(x) {} +#define LOG_EXIT(x) {} +#define LOG_EVENT(x) {} + +#endif + + + +#ifdef TARGET_DC + + +#define AENG_rdtsc() 0 +#else +ULONG AENG_rdtsc() +{ + ULONG hi; + ULONG lo; + + _asm + { + rdtsc + mov hi, edx + mov lo, eax + } + + ULONG ans; + + ans = lo >> 16; + ans |= hi << 16; + ans = lo; + + return ans; +} +#endif + + + + + +void AENG_draw_far_facets(void); +void AENG_draw_box_around_recessed_door(DFacet *df, SLONG inside_out); +void AENG_get_rid_of_unused_dfcache_lighting(SLONG splitscreen); +void AENG_draw_inside_floor(UWORD inside_index,UWORD inside_room,UBYTE fade); + +UBYTE aeng_draw_cloud_flag = 1; +UWORD light_inside=0; +UWORD fade_black=1; +#ifdef TARGET_DC +#define sw_hack FALSE +#else +UBYTE sw_hack; +#endif + +#ifndef TARGET_DC +UBYTE cloud_data[32][32]; +SLONG cloud_x,cloud_z; +#endif + +extern SLONG FirstPersonMode; +SLONG FirstPersonAlpha = 255; +#define MAX_FPM_ALPHA 160 + + + +int AENG_total_polys_drawn; + +int AENG_detail_stars = 1; +int AENG_detail_shadows = 1; +int AENG_detail_moon_reflection = 1; +int AENG_detail_people_reflection = 1; +int AENG_detail_puddles = 1; +int AENG_detail_dirt = 1; +int AENG_detail_mist = 1; +int AENG_detail_rain = 1; +int AENG_detail_skyline = 1; +int AENG_detail_filter = 1; +int AENG_detail_perspective = 1; +int AENG_detail_crinkles = 1; +#ifndef TARGET_DC +int AENG_estimate_detail_levels = 1; +#endif + + + + + +SLONG AENG_cur_fc_cam; + + +#ifndef TARGET_DC +// Clouds?!?!?!?!?!?!? Madness. + +void move_clouds(void) +{ + cloud_x+=10; + cloud_z+=5; +} + +SLONG global_b=0; + +// +// calc a cloud shadow value for a world co-ord for reapeated use by prim or person or ... +// +void calc_global_cloud(SLONG x,SLONG y,SLONG z) +{ + SLONG in,r,g,b; + SLONG in1,in2,in3,in0; + SLONG dx,dz,mx,mz; + if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME)) + return; + y>>=1; + + x=(x+(cloud_x)-y);//&0x1f; + z=(z+(cloud_z)-y);//&0x1f; + + mx=(x>>8)&0x1f; + mz=(z>>8)&0x1f; + + in0=cloud_data[mx][mz]; + in1=cloud_data[(mx+1)&0x1f][mz]; + in2=cloud_data[(mx)&0x1f][(mz+1)&0x1f]; + in3=cloud_data[(mx+1)&0x1f][(mz+1)&0x1f]; + + + // in0 in1 + // + // + // in2 in3 + + dx=x&0xff; + dz=z&0xff; + + if(dx+dz<256) + { + in=in0; + in+=((in1-in0)*dx)>>8; + in+=((in2-in0)*dz)>>8; + } + else + { + in=in3; + in+=((in2-in3)*(256-dx))>>8; + in+=((in1-in3)*(256-dz))>>8; + + } + if(in<0) + in=0; + global_b=in; + +} + +// +// use pre-calced shadow value +// +void use_global_cloud(ULONG *col) +{ + SLONG r,g,b; + SLONG in=global_b; + + if (!aeng_draw_cloud_flag) return; + + if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME)) + return; + r=((*col)&0xff0000)>>16; + + in=(in*(r))>>8; + + + { + r-=in; + if(r<0) + r=0; + } + + g=((*col)&0xff00)>>8; +// if(g-global_bright>Mglobal_bright_CLOUD) + { + g-=in; + if(g<0) + g=0; + } + + b=((*col)&0xff); + +// if(b-global_bright>Mglobal_bright_CLOUD) + { + b-=in;//(global_bright*220)>>8; + if(b<0) + b=0; + } + + + *col=(*col&0xff000000)|(r<<16)|(g<<8)|(b); + +} + +// +// Take a co-ord in the world, calcultae how much shadow the clouds are producing at that point +// and darken the colour accordingly + + +#define MIN_CLOUD 48 +inline void apply_cloud(SLONG x,SLONG y,SLONG z,ULONG *col) +{ + return; + + if (!aeng_draw_cloud_flag) return; + + SLONG in,r,g,b; + SLONG in1,in2,in3,in0; + SLONG dx,dz,mx,mz; + if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME)) + return; + y>>=1; + + x=(x+(cloud_x)-y);//&0x1f; + z=(z+(cloud_z)-y);//&0x1f; + + mx=(x>>8)&0x1f; + mz=(z>>8)&0x1f; + + in0=cloud_data[mx][mz]; + in1=cloud_data[(mx+1)&0x1f][mz]; + in2=cloud_data[(mx)&0x1f][(mz+1)&0x1f]; + in3=cloud_data[(mx+1)&0x1f][(mz+1)&0x1f]; + + + // in0 in1 + // + // + // in2 in3 + + dx=x&0xff; + dz=z&0xff; + + if(dx+dz<256) + { + in=in0; + in+=((in1-in0)*dx)>>8; + in+=((in2-in0)*dz)>>8; + } + else + { + in=in3; + in+=((in2-in3)*(256-dx))>>8; + in+=((in1-in3)*(256-dz))>>8; + + } + if(in<0) + in=0; + + + r=((*col)&0xff0000)>>16; + + // + // use the redness that's there as a general brightness factor for the vertex + // + + // + // adjust the shadow factor so dark things only get affected a little, & light things get affected a lot + // + + in=(in*(r))>>8; + + { + r-=in; + if(r<0) + r=0; +// if(r>255) +// r=255; + } + + g=((*col)&0xff00)>>8; +// if(g-in>MIN_CLOUD) + { + g-=in; + if(g<0) + g=0; +// if(g>255) +// g=255; + } + + b=((*col)&0xff); + +// if(b-in>MIN_CLOUD) + { + b-=in;//(in*220)>>8; + if(b<0) + b=0; +// if(b>255) +// b=255; + } + + *col=(*col&0xff000000)|(r<<16)|(g<<8)|(b); + + +} + +void init_clouds(void) +{ + MFFileHandle handle; + handle=FileOpen("data\\cloud.raw"); + if(handle!=FILE_OPEN_ERROR) + { + FileRead(handle,cloud_data,1024); + FileClose(handle); + } + else + { + memset(cloud_data,0,1024); + } +} + +#endif //#ifndef TARGET_DC + +// GetShadowPixelMapping +// +// returns a UBYTE -> UWORD table for mapping +// from the shadow buffer to the shadow texture surface + +UWORD* GetShadowPixelMapping() +{ + static UWORD mapping[256]; + static int mapping_state = -1; + + // + // create mapping, if necessary + // + + if ((mapping_state == -1) || (mapping_state != (int)the_display.GetDeviceInfo()->DestInvSourceColourSupported())) + { + // mapping must change + mapping_state = the_display.GetDeviceInfo()->DestInvSourceColourSupported(); + + if (mapping_state) + { + // density colourmap + for (int ii = 0; ii < 256; ii++) + { + int val = ii >> 1; // not too shadowy + + mapping[ii] = ((val >> TEXTURE_shadow_mask_red) << TEXTURE_shadow_shift_red) + | ((val >> TEXTURE_shadow_mask_green) << TEXTURE_shadow_shift_green) + | ((val >> TEXTURE_shadow_mask_blue) << TEXTURE_shadow_shift_blue); + } + } + else + { + // density alphamap + for (int ii = 0; ii < 256; ii++) + { + int val = ii >> 1; // not too shadowy + + mapping[ii] = (val >> TEXTURE_shadow_mask_alpha) << TEXTURE_shadow_shift_alpha; + } + } + } + + return mapping; +} + +extern SLONG dfacets_drawn_this_gameturn; +extern BOOL allow_debug_keys; + +// +// The shift of the floor... +// + +#define ALT_SHIFT (3) + +// +// The maximum draw distance. +// + +float AENG_lens = 4.0F; + +//static SLONG NormalDrawDistance = 22<<8; +SLONG CurDrawDistance = 22<<8; + +//#define AENG_DRAW_DIST ((FC_cam[1].focus) ? 16 : 22) +#define AENG_DRAW_DIST (CurDrawDistance>>8) +#define AENG_DRAW_DIST_PRECISE (CurDrawDistance) +#define AENG_DRAW_PEOPLE_DIST (CurDrawDistance + 128) + +#define AENG_LENS (AENG_lens) + +SLONG AENG_get_draw_distance() +{ + return CurDrawDistance >> 8; +} + +void AENG_set_draw_distance(SLONG dist) +{ +#if 0 + NormalDrawDistance = dist; + ENV_set_value_number("draw_distance", dist, "Render"); +#endif +} + +// +// The camera. +// + +float AENG_cam_x; +float AENG_cam_y; +float AENG_cam_z; + +float AENG_cam_yaw; +float AENG_cam_pitch; +float AENG_cam_roll; + +float AENG_cam_matrix[9]; + +SLONG AENG_cam_vec[3]; + +// +// The floating point prim points. +// + +SVector_F AENG_dx_prim_points[RMAX_PRIM_POINTS]; + +struct StoreLine +{ + SLONG x1,y1,z1,x2,y2,z2; + ULONG col; +}; + +#define MAX_LINES 100 +struct StoreLine Lines[MAX_LINES]; +SLONG next_line=0; + + +void add_debug_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG colour) +{ + SLONG line; + + line=next_line%MAX_LINES; + + Lines[line].x1=x1; + Lines[line].y1=y1; + Lines[line].z1=z1; + + Lines[line].x2=x2; + Lines[line].y2=y2; + Lines[line].z2=z2; + Lines[line].col=colour; + next_line++; + +} + +#ifdef DEBUG +void draw_debug_lines(void) +{ + SLONG c0,s,e; + if((!ControlFlag)||(!allow_debug_keys)) return; + + s=next_line-MAX_LINES; + if(s<0) + s=0; + e=next_line; + + + for(c0=s;c0> 1; + + if (AENG_frame_tick >= (1 << TICK_SHIFT)) + { + AENG_frame_tick -= (1 << TICK_SHIFT); + AENG_frame_tick &= (1 << TICK_SHIFT) - 1; + + AENG_frame_count += 1; + + if (AENG_frame_count >= AENG_frame_number) + { + if (AENG_frame_count < AENG_frame_number + 32) + { + // + // Wait a while at the end of the movie. + // + + return; + } + + AENG_frame_count = 0; + AENG_movie_upto = AENG_movie_data; + } + + // + // Load in the new frame. + // + + cd = (COMP_Delta *) AENG_movie_upto; + + COMP_decomp( + AENG_frame_last, + cd, + AENG_frame_next); + + AENG_movie_upto += cd->size + 4; + + // + // Download the new frame. + // + + ASSERT(TEXTURE_VIDEO_SIZE == COMP_SIZE); + + if (TEXTURE_86_lock()) + { + SLONG x; + SLONG y; + + UWORD *data; + UWORD pixel; + + TGA_Pixel *tp; + + for (y = 0; y < TEXTURE_VIDEO_SIZE; y++) + { + tp = &AENG_frame_next->p[y][0]; + + data = TEXTURE_shadow_bitmap; + data += y * (TEXTURE_shadow_pitch >> 1); + + for (x = 0; x < TEXTURE_VIDEO_SIZE; x++) + { + pixel = 0; + pixel |= (tp->red >> TEXTURE_shadow_mask_red ) << TEXTURE_shadow_shift_red; + pixel |= (tp->green >> TEXTURE_shadow_mask_green) << TEXTURE_shadow_shift_green; + pixel |= (tp->blue >> TEXTURE_shadow_mask_blue ) << TEXTURE_shadow_shift_blue; + + *data = pixel; + + tp += 1; + data += 1; + } + } + + TEXTURE_86_unlock(); + TEXTURE_86_update(); + } + + SWAP_FRAME(AENG_frame_last, AENG_frame_next); + } +} + + + + +/* + +COMP_Frame cf1; +COMP_Frame cf2; +COMP_Frame cf3; +COMP_Frame cf4; + +#define MAX_MOVIE_DATA (1024 * 512) + +UBYTE movie_data[MAX_MOVIE_DATA]; +UBYTE *movie_data_upto; + +*/ + +void AENG_init(void) +{ + extern void this_may_well_be_the_last_ever_function_call_put_into_the_game(void); + + this_may_well_be_the_last_ever_function_call_put_into_the_game(); + + + MESH_init(); +// FONT2D_init(); +#ifndef TARGET_DC + init_clouds(); +#endif + SKY_init("stars\\poo"); + POLY_init(); + AENG_movie_init(); + TEXTURE_choose_set(1); + INDOORS_INDEX_FADE=255; + //POLY_frame_init(FALSE, FALSE); + + #if 0 + + // + // Create the movie. + // + + { + SLONG i; + + COMP_Frame *curr = &cf1; + COMP_Frame *last = &cf2; + COMP_Frame *next = &cf3; + + COMP_Delta *cd; + + SLONG load_ok; + + CBYTE name[256]; + + movie_data_upto = movie_data; + + for (i = 1; i <= 200; i++) + { + sprintf(name, "movie\\frames\\cin1%03d.tga", i); + + load_ok = COMP_load(name, curr); + + ASSERT(load_ok); + + cd = COMP_calc(last, curr, next); + + ASSERT(movie_data_upto + (cd->size + 4) <= &movie_data[MAX_MOVIE_DATA]); + + memcpy(movie_data_upto, cd, cd->size + 4); + + movie_data_upto += cd->size + 4; + + sprintf(name, "movie\\comp\\comp%03d.tga", i); + + TGA_save( + name, + COMP_SIZE, + COMP_SIZE, + (TGA_Pixel *) next->p, + FALSE); + + SWAP_FRAME(last,next); + } + } + + /* + + SLONG cf1_ok = COMP_load("movie\\frames\\cin1040.tga", &cf1); + SLONG cf2_ok = COMP_load("movie\\frames\\cin1041.tga", &cf2); + + COMP_Delta *cd = COMP_calc(&cf1, &cf2, &cf3); + + COMP_decomp(&cf1, cd, &cf4); + + TGA_save( + "movie\\test1.tga", + COMP_SIZE, + COMP_SIZE, + (TGA_Pixel *) cf1.p, + FALSE); + + TGA_save( + "movie\\test2.tga", + COMP_SIZE, + COMP_SIZE, + (TGA_Pixel *) cf2.p, + FALSE); + + TGA_save( + "movie\\test3.tga", + COMP_SIZE, + COMP_SIZE, + (TGA_Pixel *) cf3.p, + FALSE); + + TGA_save( + "movie\\test4.tga", + COMP_SIZE, + COMP_SIZE, + (TGA_Pixel *) cf4.p, + FALSE); + + IC_test(); + + */ + + SLONG num_bytes; + + num_bytes = movie_data_upto - movie_data; + + FILE *handle = MF_Fopen("movie\\bond.mmv", "wb"); + + if (handle) + { + fwrite(movie_data, sizeof(UBYTE), num_bytes, handle); + MF_Fclose(handle); + } + + exit(0); + + #endif + + // + // Load the fade palette for the bonfires + // + + init_flames(); + +} + +void AENG_fini() +{ + TEXTURE_free(); +} + +void AENG_create_dx_prim_points() +{ + SLONG i; + + for (i = 0; i < MAX_PRIM_POINTS; i++) + { + AENG_dx_prim_points[i].X = float(prim_points[i].X); + AENG_dx_prim_points[i].Y = float(prim_points[i].Y); + AENG_dx_prim_points[i].Z = float(prim_points[i].Z); + } +} + +void AENG_world_line( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + SLONG sort_to_front) +{ + +#ifdef DEBUG +#ifdef TARGET_DC + ASSERT ( FALSE ); + return; +#endif +#else + + POLY_Point p1; + POLY_Point p2; + + POLY_transform(float(x1), float(y1), float(z1), &p1); + POLY_transform(float(x2), float(y2), float(z2), &p2); + + if (POLY_valid_line(&p1, &p2)) + { + p1.colour = colour1; + p1.specular = 0xff000000; + + p2.colour = colour2; + p2.specular = 0xff000000; + + POLY_add_line(&p1, &p2, float(width1), float(width2), POLY_PAGE_COLOUR, sort_to_front); + } +#endif +} + + + +void AENG_world_line_nondebug ( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + SLONG sort_to_front) +{ + + POLY_Point p1; + POLY_Point p2; + + POLY_transform(float(x1), float(y1), float(z1), &p1); + POLY_transform(float(x2), float(y2), float(z2), &p2); + + if (POLY_valid_line(&p1, &p2)) + { + p1.colour = colour1; + p1.specular = 0xff000000; + + p2.colour = colour2; + p2.specular = 0xff000000; + + POLY_add_line(&p1, &p2, float(width1), float(width2), POLY_PAGE_COLOUR, sort_to_front); + } +} + + + +void AENG_world_line_infinite( + SLONG ix1, SLONG iy1, SLONG iz1, SLONG iwidth1, ULONG colour1, + SLONG ix2, SLONG iy2, SLONG iz2, SLONG iwidth2, ULONG colour2, + SLONG sort_to_front) +{ + +#ifdef TARGET_DC + ASSERT ( FALSE ); + return; + +#else + + + float x1 = float(ix1); + float y1 = float(iy1); + float z1 = float(iz1); + float w1 = float(iwidth1); + float r1 = float((colour1 >> 16) & 0xff); + float g1 = float((colour1 >> 8) & 0xff); + float b1 = float((colour1 >> 0) & 0xff); + + float x2 = float(ix2); + float y2 = float(iy2); + float z2 = float(iz2); + float w2 = float(iwidth2); + float r2 = float((colour2 >> 16) & 0xff); + float g2 = float((colour2 >> 8) & 0xff); + float b2 = float((colour2 >> 0) & 0xff); + + float dx = x2 - x1; + float dy = y2 - y1; + float dz = z2 - z1; + float dr = r2 - r1; + float dg = g2 - g1; + float db = b2 - b1; + float dw = w2 - w1; + + float dist = sqrt(dx*dx + dy*dy + dz*dz); + float steps = (float)floor(dist * (1.0F / 1024.0F)) + 1.0F; + float oversteps = 1.0F / steps; + + float x = x1; + float y = y1; + float z = z1; + float w = w1; + float r = r1; + float g = g1; + float b = b1; + + dx *= oversteps; + dy *= oversteps; + dz *= oversteps; + dw *= oversteps; + dr *= oversteps; + dg *= oversteps; + db *= oversteps; + + float f; + + for (f = 0.0F; f < steps; f += 1.0F) + { + colour1 = (SLONG(r ) << 16) | (SLONG(g ) << 8) | (SLONG(b ) << 0); + colour2 = (SLONG(r + dr) << 16) | (SLONG(g + dg) << 8) | (SLONG(b + db) << 0); + + AENG_world_line( + SLONG(x), + SLONG(y), + SLONG(z), + SLONG(w), + colour1, + SLONG(x + dx), + SLONG(y + dy), + SLONG(z + dz), + SLONG(w + dw), + colour2, + sort_to_front); + + x += dx; + y += dy; + z += dz; + w += dw; + r += dr; + g += dg; + b += db; + } +#endif +} + + +struct +{ + float x; + float y; + float z; + +} AENG_cone[5]; + +void AENG_calc_gamut( + float x, + float y, + float z, + float yaw, + float pitch, + float roll, + float draw_dist, + float lens) +{ + float width; + float height; + float depth; + float aspect; + float matrix[9]; + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + // + // The dimensions of the view pyramid. + // + + width = draw_dist; + height = draw_dist; + depth = draw_dist; + + width *= POLY_screen_width; + width /= POLY_screen_height; + + if (FC_cam[1].focus) + { + // + // We are in splitscreen mode. + // + + width *= 2.0F; + } + + width /= lens; + height /= lens; + + // + // Finds the points of the cone in world space + // + + AENG_cone[3].x = AENG_cone[4].x = x / 256.0f; + AENG_cone[3].y = AENG_cone[4].y = y / 256.0f; + AENG_cone[3].z = AENG_cone[4].z = z / 256.0f; + + AENG_cone[3].x += depth * matrix[6]; + AENG_cone[3].y += depth * matrix[7]; + AENG_cone[3].z += depth * matrix[8]; + + // + // AENG_cone[0] is the top left corner... + // + + AENG_cone[0].x = AENG_cone[3].x + height * matrix[3]; + AENG_cone[0].y = AENG_cone[3].y + height * matrix[4]; + AENG_cone[0].z = AENG_cone[3].z + height * matrix[5]; + + AENG_cone[0].x = AENG_cone[0].x - width * matrix[0]; + AENG_cone[0].y = AENG_cone[0].y - width * matrix[1]; + AENG_cone[0].z = AENG_cone[0].z - width * matrix[2]; + + // + // AENG_cone[1] is the top right corner... + // + + AENG_cone[1].x = AENG_cone[3].x + height * matrix[3]; + AENG_cone[1].y = AENG_cone[3].y + height * matrix[4]; + AENG_cone[1].z = AENG_cone[3].z + height * matrix[5]; + + AENG_cone[1].x = AENG_cone[1].x + width * matrix[0]; + AENG_cone[1].y = AENG_cone[1].y + width * matrix[1]; + AENG_cone[1].z = AENG_cone[1].z + width * matrix[2]; + + // + // AENG_cone[2] is the bottom right corner... + // + + AENG_cone[2].x = AENG_cone[3].x - height * matrix[3]; + AENG_cone[2].y = AENG_cone[3].y - height * matrix[4]; + AENG_cone[2].z = AENG_cone[3].z - height * matrix[5]; + + AENG_cone[2].x = AENG_cone[2].x + width * matrix[0]; + AENG_cone[2].y = AENG_cone[2].y + width * matrix[1]; + AENG_cone[2].z = AENG_cone[2].z + width * matrix[2]; + + // + // AENG_cone[3] is the bottom left corner... + // + + AENG_cone[3].x = AENG_cone[3].x - height * matrix[3]; + AENG_cone[3].y = AENG_cone[3].y - height * matrix[4]; + AENG_cone[3].z = AENG_cone[3].z - height * matrix[5]; + + AENG_cone[3].x = AENG_cone[3].x - width * matrix[0]; + AENG_cone[3].y = AENG_cone[3].y - width * matrix[1]; + AENG_cone[3].z = AENG_cone[3].z - width * matrix[2]; + + // + // Create the gamut. + // + + NGAMUT_init(); + + NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[0].x, AENG_cone[0].z); + NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[1].x, AENG_cone[1].z); + NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[2].x, AENG_cone[2].z); + NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[3].x, AENG_cone[3].z); + + NGAMUT_add_line(AENG_cone[0].x, AENG_cone[0].z, AENG_cone[1].x, AENG_cone[1].z); + NGAMUT_add_line(AENG_cone[1].x, AENG_cone[1].z, AENG_cone[2].x, AENG_cone[2].z); + NGAMUT_add_line(AENG_cone[2].x, AENG_cone[2].z, AENG_cone[3].x, AENG_cone[3].z); + NGAMUT_add_line(AENG_cone[3].x, AENG_cone[3].z, AENG_cone[0].x, AENG_cone[0].z); + + NGAMUT_calculate_point_gamut(); + NGAMUT_calculate_out_gamut(); + NGAMUT_calculate_lo_gamut(); +} + + + + +// The gamut calculation for the skyline - lo-rez map only. +// This doesn't even do the gamut "properly" - there are only 32x32 squares, +// so it's much quicker to just find the bounding box. Much easier too. +// So, only these four are updated: +SLONG AENG_gamut_lo_xmin; +SLONG AENG_gamut_lo_xmax; +SLONG AENG_gamut_lo_zmin; +SLONG AENG_gamut_lo_zmax; + +void AENG_calc_gamut_lo_only( + float x, + float y, + float z, + float yaw, + float pitch, + float roll, + float draw_dist, + float lens) +{ + float width; + float height; + float depth; + float aspect; + float matrix[9]; + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + // + // The dimensions of the view pyramid. + // + + width = draw_dist; + height = draw_dist; + depth = draw_dist; + + width *= POLY_screen_width; + width /= POLY_screen_height; + + if (FC_cam[1].focus) + { + // + // We are in splitscreen mode. + // + + width *= 2.0F; + } + + width /= lens; + height /= lens; + + // + // Finds the points of the cone in world space + // + + AENG_cone[3].x = AENG_cone[4].x = x / 256.0f; + //AENG_cone[3].y = AENG_cone[4].y = y / 256.0f; + AENG_cone[3].z = AENG_cone[4].z = z / 256.0f; + + AENG_cone[3].x += depth * matrix[6]; + //AENG_cone[3].y += depth * matrix[7]; + AENG_cone[3].z += depth * matrix[8]; + + // + // AENG_cone[0] is the top left corner... + // + + AENG_cone[0].x = ( AENG_cone[3].x + height * matrix[3] ); + //AENG_cone[0].y = ( AENG_cone[3].y + height * matrix[4] ); + AENG_cone[0].z = ( AENG_cone[3].z + height * matrix[5] ); + + AENG_cone[0].x = ( AENG_cone[0].x - width * matrix[0] ); + //AENG_cone[0].y = ( AENG_cone[0].y - width * matrix[1] ); + AENG_cone[0].z = ( AENG_cone[0].z - width * matrix[2] ); + + // + // AENG_cone[1] is the top right corner... + // + + AENG_cone[1].x = ( AENG_cone[3].x + height * matrix[3] ); + //AENG_cone[1].y = ( AENG_cone[3].y + height * matrix[4] ); + AENG_cone[1].z = ( AENG_cone[3].z + height * matrix[5] ); + + AENG_cone[1].x = ( AENG_cone[1].x + width * matrix[0] ); + //AENG_cone[1].y = ( AENG_cone[1].y + width * matrix[1] ); + AENG_cone[1].z = ( AENG_cone[1].z + width * matrix[2] ); + + // + // AENG_cone[2] is the bottom right corner... + // + + AENG_cone[2].x = ( AENG_cone[3].x - height * matrix[3] ); + //AENG_cone[2].y = ( AENG_cone[3].y - height * matrix[4] ); + AENG_cone[2].z = ( AENG_cone[3].z - height * matrix[5] ); + + AENG_cone[2].x = ( AENG_cone[2].x + width * matrix[0] ); + //AENG_cone[2].y = ( AENG_cone[2].y + width * matrix[1] ); + AENG_cone[2].z = ( AENG_cone[2].z + width * matrix[2] ); + + // + // AENG_cone[3] is the bottom left corner... + // + + AENG_cone[3].x = ( AENG_cone[3].x - height * matrix[3] ); + //AENG_cone[3].y = ( AENG_cone[3].y - height * matrix[4] ); + AENG_cone[3].z = ( AENG_cone[3].z - height * matrix[5] ); + + AENG_cone[3].x = ( AENG_cone[3].x - width * matrix[0] ); + //AENG_cone[3].y = ( AENG_cone[3].y - width * matrix[1] ); + AENG_cone[3].z = ( AENG_cone[3].z - width * matrix[2] ); + + // + // Create the gamut. + // + + + // Clip the eight lines to the size of the map, then find their bounding box. + float gamut_lo_xmax = AENG_cone[4].x * 0.25f; + float gamut_lo_xmin = AENG_cone[4].x * 0.25f; + float gamut_lo_zmax = AENG_cone[4].z * 0.25f; + float gamut_lo_zmin = AENG_cone[4].z * 0.25f; + // Point 4 should always be on the map, AFAICS. + ASSERT ( ( gamut_lo_xmax < PAP_SIZE_LO ) && ( gamut_lo_xmin > 0 ) ); + ASSERT ( ( gamut_lo_xmax < PAP_SIZE_LO ) && ( gamut_lo_xmin > 0 ) ); + + for ( int i = 0; i < 8; i++ ) + { + int iPt1, iPt2; + switch ( i ) + { + case 0: iPt1 = 4; iPt2 = 0; break; + case 1: iPt1 = 4; iPt2 = 1; break; + case 2: iPt1 = 4; iPt2 = 2; break; + case 3: iPt1 = 4; iPt2 = 3; break; + case 4: iPt1 = 0; iPt2 = 1; break; + case 5: iPt1 = 1; iPt2 = 2; break; + case 6: iPt1 = 2; iPt2 = 3; break; + case 7: iPt1 = 3; iPt2 = 4; break; + } + + float fX1 = AENG_cone[iPt1].x * 0.25f; + float fZ1 = AENG_cone[iPt1].z * 0.25f; + float fX2 = AENG_cone[iPt2].x * 0.25f; + float fZ2 = AENG_cone[iPt2].z * 0.25f; + + // Clip to +ve X + if ( fX1 >= PAP_SIZE_LO ) + { + if ( fX2 >= PAP_SIZE_LO ) + { + // Quick reject. + gamut_lo_xmax = PAP_SIZE_LO; + continue; + } + else + { + float lambda = ( (float)PAP_SIZE_LO - fX1 ) / ( fX2 - fX1 ); + fZ1 = fZ1 + lambda * ( fZ2 - fZ1 ); + fX1 = PAP_SIZE_LO; + } + } + else + { + if ( fX2 >= PAP_SIZE_LO ) + { + float lambda = ( (float)PAP_SIZE_LO - fX1 ) / ( fX2 - fX1 ); + fZ2 = fZ1 + lambda * ( fZ2 - fZ1 ); + fX2 = PAP_SIZE_LO; + } + else + { + // Accept. + } + } + + // Clip to 0 X + if ( fX1 <= 0.0f ) + { + if ( fX2 <= 0.0f ) + { + // Quick reject. + gamut_lo_xmin = 0; + continue; + } + else + { + float lambda = ( 0.0f - fX1 ) / ( fX2 - fX1 ); + fZ1 = fZ1 + lambda * ( fZ2 - fZ1 ); + fX1 = 0.0f; + } + } + else + { + if ( fX2 <= 0.0f ) + { + float lambda = ( 0.0f - fX1 ) / ( fX2 - fX1 ); + fZ2 = fZ1 + lambda * ( fZ2 - fZ1 ); + fX2 = 0.0f; + } + else + { + // Accept. + } + } + + // Clip to +ve Z + if ( fZ1 >= PAP_SIZE_LO ) + { + if ( fZ2 >= PAP_SIZE_LO ) + { + // Quick reject. + gamut_lo_zmax = PAP_SIZE_LO; + continue; + } + else + { + float lambda = ( (float)PAP_SIZE_LO - fZ1 ) / ( fZ2 - fZ1 ); + fX1 = fX1 + lambda * ( fX2 - fX1 ); + fZ1 = PAP_SIZE_LO; + } + } + else + { + if ( fZ2 >= PAP_SIZE_LO ) + { + float lambda = ( (float)PAP_SIZE_LO - fZ1 ) / ( fZ2 - fZ1 ); + fX2 = fX1 + lambda * ( fX2 - fX1 ); + fZ2 = PAP_SIZE_LO; + } + else + { + // Accept. + } + } + + // Clip to 0 Z + if ( fZ1 <= 0.0f ) + { + if ( fZ2 <= 0.0f ) + { + // Quick reject. + gamut_lo_zmin = 0; + continue; + } + else + { + float lambda = ( 0.0f - fZ1 ) / ( fZ2 - fZ1 ); + fX1 = fX1 + lambda * ( fX2 - fX1 ); + fZ1 = 0.0f; + } + } + else + { + if ( fZ2 <= 0.0f ) + { + float lambda = ( 0.0f - fZ1 ) / ( fZ2 - fZ1 ); + fX2 = fX1 + lambda * ( fX2 - fX1 ); + fZ2 = 0.0f; + } + else + { + // Accept. + } + } + + + ASSERT ( ( fX1 <= PAP_SIZE_LO ) && ( fX1 >= 0.0f ) ); + ASSERT ( ( fX2 <= PAP_SIZE_LO ) && ( fX2 >= 0.0f ) ); + ASSERT ( ( fZ1 <= PAP_SIZE_LO ) && ( fZ1 >= 0.0f ) ); + ASSERT ( ( fZ2 <= PAP_SIZE_LO ) && ( fZ2 >= 0.0f ) ); + + + // Expand BB. + if ( gamut_lo_xmax < fX1 ) + { + gamut_lo_xmax = fX1; + } + else if ( gamut_lo_xmin > fX1 ) + { + gamut_lo_xmin = fX1; + } + if ( gamut_lo_zmax < fZ1 ) + { + gamut_lo_zmax = fZ1; + } + else if ( gamut_lo_zmin > fZ1 ) + { + gamut_lo_zmin = fZ1; + } + + if ( gamut_lo_xmax < fX2 ) + { + gamut_lo_xmax = fX2; + } + else if ( gamut_lo_xmin > fX2 ) + { + gamut_lo_xmin = fX2; + } + if ( gamut_lo_zmax < fZ2 ) + { + gamut_lo_zmax = fZ2; + } + else if ( gamut_lo_zmin > fZ2 ) + { + gamut_lo_zmin = fZ2; + } + + } + + +#if 0 + + float gamut_lo_xmax = AENG_cone[0].x; + float gamut_lo_xmin = AENG_cone[0].x; + float gamut_lo_zmax = AENG_cone[0].z; + float gamut_lo_zmin = AENG_cone[0].z; + for ( int i = 1; i <= 4; i++ ) + { + if ( gamut_lo_xmax < AENG_cone[i].x ) + { + gamut_lo_xmax = AENG_cone[i].x; + } + else if ( gamut_lo_xmin > AENG_cone[i].x ) + { + gamut_lo_xmin = AENG_cone[i].x; + } + if ( gamut_lo_zmax < AENG_cone[i].z ) + { + gamut_lo_zmax = AENG_cone[i].z; + } + else if ( gamut_lo_zmin > AENG_cone[i].z ) + { + gamut_lo_zmin = AENG_cone[i].z; + } + } + +#endif + +#if 1 + AENG_gamut_lo_xmin = (SLONG)( gamut_lo_xmin ); + AENG_gamut_lo_xmax = (SLONG)( gamut_lo_xmax ); + AENG_gamut_lo_zmin = (SLONG)( gamut_lo_zmin ); + AENG_gamut_lo_zmax = (SLONG)( gamut_lo_zmax ); +#else + AENG_gamut_lo_xmin = (SLONG)( gamut_lo_xmin * 0.25f ); + AENG_gamut_lo_xmax = (SLONG)( gamut_lo_xmax * 0.25f ); + AENG_gamut_lo_zmin = (SLONG)( gamut_lo_zmin * 0.25f ); + AENG_gamut_lo_zmax = (SLONG)( gamut_lo_zmax * 0.25f ); +#endif + + // Just catch the dodgy edge condition. + if ( AENG_gamut_lo_xmax == PAP_SIZE_LO ) + { + AENG_gamut_lo_xmax = PAP_SIZE_LO - 1; + } + if ( AENG_gamut_lo_xmin == PAP_SIZE_LO ) + { + AENG_gamut_lo_xmin = PAP_SIZE_LO - 1; + } + if ( AENG_gamut_lo_zmax == PAP_SIZE_LO ) + { + AENG_gamut_lo_zmax = PAP_SIZE_LO - 1; + } + if ( AENG_gamut_lo_zmin == PAP_SIZE_LO ) + { + AENG_gamut_lo_zmin = PAP_SIZE_LO - 1; + } + + + +#if 0 + if ( AENG_gamut_lo_xmax < 0 ) + { + AENG_gamut_lo_xmax = 0; + AENG_gamut_lo_xmin = 0; + } + else if ( AENG_gamut_lo_xmax >= PAP_SIZE_LO ) + { + AENG_gamut_lo_xmax = PAP_SIZE_LO - 1; + } + + if ( AENG_gamut_lo_xmin >= PAP_SIZE_LO ) + { + AENG_gamut_lo_xmax = PAP_SIZE_LO - 1; + AENG_gamut_lo_xmin = PAP_SIZE_LO - 1; + } + else if ( AENG_gamut_lo_xmin < 0 ) + { + AENG_gamut_lo_xmin = 0; + } + + if ( AENG_gamut_lo_zmax < 0 ) + { + AENG_gamut_lo_zmax = 0; + AENG_gamut_lo_zmin = 0; + } + else if ( AENG_gamut_lo_zmax >= PAP_SIZE_LO ) + { + AENG_gamut_lo_zmax = PAP_SIZE_LO - 1; + } + + if ( AENG_gamut_lo_zmin >= PAP_SIZE_LO ) + { + AENG_gamut_lo_zmax = PAP_SIZE_LO - 1; + AENG_gamut_lo_zmin = PAP_SIZE_LO - 1; + } + else if ( AENG_gamut_lo_zmin < 0 ) + { + AENG_gamut_lo_zmin = 0; + } +#endif + +} + + +void AENG_set_camera_radians( + SLONG wx, + SLONG wy, + SLONG wz, + float y, + float p, + float r) +{ + AENG_cam_x = float(wx); + AENG_cam_y = float(wy); + AENG_cam_z = float(wz); + + AENG_cam_yaw = y; + AENG_cam_pitch = p; + AENG_cam_roll = r; + + MATRIX_calc( + AENG_cam_matrix, + y,p,r); + + POLY_camera_set( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + float(AENG_DRAW_DIST) * 256.0F, + AENG_LENS, + POLY_SPLITSCREEN_NONE); + + FMATRIX_vector(AENG_cam_vec,(y*2048)/(2*PI),(p*2048)/(2*PI)); + + // + // Create the gamut + // + + AENG_calc_gamut( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + AENG_DRAW_DIST, + AENG_LENS); +} + + +void AENG_set_camera_radians( + SLONG wx, + SLONG wy, + SLONG wz, + float y, + float p, + float r, + SLONG splitscreen) +{ + AENG_cam_x = float(wx); + AENG_cam_y = float(wy); + AENG_cam_z = float(wz); + + AENG_cam_yaw = y; + AENG_cam_pitch = p; + AENG_cam_roll = r; + + MATRIX_calc( + AENG_cam_matrix, + y,p,r); + + POLY_camera_set( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + float(AENG_DRAW_DIST) * 256.0F, + AENG_LENS, + splitscreen); + + FMATRIX_vector(AENG_cam_vec,(y*2048)/(2*PI),(p*2048)/(2*PI)); + + + // + // Create the gamut + // + + AENG_calc_gamut( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + AENG_DRAW_DIST, + AENG_LENS); +} + +void AENG_set_camera( + SLONG wx, + SLONG wy, + SLONG wz, + SLONG y, + SLONG p, + SLONG r) +{ + float radians_yaw = float(y) * (2.0F * PI / 2048.0F); + float radians_pitch = float(p) * (2.0F * PI / 2048.0F); + float radians_roll = float(r) * (2.0F * PI / 2048.0F); + + FC_cam[0].x=wx<<8; + FC_cam[0].y=wy<<8; + FC_cam[0].z=wz<<8; + + FC_cam[0].yaw=y<<8; + FC_cam[0].pitch=p<<8; + FC_cam[0].roll=r<<8; + + AENG_set_camera_radians( + wx, + wy, + wz, + radians_yaw, + radians_pitch, + radians_roll, + POLY_SPLITSCREEN_NONE); +} + + + + + + +void AENG_do_cached_lighting_old(void) +{ + SLONG i; + SLONG x; + SLONG z; + SLONG kept=0,new_squares=0; + + NIGHT_Square *nq; + +extern SLONG HEAP_max_free(void); + + if(HEAP_max_free()<4000 || Keys[KB_Q]) + { + CBYTE str[100]; + NIGHT_destroy_all_cached_info(); + +// sprintf(str," RECALC LIGHTING FREE = %d",HEAP_max_free()); +// CONSOLE_text(str,10000); + } + else + { + // + // Get rid of any cached squares we dont need anymore. + // + + for (i = 1; i < NIGHT_MAX_SQUARES; i++) + { + nq = &NIGHT_square[i]; + + if (nq->flag & NIGHT_SQUARE_FLAG_USED) + { + if (WITHIN(nq->lo_map_z, NGAMUT_lo_zmin, NGAMUT_lo_zmax) && + WITHIN( + nq->lo_map_x, + NGAMUT_lo_gamut[nq->lo_map_z].xmin, + NGAMUT_lo_gamut[nq->lo_map_z].xmax)) + { + // + // We still need this cache info. + // + kept++; + } + else + { + // + // We dont need this square any more. + // + + NIGHT_cache_destroy(i); + } + } + } + } + + + + + if(INDOORS_INDEX) + { + if(light_inside!=INDOORS_INDEX) + { + // + // remove floor lighting + // + for (i = 1; i < NIGHT_MAX_SQUARES; i++) + { + nq = &NIGHT_square[i]; + if (nq->flag & NIGHT_SQUARE_FLAG_USED) + NIGHT_cache_destroy(i); + } + + } + light_inside=INDOORS_INDEX; + + // + // create the squares we need for the inside bounding rect clipped with gamut + // + + { + SLONG x,z,floor_y; + struct InsideStorey *p_inside; + SLONG in_width; + UBYTE *in_block; + SLONG min_z,max_z; + SLONG min_x,max_x; + + + + p_inside=&inside_storeys[INDOORS_INDEX]; + + floor_y=p_inside->StoreyY; + + min_z=MAX(NGAMUT_lo_zmin,p_inside->MinZ>>2); + max_z=MIN(NGAMUT_lo_zmax,p_inside->MaxZ>>2); + + in_width=p_inside->MaxX-p_inside->MinX; + + for (z = min_z; z <= max_z+1; z++) + { + min_x=MAX(NGAMUT_lo_gamut[z].xmin,p_inside->MinX>>2); + max_x=MIN(NGAMUT_lo_gamut[z].xmax,p_inside->MaxX>>2); + + if(z>min_z) + { + min_x=MIN(NGAMUT_lo_gamut[z-1].xmin,min_x); + max_x=MAX(NGAMUT_lo_gamut[z-1].xmax,max_x); + } + + for (x = min_x;x<=max_x+1;x++) + { + if (NIGHT_cache[x][z] == NULL) + { + // + // Creating cached lighting for this square. + // + + NIGHT_cache_create_inside(x,z,floor_y); + new_squares++; + } + + + } + } + } + + return; + } + else + if(light_inside) + { + light_inside=0; + for (i = 1; i < NIGHT_MAX_SQUARES; i++) + { + nq = &NIGHT_square[i]; + + if (nq->flag & NIGHT_SQUARE_FLAG_USED) + { + NIGHT_cache_destroy(i); + } + } + } + + // + // Create any square we need. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + if (NIGHT_cache[x][z] == NULL) + { + // + // Creating cached lighting for this square. + // + + NIGHT_cache_create(x,z); + } + } + } +} + +// +// Marks all caches squares with 'DELETEME'. When a square is drawn +// its DELETEME flag is cleared. +// + +void AENG_mark_night_squares_as_deleteme(void) +{ + SLONG i; + + NIGHT_Square *nq; + + for (i = 1; i < NIGHT_MAX_SQUARES; i++) + { + nq = &NIGHT_square[i]; + + // + // Do this to all NIGHT_squares... not just the used ones. + // + + nq->flag |= NIGHT_SQUARE_FLAG_DELETEME; + } +} + +// +// Makes sure that all lo-res gamut squares have the right kind of +// lighting caching done for them. (In a warehouse or not). +// + +void AENG_ensure_appropriate_caching(SLONG ware) +{ + SLONG x; + SLONG z; + SLONG ok; + + NIGHT_Square *nq; + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + if (NIGHT_cache[x][z] == NULL) + { + // + // Creating cached lighting for this square. + // + + NIGHT_cache_create(x,z,ware); + } + else + { + // + // Make sure this square has the correct type. + // + + nq = &NIGHT_square[NIGHT_cache[x][z]]; + + if (nq->flag & NIGHT_SQUARE_FLAG_WARE) + { + ok = ware; + } + else + { + ok = !ware; + } + + if (!ok) + { + // + // The caching is the wrong sort! + // + + NIGHT_cache_destroy(NIGHT_cache[x][z]); + NIGHT_cache_create(x,z,ware); + } + } + } + } +} + + +void AENG_get_rid_of_deleteme_squares() +{ + SLONG i; + + NIGHT_Square *nq; + + for (i = 1; i < NIGHT_MAX_SQUARES; i++) + { + nq = &NIGHT_square[i]; + + if (nq->flag & NIGHT_SQUARE_FLAG_USED) + { + if (nq->flag & NIGHT_SQUARE_FLAG_DELETEME) + { + NIGHT_cache_destroy(i); + } + } + } +} + +// +// Adds a projected shadow poly to the POLY module. +// + +float AENG_project_offset_u; +float AENG_project_offset_v; + +float AENG_project_mul_u; +float AENG_project_mul_v; + +float AENG_project_lit_light_x; +float AENG_project_lit_light_y; +float AENG_project_lit_light_z; +float AENG_project_lit_light_range; + +float AENG_project_fadeout_x; +float AENG_project_fadeout_z; + + +#define SHADOW_Z_BIAS_BODGE 0.0001f + + +void AENG_add_projected_shadow_poly(SMAP_Link *sl) +{ + SLONG i; + + POLY_Point *pp; + + // + // Transform all the points into the poly buffer. + // + + POLY_buffer_upto = 0; + + while(sl) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform( + sl->wx, + sl->wy, + sl->wz, + pp); + + if (pp->MaybeValid()) + { + pp->u = AENG_project_offset_u + sl->u * AENG_project_mul_u; + pp->v = AENG_project_offset_v + sl->v * AENG_project_mul_v; + + pp->colour = 0xffffffff; + pp->specular = 0xff000000; + +#ifdef TARGET_DC + // Stop Z fighting + pp->Z += SHADOW_Z_BIAS_BODGE; +#endif + } + else + { + // + // Abandon the whole shadow polygon. + // + + return; + } + + sl = sl->next; + } + + // + // Add the triangles. + // + + POLY_Point *tri[3]; + + tri[0] = &POLY_buffer[0]; + + for (i = 1; i < POLY_buffer_upto - 1; i++) + { + tri[1] = &POLY_buffer[i + 0]; + tri[2] = &POLY_buffer[i + 1]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_SHADOW, TRUE); + } + } +} + +void AENG_add_projected_fadeout_shadow_poly(SMAP_Link *sl) +{ + float dx; + float dz; + float dist; + + SLONG i; + SLONG alpha; + + POLY_Point *pp; + + // + // Transform all the points into the poly buffer. + // + + POLY_buffer_upto = 0; + + while(sl) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform( + sl->wx, + sl->wy, + sl->wz, + pp); + + if (pp->MaybeValid()) + { + dx = sl->wx - AENG_project_fadeout_x; + dz = sl->wz - AENG_project_fadeout_z; + + dist = fabs(dx) + fabs(dz); + + if (dist < 64.0F) + { + alpha = 0xff; + } + else + { + if (dist > 256.0F) + { + alpha = 0; + } + else + { + alpha = 0xff - SLONG((dist - 64.0F) * (255.0F / 192.0F)); + } + } + + pp->u = AENG_project_offset_u + sl->u * AENG_project_mul_u; + pp->v = AENG_project_offset_v + sl->v * AENG_project_mul_v; + + alpha |= alpha << 8; + alpha |= alpha << 16; + + pp->colour = alpha; + pp->specular = 0xff000000; + +#ifdef TARGET_DC + // Stop Z fighting + pp->Z += SHADOW_Z_BIAS_BODGE; +#endif + } + else + { + // + // Abandon the whole shadow polygon. + // + + return; + } + + sl = sl->next; + } + + // + // Add the triangles. + // + + POLY_Point *tri[3]; + + tri[0] = &POLY_buffer[0]; + + for (i = 1; i < POLY_buffer_upto - 1; i++) + { + tri[1] = &POLY_buffer[i + 0]; + tri[2] = &POLY_buffer[i + 1]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_SHADOW, TRUE); + } + } +} + +void AENG_add_projected_lit_shadow_poly(SMAP_Link *sl) +{ + SLONG i; + + float dx; + float dy; + float dz; + float dist; + float bright; + + POLY_Point *pp; + + // + // Transform all the points into the poly buffer. + // + + POLY_buffer_upto = 0; + + while(sl) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform( + sl->wx, + sl->wy, + sl->wz, + pp); + + if (pp->MaybeValid()) + { + pp->u = AENG_project_offset_u + sl->u * AENG_project_mul_u; + pp->v = AENG_project_offset_v + sl->v * AENG_project_mul_v; + + dx = sl->wx - AENG_project_lit_light_x; + dy = sl->wy - AENG_project_lit_light_y; + dz = sl->wz - AENG_project_lit_light_z; + + dist = fabs(dx) + fabs(dy) + fabs(dz); + bright = dist / AENG_project_lit_light_range; + bright = 1.0F - bright; + bright *= 512.0F; + + if (bright > 0.0F) + { + SLONG alpha = SLONG(bright); + + if (alpha > 255) {alpha = 255;} + + alpha |= alpha << 8; + alpha |= alpha << 16; +#ifdef TARGET_DC + alpha |= 0xff000000; +#endif + + pp->colour = alpha; + pp->specular = 0xff000000; + } + else + { +#ifdef TARGET_DC + pp->colour = 0xff000000; +#else + pp->colour = 0x00000000; +#endif + pp->specular = 0xff000000; + } + +#ifdef TARGET_DC + // Stop Z fighting + pp->Z += SHADOW_Z_BIAS_BODGE; +#endif + + } + else + { + // + // Abandon the whole shadow polygon. + // + + return; + } + + sl = sl->next; + } + + // + // Add the triangles. + // + + POLY_Point *tri[3]; + + tri[0] = &POLY_buffer[0]; + + for (i = 1; i < POLY_buffer_upto - 1; i++) + { + tri[1] = &POLY_buffer[i + 0]; + tri[2] = &POLY_buffer[i + 1]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_SHADOW, TRUE); + } + } +} + + + +// +// Draws the rain. +// + +void AENG_draw_rain_old(float angle) +{ + SLONG i; + + float vec1x; + float vec1y; + float vec2x; + float vec2y; + + float z; + float X; + float Y; + float Z; + + POLY_Point pp [3]; + POLY_Point *tri[3]; + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + // + // Common to all poly points. + // + + pp[0].colour = 0x00000000; + pp[1].colour = 0x88333344; + pp[2].colour = 0x88555577; + + pp[0].specular = 0x00000000; + pp[1].specular = 0x00000000; + pp[2].specular = 0x00000000; + + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[1].u = 0.0F; + pp[1].v = 0.0F; + pp[2].u = 0.0F; + pp[2].v = 0.0F; + + // + // Work out the vectors from the angle. + // + + #define AENG_RAIN_SIZE (4.0F) + + vec1x = (float)sin(angle) * (32.0F * AENG_RAIN_SIZE); + vec1y = -(float)cos(angle) * (32.0F * AENG_RAIN_SIZE); + + vec2x = (float)cos(angle) * AENG_RAIN_SIZE; + vec2y = (float)sin(angle) * AENG_RAIN_SIZE; + + #define AENG_NUM_RAINDROPS 128 + + for (i = 0; i < AENG_NUM_RAINDROPS; i++) + { + z = float(rand() & 0xff) * (0.5F / 256.0F) + POLY_ZCLIP_PLANE; + X = float(rand() % DisplayWidth); + Y = float(rand() % DisplayHeight); + Z = POLY_ZCLIP_PLANE / z; + + pp[0].X = X; + pp[0].Y = Y; + pp[0].Z = Z; + pp[0].z = z; + + pp[1].X = X + vec1x * Z; + pp[1].Y = Y + vec1y * Z; + pp[1].Z = Z; + pp[1].z = z; + + pp[2].X = X + vec2x * Z; + pp[2].Y = Y + vec2y * Z; + pp[2].Z = Z; + pp[2].z = z; + + POLY_add_triangle(tri, POLY_PAGE_ALPHA, FALSE, TRUE); + } +} + + +void AENG_draw_rain() +{ + SLONG i; + + float x1; + float y1; + float z1; + + float x2; + float y2; + float z2; + + float matrix[9]; + + float fade; + SLONG bright; + SLONG r; + SLONG g; + SLONG b; + ULONG colour; + + // + // The cameras view matrix. + // + + MATRIX_calc( + matrix, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll); + + // + // Fiddle the matrix so multipling (a,b,c) by the matrix + // where a,b are between -1 and 1 and c is between 0 and 1 + // gives a place in the world that the camera can see... + // + + matrix[0] *= 640.0F / 480.0F; + matrix[1] *= 640.0F / 480.0F; + matrix[2] *= 640.0F / 480.0F; + + matrix[0] /= AENG_LENS; + matrix[1] /= AENG_LENS; + matrix[2] /= AENG_LENS; + + matrix[3] /= AENG_LENS; + matrix[4] /= AENG_LENS; + matrix[5] /= AENG_LENS; + + // + // Rain lasts 8 squares into the distance. + // + +//#undef AENG_NUM_RAINDROPS +//#define AENG_NUM_RAINDROPS 500 + + matrix[0] *= 256.0F * 8.0F; + matrix[1] *= 256.0F * 8.0F; + matrix[2] *= 256.0F * 8.0F; + + matrix[3] *= 256.0F * 8.0F; + matrix[4] *= 256.0F * 8.0F; + matrix[5] *= 256.0F * 8.0F; + + matrix[6] *= 256.0F * 8.0F; + matrix[7] *= 256.0F * 8.0F; + matrix[8] *= 256.0F * 8.0F; + + for (i = 0; i < AENG_NUM_RAINDROPS; i++) + { + // + // Pick a random place in world space in front of the camera. + // + + x1 = float(rand()) * (1.0F / float(RAND_MAX >> 1)) - 1.0F; + y1 = float(rand()) * (1.0F / float(RAND_MAX >> 1)) - 0.5F; + z1 = float(rand()) * (1.0F / float(RAND_MAX )) + 0.1F; + + fade = 1.0F - z1 * 0.8F; + bright = SLONG(fade * 256.0F); + + colour = (bright << 24) | ((69 << 16) | (74 << 8) | (98 << 0)); + + MATRIX_MUL_BY_TRANSPOSE( + matrix, + x1, + y1, + z1); + + x1 += AENG_cam_x; + y1 += AENG_cam_y; + z1 += AENG_cam_z; + +#if 1 // shade the rain + SLONG px = SLONG(x1) >> 10; + SLONG pz = SLONG(z1) >> 10; + SLONG dx = (SLONG(x1) >> 8) & 3; + SLONG dz = (SLONG(z1) >> 8) & 3; + + if ((px < 0) || (px >= PAP_SIZE_LO)) continue; + if ((pz < 0) || (pz >= PAP_SIZE_LO)) continue; + + SLONG square = NIGHT_cache[px][pz]; + + if (!square) continue; + + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + + NIGHT_Square* nq = &NIGHT_square[square]; + ULONG col,spec; + + NIGHT_get_d3d_colour(nq->colour[dx + dz * PAP_BLOCKS], &col, &spec); + + colour = col; +#endif + + SHAPE_droplet( + SLONG(x1), + SLONG(y1), + SLONG(z1), + 8, + -64, + 8, + colour, + POLY_PAGE_RAINDROP); + } +} + +void AENG_draw_drips(UBYTE puddles_only) +{ + // + // Draw the drips. + // + + SLONG i; + + float midx; + float midy; + float midz; + + float px; + float pz; + + float radius; + ULONG colour; + + DRIP_Info *di; + + POLY_Point pp[4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + // + // The same for all drips. + // + + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + + pp[0].specular = 0xff000000; + pp[1].specular = 0xff000000; + pp[2].specular = 0xff000000; + pp[3].specular = 0xff000000; + + DRIP_get_start(); + + while(di = DRIP_get_next()) + { + + if (puddles_only != (di->flags&DRIP_FLAG_PUDDLES_ONLY)) + continue; // Abandon this drip. + + + midx = float(di->x); + midy = float(di->y); + midz = float(di->z); + + midy += 8.0F; + + radius = float(di->size); + + for (i = 0; i < 4; i++) + { + px = midx + ((i & 0x1) ? +radius : -radius); + pz = midz + ((i & 0x2) ? +radius : -radius); + + POLY_transform(px, midy, pz, &pp[i]); + + if (!pp[i].IsValid()) + continue; // Abandon this drip. + } + + if (POLY_valid_quad(quad)) + { + colour = (di->fade << 16) | (di->fade << 8) | (di->fade << 0); + + pp[0].colour = colour; + pp[1].colour = colour; + pp[2].colour = colour; + pp[3].colour = colour; + + POLY_add_quad(quad, POLY_PAGE_DRIP, FALSE); + } + + } +} + + +// +// Adds the bangs in the current gamut to the POLY module. +// + +void AENG_draw_bangs() +{ + float u_mid; + float v_mid; +#ifdef DOG_POO + SLONG z; + + BANG_Info *bi; + + for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++) + { + BANG_get_start( + NGAMUT_point_gamut[z].xmin, + NGAMUT_point_gamut[z].xmax, + z); + + while(bi = BANG_get_next()) + { + u_mid = (1.0F / 8.0F) + (1.0F / 4.0F) * float(bi->frame & 0x3); + v_mid = (1.0F / 8.0F) + (1.0F / 4.0F) * float(bi->frame >> 2); + + #ifdef MAKE_THEM_FACE_THE_CAMERA + + // + // Always make it face the camera. + // + + float dx = AENG_cam_x - float(bi->x); + float dy = AENG_cam_y - float(bi->y); + float dz = AENG_cam_z - float(bi->z); + +#ifdef TARGET_DC + float len = 256.0f * _InvSqrtA(dx*dx + dy*dy + dz*dz); + + dx = dx * len; + dy = dy * len; + dz = dz * len; +#else + float len = sqrt(dx*dx + dy*dy + dz*dz); + + dx = dx * (256.0F / len); + dy = dy * (256.0F / len); + dz = dz * (256.0F / len); +#endif + + #endif + + SHAPE_semisphere_textured( + bi->x, + bi->y, + bi->z, + bi->dx, + bi->dy, + bi->dz, + bi->radius, + u_mid, + v_mid, + 1.0F / 8.0F, + POLY_PAGE_BANG, + bi->red, + bi->green, + bi->blue); + } + } +#endif +} + +// +// Draws the cloth. +// + +void AENG_draw_cloth(void) +{ +#ifdef DOG_POO + SLONG i; + + SLONG x; + SLONG z; + + UBYTE cloth; + + CLOTH_Info *ci; + + POLY_Point pp[CLOTH_WIDTH * CLOTH_HEIGHT]; + + // + // Our lighting normal for each point. The normal's length is less + // than one so the dprod will always be in range. The normal from + // the CLOTH module is only approximately of length 1.0! + // + + static float light_x = 0.55F; + static float light_y = 0.55F; + static float light_z = 0.55F; + + float dprod; + + SLONG bright; + SLONG r; + SLONG g; + SLONG b; + + SLONG base_r; + SLONG base_g; + SLONG base_b; + + SLONG px; + SLONG py; + + POLY_Point *quad[4]; + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + for (cloth = CLOTH_get_first(x,z); cloth; cloth = ci->next) + { + ci = CLOTH_get_info(cloth); + + base_r = (ci->colour >> 16) & 0xff; + base_g = (ci->colour >> 8) & 0xff; + base_b = (ci->colour >> 0) & 0xff; + + // + // Transform all the points. + // + + for (i = 0; i < CLOTH_WIDTH * CLOTH_HEIGHT; i++) + { + POLY_transform( + ci->p[i].x, + ci->p[i].y, + ci->p[i].z, + &pp[i]); + + if (!pp[i].MaybeValid()) + { + goto abandon_this_cloth; + } + + // + // Light the point. + // + + dprod = + light_x * ci->p[i].nx + + light_y * ci->p[i].ny + + light_z * ci->p[i].nz; + + dprod = fabs(dprod); + bright = SLONG(dprod * 255.0F); + + r = bright * base_r >> 8; + g = bright * base_g >> 8; + b = bright * base_b >> 8; + + pp[i].colour = (r << 16) | (g << 8) | (b << 0); + pp[i].specular = 0xff000000; + pp[i].u = 0.0F; + pp[i].v = 0.0F; + } + + // + // Create all the faces. + // + + for (px = 0; px < CLOTH_WIDTH - 1; px++) + for (py = 0; py < CLOTH_HEIGHT - 1; py++) + { + quad[0] = &pp[CLOTH_INDEX(px + 0, py + 0)]; + quad[1] = &pp[CLOTH_INDEX(px + 1, py + 0)]; + quad[2] = &pp[CLOTH_INDEX(px + 0, py + 1)]; + quad[3] = &pp[CLOTH_INDEX(px + 1, py + 1)]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE); + } + } + + abandon_this_cloth:; + } + } + } +#endif +} + +// +// Adds the fire in the current gamut to the POLY module. +// + +void AENG_draw_fire() +{ + SLONG z; + + FIRE_Info *fi; + FIRE_Point *fp; + + for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++) + { + FIRE_get_start( + NGAMUT_point_gamut[z].xmin, + NGAMUT_point_gamut[z].xmax, + z); + } +} + +void AENG_draw_sparks() +{ + SLONG z; + + SPARK_Info *si; + GLITTER_Info *gi; + + // Internal gubbins. + POLY_flush_local_rot(); + + for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++) + { + SPARK_get_start( + NGAMUT_point_gamut[z].xmin, + NGAMUT_point_gamut[z].xmax, + z); + + while(si = SPARK_get_next()) + { + SHAPE_sparky_line( + si->num_points, + si->x, + si->y, + si->z, + si->colour, + float(si->size)); + } + + GLITTER_get_start( + NGAMUT_point_gamut[z].xmin, + NGAMUT_point_gamut[z].xmax, + z); + + while(gi = GLITTER_get_next()) + { + SHAPE_glitter( + gi->x1, + gi->y1, + gi->z1, + gi->x2, + gi->y2, + gi->z2, + gi->colour); + } + } +} + +// +// Draws the hook. +// + +void AENG_draw_hook(void) +{ +#ifdef TARGET_DC + ASSERT ( FALSE ); +#else //#ifdef TARGET_DC + SLONG i; + + SLONG x; + SLONG y; + SLONG z; + SLONG yaw; + SLONG pitch; + SLONG roll; + + SLONG x1; + SLONG y1; + SLONG z1; + + SLONG x2; + SLONG y2; + SLONG z2; + + SLONG red = 0x80; + SLONG green = 0x20; + SLONG blue = 0x00; + + ULONG colour1; + ULONG colour2; + + HOOK_pos_grapple( + &x, + &y, + &z, + &yaw, + &pitch, + &roll); + + x >>= 8; + y >>= 8; + z >>= 8; + + MESH_draw_poly( + PRIM_OBJ_HOOK, + x, y, z, + yaw, + pitch, + roll, + NULL,0xff,0); + + for (i = HOOK_NUM_POINTS - 1; i >= 1; i--) + { + HOOK_pos_point(i + 0, &x1, &y1, &z1); + HOOK_pos_point(i - 1, &x2, &y2, &z2); + + x1 >>= 8; + y1 >>= 8; + z1 >>= 8; + + x2 >>= 8; + y2 >>= 8; + z2 >>= 8; + + if (red < 250) + { + red += 2; + } + else + { + if (green < 250) + { + green += 2; + } + else + { + if (blue < 250) + { + blue += 3; + } + } + } + + colour1 = (red << 16) | (green << 8) | (blue << 0); + colour2 = (red << 17) | (green << 8) | (blue >> 1); + + AENG_world_line( + x1, y1, z1, 0x8, colour1, + x2, y2, z2, 0x6, colour2, + FALSE); + } +#endif //#else //#ifdef TARGET_DC +} + +ULONG AENG_colour_mult(ULONG c1, ULONG c2) +{ + SLONG r1 = (c1 >> 16) & 0xff; + SLONG g1 = (c1 >> 8) & 0xff; + SLONG b1 = (c1 >> 0) & 0xff; + + SLONG r2 = (c2 >> 16) & 0xff; + SLONG g2 = (c2 >> 8) & 0xff; + SLONG b2 = (c2 >> 0) & 0xff; + + SLONG ar = r1 * r2 >> 8; + SLONG ag = g1 * g2 >> 8; + SLONG ab = b1 * b2 >> 8; + + ULONG ans = (ar << 16) | (ag << 8) | (ab << 0); + + return ans; +} + +// +// Draws the dirt. +// + +extern UBYTE estate; + +#define AENG_MAX_DIRT_LVERTS (64 * 3) +#define AENG_MAX_DIRT_INDICES (AENG_MAX_DIRT_LVERTS * 4 / 3) + +D3DLVERTEX AENG_dirt_lvert_buffer[AENG_MAX_DIRT_LVERTS + 1]; +D3DLVERTEX *AENG_dirt_lvert; +SLONG AENG_dirt_lvert_upto; + +UWORD AENG_dirt_index[AENG_MAX_DIRT_INDICES]; +SLONG AENG_dirt_index_upto; + +UBYTE AENG_dirt_matrix_buffer[sizeof(D3DMATRIX) + 32]; +D3DMATRIX *AENG_dirt_matrix; + + +#define AENG_MAX_DIRT_UVLOOKUP 16 + +struct +{ + float u; + float v; + +} AENG_dirt_uvlookup[AENG_MAX_DIRT_UVLOOKUP]; +SLONG AENG_dirt_uvlookup_valid; +SWORD AENG_dirt_uvlookup_world_type; + + +void AENG_draw_dirt() +{ + if (GAME_FLAGS & GF_NO_FLOOR) + { + // + // No dirt if there is no floor! + // + + return; + } + + SLONG i; + + #define LEAF_PAGE (POLY_PAGE_LEAF) + #define LEAF_CENTRE_U (0.5F) + #define LEAF_CENTRE_V (0.5F) + #define LEAF_RADIUS (0.5F) + #define LEAF_U(a) (LEAF_CENTRE_U + LEAF_RADIUS * (float)sin(a)) + #define LEAF_V(a) (LEAF_CENTRE_V + LEAF_RADIUS * (float)cos(a)) + + + #define SNOW_CENTRE_U (0.5F) + #define SNOW_CENTRE_V (0.5F) + #define SNOW_RADIUS (1.0F) + +//#ifdef TARGET_DC + // Slightly more for the DC - not sure why. + //#define LEAF_UP 12 +//#else + #define LEAF_UP 8 +//#endif + #define LEAF_SIZE (20.0F+(float)(i&15)) + + SLONG j; + + float fyaw; + float fpitch; + float froll; + float ubase; + float vbase; + + float matrix[9]; + float angle; + SVector_F temp[4]; + PolyPage *pp; + D3DLVERTEX *lv; + ULONG rubbish_colour; + + #ifdef TARGET_DC + ULONG leaf_colour_choice_rgb[4] = + { + 0xff332d1d, + 0xff243224, + 0xff123320, + 0xff332f07 + }; + + ULONG leaf_colour_choice_grey[4] = + { + 0xff333333, + 0xff444444, + 0xff222222, + 0xff383838 + }; + #else + ULONG leaf_colour_choice_rgb[4] = + { + 0x332d1d, + 0x243224, + 0x123320, + 0x332f07 + }; + + ULONG leaf_colour_choice_grey[4] = + { + 0x333333, + 0x444444, + 0x222222, + 0x383838 + }; + #endif + + if (AENG_dirt_uvlookup_valid && AENG_dirt_uvlookup_world_type == world_type) + { + // + // Valid lookup table. + // + } + else + { + // + // Calclate the uvlookup table. + // + + for (i = 0; i < AENG_MAX_DIRT_UVLOOKUP; i++) + { + float angle = float(i) * (2.0F * PI / AENG_MAX_DIRT_UVLOOKUP); + + float cangle; + float sangle; + + #ifdef TARGET_DC + + _SinCosA(&sangle, &cangle, angle); + + #else + + sangle = sinf(angle); + cangle = cosf(angle); + + #endif + + // + // Fix the uv's for texture paging. + // + + #ifdef TEX_EMBED + + if (world_type == WORLD_TYPE_SNOW) + { + pp = &POLY_Page[POLY_PAGE_SNOWFLAKE]; + // And the snowflake texture is bigger and needs a bit of squishing. + AENG_dirt_uvlookup[i].u = SNOW_CENTRE_U + sangle * SNOW_RADIUS; + AENG_dirt_uvlookup[i].v = SNOW_CENTRE_V + cangle * SNOW_RADIUS; + } + else + { + pp = &POLY_Page[POLY_PAGE_LEAF]; + AENG_dirt_uvlookup[i].u = LEAF_CENTRE_U + sangle * LEAF_RADIUS; + AENG_dirt_uvlookup[i].v = LEAF_CENTRE_V + cangle * LEAF_RADIUS; + } + + AENG_dirt_uvlookup[i].u = AENG_dirt_uvlookup[i].u * pp->m_UScale + pp->m_UOffset; + AENG_dirt_uvlookup[i].v = AENG_dirt_uvlookup[i].v * pp->m_VScale + pp->m_VOffset; + + #endif + } + + AENG_dirt_uvlookup_valid = TRUE; + AENG_dirt_uvlookup_world_type = world_type; + } + + + for (i = 0; i < 4; i++) + { + leaf_colour_choice_rgb[i] = AENG_colour_mult(leaf_colour_choice_rgb[i], NIGHT_amb_d3d_colour); + } + + ULONG flag[4]; + ULONG leaf_colour; + ULONG leaf_specular; + + // Cope with some wacky internals. + POLY_set_local_rotation_none(); + POLY_flush_local_rot(); + + // + // Initialise the leaf page and MM stuff... + // + + AENG_dirt_lvert_upto = 0; + AENG_dirt_index_upto = 0; + + AENG_dirt_lvert = (D3DLVERTEX *) ((SLONG(AENG_dirt_lvert_buffer) + 31) & ~0x1f); + AENG_dirt_matrix = (D3DMATRIX *) ((SLONG(AENG_dirt_matrix_buffer) + 31) & ~0x1f); + + // + // Draw the dirt. + // + + DIRT_Dirt *dd; + +#ifdef DEBUG + int iDrawnDirtCount = 0; +#endif + for (i = 0; i < DIRT_MAX_DIRT; i++) + { + dd = &DIRT_dirt[i]; + + if (dd->type == DIRT_TYPE_UNUSED) + { + continue; + } + + dd->flag &= ~DIRT_FLAG_DELETE_OK; + + // + // Is this bit of dirt behind the camera? + // + + { + float dx; + float dy; + float dz; + + dx = float(dd->x) - AENG_cam_x; + dy = float(dd->y) - AENG_cam_y; + dz = float(dd->z) - AENG_cam_z; + + float dprod; + + dprod = + dx * AENG_cam_matrix[6] + + dy * AENG_cam_matrix[7] + + dz * AENG_cam_matrix[8]; + + if (dprod < 64.0F) + { + // + // Offscreen... + // + + DIRT_MARK_AS_OFFSCREEN_QUICK(i); + + goto do_next_dirt; + } + } + +#ifdef DEBUG + iDrawnDirtCount++; +#endif + + switch(dd->type) + { + case DIRT_TYPE_LEAF: + case DIRT_TYPE_SNOW: + + { + // + // Get four vertices from the leaf page. + // + + if (AENG_dirt_lvert_upto + 4 > AENG_MAX_DIRT_LVERTS) + { + // + // Draw what we have so far... + // + + // Cope with some wacky internals. + POLY_set_local_rotation_none(); + + if (world_type == WORLD_TYPE_SNOW) + { + POLY_Page[POLY_PAGE_SNOWFLAKE].RS.SetChanged(); + } + else + { + POLY_Page[POLY_PAGE_LEAF].RS.SetChanged(); + } + + + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + AENG_dirt_lvert, + AENG_dirt_lvert_upto, + AENG_dirt_index, + AENG_dirt_index_upto, + 0); + + AENG_dirt_lvert_upto = 0; + AENG_dirt_index_upto = 0; + + lv = AENG_dirt_lvert; + } + else + { + lv = &AENG_dirt_lvert[AENG_dirt_lvert_upto]; + } + + if ((i & 0xf) == 0 && !estate && world_type != WORLD_TYPE_SNOW) + { + // + // This is some rubbish... + // + + fpitch = float(dd->pitch) * (PI / 1024.0F); + froll = float(dd->roll) * (PI / 1024.0F); + + // + // Copied from MATRIX_calc then fucked with... + // + + float cy, cp, cr; + float sy, sp, sr; + + #ifdef TARGET_DC + + // Use the fast intrinsics. + // Error is 2e-21 at most. + + sy = 0.0F; // sin(0) + cy = 1.0F; // cos(0) + + _SinCosA ( &sr, &cr, froll ); + _SinCosA ( &sp, &cp, fpitch ); + + #else + + sy = 0.0F; // sin(0) + cy = 1.0F; // cos(0) + + sp = sin(fpitch); + sr = sin(froll); + + cp = cos(fpitch); + cr = cos(froll); + + #endif + + // + // (matrix[3],matrix[4],matrix[5]) remains undefined... + // + + matrix[0] = cy * cr + sy * sp * sr; + matrix[6] = sy * cp; + matrix[1] = -cp * sr; + matrix[7] = sp; + matrix[2] = -sy * cr + cy * sp * sr; + matrix[8] = cy * cp; + + matrix[0] *= 24.0F; + matrix[1] *= 24.0F; + matrix[2] *= 24.0F; + + matrix[6] *= 24.0F; + matrix[7] *= 24.0F; + matrix[8] *= 24.0F; + + // + // Work out the position of the points. + // + + float base_x = float(dd->x); + float base_y = float(dd->y + LEAF_UP); + float base_z = float(dd->z); + + lv[0].x = base_x + matrix[6] + matrix[0]; + lv[0].y = base_y + matrix[7] + matrix[1]; + lv[0].z = base_z + matrix[8] + matrix[2]; + + lv[1].x = base_x + matrix[6] - matrix[0]; + lv[1].y = base_y + matrix[7] - matrix[1]; + lv[1].z = base_z + matrix[8] - matrix[2]; + + lv[2].x = base_x - matrix[6] + matrix[0]; + lv[2].y = base_y - matrix[7] + matrix[1]; + lv[2].z = base_z - matrix[8] + matrix[2]; + + lv[3].x = base_x - matrix[6] - matrix[0]; + lv[3].y = base_y - matrix[7] - matrix[1]; + lv[3].z = base_z - matrix[8] - matrix[2]; + + // + // What are the uv's and colour of this quad? + // + + rubbish_colour = NIGHT_amb_d3d_colour; + + if (i & 32) + { + ubase = 0.0F; + vbase = 0.0F; + } + else + { + ubase = 0.5F; + vbase = 0.0F; + } + + if (i == 64) + { + // + // Only one bit of money! + // + + ubase = 0.0F; + vbase = 0.5F; + } + else + { + if (!(i & 32)) + { + if (i & 64) + { + rubbish_colour &= 0xffffff00; + } + } + } + + lv[0].tu = ubase; + lv[0].tv = vbase; + lv[0].color = rubbish_colour; + lv[0].specular = 0xff000000; + + lv[1].tu = ubase + 0.5F; + lv[1].tv = vbase; + lv[1].color = rubbish_colour; + lv[1].specular = 0xff000000; + + lv[2].tu = ubase; + lv[2].tv = vbase + 0.5F; + lv[2].color = rubbish_colour; + lv[2].specular = 0xff000000; + + lv[3].tu = ubase + 0.5F; + lv[3].tv = vbase + 0.5F; + lv[3].color = rubbish_colour; + lv[3].specular = 0xff000000; + + #ifdef TEX_EMBED + + pp = &POLY_Page[POLY_PAGE_RUBBISH]; + + lv[0].tu = lv[0].tu * pp->m_UScale + pp->m_UOffset; + lv[0].tv = lv[0].tv * pp->m_VScale + pp->m_VOffset; + + lv[1].tu = lv[1].tu * pp->m_UScale + pp->m_UOffset; + lv[1].tv = lv[1].tv * pp->m_VScale + pp->m_VOffset; + + lv[2].tu = lv[2].tu * pp->m_UScale + pp->m_UOffset; + lv[2].tv = lv[2].tv * pp->m_VScale + pp->m_VOffset; + + lv[3].tu = lv[3].tu * pp->m_UScale + pp->m_UOffset; + lv[3].tv = lv[3].tv * pp->m_VScale + pp->m_VOffset; + + #endif + + // + // Build the indices. + // + + ASSERT(AENG_dirt_index_upto + 6 <= AENG_MAX_DIRT_INDICES); + + AENG_dirt_index[AENG_dirt_index_upto + 0] = AENG_dirt_lvert_upto + 0; + AENG_dirt_index[AENG_dirt_index_upto + 1] = AENG_dirt_lvert_upto + 1; + AENG_dirt_index[AENG_dirt_index_upto + 2] = AENG_dirt_lvert_upto + 2; + + AENG_dirt_index[AENG_dirt_index_upto + 3] = AENG_dirt_lvert_upto + 3; + AENG_dirt_index[AENG_dirt_index_upto + 4] = AENG_dirt_lvert_upto + 2; + AENG_dirt_index[AENG_dirt_index_upto + 5] = AENG_dirt_lvert_upto + 1; + + AENG_dirt_index_upto += 6; + AENG_dirt_lvert_upto += 4; + } + else + { + // + // This is a leaf or snowflake + // + + float leaf_size = LEAF_SIZE; + + if ((dd->pitch | dd->roll) == 0) + { + // + // This happens often... so we optimise it out. + // + + lv[0].x = float(dd->x); + lv[0].y = float(dd->y + LEAF_UP); + lv[0].z = float(dd->z + leaf_size); + + lv[1].x = float(dd->x + leaf_size); + lv[1].y = float(dd->y + LEAF_UP); + lv[1].z = float(dd->z - leaf_size); + + lv[2].x = float(dd->x - leaf_size); + lv[2].y = float(dd->y + LEAF_UP); + lv[2].z = float(dd->z - leaf_size); + } + else + { + // + // The rotation matrix of this bit of dirt. + // + + fpitch = float(dd->pitch) * (PI / 1024.0F); + froll = float(dd->roll) * (PI / 1024.0F); + + // + // Copied from MATRIX_calc then fucked with... + // + + float cy, cp, cr; + float sy, sp, sr; + + #ifdef TARGET_DC + + // Use the fast intrinsics. + // Error is 2e-21 at most. + + sy = 0.0F; // sin(0) + cy = 1.0F; // cos(0) + + _SinCosA ( &sr, &cr, froll ); + _SinCosA ( &sp, &cp, fpitch ); + + #else + + sy = 0.0F; // sin(0) + cy = 1.0F; // cos(0) + + sp = sin(fpitch); + sr = sin(froll); + + cp = cos(fpitch); + cr = cos(froll); + + #endif + + // + // (matrix[3],matrix[4],matrix[5]) remains undefined... + // + + matrix[0] = cy * cr + sy * sp * sr; + matrix[6] = sy * cp; + matrix[1] = -cp * sr; + matrix[7] = sp; + matrix[2] = -sy * cr + cy * sp * sr; + matrix[8] = cy * cp; + + matrix[0] *= leaf_size; + matrix[1] *= leaf_size; + matrix[2] *= leaf_size; + + matrix[6] *= leaf_size; + matrix[7] *= leaf_size; + matrix[8] *= leaf_size; + + // + // Work out the position of the points. + // + + lv[0].x = float(dd->x); + lv[0].y = float(dd->y + LEAF_UP); + lv[0].z = float(dd->z); + + lv[1].x = lv[0].x - matrix[6] + matrix[0]; + lv[1].y = lv[0].y - matrix[7] + matrix[1]; + lv[1].z = lv[0].z - matrix[8] + matrix[2]; + + lv[2].x = lv[0].x - matrix[6] - matrix[0]; + lv[2].y = lv[0].y - matrix[7] - matrix[1]; + lv[2].z = lv[0].z - matrix[8] - matrix[2]; + + lv[0].x += matrix[6]; + lv[0].y += matrix[7]; + lv[0].z += matrix[8]; + } + + if (world_type == WORLD_TYPE_SNOW) + { + // A snowflake - just subtle shades of grey + DWORD dwColour = ( ( i & 0x0f ) << 2 ) + 0xc0; + dwColour *= 0x010101; + dwColour |= 0xff000000; + + lv[0].color = dwColour; + lv[0].specular = 0xff000000; + + lv[1].color = dwColour; + lv[1].specular = 0xff000000; + + lv[2].color = dwColour; + lv[2].specular = 0xff000000; + } + else + { + // + // The colour of this leaf. + // + + leaf_colour = leaf_colour_choice_rgb[i & 0x3]; + + lv[0].color = (leaf_colour * 3) | 0xff000000; + lv[0].specular = 0xff000000; + + lv[1].color = (leaf_colour * 4) | 0xff000000; + lv[1].specular = 0xff000000; + + lv[2].color = (leaf_colour * 5) | 0xff000000; + lv[2].specular = 0xff000000; + } + + // + // The rotation angle of the leaf. + // + + lv[0].tu = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 0 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].u; + lv[0].tv = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 0 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].v; + + lv[1].tu = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 1 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].u; + lv[1].tv = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 1 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].v; + + lv[2].tu = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 2 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].u; + lv[2].tv = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 2 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].v; + + // + // Build the indices. + // + + ASSERT(AENG_dirt_index_upto + 3 <= AENG_MAX_DIRT_INDICES); + + AENG_dirt_index[AENG_dirt_index_upto + 0] = AENG_dirt_lvert_upto + 0; + AENG_dirt_index[AENG_dirt_index_upto + 1] = AENG_dirt_lvert_upto + 1; + AENG_dirt_index[AENG_dirt_index_upto + 2] = AENG_dirt_lvert_upto + 2; + + AENG_dirt_index_upto += 3; + AENG_dirt_lvert_upto += 3; + } + } + + break; + + case DIRT_TYPE_HELDCAN: + + // + // Don't draw inside the car?! + // + + { + Thing *p_person = TO_THING(dd->droll); // droll => owner + + if (p_person->Genus.Person->InCar) + { + continue; + } + } + + // + // FALLTHROUGH! + // + + case DIRT_TYPE_CAN: + case DIRT_TYPE_THROWCAN: + + MESH_draw_poly( + PRIM_OBJ_CAN, + dd->x, + dd->y, + dd->z, + dd->yaw, + dd->pitch, + dd->roll, + #ifdef TARGET_DC + NULL,0xff,0); + #else + NULL,0,0); + #endif + + break; + + case DIRT_TYPE_BRASS: + + extern UBYTE kludge_shrink; + + kludge_shrink = TRUE; + + MESH_draw_poly( + PRIM_OBJ_ITEM_AMMO_SHOTGUN, + dd->x, + dd->y, + dd->z, + dd->yaw, + dd->pitch, + dd->roll, + #ifdef TARGET_DC + NULL,0xff,0); + #else + NULL,0,0); + #endif + + kludge_shrink = FALSE; + + break; + + case DIRT_TYPE_WATER: + + SHAPE_droplet( + dd->x, + dd->y, + dd->z, + dd->dx >> 2, + dd->dy >> TICK_SHIFT, + dd->dz >> 2, + #ifdef TARGET + 0xff224455, + #else + 0x00224455, + #endif + POLY_PAGE_DROPLET); + break; + + case DIRT_TYPE_SPARKS: + + SHAPE_droplet( + dd->x, + dd->y, + dd->z, + dd->dx >> 2, + dd->dy >> TICK_SHIFT, + dd->dz >> 2, + 0x7f997744, + POLY_PAGE_BLOOM1); + break; + + case DIRT_TYPE_URINE: + SHAPE_droplet( + dd->x, + dd->y, + dd->z, + dd->dx >> 2, + dd->dy >> TICK_SHIFT, + dd->dz >> 2, + #ifdef TARGET + 0xff775533, + #else + 0x00775533, + #endif + POLY_PAGE_DROPLET); + break; + + case DIRT_TYPE_BLOOD: + SHAPE_droplet( + dd->x, + dd->y, + dd->z, + dd->dx >> 2, + dd->dy >> TICK_SHIFT, + dd->dz >> 2, + 0x9fFFFFFF, + POLY_PAGE_BLOODSPLAT); + break; + + default: + ASSERT(0); + break; + } + + + +#if 0 +/* + switch(di.type) + { + case DIRT_INFO_TYPE_WATER: + + SHAPE_droplet( + di.x, + di.y, + di.z, + di.dx * 4, + di.dy * 4, + di.dz * 4, +#ifdef TARGET + 0xff224455, +#else + 0x00224455, +#endif + POLY_PAGE_DROPLET); + + break; + + case DIRT_INFO_TYPE_URINE: + + SHAPE_droplet( + di.x, + di.y, + di.z, + di.dx * 4, + di.dy * 4, + di.dz * 4, +#ifdef TARGET + 0xff775533, +#else + 0x00775533, +#endif + POLY_PAGE_DROPLET); + + break; + + case DIRT_INFO_TYPE_SPARKS: + + SHAPE_droplet( + di.x, + di.y, + di.z, + di.dx * 4, + di.dy * 4, + di.dz * 4, + 0x7f997744, + POLY_PAGE_BLOOM1); + + break; + + case DIRT_INFO_TYPE_BLOOD: + + SHAPE_droplet( + di.x, + di.y, + di.z, + di.dx * 4, + di.dy * 4, + di.dz * 4, + 0x9fFFFFFF, + POLY_PAGE_BLOODSPLAT); + + break; + + case DIRT_INFO_TYPE_SNOW: + leaf_colour=di.morph1; + leaf_colour<<=23; + leaf_colour|=0xffFFff; + SPRITE_draw_tex(di.x,di.y,di.z,20,leaf_colour,0xFF000000,POLY_PAGE_SNOWFLAKE,0.0,0.0,1.0,1.0,SPRITE_SORT_NORMAL); + break; + + case DIRT_INFO_TYPE_LEAF: + + // + // Create the rotation matrix for this bit of dirt... + // + + if ((di.pitch | di.roll) == 0) + { + + } + + // + // There is a chance we are going to draw some rubbish instead of a leaf. + // + + if ((i & 0xf) == 0 && estate==0) + { + // + // The rotation matrix of this bit of dirt. + // + + fpitch = float(di.pitch) * (PI / 1024.0F); + froll = float(di.roll) * (PI / 1024.0F); + fyaw = float(i); + + MATRIX_calc(matrix, fyaw, fpitch, froll); + + matrix[0] *= 24.0F; + matrix[1] *= 24.0F; + matrix[2] *= 24.0F; + + matrix[6] *= 24.0F; + matrix[7] *= 24.0F; + matrix[8] *= 24.0F; + + temp[0].X = float(di.x) + matrix[6] + matrix[0]; + temp[0].Y = float(di.y) + matrix[7] + matrix[1]; + temp[0].Z = float(di.z) + matrix[8] + matrix[2]; + + temp[1].X = float(di.x) + matrix[6] - matrix[0]; + temp[1].Y = float(di.y) + matrix[7] - matrix[1]; + temp[1].Z = float(di.z) + matrix[8] - matrix[2]; + + temp[2].X = float(di.x) - matrix[6] + matrix[0]; + temp[2].Y = float(di.y) - matrix[7] + matrix[1]; + temp[2].Z = float(di.z) - matrix[8] + matrix[2]; + + temp[3].X = float(di.x) - matrix[6] - matrix[0]; + temp[3].Y = float(di.y) - matrix[7] - matrix[1]; + temp[3].Z = float(di.z) - matrix[8] - matrix[2]; + + // + // Transform the points. + // + + for (j = 0; j < 4; j++) + { + POLY_transform( + temp[j].X, + temp[j].Y + 4.0F, + temp[j].Z, + &pp[j]); + + if (!pp[j].IsValid()) + { + // + // Tell the DIRT module that the leaf is off-screen. + // + + DIRT_mark_as_offscreen(i); + + // + // Don't bother transforming the other points. + // + + goto do_next_dirt; + } + } + + if (POLY_valid_quad(quad)) + { + float ubase; + float vbase; + + SLONG colour_and = 0xffffffff; + + if (i & 32) + { + ubase = 0.0F; + vbase = 0.0F; + } + else + { + ubase = 0.5F; + vbase = 0.0F; + } + + if (i == 64) + { + // + // Only one bit of money! + // + + ubase = 0.0F; + vbase = 0.5F; + } + else + { + if (!(i & 32)) + { + if (i & 64) + { + colour_and = 0xffffff00; + } + } + } + + // + // Set the uvs. + // + + for (j = 0; j < 4; j++) + { + pp[j].u = ubase; + pp[j].v = vbase; + + if (j & 1) {pp[j].u += 0.5F;} + if (j & 2) {pp[j].v += 0.5F;} + +#ifdef TARGET_DC + pp[j].colour = ( NIGHT_amb_d3d_colour & colour_and ) | 0xff000000; +#else + pp[j].colour = NIGHT_amb_d3d_colour & colour_and; +#endif + pp[j].specular = 0xff000000; + } + + // + // Draw the quad. + // + + POLY_add_quad(quad, POLY_PAGE_RUBBISH, FALSE); + } + else + { + // + // Tell the DIRT module that the leaf is off-screen. + // + + DIRT_mark_as_offscreen(i); + } + } + else + { + if ((di.yaw | di.pitch | di.roll) == 0) + { + // + // This happens often... so we optimise it out. + // + + temp[0].X = float(di.x); + temp[0].Y = float(di.y + LEAF_UP); + temp[0].Z = float(di.z + LEAF_SIZE); + + temp[1].X = float(di.x + LEAF_SIZE); + temp[1].Y = float(di.y + LEAF_UP); + temp[1].Z = float(di.z - LEAF_SIZE); + + temp[2].X = float(di.x - LEAF_SIZE); + temp[2].Y = float(di.y + LEAF_UP); + temp[2].Z = float(di.z - LEAF_SIZE); + } + else + { + // + // The rotation matrix of this bit of dirt. + // + + fyaw = float(di.yaw) * (PI / 1024.0F); + fpitch = float(di.pitch) * (PI / 1024.0F); + froll = float(di.roll) * (PI / 1024.0F); + + MATRIX_calc(matrix, fyaw, fpitch, froll); + + // + // Work out the position of the points. + // + + for (j = 0; j < 3; j++) + { + + temp[j].X = float(di.x); + temp[j].Y = float(di.y); + temp[j].Z = float(di.z); + + temp[j].Y += float(LEAF_UP); + } + + + temp[0].X += matrix[6] * LEAF_SIZE; + temp[0].Y += matrix[7] * LEAF_SIZE; + temp[0].Z += matrix[8] * LEAF_SIZE; + + temp[1].X -= matrix[6] * LEAF_SIZE; + temp[1].Y -= matrix[7] * LEAF_SIZE; + temp[1].Z -= matrix[8] * LEAF_SIZE; + + temp[2].X -= matrix[6] * LEAF_SIZE; + temp[2].Y -= matrix[7] * LEAF_SIZE; + temp[2].Z -= matrix[8] * LEAF_SIZE; + + temp[1].X += matrix[0] * LEAF_SIZE; + temp[1].Y += matrix[1] * LEAF_SIZE; + temp[1].Z += matrix[2] * LEAF_SIZE; + + temp[2].X -= matrix[0] * LEAF_SIZE; + temp[2].Y -= matrix[1] * LEAF_SIZE; + temp[2].Z -= matrix[2] * LEAF_SIZE; + + falling = TRUE; + } + + // + // Transform the points. + // + + for (j = 0; j < 3; j++) + { + POLY_transform( + temp[j].X, + temp[j].Y, + temp[j].Z, + &pp[j]); + + if (!pp[j].IsValid()) + { + // + // Tell the DIRT module that the leaf is off-screen. + // + + DIRT_mark_as_offscreen(i); + + // + // Don't bother transforming the other points. + // + + goto do_next_dirt; + } + } + + if (POLY_valid_triangle(tri)) + { + // + // The colour and texture of the leaf. + // + + if (POLY_force_additive_alpha) + { + leaf_colour = leaf_colour_choice_grey[i & 0x3]; + } + else + { + leaf_colour = leaf_colour_choice_rgb[i & 0x3]; + leaf_colour = AENG_colour_mult(leaf_colour, NIGHT_amb_d3d_colour); + } + + angle = float(i); + + for (j = 0; j < 3; j++) + { + pp[j].colour = leaf_colour * (j + 3); + pp[j].colour &= ~POLY_colour_restrict; +#ifdef TARGET_DC + pp[j].colour |= 0xff000000; +#endif + pp[j].specular = 0xff000000; + pp[j].u = LEAF_U(angle); + pp[j].v = LEAF_V(angle); + + angle += 2.0F * PI / 3.0F; + } + + POLY_add_triangle(tri, LEAF_PAGE, FALSE); + } + else + { + // + // Tell the DIRT module that the leaf is off-screen. + // + + DIRT_mark_as_offscreen(i); + } + + } + + break; + + case DIRT_INFO_TYPE_PRIM: + + extern UBYTE kludge_shrink; + + if (di.held||(di.prim==253)) + { + kludge_shrink = TRUE; + } + + MESH_draw_poly( + di.prim, + di.x, + di.y, + di.z, + di.yaw, + di.pitch, + di.roll, +#ifdef TARGET_DC + NULL,0xff,0); +#else + NULL,0,0); +#endif + + kludge_shrink = FALSE; + + break; + + case DIRT_INFO_TYPE_MORPH: + + MESH_draw_morph( + di.prim, + di.morph1, + di.morph2, + di.tween, + di.x, + di.y, + di.z, + di.yaw, + di.pitch, + di.roll, + NULL); + + break; + + default: + ASSERT(0); + break; + } +*/ +#endif + + do_next_dirt:; + + } + + // + // Draw left-over leaves. + // + + if (AENG_dirt_lvert_upto) + { + // Cope with some wacky internals. + POLY_set_local_rotation_none(); + + if (world_type == WORLD_TYPE_SNOW) + { + POLY_Page[POLY_PAGE_SNOWFLAKE].RS.SetChanged(); + } + else + { + POLY_Page[POLY_PAGE_LEAF].RS.SetChanged(); + } + + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + AENG_dirt_lvert, + AENG_dirt_lvert_upto, + AENG_dirt_index, + AENG_dirt_index_upto, + 0); + } + + //TRACE ( "Drew %i bits of dirt\n", iDrawnDirtCount ); +} + + +// +// A bucket list for the pows! +// + +typedef struct aeng_pow +{ + SLONG frame; + float sx; + float sy; + float sz; + float Z; + + struct aeng_pow *next; + +} AENG_Pow; + +#define AENG_MAX_POWS 256 + +AENG_Pow AENG_pow[AENG_MAX_POWS]; +SLONG AENG_pow_upto; + +#define AENG_POW_NUM_BUCKETS 1024 + +AENG_Pow *AENG_pow_bucket[AENG_POW_NUM_BUCKETS]; + +// +// Draws the POWS +// + +void AENG_draw_pows(void) +{ + SLONG pow; + SLONG sprite; + SLONG bucket; + + AENG_Pow *ap; + POW_Pow *pp; + POW_Sprite *ps; + + POLY_Point pt; + + // + // Clear the buckets and the AENG_pows. + // + + memset(AENG_pow_bucket, 0, sizeof(AENG_pow_bucket)); + + AENG_pow_upto = 0; + + // + // Draw all used pows. Ignore the NGAMUT for now. + // + + for (pow = POW_pow_used; pow; pow = pp->next) + { + ASSERT(WITHIN(pow, 1, POW_MAX_POWS - 1)); + + pp = &POW_pow[pow]; + + for (sprite = pp->sprite; sprite; sprite = ps->next) + { + ASSERT(WITHIN(sprite, 1, POW_MAX_SPRITES - 1)); + + ps = &POW_sprite[sprite]; + + POLY_transform( + float(ps->x) * (1.0F / 256.0F), + float(ps->y) * (1.0F / 256.0F), + float(ps->z) * (1.0F / 256.0F), + &pt); + + if (pt.clip & POLY_CLIP_TRANSFORMED) + { + // + // Create an AENG_pow. + // + + ASSERT(WITHIN(AENG_pow_upto, 0, AENG_MAX_POWS - 1)); + + ap = &AENG_pow[AENG_pow_upto++]; + + ap->frame = ps->frame; + ap->sx = pt.X; + ap->sy = pt.Y; + ap->sz = pt.z; + ap->Z = pt.Z; + ap->next = NULL; + + // + // Add to the bucket list. + // + + bucket = ftol(pt.z * float(AENG_POW_NUM_BUCKETS)); + + SATURATE(bucket, 0, AENG_POW_NUM_BUCKETS - 1); + + ap->next = AENG_pow_bucket[bucket]; + AENG_pow_bucket[bucket] = ap; + } + } + } + + // + // Draw the buckets. + // + + { + POLY_Point ppt[4]; + POLY_Point *quad[4]; + + float size; + float u; + float v; + + ppt[0].colour = 0xffffffff; + ppt[1].colour = 0xffffffff; + ppt[2].colour = 0xffffffff; + ppt[3].colour = 0xffffffff; + + ppt[0].specular = 0xff000000; + ppt[1].specular = 0xff000000; + ppt[2].specular = 0xff000000; + ppt[3].specular = 0xff000000; + + quad[0] = &ppt[0]; + quad[1] = &ppt[1]; + quad[2] = &ppt[2]; + quad[3] = &ppt[3]; + + for (bucket = 0; bucket < AENG_POW_NUM_BUCKETS; bucket++) + { + for (ap = AENG_pow_bucket[bucket]; ap; ap = ap->next) + { + // + // Push forward in the z-buffer + // + + ap->sz -= 0.025F; // Half a mapsquare! + + if (ap->sz < POLY_ZCLIP_PLANE) + { + ap->sz = POLY_ZCLIP_PLANE; + } + + ap->Z = POLY_ZCLIP_PLANE / ap->sz; + + // + // The frame. + // + + u = float(ap->frame & 0x3) * (1.0F / 4.0F); + v = float(ap->frame >> 2) * (1.0F / 4.0F); + + // + // Add this sprite to the bucket list. + // + + size = 650.0F * ap->Z; + + ppt[0].X = ap->sx - size; + ppt[0].Y = ap->sy - size; + ppt[1].X = ap->sx + size; + ppt[1].Y = ap->sy - size; + ppt[2].X = ap->sx - size; + ppt[2].Y = ap->sy + size; + ppt[3].X = ap->sx + size; + ppt[3].Y = ap->sy + size; + + ppt[0].u = u + (0.0F / 4.0F); + ppt[0].v = v + (0.0F / 4.0F); + ppt[1].u = u + (1.0F / 4.0F); + ppt[1].v = v + (0.0F / 4.0F); + ppt[2].u = u + (0.0F / 4.0F); + ppt[2].v = v + (1.0F / 4.0F); + ppt[3].u = u + (1.0F / 4.0F); + ppt[3].v = v + (1.0F / 4.0F); + + ppt[0].Z = ap->Z; + ppt[1].Z = ap->Z; + ppt[2].Z = ap->Z; + ppt[3].Z = ap->Z; + + ppt[0].z = ap->sz; + ppt[1].z = ap->sz; + ppt[2].z = ap->sz; + ppt[3].z = ap->sz; + + POLY_add_quad(quad, POLY_PAGE_EXPLODE1, FALSE, TRUE); + } + } + } +} + + +#ifndef TARGET_DC +void AENG_draw_released_balloons(void) +{ + SLONG i; + + BALLOON_Balloon *bb; + + for (i = 1; i < BALLOON_balloon_upto; i++) + { + bb = &BALLOON_balloon[i]; + + if (bb->type && !bb->thing) + { + // + // Nobody is holding this balloon so we have to draw it here. + // + + SHAPE_draw_balloon(i); + } + } +} +#endif + + +// +// AA test. +// + +#define AENG_AA_LEFT 20 +#define AENG_AA_TOP 20 +#define AENG_AA_PIX_SIZE 4 +#define AENG_AA_BUF_SIZE 32 + +UBYTE AENG_aa_buffer[AENG_AA_BUF_SIZE][AENG_AA_BUF_SIZE]; + +#ifdef TARGET_DC +// Try to misalign the map rows to try to stop the cache thrashing. +// DC's cache is 32k and 1-way asssociative! +//#define MAP_SIZE_TWEAK 4 +// Actually, it seemed to make very little difference. +#define MAP_SIZE_TWEAK 0 +#else +#define MAP_SIZE_TWEAK 0 +#endif + + +#ifdef TARGET_DC +#define NEW_FLOOR defined +#else +#define NEW_FLOOR defined +#endif + +#ifndef NEW_FLOOR +POLY_Point AENG_upper[MAP_WIDTH / 2 + MAP_SIZE_TWEAK][MAP_HEIGHT / 2 + MAP_SIZE_TWEAK]; +POLY_Point AENG_lower[MAP_WIDTH / 2 + MAP_SIZE_TWEAK*2][MAP_HEIGHT / 2 + MAP_SIZE_TWEAK*2]; +#endif + + +// +// Globals affecting the way the engine works. +// + +#define AENG_SKY_TYPE_NIGHT 0 +#define AENG_SKY_TYPE_DAY 1 + +SLONG AENG_torch_on = FALSE; +SLONG AENG_shadows_on = TRUE; +SLONG AENG_sky_type = AENG_SKY_TYPE_DAY; +ULONG AENG_sky_colour_bot = 0x008890ee; +ULONG AENG_sky_colour_top = 0x006670cc; + + +void AENG_set_sky_nighttime() +{ + AENG_sky_type = AENG_SKY_TYPE_NIGHT; +} + +void AENG_set_sky_daytime(ULONG bottom_colour, ULONG top_colour) +{ + AENG_sky_type = AENG_SKY_TYPE_DAY; + AENG_sky_colour_bot = bottom_colour; + AENG_sky_colour_top = top_colour; +} + +struct RRect +{ + SLONG x; + SLONG y; + SLONG w; + SLONG h; + SLONG col; + SLONG layer; + SLONG page; + +}; + +struct RRect rrect[2000]; +SLONG next_rrect=1; + + + +void AENG_draw_rectr(SLONG x,SLONG y,SLONG w,SLONG h,SLONG col,SLONG layer,SLONG page) +{ + ASSERT(next_rrect<2000); + rrect[next_rrect].x=x; + rrect[next_rrect].y=y; + rrect[next_rrect].w=w; + rrect[next_rrect].h=h; + rrect[next_rrect].col=col; + rrect[next_rrect].layer=layer; + rrect[next_rrect].page=page; + next_rrect++; + +} + +void AENG_draw_rect(SLONG x,SLONG y,SLONG w,SLONG h,SLONG col,SLONG layer,SLONG page); +void draw_all_boxes(void) +{ + SLONG x,y,w,h, col,layer,page; + SLONG c0; + + + + for(c0=1;c0x[0]; + x2=p_facet->x[1]; + z1=p_facet->z[0]; + z2=p_facet->z[1]; + + x1*=2; + z1*=2; + x2*=2; + z2*=2; + + x1+=(p_facet->Y[0]>>8); + z1-=(p_facet->Y[0]>>8); + x2+=(p_facet->Y[0]>>8); + z2-=(p_facet->Y[0]>>8); + + switch(p_facet->Height) + { + case 2: + colour=0xff; + break; + case 3: + colour=0xff00; + break; + case 4: + colour=0x7f7f; + break; + case 5: + colour=0xffff; + break; + } + + POLY_add_line_2d( (float)x1,(float)z1,(float)x2,(float)z2,colour); + +} + +#endif + + +void AENG_draw_people_messages() +{ + return; + + SLONG x; + SLONG z; + + SLONG t_index; + Thing *p_thing; + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Flags & FLAGS_IN_BUILDING) + { + // + // Dont draw things inside buildings when we are outdoors. + // + } + else + { + switch(p_thing->DrawType) + { + case DT_ROT_MULTI: + + if (POLY_sphere_visible( + float(p_thing->WorldPos.X >> 8), + float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT, + float(p_thing->WorldPos.Z >> 8), + 256.0F / (AENG_DRAW_DIST * 256.0F))) + { + CBYTE str[100]; +// FIGURE_draw(p_thing); + + sprintf(str,"%d %d",p_thing->State,p_thing->SubState); + AENG_world_text( + (p_thing->WorldPos.X >> 8), + (p_thing->WorldPos.Y >> 8) + 0x60, + (p_thing->WorldPos.Z >> 8), + 200, + 180, + 50, + TRUE, + str); +// PCOM_person_state_debug(p_thing)); + + + } + + break; + } + } + + t_index = p_thing->Child; + } + } + } +} + + + + +// +// Sets the rotation of the bike wheel prim for the given rotation. +// + +void AENG_set_bike_wheel_rotation(UWORD rot, UBYTE prim) +{ + SLONG i; + + PrimObject *po; + PrimFace4 *f4; + + po = &prim_objects[prim]; + + // + // The texture rotation vector. + // + + + +// Oh no they're not. +#if 0 + // All the textures are symmetrical, so you can't tell if they rotate. + // Optimised! + const SLONG du1 = 0xf; + const SLONG dv1 = 0; + + const SLONG du2 = 0xf; + const SLONG dv2 = 0; + + SLONG u; + SLONG v; + + static SLONG order[4] = {2, 1, 3, 0}; + + // + // The faces we rotate the textures on are faces 6 and 7 for PRIM_OBJ_BIKE_BWHEEL. + // + + f4 = &prim_faces4[po->StartFace4 + 6]; + + for (i = 0; i < 4; i++) + { + switch(order[i]) + { + case 0: u = 16 + du1; v = 16 + dv1; break; + case 1: u = 16 + dv1; v = 16 - du1; break; + case 2: u = 16 - du1; v = 16 - dv1; break; + case 3: u = 16 - dv1; v = 16 + du1; break; + } + + f4[0].UV[i][0] &= ~0x3f; + f4[0].UV[i][1] &= ~0x3f; + + f4[0].UV[i][0] |= u; + f4[0].UV[i][1] |= v; + + switch(order[i]) + { + case 0: u = 16 + du2; v = 16 + dv2; break; + case 1: u = 16 + dv2; v = 16 - du2; break; + case 2: u = 16 - du2; v = 16 - dv2; break; + case 3: u = 16 - dv2; v = 16 + du2; break; + } + + f4[1].UV[i][0] &= ~0x3f; + f4[1].UV[i][1] &= ~0x3f; + + f4[1].UV[i][0] |= u; + f4[1].UV[i][1] |= v; + } + +#else + + SLONG du1 = SIN(+rot & 2047) * 15 >> 16; + SLONG dv1 = COS(+rot & 2047) * 15 >> 16; + + SLONG du2 = SIN(-rot & 2047) * 15 >> 16; + SLONG dv2 = COS(-rot & 2047) * 15 >> 16; + + SLONG u; + SLONG v; + + static SLONG order[4] = {2, 1, 3, 0}; + + // + // The faces we rotate the textures on are faces 6 and 7 for PRIM_OBJ_BIKE_BWHEEL. + // + + f4 = &prim_faces4[po->StartFace4 + 6]; + + for (i = 0; i < 4; i++) + { + switch(order[i]) + { + case 0: u = 16 + du1; v = 16 + dv1; break; + case 1: u = 16 + dv1; v = 16 - du1; break; + case 2: u = 16 - du1; v = 16 - dv1; break; + case 3: u = 16 - dv1; v = 16 + du1; break; + } + + f4[0].UV[i][0] &= ~0x3f; + f4[0].UV[i][1] &= ~0x3f; + + f4[0].UV[i][0] |= u; + f4[0].UV[i][1] |= v; + + switch(order[i]) + { + case 0: u = 16 + du2; v = 16 + dv2; break; + case 1: u = 16 + dv2; v = 16 - du2; break; + case 2: u = 16 - du2; v = 16 - dv2; break; + case 3: u = 16 - dv2; v = 16 + du2; break; + } + + f4[1].UV[i][0] &= ~0x3f; + f4[1].UV[i][1] &= ~0x3f; + + f4[1].UV[i][0] |= u; + f4[1].UV[i][1] |= v; + } +#endif +} + + + +/* + +// +// Draws warehouse floor surrounding the given facet. +// + +void AENG_draw_warehouse_floor_near_door(DFacet *df) +{ + SLONG dx; + SLONG dz; + + SLONG sx; + SLONG sz; + + SLONG lx1; + SLONG lx2; + + SLONG x1; + SLONG z1; + SLONG x2; + SLONG z2; + + SLONG mx; + SLONG mz; + SLONG page; + + POLY_Point *quad[4]; + PAP_Hi *ph; + + // + // The bounding box of the points. + // + + x1 = df->x[0]; + z1 = df->z[0]; + x2 = df->x[1]; + z2 = df->z[1]; + + if (x1 > x2) {SWAP(x1,x2);} + if (z1 > z2) {SWAP(z1,z2);} + + x1 -= 1; + x2 += 1; + + z1 -= 1; + z2 += 1; + + SATURATE(x1, 1, PAP_SIZE_HI - 2); + SATURATE(z1, 1, PAP_SIZE_HI - 2); + SATURATE(x2, 1, PAP_SIZE_HI - 2); + SATURATE(z2, 1, PAP_SIZE_HI - 2); + + // + // Set the colour of the points depending on their distance + // from from the entrance of the warehouse. + // + + for (mz = z1; mz <= z2; mz++) + { + if (!WITHIN(mz, NGAMUT_point_zmin, NGAMUT_point_zmax)) + { + continue; + } + + lx1 = x1; + lx2 = x2; + + SATURATE(lx1, NGAMUT_point_gamut[mz].xmin, NGAMUT_point_gamut[mz].xmax); + SATURATE(lx2, NGAMUT_point_gamut[mz].xmin, NGAMUT_point_gamut[mz].xmax); + + for (mx = lx1; mx <= lx2; mx++) + { + // + // Remember the upper point colour. + // + + AENG_lower[mx][mz].colour = AENG_upper[mx][mz].colour; + + // + // Darken this point if it is not adjacent to the exit. + // + + for (dx = -1; dx <= 0; dx++); + for (dz = -1; dz <= 0; dz++); + { + sx = mx + dx; + sz = mz + dz; + + if (!(PAP_2HI(sx,sz).Flags & PAP_FLAG_HIDDEN)) + { + goto dont_darken; + } + } + + // + // Completely fogged out... + // + + AENG_upper[mx][mz].colour &= 0x00ffffff; + + dont_darken:; + } + } + + for (mz = z1; mz < z2; mz++) + { + if (!WITHIN(mz, NGAMUT_zmin, NGAMUT_zmax)) + { + continue; + } + + lx1 = x1; + lx2 = x2; + + SATURATE(lx1, NGAMUT_gamut[mz].xmin, NGAMUT_gamut[mz].xmax); + SATURATE(lx2, NGAMUT_gamut[mz].xmin, NGAMUT_gamut[mz].xmax); + + for (mx = lx1; mx < lx2; mx++) + { + ph = &PAP_2HI(mx,mz); + + if (!(ph->Flags & PAP_FLAG_HIDDEN)) + { + continue; + } + + quad[0] = &AENG_upper[mx + 0][mz + 0]; + quad[1] = &AENG_upper[mx + 1][mz + 0]; + quad[2] = &AENG_upper[mx + 0][mz + 1]; + quad[3] = &AENG_upper[mx + 1][mz + 1]; + + if (POLY_valid_quad(quad)) + { + TEXTURE_get_minitexturebits_uvs( + ph->Texture, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + + POLY_add_quad(quad, page, TRUE); + } + } + } +} + +*/ + + + +// return current detail levels + +//#pragma optimize( "a", off ) +//#pragma optimize( "y", off ) + +// store new detail levels + +#ifdef TARGET_DC +// Fewer things to set. +void AENG_set_detail_levels(//int stars, + int shadows, + int puddles, + int dirt, + int mist, + int rain, + int skyline, + int crinkles) +#else +void AENG_set_detail_levels(int stars, + int shadows, + int moon_reflection, + int people_reflection, + int puddles, + int dirt, + int mist, + int rain, + int skyline, + int filter, + int perspective, + int crinkles) +#endif +{ + //ENV_set_value_number("detail_stars", stars, "Render"); + ENV_set_value_number("detail_shadows", shadows, "Render"); + //ENV_set_value_number("detail_moon_reflection", moon_reflection, "Render"); + //ENV_set_value_number("detail_people_reflection", people_reflection, "Render"); + ENV_set_value_number("detail_puddles", puddles, "Render"); + ENV_set_value_number("detail_dirt", dirt, "Render"); + ENV_set_value_number("detail_mist", mist, "Render"); + ENV_set_value_number("detail_rain", rain, "Render"); + ENV_set_value_number("detail_skyline", skyline, "Render"); + //ENV_set_value_number("detail_filter", filter, "Render"); + //ENV_set_value_number("detail_perspective", perspective, "Render"); + ENV_set_value_number("detail_crinkles", crinkles, "Render"); + + // heh heh heh + AENG_read_detail_levels(); +} + +#ifndef TARGET_DC +// draw some polys + +float AENG_draw_some_polys(bool large, bool blend) +{ + PolyPoint2D *vert,*vp; + WORD *ind,*ip; + + vert = new PolyPoint2D[large ? 300 : 30000]; + vp = vert; + + ind = new WORD[large ? 300 : 30000]; + ip = ind; + + float u = 0; + float v = 0; + + if (large) + { + for (int ii = 0; ii < 100; ii++) + { + vp->SetSC(0,0); + vp->SetColour(0x80FFFFFF); + vp->SetSpecular(0); + vp->SetUV(u,v); + vp++; + + vp->SetSC(640,0); + vp->SetColour(0x80FFFFFF); + vp->SetSpecular(0); + vp->SetUV(u,v); + vp++; + + vp->SetSC(0,480); + vp->SetColour(0x80FFFFFF); + vp->SetSpecular(0); + vp->SetUV(u,v); + vp++; + + *ip++ = ii*3; + *ip++ = ii*3+1; + *ip++ = ii*3+2; + } + } + else + { + for (int ii = 0; ii < 10000; ii++) + { + int x = ii % 20; + int y = (ii / 20) % 15; + + vp->SetSC(x*32,y*32); + vp->SetColour(0x80FFFFFF); + vp->SetSpecular(0); + vp->SetUV(u,v); + vp++; + + vp->SetSC(x*32+32,y*32); + vp->SetColour(0x80FFFFFF); + vp->SetSpecular(0); + vp->SetUV(u,v); + vp++; + + vp->SetSC(x*32,y*32+32); + vp->SetColour(0x80FFFFFF); + vp->SetSpecular(0); + vp->SetUV(u,v); + vp++; + + *ip++ = ii*3; + *ip++ = ii*3+1; + *ip++ = ii*3+2; + } + } + + StartStopwatch(); + + BEGIN_SCENE; + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE, FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE, FALSE); + if (blend) + { + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + } + else + { + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); + } + + if (large) + { + + HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, (D3DTLVERTEX*)vert, 300, ind, 300, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + //HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, vert->GetTLVert(), 300, ind, 300, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + ASSERT(!FAILED(res)); + } + else + { + HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, (D3DTLVERTEX*)vert, 30000, ind, 30000, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + //HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, vert->GetTLVert(), 30000, ind, 30000, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + ASSERT(!FAILED(res)); + } + + END_SCENE; + + the_display.screen_lock(); + the_display.screen_unlock(); + + float time = StopStopwatch(); + + delete[] vert; + delete[] ind; + + return time; +} + +// guess detail levels +// +// this is only done if AENG_estimate_detail_levels is true + +void AENG_guess_detail_levels() +{ + if (!AENG_estimate_detail_levels) return; // don't estimate them + + ENV_set_value_number("estimate_detail_levels", 0, "Render"); + AENG_estimate_detail_levels = 0; + + int generation; + + // 0 = software or 1-2 for hardware + D3DDeviceInfo* dev = the_display.GetDeviceInfo(); + + if (!dev->IsHardware()) + { + generation = 0; + } + else + { + // software (P450) 3500/s + // Permedia2 60000/s + + float tso = 10000 / AENG_draw_some_polys(false, false); + + TRACE("card draws 512-pixel opaque polys at %f per second\n", tso); + + if (tso < 10000) + { + generation = 0; + } + else if (tso < 40000) + { + generation = 1; + } + else + { + generation = 2; + if (dev->ModulateAlphaSupported() && dev->DestInvSourceColourSupported()) + { + generation = 3; + } + } + } + + TRACE("Card generation = %d\n", generation); + + // GENVAR(n) = in all generations >= n +#define GENVAR(G) ((generation >= G) ? 1 : 0) + + int stars = GENVAR(0); + int shadows = GENVAR(2); + int moon_reflection = GENVAR(2); + int people_reflection = GENVAR(3); + int puddles = GENVAR(2); + int dirt = GENVAR(1); + int mist = GENVAR(2); + int rain = GENVAR(0); + int skyline = GENVAR(2); + int filter = GENVAR(1); + int perspective = GENVAR(1); + int crinkles = GENVAR(3); + + AENG_set_detail_levels(stars, shadows, moon_reflection, people_reflection, puddles, dirt, mist, rain, skyline, filter, perspective, crinkles); +} + +#endif + + + + + +#ifdef TARGET_DC +// Fewer things to set. +void AENG_get_detail_levels(//int* stars, + int* shadows, + int* puddles, + int* dirt, + int* mist, + int* rain, + int* skyline, + int* crinkles) +#else +void AENG_get_detail_levels(int* stars, + int* shadows, + int* moon_reflection, + int* people_reflection, + int* puddles, + int* dirt, + int* mist, + int* rain, + int* skyline, + int* filter, + int* perspective, + int* crinkles) +#endif +{ + //*stars = AENG_detail_stars; + *shadows = AENG_detail_shadows; + //*moon_reflection = AENG_detail_moon_reflection; + //*people_reflection = AENG_detail_people_reflection; + *puddles = AENG_detail_puddles; + *dirt = AENG_detail_dirt; + *mist = AENG_detail_mist; + *rain = AENG_detail_rain; + *skyline = AENG_detail_skyline; + //*filter = AENG_detail_filter; + //*perspective = AENG_detail_perspective; + *crinkles = AENG_detail_crinkles; +} + +//#pragma optimize( "y", on ) +//#pragma optimize( "a", on ) + + +#define MAX_WIDTH_DRAWN 100 + + +#define MAX_FLOOR_TILES_FOR_STRIPS (16) // I doubt we will get more than 32 very often (map is 128 wide) +#define MAX_VERTS_FOR_STRIPS (MAX_FLOOR_TILES_FOR_STRIPS*4) // 4 verts per map square +#define MAX_INDICES_FOR_STRIPS (MAX_FLOOR_TILES_FOR_STRIPS*5) // 5 indicies per map square + + + +#ifdef STRIP_STATS +ULONG strip_stats[MAX_FLOOR_TILES_FOR_STRIPS+10]; +#endif + + + + + + +#ifdef MIKES_UNUSED_AUTOMATIC_FLOOR_TEXTURE_GROUPER + +// +// draws the floor quicker by grouping adjacent squares with the same texture into one index prim +// +UWORD in_group[64*10]; + +UWORD groups[256][9]; +UWORD group_count[256]; +SLONG group_stats[256][9]; //how often each member of the group is used +SLONG group_break[256][64*10]; // for each group how often the strip is broken by each texture +SLONG group_hits[256][64*10]; // for each group how often the strip is broken by each texture + +UWORD page_next[64*10][64*10]; +ULONG group_upto=1; + + +#define MAX_PREV 8 +float how_good(void) +{ + SLONG x,z; + SLONG page,my_group=0,prev_group[10]; + SLONG bucket_group[10],bucket_length[10],bucket=0; + SLONG length=1; + SLONG total_length=0,strip_count=0; + float average_len,prev_average_len=0.0f; + SLONG count; + SLONG quit=0; + SLONG c0; + UWORD strips[128]; + SLONG match; + + memset(strips,0,128*2); + + PAP_Hi *ph; + + group_upto=1; + + memset(prev_group,0,4*10); + + memset(bucket_group,0,4*10); + memset(bucket_length,0,4*10); +// prev_group[0]=0; + + total_length=0; + strip_count=0; + + for(z=0;z<128;z++) + { + for(x=0;x<128;x++) + { + + ph = &PAP_2HI(x,z); + ASSERT(bucket_group[0]<128*128); + ASSERT(bucket_length[0]<128*128); +// if(x==22 && z==16) +// ASSERT(0); + + my_group=0; + + page=ph->Texture&0x3ff; + + if(in_group[page]) + { + my_group=in_group[page]; + } + else + { + ASSERT(0); + + } + + match=0; + for(c0=0;c032) + { + match=0; + } + } + + if(match)//y_group==prev_group) + { + // + // the same group hoorah + // + + bucket_length[match-1]++; + ASSERT(bucket_length[bucket]<128); + //length++; + + } + else + { + // + // different group + // + + // store length stat + + bucket++; + bucket%=MAX_PREV; + + + total_length+=bucket_length[bucket]; + ASSERT(bucket_length[bucket]<128); + strip_count++; + strips[bucket_length[bucket]]++; + + bucket_length[bucket]=1; + bucket_group[bucket]=my_group; + } + ASSERT(my_group); + for(c0=MAX_PREV;c0>0;c0--) + { + prev_group[c0]=prev_group[c0-1]; + } + prev_group[0]=my_group; + } + } + + + DebugText(" FLOOR STRIP \n"); + for(c0=0;c0<128;c0++) + { + DebugText(" %d %d \n",c0,strips[c0]); + } + + + ASSERT(strip_count>0); + average_len=(float)total_length/(float)strip_count; + DebugText(" FLOOR STRIP average %f\n",average_len); + + return(average_len); + + +} +UWORD frequency[64*10]; + +float init_groups2(void) +{ + SLONG x,z; + SLONG page,p1,p2; + SLONG highest,best; + SLONG g_count=0,g_index=0; + SLONG c1,c2; + SLONG c0; + + PAP_Hi *ph; +/* + for(c0=0;c0<64*10;c0++) + { + in_group[c0]=c0+1; + + } + how_good(); +*/ + + memset(page_next,0,64*10*64*10*2); + memset(frequency,0,64*10*2); + memset(in_group,0,64*10*2); + memset(groups,0,256*9*2); + +// for(page=0;page<8*64;page++) + for(z=0;z<128;z++) + { + for(x=0;x<128;x++) + { + ph = &PAP_2HI(x,z); + p1=ph->Texture&0x3ff; + if(x) + { + ph = &PAP_2HI(x-1,z); //to the left + p2=ph->Texture&0x3ff; + if(p1!=p2) + page_next[p1][p2]++; + } + if(x<127) + { + ph = &PAP_2HI(x+1,z); //to the right + p2=ph->Texture&0x3ff; + if(p1!=p2) + page_next[p1][p2]++; + + } + + + frequency[p1]++; + } + + } + // + // for every texture we now know how many times every other texture appears next to it + // + +/* + highest=0; + for(c0=0;c0<64*10;c0++) + { + if(frequency[c0]>highest) + { + highest=frequency[c0]; + best=c0; + } + + } +*/ + + while(1) + { + g_count=0; + + highest=0; + best=-1; + for(c0=0;c0<64*10;c0++) + { + if(!in_group[c0]) + for(c1=0;c1<64*10;c1++) + { + if(c0!=c1) + if(page_next[c0][c1]>highest) + { + highest=page_next[c0][c1]; + best=c0; + } + + + } + } + if(best==-1) + break; + + + + // + // for the most frequently used texture, group with it the textures that often appear next to it + // + + g_index++; + groups[g_index][g_count]=best; + in_group[best]=g_index; + for(c0=0;c0<64*10;c0++) + { + page_next[c0][best]=0; //remove me from next to other textures +// page_next[best][c0]=0; //remove me from next to other textures + } +// frequency[best]=0; + + g_count++; + { + SLONG group_perc[9]; + SLONG ndhighest=0; + SLONG perc; + SLONG current_best_perc=0; + SLONG c2; + + page=best; + + page=-1; + + while(g_count<9) + { + SLONG n_of; + + // + // for all members of the group find the highest probabilty neihbour + // + ndhighest=0; + best=-1; + for(c1=0;c1ndhighest) + { + SLONG abort_store=0; + // + //check if better paired up elsewhere + // + for(c2=0;c2<64*10;c2++) + { + if(page_next[c0][c2]>perc) + abort_store=1; + + } + if(!abort_store) + { + ndhighest=perc; + best=c0; + } + } + } + } + } + if(best>=0) + { + groups[g_index][g_count]=best; + g_count++; + in_group[best]=g_index; +// frequency[best]=0; + for(c0=0;c0<64*10;c0++) + { + page_next[c0][best]=0; //remove me from next to other textures +// page_next[best][c0]=0; //remove me from next to other textures + } + } + else + { + // + // no more for this group so exit the while loop + // + break; + } + + } + group_count[g_index]=g_count; + } + } + + for(c0=0;c0<64*10;c0++) + { + if(!in_group[c0] && frequency[c0]) + { + // + // not in a group but exists on map + // + groups[g_index][g_count]=c0; + in_group[c0]=g_index; + + g_count++; + if(g_count>=9) + { + g_count=0; + g_index++; + } + + + } + } + + // + // compress groups + // + + for(c0=1;c00;g_index--) + { + if(group_count[g_index-1]) + break; + } + + + float ret; + + ret=how_good(); + DebugText(" FLOOR STRIP pages %d\n",g_index); + + DebugText(" try random \n",g_index); + + + + return(ret); +} + +#endif + + +#define IPRIM_COUNT 5 + +// +// 16k cache // 512x32byte // 1 way associative +// + +// +// data bus 64 bit //100mhz +// + +#define MAX_DRAW_WIDTH 128 + +struct FloorStore +{ + ULONG Colour; +// ULONG Specular; // is this needed? + float Alt; + UWORD Flags; //not really needed + UWORD Texture; //not really needed +// SLONG x,z; +}; + +//40*12 =480 bytes per row, need 2 rows + +inline void cache_a_row(SLONG x,SLONG z,struct FloorStore *p2,SLONG endx) +{ + SLONG px,pz,dx,dz; + SLONG square; + SLONG mapz; + NIGHT_Square *nq; + PAP_Hi *ph; + ULONG spec; + SLONG y; + + // + // pre fetch the data, to avoid reading it 4 times + // + +// TRACE(" cache row %d -> %d \n",x,endx); + + + + for (ph = &PAP_2HI(x,z); x <= endx; x++, ph += PAP_SIZE_HI) + { + float dist; + +// p2->Alt=ph->Alt; //15 ticks later the cache will have loaded + + y = ph->Alt << ALT_SHIFT; + + p2->Alt=float(y); + + px = x >> 2; + pz = z >> 2; + + dx = x & 0x3; + dz = z & 0x3; + + + square = NIGHT_cache[px][pz]; + + + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + + nq = &NIGHT_square[square]; + + /* + + { + SLONG cdx,cdz; + cdx=abs(AENG_cam_x-(x<<8)); + cdz=abs(AENG_cam_z-(z<<8)); + mapz = QDIST2(cdx,cdz); + dist=((float)mapz)/(float)(AENG_DRAW_DIST<<8); + if(dist>1.0f) + dist=1.0f; + } + + NIGHT_get_d3d_colour_and_fade( + nq->colour[dx + dz * PAP_BLOCKS], + &p2->Colour, + &spec,dist); + + */ + + { + NIGHT_Colour *col = &nq->colour[dx + dz * PAP_BLOCKS]; + + SLONG r = col->red << 2; + SLONG g = col->green << 2; + SLONG b = col->blue << 2; + + if (r > 255) {r = 255;} + if (g > 255) {g = 255;} + if (b > 255) {b = 255;} + + p2->Colour = (r << 16) | (g << 8) | b; + } + + p2->Flags=ph->Flags; + p2->Texture=ph->Texture; + + /* + + dx = abs(quick_floor_cam_x - (x << 8)); + dy = abs(quick_floor_cam_y - y ); + dz = abs(quick_floor_cam_z - (z << 8)); + + if (dx + dy + dz <= 256) + { + // + // Too close to camera- set the alpha of the colour. + // + + p2->Colour |= 0x01000000; + } + + */ + +// p2->x=x; +// p2->z=z; + + //POLY_fadeout_point(pp); + +// ph++; + + + p2++; + } + +} + + +float kerb_scaleu; +float kerb_scalev; +float kerb_du; +float kerb_dv; + +inline SLONG add_kerb(float alt1,float alt2,SLONG x,SLONG z,SLONG dx,SLONG dz,D3DLVERTEX *pv, UWORD *p_indicies,SLONG count,ULONG c1,ULONG c2,SLONG flip) +{ +// pv=&p_verts[current_set][vert_count[current_set]]; +// p_indicies=&indicies[current_set][index_count[current_set]]; + + + + // 0 1 0 1 1 + // + // 3 2 3 3 2 + + pv->x = x * 256.0F; + pv->z = z * 256.0F; + pv->y = alt1-KERB_HEIGHT; + + pv->tu=0.0f; + pv->tv=1.0f; + +#ifdef TEX_EMBED + pv->tu=pv->tu*kerb_scaleu+kerb_du; + pv->tv=pv->tv*kerb_scalev+kerb_dv; + +#endif + + + + // set verts colour + pv->color=c1;//0xff808080;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); + pv++; + + + pv->x = (x+dx) * 256.0F; + pv->z = (z+dz) * 256.0F; + pv->y = alt2-KERB_HEIGHT; + + pv->tu=1.0f; + pv->tv=1.0f; + +#ifdef TEX_EMBED + pv->tu=pv->tu*kerb_scaleu+kerb_du; + pv->tv=pv->tv*kerb_scalev+kerb_dv; + +#endif + + // set verts colour + pv->color=c2;//0xff808080;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); + pv++; + + pv->x = (x+dx) * 256.0F; + pv->z = (z+dz) * 256.0F; + pv->y = alt2; + + pv->tu=1.0f; + pv->tv=0.0f; + +#ifdef TEX_EMBED + pv->tu=pv->tu*kerb_scaleu+kerb_du; + pv->tv=pv->tv*kerb_scalev+kerb_dv; + +#endif + + // set verts colour + pv->color=c2;//0xff808080;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); + pv++; + + pv->x = (x) * 256.0F; + pv->z = (z) * 256.0F; + pv->y = alt1; + + pv->tu=0.0f; + pv->tv=0.0f; + +#ifdef TEX_EMBED + + pv->tu=pv->tu*kerb_scaleu+kerb_du; + pv->tv=pv->tv*kerb_scalev+kerb_dv; + +#endif + + // set verts colour + pv->color=c1;//0xff808080;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); + pv++; + + pv-=4; + + + // + // Shall we z-reject + // + + { + SLONG i; + + float dx; + float dy; + float dz; + + float dprod; + + dx = pv[0].x - AENG_cam_x; + dy = pv[0].y - AENG_cam_y; + dz = pv[0].z - AENG_cam_z; + + float dist; + + float adx; + float ady; + float adz; + + adx = fabsf(dx); + ady = fabsf(dy); + adz = fabsf(dz); + + dist = adx + ady + adz; + + if (dist > 768.0F) + { + // + // No need to zclip! + // + } + else + { + for (i = 0; i < 4; i++) + { + dx = pv[i].x - AENG_cam_x; + dy = pv[i].y - AENG_cam_y; + dz = pv[i].z - AENG_cam_z; + + dprod = dx*AENG_cam_matrix[6] + dy*AENG_cam_matrix[7] + dz*AENG_cam_matrix[8]; + + if (dprod < 8.0F) + { + // + // Too close the camera! + // + + return FALSE; + } + } + } + } + + // + // make the indicies as we go along + // + + if (flip) + { + *p_indicies++=count+0; + *p_indicies++=count+3; + *p_indicies++=count+1; + + *p_indicies++=count+2; + *p_indicies++=0xffff; + } + else + { +// SLONG count=vert_count[current_set]; + + *p_indicies++=count; + *p_indicies++=count+1; + *p_indicies++=count+3; + + *p_indicies++=count+2; + *p_indicies++=0xffff; + } + + return TRUE; +} + +inline void draw_i_prim ( LPDIRECT3DTEXTURE2 page, D3DLVERTEX *verts, UWORD *indicies, SLONG *vert_count, SLONG *index_count, D3DMULTIMATRIX *mm_draw_floor ) +{ + HRESULT res; +#ifdef STRIP_STATS + strip_stats[(*vert_count>>2)+1]++; + strip_stats[0]++; + strip_stats[1]+=(*vert_count>>2); +#endif + + mm_draw_floor->lpvVertices =verts; + + indicies[*index_count]=0x1234; + + REALLY_SET_TEXTURE(page); + + //TRACE ( "S1" ); + res=DrawIndPrimMM (the_display.lp_D3D_Device,D3DFVF_LVERTEX ,mm_draw_floor,*vert_count,indicies,*index_count); + //TRACE ( "F1" ); + + + + ASSERT(res == DD_OK); //761 //0x887602f9 + + + *index_count = 0; + *vert_count = 0; + +} + + +#define HALF_COL(col) (col)=((col)>>2)&0xff3f3f3f + +#define KERB_TILES 16 +#define KERB_VERTS (4*KERB_TILES) +#define KERB_INDICIES (5*KERB_TILES) + + +// Well, it's now become the final code... +#define TOMS_TEST_FIXUP_CODE yes + + + +#ifdef DEBUG +int m_iDrawThingCount = 0; +#endif + + + +// Look Mike, when I say "don't put stuff on the stack", I mean +// DONT PUT STUFF ON THE STACK. And it's "indices" - only two "i"s. +UBYTE m_vert_mem_block32[sizeof(D3DLVERTEX)*KERB_VERTS+sizeof(D3DLVERTEX)*MAX_VERTS_FOR_STRIPS*IPRIM_COUNT+32]; // used to 32 byte align the vertex memory +UWORD m_indicies[IPRIM_COUNT][MAX_INDICES_FOR_STRIPS+1]; //data for verts, on stack or not? + + +struct GroupInfo +{ + LPDIRECT3DTEXTURE2 page; //ptr to actual page to use for drawing +#ifndef TOMS_TEST_FIXUP_CODE + float uscale; + float vscale; + float du,dv; +#endif +#ifdef DEBUG + int iDebugCount; +#endif +}; + + +#define MAX_STEAM 20 +inline void general_steam(SLONG x,SLONG z,UWORD texture,SLONG mode) +{ + static SLONG stx[MAX_STEAM],sty[MAX_STEAM],stz[MAX_STEAM],lod[MAX_STEAM]; + static SLONG count_steam=0; + + if(mode==0) + { + count_steam=0; + return; + } + else + if(mode==2) + { + for(SLONG c0=0;c0=MAX_STEAM) + return; + + +#ifdef TARGET_DC + // Key off the "mist" detail setting instead + if (AENG_detail_mist) +#else + if (AENG_detail_shadows) +#endif +// if(page==4*64+53) function only called if page is correct + { + SLONG dx,dz,dist,sx,sy,sz; + + dx=abs( (((SLONG)AENG_cam_x)>>8)-(x) ); + dz=abs( (((SLONG)AENG_cam_z)>>8)-(z) ); + + dist=QDIST2(dx,dz); + + if(dist<15) + { + SLONG sx,sy,sz; + switch((texture >> 0xa) & 0x3) + { + case 0: + sx=190; + sz=128; + break; + case 1: + sx=128; + sz=66; + break; + case 2: + sx=66; + sz=128; + break; + case 3: + sx=128; + sz=190; + break; + default: + ASSERT(0); + break; + + } + sx+=x<<8; + sz+=z<<8; + sy=PAP_calc_height_at(sx,sz); + + stx[count_steam]=sx; + sty[count_steam]=sy; + stz[count_steam]=sz; + lod[count_steam]=10+(15-dist)*3; + count_steam++; +// draw_steam(sx,sy,sz,10+(15-dist)*3); + + } + } + +} + +void draw_quick_floor(SLONG warehouse) +{ + PAP_Hi *ph; +// ULONG colour,specular; + + SLONG c0; + SLONG x,z; + float dy,y; + UWORD index; + + SLONG page,page2,prev_page=-10000,apage=0; + + SLONG current_set=0; + + struct GroupInfo group[IPRIM_COUNT]; + + PolyPage *pp; + LPDIRECT3DTEXTURE2 tex_handle; + + + UWORD kerb_indicies[KERB_INDICIES]; + + + UWORD *p_indicies; + + D3DMATRIX *m_view; + D3DLVERTEX *p_verts[IPRIM_COUNT],*pv,*kerb_verts; + + UBYTE some_data[sizeof(D3DMATRIX)+32]; // used to 32 byte align the funny fanny thing + UBYTE *ptr32; + + SLONG index_count[IPRIM_COUNT],vert_count[IPRIM_COUNT],age[IPRIM_COUNT],kerb_counti=0,kerb_countv=0; + + + SLONG bin_set; + + D3DMULTIMATRIX mm_draw_floor; + + static init_stats=1; + + static SLONG biggest=0; + + struct FloorStore row[MAX_DRAW_WIDTH*2+2]; + struct FloorStore *p1,*p2; + SLONG startx,endx,offsetx; + SLONG no_floor=0; + SLONG is_shadow; + + +#ifdef TEX_EMBED + pp=&POLY_Page[0]; + + kerb_du =pp->m_UOffset; + kerb_dv =pp->m_VOffset; + kerb_scaleu =pp->m_UScale; + kerb_scalev =pp->m_VScale; +#endif + + if (GAME_FLAGS & GF_NO_FLOOR) + no_floor=1; + + general_steam(0,0,0,0); //init it + + +#ifdef STRIP_STATS + memset(strip_stats,0,4*MAX_FLOOR_TILES_FOR_STRIPS+4*10); +#endif + memset(group,0,sizeof(struct GroupInfo)*IPRIM_COUNT); + +#ifdef DEBUG + for ( int i = 0; i < IPRIM_COUNT; i++ ) + { + group[i].iDebugCount = ( i << 5 ) + 2; + } +#endif + + if(init_stats) + { + init_stats=0; + } + + + ptr32=(UBYTE *)(((ULONG)(some_data+32))&0xffffffe0); + m_view=(D3DMATRIX *)ptr32; + + mm_draw_floor.lpd3dMatrices =m_view; + mm_draw_floor.lpvLightDirs =NULL; + mm_draw_floor.lpLightTable =NULL; + + ptr32=(UBYTE *)(((ULONG)(m_vert_mem_block32+32))&0xffffffe0); + + kerb_verts=(D3DLVERTEX *)ptr32; + ptr32+=sizeof(D3DLVERTEX)*KERB_VERTS; + + for(c0=0;c0biggest) +// biggest=NGAMUT_gamut[z].xmax-NGAMUT_gamut[z].xmin; + + for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++,p1++,p2++) + { +// ASSERT(p1->x==x); +// ASSERT(p1->z==z); +// ASSERT(p2->x==x); +// ASSERT(p2->z==z+1); + ASSERT(WITHIN(x, 0, MAP_WIDTH - 1)); + ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1)); + + ASSERT(p1>=&row[0]); + ASSERT(p2>=&row[0]); + ASSERT(p1<&row[MAX_DRAW_WIDTH*2+2]); + ASSERT(p2<&row[MAX_DRAW_WIDTH*2+2]); + + ph = &PAP_2HI(x,z); + + +// ASSERT(ph->Texture==p1->Texture); + + if(warehouse) + { + if (!(p1->Flags & PAP_FLAG_HIDDEN)) + { + continue; + } + + } + else + { + SLONG s1,s2; + + s1=p1->Flags & PAP_FLAG_SINK_SQUARE; + s2=(p1+1)->Flags & PAP_FLAG_SINK_SQUARE; + + if(s1!=s2) + { + // + // change of sink status along x + // + + if(kerb_countv>=KERB_VERTS-4) + { + draw_i_prim(POLY_Page[0].RS.GetTexture(),kerb_verts,kerb_indicies,&kerb_countv,&kerb_counti,&mm_draw_floor); + } + + if (add_kerb((p1+1)->Alt,(p2+1)->Alt,x+1,z,0,1,&kerb_verts[kerb_countv],&kerb_indicies[kerb_counti],kerb_countv,(p1+1)->Colour,(p2+1)->Colour,s1)) + { + kerb_countv+=4; + kerb_counti+=5; + } + + } + + s1=p1->Flags & PAP_FLAG_SINK_SQUARE; + s2=(p2)->Flags & PAP_FLAG_SINK_SQUARE; + + if(s1!=s2) + { + // + // change of sink status along z + // + + if(kerb_countv>=KERB_VERTS-4) + { + draw_i_prim(POLY_Page[0].RS.GetTexture(),kerb_verts,kerb_indicies,&kerb_countv,&kerb_counti,&mm_draw_floor); + } + + if (add_kerb((p2)->Alt,(p2+1)->Alt,x,z+1,1,0,&kerb_verts[kerb_countv],&kerb_indicies[kerb_counti],kerb_countv,(p2)->Colour,(p2+1)->Colour,s2)) + { + kerb_countv+=4; + kerb_counti+=5; + } + + } + + // + // Mark this needs to be in the else! MikeD + // + + if ((p1->Flags & (PAP_FLAG_HIDDEN|PAP_FLAG_ROOF_EXISTS))== PAP_FLAG_HIDDEN) + { + continue; + } + } + + + if (warehouse==0 && (p1->Flags & (PAP_FLAG_ROOF_EXISTS)) ) + { + y=MAVHEIGHT(x,z)<<6; + if(y>AENG_cam_y) + continue; + } + else + { + if (no_floor) + { + // + // Don't draw the floor if there isn't any! (like the final level) + // + + continue; + } + + // + // not a roof so might have a kerb + // + + + } + + if(warehouse) + is_shadow=0; + else + is_shadow=p1->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3); + + + page=p1->Texture&0x3ff; + + if(page==4*64+53) + general_steam(x,z,p1->Texture,1); //store it + + pp=&POLY_Page[page]; + + tex_handle=pp->RS.GetTexture(); + + current_set=-1; + + // + // age the iprims + // + for(c0=0;c0m_UOffset; + group[current_set].dv=pp->m_VOffset; + group[current_set].uscale=pp->m_UScale; + group[current_set].vscale=pp->m_VScale; +#endif +#endif + + + break; + } + + if(age[c0]>oldest) + { + bin_set=c0; + current_set=c0; + oldest=age[c0]; + } + } + + } + else + { + SLONG cv=4,ci=5; + if(is_shadow) + { + cv=5; // shadow squares require more verts and indicies as quads are drawn as two seperate tri's + ci=8; // + } + // + // do we have to bin(draw) a prim because it is too full? + // + if(vert_count[current_set]>=MAX_VERTS_FOR_STRIPS-cv || index_count[current_set]>=MAX_INDICES_FOR_STRIPS-ci) + bin_set=current_set; + } + age[current_set]=0; + + ASSERT(current_set>=0&& current_set=0)// || vert_count[current_set]>=MAX_VERTS_FOR_STRIPS-4) + { + if(vert_count[bin_set]) + { + draw_i_prim(group[bin_set].page,p_verts[bin_set],&m_indicies[bin_set][0],&vert_count[bin_set],&index_count[bin_set],&mm_draw_floor); +#ifdef DEBUG + group[bin_set].iDebugCount++; +#endif + + ASSERT(bin_set==current_set); + + group[current_set].page=tex_handle; +#ifdef TEX_EMBED +#ifndef TOMS_TEST_FIXUP_CODE + group[current_set].du=pp->m_UOffset; + group[current_set].dv=pp->m_VOffset; + group[current_set].uscale=pp->m_UScale; + group[current_set].vscale=pp->m_VScale; +#endif +#endif + + } + } +// group[current_set]=page; + +// current_set=0; + + // + // build the floor quad + // + pv=&p_verts[current_set][vert_count[current_set]]; + p_indicies=&m_indicies[current_set][index_count[current_set]]; + + ASSERT(vert_count[current_set]Flags & PAP_FLAG_SINK_SQUARE) && warehouse==0) + { + dy = -KERB_HEIGHT; + } + else + { + dy = 0.0f; + } + + + // 0 1 0 1 1 + // + // 3 2 3 3 2 + + pv->x = x * 256.0F; + pv->z = z * 256.0F; + pv->color=p1->Colour;//0xff808080;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); + pv++; + + + pv->x = (x+1) * 256.0F; + pv->z = z * 256.0F; + pv->color=(p1+1)->Colour;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); + pv++; + + pv->x = (x+1) * 256.0F; + pv->z = (z+1) * 256.0F; + pv->color=(p2+1)->Colour;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); + pv++; + + pv->x = x * 256.0F; + pv->z = (z+1) * 256.0F; + pv->color=p2->Colour;//202020; + pv->specular=0xff000000; + SET_MM_INDEX(*pv,0); +// pv++; + + pv-=3; + + TEXTURE_get_minitexturebits_uvs( + p1->Texture, + &page2, + &pv[0].tu, + &pv[0].tv, + &pv[1].tu, + &pv[1].tv, + &pv[3].tu, + &pv[3].tv, + &pv[2].tu, + &pv[2].tv); + + #ifdef TEX_EMBED + +#ifdef TOMS_TEST_FIXUP_CODE + pv[0].tu=pv[0].tu*pp->m_UScale+pp->m_UOffset; + pv[1].tu=pv[1].tu*pp->m_UScale+pp->m_UOffset; + pv[2].tu=pv[2].tu*pp->m_UScale+pp->m_UOffset; + pv[3].tu=pv[3].tu*pp->m_UScale+pp->m_UOffset; + + pv[0].tv=pv[0].tv*pp->m_VScale+pp->m_VOffset; + pv[1].tv=pv[1].tv*pp->m_VScale+pp->m_VOffset; + pv[2].tv=pv[2].tv*pp->m_VScale+pp->m_VOffset; + pv[3].tv=pv[3].tv*pp->m_VScale+pp->m_VOffset; +#else + pv[0].tu=pv[0].tu*group[current_set].uscale+group[current_set].du; + pv[1].tu=pv[1].tu*group[current_set].uscale+group[current_set].du; + pv[2].tu=pv[2].tu*group[current_set].uscale+group[current_set].du; + pv[3].tu=pv[3].tu*group[current_set].uscale+group[current_set].du; + + pv[0].tv=pv[0].tv*group[current_set].vscale+group[current_set].dv; + pv[1].tv=pv[1].tv*group[current_set].vscale+group[current_set].dv; + pv[2].tv=pv[2].tv*group[current_set].vscale+group[current_set].dv; + pv[3].tv=pv[3].tv*group[current_set].vscale+group[current_set].dv; +#endif + + #endif + + +#ifdef DEBUG +#ifdef TARGET_DC + // Colour the vertices. +#define BUTTON_IS_PRESSED(value) ((value&0x80)!=0) +extern DIJOYSTATE the_state; + if ( BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_LTRIGGER] ) && BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_RTRIGGER] ) ) + { + DWORD dwTemp = group[current_set].iDebugCount; + dwTemp = ( dwTemp ) + ( dwTemp << 8 ) + ( dwTemp << 17 ) + ( dwTemp << 26 ); + dwTemp &= 0x7f7f7f7f; + pv[0].dcColor = dwTemp; + pv[1].dcColor = dwTemp; + pv[2].dcColor = dwTemp; + pv[3].dcColor = dwTemp; + pv[0].dcSpecular = dwTemp; + pv[1].dcSpecular = dwTemp; + pv[2].dcSpecular = dwTemp; + pv[3].dcSpecular = dwTemp; + } +#endif +#endif + + if ((p1->Flags & (PAP_FLAG_ROOF_EXISTS)) && warehouse==0) + { + y=MAVHEIGHT(x,z)<<6; + + pv[0].y = y; + pv[1].y = y; + pv[2].y = y; + pv[3].y = y; + } + else + { + + pv[0].y = p1->Alt+dy;// * float(1 << ALT_SHIFT)+dy; + pv[1].y = (p1+1)->Alt+dy;// * float(1 << ALT_SHIFT)+dy; + pv[2].y = (p2+1)->Alt+dy;// * float(1 << ALT_SHIFT)+dy; + pv[3].y = (p2)->Alt+dy;// * float(1 << ALT_SHIFT)+dy; + } + + { + SLONG i; + + float dx; + float dy; + float dz; + + float dprod; + + dx = (pv[0].x + pv[2].x) * 0.5F - AENG_cam_x; + dy = (pv[0].y + pv[2].y) * 0.5F - AENG_cam_y; + dz = (pv[0].z + pv[2].z) * 0.5F - AENG_cam_z; + + float dist; + + float adx; + float ady; + float adz; + + adx = fabsf(dx); + ady = fabsf(dy); + adz = fabsf(dz); + + dist = 0; + dist += adx; + dist += ady; + dist += adz; + + if (dist > 512.0F) + { + // + // No need to zclip! + // + } + else + { + ULONG zclip = 0; + float along[4]; + + for (i = 0; i < 4; i++) + { + dx = pv[i].x - AENG_cam_x; + dy = pv[i].y - AENG_cam_y; + dz = pv[i].z - AENG_cam_z; + + dprod = dx*AENG_cam_matrix[6] + dy*AENG_cam_matrix[7] + dz*AENG_cam_matrix[8]; + + if (dprod < 8.0F) + { + // + // Too close the camera- zfuck! + // + + along[i] = 8.0F - dprod; + + zclip |= 1 << i; + + } + } + + if (zclip) + { + if (zclip == 0xf) + { + // + // Reject whole quad! + // + + goto abandon_quad; + } + + for (i = 0; i < 4; i++) + { + if (zclip & (1 << i)) + { + pv[i].x += along[i] * AENG_cam_matrix[6]; + pv[i].y += along[i] * AENG_cam_matrix[7]; + pv[i].z += along[i] * AENG_cam_matrix[8]; + } + } + } + } + } + + pv += 4; + + // + // shadows + // + if(is_shadow) + { + // + // for shadows we need to duplicate the diag verts + // + + pv-=4; + pv[4]=pv[3]; + + // to be compatible with shadow.h we have to rotate quad by 180 Degrees + + + // 3 2 4 + // + // 1 0 1 + + switch(is_shadow)//p1->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3)) + { + case 0: + ASSERT(0); // We shouldn't be doing any of this in this case. + break; + + case 1: + HALF_COL(pv[0].color); + HALF_COL(pv[3].color); + + break; + + case 2: + case 6: + HALF_COL(pv[4].color); + HALF_COL(pv[3].color); + HALF_COL(pv[0].color); + //HALF_COL(pv[2].color); + + break; + + case 3: + HALF_COL(pv[4].color); + HALF_COL(pv[3].color); + + + break; + + case 4: + HALF_COL(pv[2].color); + HALF_COL(pv[3].color); + HALF_COL(pv[4].color); + + break; + + case 5: + HALF_COL(pv[2].color); + HALF_COL(pv[0].color); + HALF_COL(pv[4].color); + HALF_COL(pv[3].color); + break; + + case 7: + HALF_COL(pv[2].color); + HALF_COL(pv[4].color); + break; + + default: + ASSERT(0); + break; + } + pv+=5; + + // + // make the indicies as we go along, for 6 vert shadow split quad + // + + + SLONG count=vert_count[current_set]; + + *p_indicies++=count+3; + *p_indicies++=count+0; + *p_indicies++=count+1; + *p_indicies++=0xffff; + + *p_indicies++=count+2; + *p_indicies++=count+4; + *p_indicies++=count+1; + *p_indicies++=0xffff; + + vert_count[current_set]+=5; + index_count[current_set]+=8; //8 per quad because its two separte tri's + + } + else + { + // + // make the indicies as we go along, for 4 vert normal quad + // + + SLONG count=vert_count[current_set]; + + *p_indicies++=count+0; + *p_indicies++=count+1; + *p_indicies++=count+3; + *p_indicies++=count+2; + *p_indicies++=0xffff; + + vert_count[current_set]+=4; + index_count[current_set]+=5; //5 per quad because terminates with -1 + + } + + abandon_quad:; + } + } + + + + // + // Draw any prims left with data in + // + for(c0=0;c0 192 ) + { + m_iDCFramerateMin++; + } + } + TRACE ( "Min framerate: %i\n", m_iDCFramerateMin ); + } + if ( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_Y] ) ) + { + // Change min frame rate + if ( ( iNotTooFastCounter & 0x3 ) == 0 ) + { + if ( the_state.lX < 64 ) + { + m_iDCFramerateMax--; + } + else if ( the_state.lX > 192 ) + { + m_iDCFramerateMax++; + } + } + TRACE ( "Max framerate: %i\n", m_iDCFramerateMax ); + } + if ( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_B] ) ) + { + // Kill the auto throttle system. + m_iDCFramerateMin = -1; + m_iDCFramerateMax = 60; + } + } + else +//#endif + { + + extern SLONG tick_tock_unclipped; + if(tick_tock_unclipped) + { + int iFramerate = 1000/tick_tock_unclipped; + + // If in a cutscene, or in "first-person" mode, move the fog plane to the distance, + // because it looks nicer, and the framerate hit is not nearly as noticeable. + if ( FirstPersonMode || EWAY_stop_player_moving() ) + { + CurDrawDistance += 64; + } + else if( iFramerate < m_iDCFramerateMin) + { + CurDrawDistance -= 64; + //remove_dead_people=1; + } + else if ( iFramerate > m_iDCFramerateMax ) + { + CurDrawDistance += 64; + } + SATURATE(CurDrawDistance,(10<<8)+128,(22<<8)+128); + } + } + +} +#endif + + + +UBYTE index_lookup[]={0,1,3,2}; + +void AENG_draw_city() +{ + + //LOG_ENTER ( AENG_Draw_City ) + + + //TRACE ( "AengIn" ); + + ANNOYINGSCRIBBLECHECK; + + + DumpTracies(); + + + SLONG i; + + SLONG x; + SLONG y; + SLONG z; + + SLONG dx; + SLONG dy; + SLONG dz; + SLONG dist; + + SLONG nx; + SLONG nz; + + SLONG page; + SLONG shadow; + SLONG square; + + float world_x; + float world_y; + float world_z; + + POLY_Point *pp; + POLY_Point *ppl; +#ifndef TARGET_DC + MapElement *me; +#endif + + PAP_Lo *pl; + PAP_Hi *ph; + + THING_INDEX t_index; + Thing *p_thing; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + NIGHT_Square *nq; + + SLONG red; + SLONG green; + SLONG blue; + + SLONG px; + SLONG pz; + + SLONG sx; + SLONG sz; + + SLONG px1; + SLONG pz1; + SLONG px2; + SLONG pz2; + + SLONG mx; + SLONG mz; + + SLONG worked_out_colour; + ULONG colour; + ULONG specular; + + OB_Info *oi; + + LIGHT_Colour pcol; + static outside=1; + static sea_offset=0; + + AENG_total_polys_drawn = 0; +void draw_all_boxes(void); + draw_all_boxes(); + + +extern SLONG tick_tock_unclipped; + sea_offset+=(tick_tock_unclipped); + + +#if 0 +#ifdef TARGET_DC + // For some reason the PC version decides not to call this. + // I think they have some mad scheme of calling it in the previous + // frame, but it really screws things up. STOP IT! + POLY_frame_init(TRUE,TRUE); +#endif +#endif + + + + + + LOG_ENTER ( AENG_Check_Visible ); + + // + // Work out which things are in view. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Flags & FLAGS_IN_BUILDING) + { + // + // Dont draw things inside buildings when we are outdoors. + // + } + else + { + switch(p_thing->Class) + { + case CLASS_PERSON: + + // + // We only have a rejection test for people now. + // + + if(p_thing->Genus.Person->PlayerID && !p_thing->Genus.Person->Ware) + p_thing->Flags |= FLAGS_IN_VIEW; + else + if (!p_thing->Genus.Person->Ware && FC_can_see_person(AENG_cur_fc_cam, p_thing)) + { + if (POLY_sphere_visible( + float(p_thing->WorldPos.X >> 8), + float(p_thing->WorldPos.Y >> 8) + 0x80, + float(p_thing->WorldPos.Z >> 8), + 256.0F / (AENG_DRAW_DIST * 256.0F))) + { + p_thing->Flags |= FLAGS_IN_VIEW; + } + } + + break; + + default: + p_thing->Flags |= FLAGS_IN_VIEW; + break; + } + } + + t_index = p_thing->Child; + } + + NIGHT_square[NIGHT_cache[x][z]].flag &= ~NIGHT_SQUARE_FLAG_DELETEME; + } + } + + BreakTime("Worked out things in view"); + + LOG_EXIT ( AENG_Check_Visible ); + + LOG_ENTER ( AENG_Draw_Indoors_Floors ); + + ANNOYINGSCRIBBLECHECK; + + + // + // Points out of the ambient light. + // + + shadow = + ((NIGHT_amb_red >> 1) << 16) | + ((NIGHT_amb_green >> 1) << 8) | + ((NIGHT_amb_blue >> 1) << 0); + + if(Keys[KB_L]&&ControlFlag) + { + outside^=1; + } + + if(INDOORS_INDEX) + { +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); + POLY_frame_init(TRUE,TRUE); +#endif + if(INDOORS_INDEX_NEXT) + AENG_draw_inside_floor(INDOORS_INDEX_NEXT,INDOORS_ROOM_NEXT,0); + +// POLY_frame_draw(TRUE,TRUE); + if(INDOORS_INDEX) + AENG_draw_inside_floor(INDOORS_INDEX,INDOORS_ROOM,INDOORS_INDEX_FADE); +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); + POLY_frame_init(TRUE,TRUE); +#endif +// return; + } + + LOG_EXIT ( AENG_Draw_Indoors_Floors ); + +#ifdef NEW_FLOOR + draw_quick_floor(0); +#endif + + // + // Rotate all the points. //draw_floor + // + + LOG_ENTER ( AENG_Rotate_Points ); +#ifndef NEW_FLOOR + colour = 0x00888888; + specular = 0xff000000; + +#ifdef TARGET_DC + // DC internals fixup. + POLY_flush_local_rot(); +#endif + + if(!INDOORS_INDEX||outside) + for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++) + { + for (x = NGAMUT_point_gamut[z].xmin; x <= NGAMUT_point_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, MAP_WIDTH - 1)); + ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1)); + +extern UBYTE player_visited[16][128]; +// player_visited[x>>3][z]|=1<<(x&7); + + ph = &PAP_2HI(x,z); + //show_gamut_hi(x,z); + + // + // The upper point. + // + + world_x = x * 256.0F; + world_y = ph->Alt * float(1 << ALT_SHIFT); + world_z = z * 256.0F; + + worked_out_colour = FALSE; + + if (!(ph->Flags & PAP_FLAG_NOUPPER)) + { + pp = &AENG_upper[x & 63][z & 63]; + + POLY_transform(world_x, world_y, world_z, pp); + + if (pp->MaybeValid()) + { + // + // Work out the colour of this point... what a palaver! + // + + + if(INDOORS_INDEX) + { +/* + NIGHT_get_d3d_colour_dim( + nq->colour[dx + dz * PAP_BLOCKS], + &pp->colour, + &pp->specular); +*/ +#ifdef TARGET_DC + pp->colour=0xff808080;//202020; + pp->specular=0xff000000; +#else + pp->colour=0x80808080;//202020; + pp->specular=0x80000000; +#endif + } + else + { + px = x >> 2; + pz = z >> 2; + + dx = x & 0x3; + dz = z & 0x3; + + ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1)); + + square = NIGHT_cache[px][pz]; + + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + + nq = &NIGHT_square[square]; + + NIGHT_get_d3d_colour( + nq->colour[dx + dz * PAP_BLOCKS], + &pp->colour, + &pp->specular); + } + +#ifndef TARGET_DC + apply_cloud((SLONG)world_x,(SLONG)world_y,(SLONG)world_z,&pp->colour); +#endif + + + POLY_fadeout_point(pp); + + colour = pp->colour; + specular = pp->specular; + + worked_out_colour = TRUE; + } + } + + // + // The lower point. + // + + if (ph->Flags & PAP_FLAG_SINK_POINT|| (MAV_SPARE(x,z) & MAV_SPARE_FLAG_WATER)) + { + + if(ph->Flags & PAP_FLAG_SINK_POINT) + { + world_y -= KERB_HEIGHT; + } + else + { + world_y+=(COS(((x<<8)+(sea_offset>>1))&2047)+SIN(((z<<8)+(sea_offset>>1)+700)&2047))>>13; + + } + + ppl = &AENG_lower[x & 63][z & 63]; + + POLY_transform(world_x, world_y, world_z, ppl); + + if (ppl->MaybeValid()) + { + if (worked_out_colour) + { + // + // Use the colour of the upper point... + // + + ppl->colour = colour; + ppl->specular = specular; +#ifdef TARGET_DC + ppl->colour |= 0xff000000; + ppl->specular |= 0xff000000; +#endif + } + else + { + // + // Work out the colour of this point... what a palaver! + // + + + if(INDOORS_INDEX) + { +/* + NIGHT_get_d3d_colour_dim( + nq->colour[dx + dz * PAP_BLOCKS], + &ppl->colour, + &ppl->specular); +*/ + ppl->colour=0x202020; + ppl->specular=0xff000000; +#ifdef TARGET_DC + ppl->colour |= 0xff000000; + ppl->specular |= 0xff000000; +#endif + + } + else + { + px = x >> 2; + pz = z >> 2; + + dx = x & 0x3; + dz = z & 0x3; + + ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1)); + + square = NIGHT_cache[px][pz]; + + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + + nq = &NIGHT_square[square]; + + NIGHT_get_d3d_colour( + nq->colour[dx + dz * PAP_BLOCKS], + &ppl->colour, + &ppl->specular); + } + + POLY_fadeout_point(ppl); + } +#ifndef TARGET_DC + apply_cloud((SLONG)world_x,(SLONG)world_y,(SLONG)world_z,&ppl->colour); +#endif + } + } + } + } +#endif + BreakTime("Rotated points"); + + ANNOYINGSCRIBBLECHECK; + + LOG_EXIT ( AENG_Rotate_Points ); + + // + // No reflection and shadow stuff second time round during 3d mode. + // + + +#ifndef TARGET_DC + LOG_ENTER ( AENG_Draw_Stars ); + + if (AENG_detail_stars && !(NIGHT_flag & NIGHT_FLAG_DAYTIME)) + { + // + // Draw the stars... + // + if (the_display.screen_lock()) + { + BreakTime("Locked for stars"); + + SKY_draw_stars( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_DRAW_DIST * 256.0F); + + BreakTime("Drawn stars"); + + the_display.screen_unlock(); + } + } + + BreakTime("Done stars"); + + LOG_EXIT ( AENG_Draw_Stars ); +#endif + + + ANNOYINGSCRIBBLECHECK; + + // + // Shadows. + // + +#ifdef TARGET_DC + // Tweak my number of shadows PLEASE BOB + #define AENG_NUM_SHADOWS 4 +#else + #define AENG_NUM_SHADOWS 4 +#endif + + LOG_ENTER ( AENG_Draw_Shadows ) + + struct + { + Thing *p_person; + SLONG dist; + + } shadow_person[AENG_NUM_SHADOWS]; + SLONG shadow_person_upto = 0; + + + if (AENG_detail_shadows) + { + Thing *darci = FC_cam[AENG_cur_fc_cam].focus; + + // + // How many people do we generate shadows for? + // + + SLONG shadow_person_worst_dist = -INFINITY; + SLONG shadow_person_worst_person; + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_VIEW)) + { + // + // Distance from darci. + // + + dx = p_thing->WorldPos.X - darci->WorldPos.X; + dz = p_thing->WorldPos.Z - darci->WorldPos.Z; + + dist = abs(dx) + abs(dz); + + if (dist < 0x60000) + { + if (shadow_person_upto < AENG_NUM_SHADOWS) + { + // + // Put this person in the shadow array. + // + + shadow_person[shadow_person_upto].p_person = p_thing; + shadow_person[shadow_person_upto].dist = dist; + + // + // Keep track of the furthest person away. + // + + if (dist > shadow_person_worst_dist) + { + shadow_person_worst_dist = dist; + shadow_person_worst_person = shadow_person_upto; + } + + shadow_person_upto += 1; + } + else + { + if (dist < shadow_person_worst_dist) + { + // + // Replace the worst person. + // + + ASSERT(WITHIN(shadow_person_worst_person, 0, AENG_NUM_SHADOWS - 1)); + + shadow_person[shadow_person_worst_person].p_person = p_thing; + shadow_person[shadow_person_worst_person].dist = dist; + + // + // Find the worst person + // + + shadow_person_worst_dist = -INFINITY; + + for (i = 0; i < AENG_NUM_SHADOWS; i++) + { + if (shadow_person[i].dist > shadow_person_worst_dist) + { + shadow_person_worst_dist = shadow_person[i].dist; + shadow_person_worst_person = i; + } + } + } + } + } + } + + t_index = p_thing->Child; + } + } + } + + // + // Draw the people's shadow maps. + // + + SLONG offset_x; + SLONG offset_y; + + POLY_flush_local_rot(); + + for (i = 0; i < shadow_person_upto; i++) + { + darci = shadow_person[i].p_person; + + memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer)); + + SMAP_person( + darci, + (UBYTE *) AENG_aa_buffer, + AENG_AA_BUF_SIZE, + AENG_AA_BUF_SIZE, + 147, + -148, + -147); + + // + // Where do we put it in the shadow texture page? Hard code everything! + // + + ASSERT(AENG_AA_BUF_SIZE == 32); + ASSERT(TEXTURE_SHADOW_SIZE == 64); + + offset_x = (i & 1) << 5; + offset_y = (i & 2) << 4; + + // + // Plonk it into the shadow texture page. + // + + if (TEXTURE_shadow_lock()) + { + SLONG x; + SLONG y; + UWORD *line; + UBYTE *buf = (UBYTE *) AENG_aa_buffer; + UWORD* mapping = GetShadowPixelMapping(); + + for (y = 0; y < AENG_AA_BUF_SIZE; y++) + { + line = &TEXTURE_shadow_bitmap[((y + offset_y) * TEXTURE_shadow_pitch >> 1) + offset_x]; + + for (x = AENG_AA_BUF_SIZE - 1; x >= 0; x--) + { + *line++ = mapping[*buf++]; + } + } + + TEXTURE_shadow_unlock(); + } + + // + // How we map floating points coordinates from 0 to 1 onto + // where we plonked the shadow map in the texture page. + // + + AENG_project_offset_u = float(offset_x) / float(TEXTURE_SHADOW_SIZE); + AENG_project_offset_v = float(offset_y) / float(TEXTURE_SHADOW_SIZE); + AENG_project_mul_u = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE); + AENG_project_mul_v = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE); + + // + // The position from which the shadow fades out. + // + + AENG_project_fadeout_x = float(darci->WorldPos.X >> 8); + AENG_project_fadeout_z = float(darci->WorldPos.Z >> 8); + + { + // + // Map this poly onto the mapsquares surrounding darci. + // + + SLONG i; + + SLONG mx; + SLONG mz; + SLONG dx; + SLONG dz; + + SLONG mx1; + SLONG mz1; + SLONG mx2; + SLONG mz2; + SLONG exit = FALSE; + + SLONG mx_lo; + SLONG mz_lo; + +#ifndef TARGET_DC + MapElement *me[4]; +#endif + PAP_Hi *ph[4]; + + SVector_F poly[4]; + SMAP_Link *projected; + + SLONG v_list; + SLONG i_vect; + + DFacet *df; + + SLONG w_list; + SLONG w_face; + + PrimFace4 *p_f4; + PrimPoint *pp; + + SLONG wall; + SLONG storey; + SLONG building; + SLONG thing; + SLONG face_height; + UBYTE face_order[4] = {0,1,3,2}; + + Thing *p_fthing; + + // + // Colvects we have already done. + // + + #define AENG_MAX_DONE 8 + + SLONG done[AENG_MAX_DONE]; + SLONG done_upto = 0; + + for (dx = -1; dx <= 1; dx++) + for (dz = -1; dz <= 1; dz++) + { + mx = (darci->WorldPos.X >> 16) + dx; + mz = (darci->WorldPos.Z >> 16) + dz; + + if (WITHIN(mx, 0, MAP_WIDTH - 2) && + WITHIN(mz, 0, MAP_HEIGHT - 2)) + { +#ifndef TARGET_DC + me[0] = &MAP[MAP_INDEX(mx + 0, mz + 0)]; + me[1] = &MAP[MAP_INDEX(mx + 1, mz + 0)]; + me[2] = &MAP[MAP_INDEX(mx + 1, mz + 1)]; + me[3] = &MAP[MAP_INDEX(mx + 0, mz + 1)]; +#endif + + ph[0] = &PAP_2HI(mx + 0, mz + 0); + ph[1] = &PAP_2HI(mx + 1, mz + 0); + ph[2] = &PAP_2HI(mx + 1, mz + 1); + ph[3] = &PAP_2HI(mx + 0, mz + 1); + + if ( (!(PAP_2HI(mx,mz).Flags & (PAP_FLAG_HIDDEN|PAP_FLAG_WATER))) || (PAP_2HI(mx,mz).Flags & (PAP_FLAG_ROOF_EXISTS))) + { + poly[3].X = float(mx << 8); + poly[3].Z = float(mz << 8); + + poly[0].X = poly[3].X + 256.0F; + poly[0].Z = poly[3].Z; + + poly[1].X = poly[3].X + 256.0F; + poly[1].Z = poly[3].Z + 256.0F; + + poly[2].X = poly[3].X; + poly[2].Z = poly[3].Z + 256.0F; + + + if (PAP_2HI(mx,mz).Flags & (PAP_FLAG_ROOF_EXISTS)) + { + poly[0].Y =poly[1].Y =poly[2].Y =poly[3].Y = MAVHEIGHT(mx,mz)<<6; + } + else + { + poly[3].Y = float(ph[0]->Alt << ALT_SHIFT); + poly[2].Y = float(ph[3]->Alt << ALT_SHIFT); + poly[0].Y = float(ph[1]->Alt << ALT_SHIFT); + poly[1].Y = float(ph[2]->Alt << ALT_SHIFT); + } + + if (PAP_2HI(mx,mz).Flags & PAP_FLAG_SINK_SQUARE) + { + poly[0].Y -= KERB_HEIGHT; + poly[1].Y -= KERB_HEIGHT; + poly[2].Y -= KERB_HEIGHT; + poly[3].Y -= KERB_HEIGHT; + } + + if (ph[0]->Alt == ph[1]->Alt && + ph[0]->Alt == ph[2]->Alt && + ph[0]->Alt == ph[3]->Alt) + { + // + // This quad is coplanar. + // + + projected = SMAP_project_onto_poly(poly, 4); + + if (projected) + { + AENG_add_projected_fadeout_shadow_poly(projected); + } + } + else + { + // + // Do each triangle separatly. + // + + projected = SMAP_project_onto_poly(poly, 3); + + if (projected) + { + AENG_add_projected_fadeout_shadow_poly(projected); + } + + // + // The triangles are 0,1,2 and 0,2,3. + // + + poly[1] = poly[0]; + + projected = SMAP_project_onto_poly(poly + 1, 3); + + if (projected) + { + AENG_add_projected_fadeout_shadow_poly(projected); + } + } + } + } + } + + mx1 = (darci->WorldPos.X >> 8) - 0x100 >> PAP_SHIFT_LO; + mz1 = (darci->WorldPos.Z >> 8) - 0x100 >> PAP_SHIFT_LO; + + mx2 = (darci->WorldPos.X >> 8) + 0x100 >> PAP_SHIFT_LO; + mz2 = (darci->WorldPos.Z >> 8) + 0x100 >> PAP_SHIFT_LO; + + SATURATE(mx1, 0, PAP_SIZE_LO - 1); + SATURATE(mz1, 0, PAP_SIZE_LO - 1); + SATURATE(mx2, 0, PAP_SIZE_LO - 1); + SATURATE(mz2, 0, PAP_SIZE_LO - 1); + + for (mx_lo = mx1; mx_lo <= mx2; mx_lo++) + for (mz_lo = mz1; mz_lo <= mz2; mz_lo++) + { + SLONG count = 0; + + // + // Project onto nearby colvects... + // + + v_list = PAP_2LO(mx_lo,mz_lo).ColVectHead; + + if (v_list) + { + exit = FALSE; + + while(!exit) + { + i_vect = facet_links[v_list]; + + if(i_vect<0) + { + i_vect = -i_vect; + + exit = TRUE; + } + + df = &dfacets[i_vect]; + + if (df->FacetType == STOREY_TYPE_NORMAL) + { + for (i = 0; i < done_upto; i++) + { + if (done[i] == i_vect) + { + // + // Dont do this facet again + // + + goto ignore_this_facet; + } + } + + if (1 /* Fast facet shadows */) + { + float facet_height = float((df->BlockHeight << 4) * (df->Height >> 2)); + + poly[0].X = float(df->x[1] << 8); + poly[0].Y = float(df->Y[1] ); + poly[0].Z = float(df->z[1] << 8); + + poly[1].X = float(df->x[1] << 8); + poly[1].Y = float(df->Y[1] ) + facet_height; + poly[1].Z = float(df->z[1] << 8); + + poly[2].X = float(df->x[0] << 8); + poly[2].Y = float(df->Y[0] ) + facet_height; + poly[2].Z = float(df->z[0] << 8); + + poly[3].X = float(df->x[0] << 8); + poly[3].Y = float(df->Y[0] ); + poly[3].Z = float(df->z[0] << 8); + + if (df->FHeight) + { + // + // Foundations go down deep into the ground... + // + + poly[0].Y -= 512.0F; + poly[3].Y -= 512.0F; + } + + projected = SMAP_project_onto_poly(poly, 4); + + if (projected) + { + AENG_add_projected_fadeout_shadow_poly(projected); + } + } + else + { + // + // Slow crinkled-shadows! + // + + FACET_project_crinkled_shadow(i_vect); + } + + // + // Remember We've already done this facet. + // + + if (done_upto < AENG_MAX_DONE) + { + done[done_upto++] = i_vect; + } + } + + ignore_this_facet:; + + v_list++; + } + } + + //if (darci->OnFace) Always do this. + { + // + // Cast shadow on walkable faces. + // + + w_face = PAP_2LO(mx_lo,mz_lo).Walkable; + + while(w_face) + { + if (w_face > 0) + { + p_f4 = &prim_faces4[w_face]; + face_height = prim_points[p_f4->Points[0]].Y; + + if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8)) + { + // + // This face is above Darci, so don't put her shadow + // on it. + // + } + else + { + for (i = 0; i < 4; i++) + { + pp = &prim_points[p_f4->Points[face_order[i]]]; + + poly[i].X = float(pp->X); + poly[i].Y = float(pp->Y); + poly[i].Z = float(pp->Z); + } + + projected = SMAP_project_onto_poly(poly, 4); + + if (projected) + { + AENG_add_projected_fadeout_shadow_poly(projected); + } + } + + w_face = p_f4->Col2; + } + else + { + struct RoofFace4 *rf; + rf = &roof_faces4[-w_face]; + face_height = rf->Y; + + if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8)) + { + // + // This face is above Darci, so don't put her shadow + // on it. + // + } + else + { + SLONG mx,mz; + mx=(rf->RX&127)<<8; + mz=(rf->RZ&127)<<8; + + poly[0].X=(float)(mx); + poly[0].Y=(float)(rf->Y); + poly[0].Z=(float)(mz); + + poly[1].X=(float)(mx+256); + poly[1].Y=(float)(rf->Y+(rf->DY[0]<Y+(rf->DY[1]<Y+(rf->DY[2]<Next; + + } + } + } + } + } + + TEXTURE_shadow_update(); + } + } + + BreakTime("Done shadows"); + + LOG_EXIT ( AENG_Draw_Shadows ) + + +#ifndef TARGET_DC +// No reflections on DC. + + + + ANNOYINGSCRIBBLECHECK; + + // + // Where we remember the bounding boxes of reflections. + // + + LOG_ENTER ( AENG_Moon ) + + struct + { + SLONG x1; + SLONG y1; + SLONG x2; + SLONG y2; + SLONG water_box; + + } bbox[AENG_MAX_BBOXES]; + SLONG bbox_upto = 0; + + if (AENG_detail_moon_reflection && !(NIGHT_flag & NIGHT_FLAG_DAYTIME) && !(GAME_FLAGS & GF_NO_FLOOR)) + { + // + // The moon upside down... + // + + float moon_x1; + float moon_y1; + float moon_x2; + float moon_y2; + + if (SKY_draw_moon_reflection( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_DRAW_DIST * 256.0F, + &moon_x1, + &moon_y1, + &moon_x2, + &moon_y2)) + { + /* + + // + // The moon is wibbled with polys now. + // + + bbox[0].x1 = MAX((SLONG)moon_x1 - AENG_BBOX_PUSH_OUT, AENG_BBOX_PUSH_IN); + bbox[0].y1 = MAX((SLONG)moon_y1, 0); + bbox[0].x2 = MIN((SLONG)moon_x2 + AENG_BBOX_PUSH_OUT, DisplayWidth - AENG_BBOX_PUSH_IN); + bbox[0].y2 = MIN((SLONG)moon_y2, DisplayHeight); + + bbox[0].water_box = FALSE; + + bbox_upto = 1; + + */ + } + } + + LOG_EXIT ( AENG_Moon ) + + ANNOYINGSCRIBBLECHECK; + + // + // Draw the reflections of people. + // + + LOG_ENTER ( AENG_People_Reflection ) + + if (AENG_detail_people_reflection) + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_VIEW)) + { + // + // This is a person... Is she standing near a puddle or some water? + // + + mx = p_thing->WorldPos.X >> 16; + mz = p_thing->WorldPos.Z >> 16; + + if (!PAP_on_map_hi(mx,mz)) + { + // + // Off the map. + // + } + else + { + ph = &PAP_2HI(mx,mz); + + if (ph->Flags & (PAP_FLAG_REFLECTIVE|PAP_FLAG_WATER)) + { + // + // Not too far away? + // + + dx = abs(p_thing->WorldPos.X - FC_cam[AENG_cur_fc_cam].x >> 8); + dz = abs(p_thing->WorldPos.Z - FC_cam[AENG_cur_fc_cam].z >> 8); + + if (dx + dz < 0x600) + { + SLONG reflect_height; + + // + // Puddles are always on the floor nowadays... + // + + if (ph->Flags & PAP_FLAG_REFLECTIVE) + { + reflect_height = PAP_calc_height_at(p_thing->WorldPos.X >> 8, p_thing->WorldPos.Z >> 8); + } + else + { + // + // The height of the water is given by the lo-res mapsquare corresponding + // to the hi-res mapsquare that Darci is standing on. + // + + pl = &PAP_2LO( + p_thing->WorldPos.X >> (8 + PAP_SHIFT_LO), + p_thing->WorldPos.Z >> (8 + PAP_SHIFT_LO)); + + reflect_height = pl->water << ALT_SHIFT; + } + + // + // Draw the reflection! + // + + FIGURE_draw_reflection(p_thing, reflect_height); + + if (WITHIN(bbox_upto, 0, AENG_MAX_BBOXES - 1)) + { + // + // Create a new bounding box + // + + bbox[bbox_upto].x1 = MAX(FIGURE_reflect_x1 - AENG_BBOX_PUSH_OUT, AENG_BBOX_PUSH_IN); + bbox[bbox_upto].y1 = MAX(FIGURE_reflect_y1, 0); + bbox[bbox_upto].x2 = MIN(FIGURE_reflect_x2 + AENG_BBOX_PUSH_OUT, DisplayWidth - AENG_BBOX_PUSH_IN); + bbox[bbox_upto].y2 = MIN(FIGURE_reflect_y2, DisplayHeight); + + bbox[bbox_upto].water_box = ph->Flags & PAP_FLAG_WATER; + + bbox_upto += 1; + } + } + } + } + } + + t_index = p_thing->Child; + } + } + } + + /* + + // + // Draw the reflections of the OBs. + // + + if(DETAIL_LEVEL&DETAIL_REFLECTIONS) + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + for (oi = OB_find(x,z); oi->prim; oi += 1) + { + // + // On map? + // + + mx = oi->x >> 8; + mz = oi->z >> 8; + + if (WITHIN(mx, 0, PAP_SIZE_HI - 1) && + WITHIN(mz, 0, PAP_SIZE_HI - 1)) + { + // + // On a reflective square? + // + + if (PAP_2HI(mx,mz).Flags & (PAP_FLAG_WATER|PAP_FLAG_REFLECTIVE)) + { + // + // Not too far away? + // + + dx = abs(oi->x - (FC_cam[AENG_cur_fc_cam].x >> 8)); + dz = abs(oi->z - (FC_cam[AENG_cur_fc_cam].z >> 8)); + + if (dx + dz < 0x00) + { + MESH_draw_reflection( + oi->prim, + oi->x, + oi->y, + oi->z, + oi->yaw, + NULL); + } + } + } + } + } + } + + */ + + BreakTime("Drawn reflections"); + + LOG_EXIT ( AENG_People_Reflection ) + + ANNOYINGSCRIBBLECHECK; + + +#ifdef TARGET_DC + if ( AENG_detail_moon_reflection || AENG_detail_people_reflection ) +#endif + { + // + // Drips inside puddles only... + // + + AENG_draw_drips(1); + + // + // Draw the reflections and drips. Clear the poly lists. + // + +#ifndef TARGET_DC + POLY_frame_draw(FALSE,FALSE); + POLY_frame_init(TRUE,TRUE); +#endif + BreakTime("Done first poly flush"); + } + + // + // Draw the puddles. + // + + LOG_ENTER ( AENG_Puddles ) + + if (AENG_detail_puddles && !(GAME_FLAGS & GF_NO_FLOOR)) + { + SLONG i; + + PUDDLE_Info *pi; + + float px1; + float pz1; + float px2; + float pz2; + + float world_x; + float world_y; + float world_z; + + static struct + { + float u; + float v; + + } texture_coords[4] = + { + {0.0F,0.0F}, + {1.0F,0.0F}, + {1.0F,1.0F}, + {0.0F,1.0F} + }; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++) + { + PUDDLE_get_start(z, NGAMUT_gamut[z].xmin, NGAMUT_gamut[z].xmax); + + while(pi = PUDDLE_get_next()) + { + px1 = float(pi->x1); + pz1 = float(pi->z1); + px2 = float(pi->x2); + pz2 = float(pi->z2); + + world_y = float(pi->y); + + for (i = 0; i < 4; i++) + { + world_x = (i & 0x1) ? px1 : px2; + world_z = (i & 0x2) ? pz1 : pz2; + + POLY_transform( + world_x, + world_y, + world_z, + &pp[i]); + + if (pp[i].MaybeValid()) + { + pp[i].u = ((i & 0x1) ? float(pi->u1) : float(pi->u2)) * (1.0F / 256.0F); + pp[i].v = ((i & 0x2) ? float(pi->v1) : float(pi->v2)) * (1.0F / 256.0F); + pp[i].colour = 0xffffffff; + + if (ControlFlag) {pp[i].colour = 0x44ffffff;} + if (ShiftFlag) {pp[i].colour = 0x88ffffff;} + + pp[i].specular = 0xff000000; + } + else + { + goto ignore_this_puddle; + } + } + + if (POLY_valid_quad(quad)) + { + if ((GAME_FLAGS & GF_RAINING) && (rand() & 0x100)) + { + float drip_along_x; + float drip_along_z; + + // + // Choose somewhere in the puddle to put a drip. + // + + drip_along_x = float(rand() & 0xff) * (1.0F / 256.0F); + drip_along_z = float(rand() & 0xff) * (1.0F / 256.0F); + + world_x = px1 + (px2 - px1) * drip_along_x; + world_z = pz1 + (pz2 - pz1) * drip_along_z; + + DRIP_create( + UWORD(world_x), + SWORD(world_y), + UWORD(world_z), + 1); + + if (rand() & 0x11) + { + // + // Don't splash. + // + } + else + { + // + // Splash the puddle. + // + + PUDDLE_splash( + SLONG(world_x), + SLONG(world_y), + SLONG(world_z)); + } + } + + if (pi->rotate_uvs) + { + SWAP_FL(pp[0].u, pp[1].u); + SWAP_FL(pp[1].u, pp[3].u); + SWAP_FL(pp[3].u, pp[2].u); + + SWAP_FL(pp[0].v, pp[1].v); + SWAP_FL(pp[1].v, pp[3].v); + SWAP_FL(pp[3].v, pp[2].v); + } + + POLY_add_quad(quad, POLY_PAGE_PUDDLE, FALSE); + + if (pi->puddle_s1 | pi->puddle_s2) + { + // + // Find the bounding box of this puddle quad on screen. + // + + SLONG px; + SLONG py; + SLONG px1 = +INFINITY; + SLONG py1 = +INFINITY; + SLONG px2 = -INFINITY; + SLONG py2 = -INFINITY; + + for (i = 0; i < 4; i++) + { + px = SLONG(pp[i].X); + py = SLONG(pp[i].Y); + + if (px < px1) {px1 = px;} + if (py < py1) {py1 = py;} + if (px > px2) {px2 = px;} + if (py > py2) {py2 = py;} + } + + // + // Wibble the intersection of this bounding box with the bounding + // box of each reflection we have drawn. + // + + SLONG ix1; + SLONG iy1; + SLONG ix2; + SLONG iy2; + + for (i = 0; i < bbox_upto; i++) + { + if (bbox[i].water_box) + { + // + // This box always gets wibbled anyway. + // + + continue; + } + + ix1 = MAX(px1, bbox[i].x1); + iy1 = MAX(py1, bbox[i].y1); + ix2 = MIN(px2, bbox[i].x2); + iy2 = MIN(py2, bbox[i].y2); + + if (ix1 < ix2 && iy1 < iy2) + { + if (the_display.screen_lock()) + { + // + // Wibble away! + // + + WIBBLE_simple( + ix1, iy1, + ix2, iy2, + pi->puddle_y1, + pi->puddle_y2, + pi->puddle_g1, + pi->puddle_g2, + pi->puddle_s1, + pi->puddle_s2); + + the_display.screen_unlock(); + } + } + } + } + } + + ignore_this_puddle:; + } + } + } + + BreakTime("Drawn puddles"); + + LOG_EXIT ( AENG_Puddles ) + + ANNOYINGSCRIBBLECHECK; + +#ifndef NEW_FLOOR + if (AENG_detail_people_reflection) +#ifndef TARGET_DC + if(!SOFTWARE) +#endif + { + SLONG oldcolour [4]; + SLONG oldspecular[4]; + + // + // Draw all the floor-reflective squares + // + + for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++) + { + for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++) + { +#ifndef TARGET_DC + me = &MAP[MAP_INDEX(x,z)]; +#endif + ph = &PAP_2HI(x,z); + + if (ph->Flags & PAP_FLAG_HIDDEN) + { + continue; + } + + if (!(ph->Flags & PAP_FLAG_REFLECTIVE)) + { + continue; + } + + // + // The four points of the quad. + // + + if (ph->Flags & PAP_FLAG_SINK_SQUARE) + { + quad[0] = &AENG_lower[(x + 0) & 63][(z + 0) & 63]; + quad[1] = &AENG_lower[(x + 1) & 63][(z + 0) & 63]; + quad[2] = &AENG_lower[(x + 0) & 63][(z + 1) & 63]; + quad[3] = &AENG_lower[(x + 1) & 63][(z + 1) & 63]; + } + else + { + quad[0] = &AENG_upper[(x + 0) & 63][(z + 0) & 63]; + quad[1] = &AENG_upper[(x + 1) & 63][(z + 0) & 63]; + quad[2] = &AENG_upper[(x + 0) & 63][(z + 1) & 63]; + quad[3] = &AENG_upper[(x + 1) & 63][(z + 1) & 63]; + } + + if (POLY_valid_quad(quad)) + { + // + // Darken the quad. + // + + for (i = 0; i < 4; i++) + { + oldcolour [i] = quad[i]->colour; + oldspecular[i] = quad[i]->specular; + + quad[i]->colour >>= 1; + quad[i]->colour &= 0x007f7f7f; +#ifdef TARGET_DC + quad[i]->colour |= 0xff000000; +#endif + quad[i]->specular = 0xff000000; + } + + // + // Texture the quad. + // + + if (ph->Flags & PAP_FLAG_ANIM_TMAP) + { + struct AnimTmap *p_a; + SLONG cur; + p_a=&anim_tmaps[ph->Texture]; + cur=p_a->Current; + + quad[0]->u = float(p_a->UV[cur][0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_a->UV[cur][0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_a->UV[cur][1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_a->UV[cur][1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_a->UV[cur][2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_a->UV[cur][2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_a->UV[cur][3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_a->UV[cur][3][1] ) * (1.0F / 32.0F); + + page = p_a->UV[cur][0][0] & 0xc0; + page <<= 2; + page |= p_a->Page[cur]; + } + else + { + TEXTURE_get_minitexturebits_uvs( + ph->Texture, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + } + + POLY_add_quad(quad, page, FALSE); + + // + // Restore old colour info. + // + + for (i = 0; i < 4; i++) + { + quad[i]->colour = oldcolour [i]; + quad[i]->specular = oldspecular[i]; + } + } + } + } + } +#endif + BreakTime("Drawn reflective squares"); + + /* + + // + // Draw the water in the city. + // + + { + SLONG dmx; + SLONG dmz; + + SLONG dx; + SLONG dz; + + SLONG px; + SLONG py; + SLONG pz; + + SLONG ix; + SLONG iz; + + POLY_Point water_pp[5][5]; + POLY_Point *quad[4]; + POLY_Point *pp; + + SLONG user_upto = 1; + + for (i = 0, pp = &water_pp[0][0]; i < 25; i++, pp++) + { + pp->user = 0; + } + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + pl = &PAP_2LO(x,z); + + if (pl->water == PAP_LO_NO_WATER) + { + // + // No water in this square. + // + } + else + { + // + // The height of water in this lo-res mapsquare. + // + + py = pl->water << ALT_SHIFT; + + // + // Look for water in the hi-res mapsquare enclosed by this + // lo-res mapsqure. + // + + for (dmx = 0; dmx < 4; dmx++) + for (dmz = 0; dmz < 4; dmz++) + { + mx = (x << 2) + dmx; + mz = (z << 2) + dmz; + + ph = &PAP_2HI(mx,mz); + + if (ph->Flags & PAP_FLAG_WATER) + { + // + // Transform all the points. + // + + i = 0; + + for (i = 0; i < 4; i++) + { + dx = i & 1; + dz = i >> 1; + + ix = dmx + dx; + iz = dmz + dz; + + if (water_pp[ix][iz].user == user_upto) + { + // + // Already transformed. + // + } + else + { + // + // Transform this point. + // + + water_pp[ix][iz].user = user_upto; + + px = mx + dx << 8; + pz = mz + dz << 8; + + POLY_transform( + float(px), + float(py), + float(pz), + &water_pp[ix][iz]); + + water_pp[ix][iz].colour = 0x44608564; + water_pp[ix][iz].specular = 0xff000000; + + POLY_fadeout_point(&water_pp[ix][iz]); + + // + // This point's (u,v) coordinates are a function of its + // position and the time. + // + + { + float angle_u = float(((((mx + dx) * 5 + (mz + dz) * 6) & 0x1f) + 0x1f) * GAME_TURN) * (1.0F / 1754.0F); + float angle_v = float(((((mx + dx) * 4 + (mz + dz) * 7) & 0x1f) + 0x1f) * GAME_TURN) * (1.0F / 1816.0F); + + water_pp[ix][iz].u = px * (1.0F / 256.0F) + sin(angle_u) * 0.15F; + water_pp[ix][iz].v = pz * (1.0F / 256.0F) + cos(angle_v) * 0.15F; + } + } + + if (!water_pp[ix][iz].MaybeValid()) + { + goto abandon_poly; + } + + quad[i] = &water_pp[ix][iz]; + } + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_SEWATER, FALSE); + } + } + + abandon_poly:; + } + + user_upto += 1; + } + } + } + } + + */ + +// End of reflection stuff. +#endif //#ifndef TARGET_DC + + + // + // The sky. + // + + LOG_ENTER ( AENG_Draw_Sky ) + +extern void SKY_draw_poly_sky_old(float world_camera_x,float world_camera_y,float world_camera_z,float world_camera_yaw,float max_dist,ULONG bot_colour,ULONG top_colour); + +#ifdef TARGET_DC + // Fade sky textures out a bit. + if (AENG_detail_skyline) + SKY_draw_poly_sky_old(AENG_cam_x,AENG_cam_y,AENG_cam_z,AENG_cam_yaw,AENG_DRAW_DIST * 256.0F,0x80808080,0x80808080); +#else + if (AENG_detail_skyline) + SKY_draw_poly_sky_old(AENG_cam_x,AENG_cam_y,AENG_cam_z,AENG_cam_yaw,AENG_DRAW_DIST * 256.0F,0xffffff,0xffffff); +#endif +/* + SKY_draw_poly_clouds( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_DRAW_DIST * 256.0F); + */ + if(!INDOORS_INDEX||outside) + if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME)) + { + SKY_draw_poly_moon( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + /*AENG_DRAW_DIST * 256.0F*/ + 256.0f * 22.0f); + } + + LOG_EXIT ( AENG_Draw_Sky ) + + + + ANNOYINGSCRIBBLECHECK; + + + + + + + + + + // + // Draw the puddles and clear the poly lists. + // + +#ifdef TARGET_DC + if ( AENG_detail_people_reflection && AENG_detail_puddles ) +#endif + { +#ifndef TARGET_DC + POLY_frame_draw_odd(); + POLY_frame_draw_puddles(); +#endif + +#ifdef DEBUG + POLY_frame_draw_sewater(); +#endif + +#ifndef TARGET_DC + POLY_frame_init(TRUE,TRUE); +#endif + } + BreakTime("Done second polygon flush"); + + + + + + + // + // FAR FACETS!!!!!!!!!!!!! + // + + LOG_ENTER ( AENG_Draw_Skyline ) + + FARFACET_draw( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + // Draw dist changes dynamically, so do it to a fixed distance. + //AENG_DRAW_DIST * 4, + 90.0F*256.0F, + + AENG_LENS); + +//#if defined(NDEBUG) || defined(TARGET_DC) +// if (AENG_detail_skyline) +// AENG_draw_far_facets(); +//#endif + + LOG_EXIT ( AENG_Draw_Skyline ) + + + + + + ANNOYINGSCRIBBLECHECK; + + + // + // Create all the squares. + // + + // + // draw floor draw_floor //things to search for + // + +#ifndef NEW_FLOOR + LOG_ENTER ( AENG_Draw_Floors ) + + SLONG num_squares_drawn = 0; + + { + if(!INDOORS_INDEX||outside) + for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++) + { + for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 2)); + ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 2)); + + ph = &PAP_2HI(x,z); + + if ((ph->Flags & (PAP_FLAG_HIDDEN|PAP_FLAG_ROOF_EXISTS))== PAP_FLAG_HIDDEN) + { + continue; + } + + #ifdef FAST_EDDIE + if (Keys[KB_1] && ((x ^ z) & 1)) continue; + #endif + + /* + + if (ph->Flags & PAP_FLAG_WATER) + { + // + // We don't draw the ground because it is covered by water. + // + } + else + + */ + { + POLY_Point fake_roof[4]; + + // + // The four points of the quad. + // + if ((ph->Flags & (PAP_FLAG_ROOF_EXISTS)) ) + { + SLONG c0,light_lookup; + float y; + + y=MAVHEIGHT(x,z)<<6;//(PAP_hi[x][z].Height<<6); + // 0 1 + // + // 2 3 + + POLY_transform((x)<<8,y, (z)<<8, &fake_roof[0]); + POLY_transform((x+1)<<8,y, (z)<<8, &fake_roof[1]); + POLY_transform((x)<<8,y, (z+1)<<8, &fake_roof[3]); + POLY_transform((x+1)<<8,y, (z+1)<<8, &fake_roof[2]); + + + extern UWORD hidden_roof_index[128][128]; + + light_lookup=hidden_roof_index[x][z]; + + ASSERT(light_lookup); + + for(c0=0;c0<4;c0++) + { + SLONG c0_bodge; + c0_bodge=index_lookup[c0]; + pp=&fake_roof[c0]; + // pp->colour=0x808080; + + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour(NIGHT_ROOF_WALKABLE_POINT(light_lookup,c0),&pp->colour,&pp->specular); + + apply_cloud((x+(c0_bodge&1))<<8,y,(z+((c0_bodge&2)>>1))<<8,&pp->colour); + + POLY_fadeout_point(pp); + } + // pp->specular=0xff000000; + // pp->colour=0xff000000; + + + } + + + quad[0] = &fake_roof[0]; + quad[1] = &fake_roof[1]; + quad[2] = &fake_roof[3]; + quad[3] = &fake_roof[2]; + + } + else + { + if (GAME_FLAGS & GF_NO_FLOOR) + { + // + // Don't draw the floor if there isn't any! + // + + continue; + } + + if (ph->Flags & PAP_FLAG_SINK_SQUARE) + { + quad[0] = &AENG_lower[(x + 0) & 63][(z + 0) & 63]; + quad[1] = &AENG_lower[(x + 1) & 63][(z + 0) & 63]; + quad[2] = &AENG_lower[(x + 0) & 63][(z + 1) & 63]; + quad[3] = &AENG_lower[(x + 1) & 63][(z + 1) & 63]; + } + else + { + + if((MAV_SPARE(x,z) & MAV_SPARE_FLAG_WATER)) + quad[0] = &AENG_lower[(x + 0) & 63][(z + 0) & 63]; + else + quad[0] = &AENG_upper[(x + 0) & 63][(z + 0) & 63]; + + if((MAV_SPARE(x+1,z) & MAV_SPARE_FLAG_WATER)) + quad[1] = &AENG_lower[(x + 1) & 63][(z + 0) & 63]; + else + quad[1] = &AENG_upper[(x + 1) & 63][(z + 0) & 63]; + + if((MAV_SPARE(x,z+1) & MAV_SPARE_FLAG_WATER)) + quad[2] = &AENG_lower[(x + 0) & 63][(z + 1) & 63]; + else + quad[2] = &AENG_upper[(x + 0) & 63][(z + 1) & 63]; + + if((MAV_SPARE(x+1,z+1) & MAV_SPARE_FLAG_WATER)) + quad[3] = &AENG_lower[(x + 1) & 63][(z + 1) & 63]; + else + quad[3] = &AENG_upper[(x + 1) & 63][(z + 1) & 63]; + + } + } + + if (POLY_valid_quad(quad)) + { + num_squares_drawn += 1; + + { + // + // Texture the quad. + // + /* + if (ph->Flags & PAP_FLAG_ANIM_TMAP) + { + struct AnimTmap *p_a; + SLONG cur; + p_a=&anim_tmaps[ph->Texture]; + cur=p_a->Current; + + quad[0]->u = float(p_a->UV[cur][0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_a->UV[cur][0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_a->UV[cur][1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_a->UV[cur][1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_a->UV[cur][2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_a->UV[cur][2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_a->UV[cur][3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_a->UV[cur][3][1] ) * (1.0F / 32.0F); + + page = p_a->UV[cur][0][0] & 0xc0; + page <<= 2; + page |= p_a->Page[cur]; + } + else + */ + { + TEXTURE_get_minitexturebits_uvs( + ph->Texture, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + + // page = 86; + } + +#ifdef TARGET_DC + // Key off the "mist" detail setting instead + if (AENG_detail_mist) +#else + if (AENG_detail_shadows) +#endif + if(page==4*64+53) + { + SLONG dx,dz,dist; + + dx=abs( (((SLONG)AENG_cam_x)>>8)-(x) ); + dz=abs( (((SLONG)AENG_cam_z)>>8)-(z) ); + + dist=QDIST2(dx,dz); + + if(dist<15) + { + SLONG sx,sy,sz; + void draw_steam(SLONG x,SLONG y,SLONG z,SLONG lod); + switch((ph->Texture >> 0xa) & 0x3) + { + case 0: + sx=190; + sz=128; + break; + case 1: + sx=128; + sz=66; + break; + case 2: + sx=66; + sz=128; + break; + case 3: + sx=128; + sz=190; + break; + default: + ASSERT(0); + break; + + } + sx+=x<<8; + sz+=z<<8; + sy=PAP_calc_height_at(sx,sz); + + + draw_steam(sx,sy,sz,10+(15-dist)*3); + + } + } + + + if (ph->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3)) + { + POLY_Point ps[4]; + + // + // Create four darkened points. + // + + ps[0] = *(quad[0]); + ps[1] = *(quad[1]); + ps[2] = *(quad[2]); + ps[3] = *(quad[3]); + + // + // Darken the points. + // + + for (i = 0; i < 4; i++) + { + red = (ps[i].colour >> 16) & 0xff; + green = (ps[i].colour >> 8) & 0xff; + blue = (ps[i].colour >> 0) & 0xff; + + red -= 120; + green -= 120; + blue -= 120; + + if (red < 0) {red = 0;} + if (green < 0) {green = 0;} + if (blue < 0) {blue = 0;} + + ps[i].colour = (red << 16) | (green << 8) | (blue << 0)|(0xff000000); + } + + ASSERT(PAP_FLAG_SHADOW_1 == 1); + + switch(ph->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3)) + { + case 0: + ASSERT(0); // We shouldn't be doing any of this in this case. + break; + + case 1: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 2: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 3: + + //ps[2].colour += 0x00101010; + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 4: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 5: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 6: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 7: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + default: + ASSERT(0); + break; + } + } + else + { + #if 0 + + // + // Crinkle? Not on the ground yet... I'll have to code rotation first. + // + + if (/*crinkles enabled*/ 0 && page < 64 * 8 && TEXTURE_crinkle[page]) + { + // + // This quad could be crinkled! + // + + if (quad[0]->z > 0.5F) + { + // + // Too far away to be crinkled. + // + + POLY_add_quad(quad, page, FALSE); + } + else + if (quad[0]->z < 0.2F) + { + // + // Maximum crinkleyness! + // + + CRINKLE_do( + TEXTURE_crinkle[page], + page, + 1.0F, + quad, + FALSE); + } + else + { + float extrude; + float av_z; + + // + // Intermediate crinkle extrusion. + // + + av_z = quad[0]->z + quad[1]->z + quad[2]->z + quad[3]->z; + av_z *= 0.25F; + + extrude = av_z - 0.4F; + extrude *= 1.0F / (0.3F - 0.4F); + + if (extrude > 0.0F) + { + if (extrude > 1.0F) + { + extrude = 1.0F; + } + + CRINKLE_do( + TEXTURE_crinkle[page], + page, + extrude, + quad, + FALSE); + } + else + { + POLY_add_quad(quad, page, FALSE); + } + } + } + else + + #endif + { + POLY_add_quad(quad, page, FALSE); + } + } + } + } + } + + if (ph->Flags & (PAP_FLAG_SINK_SQUARE|PAP_FLAG_WATER)) + { + // + // Do the curbs now. + // + + static struct + { + SLONG dpx1; + SLONG dpz1; + SLONG dpx2; + SLONG dpz2; + + SLONG dsx; + SLONG dsz; + + } curb[4] = + { + {0,0,0,1,-1,0}, + {0,1,1,1,0,+1}, + {1,1,1,0,+1,0}, + {1,0,0,0,0,-1} + }; + + for (i = 0; i < 4; i++) + { + nx = x + curb[i].dsx; + nz = z + curb[i].dsz; + + if (PAP_on_map_hi(nx,nz)) + { + if (PAP_2HI(nx,nz).Flags & (PAP_FLAG_SINK_SQUARE|PAP_FLAG_WATER)) + { + // + // No need for a curb here. + // + } + else + { + quad[0] = &AENG_lower[(x + curb[i].dpx1) & 63][(z + curb[i].dpz1) & 63]; + quad[1] = &AENG_lower[(x + curb[i].dpx2) & 63][(z + curb[i].dpz2) & 63]; + quad[2] = &AENG_upper[(x + curb[i].dpx1) & 63][(z + curb[i].dpz1) & 63]; + quad[3] = &AENG_upper[(x + curb[i].dpx2) & 63][(z + curb[i].dpz2) & 63]; + + if (POLY_valid_quad(quad)) + { + TEXTURE_get_minitexturebits_uvs( + 0, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + + // + // Add the poly. + // + + POLY_add_quad(quad, page, TRUE); + } + } + } + } + } + } + } + } +#endif + BreakTime("Drawn floors"); + + LOG_EXIT ( AENG_Draw_Floors ) + + ANNOYINGSCRIBBLECHECK; + + +// POLY_frame_draw(FALSE,FALSE); +// POLY_frame_init(TRUE,TRUE); +// BreakTime("Done another flush"); + + // + // Draw the objects and the things. + // + + LOG_ENTER ( AENG_Draw_Things ) + + dfacets_drawn_this_gameturn = 0; + { + + LOG_ENTER ( AENG_Draw_Prims ) + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + OB_Info *oi; + NIGHT_Colour *col; + + // + // The cached lighting for this low-res mapsquare. + // + + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + //ASSERT(WITHIN(NIGHT_cache[x][z], 1, NIGHT_MAX_SQUARES - 1)); + + col = NIGHT_square[NIGHT_cache[x][z]].colour; + + // + // Skip over the mapsquares. + // + + col += PAP_BLOCKS * PAP_BLOCKS; + + // + // The objects on this mapsquare. + // + + oi = OB_find(x,z); + + while(oi->prim) + { + if (!(oi->flags & OB_FLAG_WAREHOUSE)) + { + if (oi->prim == 133 || oi->prim == 235) + { + // + // This prim slowly rotates... + // + + oi->yaw = (GAME_TURN << 1) & 2047; + } + +#ifdef EDITOR + UBYTE fade; +extern HWND GEDIT_edit_wnd; + + if (GEDIT_edit_wnd) + fade=(oi->flags & OB_FLAG_NOT_ON_PSX)?0x7f:0xff; + else + fade=0xff; +#else + UBYTE fade=0xff; + +#endif + + col = MESH_draw_poly( + oi->prim, + oi->x, + oi->y, + oi->z, + oi->yaw, + oi->pitch, + oi->roll, + col, + fade, + oi->crumple); + if(!SOFTWARE) + SHAPE_prim_shadow(oi); + + if ((prim_objects[oi->prim].flag & PRIM_FLAG_GLARE)&& !SOFTWARE) + { + if (oi->prim == 230) + { + BLOOM_draw(oi->x,oi->y+48,oi->z, 0,0,0,0x808080,BLOOM_RAISE_LOS); + } + else + { + BLOOM_draw(oi->x,oi->y,oi->z, 0,0,0,0x808080,0); + } + } + else + if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME) && !SOFTWARE) + { + + switch (oi->prim) + { + case 2: + /* + BLOOM_draw(oi->x+270,oi->y+350,oi->z, 0,-255,0,0x7f6500,BLOOM_BEAM); + BLOOM_draw(oi->x-270,oi->y+350,oi->z, 0,-255,0,0x7f6500,BLOOM_BEAM); + BLOOM_draw(oi->x,oi->y+350,oi->z+270, 0,-255,0,0x7f6500,BLOOM_BEAM); + BLOOM_draw(oi->x,oi->y+350,oi->z-270, 0,-255,0,0x7f6500,BLOOM_BEAM); + */ + break; + case 190: + BLOOM_draw(oi->x,oi->y,oi->z, 0,0,0,0x808080,0); + break; + } + } + + // + // As good a place as any to put this! + // + + if (prim_objects[oi->prim].flag & PRIM_FLAG_ITEM) + { + OB_ob[oi->index].yaw += 1; + } + } + + oi += 1; + } + } + } + + LOG_EXIT ( AENG_Draw_Prims ) + + ANNOYINGSCRIBBLECHECK; + + + BreakTime("Drawn prims"); +// POLY_frame_draw(FALSE,FALSE); +// POLY_frame_init(TRUE,TRUE); +// BreakTime("Flushed prims"); + + + + LOG_ENTER ( AENG_Draw_Facets ) + + POLY_set_local_rotation_none(); + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + // + // The cached lighting for this low-res mapsquare. + // + + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + // + // Look at the colvects on this square. + // + + { + SLONG f_list; + SLONG facet; + SLONG build; + SLONG exit = FALSE; + + f_list = PAP_2LO(x,z).ColVectHead; + + show_gamut_lo(x,z); + + if (f_list) + { + SLONG count=0; + while(!exit) + { + struct DFacet *p_vect; + facet=facet_links[f_list]; + + p_vect=&dfacets[facet]; +/* + AENG_world_text(x<<10,(PAP_2HI(x<<2,z<<2).Alt<<3)+count*50,z<<10,128,128,128,1,"x %d z %d %d type %d",x,z,facet,p_vect->FacetType); + if(x==13 && z==5) + AENG_world_line_infinite(p_vect->X[0],p_vect->Y[0]+10+count*50,p_vect->Z[0],2,0xffffff, + p_vect->X[1],p_vect->Y[1]+10+count*50,p_vect->Z[1],2,0xffffff,0); + */ + + count++; + + ASSERT(facet); + + if (facet < 0) + { + // + // The last facet in the list for each square + // is negative. + // + + facet = -facet; + exit = TRUE; + } + + if(dfacets[facet].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam]) + { +// ASSERT(facet!=676); + // + // Mark this facet as drawn this gameturn already. + // + + dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam]; + + if(dfacets[facet].FacetType==STOREY_TYPE_NORMAL) + build = dfacets[facet].Building; + else + build = 0; + + // + // Don't draw inside facets + // + if (build && dbuildings[build].Type == BUILDING_TYPE_CRATE_IN || (dfacets[facet].FacetFlags&FACET_FLAG_INSIDE)) + { + // + // Don't draw inside buildings outside. + // + } + else + if (dfacets[facet].FacetType == STOREY_TYPE_DOOR) + { + // + // Draw the warehouse ground around this facet but don't draw + // the facet. + // + + AENG_draw_box_around_recessed_door(&dfacets[facet], FALSE); + } + else + { + // + // Draw the facet. + // + + show_facet(facet); + FACET_draw(facet,0); + + // + // Has this facet's building been processed this + // gameturn yet? + // + + switch(dfacets[facet].FacetType) + { + case STOREY_TYPE_NORMAL: + + if (build) + { + if (dbuildings[build].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam]) + { + // + // Draw all the walkable faces for this building. + // + + FACET_draw_walkable(build); + + // + // Mark the buiding as procesed this gameturn. + // + + dbuildings[build].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam]; + } + } + break; + + } + } + } + + f_list++; + } + } + } + } + } + + BreakFacets(dfacets_drawn_this_gameturn); + BreakTime("Drawn facets"); +// POLY_frame_draw(FALSE,FALSE); +// POLY_frame_init(TRUE,TRUE); +// BreakTime("Flushed facets"); + + LOG_EXIT ( AENG_Draw_Facets ) + + ANNOYINGSCRIBBLECHECK; + + + LOG_ENTER ( AENG_Draw_Other_Things ) + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + // + // The cached lighting for this low-res mapsquare. + // + + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Flags & FLAGS_IN_VIEW) + { +// p_thing->Flags &=~FLAGS_IN_VIEW; + switch(p_thing->DrawType) + { + case DT_NONE: + break; + + case DT_BUILDING: + break; + + case DT_PRIM: + break; + case DT_ANIM_PRIM: + extern void ANIM_obj_draw(Thing *p_thing,DrawTween *dt); + ANIM_obj_draw(p_thing,p_thing->Draw.Tweened); + + if (p_thing->Class == CLASS_BAT && + p_thing->Genus.Bat->type == BAT_TYPE_BANE) + { + DRAWXTRA_final_glow( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y + 0x8000 >> 8, + p_thing->WorldPos.Z >> 8, + p_thing->Genus.Bat->glow >> 8); + } + break; + + case DT_ROT_MULTI: + LOG_ENTER ( AENG_Draw_DT_ROT_MULTI ) + + /* + if (ControlFlag) + if (p_thing->Genus.Person->PlayerID) + { + // + // Draw some wheels above Darci's head! + // + + AENG_set_bike_wheel_rotation((GAME_TURN << 3) & 2047, PRIM_OBJ_BIKE_BWHEEL); + + MESH_draw_poly( + PRIM_OBJ_BIKE_BWHEEL, + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y + 0xa000 >> 8, + p_thing->WorldPos.Z >> 8, + p_thing->Draw.Tweened->Angle, + 0,0, + NULL,0); + + AENG_set_bike_wheel_rotation((GAME_TURN << 3) & 2047, PRIM_OBJ_VAN_WHEEL); + + MESH_draw_poly( + PRIM_OBJ_VAN_WHEEL, + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y + 0x10000 >> 8, + p_thing->WorldPos.Z >> 8, + p_thing->Draw.Tweened->Angle, + 0,0, + NULL,0); + + AENG_set_bike_wheel_rotation((GAME_TURN << 3) & 2047, PRIM_OBJ_CAR_WHEEL); + + MESH_draw_poly( + PRIM_OBJ_CAR_WHEEL, + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y + 0x16000 >> 8, + p_thing->WorldPos.Z >> 8, + p_thing->Draw.Tweened->Angle, + 0,0, + NULL,0); + } + */ + + { + ASSERT(p_thing->Class == CLASS_PERSON); + +#ifdef BIKE +#error Better not be doing this. + // + // If this person is riding the bike... + // + + if (p_thing->SubState == SUB_STATE_RIDING_BIKE) + { + Thing *p_bike = TO_THING(p_thing->Genus.Person->InCar); + + ASSERT(p_thing->Genus.Person->Flags & FLAG_PERSON_BIKING); + ASSERT(p_thing->Genus.Person->InCar); + + BIKE_Drawinfo bdi = BIKE_get_drawinfo(p_bike); + + // + // Move to the same position above the bike. + // + + GameCoord newpos = p_bike->WorldPos; + + p_thing->Draw.Tweened->Angle = bdi.yaw; + p_thing->Draw.Tweened->Tilt = bdi.pitch; + p_thing->Draw.Tweened->Roll = bdi.roll; + + /* + { + SLONG roll = bdi.roll; + + if (roll > 1024) + { + roll -= 2048; + } + + roll /= 2; + roll &= 2047; + + p_thing->Draw.Tweened->Roll = roll; + } + */ + + { + BIKE_Control bc; + DrawTween *dt = p_thing->Draw.Tweened; + SLONG steer; + + bc = BIKE_control_get(p_bike); + steer=bc.steer>>1; + + if(steer>32) + steer=32; + else + if(steer<-32) + steer=-32; + + if(abs(steer)>21) + { + SLONG tween; + if(steer<0) + { + dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_RIGHT]; + dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_RIGHT_FOOT]; + tween = ((-steer)-21) << 5; + + + } + else + { + dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_LEFT]; + dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_LEFT_FOOT]; + tween = ((steer)-21) << 5; + } + if(tween<0) + tween=0; + if(tween>255) + tween=255; + + dt->AnimTween=tween; + } + else + if (bc.steer == 0) + { + //dt->CurrentFrame = dt->TheChunk->AnimList[248]; + //dt->NextFrame = dt->TheChunk->AnimList[248]; + dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN]; + dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN]; + } + else + if (bc.steer < 0) + { + + //dt->CurrentFrame = dt->TheChunk->AnimList[248]; + //dt->NextFrame = dt->TheChunk->AnimList[250]; + dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN]; + dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_RIGHT]; + dt->AnimTween = -steer << 3; + } + else + { + //dt->CurrentFrame = dt->TheChunk->AnimList[248]; + //dt->NextFrame = dt->TheChunk->AnimList[252]; + dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN]; + dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_LEFT]; + dt->AnimTween = steer << 3; + } + } + + { + GameCoord oldpos = p_thing->WorldPos; + + + p_thing->WorldPos = newpos; + FIGURE_draw(p_thing); + + p_thing->WorldPos = oldpos; + } + + /* + + + // p_person->Draw.Tweened->Roll = bdi.roll;//BIKE_get_roll(TO_THING(p_person->Genus.Person->InCar)); + // p_person->Draw.Tweened->Tilt = bdi.pitch; + + // if (p_person->Draw.Tweened.Roll > 1024) + + */ + } + else +#endif + { + if (p_thing->Genus.Person->PlayerID) + { + if (FirstPersonMode) + { + FirstPersonAlpha -= (TICK_RATIO * 16) >> TICK_SHIFT; + if (FirstPersonAlpha < MAX_FPM_ALPHA) FirstPersonAlpha = MAX_FPM_ALPHA; + } + else + { + FirstPersonAlpha += (TICK_RATIO * 16) >> TICK_SHIFT; + if (FirstPersonAlpha > 255) FirstPersonAlpha = 255; + } + + //FIGURE_alpha = FirstPersonAlpha; + FIGURE_draw(p_thing); + //FIGURE_alpha = 255; + } + else + { + SLONG dx,dy,dz,dist; + + dx=abs((p_thing->WorldPos.X >> 8)-AENG_cam_x); + dy=abs((p_thing->WorldPos.Y >> 8)-AENG_cam_y); + dz=abs((p_thing->WorldPos.Z >> 8)-AENG_cam_z); + + dist=QDIST3(dx,dy,dz); + + if(distDraw.Tweened->Drawn=(UBYTE)SUPERMAP_counter; + + if (ControlFlag&&allow_debug_keys) + { + AENG_world_text( + (p_thing->WorldPos.X >> 8), + (p_thing->WorldPos.Y >> 8) + 0x60, + (p_thing->WorldPos.Z >> 8), + 200, + 180, + 50, + TRUE, + PCOM_person_state_debug(p_thing)); + } + + #if DRAW_THIS_DEBUG_STUFF + + AENG_world_line( + (p_thing->WorldPos.X >> 8), + (p_thing->WorldPos.Y >> 8) + 0x60, + (p_thing->WorldPos.Z >> 8), + 32, + 0x00ffffff, + (x << PAP_SHIFT_LO) + (1 << (PAP_SHIFT_LO - 1)), + (p_thing->WorldPos.Y >> 8), + (z << PAP_SHIFT_LO) + (1 << (PAP_SHIFT_LO - 1)), + 0, + 0x0000ff00, + FALSE); + + #endif + } + +#ifndef TARGET_DC + #if NO_MORE_BALLOONS + + if (p_thing->Genus.Person->Balloon) + { + SLONG balloon; + BALLOON_Balloon *bb; + + // + // Draw this person's balloon. + // + + for (balloon = p_thing->Genus.Person->Balloon; balloon; balloon = BALLOON_balloon[balloon].next) + { + SHAPE_draw_balloon(balloon); + } + } + + #endif +#endif + + if (p_thing->State == STATE_DEAD) + { + if (p_thing->Genus.Person->Timer1 > 10) + { + if (p_thing->Genus.Person->PersonType == PERSON_MIB1 || + p_thing->Genus.Person->PersonType == PERSON_MIB2 || + p_thing->Genus.Person->PersonType == PERSON_MIB3) + { + // + // Dead MIB self destruct! + // + DRAWXTRA_MIB_destruct(p_thing); +/* + SLONG px; + SLONG py; + SLONG pz; + + calc_sub_objects_position( + p_thing, + p_thing->Draw.Tweened->AnimTween, + SUB_OBJECT_PELVIS, + &px, + &py, + &pz); + + px += p_thing->WorldPos.X >> 8; + py += p_thing->WorldPos.Y >> 8; + pz += p_thing->WorldPos.Z >> 8; + + // + // Ripped from the DRAWXTRA_special! + // + + // (So why didn't you put it there?!) + + { + SLONG c0; + SLONG dx; + SLONG dz; + + c0=3+(THING_NUMBER(p_thing)&7); + c0=(((GAME_TURN*c0)+(THING_NUMBER(p_thing)*9))<<4)&2047; + dx=SIN(c0)>>8; + dz=COS(c0)>>8; + BLOOM_draw( + px, py+15, pz, + dx,0,dz,0x9F2040,0); + }*/ + } + } + } + + if (p_thing->Genus.Person->pcom_ai == PCOM_AI_BANE) + { + DRAWXTRA_final_glow( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y + 0x8000 >> 8, + p_thing->WorldPos.Z >> 8, + -p_thing->Draw.Tweened->Tilt); + } + + LOG_EXIT ( AENG_Draw_DT_ROT_MULTI ) + + break; + + case DT_EFFECT: + break; + + case DT_MESH: + + { + // Weapons & other powerups. + if (p_thing->Class == CLASS_SPECIAL) DRAWXTRA_Special(p_thing); + + MESH_draw_poly( + p_thing->Draw.Mesh->ObjectId, + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + p_thing->Draw.Mesh->Angle, + p_thing->Draw.Mesh->Tilt, + p_thing->Draw.Mesh->Roll, + NULL,0xff,0); + } + + break; + + #ifdef BIKE + + +#error A bike! Are you mad? + + case DT_BIKE: + + ASSERT(p_thing->Class == CLASS_BIKE); + { + // + // Nasty eh! But I can't be arsed to create a new drawtype. + // + + BIKE_Drawinfo bdi = BIKE_get_drawinfo(p_thing); + + // + // Draw the frame of the bike. + // + + ANIM_obj_draw(p_thing, p_thing->Draw.Tweened); + + // + // If the bike is parked or being mounted then the wheels are + // included in the animating object. + // + + if (p_thing->Genus.Bike->mode == BIKE_MODE_DRIVING) + { + AENG_set_bike_wheel_rotation(bdi.front_rot, PRIM_OBJ_BIKE_BWHEEL); + + MESH_draw_poly( + PRIM_OBJ_BIKE_BWHEEL, + bdi.front_x, + bdi.front_y, + bdi.front_z, + bdi.steer, + bdi.pitch, + bdi.roll, + NULL,0xff,0); + + AENG_set_bike_wheel_rotation(bdi.back_rot, PRIM_OBJ_BIKE_BWHEEL); + + MESH_draw_poly( + PRIM_OBJ_BIKE_BWHEEL, + bdi.back_x, + bdi.back_y, + bdi.back_z, + bdi.yaw, + 0, + bdi.roll, + NULL,0xff,0); + } + + // Now some bike fx... first the exhaust + PARTICLE_Exhaust2(p_thing, 5, 16); + + if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME)) + { + SLONG matrix[9], vector[3], dx,dy,dz; +// FMATRIX_calc(matrix, 1024-bdi.steer, bdi.pitch, bdi.roll); + FMATRIX_calc(matrix, bdi.steer, bdi.pitch, bdi.roll); + FMATRIX_TRANSPOSE(matrix); + vector[2]=-255; vector[1]=0; vector[0]=0; + FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]); + dx=vector[0]; dy=vector[1]; dz=vector[2]; + vector[2]=25; vector[1]=80; vector[0]=0; + FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]); + BLOOM_draw(bdi.front_x+vector[0],bdi.front_y+vector[1],bdi.front_z+vector[2],dx,dy,dz,0x606040,BLOOM_LENSFLARE|BLOOM_BEAM); + + FMATRIX_calc(matrix, bdi.yaw, bdi.pitch, bdi.roll); + FMATRIX_TRANSPOSE(matrix); + vector[2]=255; vector[1]=0; vector[0]=0; + FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]); + dx=vector[0]; dy=vector[1]; dz=vector[2]; + vector[2]=70; vector[1]=75; vector[0]=0; + FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]); + + BLOOM_draw( + (p_thing->WorldPos.X >> 8)+vector[0], + (p_thing->WorldPos.Y >> 8)+vector[1], + (p_thing->WorldPos.Z >> 8)+vector[2], + dx,dy,dz,0x800000,0); + + } + } + + break; + + #endif + + case DT_VEHICLE: + + if(p_thing->Class==CLASS_VEHICLE) + { + if(p_thing->Genus.Vehicle->Driver) + { + TO_THING(p_thing->Genus.Vehicle->Driver)->Flags|=FLAGS_IN_VIEW; + + } + } + // + // Set the tinted colour of this van. + // + + { +#if 1 + ULONG car_colours[6] = + { + 0xffffff00, + 0xffff00ff, + 0xff00ffff, + 0xffff0000, + 0xff00ff00, + 0xf00000ff + }; + + MESH_colour_and = car_colours[THING_NUMBER(p_thing) % 6]; +#else + +#define DEFCOL(R,G,B) (0xFF000000 | R | (G << 8) | (B << 16)) + + static DWORD colours[7] = + { + DEFCOL(18,192,120), + DEFCOL(255,14,90), + DEFCOL(112,122,216), + DEFCOL(176,158,54), + DEFCOL(0,149,186), + DEFCOL(194,162,34), + DEFCOL(255,255,255), + }; + + int col = THING_NUMBER(p_thing) % 7; + MESH_colour_and = colours[col]; +#endif + } + + extern void draw_car(Thing *p_car); + + draw_car(p_thing); + +#ifndef TARGET_DC + if (ControlFlag && allow_debug_keys) + { + // + // Draw a line towards where you have to be + // to get into the van. + // + + SLONG dx = -SIN(p_thing->Genus.Vehicle->Draw.Angle); + SLONG dz = -COS(p_thing->Genus.Vehicle->Draw.Angle); + + SLONG ix = p_thing->WorldPos.X >> 8; + SLONG iz = p_thing->WorldPos.Z >> 8; + + ix += dx >> 9; + iz += dz >> 9; + + ix -= dz >> 9; + iz += dx >> 9; + + AENG_world_line( + p_thing->WorldPos.X >> 8, p_thing->WorldPos.Y >> 8, p_thing->WorldPos.Z >> 8, 64, 0x00ffffff, + ix, p_thing->WorldPos.Y >> 8, iz, 0, 0x0000ff00, TRUE); + } +#endif + + break; + + case DT_CHOPPER: + CHOPPER_draw_chopper(p_thing); + break; + + case DT_PYRO: + PYRO_draw_pyro(p_thing); + break; + case DT_ANIMAL_PRIM: +#if 0 +extern void ANIMAL_draw(Thing *p_thing); + ANIMAL_draw(p_thing); +#endif + break; + + case DT_TRACK: + if(!INDOORS_INDEX) + TRACKS_DrawTrack(p_thing); + break; + + + default: + ASSERT(0); + break; + } + } + t_index = p_thing->Child; + } + + } + } + LOG_EXIT ( AENG_Draw_Other_Things ) + } + + BreakTime("Drawn things"); + + LOG_EXIT ( AENG_Draw_Things ) + + + ANNOYINGSCRIBBLECHECK; + + +// POLY_frame_draw(FALSE,FALSE); +// POLY_frame_init(TRUE,TRUE); +// BreakTime("Flushed things"); + + // + // debug info for the car movement + // +//void draw_car_tracks(void); +// if(!INDOORS_INDEX||outside) +// draw_car_tracks(); + + LOG_ENTER ( AENG_Draw_Oval_Shadows ) + + if(!SOFTWARE) + { + // + // Do oval shadows. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Flags & FLAGS_IN_VIEW) + { + bool draw = true; + + for (int ii = 0; ii < shadow_person_upto; ii++) + { + if (shadow_person[ii].p_person == p_thing) + { + draw = false; + break; + } + } + + if (draw) + { + switch(p_thing->Class) + { + case CLASS_PERSON: + + { + + SLONG px; + SLONG py; + SLONG pz; + + calc_sub_objects_position( + p_thing, + p_thing->Draw.Tweened->AnimTween, + SUB_OBJECT_PELVIS, + &px, + &py, + &pz); + + px += p_thing->WorldPos.X >> 8; + py += p_thing->WorldPos.Y >> 8; + pz += p_thing->WorldPos.Z >> 8; + + OVAL_add( + px, + py, + pz, + 130); + } + + break; + + case CLASS_SPECIAL: + + OVAL_add( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + 100); + + break; + + case CLASS_BARREL: + + OVAL_add( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + 128); + + break; + + default: + break; + } + } + } + + t_index = p_thing->Child; + } + } + } + } + + LOG_EXIT ( AENG_Draw_Oval_Shadows ) + + + ANNOYINGSCRIBBLECHECK; + + // + // The dirt. + // + + LOG_ENTER ( AENG_Draw_Dirt ) + + if(!INDOORS_INDEX||outside) + if(AENG_detail_dirt) + AENG_draw_dirt(); + + LOG_EXIT ( AENG_Draw_Dirt ) + + + // Cope with some wacky internals. + POLY_set_local_rotation_none(); + POLY_flush_local_rot(); + + + ANNOYINGSCRIBBLECHECK; + + // Grenades should be drawn here. + DrawGrenades(); + + ANNOYINGSCRIBBLECHECK; + + + LOG_ENTER ( AENG_Draw_Ballons ) + + // + // The balloons that nobody is holding. + // + +#ifndef TARGET_DC + if(!INDOORS_INDEX||outside) + AENG_draw_released_balloons(); +#endif + + LOG_EXIT ( AENG_Draw_Ballons ) + + ANNOYINGSCRIBBLECHECK; + + // + // The POWs! + // + + LOG_ENTER ( AENG_Draw_POWs ) + + AENG_draw_pows(); + + LOG_EXIT ( AENG_Draw_POWs ) + + + + ANNOYINGSCRIBBLECHECK; + + + + // + // Draw the mist. + // + + LOG_ENTER ( AENG_Draw_Mist ) + + if(!INDOORS_INDEX||outside) + if (AENG_detail_mist) + { + SLONG i; + + SLONG sx; + SLONG sz; + + SLONG px; + SLONG pz; + SLONG detail; + + SLONG wx; + SLONG wy; + SLONG wz; + + // Internal gubbins. + POLY_flush_local_rot(); + + POLY_Point *pp; + POLY_Point *quad[4]; + + #define MAX_MIST_DETAIL 32 + + POLY_Point mist_pp[MAX_MIST_DETAIL][MAX_MIST_DETAIL]; + + MIST_get_start(); + + while(detail = MIST_get_detail()) + { + // + // Only draw as much as we can! + // + + if (detail > MAX_MIST_DETAIL) + { + detail = MAX_MIST_DETAIL; + } + + for (px = 0; px < detail; px++) + for (pz = 0; pz < detail; pz++) + { + pp = &mist_pp[px][pz]; + + MIST_get_point(px, pz, + &wx, + &wy, + &wz); + + POLY_transform( + float(wx), + float(wy), + float(wz), + pp); + + if (pp->MaybeValid()) + { + pp->colour = 0x88666666; + pp->specular = 0xff000000; + + MIST_get_texture( + px, + pz, + &pp->u, + &pp->v); + + POLY_fadeout_point(pp); + } + } + + for (sx = 0; sx < detail - 1; sx++) + for (sz = 0; sz < detail - 1; sz++) + { + quad[0] = &mist_pp[sx + 0][sz + 0]; + quad[1] = &mist_pp[sx + 1][sz + 0]; + quad[2] = &mist_pp[sx + 0][sz + 1]; + quad[3] = &mist_pp[sx + 1][sz + 1]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_FOG, FALSE); + } + } + } + } + + LOG_EXIT ( AENG_Draw_Mist ) + + ANNOYINGSCRIBBLECHECK; + + + // + // Rain. + // + + LOG_ENTER ( AENG_Draw_Rain ) + + +/* +#ifdef _DEBUG // about time we removed this kind of crap + if (Keys[KB_R] && !ShiftFlag) + { + Keys[KB_R] = 0; + + GAME_FLAGS ^= GF_RAINING; + } +#endif +*/ + + if(!INDOORS_INDEX||outside) + { + if (GAME_FLAGS & GF_RAINING) + { + if(AENG_detail_rain) + AENG_draw_rain(); + } + } + +#ifdef _DEBUG + if(Keys[KB_N]) + { + Keys[KB_N]=0; + + if ((NIGHT_flag & NIGHT_FLAG_DAYTIME)) + { + NIGHT_flag &=~NIGHT_FLAG_DAYTIME; + DETAIL_LEVEL|=DETAIL_RAIN; + } + else + { + NIGHT_flag |=NIGHT_FLAG_DAYTIME; + DETAIL_LEVEL&=~DETAIL_RAIN; + } + } +#endif + +#if defined(_DEBUG) && defined(FAST_EDDIE) && 0 + POLY_Point tpt[4]; + POLY_Point *tptp[4]; + + tpt[0].X = 0; tpt[0].Y = 0; tpt[0].Z = 1; tpt[0].u = 0; tpt[0].v = 0; + tpt[1].X = 64; tpt[1].Y = 0; tpt[1].Z = 1; tpt[1].u = 1; tpt[1].v = 0; + tpt[2].X = 0; tpt[2].Y = 64; tpt[2].Z = 1; tpt[2].u = 0; tpt[2].v = 1; + tpt[3].X = 64; tpt[3].Y = 64; tpt[3].Z = 1; tpt[3].u = 1; tpt[3].v = 1; + + tpt[0].colour = 0xFFFFFFFF; tpt[0].specular = 0xFF000000; + tpt[1].colour = 0xFFFFFFFF; tpt[1].specular = 0xFF000000; + tpt[2].colour = 0xFFFFFFFF; tpt[2].specular = 0xFF000000; + tpt[3].colour = 0xFFFFFFFF; tpt[3].specular = 0xFF000000; + + tptp[0] = &tpt[0]; + tptp[1] = &tpt[1]; + tptp[2] = &tpt[2]; + tptp[3] = &tpt[3]; + + POLY_add_quad(tptp, POLY_PAGE_TEST_SHADOWMAP, FALSE, TRUE); +#endif + + LOG_EXIT ( AENG_Draw_Rain ) + + ANNOYINGSCRIBBLECHECK; + + + // + // Drawing the steam. + // + +// void draw_steam(SLONG x,SLONG y,SLONG z,SLONG lod); +// void draw_flames(SLONG x,SLONG y,SLONG z,SLONG lod); + + // + // Pyrotechincs. + // + + LOG_ENTER ( AENG_Draw_Pyros ) + + if(!INDOORS_INDEX||outside) + AENG_draw_bangs(); + if(!INDOORS_INDEX||outside) + AENG_draw_fire(); + if(!INDOORS_INDEX||outside) + AENG_draw_sparks(); +// ANEG_draw_messages(); + + LOG_EXIT ( AENG_Draw_Pyros ) + + + ANNOYINGSCRIBBLECHECK; + + /* + + for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++) + { + PUDDLE_Info *pi; + SLONG sx,sy,sz; + SLONG dx,dy,dz,dist,lod; + PUDDLE_get_start(z, NGAMUT_gamut[z].xmin, NGAMUT_gamut[z].xmax); + + while(pi = PUDDLE_get_next()) + { + sx = (pi->x1+pi->x2)>>1; + sz = (pi->z1+pi->z2)>>1; + sy = pi->y; + + dx=abs( ((SLONG)AENG_cam_x>>0)-sx); +// dy=abs( ((SLONG)AENG_cam_y>>0)-SLONG(world_y))*4; + dy=abs( ((SLONG)AENG_cam_y>>0)-sy); + dz=abs( ((SLONG)AENG_cam_z>>0)-sz); + + dist=QDIST3(dx,dy,dz); + + lod = 90-(dist/(32*2)); + if(lod>0) + draw_steam(sx,sy,sz,lod); +// draw_flames(sx,sy,sz,lod); + } + } +*/ + + +// if (Keys[KB_RBRACE] && !ShiftFlag) {Keys[KB_RBRACE] = 0; AENG_torch_on ^= TRUE;} + + // + // Draw a torch out of darci... + // + +#ifdef TARGET_DC + // No more torches. + ASSERT ( !AENG_torch_on ); +#else + if (AENG_torch_on) + { + Thing *darci = NET_PERSON(0); + + float angle; + + float dx; + float dy; + float dz; + + SLONG x; + SLONG y; + SLONG z; + + calc_sub_objects_position( + darci, + darci->Draw.Tweened->AnimTween, + 0, // Torso? + &x, + &y, + &z); + + x += darci->WorldPos.X >> 8; + y += darci->WorldPos.Y >> 8; + z += darci->WorldPos.Z >> 8; + + angle = float(darci->Draw.Tweened->Angle); + angle *= 2.0F * PI / 2048.0F; + + float dyaw = ((float)sin(float(GAME_TURN) * 0.025F)) * 0.25F; + float dpitch = ((float)cos(float(GAME_TURN) * 0.020F) - 0.5F) * 0.25F; + + float matrix[3]; + + dyaw += angle; + dyaw += PI; + + MATRIX_vector( + matrix, + dyaw, + dpitch); + + dx = matrix[0]; + dy = matrix[1]; + dz = matrix[2]; + + // experimental light bloom +// BLOOM_draw(x,y,z,dx*256,dy*256,dz*256,0x00666600); + BLOOM_draw(x,y,z,dx*256,dy*256,dz*256,0x00ffffa0); + + CONE_create( + float(x), + float(y), + float(z), + dx, + dy, + dz, + 256.0F * 4.0F, + 256.0F, + 0x00666600, + 0x00000000, + 50); + + CONE_intersect_with_map(); + +// CONE_draw(); + } +#endif + + // + // Draw the tripwires. + // + + LOG_ENTER ( AENG_Draw_Tripwires ) + + { + SLONG map_x1; + SLONG map_z1; + + SLONG map_x2; + SLONG map_z2; + + TRIP_Info *ti; + + // Deal with internal bollocks. + POLY_flush_local_rot(); + + TRIP_get_start(); + + while(ti = TRIP_get_next()) + { + // + // Check whether this tripwire is on the map. + // + + map_x1 = ti->x1 >> 8; + map_z1 = ti->z1 >> 8; + + map_x2 = ti->x2 >> 8; + map_z2 = ti->z2 >> 8; + + if ((WITHIN(map_z1, NGAMUT_zmin, NGAMUT_zmax) && WITHIN(map_x1, NGAMUT_gamut[map_z1].xmin, NGAMUT_gamut[map_z1].xmax)) || + (WITHIN(map_z2, NGAMUT_zmin, NGAMUT_zmax) && WITHIN(map_x2, NGAMUT_gamut[map_z2].xmin, NGAMUT_gamut[map_z2].xmax))) + { + // + // Draw the bugger. + // + + #define AENG_TRIPWIRE_WIDTH 0x3 + + SHAPE_tripwire( + ti->x1, + ti->y, + ti->z1, + ti->x2, + ti->y, + ti->z2, + AENG_TRIPWIRE_WIDTH, + 0x00661122, + ti->counter, + ti->along); + } + } + } + + LOG_EXIT ( AENG_Draw_Tripwires ) + + + ANNOYINGSCRIBBLECHECK; + + + // + // Draw the hook. + // + +#ifndef TARGET_DC + if(!INDOORS_INDEX||outside) + AENG_draw_hook(); +#endif + + // + // Draw the sphere-matter. + // + + LOG_ENTER ( AENG_Draw_Spherematter ) + + if(!INDOORS_INDEX||outside) + { + SM_Info *si; + + SM_get_start(); + + while(si = SM_get_next()) + { + SHAPE_sphere( + si->x, + si->y, + si->z, + si->radius, + si->colour); + } + } + + LOG_EXIT ( AENG_Draw_Spherematter ) + + + ANNOYINGSCRIBBLECHECK; + + + // + // Draw the drips... again! + // + + LOG_ENTER ( AENG_Draw_Drips2 ) + + if(!INDOORS_INDEX||outside) + AENG_draw_drips(0); + + LOG_EXIT ( AENG_Draw_Drips2 ) + + ANNOYINGSCRIBBLECHECK; + + // + // Draw the particle system + // + + LOG_ENTER ( AENG_Draw_Particles ) + + if(!INDOORS_INDEX||outside) + PARTICLE_Draw(); + + LOG_EXIT ( AENG_Draw_Particles ) + + ANNOYINGSCRIBBLECHECK; + + // + // Draw the ribbon system + // + + LOG_ENTER ( AENG_Draw_Ribbons ) + + if(!INDOORS_INDEX||outside) + RIBBON_draw(); + + LOG_EXIT ( AENG_Draw_Ribbons ) + + + ANNOYINGSCRIBBLECHECK; + + // + // Draw the tyre tracks (changed -- now turned into things) + // +/* + if (ControlFlag) { + TRACKS_Draw(); + }*/ + + // + // Draw the cloth. + // + + +// if(!INDOORS_INDEX||outside) +// AENG_draw_cloth(); + + // + // Draw. + // + // + // Draw the people messages. + // + + AENG_draw_people_messages(); + + +// MSG_add(" draw insides %d and %d \n",INDOORS_INDEX,INDOORS_INDEX_NEXT); + + /* + + POLY_frame_draw(TRUE,TRUE); + if(INDOORS_INDEX_NEXT) + AENG_draw_inside_floor(INDOORS_INDEX_NEXT,INDOORS_ROOM_NEXT,255); //downtairs non transparent + + POLY_frame_draw(TRUE,TRUE); + if(INDOORS_INDEX) + { + AENG_draw_inside_floor(INDOORS_INDEX,INDOORS_ROOM,INDOORS_INDEX_FADE); + + } + + */ + + + + + + + + + BreakTime("Drawn other crap"); + + + + LOG_ENTER ( AENG_Poly_Flush ) + +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); +#endif + + LOG_EXIT ( AENG_Poly_Flush ) + + BreakTime("Done final polygon flush"); + + ANNOYINGSCRIBBLECHECK; + + + // Tell the pyros we've done a frame. + Pyros_EndOfFrameMarker(); + + +// ANEG_draw_messages(); + + /* + + // + // This really _is_ shite! + // + + if (ShiftFlag) + { + static float focus = 0.95F; + + if (Keys[KB_P7]) {focus += 0.001F;} + if (Keys[KB_P4]) {focus -= 0.001F;} + + POLY_frame_draw_focused(focus); + } + + */ + +// TRACE("Total polys = %d\n", AENG_total_polys_drawn); + + //LOG_EXIT ( AENG_Draw_City ) + + LOG_EVENT ( AENG_Draw_End ) + + + //TRACE ( "AengOut" ); + + + +} + + + + + + + + + +void AENG_draw_far_facets(void) +{ + SLONG x,z; + + POLY_camera_set( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + 129.0F*256.0F,//float(AENG_DRAW_DIST) * 256.0F*3.0F, + AENG_LENS, + POLY_SPLITSCREEN_NONE); + + AENG_calc_gamut_lo_only( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + 64.0F*256.0F,//AENG_DRAW_DIST*3, + AENG_LENS); + + +#ifdef DEBUG + SLONG count = 0; +#endif + + LOG_ENTER ( Skyline_Scan_Map_Square ) + + for (z = AENG_gamut_lo_zmin; z <= AENG_gamut_lo_zmax; z++) + { + for (x = AENG_gamut_lo_xmin; x <= AENG_gamut_lo_xmax; x++) + { + // + // The cached lighting for this low-res mapsquare. + // + + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + // + // Look at the colvects on this square. + // + + { + SLONG f_list; + SLONG facet; + SLONG build; + SLONG exit = FALSE; + + f_list = PAP_2LO(x,z).ColVectHead; + + + if (f_list) + { + + LOG_ENTER ( Skyline_Draw_Facet ) + + + while(!exit) + { + struct DFacet *p_vect; + facet=facet_links[f_list]; + + p_vect=&dfacets[facet]; + + ASSERT(facet); + + if (facet < 0) + { + // + // The last facet in the list for each square + // is negative. + // + + facet = -facet; + exit = TRUE; + } + + if(dfacets[facet].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam]) + { + + dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam]; + + if(dfacets[facet].FacetType==STOREY_TYPE_NORMAL) + build = dfacets[facet].Building; + else + build = 0; + + // + // Don't draw inside facets + // + if (build && dbuildings[build].Type == BUILDING_TYPE_CRATE_IN || (dfacets[facet].FacetFlags&FACET_FLAG_INSIDE)) + { + // + // Don't draw inside buildings outside. + // + } + else + if (dfacets[facet].FacetType == STOREY_TYPE_DOOR) + { + } + else + { + // + // Draw the facet. + // + + + show_facet(facet); +extern void FACET_draw_quick(SLONG facet,UBYTE alpha); + FACET_draw_quick(facet,0); +#ifdef DEBUG + count++; +#endif + + } + } + + f_list++; + } + + LOG_EXIT ( Skyline_Draw_Facet ) + + + } + } + } + } + + //TRACE("Far facets = %d\n", count); + + LOG_EXIT ( Skyline_Scan_Map_Square ) + + + POLY_camera_set( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + float(AENG_DRAW_DIST) * 256.0F, + AENG_LENS, + POLY_SPLITSCREEN_NONE); +} + + +// +// Draws the warehouse that they player is in. +// + +void AENG_draw_warehouse() +{ + SLONG i; + + SLONG x; + SLONG z; + + SLONG dx; + SLONG dz; + + SLONG px; + SLONG pz; + + SLONG dist; + SLONG t_index; + SLONG square; + SLONG build; + SLONG page; + SLONG facet; + SLONG f_list; + SLONG exit; + SLONG balloon; + SLONG dfcache; + SLONG next; + + ULONG colour; + ULONG specular; + + float world_x; + float world_y; + float world_z; + + // + // No cloud inside warehouses! + // + + + SLONG old_aeng_draw_cloud_flag = aeng_draw_cloud_flag; FALSE; + + aeng_draw_cloud_flag = FALSE; + + Thing *p_thing; + OB_Info *oi; + PAP_Hi *ph; + NIGHT_Square *nq; + NIGHT_Colour *col; + NIGHT_Dfcache *ndf; + POLY_Point *pp; + DFacet *df; +#ifndef TARGET_DC + //BALLOON_Balloon *bb; +#endif + POLY_Point *quad[4]; + + //POLY_frame_init(FALSE,FALSE); + +#ifndef TARGET_DC + POLY_frame_init(FALSE,FALSE); +#endif + + // + // Work out which things are in view. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + switch(p_thing->Class) + { + case CLASS_PERSON: + + // + // Only draw people who are in warehouses. + // + if(p_thing->Genus.Person->PlayerID && (p_thing->Genus.Person->Flags & FLAG_PERSON_WAREHOUSE)) + p_thing->Flags |= FLAGS_IN_VIEW; + else + if (p_thing->Genus.Person->Flags & FLAG_PERSON_WAREHOUSE) + { + if (POLY_sphere_visible( + float(p_thing->WorldPos.X >> 8), + float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT, + float(p_thing->WorldPos.Z >> 8), + 256.0F / (AENG_DRAW_DIST * 256.0F))) + { + p_thing->Flags |= FLAGS_IN_VIEW; + } + } + + break; + + default: + + // + // Draw everything else that is on a HIDDEN square (i.e. is inside the + // floorplan of the warehouse) + // + + if (PAP_2HI(p_thing->WorldPos.X >> 16, p_thing->WorldPos.Z >> 16).Flags & PAP_FLAG_HIDDEN) + { + p_thing->Flags |= FLAGS_IN_VIEW; + } + + break; + } + + t_index = p_thing->Child; + } + + NIGHT_square[NIGHT_cache[x][z]].flag &= ~NIGHT_SQUARE_FLAG_DELETEME; + } + } + + // + // Rotate all the points. + // +#ifndef NEW_FLOOR + for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++) + { + for (x = NGAMUT_point_gamut[z].xmin; x <= NGAMUT_point_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 1)); + + ph = &PAP_2HI(x,z); + + // + // We only have upper points inside a warehouse. + // + + world_x = x * 256.0F; + world_y = ph->Alt * float(1 << ALT_SHIFT); + world_z = z * 256.0F; + + pp = &AENG_upper[x & 63][z & 63]; + + POLY_transform( + world_x, + world_y, + world_z, + pp); + + if (pp->MaybeValid()) + { + // + // Work out the colour of this point... what a palaver! + // + + px = x >> 2; + pz = z >> 2; + + dx = x & 0x3; + dz = z & 0x3; + + ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1)); + + square = NIGHT_cache[px][pz]; + + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + + nq = &NIGHT_square[square]; + + NIGHT_get_d3d_colour( + nq->colour[dx + dz * PAP_BLOCKS], + &pp->colour, + &pp->specular); + + apply_cloud((SLONG)world_x,(SLONG)world_y,(SLONG)world_z,&pp->colour); + + POLY_fadeout_point(pp); + + colour = pp->colour; + specular = pp->specular; + } + } + } +#endif + // + // Who shall we generate shadows for? + // + + if (AENG_shadows_on) + { + Thing *darci = NET_PERSON(0); + + // + // How many people do we generate shadows for? + // + + #define AENG_NUM_SHADOWS 4 + + struct + { + Thing *p_person; + SLONG dist; + + } shadow_person[AENG_NUM_SHADOWS]; + SLONG shadow_person_upto = 0; + SLONG shadow_person_worst_dist = -INFINITY; + SLONG shadow_person_worst_person; + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_VIEW)) + { + // + // Distance from darci. + // + + dx = p_thing->WorldPos.X - darci->WorldPos.X; + dz = p_thing->WorldPos.Z - darci->WorldPos.Z; + + dist = abs(dx) + abs(dz); + + if (dist < 0x60000) + { + if (shadow_person_upto < AENG_NUM_SHADOWS) + { + // + // Put this person in the shadow array. + // + + shadow_person[shadow_person_upto].p_person = p_thing; + shadow_person[shadow_person_upto].dist = dist; + + // + // Keep track of the furthest person away. + // + + if (dist > shadow_person_worst_dist) + { + shadow_person_worst_dist = dist; + shadow_person_worst_person = shadow_person_upto; + } + + shadow_person_upto += 1; + } + else + { + if (dist < shadow_person_worst_dist) + { + // + // Replace the worst person. + // + + ASSERT(WITHIN(shadow_person_worst_person, 0, AENG_NUM_SHADOWS - 1)); + + shadow_person[shadow_person_worst_person].p_person = p_thing; + shadow_person[shadow_person_worst_person].dist = dist; + + // + // Find the worst person + // + + shadow_person_worst_dist = -INFINITY; + + for (i = 0; i < AENG_NUM_SHADOWS; i++) + { + if (shadow_person[i].dist > shadow_person_worst_dist) + { + shadow_person_worst_dist = shadow_person[i].dist; + shadow_person_worst_person = i; + } + } + } + } + } + } + + t_index = p_thing->Child; + } + } + } + + // + // Draw the people's shadow maps. + // + + SLONG offset_x; + SLONG offset_y; + + for (i = 0; i < shadow_person_upto; i++) + { + darci = shadow_person[i].p_person; + + memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer)); + + SMAP_person( + darci, + (UBYTE *) AENG_aa_buffer, + AENG_AA_BUF_SIZE, + AENG_AA_BUF_SIZE, + 0, + -255, + -0); + + // + // Where do we put it in the shadow texture page? Hard code everything! + // + + ASSERT(AENG_AA_BUF_SIZE == 32); + ASSERT(TEXTURE_SHADOW_SIZE == 64); + + offset_x = (i & 1) << 5; + offset_y = (i & 2) << 4; + + // + // Plonk it into the shadow texture page. + // + + if (TEXTURE_shadow_lock()) + { + SLONG x; + SLONG y; + UWORD *line; + UBYTE *buf = (UBYTE *) AENG_aa_buffer; + UWORD* mapping = GetShadowPixelMapping(); + + for (y = 0; y < AENG_AA_BUF_SIZE; y++) + { + line = &TEXTURE_shadow_bitmap[((y + offset_y) * TEXTURE_shadow_pitch >> 1) + offset_x]; + + for (x = AENG_AA_BUF_SIZE - 1; x >= 0; x--) + { + *line++ = mapping[*buf++]; + } + } + + TEXTURE_shadow_unlock(); + } + + // + // How we map floating points coordinates from 0 to 1 onto + // where we plonked the shadow map in the texture page. + // + + AENG_project_offset_u = float(offset_x) / float(TEXTURE_SHADOW_SIZE); + AENG_project_offset_v = float(offset_y) / float(TEXTURE_SHADOW_SIZE); + AENG_project_mul_u = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE); + AENG_project_mul_v = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE); + + { + // + // Map this poly onto the mapsquares surrounding darci. + // + + SLONG i; + + SLONG mx; + SLONG mz; + SLONG dx; + SLONG dz; + + SLONG mx1; + SLONG mz1; + SLONG mx2; + SLONG mz2; + SLONG exit = FALSE; + + SLONG mx_lo; + SLONG mz_lo; + +#ifndef TARGET_DC + MapElement *me[4]; +#endif + PAP_Hi *ph[4]; + + SVector_F poly[4]; + SMAP_Link *projected; + + SLONG v_list; + SLONG i_vect; + + DFacet *df; + + SLONG w_list; + SLONG w_face; + + PrimFace4 *p_f4; + PrimPoint *pp; + + SLONG wall; + SLONG storey; + SLONG building; + SLONG thing; + SLONG face_height; + UBYTE face_order[4] = {0,1,3,2}; + + Thing *p_fthing; + + // + // Colvects we have already done. + // + + #define AENG_MAX_DONE 8 + + SLONG done[AENG_MAX_DONE]; + SLONG done_upto = 0; + + for (dx = -1; dx <= 1; dx++) + for (dz = -1; dz <= 1; dz++) + { + mx = (darci->WorldPos.X >> 16) + dx; + mz = (darci->WorldPos.Z >> 16) + dz; + + if (WITHIN(mx, 0, MAP_WIDTH - 2) && + WITHIN(mz, 0, MAP_HEIGHT - 2)) + { +#ifndef TARGET_DC + me[0] = &MAP[MAP_INDEX(mx + 0, mz + 0)]; + me[1] = &MAP[MAP_INDEX(mx + 1, mz + 0)]; + me[2] = &MAP[MAP_INDEX(mx + 1, mz + 1)]; + me[3] = &MAP[MAP_INDEX(mx + 0, mz + 1)]; +#endif + + ph[0] = &PAP_2HI(mx + 0, mz + 0); + ph[1] = &PAP_2HI(mx + 1, mz + 0); + ph[2] = &PAP_2HI(mx + 1, mz + 1); + ph[3] = &PAP_2HI(mx + 0, mz + 1); + + if (PAP_2HI(mx,mz).Flags & PAP_FLAG_HIDDEN) + { + poly[3].X = float(mx << 8); + poly[3].Y = float(ph[0]->Alt << ALT_SHIFT); + poly[3].Z = float(mz << 8); + + poly[0].X = poly[3].X + 256.0F; + poly[0].Y = float(ph[1]->Alt << ALT_SHIFT); + poly[0].Z = poly[3].Z; + + poly[1].X = poly[3].X + 256.0F; + poly[1].Y = float(ph[2]->Alt << ALT_SHIFT); + poly[1].Z = poly[3].Z + 256.0F; + + poly[2].X = poly[3].X; + poly[2].Y = float(ph[3]->Alt << ALT_SHIFT); + poly[2].Z = poly[3].Z + 256.0F; + + if (ph[0]->Alt == ph[1]->Alt && + ph[0]->Alt == ph[2]->Alt && + ph[0]->Alt == ph[3]->Alt) + { + // + // This quad is coplanar. + // + + projected = SMAP_project_onto_poly(poly, 4); + + if (projected) + { + AENG_add_projected_shadow_poly(projected); + } + } + else + { + // + // Do each triangle separatly. + // + + projected = SMAP_project_onto_poly(poly, 3); + + if (projected) + { + AENG_add_projected_fadeout_shadow_poly(projected); + } + + // + // The triangles are 0,1,2 and 0,2,3. + // + + poly[1] = poly[0]; + + projected = SMAP_project_onto_poly(poly + 1, 3); + + if (projected) + { + AENG_add_projected_fadeout_shadow_poly(projected); + } + } + } + } + } + + mx1 = (darci->WorldPos.X >> 8) - 0x100 >> PAP_SHIFT_LO; + mz1 = (darci->WorldPos.Z >> 8) - 0x100 >> PAP_SHIFT_LO; + + mx2 = (darci->WorldPos.X >> 8) + 0x100 >> PAP_SHIFT_LO; + mz2 = (darci->WorldPos.Z >> 8) + 0x100 >> PAP_SHIFT_LO; + + SATURATE(mx1, 0, PAP_SIZE_LO - 1); + SATURATE(mz1, 0, PAP_SIZE_LO - 1); + SATURATE(mx2, 0, PAP_SIZE_LO - 1); + SATURATE(mz2, 0, PAP_SIZE_LO - 1); + + for (mx_lo = mx1; mx_lo <= mx2; mx_lo++) + for (mz_lo = mz1; mz_lo <= mz2; mz_lo++) + { + // + // Cast shadow on walkable faces. + // + + w_face = PAP_2LO(mx_lo,mz_lo).Walkable; + + while(w_face) + { + if (w_face > 0) + { + p_f4 = &prim_faces4[w_face]; + face_height = prim_points[p_f4->Points[0]].Y; + + if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8)) + { + // + // This face is above Darci, so don't put her shadow + // on it. + // + } + else + { + for (i = 0; i < 4; i++) + { + pp = &prim_points[p_f4->Points[face_order[i]]]; + + poly[i].X = float(pp->X); + poly[i].Y = float(pp->Y); + poly[i].Z = float(pp->Z); + } + + projected = SMAP_project_onto_poly(poly, 4); + + if (projected) + { + AENG_add_projected_shadow_poly(projected); + } + } + + w_face = p_f4->Col2; + } + else + { + struct RoofFace4 *rf; + rf = &roof_faces4[-w_face]; + face_height = rf->Y; + + if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8)) + { + // + // This face is above Darci, so don't put her shadow + // on it. + // + } + else + { + SLONG mx,mz; + + mx=(rf->RX&127)<<8; + mz=(rf->RZ&127)<<8; + + + + poly[0].X=(float)(mx); + poly[0].Y=(float)(rf->Y); + poly[0].Z=(float)(mz); + + poly[1].X=(float)((mx)+256); + poly[1].Y=(float)(rf->Y+(rf->DY[0]<Y+(rf->DY[1]<Y+(rf->DY[2]<Next; + + } + } + } + } + + TEXTURE_shadow_update(); + } + } + else + { + // + // Do oval shadows instead! + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Flags & FLAGS_IN_VIEW) + { + switch(p_thing->Class) + { + case CLASS_PERSON: + + OVAL_add( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + 32); + + break; + + case CLASS_SPECIAL: + + OVAL_add( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + 16); + + break; + + case CLASS_BARREL: + + OVAL_add( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + 32); + + break; + + default: + break; + } + } + + t_index = p_thing->Child; + } + } + } + } + +#ifdef NEW_FLOOR + draw_quick_floor(1); +#endif + + // + // Create all the squares. + // +#ifndef NEW_FLOOR + for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++) + { + for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 2)); + ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 2)); + + ph = &PAP_2HI(x,z); + + if (!(ph->Flags & PAP_FLAG_HIDDEN)) + { + // + // We only draw hidden squares! + // + + continue; + } + + // + // The four points of the quad. + // + + quad[0] = &AENG_upper[(x + 0) & 63][(z + 0) & 63]; + quad[1] = &AENG_upper[(x + 1) & 63][(z + 0) & 63]; + quad[2] = &AENG_upper[(x + 0) & 63][(z + 1) & 63]; + quad[3] = &AENG_upper[(x + 1) & 63][(z + 1) & 63]; + + if (POLY_valid_quad(quad)) + { + TEXTURE_get_minitexturebits_uvs( + ph->Texture, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + + POLY_add_quad(quad, page, TRUE); + } + } + } +#endif + + // + // Draw the objects and the things. + // + + SLONG pos = 0; + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + /* + + { + CBYTE str[20]; + + sprintf(str, "%d,%d", x, z); + + FONT2D_DrawString(str, (pos & 7) * 60 + 20, (pos >> 3) * 20 + 200, 0xff00ff); + } + + pos += 1; + + */ + + // + // The cached lighting for this low-res mapsquare. + // + + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(NIGHT_cache[x][z], 1, NIGHT_MAX_SQUARES - 1)); + + col = NIGHT_square[NIGHT_cache[x][z]].colour; + + // + // Skip over the mapsquares. + // + + col += PAP_BLOCKS * PAP_BLOCKS; + + // + // The objects on this mapsquare. + // + + oi = OB_find(x,z); + + while(oi->prim) + { + // + // Only draw objects that are in buildings. (Assume that means our warehouse!) + // + + if (oi->flags & OB_FLAG_WAREHOUSE) + { + if (oi->prim == 235) + { + oi->yaw = GAME_TURN; + } + + col = MESH_draw_poly( + oi->prim, + oi->x, + oi->y, + oi->z, + oi->yaw, + oi->pitch, + oi->roll, + col,0xff,0); + + // + // As good a place as any to put this! + // + + if (prim_objects[oi->prim].flag & PRIM_FLAG_ITEM) + { + OB_ob[oi->index].yaw += 1; + } + } + + oi += 1; + } + + // + // Draw the facets on this square. + // + + f_list = PAP_2LO(x,z).ColVectHead; + + if (f_list) + { + exit = FALSE; + + while(!exit) + { + facet = facet_links[f_list]; + + ASSERT(facet); + + if (facet < 0) + { + // + // The last facet in the list for each square is negative. + // + + facet = -facet; + exit = TRUE; + } + + df = &dfacets[facet]; + + if ( ( df->FacetType == STOREY_TYPE_NORMAL ) || ( df->FacetType == STOREY_TYPE_DOOR ) ||( df->FacetType == STOREY_TYPE_FENCE )||( df->FacetType == STOREY_TYPE_FENCE_FLAT )) + { + build = df->Building; + + // + // Has this facet's building been processed this gameturn yet? + // + + if (df->Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam]) + { + // + // warehouse walls only drawn if they are inside walls + // + + if ( (dbuildings[build].Type == BUILDING_TYPE_WAREHOUSE && (df->FacetFlags&FACET_FLAG_INSIDE))|| + dbuildings[build].Type == BUILDING_TYPE_CRATE_IN||df->FacetType == STOREY_TYPE_DOOR) + { + // + // Draw the facet. + // + + if (df->FacetType == STOREY_TYPE_DOOR) + { + // + // Draw the outside around this facet but don't draw + // + + AENG_draw_box_around_recessed_door(&dfacets[facet], TRUE); + } + else + //if (df->FacetType == STOREY_TYPE_NORMAL) Why only draw normal facets? + { + FACET_draw(facet,0); + + build = df->Building; + + if (df->FacetType == STOREY_TYPE_NORMAL) //Why only draw normal facets? + if (build) + { + if (dbuildings[build].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam]) + { + // + // Draw all the walkable faces for this building. + // + + FACET_draw_walkable(build); + + // + // Mark the buiding as procesed this gameturn. + // + + dbuildings[build].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam]; + } + } + } + } + + // + // Mark this facet as drawn this gameturn already. + // + + dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam]; + } + } + + f_list++; + } + } + + // + // Draw the things. + // + + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Flags & FLAGS_IN_VIEW) + { + switch(p_thing->DrawType) + { + case DT_NONE: + break; + + case DT_BUILDING: + break; + + case DT_PRIM: + break; + + case DT_ANIM_PRIM: + ANIM_obj_draw(p_thing,p_thing->Draw.Tweened); + break; + + case DT_ROT_MULTI: + + ASSERT(p_thing->Class == CLASS_PERSON); + + if (p_thing->Genus.Person->PlayerID) + { + if (FirstPersonMode) + { + FirstPersonAlpha -= (TICK_RATIO * 16) >> TICK_SHIFT; + if (FirstPersonAlpha < MAX_FPM_ALPHA) FirstPersonAlpha = MAX_FPM_ALPHA; + } + else + { + FirstPersonAlpha += (TICK_RATIO * 16) >> TICK_SHIFT; + if (FirstPersonAlpha > 255) FirstPersonAlpha = 255; + } + + //FIGURE_alpha = FirstPersonAlpha; + FIGURE_draw(p_thing); + //FIGURE_alpha = 255; + } + else + { + SLONG dx,dy,dz,dist; + + dx=abs((p_thing->WorldPos.X >> 8)-AENG_cam_x); + dy=abs((p_thing->WorldPos.Y >> 8)-AENG_cam_y); + dz=abs((p_thing->WorldPos.Z >> 8)-AENG_cam_z); + + dist=QDIST3(dx,dy,dz); + + if(distGenus.Person->Balloon) + { + // + // Draw this person's balloon. + // + + for (balloon = p_thing->Genus.Person->Balloon; balloon; balloon = BALLOON_balloon[balloon].next) + { + SHAPE_draw_balloon(balloon); + } + } + + #endif + + if (ControlFlag&&allow_debug_keys) + { + AENG_world_text( + (p_thing->WorldPos.X >> 8), + (p_thing->WorldPos.Y >> 8) + 0x60, + (p_thing->WorldPos.Z >> 8), + 200, + 180, + 50, + TRUE, + PCOM_person_state_debug(p_thing)); + } + + if ((p_thing->State == STATE_DEAD)&&(p_thing->Genus.Person->Timer1 > 10)) + { + if (p_thing->Genus.Person->PersonType == PERSON_MIB1 || + p_thing->Genus.Person->PersonType == PERSON_MIB2 || + p_thing->Genus.Person->PersonType == PERSON_MIB3) + { + // + // Dead MIB self destruct! + // + DRAWXTRA_MIB_destruct(p_thing); + } + } + + break; + + case DT_EFFECT: + break; + + case DT_MESH: + + if (p_thing->Class == CLASS_SPECIAL) + { + DRAWXTRA_Special(p_thing); + } + + if (p_thing->Class == CLASS_BIKE) + { + // + // There shouldn't be any bikes indoors. + // + + ASSERT(0); + } + else + { + MESH_draw_poly( + p_thing->Draw.Mesh->ObjectId, + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + p_thing->Draw.Mesh->Angle, + p_thing->Draw.Mesh->Tilt, + p_thing->Draw.Mesh->Roll, + NULL,0xff,0); + } + + break; + + case DT_VEHICLE: + case DT_CHOPPER: + + // + // There shouldn't be any vehicles or helicopters indoors. + // + + break; + + case DT_PYRO: + PYRO_draw_pyro(p_thing); + break; + + case DT_ANIMAL_PRIM: +#if 0 + ANIMAL_draw(p_thing); +#endif + break; + + case DT_TRACK: + TRACKS_DrawTrack(p_thing); + break; + + default: + break; + } + } + + t_index = p_thing->Child; + } + } + } + + // + // Now draw the special fx that somebody left out before + // + + POLY_set_local_rotation_none(); + PARTICLE_Draw(); + RIBBON_draw(); + AENG_draw_sparks(); + + // + // Now actually draw everything! + // + +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); +#endif + + // + // Restore cloud to default value. + // + + aeng_draw_cloud_flag = old_aeng_draw_cloud_flag; +} + + + + + + + + + +// +// For drawing water. +// + +#ifdef EDITOR +typedef struct +{ + UBYTE height[4]; + POLY_Point pp[4]; + +} AENG_Nswater; + +AENG_Nswater AENG_nswater[5][5]; + + +void AENG_draw_ns() +{ + SLONG i; + SLONG j; + SLONG k; + + SLONG x; + SLONG z; + + float base_x; + float base_z; + + float px; + float py; + float pz; + + SLONG x1; + SLONG z1; + SLONG x2; + SLONG z2; + + SLONG dropx; + SLONG dropy; + SLONG dropz; + + SLONG dropdx; + SLONG dropdy; + SLONG dropdz; + + SLONG along; + + SLONG bx; + SLONG bz; + + SLONG dx; + SLONG dz; + SLONG dist; + + SLONG dsx; + SLONG dsz; + + SLONG sx; + SLONG sz; + + SLONG ix; + SLONG iz; + + SLONG page; + + NS_Cache *nc; + NS_Point *np; + NS_Face *nf; + NS_Texture *nt; + NS_Lo *nl; + NS_St *nst; + + POLY_Point *pp; + POLY_Point *quad[4]; + + THING_INDEX t_index; + Thing *p_thing; + + static bright = FALSE; + + if (Keys[KB_COLON]) + { + Keys[KB_COLON] = 0; + + bright ^= TRUE; + } + + // + // Where we remember the bounding boxes of reflections. + // + + struct + { + SLONG x1; + SLONG y1; + SLONG x2; + SLONG y2; + + } bbox[AENG_MAX_BBOXES]; + SLONG bbox_upto = 0; + + // + // Create the gamut + // + + AENG_calc_gamut( + AENG_cam_x, + AENG_cam_y, + AENG_cam_z, + AENG_cam_yaw, + AENG_cam_pitch, + AENG_cam_roll, + AENG_DRAW_DIST, + AENG_LENS); + + // + // Start the frame. + // + +#ifndef TARGET_DC + POLY_frame_init(TRUE, TRUE); +#endif + + // + // Go through the cache squares and free any we don't need. + // + + for (i = 1; i < NS_MAX_CACHES; i++) + { + nc = &NS_cache[i]; + + if (nc->used) + { + ASSERT(WITHIN(nc->map_x, 1, PAP_SIZE_LO - 2)); + ASSERT(WITHIN(nc->map_z, 1, PAP_SIZE_LO - 2)); + + if (!WITHIN(nc->map_z, NGAMUT_lo_zmin, NGAMUT_lo_zmax) || + !WITHIN(nc->map_x, NGAMUT_lo_gamut[nc->map_z].xmin, NGAMUT_lo_gamut[nc->map_z].xmax)) + { + // + // We don't need this any more. + // + + NS_cache_destroy(i); + } + } + } + + // + // Shadows. + // + + if (Keys[KB_3]) {Keys[KB_3] = 0; AENG_shadows_on ^= TRUE;} + + if (AENG_shadows_on) + { + Thing *darci = NET_PERSON(0); + + // + // Find the 'AENG_NUM_SHADOWS' nearest people to generate shadows for. + // + + struct + { + Thing *p_person; + SLONG dist; + + } shadow_person[AENG_NUM_SHADOWS]; + SLONG shadow_person_upto = 0; + SLONG shadow_person_worst_dist = -INFINITY; + SLONG shadow_person_worst_person; + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_SEWERS)) + { + if (POLY_sphere_visible( + float(p_thing->WorldPos.X >> 8), + float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT, + float(p_thing->WorldPos.Z >> 8), + 256.0F / (AENG_DRAW_DIST * 256.0F))) + { + // + // Distance from darci. + // + + dx = p_thing->WorldPos.X - darci->WorldPos.X; + dz = p_thing->WorldPos.Z - darci->WorldPos.Z; + + dist = abs(dx) + abs(dz); + + if (shadow_person_upto < AENG_NUM_SHADOWS) + { + // + // Put this person in the shadow array. + // + + shadow_person[shadow_person_upto].p_person = p_thing; + shadow_person[shadow_person_upto].dist = dist; + + // + // Keep track of the furthest person away. + // + + if (dist > shadow_person_worst_dist) + { + shadow_person_worst_dist = dist; + shadow_person_worst_person = shadow_person_upto; + } + + shadow_person_upto += 1; + } + else + { + if (dist < shadow_person_worst_dist) + { + // + // Replace the worst person. + // + + ASSERT(WITHIN(shadow_person_worst_person, 0, AENG_NUM_SHADOWS - 1)); + + shadow_person[shadow_person_worst_person].p_person = p_thing; + shadow_person[shadow_person_worst_person].dist = dist; + + // + // Find the worst person + // + + shadow_person_worst_dist = -INFINITY; + + for (i = 0; i < AENG_NUM_SHADOWS; i++) + { + if (shadow_person[i].dist > shadow_person_worst_dist) + { + shadow_person_worst_dist = shadow_person[i].dist; + shadow_person_worst_person = i; + } + } + } + } + } + } + + t_index = p_thing->Child; + } + } + } + + // + // Draw the people's shadow maps. + // + + SLONG mx; + SLONG mz; + + SLONG light_x; + SLONG light_y; + SLONG light_z; + + SLONG light_dx; + SLONG light_dy; + SLONG light_dz; + + SLONG offset_x; + SLONG offset_y; + + NS_Lo *nl; + + for (i = 0; i < shadow_person_upto; i++) + { + darci = shadow_person[i].p_person; + + mx = darci->WorldPos.X >> (8 + PAP_SHIFT_LO); + mz = darci->WorldPos.Z >> (8 + PAP_SHIFT_LO); + + if (!WITHIN(mx, 0, PAP_SIZE_LO - 1) || + !WITHIN(mz, 0, PAP_SIZE_LO - 1)) + { + continue; + } + + nl = &NS_lo[mx][mz]; + + // + // If this lo-res sewer square doesn't have a light, then + // we don't have to do any shadow stuff. + // + + if (nl->light_y == 0) + { + continue; + } + + // + // Where is the light in this lo-res mapsquare? + // + + light_x = (mx << PAP_SHIFT_LO) + (nl->light_x << 3); + light_z = (mz << PAP_SHIFT_LO) + (nl->light_z << 3); + light_y = (nl->light_y << 5) + -32 * 0x100; + + // + // The direction vector of the light creating the shadow- + // we dont have to bother normalising it. + // + + light_dx = (darci->WorldPos.X >> 8) - light_x; + light_dy = (darci->WorldPos.Y >> 8) - light_y; + light_dz = (darci->WorldPos.Z >> 8) - light_z; + + // + // Draw the shadow of the person from the light. + // + + memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer)); + + SMAP_person( + darci, + (UBYTE *) AENG_aa_buffer, + AENG_AA_BUF_SIZE, + AENG_AA_BUF_SIZE, + light_dx, + light_dy, + light_dz); + + // + // Where do we put it in the shadow texture page? Hard code everything! + // + + ASSERT(AENG_AA_BUF_SIZE == 32); + ASSERT(TEXTURE_SHADOW_SIZE == 64); + + offset_x = (i & 1) << 5; + offset_y = (i & 2) << 4; + + // + // Plonk it into the shadow texture page. + // + + if (TEXTURE_shadow_lock()) + { + SLONG x; + SLONG y; + UWORD *line; + UBYTE *buf = (UBYTE *) AENG_aa_buffer; + UWORD* mapping = GetShadowPixelMapping(); + + for (y = 0; y < AENG_AA_BUF_SIZE; y++) + { + line = &TEXTURE_shadow_bitmap[((y + offset_y) * TEXTURE_shadow_pitch >> 1) + offset_x]; + + for (x = AENG_AA_BUF_SIZE - 1; x >= 0; x--) + { + *line++ = mapping[*buf++]; + } + } + + TEXTURE_shadow_unlock(); + } + + // + // How we map floating points coordinates from 0 to 1 onto + // where we plonked the shadow map in the texture page. + // + + AENG_project_offset_u = float(offset_x) / float(TEXTURE_SHADOW_SIZE); + AENG_project_offset_v = float(offset_y) / float(TEXTURE_SHADOW_SIZE); + AENG_project_mul_u = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE); + AENG_project_mul_v = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE); + AENG_project_lit_light_x = float(light_x); + AENG_project_lit_light_y = float(light_y); + AENG_project_lit_light_z = float(light_z); + AENG_project_lit_light_range = 600.0F; + + // + // Map the shadow polygon onto the sewers around each Darci. + // + + { + SLONG mx1; + SLONG mz1; + + SLONG mx2; + SLONG mz2; + + SLONG px; + SLONG py; + SLONG pz; + + SLONG base_x; + SLONG base_z; + + NS_Hi *nh; + NS_Lo *nl; + NS_Cache *nc; + NS_Point *np_base; + NS_Face *nf_base; + NS_Point *np; + NS_Face *nf; + + SLONG face_point; + UBYTE face_order[4] = {0,1,3,2}; + + SVector_F poly[4]; + SMAP_Link *projected; + + mx1 = (darci->WorldPos.X - 0x10000) >> (8 + PAP_SHIFT_LO); + mz1 = (darci->WorldPos.Z - 0x10000) >> (8 + PAP_SHIFT_LO); + mx2 = (darci->WorldPos.X + 0x10000) >> (8 + PAP_SHIFT_LO); + mz2 = (darci->WorldPos.Z + 0x10000) >> (8 + PAP_SHIFT_LO); + + SATURATE(mx1, 0, PAP_SIZE_LO - 1); + SATURATE(mz1, 0, PAP_SIZE_LO - 1); + SATURATE(mx2, 0, PAP_SIZE_LO - 1); + SATURATE(mz2, 0, PAP_SIZE_LO - 1); + + for (mx = mx1; mx <= mx2; mx++) + for (mz = mz1; mz <= mz2; mz++) + { + nl = &NS_lo[mx][mz]; + + if (nl->cache == NULL) + { + // + // We can't see this lo-res mapsquare, so there is no point projecting + // a shadow onto it! + // + + continue; + } + ASSERT(WITHIN(nl->cache, 1, NS_MAX_CACHES - 1)); + + nc = &NS_cache[nl->cache]; + + // + // The origin of this lo-res mapsquare. + // + + base_x = mx << PAP_SHIFT_LO; + base_z = mz << PAP_SHIFT_LO; + + // + // Point and face memory. + // + + np_base = (NS_Point *) nc->memory; + nf_base = (NS_Face *) &np_base[nc->num_points]; + + for (j = 0, nf = nf_base; j < nc->num_faces; j++, nf++) + { + for (k = 0; k < 4; k++) + { + face_point = face_order[k]; + + ASSERT(WITHIN(nf->p[face_point], 0, nc->num_points - 1)); + + np = &np_base[nf->p[face_point]]; + + px = base_x + (np->x << 3); + pz = base_z + (np->z << 3); + + py = (np->y << 5) + -32 * 0x100; + + poly[k].X = float(px); + poly[k].Y = float(py); + poly[k].Z = float(pz); + } + + projected = SMAP_project_onto_poly(poly, 4); + + if (projected) + { + // + // We have generated a shadow poly! + // + + AENG_add_projected_lit_shadow_poly(projected); + } + } + } + } + } + } + + TEXTURE_shadow_update(); + + // + // Draw the reflections of people in the sewers. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (!(p_thing->Flags & FLAGS_IN_SEWERS)) + { + // + // Only draw things in the sewers. + // + } + else + { + if (p_thing->DrawType == DT_ROT_MULTI) + { + if (POLY_sphere_visible( + float(p_thing->WorldPos.X >> 8), + float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT, + float(p_thing->WorldPos.Z >> 8), + 256.0F / (AENG_DRAW_DIST * 256.0F))) + { + SLONG mx = p_thing->WorldPos.X >> 16; + SLONG mz = p_thing->WorldPos.Z >> 16; + + ASSERT(WITHIN(mx, 0, PAP_SIZE_HI - 1)); + ASSERT(WITHIN(mz, 0, PAP_SIZE_HI - 1)); + + NS_Hi *nh = &NS_hi[mx][mz]; + + if (NS_HI_TYPE(nh) != NS_HI_TYPE_ROCK && + NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE && + nh->water) + { + // + // The height of the reflection. + // + + SLONG reflect_height = (nh->water << 5) + (-32 * 0x100); + + FIGURE_draw_reflection(p_thing, reflect_height); + + if (WITHIN(bbox_upto, 0, AENG_MAX_BBOXES - 1)) + { + // + // Create a new bounding box + // + + bbox[bbox_upto].x1 = MAX(FIGURE_reflect_x1 - AENG_BBOX_PUSH_OUT, AENG_BBOX_PUSH_IN); + bbox[bbox_upto].y1 = MAX(FIGURE_reflect_y1, 0); + bbox[bbox_upto].x2 = MIN(FIGURE_reflect_x2 + AENG_BBOX_PUSH_OUT, DisplayWidth - AENG_BBOX_PUSH_IN); + bbox[bbox_upto].y2 = MIN(FIGURE_reflect_y2, DisplayHeight); + + bbox_upto += 1; + } + } + } + } + } + + t_index = p_thing->Child; + } + } + } + + // + // Draw the reflections. + // Clear the poly lists. + // + +#ifndef TARGET_DC + POLY_frame_draw(FALSE,FALSE); + POLY_frame_init(TRUE,TRUE); +#endif + + // + // Draw the water in all the lo-res mapsquares. Create the ones + // that aren't already cached. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + if (z == 0 || z == PAP_SIZE_LO - 1) + { + continue; + } + + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + if (x == 0 || x == PAP_SIZE_LO - 1) + { + continue; + } + + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + nl = &NS_lo[x][z]; + + if (nl->cache == NULL) + { + // + // Create the points and faces for this mapsquare. + // + + if (!NS_cache_create(x,z)) + { + // + // Houston, we have a problem [grrrrrrrgh] + // + + continue; + } + } + + ASSERT(WITHIN(nl->cache, 1, NS_MAX_CACHES - 1)); + + nc = &NS_cache[nl->cache]; + + base_x = float(x << PAP_SHIFT_LO); + base_z = float(z << PAP_SHIFT_LO); + + // + // Draw the water. + // + + { + float water_height; + + AENG_Nswater *answ; + + NS_Hi *nh; + + // + // Mark all the water points as untransformed. + // + + answ = &AENG_nswater[0][0]; + + for (i = 0; i < 25; i++) + { + answ->height[0] = 0; + answ->height[1] = 0; + answ->height[2] = 0; + answ->height[3] = 0; + + answ += 1; + } + + // + // Draw the water squares. + // + + bx = x << 2; + bz = z << 2; + + for (dx = 0; dx < 4; dx++) + for (dz = 0; dz < 4; dz++) + { + sx = bx + dx; + sz = bz + dz; + + ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1)); + ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1)); + + nh = &NS_hi[sx][sz]; + + // + // Curve squares use the water field as the type of curve... + // + + if (nh->water && NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE) + { + // + // The height of this square. + // + + water_height = float((nh->water << 5) + (-32 * 0x100)); + + for (i = 0; i < 4; i++) + { + ix = dx + (i & 1); + iz = dz + (i >> 1); + + answ = &AENG_nswater[ix][iz]; + + for (j = 0; j < 4; j++) + { + if (answ->height[j] == nh->water) + { + quad[i] = &answ->pp[j]; + + goto found_point; + } + + if (answ->height[j] == 0) + { + // + // We must create a new point. + // + + POLY_transform( + float(bx + ix << 8), + water_height, + float(bz + iz << 8), + &answ->pp[j]); + + if (answ->pp[j].MaybeValid()) + { + answ->pp[j].colour = 0xaa4488aa; + answ->pp[j].specular = 0xff000000; + + POLY_fadeout_point(&answ->pp[j]); + } + + quad[i] = &answ->pp[j]; + + goto found_point; + } + } + + found_point:; + } + + if (POLY_valid_quad(quad)) + { + // + // No textures? + // + + quad[0]->u = 0.0F; + quad[0]->v = 0.0F; + quad[1]->u = 1.0F; + quad[1]->v = 0.0F; + quad[2]->u = 0.0F; + quad[2]->v = 1.0F; + quad[3]->u = 1.0F; + quad[3]->v = 1.0F; + + POLY_add_quad(quad, POLY_PAGE_SEWATER, TRUE); + } + } + } + } + } + } + + if (bbox_upto) + { + if (the_display.screen_lock()) + { + // + // Wibble the bounding boxes of the reflections. + // + + for (i = 0; i < bbox_upto; i++) + { + WIBBLE_simple( + bbox[i].x1, + bbox[i].y1, + bbox[i].x2, + bbox[i].y2, + 62, 137, 17, 178, 40, 45); + } + + the_display.screen_unlock(); + } + } + + // + // Draw the sewer water. + // + +/* +#if 0 + POLY_sort_sewater_page(); + POLY_frame_draw_sewater(); +#else + // Shouldn't need to render sewer stuff. + ASSERT ( !(POLY_Page[POLY_PAGE_SEWATER].NeedsRendering()) ); +#endif +*/ + +#ifndef TARGET_DC + POLY_frame_init(TRUE,TRUE); +#endif + + // + // Draw all the low res mapsquares. None of the mapsquare + // should be uncached. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + if (z == 0 || z == PAP_SIZE_LO - 1) + { + continue; + } + + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + if (x == 0 || x == PAP_SIZE_LO - 1) + { + continue; + } + + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + nl = &NS_lo[x][z]; + + ASSERT(WITHIN(nl->cache, 1, NS_MAX_CACHES - 1)); + + nc = &NS_cache[nl->cache]; + + // + // Draw the waterfalls... + // + + { + SLONG top; + SLONG bot; + SLONG fall; + + NS_Fall *nf; + + for (fall = nc->fall; fall; fall = nf->next) + { + ASSERT(WITHIN(fall, 1, NS_MAX_FALLS - 1)); + + nf = &NS_fall[fall]; + + top = (nf->top << 5) + (-32 * 0x100); + bot = (nf->bot << 5) + (-32 * 0x100); + + SHAPE_waterfall( + nf->x, + nf->z, + nf->dx, + nf->dz, + top, + bot); + + // + // Create dirt-drops... + // + + sx = (nf->x << 8) + 0x80; + sz = (nf->z << 8) + 0x80; + + dsx = nf->dx; + dsz = nf->dz; + + dsx <<= 7; + dsz <<= 7; + + x1 = sx + dsx; + z1 = sz + dsz; + + x2 = sx + dsx; + z2 = sz + dsz; + + x1 += -dsz; + z1 += +dsx; + + x2 -= -dsz; + z2 -= +dsx; + + dropdx = -nf->dx << 3; + dropdz = -nf->dz << 3; + dropdy = 0; + + for (i = 0; i < 4; i++) + { + along = rand() & 0xff; + + dropx = x1 + ((x2 - x1) * along >> 8); + dropz = z1 + ((z2 - z1) * along >> 8); + + dropy = top; + + DIRT_new_water( + dropx, + dropy, + dropz, + dropdx, + dropdy, + dropdz); + } + } + } + + base_x = float(x << PAP_SHIFT_LO); + base_z = float(z << PAP_SHIFT_LO); + + // + // Rotate all the points into the POLY_buffer. + // + + POLY_buffer_upto = 0; + np = (NS_Point *) nc->memory; + pp = &POLY_buffer[0]; + + for (i = 0; i < nc->num_points; i++) + { + px = float(np->x << 3) + base_x; + pz = float(np->z << 3) + base_z; + + py = float(np->y << 5) + (32.0F * -256.0F); + + POLY_transform( + px, + py, + pz, + pp); + + if (pp->MaybeValid()) + { + pp->colour = (np->bright) | (np->bright << 8) | (np->bright << 16); +#ifdef TARGET_DC + pp->colour |= 0xff000000; +#endif + pp->specular = 0xff000000; + + if (bright) + { +#ifdef TARGET_DC + pp->colour = 0xffffffff; +#else + pp->colour = 0x00ffffff; +#endif + } + + POLY_fadeout_point(pp); + } + + np++; + pp++; + } + + // + // Create all the faces. + // + + nf = (NS_Face *) np; + + for (i = 0; i < nc->num_faces; i++) + { + ASSERT(WITHIN(nf->p[0], 0, nc->num_points - 1)); + ASSERT(WITHIN(nf->p[1], 0, nc->num_points - 1)); + ASSERT(WITHIN(nf->p[2], 0, nc->num_points - 1)); + ASSERT(WITHIN(nf->p[3], 0, nc->num_points - 1)); + + quad[0] = &POLY_buffer[nf->p[0]]; + quad[1] = &POLY_buffer[nf->p[1]]; + quad[2] = &POLY_buffer[nf->p[2]]; + quad[3] = &POLY_buffer[nf->p[3]]; + + if (POLY_valid_quad(quad)) + { + // + // Texture the quad. + // + + ASSERT(WITHIN(nf->texture, 0, NS_texture_upto - 1)); + + nt = &NS_texture[nf->texture]; + + for (j = 0; j < 4; j++) + { + quad[j]->u = float(nt->u[j]) * (1.0F / 32.0F); + quad[j]->v = float(nt->v[j]) * (1.0F / 32.0F); + } + + // + // Find the texture page. + // + + ASSERT(WITHIN(nf->page, 0, NS_PAGE_NUMBER - 1)); + + // + // And add it. + // + + page = NS_page[nf->page].page; + + POLY_add_quad(quad, page, TRUE); + } + + nf += 1; + } + + + // + // The sewer mapwho. + // + + for (i = nl->st; i; i = nst->next) + { + ASSERT(WITHIN(i, 1, NS_MAX_STS - 1)); + + nst = &NS_st[i]; + + switch(nst->type) + { + case NS_ST_TYPE_PRIM: + + MESH_draw_poly( + nst->prim.prim, + (x << PAP_SHIFT_LO) + (nst->prim.x << 3), + (nst->prim.y << 5) + 0x100 * -32, + (z << PAP_SHIFT_LO) + (nst->prim.z << 3), + nst->prim.yaw << 3, + 0, 0, + NULL,0xff,0); + + break; + + case NS_ST_TYPE_LADDER: + + FACET_draw_ns_ladder( + nst->ladder.x1, + nst->ladder.z1, + nst->ladder.x2, + nst->ladder.z2, + nst->ladder.height); + + break; + + default: + ASSERT(0); + break; + + } + } + + // + // Look at the colvects on this square. + // + + { + SLONG f_list; + SLONG facet; + SLONG build; + SLONG exit = FALSE; + + f_list = PAP_2LO(x,z).ColVectHead; + + show_gamut_lo(x,z); + + if (f_list) + { + while(!exit) + { + facet=facet_links[f_list]; + + ASSERT(facet); + + if (facet < 0) + { + // + // The last facet in the list for each square + // is negative. + // + + facet = -facet; + exit = TRUE; + } + + if (dfacets[facet].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam]) + { + if (dfacets[facet].FacetType == STOREY_TYPE_LADDER) + { + // + // Draw the facet. + // + + FACET_draw(facet,0); + } + + // + // Mark this facet as drawn this gameturn already. + // + + dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam]; + } + + f_list++; + } + } + } + } + } + + // + // Draw the objects and the things. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + // + // The game mapwho. + // + + t_index = PAP_2LO(x,z).MapWho; + + while(t_index) + { + p_thing = TO_THING(t_index); + + if (!(p_thing->Flags & FLAGS_IN_SEWERS)) + { + // + // Only draw things in the sewers. + // + } + else + { + switch(p_thing->DrawType) + { + case DT_NONE: + break; + + case DT_BUILDING: + break; + + case DT_PRIM: + break; + + case DT_ROT_MULTI: + + if (POLY_sphere_visible( + float(p_thing->WorldPos.X >> 8), + float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT, + float(p_thing->WorldPos.Z >> 8), + 256.0F / (AENG_DRAW_DIST * 256.0F))) + { + FIGURE_draw(p_thing); + } + + break; + + case DT_EFFECT: + break; + + case DT_MESH: + break; + + default: + ASSERT(0); + break; + } + } + + t_index = p_thing->Child; + } + } + } + + // + // The dirt. + // + + AENG_draw_dirt(); + + // + // Draw the drips. + // + +// AENG_draw_drips(0); + + // + // Draw the polys. + // + + POLY_frame_draw(TRUE,TRUE); + +} + + +#endif + + +void AENG_draw_scanner( + SLONG screen_x1, + SLONG screen_y1, + SLONG screen_x2, + SLONG screen_y2, + SLONG map_x, + SLONG map_z, + SLONG map_zoom, + SLONG map_angle) +{ +#ifdef DOG_POO + SLONG i; + + AZ_Line *al; + + float tx1; + float tx2; + float tz1; + float tz2; + + float rx1; + float rx2; + float rz1; + float rz2; + + float sx1; + float sx2; + float sy1; + float sy2; + + float left = float(screen_x1); + float right = float(screen_x2); + float top = float(screen_y1); + float bottom = float(screen_y2); + + float screen_mid_x = float(screen_x1 + screen_x2 >> 1); + float screen_mid_y = float(screen_y1 + screen_y2 >> 1); + float angle = float(map_angle) * (-2.0F * PI / 2048.0F); + float zoom = float(map_zoom) * (1.0F / 65536.0F); + + float sin_yaw = sin(angle); + float cos_yaw = cos(angle); + float matrix[4]; + + UBYTE clip1; + UBYTE clip2; + UBYTE clip_and; + UBYTE clip_xor; + + matrix[0] = cos_yaw; + matrix[1] = sin_yaw; + matrix[2] = -sin_yaw; + matrix[3] = cos_yaw; + + // + // Set the clipping rectangle. + // + + POLY_clip_line_box( + left, + top, + right, + bottom); + + // + // Initialise the frame. + // + + POLY_frame_init(FALSE,FALSE); + + // + // Add each line in turn. + // + + ULONG type_colour[AZ_LINE_TYPE_NUMBER] = + { + 0x00d83377, + 0x00eed811, + 0x0033ccff + }; + + for (i = 0; i < AZ_line_upto; i++) + { + al = &AZ_line[i]; + + tx1 = float((al->x1 << ELE_SHIFT) - map_x); + tz1 = float((al->z1 << ELE_SHIFT) - map_z); + + tx2 = float((al->x2 << ELE_SHIFT) - map_x); + tz2 = float((al->z2 << ELE_SHIFT) - map_z); + + // + // Rotate the points. + // + + rx1 = tx1 * matrix[0] + tz1 * matrix[1]; + rz1 = tx1 * matrix[2] + tz1 * matrix[3]; + + rx2 = tx2 * matrix[0] + tz2 * matrix[1]; + rz2 = tx2 * matrix[2] + tz2 * matrix[3]; + + // + // Their screen positions. + // + + sx1 = screen_mid_x + zoom * rx1; + sy1 = screen_mid_y + zoom * rz1; + + sx2 = screen_mid_x + zoom * rx2; + sy2 = screen_mid_y + zoom * rz2; + + // + // Add the line. + // + + ASSERT(WITHIN(al->type, 0, AZ_LINE_TYPE_NUMBER - 1)); + + POLY_clip_line_add(sx1, sy1, sx2, sy2, type_colour[al->type]); + } + + // + // Draw all the people. + // + + { + THING_INDEX t_index; + Thing *p_thing; + + SLONG dx; + SLONG dz; + + for (t_index = the_game.UsedPrimaryThings; t_index; t_index = p_thing->LinkChild) + { + p_thing = TO_THING(t_index); + + if (p_thing->Class == CLASS_PERSON) + { + dx = -SIN(p_thing->Draw.Tweened->Angle) >> 9; + dz = -COS(p_thing->Draw.Tweened->Angle) >> 9; + + tx1 = float((p_thing->WorldPos.X >> 8) - map_x); + tz1 = float((p_thing->WorldPos.Z >> 8) - map_z); + + tx2 = float((p_thing->WorldPos.X >> 8) + dx - map_x); + tz2 = float((p_thing->WorldPos.Z >> 8) + dz - map_z); + + // + // Rotate the points. + // + + rx1 = tx1 * matrix[0] + tz1 * matrix[1]; + rz1 = tx1 * matrix[2] + tz1 * matrix[3]; + + rx2 = tx2 * matrix[0] + tz2 * matrix[1]; + rz2 = tx2 * matrix[2] + tz2 * matrix[3]; + + // + // Their screen positions. + // + + sx1 = screen_mid_x + zoom * rx1; + sy1 = screen_mid_y + zoom * rz1; + + sx2 = screen_mid_x + zoom * rx2; + sy2 = screen_mid_y + zoom * rz2; + + // + // Add the line. + // + + POLY_clip_line_add(sx1, sy1, sx2, sy2, 0x00ffffff); + } + } + } + + // + // Draw a cross in the middle of the map. + // + + #define AENG_CROSS_SIZE 5 + #define AENG_CROSS_COLOUR 0x0033aa33 + + POLY_clip_line_add( + screen_mid_x - AENG_CROSS_SIZE, + screen_mid_y - AENG_CROSS_SIZE, + screen_mid_x + AENG_CROSS_SIZE, + screen_mid_y + AENG_CROSS_SIZE, + AENG_CROSS_COLOUR); + + POLY_clip_line_add( + screen_mid_x - AENG_CROSS_SIZE, + screen_mid_y + AENG_CROSS_SIZE, + screen_mid_x + AENG_CROSS_SIZE, + screen_mid_y - AENG_CROSS_SIZE, + AENG_CROSS_COLOUR); + + // + // Draw an outline. + // + + #define AENG_BORDER_COLOUR 0x003355cc + + POLY_add_line_2d(left, top, right, top, AENG_BORDER_COLOUR); + POLY_add_line_2d(right, top, right, bottom, AENG_BORDER_COLOUR); + POLY_add_line_2d(right, bottom, left, bottom, AENG_BORDER_COLOUR); + POLY_add_line_2d(left, bottom, left, top, AENG_BORDER_COLOUR); + + // + // The transparent background background. + // + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + #define AENG_BACKGROUND_COLOUR 0x55888800 + + pp[0].X = left; + pp[0].Y = top; + pp[0].z = 0.0F; + pp[0].Z = 1.0F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = AENG_BACKGROUND_COLOUR; + pp[0].specular = 0; + + pp[1].X = right; + pp[1].Y = top; + pp[1].z = 0.0F; + pp[1].Z = 1.0F; + pp[1].u = 0.0F; + pp[1].v = 0.0F; + pp[1].colour = AENG_BACKGROUND_COLOUR; + pp[1].specular = 0; + + pp[2].X = left; + pp[2].Y = bottom; + pp[2].z = 0.0F; + pp[2].Z = 1.0F; + pp[2].u = 0.0F; + pp[2].v = 0.0F; + pp[2].colour = AENG_BACKGROUND_COLOUR; + pp[2].specular = 0; + + pp[3].X = right; + pp[3].Y = bottom; + pp[3].z = 0.0F; + pp[3].Z = 1.0F; + pp[3].u = 0.0F; + pp[3].v = 0.0F; + pp[3].colour = AENG_BACKGROUND_COLOUR; + pp[3].specular = 0; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE); + + #if WE_WANT_TO_DRAW_THE_TEXTURE_SHADOW_PAGE + + { + left = 80; + top = 80; + + right = 144; + bottom = 144; + + #define USIZE (float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE)) + + pp[0].X = left; + pp[0].Y = top; + pp[0].z = 0.0F; + pp[0].Z = 1.0F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = 0xffffffff; + pp[0].specular = 0xff000000; + + pp[1].X = right; + pp[1].Y = top; + pp[1].z = 0.0F; + pp[1].Z = 1.0F; + pp[1].u = USIZE; + pp[1].v = 0.0F; + pp[1].colour = 0xffffffff; + pp[1].specular = 0xff000000; + + pp[2].X = left; + pp[2].Y = bottom; + pp[2].z = 0.0F; + pp[2].Z = 1.0F; + pp[2].u = 0.0F; + pp[2].v = USIZE; + pp[2].colour = 0xffffffff; + pp[2].specular = 0xff000000; + + pp[3].X = right; + pp[3].Y = bottom; + pp[3].z = 0.0F; + pp[3].Z = 1.0F; + pp[3].u = USIZE; + pp[3].v = USIZE; + pp[3].colour = 0xffffffff; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_SHADOW, FALSE, TRUE); + } + + #endif + + // + // Draw the polys. + // + + POLY_frame_draw(TRUE,TRUE); +#endif +} + +void AENG_draw_power(SLONG x,SLONG y,SLONG w,SLONG h,SLONG val,SLONG max) +{ + /* + + SLONG left,right,top,bottom; + POLY_Point pp [4]; + POLY_Point *quad[4]; + + left=x; + right=left+w; + top=y; + bottom=y+h; + + // + // Set the clipping rectangle. + // + POLY_clip_line_box( + x, + y, + x+w, + y+h); + + POLY_frame_init(FALSE,FALSE); + + // + // Draw an outline. + // + + #define AENG_PBORDER_COLOUR 0x003355cc + #define AENG_PFOREGROUND_COLOUR 0x55888800 + + POLY_add_line_2d(left, top, right, top, AENG_PBORDER_COLOUR); + POLY_add_line_2d(right, top, right, bottom, AENG_PBORDER_COLOUR); + POLY_add_line_2d(right, bottom, left, bottom, AENG_PBORDER_COLOUR); + POLY_add_line_2d(left, bottom, left, top, AENG_PBORDER_COLOUR); + + right=left+(val*w)/max; + + pp[0].X = left; + pp[0].Y = top; + pp[0].z = 0.0F; + pp[0].Z = 1.0F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[1].colour = AENG_PFOREGROUND_COLOUR; + pp[0].specular = 0; + + pp[1].X = right; + pp[1].Y = top; + pp[1].z = 0.0F; + pp[1].Z = 1.0F; + pp[1].u = 0.0F; + pp[1].v = 0.0F; + pp[1].colour = AENG_PFOREGROUND_COLOUR; + pp[1].specular = 0; + + pp[2].X = left; + pp[2].Y = bottom; + pp[2].z = 0.0F; + pp[2].Z = 1.0F; + pp[2].u = 0.0F; + pp[2].v = 0.0F; + pp[1].colour = AENG_PFOREGROUND_COLOUR; + pp[2].specular = 0; + + pp[3].X = right; + pp[3].Y = bottom; + pp[3].z = 0.0F; + pp[3].Z = 1.0F; + pp[3].u = 0.0F; + pp[3].v = 0.0F; + pp[1].colour = AENG_PFOREGROUND_COLOUR; + pp[3].specular = 0; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE, TRUE); + + POLY_frame_draw(TRUE,TRUE); + + */ +} + +UBYTE record_video=0; + +#if defined(TARGET_DC) + +// Chews memory - sod it. +void AENG_screen_shot(void) +{ +} + +// time.h doesn't seem to exist in the DC stuff - wierd. +// Bin this function on the DC for now. +void AENG_draw_FPS() +{ +} + + +#else //#if defined(TARGET_DC) + +void AENG_screen_shot(void) +{ + if(allow_debug_keys) + if (Keys[KB_S] || record_video) + { + Keys[KB_S] = 0; + if(ShiftFlag) + { + record_video^=1; + } + + if (the_display.screen_lock()) + { +extern void tga_dump(void); + tga_dump(); + + //DumpBackToRaw(); + the_display.screen_unlock(); + } + } +} + + +void AENG_draw_FPS() +{ + static SLONG fps = 0; // current FPS + static SLONG avfps = 0; // average FPS + static SLONG last_game_turn = 0; // game turn when FPS was sampled + static clock_t last_time = 0; // time when FPS was sampled + static SLONG total_frames = 0; + static float total_time = 0; + static SLONG ups = 0; // us per frame + static SLONG avups = 0; + + clock_t this_time = clock(); + + int frames_passed = GAME_TURN - last_game_turn; + + if ((frames_passed < 0) || (frames_passed > 200)) + { + // reset + fps = 0; + last_game_turn = GAME_TURN; + last_time = this_time; + } + else + { + if (frames_passed >= 20) + { + float seconds = float(this_time - last_time) / float(CLOCKS_PER_SEC); + float _fps = float(frames_passed) / seconds; + fps = floor(_fps + 0.5); + float _ups = 1000000 / _fps; + ups = floor(_ups + 0.5); + + if (fps > 10) // don't include really slow frames in the average + { + total_frames += frames_passed; + total_time += seconds; + float _avfps = float(total_frames) / total_time; + avfps = floor(_avfps + 0.5); + float _avups = 1000000 / _avfps; + avups = floor(_avups + 0.5); + } + + last_time = this_time; + last_game_turn = GAME_TURN; + + } + } +/* + if (the_display.screen_lock()) + { + FONT_draw(DisplayWidth >> 1, 10, "FPS: %d = %d us", fps, ups); + FONT_draw(DisplayWidth >> 1, 30, "Avg: %d = %d us", avfps, avups); + the_display.screen_unlock(); + } +*/ + + if (allow_debug_keys) + { + CBYTE str[100]; + + sprintf(str,"FPS: %d = %d us",fps,ups); + FONT2D_DrawString(str,DisplayWidth >> 1, 10,0xffffff,128); + sprintf(str,"Avg: %d = %d us",avfps,avups); + FONT2D_DrawString(str,DisplayWidth >> 1, 30,0xffffff,128); + } + +} + +#endif //#else //#if defined(TARGET_DC) + +void AENG_draw_messages() +{ + // + // fps stuff. + // + + static SLONG fps = 0; +#if !defined(TARGET_DC) + static SLONG last_game_turn = 0; + static clock_t last_time = 0; + clock_t this_time = 0; + + this_time = clock() / CLOCKS_PER_SEC; + + if (this_time != last_time) + { + if (this_time - last_time > 1) + { + // + // Only work out the new frames per second if there hasn't been a major + // delay. + // + } + else + { + fps = GAME_TURN - last_game_turn; + } + + last_time = this_time; + last_game_turn = GAME_TURN; + } +#else + fps = 0; +#endif + + #if ARGH + + static SLONG px[3] = {4 << 16, 8 << 16, 8 << 16}; + static SLONG py[3] = {4 << 16, 4 << 16, 8 << 16}; + + if (LeftButton) + { + SLONG mx; + SLONG my; + + SLONG dx; + SLONG dy; + + mx = MouseX - AENG_AA_LEFT; + my = MouseY - AENG_AA_TOP; + + mx <<= 16; + my <<= 16; + + mx /= AENG_AA_PIX_SIZE; + my /= AENG_AA_PIX_SIZE; + + SLONG i; + + SLONG dist; + SLONG best_dist = INFINITY; + SLONG *best_x; + SLONG *best_y; + + for (i = 0; i < 3; i++) + { + dx = abs(px[i] - mx); + dy = abs(py[i] - my); + + dist = dx + dy; + + if (dist < best_dist) + { + best_dist = dist; + best_x = &px[i]; + best_y = &py[i]; + } + } + + *best_x = mx; + *best_y = my; + } + + { + // + // Draw a mad quad! + // + + memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer)); + + AA_draw( + (UBYTE *) AENG_aa_buffer, + AENG_AA_BUF_SIZE, + AENG_AA_BUF_SIZE, + AENG_AA_BUF_SIZE, + px[0], py[0], + px[1], py[1], + px[2], py[2]); + } + + #endif + + // + // Draw stuff straight to the screen. + // + + if (the_display.screen_lock()) + { +/* + if (Keys[KB_S]) + { + Keys[KB_S] = 0; + + // + // Take a screen shot. + // + + DumpBackToRaw(); + } +*/ + + + // + // Draw the fps. + // + FONT_draw(DisplayWidth >> 1, 10, "FPS: %d", fps); +/* + + // + // Number of facets drawn. + // + + FONT_draw(DisplayWidth >> 1, 20, "Facets: %d", dfacets_drawn_this_gameturn); +extern SLONG damp; + FONT_draw(20,30, "DAMP: %d", damp); + */ + + // + // Draw the messages. + // + + //MSG_draw(); + #if werrr + + SLONG x; + SLONG y; + + SLONG dx; + SLONG dy; + + for (x = 0; x < AENG_AA_BUF_SIZE; x++) + for (y = 0; y < AENG_AA_BUF_SIZE; y++) + { + for (dx = 0; dx < AENG_AA_PIX_SIZE; dx++) + for (dy = 0; dy < AENG_AA_PIX_SIZE; dy++) + { + the_display.PlotPixel( + AENG_AA_LEFT + x * AENG_AA_PIX_SIZE + dx, + AENG_AA_TOP + y * AENG_AA_PIX_SIZE + dy, + AENG_aa_buffer[y][x], + AENG_aa_buffer[y][x], + AENG_aa_buffer[y][x]); + } + } + + for (SLONG i = 0; i < 3; i++) + { + x = AENG_AA_LEFT + (px[i] * AENG_AA_PIX_SIZE >> 16); + y = AENG_AA_TOP + (py[i] * AENG_AA_PIX_SIZE >> 16); + + the_display.PlotPixel(x + 0, y + 0, 255, 255, 0); + the_display.PlotPixel(x + 1, y + 0, 255, 100, 0); + the_display.PlotPixel(x + 0, y + 1, 255, 100, 0); + the_display.PlotPixel(x - 1, y + 0, 255, 100, 0); + the_display.PlotPixel(x + 0, y - 1, 255, 100, 0); + } + + #endif + + the_display.screen_unlock(); + } +} + +void AENG_fade_out(UBYTE amount) +{ + SLONG logo_fade_top = amount; + SLONG back_fade_top = amount; + + ULONG logo_colour_top = (logo_fade_top << 24) | 0x00ffffff; + ULONG back_colour_top = (back_fade_top << 24) | 0x00ffffff; + + SLONG logo_fade_bot = amount; + SLONG back_fade_bot = amount; + + ULONG logo_colour_bot = (logo_fade_bot << 24) | 0x00ffffff; + ULONG back_colour_bot = (back_fade_bot << 24) | 0x00ffffff; + + // + // Draw the logo. + // + + POLY_Point pp[4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + #define AENG_LOGO_MID_X (320.0F) + #define AENG_LOGO_MID_Y (240.0F) + #define AENG_LOGO_SIZE (128.0F) + +#ifndef TARGET_DC + POLY_frame_init(FALSE,FALSE); +#endif + + pp[0].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE; + pp[0].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE; + pp[0].z = 1.0F / 65536.0F; + pp[0].Z = 1.0F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = logo_colour_top; + pp[0].specular = 0x00000000; + + pp[1].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE; + pp[1].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE; + pp[1].z = 1.0F / 65536.0F; + pp[1].Z = 1.0F; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[1].colour = logo_colour_top; + pp[1].specular = 0x00000000; + + pp[2].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE; + pp[2].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE; + pp[2].z = 1.0F / 65536.0F; + pp[2].Z = 1.0F; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[2].colour = logo_colour_bot; + pp[2].specular = 0x00000000; + + pp[3].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE; + pp[3].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE; + pp[3].z = 1.0F / 65536.0F; + pp[3].Z = 1.0F; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + pp[3].colour = logo_colour_bot; + pp[3].specular = 0x00000000; + + POLY_add_quad(quad, POLY_PAGE_LOGO, FALSE, TRUE); + +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); + POLY_frame_init(FALSE,FALSE); +#endif + + pp[0].X = 0.0F; + pp[0].Y = 0.0F; + pp[0].z = 2.0F / 65536.0F; + pp[0].Z = 65535.0F / 65536.0F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = back_colour_top; + pp[0].specular = 0x00000000; + + pp[1].X = 640.0F; + pp[1].Y = 0.0F; + pp[1].z = 2.0F / 65536.0F; + pp[1].Z = 65535.0F / 65536.0F; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[1].colour = back_colour_top; + pp[1].specular = 0x00000000; + + pp[2].X = 0.0F; + pp[2].Y = 480.0F; + pp[2].z = 2.0F / 65536.0F; + pp[2].Z = 65535.0F / 65536.0F; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[2].colour = back_colour_bot; + pp[2].specular = 0x00000000; + + pp[3].X = 640.0F; + pp[3].Y = 480.0F; + pp[3].z = 2.0F / 65536.0F; + pp[3].Z = 65535.0F / 65536.0F; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + pp[3].colour = back_colour_bot; + pp[3].specular = 0x00000000; + + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE); + +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); +#endif +} + + +void AENG_fade_in(UBYTE amount) +{ + SLONG logo_fade_top = 255 - amount; + SLONG back_fade_top = 255 - (amount * amount >> 8); + + ULONG logo_colour_top = (logo_fade_top << 24); + ULONG back_colour_top = (back_fade_top << 24); + + SLONG logo_fade_bot = 255 - amount; + SLONG back_fade_bot = 255 - (amount * amount >> 8); + + ULONG logo_colour_bot = (logo_fade_bot << 24); + ULONG back_colour_bot = (back_fade_bot << 24); + + // + // Draw the logo. + // + + POLY_Point pp[4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + +#ifndef TARGET_DC + POLY_frame_init(TRUE,TRUE); +#endif + + pp[0].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE; + pp[0].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE; + pp[0].z = 1.0F / 65536.0F; + pp[0].Z = 1.0F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = logo_colour_top; + pp[0].specular = 0xff000000; + + pp[1].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE; + pp[1].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE; + pp[1].z = 1.0F / 65536.0F; + pp[1].Z = 1.0F; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[1].colour = logo_colour_top; + pp[1].specular = 0xff000000; + + pp[2].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE; + pp[2].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE; + pp[2].z = 1.0F / 65536.0F; + pp[2].Z = 1.0F; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[2].colour = logo_colour_bot; + pp[2].specular = 0xff000000; + + pp[3].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE; + pp[3].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE; + pp[3].z = 1.0F / 65536.0F; + pp[3].Z = 1.0F; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + pp[3].colour = logo_colour_bot; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad, POLY_PAGE_LOGO, FALSE, TRUE); + +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); +#endif + + pp[0].X = 0.0F; + pp[0].Y = 0.0F; + pp[0].z = 2.0F / 65536.0F; + pp[0].Z = 65535.0F / 65536.0F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = back_colour_top; + pp[0].specular = 0xff000000; + + pp[1].X = 640.0F; + pp[1].Y = 0.0F; + pp[1].z = 2.0F / 65536.0F; + pp[1].Z = 65535.0F / 65536.0F; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[1].colour = back_colour_top; + pp[1].specular = 0xff000000; + + pp[2].X = 0.0F; + pp[2].Y = 480.0F; + pp[2].z = 2.0F / 65536.0F; + pp[2].Z = 65535.0F / 65536.0F; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[2].colour = back_colour_bot; + pp[2].specular = 0xff000000; + + pp[3].X = 640.0F; + pp[3].Y = 480.0F; + pp[3].z = 2.0F / 65536.0F; + pp[3].Z = 65535.0F / 65536.0F; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + pp[3].colour = back_colour_bot; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE); + +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); + POLY_frame_init(FALSE,FALSE); +#endif +} + + +void AENG_clear_screen() +{ +#ifdef TARGET_DC + static int iBlah = 0; + iBlah++; + iBlah = 0; + if ( ( iBlah & 0x3 ) == 0 ) + { + SET_BLACK_BACKGROUND; + } + else if ( ( iBlah & 0x3 ) == 1 ) + { + SET_WHITE_BACKGROUND; + } + else if ( ( iBlah & 0x3 ) == 2 ) + { + SET_BLACK_BACKGROUND; + } + else if ( ( iBlah & 0x3 ) == 3 ) + { + SET_WHITE_BACKGROUND; + } +#else + SET_BLACK_BACKGROUND; +#endif + CLEAR_VIEWPORT; + TheVPool->ReclaimBuffers(); +} + +SLONG AENG_lock() +{ + return SLONG(the_display.screen_lock()); +} + +void AENG_unlock() +{ + the_display.screen_unlock(); +} + +void AENG_flip() +{ +#ifndef TARGET_DC + if (sw_hack) + { + SW_copy_to_bb(); + } +#endif + + FLIP(NULL, DDFLIP_WAIT); // PerMedia2 needs this, or else! +} + +void AENG_blit() +{ +#ifndef TARGET_DC + if (sw_hack) + { + SW_copy_to_bb(); + } +#endif + + the_display.blit_back_buffer(); +} + + +#ifndef TARGET_DC +void AENG_e_draw_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2) +{ + AENG_world_line( + x1,y1,z1,8,0x00ffffff, + x2,y2,z2,8,0x00ffffff, + TRUE); +} + +void AENG_e_draw_3d_line_dir(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2) +{ + AENG_world_line( + x1,y1,z1,32,0x00ffffff, + x2,y2,z2, 0,0x00553311, + TRUE); +} + +void AENG_e_draw_3d_line_col(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b) +{ + ULONG colour; + + colour = r << 16; + colour |= g << 8; + colour |= b << 0; + + AENG_world_line( + x1,y1,z1,8,colour, + x2,y2,z2,8,colour, + TRUE); +} + +void AENG_e_draw_3d_line_col_sorted(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b) +{ + ULONG colour; + + colour = r << 16; + colour |= g << 8; + colour |= b << 0; + + AENG_world_line( + x1,y1,z1,8,colour, + x2,y2,z2,8,colour, + FALSE); +} + +void AENG_e_draw_3d_mapwho(SLONG x1, SLONG z1) +{ + x1 <<= ELE_SHIFT; + z1 <<= ELE_SHIFT; + + e_draw_3d_line(x1,0,z1,x1+256,0,z1); + e_draw_3d_line(x1+256,0,z1,x1+256,0,z1+256); + e_draw_3d_line(x1+256,0,z1+256,x1,0,z1+256); + e_draw_3d_line(x1,0,z1+256,x1,0,z1); +} + +void AENG_e_draw_3d_mapwho_y(SLONG x1, SLONG y1, SLONG z1) +{ + x1 <<= ELE_SHIFT; + z1 <<= ELE_SHIFT; + + e_draw_3d_line(x1,y1,z1,x1+256,y1,z1); + e_draw_3d_line(x1+256,y1,z1,x1+256,y1,z1+256); + e_draw_3d_line(x1+256,y1,z1+256,x1,y1,z1+256); + e_draw_3d_line(x1,y1,z1+256,x1,y1,z1); +} +#endif //#ifndef TARGET_DC + + +//--------------------------------------------------------------- + +void AENG_demo_attract(SLONG x,SLONG y,CBYTE *text) +{ + /* + + static flash = 0; + + POLY_frame_init(FALSE,FALSE); + + + text_fudge = TRUE; + + + draw_centre_text_at(x,y,text,1,1); + + //if (flash++ & 0x10) Do it all the time! + { + text_fudge = FALSE; + text_colour = 0x00eeeeff; + + draw_centre_text_at( + 320, 30, + "Press any button to play demo\n", + 0,0); + } + + POLY_frame_draw(FALSE,TRUE); + + */ +} + +//--------------------------------------------------------------- + + +#ifndef TARGET_DC +// ======================================================== +// +// EDITOR SUPPORT FUNCTIONS. +// +// ======================================================== + +SLONG AENG_raytraced_position( + SLONG sx, + SLONG sy, + SLONG *world_x, + SLONG *world_y, + SLONG *world_z, + SLONG indoors) +{ + SLONG i; + + float ax; + float ay; + + float ex; + float ey; + float ez; + + float dx; + float dy; + float dz; + float len; + + SLONG wx; + SLONG wy; + SLONG wz; + + float rx = AENG_cam_x; + float ry = AENG_cam_y; + float rz = AENG_cam_z; + + // + // Use to cone to find out the direction of the vector through (sx,sy). + // + + ax = float(sx) * (1.0F / 640.0F); + ay = float(sy) * (1.0F / 480.0F); + + ex = AENG_cone[1].x; + ey = AENG_cone[1].y; + ez = AENG_cone[1].z; + + ex += ax * (AENG_cone[0].x - AENG_cone[1].x); + ey += ax * (AENG_cone[0].y - AENG_cone[1].y); + ez += ax * (AENG_cone[0].z - AENG_cone[1].z); + + ex += ay * (AENG_cone[2].x - AENG_cone[1].x); + ey += ay * (AENG_cone[2].y - AENG_cone[1].y); + ez += ay * (AENG_cone[2].z - AENG_cone[1].z); + + // + // This is all in mapsquare coordinates, not world coordinates. + // + + ex *= 256.0F; + ey *= 256.0F; + ez *= 256.0F; + + // + // The direction of our ray. + // + + dx = ex - rx; + dy = ey - ry; + dz = ez - rz; + + len = sqrt(dx*dx + dy*dy + dz*dz); + + #define AENG_RAYTRACE_ACCURACY 16 + + dx *= (256.0F / AENG_RAYTRACE_ACCURACY) / len; + dy *= (256.0F / AENG_RAYTRACE_ACCURACY) / len; + dz *= (256.0F / AENG_RAYTRACE_ACCURACY) / len; + + if (GAME_FLAGS & GF_SEWERS) + { + // + // Use the sewer LOS function. + // + + SLONG x1 = SLONG(rx); + SLONG y1 = SLONG(ry); + SLONG z1 = SLONG(rz); + + SLONG x2 = SLONG(rx + dx * (AENG_RAYTRACE_ACCURACY * 16)); + SLONG y2 = SLONG(ry + dy * (AENG_RAYTRACE_ACCURACY * 16)); + SLONG z2 = SLONG(rz + dz * (AENG_RAYTRACE_ACCURACY * 16)); + + if (NS_there_is_a_los( + x1, y1, z1, + x2, y2, z2)) + { + return FALSE; + } + + *world_x = NS_los_fail_x; + *world_y = NS_los_fail_y; + *world_z = NS_los_fail_z; + + if (!WITHIN(*world_x, 0, (PAP_SIZE_HI << 8) - 1) || + !WITHIN(*world_z, 0, (PAP_SIZE_HI << 8) - 1)) + { + return FALSE; + } + else + { + return TRUE; + } + } + + // + // Intersect the ray with the world. + // + + rx += dx * AENG_RAYTRACE_ACCURACY; + ry += dy * AENG_RAYTRACE_ACCURACY; + rz += dz * AENG_RAYTRACE_ACCURACY; + + for (i = 0; i < AENG_RAYTRACE_ACCURACY * (AENG_DRAW_DIST - 1); i++) + { + wx = (SLONG) rx; + wy = (SLONG) ry; + wz = (SLONG) rz; + + if ( + (indoors&&(wy> 4), + colour,0xFF000000); + + AENG_world_line( + lx, h1, lz, 32, 0xffffff, + lx, h2, lz, 0, colour, + FALSE); + +#ifndef TARGET_DC + POLY_frame_draw(FALSE, FALSE); +#endif + + // + // Was either over the mouse? + // + + SLONG dx; + SLONG dy; + SLONG dist; + + SLONG sx; + SLONG sy; + SLONG swidth; + + if (POLY_get_sphere_circle( + float(lx), + float(h1), + float(lz), + 30.0F, + &sx, + &sy, + &swidth)) + { + dx = abs(sx - mx); + dy = abs(sy - my); + + dist = QDIST2(dx,dy); + + if (dist < swidth * 3) + { + ans |= AENG_MOUSE_OVER_LIGHT_BOT; + } + } + + if (POLY_get_sphere_circle( + float(lx), + float(h2), + float(lz), + 30.0F, + &sx, + &sy, + &swidth)) + { + dx = abs(sx - mx); + dy = abs(sy - my); + + dist = QDIST2(dx,dy); + + if (dist < swidth * 3) + { + ans |= AENG_MOUSE_OVER_LIGHT_TOP; + } + } + + return ans; +} + + +#ifdef SEWERS + +void AENG_draw_sewer_editor( + SLONG cam_x, + SLONG cam_y, + SLONG cam_z, + SLONG cam_yaw, + SLONG cam_pitch, + SLONG cam_roll, + SLONG mouse_x, + SLONG mouse_y, + SLONG *mouse_over_valid, + SLONG *mouse_over_x, + SLONG *mouse_over_y, + SLONG *mouse_over_z, + SLONG draw_prim_at_mouse, + SLONG prim_object, + SLONG prim_yaw) +{ + SLONG i; + + SLONG x; + SLONG z; + + float px; + float py; + float pz; + + float wy; + + SLONG height; + SLONG page; + + float along_01; + float along_02; + + POLY_Point pp[4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + pp[0].colour = 0x00ffffff; + pp[1].colour = 0x00ffffff; + pp[2].colour = 0x00ffffff; + pp[3].colour = 0x00ffffff; + + pp[0].specular = 0xff000000; + pp[1].specular = 0xff000000; + pp[2].specular = 0xff000000; + pp[3].specular = 0xff000000; + + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + + ES_Hi *eh; + ES_Lo *el; + + ES_Thing *et; + + // + // Clear screen. + // + + AENG_clear_screen(); + + // + // Clear out stuff. + // + + POLY_frame_init(FALSE,FALSE); + + // + // Set the camera. + // + + POLY_camera_set( + float(cam_x), + float(cam_y), + float(cam_z), + float(cam_yaw) * 2.0F * PI / 2048.0F, + float(cam_pitch) * 2.0F * PI / 2048.0F, + float(cam_roll) * 2.0F * PI / 2048.0F, + float(AENG_DRAW_DIST) * 256.0F, + AENG_LENS); + + // + // Calculate the gamut. + // + + AENG_calc_gamut( + float(cam_x), + float(cam_y), + float(cam_z), + float(cam_yaw) * 2.0F * PI / 2048.0F, + float(cam_pitch) * 2.0F * PI / 2048.0F, + float(cam_roll) * 2.0F * PI / 2048.0F, + float(AENG_DRAW_DIST), + AENG_LENS); + + *mouse_over_valid = FALSE; + + for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++) + { + for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 1)); + + eh = &ES_hi[x][z]; + + switch(eh->type) + { + case ES_TYPE_ROCK: page = NS_page[NS_PAGE_ROCK ].page; break; + case ES_TYPE_SEWER: page = NS_page[NS_PAGE_SWALL].page; break; + case ES_TYPE_GROUND: page = NS_page[NS_PAGE_STONE].page; break; + case ES_TYPE_HOLE: page = 0; break; + default: + ASSERT(0); + break; + } + + if (eh->flag & ES_FLAG_GRATING) + { + page = NS_page[NS_PAGE_GRATE].page; + } + + // + // The height. + // + + py = float((eh->height << 5) + -32 * 0x100); + + // + // Create the four points. + // + + for (i = 0; i < 4; i++) + { + px = float(x + ((i & 1) ? 1 : 0)) * 256.0F; + pz = float(z + ((i & 2) ? 1 : 0)) * 256.0F; + + POLY_transform( + px, + py, + pz, + &pp[i]); + + if (!pp[i].MaybeValid()) + { + goto abandon_this_square; + } + } + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, page, FALSE); + + // + // Is the mouse in this quad? + // + + if (POLY_inside_quad( + float(mouse_x), + float(mouse_y), + quad, + &along_01, + &along_02)) + { + *mouse_over_valid = TRUE; + + *mouse_over_x = x * 256 + 0x80; + *mouse_over_y = SLONG(py); + *mouse_over_z = z * 256 + 0x80; + } + } + + abandon_this_square:; + + // + // Draw water above this square? + // + + if (eh->water) + { + // + // The height. + // + + wy = float((eh->water << 5) + -32 * 0x100); + + // + // Create the four points. + // + + for (i = 0; i < 4; i++) + { + px = float(x + ((i & 1) ? 1 : 0)) * 256.0F; + pz = float(z + ((i & 2) ? 1 : 0)) * 256.0F; + + POLY_transform( + px, + wy, + pz, + &pp[i]); + + if (!pp[i].MaybeValid()) + { + goto abandon_this_water; + } + } + + pp[0].colour = 0x00222266; + pp[1].colour = 0x00222266; + pp[2].colour = 0x00222266; + pp[3].colour = 0x00222266; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_ADDITIVE, FALSE); + } + + pp[0].colour = 0x00ffffff; + pp[1].colour = 0x00ffffff; + pp[2].colour = 0x00ffffff; + pp[3].colour = 0x00ffffff; + + abandon_this_water:; + + } + + if (eh->flag & ES_FLAG_ENTRANCE) + { + SLONG mx = (x << 8) + 0x80; + SLONG mz = (z << 8) + 0x80; + + SLONG colourbot; + SLONG colourtop; + + if (eh->flag & ES_FLAG_NOCURBS) + { + colourbot = 0x0000ff00; + colourtop = 0x000000ff; + } + else + { + colourbot = 0x00ff0000; + colourtop = 0x00ffff88; + } + + AENG_world_line( + mx, SLONG(py) + 0x010, mz, 32, colourbot, + mx, SLONG(py) + 0x280, mz, 0, colourtop, + FALSE); + } + } + } + + // + // Draw the lights. + // + + for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++) + { + for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++) + { + ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1)); + + el = &ES_lo[x][z]; + + if (el->light_y) + { + SLONG lx = (x << PAP_SHIFT_LO) + (el->light_x << 3); + SLONG ly = (el->light_y << 5) + -32 * 0x100; + SLONG lz = (z << PAP_SHIFT_LO) + (el->light_z << 3); + + SHAPE_sphere( + lx, ly, lz, + 32, + 0x00ddddff); + } + } + } + + // + // Draw the things. + // + + for (i = 0; i < ES_MAX_THINGS; i++) + { + et = &ES_thing[i]; + + switch(et->type) + { + case ES_THING_TYPE_UNUSED: + break; + + case ES_THING_TYPE_LADDER: + + FACET_draw_ns_ladder( + et->x1, + et->z1, + et->x2, + et->z2, + et->height); + + break; + + case ES_THING_TYPE_PRIM: + + MESH_draw_poly( + et->prim, + et->x, + et->y, + et->z, + et->yaw, 0, 0, + NULL,0xff,0); + + break; + + default: + ASSERT(0); + break; + } + } + + if (*mouse_over_valid) + { + // + // Highlight the square the mouse is over. + // + + AENG_e_draw_3d_mapwho_y( + *mouse_over_x >> 8, + *mouse_over_y, + *mouse_over_z >> 8); + + if (draw_prim_at_mouse) + { + MESH_draw_poly( + prim_object, + *mouse_over_x & ~0xff, + *mouse_over_y, + *mouse_over_z & ~0xff, + prim_yaw, 0, 0, + NULL,0xff,0); + } + } + + POLY_frame_draw(TRUE,TRUE); + + return; +} + +#endif + +#endif //#ifndef TARGET_DC + + +// +// Draws text at the given point. +// + +void AENG_world_text( + SLONG x, + SLONG y, + SLONG z, + UBYTE red, + UBYTE blue, + UBYTE green, + UBYTE shadowed_or_not, + CBYTE *fmt, ...) +{ + POLY_Point pp; + +// return; + + POLY_transform( + float(x), + float(y), + float(z), + &pp); + + if (pp.IsValid()) + { + // + // Work out the real message. + // + + CBYTE message[FONT_MAX_LENGTH]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + // + // Add the message. + // + + FONT_buffer_add( + pp.X, + pp.Y, + red, + green, + blue, + shadowed_or_not, + message); + } +} + + + + + + +#ifndef TARGET_DC +//--------------------------------------------------------------- +// GUY. +//--------------------------------------------------------------- + +ULONG AENG_waypoint_draw( + SLONG mx, + SLONG my, + SLONG lx, + SLONG ly, + SLONG lz, + ULONG colour, + UBYTE highlight) +{ + ULONG ans = 0; + +// SLONG h1 = PAP_calc_map_height_at(lx, lz); + SLONG h2 = ly; + + POLY_frame_init(FALSE, FALSE); + + // + // Draw a single sphere. + // + + if (INDOORS_INDEX) + SHAPE_alpha_sphere( + lx, + h2, + lz, + 30 + (highlight >> 4), + colour, + 0xff000000); + else + SHAPE_sphere( + lx, + h2, + lz, + 30 + (highlight >> 4), + colour); + + POLY_frame_draw(FALSE, FALSE); + + // + // Was it over the mouse? + // + + SLONG dx; + SLONG dy; + SLONG dist; + + SLONG sx; + SLONG sy; + SLONG swidth; + + if (POLY_get_sphere_circle( + float(lx), + float(h2), + float(lz), + (float)(30 + (highlight >> 4)), + &sx, + &sy, + &swidth)) + { + dx = abs(sx - mx); + dy = abs(sy - my); + + dist = QDIST2(dx,dy); + + if (dist < swidth * 2) + { + ans |= AENG_MOUSE_OVER_WAYPOINT; + } + } + + return ans; +} + +//--------------------------------------------------------------- + +ULONG AENG_rad_trigger_draw( + SLONG mx, + SLONG my, + SLONG lx, + SLONG ly, + SLONG lz, + ULONG rad, + ULONG colour, + UBYTE highlight) +{ + ULONG ans = 0; + + SLONG h1 = PAP_calc_map_height_at(lx, lz); + SLONG h2 = ly; + + POLY_frame_init(FALSE, FALSE); + + // + // Draw a single sphere. + // +/* + SHAPE_sphere( + lx, + h1, + lz, + 30 + (highlight >> 4), + colour); +*/ + + SHAPE_alpha_sphere( + lx, + h2, + lz, + rad, + colour, + 0x88000000); + + POLY_frame_draw(FALSE, FALSE); + + // + // Was it over the mouse? + // + + SLONG dx; + SLONG dy; + SLONG dist; + + SLONG sx; + SLONG sy; + SLONG swidth; + + if (POLY_get_sphere_circle( + float(lx), + float(h1), + float(lz), + (float)(30 + (highlight >> 4)), + &sx, + &sy, + &swidth)) + { + dx = abs(sx - mx); + dy = abs(sy - my); + + dist = QDIST2(dx,dy); + + if (dist < swidth * 2) + { + ans |= AENG_MOUSE_OVER_WAYPOINT; + } + } + + return ans; +} + + +//--------------------------------------------------------------- +// CANIS. +//--------------------------------------------------------------- + + +void AENG_groundsquare_draw( + SLONG lx, + SLONG ly, + SLONG lz, + ULONG colour, + UBYTE polyinit) +{ + POLY_Point pp[4]; + POLY_Point *quad[4]; + SLONG x,y,z,id,diff; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + +// y = PAP_calc_map_height_at(lx>>8,lz>>8)+ly; + POLY_transform(lx ,ly,lz ,&pp[0]); + +// y = PAP_calc_map_height_at((lx>>8)+1,lz>>8)+ly; + POLY_transform(lx+256,ly,lz ,&pp[1]); + +// y = PAP_calc_map_height_at(lx>>8,(lz>>8)+1)+ly; + POLY_transform(lx ,ly,lz+256 ,&pp[2]); + +// y = PAP_calc_map_height_at((lx>>8)+1,(lz>>8)+1)+ly; + POLY_transform(lx+256,ly,lz+256 ,&pp[3]); + + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xFF000000; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=colour; + + if (polyinit & 1) POLY_frame_init(FALSE, FALSE); + + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid() && pp[3].MaybeValid()) + { + POLY_add_quad(quad,POLY_PAGE_ALPHA,FALSE); + } + + if (polyinit & 2) POLY_frame_draw(FALSE, FALSE); +} + +#endif //#ifndef TARGET_DC + + +//--------------------------------------------------------------- + +UBYTE AENG_transparent_warehouses; + +void AENG_clear_viewport() +{ + // + // Clear screen... + // + + if (INDOORS_INDEX||(GAME_FLAGS & GF_SEWERS) || (GAME_FLAGS & GF_INDOORS)) + { + SET_BLACK_BACKGROUND; + CLEAR_VIEWPORT; + } + else + { + if (draw_3d) + { + SLONG white = NIGHT_sky_colour.red + NIGHT_sky_colour.green + NIGHT_sky_colour.blue; + + white /= 3; + + the_display.SetUserColour( + white, + white, + white); + } + else + { + if(fade_black) + { + the_display.SetUserColour(0,0,0); + } + else + { + the_display.SetUserColour( + NIGHT_sky_colour.red, + NIGHT_sky_colour.green, + NIGHT_sky_colour.blue); + + } + } + + the_display.SetUserBackground(); + the_display.ClearViewport(); + +#if 0 && USE_TOMS_ENGINE_PLEASE_BOB + // Haha! Nasty kludge! + the_display.lp_D3D_Viewport->Clear2( + 1, + &(the_display.ViewportRect), + D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + 0xff806040, + 1.0f, + 0); +#endif + } + + BreakTime("Cleared Viewport"); +} + + +SLONG AENG_drawing_a_warehouse; + + + +ULONG AENG_draw_time; +ULONG AENG_poly_add_quad_time; + + + +void AENG_draw(SLONG draw_3d) +{ + ULONG start_rdtsc = AENG_rdtsc(); + + AENG_poly_add_quad_time = 0; + + + +#ifndef TARGET_DC + if (SOFTWARE) + { + // + // Leave dirt as it is. Turn everything else off. + // + + AENG_detail_crinkles = FALSE; + AENG_detail_stars = FALSE; + AENG_detail_shadows = FALSE; + AENG_detail_moon_reflection = FALSE; + AENG_detail_people_reflection = FALSE; + AENG_detail_puddles = FALSE; + AENG_detail_mist = FALSE; + AENG_detail_rain = FALSE; + AENG_detail_skyline = FALSE; + AENG_detail_filter = FALSE; + } +#endif //#ifndef TARGET_DC + + /* + + if (Keys[KB_PPOINT]) + { + Keys[KB_PPOINT] = 0; + + sw_hack ^= TRUE; + + if (sw_hack) + { + SW_reload_textures(); + + NIGHT_amb_red >>= 1; + NIGHT_amb_green >>= 1; + NIGHT_amb_blue >>= 1; + } + else + { + NIGHT_amb_red <<= 1; + NIGHT_amb_green <<= 1; + NIGHT_amb_blue <<= 1; + } + + NIGHT_Colour amb_colour; + + amb_colour.red = NIGHT_amb_red; + amb_colour.green = NIGHT_amb_green; + amb_colour.blue = NIGHT_amb_blue; + + NIGHT_get_d3d_colour( + amb_colour, + &NIGHT_amb_d3d_colour, + &NIGHT_amb_d3d_specular); + + NIGHT_cache_recalc(); + NIGHT_dfcache_recalc(); + NIGHT_generate_walkable_lighting(); + } + + */ + + SLONG i; + SLONG warehouse; + + FC_Cam *fc; + +#if 0 + // set CurDrawDistance + CurDrawDistance = FC_cam[1].focus ? 16 : NormalDrawDistance; +#endif + +#ifndef TARGET_DC + if (SOFTWARE) + { + CurDrawDistance = 16; + } +#endif + + + +#ifdef TARGET_DC + fiddle_draw_distance_DC(); +#endif + + +/* + if (Keys[KB_RBRACE]) + { + Keys[KB_RBRACE] = 0; + + AENG_transparent_warehouses ^= 1; + } +*/ + + AENG_drawing_a_warehouse = FALSE; + + // + // Update stuff. + // + +//d AENG_movie_update(); +#ifndef TARGET_DC + move_clouds(); +#endif + POLY_set_wibble(62, 137, 17, 178, 20, 25); + +#ifndef TARGET_DC + if (sw_hack) + { + SLONG width = MIN(RealDisplayWidth, SW_MAX_WIDTH); + SLONG height = MIN(RealDisplayHeight, SW_MAX_HEIGHT); + + SW_init(width, height); + } +#endif + + AENG_clear_viewport(); + + // + // reclaim vertex buffers + // + + TheVPool->ReclaimBuffers(); + + // + // Put in the dynamic lighting. + // + + NIGHT_dlight_squares_up(); + + POLY_colour_restrict = 0; + POLY_force_additive_alpha = FALSE; + + // + // Mark all NIGHT cache squares for deletion. + // + + AENG_mark_night_squares_as_deleteme(); + + if (FC_cam[1].focus) + { + // + // Splitscreen mode! + // + + SUPERMAP_counter_increase(0); + SUPERMAP_counter_increase(1); + + for (i = 0; i < FC_MAX_CAMS; i++) + { + fc = &FC_cam[i]; + + AENG_lens = fc->lens * 1.5F * (1.0F / float(65536.0F)); + + AENG_set_camera_radians( + fc->x >> 8, + fc->y >> 8, + fc->z >> 8, + float(fc->yaw) * (2.0F * PI / (2048.0F * 256.0F)), + float(fc->pitch) * (2.0F * PI / (2048.0F * 256.0F)), + float(fc->roll) * (2.0F * PI / (2048.0F * 256.0F)), + (i == 0) ? POLY_SPLITSCREEN_TOP : POLY_SPLITSCREEN_BOTTOM); + + AENG_cur_fc_cam = i; + + if (fc->focus->Class == CLASS_PERSON && + fc->focus->Genus.Person->Ware) + { + AENG_ensure_appropriate_caching(TRUE); + AENG_draw_warehouse(); + } + else + { + AENG_ensure_appropriate_caching(FALSE); + AENG_draw_city(); + } + } + + AENG_get_rid_of_deleteme_squares(); + AENG_get_rid_of_unused_dfcache_lighting(TRUE); + } + else + { + fc = &FC_cam[0]; + + SUPERMAP_counter_increase(0); + + // + // Not splitscreen. We might have to use the cutscene camera. + // + + SLONG old_cam_x = fc->x; + SLONG old_cam_y = fc->y; + SLONG old_cam_z = fc->z; + SLONG old_cam_yaw = fc->yaw; + SLONG old_cam_pitch = fc->pitch; + SLONG old_cam_roll = fc->roll; + SLONG old_cam_lens = fc->lens; + + // + // If there is a cut-scene camera... + // + + if (EWAY_grab_camera( + &fc->x, + &fc->y, + &fc->z, + &fc->yaw, + &fc->pitch, + &fc->roll, + &fc->lens)) + { + warehouse = EWAY_camera_warehouse(); + } + else + { + warehouse = (fc->focus->Class == CLASS_PERSON && fc->focus->Genus.Person->Ware); + } + +extern MFFileHandle playback_file; +extern MFFileHandle verifier_file; + + if (GAME_STATE & GS_PLAYBACK) + { + FileRead(playback_file, &fc->x, sizeof(fc->x)); + FileRead(playback_file, &fc->y, sizeof(fc->y)); + FileRead(playback_file, &fc->z, sizeof(fc->z)); + FileRead(playback_file, &fc->yaw, sizeof(fc->yaw)); + FileRead(playback_file, &fc->pitch, sizeof(fc->pitch)); + FileRead(playback_file, &fc->roll, sizeof(fc->roll)); + FileRead(playback_file, &fc->lens, sizeof(fc->lens)); + + if (verifier_file) + { +extern void check_thing_data(); + check_thing_data(); + } + } + else if (GAME_STATE & GS_RECORD) + { + FileWrite(playback_file, &fc->x, sizeof(fc->x)); + FileWrite(playback_file, &fc->y, sizeof(fc->y)); + FileWrite(playback_file, &fc->z, sizeof(fc->z)); + FileWrite(playback_file, &fc->yaw, sizeof(fc->yaw)); + FileWrite(playback_file, &fc->pitch, sizeof(fc->pitch)); + FileWrite(playback_file, &fc->roll, sizeof(fc->roll)); + FileWrite(playback_file, &fc->lens, sizeof(fc->lens)); + + if (verifier_file) + { +extern void store_thing_data(); + store_thing_data(); + } + } + + AENG_lens = fc->lens * (1.0F / float(65536.0F)); + + AENG_set_camera_radians( + fc->x >> 8, + fc->y >> 8, + fc->z >> 8, + float(fc->yaw ) * (2.0F * PI / (2048.0F * 256.0F)), + float(fc->pitch) * (2.0F * PI / (2048.0F * 256.0F)), + float(fc->roll ) * (2.0F * PI / (2048.0F * 256.0F)), + POLY_SPLITSCREEN_NONE); + + AENG_cur_fc_cam = 0; + + if (warehouse) + { + AENG_drawing_a_warehouse = TRUE; + + AENG_ensure_appropriate_caching(TRUE); + AENG_draw_warehouse(); + } + else + { + AENG_ensure_appropriate_caching(FALSE); +// if(ShiftFlag) + AENG_draw_city(); + + if (AENG_transparent_warehouses) + { + SUPERMAP_counter_increase(0); + + AENG_ensure_appropriate_caching(TRUE); + AENG_draw_warehouse(); + } + } + + AENG_get_rid_of_deleteme_squares(); + AENG_get_rid_of_unused_dfcache_lighting(FALSE); + + // + // Restore the old camera. + // + + fc->x = old_cam_x; + fc->y = old_cam_y; + fc->z = old_cam_z; + fc->yaw = old_cam_yaw; + fc->pitch = old_cam_pitch; + fc->roll = old_cam_roll; + fc->lens = old_cam_lens; + } + + /* + + if (draw_3d) + { + // + // How far apart are our eyes!? + // + + static float eyes_apart = 10.0F; + + if (Keys[KB_6]) + { + if (ShiftFlag) + { + eyes_apart -= 1.0F; + } + else + { + eyes_apart += 1.0F; + } + } + + float cam_x = AENG_cam_x; + float cam_y = AENG_cam_y; + float cam_z = AENG_cam_z; + float cam_yaw = AENG_cam_yaw; + float cam_pitch = AENG_cam_pitch; + float cam_roll = AENG_cam_roll; + float cam_matrix[9]; + + MATRIX_calc( + cam_matrix, + cam_yaw, + cam_pitch, + cam_roll); + + // + // Left eye. + // + + if (!ControlFlag) + { + AENG_set_camera_radians( + SLONG(cam_x + cam_matrix[0] * eyes_apart), + SLONG(cam_y + cam_matrix[1] * eyes_apart), + SLONG(cam_z + cam_matrix[2] * eyes_apart), + cam_yaw, + cam_pitch, + cam_roll); + + POLY_colour_restrict = 0x0000ffff; // No green or blue + POLY_force_additive_alpha = FALSE; + + AENG_draw_city(); + + // + // Clear just the z-buffer. + // + + HRESULT res = the_display.lp_D3D_Viewport->Clear(1, &the_display.ViewportRect, D3DCLEAR_ZBUFFER); + + ASSERT(res == DD_OK); + } + + if (!ShiftFlag) + { + // + // Right eye. + // + + AENG_set_camera_radians( + SLONG(cam_x - cam_matrix[0] * eyes_apart), + SLONG(cam_y - cam_matrix[1] * eyes_apart), + SLONG(cam_z - cam_matrix[2] * eyes_apart), + cam_yaw, + cam_pitch, + cam_roll); + + POLY_colour_restrict = 0x00ff0000; // No red + POLY_force_additive_alpha = TRUE; + + GAME_TURN += 1; // So the buildings are drawn again... + + AENG_draw_city(); + } + } + else + { + if (GAME_FLAGS & GF_INDOORS) + { +// AENG_draw_inside(); + } + else + if (GAME_FLAGS & GF_SEWERS) + { + AENG_draw_ns(); + } + else + if (WARE_in) + { + AENG_draw_warehouse(); + } + else + { + AENG_draw_city(); + } + } + + */ + + // + // Take out the dynamic lighting. + // + + NIGHT_dlight_squares_down(); + + POLY_colour_restrict = 0; + POLY_force_additive_alpha = FALSE; + + //SPONG +//#if !USE_TOMS_ENGINE_PLEASE_BOB + // + // Do it here so that AENG_world_line works during the game. + // + +#ifndef TARGET_DC + POLY_frame_init(FALSE, FALSE); +#endif +//#endif + + + ULONG end_rdtsc = AENG_rdtsc(); + + if (end_rdtsc > start_rdtsc) + { + // + // The counter hasn't wrapped... + // + + AENG_draw_time = end_rdtsc - start_rdtsc; + } +} + + + + + + + + +// read detail levels from file + +void AENG_read_detail_levels() +{ +#ifdef TARGET_DC + // Most things turned on, apart from the things that won't work. + //AENG_estimate_detail_levels = ENV_get_value_number("estimate_detail_levels", 0, "Render"); + + AENG_detail_stars = ENV_get_value_number("detail_stars", 1, "Render"); + AENG_detail_shadows = ENV_get_value_number("detail_shadows", 0, "Render"); + AENG_detail_moon_reflection = ENV_get_value_number("detail_moon_reflection", 0, "Render"); + AENG_detail_people_reflection = ENV_get_value_number("detail_people_reflection", 0, "Render"); + AENG_detail_puddles = ENV_get_value_number("detail_puddles", 0, "Render"); + AENG_detail_dirt = ENV_get_value_number("detail_dirt", 1, "Render"); + AENG_detail_mist = ENV_get_value_number("detail_mist", 1, "Render"); + AENG_detail_rain = ENV_get_value_number("detail_rain", 1, "Render"); + AENG_detail_skyline = ENV_get_value_number("detail_skyline", 1, "Render"); + AENG_detail_filter = ENV_get_value_number("detail_filter", 1, "Render"); + AENG_detail_perspective = ENV_get_value_number("detail_perspective", 1, "Render"); + AENG_detail_crinkles = ENV_get_value_number("detail_crinkles", 0, "Render"); +#ifndef DEBUG + // Release build - doesn't include the things that don't work yet! + AENG_detail_stars = ENV_get_value_number("detail_stars", 1, "Render"); + AENG_detail_shadows = ENV_get_value_number("detail_shadows", 0, "Render"); + AENG_detail_moon_reflection = ENV_get_value_number("detail_moon_reflection", 0, "Render"); + AENG_detail_people_reflection = ENV_get_value_number("detail_people_reflection", 0, "Render"); + AENG_detail_puddles = ENV_get_value_number("detail_puddles", 1, "Render"); + AENG_detail_dirt = ENV_get_value_number("detail_dirt", 1, "Render"); + AENG_detail_mist = ENV_get_value_number("detail_mist", 1, "Render"); + AENG_detail_rain = ENV_get_value_number("detail_rain", 1, "Render"); + AENG_detail_skyline = ENV_get_value_number("detail_skyline", 1, "Render"); + AENG_detail_filter = ENV_get_value_number("detail_filter", 1, "Render"); + AENG_detail_perspective = ENV_get_value_number("detail_perspective", 1, "Render"); + AENG_detail_crinkles = ENV_get_value_number("detail_crinkles", 0, "Render"); +#endif +#else + AENG_estimate_detail_levels = ENV_get_value_number("estimate_detail_levels", 1, "Render"); + + AENG_detail_stars = ENV_get_value_number("detail_stars", 1, "Render"); + AENG_detail_shadows = ENV_get_value_number("detail_shadows", 1, "Render"); + AENG_detail_moon_reflection = ENV_get_value_number("detail_moon_reflection", 1, "Render"); + AENG_detail_people_reflection = ENV_get_value_number("detail_people_reflection", 1, "Render"); + AENG_detail_puddles = ENV_get_value_number("detail_puddles", 1, "Render"); + AENG_detail_dirt = ENV_get_value_number("detail_dirt", 1, "Render"); + AENG_detail_mist = ENV_get_value_number("detail_mist", 1, "Render"); + AENG_detail_rain = ENV_get_value_number("detail_rain", 1, "Render"); + AENG_detail_skyline = ENV_get_value_number("detail_skyline", 1, "Render"); + AENG_detail_filter = ENV_get_value_number("detail_filter", 1, "Render"); + AENG_detail_perspective = ENV_get_value_number("detail_perspective", 1, "Render"); + AENG_detail_crinkles = ENV_get_value_number("detail_crinkles", 1, "Render"); +#endif +} + + + + + +// +// Draws a small inside of the warehouse. +// + +void AENG_draw_box_around_recessed_door(DFacet *df, SLONG inside_out) +{ + SLONG i; + + SLONG x; + SLONG z; + + SLONG dx; + SLONG dz; + + SLONG mx; + SLONG mz; + + SLONG page; + SLONG upto; + + ULONG sky_colour; + ULONG sky_specular; + + SLONG col_page; + SLONG specular; + +#ifdef TARGET_DC + POLY_flush_local_rot(); +#endif + + NIGHT_get_d3d_colour( + NIGHT_sky_colour, + &sky_colour, + &sky_specular); + + sky_specular |= 0xff000000; + + PAP_Hi *ph; + + float wx; + float wy; + float wz; + + #define MAX_DOOR_LENGTH 8 + + POLY_Point lower[MAX_DOOR_LENGTH][2]; + POLY_Point upper[MAX_DOOR_LENGTH][2]; + + POLY_Point *pp; + POLY_Point *quad[4]; + + if (inside_out) + { + SWAP(df->x[0], df->x[1]); + SWAP(df->z[0], df->z[1]); + } + + if (sw_hack) + { + col_page = POLY_PAGE_COLOUR; + specular = 0xee000000; + } + else + { + col_page = POLY_PAGE_COLOUR_WITH_FOG; + specular = 0xff000000; + } + + // + // Create the points. + // + + x = df->x[0]; + z = df->z[0]; + + dx = df->x[1] - df->x[0]; + dz = df->z[1] - df->z[0]; + + dx = SIGN(dx); + dz = SIGN(dz); + + upto = 0; + + while(1) + { + ASSERT(WITHIN(upto, 0, MAX_DOOR_LENGTH - 1)); + + for (i = 0; i < 4; i++) + { + wx = float(x << 8); + wz = float(z << 8); + wy = float(df->Y[0]); + + if (i & 1) + { + // + // One block inside the warehouse. + // + + wx += float(-dz << 8); + wz += float(+dx << 8); + } + + if (i & 2) + { + // + // The upper level. + // + + pp = &upper[upto][i & 1]; + + wy += 256.0F; + } + else + { + // + // The lower level. + // + + pp = &lower[upto][i & 1]; + } + + POLY_transform( + wx, + wy, + wz, + pp); + + if (i == 0) + { + if (inside_out) + { + pp->colour = 0xffaaaaaa; + pp->specular = 0xff000000; + } + else + { + pp->colour = 0xffaaaaaa; + pp->specular = 0xff000000; + } + } + else + { + if (inside_out) + { + pp->colour = 0xffffffff; + pp->specular = 0x01000000; // Completely fogged out... + } + else + { + pp->colour = 0xff000000; + pp->specular = 0xff000000; + } + } + + pp->u = 0.0F; + pp->v = 0.0F; + } + + upto += 1; + + if (x == df->x[1] && z == df->z[1]) + { + break; + } + + x += dx; + z += dz; + } + + ASSERT(upto >= 2); + + // + // The faces on the floor and the ceiling. + // + + x = df->x[0]; + z = df->z[0]; + + for (i = 0; i < upto - 1; i++) + { + mx = (x << 8) + dx - dz >> 8; + mz = (z << 8) + dz + dx >> 8; + + // + // The floor. + // + + ph = &PAP_2HI(mx,mz); + + quad[0] = &lower[i + 0][0]; + quad[1] = &lower[i + 0][1]; + quad[2] = &lower[i + 1][0]; + quad[3] = &lower[i + 1][1]; + + if (POLY_valid_quad(quad)) + { + TEXTURE_get_minitexturebits_uvs( + ph->Texture, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + + POLY_add_quad(quad, page, FALSE); + } + + // + // The ceiling. + // + + quad[0] = &upper[i + 0][0]; + quad[1] = &upper[i + 0][1]; + quad[2] = &upper[i + 1][0]; + quad[3] = &upper[i + 1][1]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, col_page, FALSE); + } + + // + // The back wall. + // + + quad[0] = &lower[i + 0][1]; + quad[1] = &lower[i + 1][1]; + quad[2] = &upper[i + 0][1]; + quad[3] = &upper[i + 1][1]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, col_page, FALSE); + } + + x += dx; + z += dz; + } + + // + // Create the two faces at each end. + // + + quad[0] = &upper[0][0]; + quad[2] = &upper[0][1]; + quad[1] = &lower[0][0]; + quad[3] = &lower[0][1]; + + if (POLY_valid_quad(quad)) + { + if (!inside_out) + { + quad[0]->colour = 0xff000000; + quad[0]->specular = 0xff000000; + quad[1]->colour = 0xff000000; + quad[1]->specular = 0xff000000; + } + + POLY_add_quad(quad, col_page, TRUE); + } + + quad[0] = &upper[upto - 1][0]; + quad[1] = &upper[upto - 1][1]; + quad[2] = &lower[upto - 1][0]; + quad[3] = &lower[upto - 1][1]; + + if (POLY_valid_quad(quad)) + { + if (!inside_out) + { + quad[0]->colour = 0xff000000; + quad[0]->specular = 0xff000000; + quad[2]->colour = 0xff000000; + quad[2]->specular = 0xff000000; + } + + POLY_add_quad(quad, col_page, TRUE); + } + + if (inside_out) + { + SWAP(df->x[0], df->x[1]); + SWAP(df->z[0], df->z[1]); + } +} + + + + +// +// Get rid of any unused dfcache lighting. +// + +void AENG_get_rid_of_unused_dfcache_lighting(SLONG splitscreen) // Splitscreen = TRUE or FALSE +{ + SLONG dfcache; + SLONG next; + + NIGHT_Dfcache *ndf; + + for (dfcache = NIGHT_dfcache_used; dfcache; dfcache = next) + { + ASSERT(WITHIN(dfcache, 1, NIGHT_MAX_DFCACHES - 1)); + + ndf = &NIGHT_dfcache[dfcache]; + next = ndf->next; + + // + // Was this facet drawn this gameturn? If it wasn't then + // free up the cached lighting info for it. + // + + ASSERT(WITHIN(ndf->dfacet, 1, next_dfacet - 1)); + ASSERT(dfacets[ndf->dfacet].Dfcache == dfcache); + + if (dfacets[ndf->dfacet].Counter[0] != SUPERMAP_counter[0]) + { + if (splitscreen) + { + // + // Might have been drawn from the second camera. + // + + if (dfacets[ndf->dfacet].Counter[1] == SUPERMAP_counter[1]) + { + // + // It was drawn from the second camera! Don't get rid of it. + // + + continue; + } + } + + // + // Free up the lighting info. + // + + dfacets[ndf->dfacet].Dfcache = 0; + + NIGHT_dfcache_destroy(dfcache); + } + } +} + + +void AENG_draw_inside_floor(UWORD inside_index,UWORD inside_room,UBYTE fade) +{ + SLONG x,z; + SLONG page; + + float world_x; + float world_y,floor_y,roof_y; + float world_z; + + POLY_Point pp[4]; +#ifndef TARGET_DC + MapElement *me; +#endif + + PAP_Lo *pl; + PAP_Hi *ph; + + POLY_Point *quad[4]; + + struct InsideStorey *p_inside; + SLONG in_width; + UBYTE *in_block; + SLONG min_z,max_z; + SLONG c0; + SLONG floor_type; + SLONG do_light; + + if(inside_index==light_inside) + do_light=1; + else + do_light=0; + + + // + // draw the internal walls + // +extern void draw_insides(SLONG indoor_index,SLONG room,UBYTE fade); + draw_insides(inside_index,inside_room,fade); + + + p_inside=&inside_storeys[inside_index]; + + floor_type=p_inside->TexType; + +// MSG_add("in room %d\n",INDOORS_ROOM); + + + floor_y=(float)p_inside->StoreyY; + roof_y=floor_y+256.0f; + + min_z=MAX(NGAMUT_point_zmin,p_inside->MinZ); + max_z=MIN(NGAMUT_point_zmax,p_inside->MaxZ); + + in_width=p_inside->MaxX-p_inside->MinX; + + in_block=&inside_block[p_inside->InsideBlock]; + + for(c0=0;c0<4;c0++) + { + pp[c0].colour=0xffffff; + pp[c0].specular=0xff000000; + } + + quad[0]=&pp[0]; + quad[1]=&pp[1]; + quad[2]=&pp[2]; + quad[3]=&pp[3]; + + quad[0]->u=0.0; + quad[0]->v=0.0; + quad[1]->u=1.0; + quad[1]->v=0.0; + quad[2]->u=0.0; + quad[2]->v=1.0; + quad[3]->u=1.0; + quad[3]->v=1.0; + + + for (z = min_z; z < max_z; z++) + { + SLONG min_x,max_x; + float face_y; + SLONG col; + min_x=MAX(NGAMUT_point_gamut[z].xmin,p_inside->MinX); + max_x=MIN(NGAMUT_point_gamut[z].xmax,p_inside->MaxX); + + for (x = min_x;xMinX)+(z-p_inside->MinZ)*in_width]&(0xf|0x80|0x40); + if(!(room_id&0xc0)) + { + if(1||(room_id&0xf)==inside_room) + { + face_y=floor_y; + col=0xffffff; + } + else + { + face_y=roof_y; + col=0; + + } + + col=col|( (fade&255)<<24); + if(room_id) + { + + world_x = x * 256.0F; + world_z = z * 256.0F; + POLY_transform(world_x, face_y, world_z, &pp[0]); + + if(do_light) + { + px = x >> 2; + pz = z >> 2; + + + ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1)); + + square = NIGHT_cache[px][pz]; + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + if(!square) + return; + nq = &NIGHT_square[square]; + + NIGHT_get_d3d_colour( + nq->colour[(x&3) + (z&3) * PAP_BLOCKS], + &pp->colour, + &pp->specular); + pp->colour|=fade<<24; + } + else + { + pp->colour=0x7f7f7f|(fade<<24); + pp->specular=0xff000000; + } + + + world_x = (x+1) * 256.0F; + world_z = z * 256.0F; + POLY_transform(world_x, face_y, world_z, &pp[1]); + + if(do_light) + { + if( (x+1)>>2!=px) + { + px = (x+1) >> 2; + // pz = z >> 2; + + + ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1)); + + square = NIGHT_cache[px][pz]; + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + if(!square) + return; + nq = &NIGHT_square[square]; + } + NIGHT_get_d3d_colour( + nq->colour[((x+1)&3) + (z&3) * PAP_BLOCKS], + &(pp[1].colour), + &(pp[1].specular)); + + pp[1].colour|=fade<<24; + } + else + { + pp[1].colour=0x7f7f7f|(fade<<24); + pp[1].specular=0xff000000; + } + + + + + + world_x = x * 256.0F; + world_z = (z+1) * 256.0F; + POLY_transform(world_x, face_y, world_z, &pp[2]); + + + if(do_light) + { + if( (z+1)>>2!=pz || (x>>2)!=px) + { + px = x >> 2; + pz = (z+1) >> 2; + + + ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1)); + + square = NIGHT_cache[px][pz]; + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + if(!square) + return; + nq = &NIGHT_square[square]; + } + + NIGHT_get_d3d_colour( + nq->colour[(x&3) + ((z+1)&3) * PAP_BLOCKS], + &(pp[2].colour), + &(pp[2].specular)); + pp[2].colour|=fade<<24; + } + else + { + pp[2].colour=0x7f7f7f|(fade<<24); + pp[2].specular=0xff000000; + } + + + + + world_x = (x+1) * 256.0F; + world_z = (z+1) * 256.0F; + POLY_transform(world_x, face_y, world_z, &pp[3]); + + if(do_light) + { + if( (x+1)>>2!=px || (z+1)>>2!=pz) + { + px = (x+1) >> 2; + pz = (z+1) >> 2; + + + ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1)); + ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1)); + + square = NIGHT_cache[px][pz]; + if(!square) + return; + ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1)); + ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED); + nq = &NIGHT_square[square]; + } + + NIGHT_get_d3d_colour( + nq->colour[((x+1)&3) + ((z+1)&3) * PAP_BLOCKS], + &(pp[3].colour), + &(pp[3].specular)); + pp[3].colour|=fade<<24; + } + else + { + pp[3].colour=0x7f7f7f|(fade<<24); + pp[3].specular=0xff000000; + } + + + + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid() && pp[3].MaybeValid()) + { + pp[0].colour=col; + pp[1].colour=col; + pp[2].colour=col; + pp[3].colour=col; + page=inside_tex[floor_type][room_id-1]+START_PAGE_FOR_FLOOR*64; // temp + POLY_add_quad(quad, page, FALSE); + } + } + } + } + } + } +} + + + diff --git a/fallen/DDEngine/Source/build.cpp b/fallen/DDEngine/Source/build.cpp new file mode 100644 index 0000000..c161b28 --- /dev/null +++ b/fallen/DDEngine/Source/build.cpp @@ -0,0 +1,528 @@ +// +// Draws buildings. +// + +#include "game.h" +#include "aeng.h" +#include "poly.h" +#include "light.h" +#include "build.h" +#include "memory.h" + +void BUILD_draw(Thing *p_thing) +{ + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + LIGHT_Colour pcol; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + SLONG page; + SLONG backface_cull; + ULONG shadow; + ULONG face_colour; + ULONG face_specular; + + float bx = float(p_thing->WorldPos.X >> 8); + float by = float(p_thing->WorldPos.Y >> 8); + float bz = float(p_thing->WorldPos.Z >> 8); + + SLONG bo_index; + SLONG bf_index; + + BuildingFacet *bf; + BuildingObject *bo; + + bo_index = p_thing->Index; + bo = &building_objects[bo_index]; + + // + // Points out of the ambient light. + // + + shadow = + ((LIGHT_amb_colour.red >> 1) << 16) | + ((LIGHT_amb_colour.green >> 1) << 8) | + ((LIGHT_amb_colour.blue >> 1) << 0); + + // + // The ambient light colour. + // + + ULONG colour; + ULONG specular; + + LIGHT_get_d3d_colour( + LIGHT_amb_colour, + &colour, + &specular); + + // + // ONLY TRIANGLES USE THESE VALUES. MAKE THEM STAND OUT. + // + + colour = 0xffffffff; + specular = 0xffffffff; + + // + // Draw each facet. + // + + bf_index = bo->FacetHead; + + while(bf_index) + { + bf = &building_facets[bf_index]; + + // + // Rotate all the points. + // + + sp = bf->StartPoint; + ep = bf->EndPoint; + + POLY_buffer_upto = 0; + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform( + AENG_dx_prim_points[i].X + bx, + AENG_dx_prim_points[i].Y + by, + AENG_dx_prim_points[i].Z + bz, + pp); + + if (pp->MaybeValid()) + { + LIGHT_get_d3d_colour( + LIGHT_building_point[i], + &pp->colour, + &pp->specular); + + POLY_fadeout_point(pp); + } + } + + // + // Draw all the quads. + // + + for (i = bf->StartFace4; i < bf->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + // + // Should this poly be backface culled? + // + + backface_cull = !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED); + + // + // Texture the quad. + // + + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + if (p_f4->FaceFlags & (FACE_FLAG_SHADOW_1 | FACE_FLAG_SHADOW_2)) + { + POLY_Point ps[4]; + + // + // Create four darkened points. + // + + ps[0] = *(quad[0]); + ps[1] = *(quad[1]); + ps[2] = *(quad[2]); + ps[3] = *(quad[3]); + + // + // Darken the points. + // + + for (j = 0; j < 4; j++) + { + pcol = LIGHT_building_point[p_f4->Points[j]]; + + pcol.red -= 16; + pcol.green -= 16; + pcol.blue -= 16; + + LIGHT_get_d3d_colour( + pcol, + &ps[j].colour, + &ps[j].specular); + } + + if ((p_f4->FaceFlags & FACE_FLAG_SHADOW_1) && + (p_f4->FaceFlags & FACE_FLAG_SHADOW_2)) + { + quad[0] = &ps[0]; + quad[1] = &ps[1]; + quad[2] = &ps[2]; + quad[3] = &ps[3]; + + POLY_add_quad(quad, page, backface_cull); + } + else + { + if (p_f4->FaceFlags & FACE_FLAG_SHADOW_2) + { + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, backface_cull); + + tri[0] = &ps[1]; + tri[1] = &ps[3]; + tri[2] = &ps[2]; + + POLY_add_triangle(tri, page, backface_cull); + } + else + { + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, backface_cull); + + tri[0] = &ps[0]; + tri[1] = &ps[1]; + tri[2] = &ps[2]; + + POLY_add_triangle(tri, page, backface_cull); + } + } + } + else + { + POLY_add_quad(quad, page, backface_cull); + } + } + } + + // + // Draw all the triangles. + // + + for (i = bf->StartFace3; i < bf->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + // + // Should this poly be backface culled? + // + + backface_cull = !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED); + + // + // Texture the triangle. + // + + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + + POLY_add_triangle(tri, page, backface_cull); + } + } + + bf_index = bf->NextFacet; + } +} + + +void BUILD_draw_inside() +{ + /* + + Thing *p_thing = TO_THING(INDOORS_THING); + + SLONG i; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG page; + + float max_height; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + ULONG amb_colour; + ULONG amb_specular; + + float bx = float(p_thing->WorldPos.X >> 8); + float by = float(p_thing->WorldPos.Y >> 8); + float bz = float(p_thing->WorldPos.Z >> 8); + + SLONG bo_index; + SLONG bf_index; + + BuildingFacet *bf; + BuildingObject *bo; + + bo_index = p_thing->Index; + bo = &building_objects[bo_index]; + + // + // The ambient light colour. + // + + ULONG colour; + ULONG specular; + + LIGHT_get_d3d_colour( + LIGHT_amb_colour, + &colour, + &specular); + + // + // Draw each facet. + // + + bf_index = bo->FacetHead; + + while(bf_index) + { + bf = &building_facets[bf_index]; + + if (bf->FacetFlags & FACET_FLAG_ROOF) + { + max_height = float(INDOORS_HEIGHT_FLOOR + 32); + } + else + { + if (building_list[p_thing->BuildingList].BuildingType == BUILDING_TYPE_WAREHOUSE) + { + max_height = float(INDOORS_HEIGHT_CEILING + 256 + 32); + } + else + { + max_height = float(INDOORS_HEIGHT_CEILING + 32); + } + } + + // + // Rotate all the points. + // + + sp = bf->StartPoint; + ep = bf->EndPoint; + + POLY_buffer_upto = 0; + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + if (AENG_dx_prim_points[i].Y + by <= max_height) + { + POLY_transform( + AENG_dx_prim_points[i].X + bx, + AENG_dx_prim_points[i].Y + by, + AENG_dx_prim_points[i].Z + bz, + pp); + + if (pp->MaybeValid()) + { + pp->colour = colour; + pp->specular = specular; + + POLY_fadeout_point(pp); + } + } + else + { + pp->clip = 0; + } + } + + // + // Draw all the quads. + // + + for (i = bf->StartFace4; i < bf->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + quad[0]->u = float(p_f4->UV[0][0]) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1]) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0]) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1]) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0]) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1]) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0]) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1]) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + POLY_add_quad(quad, page, TRUE); + } + } + + + // + // Draw all the quads. + // + + for (i = bf->StartFace3; i < bf->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + tri[0]->u = float(p_f3->UV[0][0]) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1]) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0]) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1]) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0]) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1]) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + + POLY_add_triangle(tri, page, TRUE); + } + } + + bf_index = bf->NextFacet; + } + + */ +} + + + + + + + diff --git a/fallen/DDEngine/Source/comp.cpp b/fallen/DDEngine/Source/comp.cpp new file mode 100644 index 0000000..db16e3a --- /dev/null +++ b/fallen/DDEngine/Source/comp.cpp @@ -0,0 +1,715 @@ +// +// Movie compression. +// + +#include +#include "comp.h" +#include "ic.h" +#include "tga.h" + + + +// +// COMP_Delta data structures. There are as many pan structures as you need +// followed by at least one COMP_Update structure. If (last) then that +// COMP_Update is the last one. +// + +typedef struct +{ + UBYTE num; + UBYTE pan; + +} COMP_Pan; + +typedef struct +{ + UBYTE x; + UBYTE y; + UBYTE num; + UBYTE last; // TRUE => there are no more update structures. + IC_Packet ip[]; + +} COMP_Update; + + +// +// Memory for a tga. +// + +#ifndef TARGET_DC +TGA_Pixel COMP_tga_data[COMP_TGA_MAX_WIDTH * COMP_TGA_MAX_HEIGHT]; +#endif +TGA_Info COMP_tga_info; + + +// +// Returns the colour of the virtual pixel at the given location where +// x and y go from 0.0 to 1.0F +// + +TGA_Pixel COMP_tga_colour(float x, float y) +{ + TGA_Pixel ans; +#ifdef TARGET_DC + // This has been spoofed to save memory - + // hopefully we won't need it. + ASSERT(FALSE); + return ans; +#else + SLONG px; + SLONG py; + + + px = SLONG(float(COMP_tga_info.width) * x); + py = SLONG(float(COMP_tga_info.height) * y); + + SATURATE(px, 0, COMP_tga_info.width - 1); + SATURATE(py, 0, COMP_tga_info.height - 1); + + ans = COMP_tga_data[px + py * COMP_tga_info.width]; + + return ans; + +#endif +} + + + +SLONG COMP_load(CBYTE *filename, COMP_Frame *cf) +{ +#ifdef TARGET_DC + // This has been spoofed to save memory - + // hopefully we won't need it. + ASSERT(FALSE); + return TRUE; +#else + + SLONG px; + SLONG py; + + SLONG dx; + SLONG dy; + + SLONG r; + SLONG g; + SLONG b; + + TGA_Pixel tp; + + float x; + float y; + + COMP_tga_info = TGA_load( + filename, + COMP_TGA_MAX_WIDTH, + COMP_TGA_MAX_HEIGHT, + COMP_tga_data,-1); + + if (!COMP_tga_info.valid) + { + return FALSE; + } + + // + // Sample the tga to fit into our frame. + // + + #define COMP_SAMPLES_PER_PIXEL 4 + + for (px = 0; px < COMP_SIZE; px++) + for (py = 0; py < COMP_SIZE; py++) + { + r = 0; + g = 0; + b = 0; + + for (dx = 0; dx < COMP_SAMPLES_PER_PIXEL; dx++) + for (dy = 0; dy < COMP_SAMPLES_PER_PIXEL; dy++) + { + x = float((px * COMP_SAMPLES_PER_PIXEL) + dx) * (1.0F / float(COMP_SIZE * COMP_SAMPLES_PER_PIXEL)); + y = float((py * COMP_SAMPLES_PER_PIXEL) + dy) * (1.0F / float(COMP_SIZE * COMP_SAMPLES_PER_PIXEL)); + + tp = COMP_tga_colour(x,y); + + r += tp.red; + g += tp.green; + b += tp.blue; + } + + r /= COMP_SAMPLES_PER_PIXEL * COMP_SAMPLES_PER_PIXEL; + g /= COMP_SAMPLES_PER_PIXEL * COMP_SAMPLES_PER_PIXEL; + b /= COMP_SAMPLES_PER_PIXEL * COMP_SAMPLES_PER_PIXEL; + + cf->p[py][px].red = r; + cf->p[py][px].green = g; + cf->p[py][px].blue = b; + } + + return TRUE; +#endif +} + + + +#ifndef TARGET_DC +// +// Returns the difference between the two squares. The square coordinates +// clamp to be inside the frame. +// + +SLONG COMP_square_error( + COMP_Frame *f1, + SLONG sx1, + SLONG sy1, + COMP_Frame *f2, + SLONG sx2, + SLONG sy2, + SLONG size) +{ + SLONG dx; + SLONG dy; + + SLONG x1; + SLONG y1; + + SLONG x2; + SLONG y2; + + TGA_Pixel *tp1; + TGA_Pixel *tp2; + + SLONG error = 0; + + for (dx = 0; dx < size; dx++) + for (dy = 0; dy < size; dy++) + { + x1 = sx1 + dx; + y1 = sy1 + dy; + + x2 = sx2 + dx; + y2 = sy2 + dy; + + SATURATE(x1, 0, COMP_SIZE - 1); + SATURATE(y1, 0, COMP_SIZE - 1); + + SATURATE(x2, 0, COMP_SIZE - 1); + SATURATE(y2, 0, COMP_SIZE - 1); + + tp1 = &f1->p[y1][x1]; + tp2 = &f2->p[y2][x2]; + + error += abs(tp1->red - tp2->red ); + error += abs(tp1->green - tp2->green); + error += abs(tp1->blue - tp2->blue ); + } + + return error; +} + +// +// Copies one square onto another. +// + +void COMP_square_copy( + COMP_Frame *f1, + SLONG sx1, + SLONG sy1, + COMP_Frame *f2, + SLONG sx2, + SLONG sy2, + SLONG size) +{ + SLONG dx; + SLONG dy; + + SLONG x1; + SLONG y1; + + SLONG x2; + SLONG y2; + + TGA_Pixel *tp1; + TGA_Pixel *tp2; + + for (dx = 0; dx < size; dx++) + for (dy = 0; dy < size; dy++) + { + x1 = sx1 + dx; + y1 = sy1 + dy; + + x2 = sx2 + dx; + y2 = sy2 + dy; + + SATURATE(x1, 0, COMP_SIZE - 1); + SATURATE(y1, 0, COMP_SIZE - 1); + + SATURATE(x2, 0, COMP_SIZE - 1); + SATURATE(y2, 0, COMP_SIZE - 1); + + tp1 = &f1->p[y1][x1]; + tp2 = &f2->p[y2][x2]; + + *tp2 = *tp1; + } +} + + +// +// The compression data. +// + +#define COMP_MAX_DATA (1024 * 16) + +struct +{ + SLONG size; + UBYTE data[COMP_MAX_DATA]; + +} COMP_data; + +COMP_Frame COMP_frame; + +COMP_Delta *COMP_calc(COMP_Frame *f1, COMP_Frame *f2, COMP_Frame *ans) +{ + SLONG i; + + SLONG sx; + SLONG sy; + + SLONG dx; + SLONG dy; + + SLONG sx1; + SLONG sy1; + + SLONG sx2; + SLONG sy2; + + SLONG error; + + SLONG best_error; + SLONG best_dx; + SLONG best_dy; + SLONG best_pan; + + UBYTE pan[COMP_SNUM * COMP_SNUM]; + SLONG pan_upto = 0; + SLONG pan_index; + + UBYTE diff[COMP_SIZE * COMP_SIZE / 16]; + SLONG diff_upto = 0; + + COMP_Pan *cp; + COMP_Update *cu; + IC_Packet *ip; + + SLONG cu_valid; + SLONG cu_num; + + // + // Work out the best pan values to get from frame one to frame two. + // + + #define COMP_MAX_PAN 5 + + for (sx = 0; sx < COMP_SNUM; sx++) + for (sy = 0; sy < COMP_SNUM; sy++) + { + sx2 = sx * COMP_SSIZE; + sy2 = sy * COMP_SSIZE; + + best_error = INFINITY; + best_dx = 0; + best_dy = 0; + + for (dx = -COMP_MAX_PAN; dx <= +COMP_MAX_PAN; dx++) + for (dy = -COMP_MAX_PAN; dy <= +COMP_MAX_PAN; dy++) + { + sx1 = sx2 + dx; + sy1 = sy2 + dy; + + error = COMP_square_error( + f1, sx1, sy1, + f2, sx2, sy2, + COMP_SSIZE); + + if (error < best_error) + { + best_error = error; + best_dx = dx; + best_dy = dy; + + if (best_error == 0) + { + // + // We're not going to get any better than this! + // + + goto found_best_pan; + } + } + } + + found_best_pan:; + + // + // The maximum error per-pixel we can live with. + // + + #define COMP_MAX_ERROR_PER_PIXEL 32 + + if (best_error < (COMP_SSIZE * COMP_SSIZE * COMP_MAX_ERROR_PER_PIXEL)) + { + pan[pan_upto++] = (best_dx + COMP_MAX_PAN) | ((best_dy + COMP_MAX_PAN) << 4); + } + else + { + // + // Mark as undefined. + // + + pan[pan_upto++] = 255; + } + } + + // + // RLE the pan values + // + + cp = (COMP_Pan *) COMP_data.data; + + cp->num = 1; + cp->pan = pan[0]; + + for (i = 1; i < COMP_SNUM * COMP_SNUM; i++) + { + if (pan[i] == cp->pan && cp->num != 255) + { + cp->num += 1; + } + else + { + cp += 1; + + cp->num = 1; + cp->pan = pan[i]; + } + } + + // + // Build the frame from just the pan info. + // + + pan_upto = 0; + + for (sx = 0; sx < COMP_SNUM; sx++) + for (sy = 0; sy < COMP_SNUM; sy++) + { + sx2 = sx * COMP_SSIZE; + sy2 = sy * COMP_SSIZE; + + if (pan[pan_upto] != 255) + { + dx = pan[pan_upto] & 0xf; + dy = pan[pan_upto] >> 4; + + dx -= COMP_MAX_PAN; + dy -= COMP_MAX_PAN; + + sx1 = sx2 + dx; + sy1 = sy2 + dy; + + COMP_square_copy( + f1, sx1, sy1, + ans, sx2, sy2, + COMP_SSIZE); + } + + pan_upto += 1; + } + + // + // Work out which packets we have to store in full. + // + + cu = (COMP_Update *) (cp + 1); + ip = (IC_Packet *) (cp + 1); + cu_valid = FALSE; + cu_num = 0; + + for (sx = 0; sx < COMP_SIZE; sx += 4) + for (sy = 0; sy < COMP_SIZE; sy += 4) + { + pan_index = (sx / COMP_SSIZE) * COMP_SNUM + (sy / COMP_SSIZE); + + if (pan[pan_index] == 255) + { + // + // Always update undefined pans. + // + + error = INFINITY; + } + else + { + error = COMP_square_error( + f1, sx, sy, + f2, sx, sy, + 4); + } + + if (error >= 16 * COMP_MAX_ERROR_PER_PIXEL) + { + cu_num += 1; + + if (cu_valid) + { + // + // Add another packet. + // + + *ip = IC_pack( + (TGA_Pixel *) f2->p, + COMP_SIZE, + COMP_SIZE, + sx, + sy); + + cu->num += 1; + + if (cu->num == 255) + { + // + // We have to start another run! + // + + cu_valid = FALSE; + } + } + else + { + // + // Create a new packet. + // + + cu = (COMP_Update *) ip; + + ASSERT((sx & 0x3) == 0); + ASSERT((sy & 0x3) == 0); + + cu->x = sx; + cu->y = sy; + cu->num = 1; + cu->last = FALSE; + ip = cu->ip; + + *ip = IC_pack( + (TGA_Pixel *) f2->p, + COMP_SIZE, + COMP_SIZE, + sx, + sy); + + cu_valid = TRUE; + } + + // + // Build the frame. + // + + IC_unpack( + *ip, + (TGA_Pixel *) ans->p, + COMP_SIZE, + COMP_SIZE, + sx, + sy); + + ip += 1; + } + else + { + // + // We'll have to start another RLE run next time we find a + // square to update. + // + + cu_valid = FALSE; + } + } + + if (cu_num == 0) + { + // + // Create a dud last packet. + // + + cu->x = 0; + cu->y = 0; + cu->num = 0; + cu->last = 1; + ip = cu->ip; + } + else + { + // + // Mark the last packet as the last one. + // + + cu->last = TRUE; + } + + UBYTE *data_start = COMP_data.data; + UBYTE *data_end = (UBYTE *) ip; + + COMP_data.size = data_end - data_start; + + // + // Done! + // + + return (COMP_Delta *) &COMP_data; +} + + + +void COMP_decomp( + COMP_Frame *base, + COMP_Delta *delta, + COMP_Frame *result) +{ + SLONG i; + SLONG sx; + SLONG sy; + SLONG dx; + SLONG dy; + + COMP_Pan *cp; + COMP_Update *cu; + IC_Packet *ip; + + // + // Use the pan info to copy over data. + // + + cp = (COMP_Pan *) delta->data; + + sx = 0; + sy = 0; + + while(1) + { + dx = cp->pan & 0xf; + dy = cp->pan >> 4; + + dx -= COMP_MAX_PAN; + dy -= COMP_MAX_PAN; + + for (i = 0; i < cp->num; i++) + { + if (cp->pan != 255) + { + COMP_square_copy( + base, + sx + dx, + sy + dy, + result, + sx, + sy, + COMP_SSIZE); + } + + sy += COMP_SSIZE; + + if (sy >= COMP_SIZE) + { + sy = 0; + + sx += COMP_SSIZE; + + if (sx >= COMP_SIZE) + { + // + // Finished doing pan copying. + // + + goto finished_panning; + } + } + } + + cp += 1; + } + + finished_panning:; + + // + // Put in all the packets. + // + + cu = (COMP_Update *) (cp + 1); + + while(1) + { + sx = cu->x; + sy = cu->y; + ip = cu->ip; + + ASSERT((sx & 0x3) == 0); + ASSERT((sy & 0x3) == 0); + + for (i = 0; i < cu->num; i++) + { + ASSERT(WITHIN(sx, 0, COMP_SIZE - 4)); + ASSERT(WITHIN(sy, 0, COMP_SIZE - 4)); + + IC_unpack( + *ip, + (TGA_Pixel *) result->p, + COMP_SIZE, + COMP_SIZE, + sx, + sy); + + sy += 4; + + if (sy >= COMP_SIZE) + { + sy = 0; + + sx += 4; + } + + ip += 1; + } + + if (cu->last) + { + break; + } + + cu = (COMP_Update *) ip; + } +} + + +#else //#ifndef TARGET_DC + +// Spoof em, Danno. +void COMP_decomp( + COMP_Frame *base, + COMP_Delta *delta, + COMP_Frame *result) +{ + ASSERT(FALSE); +} + +COMP_Delta *COMP_calc(COMP_Frame *f1, COMP_Frame *f2, COMP_Frame *ans) +{ + ASSERT(FALSE); + return ( NULL ); +} + +#endif //#else //#ifndef TARGET_DC + diff --git a/fallen/DDEngine/Source/cone.cpp b/fallen/DDEngine/Source/cone.cpp new file mode 100644 index 0000000..06e21af --- /dev/null +++ b/fallen/DDEngine/Source/cone.cpp @@ -0,0 +1,1142 @@ +// +// Cones clipped by planar polygons. +// + +#include "game.h" +#include "poly.h" +#include "cone.h" +#include "pap.h" +#include "supermap.h" +#include +#include "memory.h" + + +#ifdef TARGET_DC +// intrinsic maths +#include +#endif + +// +// The origin of the cone. +// + +float CONE_origin_x; +float CONE_origin_y; +float CONE_origin_z; +ULONG CONE_origin_colour; +float CONE_end_x; +float CONE_end_y; +float CONE_end_z; + +// +// The points around the base of the cone. +// + +typedef struct +{ + float x; + float y; + float z; + ULONG colour; + POLY_Point pp; + +} CONE_Point; + +#define CONE_MAX_POINTS 64 + +CONE_Point CONE_point[CONE_MAX_POINTS]; +SLONG CONE_point_upto; + +void CONE_create( + float x, + float y, + float z, + float dx, + float dy, + float dz, + float length, + float radius, + ULONG colour_start, + ULONG colour_end, + SLONG detail) +{ + SLONG i; + + float ax; + float ay; + float az; + + float bx; + float by; + float bz; + + float px; + float py; + float pz; + + float dist; + + // + // The origin of the cone. + // + + CONE_origin_x = x; + CONE_origin_y = y; + CONE_origin_z = z; + CONE_origin_colour = colour_start; + + // + // Normalise (dx,dy,dz). + // + +#ifdef TARGET_DC + dist = dx*dx + dy*dy + dz*dz; + dist = _InvSqrtA(dist); + + dx = dx * dist; + dy = dy * dist; + dz = dz * dist; +#else + dist = dx*dx + dy*dy + dz*dz; + dist = sqrt(dist); + + dx = dx * (1.0F / dist); + dy = dy * (1.0F / dist); + dz = dz * (1.0F / dist); +#endif + + // + // Construct two vectors orthogonal to (dx,dy,dz) and to eachother. + // + + px = dy; + py = dz; + pz = dx; + + // + // (px,py,pz) is not paralell to (dx,dy,dz) so (d x p) will be + // orthogonal to (dx,dy,dz) + // + + ax = dy*pz - dz*py; + ay = dz*px - dx*pz; + az = dx*py - dy*px; + + // + // Create a vector parallel to both a and d. + // + + bx = dy*az - dz*ay; + by = dz*ax - dx*az; + bz = dx*ay - dy*ax; + + // + // The number of points around the edge of the base depends on 'detail'... + // Always use at least 4 points. + // + + ASSERT(WITHIN(detail, 0, 256)); + + CONE_point_upto = 4; + CONE_point_upto += detail * (CONE_MAX_POINTS - 4) >> 8; + + // + // The midpoints of the circle at the end of the cone. + // + + CONE_end_x = CONE_origin_x + dx * length; + CONE_end_y = CONE_origin_y + dy * length; + CONE_end_z = CONE_origin_z + dz * length; + + // + // Build the bottom points of the cone. + // + + float angle; + float along_a; + float along_b; + + CONE_Point *cp; + + for (i = 0; i < CONE_point_upto; i++) + { + cp = &CONE_point[i]; + + angle = float(i) * (2.0F * PI / float(CONE_point_upto)); + along_a = cos(angle) * radius; + along_b = sin(angle) * radius; + + cp->x = CONE_end_x + along_a * ax + along_b * bx; + cp->y = CONE_end_y + along_a * ay + along_b * by; + cp->z = CONE_end_z + along_a * az + along_b * bz; + cp->colour = colour_end; + } +} + + + +ULONG CONE_interpolate_colour(float v, ULONG colour1, ULONG colour2) +{ + SLONG rb1, rb2, drb, rba; + SLONG ga1, ga2, dga, gaa; + + union + { + float vfloat; + ULONG vfixed8; + }; + + SLONG answer; + + // + // Early outs. + // + + if (colour1 == colour2) {return colour1;} + + if (v < 0.01F) {return colour1;} + if (v > 0.99F) {return colour2;} + + // + // Work out how much to interpolate along in fixed point 8. + // + + vfloat = 32768.0F + v; + vfixed8 &= 0xff; + + // + // Red and blue. + // + + rb1 = colour1 & (0x00ff00ff); + rb2 = colour2 & (0x00ff00ff); + + if (rb1 != rb2) + { + // + // Do interpolation of red and blue simultaneously. + // + + drb = rb2 - rb1; + drb *= vfixed8; + drb >>= 8; + rba = rb1 + drb; + rba &= 0x00ff00ff; + } + else + { + // + // No need to interpolated red and blue. + // + + rba = rb1; + } + + // + // Green and alpha. + // + + ga1 = colour1 >> 8; + ga2 = colour2 >> 8; + + ga1 &= 0x00ff00ff; + ga2 &= 0x00ff00ff; + + if (ga1 != ga2) + { + // + // Do interpolationg of red and blue simultaneously. + // + + dga = ga2 - ga1; + dga *= vfixed8; + gaa = (ga1 << 8) + dga; + gaa &= 0xff00ff00; + } + else + { + // + // No need to interpolate green and alpha. + // + + gaa = ga1 << 8; + } + + answer = rba | gaa; + + return answer; +} + + +// +// Inserts two new points in the cone after the given point at the given +// position. +// + +void CONE_insert_points( + SLONG point, + float x1, + float y1, + float z1, + ULONG colour1, + float x2, + float y2, + float z2, + ULONG colour2) +{ + SLONG i; + + ASSERT(WITHIN(point, 0, CONE_point_upto - 1)); + + if (CONE_point_upto >= CONE_MAX_POINTS - 1) + { + // + // We already have the maximum number of point. + // + + return; + } + + for (i = CONE_point_upto + 1; i - 2 >= point; i--) + { + CONE_point[i] = CONE_point[i - 2]; + } + + CONE_point[point + 0].x = x1; + CONE_point[point + 0].y = y1; + CONE_point[point + 0].z = z1; + CONE_point[point + 0].colour = colour1; + + CONE_point[point + 1].x = x2; + CONE_point[point + 1].y = y2; + CONE_point[point + 1].z = z2; + CONE_point[point + 1].colour = colour2; + + CONE_point_upto += 2; +} + + + +void CONE_clip( + CONE_Poly p[], + SLONG num_points) +{ + SLONG i; + SLONG j; + + SLONG p1; + SLONG p2; + + float av; + float aw; + + float bv; + float bw; + + float along; + + float along_v; + float along_w; + + float len_v; + float len_w; + + float overlen_v; + float overlen_w; + + float dpc; + + float px; + float py; + float pz; + + float dx; + float dy; + float dz; + float dist; + float dist_want; + float dist_mul; + + float ix; + float iy; + float iz; + ULONG icolour; + + float insert_x1; + float insert_y1; + float insert_z1; + ULONG insert_colour1; + + float insert_x2; + float insert_y2; + float insert_z2; + ULONG insert_colour2; + + float dprod; + + CONE_Poly *pp; + CONE_Point *cp; + + #define CONE_MAX_POLY_POINTS 16 + + struct + { + float along_v; + float along_w; + + } along_p[CONE_MAX_POLY_POINTS]; + + struct + { + UBYTE failed_side; + UBYTE failed_dprod; + UWORD shit; + float ix; + float iy; + float iz; + ULONG icolour; + float dprod[CONE_MAX_POLY_POINTS]; + + } point_info[2], + *point_info_now, + *point_info_then, + *point_info_spare; + + #define CONE_SWAP_POINT_INFO(a,b) {point_info_spare = (a); (a) = (b); (b) = point_info_spare;} + + point_info_now = &point_info[0]; + point_info_then = &point_info[1]; + + ASSERT(WITHIN(num_points, 3, CONE_MAX_POLY_POINTS)); + + // + // Find the plane of the polygon. Defined by the position of point 0, and + // two vectors from point 0 to point 1 and point 0 to point (num_points - 1). + // + + CONE_Poly *vp = &p[1]; + CONE_Poly *wp = &p[num_points - 1]; + + float vx = vp->x - p[0].x; + float vy = vp->y - p[0].y; + float vz = vp->z - p[0].z; + + float wx = wp->x - p[0].x; + float wy = wp->y - p[0].y; + float wz = wp->z - p[0].z; + + len_v = sqrt(vx*vx + vy*vy + vz*vz); + len_w = sqrt(wx*wx + wy*wy + wz*wz); + + overlen_v = 1.0F / len_v; + overlen_w = 1.0F / len_w; + + // + // The normal of the plane. + // + + float nx = vy * wz - vz * wy; + float ny = vz * wx - vx * wz; + float nz = vx * wy - vy * wx; + + // + // Which side of the plane is the origin of the cone? + // + + float ox = CONE_origin_x - p[0].x; + float oy = CONE_origin_y - p[0].y; + float oz = CONE_origin_z - p[0].z; + + float dpo = ox*nx + oy*ny + oz*nz; + + if (dpo >= 0.0F) + { + // + // The origin is on the back side of the quad. + // + + return; + } + + // + // Find all the points of the polyon in terms of the + // two vectors v and w. + // + + along_p[0].along_v = 0.0F; + along_p[0].along_w = 0.0F; + + along_p[1].along_v = len_v; + along_p[1].along_w = 0.0F; + + along_p[num_points - 1].along_v = 0.0F; + along_p[num_points - 1].along_w = len_w; + + for (i = 2; i < num_points - 1; i++) + { + pp = &p[i]; + + px = pp->x - p[0].x; + py = pp->y - p[0].y; + pz = pp->z - p[0].z; + + along_p[i].along_v = (px*vx + py*vy + pz*vz) * overlen_v; + along_p[i].along_w = (px*wx + py*wy + pz*wz) * overlen_w; + } + + // + // Check all the points of the cone. If the line connecting two points + // crosses over the edge of a polygon, then create a point at the intersection. + // + + point_info_then->failed_side = TRUE; + + for (i = 0; i < CONE_point_upto; i++) + { + cp = &CONE_point[i]; + + px = cp->x - p[0].x; + py = cp->y - p[0].y; + pz = cp->z - p[0].z; + + dpc = px*nx + py*ny + pz*nz; + + if (dpc <= 0.0F) + { + // + // This point is on the front side of the quad. + // + + point_info_now->failed_side = TRUE; + } + else + { + point_info_now->failed_side = FALSE; + + // + // The origin of the cone is on the front of the quad and this + // point is on the back of the quad. How far along the line + // is the intersection with the plane? + // + + along = dpo / (dpo - dpc); + + ASSERT(WITHIN(along, 0.0F, 1.0F)); + + // + // The intersection point. + // + + ix = CONE_origin_x + along * (cp->x - CONE_origin_x); + iy = CONE_origin_y + along * (cp->y - CONE_origin_y); + iz = CONE_origin_z + along * (cp->z - CONE_origin_z); + icolour = CONE_interpolate_colour(along, CONE_origin_colour, cp->colour); + + point_info_now->ix = ix; + point_info_now->iy = iy; + point_info_now->iz = iz; + point_info_now->icolour = icolour; + + // + // Find the intersection point in terms of the two vectors + // v and w. + // + + px = ix - p[0].x; + py = iy - p[0].y; + pz = iz - p[0].z; + + along_v = (px*vx + py*vy + pz*vz) * overlen_v; + along_w = (px*wx + py*wy + pz*wz) * overlen_w; + + // + // Is this point inside the polygon? We can optimise here because + // the first and last points (av,aw)s are easy constants. (0s and 1s) + // + + for (j = 0; j < num_points; j++) + { + p1 = j + 0; + p2 = j + 1; + + if (p2 == num_points) {p2 = 0;} + + av = along_p[p2].along_v - along_p[p1].along_v; + aw = along_p[p2].along_w - along_p[p1].along_w; + + bv = along_v - along_p[p1].along_v; + bw = along_w - along_p[p1].along_w; + + dprod = av*bv + aw*bw; + + // + // Remember the dprods WRT each line of the poly so we can create + // a point on the intersection of each line. + // + + point_info_now->dprod[j] = dprod; + + if (dprod < 0.0F) + { + // + // This ray does not intersect the polygon. + // + + point_info_now->failed_dprod = j; + + if (point_info_then->failed_side == FALSE && + point_info_then->failed_dprod == num_points) + { + // + // The last point did intersect the polygon. We must + // create a point along the edge of the polygon. + // + + along = point_info_then->dprod[j] / (point_info_then->dprod[j] - dprod); + + insert_x1 = point_info_then->ix + along * (ix - point_info_then->ix); + insert_y1 = point_info_then->iy + along * (iy - point_info_then->iy); + insert_z1 = point_info_then->iz + along * (iz - point_info_then->iz); + insert_colour1 = CONE_interpolate_colour(along, point_info_then->icolour, icolour); + + // + // Create another point at the end of the ray... + // + + dx = cp->x - CONE_origin_x; + dy = cp->y - CONE_origin_y; + dz = cp->z - CONE_origin_z; + + dist_want = sqrt(dx*dx + dy*dy + dz*dz); + + dx = insert_x1 - CONE_origin_x; + dy = insert_y1 - CONE_origin_y; + dz = insert_z1 - CONE_origin_z; + + dist = sqrt(dx*dx + dy*dy + dz*dz); + + dist_mul = dist_want / dist; + + dx *= dist_mul; + dy *= dist_mul; + dz *= dist_mul; + + insert_x2 = CONE_origin_x + dx; + insert_y2 = CONE_origin_y + dy; + insert_z2 = CONE_origin_z + dz; + insert_colour2 = cp->colour; + + CONE_insert_points( + i, + insert_x1, + insert_y1, + insert_z1, + insert_colour1, + insert_x2, + insert_y2, + insert_z2, + insert_colour2); + + // + // Skip over the inserted points... + // + + i += 2; + } + + goto point_outside_polygon; + } + } + + // + // Make this ray finish at the intersection with this polygon. + // + + point_info_now->failed_dprod = num_points; + + cp->x = ix; + cp->y = iy; + cp->z = iz; + cp->colour = icolour; + + if (point_info_then->failed_side == FALSE && + point_info_then->failed_dprod < num_points) + { + // + // The last point was not in the polygon, so create an intersection + // point between this point and the last one. + // + + along = point_info_then->dprod[point_info_then->failed_dprod] / (point_info_then->dprod[point_info_then->failed_dprod] - point_info_now->dprod[point_info_then->failed_dprod]); + + insert_x2 = point_info_then->ix + along * (ix - point_info_then->ix); + insert_y2 = point_info_then->iy + along * (iy - point_info_then->iy); + insert_z2 = point_info_then->iz + along * (iz - point_info_then->iz); + insert_colour2 = CONE_interpolate_colour(along, point_info_then->icolour, icolour); + + // + // Create another point at the end of the ray... + // + + ASSERT(WITHIN(i, 1, CONE_point_upto)); + + CONE_Point *lp = &CONE_point[i - 1]; + + dx = lp->x - CONE_origin_x; + dy = lp->y - CONE_origin_y; + dz = lp->z - CONE_origin_z; + + dist_want = sqrt(dx*dx + dy*dy + dz*dz); + + dx = insert_x2 - CONE_origin_x; + dy = insert_y2 - CONE_origin_y; + dz = insert_z2 - CONE_origin_z; + + dist = sqrt(dx*dx + dy*dy + dz*dz); + + dist_mul = dist_want / dist; + + dx *= dist_mul; + dy *= dist_mul; + dz *= dist_mul; + + insert_x1 = CONE_origin_x + dx; + insert_y1 = CONE_origin_y + dy; + insert_z1 = CONE_origin_z + dz; + insert_colour1 = lp->colour; + + CONE_insert_points( + i, + insert_x1, + insert_y1, + insert_z1, + insert_colour1, + insert_x2, + insert_y2, + insert_z2, + insert_colour2); + + // + // Skip over the inserted points. + // + + i += 2; + } + + point_outside_polygon:; + } + + CONE_SWAP_POINT_INFO( + point_info_now, + point_info_then); + } +} + +// +// Intersects the cone with colvects and walkable faces on the +// given square. +// + +#define CONE_COLVECT_DONE 4 + +SLONG CONE_colvect_done[CONE_COLVECT_DONE]; +SLONG CONE_colvect_done_upto; + +void CONE_intersect_square( + SLONG mx, + SLONG mz) +{ + SLONG i; + + SLONG x1; + SLONG z1; + + SLONG w_list; + SLONG w_face; + + PrimFace4 *p_f4; + PrimPoint *pp; + + SLONG f_list; + SLONG exit; + SLONG facet; + SLONG build; + + DFacet *df; + + SLONG face_height; + UBYTE face_order[4] = {0,1,3,2}; + + Thing *p_fthing; + + CONE_Poly poly[4]; + + if (!WITHIN(mx, 0, PAP_SIZE_LO - 1) || + !WITHIN(mz, 0, PAP_SIZE_LO - 1)) + { + return; + } + + PAP_Lo *pl = &PAP_2LO(mx,mz); + + f_list = pl->ColVectHead; + + if (f_list) + { + exit = FALSE; + + while(!exit) + { + facet = facet_links[f_list]; + + ASSERT(facet); + + if (facet < 0) + { + facet = -facet; + exit = TRUE; + } + + // + // Have we done this facet already? + // + + for (i = 0; i < CONE_COLVECT_DONE; i++) + { + if (CONE_colvect_done[i] == facet) + { + // + // Dont do this facet again + // + + goto ignore_this_facet; + } + } + + // + // Remember this facet. + // + + ASSERT(WITHIN(CONE_colvect_done_upto, 0, CONE_COLVECT_DONE - 1)); + ASSERT(CONE_COLVECT_DONE == 4 || CONE_COLVECT_DONE == 8); + + CONE_colvect_done[CONE_colvect_done_upto] = facet; + CONE_colvect_done_upto += 1; + CONE_colvect_done_upto &= CONE_COLVECT_DONE - 1; + + // + // The poly covering the facet. + // + + df = &dfacets[facet]; + + poly[0].x = float(df->x[1] << 8); + poly[0].y = float(df->Y[1] ); + poly[0].z = float(df->z[1] << 8); + + poly[1].x = float(df->x[1] << 8); + poly[1].y = float(df->Y[1] + BLOCK_SIZE * df->Height); + poly[1].z = float(df->z[1] << 8); + + poly[2].x = float(df->x[0] << 8); + poly[2].y = float(df->Y[0] + BLOCK_SIZE * df->Height); + poly[2].z = float(df->z[0] << 8); + + poly[3].x = float(df->x[0] << 8); + poly[3].y = float(df->Y[0] ); + poly[3].z = float(df->z[0] << 8); + + if (df->FacetType == STOREY_TYPE_NORMAL_FOUNDATION) + { + // + // Foundations go down deep into the ground... + // + + poly[0].y -= 256.0F; + poly[3].y -= 256.0F; + } + + // + // Clip the cone to this colvect. + // + + CONE_clip(poly, 4); + + + ignore_this_facet:; + + f_list++; + } + } + + + + /* + + // + // The walkable faces. + // + + w_list = me->Walkable; + + while(w_list) + { + w_face = walk_links[w_list].Face; + + if (w_face > 0) + { + p_f4 = &prim_faces4[w_face]; + + // + // Find the thing this face is a part of!!! + // + + wall = p_f4->ThingIndex; + + if (wall < 0) + { + storey = wall_list[-wall].StoreyHead; + building = storey_list[storey].BuildingHead; + thing = building_list[building].ThingIndex; + p_fthing = TO_THING(thing); + + poly[0].x = float(p_fthing->WorldPos.X >> 8); + poly[0].y = float(p_fthing->WorldPos.Y >> 8); + poly[0].z = float(p_fthing->WorldPos.Z >> 8); + + poly[1] = poly[0]; + poly[2] = poly[0]; + poly[3] = poly[0]; + + for (i = 0; i < 4; i++) + { + pp = &prim_points[p_f4->Points[face_order[i]]]; + + poly[i].x += float(pp->X); + poly[i].y += float(pp->Y); + poly[i].z += float(pp->Z); + } + + // + // Clip the cone to this walkable face. + // + + CONE_clip(poly, 4); + } + } + + w_list = walk_links[w_list].Next; + } + + */ +} + +void CONE_intersect_with_map() +{ + SLONG i; + SLONG j; + SLONG k; + + SLONG x; + SLONG z; + + SLONG x1; + SLONG z1; + SLONG x2; + SLONG z2; + + SLONG dx; + SLONG dz; + + SLONG lx; + SLONG lz; + + SLONG mx; + SLONG mz; + + SLONG len; + SLONG steps; + + // + // Make sure we dont do the same mapsquare more than once. + // + + #define CONE_MAX_DONE 4 + + struct + { + SLONG x; + SLONG z; + + } done[CONE_MAX_DONE] = {{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; + SLONG done_upto = 0; + + // + // Make sure we dont do a colvect more than once. + // + + for (i = 0; i < CONE_COLVECT_DONE; i++) + { + CONE_colvect_done[i] = -1; + } + + CONE_colvect_done_upto = 0; + + x1 = SLONG(CONE_origin_x); + z1 = SLONG(CONE_origin_z); + + x2 = SLONG(CONE_end_x); + z2 = SLONG(CONE_end_z); + + dx = x2 - x1; + dz = z2 - z1; + + len = QDIST2(abs(dx),abs(dz)) + 1; + + // + // Four steps per lo-res mapsquare. + // + + dx = (dx << 8) / len; + dz = (dz << 8) / len; + + steps = len >> 8; + steps += 1; + + x = x1; + z = z1; + + lx = -dz; + lz = dx; + + for (i = 0; i < steps; i++) + { + for (j = 0; j < 3; j++) + { + mx = x - lx + lx * j >> PAP_SHIFT_LO; + mz = z - lz + lz * j >> PAP_SHIFT_LO; + + // + // Have we done this mapsquare before? + // + + for (k = 0; k < CONE_MAX_DONE; k++) + { + if (done[k].x == mx && + done[k].z == mz) + { + goto already_done_this_square; + } + } + + // + // Remember this square. + // + + ASSERT(WITHIN(done_upto, 0, CONE_MAX_DONE - 1)); + + done[done_upto].x = mx; + done[done_upto].z = mz; + + ASSERT(CONE_MAX_DONE == 4 || CONE_MAX_DONE == 8); + + done_upto += 1; + done_upto &= CONE_MAX_DONE - 1; + + // + // Intersect the cone with stuff one this mapsquare. + // + + CONE_intersect_square(mx,mz); + + already_done_this_square:; + } + + x += dx; + z += dz; + } +} + + +void CONE_draw() +{ + SLONG i; + + SLONG p1; + SLONG p2; + + POLY_Point ppo; + + POLY_Point *tri[3]; + + CONE_Point *cp; + CONE_Point *cp1; + CONE_Point *cp2; + + // + // Rotate the origin of the cone. + // + + POLY_transform( + CONE_origin_x, + CONE_origin_y, + CONE_origin_z, + &ppo); + + if (!ppo.IsValid()) + { + // + // If the origin of the cone is behind us, then we are doomed! + // + + return; + } + + ppo.u = 0.0F; + ppo.v = 0.0F; + ppo.colour = CONE_origin_colour; + ppo.specular = 0x00000000; + + // + // Rotate all the points in the cone. + // + + for (i = 0; i < CONE_point_upto; i++) + { + cp = &CONE_point[i]; + + POLY_transform( + cp->x, + cp->y, + cp->z, + &cp->pp); + + cp->pp.colour = cp->colour; + cp->pp.specular = 0x00000000; + cp->pp.u = 0.0F; + cp->pp.v = 0.0F; + } + + // + // Generate the triangles. + // + + tri[0] = &ppo; + + for (i = 0; i < CONE_point_upto; i++) + { + p1 = i + 0; + p2 = i + 1; + + if (p2 == CONE_point_upto) {p2 = 0;} + + tri[1] = &CONE_point[p1].pp; + tri[2] = &CONE_point[p2].pp; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_ADDITIVE, FALSE); + } + } +} + diff --git a/fallen/DDEngine/Source/console.cpp b/fallen/DDEngine/Source/console.cpp new file mode 100644 index 0000000..93a967e --- /dev/null +++ b/fallen/DDEngine/Source/console.cpp @@ -0,0 +1,671 @@ +/************************************************************ + * + * console.cpp + * a crude message console for queuing and writing + * messages to the user + * + */ + +#include "game.h" +#include "console.h" +#include "poly.h" +#include "C:\fallen\DDLibrary\headers\D3DTexture.h" +#include "C:\fallen\DDLibrary\headers\GDisplay.h" +//#include "font3d.h" +#include "font2d.h" +#include "panel.h" +#include + +#ifdef TARGET_DC +#include "target.h" +#endif + +#define CONSOLE_LINES 15 +#define CONSOLE_WIDTH 50 + +struct ConsoleText { + CBYTE Text[CONSOLE_WIDTH]; + SLONG Age; +}; + +//static Font3D *font=0; +static ConsoleText Data[CONSOLE_LINES]; +static CBYTE status_text[_MAX_PATH]; + +// +// The messages at specific place on the screen. +// + +typedef struct +{ + SLONG delay; // (delay == 0) => Don't display message. + SLONG x; + SLONG y; + CBYTE mess[CONSOLE_WIDTH]; + +} CONSOLE_Mess; + +#define CONSOLE_MAX_MESSES 16 + +CONSOLE_Mess CONSOLE_mess[CONSOLE_MAX_MESSES]; + + + + +void CONSOLE_font(CBYTE *fontpath, float scale) { +// if (font) delete font; +// font = new Font3D(fontpath,scale); +} + + +// +// Returns TRUE if there is no text to write to the screen. +// + +SLONG CONSOLE_no_text() +{ + SLONG i; + + CONSOLE_Mess *cm; +/* + if (GAME_STATE & GS_PLAYBACK) + { + return TRUE; + } +*/ + for (i = 0; i < CONSOLE_MAX_MESSES; i++) + { + cm = &CONSOLE_mess[i]; + + if (cm->delay) + { + // + // There is a text_at message to display. + // + + return FALSE; + } + } +/* + if (Data[0].Age) + { + return FALSE; + } +*/ + return TRUE; +} + +static SLONG last_tick; +static SLONG this_tick; + +void CONSOLE_draw() { + + +#ifndef TARGET_DC + + + SLONG i; + + CONSOLE_Mess *cm; + + + last_tick = this_tick; + this_tick = GetTickCount(); + if (this_tick-last_tick>4000) { + // it's prolly lying. ish. + last_tick=this_tick-1000; + } + +// if (!font) return; + + + if (CONSOLE_no_text()&&!Data[0].Age) + { +/* static moo=0; + POLY_frame_init(FALSE,FALSE); + FONT2D_DrawString("YADDA YADDA...",10,10,0xFF00FF,16,POLY_PAGE_FONT2D,moo>>2); + moo++; + POLY_frame_draw(FALSE,FALSE);*/ + // + // Nothing to draw. + // + if (*status_text) { + POLY_frame_init(FALSE, FALSE); + FONT2D_DrawString(status_text,10,10,0x7f00ff00,256,POLY_PAGE_FONT2D); + POLY_frame_draw(FALSE,TRUE); + } + + return; + + // if (!(GAME_STATE & GS_PLAYBACK) && !Data[0].Age) return; // quick return when there's no text to write + } + + // probably want to change this to only blank areas we'll be writing to +// the_display.lp_D3D_Viewport->Clear(1, &the_display.ViewportRect, D3DCLEAR_ZBUFFER); + + POLY_frame_init(FALSE, FALSE); + if (*status_text) FONT2D_DrawString(status_text,10,10,0x7f00ff00,256,POLY_PAGE_FONT2D); +/* + if (GAME_STATE & GS_PLAYBACK) + { +void draw_a_3d_menu(Font3D &font, SLONG menu); + + draw_a_3d_menu((*font),1); + } +*/ + + for (i=0;i512) { + FONT2D_DrawString(Data[i].Text,135,370+(17*i),0x00ff00,256,POLY_PAGE_FONT2D); +// FONT2D_DrawString(Data[i].Text,2,44+(18*i),0x20ffd0,11,POLY_PAGE_FONT2D); + } else { + FONT2D_DrawString(Data[i].Text,135,370+(17*i),0x00ff00,256,POLY_PAGE_FONT2D,(512-Data[i].Age)>>3); +// FONT2D_DrawString(Data[i].Text,2,44+(18*i),0x20ffd0,11,POLY_PAGE_FONT2D,(512-Data[i].Age)>>3); + } +/* if (Data[i].Age>500) { + font->DrawString(Data[i].Text,320,200+(55*i),0xff9f9f,2.0,0); + } else { + font->DrawString(Data[i].Text,320,200+(55*i),0xff9f9f,2.0,0,(500-Data[i].Age)*0.0015); + }*/ + Data[i].Age -= this_tick - last_tick; + + if (Data[i].Age < 0) + { + Data[i].Age = 0; + } + } + + // + // The messages at specific points on the screen. + // + +/* if (!CONSOLE_no_text()) { + the_display.lp_D3D_Viewport->Clear(1, &the_display.ViewportRect, D3DCLEAR_ZBUFFER); + for (i = 0; i < CONSOLE_MAX_MESSES; i++) + { + cm = &CONSOLE_mess[i]; + + if (cm->delay) + { + font->DrawString( + cm->mess, + cm->x, + cm->y, + 0xffffff, + 1.0); + + cm->delay -= this_tick - last_tick; + + if (cm->delay < 0) + { + cm->delay = 0; + } + } + } + }*/ + + POLY_frame_draw(FALSE,TRUE); + if (!Data[0].Age) CONSOLE_scroll(); + + +#endif //#ifndef TARGET_DC + +} + +void CONSOLE_text(CBYTE *text, SLONG delay) +{ + PANEL_new_text(NULL, delay, text); + + return; + + + SLONG i; + CBYTE *ch; + CBYTE *ch1; + CBYTE *ch2; + CBYTE *pipe; + + CBYTE temp[1024]; + + // + // Early out on NULL strings or strings with just spaces in them. + // + + if (text == NULL) + { + return; + } + + for (ch = text; *ch; ch++) + { + if (!isspace(*ch)) + { + goto found_non_white_space; + } + } + + return; + + found_non_white_space:; + + // + // Check for pipes that split up the text. + // + + pipe = strchr(text, '|'); + + if (pipe) + { + // + // Create two strings... + // + + strcpy(temp, text); + + // + // Terminate the first string but overwriting '|'. + // + + temp[pipe - text] = '\000'; + + // + // Print each half separately. + // + + CONSOLE_text( temp, delay); + CONSOLE_text(&temp[pipe + 1 - text], delay); + + return; + } + + // + // Make sure the the string is not too long to fit on one line. + // + + if (strlen(text) <= CONSOLE_WIDTH) + { + ch1 = text; + ch2 = NULL; + } + else + { + strcpy(temp, text); + + // + // Find the first SPACE character <= CONSOLE_WIDTH + // + + for (i = CONSOLE_WIDTH - 1; i > 0; i--) + { + if (isspace(temp[i])) + { + // + // This is where to break up the line. + // + + temp[i] = '\000'; + + ch1 = temp; + ch2 = temp + i + 1; + + goto split_up_line; + } + } + + // + // Too long and nowhere to split it up! + // + + return; + + split_up_line:; + } + + // + // Add 'ch1' to the message list. + // + + i=0; + while ((idelay && cm->x == x && cm->y == y) + { + // + // Found an message at the same place. + // + + strncpy(cm->mess, message, CONSOLE_WIDTH); + + cm->delay = delay; + cm->x = x; + cm->y = y; + + return; + } + } + + // + // Look for an unused message. + // + + for (i = 0; i < CONSOLE_MAX_MESSES; i++) + { + cm = &CONSOLE_mess[i]; + + if (cm->delay <= 0) + { + // + // Found an unused message. + // + + strncpy(cm->mess, message, CONSOLE_WIDTH); + + cm->delay = delay; + cm->x = x; + cm->y = y; + + return; + } + } +} + +void CONSOLE_status(CBYTE *msg) { + strcpy(status_text,msg); + for (CBYTE *ch = status_text; *ch; *ch++ = toupper(*ch)); +} + +#if 0 +#ifndef FINAL + +// TCP/IP console + +#pragma comment ( lib, "ws2_32.lib" ) + +static DWORD WINAPI ThreadRun(LPVOID arg); +static int GetPort(SOCKET& s); +static void ReadMessage(SOCKET s); + +HANDLE hThread = NULL; + +void CONSOLE_TCP() +{ + if (hThread) return; + + DWORD tid; + hThread = CreateThread(NULL, 0, ThreadRun, NULL, 0, &tid); +} + +static DWORD WINAPI ThreadRun(LPVOID arg) +{ + // begin Windows sockets + WORD wVersionRequested = MAKEWORD(2, 0); + WSADATA wsaData; + + if (WSAStartup(wVersionRequested, &wsaData)) + { + TRACE("FATAL: Cannot initialize WinSock\n"); + return 1; + } + + // get socket + SOCKET s; + int rc = GetPort(s); + + if (rc == -1) + { + TRACE("FATAL: Cannot open socket\n"); + return 1; + } + else if (rc == -2) + { + TRACE("FATAL: Address in use\n"); + return 1; + } + + for (;;) + { + struct sockaddr raddr; + struct sockaddr_in *rap = (struct sockaddr_in *)&raddr; + + int raddrlen = sizeof(raddr); + + SOCKET as; + + // accept connection + for (;;) + { + as = accept(s, &raddr, &raddrlen); + if (as != INVALID_SOCKET) break; // connected + if (WSAGetLastError() == WSAEINTR) continue; // harmless - try again + if (WSAGetLastError() != WSAEWOULDBLOCK) break; // actual error + Sleep(0); + } + + if (as == INVALID_SOCKET) + { + TRACE("Accept failed\n"); + } + else + { + TRACE("Accept: %s:%d\n", inet_ntoa(rap->sin_addr), 23); + + // set new socket to non-blocking + u_long one = 1; + if (ioctlsocket(as, FIONBIO, &one) != SOCKET_ERROR) + { + // read message from socket + ReadMessage(as); + } + + closesocket(as); + } + } +} + +static int GetPort(SOCKET& s) +{ + // create socket + struct sockaddr_in inaddr; + + memset(&inaddr, 0, sizeof(inaddr)); + + inaddr.sin_family = AF_INET; + inaddr.sin_addr.s_addr = INADDR_ANY; + inaddr.sin_port = htons(23); + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) return -1; + + // bind socket + if (bind(s, (struct sockaddr *)&inaddr, sizeof(inaddr)) == SOCKET_ERROR) + { + closesocket(s); + if (WSAGetLastError() == WSAEADDRINUSE) return -2; + else return -1; + } + + // listen + while (listen(s, 5) == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEINTR) + { + closesocket(s); + return -1; + } + } + + // set socket to non-blocking + u_long one = 1; + if (ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR) + { + closesocket(s); + return -1; + } + + return 0; +} + +static int Send(SOCKET s, const char* dbuf, int dlen, int flags) +{ + int olen = dlen; + int slen; + + for (;;) + { + slen = send(s, dbuf, dlen, flags); + if (slen != SOCKET_ERROR) + { + if (slen == dlen) return olen; + dbuf += slen; + dlen -= slen; + } + else + { + if (WSAGetLastError() != WSAEWOULDBLOCK) break; // proper error + } + Sleep(0); + } + + return SOCKET_ERROR; +} + +static int Recv(SOCKET s, char* buf, int dlen, int flags) +{ + int rlen; + + for (;;) + { + rlen = recv(s, buf, 512, 0); + if (!rlen) return SOCKET_ERROR; // connection is closed + if (rlen != SOCKET_ERROR) return rlen; + if (WSAGetLastError() != WSAEWOULDBLOCK) break; // real error + Sleep(0); + } + + return SOCKET_ERROR; +} + +extern void parse_console(CBYTE* str); + +static void ReadMessage(SOCKET s) +{ + char buf[512]; // buffer for data + char cmd[512]; + char* cptr; + + cptr = cmd; + + char* welcome = "Welcome to the Urban Chaos embedded Telnet server\x0D\n(c) Mucky Foot 1999\x0D\n\x0D\n> "; + Send(s, welcome, strlen(welcome), 0); + + for (;;) + { + int rlen = Recv(s, buf, 512, 0); + + if (rlen == SOCKET_ERROR) return; + + // echo + Send(s, buf, rlen, 0); + + for (int ii = 0; ii < rlen; ii++) + { + if (buf[ii] == 0x0D) continue; + if (buf[ii] == 0x08) + { + if (cptr > cmd) cptr--; + continue; + } + if (buf[ii] == 0x0A) + { + *cptr = 0; + TRACE("Command: %s\n", cmd); + parse_console(cmd); + cptr = cmd; + send(s, "> ", 2, 0); + continue; + } + *cptr++ = buf[ii]; + } + } +} + +#endif +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Source/drawxtra.cpp b/fallen/DDEngine/Source/drawxtra.cpp new file mode 100644 index 0000000..5c76fff --- /dev/null +++ b/fallen/DDEngine/Source/drawxtra.cpp @@ -0,0 +1,3426 @@ +// +// DrawXtra.cpp +// Matthew Rosenfeld 12 October 1998 +// +// In order to make fallen more PSX-friendly, the various Really Gnasty Hacks scattered +// throughout the game code to draw "special" objects are being collected together in +// drawxtra.cpp -- stuff like the van, helicopter, footprints, etc. +// + +#include "DDLib.h" +#include "drawxtra.h" +#include "FMatrix.h" +#include "animate.h" +#include "mesh.h" +#include "cone.h" +#include "poly.h" +#include "psystem.h" +#include "sprite.h" +#include "spark.h" +#include "dirt.h" +#include "statedef.h" +#include "memory.h" +#include "collide.h" +#include "tracks.h" +#include "c:\fallen\headers\fc.h" +#include "barrel.h" +#include "eway.h" +#include "mfx.h" +#include "sound.h" +#include "gamemenu.h" + + + +/************************************************************* + * + * Helicopter + * + */ + +void CHOPPER_draw_chopper(Thing *p_chopper) +{ + + Chopper *chopper = CHOPPER_get_chopper(p_chopper); + SLONG matrix[9], vector[3]; + + + vector[0]=(chopper->dx/64)&2047; vector[1]=(-chopper->dz/64)&2047; vector[2]=0; + p_chopper->Draw.Mesh->Roll=vector[0]; + p_chopper->Draw.Mesh->Tilt=vector[1]; + + + if (!(chopper->target)) { + + FMATRIX_calc(matrix, p_chopper->Draw.Mesh->Angle, p_chopper->Draw.Mesh->Tilt, p_chopper->Draw.Mesh->Roll); + + vector[0]=vector[2]=0; vector[1]=-1; + + FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]); + + chopper->spotx=p_chopper->WorldPos.X; + chopper->spotz=p_chopper->WorldPos.Z; + + chopper->spotdx=chopper->spotdz=0; + + } else { + + SLONG target_x; + SLONG target_y; + SLONG target_z; + + // + // Look at Darci's body. + // + + calc_sub_objects_position( + chopper->target, + chopper->target->Draw.Tweened->AnimTween, + SUB_OBJECT_PELVIS, + &target_x, + &target_y, + &target_z); + + target_x <<= 8; + target_y <<= 8; + target_z <<= 8; + + target_x += chopper->target->WorldPos.X; + target_y += chopper->target->WorldPos.Y; + target_z += chopper->target->WorldPos.Z; + + SLONG dx, dz, dist; + SLONG maxspd = chopper->speed<<6; + + if (chopper->spotx > target_x) chopper->spotdx-=(chopper->since_takeoff >> 1); + if (chopper->spotz > target_z) chopper->spotdz-=(chopper->since_takeoff >> 1); + + if (chopper->spotx < target_x) chopper->spotdx+=(chopper->since_takeoff >> 1); + if (chopper->spotz < target_z) chopper->spotdz+=(chopper->since_takeoff >> 1); + + if (chopper->spotdx> maxspd) chopper->spotdx= maxspd; + if (chopper->spotdx<-maxspd) chopper->spotdx=-maxspd; + if (chopper->spotdz> maxspd) chopper->spotdz= maxspd; + if (chopper->spotdz<-maxspd) chopper->spotdz=-maxspd; + + + chopper->spotx += chopper->spotdx + chopper->dx; + chopper->spotz += chopper->spotdz + chopper->dz; + + chopper->spotx = ((chopper->spotx*24.0f)+target_x)*0.04f; // Was 24 and 0.04 + chopper->spotz = ((chopper->spotz*24.0f)+target_z)*0.04f; + + vector[0]= chopper->spotx - p_chopper->WorldPos.X; + + // unlikely event you're higher than the chopper, it won't aim up at you + if (target_y>p_chopper->WorldPos.Y) + vector[1]=0; + else + vector[1]=target_y - p_chopper->WorldPos.Y; + + vector[2]= chopper->spotz - p_chopper->WorldPos.Z; + + } + + MESH_draw_poly_inv_matrix( + p_chopper->Draw.Mesh->ObjectId, + p_chopper->WorldPos.X >> 8 , + p_chopper->WorldPos.Y >> 8, + p_chopper->WorldPos.Z >> 8 , + -p_chopper->Draw.Mesh->Angle, + -p_chopper->Draw.Mesh->Tilt, + -p_chopper->Draw.Mesh->Roll, + NULL); + MESH_draw_poly_inv_matrix( + chopper->rotorprim, + p_chopper->WorldPos.X >> 8 , + p_chopper->WorldPos.Y >> 8, + p_chopper->WorldPos.Z >> 8 , + -(p_chopper->Draw.Mesh->Angle+chopper->rotors), + -(p_chopper->Draw.Mesh->Tilt), + -(p_chopper->Draw.Mesh->Roll), + NULL); + + + if (chopper->light) { + SLONG colour; + + colour=(0x66 * chopper->light)/255; + colour+=(colour<<8); + colour<<=8; + + CONE_create( + p_chopper->WorldPos.X>>8, + p_chopper->WorldPos.Y>>8, + p_chopper->WorldPos.Z>>8, + vector[0], + vector[1], + vector[2], + 256.0F * 5.0F, + 256.0F, + colour, + 0x00000000, + 50); + + CONE_intersect_with_map(); + + CONE_draw(); + + } + +} + + +/************************************************************* + * + * Tracks (footprints + tyre tracks) + * + */ + + + +void TRACKS_DrawTrack(Thing *p_thing) +{ + Track *walk=p_thing->Genus.Track; + SLONG x,y,z,id,diff; + POLY_Point pp[4]; + POLY_Point *quad[4]; + UBYTE fade; + SLONG wpx,wpy,wpz; + SWORD sx,sz; + + POLY_flush_local_rot(); + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + diff=track_head-TRACK_NUMBER(walk); + if (diff<0) diff+=TRACK_BUFFER_LENGTH; + SATURATE(diff,0,255); diff=255-diff; + diff-=((walk->colour>>24)&0xff); + SATURATE(diff,0,255); fade=diff; + if (walk->flags&TRACK_FLAGS_INVALPHA) fade=255-fade; + + // we should be using gamecoord... but... juuust in case. (this is a debug thing) + /* + wpx=p_thing->Genus.Track->x>>8; + wpy=p_thing->Genus.Track->y>>8; + wpz=p_thing->Genus.Track->z>>8; + */ + wpx=p_thing->WorldPos.X>>8; + wpy=p_thing->WorldPos.Y>>8; + wpz=p_thing->WorldPos.Z>>8; + + sx=walk->sx; + sz=walk->sz; + if (walk->flags&TRACK_FLAGS_SPLUTTING) { + walk->splut++; + if (walk->splut==walk->splutmax) { + walk->flags&=~TRACK_FLAGS_SPLUTTING; + } else { + sx*=walk->splut; sx/=walk->splutmax; + sz*=walk->splut; sz/=walk->splutmax; + } + } + x=wpx + sx; + z=wpz + sz; + y=wpy; + POLY_transform(x,y,z,&pp[0]); + x=wpx - sx; + z=wpz - sz; + y=wpy; + POLY_transform(x,y,z,&pp[1]); + x=wpx + walk->dx + sx; + z=wpz + walk->dz + sz; + y=wpy + walk->dy; + POLY_transform(x,y,z,&pp[2]); + x=wpx + walk->dx - sx; + z=wpz + walk->dz - sz; + y=wpy + walk->dy; + POLY_transform(x,y,z,&pp[3]); + + + if (walk->flags&TRACK_FLAGS_FLIPABLE) { + if (walk->flip) { + pp[0].u=0.5; pp[0].v=1; + pp[1].u=0.0; pp[1].v=1; + pp[2].u=0.5; pp[2].v=0; + pp[3].u=0.0; pp[3].v=0; + } else { + pp[0].u=0.0; pp[0].v=1; + pp[1].u=0.5; pp[1].v=1; + pp[2].u=0.0; pp[2].v=0; + pp[3].u=0.5; pp[3].v=0; + } + } else { + pp[0].u=1.0; pp[0].v=1.0; + pp[1].u=0.0; pp[1].v=1.0; + pp[2].u=1.0; pp[2].v=0.0; + pp[3].u=0.0; pp[3].v=0.0; + } + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xFF000000; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=(fade<<24)+(walk->colour&0x00ffffff); + + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid() && pp[3].MaybeValid()) + { + POLY_add_quad(quad,walk->page,FALSE); + } +} + + +/************************************************************* + * + * Particle System + * + */ + +extern Particle particles[PSYSTEM_MAX_PARTICLES]; +extern SLONG next_free, next_used; + + +void PARTICLE_Draw() +{ + SLONG ctr; + UBYTE ndx; + Particle *p; + float u,v,w,h,sz; + +// p=particles; +// for (ctr=0;ctrprev) +// if (p->priority) + { + if (!p->sprite) { + u=0; v=0; w=1; h=1; + } else { + ndx=p->sprite>>2; + switch (p->sprite&3) { + case 1: // split in half each way + if (p->flags&PFLAG_SPRITELOOP) ndx&=3; + u=ndx&1; v=ndx>>1; + u*=0.5f; v*=0.5f; + w=0.5f; h=0.5f; + break; + case 2: // split in quarters each way + if (p->flags&PFLAG_SPRITELOOP) ndx&=0xf; + u=ndx&3; v=ndx>>2; + u*=0.25f; v*=0.25f; + w=0.25f; h=0.25f; + break; + } + } + sz=float(p->size); + if (p->flags&PFLAG_RESIZE2) sz*=0.00390625f; + SPRITE_draw_tex( + float(p->x>>8), + float(p->y>>8), + float(p->z>>8), + sz, + p->colour, + 0xff000000, + p->page, + u, v, w, h, + SPRITE_SORT_NORMAL); + } +} + + +/************************************************************* + * + * Pyros (bonfire like things) + * + */ + + +extern UBYTE fire_pal[768]; + +SLONG pyro_seed; + +void draw_flames(SLONG x,SLONG y,SLONG z,SLONG lod,SLONG offset); +void draw_flame_element(SLONG x,SLONG y,SLONG z,SLONG c0,UBYTE base,UBYTE rand=1); + +void POLY_add_line_tex_uv(POLY_Point *p1, POLY_Point *p2, float width1, float width2, SLONG page, UBYTE sort_to_front); + + + +// Pyro detail levels. +#ifdef TARGET_DC + +// Lower detail: +#define DUSTWAVE_SECTORS 16 +#define FIREBOMB_SPRITES 16 + +// Define this to dynamically limit the number of pyro sprites. +// This means that you get this many sprites, no +// matter how many explosions are on screen - very helpful +// when four mines go off together. +#define LIMIT_TOTAL_PYRO_SPRITES_PLEASE_BOB 500 + +#else + +// Hi detail: +#define DUSTWAVE_SECTORS 16 +#define FIREBOMB_SPRITES 16 + +// Turned off for the PC. You madmen :-) +//#define LIMIT_TOTAL_PYRO_SPRITES_PLEASE_BOB 100 + +#endif + + +#define DUSTWAVE_MULTIPLY ( 2048 / DUSTWAVE_MULTIPLY ) + + + + + +#ifdef LIMIT_TOTAL_PYRO_SPRITES_PLEASE_BOB + +static int iWantedToGivenMultiplier = 256; +static int iNumWantedPyrosThisFrame = 0; +static int iNumFixedPyrosThisFrame = 0; +// Called with how many sprites are wanted. +// Returns the number it can have. +int IWouldLikeSomePyroSpritesHowManyCanIHave ( int iIWantThisMany ) +{ + // Keep a tally for this frame. + iNumWantedPyrosThisFrame += iIWantThisMany; + + return ( ( iWantedToGivenMultiplier * iIWantThisMany ) >> 8 ); +} + +// If the rout can't change how many it uses, at least call this to warn the pyro system that they will be used. +void IHaveToHaveSomePyroSprites( int iINeedThisMany ) +{ + // Keep a tally for this frame. + iNumFixedPyrosThisFrame += iINeedThisMany; +} + + + + +void Pyros_EndOfFrameMarker ( void ) +{ + // Figure out how much we were "oversubscribed" by. + if ( ( iNumFixedPyrosThisFrame + iNumWantedPyrosThisFrame ) > LIMIT_TOTAL_PYRO_SPRITES_PLEASE_BOB ) + { + // Over the limit - ration pyro bits. + iWantedToGivenMultiplier = ( ( LIMIT_TOTAL_PYRO_SPRITES_PLEASE_BOB - iNumFixedPyrosThisFrame ) * 256 ) / iNumWantedPyrosThisFrame; + if ( iWantedToGivenMultiplier < 32 ) + { + // Silly number - obviously far to much going on - hit the framerate, + // rather than making it look stupid. + iWantedToGivenMultiplier = 32; + } + } + else + { + // Nope - still under the limit - have all you want. + iWantedToGivenMultiplier = 256; + } + + // And reset it. + iNumWantedPyrosThisFrame = 0; + iNumFixedPyrosThisFrame = 0; +} + + +#else + +// Not using the limiting stuff - these do nothing exciting. + +inline int IWouldLikeSomePyroSpritesHowManyCanIHave ( int iIWantThisMany ) +{ + // Sure. + return ( iIWantThisMany ); +} + +// If the rout can't change how many it uses, at leats call this to warn the phyro system that they will be used. +inline void IHaveToHaveSomePyroSprites( int iINeedThisMany ) +{ + // Does nothing in this case. +} + +void Pyros_EndOfFrameMarker ( void ) +{ + // Does nothing in this case. +} + +#endif + + + +// +// Pyro Utility Belt +// + +inline SLONG lerp_long(SLONG a, SLONG b, UBYTE pos) { + return ((a*(256-pos))>>8)+((b*pos)>>8); +} + +GameCoord lerp_vector(GameCoord a, GameCoord b, UBYTE pos) { + GameCoord result; + + result.X = lerp_long(a.X,b.X,pos); + result.Y = lerp_long(a.Y,b.Y,pos); + result.Z = lerp_long(a.Z,b.Z,pos); + + return result; + +} + +SLONG get_pyro_rand(void) +{ + pyro_seed*=31415965; + pyro_seed+=123456789; + return(pyro_seed>>8); +} + + +void SPRITE_draw_tex2( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + float u,float v,float w,float h, + SLONG sort) +{ + float screen_size; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + + POLY_transform( + world_x, + world_y, + world_z, + &mid); + + if (mid.IsValid()) + { + screen_size = POLY_world_length_to_screen(world_size) * mid.Z; + + if (mid.X + screen_size < 0 || + mid.X - screen_size > POLY_screen_width || + mid.Y + screen_size < 0 || + mid.Y - screen_size > POLY_screen_height) + { + // + // Off screen. + // + } + else + { + pp[0].X = mid.X - (screen_size*0.5f); + pp[0].Y = mid.Y - screen_size; + pp[1].X = mid.X + (screen_size*0.5f); + pp[1].Y = mid.Y - screen_size; + pp[2].X = mid.X - (screen_size*0.5f); + pp[2].Y = mid.Y + screen_size; + pp[3].X = mid.X + (screen_size*0.5f); + pp[3].Y = mid.Y + screen_size; + + pp[0].u = u; + pp[0].v = v; + pp[1].u = u+w; + pp[1].v = v; + pp[2].u = u; + pp[2].v = v+h; + pp[3].u = u+w; + pp[3].v = v+h; + + pp[0].colour = colour; + pp[1].colour = colour; + pp[2].colour = colour; + pp[3].colour = colour; + + pp[0].specular = specular; + pp[1].specular = specular; + pp[2].specular = specular; + pp[3].specular = specular; + + switch(sort) + { + case SPRITE_SORT_NORMAL: + pp[0].z = mid.z; + pp[0].Z = mid.Z; + pp[1].z = mid.z; + pp[1].Z = mid.Z; + pp[2].z = mid.z; + pp[2].Z = mid.Z; + pp[3].z = mid.z; + pp[3].Z = mid.Z; + break; + + case SPRITE_SORT_FRONT: + pp[0].z = 0.01F; + pp[0].Z = 1.00F; + pp[1].z = 0.01F; + pp[1].Z = 1.00F; + pp[2].z = 0.01F; + pp[2].Z = 1.00F; + pp[3].z = 0.01F; + pp[3].Z = 1.00F; + break; + + default: + ASSERT(0); + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + } +} + + + +void draw_flame_element2(SLONG x,SLONG y,SLONG z,SLONG c0) +{ + SLONG trans; + SLONG page; + float scale; + float u,v,w,h; + UBYTE* palptr; + SLONG palndx; + SLONG dx,dy,dz; + + pyro_seed=54321678+c0; + + + w=h=1.0; + u=v=0.0; + + if(!(c0&3)) + page=POLY_PAGE_FLAMES; + else + page=POLY_PAGE_SMOKE; + +// dy=get_pyro_rand()&0x1ff; + dy=get_pyro_rand()&0x1ff; + dy+=(GAME_TURN*5); + dy%=256; + dx=(((get_pyro_rand()&0xff)-128)*((dy>>2)+150))>>9; + dz=(((get_pyro_rand()&0xff)-128)*((dy>>2)+150))>>9; + if (page==POLY_PAGE_FLAMES) { + dx>>=2; dz>>=2; + } + + trans=255-dy; + + dx+=x; + dy+=y; + dz+=z; + + + if(trans>=1) + { + switch (page) { + case POLY_PAGE_FLAMES: + palptr=(trans*3)+fire_pal; + palndx=(256-trans)*3; + trans<<=24; + trans+=(fire_pal[palndx]<<16)+(fire_pal[palndx+1]<<8)+fire_pal[palndx+2]; + scale=150; + SPRITE_draw_tex2( + float(dx), + float(dy), + float(dz), + float(scale), + trans, + 0, + page, + u, v, w, h, + SPRITE_SORT_NORMAL); + break; + case POLY_PAGE_SMOKE: + trans+=(trans<<8)|(trans<<16)|(trans<<24); + scale=((dy-y)>>1)+50; + dy+=50; + SPRITE_draw_tex( + float(dx), + float(dy), + float(dz), + float(scale), + trans, + 0, + page, + u, v, w, h, + SPRITE_SORT_NORMAL); + break; + } + } + +} + + +void PYRO_draw_explosion(Pyrex *pyro); +void PYRO_draw_explosion2(Pyro *pyro); +void PYRO_draw_newdome(Pyro *pyro); +void PYRO_draw_dustwave(Pyro *pyro); +void PYRO_draw_streamer(Pyro *pyro); +void PYRO_draw_twanger(Pyro *pyro); +void PYRO_draw_blob(Pyro *pyro); +void PYRO_draw_armageddon(Pyro *pyro); +/* +void check_pyro(Pyro *pyro) +{ + static UBYTE remember[1000]; + SLONG index; + + index=PYRO_NUMBER(pyro); + + if(pyro->counter) + if(pyro->counter==remember[index]) + { + DebugText(" pyro %d counter %d again error thing %d\n",index,pyro->counter,THING_NUMBER(pyro->thing)); +// ASSERT(0); + } + + remember[index]=pyro->counter; + + +} +*/ +void PYRO_draw_pyro(Thing *p_pyro) { + Pyro *pyro = PYRO_get_pyro(p_pyro); + SLONG fx,fy,fz; + SLONG i,j; + GameCoord pos; + float dir[8][2] = { { 0.0f, 1.0f}, { 0.7f, 0.7f}, { 1.0f, 0.0f}, { 0.7f,-0.7f}, { 0.0f,-1.0f}, {-0.7f,-0.7f}, {-1.0f, 0.0f}, {-0.7f, 0.7f} }; + float uvs[8][2] = { { 0.5f, 1.0f}, { 0.85f, 0.85f}, { 1.0f, 0.5f}, { 0.85f, 0.15f}, { 0.5f, 0.0f}, { 0.15f, 0.15f}, { 0.0f, 0.5f}, { 0.15f, 0.85f} }; + + POLY_flush_local_rot(); + + fx=p_pyro->WorldPos.X; + fy=p_pyro->WorldPos.Y; + fz=p_pyro->WorldPos.Z; + + switch(pyro->PyroType) { + case PYRO_EXPLODE: + PYRO_draw_explosion((Pyrex*)pyro); + break; + + case PYRO_FIREWALL: +/* + for (i=0;icounter;i++) { + pos = lerp_vector(p_pyro->WorldPos,pyro->target,i); + draw_flame_element(pos.X>>8,pos.Y>>8,pos.Z>>8,i,1); + if (!(i&3)) { + pyro_seed=54321678+(i*get_pyro_rand()); + draw_flame_element2(pos.X>>8,pos.Y>>8,pos.Z>>8,get_pyro_rand()); + } + }*/ + break; + case PYRO_FIREPOOL: + if (pyro->thing->Flags&FLAGS_IN_VIEW) + { + SLONG radsqr,dx,dz,distsqr,radius,id; + GameCoord ctr,edge; + POLY_Point pp[3]; + POLY_Point *tri[3]; + POLY_Point temppnt; + + ctr=p_pyro->WorldPos; + ctr.X>>=8; ctr.Y>>=8; ctr.Z>>=8; + + POLY_transform(ctr.X,ctr.Y+0xa,ctr.Z,pp); + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + pp[0].colour = 0xFFFFFFFF; + pp[1].colour = 0xFFFFFFFF; + pp[2].colour = 0xFFFFFFFF; + pp[0].specular = 0xFF000000; + pp[1].specular = 0xFF000000; + pp[2].specular = 0xFF000000; + + pp[0].u=0.5; pp[0].v=0.5; + + if (pyro->Flags&PYRO_FLAGS_TOUCHPOINT) { + radius=pyro->radius; + distsqr=(pyro->counter*pyro->radius)>>7; // double to get diameter + distsqr*=distsqr; + } else { + radius=(pyro->counter*pyro->radius)>>8; + + edge=ctr; edge.Y+=0xa; + edge.X+=dir[0][0]*pyro->radii[0]; edge.Z+=dir[0][1]*pyro->radii[0]; + POLY_transform(edge.X,edge.Y,edge.Z,&temppnt); + pp[2].X=temppnt.X; pp[2].Y=temppnt.Y; pp[2].Z=temppnt.Z; + pp[2].clip=temppnt.clip; pp[2].z=temppnt.z; + pp[2].u=uvs[0][0]; pp[2].v=uvs[0][1]; + + // Throttle + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( 16 ); + + for (i=0;iradii[i]<(unsigned)radius) { + id=(pyro->counter<<3)+(i<<8); + id&=2047; + pyro->radii[i]+=abs(SIN(id)/4095); + } else { + id=((GAME_TURN<<1)+(i<<8)); + id&=2047; + pyro->radii[i]=radius+256+(SIN(id)/256); + } + j=(i+1)&7; + pp[1]=pp[2]; + + pp[2].u=uvs[j][0]; pp[2].v=uvs[j][1]; + edge=ctr; edge.Y+=0xa; + edge.X+=dir[j][0]*pyro->radii[j]; + edge.Z+=dir[j][1]*pyro->radii[j]; + POLY_transform(edge.X,edge.Y,edge.Z,&temppnt); + pp[2].X=temppnt.X; pp[2].Y=temppnt.Y; pp[2].Z=temppnt.Z; + pp[2].clip=temppnt.clip; pp[2].z=temppnt.z; + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid()) + { + POLY_add_triangle(tri,POLY_PAGE_FLAMES,FALSE,TRUE); + } + } + } + id=0; + radsqr=radius*radius; + + // Throttle + int iConst = ( pyro->radius * pyro->radius ); + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( iConst / ( 25 * 25 ) ); + + if ( iNumFlames < 10 ) + { + iNumFlames = 10; + } + + int iStepSize = (int)sqrtf ( (float)iConst / (float)iNumFlames ); + + for (i=-pyro->radius;iradius;i+=iStepSize) { + for (j=-pyro->radius;jradius;j+=iStepSize) { + id*=31415965; + id+=123456789; + if ((i*i+j*j)Flags&PYRO_FLAGS_TOUCHPOINT) { + dx=(pyro->target.X>>8)-pos.X; + dz=(pyro->target.Z>>8)-pos.Z; + if ((dx*dx+dz*dz)thing->Flags&FLAGS_IN_VIEW) + { + +extern int AENG_detail_skyline; + + int iNumFlames = 40; +#ifndef TARGET_DC +extern UBYTE sw_hack; + if (sw_hack || !AENG_detail_skyline)//||ShiftFlag) +#else + if (!AENG_detail_skyline)//||ShiftFlag) +#endif + { + iNumFlames *= 2; + } + else + { + iNumFlames *= 5; + } + + + // Throttle + iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( iNumFlames ); + // And draw. + draw_flames(fx>>8,fy/256,fz>>8,iNumFlames,(SLONG)p_pyro); + + if(AENG_detail_skyline) + if (!(Random()&7)) + PARTICLE_Add(fx+((Random()&0x9ff)-0x4ff), + fy+((Random()&0x9ff)-0x4ff), + fz+((Random()&0x9ff)-0x4ff), + (Random()&0xff)-0x7f,256+(Random()&0x1ff),(Random()&0xff)-0x7f, + POLY_PAGE_SMOKECLOUD2,2+((Random()&3)<<2),0x7FFFFFFF, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FIRE|PFLAG_FADE|PFLAG_RESIZE, + 300,70,1,1,2); + } + break; + + case PYRO_WHOOMPH: + if (pyro->thing->Flags&FLAGS_IN_VIEW) + { + + + + UBYTE i, radius; +#if 0 + UBYTE steps=1+(pyro->counter>>4); +#else + // Throttle + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( ( 1+(pyro->counter>>4) ) * 2 ); + UBYTE steps = iNumFlames >> 1; + if ( steps < 3 ) + { + steps = 3; + } + +#endif + UWORD angle=0, step=2048/steps; + SLONG px, py, pz; + + for (i=0;icounter)>>10; + radius+=(radius>>1); + px=fx+((SIN(angle)>>6)*radius); + py=fy; + pz=fz+((COS(angle)>>6)*radius); + PARTICLE_Add(px+((Random()&0x13ff)-0x9ff), + py+((Random()&0x13ff)-0x9ff), + pz+((Random()&0x13ff)-0x9ff), + 0,0,0, + POLY_PAGE_PCFLAMER,2+((Random()&3)<<2),0xaFffffff, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FIRE|PFLAG_FADE, + 150,70,1,8,2); + PARTICLE_Add(px+((Random()&0x13ff)-0x9ff), + py+((Random()&0x13ff)-0x9ff), + pz+((Random()&0x13ff)-0x9ff), + 0,0,0, + POLY_PAGE_PCFLAMER,2+((Random()&3)<<2),0xaFffffff, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FIRE|PFLAG_FADE, + 150,70,1,8,2); + + angle+=step; + angle&=2047; + } + +/* PARTICLE_Add(fx+((Random()&0x9ff)-0x4ff), + fy+((Random()&0x9ff)-0x4ff), + fz+((Random()&0x9ff)-0x4ff), + 0,0,0, + POLY_PAGE_PCFLAMER,2+((Random()&3)<<2),0xFFffffff, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FIRE|PFLAG_FADE, + 300,70,1,1,2);*/ + +/* draw_flames(fx>>8,fy/256,fz>>8,40,(SLONG)p_pyro); + if (!(Random()&3)) + PARTICLE_Add(fx+((Random()&0x9ff)-0x4ff), + fy+((Random()&0x9ff)-0x4ff), + fz+((Random()&0x9ff)-0x4ff), + (Random()&0xff)-0x7f,256+(Random()&0x1ff),(Random()&0xff)-0x7f, + POLY_PAGE_SMOKECLOUD2,2+((Random()&3)<<2),0x7FFFFFFF, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FIRE|PFLAG_FADE|PFLAG_RESIZE, + 300,70,1,1,2); + */ + } + break; + + case PYRO_IMMOLATE: + if (pyro->Flags&PYRO_FLAGS_SMOKE) { + if (pyro->victim) + pos = pyro->victim->WorldPos; + else + pos = pyro->thing->WorldPos; + if (pyro->Flags&PYRO_FLAGS_STATIC) + { + pos.X>>=8; pos.Y>>=8; pos.Z>>=8; + + // Throttle + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( 40 ); + + for (i=0;iFlags&PYRO_FLAGS_FLAME) { + if (pyro->victim) + pos = pyro->victim->WorldPos; + else + pos = pyro->thing->WorldPos; + if (pyro->Flags&PYRO_FLAGS_STATIC) + { + pos.X>>=8; pos.Y>>=8; pos.Z>>=8; + // Throttle + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( 40 ); + + for (i=0;ivictim) { + if (!(pyro->victim->Flags&FLAGS_IN_VIEW)) break; + if ((pyro->Flags&PYRO_FLAGS_FLICKER)||(pyro->Flags&PYRO_FLAGS_BONFIRE)) { + PrimObject* p_obj; + ULONG sp; + ULONG ep; + SLONG px,py,pz; + POLY_Point* pp; + SLONG matrix[9]; + GameCoord bob; + switch(pyro->victim->DrawType) { + case DT_MESH: + switch(pyro->victim->Class) + { + case CLASS_BARREL: + { + bob=BARREL_fire_pos(pyro->victim); + px = bob.X + (Random()&0x3fff)-0x1fff; + py = bob.Y + (Random()&0x3fff)-0x13ff; + pz = bob.Z + (Random()&0x3fff)-0x1fff; + RIBBON_extend(pyro->radii[0],px>>8,py>>8,pz>>8); + } + break; + } + break; + case DT_CHOPPER: + { + p_obj=&prim_objects[pyro->victim->Draw.Mesh->ObjectId]; + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + FMATRIX_calc( + matrix, + pyro->victim->Draw.Mesh->Angle, + pyro->victim->Draw.Mesh->Tilt, + pyro->victim->Draw.Mesh->Roll); + pp = &POLY_buffer[POLY_buffer_upto]; + + if (pyro->Flags&PYRO_FLAGS_FLICKER) { + if ((pyro->radii[7]radii[7]>ep)) pyro->radii[7]=sp; + pp->x=AENG_dx_prim_points[pyro->radii[7]].X; + pp->y=AENG_dx_prim_points[pyro->radii[7]].Y; + pp->z=AENG_dx_prim_points[pyro->radii[7]].Z; + + FMATRIX_MUL(matrix,pp->x,pp->y,pp->z); + + pos.X = (pp->x)+(pyro->victim->WorldPos.X>>8); + pos.Y = (pp->y)+(pyro->victim->WorldPos.Y>>8); + pos.Z = (pp->z)+(pyro->victim->WorldPos.Z>>8); + + RIBBON_extend(pyro->radii[0],pos.X,pos.Y,pos.Z); + pyro->radii[7]++; + } + if (pyro->Flags&PYRO_FLAGS_BONFIRE) + { + for (i=sp;i<(signed)ep;i++) + if (!(i&7)) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto]; + pp->x=AENG_dx_prim_points[i].X; + pp->y=AENG_dx_prim_points[i].Y; + pp->z=AENG_dx_prim_points[i].Z; + + FMATRIX_MUL(matrix,pp->x,pp->y,pp->z); + + pos.X = (pp->x)+(pyro->victim->WorldPos.X>>8); + pos.Y = (pp->y)+(pyro->victim->WorldPos.Y>>8); + pos.Z = (pp->z)+(pyro->victim->WorldPos.Z>>8); + + for (j=0;j<8;j++) { + draw_flame_element2(pos.X,pos.Y,pos.Z,i+(j*128)); + draw_flame_element2(pos.X,pos.Y,pos.Z,i+(j*128)+1); + } + + } + } + + return; + } + break; + case DT_ROT_MULTI: + if (pyro->Flags & PYRO_FLAGS_FLICKER) + { + SLONG px,py,pz; + UBYTE i,r,p; + + if (pyro->Dummy==2) r=5; else r=1; //r=1 was r=2 MikeD Aug 2000 + r=2; + for (i=0;ivictim->State){ + case STATE_DYING: p=7; break; + case STATE_DEAD: p=3; break; + default: p=0xf; break; + } + p=rand()&p; + calc_sub_objects_position( + pyro->victim, + pyro->victim->Draw.Tweened->AnimTween, + p, + &px, + &py, + &pz); + px += pyro->victim->WorldPos.X >> 8; + py += pyro->victim->WorldPos.Y >> 8; + pz += pyro->victim->WorldPos.Z >> 8; + RIBBON_extend(pyro->radii[i],px,py,pz); + /*for (p=0;p<5;p++) { + calc_sub_objects_position( + pyro->victim, + pyro->victim->Draw.Tweened->AnimTween, + p, + &px, + &py, + &pz); + px = pyro->victim->WorldPos.X >> 8; + py = pyro->victim->WorldPos.Y >> 8; + pz = pyro->victim->WorldPos.Z >> 8; + PARTICLE_Add(px,py,pz,0,512,0,POLY_PAGE_FLAMES2,2+((Random()&3)<<2),0x00FFFFFF, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FADE2|PFLAG_RESIZE, + 300,50,1,1,1); + }*/ + } + } + return; + } + } +/* if (pyro->Flags&PYRO_FLAGS_FACES) { + PrimObject* p_obj; + SLONG sp; + SLONG ep; + POLY_Point* pp; + SLONG matrix[9]; + + switch (pyro->victim->DrawType) { + case DT_MESH: + case DT_CHOPPER: + { + p_obj=&prim_objects[pyro->victim->Draw.Mesh->ObjectId]; + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + FMATRIX_calc( + matrix, + pyro->victim->Draw.Mesh->Angle, + pyro->victim->Draw.Mesh->Tilt, + pyro->victim->Draw.Mesh->Roll); + pp = &POLY_buffer[POLY_buffer_upto]; + if ((pyro->radii[7]radii[7]>ep)) pyro->radii[7]=sp; + pp->x=AENG_dx_prim_points[pyro->radii[7]].X; + pp->y=AENG_dx_prim_points[pyro->radii[7]].Y; + pp->z=AENG_dx_prim_points[pyro->radii[7]].Z; + + FMATRIX_MUL(matrix,pp->x,pp->y,pp->z); + + pos.X = (pp->x)+(pyro->victim->WorldPos.X>>8); + pos.Y = (pp->y)+(pyro->victim->WorldPos.Y>>8); + pos.Z = (pp->z)+(pyro->victim->WorldPos.Z>>8); + + RIBBON_extend(pyro->radii[0],pos.X,pos.Y,pos.Z); + + pyro->radii[7]++; + return; + } + break; + case DT_ROT_MULTI: + { + SLONG px,py,pz; + UBYTE i,r,p; + + if (pyro->padding==2) r=5; else r=2; + for (i=0;ivictim->State){ + case STATE_DYING: p=7; break; + case STATE_DEAD: p=3; break; + default: p=0xf; break; + } + p=rand()&p; + calc_sub_objects_position( + pyro->victim, + pyro->victim->Draw.Tweened->AnimTween, + p, + &px, + &py, + &pz); + px += pyro->victim->WorldPos.X >> 8; + py += pyro->victim->WorldPos.Y >> 8; + pz += pyro->victim->WorldPos.Z >> 8; + RIBBON_extend(pyro->radii[i],px,py,pz); + } + } + return; + default: + pos = pyro->victim->WorldPos; + pos.X>>=8; pos.Y>>=8; pos.Z>>=8; + for (i=0;i<40;i++) + draw_flame_element(pos.X,pos.Y,pos.Z,i,0); + return; + } + + + for (i=sp;ix=AENG_dx_prim_points[i].X; + pp->y=AENG_dx_prim_points[i].Y; + pp->z=AENG_dx_prim_points[i].Z; + + FMATRIX_MUL(matrix,pp->x,pp->y,pp->z); + + pos.X = (pp->x)+(pyro->victim->WorldPos.X>>8); + pos.Y = (pp->y)+(pyro->victim->WorldPos.Y>>8); + pos.Z = (pp->z)+(pyro->victim->WorldPos.Z>>8); + + for (j=0;j<8;j++) { + draw_flame_element2(pos.X,pos.Y,pos.Z,i+(j*128)); + draw_flame_element2(pos.X,pos.Y,pos.Z,i+(j*128)+1); + } + } + + + } else { + pos = pyro->victim->WorldPos; + pos.X>>=8; pos.Y>>=8; pos.Z>>=8; + for (i=0;i<40;i++) + draw_flame_element(pos.X,pos.Y,pos.Z,i,0); + }*/ + } else { + if (pyro->Flags&PYRO_FLAGS_FLICKER) { + pos=pyro->thing->WorldPos; + pos.X+=(rand()/2); + pos.Z+=(rand()/2); + RIBBON_extend(pyro->radii[0],pos.X>>8,pos.Y/256,pos.Z>>8); + } + } + break; + + case PYRO_DUSTWAVE: + PYRO_draw_dustwave(pyro); + break; + + case PYRO_EXPLODE2: + PYRO_draw_explosion2(pyro); + break; + + case PYRO_STREAMER: + PYRO_draw_streamer(pyro); + break; + + case PYRO_TWANGER: + PYRO_draw_twanger(pyro); + { + SLONG str; + if (pyro->counter<30) { + str=pyro->counter*5; + } else { + str=(285-pyro->counter*2); + str>>=1; + } + if (str>0) BLOOM_flare_draw(pyro->thing->WorldPos.X>>8,pyro->thing->WorldPos.Y>>8,pyro->thing->WorldPos.Z>>8,str); + } + break; + + case PYRO_NEWDOME: + PYRO_draw_newdome(pyro); + break; + + case PYRO_SPLATTERY: + // this only creates other things so no drawing + break; + + case PYRO_FIREBOMB: + if (!(pyro->thing->Flags&FLAGS_IN_VIEW)) break; + // temp behaviour: draw a sprite +// BLOOM_flare_draw(pyro->thing->WorldPos.X>>8,pyro->thing->WorldPos.Y>>8,pyro->thing->WorldPos.Z>>8,0x75); + { + // SLONG col=(255-pyro->counter)<<24; + //col|=0x007f7f7f; + //SPRITE_draw_tex(pyro->thing->WorldPos.X>>8,pyro->thing->WorldPos.Y>>8,pyro->thing->WorldPos.Z>>8,50,col,0xff000000,POLY_PAGE_FLAMES, 0.0,0.0,1.0,1.0, SPRITE_SORT_NORMAL); + //PYRO_draw_blob(pyro); + + SLONG x,y,z,d,h,i; + + if (pyro->counter<10) + { + + // Ten "clocks" of particle-creation, each particle lives for about 70 clocks. + int iNumSprites = IWouldLikeSomePyroSpritesHowManyCanIHave ( FIREBOMB_SPRITES * 10 * 70 ); + iNumSprites /= ( 10 * 70 ); + int iMultiplier = ( 16 * (1<<7) ) / iNumSprites; + + + for (d=0;dFlags&PYRO_FLAGS_WAVE)&&(pyro->counter<6)) + { +#if 0 + x=SIN((d<<7)+(Random()&127))>>3; z=COS((d<<7)+(Random()&127))>>3; +#else + x=SIN(iAngle+(Random()&127))>>3; + z=COS(iAngle+(Random()&127))>>3; +#endif + + PARTICLE_Add(pyro->thing->WorldPos.X,pyro->thing->WorldPos.Y,pyro->thing->WorldPos.Z, + x,(Random()&0xff),z, + POLY_PAGE_FLAMES2,2+((Random()&3)<<2),0x7FFFFFFF, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FADE2|PFLAG_RESIZE|PFLAG_DAMPING, + 55+(Random()&0x3f),80,1,8-(Random()&3),4); + } + + x=SIN(iAngle)>>4; z=COS(iAngle)>>4; + i=Random()&0xff; + if (pyro->counter>3) { + i-=pyro->counter*15; + if (i<0) i=0; + h=i; + i=SIN(h<<1)>>7; + y=COS(h<<1)>>4; + } else { + y=(128+(Random()&0xff))<<4; + } + x*=i; z*=i; + x>>=8; z>>=8; + h=(127+(Random()&0x7f))<<24; + h|=0xFFFFFF; + + PARTICLE_Add(pyro->thing->WorldPos.X,pyro->thing->WorldPos.Y,pyro->thing->WorldPos.Z, + x,y,z, + POLY_PAGE_FLAMES2,2+((Random()&3)<<2),h, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FADE2|PFLAG_RESIZE|PFLAG_DAMPING|PFLAG_GRAVITY, + 70+(Random()&0x3f),160,1,6,-4); + } + d=Random()&2047; + x=SIN(d)>>4; z=COS(d)>>4; + d=Random()&0xff; + x*=d; z*=d; + x>>=8; z>>=8; + PARTICLE_Add(pyro->thing->WorldPos.X,pyro->thing->WorldPos.Y,pyro->thing->WorldPos.Z, + x,(128+(Random()&0xff))<<4,z, + POLY_PAGE_FLAMES2,2+((Random()&3)<<2),0x7FFFFFFF, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FADE2|PFLAG_RESIZE|PFLAG_DAMPING|PFLAG_GRAVITY, + 75+(Random()&0x3f),160,1,5+(Random()&3),-(2+(Random()&3))); + } + if (pyro->counter<240) { + if ((pyro->counter>110)&&(pyro->counter<140)) { + PARTICLE_Add(pyro->thing->WorldPos.X,pyro->thing->WorldPos.Y,pyro->thing->WorldPos.Z, + 0,0,0, + POLY_PAGE_FLAMES2,2+((Random()&3)<<2),0xffFFFFFF, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FADE2|PFLAG_RESIZE, + 100,255,1,20,5); + } + //if (pyro->counter>10) pyro->counter+=10; + if ((pyro->counter>4)&&(pyro->counter<110)) { + d=Random()&2047; + x=SIN(d)>>4; z=COS(d)>>4; + //h=Random()&0xff; + h=(Random()&0x7f); + i=SIN(h<<1)>>8; + y=COS(h<<1)>>4; + x*=i; z*=i; + x>>=8; z>>=8; + //h=(127+(Random()&0x7f))<<24; + //h|=0x7003f; + h=0x7fffffff; + PARTICLE_Add(pyro->thing->WorldPos.X,pyro->thing->WorldPos.Y,pyro->thing->WorldPos.Z, + x,y,z, +// POLY_PAGE_FLAMES2,2+((Random()&3)<<2),h, + POLY_PAGE_SMOKECLOUD2,2+((Random()&3)<<2),h, + PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FIRE|PFLAG_FADE|PFLAG_RESIZE|PFLAG_DAMPING, + 70+(Random()&0x3f),100,1,2,4+(Random()&3)); + } + } + + } + break; + + case PYRO_GAMEOVER: + PYRO_draw_armageddon(pyro); + break; + + case PYRO_HITSPANG: + // in case you were wondering, a spang is a sort of ricochet/blast effect + // that appears when bullets hit you (or, i guess, walls, cars, etc) + +// check_pyro(pyro); //debug tool to find a bug MD 30-12-99 + + // make sure it is processed + + +// if(pyro->counter) +#ifdef PSX + { + POLY_Point pt1,pt2; + SLONG x,y,z; + +// POLY_transform(x+pyro->target.X,y+pyro->target.Y,z+pyro->target.Z,&pt1); + + // hardwired test +/* x=NET_PERSON(0)->WorldPos.X>>8; + y=(NET_PERSON(0)->WorldPos.Y>>8)+256; + z=NET_PERSON(0)->WorldPos.Z>>8; + POLY_transform(x,y,z,&pt1);*/ + + x=pyro->thing->WorldPos.X>>8; + y=pyro->thing->WorldPos.Y>>8; + z=pyro->thing->WorldPos.Z>>8; + + if (pyro->counter) + POLY_transform(x+pyro->target.X,y+pyro->target.Y,z+pyro->target.Z,&pt1); + else + POLY_transform(x+(pyro->target.X<<1),y+(pyro->target.Y<<1),z+(pyro->target.Z<<1),&pt1); + + + POLY_transform(x,y,z,&pt2); + + pt1.colour=pt2.colour=0xFFFFFFFF; + pt1.specular=pt2.specular=0xFF000000; + + switch(pyro->counter) + { + case 0: + pt1.u=0; pt1.v=0; + pt2.u=0.5; pt2.v=0.5; + break; + case 1: + pt1.u=0; pt1.v=0.5; + pt2.u=0.5; pt2.v=1.0; + break; + case 2: + pt1.u=0.5; pt1.v=0; + pt2.u=1.0; pt2.v=0.5; + break; + case 3: + pt1.u=0.5; pt1.v=0.5; + pt2.u=1.0; pt2.v=1.0; + break; + } + if (POLY_valid_line(&pt1,&pt2)) + { + if (pyro->counter>1) + POLY_add_line_tex_uv(&pt1,&pt2,42,42,POLY_PAGE_HITSPANG,0); + else + POLY_add_line_tex_uv(&pt1,&pt2,22,22,POLY_PAGE_HITSPANG,0); + } + } +#endif + break; + } + +} + + +extern RadPoint PYRO_defaultpoints[16]; + +#define TEXSCALE 0.003f +#define TEXSCALE2 0.006f + +void PYRO_draw_explosion(Pyrex *pyro) { + POLY_Point pp[3]; + POLY_Point *tri[3]; + UBYTE i,j; + SLONG ok,spec; + SLONG cx,cy,cz; + RadPoint points[17]; + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + cx=pyro->thing->WorldPos.X>>8; + cy=pyro->thing->WorldPos.Y>>8; + cz=pyro->thing->WorldPos.Z>>8; + + for (i=0;i<16;i++) { + points[i].x=(PYRO_defaultpoints[i].x*pyro->points[i].radius)>>16; + points[i].y=(PYRO_defaultpoints[i].y*pyro->points[i].radius)>>16; + points[i].z=(PYRO_defaultpoints[i].z*pyro->points[i].radius)>>16; + } + points[16].y=(65535*pyro->points[i].radius)>>16; + + spec=(255-(pyro->thing->Genus.Pyro->Timer1*4)); + if (spec<0) spec=0; + spec*=0x010101; + + DIRT_gust(pyro->thing,cx,cz,(points[0].x/4)+cx,(points[0].z/4)+cz); + DIRT_gust(pyro->thing,cx,cz,(points[4].x/4)+cx,(points[4].z/4)+cz); + + // Draw bottom "rung" + for (i=0;i<8;i++) { + + j=i+1; + if (j==8) j=0; + POLY_transform( points[i].x+cx, + points[i].y+cy, + points[i].z+cz, + &pp[0]); + pp[0].u=points[i].x*TEXSCALE; + pp[0].v=points[i].z*TEXSCALE; + POLY_transform( points[i+8].x+cx, + points[i+8].y+cy, + points[i+8].z+cz, + &pp[1]); + pp[1].u=points[i+8].x*TEXSCALE; + pp[1].v=points[i+8].z*TEXSCALE; + POLY_transform( points[j+8].x+cx, + points[j+8].y+cy, + points[j+8].z+cz, + &pp[2]); + pp[2].u=points[j+8].x*TEXSCALE; + pp[2].v=points[j+8].z*TEXSCALE; + pp[0].colour=pp[1].colour=pp[2].colour=0xFFFFFF+(pyro->thing->Genus.Pyro->Timer1<<24); + pp[0].specular=pp[1].specular=pp[2].specular=0xFF000000+spec; + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid()) + { + POLY_add_triangle(tri,POLY_PAGE_BIGBANG,FALSE); + } + + POLY_transform( points[i].x+cx, + points[i].y+cy, + points[i].z+cz, + &pp[0]); + pp[0].u=points[i].x*TEXSCALE; + pp[0].v=points[i].z*TEXSCALE; + POLY_transform( points[j+8].x+cx, + points[j+8].y+cy, + points[j+8].z+cz, + &pp[1]); + pp[1].u=points[j+8].x*TEXSCALE; + pp[1].v=points[j+8].z*TEXSCALE; + POLY_transform( points[j].x+cx, + points[j].y+cy, + points[j].z+cz, + &pp[2]); + pp[2].u=points[j].x*TEXSCALE; + pp[2].v=points[j].z*TEXSCALE; + pp[0].colour=pp[1].colour=pp[2].colour=0xFFFFFF+(pyro->thing->Genus.Pyro->Timer1<<24); + pp[0].specular=pp[1].specular=pp[2].specular=0xFF000000+spec; + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid()) + { + POLY_add_triangle(tri,POLY_PAGE_BIGBANG,FALSE); + } + } + + // Draw top "rung" + for (i=8;i<16;i++) { + j=i+1; + if (j==16) j=8; + POLY_transform( points[i].x+cx, + points[i].y+cy, + points[i].z+cz, + &pp[0]); + pp[0].u=points[i].x*TEXSCALE; + pp[0].v=points[i].z*TEXSCALE; + POLY_transform( cx, + points[16].y+cy, + cz, + &pp[1]); + pp[1].u=0; + pp[1].v=0; + POLY_transform( points[j].x+cx, + points[j].y+cy, + points[j].z+cz, + &pp[2]); + pp[2].u=points[j].x*TEXSCALE; + pp[2].v=points[j].z*TEXSCALE; + pp[0].colour=pp[1].colour=pp[2].colour=0xFFFFFF+(pyro->thing->Genus.Pyro->Timer1<<24); + pp[0].specular=pp[1].specular=pp[2].specular=0xFF000000+spec; + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid()) + { + POLY_add_triangle(tri,POLY_PAGE_BIGBANG,FALSE); + } + } + +} + + +// Lo Detail: +//#define DUSTWAVE_SECTORS 8 +//#define DUSTWAVE_MULTIPLY 256 +/* +void PYRO_draw_dustwave(Pyro *pyro) { + POLY_Point pp[3],mid; + POLY_Point *tri[3] = { &pp[0], &pp[1], &pp[2] }; + SLONG cx,cy,cz,ok,fade; + UBYTE sections, pass, sector, next; + SLONG dxs[DUSTWAVE_SECTORS],dys[DUSTWAVE_SECTORS], dists[4], heights[4]; + float thisscale, nextscale; + + // we'll need these to add on to relative coords + cx=pyro->thing->WorldPos.X>>8; + cy=pyro->thing->WorldPos.Y>>8; + cz=pyro->thing->WorldPos.Z>>8; + // and we'll often need to join stuff back up to the centre + POLY_transform( cx, cy, cz, &mid); + mid.u=mid.v=0; +/+ + sections=4; + if (pyro->counter<192) sections=3; + if (pyro->counter<128) sections=2; + if (pyro->counter<64) sections=1; + ++/ // debug override + sections=3; + + for(sector=0;sectorcounter<120) { + dists[0]=SIN(pyro->counter*4)/128; + } else { + dists[0]=512+(pyro->counter-120); + } + +/ + if (pyro->counter<60) { + dists[0]=SIN(pyro->counter*6)/128; + } else { + dists[0]=(SIN(60*6)/128)+((pyro->counter-60)*2); + } + heights[0]=2; + break; + case 1: + dists[1]=(dists[0]*SIN(pyro->counter*2))/65536; + heights[1]=SIN(pyro->counter*4)/1024; + break; + case 2: + dists[2]=(dists[1]*SIN(pyro->counter*2))/65536; + heights[2]=heights[1]*0.75; + break; + case 3: + dists[3]=(dists[2]*SIN(pyro->counter*2))/65536; + heights[3]=2; + break; + } + } + + if (pyro->counter<192) + fade=0; + else + fade=((pyro->counter-192)*4)<<24; + + // draw the data + for(pass=0;passthing, + cx+((dists[2]*dxs[shock_sector])/256), + cz+((dists[2]*dys[shock_sector])/256), + cx+((dists[1]*dxs[shock_sector])/256), + cz+((dists[1]*dys[shock_sector])/256) + ); + shock_sector++; + if (shock_sector==DUSTWAVE_SECTORS) shock_sector=0; + } + + +} +*/ + + + +void PYRO_draw_dustwave(Pyro *pyro) { + POLY_Point pp[3],mid; + POLY_Point *tri[3] = { &pp[0], &pp[1], &pp[2] }; + SLONG cx,cy,cz,ok,fade; + UBYTE sections, pass, sector, next; + SLONG dxs[DUSTWAVE_SECTORS],dys[DUSTWAVE_SECTORS], dists[4], heights[4]; + float thisscale, nextscale; + + // we'll need these to add on to relative coords + cx=pyro->thing->WorldPos.X>>8; + cy=pyro->thing->WorldPos.Y>>8; + cz=pyro->thing->WorldPos.Z>>8; + // and we'll often need to join stuff back up to the centre + POLY_transform( cx, cy, cz, &mid); +// mid.u=mid.v=0; + mid.u=0.5; + mid.v=1.0; + + sections=3; + + + int iNumSectors = IWouldLikeSomePyroSpritesHowManyCanIHave ( DUSTWAVE_SECTORS ); + + if ( iNumSectors < 7 ) + { + // Looks silly with less than 7 + iNumSectors = 7; + } + + int iMultiplier = 2048 / iNumSectors; + + for(sector=0;sector> 8; + dys[sector]=COS((sector*iMultiplier)) >> 8; + } + +#if 0 + // What the fuck? + // Why not just - er - do these in order? Why the for and the switch? + // Bonkers, mate. ATF. + + + // precalc the ring data + for(pass=0;pass<4;pass++) { + switch(pass) { + case 0: + if (pyro->counter>1) + dists[0]=512+SIN(pyro->counter*4)/256; + else + dists[0]=256+SIN(pyro->counter*4)/256; +/* if (pyro->counter<60) { + dists[0]=SIN(pyro->counter*6)/128; + } else { + dists[0]=(SIN(60*6)/128)+((pyro->counter-60)*2); + }*/ + heights[0]=2; + break; + case 1: + dists[1]=(dists[0]*SIN(pyro->counter*4))/65536; + heights[1]=SIN(pyro->counter*4)/1024; + break; + case 2: + dists[2]=(dists[1]*SIN(pyro->counter*4))/65536; + heights[2]=heights[1]*0.75f; + break; + case 3: + dists[3]=(dists[2]*SIN(pyro->counter*4))/65536; + heights[3]=2; + break; + } + } +#else + // precalc the ring data + if (pyro->counter>1) + dists[0]=512+SIN(pyro->counter*4)/256; + else + dists[0]=256+SIN(pyro->counter*4)/256; +/* if (pyro->counter<60) { + dists[0]=SIN(pyro->counter*6)/128; + } else { + dists[0]=(SIN(60*6)/128)+((pyro->counter-60)*2); + }*/ + heights[0]=2; + + dists[1]=(dists[0]*SIN(pyro->counter*4))/65536; + heights[1]=SIN(pyro->counter*4)/1024; + + dists[2]=(dists[1]*SIN(pyro->counter*4))/65536; + heights[2]=heights[1]*0.75f; + + dists[3]=(dists[2]*SIN(pyro->counter*4))/65536; + heights[3]=2; +#endif + +/* if (pyro->counter<192) + fade=0; + else + fade=((pyro->counter-192)*4)<<24; + */ + fade=pyro->counter<<25; + + // draw the data + for(pass=0;passthing, + cx+((dists[2]*dxs[shock_sector])/256), + cz+((dists[2]*dys[shock_sector])/256), + cx+((dists[1]*dxs[shock_sector])/256), + cz+((dists[1]*dys[shock_sector])/256) + ); + shock_sector++; + if (shock_sector==iNumSectors) shock_sector=0; + } + + +} + + + + + + +RadPoint PYRO_defaultpoints2[32]; + +void PYRO_draw_explosion2(Pyro *pyro) { + + POLY_Point pp[3]; + POLY_Point *tri[3]; + UBYTE i,j,k,b; + SLONG ok,spec,fade[4]; + SLONG cx,cy,cz; + RadPoint points[33]; + SLONG sc_radius; + float subscale; // deal with it -- tex coords :P + +// subscale=(TEXSCALE2*((256-pyro->counter)>>8)); +// subscale=(256-pyro->counter); + subscale=(170-pyro->counter); + subscale/=32; + subscale*=TEXSCALE2; + + + // -- called only once, to init -- + if (!PYRO_defaultpoints2[0].flags) { + SLONG height,radius; + RadPoint *pt; + + PYRO_defaultpoints2[0].flags=1; + pt=PYRO_defaultpoints2; + for (i=0;i<4;i++) { + + height=SIN(i*128); + radius=COS(i*128)>>8; + + // generate ring x,y + + for (j=0;j<8;j++) { + pt->x=(radius*((SLONG)SIN(j*256)))/256; + pt->z=(radius*((SLONG)COS(j*256)))/256; + pt->y=height; + pt++; + } + } + } + // -- + + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + cx=pyro->thing->WorldPos.X>>8; + cy=pyro->thing->WorldPos.Y>>8; + cz=pyro->thing->WorldPos.Z>>8; + + sc_radius=(pyro->radius*pyro->scale)/256; + + + // Throttle in a dodgy way. + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( 8 * 4 ); + iNumFlames >>= 2; + int iIncrement = 1; + // Should we bin some? + if ( iNumFlames < 6 ) + { + iIncrement = 2; + } + + for (i=0;i<32;i += iIncrement) { + points[i].x=(PYRO_defaultpoints2[i].x*sc_radius)>>16; + points[i].y=(PYRO_defaultpoints2[i].y*sc_radius)>>16; + points[i].z=(PYRO_defaultpoints2[i].z*sc_radius)>>16; + } + points[32].y=(65535*sc_radius)>>16; + + spec=(255-(pyro->counter*2)); + if (spec<0) spec=0; + spec*=0x010101; +// fade=(pyro->counter<<24); + + if (pyro->counter>170) { + fade[3]=SIN((pyro->counter-170)*6)>>8; + + fade[2]=fade[3]*2; + if (fade[2]>255) fade[2]=255; + + fade[1]=fade[2]*2; + if (fade[1]>255) fade[1]=255; + + fade[0]=fade[1]*2; + if (fade[0]>255) fade[0]=255; + + fade[0]<<=24; + fade[1]<<=24; + fade[2]<<=24; + fade[3]<<=24; + } else fade[0]=fade[1]=fade[2]=fade[3]=0; + +// DIRT_gust(pyro->thing,cx,cz,(points[0].x/4)+cx,(points[0].z/4)+cz); +// DIRT_gust(pyro->thing,cx,cz,(points[4].x/4)+cx,(points[4].z/4)+cz); + + + + // Draw bottom rungs + for (k=0;k<3;k++) { + b=k*8; + for (i=b;icounter)>>8)); +// subscale=(256-pyro->counter); + subscale=(170-pyro->counter); + subscale/=32; + subscale*=TEXSCALE2; + + + // -- called only once, to init -- + if (!PYRO_defaultpoints2[0].flags) { + SLONG height,radius; + RadPoint *pt; + + PYRO_defaultpoints2[0].flags=1; + pt=PYRO_defaultpoints2; + for (i=0;i<4;i++) { + + height=SIN(i*128); + radius=COS(i*128)>>8; +// radius+=Random()&0x7f; + + // generate ring x,y + + for (j=0;j<8;j++) { + pt->x=(radius*((SLONG)SIN(j*256)))/256; + pt->z=(radius*((SLONG)COS(j*256)))/256; + pt->y=height; + pt++; + } + } + } + // -- + + store_seed=GetSeed(); + SetSeed((ULONG)pyro); + + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + cx=pyro->thing->WorldPos.X>>8; + cy=pyro->thing->WorldPos.Y>>8; + cz=pyro->thing->WorldPos.Z>>8; + + sc_radius=(pyro->radius*pyro->scale)/256; + + // Throttle in a dodgy way. + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( 8 * 4 ); + iNumFlames >>= 2; + int iIncrement = 1; + // Should we bin some? + if ( iNumFlames < 6 ) + { + iIncrement = 2; + } + + + + for (i=0;i<32;i += iIncrement) { + points[i].x=(PYRO_defaultpoints2[i].x*sc_radius)>>16; + points[i].y=(PYRO_defaultpoints2[i].y*sc_radius)>>16; + points[i].z=(PYRO_defaultpoints2[i].z*sc_radius)>>16; + } + points[32].y=(65535*sc_radius)>>16; + + spec=(255-(pyro->counter*1)); + if (spec<0) spec=0; + spec*=0x010101; + + if (pyro->counter>170) { + fade[3]=SIN((pyro->counter-170)*6)>>8; + + fade[2]=fade[3]*2; + if (fade[2]>255) fade[2]=255; + + fade[1]=fade[2]*2; + if (fade[1]>255) fade[1]=255; + + fade[0]=fade[1]*2; + if (fade[0]>255) fade[0]=255; + + fade[0]<<=24; + fade[1]<<=24; + fade[2]<<=24; + fade[3]<<=24; + } else fade[0]=fade[1]=fade[2]=fade[3]=0; + + iu=(pyro->counter>>4); + iv=iu>>2; + iu=iu&3; + u=(float)iu; v=(float)iv; + u*=0.25f; v*=0.25f; + SPRITE_draw_tex(cx,cy,cz, + pyro->radius<<2,0xFFFFFF|(pyro->counter<<24),0xff000000,POLY_PAGE_EXPLODE1_ADDITIVE-(Random()&1),u,v,0.25,0.25,SPRITE_SORT_NORMAL); + SPRITE_draw_tex(cx,cy,cz, + pyro->radius<<3,0xFFFFFF|(pyro->counter<<24),0xff000000,POLY_PAGE_EXPLODE1_ADDITIVE-(Random()&1),u,v,0.25,0.25,SPRITE_SORT_NORMAL); + + // Draw bottom rungs + for (k=0;k<3;k++) { + b=k*8; + for (i=b;icounter>>4); + iv=iu>>2; + iu=iu&3; + u=(float)iu; v=(float)iv; + u*=0.25f; v*=0.25f; + SPRITE_draw_tex(points[j].x+cx,points[j].y+cy,points[j].z+cz, + pyro->radius<<1,0xFFFFFF|(pyro->counter<<24),0xff000000,POLY_PAGE_EXPLODE1_ADDITIVE-(Random()&1),u,v,0.25,0.25,SPRITE_SORT_NORMAL); + } + + POLY_transform( points[j].x+cx, + points[j].y+cy, + points[j].z+cz, + &pp[1]); + pp[1].u=points[j].x*subscale; + pp[1].v=points[j].z*subscale; + pp[1].colour=0xFFFFFF+fade[k]; + pp[0].specular=pp[1].specular=pp[2].specular=0xFF000000+spec; + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid()) + { + POLY_add_triangle(tri,POLY_PAGE_BIGBANG,FALSE); + } + } + } + + // Draw top "rung" + for (i=24;i<32;i += iIncrement) { + j=i+iIncrement; + if (j==32) j=24; + if (Random()&1) + SPRITE_draw_tex(points[i].x+cx,points[i].y+cy,points[i].z+cz, + pyro->radius<<1,0xFFFFFF|(pyro->counter<<24),0xff000000,POLY_PAGE_EXPLODE1_ADDITIVE,u,v,0.25,0.25,SPRITE_SORT_NORMAL); + POLY_transform( points[i].x+cx, + points[i].y+cy, + points[i].z+cz, + &pp[0]); + pp[0].u=points[i].x*subscale; + pp[0].v=points[i].z*subscale; + POLY_transform( cx, + points[32].y+cy, + cz, + &pp[1]); + pp[1].u=0; + pp[1].v=0; + POLY_transform( points[j].x+cx, + points[j].y+cy, + points[j].z+cz, + &pp[2]); + pp[2].u=points[j].x*subscale; + pp[2].v=points[j].z*subscale; + pp[0].colour=pp[1].colour=pp[2].colour=0xFFFFFF+fade[3]; + pp[0].specular=pp[1].specular=pp[2].specular=0xFF000000+spec; + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid()) + { + POLY_add_triangle(tri,POLY_PAGE_BIGBANG,FALSE); + } + } + + SetSeed(store_seed); + + +} + + + + + + +void PYRO_alpha_line( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + SLONG sort_to_front) +{ + POLY_Point p1; + POLY_Point p2; + + POLY_transform(float(x1), float(y1), float(z1), &p1); + POLY_transform(float(x2), float(y2), float(z2), &p2); + + if (POLY_valid_line(&p1, &p2)) + { + p1.colour = colour1; + p1.specular = 0xff000000; + + p2.colour = colour2; + p2.specular = 0xff000000; + + POLY_add_line(&p1, &p2, float(width1), float(width2), POLY_PAGE_ALPHA, sort_to_front); + } +} + +void PYRO_draw_twanger(Pyro *pyro) { + SLONG cx,cy,cz,c; + SLONG dx,dy,dz,tx,ty; + SLONG col1,col2,dir,ang; + UBYTE i; + + cx=pyro->thing->WorldPos.X>>8; + cy=pyro->thing->WorldPos.Y>>8; + cz=pyro->thing->WorldPos.Z>>8; + + + // Throttle in a dodgy way. + int iNumFlames = IWouldLikeSomePyroSpritesHowManyCanIHave ( 8 ); + int iIncrement = 1; + // Should we bin some? + if ( iNumFlames < 6 ) + { + iIncrement = 2; + } + + + for (i=0;i<8;i += iIncrement) { + ang=pyro->radii[i]&0xff; + dir=(pyro->radii[i]>>4); + + c=((COS(ang)>>8)*pyro->counter)/128; + + dx=((SIN(dir)/256)*c)/256; + dy=0; + dz=((COS(dir)/256)*c)/256; + + // scale + dx=(dx*pyro->scale)/256; + dz=(dz*pyro->scale)/256; + + if ((!pyro->tints[0])&&!pyro->tints[1]) { + col1=0x00FFFFFF+((COS(pyro->counter*2)&0xFF00)<<16); + col2=0x00FFFFFF-(SIN(pyro->counter*2)>>8); + } else { + col1=pyro->tints[0]+((COS(pyro->counter*2)&0xFF00)<<16); + col2=pyro->tints[1]; + } + + //debugoverride +// col1=0xFFFFFFFF; +// col2=0x00FFFF00; + + c=256-(COS(pyro->counter*2)>>8); + + PYRO_alpha_line(cx,cy,cz,2,col1,cx+dx,cy+dy,cz+dz,c,col2,1); + } + +} + + +void PYRO_draw_streambit(Pyro *pyro,SLONG cx, SLONG cy, SLONG cz, SLONG c, UBYTE i) { + SLONG x,y,z,dx,dy,dir; + + // get dir index + dir=(pyro->radii[i+4]>>8)*16; + // dx/dy specify steepness of streamer + dx=SIN(pyro->radii[i+4]&0xff)/256; + dy=COS(pyro->radii[i+4]&0xff)/256; + y=((SIN(c*4)/256)*dy)+cy; + // x/z handle the bearing + c=(c*dx)/128; + x=((SIN(dir)*c)/128)+cx; + z=((COS(dir)*c)/128)+cz; + PARTICLE_Add(x, y, z, 0, -2, 0, POLY_PAGE_STEAM, 1+((rand()&3)<<2), 0x888888, PFLAG_RESIZE|PFLAG_FADE, 40+(rand()&0xf), 4, 1, 5, 2); +} + +void PYRO_draw_streamer(Pyro *pyro) { + UBYTE i; + SLONG cx,cy,cz; + + cx=pyro->thing->WorldPos.X; + cy=pyro->thing->WorldPos.Y; + cz=pyro->thing->WorldPos.Z; + + for (i=0;i<4;i++) + if ((pyro->radii[i]>64)&&(pyro->radii[i]<320)) { + PYRO_draw_streambit(pyro,cx,cy,cz,pyro->radii[i]-64,i); + PYRO_draw_streambit(pyro,cx,cy,cz,pyro->radii[i]-60,i); + } else + if ((pyro->radii[i]>320)&&(pyro->radii[i]<400)) { + pyro->radii[i]=400; + pyro->counter--; + } + +} + +void PYRO_draw_blob(Pyro *p_thing) +{ + +} + + +void PYRO_draw_armageddon(Pyro *pyro) +{ + Thing *thing; + GameCoord pos; + SWORD i,j; + + if (GAMEMENU_is_paused()) return; + + move_thing_on_map(pyro->thing,&NET_PERSON(0)->WorldPos); + + // let's start things going nuts +// for (i=0;i<5;i++) +/* { + pos=pyro->thing->WorldPos; + pos.X+=((Random()&0xff00)-0x7f00)<<2; + pos.Z+=((Random()&0xff00)-0x7f00)<<2; + thing = PYRO_create(pos,PYRO_TWANGER); + if (thing) { + thing->StateFn(thing); + if (Random()&0xf) + { + thing->Genus.Pyro->tints[0]=0x00FFFF00; + thing->Genus.Pyro->tints[1]=0x00FF0000; + } + else + { + thing->Genus.Pyro->tints[0]=0x00FFFFFF; + thing->Genus.Pyro->tints[1]=0x00FFFF00; + } + j=pyro->counter; + j*=3; + thing->Genus.Pyro->scale=j; + } + }*/ + + SLONG and_1; + SLONG and_2; + +#ifndef TARGET_DC + if (SOFTWARE) + { + and_1 = 7; + and_2 = 7; + } + else +#endif + { +#ifdef TARGET_DC + // Ease off a bit. + and_1 = 3; + and_2 = 7; +#else + and_1 = 2; + and_2 = 3; +#endif + } + + if (!(Random()&and_1)) + { + pos=pyro->thing->WorldPos; + pos.X+=((Random()&0xff00)-0x7f00)<<3; + pos.Z+=((Random()&0xff00)-0x7f00)<<3; + pos.Y=PAP_calc_map_height_at(pos.X>>8,pos.Z>>8)<<8; + thing=PYRO_create(pos,PYRO_NEWDOME); + if (thing) + thing->Genus.Pyro->scale=(400+Random()&0x7f)+(pyro->counter<<1); + } + if (!(Random()&and_2)) + { + SLONG flags = PFLAG_SPRITEANI | PFLAG_SPRITELOOP | PFLAG_EXPLODE_ON_IMPACT | PFLAG_LEAVE_TRAIL; + if (Random()&1) flags|=PFLAG_GRAVITY ; + pos=pyro->thing->WorldPos; + pos.X+=((Random()&0xff00)-0x7f00)<<3; + pos.Z+=((Random()&0xff00)-0x7f00)<<3; + pos.Y=PAP_calc_map_height_at(pos.X>>8,pos.Z>>8)<<8; + + PARTICLE_Add( + pos.X, + pos.Y+0x1000, + pos.Z, + 0, + (0xff+(Random()&0xff)<<4), + 0, + POLY_PAGE_METEOR, + 2 + ((Random() & 0x3) << 2), + 0xffffffff, + flags, + 100, + 160, + 1, + 1, + 1); + + MFX_play_xyz(THING_NUMBER(pyro->thing),S_BALROG_FIREBALL,MFX_OVERLAP,pos.X,pos.Y,pos.Z); + } + +} + + +/************************************************************* + * + * Animals + * + */ + +#if 0 + +extern void ANIM_obj_draw(Thing *p_thing,DrawTween *dt); +extern void ANIM_obj_draw_warped(Thing *p_thing,DrawTween *dt); + +void ANIMAL_draw(Thing *p_thing) +{ + UBYTE i; + Animal *animal=ANIMAL_get_animal(p_thing); +// DrawTween *dt=ANIMAL_get_drawtween(animal); + + p_thing->WorldPos.Y=100<<8; + ANIM_obj_draw(p_thing,p_thing->Draw.Tweened); + +/* FIGURE_draw_prim_tween( + start_object + object_offset, + (p_thing->WorldPos.X >> 8)+xd, + (p_thing->WorldPos.Y >> 8)+yd, + (p_thing->WorldPos.Z >> 8)+zd, + dt->AnimTween, + &ae1[i], + &ae2[i], + &r_matrix, + dx,dy,dz, + colour, + specular); +*/ + +/* + for (i=0;iHead,ribbon->Tail,ribbon->Size); + i=ribbon->Tail; + p=ctr=0; + vo=ribbon->Scroll; + vo*= 0.015625f; + vs=ribbon->TextureV; + vs=1.0f/vs; + do { + POLY_transform(ribbon->Points[i].X, ribbon->Points[i].Y, ribbon->Points[i].Z, &pp[p]); + if (ribbon->Flags & RIBBON_FLAG_FADE) { + if (ribbon->Flags & RIBBON_FLAG_IALPHA) + id=((256*ctr)/ribbon->FadePoint); + else + id=255-((256*ctr)/ribbon->FadePoint); + if (id<0) id=0; + if (id>255) id=255; + pp[p].colour=(id<<24)|ribbon->RGB; + } else { + pp[p].colour=(((SLONG)ribbon->FadePoint)<<24)|ribbon->RGB; + } + pp[p].specular=0xFF000000; + if (i&1) { + pp[p].u=0; + } else { + pp[p].u=ribbon->TextureU; + } + pp[p].v=i; // heh + pp[p].v*=vs; + pp[p].v+=vo; + p++; i++; ctr++; + if (i==ribbon->Size) i=0; + if (p==3) p=0; + if (ctr>2) { + if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid()) + { + POLY_add_triangle(tri,ribbon->Page,FALSE); + } + } + ASSERT(ctrHead); // egad! + + +} + +/************************************************************* + * + * Light Blooms + * + */ + +// x,y,z specify light source centre +// dx,dy,dz its direction normal, scaled so 0 -> 0, 1 -> 256, or 0,0,0 for an omni light +// col is an 0x00RRGGBB colour value. Brightness does count. + +extern SLONG AENG_cam_vec[3]; + +/* +void BLOOM_draw_floats(float x, float y, float z, float dx, float dy, float dz, SLONG col) { + float dot; + float cx,cy,cz; + SLONG sz, rgba, scale; + POLY_Point pt1,pt2; + + cx=AENG_cam_vec[0]; cx/=65536.0; + cy=AENG_cam_vec[1]; cy/=65536.0; + cz=AENG_cam_vec[2]; cz/=65536.0; + dot=(dx*cx)+(dy*cy)+(dz*cz); +// TRACE("CamVec %d %d %d\n",AENG_cam_vec[0],AENG_cam_vec[1],AENG_cam_vec[2]); +// TRACE("dot %f\n",dot); + sz=((col&0xff)+((col&0xff00)>>8)+((col&0xff0000)>>16))>>2; + + // draw the glow bloom if the light is pointing towards us + if (dot<0) { + rgba=-255*dot; + rgba<<=24; + rgba+=col; +// SPRITE_draw(x,y,z,sz,rgba,0xFF000000,POLY_PAGE_BLOOM1,SPRITE_SORT_NORMAL); + SPRITE_draw(x,y,z,sz,rgba,0xFF000000,POLY_PAGE_BLOOM1,SPRITE_SORT_FRONT); + } + + // draw the flare bloom + scale=sz<<2; + POLY_transform(x,y,z,&pt1); + POLY_transform(x+(dx*scale),y+(dy*scale),z+(dz*scale),&pt2); + + rgba=255-abs(255*dot); + rgba<<=24; + pt1.colour=col|rgba; +// pt2.colour=col; + pt2.colour=col|rgba; + pt1.specular=pt2.specular=0xFF000000; + + sz*=3; + + if (POLY_valid_line(&pt1, &pt2)) + POLY_add_line_tex(&pt1, &pt2, sz>>2, sz>>1, POLY_PAGE_BLOOM2, 0); +// POLY_add_line(&pt1, &pt2, sz>>2, sz>>1, POLY_PAGE_ALPHA, 0); + +} +*/ + +void SPRITE_draw_rotated( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + SLONG page, + SLONG sort, + SLONG rotate) +{ + float screen_size; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + SLONG opp,adj,xofs,yofs,angle; + + POLY_transform( + world_x, + world_y, + world_z, + &mid); + + if (mid.IsValid()) + { + screen_size = POLY_world_length_to_screen(world_size) * mid.Z; + + if (mid.X + screen_size < 0 || + mid.X - screen_size > POLY_screen_width || + mid.Y + screen_size < 0 || + mid.Y - screen_size > POLY_screen_height) + { + // + // Off screen. + // + } + else + { + if (rotate==0xffffff) { + opp=(DisplayWidth>>1)-mid.X; + adj=(DisplayHeight>>1)-mid.Y; + angle=-Arctan(opp,adj); + angle&=2047; + } else angle=rotate; + + xofs=screen_size*SIN(angle); + yofs=screen_size*COS(angle); + xofs>>=16; yofs>>=16; + + pp[0].X = mid.X - xofs; + pp[0].Y = mid.Y - yofs; + pp[1].X = mid.X + yofs; + pp[1].Y = mid.Y - xofs; + pp[2].X = mid.X - yofs; + pp[2].Y = mid.Y + xofs; + pp[3].X = mid.X + xofs; + pp[3].Y = mid.Y + yofs; + +/* pp[0].X = mid.X - screen_size; + pp[0].Y = mid.Y - screen_size; + pp[1].X = mid.X + screen_size; + pp[1].Y = mid.Y - screen_size; + pp[2].X = mid.X - screen_size; + pp[2].Y = mid.Y + screen_size; + pp[3].X = mid.X + screen_size; + pp[3].Y = mid.Y + screen_size; +*/ + pp[0].u = 0; + pp[0].v = 0; + pp[1].u = 1; + pp[1].v = 0; + pp[2].u = 0; + pp[2].v = 1; + pp[3].u = 1; + pp[3].v = 1; + + pp[0].colour = pp[1].colour = pp[2].colour = pp[3].colour = colour; + + pp[0].specular = pp[1].specular = pp[2].specular = pp[3].specular = 0xFF000000; + + switch(sort) + { + case SPRITE_SORT_NORMAL: + + mid.z -= 1.0F / 64.0F; + mid.Z += 1.0F / 64.0F; + + if (mid.z < 0.0F) + { + mid.z = 0.0F; + } + + if (mid.Z > 0.999F) + { + mid.Z = 0.999F; + } + + pp[0].z = mid.z; + pp[0].Z = mid.Z; + pp[1].z = mid.z; + pp[1].Z = mid.Z; + pp[2].z = mid.z; + pp[2].Z = mid.Z; + pp[3].z = mid.z; + pp[3].Z = mid.Z; + break; + + case SPRITE_SORT_FRONT: + pp[0].z = 0.01F; + pp[0].Z = 1.00F; + pp[1].z = 0.01F; + pp[1].Z = 1.00F; + pp[2].z = 0.01F; + pp[2].Z = 1.00F; + pp[3].z = 0.01F; + pp[3].Z = 1.00F; + break; + + default: + ASSERT(0); + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + } +} + +extern SLONG AENG_cur_fc_cam; + +const UBYTE flare_table[7][3] = +{ + { 132 , 92 , 80 }, + { 135 , 114 , 79 }, + { 128 , 134 , 78 }, + { 81 , 125 , 73 }, + { 78 , 132 , 127 }, + { 76 , 88 , 126 }, + { 101 , 73 , 125 } + +}; + + +void BLOOM_flare_draw(SLONG x, SLONG y, SLONG z, SLONG str) { + POLY_Point pt1,pt2,pt3,pt4; + SLONG dx,dy,fx,fy,cx,cy; + SLONG i,sz,j; + SLONG scale; + POLY_Point *quad[4]; + SLONG fc_x, fc_y, fc_z, dummy; + + if (!EWAY_grab_camera( + &fc_x, &fc_y, &fc_z, + &dummy, &dummy, &dummy, &dummy)) + { + fc_x=FC_cam[AENG_cur_fc_cam].x; + fc_y=FC_cam[AENG_cur_fc_cam].y; + fc_z=FC_cam[AENG_cur_fc_cam].z; + } + + + if (!there_is_a_los(x,y,z, + fc_x>>8,fc_y>>8,fc_z>>8, + LOS_FLAG_IGNORE_PRIMS)) return; + + POLY_transform(x,y,z,&pt1); + + if ((pt1.X<0)||(pt1.X>POLY_screen_width)||(pt1.Y<0)||(pt1.Y>POLY_screen_height)) return; + + cx=DisplayWidth>>1; + cy=DisplayHeight>>1; + dx=pt1.X-cx; + dy=pt1.Y-cy; + +// dx>>=4; dy>>=4; + dx<<=4; dy<<=4; + + pt1.z=0.01F; pt1.Z=1.00F; + + pt2=pt3=pt4=pt1; + pt1.u=0; pt1.v=0; + pt2.u=1; pt2.v=0; + pt3.u=0; pt3.v=1; + pt4.u=1; pt4.v=1; + + quad[0]=&pt1; + quad[1]=&pt2; + quad[2]=&pt3; + quad[3]=&pt4; + + // + // Darker the further the lens flare is from the camera. + // + + { + SLONG dx = abs(x - (fc_x >> 8)); + SLONG dy = abs(y - (fc_y >> 8)); + SLONG dz = abs(z - (fc_z >> 8)); + + SLONG dist = QDIST3(dx,dy,dz); + + // scale = 256 - (dist * 256 / (16 * 256)); // surely that's nonsense mark? + scale = 256 - (dist / 16); + + if (scale<0) return; + + //TRACE("flare scale: %d str: %d\n",scale, str); + + SATURATE(scale, 0, 256); +// SATURATE(str, 0, 255); + + scale *= str; + scale >>= 8; + } + + +// scale=str; + + //TRACE("final flare scale: %d\n",scale); + if (!scale) return; + + for (i=-12;i<15;i++) + if (i) { + j=abs(i>>2); + j*=i; + fx=cx+((j*dx)>>8); + fy=cy+((j*dy)>>8); + sz=abs(abs(i)-3)*8; + if (abs(i)>7) sz>>=1; + if (abs(i)>11) sz>>=1; + pt1.X=fx-sz; pt1.Y=fy-sz; + pt2.X=fx+sz; pt2.Y=fy-sz; + pt3.X=fx-sz; pt3.Y=fy+sz; + pt4.X=fx+sz; pt4.Y=fy+sz; + pt1.specular=pt2.specular=pt3.specular=pt4.specular=0; + + SLONG r,g,b; + + r=flare_table[(i>>2)+3][0]; + g=flare_table[(i>>2)+3][1]; + b=flare_table[(i>>2)+3][2]; + + r*=scale; r>>=8; + g*=scale; g>>=8; + b*=scale; b>>=8; + +// j=(i>>2)+3; +// TRACE("ival : str : r,g,b %d : %d, %d,%d,%d\n",j, str,r,g,b); + + pt1.colour=pt2.colour=pt3.colour=pt4.colour= r | (g<<8) | (b<<16); + +/* //(str<<24)| + ( flare_table[(i>>2)+4][0] ) | + ( flare_table[(i>>2)+4][1] << 8) | + ( flare_table[(i>>2)+4][2] << 16);*/ + +/* ((flare_table[(i>>2)+4][0] * scale >> 8) << 0) | + ((flare_table[(i>>2)+4][1] * scale >> 8) << 8) | + ((flare_table[(i>>2)+4][2] * scale >> 8) << 16);*/ + + if (POLY_valid_quad(quad)) + POLY_add_quad(quad, POLY_PAGE_LENSFLARE, FALSE, true); + } + + +} + +void BLOOM_draw(SLONG x, SLONG y, SLONG z, SLONG dx, SLONG dy, SLONG dz, SLONG col, UBYTE opts) { + SLONG a,b,c,dot; + SLONG rgba,sz; +// POLY_Point pp[4],pt1,pt2; + POLY_Point pt1,pt2; +// POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + SLONG fc_x, fc_y, fc_z, dummy; + + POLY_flush_local_rot(); + + if (!EWAY_grab_camera( + &fc_x, &fc_y, &fc_z, + &dummy, &dummy, &dummy, &dummy)) + { + fc_x=FC_cam[AENG_cur_fc_cam].x; + fc_y=FC_cam[AENG_cur_fc_cam].y; + fc_z=FC_cam[AENG_cur_fc_cam].z; + } + + // check LOS against wall + SLONG losy = (opts & BLOOM_RAISE_LOS) ? y + 16 : y; + if (!there_is_a_los(x,losy,z, + fc_x>>8,fc_y>>8,fc_z>>8, + LOS_FLAG_IGNORE_PRIMS)) return; + + if ((!dx)&&(!dy)&&(!dz)) + dot=-255; + else { + // first order of the day: calculate the dot product of the light and view normal + a=(dx*AENG_cam_vec[0])/65536; + b=(dy*AENG_cam_vec[1])/65536; + c=(dz*AENG_cam_vec[2])/65536; + dot = a+b+c; + } + + sz=((col&0xff)+((col&0xff00)>>8)+((col&0xff0000)>>16))>>2; + + // draw the "glow bloom" if the light is pointing towards us + if ((dot<0)||(opts&BLOOM_GLOW_ALWAYS)) { + rgba=abs(dot); + rgba<<=24; + rgba|=col; +// SPRITE_draw((float)x,(float)y,(float)z,sz<<1,rgba,0xFF000000,POLY_PAGE_BLOOM1,SPRITE_SORT_NORMAL); + SPRITE_draw_rotated((float)x,(float)y,(float)z,sz<<2,rgba,POLY_PAGE_BLOOM1,SPRITE_SORT_NORMAL,0xffffff); + + // lil bit o lens flare + if (opts&BLOOM_LENSFLARE) { + rgba=abs(dot); + rgba>>=1; + if (opts&BLOOM_FLENSFLARE) rgba>>=1; + BLOOM_flare_draw(x,y,z,rgba); + } + } + + if (opts&BLOOM_BEAM) { + + // scale the flare + dx*=sz; dy*=sz; dz*=sz; + dx>>=5; dy>>=5; dz>>=5; + + // draw the "flare bloom" reaching out + POLY_transform(x,y,z,&pt1); + POLY_transform(x+dx,y+dy,z+dz,&pt2); + + rgba=255-abs(dot); + rgba<<=24; + pt1.colour=col|rgba; + pt2.colour=col; + pt1.specular=pt2.specular=0xFF000000; + + sz*=3; + + if (POLY_valid_line(&pt1, &pt2)) + POLY_add_line_tex(&pt1, &pt2, sz>>2, sz, POLY_PAGE_BLOOM2, 0); + } + +} + +/************************************************************* + * + * "Specials" that have their own extra draw stuff + * + */ + + +void DRAWXTRA_Special(Thing *p_thing) { + SLONG dx,dz,c0, flags=0; + + switch(p_thing->Genus.Special->SpecialType) { + + case SPECIAL_MINE: + if (p_thing->SubState == SPECIAL_SUBSTATE_ACTIVATED) + { + c0=(p_thing->Genus.Special->counter>>1)&2047; + dx=SIN(c0)>>8; + dz=COS(c0)>>8; + BLOOM_draw(p_thing->WorldPos.X>>8,(p_thing->WorldPos.Y>>8)+25,p_thing->WorldPos.Z>>8, + dx,0,dz,0x7F0000,BLOOM_BEAM); + } + else + { + c0=3+(THING_NUMBER(p_thing)&7); + c0=(((GAME_TURN*c0)+(THING_NUMBER(p_thing)*9))<<4)&2047; + dx=SIN(c0)>>8; + dz=COS(c0)>>8; + BLOOM_draw(p_thing->WorldPos.X>>8,(p_thing->WorldPos.Y>>8)+15,p_thing->WorldPos.Z>>8, + dx,0,dz,0x7F0000,0); + } + break; + case SPECIAL_EXPLOSIVES: + flags=BLOOM_BEAM; + // FALL THRU + //case SPECIAL_GRENADE: + if (p_thing->SubState == SPECIAL_SUBSTATE_ACTIVATED) + { + c0=p_thing->Genus.Special->timer; + c0=(c0<<3)&2047; + dx=SIN(c0)>>8; + dz=COS(c0)>>8; + BLOOM_draw(p_thing->WorldPos.X>>8,(p_thing->WorldPos.Y>>8)+25,p_thing->WorldPos.Z>>8, + dx,0,dz,0x007F5D,flags); + } + break; + + // no default -- not all specials have extra stuff. + } +} + +/************************************************************* + * + * DRAW2D -- some utils for the Widgets library + * hardly worth sticking here except to keep PC-specific stuff out of widgets + * + */ + +void DRAW2D_Box(SLONG x, SLONG y, SLONG ox, SLONG oy, SLONG rgb, UBYTE flag, UBYTE depth) { + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; +// SLONG page = flag ? POLY_PAGE_SUBTRACTIVE : POLY_PAGE_ALPHA; + SLONG page = flag ? POLY_PAGE_SUBTRACTIVEALPHA : POLY_PAGE_ADDITIVEALPHA; + float fdepth=(float)depth; + + pp[0].colour=rgb; pp[0].specular=0; + pp[0].Z=fdepth/256.0f; + + pp[1]=pp[2]=pp[3]=pp[0]; + + pp[0].X=x; pp[0].Y=y; + pp[1].X=ox; pp[1].Y=y; + pp[2].X=x; pp[2].Y=oy; + pp[3].X=ox; pp[3].Y=oy; + + POLY_add_quad(quad,page,FALSE,TRUE); + +} + +void DRAW2D_Box_Page(SLONG x, SLONG y, SLONG ox, SLONG oy, SLONG rgb, SLONG page, UBYTE depth) { + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + float fdepth=(float)depth; + + pp[0].colour=rgb; pp[0].specular=0; + pp[0].Z=fdepth/256.0f; + + pp[1]=pp[2]=pp[3]=pp[0]; + + pp[0].X=x; pp[0].Y=y; + pp[1].X=ox; pp[1].Y=y; + pp[2].X=x; pp[2].Y=oy; + pp[3].X=ox; pp[3].Y=oy; + + POLY_add_quad(quad,page,FALSE,TRUE); + +} + +void DRAW2D_Tri(SLONG x, SLONG y, SLONG ox, SLONG oy, SLONG tx, SLONG ty, SLONG rgb, UBYTE flag) { + POLY_Point pp[3]; + POLY_Point *tri[3] = { &pp[0], &pp[1], &pp[2] }; + SLONG page = flag ? POLY_PAGE_SUBTRACTIVEALPHA : POLY_PAGE_ADDITIVEALPHA; + + pp[0].colour=rgb; pp[0].specular=0; + pp[0].Z=0.5f; + + pp[1]=pp[2]=pp[0]; + + pp[0].X=x; pp[0].Y=y; + pp[1].X=ox; pp[1].Y=oy; + pp[2].X=tx; pp[2].Y=ty; + + POLY_add_triangle(tri,page,FALSE,TRUE); +} + +void DRAW2D_Sprite(SLONG x, SLONG y, SLONG ox, SLONG oy, float u, float v, float ou, float ov, SLONG page, SLONG rgb) { + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + + pp[0].colour=rgb; pp[0].specular=0; + pp[0].Z=0.5f; + + pp[1]=pp[2]=pp[3]=pp[0]; + + pp[0].X=x; pp[0].Y=y; pp[0].u=u; pp[0].v=v; + pp[1].X=ox; pp[1].Y=y; pp[1].u=ou; pp[1].v=v; + pp[2].X=x; pp[2].Y=oy; pp[2].u=u; pp[2].v=ov; + pp[3].X=ox; pp[3].Y=oy; pp[3].u=ou; pp[3].v=ov; + + POLY_add_quad(quad,page,FALSE,TRUE); +} + + +/************************************************************* + * + * MIBS + * they blow up properly now. + * + */ + + +void DRAWXTRA_MIB_destruct(Thing *p_thing) +{ + UBYTE i; + SLONG ctr=p_thing->Genus.Person->Timer1; + GameCoord posn; + Thing *thing; + SLONG j; + + p_thing->WorldPos.Y+=SIN(ctr>>2)>>7; + + calc_sub_objects_position( + p_thing, + p_thing->Draw.Tweened->AnimTween, + SUB_OBJECT_PELVIS, + &posn.X, + &posn.Y, + &posn.Z); + + posn.X<<=8; posn.Y<<=8; posn.Z<<=8; + posn.X+=p_thing->WorldPos.X; + posn.Y+=p_thing->WorldPos.Y; + posn.Z+=p_thing->WorldPos.Z; + + if (ctr>32 * 20 * 5) + { + POLY_Point pt1,pt2; + + POLY_transform(posn.X>>8,(posn.Y>>8)+1000,posn.Z>>8,&pt1); + POLY_transform(posn.X>>8,PAP_calc_map_height_at(posn.X>>8,posn.Z>>8),posn.Z>>8,&pt2); + + pt1.colour=pt2.colour=0xFFFFFFFF; + pt1.specular=pt2.specular=0xFF000000; + pt1.u=0; pt1.v=0; + pt2.u=1.0; pt2.v=0.25; + if (POLY_valid_line(&pt1,&pt2)) + POLY_add_line_tex_uv(&pt1,&pt2,142,142,POLY_PAGE_LITE_BOLT,0); + } + + if (ctr>1200+p_thing->Genus.Person->ammo_packs_pistol) + { + + // + // A dynamic light lightning-bolt flash that only lasts one frame. + // + + UBYTE dlight; + + dlight = NIGHT_dlight_create( + (posn.X >> 8), + (posn.Y >> 8) + 0x80, + (posn.Z >> 8), + 90+(Random()&0x1f), + 5, + 25, + 30); + + if (dlight) + { + NIGHT_dlight[dlight].flag |= NIGHT_DLIGHT_FLAG_REMOVE; + } + + + p_thing->Genus.Person->ammo_packs_pistol = (3200-ctr)>>3; + thing=PYRO_create(posn,PYRO_TWANGER); + if (thing) { + thing->StateFn(thing); + if (Random()&0xf) + { + thing->Genus.Pyro->tints[0]=0x0000FFFF; + thing->Genus.Pyro->tints[1]=0x000000FF; + } + else + { + thing->Genus.Pyro->tints[0]=0x00FFFFFF; + thing->Genus.Pyro->tints[1]=0x0000FFFF; + } + j=ctr-1199; + if (j>400) j=400; + thing->Genus.Pyro->scale=j; + } + } else p_thing->Genus.Person->ammo_packs_pistol=0; + + if (GAME_TURN&1) + { + + SPARK_Pinfo p1; + SPARK_Pinfo p2; + + UBYTE limbs[] = { SUB_OBJECT_LEFT_HAND, SUB_OBJECT_RIGHT_HAND, SUB_OBJECT_LEFT_FOOT, SUB_OBJECT_RIGHT_FOOT }; + + p1.type = SPARK_TYPE_GROUND; + p1.flag = 0; + p1.person = THING_NUMBER(p_thing); +// p1.limb = limbs[Random()&3]; + p1.dist = SPARK_TYPE_GROUND; + p1.x=posn.X>>8; p1.y=posn.Y>>8; p1.z=posn.Z>>8; + if (ctr<400) + { + p1.x+=(Random()&0xff)-0x7f; + p1.z+=(Random()&0xff)-0x7f; + } else + if (ctr<800) + { + p1.x+=(Random()&0x1ff)-0xff; + p1.z+=(Random()&0x1ff)-0xff; + } + else + { + p1.x+=(Random()&0x3ff)-0x1ff; + p1.z+=(Random()&0x3ff)-0x1ff; + } + + p2.type = SPARK_TYPE_LIMB; + p2.flag = 0; + p2.person = THING_NUMBER(p_thing); + p2.limb = SUB_OBJECT_PELVIS; + + SPARK_create( + &p1, + &p2, + 25); + } + +} + +/************************************************************* + * + * final_glow is the fx Mark did for the final level, + * but didn't bother putting a banner in for them, so I'm + * doing it now.... + * + * I put a comment into the header file instead. + * + * No, you don't understand. The banners are so you can easily + * find where one section (eg MIBs) ends and the next section + * (eg final_glow) begins. Comments in the header are no use + * whatsoever for this. + * + * I rarely use 'banners' in my code. + * + * I noticed. + */ + + +void DRAWXTRA_final_glow(SLONG x, SLONG y, SLONG z, UBYTE fade) +{ + static SLONG rotation = 0; + + POLY_Point mid; + + // Internal DC gubbins. + POLY_flush_local_rot(); + + POLY_transform( + float(x), + float(y), + float(z), + &mid); + + if (!(mid.clip & POLY_CLIP_TRANSFORMED)) + { + return; + } + + rotation += 10 * TICK_RATIO >> TICK_SHIFT; + + // + // Push forward in the z-buffer a bit... + // + + mid.z -= 1.0F / 22.0F; + + if (mid.z < POLY_ZCLIP_PLANE) + { + mid.z = POLY_ZCLIP_PLANE; + } + + mid.Z = POLY_ZCLIP_PLANE / mid.z; + + // + // Draw overlays rotated sprites. + // + + SLONG i; + SLONG j; + SLONG angle; + SLONG colour; + + float dx; + float dy; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + colour = fade * 0x60 >> 8; + colour |= colour << 8; + colour |= colour << 8; + + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = colour; + pp[0].specular = 0x00000000; + pp[0].Z = mid.Z; + pp[0].z = mid.z; + + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[1].colour = colour; + pp[1].specular = 0x00000000; + pp[1].Z = mid.Z; + pp[1].z = mid.z; + + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[2].colour = colour; + pp[2].specular = 0x00000000; + pp[2].Z = mid.Z; + pp[2].z = mid.z; + + pp[3].u = 1.0F; + pp[3].v = 1.0F; + pp[3].colour = colour; + pp[3].specular = 0x00000000; + pp[3].Z = mid.Z; + pp[3].z = mid.z; + + POLY_fadeout_point(&pp[0]); + POLY_fadeout_point(&pp[1]); + POLY_fadeout_point(&pp[2]); + POLY_fadeout_point(&pp[3]); + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + for (i = 0; i < 4; i++) + { + switch(i) + { + case 0: angle = rotation >> 0; break; + case 1: angle = -rotation >> 0; break; + case 2: angle = rotation >> 1; break; + case 3: angle = -rotation >> 1; break; + } + + angle += i << 6; + angle += i << 3; + angle &= 2047; + + dx = float(SIN(angle)) * mid.Z * (1.0F / 32.0F); + dy = float(COS(angle)) * mid.Z * (1.0F / 32.0F); + + for (j = 0; j < 4; j++) + { + if (j & 1) + { + pp[j].X = mid.X + dx; + pp[j].Y = mid.Y + dy; + } + else + { + pp[j].X = mid.X - dx; + pp[j].Y = mid.Y - dy; + } + + if (j & 2) + { + pp[j].X += -dy; + pp[j].Y += +dx; + } + else + { + pp[j].X -= -dy; + pp[j].Y -= +dx; + } + } + + POLY_add_quad(quad, POLY_PAGE_FINALGLOW, FALSE, TRUE); + } +} diff --git a/fallen/DDEngine/Source/facet.cpp b/fallen/DDEngine/Source/facet.cpp new file mode 100644 index 0000000..35ca8e4 --- /dev/null +++ b/fallen/DDEngine/Source/facet.cpp @@ -0,0 +1,5698 @@ +#include "game.h" + +#include "aeng.h" +#include "mesh.h" +#include "math.h" +#include "poly.h" +#include "c:\fallen\headers\supermap.h" +#include "c:\fallen\headers\inside2.h" +#include "night.h" +#include "c:\fallen\headers\pap.h" +#include "math.h" +#include "ns.h" +#include "c:\fallen\sedit\headers\es.h" +#include "memory.h" +#include "texture.h" +#include "polypage.h" +#include "ware.h" +#include "fc.h" +#include "font2d.h" +#include "smap.h" +#include "superfacet.h" +#include "supercrinkle.h" +#include "matrix.h" + +// temptemptempetc. +#include "sprite.h" + + +#ifdef TARGET_DC +#include "target.h" +#endif + +#ifdef TARGET_DC +// intrinsic maths +#include +#endif + + +#ifndef TARGET_DC + +#define LOG_ENTER(x) {} +#define LOG_EXIT(x) {} +#define LOG_EVENT(x) {} +#define POLY_set_local_rotation_none() {} + +#endif + + + + +#define FACETINFO +#ifdef FACETINFO + +// +// This is code to count the number of texture pages used in each +// facet and how many quads use each page... +// + +typedef struct +{ + UWORD page; + UWORD quads; + +} FACET_Pageinfo; + +#define FACET_MAX_PAGEINFO_PER_FACET 32 + +typedef struct +{ + UBYTE done; + UBYTE num_pages; + FACET_Pageinfo page[FACET_MAX_PAGEINFO_PER_FACET]; + +} FACET_Facetinfo; + +#define FACET_MAX_FACETINFO 4096 + +FACET_Facetinfo FACET_facetinfo[FACET_MAX_FACETINFO]; + +// +// The facet we are currently drawing... (this isn't passed down to FillFacetPointsCommon())! +// + +SLONG FACET_facetinfo_current; + + +#endif + + + + +float FACET_direction_matrix[9]; + + + + +void FACET_output(CBYTE *fmt, ...) +{ + // + // Work out the real message. + // + + CBYTE message[512]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + OutputDebugString(message); +} + + + +void FACET_facetinfo_trace(void) +{ + SLONG i; + SLONG j; + + SLONG num_facets = 0; + SLONG num_pages = 0; + SLONG num_quads = 0; + + SLONG max_pages_per_facet = 0; + + #define MAX_QUADS_PER_PAGE 1024 + + SLONG quads_per_page[MAX_QUADS_PER_PAGE]; + + memset(quads_per_page, 0, sizeof(quads_per_page)); + + float ave_pages_per_facet; + float ave_quads_per_page; + + FACET_Facetinfo *ff; + + for (i = 0; i < FACET_MAX_FACETINFO; i++) + { + ff = &FACET_facetinfo[i]; + + if (ff->done) + { + num_facets += 1; + num_pages += ff->num_pages; + + for (j = 0; j < ff->num_pages; j++) + { + num_quads += ff->page[j].quads; + + ASSERT(WITHIN(ff->page[j].quads, 0, MAX_QUADS_PER_PAGE - 1)); + + quads_per_page[ff->page[j].quads] += 1; + } + + if (ff->num_pages > max_pages_per_facet) + { + max_pages_per_facet = ff->num_pages; + } + } + } + + ave_pages_per_facet = float(num_pages) / float(num_facets); + ave_quads_per_page = float(num_quads) / float(num_pages ); + + FACET_output("*****************************************\n"); + FACET_output("\n"); + FACET_output("Num facets = %d\n", num_facets); + FACET_output("Average number of pages per facet = %f\n", ave_pages_per_facet); + FACET_output("Average number of quads per page = %f\n", ave_quads_per_page ); + FACET_output("Max pages per facet = %d\n", max_pages_per_facet); + FACET_output("\n"); + + for (i = 0; i < MAX_QUADS_PER_PAGE; i++) + { + FACET_output("%4d Quads per page : %5d\n", i, quads_per_page[i]); + } + + FACET_output("\n"); + FACET_output("*****************************************\n"); +} + + + + + + + + + +static int iNumFacets = 0; +static int iNumFacetTextures = 0; + + + + +//#define QUICK_FACET 1 +//#define FACET_REMOVAL_TEST // show removed facets and use 'F' key to swap (must be defined in build2.cpp too) + +SLONG dfacets_drawn_this_gameturn; +extern SLONG get_fence_hole(struct DFacet *p_facet); +extern SLONG get_fence_hole_next(struct DFacet *p_facet,SLONG along); + +static ULONG facet_seed=0x12345678; + +inline void apply_cloud(SLONG x,SLONG y,SLONG z,ULONG *col) +{ + return; +} + +void DRAW_ladder(struct DFacet *p_facet); + + +void FACET_draw(SLONG facet,UBYTE alpha); +void FACET_draw_rare(SLONG facet,UBYTE alpha); + + +extern BOOL allow_debug_keys; + +// inline utility calls + +inline float grid_height_at(SLONG mx,SLONG mz) +{ + float dy; + PAP_Hi *pap; + pap=&PAP_hi[mx][mz]; + dy=(float)(pap->Alt<<3); +// if (pap->Flags & PAP_FLAG_SINK_SQUARE) +// { +// dy -= KERB_HEIGHT; +// } + + return(dy); +} + +inline float grid_height_at_world(float x,float z) +{ + return(grid_height_at( ((SLONG)x)>>8,((SLONG)z)>>8) ); +} + +ULONG facet_rand(void) +{ + facet_seed=(facet_seed*69069)+1; + + return(facet_seed>>7); +} + +void set_facet_seed(SLONG seed) +{ + facet_seed=seed; +} + +// 1 0 +// b +// 3 a c 2 +#define GAP_HEIGHT 96.0 +#define GAP_WIDTH_PERC 0.2 +#ifdef UNUSED_WIRE_CUTTERS +void draw_fence_gap(POLY_Point *quad[4],SLONG page,SLONG along,float sx,float sy,float sz,float dx,float dy,float dz) +{ + POLY_Point *pp; + POLY_Point ppb[3]; + float a_f; + float mx,my,mz,du; + POLY_Point *g_quad[4]; + POLY_Point *g_tri[3]; + + a_f=(float)(along&0xff); + + a_f*=1.0/256.0; + + if(a_f1.0-GAP_WIDTH_PERC) + a_f=1.0-GAP_WIDTH_PERC; + + du=(quad[2]->u-quad[3]->u); // 1 or -1 ? + + + mx=sx+dx*a_f; + my=sy+dy*a_f; + mz=sz+dz*a_f; + + dx*=GAP_WIDTH_PERC; + dy*=GAP_WIDTH_PERC; + dz*=GAP_WIDTH_PERC; + + + pp = &ppb[0]; + + POLY_transform(mx-dx,my-dy,mz-dz,pp); + if (pp->MaybeValid()) + { + pp->colour=quad[3]->colour; + pp->specular=quad[3]->specular; + pp->u=quad[3]->u+du*(a_f-GAP_WIDTH_PERC); + pp->v=quad[3]->v; + } + pp++; + + POLY_transform(mx,my-dy+GAP_HEIGHT,mz,pp); + if (pp->MaybeValid()) + { + pp->colour=quad[3]->colour; + pp->specular=quad[3]->specular; + pp->u=a_f; + pp->v=quad[3]->v-(GAP_HEIGHT/512.0); +// pp->u=mu; +// pp->v=mv; + } + pp++; + + POLY_transform(mx+dx,my-dy,mz+dz,pp); + if (pp->MaybeValid()) + { + pp->colour=quad[3]->colour; + pp->specular=quad[3]->specular; + pp->u=quad[3]->u+du*(a_f+GAP_WIDTH_PERC); +// pp->u=a_f+du;//GAP_WIDTH_PERC; + pp->v=quad[3]->v; + } + pp++; + +// 1 0 +// b +// 3 a c 2 + + + g_quad[0]=quad[0]; + g_quad[1]=&ppb[1]; + g_quad[2]=quad[2]; + g_quad[3]=&ppb[2]; + + + if (POLY_valid_quad(g_quad)) + POLY_add_quad(g_quad, page, 0); // 1 means perform a backface cull + + g_quad[0]=&ppb[1]; + g_quad[1]=quad[1]; + g_quad[2]=&ppb[0]; + g_quad[3]=quad[3]; + if (POLY_valid_quad(g_quad)) + POLY_add_quad(g_quad, page, 0); // 1 means perform a backface cull + + g_tri[0]=quad[0]; + g_tri[1]=quad[1]; + g_tri[2]=&ppb[1]; + if (POLY_valid_triangle(g_tri)) + POLY_add_triangle(g_tri, page, 0); // 1 means perform a backface cull + +} +#endif + +// texture_quad +// +// set u,v in the poly points and return the page number for this quad + +SLONG flip; // Nasty! + +SLONG texture_quad(POLY_Point *quad[4],SLONG texture_style,SLONG pos,SLONG count,SLONG flipx=0) +{ + SLONG page; + SLONG texture_piece; + SLONG rand; + SLONG random=0; + + rand = facet_rand() & 0x3; + + if(pos==0) + texture_piece=flipx?TEXTURE_PIECE_LEFT:TEXTURE_PIECE_RIGHT; + else + if(pos==count-2) + texture_piece=flipx?TEXTURE_PIECE_RIGHT:TEXTURE_PIECE_LEFT; + else + { + static const UBYTE choice[4] = + { + TEXTURE_PIECE_MIDDLE, + TEXTURE_PIECE_MIDDLE, + TEXTURE_PIECE_MIDDLE1, + TEXTURE_PIECE_MIDDLE2 + }; + + texture_piece = choice[rand]; + if(rand>1) + random=1; + } + + if(texture_style<0) + { + SLONG index; + struct DStorey *p_storey; + + flip=0; + p_storey=&dstoreys[-texture_style]; +// ASSERT(p_storey->Count!=2); + + index=p_storey->Index; + ASSERT(p_storey->Count); + + if(posCount) + { + page=paint_mem[index+pos]; +// ASSERT(page!=156); + +// MSG_add(" pos %d page %x count %d index %d \n",pos,page,p_storey->Count,p_storey->Index); + + if(page&0x80) + { + + flip=1; + page&=0x7f; + if(ControlFlag&&allow_debug_keys) + { + quad[0]->colour=0xff0000; + quad[0]->specular=0xff000000; + quad[1]->colour=0xff0000; + quad[1]->specular=0xff000000; + quad[2]->colour=0xff0000; + quad[2]->specular=0xff000000; + quad[3]->colour=0xff0000; + quad[3]->specular=0xff000000; + page=POLY_PAGE_COLOUR; +// ASSERT(page!=156); + } + } + else + { + if(ControlFlag&&allow_debug_keys) + { + quad[0]->colour=0xff00; + quad[0]->specular=0xff000000; + quad[1]->colour=0xff00; + quad[1]->specular=0xff000000; + quad[2]->colour=0xff00; + quad[2]->specular=0xff000000; + quad[3]->colour=0xff00; + quad[3]->specular=0xff000000; + page=POLY_PAGE_COLOUR; +// ASSERT(page!=156); + } + + } + + if((page&0x7f)==0) + { + texture_style = p_storey->Style; + if(ControlFlag&&allow_debug_keys) + { + quad[0]->colour=0xff; + quad[0]->specular=0xff000000; + quad[1]->colour=0xff; + quad[1]->specular=0xff000000; + quad[2]->colour=0xff; + quad[2]->specular=0xff000000; + quad[3]->colour=0xff; + quad[3]->specular=0xff000000; + page=POLY_PAGE_COLOUR; +// ASSERT(page!=156); + } + + + } + } + else + { + texture_style = p_storey->Style; + + } + } + + if(texture_style>=0) + { + if(texture_style==0) + texture_style=1; + page=dx_textures_xy[texture_style][texture_piece].Page; +// ASSERT(page!=156); +// ASSERT(page<64*8); + flip=dx_textures_xy[texture_style][texture_piece].Flip; + if(ControlFlag&&allow_debug_keys&&random) + { + quad[0]->colour=0xffff; + quad[0]->specular=0xff000000; + quad[1]->colour=0xffff; + quad[1]->specular=0xff000000; + quad[2]->colour=0xffff; + quad[2]->specular=0xff000000; + quad[3]->colour=0xffff; + quad[3]->specular=0xff000000; + page=POLY_PAGE_COLOUR; +// ASSERT(page!=156); + } + + + } +/* + if(flipx) + { + flip^=1; + } +*/ + switch(flip) + { + case 0: + quad[1]->u = 1.0; + quad[1]->v = 0.0; + quad[0]->u = 0.0; + quad[0]->v = 0.0; + quad[3]->u = 1.0; + quad[3]->v = 1.0; + quad[2]->u = 0.0; + quad[2]->v = 1.0; + + break; + case 1: //flip x + quad[1]->u = 0.0; + quad[1]->v = 0.0; + quad[0]->u = 1.0; + quad[0]->v = 0.0; + quad[3]->u = 0.0; + quad[3]->v = 1.0; + quad[2]->u = 1.0; + quad[2]->v = 1.0; + + break; + case 2: //flip y + quad[1]->u = 1.0; + quad[1]->v = 1.0; + quad[0]->u = 0.0; + quad[0]->v = 1.0; + quad[3]->u = 1.0; + quad[3]->v = 0.0; + quad[2]->u = 0.0; + quad[2]->v = 0.0; + + break; + case 3: //flip x+y + quad[1]->u = 0.0; + quad[1]->v = 1.0; + quad[0]->u = 1.0; + quad[0]->v = 1.0; + quad[3]->u = 0.0; + quad[3]->v = 0.0; + quad[2]->u = 1.0; + quad[2]->v = 0.0; + + break; + } + + + +// LogText("quad text page %d \n",page); + +// ASSERT(page!=156); + return(page); + +} + + +// +// find page and flip +// +SLONG get_texture_page(SLONG texture_style,SLONG pos,SLONG count,UBYTE *rflip) +{ + SLONG page; + SLONG texture_piece; + SLONG rand; + SLONG flip; + + rand = facet_rand() & 0x3; + + if(pos==0) + texture_piece=TEXTURE_PIECE_RIGHT; + else + if(pos==count-2) + texture_piece=TEXTURE_PIECE_LEFT; + else + { + static const UBYTE choice[4] = + { + TEXTURE_PIECE_MIDDLE, + TEXTURE_PIECE_MIDDLE, + TEXTURE_PIECE_MIDDLE1, + TEXTURE_PIECE_MIDDLE2 + }; + + texture_piece = choice[rand]; + } + + if(texture_style<0) + { + SLONG index; + struct DStorey *p_storey; + + flip=0; + p_storey=&dstoreys[-texture_style]; +// ASSERT(p_storey->Count!=2); + + index=p_storey->Index; + ASSERT(p_storey->Count); + + if(posCount) + { + page=paint_mem[index+pos]; +// MSG_add(" pos %d page %x count %d index %d \n",pos,page,p_storey->Count,p_storey->Index); + + if(page&0x80) + { + flip=1; + page&=0x7f; + } + if((page&0x7f)==0) + { + texture_style = p_storey->Style; + + + } + } + else + { + texture_style = p_storey->Style; + + } + } + + if(texture_style>=0) + { + if(texture_style==0) + texture_style=1; + page=dx_textures_xy[texture_style][texture_piece].Page; + flip=dx_textures_xy[texture_style][texture_piece].Flip; + } + + *rflip=UBYTE(flip); + return(page); +} + + +SLONG texture_quad2(POLY_Point *quad[4],SLONG texture_style,SLONG texture_piece) +{ + SLONG page; + + if(texture_style==0) + texture_style=1; + page=dx_textures_xy[texture_style][texture_piece].Page; + switch(dx_textures_xy[texture_style][texture_piece].Flip) + { + case 0: + quad[1]->u = 1.0; + quad[1]->v = 0.0; + quad[0]->u = 0.0; + quad[0]->v = 0.0; + quad[3]->u = 1.0; + quad[3]->v = 1.0; + quad[2]->u = 0.0; + quad[2]->v = 1.0; + + break; + case 1: //flip x + quad[1]->u = 0.0; + quad[1]->v = 0.0; + quad[0]->u = 1.0; + quad[0]->v = 0.0; + quad[3]->u = 0.0; + quad[3]->v = 1.0; + quad[2]->u = 1.0; + quad[2]->v = 1.0; + + break; + case 2: //flip y + quad[1]->u = 1.0; + quad[1]->v = 1.0; + quad[0]->u = 0.0; + quad[0]->v = 1.0; + quad[3]->u = 1.0; + quad[3]->v = 0.0; + quad[2]->u = 0.0; + quad[2]->v = 0.0; + + break; + case 3: //flip x+y + quad[1]->u = 0.0; + quad[1]->v = 1.0; + quad[0]->u = 1.0; + quad[0]->v = 1.0; + quad[3]->u = 0.0; + quad[3]->v = 0.0; + quad[2]->u = 1.0; + quad[2]->v = 0.0; + + break; + } + + + +// LogText("quad text page %d \n",page); + + return(page); + +} +SLONG texture_tri2(POLY_Point *quad[3],SLONG texture_style,SLONG texture_piece) +{ + SLONG page; + + if(texture_style==0) + texture_style=1; + page=dx_textures_xy[texture_style][texture_piece].Page; + switch(dx_textures_xy[texture_style][texture_piece].Flip) + { + case 0: + quad[1]->u = 1.0; + quad[1]->v = 0.0; + quad[0]->u = 0.0; + quad[0]->v = 0.0; + quad[2]->u = 0.0; + quad[2]->v = 1.0; + + break; + case 1: //flip x + quad[1]->u = 0.0; + quad[1]->v = 0.0; + quad[0]->u = 1.0; + quad[0]->v = 0.0; + quad[2]->u = 1.0; + quad[2]->v = 1.0; + + break; + case 2: //flip y + quad[1]->u = 1.0; + quad[1]->v = 1.0; + quad[0]->u = 0.0; + quad[0]->v = 1.0; + quad[2]->u = 0.0; + quad[2]->v = 0.0; + + break; + case 3: //flip x+y + quad[1]->u = 0.0; + quad[1]->v = 1.0; + quad[0]->u = 1.0; + quad[0]->v = 1.0; + quad[2]->u = 1.0; + quad[2]->v = 0.0; + + break; + } + + + +// LogText("quad text page %d \n",page); + + return(page); + +} + +// +// should work for any angle +// +void build_fence_poles(float sx,float sy,float sz,float fdx,float fdz,SLONG count,float *rdx,float *rdz,SLONG style) +{ + float x[13],y[13],z[13]; + float dx,dz,nx,nz,dist; + float gx,gy,gz; + POLY_Point *quad[4]; + POLY_Point *tri[3]; + POLY_Point *pp; + + float dy; + + NIGHT_Colour col; + + col.red=64; + col.green=64; + col.blue=64; + + + x[0]=0; + y[0]=0; + z[0]=0; + +#ifdef TARGET_DC + dist=(fdx*fdx+fdz*fdz); + if(dist==0.0f) + return; + + dist = _InvSqrtA(dist); + + dx=(fdx)*dist; + dz=(fdz)*dist; +#else + dist=sqrt(fdx*fdx+fdz*fdz); + if(dist==0.0f) + return; + + dx=(fdx)/dist; + dz=(fdz)/dist; +#endif + + *rdx=dx; + *rdz=dz; + + nx=(dz*10.0f);// /1024; + nz=-(dx*10.0f); ///1204; + + x[1]=dx*20.0f; + y[1]=0.0f; + z[1]=dz*20.0f; + + x[2]=dx*10.0f+nx; + y[2]=0.0f; + z[2]=dz*10.0f+nz; + + + gx=sx; + gy=sy; + gz=sz; + + while(count-->0) + { + SLONG c0; + + POLY_buffer_upto = 0; + pp = &POLY_buffer[0]; + + dy= grid_height_at_world(gx,gz); + + // + // 3 points at base of pilla + // + for(c0=0;c0<3;c0++) + { + POLY_transform(gx+x[c0],gy+y[c0]+dy,gz+z[c0],pp); + + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + col, + &pp->colour, + &pp->specular); + + //POLY_fadeout_point(pp); + } + pp++; + } + + y[2]=-10.0; + // 3 points at middle + for(c0=0;c0<3;c0++) + { + POLY_transform(gx+x[c0],gy+y[c0]+dy+200.0f,gz+z[c0],pp); + + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + col, + &pp->colour, + &pp->specular); + + //POLY_fadeout_point(pp); + } + pp++; + } + y[2]=0.0; + + // point at top + POLY_transform(gx+x[2]+nx*5.0f,gy+y[2]+dy+250.0f,gz+z[2]+nz*5.0f,pp); + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + col, + &pp->colour, + &pp->specular); + + //POLY_fadeout_point(pp); + } + pp++; + + + + // + // 3 quads and 3 tris + // + + // 0 3 + // 2 5 6 + // 1 4 + { + SLONG q,t; + SLONG q_lookup[]={1,2,0}; + + for(q=0;q<3;q++) + { + + quad[0] = &POLY_buffer[3+q]; + quad[1] = &POLY_buffer[3+q_lookup[q]]; + quad[2] = &POLY_buffer[0+q]; + quad[3] = &POLY_buffer[0+q_lookup[q]]; + + if (POLY_valid_quad(quad)) + { + SLONG page; + + // + // Texture the quad. + // + + page=texture_quad2(quad,dstyles[style],TEXTURE_PIECE_MIDDLE2); + + POLY_add_quad(quad, page, 1); // 1 means perform a backface cull + } + + } + + + + tri[2] = &POLY_buffer[6]; + for(t=0;t<3;t++) + { + + tri[1] = &POLY_buffer[3+t]; + tri[0] = &POLY_buffer[3+q_lookup[t]]; + + if (POLY_valid_triangle(tri)) + { + SLONG page=0; + + // + // Texture the quad. + // + + page=texture_tri2(tri,dstyles[style],TEXTURE_PIECE_MIDDLE2); //TOP_LEFT); + + POLY_add_triangle(tri, page, 1); // 1 means perform a backface cull + } + + } + + + } + + gx+=fdx; + gz+=fdz; + + // end while + } +} + + + +void cable_draw(struct DFacet *p_facet) +{ + static const float width = 4.0F * 65536.0F /3.0F; // width of cable + + float x1,y1,z1; // start of cable + float x2,y2,z2; // end of cable + float dx,dy,dz; // section vector + SLONG count; // number of sections + float cx,cy,cz; // current point on cable + + SLONG angle; // current eccentricity angle + SLONG dangle1; // delta angle #1 + SLONG dangle2; // delta angle #2 + SLONG sag; // sagginess + + + POLY_flush_local_rot(); + + // + // setup + // + + x1 = p_facet->x[0] * 256; + y1 = p_facet->Y[0]; + z1 = p_facet->z[0] * 256; + + x2 = p_facet->x[1] * 256; + y2 = p_facet->Y[1]; + z2 = p_facet->z[1] * 256; + + count = p_facet->Height; + + dx = (x2 - x1) / count; + dy = (y2 - y1) / count; + dz = (z2 - z1) / count; + + cx = x1; + cy = y1; + cz = z1; + + angle = -512; + dangle1 = (SWORD)p_facet->StyleIndex; + dangle2 = (SWORD)p_facet->Building; + sag = p_facet->FHeight * 64; + + // + // generate points & transform them + // + + POLY_Point* pp; // point ptr + POLY_Point qp[4]; // quad points + POLY_Point* pqp[4]; // ptrs to quad points + + SLONG ii; + + POLY_buffer_upto = 0; + pp = &POLY_buffer[0]; + + float u = 0.0F; + float du = 1.0F / count; + + for (ii = 0; ii <= count; ii++) + { + float sagy = float((COS((angle+2048)&2047)*sag) >> 16); + + POLY_transform(cx, cy - sagy, cz, pp); + pp->u = u; + pp->v = 0.0; + NIGHT_get_d3d_colour( + NIGHT_get_light_at(cx, cy - sagy, cz), + &pp->colour, + &pp->specular); + //POLY_fadeout_point(pp); + + pp++; + + cx += dx; + cy += dy; + cz += dz; + + angle += dangle1; + if (angle >= -30) dangle1 = dangle2; + + u += du; + } + + // + // expand points to quads + // + + pqp[0] = &qp[3]; + pqp[1] = &qp[1]; + pqp[2] = &qp[2]; + pqp[3] = &qp[0]; + + pp = &POLY_buffer[0]; + + POLY_Point old[2]; + bool old_set = false; + + for (ii = 0; ii < count; ii++) + { + if (pp[0].IsValid() && pp[1].IsValid()) + { + POLY_create_cylinder_points(&pp[0], &pp[1], width, &qp[0]); + + // set V coords for envmap + qp[0].v = 0.0F; + qp[1].v = 1.0F; + qp[2].v = 0.0F; + qp[3].v = 1.0F; + + if (old_set) + { + // + // force coordinates to match up with last quad + // + + qp[0].X = old[0].X; + qp[0].Y = old[0].Y; + qp[1].X = old[1].X; + qp[1].Y = old[1].Y; + } + + if (POLY_valid_quad(pqp)) + { +#ifndef TARGET_DC + extern UBYTE sw_hack; + + if (sw_hack) + { + qp[0].colour = pp[0].colour; + qp[1].colour = pp[0].colour; + qp[2].colour = pp[1].colour; + qp[3].colour = pp[1].colour; + } + else +#endif + { + qp[0].colour = 0; + qp[1].colour = 0; + qp[2].colour = 0; + qp[3].colour = 0; + } + + POLY_add_quad(pqp, POLY_PAGE_COLOUR, false, true); + + qp[0].colour = pp[0].colour | 0xFF000000; + qp[1].colour = pp[0].colour | 0xFF000000; + qp[2].colour = pp[1].colour | 0xFF000000; + qp[3].colour = pp[1].colour | 0xFF000000; + POLY_add_quad(pqp, POLY_PAGE_ENVMAP, false, true); + } + + // + // save end coordinates for next quad + // + + old[0].X = qp[2].X; + old[0].Y = qp[2].Y; + old[1].X = qp[3].X; + old[1].Y = qp[3].Y; + old_set = true; + } + else + { + old_set = false; + } + pp++; + } +} + + +void DRAW_stairs(SLONG stair,SLONG storey,UBYTE fade) +{ + SLONG x,y,z; + SLONG prim=0; + SLONG dir,angle; + + x=inside_stairs[stair].X<<8; + z=inside_stairs[stair].Z<<8; + + y=inside_storeys[storey].StoreyY; + + if(inside_stairs[stair].UpInside) + prim|=1; + + if(inside_stairs[stair].DownInside) + prim|=2; + + switch(prim) + { + case 1: + prim=27; + break; + case 2: + prim=29; + break; + case 3: + prim=28; + break; + } + + dir=GET_STAIR_DIR(inside_stairs[stair].Flags); + switch(dir) + { + case 0: + //n + angle=0; + break; + case 1: + //e + angle=2048-512; + break; + case 2: + //s + angle=1024; + break; + case 3: + //w + angle=512; + break; + } + + if(prim) + { + MESH_draw_poly(prim,x,y,z,angle,0,0,0,fade); + } +} + +void draw_insides(SLONG indoor_index,SLONG room,UBYTE fade) +{ + struct InsideStorey *p_inside; + SLONG c0; + static int recursive=0; + SLONG stair; + ASSERT(recursive==0); + +// fade=128; + + recursive++; + p_inside=&inside_storeys[indoor_index]; +// MSG_add(" fade %d \n",INDOORS_INDEX_FADE); + for(c0=p_inside->FacetStart;c0FacetEnd;c0++) + { + FACET_draw(c0,fade); + } + stair=inside_storeys[indoor_index].StairCaseHead; + while(stair) + { + DRAW_stairs(stair,indoor_index,fade); + stair=inside_stairs[stair].NextStairs; + } + recursive--; +} + +// +// 1 2 +// 6 5 +// +// +// 0 7 4 3 + + +UBYTE door_poly[][4]= +{ + {0,1,7,6}, + {1,2,6,5}, + {2,3,5,4} +}; + +void DRAW_door(float sx,float sy,float sz,float fx,float fy,float fz,float block_height,SLONG count,ULONG fade_alpha,SLONG style,SLONG flipx=0) +{ + + float dy,dx,dz; + SLONG start_index; + SLONG page; + UBYTE flip; + + POLY_Point *pp,*ps; + POLY_Point *quad[4]; + SLONG c0,face; + + start_index=POLY_buffer_upto; + dy=block_height*0.7f; + + dx=fx*0.3f; + dz=fz*0.3f; + pp = &POLY_buffer[POLY_buffer_upto]; + ps=pp; + + POLY_transform(sx,sy,sz,pp++); + POLY_transform(sx,sy+block_height,sz,pp++); + POLY_transform(sx+fx,sy+block_height,sz+fz,pp++); + POLY_transform(sx+fx,sy,sz+fz,pp++); + POLY_transform(sx+fx-dx,sy,sz+fz-dz,pp++); + POLY_transform(sx+fx-dx,sy+dy,sz+fz-dz,pp++); + POLY_transform(sx+dx,sy+dy,sz+dz,pp++); + POLY_transform(sx+dx,sy,sz+dz,pp++); + + POLY_buffer_upto+=8; + + + for(c0=0;c0<8;c0++) + { + ps[c0].colour=0xffffff|fade_alpha; + ps[c0].specular=0xff000000; + + } + +SLONG get_texture_page(SLONG texture_style,SLONG pos,SLONG count,UBYTE *rflip); + page=get_texture_page(style,0,1,&flip); + + ps[0].u=0.0f; + ps[0].v=1.0f-0.0f; + + ps[1].u=0.0f; + ps[1].v=1.0f-1.0f; + + ps[2].u=1.0f; + ps[2].v=1.0f-1.0f; + + ps[3].u=1.0f; + ps[3].v=1.0f-0.0f; + + ps[4].u=0.7f; + ps[4].v=1.0f-0.0f; + + ps[5].u=0.7f; + ps[5].v=1.0f-0.7f; + + ps[6].u=0.3f; + ps[6].v=1.0f-0.7f; + + ps[7].u=0.3f; + ps[7].v=1.0f-0.0f; + + + if(flipx) + for(c0=0;c0<8;c0++) + { + ps[c0].u=1.0f-ps[c0].u; + + } + + for(face=0;face<3;face++) + { + for(c0=0;c0<4;c0++) + { + quad[c0] = &ps[door_poly[face][c0]];; + } + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, page, FALSE); // TRUE means perform a backface cull + } + } +} + +// +// draw the top of an inside wall +// + +void draw_wall_thickness(struct DFacet *p_facet,ULONG fade_alpha) +{ + POLY_Point* pp; + POLY_Point* quad[4]; + float x1,z1; + float x2,z2; + float y; + float dx,dz; + + static const ULONG colour = 0xFF8844; + + // get coordinates & vector along the facet + + y = float(p_facet->Y[0] + 256); + + x1 = float(p_facet->x[0] << 8); + z1 = float(p_facet->z[0] << 8); + + x2 = float(p_facet->x[1] << 8); + z2 = float(p_facet->z[1] << 8); + + dx = x2 - x1; + dz = z2 - z1; + + // generate dx,dy for segment (premultiplied by half the wall thickness) + + if (dz == 0) + { + dx = (dx < 0) ? -10 : +10; + } + else if (dx == 0) + { + dz = (dz < 0) ? -10 : +10; + } + else + { + float scalar = 10.0f / (float)sqrt(dx*dx+dz*dz); + + dx *= scalar; + dz *= scalar; + } + + // now, "along" vector is (dx,dz) and "perp" vector is (dz,-dx) + + pp = &POLY_buffer[POLY_buffer_upto++]; + + // pt 1: p1, along -1, perp +1 + POLY_transform(x1-dx+dz, y, z1-dz-dx, pp); + pp->colour = colour | fade_alpha; + pp->specular = 0xff000000; + + quad[0] = pp++; + + // pt2: p1, along -1, perp -1 + POLY_transform(x1-dx-dz, y, z1-dz+dx, pp); + pp->colour = colour | fade_alpha; + pp->specular = 0xff000000; + + quad[1] = pp++; + + // pt3: p2, along +1, perp +1 + POLY_transform(x2+dx+dz, y, z2+dz-dx, pp); + pp->colour = colour | fade_alpha; + pp->specular = 0xff000000; + + quad[2] = pp++; + + // pt4: p2, along +1, perp -1 + POLY_transform(x2+dx-dz, y, z2+dz+dx, pp); + pp->colour = colour | fade_alpha; + pp->specular = 0xff000000; + + quad[3] = pp; + + // draw the quad + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE); // TRUE means perform a backface cull + } +} + +void FACET_barbedwire_top(struct DFacet *p_facet) +{ + float dx=(p_facet->x[1]-p_facet->x[0] << 8); + float dy=(p_facet->Y[1]-p_facet->Y[0]); + float dz=(p_facet->z[1]-p_facet->z[0] << 8); + float mag=sqrt((dx*dx)+(dz*dz)); + float stepx=(dx/mag)*10; + float stepy=(dy/mag)*10; + float stepz=(dz/mag)*10; + SLONG cx=p_facet->x[0] << 8; + SLONG cy=p_facet->Y[0]; + SLONG cz=p_facet->z[0] << 8; + SLONG seed=54321678; + float base=0; + SLONG contour = 0; + float block_height=256.0; + float height; + ULONG normal=0; + + POLY_set_local_rotation_none(); + + if(p_facet->FacetType==STOREY_TYPE_NORMAL) + { + block_height=p_facet->BlockHeight<<4; + height=(p_facet->Height*block_height)*0.25f; + normal=1; + contour=90; + } + else + { + height=(64*p_facet->Height); + } + + + while (baseFacetFlags & FACET_FLAG_ONBUILDING)) + { + //contour = PAP_calc_map_height_at(cx,cz); + contour = PAP_calc_height_noroads(cx,cz); + } + else + { + contour = p_facet->Y[0]; + } + } + + SPRITE_draw_tex( + cx, + height-64+((seed>>8)&0xf) + contour, + cz, + 50, + 0xffffff, + 0, + POLY_PAGE_BARBWIRE, + 0.0, 0.0, 1.0, 1.0, + SPRITE_SORT_NORMAL); + + + base+=10; + cx+=stepx; + cy+=stepy; + cz+=stepz; + } + +} + +extern UBYTE AENG_transparent_warehouses; + +SWORD FacetRows[100]; +float FacetDiffY[128]; + +static void MakeFacetPoints(float sx, float sy, float sz, float dx, float dz, float block_height, + SLONG height, SLONG max_height, NIGHT_Colour* col, SLONG foundation, SLONG count, SLONG invisible,SLONG hug) +{ + SLONG hf = 0; + + ASSERT(POLY_buffer_upto == 0); // or else FacetDiffY is accessed wrongly + + while (height >= 0) + { + float x = sx; + float y = sy; + float z = sz; + + FacetRows[hf] = POLY_buffer_upto; + + for (SLONG c0 = count; c0 > 0; c0--) + { + float ty; + + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + POLY_Point* pp = &POLY_buffer[POLY_buffer_upto++]; + + if(hug) + { + + ty = float(PAP_2HI(SLONG(x) >> 8, SLONG(z) >> 8).Alt << 3); + ty+=y; + + } + else + if (foundation != 2) + { + ty=y; + } + else + { + ty = float(PAP_2HI(SLONG(x) >> 8, SLONG(z) >> 8).Alt << 3); + + FacetDiffY[POLY_buffer_upto - 1] = ( ( y - ty ) * ( 1.0f / 256.0f ) ) + 1.0f; + } + + POLY_transform_c_saturate_z(x,ty,z, pp); + + if (pp->MaybeValid()) + { + if (INDOORS_INDEX) + { + NIGHT_get_d3d_colour_dim(*col, &pp->colour, &pp->specular); + } + else + { + NIGHT_get_d3d_colour(*col, &pp->colour, &pp->specular); + } + + //apply_cloud(SLONG(x), SLONG(ty), SLONG(z), &pp->colour); + + //POLY_fadeout_point(pp); + +#if defined(FACET_REMOVAL_TEST) || defined(_DEBUG) + + // colour invisible facets red + if (invisible) + { + pp->colour = 0xFF0000; + pp->specular = 0xFF000000; + } +#endif + } + +#if 0 + if (((pp->clip & POLY_CLIP_LEFT) && (pp->clip & POLY_CLIP_TRANSFORMED) && (c0 < count) && (pp[-1].clip & POLY_CLIP_TRANSFORMED) && (pp->X < pp[-1].X)) || // off left and going left + ((pp->clip & POLY_CLIP_RIGHT) && (pp->clip & POLY_CLIP_TRANSFORMED) && (c0 < count) && (pp[-1].clip & POLY_CLIP_TRANSFORMED) && (pp->X > pp[-1].X))) // off right and going right + { + col += c0; + break; + } +#endif + + x += dx; + z += dz; + col++; + } + sy += block_height; + height -= 4; + hf++; + foundation--; + if (sy > max_height) break; + } + FacetRows[hf] = POLY_buffer_upto; + +} + + +static void MakeFacetPointsFence(float sx, float sy, float sz, float dx, float dz, float block_height, + SLONG height, SLONG max_height, NIGHT_Colour* col, SLONG foundation, SLONG count, SLONG invisible,float *diff_y) +{ + SLONG hf = 0; + float *p_diffy; + + + + ASSERT(POLY_buffer_upto == 0); // or else FacetDiffY is accessed wrongly + + while (height >= 0) + { + float x = sx; + float y = sy; + float z = sz; + p_diffy=diff_y; + FacetRows[hf] = POLY_buffer_upto; + + for (SLONG c0 = count; c0 > 0; c0--) + { + float ty; + + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + POLY_Point* pp = &POLY_buffer[POLY_buffer_upto++]; + + { + ty=y+*p_diffy; + p_diffy++; + POLY_transform_c_saturate_z(x,ty,z, pp); + } + + if (pp->MaybeValid()) + { + { + NIGHT_get_d3d_colour(*col, &pp->colour, &pp->specular); + } + + { + // apply_cloud(SLONG(x), SLONG(ty), SLONG(z), &pp->colour); + } + + //POLY_fadeout_point(pp); + +#if defined(FACET_REMOVAL_TEST) || defined(_DEBUG) + + // colour invisible facets red + if (invisible) + { + pp->colour = 0xFF0000; + pp->specular = 0xFF000000; + } +#endif + } + + + x += dx; + z += dz; + col++; + } + sy += block_height; + height -= 4; + hf++; + foundation--; + if (sy > max_height) break; + } + FacetRows[hf] = POLY_buffer_upto; +} + +static void FillFacetPoints(SLONG count, ULONG base_row, SLONG foundation, SLONG facet_backwards, SLONG style_index, float block_height,SLONG reverse_texture) +{ + POLY_Point* quad[4]; + + SLONG row1 = FacetRows[base_row]; + SLONG row2 = FacetRows[base_row+1]; + + for (SLONG c0 = 0; c0 < row2 - row1 - 1; c0++) + { + if (facet_backwards) + { + quad[0] = &POLY_buffer[row2+c0]; + quad[1] = &POLY_buffer[row2+c0+1]; + quad[2] = &POLY_buffer[row1+c0]; + quad[3] = &POLY_buffer[row1+c0+1]; + } + else + { + quad[0] = &POLY_buffer[row2+c0+1]; + quad[1] = &POLY_buffer[row2+c0]; + quad[2] = &POLY_buffer[row1+c0+1]; + quad[3] = &POLY_buffer[row1+c0]; + } + + if (POLY_valid_quad(quad)) + { + SLONG page; + if(reverse_texture) + page = texture_quad(quad, dstyles[style_index], count-2-c0, count,1); + else + page = texture_quad(quad, dstyles[style_index], c0, count); + + if(block_height!=256.0f) + { + if(block_height==192.0f) + { + quad[2]->v=0.75f; + quad[3]->v=0.75f; + } + else if(block_height==128.0f) + { + quad[2]->v=0.5f; + quad[3]->v=0.5f; + } + else if(block_height==64.0f) + { + quad[2]->v=0.25f; + quad[3]->v=0.25f; + } + } + + if (foundation == 2) + { + quad[3]->v = FacetDiffY[c0]; + quad[2]->v = FacetDiffY[c0+1]; + + // This doesn't work with texture paging. + //POLY_Page[page].RS.WrapJustOnce(); + + // So we panic and clamp to 1.0. Pants stretchy effect, but better than + // going on to the next bit of the page. + if ( quad[3]->v > 1.0f ) + { + quad[3]->v = 1.0f; + } + if ( quad[2]->v > 1.0f ) + { + quad[2]->v = 1.0f; + } + + } + + // + // Add crinkle? + // +extern int AENG_detail_crinkles; + if (AENG_detail_crinkles) + { + if (page < 64 * 8) + { + if (TEXTURE_crinkle[page]) + { + // + // This quad could be crinkled! + // + + if (quad[0]->z > 0.6F) + { + // + // Too far away to be crinkled. + // + } + else + if (quad[0]->z < 0.3F) + { + // + // Maximum crinkleyness! + // + + CRINKLE_do( + TEXTURE_crinkle[page], + page, + 1.0F, + quad, + flip); + + goto added_crinkle; + } + else + { + float extrude; + float av_z; + + // + // Intermediate crinkle extrusion. + // + + // av_z = quad[0]->z + quad[1]->z + quad[2]->z + quad[3]->z; + // av_z *= 0.25F; + + av_z = quad[0]->z; + + extrude = av_z - 0.5F; + extrude *= 1.0F / (0.4F - 0.5F); + + if (extrude > 0.0F) + { + if (extrude > 1.0F) + { + extrude = 1.0F; + } + + CRINKLE_do( + TEXTURE_crinkle[page], + page, + extrude, + quad, + flip); + + goto added_crinkle; + } + } + } + } + } + + POLY_add_quad(quad, page, TRUE); // TRUE means perform a backface cull + + added_crinkle:; + } + else + { + // + // Even though we don't draw the quad, we must + // push on the random number generator. + // + + facet_rand(); + } + } + for (;c0 < count; c0++) + { + facet_rand(); + } +} + + + + + + +// Like MakeFacetPoints, but used in the most common cases. +inline void MakeFacetPointsCommon(float sx, float sy, float sz, float dx, float dz, float block_height, + SLONG height, NIGHT_Colour* col, SLONG foundation, SLONG count, SLONG hug) +{ + SLONG hf = 0; + + + + + LOG_ENTER ( Facet_MakeFacetPoints ) + + ASSERT(POLY_buffer_upto == 0); // or else FacetDiffY is accessed wrongly + + while (height >= 0) + { + float x = sx; + float y = sy; + float z = sz; + + FacetRows[hf] = POLY_buffer_upto; + + for (SLONG c0 = count; c0 > 0; c0--) + { + float ty; + + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + POLY_Point* pp = &POLY_buffer[POLY_buffer_upto++]; + + if(hug) + { + + ty = float(PAP_2HI(SLONG(x) >> 8, SLONG(z) >> 8).Alt << 3); + ty+=y; + + } + else + if (foundation != 2) + { + ty=y; + } + else + { + ty = float(PAP_2HI(SLONG(x) >> 8, SLONG(z) >> 8).Alt << 3); + + FacetDiffY[POLY_buffer_upto - 1] = ( ( y - ty ) * ( 1.0f / 256.0f ) ) + 1.0f; + } + + POLY_transform_c_saturate_z(x,ty,z, pp); + + if (pp->MaybeValid()) + { + if (INDOORS_INDEX) + { + NIGHT_get_d3d_colour_dim(*col, &pp->colour, &pp->specular); + } + else + { + NIGHT_get_d3d_colour(*col, &pp->colour, &pp->specular); + } + + //apply_cloud(SLONG(x), SLONG(ty), SLONG(z), &pp->colour); + + //POLY_fadeout_point(pp); + + } + + x += dx; + z += dz; + col++; + } + sy += block_height; + height -= 4; + hf++; + foundation--; + } + FacetRows[hf] = POLY_buffer_upto; + + LOG_EXIT ( Facet_MakeFacetPoints ) + +} + + + + +// Like FillFacetPoints, but used in the most common cases. +inline void FillFacetPointsCommon(SLONG count, ULONG base_row, SLONG foundation, SLONG style_index, float block_height ) +{ + POLY_Point* quad[4]; + + LOG_ENTER ( Facet_FillFacetPoints ) + + SLONG row1 = FacetRows[base_row]; + SLONG row2 = FacetRows[base_row+1]; + + #ifdef FACETINFO + FACET_Facetinfo *ff; + #endif + + for (SLONG c0 = 0; c0 < row2 - row1 - 1; c0++) + { + { + quad[0] = &POLY_buffer[row2+c0+1]; + quad[1] = &POLY_buffer[row2+c0]; + quad[2] = &POLY_buffer[row1+c0+1]; + quad[3] = &POLY_buffer[row1+c0]; + } + + if (POLY_valid_quad(quad)) + { + SLONG page; + page = texture_quad(quad, dstyles[style_index], c0, count); + + #ifdef FACETINFO + + if (FACET_facetinfo[FACET_facetinfo_current].done) + { + // + // Already got facet info for this facet. + // + } + else + { + ASSERT(WITHIN(FACET_facetinfo_current, 0, FACET_MAX_FACETINFO - 1)); + + ff = &FACET_facetinfo[FACET_facetinfo_current]; + + SLONG i; + + for (i = 0; i < ff->num_pages; i++) + { + if (ff->page[i].page == page) + { + ff->page[i].quads += 1; + + goto found_page1; + } + } + + ASSERT(WITHIN(ff->num_pages, 0, FACET_MAX_PAGEINFO_PER_FACET - 1)); + + ff->page[ff->num_pages].page = page; + ff->page[ff->num_pages].quads = 1; + + ff->num_pages += 1; + + found_page1:; + } + + #endif + + if(block_height!=256.0f) + { + float fTemp = (float)block_height * ( 1.0f / 256.0f ); + quad[2]->v = fTemp; + quad[3]->v = fTemp; + /* + if(block_height==192.0f) + { + quad[2]->v=0.75f; + quad[3]->v=0.75f; + } + else if(block_height==128.0f) + { + quad[2]->v=0.5f; + quad[3]->v=0.5f; + } + else if(block_height==64.0f) + { + quad[2]->v=0.25f; + quad[3]->v=0.25f; + } + */ + } + + if (foundation == 2) + { + quad[3]->v = FacetDiffY[c0]; + quad[2]->v = FacetDiffY[c0+1]; + + POLY_Page[page].RS.WrapJustOnce(); + } + + // + // Add crinkle? + // +extern int AENG_detail_crinkles; + if (AENG_detail_crinkles && (GAME_TURN & 0x20)) + { + if (page < 64 * 8) + { + if (TEXTURE_crinkle[page]) + { + // + // This quad could be crinkled! + // + + if (quad[0]->z > 0.6F) + { + // + // Too far away to be crinkled. + // + } + else + if (quad[0]->z < 0.3F) + { + // + // Maximum crinkleyness! + // + + CRINKLE_do( + TEXTURE_crinkle[page], + page, + 1.0F, + quad, + flip); + + goto added_crinkle_common; + } + else + { + float extrude; + float av_z; + + // + // Intermediate crinkle extrusion. + // + + // av_z = quad[0]->z + quad[1]->z + quad[2]->z + quad[3]->z; + // av_z *= 0.25F; + + av_z = quad[0]->z; + + extrude = av_z - 0.5F; + extrude *= 1.0F / (0.4F - 0.5F); + + if (extrude > 0.0F) + { + if (extrude > 1.0F) + { + extrude = 1.0F; + } + + CRINKLE_do( + TEXTURE_crinkle[page], + page, + extrude, + quad, + flip); + + goto added_crinkle_common; + } + } + } + } + } + else + { + if (page < 512 && SUPERCRINKLE_IS_CRINKLED(page)) + { + float world_x; + float world_y; + float world_z; + + world_x = quad[3]->x; + world_y = quad[3]->y; + world_z = quad[3]->z; + + extern float AENG_cam_matrix[9]; + extern float POLY_cam_over_view_dist; + extern float POLY_cam_aspect; + extern float POLY_cam_lens; + + MATRIX_MUL_BY_TRANSPOSE( + AENG_cam_matrix, + world_x, + world_y, + world_z); + + world_x /= POLY_cam_over_view_dist; + world_y /= POLY_cam_over_view_dist; + world_z /= POLY_cam_over_view_dist; + + world_x /= POLY_cam_aspect; + + world_x /= POLY_cam_lens; + world_y /= POLY_cam_lens; + + world_x += POLY_cam_x; + world_y += POLY_cam_y; + world_z += POLY_cam_z; + + POLY_set_local_rotation( + world_x, + world_y, + world_z, + FACET_direction_matrix); + + ULONG colour [4] = {quad[0]->colour, quad[1]->colour, quad[2]->colour, quad[3]->colour }; + ULONG specular[4] = {quad[0]->specular, quad[1]->specular, quad[2]->specular, quad[3]->specular}; + + if (SUPERCRINKLE_draw(page, colour, specular)) + { + goto added_crinkle_common; + } + } + } + + + + // I don't think we need to backface cull - should already have been done for the whole facet. + //POLY_add_quad(quad, page, TRUE); // TRUE means perform a backface cull + POLY_add_quad(quad, page, FALSE); + +added_crinkle_common:; + } + else + { + // + // Even though we don't draw the quad, we must + // push on the random number generator. + // + + #ifdef FACETINFO + + SLONG page; + page = texture_quad(quad, dstyles[style_index], c0, count); + + if (FACET_facetinfo[FACET_facetinfo_current].done) + { + // + // Already got facet info for this facet. + // + } + else + { + ASSERT(WITHIN(FACET_facetinfo_current, 0, FACET_MAX_FACETINFO - 1)); + + ff = &FACET_facetinfo[FACET_facetinfo_current]; + + SLONG i; + + for (i = 0; i < ff->num_pages; i++) + { + if (ff->page[i].page == page) + { + ff->page[i].quads += 1; + + goto found_page2; + } + } + + ASSERT(WITHIN(ff->num_pages, 0, FACET_MAX_PAGEINFO_PER_FACET - 1)); + + ff->page[ff->num_pages].page = page; + ff->page[ff->num_pages].quads = 1; + + ff->num_pages += 1; + + found_page2:; + } + + #else + + facet_rand(); + + #endif + } + } + for (;c0 < count; c0++) + { + #ifdef FACETINFO + + SLONG page; + page = texture_quad(quad, dstyles[style_index], c0, count); + + if (FACET_facetinfo[FACET_facetinfo_current].done) + { + // + // Already got facet info for this facet. + // + } + else + { + ASSERT(WITHIN(FACET_facetinfo_current, 0, FACET_MAX_FACETINFO - 1)); + + ff = &FACET_facetinfo[FACET_facetinfo_current]; + + SLONG i; + + for (i = 0; i < ff->num_pages; i++) + { + if (ff->page[i].page == page) + { + ff->page[i].quads += 1; + + goto found_page3; + } + } + + ASSERT(WITHIN(ff->num_pages, 0, FACET_MAX_PAGEINFO_PER_FACET - 1)); + + ff->page[ff->num_pages].page = page; + ff->page[ff->num_pages].quads = 1; + + ff->num_pages += 1; + + found_page3:; + } + + #else + + facet_rand(); + + #endif + } + + LOG_EXIT ( Facet_FillFacetPoints ) +} + + + + + + + + +extern UWORD fade_black; + +void FACET_draw_quick(SLONG facet,UBYTE alpha) +{ + POLY_Point *pp; + POLY_Point *quad[4]; + float fx1,fx2,fz1,fz2,fy1,fy2,height; + ULONG col=0xff000000; + struct DFacet *p_facet; + + + p_facet=&dfacets[facet]; + if(allow_debug_keys) + if (Keys[KB_P1]) + { + col = 0xFF200000; + } + + switch(p_facet->FacetType) + { + case STOREY_TYPE_FENCE: + case STOREY_TYPE_FENCE_FLAT: + case STOREY_TYPE_NORMAL: + + fx1=p_facet->x[0]<<8; + fx2=p_facet->x[1]<<8; + fz1=p_facet->z[0]<<8; + fz2=p_facet->z[1]<<8; + + fy1=p_facet->Y[0]; + fy2=fy1+p_facet->Height*p_facet->BlockHeight*4; + + + POLY_buffer_upto=0; + pp = &POLY_buffer[POLY_buffer_upto]; + + POLY_transform(fx2,fy2,fz2,pp); + if (pp->clip & POLY_CLIP_NEAR) return; + if (pp->MaybeValid()) + { + pp->colour=col; + //pp->colour = 0xff000000; + pp->specular=0; + pp->z=0.99999f; + pp->Z=0.00001f; + pp->u=0.5f; + pp->v=0.5f; + } + pp++; + POLY_transform(fx1,fy2,fz1,pp); + if (pp->clip & POLY_CLIP_NEAR) return; + if (pp->MaybeValid()) + { + pp->colour=col; + //pp->colour = 0x00ff0000; + pp->specular=0; + pp->z=0.99999f; + pp->Z=0.00001f; + pp->u=0.5f; + pp->v=0.5f; + } + pp++; + POLY_transform(fx2,fy1,fz2,pp); + if (pp->clip & POLY_CLIP_NEAR) return; + if (pp->MaybeValid()) + { + pp->colour=col; + //pp->colour = 0xff00; + pp->specular=0; + pp->z=0.99999f; + pp->Z=0.00001f; + pp->u=0.5f; + pp->v=0.5f; + } + pp++; + POLY_transform(fx1,fy1,fz1,pp); + if (pp->clip & POLY_CLIP_NEAR) return; + if (pp->MaybeValid()) + { + pp->colour=col; + //pp->colour = 0xff; + pp->specular=0; + pp->z=0.99999f; + pp->Z=0.00001f; + pp->u=0.5f; + pp->v=0.5f; + } + pp++; + + quad[0]=&POLY_buffer[0]; + quad[1]=&POLY_buffer[1]; + quad[2]=&POLY_buffer[2]; + quad[3]=&POLY_buffer[3]; + + // add with no back-facing culling and no clip flag generation + // clip flags should be correct already; back-face culling ruins + // the render (since tops of buildings aren't plotted) + if (POLY_valid_quad(quad)) + POLY_add_quad(quad, POLY_PAGE_COLOUR_WITH_FOG, 0,0); + break; + } + +} + + + + +// Handles all sorts of facets - called by FACET_draw in those cases. +void FACET_draw_rare(SLONG facet,UBYTE alpha) +{ + struct DFacet *p_facet; + static SWORD rows[100]; + SLONG c0,count; + SLONG dx,dz; + float x,y,z,sx,sy,sz,fdx,fdz; + SLONG height; + POLY_Point *pp; + SLONG hf; + POLY_Point *quad[4]; + SLONG style_index; + NIGHT_Colour *col; + SLONG max_height; + SLONG foundation=0; + static float diff_y[128]; + float block_height=256.0; + + SLONG diag=0; + SLONG facet_backwards=0; + ULONG fade_alpha=alpha<<24; + SLONG inside_clip=0; + SLONG reverse_textures=0; + SLONG style_index_offset=1; + SLONG style_index_step=2; +#ifdef UNUSED_WIRECUTTERS + SLONG fence_gap,fence_gap_compare; //GAME_TURN&0xff; +#endif + SLONG flipx=0; + + + #define MAX_SHAKE 32 + + + // Deal with internal gubbins. + POLY_set_local_rotation_none(); + POLY_flush_local_rot(); + + + static float shake[MAX_SHAKE] = + { + 0,0,0,0, + +1,-2,+1,-1, + +3,-3,+2,-2, + +4,-3,+2,-4, + +5,-5,+5,-4, + +6,-4,+7,-6, + +7,-6,+8,-9, + +9,-7,+8,-9, + }; + + ASSERT(facet>0&&facetFacetFlags&FACET_FLAG_INVISIBLE) + { + return; + } + +#ifdef QUICK_FACET + draw_quick_facet(p_facet); + return; +#endif + +// if(facet==114 || facet==115 || facet==2037 ||facet==2036) +// return; +#ifdef UNUSED_WIRECUTTERS + fence_gap=get_fence_hole(p_facet); +#endif + + + + + if(INDOORS_DBUILDING==p_facet->Building && INDOORS_INDEX) + inside_clip=1; + + if(facet==1) + { +// MSG_add("style %d \n",p_facet->StyleIndex); + } + + // + //Some types dont need back face culling + // + switch(p_facet->FacetType) + { + case STOREY_TYPE_CABLE: + cable_draw(p_facet); + return; + break; + } + +#ifndef TARGET_DC + #ifndef NDEBUG + + // + // For the editors... + // + + if (dbuildings[p_facet->Building].Type == BUILDING_TYPE_WAREHOUSE) + { + if (AENG_transparent_warehouses) + { + return; + } + } + + #endif +#endif + + // + // Should we bother drawing this facet? + // + +#ifdef FACET_REMOVAL_TEST + + // test + // + // normally only show invisible facets; press F to + // remove invisible and show visible ones + + if (Keys[KB_F] && p_facet->Invisible) + { + return; + } + if (!Keys[KB_F] && !p_facet->Invisible) + { + return; + } + +#endif + + if ((p_facet->FacetType == STOREY_TYPE_FENCE || + p_facet->FacetType == STOREY_TYPE_FENCE_FLAT || + p_facet->FacetType == STOREY_TYPE_FENCE_BRICK || + p_facet->FacetType == STOREY_TYPE_INSIDE || +// p_facet->FacetType == STOREY_TYPE_OINSIDE || + p_facet->FacetType == STOREY_TYPE_INSIDE_DOOR || + p_facet->FacetType == STOREY_TYPE_OUTSIDE_DOOR || + p_facet->FacetType == STOREY_TYPE_LADDER) + && !(p_facet->FacetFlags&FACET_FLAG_2SIDED)) // actually brick is barbed wire... + { + // 2sided flag means textured for both sides, if its textued on both sideds then you need to + // do a backface cull to decide which side you are drawing + + + // + // These facets are double-sided so they can't be backface culled. + // + } + else + if (p_facet->FacetType == STOREY_TYPE_JUST_COLLISION) + { + // + // Don't draw these. + // + +//#define WE_WANT_TO_DRAW_THESE_FACET_LINES 1 + #if WE_WANT_TO_DRAW_THESE_FACET_LINES + + AENG_world_line_infinite( + p_facet->X[0], + p_facet->Y[0], + p_facet->Z[0], + 128, + 0x00ffff00, + p_facet->X[1], + p_facet->Y[1], + p_facet->Z[1], + 0, + 0x00444488, + TRUE); + + #endif + + return; + } + else + { + // + // Backface cull the entire facet? + // + + float x1, z1; + float x2, z2; + + float vec1x; + float vec1z; + + float vec2x; + float vec2z; + + float cprod; + + x1 = float(p_facet->x[0] << 8); + z1 = float(p_facet->z[0] << 8); + + x2 = float(p_facet->x[1] << 8); + z2 = float(p_facet->z[1] << 8); + + vec1x = x2 - x1; + vec1z = z2 - z1; + + vec2x = POLY_cam_x - x1; + vec2z = POLY_cam_z - z1; + + cprod = vec1x*vec2z - vec1z*vec2x; + + if (cprod >= 0) + { + // + // We've got rid of a whole facet :o) + // + + if((p_facet->FacetFlags&FACET_FLAG_2SIDED) || p_facet->FacetType == STOREY_TYPE_OINSIDE) + { + //except its textured on the other side + facet_backwards=1; + } + else + { + // + // draw the barbedwire on the top of backface culled normal facets + // + if(p_facet->FacetFlags&FACET_FLAG_BARB_TOP) + FACET_barbedwire_top(p_facet); + + return; + } + } + else + { + // if OINSIDE, we don't draw it (there's another facet + // for the outside wall) *but* we still need its thickness + if (p_facet->FacetType == STOREY_TYPE_OINSIDE) + { + draw_wall_thickness(p_facet,fade_alpha); + return; //only draw the 'other' side of these facets + } + } + } + + // + // Transform the bounding box of the facet to quickly try and reject the + // entire facet. + // + + if (abs(p_facet->x[1] - p_facet->x[0]) + + abs(p_facet->z[1] - p_facet->z[0]) <= 2) + { + // + // Too small the bother with the rejection test? + // Nah! just do the rejection test anyway... + // + } + + if (p_facet->FacetType == STOREY_TYPE_OUTSIDE_DOOR) + { + // + // We can't do this rejection test because the fence might be + // open or closed. + // +#ifdef EDITOR + extern BOOL is_in_mission_editor; + + if (is_in_mission_editor) + { + p_facet->Open += 1; + + if (p_facet->FacetFlags & FACET_FLAG_90DEGREE) + { + if (p_facet->Open > 120) + { + p_facet->Open = 0; + } + } + } +#endif + } + else + { + + SLONG i; + + ULONG clip; + ULONG clip_and; + ULONG clip_or; + + POLY_Point bound; + + float x; + float y; + float z; + + float x1 = float(p_facet->x[0] << 8); + float y1 = float(p_facet->Y[0]); + float z1 = float(p_facet->z[0] << 8); + + float x2 = float(p_facet->x[1] << 8); + float y2 = float(p_facet->Y[1]) + float(p_facet->Height * 64); + float z2 = float(p_facet->z[1] << 8); + + clip_or = 0x00000000; + clip_and = 0xffffffff; + + for (i = 0; i < 4; i++) + { + x = (i & 0x1) ? x1 : x2; + y = (i & 0x2) ? y1 : y2; + z = (i & 0x1) ? z1 : z2; + + POLY_transform_c_saturate_z(x, y, z, &bound); + + clip = bound.clip; + + if ((clip & POLY_CLIP_TRANSFORMED) && !(clip & POLY_CLIP_OFFSCREEN)) + { + // + // Draw the whole facet because this point is on-screen. + // + + goto draw_the_facet; + } + + clip_and &= clip; + clip_or |= clip; + } + + if (clip_and & POLY_CLIP_OFFSCREEN) + { + // + // Reject the whole facet. + // + + return; + } + + if (!(clip_or & POLY_CLIP_TRANSFORMED)) + { + // + // Reject the whole facet if all points are too far or all points are too near + // + if(clip_and & (POLY_CLIP_NEAR|POLY_CLIP_FAR)) + { + return; + } + } + + draw_the_facet:; + } + + // + // Draw the facet. + // + + dfacets_drawn_this_gameturn += 1; + + if (p_facet->FacetType == STOREY_TYPE_LADDER) + { + // + // This is a ladder, and it is drawn with its + // own special routine. + // + + POLY_flush_local_rot(); + DRAW_ladder(p_facet); + + return; + } + + POLY_buffer_upto = 0; + + style_index=p_facet->StyleIndex; + + // + // Should this be passed an x,y,z to be relative to? Nah! + // + + set_facet_seed(p_facet->x[0] * p_facet->z[0] + p_facet->Y[0]); + + // + // If we are drawing the building we are in, dont draw + // the building above the ceiling. + // + + if (GAME_FLAGS & GF_INDOORS) + { + max_height = INDOORS_HEIGHT_CEILING; + } + else + { + max_height = INFINITY; + } + + // + // If there is no cached lighting for this facet, then we + // must make some. + // + + if (p_facet->Dfcache == 0) + { + // I've just seen how this work's and I'm scared + // looks like NIGHT_dfcache_create has to completely understand how to build any facet + // like the fence struts I've just crafted... + + p_facet->Dfcache = NIGHT_dfcache_create(facet); + + if (p_facet->Dfcache == NULL) + { + return; + } + } + + ASSERT(WITHIN(p_facet->Dfcache, 1, NIGHT_MAX_DFCACHES - 1)); + + col = NIGHT_dfcache[p_facet->Dfcache].colour; + + dx = (p_facet->x[1]-p_facet->x[0]) << 8; + dz = (p_facet->z[1]-p_facet->z[0]) << 8; + + sx = float(p_facet->x[0] << 8); + sy = float(p_facet->Y[0] ); + sz = float(p_facet->z[0] << 8); +/* + if(dz) + return; + + if(sy>256.0) // || sy>513.0) + return; + */ + + height=p_facet->Height; + // if(height!=12) + // return; + + if(dx&&dz) + { + LogText(" diagonal wall \n"); + if(p_facet->FacetType==STOREY_TYPE_NORMAL) + { + ASSERT(0); + } + + + + { + SLONG len; + SLONG adx,adz; + + adx=abs(dx); + adz=abs(dz); + len=QDIST2(adx,adz); + count=len>>8; + if(count==0) + count=1; + + fdx=(float)dx/(float)count; + fdz=(float)dz/(float)count; + + diag=0; + + } + +// return; + } + else + { + if(dx) + { + count=abs(dx)>>8; + if(dx>0) + dx=256; + else + dx=-256; + } + else + { + count=abs(dz)>>8; + if(dz>0) + dz=256; + else + dz=-256; + } + + fdx=(float)dx; + fdz=(float)dz; + + if (p_facet->Open) + { + float rdx; + float rdz; + float angle = float(p_facet->Open) * (PI / 256.0F); + + // + // Open the facet! + // + + rdx = cos(angle) * fdx + sin(angle) * fdz; + rdz = -sin(angle) * fdx + cos(angle) * fdz; + + fdx = rdx; + fdz = rdz; + } + } + + count++; +/* + + { + CBYTE str[10]; + sprintf(str,"facet %d h %d bs %d",facet,p_facet->Height,p_facet->BlockHeight); + +extern FONT2D_DrawString_3d(CBYTE*str, ULONG world_x, ULONG world_y,ULONG world_z, ULONG rgb, SLONG text_size, SWORD fade); + FONT2D_DrawString_3d(str,p_facet->x[0]<<8,p_facet->Y[0],p_facet->z[0]<<8,0xff0000,60,0); + } +*/ + + + + + // + // Work out the height offset for each point along a fence. + // + + switch(p_facet->FacetType) + { + case STOREY_TYPE_FENCE: + case STOREY_TYPE_FENCE_FLAT: + case STOREY_TYPE_FENCE_BRICK: + case STOREY_TYPE_OUTSIDE_DOOR: + + { + float *p_diffy; + float dy; + + p_diffy=diff_y; + + x=sx; + y=sy; + z=sz; + c0=count; + while(c0-->0) + { + if (p_facet->FacetFlags & FACET_FLAG_ONBUILDING) + { + // + // No offset for building facets. + // + + *p_diffy++ = p_facet->Y[0]; + } + else + { + if(diag) + { + dy=(float)PAP_calc_height_noroads((SLONG)x,(SLONG)z); + } + else + { + dy=grid_height_at_world(x,z); + } + *p_diffy=dy; + + p_diffy++; + + x += fdx; + z += fdz; + } + } + } + break; + } + + + //MSG_add(" facet %d draw count %d\n",facet,count); + + switch(p_facet->FacetType) + { + case STOREY_TYPE_CABLE: + cable_draw(p_facet); + break; + case STOREY_TYPE_INSIDE_DOOR: + if(facet_backwards && (p_facet->FacetFlags&FACET_FLAG_2SIDED)) + style_index++; + if(facet_backwards) + { + + DRAW_door(sx,sy,sz,fdx,256.0,fdz,block_height,count,fade_alpha,dstyles[style_index],1); + } + else + { + DRAW_door(sx,sy,sz,fdx,256.0,fdz,block_height,count,fade_alpha,dstyles[style_index],0); + } + break; + case STOREY_TYPE_OINSIDE: + + style_index--; +// ASSERT(0); + + case STOREY_TYPE_INSIDE: + draw_wall_thickness(p_facet,fade_alpha); + if(facet_backwards) + { + flipx=1; + if(!ShiftFlag) + style_index++; + } + + hf=0; + while(height>=0) + { + x=sx; + y=sy; + z=sz; + rows[hf]=POLY_buffer_upto; + c0=count; + while(c0-->0) + { + + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform(x,y,z,pp); + + if (pp->MaybeValid()) + { + + NIGHT_get_d3d_colour( + *col, + &pp->colour, + &pp->specular); + //POLY_fadeout_point(pp); + + pp->colour|=fade_alpha; +// pp->specular=0xff000000; + } + + x += fdx; + z += fdz; + col += 1; + } + + if(hf>0) + { + SLONG row1,row2; + + row1=rows[hf-1]; + row2=rows[hf]; + + // + // create the quads and submit them for drawing + // + + c0=0; //count-1; + while(c0v=diff_y[c0]/256.0f; + quad[2]->v=diff_y[c0+1]/256.0f; + } + + POLY_add_quad(quad, page, FALSE); // TRUE means perform a backface cull + } + else + { + // + // Even though we don't draw the quad, we must + // push on the random number generator. + // + + facet_rand(); + } + + c0++; + + } + } + foundation--; + sy+=block_height;//+64.0; + height-=4; + hf+=1; +/* + style_index++; + if(facet_backwards) + { + style_index++; + } +*/ + + // + // For when we are drawing the building we are in. + // + + if (sy > max_height) + { + break; + } + } + break; + + + case STOREY_TYPE_TRENCH: + LogText(" alt %d \n",p_facet->Y[0]); + + case STOREY_TYPE_NORMAL: + case STOREY_TYPE_DOOR: + + if(p_facet->FacetFlags&FACET_FLAG_BARB_TOP) + FACET_barbedwire_top(p_facet); + + // + // warehouses can be double sided and storey_type_normal + // + if(facet_backwards&&!(p_facet->FacetFlags&FACET_FLAG_HUG_FLOOR)) + { + // + // I don't understand by Mike! + // + style_index++; + } + + block_height=p_facet->BlockHeight<<4; + + if(inside_clip) //INDOORS_INDEX) + { + SLONG top; + top=block_height; + top=(top*height)>>2; + top+=sy; + if( top>=(inside_storeys[INDOORS_INDEX].StoreyY+256)) + { + // + // clip the top of the building, but first check fade status + // + +/* + if(INDOORS_INDEX_FADE_EXT_DIR) + { + // + // we are fadeing so draw it + // + fade_alpha=INDOORS_INDEX_FADE_EXT<<24; + } + else +*/ + { + height-=((top+4)-(inside_storeys[INDOORS_INDEX].StoreyY+256))/(p_facet->BlockHeight<<2); + } + } + + + } + + if(p_facet->FHeight) + foundation=2; + +// MakeFacetPoints(sx, sy, sz, fdx, fdz, block_height, height, max_height, col, foundation, count, p_facet->FacetFlags&(FACET_FLAG_INVISIBLE|FACET_FLAG_IN_SEWERS),p_facet->FacetFlags&FACET_FLAG_HUG_FLOOR); + MakeFacetPoints(sx, sy, sz, fdx, fdz, block_height, height, max_height, col, foundation, count, p_facet->FacetFlags&(FACET_FLAG_INVISIBLE),p_facet->FacetFlags&FACET_FLAG_HUG_FLOOR); + +// p_facet->FacetFlags&=~(FACET_FLAG_IN_SEWERS); + + if(p_facet->FacetFlags&(FACET_FLAG_INSIDE)) + { + reverse_textures=1; + style_index--; + } + else + if(p_facet->FacetFlags&(FACET_FLAG_2TEXTURED)) + { + style_index--; + } + + if(!(p_facet->FacetFlags&FACET_FLAG_HUG_FLOOR) && (p_facet->FacetFlags&(FACET_FLAG_2TEXTURED|FACET_FLAG_2SIDED))) + { + style_index_offset=1; + style_index_step=2; + } + else + { + style_index_offset=1; + style_index_step=1; + + } + + + hf = 0; + while (height >= 0) + { + if (hf) + { + FillFacetPoints(count, hf - 1, foundation + 1, facet_backwards, style_index - style_index_offset, block_height,reverse_textures); + } + + foundation--; + sy += block_height; + height -= 4; + hf++; + style_index+=style_index_step; +// if(p_facet->FacetFlags&(FACET_FLAG_2SIDED|FACET_FLAG_2TEXTURED)) +// style_index++; + + if (sy > max_height) + { + break; + } + } + break; + + case STOREY_TYPE_FENCE_BRICK: + + // hardwire the height + p_facet->Height += 1; + + // bollocks to it all i'm doing my own so nnyeerrrr + FACET_barbedwire_top(p_facet); + /* + { + float dx=(p_facet->x[1]-p_facet->x[0] << 8); + float dy=(p_facet->Y[1]-p_facet->Y[0]); + float dz=(p_facet->z[1]-p_facet->z[0] << 8); + float mag=sqrt((dx*dx)+(dz*dz)); + float stepx=(dx/mag)*10; + float stepy=(dy/mag)*10; + float stepz=(dz/mag)*10; + SLONG cx=p_facet->x[0] << 8; + SLONG cy=p_facet->Y[0]; + SLONG cz=p_facet->z[0] << 8; + SLONG seed=54321678; + float base=0; + SLONG contour = 0; + + + while (baseFacetFlags & FACET_FLAG_ONBUILDING)) + { + contour = PAP_calc_map_height_at(cx,cz); + } + else + { + contour = p_facet->Y[0]; + } + + SPRITE_draw_tex( + cx, + (64*p_facet->Height)-64+((seed>>8)&0xf) + contour, + cz, + 50, + 0xffffff, + 0, + POLY_PAGE_BARBWIRE, + 0.0, 0.0, 1.0, 1.0, + SPRITE_SORT_NORMAL); + + + base+=10; + cx+=stepx; + cy+=stepy; + cz+=stepz; + } + + } + */ + p_facet->Height -= 1; + + // + // FALLTHROUGH! + // + + case STOREY_TYPE_FENCE: + + POLY_set_local_rotation_none(); + + // this check is due to fence_brick dropping thru + if (p_facet->FacetType==STOREY_TYPE_FENCE) + { + // + // build the slope at the top of the fence + // + float dx,dz,nx,nz; + float tsx,tsy,tsz; + sy=0; + build_fence_poles(sx,sy,sz,fdx,fdz,count,&dx,&dz,style_index); + + tsx=sx; + tsy=sy; + tsz=sz; + + nx=dz; + nz=-dx; + + sx+=nx*10.0f; + sz+=nz*10.0f; + sy+=210.0f; + + hf=0; + while(hf<=1) + { + float *p_diffy=diff_y; + x=sx; + y=sy; + z=sz; + rows[hf]=POLY_buffer_upto; + c0=count; + while(c0-->0) + { + float dy = 0; + + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + +// dy=0; //(float)(PAP_2HI(((SLONG)x)>>8,((SLONG)z)>>8).Alt<<3); +/* + if(diag) + { + dy=PAP_calc_height_at((SLONG)x,(SLONG)z); + } + else + { + dy=grid_height_at_world(x,z); + } + */ + + dy=*p_diffy++; + + POLY_transform_c_saturate_z(x,y+dy,z,pp); + + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + *col, + &pp->colour, + &pp->specular); + //apply_cloud((SLONG)x,(SLONG)(y+dy),(SLONG)z,&pp->colour); + + //POLY_fadeout_point(pp); + } + + pp->colour|=fade_alpha; + x += fdx; + z += fdz; +// col += 1; better not increase this until the cache create knows about fences + } + sy+=40.0f; + sx+=nx*50.0f; + sz+=nz*50.0f; + hf++; + + } + + // + // now draw the quads + // + { + SLONG row1,row2; + + row1=rows[0]; + row2=rows[1]; + + // + // create the quads and submit them for drawing + // + + c0=0; //count-1; + while(c0FacetFlags&(FACET_FLAG_INVISIBLE|FACET_FLAG_IN_SEWERS),diff_y); + p_facet->FacetFlags&=~(FACET_FLAG_IN_SEWERS); + + + + hf = 0; + while (height >= 0) + { + if (hf) + { + FillFacetPoints(count, hf - 1, foundation + 1, facet_backwards, style_index - 1, block_height,reverse_textures); + } + + foundation--; + sy += block_height; + height -= 4; + hf++; + //style_index++; + // if(p_facet->FacetFlags&(FACET_FLAG_2SIDED|FACET_FLAG_2TEXTURED)) + // style_index++; + + if (sy > max_height) + { + break; + } + } + break; + + + } +*/ + + + if (p_facet->Shake) + { + p_facet->Shake -= p_facet->Shake >> 2; + p_facet->Shake -= 1; + } + + // + // fences DO lock to the floor + // + + sy=0; + +#ifdef UNUSED_WIRECUTTERS + fence_gap_compare=fence_gap*(count-1); +#endif + y=sy; + + + while(hf<=1) + { + float *p_diffy=diff_y; + x=sx; +// y=sy; + z=sz; + rows[hf]=POLY_buffer_upto; + c0=count; + while(c0-->0) + { + float dy = 0; + + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; +// dy=(float)(PAP_2HI(((SLONG)x)>>8,((SLONG)z)>>8).Alt<<3); + +/* + if(diag) + { + dy=PAP_calc_height_at((SLONG)x,(SLONG)z); + } + else + { + dy=grid_height_at_world(x,z); + } +*/ +// ASSERT(dy==0); + + dy=*p_diffy++; + + POLY_transform_c_saturate_z( + x + shake[(Random() & 3) + ((p_facet->Shake >> 3) & ~0x3)], + y + dy, + z + shake[(Random() & 3) + ((p_facet->Shake >> 3) & ~0x3)], + pp); + + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + *col, + &pp->colour, + &pp->specular); + + //apply_cloud((SLONG)x,(SLONG)(y+dy),(SLONG)z,&pp->colour); + //POLY_fadeout_point(pp); + pp->colour|=fade_alpha; + } + + x += fdx; + z += fdz; + col += 1; + } + if(height==2) + y+=102; //256.0/3.0; + else + y+=height*BLOCK_SIZE; + + hf++; + + } + + { + SLONG row1,row2; + + row1=rows[0]; + row2=rows[1]; + + // + // create the quads and submit them for drawing + // + + c0=0; //count-1; + while(c0>8)) + { + SLONG page; + float fdy; + + fdy=diff_y[c0+1]-diff_y[c0]; + page=texture_quad(quad,dstyles[style_index],c0,count); + draw_fence_gap(quad,page,fence_gap_compare,sx+fdx*c0,sy+fdy*c0,sz+fdz*c0,fdx,fdy,fdz); + // + // Push on the random number generator. + // + + facet_rand(); + + fence_gap=get_fence_hole_next(p_facet,fence_gap); + fence_gap_compare=fence_gap*(count-1); + } + else + + */ + { + if (POLY_valid_quad(quad)) + { + SLONG page; + + // + // Texture the quad. + // + + page=texture_quad(quad,dstyles[style_index],c0,count); + +// Flashing pink! No thanks. +#if 0 + #ifndef NDEBUG + + if (p_facet->Height == 2 && p_facet->BlockHeight == 16) + { + // + // This is a vaultable fence- so it doesn't matter. + // + } + else + { + if (page == 284) + { + // + // This is the mesh texture so the fence should be + // climable. + // + + if (p_facet->FacetFlags & FACET_FLAG_UNCLIMBABLE) + { + if (GAME_TURN & 0x8) + { + quad[0]->specular |= 0xff00ff; + quad[1]->specular |= 0xff00ff; + quad[2]->specular |= 0xff00ff; + quad[3]->specular |= 0xff00ff; + } + } + } + else + { + // + // A climbable non-mesh fence. + // + + if (!(p_facet->FacetFlags & FACET_FLAG_UNCLIMBABLE)) + { + if (GAME_TURN & 0x8) + { + quad[0]->specular |= 0xff00ff; + quad[1]->specular |= 0xff00ff; + quad[2]->specular |= 0xff00ff; + quad[3]->specular |= 0xff00ff; + } + } + } + } + + #endif +#endif + + POLY_add_quad(quad, page, 0); // 1 means perform a backface cull + } + else + { + // + // Push on the random number generator. + // + + facet_rand(); + } + } + + c0++; + } + } + + break; + + break; + } + return; +} + + + + +#ifdef DEBUG +static bPleaseDoSuperFacets = TRUE; +#endif + + + +// Like FACET_draw_rare, but for the most common class. +void FACET_draw(SLONG facet,UBYTE alpha) +{ + struct DFacet *p_facet; + static SWORD rows[100]; + SLONG c0,count; + SLONG dx,dz; + float x,y,z,sx,sy,sz,fdx,fdz; + SLONG height; + POLY_Point *pp; + SLONG hf; + POLY_Point *quad[4]; + SLONG style_index; + NIGHT_Colour *col; + SLONG max_height; + SLONG foundation=0; + static float diff_y[128]; + float block_height=256.0; + + SLONG diag=0; + SLONG facet_backwards=0; + ULONG fade_alpha=alpha<<24; + SLONG inside_clip=0; + SLONG reverse_textures=0; + //SLONG style_index_offset=1; + SLONG style_index_step=2; + SLONG flipx=0; + + + LOG_ENTER ( Facet_draw_start ) + + + ASSERT(facet>0&&facetFacetFlags&FACET_FLAG_INVISIBLE) + { + LOG_EXIT ( Facet_draw_start ) + return; + } + + + // Alpha seems to be never used, and always set to 0 + ASSERT ( alpha == 0 ); + + // Now spot the odder forms of facet, and use the _rare routine to draw them instead. + if ( ( p_facet->FacetType != STOREY_TYPE_NORMAL ) || + ( INDOORS_INDEX ) || + ( ( p_facet->FacetFlags & ( FACET_FLAG_BARB_TOP | FACET_FLAG_2SIDED | FACET_FLAG_INSIDE ) ) != 0 ) ) + { + // Use it! + FACET_draw_rare ( facet, alpha ); + LOG_EXIT ( Facet_draw_start ) + return; + } + + + ASSERT ( ( p_facet->FacetType == STOREY_TYPE_NORMAL ) ); + ASSERT ( ( p_facet->FacetFlags & FACET_FLAG_INVISIBLE ) == 0 ); + ASSERT ( ( p_facet->FacetFlags & FACET_FLAG_BARB_TOP ) == 0 ); + ASSERT ( ( p_facet->FacetFlags & FACET_FLAG_2SIDED ) == 0 ); + ASSERT ( ( p_facet->FacetFlags & FACET_FLAG_INSIDE ) == 0 ); + ASSERT ( !INDOORS_INDEX ); + + // + // Should we bother drawing this facet? + // + + { + // + // Backface cull the entire facet? + // + + float x1, z1; + float x2, z2; + + float vec1x; + float vec1z; + + float vec2x; + float vec2z; + + float cprod; + + x1 = float(p_facet->x[0] << 8); + z1 = float(p_facet->z[0] << 8); + + x2 = float(p_facet->x[1] << 8); + z2 = float(p_facet->z[1] << 8); + + vec1x = x2 - x1; + vec1z = z2 - z1; + + vec2x = POLY_cam_x - x1; + vec2z = POLY_cam_z - z1; + + cprod = vec1x*vec2z - vec1z*vec2x; + + if (cprod >= 0) + { + // + // We've got rid of a whole facet :o) + // + LOG_EXIT ( Facet_draw_start ) + return; + } + } + + // + // Transform the bounding box of the facet to quickly try and reject the + // entire facet. + // + + ULONG clip_or; // Used below. + { + + SLONG i; + + ULONG clip; + ULONG clip_and; + + POLY_Point bound; + + float x; + float y; + float z; + + float x1 = float(p_facet->x[0] << 8); + float y1 = float(p_facet->Y[0]); + float z1 = float(p_facet->z[0] << 8); + + float x2 = float(p_facet->x[1] << 8); + float y2 = float(p_facet->Y[1]) + float(p_facet->Height * 64); + float z2 = float(p_facet->z[1] << 8); + + clip_or = 0x00000000; + clip_and = 0xffffffff; + + for (i = 0; i < 4; i++) + { + x = (i & 0x1) ? x1 : x2; + y = (i & 0x2) ? y1 : y2; + z = (i & 0x1) ? z1 : z2; + + POLY_transform_c_saturate_z(x, y, z, &bound); + + clip = bound.clip; + + if ((clip & POLY_CLIP_TRANSFORMED) && !(clip & POLY_CLIP_OFFSCREEN)) + { + // + // Draw the whole facet because this point is on-screen. + // + + // But this frags the near-plane clip detection. + // Don't need it any more. Hooray! + goto draw_the_facet_common; + } + + clip_and &= clip; + clip_or |= clip; + } + + if (clip_and & POLY_CLIP_OFFSCREEN) + { + // + // Reject the whole facet. + // + + LOG_EXIT ( Facet_draw_start ) + return; + } + + if (!(clip_or & POLY_CLIP_TRANSFORMED)) + { + // + // Reject the whole facet if all points are too far or all points are too near + // + if(clip_and & (POLY_CLIP_NEAR|POLY_CLIP_FAR)) + { + LOG_EXIT ( Facet_draw_start ) + return; + } + } + +draw_the_facet_common:; + } + + LOG_EXIT ( Facet_draw_start ) + + dfacets_drawn_this_gameturn += 1; + LOG_ENTER ( Facet_draw_mid ) + + { + float yaw; + + if (p_facet->z[0] == p_facet->z[1]) + { + if (p_facet->x[0] < p_facet->x[1]) + { + yaw = 0.0F; + } + else + { + yaw = PI; + } + } + else + { + if (p_facet->z[0] > p_facet->z[1]) + { + yaw = 3 * PI / 2; + } + else + { + yaw = PI / 2; + } + } + + MATRIX_calc( + FACET_direction_matrix, + yaw, + 0.0F, + 0.0F); + } + +// Can't do these for release yet - no glowing windows, and the fog doesn't work. +// Fog works, and Mark says he's done the glowing windows. Hooray! +#define DO_SUPERFACETS_PLEASE_BOB defined + + +#ifdef DO_SUPERFACETS_PLEASE_BOB + if (p_facet->Open) + { + // + // Don't cache facets that open and close! + // + } + else + { + if (SUPERFACET_draw(facet)) + { + p_facet->FacetFlags &= ~FACET_FLAG_DLIT; + + return; + } + + p_facet->FacetFlags &= ~FACET_FLAG_DLIT; + + /* + + + + if ( ( ( clip_or & POLY_CLIP_NEAR ) == 0) +#ifdef DEBUG + && bPleaseDoSuperFacets +#endif + ) + { + if (SUPERFACET_draw(facet)) + { + return; + } + } + + */ + + } +#endif + + // + // Draw the facet. + // + + p_facet->FacetFlags &= ~FACET_FLAG_DLIT; + + POLY_buffer_upto = 0; + + style_index=p_facet->StyleIndex; + + // + // Should this be passed an x,y,z to be relative to? Nah! + // + + set_facet_seed(p_facet->x[0] * p_facet->z[0] + p_facet->Y[0]); + + ASSERT ( ( GAME_FLAGS & GF_INDOORS ) == 0 ); + + max_height = INFINITY; + + // + // If there is no cached lighting for this facet, then we + // must make some. + // + + if (p_facet->Dfcache == 0) + { + // I've just seen how this work's and I'm scared + // looks like NIGHT_dfcache_create has to completely understand how to build any facet + // like the fence struts I've just crafted... + + p_facet->Dfcache = NIGHT_dfcache_create(facet); + + if (p_facet->Dfcache == NULL) + { + LOG_EXIT ( Facet_draw_mid ) + return; + } + } + + ASSERT(WITHIN(p_facet->Dfcache, 1, NIGHT_MAX_DFCACHES - 1)); + + col = NIGHT_dfcache[p_facet->Dfcache].colour; + + dx = (p_facet->x[1]-p_facet->x[0]) << 8; + dz = (p_facet->z[1]-p_facet->z[0]) << 8; + + sx = float(p_facet->x[0] << 8); + sy = float(p_facet->Y[0] ); + sz = float(p_facet->z[0] << 8); +/* + if(dz) + return; + + if(sy>256.0) // || sy>513.0) + return; + */ + + height=p_facet->Height; + // if(height!=12) + // return; + + // No diagonal walls allowed. + ASSERT ( !(dx && dz) ); + + { + if(dx) + { + count=abs(dx)>>8; + if(dx>0) + dx=256; + else + dx=-256; + } + else + { + count=abs(dz)>>8; + if(dz>0) + dz=256; + else + dz=-256; + } + + fdx=(float)dx; + fdz=(float)dz; + + if (p_facet->Open) + { + float rdx; + float rdz; + float angle = float(p_facet->Open) * (PI / 256.0F); + + // + // Open the facet! + // + + rdx = cos(angle) * fdx + sin(angle) * fdz; + rdz = -sin(angle) * fdx + cos(angle) * fdz; + + fdx = rdx; + fdz = rdz; + } + } + + count++; + + LOG_EXIT ( Facet_draw_mid ) + + LOG_ENTER ( Facet_draw_main ) + + //MSG_add(" facet %d draw count %d\n",facet,count); + + ASSERT ( p_facet->FacetType == STOREY_TYPE_NORMAL ); + + ASSERT ( (p_facet->FacetFlags&FACET_FLAG_BARB_TOP) == 0 ); + + // + // warehouses can be double sided and storey_type_normal + // + + ASSERT ( facet_backwards == 0 ); + + block_height=p_facet->BlockHeight<<4; + + ASSERT ( inside_clip == 0 ); + + if(p_facet->FHeight) + { + foundation=2; + } + + MakeFacetPointsCommon(sx, sy, sz, fdx, fdz, block_height, height, col, foundation, count, p_facet->FacetFlags&FACET_FLAG_HUG_FLOOR ); + +// p_facet->FacetFlags&=~(FACET_FLAG_IN_SEWERS); + + ASSERT ( ( p_facet->FacetFlags&(FACET_FLAG_INSIDE) ) == 0 ); + if(p_facet->FacetFlags&(FACET_FLAG_2TEXTURED)) + { + style_index--; + } + + if(!(p_facet->FacetFlags&FACET_FLAG_HUG_FLOOR) && (p_facet->FacetFlags&(FACET_FLAG_2TEXTURED|FACET_FLAG_2SIDED))) + { + //style_index_offset=1; + style_index_step=2; + } + else + { + //style_index_offset=1; + style_index_step=1; + + } + + #ifdef FACETINFO + FACET_facetinfo_current = facet; + #endif + + ASSERT ( reverse_textures == 0 ); + + hf = 0; + while (height >= 0) + { + if (hf) + { + ASSERT ( facet_backwards == 0 ); + ASSERT ( reverse_textures == 0 ); + //FillFacetPoints(count, hf - 1, foundation + 1, 0, style_index - style_index_offset, block_height, 0); + FillFacetPointsCommon(count, hf - 1, foundation + 1, style_index - 1, block_height ); + } + + foundation--; + sy += block_height; + height -= 4; + hf++; + style_index+=style_index_step; + // if(p_facet->FacetFlags&(FACET_FLAG_2SIDED|FACET_FLAG_2TEXTURED)) + // style_index++; + + } + + #ifdef FACETINFO + ASSERT(WITHIN(FACET_facetinfo_current, 0, FACET_MAX_FACETINFO - 1)); + FACET_facetinfo[FACET_facetinfo_current].done = TRUE; + #endif + + LOG_EXIT ( Facet_draw_main ) + return; +} + + + +extern SLONG AENG_drawing_a_warehouse; + +void FACET_draw_walkable(SLONG build) +{ + SLONG i; + SLONG j; + + SLONG ep; + + SLONG red; + SLONG green; + SLONG blue; + + SLONG page; + SLONG warehouse; + + SLONG walkable; + + struct RoofFace4 *p_f4; + struct DWalkable *p_walk; + struct DBuilding *p_dbuilding; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri[3]; + POLY_Point *quad[4]; + + ASSERT(WITHIN(build, 1, next_dbuilding - 1)); + + p_dbuilding = &dbuildings[build]; + + UWORD *rooftex = NULL; + +#ifdef TARGET_DC + // Internal stuff fixup + POLY_flush_local_rot(); +#endif + + // + // Is this building a warehouse? + // + + warehouse = (p_dbuilding->Type == BUILDING_TYPE_WAREHOUSE); + + #ifndef NDEBUG + + if (warehouse && AENG_transparent_warehouses) + { + return; + } + + #endif + + if (warehouse) + { + ASSERT(WITHIN(p_dbuilding->Ware, 0, WARE_ware_upto - 1)); + + rooftex = &WARE_rooftex[WARE_ware[p_dbuilding->Ware].rooftex]; + + //FONT2D_DrawString("Warehouse walkables", 50 + (rand() & 0xf), 50, 0xffffff); + + } + else + { + //FONT2D_DrawString("Non-warehouse walkables", 50 + (rand() & 0xf), 70, 0xffffff); + } + + // + // Rotate all the points into the POLY_buffer and all the + // shadow points in the POLY_shadow. + // + + for (walkable = p_dbuilding->Walkable; walkable; walkable = p_walk->Next) + { + p_walk = &dwalkables[walkable]; + + // + // REJECTION OF WHOLE WALKABLE SET IF ITS ABOVE THE CAMERA? + // + + { + // + // The quads. + // + + POLY_buffer_upto = 0; + POLY_shadow_upto = 0; + + for (i = p_walk->StartFace4; i < p_walk->EndFace4; i++, rooftex++) + { + float px,py,pz,sy; + p_f4 = &roof_faces4[i]; + + if (p_f4->DrawFlags & RFACE_FLAG_NODRAW) + { + continue; + } + + pp = &POLY_buffer[0]; + + px=(float)((p_f4->RX&127)<<8); + pz=(float)((p_f4->RZ&127)<<8); + py=(float)(p_f4->Y); + sy=py; + POLY_transform(px,py,pz,pp); + + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + NIGHT_ROOF_WALKABLE_POINT(i,0), + &pp->colour, + &pp->specular); + + //apply_cloud((SLONG)px,(SLONG)py,(SLONG) pz,&pp->colour); + + //POLY_fadeout_point(pp); + } + pp++; + px+=256.0f; + py+=p_f4->DY[0]<MaybeValid()) + { + NIGHT_get_d3d_colour( + NIGHT_ROOF_WALKABLE_POINT(i,1), + &pp->colour, + &pp->specular); + + //apply_cloud((SLONG)px,(SLONG)py,(SLONG) pz,&pp->colour); + + //POLY_fadeout_point(pp); + } + pp++; + pz+=256.0f; + py=sy+(p_f4->DY[1]<MaybeValid()) + { + NIGHT_get_d3d_colour( + NIGHT_ROOF_WALKABLE_POINT(i,3), + &pp->colour, + &pp->specular); + + //apply_cloud((SLONG)px,(SLONG)py,(SLONG) pz,&pp->colour); + + //POLY_fadeout_point(pp); + } + pp++; + px-=256.0f; + py=sy+(p_f4->DY[2]<MaybeValid()) + { + NIGHT_get_d3d_colour( + NIGHT_ROOF_WALKABLE_POINT(i,2), + &pp->colour, + &pp->specular); + + //apply_cloud((SLONG)px,(SLONG)py,(SLONG) pz,&pp->colour); + + //POLY_fadeout_point(pp); + } + + quad[0] = &POLY_buffer[0]; + quad[1] = &POLY_buffer[1]; + quad[2] = &POLY_buffer[3]; + quad[3] = &POLY_buffer[2]; + + if (POLY_valid_quad(quad)) + { +// #if DRAW_THIS_DEBUG_STUFF + +#ifndef TARGET_DC + if(ControlFlag&&allow_debug_keys) + { + SLONG x,z,y; + + x=(p_f4->RX&127)<<8; + z=(p_f4->RZ&127)<<8; + y=p_f4->Y; + // + // Draw the slide-edges + // + + + if (p_f4->DrawFlags & (RFACE_FLAG_SLIDE_EDGE_0)) + { + AENG_world_line(x,y,z,4,0xffffff,x+256,y,z,4,0xffffff,1); + + } + if (p_f4->DrawFlags & (RFACE_FLAG_SLIDE_EDGE_1)) + { + AENG_world_line(x+256,y,z,4,0xffffff,x+256,y,z+256,4,0xffffff,1); + + } + if (p_f4->DrawFlags & (RFACE_FLAG_SLIDE_EDGE_2)) + { + AENG_world_line(x+256,y,z+256,4,0xffffff,x,y,z+256,4,0xffffff,1); + + } + if (p_f4->DrawFlags & (RFACE_FLAG_SLIDE_EDGE_3)) + { + AENG_world_line(x,y,z+256,4,0xffffff,x,y,z,4,0xffffff,1); + + } + } +#endif + +// #endif + + if (warehouse) + { + // + // If this face is above the camera... it must be the ceiling- + // so draw it all in black. + // + + if (p_f4->Y > (FC_cam[0].y >> 8)) + { + quad[0]->colour = 0x00000000; + quad[0]->specular = 0xff000000; + + quad[1]->colour = 0x00000000; + quad[1]->specular = 0xff000000; + + quad[2]->colour = 0x00000000; + quad[2]->specular = 0xff000000; + + quad[3]->colour = 0x00000000; + quad[3]->specular = 0xff000000; + + POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE); + + continue; + } + else + { + TEXTURE_get_minitexturebits_uvs( + *rooftex, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + } + } + else + { + PAP_Hi *ph; + ph = &PAP_2HI(p_f4->RX&127,p_f4->RZ&127); + + TEXTURE_get_minitexturebits_uvs( + ph->Texture, + &page, + &quad[0]->u, + &quad[0]->v, + &quad[1]->u, + &quad[1]->v, + &quad[2]->u, + &quad[2]->v, + &quad[3]->u, + &quad[3]->v); + } + + if(page>POLY_NUM_PAGES - 2) + page=0; + + // + // Do the shadowing of this quad. + // + + { + if (!AENG_drawing_a_warehouse && (p_f4->DrawFlags & (RFACE_FLAG_SHADOW_1 | RFACE_FLAG_SHADOW_2 | RFACE_FLAG_SHADOW_3))) + { + // + // Create the shadow points. + // + + POLY_Point pshad[4]; + + // + // Create four darkened points. + // + + pshad[0] = *(quad[0]); + pshad[1] = *(quad[1]); + pshad[2] = *(quad[2]); + pshad[3] = *(quad[3]); + + // + // Darken the points. + // + + for (j = 0; j < 4; j++) + { + red = (pshad[j].colour >> 16) & 0xff; + green = (pshad[j].colour >> 8) & 0xff; + blue = (pshad[j].colour >> 0) & 0xff; + + red -= 130; + green -= 130; + blue -= 130; + + if (red < 0) {red = 0;} + if (green < 0) {green = 0;} + if (blue < 0) {blue = 0;} + + pshad[j].colour = (red << 16) | (green << 8) | (blue << 0) | 0xff000000; + } + + ASSERT(FACE_FLAG_SHADOW_1 == 1 << 2); + + switch((p_f4->DrawFlags & (RFACE_FLAG_SHADOW_1|RFACE_FLAG_SHADOW_2|RFACE_FLAG_SHADOW_3))) + { + case 0: + ASSERT(0); // We shouldn't be doing any of this in this case. + break; + + case 1: + + tri[0] = &pshad [0]; + tri[1] = quad[1]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, !warehouse); + + break; + + case 2: + + tri[0] = &pshad [0]; + tri[1] = quad[1]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + break; + + case 3: + + //pshad[2].colour += 0x00101010; + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + break; + + case 4: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[1]; + tri[1] = &pshad [3]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + break; + + case 5: + + tri[0] = &pshad [0]; + tri[1] = quad[1]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[1]; + tri[1] = &pshad [3]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + break; + + case 6: + + tri[0] = &pshad [0]; + tri[1] = quad[1]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + break; + + case 7: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[1]; + tri[1] = &pshad [3]; + tri[2] = &pshad [2]; + + POLY_add_triangle(tri, page, !warehouse); + + break; + + default: + ASSERT(0); + break; + } + } + else + { + if(p_f4->RX&(1<<7)) + { + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = quad[3]; + + POLY_add_triangle(tri, page, !warehouse); + + tri[0] = quad[3]; + tri[1] = quad[2]; + tri[2] = quad[0]; + + POLY_add_triangle(tri, page, !warehouse); + } + else + { + POLY_add_quad(quad, page, !warehouse); + } + } + } + } + } + } + } +} + +// +// when walkable faces where prim_faces +// +void FACET_draw_walkable_old(SLONG build) +{ + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG red; + SLONG green; + SLONG blue; + + SLONG page; + + SLONG walkable; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + struct DWalkable *p_walk; + struct DBuilding *p_dbuilding; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + ASSERT(WITHIN(build, 1, next_dbuilding - 1)); + + p_dbuilding = &dbuildings[build]; + + // + // Rotate all the points into the POLY_buffer and all the + // shadow points in the POLY_shadow. + // + + for (walkable = p_dbuilding->Walkable; walkable; walkable = p_walk->Next) + { + p_walk = &dwalkables[walkable]; + + // + // REJECTION OF WHOLE WALKABLE SET IF ITS ABOVE THE CAMERA? + // + + if((build!=INDOORS_DBUILDING) || p_walk->StoreyY*256< inside_storeys[INDOORS_INDEX].StoreyY) + { + sp = p_walk->StartPoint; + ep = p_walk->EndPoint; + + POLY_buffer_upto = 0; + POLY_shadow_upto = 0; + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform( + AENG_dx_prim_points[i].X, + AENG_dx_prim_points[i].Y, + AENG_dx_prim_points[i].Z, + pp); + + if (pp->MaybeValid()) + { + +#ifndef TARGET_DC + NIGHT_get_d3d_colour( + NIGHT_WALKABLE_POINT(i), + &pp->colour, + &pp->specular); +#endif + //apply_cloud((SLONG)AENG_dx_prim_points[i].X,(SLONG)AENG_dx_prim_points[i].Y,(SLONG)AENG_dx_prim_points[i].Z,&pp->colour); + + //POLY_fadeout_point(pp); +// pp->colour|=fade_alpha; + } + } + + // + // The quads. + // + + for (i = p_walk->StartFace4; i < p_walk->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + #if DRAW_THIS_DEBUG_STUFF + + { + // + // Draw the slide-edges + // + + SLONG ei; + + UBYTE point_order[4] = {0, 1, 3, 2}; + + for (ei = 0; ei < 4; ei++) + { + if (p_f4->FaceFlags & (FACE_FLAG_SLIDE_EDGE << ei)) + { + AENG_world_line( + prim_points[p_f4->Points[point_order[(ei + 0) & 0x3]]].X, + prim_points[p_f4->Points[point_order[(ei + 0) & 0x3]]].Y, + prim_points[p_f4->Points[point_order[(ei + 0) & 0x3]]].Z, + 32, + 0xffffff, + prim_points[p_f4->Points[point_order[(ei + 1) & 0x3]]].X, + prim_points[p_f4->Points[point_order[(ei + 1) & 0x3]]].Y, + prim_points[p_f4->Points[point_order[(ei + 1) & 0x3]]].Z, + 32, + 0xffffff, + TRUE); + } + } + } + + #endif + + if (p_f4->DrawFlags & POLY_FLAG_TEXTURED) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + if(page>POLY_NUM_PAGES - 2) + page=0; + + // + // Do the shadowing of this quad. + // + + if (p_f4->FaceFlags & (FACE_FLAG_SHADOW_1 | FACE_FLAG_SHADOW_2 | FACE_FLAG_SHADOW_3)) + { + // + // Create the shadow points. + // + + POLY_Point ps[4]; + + // + // Create four darkened points. + // + + ps[0] = *(quad[0]); + ps[1] = *(quad[1]); + ps[2] = *(quad[2]); + ps[3] = *(quad[3]); + + // + // Darken the points. + // + + for (j = 0; j < 4; j++) + { + red = (ps[j].colour >> 16) & 0xff; + green = (ps[j].colour >> 8) & 0xff; + blue = (ps[j].colour >> 0) & 0xff; + + red -= 130; + green -= 130; + blue -= 130; + + if (red < 0) {red = 0;} + if (green < 0) {green = 0;} + if (blue < 0) {blue = 0;} + + ps[j].colour = (red << 16) | (green << 8) | (blue << 0) | 0xff000000; + } + + ASSERT(FACE_FLAG_SHADOW_1 == 1 << 2); + + switch((p_f4->FaceFlags & (FACE_FLAG_SHADOW_1|FACE_FLAG_SHADOW_2|FACE_FLAG_SHADOW_3)) >> 2) + { + case 0: + ASSERT(0); // We shouldn't be doing any of this in this case. + break; + + case 1: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 2: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 3: + + + ps[2].colour += 0x00202020; + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 4: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 5: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 6: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + case 7: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, TRUE); + + break; + + default: + ASSERT(0); + break; + } + } + else + { + POLY_add_quad(quad, page, TRUE); + } + } + else + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + } + } +} + + + + +void DRAW_ladder_rungs(float x1,float z1,float x2,float z2,struct DFacet *p_facet,float dx,float dz,ULONG colour, ULONG specular) +{ + SLONG count; + float y; + POLY_Point *quad[4]; + POLY_Point *pp; + + // Do this signed so that the alpha values stay at ff or 00 as appropriate. + ULONG dcolour = ((signed)colour >> 2) & 0xff3f3f3f; + + // + // do a height test so just process rungs in height range we can see + // + + x1 += dx * (3.0f / 4.0f); + z1 += dz * (3.0f / 4.0f); + + x2 -= dx * (3.0f / 4.0f); + z2 -= dz * (3.0f / 4.0f); + + y = (float) p_facet->Y[0]; + + count = p_facet->Height; + + quad[0] = &POLY_buffer[0]; + quad[1] = &POLY_buffer[1]; + quad[2] = &POLY_buffer[2]; + quad[3] = &POLY_buffer[3]; + + while(count--) + { + y+=BLOCK_SIZE; + + POLY_buffer_upto=0; + pp = &POLY_buffer[0]; + + POLY_transform(x1,y-8,z1,pp); + pp->colour = dcolour; + pp->specular = specular; + pp->u = 0.0F; + pp->v = 0.2F; + + //POLY_fadeout_point(pp); + + POLY_transform(x2,y-8,z2,++pp); + pp->colour = dcolour; + pp->specular = specular; + pp->u = 2.0F; + pp->v = 0.2F; + + //POLY_fadeout_point(pp); + + POLY_transform(x1,y,z1,++pp); + pp->colour = colour; + pp->specular = specular; + pp->u = 0.0F; + pp->v = 0.8F; + + //POLY_fadeout_point(pp); + + POLY_transform(x2,y,z2,++pp); + pp->colour = colour; + pp->specular = specular; + pp->u = 2.0F; + pp->v = 0.8F; + + //POLY_fadeout_point(pp); + + if (POLY_valid_quad(quad)) + { + SLONG page; + + // + // Texture the quad. + // + + page = POLY_PAGE_LADDER; + + POLY_add_quad(quad, page, FALSE); // TRUE means perform a backface cull + } + } +} + +#define LADDER_SPINE_WIDTH 12 +void DRAW_ladder_sides(float x1,float z1,float x2,float z2,struct DFacet *p_facet,float dx,float dz,ULONG colour, ULONG specular) +{ + SLONG count; + float y; + POLY_Point *quad[4]; + POLY_Point *pp; + float height; + UWORD sp[64]; + + // Do this signed so that the alpha values stay at ff or 00 as appropriate. + ULONG dcolour = ((signed)colour >> 2) & 0xff3f3f3f; + + float v; + + // + // do a height test so just process rungs in height range we can see + // + + y=(float)p_facet->Y[0]; + count=(p_facet->Height*BLOCK_SIZE)/256; + if(count==0) + height=256; + else + height=(float)((p_facet->Height*BLOCK_SIZE)/count); + count++; + + { + float x1mdz,x1pdx,x2mdx,x2mdz; + float z1pdx,z1pdz,z2mdz,z2pdx; + SLONG c0=0; + + x1mdz=x1-dz; + x1pdx=x1+dx; + x2mdx=x2-dx; + x2mdz=x2-dz; + + z1pdx=z1+dx; + z1pdz=z1+dz; + z2mdz=z2-dz; + z2pdx=z2+dx; + + POLY_buffer_upto=0; + pp = &POLY_buffer[0]; + while(c0colour = dcolour; + pp->specular = specular; + pp->u = 0.0F; + pp->v = v; + + //POLY_fadeout_point(pp); + + POLY_transform(x1,y,z1,++pp); + pp->colour = colour; + pp->specular = specular; + pp->u = 0.5F; + pp->v = v; + + //POLY_fadeout_point(pp); + + POLY_transform(x1pdx,y,z1pdz,++pp); + pp->colour = dcolour; + pp->specular = specular; + pp->u = 1.0F; + pp->v = v; + + //POLY_fadeout_point(pp); + + POLY_transform(x2mdx,y,z2mdz,++pp); + pp->colour = dcolour; + pp->specular = specular; + pp->u = 0.0F; + pp->v = v; + + //POLY_fadeout_point(pp); + + POLY_transform(x2,y,z2,++pp); + pp->colour = colour; + pp->specular = specular; + pp->u = 0.5F; + pp->v = v; + + //POLY_fadeout_point(pp); + + POLY_transform(x2mdz,y,z2pdx,++pp); + pp->colour = dcolour; + pp->specular = specular; + pp->u = 1.0F; + pp->v = v; + + //POLY_fadeout_point(pp); + + pp++; + + POLY_buffer_upto+=6; + + y+=height; + + if(c0>0) + { + quad[0] = &POLY_buffer[sp[c0]]; + quad[1] = &POLY_buffer[sp[c0]+1]; + quad[2] = &POLY_buffer[sp[c0-1]]; + quad[3] = &POLY_buffer[sp[c0-1]+1]; + + if (POLY_valid_quad(quad)) + { + SLONG page; + + page = POLY_PAGE_LADDER; + + POLY_add_quad(quad, page, 0); // 1 means perform a backface cull + } + + quad[0] = &POLY_buffer[sp[c0]+1]; + quad[1] = &POLY_buffer[sp[c0]+2]; + quad[2] = &POLY_buffer[sp[c0-1]+1]; + quad[3] = &POLY_buffer[sp[c0-1]+2]; + + if (POLY_valid_quad(quad)) + { + SLONG page; + + page = POLY_PAGE_LADDER; + + POLY_add_quad(quad, page, 0); // 1 means perform a backface cull + } + + quad[0] = &POLY_buffer[sp[c0]+3]; + quad[1] = &POLY_buffer[sp[c0]+4]; + quad[2] = &POLY_buffer[sp[c0-1]+3]; + quad[3] = &POLY_buffer[sp[c0-1]+4]; + + if (POLY_valid_quad(quad)) + { + SLONG page; + + //page = texture_quad(quad,dstyles[0],0,0); + //page=texture_quad(quad,dstyles[p_facet->StyleIndex],1,5); + page = POLY_PAGE_LADDER; + + POLY_add_quad(quad, page, 0); // 1 means perform a backface cull + } + + quad[0] = &POLY_buffer[sp[c0]+4]; + quad[1] = &POLY_buffer[sp[c0]+5]; + quad[2] = &POLY_buffer[sp[c0-1]+4]; + quad[3] = &POLY_buffer[sp[c0-1]+5]; + + if (POLY_valid_quad(quad)) + { + SLONG page; + + //page = texture_quad(quad,dstyles[0],0,0); + //page=texture_quad(quad,dstyles[p_facet->StyleIndex],1,5); + page = POLY_PAGE_LADDER; + + POLY_add_quad(quad, page, 0); // 1 means perform a backface cull + } + + } + c0++; + } + } +} + +void DRAW_ladder(struct DFacet *p_facet) +{ + SLONG dx,dz; + SLONG dx3,dz3; + SLONG x1,z1,x2,z2; + + ULONG colour; + ULONG specular; + + // + // Don't bother drawing the sewer ladders when we're not in the sewers. + // + + if (p_facet->FacetFlags & FACET_FLAG_LADDER_LINK) + { + // + // We always have to draw these facets. + // + } + else + { + if (0 && (p_facet->FacetFlags & FACET_FLAG_IN_SEWERS)) + { + if (!(GAME_FLAGS & GF_SEWERS)) + { + return; + } + } + else + { + if (GAME_FLAGS & GF_SEWERS) + { + return; + } + } + } + + x1=p_facet->x[0] << 8; + x2=p_facet->x[1] << 8; + z1=p_facet->z[0] << 8; + z2=p_facet->z[1] << 8; + + dx=x2-x1; + dz=z2-z1; + + dx3=(dx*21845)>>16; // divide by 3 + dz3=(dz*21845)>>16; // divide by 3 + + x1+=dx3; + z1+=dz3; + + x2-=dx3; + z2-=dz3; + + dx>>=3; + dz>>=3; + + x1+=dz; + x2+=dz; + + z1-=dx; + z2-=dx; + + dx=x2-x1; + dz=z2-z1; + + if(dx>0) + dx=LADDER_SPINE_WIDTH; + else + if(dx<0) + dx=-LADDER_SPINE_WIDTH; + + if(dz>0) + dz=LADDER_SPINE_WIDTH; + else + if(dz<0) + dz=-LADDER_SPINE_WIDTH; + + NIGHT_Colour col = NIGHT_get_light_at( + ((x1 + x2) >> 1) + (dz << 3), + p_facet->Y[0]+ p_facet->Y[1] >> 1, + ((z1 + z2) >> 1) - (dz << 3)); + + NIGHT_get_d3d_colour( + col, + &colour, + &specular); + + colour |= 0x3f3f3f; // Always have a bit of colour! + + DRAW_ladder_rungs((float)x1,(float)z1,(float)x2,(float)z2,p_facet,(float)dx,(float)dz,colour,specular); + DRAW_ladder_sides((float)x1,(float)z1,(float)x2,(float)z2,p_facet,(float)dx,(float)dz,colour,specular); + + // + // Draw the ladder shadow... + // + + SLONG bx; + SLONG bz; + + bx = (x1 + x2 - (dz << 3) >> 9); + bz = (z1 + z2 + (dx << 3) >> 9); + + if (!WITHIN(bx, 0, PAP_SIZE_HI - 1) || + !WITHIN(bz, 0, PAP_SIZE_HI - 1)) + { + return; + } + + if (PAP_2HI(bx,bz).Flags & PAP_FLAG_HIDDEN) + { + float height = p_facet->Height * BLOCK_SIZE; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + dx >>= 3; + dz >>= 3; + + POLY_transform( + (p_facet->x[0] << 8) + dz, + (p_facet->Y[0]), + (p_facet->z[0] << 8) - dx, + &pp[0]); + + POLY_transform( + (p_facet->x[1] << 8) + dz, + (p_facet->Y[0]), + (p_facet->z[1] << 8) - dx, + &pp[1]); + + POLY_transform( + (p_facet->x[0] << 8) + dz, + (p_facet->Y[0]) + height, + (p_facet->z[0] << 8) - dx, + &pp[2]); + + POLY_transform( + (p_facet->x[1] << 8) + dz, + (p_facet->Y[0]) + height, + (p_facet->z[1] << 8) - dx, + &pp[3]); + + if (POLY_valid_quad(quad)) + { + float top_v = p_facet->Height; + + pp[0].colour = 0xffffffff; + pp[0].specular = 0xff000000; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + + pp[1].colour = 0xffffffff; + pp[1].specular = 0xff000000; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + + pp[2].colour = 0xffffffff; + pp[2].specular = 0xff000000; + pp[2].u = 0.0F; + pp[2].v = top_v; + + pp[3].colour = 0xffffffff; + pp[3].specular = 0xff000000; + pp[3].u = 1.0F; + pp[3].v = top_v; + + POLY_add_quad(quad, POLY_PAGE_LADSHAD, TRUE); + } + } +} + + +#ifdef EDITOR + +void FACET_draw_ns_ladder( + SLONG x1, + SLONG z1, + SLONG x2, + SLONG z2, + SLONG height) +{ + DFacet df; + + SLONG y; + + SLONG mx = (x1 + x2 << 7) + ((z2 - z1) << 2) >> 8; + SLONG mz = (z1 + z2 << 7) - ((x2 - x1) << 2) >> 8; + + ASSERT(WITHIN(mx, 0, PAP_SIZE_HI - 1)); + ASSERT(WITHIN(mz, 0, PAP_SIZE_HI - 1)); + + y = ES_hi[mx][mz].height << 5; + y += -32 * 0x100; + + // + // Create a pretend facet for the ladder facet function to use. + // + + df.FacetType = STOREY_TYPE_LADDER; + df.FacetFlags = FACET_FLAG_IN_SEWERS; + df.x[0] = x1; + df.z[0] = z1; + df.x[1] = x2; + df.z[1] = z2; + df.Y[0] = y; + df.Y[1] = y; + df.Height = height; + + // + // Draw a ladder facet. + // + + DRAW_ladder(&df); +} + +#endif + + + + + + +void FACET_project_crinkled_shadow(SLONG facet) +{ + SLONG i; + SLONG page; + SLONG style_index; + + // + // Our facet. + // + + DFacet *p_facet; + + ASSERT(WITHIN(facet, 1, next_dfacet - 1)); + + p_facet = &dfacets[facet]; + + // + // Ignore double-sided facets. + // + + if ((p_facet->FacetFlags & FACET_FLAG_2SIDED) || p_facet->FacetType == STOREY_TYPE_OINSIDE) + { + return; + } + + // + // Everything we need to work out the world positions of all the facet points. + // + + SLONG dx = p_facet->x[1] - p_facet->x[0]; + SLONG dz = p_facet->z[1] - p_facet->z[0]; + + float sx = float(p_facet->x[0] << 8); + float sy = float(p_facet->Y[0] ); + float sz = float(p_facet->z[0] << 8); + + float fdx = SIGN(dx) * 256.0F; + float fdz = SIGN(dz) * 256.0F; + + float block_height = float(p_facet->BlockHeight << 4); + SLONG height = p_facet->Height; + SLONG max_height = INFINITY; + + NIGHT_Colour *col = NULL; // No cached lighting needed! + + SLONG foundation = (p_facet->FHeight) ? 2 : 0; + + SLONG count = abs(dx) + abs(dz); + + // + // Work out the texturing. + // + + style_index = p_facet->StyleIndex; + + set_facet_seed(p_facet->x[0] * p_facet->z[0] + p_facet->Y[0]); + + // + // Where we put the points of the facet in. + // + + #define MAX_FACET_POINTS 512 + #define MAX_FACET_ROWS 32 + + SVector_F facet_point[MAX_FACET_POINTS]; + SLONG facet_point_upto; + + SVector_F *facet_row[MAX_FACET_ROWS]; + SLONG facet_row_upto; + + SVector_F *sv; + + // + // This is code taken from MakeFacetPoints and changed slightly... + // + + facet_row_upto = 0; + facet_point_upto = 0; + + float x; + float y; + float z; + + y = sy; + + while(height >= 0) + { + x = sx; + z = sz; + + ASSERT(WITHIN(facet_row_upto, 0, MAX_FACET_ROWS - 1)); + + facet_row[facet_row_upto] = &facet_point[facet_point_upto]; + + for (i = 0; i <= count; i++) + { + sv = &facet_point[facet_point_upto++]; + + // + // The y coordinate we actually use... + // + + float ty; + + if (foundation == 2) + { + ty = float(PAP_2HI(SLONG(x) >> 8, SLONG(z) >> 8).Alt << 3); + } + else + { + ty = y; + } + + // + // Store this point. + // + + sv->X = x; + sv->Y = ty; + sv->Z = z; + + x += fdx; + z += fdz; + } + + y += block_height; + height -= 4; + facet_row_upto += 1; + foundation -= 1; + } + + // + // Now we have all our points, we can go through each face in turn. + // + + SLONG base_row; + SVector_F poly[4]; + + height = p_facet->Height; + foundation = (p_facet->FHeight) ? 2 : 0; + + // + // Start from the second row! + // + + base_row = 0; + height -= 4; + + while(height >= 0) + { + { + UBYTE rflip; + + ASSERT(WITHIN(base_row, 0, facet_row_upto - 1)); + ASSERT(WITHIN(base_row + 1, 0, facet_row_upto - 1)); + + SVector_F *row1 = facet_row[base_row ]; + SVector_F *row2 = facet_row[base_row + 1]; + + for (i = 0; i < count; i++) + { + poly[0] = row2[1]; + poly[1] = row2[0]; + poly[2] = row1[1]; + poly[3] = row1[0]; + + row1 += 1; + row2 += 1; + + page = get_texture_page(dstyles[style_index], i, count, &rflip); + + // + // Add crinkle? + // + + SMAP_Link *sl = SMAP_project_onto_poly(poly, 4); + + if (sl) + { + extern int AENG_detail_crinkles; + + if (AENG_detail_crinkles) + { + if (page < 64 * 8) + { + if (TEXTURE_crinkle[page]) + { + POLY_Point pp; + + POLY_transform( + poly[0].X, + poly[0].Y, + poly[0].Z, + &pp); + + // + // This quad could be crinkled! + // + + if (pp.z > 0.6F) + { + // + // Too far away to be crinkled. + // + } + else + if (pp.z < 0.3F) + { + // + // Maximum crinkleyness! + // + + CRINKLE_project( + TEXTURE_crinkle[page], + 1.0F, + poly, + rflip); + + goto added_crinkle; + } + else + { + float extrude; + float av_z; + + // + // Intermediate crinkle extrusion. + // + + av_z = pp.z; + + extrude = av_z - 0.5F; + extrude *= 1.0F / (0.4F - 0.5F); + + if (extrude > 0.0F) + { + if (extrude > 1.0F) + { + extrude = 1.0F; + } + + CRINKLE_project( + TEXTURE_crinkle[page], + extrude, + poly, + rflip); + + goto added_crinkle; + } + } + } + } + } + + added_crinkle:; + } + } + } + + foundation -= 1; + height -= 4; + i += 1; + style_index += 1; + base_row += 1; + } +} + + + + diff --git a/fallen/DDEngine/Source/farfacet.cpp b/fallen/DDEngine/Source/farfacet.cpp new file mode 100644 index 0000000..e4b7f7e --- /dev/null +++ b/fallen/DDEngine/Source/farfacet.cpp @@ -0,0 +1,1165 @@ +// +// Faster far-facets... +// + +#include "game.h" +#include "ddlib.h" +#include "pap.h" +#include "poly.h" +#include "polypoint.h" +#include "polypage.h" +#include "night.h" +#include "supermap.h" +#include "memory.h" +#include "matrix.h" +#include + + +// +// How many lo-res mapsquares per FARFACET_square. +// + +#define FARFACET_RATIO (4) // 4x4 lo-res mapsqures in a FARFACET_square +#define FARFACET_SIZE (PAP_SIZE_LO / FARFACET_RATIO) + + + +// Set to 1 to use DrawIndPrim, rather than the MM stuff. +#define FARFACET_USE_INDEXED_LISTS 1 + +// +// Where we store the lverts. +// + +D3DLVERTEX *FARFACET_lvert_buffer; // Unaligned buffer FARFACET_lvert_max elements + 31bytes long. +D3DLVERTEX *FARFACET_lvert; // Aligned to 32 bytes +SLONG FARFACET_lvert_max; +SLONG FARFACET_lvert_upto; + + +// +// Index storage. +// + +UWORD *FARFACET_index; +SLONG FARFACET_index_max; // The number of elements in the FARFACET_index[] array. +SLONG FARFACET_index_upto; + + +// +// 2D map. +// + +typedef struct +{ + UWORD lvert; + UWORD lvertcount; + UWORD index; + UWORD indexcount; + +} FARFACET_Square; + +FARFACET_Square FARFACET_square[FARFACET_SIZE][FARFACET_SIZE]; + + +// +// During initialisation we use this array to store the rectangular +// outline of each facet. +// + +typedef struct +{ + UBYTE x1; + SBYTE y1; + UBYTE z1; + + UBYTE x2; + SBYTE y2; + UBYTE z2; + +} FARFACET_Outline; + +#define FARFACET_MAX_OUTLINES (8192 / ((32 / FARFACET_RATIO) * (32 / FARFACET_RATIO)) + 256) + +FARFACET_Outline *FARFACET_outline; +SLONG FARFACET_outline_upto; + + +// +// The renderstate of the farfacets... no texture, no fogging, backface culled. +// + +RenderState FARFACET_renderstate; +RenderState FARFACET_default_renderstate; + + +// +// A 32-byte aligned matrix. +// + +UBYTE FARFACET_matrix_buffer[sizeof(D3DMATRIX) + 32]; +D3DMATRIX *FARFACET_matrix; + + + +// +// Looks for a vertex at (x,y,z) for the given square. If found +// it returns that vertex index, otherwise it creates one. +// + +UWORD FARFACET_find_vertex(FARFACET_Square *fs, UBYTE map_x, SBYTE map_y, UBYTE map_z) +{ + SLONG i; + + float x = float(map_x << 8); + float y = float(map_y << 6); + float z = float(map_z << 8); + + D3DLVERTEX *lv; + + for (i = 0; i < fs->lvertcount; i++) + { + ASSERT(WITHIN(fs->lvert + i, 0, FARFACET_lvert_upto - 1)); + + lv = &FARFACET_lvert[fs->lvert + i]; + + if (lv->x == x && + lv->y == y && + lv->z == z) + { + return i; + } + } + + // + // We need to create another point. + // + + if (FARFACET_lvert_upto >= FARFACET_lvert_max) + { + SLONG old_offset; + SLONG new_offset; + + // + // How much is FARFACET_lvert offset into the FARFACET_lvert_buffer? + // + + old_offset = ((UBYTE *) FARFACET_lvert) - ((UBYTE *) FARFACET_lvert_buffer); + + // + // Double the length of the array. + // + + FARFACET_lvert_max *= 2; + FARFACET_lvert_buffer = (D3DLVERTEX *) realloc(FARFACET_lvert_buffer, sizeof(D3DLVERTEX) * FARFACET_lvert_max + 31); + ASSERT ( FARFACET_lvert_buffer != NULL ); + FARFACET_lvert = (D3DLVERTEX *) ((SLONG(FARFACET_lvert_buffer) + 31) & ~0x1f); + + ASSERT ( FARFACET_lvert_upto < FARFACET_lvert_max ); + + // + // What is the new offset into the FARFACET_lvert_buffer? + // + + new_offset = ((UBYTE *) FARFACET_lvert) - ((UBYTE *) FARFACET_lvert_buffer); + + // + // If the offsets are different then we have to move the data around. + // + + if (new_offset != old_offset) + { + memmove(((UBYTE *) FARFACET_lvert_buffer) + new_offset, ((UBYTE *) FARFACET_lvert_buffer) + old_offset, sizeof(D3DLVERTEX) * FARFACET_lvert_upto); + } + } + + ASSERT(fs->lvert + fs->lvertcount == FARFACET_lvert_upto); + + lv = &FARFACET_lvert[FARFACET_lvert_upto++]; + + lv->x = x; + lv->y = y; + lv->z = z; + lv->tu = 0.0F; + lv->tv = 0.0F; +#ifdef DEBUG + //lv->color = 0x00ff0000; + lv->color = 0x0000ff00; +#else + lv->color = 0x00000000; +#endif + lv->specular = 0x00000000; + lv->dwReserved = 0; + + return fs->lvertcount++; +} + + +// +// Adds an index to the given square. +// + +void FARFACET_add_index(FARFACET_Square *fs, UWORD index) +{ + if (FARFACET_index_upto >= FARFACET_index_max) + { + FARFACET_index_max *= 2; + FARFACET_index = (UWORD *) realloc(FARFACET_index, sizeof(UWORD) * FARFACET_index_max); + } + + ASSERT(FARFACET_index_upto == fs->index + fs->indexcount); + + FARFACET_index[FARFACET_index_upto] = index; + + FARFACET_index_upto += 1; + fs->indexcount += 1; +} + + + + + + + + +// +// Builds the drawprim call for the given square. +// + +void FARFACET_create_square(SLONG square_x, SLONG square_z) +{ + SLONG i; + SLONG j; + SLONG f_list; + SLONG facet; + SLONG build; + SLONG exit; + SLONG lvert_memory; + SLONG old_outline_upto; + + SLONG v1; + SLONG v2; + + SLONG dx1; + SLONG dz1; + + SLONG dx2; + SLONG dz2; + + FARFACET_Outline *fo; + FARFACET_Outline *fo1; + FARFACET_Outline *fo2; + DFacet *df; + FARFACET_Square *fs; + + ASSERT(WITHIN(square_x, 0, FARFACET_SIZE - 1)); + ASSERT(WITHIN(square_z, 0, FARFACET_SIZE - 1)); + + fs = &FARFACET_square[square_x][square_z]; + + // + // Initialise the outline array. + // + + memset(FARFACET_outline, 0, sizeof(FARFACET_outline)); + + FARFACET_outline_upto = 0; + + // + // Mark all facets as not added. + // + + for (i = 1; i < next_dfacet; i++) + { + df = &dfacets[i]; + + df->Counter[0] = FALSE; + } + + // + // The bounding box of lo-res mapsquares covered by this + // farfacet square. + // + + SLONG lo_min_x; + SLONG lo_min_z; + + SLONG lo_max_x; + SLONG lo_max_z; + + SLONG lo_x; + SLONG lo_z; + + lo_min_x = (square_x + 0) * FARFACET_RATIO; + lo_min_z = (square_z + 0) * FARFACET_RATIO; + + lo_max_x = (square_x + 1) * FARFACET_RATIO; + lo_max_z = (square_z + 1) * FARFACET_RATIO; + + // + // The box we clip facet outlines against. + // + + SLONG hi_min_x = lo_min_x * 4; + SLONG hi_min_z = lo_min_z * 4; + + SLONG hi_max_x = lo_max_x * 4; + SLONG hi_max_z = lo_max_z * 4; + + // + // Add this squares facets to the outline array. + // + + for (lo_x = lo_min_x; lo_x < lo_max_x; lo_x++) + for (lo_z = lo_min_z; lo_z < lo_max_z; lo_z++) + { + f_list = PAP_2LO(lo_x,lo_z).ColVectHead; + + if (f_list) + { + exit = FALSE; + + while(!exit) + { + facet = facet_links[f_list]; + + if (facet < 0) + { + // + // The last facet in the list for each square is negative. + // + + facet = -facet; + exit = TRUE; + } + + ASSERT(WITHIN(facet, 1, next_dfacet - 1)); + + df = &dfacets[facet]; + + // + // Have we done this facet before? + // + + if (df->Counter[0]) + { + // + // Don't do this facet twice. + // + + goto abort_facet; + } + + // + // Mark this facet as done. + // + + df->Counter[0] = TRUE; + + // + // Only draw certain types of facet. + // + + if (df->FacetType != STOREY_TYPE_NORMAL && + df->FacetType != STOREY_TYPE_DOOR) + { + goto abort_facet; + } + + if (dbuildings[df->Building].Type == BUILDING_TYPE_CRATE_IN) + { + goto abort_facet; + } + + if (df->FacetFlags & FACET_FLAG_INSIDE) + { + goto abort_facet; + } + + // + // Add this facet's outline to the array. + // + + ASSERT(WITHIN(FARFACET_outline_upto, 0, FARFACET_MAX_OUTLINES - 1)); + + fo = &FARFACET_outline[FARFACET_outline_upto++]; + + fo->x1 = df->x[0]; + fo->y1 = df->Y[0] >> 6; + fo->z1 = df->z[0]; + + fo->x2 = df->x[1]; + fo->y2 = df->Y[0] + df->Height * df->BlockHeight * 4 >> 6; + fo->z2 = df->z[1]; + + SATURATE(fo->x1, hi_min_x, hi_max_x); + SATURATE(fo->z1, hi_min_z, hi_max_z); + + SATURATE(fo->x2, hi_min_x, hi_max_x); + SATURATE(fo->z2, hi_min_z, hi_max_z); + + abort_facet:; + + f_list++; + } + } + } + + // + // Go through the outline array and merge rectangles that connect to eachother. + // + + while(1) + { + old_outline_upto = FARFACET_outline_upto; + + for (i = 0; i < FARFACET_outline_upto; i++) + { + fo1 = &FARFACET_outline[i]; + + dx1 = SIGN(fo1->x2 - fo1->x1); + dz1 = SIGN(fo1->z2 - fo1->z1); + + for (j = i + 1; j < FARFACET_outline_upto; j++) + { + fo2 = &FARFACET_outline[j]; + + dx2 = SIGN(fo2->x2 - fo2->x1); + dz2 = SIGN(fo2->z2 - fo2->z1); + + // + // Do facet1 and facet2 connect? + // + + if (dx1 == dx2 && dz1 == dz2) + { + // + // They are pointing in the same direction- that's a good start! + // + + if (fo1->x1 == fo2->x1 && + fo1->z1 == fo2->z1 && + fo1->x2 == fo2->x2 && + fo1->z2 == fo2->z2) + { + // + // The facets are on top of oneanother. + // + + if (fo1->y2 == fo2->y1) + { + // + // Facet2 is directly on top of our facet. + // + + fo1->y2 = fo2->y2; + + // + // Replace this facet with the one at the end of the array + // and shorten the array. + // + + FARFACET_outline[j] = FARFACET_outline[--FARFACET_outline_upto]; + + // + // Do the facet again. + // + + j--; + } + else + if (fo1->y1 == fo2->y2) + { + // + // Facet2 is directly below our facet. + // + + fo1->y1 = fo2->y1; + + // + // Replace this facet with the one at the end of the array + // and shorten the array. + // + + FARFACET_outline[j] = FARFACET_outline[--FARFACET_outline_upto]; + + // + // Do the facet again. + // + + j--; + } + } + else + if (fo1->y1 == fo2->y1 && + fo1->y2 == fo2->y2) + { + // + // The facets are at the same height. + // + + if (fo1->x1 == fo2->x2 && + fo1->z1 == fo2->z2) + { + // + // Facet2 is directly to the left of our facet. + // + + fo1->x1 = fo2->x1; + fo1->z1 = fo2->z1; + + // + // Replace this facet with the one at the end of the array + // and shorten the array. + // + + FARFACET_outline[j] = FARFACET_outline[--FARFACET_outline_upto]; + + // + // Do the facet again. + // + + j--; + } + else + if (fo1->x2 == fo2->x1 && + fo1->z2 == fo2->z1) + { + // + // Facet2 is directly to the right of our facet. + // + + fo1->x2 = fo2->x2; + fo1->z2 = fo2->z2; + + // + // Replace this facet with the one at the end of the array + // and shorten the array. + // + + FARFACET_outline[j] = FARFACET_outline[--FARFACET_outline_upto]; + + // + // Do the facet again. + // + + j--; + } + } + } + } + } + + if (FARFACET_outline_upto == old_outline_upto) + { + // + // Looped through without making any changes. + // + + break; + } + } + + // + // Now convert the outlines to strips and build the + // DrawPrimitive data. + // + + fs->lvert = FARFACET_lvert_upto; + fs->lvertcount = 0; + fs->index = FARFACET_index_upto; + fs->indexcount = 0; + + #define FARFACET_MAX_STRIP_LENGTH 256 + + UWORD strip[FARFACET_MAX_STRIP_LENGTH]; + SLONG strip_upto; + + while(1) + { + if (FARFACET_outline_upto == 0) + { + break; + } + + // + // Create a simple strip from the last outline + // and shorten the array so we don't look for + // that outline again. + // + + strip[0] = FARFACET_outline_upto - 1; + strip_upto = 1; + FARFACET_outline_upto -= 1; + + // + // Try and lengthen the strip by adding onto the beginning. + // + + fo1 = &FARFACET_outline[strip[0]]; + + add_onto_beginning:; + + for (i = 0; i < FARFACET_outline_upto; i++) + { + fo2 = &FARFACET_outline[i]; + + if (fo2->x2 == fo1->x1 && + fo2->y2 == fo1->y1 && + fo2->z2 == fo1->z1) + { + // + // Swap this facet with the one at the end of the + // outline array and shorten the array so we dont + // consider it again. + // + + FARFACET_outline_upto -= 1; + + SWAP(fo2->x1, FARFACET_outline[FARFACET_outline_upto].x1); + SWAP(fo2->y1, FARFACET_outline[FARFACET_outline_upto].y1); + SWAP(fo2->z1, FARFACET_outline[FARFACET_outline_upto].z1); + + SWAP(fo2->x2, FARFACET_outline[FARFACET_outline_upto].x2); + SWAP(fo2->y2, FARFACET_outline[FARFACET_outline_upto].y2); + SWAP(fo2->z2, FARFACET_outline[FARFACET_outline_upto].z2); + + // + // We can add this outline onto the beginning + // of the strip. + // + + ASSERT(WITHIN(strip_upto, 1, FARFACET_MAX_STRIP_LENGTH - 1)); + + memmove(strip + 1, strip + 0, sizeof(UWORD) * strip_upto); + strip_upto += 1; + + strip[0] = FARFACET_outline_upto; + + // + // Start again. + // + + goto add_onto_beginning; + } + } + + // + // Now lengthen the strip by adding onto the end. + // + + ASSERT(WITHIN(strip_upto, 1, FARFACET_MAX_STRIP_LENGTH - 1)); + + fo1 = &FARFACET_outline[strip[strip_upto - 1]]; + + add_onto_end:; + + for (i = 0; i < FARFACET_outline_upto; i++) + { + fo2 = &FARFACET_outline[i]; + + if (fo2->x1 == fo1->x2 && + fo2->y1 == fo1->y2 && + fo2->z1 == fo1->z2) + { + // + // Swap this facet with the one at the end of the + // outline array and shorten the array so we dont + // consider it again. + // + + FARFACET_outline_upto -= 1; + + SWAP(fo2->x1, FARFACET_outline[FARFACET_outline_upto].x1); + SWAP(fo2->y1, FARFACET_outline[FARFACET_outline_upto].y1); + SWAP(fo2->z1, FARFACET_outline[FARFACET_outline_upto].z1); + + SWAP(fo2->x2, FARFACET_outline[FARFACET_outline_upto].x2); + SWAP(fo2->y2, FARFACET_outline[FARFACET_outline_upto].y2); + SWAP(fo2->z2, FARFACET_outline[FARFACET_outline_upto].z2); + + // + // We can add this outline onto the end of the strip. + // + + ASSERT(WITHIN(strip_upto, 1, FARFACET_MAX_STRIP_LENGTH - 1)); + + strip[strip_upto++] = FARFACET_outline_upto; + + // + // Start again. + // + + goto add_onto_end; + } + } + + // + // Add this strip to the square. The initial points of the + // first outline now. + // + + fo = &FARFACET_outline[strip[0]]; + + v1 = FARFACET_find_vertex(fs, fo->x1,fo->y1,fo->z1); + v2 = FARFACET_find_vertex(fs, fo->x1,fo->y2,fo->z1); + +#if FARFACET_USE_INDEXED_LISTS + // Do nothing. + SLONG v1prev = v1; + SLONG v2prev = v2; +#else + FARFACET_add_index(fs, v1); + FARFACET_add_index(fs, v2); +#endif + + for (i = 0; i < strip_upto; i++) + { + fo = &FARFACET_outline[strip[i]]; + + v1 = FARFACET_find_vertex(fs, fo->x2,fo->y1,fo->z2); + v2 = FARFACET_find_vertex(fs, fo->x2,fo->y2,fo->z2); + +#if FARFACET_USE_INDEXED_LISTS + FARFACET_add_index(fs, v1prev); + FARFACET_add_index(fs, v2prev); + FARFACET_add_index(fs, v1); + FARFACET_add_index(fs, v1); + FARFACET_add_index(fs, v2prev); + FARFACET_add_index(fs, v2); + v1prev = v1; + v2prev = v2; +#else + FARFACET_add_index(fs, v1); + FARFACET_add_index(fs, v2); +#endif + } + +#if !FARFACET_USE_INDEXED_LISTS + FARFACET_add_index(fs, -1); // End of a strip... +#endif + } +} + + + + +void FARFACET_init() +{ + // + // Initialise memory. + // + + FARFACET_lvert_max = 1024; + FARFACET_lvert_upto = 0; + FARFACET_lvert_buffer = (D3DLVERTEX *) malloc(sizeof(D3DLVERTEX) * FARFACET_lvert_max + 31); + FARFACET_lvert = (D3DLVERTEX *) ((SLONG(FARFACET_lvert_buffer) + 31) & ~0x1f); + +#if FARFACET_USE_INDEXED_LISTS + FARFACET_index_max = FARFACET_lvert_max * 5 / 4; +#else + FARFACET_index_max = FARFACET_lvert_max * 6 / 4; +#endif + FARFACET_index_upto = 0; + FARFACET_index = (UWORD *) malloc(sizeof(UWORD) * FARFACET_index_max); + + FARFACET_outline = (FARFACET_Outline *) malloc(sizeof(FARFACET_Outline) * FARFACET_MAX_OUTLINES); + FARFACET_outline_upto = 0; + + memset(FARFACET_square, 0, sizeof(FARFACET_square ) ); + memset(FARFACET_lvert, 0, sizeof(D3DLVERTEX ) * FARFACET_lvert_max ); + memset(FARFACET_index, 0, sizeof(UWORD ) * FARFACET_index_max ); + memset(FARFACET_outline, 0, sizeof(FARFACET_Outline ) * FARFACET_MAX_OUTLINES); + + FARFACET_matrix = (D3DMATRIX *) ((SLONG(FARFACET_matrix_buffer) + 31) & ~0x1f); + + // + // Calculate the FARFACET squares. + // + + SLONG x; + SLONG z; + + for (x = 0; x < FARFACET_SIZE; x++) + for (z = 0; z < FARFACET_SIZE; z++) + { + FARFACET_create_square(x,z); + } + + // + // We don't need the outline array any more. + // + + free(FARFACET_outline); + + // + // Setup our renderstate. + // + + + FARFACET_renderstate.SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE); + +#if 0 +// These are all completely ignored by the DC SetChanged thing - don't bother. + FARFACET_renderstate.SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE); + FARFACET_renderstate.SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE); +#endif + + FARFACET_renderstate.SetTexture(NULL); + +} + + +SLONG FARFACET_num_squares_drawn; + +void FARFACET_draw( + float x, + float y, + float z, + float yaw, + float pitch, + float roll, + float draw_dist, + float lens) +{ + #ifndef TARGET_DC + + if (!Keys[KB_R]) + { + return; + } + + #endif + + // + // The five point of the view pyramid. + // + + float width; + float height; + float depth; + float aspect; + float matrix[9]; + + struct + { + float x; + float z; + + } cone[5]; + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + FARFACET_num_squares_drawn = 0; + + // + // The dimensions of the view pyramid. + // + + width = draw_dist; + height = draw_dist; + depth = draw_dist; + + width *= POLY_screen_width; + width /= POLY_screen_height; + + width /= lens; + height /= lens; + + // + // Finds the points of the cone in world space + // + + cone[3].x = cone[4].x = x / 256.0f; + cone[3].z = cone[4].z = z / 256.0f; + + cone[3].x += depth * matrix[6]; + cone[3].z += depth * matrix[8]; + + // + // cone[0] is the top left corner... + // + + cone[0].x = cone[3].x + height * matrix[3]; + cone[0].z = cone[3].z + height * matrix[5]; + + cone[0].x = cone[0].x - width * matrix[0]; + cone[0].z = cone[0].z - width * matrix[2]; + + // + // cone[1] is the top right corner... + // + + cone[1].x = cone[3].x + height * matrix[3]; + cone[1].z = cone[3].z + height * matrix[5]; + + cone[1].x = cone[1].x + width * matrix[0]; + cone[1].z = cone[1].z + width * matrix[2]; + + // + // cone[2] is the bottom right corner... + // + + cone[2].x = cone[3].x - height * matrix[3]; + cone[2].z = cone[3].z - height * matrix[5]; + + cone[2].x = cone[2].x + width * matrix[0]; + cone[2].z = cone[2].z + width * matrix[2]; + + // + // cone[3] is the bottom left corner... + // + + cone[3].x = cone[3].x - height * matrix[3]; + cone[3].z = cone[3].z - height * matrix[5]; + + cone[3].x = cone[3].x - width * matrix[0]; + cone[3].z = cone[3].z - width * matrix[2]; + + // + // Find the bounding box of squares we should draw. + // + + SLONG square_min_x = +INFINITY; + SLONG square_min_z = +INFINITY; + + SLONG square_max_x = -INFINITY; + SLONG square_max_z = -INFINITY; + + SLONG i; + + for (i = 0; i < 5; i++) + { + if (ftol(cone[i].x) < square_min_x) {square_min_x = ftol(cone[i].x);} + if (ftol(cone[i].z) < square_min_z) {square_min_z = ftol(cone[i].z);} + + if (ftol(cone[i].x) > square_max_x) {square_max_x = ftol(cone[i].x);} + if (ftol(cone[i].z) > square_max_z) {square_max_z = ftol(cone[i].z);} + } + + // + // This is in high-res map squares, now convert to our + // size of square. + // + + square_min_x /= 4 * FARFACET_RATIO; + square_min_z /= 4 * FARFACET_RATIO; + + square_max_x /= 4 * FARFACET_RATIO; + square_max_z /= 4 * FARFACET_RATIO; + + SATURATE(square_min_x, 0, FARFACET_SIZE - 1); + SATURATE(square_min_z, 0, FARFACET_SIZE - 1); + + SATURATE(square_max_x, 0, FARFACET_SIZE - 1); + SATURATE(square_max_z, 0, FARFACET_SIZE - 1); + + #if 0 + + // + // To draw every far-facet... + // + + square_min_x = 0; + square_min_z = 0; + + square_max_x = FARFACET_SIZE - 1; + square_max_z = FARFACET_SIZE - 1; + + #endif + + // + // Setup renderstate. + // + + FARFACET_renderstate.SetChanged(); + + + // + // Initialise Tom's doberries... + // + + + // Adjust the projection to put the RHW values a little further back than normal. + // This is sort of like a Z-bias. It's there to avoid Z-fighting with the real scene polygons. + // Note that this uniform scale _does_ put the RHWs back because we are using the multimatrix stuff, + // which has several cheats. Fortunately. +#define MY_PROJ_MATRIX_SCALE 1.01f + D3DMATRIX matMyProj = g_matProjection; + matMyProj._11 *= MY_PROJ_MATRIX_SCALE; + matMyProj._12 *= MY_PROJ_MATRIX_SCALE; + matMyProj._13 *= MY_PROJ_MATRIX_SCALE; + matMyProj._14 *= MY_PROJ_MATRIX_SCALE; + matMyProj._21 *= MY_PROJ_MATRIX_SCALE; + matMyProj._22 *= MY_PROJ_MATRIX_SCALE; + matMyProj._23 *= MY_PROJ_MATRIX_SCALE; + matMyProj._24 *= MY_PROJ_MATRIX_SCALE; + matMyProj._31 *= MY_PROJ_MATRIX_SCALE; + matMyProj._32 *= MY_PROJ_MATRIX_SCALE; + matMyProj._33 *= MY_PROJ_MATRIX_SCALE; + matMyProj._34 *= MY_PROJ_MATRIX_SCALE; + matMyProj._41 *= MY_PROJ_MATRIX_SCALE; + matMyProj._42 *= MY_PROJ_MATRIX_SCALE; + matMyProj._43 *= MY_PROJ_MATRIX_SCALE; + matMyProj._44 *= MY_PROJ_MATRIX_SCALE; + + +#if FARFACET_USE_INDEXED_LISTS + (the_display.lp_D3D_Device)->SetTransform ( D3DTRANSFORMSTATE_PROJECTION, &matMyProj ); +#else + GenerateMMMatrixFromStandardD3DOnes( + FARFACET_matrix, + &matMyProj, + NULL, + &g_viewData); +#endif + + +#ifdef DEBUG + the_display.SetRenderState ( D3DRENDERSTATE_FOGENABLE, FALSE ); +#endif + + // + // Draw all the squares. + // + + SLONG square_x; + SLONG square_z; + + float mid_x; + float mid_y; + float mid_z; + + float dx; + float dy; + float dz; + + float dist; + float dprod; + + FARFACET_Square *fs; + + for (square_x = square_min_x; square_x <= square_max_x; square_x++) + for (square_z = square_min_z; square_z <= square_max_z; square_z++) + { + fs = &FARFACET_square[square_x][square_z]; + + +#ifdef DEBUG + // Colourise the different squares + DWORD dwColour = (DWORD)fs; + dwColour += 0x32928157; + dwColour *= 0x90781; + dwColour ^= (dwColour << 3) ^ (dwColour << 5) ^(dwColour << 9) ^(dwColour << 18) ^(dwColour << 23) ^(dwColour << 28); + dwColour *= 0x9574; + dwColour += 0x90846347; + dwColour &= 0x7f7f7f7f; + for ( int i = 0; i < fs->lvertcount; i++ ) + { + FARFACET_lvert[fs->lvert + i].color = dwColour; + FARFACET_lvert[fs->lvert + i].specular = dwColour; + } +#endif + + if (fs->indexcount) + { + // + // Don't draw squares to close to the camera- or behind it! + // + + mid_y = 0.0F; + + mid_x = (float(square_x) + 0.5F) * (4.0F * FARFACET_RATIO * 256.0F); + mid_z = (float(square_z) + 0.5F) * (4.0F * FARFACET_RATIO * 256.0F); + + dx = mid_x - x; + dy = mid_y - y; + dz = mid_z - z; + + dprod = dx*matrix[6] + dy*matrix[7] + dz*matrix[8]; + +#if 0 + if (dprod < 12.0F * 256.0F) +#else + // React to the fog distance change. +extern SLONG CurDrawDistance; + if (dprod * 2.5f < (float)CurDrawDistance) +#endif + { + continue; + } + + FARFACET_num_squares_drawn += 1; + +#if FARFACET_USE_INDEXED_LISTS + the_display.DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + FARFACET_lvert + fs->lvert, + fs->lvertcount, + FARFACET_index + fs->index, + fs->indexcount, + D3DDP_DONOTUPDATEEXTENTS); +#else + D3DMULTIMATRIX d3dmm = + { + FARFACET_lvert + fs->lvert, + FARFACET_matrix, + NULL, + NULL + }; + + //TRACE ( "S2" ); + DrawIndPrimMM( + the_display.lp_D3D_Device, + D3DFVF_LVERTEX, + &d3dmm, + fs->lvertcount, + FARFACET_index + fs->index, + fs->indexcount); + //TRACE ( "F2" ); +#endif + + } + } + + // + // Revert to default renderstate. + // + +#ifdef DEBUG + the_display.SetRenderState ( D3DRENDERSTATE_FOGENABLE, TRUE ); +#endif + + FARFACET_default_renderstate.SetChanged(); + +#if FARFACET_USE_INDEXED_LISTS + // Restore the projection matrix. + (the_display.lp_D3D_Device)->SetTransform ( D3DTRANSFORMSTATE_PROJECTION, &g_matProjection ); +#endif + + + +} + + + + +void FARFACET_fini() +{ + // + // Free memory. + // + + free(FARFACET_lvert_buffer); + free(FARFACET_index ); +} + + + + + diff --git a/fallen/DDEngine/Source/fastprim.cpp b/fallen/DDEngine/Source/fastprim.cpp new file mode 100644 index 0000000..cabb086 --- /dev/null +++ b/fallen/DDEngine/Source/fastprim.cpp @@ -0,0 +1,1416 @@ +// +// Draws prims super-fast! +// + +#include "game.h" +#include "ddlib.h" +#include "poly.h" +#include "polypoint.h" +#include "polypage.h" +#include "fastprim.h" +#include "memory.h" +#include "texture.h" +#include "matrix.h" + + +//#define FASTPRIM_PERFORMANCE + +#ifdef FASTPRIM_PERFORMANCE +FILE *FASTPRIM_handle; +SLONG FASTPRIM_num_freed; +SLONG FASTPRIM_num_cached; +SLONG FASTPRIM_num_already_cached; +SLONG FASTPRIM_num_drawn; +#endif + + +// +// The D3D vertices and indices passed to DrawIndexedPrimitive +// + +D3DLVERTEX *FASTPRIM_lvert_buffer; +D3DLVERTEX *FASTPRIM_lvert; +SLONG FASTPRIM_lvert_max; +SLONG FASTPRIM_lvert_upto; +SLONG FASTPRIM_lvert_free_end; // The end of the free range of lverts. +SLONG FASTPRIM_lvert_free_unused; // From this lvert to the end of the array is unused. + +UWORD *FASTPRIM_index; +SLONG FASTPRIM_index_max; +SLONG FASTPRIM_index_upto; +SLONG FASTPRIM_index_free_end; // The end of the free range of indices +SLONG FASTPRIM_index_free_unused; // From this index to the end of the array is unused. + +// +// A 32-byte aligned matrix. +// + +UBYTE FASTPRIM_matrix_buffer[sizeof(D3DMATRIX) + 32]; +D3DMATRIX *FASTPRIM_matrix; + +// +// Each DrawIndexedPrim call has one of these structures. +// + +#define FASTPRIM_CALL_TYPE_NORMAL 0 // Uses DrawIndMM - no alpha, no MESH_colour_and, no envmapping... +#define FASTPRIM_CALL_TYPE_COLOURAND 1 // Uses DrawIndMM. The colours for this call should be AND'ed with MESH_colour_and +#define FASTPRIM_CALL_TYPE_INDEXED 2 // Uses DrawIndexedPrimitive and the texture is an alpha texture +#define FASTPRIM_CALL_TYPE_ENVMAP 3 // This is an an environment mapping call - uses DrawIndexedPrimitive and the (u,v) must be set each frame. + +#define FASTPRIM_CALL_FLAG_SELF_ILLUM (1 << 0) + +typedef struct +{ + UWORD flag; + UWORD type; + + UWORD lvert; + UWORD lvertcount; + UWORD index; + UWORD indexcount; + + LPDIRECT3DTEXTURE2 texture; + +} FASTPRIM_Call; + +#define FASTPRIM_MAX_CALLS 512 + +FASTPRIM_Call FASTPRIM_call[FASTPRIM_MAX_CALLS]; +SLONG FASTPRIM_call_upto; + + +// +// Each prim... +// + +#define FASTPRIM_PRIM_FLAG_CACHED (1 << 0) +#define FASTPRIM_PRIM_FLAG_INVALID (1 << 1) // This prim cannot be converted for some reason. + +typedef struct +{ + UWORD flag; + UWORD call_index; + UWORD call_count; + +} FASTPRIM_Prim; + +#define FASTPRIM_MAX_PRIMS 256 + +FASTPRIM_Prim FASTPRIM_prim[FASTPRIM_MAX_PRIMS]; + + +// +// Circular queue of prims we have cached. +// + +#define FASTPRIM_MAX_QUEUE 128 + +UBYTE FASTPRIM_queue[FASTPRIM_MAX_QUEUE]; +SLONG FASTPRIM_queue_start; +SLONG FASTPRIM_queue_end; + + + + +// +// Returns the actual page used. +// + +LPDIRECT3DTEXTURE2 FASTPRIM_find_texture_from_page(SLONG page) +{ + SLONG i; + + PolyPage *pp = &POLY_Page[page]; + + return pp->RS.GetTexture(); +} + + +#ifdef DEBUG +void *pvJustChecking1 = NULL; +void *pvJustChecking2 = NULL; +#endif + + +void FASTPRIM_init() +{ + // + // Allocate memory. + // + + FASTPRIM_lvert_max = 4096; + //FASTPRIM_lvert_max = 256; + + +#ifdef DEBUG + FASTPRIM_lvert_buffer = (D3DLVERTEX *) MemAlloc(sizeof(D3DLVERTEX) * FASTPRIM_lvert_max + 31 + 32); + FASTPRIM_lvert = (D3DLVERTEX *) ((((SLONG) FASTPRIM_lvert_buffer) + 31) & ~0x1f); + // And write magic numbers just afterwards to check for scribbles. + char *pcTemp = (char *)( (SLONG)FASTPRIM_lvert + sizeof(D3DLVERTEX) * FASTPRIM_lvert_max ); + strcpy ( pcTemp, "ThisIsAMagicString901234567890" ); +#else + FASTPRIM_lvert_buffer = (D3DLVERTEX *) MemAlloc(sizeof(D3DLVERTEX) * FASTPRIM_lvert_max + 31); + FASTPRIM_lvert = (D3DLVERTEX *) ((((SLONG) FASTPRIM_lvert_buffer) + 31) & ~0x1f); +#endif + FASTPRIM_lvert_upto = 0; + FASTPRIM_lvert_free_end = FASTPRIM_lvert_max; + FASTPRIM_lvert_free_unused = FASTPRIM_lvert_max; + + FASTPRIM_index_max = FASTPRIM_lvert_max * 3; // Not * 5 / 4 because we may have some extra sharing... + FASTPRIM_index = (UWORD *) MemAlloc(sizeof(UWORD) * FASTPRIM_index_max); + FASTPRIM_index_upto = 0; + FASTPRIM_index_free_end = FASTPRIM_index_max; + FASTPRIM_index_free_unused = FASTPRIM_index_max; + +#ifdef DEBUG + pvJustChecking1 = (void *)FASTPRIM_lvert_buffer; + pvJustChecking2 = (void *)FASTPRIM_index; +#endif + + FASTPRIM_call_upto = 0; + + FASTPRIM_queue_start = 0; + FASTPRIM_queue_end = 0; + + memset(FASTPRIM_lvert, 0, sizeof(D3DLVERTEX) * FASTPRIM_lvert_max); + memset(FASTPRIM_index, 0, sizeof(UWORD ) * FASTPRIM_index_max); + memset(FASTPRIM_call, 0, sizeof(FASTPRIM_call)); + memset(FASTPRIM_prim, 0, sizeof(FASTPRIM_prim)); + memset(FASTPRIM_queue, 0, sizeof(FASTPRIM_queue)); + + FASTPRIM_matrix = (D3DMATRIX *) ((SLONG(FASTPRIM_matrix_buffer) + 31) & ~0x1f); + + // + // Don't convert car wheels because their texture coordinates rotate! + // + + FASTPRIM_prim[PRIM_OBJ_CAR_WHEEL].flag = FASTPRIM_PRIM_FLAG_INVALID; + + #ifdef FASTPRIM_PERFORMANCE + if (!FASTPRIM_handle){FASTPRIM_handle = fopen("c:\\fastprim.txt", "wb");} + FASTPRIM_num_freed = 0; + FASTPRIM_num_cached = 0; + FASTPRIM_num_already_cached = 0; + FASTPRIM_num_drawn = 0; + #endif +} + + +// +// Frees up the given cached prim. +// + +void FASTPRIM_free_cached_prim(SLONG prim) +{ + SLONG i; + + FASTPRIM_Call *fc; + FASTPRIM_Prim *fp; + + ASSERT(WITHIN(prim, 0, FASTPRIM_MAX_PRIMS - 1)); + + fp = &FASTPRIM_prim[prim]; + + for (i = 0; i < fp->call_count; i++) + { + ASSERT(WITHIN(fp->call_index, 0, FASTPRIM_MAX_CALLS - 1)); + + fc = &FASTPRIM_call[fp->call_index + i]; + + // + // Free up the verts and indices used by this call. + // + + FASTPRIM_lvert_free_end = fc->lvert + fc->lvertcount; + FASTPRIM_index_free_end = fc->index + fc->indexcount; + + if (FASTPRIM_lvert_free_end >= FASTPRIM_lvert_free_unused || + FASTPRIM_index_free_end >= FASTPRIM_index_free_unused) + { + FASTPRIM_lvert_free_end = FASTPRIM_lvert_max; + FASTPRIM_index_free_end = FASTPRIM_index_max; + + FASTPRIM_lvert_free_unused = FASTPRIM_lvert_max; + FASTPRIM_index_free_unused = FASTPRIM_index_max; + + break; + } + } + + fp->flag &= ~FASTPRIM_PRIM_FLAG_CACHED; + fp->call_count = 0; + fp->call_index = 0; + + #ifdef FASTPRIM_PERFORMANCE + fprintf(FASTPRIM_handle, "Gameturn %5d free prim %3d\n", GAME_TURN, prim); + fflush(FASTPRIM_handle); + FASTPRIM_num_freed += 1; + #endif +} + + + +// +// Frees up the oldest cached prim to make room for the given call +// to grow. It may move all the data in the call! +// + +void FASTPRIM_free_queue_for_call(FASTPRIM_Call *fc) +{ + SLONG duplicates = 0; + + SLONG old_lvert_free_end; + SLONG old_index_free_end; + + SLONG copy_to_beginning = FALSE; + + while(1) + { + old_lvert_free_end = FASTPRIM_lvert_free_end; + old_index_free_end = FASTPRIM_index_free_end; + + // + // Free up the last cached prim. + // + + ASSERT(FASTPRIM_queue_end < FASTPRIM_queue_start); + + FASTPRIM_free_cached_prim(FASTPRIM_queue[FASTPRIM_queue_end++ & (FASTPRIM_MAX_QUEUE - 1)]); + + if (FASTPRIM_lvert_free_end < old_lvert_free_end || + FASTPRIM_index_free_end < old_index_free_end) + { + // + // The lverts have wrapped around. We must copy all the lverts + // in the call to the beginning of the array (when we have enough room). + // + + FASTPRIM_lvert_upto = fc->lvertcount; + FASTPRIM_index_upto = fc->indexcount; + + copy_to_beginning = TRUE; + + #ifdef FASTPRIM_PERFORMANCE + fprintf(FASTPRIM_handle, "Wrap...\n"); + fflush(FASTPRIM_handle); + #endif + } + + if (FASTPRIM_index_upto + 16 < FASTPRIM_index_free_end && + FASTPRIM_lvert_upto + 16 < FASTPRIM_lvert_free_end) + { + // + // Enough room! Do we have to copy the lverts or indices to the + // beginning of the array? + // + + if (copy_to_beginning) + { + memcpy(FASTPRIM_lvert, FASTPRIM_lvert + fc->lvert, sizeof(D3DLVERTEX) * fc->lvertcount); + memcpy(FASTPRIM_index, FASTPRIM_index + fc->index, sizeof(UWORD ) * fc->indexcount); + + FASTPRIM_lvert_free_unused = fc->lvert; + FASTPRIM_index_free_unused = fc->index; + + fc->lvert = 0; + fc->index = 0; + } + + return; + } + else + { + duplicates += 1; + } + } +} + + + + + + +// +// Makes sure the given FASTPRIM_Prim has a call structure for +// the given texture. +// + +void FASTPRIM_create_call(FASTPRIM_Prim *fp, LPDIRECT3DTEXTURE2 texture, UWORD type) +{ + SLONG i; + + FASTPRIM_Call *fc; + + // + // Do we already have a call structure for this texture? + // + + for (i = 0; i < fp->call_count; i++) + { + ASSERT(WITHIN(fp->call_index + i, 0, FASTPRIM_call_upto - 1)); + + fc = &FASTPRIM_call[fp->call_index + i]; + + if (fc->texture == texture && fc->type == type) + { + return; + } + } + + // + // Create a new call structure. + // + + ASSERT(WITHIN(FASTPRIM_call_upto, 0, FASTPRIM_MAX_CALLS - 1)); + ASSERT(fp->call_index + fp->call_count == FASTPRIM_call_upto); + + fc = &FASTPRIM_call[fp->call_index + fp->call_count]; + + fc->type = type; + fc->lvert = 0; + fc->lvertcount = 0; + fc->index = 0; + fc->indexcount = 0; + fc->texture = texture; + + fp->call_count += 1; + FASTPRIM_call_upto += 1; + + return; +} + +// +// Adds a point to the given call structure. If the point already +// exists then it returns the old point. +// + +UWORD FASTPRIM_add_point_to_call( + FASTPRIM_Call *fc, + float x, + float y, + float z, + float u, + float v, + ULONG colour, + ULONG specular) +{ + SLONG i; + + D3DLVERTEX *lv; + + // + // Does this point already exist? + // + + for (i = fc->lvertcount - 1; i >= 0; i--) + { + ASSERT(WITHIN(fc->lvert + i, 0, FASTPRIM_lvert_max - 1)); + + lv = &FASTPRIM_lvert[fc->lvert + i]; + + if (lv->x == x && + lv->y == y && + lv->z == z && + lv->tu == u && + lv->tv == v && + lv->color == colour && + lv->specular == specular) + { + return i; + } + } + + // + // Create a new point. + // + + if (FASTPRIM_lvert_upto >= FASTPRIM_lvert_free_end) + { + // + // Need more room! + // + + #ifdef FASTPRIM_PERFORMANCE + fprintf(FASTPRIM_handle, "No lverts...\n"); + fflush(FASTPRIM_handle); + #endif + + FASTPRIM_free_queue_for_call(fc); + } + + ASSERT(WITHIN(FASTPRIM_lvert_upto, 0, FASTPRIM_lvert_max - 1)); + ASSERT(fc->lvert + fc->lvertcount == FASTPRIM_lvert_upto); + + lv = &FASTPRIM_lvert[fc->lvert + fc->lvertcount]; + + lv->x = x; + lv->y = y; + lv->z = z; + lv->tu = u; + lv->tv = v; + lv->color = colour; + lv->specular = specular; + + FASTPRIM_lvert_upto += 1; + + return fc->lvertcount++; +} + + +void FASTPRIM_ensure_room_for_indices(FASTPRIM_Call *fc) +{ + if (FASTPRIM_index_upto + 8 >= FASTPRIM_index_free_end) + { + #ifdef FASTPRIM_PERFORMANCE + fprintf(FASTPRIM_handle, "No indices...\n"); + fflush(FASTPRIM_handle); + #endif + + FASTPRIM_free_queue_for_call(fc); + } +} + + + +SLONG FASTPRIM_draw( + SLONG prim, + float x, + float y, + float z, + float matrix[9], + NIGHT_Colour *lpc) +{ + #ifndef TARGET_DC + + if (!Keys[KB_R]) + { + return FALSE; + } + + #endif + + SLONG i; + SLONG j; + SLONG k; + SLONG page; + SLONG type; + SLONG index[4]; + + float px; + float py; + float pz; + float pu; + float pv; + + ULONG pcolour; + ULONG pspecular; + + FASTPRIM_Prim *fp; + PrimObject *po; + PrimFace4 *f4; + PrimFace3 *f3; + FASTPRIM_Call *fc; + PolyPage *pp; + + LPDIRECT3DTEXTURE2 texture; + + ASSERT(WITHIN(prim, 0, FASTPRIM_MAX_PRIMS - 1)); + + // + // Is this prim too close to the camera in (x,z)? Ignore y + // because lamposts and trees have a huge y! + // + + { + PrimInfo *pi = get_prim_info(prim); + + extern float AENG_cam_x; + extern float AENG_cam_z; + + float dx = x - AENG_cam_x; + float dz = z - AENG_cam_z; + + float dist = dx*dx + dz*dz; + float radius = float(MAX(pi->maxx-pi->minx,pi->maxz-pi->minz)) + 16.0f; + + if (dist < radius*radius) + { + // + // Less than 1 mapsquare distant... drawn the old way! + // + + return FALSE; + } + } + + + fp = &FASTPRIM_prim[prim]; + + #ifndef TARGET_DC + if (!Keys[KB_R]) + { + return FALSE; + } + #endif + + #ifdef FASTPRIM_PERFORMANCE + FASTPRIM_num_drawn += 1; + #endif + + if (fp->flag & FASTPRIM_PRIM_FLAG_CACHED) + { + #ifdef FASTPRIM_PERFORMANCE + FASTPRIM_num_already_cached += 1; + #endif + } + else + { + // + // We've come across a new prim. + // + + if (FASTPRIM_call_upto + 32 >= FASTPRIM_MAX_CALLS) + { + // + // Assume max of 32 calls per prim? And pray to god + // that there is enough room! + // + + FASTPRIM_call_upto = 0; + } + + fp->call_count = 0; + fp->call_index = FASTPRIM_call_upto; + + // + // Go through all the faces and create a new call + // structure for each new texture/type we come across. + // + + po = &prim_objects[prim]; + + for (i = po->StartFace3; i < po->EndFace3; i++) + { + ASSERT(WITHIN(i, 0, next_prim_face3 - 1)); + + f3 = &prim_faces3[i]; + + page = f3->UV[0][0] & 0xc0; + page <<= 2; + page |= f3->TexturePage; + page += FACE_PAGE_OFFSET; + + texture = FASTPRIM_find_texture_from_page(page); + + if (POLY_Page[page].RS.IsAlphaBlendEnabled()) + { + type = FASTPRIM_CALL_TYPE_INDEXED; + } + else + if (f3->FaceFlags & FACE_FLAG_TINT) + { + type = FASTPRIM_CALL_TYPE_COLOURAND; + } + else + { + type = FASTPRIM_CALL_TYPE_NORMAL; + } + + FASTPRIM_create_call(fp, texture, type); + } + + for (i = po->StartFace4; i < po->EndFace4; i++) + { + ASSERT(WITHIN(i, 0, next_prim_face4 - 1)); + + f4 = &prim_faces4[i]; + + page = f4->UV[0][0] & 0xc0; + page <<= 2; + page |= f4->TexturePage; + page += FACE_PAGE_OFFSET; + + texture = FASTPRIM_find_texture_from_page(page); + + if (POLY_Page[page].RS.IsAlphaBlendEnabled()) + { + type = FASTPRIM_CALL_TYPE_INDEXED; + } + else + if (f4->FaceFlags & FACE_FLAG_TINT) + { + type = FASTPRIM_CALL_TYPE_COLOURAND; + } + else + { + type = FASTPRIM_CALL_TYPE_NORMAL; + } + + FASTPRIM_create_call(fp, texture, type); + } + + // + // Now go through each texture and add the faces + // that use that texture. + // + + for (i = 0; i < fp->call_count; i++) + { + ASSERT(WITHIN(fp->call_index + i, 0, FASTPRIM_call_upto - 1)); + + fc = &FASTPRIM_call[fp->call_index + i]; + + fc->flag = 0; + + fc->lvert = FASTPRIM_lvert_upto; + fc->index = FASTPRIM_index_upto; + + fc->lvertcount = 0; + fc->indexcount = 0; + + for (j = po->StartFace3; j < po->EndFace3; j++) + { + ASSERT(WITHIN(j, 0, next_prim_face3 - 1)); + + f3 = &prim_faces3[j]; + + page = f3->UV[0][0] & 0xc0; + page <<= 2; + page |= f3->TexturePage; + page += FACE_PAGE_OFFSET; + + texture = FASTPRIM_find_texture_from_page(page); + + if (POLY_Page[page].RS.IsAlphaBlendEnabled()) + { + type = FASTPRIM_CALL_TYPE_INDEXED; + } + else + if (f3->FaceFlags & FACE_FLAG_TINT) + { + type = FASTPRIM_CALL_TYPE_COLOURAND; + } + else + { + type = FASTPRIM_CALL_TYPE_NORMAL; + } + + if (texture == fc->texture && type == fc->type) + { + // + // Add the three points of this face. + // + + pp = &POLY_Page[page]; + + for (k = 0; k < 3; k++) + { + ASSERT(WITHIN(f3->Points[k], 0, next_prim_point - 1)); + + px = AENG_dx_prim_points[f3->Points[k]].X; + py = AENG_dx_prim_points[f3->Points[k]].Y; + pz = AENG_dx_prim_points[f3->Points[k]].Z; + + pu = (f3->UV[k][0] & 0x3f) * (1.0F / 32.0F); + pv = (f3->UV[k][1] ) * (1.0F / 32.0F); + + #ifdef TEX_EMBED + + pu = pu * pp->m_UScale + pp->m_UOffset; + pv = pv * pp->m_VScale + pp->m_VOffset; + + #endif + + if (lpc) + { + NIGHT_get_d3d_colour( + lpc[f3->Points[k] - po->StartPoint], + &pcolour, + &pspecular); + } + else + { + // + // Light this point badly... + // + + pcolour = NIGHT_amb_d3d_colour; + pspecular = NIGHT_amb_d3d_specular; + } + + if (POLY_page_flag[page] & POLY_PAGE_FLAG_SELF_ILLUM) + { + pcolour = 0xffffff; + pspecular = 0xff000000; + + fc->flag |= FASTPRIM_CALL_FLAG_SELF_ILLUM; + } + + index[k] = FASTPRIM_add_point_to_call(fc, px,py,pz, pu,pv, pcolour, pspecular); + + if (type == FASTPRIM_CALL_TYPE_COLOURAND) + { + // + // Put the 'y' component of the normal into the + // top byte of dwReserved- we cheekily use just this + // value to do the lighting... + // + + ASSERT(WITHIN(fc->lvert + index[k], 0, FASTPRIM_lvert_max - 1)); + + FASTPRIM_lvert[fc->lvert + index[k]].dwReserved = prim_normal[f3->Points[k]].Y << 24; + } + else + { + // + // Put the point index into the top UWORD of the dwReserved field. + // + + ASSERT(WITHIN(fc->lvert + index[k], 0, FASTPRIM_lvert_max - 1)); + + FASTPRIM_lvert[fc->lvert + index[k]].dwReserved = (f3->Points[k] - po->StartPoint) << 16; + } + } + + // + // Now add the face. + // + + FASTPRIM_ensure_room_for_indices(fc); + + ASSERT(WITHIN(FASTPRIM_index_upto + 3, 0, FASTPRIM_index_max)); + ASSERT(fc->index + fc->indexcount == FASTPRIM_index_upto); + + if (type != FASTPRIM_CALL_TYPE_INDEXED) + { + FASTPRIM_index[FASTPRIM_index_upto++] = index[0]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + FASTPRIM_index[FASTPRIM_index_upto++] = -1; + + fc->indexcount += 4; + } + else + { + FASTPRIM_index[FASTPRIM_index_upto++] = index[0]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + + fc->indexcount += 3; + } + } + } + + for (j = po->StartFace4; j < po->EndFace4; j++) + { + ASSERT(WITHIN(j, 0, next_prim_face4 - 1)); + + f4 = &prim_faces4[j]; + + page = f4->UV[0][0] & 0xc0; + page <<= 2; + page |= f4->TexturePage; + page += FACE_PAGE_OFFSET; + + texture = FASTPRIM_find_texture_from_page(page); + + if (POLY_Page[page].RS.IsAlphaBlendEnabled()) + { + type = FASTPRIM_CALL_TYPE_INDEXED; + } + else + if (f4->FaceFlags & FACE_FLAG_TINT) + { + type = FASTPRIM_CALL_TYPE_COLOURAND; + } + else + { + type = FASTPRIM_CALL_TYPE_NORMAL; + } + + if (texture == fc->texture && type == fc->type) + { + // + // Add the four points of this face. + // + + pp = &POLY_Page[page]; + + for (k = 0; k < 4; k++) + { + ASSERT(WITHIN(f4->Points[k], 0, next_prim_point - 1)); + + px = AENG_dx_prim_points[f4->Points[k]].X; + py = AENG_dx_prim_points[f4->Points[k]].Y; + pz = AENG_dx_prim_points[f4->Points[k]].Z; + + pu = (f4->UV[k][0] & 0x3f) * (1.0F / 32.0F); + pv = (f4->UV[k][1] ) * (1.0F / 32.0F); + + #ifdef TEX_EMBED + + pu = pu * pp->m_UScale + pp->m_UOffset; + pv = pv * pp->m_VScale + pp->m_VOffset; + + #endif + + if (lpc) + { + NIGHT_get_d3d_colour( + lpc[f4->Points[k] - po->StartPoint], + &pcolour, + &pspecular); + } + else + { + // + // Light this point badly... + // + + pcolour = NIGHT_amb_d3d_colour; + pspecular = NIGHT_amb_d3d_specular; + } + + if (POLY_page_flag[page] & POLY_PAGE_FLAG_SELF_ILLUM) + { + pcolour = 0xffffff; + pspecular = 0xff000000; + } + + index[k] = FASTPRIM_add_point_to_call(fc, px,py,pz, pu,pv, pcolour, pspecular); + + if (type == FASTPRIM_CALL_TYPE_COLOURAND) + { + // + // Put the 'y' component of the normal into the + // top byte of dwReserved- we cheekily use just this + // value to do the lighting... + // + + ASSERT(WITHIN(fc->lvert + index[k], 0, FASTPRIM_lvert_max - 1)); + + FASTPRIM_lvert[fc->lvert + index[k]].dwReserved = prim_normal[f4->Points[k]].Y << 24; + } + else + { + // + // Put the point index into the top UWORD of the dwReserved field. + // + + ASSERT(WITHIN(fc->lvert + index[k], 0, FASTPRIM_lvert_max - 1)); + + FASTPRIM_lvert[fc->lvert + index[k]].dwReserved = (f4->Points[k] - po->StartPoint) << 16; + } + } + + // + // Now add the face. + // + + FASTPRIM_ensure_room_for_indices(fc); + + ASSERT(WITHIN(FASTPRIM_index_upto + 6, 0, FASTPRIM_index_max)); + ASSERT(fc->index + fc->indexcount == FASTPRIM_index_upto); + + if (type != FASTPRIM_CALL_TYPE_INDEXED) + { + FASTPRIM_index[FASTPRIM_index_upto++] = index[0]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[3]; + FASTPRIM_index[FASTPRIM_index_upto++] = -1; + + fc->indexcount += 5; + } + else + { + FASTPRIM_index[FASTPRIM_index_upto++] = index[0]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + + FASTPRIM_index[FASTPRIM_index_upto++] = index[3]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + + fc->indexcount += 6; + } + } + } + } + + if (po->flag & PRIM_FLAG_ENVMAPPED) + { + // + // Create another call for the environment mapped faces. + // + + LPDIRECT3DTEXTURE2 envtexture = FASTPRIM_find_texture_from_page(POLY_PAGE_ENVMAP); + + FASTPRIM_create_call(fp, envtexture, FASTPRIM_CALL_TYPE_ENVMAP); + + // + // Find the newly-created call structure- should be the last one in the array. + // + + ASSERT(WITHIN(fp->call_index + fp->call_count - 1, 0, FASTPRIM_call_upto - 1)); + + fc = &FASTPRIM_call[fp->call_index + fp->call_count - 1]; + + ASSERT(fc->texture == envtexture && fc->type == FASTPRIM_CALL_TYPE_ENVMAP); + + fc->flag = 0; + + fc->lvert = FASTPRIM_lvert_upto; + fc->index = FASTPRIM_index_upto; + + fc->lvertcount = 0; + fc->indexcount = 0; + + // + // Add all the environment mapped faces. + // + + for (i = po->StartFace3; i < po->EndFace3; i++) + { + ASSERT(WITHIN(i, 0, next_prim_face3 - 1)); + + f3 = &prim_faces3[i]; + + if (f3->FaceFlags & FACE_FLAG_ENVMAP) + { + for (j = 0; j < 3; j++) + { + ASSERT(WITHIN(f3->Points[j], 0, next_prim_point - 1)); + + px = AENG_dx_prim_points[f3->Points[j]].X; + py = AENG_dx_prim_points[f3->Points[j]].Y; + pz = AENG_dx_prim_points[f3->Points[j]].Z; + + pu = 0.0F; + pv = 0.0F; + + pcolour = 0xff888888; + pspecular = 0x00000000; + + index[j] = FASTPRIM_add_point_to_call(fc, px,py,pz, pu,pv, pcolour, pspecular); + + // + // Put the point index into the top UWORD of 'dwReserved' so we know + // which normal to use. + // + + ASSERT(WITHIN(fc->lvert + index[j], 0, FASTPRIM_lvert_max - 1)); + + FASTPRIM_lvert[fc->lvert + index[j]].dwReserved = f3->Points[j] << 16; + } + + // + // Now add the face. + // + + FASTPRIM_ensure_room_for_indices(fc); + + ASSERT(WITHIN(FASTPRIM_index_upto + 4, 0, FASTPRIM_index_max)); + ASSERT(fc->index + fc->indexcount == FASTPRIM_index_upto); + + FASTPRIM_index[FASTPRIM_index_upto++] = index[0]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + + fc->indexcount += 3; + + } + } + + for (i = po->StartFace4; i < po->EndFace4; i++) + { + ASSERT(WITHIN(i, 0, next_prim_face4 - 1)); + + f4 = &prim_faces4[i]; + + if (f4->FaceFlags & FACE_FLAG_ENVMAP) + { + for (j = 0; j < 4; j++) + { + ASSERT(WITHIN(f4->Points[j], 0, next_prim_point - 1)); + + px = AENG_dx_prim_points[f4->Points[j]].X; + py = AENG_dx_prim_points[f4->Points[j]].Y; + pz = AENG_dx_prim_points[f4->Points[j]].Z; + + pu = 0.0F; + pv = 0.0F; + + pcolour = 0xff888888; + pspecular = 0x00000000; + + index[j] = FASTPRIM_add_point_to_call(fc, px,py,pz, pu,pv, pcolour, pspecular); + + // + // Put the point index into the top UWORD of 'dwReserved' so we know + // which normal to use. + // + + ASSERT(WITHIN(fc->lvert + index[j], 0, FASTPRIM_lvert_max - 1)); + + FASTPRIM_lvert[fc->lvert + index[j]].dwReserved = f4->Points[j] << 16; + } + + // + // Now add the face. + // + + FASTPRIM_ensure_room_for_indices(fc); + + ASSERT(WITHIN(FASTPRIM_index_upto + 5, 0, FASTPRIM_index_max)); + ASSERT(fc->index + fc->indexcount == FASTPRIM_index_upto); + + FASTPRIM_index[FASTPRIM_index_upto++] = index[0]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + + FASTPRIM_index[FASTPRIM_index_upto++] = index[3]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[2]; + FASTPRIM_index[FASTPRIM_index_upto++] = index[1]; + + fc->indexcount += 6; + } + } + } + + // + // We've cached it now! + // + + fp->flag |= FASTPRIM_PRIM_FLAG_CACHED; + + FASTPRIM_queue[FASTPRIM_queue_start++ & (FASTPRIM_MAX_QUEUE - 1)] = prim; + + #ifdef FASTPRIM_PERFORMANCE + fprintf(FASTPRIM_handle, "Gameturn %5d cache prim %3d\n", GAME_TURN, prim); + fflush(FASTPRIM_handle); + FASTPRIM_num_cached += 1; + #endif + } + + // + // Are we strinking this prim? + // + + extern UBYTE kludge_shrink; + + if (kludge_shrink) + { + float fstretch; + + fstretch = (prim == PRIM_OBJ_ITEM_AMMO_SHOTGUN) ? 0.15F : 0.7F; + + matrix[0] *= fstretch; + matrix[1] *= fstretch; + matrix[2] *= fstretch; + + matrix[3] *= fstretch; + matrix[4] *= fstretch; + matrix[5] *= fstretch; + + matrix[6] *= fstretch; + matrix[7] *= fstretch; + matrix[8] *= fstretch; + } + + // + // Are we strinking this prim? + // + + extern UBYTE kludge_shrink; + + if (kludge_shrink) + { + float fstretch; + + fstretch = (prim == PRIM_OBJ_ITEM_AMMO_SHOTGUN) ? 0.15F : 0.7F; + + matrix[0] *= fstretch; + matrix[1] *= fstretch; + matrix[2] *= fstretch; + + matrix[3] *= fstretch; + matrix[4] *= fstretch; + matrix[5] *= fstretch; + + matrix[6] *= fstretch; + matrix[7] *= fstretch; + matrix[8] *= fstretch; + } + + // + // Draw the cached version. Set up the matrix for this object's rotation. + // + + POLY_set_local_rotation( + x,y,z, + matrix); + + GenerateMMMatrixFromStandardD3DOnes( + FASTPRIM_matrix, + &g_matProjection, + &g_matWorld, + &g_viewData); + + for (i = 0; i < fp->call_count; i++) + { + ASSERT(WITHIN(fp->call_index + i, 0, FASTPRIM_MAX_CALLS - 1)); + + fc = &FASTPRIM_call[fp->call_index + i]; + + if (fc->type == FASTPRIM_CALL_TYPE_ENVMAP) + { + // + // Work out the environment mapping. Calculate the rotation + // matrix combined with the camera. + // + + float nx; + float ny; + float nz; + + float comb[9]; + float cam_matrix[9]; + + extern float AENG_cam_yaw; + extern float AENG_cam_pitch; + extern float AENG_cam_roll; + + D3DLVERTEX *lv; + + MATRIX_calc(cam_matrix, AENG_cam_yaw, AENG_cam_pitch, AENG_cam_roll); + MATRIX_3x3mul(comb, cam_matrix, matrix); + + for (j = 0; j < fc->lvertcount; j++) + { + ASSERT(WITHIN(fc->lvert + j, 0, FASTPRIM_lvert_max - 1)); + + lv = &FASTPRIM_lvert[fc->lvert + j]; + + ASSERT(WITHIN(lv->dwReserved >> 16, 0, (unsigned)( next_prim_point - 1 ))); + + nx = prim_normal[lv->dwReserved >> 16].X * (2.0F / 256.0F); + ny = prim_normal[lv->dwReserved >> 16].Y * (2.0F / 256.0F); + nz = prim_normal[lv->dwReserved >> 16].Z * (2.0F / 256.0F); + + MATRIX_MUL( + comb, + nx, + ny, + nz); + + lv->tu = (nx * 0.5F) + 0.5F; + lv->tv = (ny * 0.5F) + 0.5F; + } + } + else + if (fc->type == FASTPRIM_CALL_TYPE_COLOURAND) + { + ULONG default_colour; + ULONG default_specular; + + NIGHT_get_d3d_colour( + NIGHT_get_light_at(x,y,z), + &default_colour, + &default_specular); + + extern ULONG MESH_colour_and; + + default_colour &= MESH_colour_and; + + // + // Relight then AND out the colours... + // + + D3DLVERTEX *lv; + + for (j = 0; j < fc->lvertcount; j++) + { + ASSERT(WITHIN(fc->lvert + j, 0, FASTPRIM_lvert_max - 1)); + + lv = &FASTPRIM_lvert[fc->lvert + j]; + + lv->color = default_colour; + lv->specular = default_specular; + } + } + else + if (fc->type == FASTPRIM_CALL_TYPE_NORMAL) + { + if (lpc) + { + // + // Relight from the cached lighting. + // + + D3DLVERTEX *lv; + + for (j = 0; j < fc->lvertcount; j++) + { + ASSERT(WITHIN(fc->lvert + j, 0, FASTPRIM_lvert_max - 1)); + + lv = &FASTPRIM_lvert[fc->lvert + j]; + + NIGHT_get_d3d_colour( + lpc[lv->dwReserved >> 16], + &lv->color, + &lv->specular); + } + } + else + { + // + // Relight using local light... + // + + ULONG default_colour; + ULONG default_specular; + + NIGHT_get_d3d_colour( + NIGHT_get_light_at(x,y,z), + &default_colour, + &default_specular); + + + D3DLVERTEX *lv; + + for (j = 0; j < fc->lvertcount; j++) + { + ASSERT(WITHIN(fc->lvert + j, 0, FASTPRIM_lvert_max - 1)); + + lv = &FASTPRIM_lvert[fc->lvert + j]; + + lv->color = default_colour; + lv->specular = default_specular; + } + } + } + + if (fc->type == FASTPRIM_CALL_TYPE_INDEXED || + fc->type == FASTPRIM_CALL_TYPE_ENVMAP) + { + // + // Standard D3D DrawIndexedPrimitive() call... + // + + if (fc->type == FASTPRIM_CALL_TYPE_INDEXED) + { + // + // Setup alphablend renderstates... + // + + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA ); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE ); + } + else + { + // + // Setup additive renderstates... + // + + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE ); + } + + the_display.lp_D3D_Device->SetTexture(0, fc->texture); + + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + FASTPRIM_lvert + fc->lvert, + fc->lvertcount, + FASTPRIM_index + fc->index, + fc->indexcount, + 0); + + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); + } + else + { + // + // Tom's DrawIndMM() call... + // + + D3DMULTIMATRIX d3dmm = + { + FASTPRIM_lvert + fc->lvert, + FASTPRIM_matrix, + NULL, + NULL + }; + + the_display.lp_D3D_Device->SetTexture(0, fc->texture); + + if (fc->flag & FASTPRIM_CALL_FLAG_SELF_ILLUM) + { + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_DECAL); + } + + //TRACE ( "S3" ); + DrawIndPrimMM( + the_display.lp_D3D_Device, + D3DFVF_LVERTEX, + &d3dmm, + fc->lvertcount, + FASTPRIM_index + fc->index, + fc->indexcount); + //TRACE ( "F3" ); + + if (fc->flag & FASTPRIM_CALL_FLAG_SELF_ILLUM) + { + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + } + } + } + + return TRUE; +} + + +void FASTPRIM_fini() +{ + +#ifdef DEBUG + ASSERT ( FASTPRIM_lvert_buffer != NULL ); + ASSERT ( FASTPRIM_index != NULL ); + ASSERT ( FASTPRIM_lvert_buffer == (void *)pvJustChecking1 ); + ASSERT ( FASTPRIM_index == (void *)pvJustChecking2 ); + + + char *pcTemp = (char *)( (SLONG)FASTPRIM_lvert + sizeof(D3DLVERTEX) * FASTPRIM_lvert_max ); + ASSERT ( 0 == strcmp ( pcTemp, "ThisIsAMagicString901234567890" ) ); + +#endif + + TRACE ( "FASTPRIM_fini " ); + MemFree(FASTPRIM_lvert_buffer); + TRACE ( "1 " ); + MemFree(FASTPRIM_index); + TRACE ( "2\n" ); + + FASTPRIM_lvert_buffer = NULL; + FASTPRIM_index = NULL; + + #ifdef FASTPRIM_PERFORMANCE + + float av_freed_per_turn = float(FASTPRIM_num_freed ) / float(GAME_TURN); + float av_cached_per_turn = float(FASTPRIM_num_cached) / float(GAME_TURN); + float av_in_cache_per_turn = float(FASTPRIM_num_already_cached) / float(GAME_TURN); + float av_drawn_per_turn = float(FASTPRIM_num_drawn) / float(GAME_TURN); + + fprintf(FASTPRIM_handle, "Average freed per gameturn = %f\n", av_freed_per_turn ); + fprintf(FASTPRIM_handle, "Average cached per gameturn = %f\n", av_cached_per_turn ); + fprintf(FASTPRIM_handle, "Average in cache per gameturn = %f\n", av_in_cache_per_turn); + fprintf(FASTPRIM_handle, "Average drawn per gameturn = %f\n", av_drawn_per_turn ); + + fflush(FASTPRIM_handle); + + #endif +} diff --git a/fallen/DDEngine/Source/figure.cpp b/fallen/DDEngine/Source/figure.cpp new file mode 100644 index 0000000..d4ca551 --- /dev/null +++ b/fallen/DDEngine/Source/figure.cpp @@ -0,0 +1,10243 @@ +// +// Draw a person. +// + +#include "game.h" +#include "aeng.h" +#include "poly.h" +#include "figure.h" +#include "sprite.h" +#include "c:\fallen\headers\fmatrix.h" +#include "c:\fallen\headers\mav.h" +#include "c:\fallen\headers\interact.h" +#include "night.h" +#include "shadow.h" +#include "matrix.h" +#include "animate.h" +#include "mesh.h" +#include "dirt.h" +#include "texture.h" + +#include "math.h" +#include "interfac.h" + + + +#include "Hierarchy.h" // JCL is gay // MA wears girly shorts // JCL +#include "Quaternion.h" +#include "memory.h" + +#include "c:\fallen\headers\person.h" +#include "c:\fallen\headers\pcom.h" +#include "c:\fallen\headers\eway.h" +#include "c:\fallen\headers\dirt.h" +#include "ddlib.h" +#include "panel.h" + +#include "renderstate.h" +#include "poly.h" +#include "polypage.h" + +#include "psystem.h" + + + +#ifndef TARGET_DC + +#define LOG_ENTER(x) {} +#define LOG_EXIT(x) {} +#define LOG_EVENT(x) {} + +#endif + + +#ifdef TARGET_DC +// intrinsic maths +#include +#endif + + +extern BOOL allow_debug_keys; + +SLONG FIGURE_alpha = 255; + +SLONG steam_seed; + +extern UWORD alt_texture[]; + +UBYTE body_part_upper[]= +{ + 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0 + +}; + + + + +void DeadAndBuried ( DWORD dwColour ) +{ + // draw a colour on the screen to try to diagnose things if they do crash. + + DDSURFACEDESC2 mine; + HRESULT res; + + InitStruct(mine); + mine.dwFlags = DDSD_PITCH; + res = the_display.lp_DD_FrontSurface->Lock ( NULL, &mine, DDLOCK_WAIT, NULL ); + if (FAILED(res)) return; + + char *pdwDest = (char *)mine.lpSurface; + for ( int i = 0; i < 50; i++ ) + { + DWORD *pdwDest1 = (DWORD*)pdwDest; + pdwDest += mine.lPitch; + for ( int j = 0; j < 50; j++ ) + { + *pdwDest1++ = dwColour; + } + } + + res = the_display.lp_DD_FrontSurface->Unlock ( NULL ); + +} + + + + + +// Returns TRUE if this chunk is not near-Z clipped, FALSE if it is. +bool FIGURE_draw_prim_tween_person_only_just_set_matrix ( + int iMatrixNum, + SLONG prim, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + SLONG recurse_level, + Thing *p_thing + ); + +void FIGURE_draw_prim_tween_person_only( + SLONG prim, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + SLONG recurse_level, + Thing *p_thing + ); + + + +// Now enabled only on a cheat! +//#define HIGH_REZ_PEOPLE_PLEASE_BOB + + +#ifdef HIGH_REZ_PEOPLE_PLEASE_BOB +bool m_bPleaseInflatePeople = FALSE; +#endif + + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + +// Useful. +#define ALIGNED_STATIC_ARRAY(def,name,number,mytype,align) \ + static char c##name##mytype##align##StaticArray [ align + number * sizeof ( mytype ) ]; \ + def##name = (mytype *)( ( (DWORD)c##name##mytype##align##StaticArray + (align-1) ) & ~(align-1) ) + + + +ALIGNED_STATIC_ARRAY ( static D3DCOLOR *, MM_pcFadeTable, 128, D3DCOLOR, 4 ); +ALIGNED_STATIC_ARRAY ( static D3DCOLOR *, MM_pcFadeTableTint, 128, D3DCOLOR, 4 ); +ALIGNED_STATIC_ARRAY ( static D3DMATRIX *, MM_pMatrix, 1, D3DMATRIX, 32 ); +ALIGNED_STATIC_ARRAY ( static D3DVERTEX *, MM_Vertex, 4, D3DVERTEX, 32 ); +ALIGNED_STATIC_ARRAY ( static float *, MM_pNormal, 4, float, 8 ); + +#if 0 +// The MM lighting table. +D3DCOLOR *MM_pcFadeTable = NULL; +D3DCOLOR *MM_pcFadeTableTint = NULL; +D3DMATRIX *MM_pMatrix = NULL; +D3DVERTEX *MM_Vertex = NULL; +float *MM_pNormal = NULL; +#endif + +D3DVECTOR MM_vLightDir; +bool MM_bLightTableAlreadySetUp = FALSE; + + + +// Something to build lighting tables. +void BuildMMLightingTable ( Pyro *p, DWORD colour_and=0xffffffff ) +{ + LOG_ENTER ( Figure_Build_Table ) + + + // REMEMBER THAT ALL THE LIGHT DIRECTIONS ARE NEGATIVE, + // EXCEPT FOR THE AMBIENT ONE, WHICH IS CORRECT. + // Daft bloody system. + + ASSERT ( MM_pcFadeTable != NULL ); + ASSERT ( MM_pcFadeTableTint != NULL ); + ASSERT ( MM_pMatrix != NULL ); + ASSERT ( MM_Vertex != NULL ); + ASSERT ( MM_pNormal != NULL ); + + + // Find the brightest-lit vector. + float fBright = NIGHT_amb_red * 0.35f + NIGHT_amb_green * 0.45f + NIGHT_amb_blue * 0.2f; + D3DVECTOR vTotal; + vTotal.x = fBright * NIGHT_amb_norm_x; + vTotal.y = fBright * NIGHT_amb_norm_y; + vTotal.z = fBright * NIGHT_amb_norm_z; + NIGHT_Found *nf; + for (int j = 0; j < NIGHT_found_upto; j++) + { + nf = &NIGHT_found[j]; + + // Find a rough approximation to brightness. + float fBright = nf->r * 0.35f + nf->g * 0.45f + nf->b * 0.2f; + + // If it is a negative light - make it "illuminate" from the opposite direction. + // This solves the problem of a red light above, an anti-red below, and a soft green to the right. + // If the reds both pulled in opposite direction, the green would actually be the main one, + // which is silly as the object is obviously mainly red and black. + //if ( fBright > 0.0f ) + { + // These are negative! + vTotal.x -= fBright * nf->dx; + vTotal.y -= fBright * nf->dy; + vTotal.z -= fBright * nf->dz; + } +#if 0 + else + { + // Negative light - make it "illuminate" from the correct direction. + // Directions are also negative! + vTotal.x += fBright * nf->dx; + vTotal.y += fBright * nf->dy; + vTotal.z += fBright * nf->dz; + } +#endif + } + + // Unitise the vector. +#ifdef TARGET_DC + float fLength = _InvSqrtA ( vTotal.x * vTotal.x + vTotal.y * vTotal.y + vTotal.z * vTotal.z ); +#else + float fLength = 1.0f / sqrtf ( vTotal.x * vTotal.x + vTotal.y * vTotal.y + vTotal.z * vTotal.z ); +#endif + vTotal.x *= fLength; + vTotal.y *= fLength; + vTotal.z *= fLength; + + // Now light this vector and its negative, just as the software engine does. + D3DCOLORVALUE cvAmb, cvLight; +//#define AMBIENT_FACTOR (1.0f * 256.0f) +#define AMBIENT_FACTOR (0.5f * 256.0f) + // Real ambient factor. + cvAmb.r = NIGHT_amb_red * AMBIENT_FACTOR; + cvAmb.g = NIGHT_amb_green * AMBIENT_FACTOR; + cvAmb.b = NIGHT_amb_blue * AMBIENT_FACTOR; + + // Terrible fudge - on nighttime missions, the ambient is too dark, or on daytime ones, it's too bright. + // So if the given ambient (the sun) is below a certain value, ramp up the ambient to compensate. + if ( ( NIGHT_amb_red + NIGHT_amb_green + NIGHT_amb_blue ) < 100 ) + { + // FUDGE IT! + cvAmb.r *= 2.0f; + cvAmb.g *= 2.0f; + cvAmb.b *= 2.0f; + } + + cvLight = cvAmb; + + float fDotProd = vTotal.x * NIGHT_amb_norm_x + vTotal.y * NIGHT_amb_norm_y + vTotal.z * NIGHT_amb_norm_z; + if ( fDotProd < 0.0f ) + { + cvAmb.r -= fDotProd * NIGHT_amb_red; + cvAmb.g -= fDotProd * NIGHT_amb_green; + cvAmb.b -= fDotProd * NIGHT_amb_blue; + } + else + { + cvLight.r += fDotProd * NIGHT_amb_red; + cvLight.g += fDotProd * NIGHT_amb_green; + cvLight.b += fDotProd * NIGHT_amb_blue; + } + for (j = 0; j < NIGHT_found_upto; j++) + { + nf = &NIGHT_found[j]; + // These are negative! + fDotProd = - vTotal.x * nf->dx - vTotal.y * nf->dy - vTotal.z * nf->dz; + if ( fDotProd < 0.0f ) + { + cvAmb.r -= fDotProd * nf->r; + cvAmb.g -= fDotProd * nf->g; + cvAmb.b -= fDotProd * nf->b; + } + else + { + cvLight.r += fDotProd * nf->r; + cvLight.g += fDotProd * nf->g; + cvLight.b += fDotProd * nf->b; + } + } + + MM_vLightDir = vTotal; + + // Is this thing on fire? + if ( p != NULL ) + { + // On fire. Blacken with soot or something. + cvLight.r = (cvLight.r > p->counter) ? (cvLight.r - p->counter) : 10; + cvLight.g = (cvLight.g > p->counter) ? (cvLight.g - p->counter) : 4; + cvLight.b = (cvLight.b > p->counter) ? (cvLight.b - p->counter) : 3; + cvAmb.r = (cvAmb.r > p->counter) ? (cvAmb.r - p->counter) : 10; + cvAmb.g = (cvAmb.g > p->counter) ? (cvAmb.g - p->counter) : 4; + cvAmb.b = (cvAmb.b > p->counter) ? (cvAmb.b - p->counter) : 3; + } + +#if 1 + // On the PC, people are lit x2, so we need to double these. + cvLight.r *= 2.0f; + cvLight.g *= 2.0f; + cvLight.b *= 2.0f; + cvAmb.r *= 2.0f; + cvAmb.g *= 2.0f; + cvAmb.b *= 2.0f; +#endif + + // OK, now make up the fade table for this light. + const float fColourScale = ( 1.0f / ( 256.0f * 128.0f ) ) * 255.0f * NIGHT_LIGHT_MULTIPLIER; + D3DCOLORVALUE cvCur = cvAmb; + cvLight.r -= cvAmb.r; + cvLight.g -= cvAmb.g; + cvLight.b -= cvAmb.b; + cvCur.r *= fColourScale; + cvCur.g *= fColourScale; + cvCur.b *= fColourScale; + cvLight.r *= ( fColourScale / 64.0f ); + cvLight.g *= ( fColourScale / 64.0f ); + cvLight.b *= ( fColourScale / 64.0f ); + + // Ambient colour. + unsigned char cR, cG, cB; + if ( cvCur.r > 255.0f ) + { + cR = 255; + } + else if ( cvCur.r < 0.0f ) + { + cR = 0; + } + else + { + cR = (unsigned char)( cvCur.r ); + } + if ( cvCur.g > 255.0f ) + { + cG = 255; + } + else if ( cvCur.g < 0.0f ) + { + cG = 0; + } + else + { + cG = (unsigned char)( cvCur.g ); + } + if ( cvCur.b > 255.0f ) + { + cB = 255; + } + else if ( cvCur.b < 0.0f ) + { + cB = 0; + } + else + { + cB = (unsigned char)( cvCur.b ); + } + + DWORD dwColour = ( (DWORD)cR << 16 ) | ( (DWORD)cG << 8 ) | ( (DWORD)cB ); + for ( int i = 64; i < 128; i++ ) + { + MM_pcFadeTable[i] = dwColour; + MM_pcFadeTableTint[i] = dwColour & colour_and; + } + + // Ramp up to full brightness. + for ( i = 0; i < 64; i++ ) + { + if ( cvCur.r > 255.0f ) + { + cR = 255; + } + else if ( cvCur.r < 0.0f ) + { + cR = 0; + } + else + { + cR = (unsigned char)( cvCur.r ); + } + if ( cvCur.g > 255.0f ) + { + cG = 255; + } + else if ( cvCur.g < 0.0f ) + { + cG = 0; + } + else + { + cG = (unsigned char)( cvCur.g ); + } + if ( cvCur.b > 255.0f ) + { + cB = 255; + } + else if ( cvCur.b < 0.0f ) + { + cB = 0; + } + else + { + cB = (unsigned char)( cvCur.b ); + } + dwColour = ( (DWORD)cR << 16 ) | ( (DWORD)cG << 8 ) | ( (DWORD)cB ); + MM_pcFadeTable[i] = dwColour; + MM_pcFadeTableTint[i] = dwColour & colour_and; + cvCur.r += cvLight.r; + cvCur.g += cvLight.g; + cvCur.b += cvLight.b; + } + + LOG_EXIT ( Figure_Build_Table ) +} + + +#endif + + + + + +struct EdgeList +{ + WORD wPt1, wPt2; + WORD wMidPt; +}; + + + +// The MS list optimiser. They gave it to me, so I'll use it! Might as well. + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Copyright (c) 1998-1999 Microsoft Corporation + + Module Name: optlist.cpp + + Abstract: Source code for Index List Optimizer +-------------------------------------------------------------------*/ + +typedef struct tagIndexTri +{ + int v1,v2,v3; + int done; +} INDEXTRISTRUCT; + +typedef struct tagIndexVert +{ + WORD wIndex; // Index of this vertex + int nShareCount; // Number of triangles sharing this vertex + int rgSharedTris[30]; // Array of triangles that share this vertex +} INDEXVERTSTRUCT; + +class MSMesh +{ +private: + INDEXTRISTRUCT *m_aTri; + int m_nNumTri; + int m_nMaxTri; + INDEXVERTSTRUCT *m_aVert; + int m_nNumVert; + int m_nMaxVert; + + int NextTri( int v1, int v2, int *v3 ); + void ClearTempDone( int nValue ); + int StripLen( int startTri, int dir, int setit, WORD *pwOut, int nMaxLen ); + +public: + MSMesh(); + ~MSMesh(); + void Clear() { m_nNumTri = 0; m_nNumVert = 0; } + int AddTri( WORD wV1, WORD wV2, WORD wV3 ); + int GetStrip( WORD *pwV, int maxlen ); + int NumVertices() { return m_nNumVert; } + int FindOrAddVertex( WORD wVert ); + int SetSize( int nTriangles ); +}; + +MSMesh::MSMesh() +{ + memset( this, 0, sizeof(*this) ); +} + +int MSMesh::SetSize ( int nTriangles ) +{ + if ( nTriangles <= 0 ) + { + // printf("SetSize: freeing allocations\n"); + if ( m_aTri ) + { + MemFree( m_aTri ); + m_aTri = (INDEXTRISTRUCT *)NULL; + } + if ( m_aVert ) + { + MemFree( m_aVert ); + m_aVert = (INDEXVERTSTRUCT *)NULL; + } + m_nMaxTri = 0; + m_nMaxVert = 0; + } + else + { + if( nTriangles > m_nMaxTri ) + { + // MemFree any previous allocation + SetSize(0); + m_nMaxTri = nTriangles + 10; // allow room for growth + m_nMaxVert = m_nMaxTri * 3; + if( m_nMaxVert > 65536 ) + m_nMaxVert = 65536; + // Allocate new space + // printf("SetSize allocating space for %d indices and %d vertices\n", + // m_nMaxTri, m_nMaxVert ); + m_aTri = (INDEXTRISTRUCT *)MemAlloc( m_nMaxTri * sizeof(INDEXTRISTRUCT) ); + if ( m_aTri == NULL ) { DeadAndBuried ( 0x07e007e0 ); } + m_aVert = (INDEXVERTSTRUCT *)MemAlloc( m_nMaxVert * sizeof(INDEXVERTSTRUCT) ); + if ( m_aVert == NULL ) { DeadAndBuried ( 0x07e007e0 ); } + if( !m_aTri || !m_aVert ) + SetSize(0); // MemFree half-allocations + } + } + return m_nMaxTri; +} + +MSMesh::~MSMesh() +{ + SetSize(0); +} + +int MSMesh::FindOrAddVertex( WORD wVert ) +{ + int vertno; + for( vertno =0; vertno < m_nNumVert; vertno++ ) + if( m_aVert[vertno].wIndex == wVert ) + return vertno; + vertno = m_nNumVert++; + m_aVert[vertno].wIndex = wVert; + m_aVert[vertno].nShareCount = 0; + return vertno; +} + +int MSMesh::AddTri( WORD wV1, WORD wV2, WORD wV3 ) +{ + int trino = m_nNumTri++; + int v1 = FindOrAddVertex( wV1 ); + int v2 = FindOrAddVertex( wV2 ); + int v3 = FindOrAddVertex( wV3 ); + + m_aVert[v1].rgSharedTris[m_aVert[v1].nShareCount++] = trino; + m_aVert[v2].rgSharedTris[m_aVert[v2].nShareCount++] = trino; + m_aVert[v3].rgSharedTris[m_aVert[v3].nShareCount++] = trino; + + m_aTri[trino].v1 = v1; + m_aTri[trino].v2 = v2; + m_aTri[trino].v3 = v3; +/* + printf(" tri %d(%d,%d,%d)\n", trino, + m_aTri[trino].v1, + m_aTri[trino].v2, + m_aTri[trino].v3 ); +*/ + m_aTri[trino].done = 0; + + return trino; +} + +void MSMesh::ClearTempDone( int nValue ) +{ + int trino; + for( trino = 0; trino < m_nNumTri; trino++ ) + if( m_aTri[trino].done == 2 ) + { + m_aTri[trino].done = nValue; + } +} + +int MSMesh::StripLen( int startTri, int dir, int setit, WORD *pwOut, int nMaxLen ) +{ + int v1, v2, v3; + int trino = startTri; + int len = 0; + + if( (dir>>1) == 0 ) + { + v1 = m_aTri[startTri].v1; + v2 = m_aTri[startTri].v2; + v3 = m_aTri[startTri].v3; + } + else if( (dir>>1) == 1 ) + { + v1 = m_aTri[startTri].v2; + v2 = m_aTri[startTri].v3; + v3 = m_aTri[startTri].v1; + } + else + { + v1 = m_aTri[startTri].v3; + v2 = m_aTri[startTri].v1; + v3 = m_aTri[startTri].v2; + } + + while( trino != -1 ) + { + if( pwOut ) + { + *pwOut++ = m_aVert[v1].wIndex; + *pwOut++ = m_aVert[v2].wIndex; + *pwOut++ = m_aVert[v3].wIndex; + // printf("len = %d, adding triangle %d: %d,%d,%d\n", len, trino, v1, v2, v3 ); + } + len++; + m_aTri[trino].done = 2; // mark as temporarily done + if( len >= nMaxLen ) + break; + + // Sequence: + // + // 0 1 2 + // 1 3 2 + // 2 3 4 + // 3 5 4 + + if( len & 1 ) // generate 1 3 2 from 0 1 2 + { + v1 = v2; + trino = NextTri( v3, v1, &v2 ); + } + else // generate 2 3 4 from 1 3 2 + { + v1 = v3; + trino = NextTri( v1, v2, &v3 ); + } + + } + + ClearTempDone(setit); + + // printf( "\nStrip starting at triangle %d, dir %d len=%d\n", startTri, dir, len); + + return len; +} + +int MSMesh::GetStrip ( WORD *pwVT, int maxLen ) +{ + int trino; + int len; + int dir; + + int bestStart; + int bestDir; + int bestLen=0; + + // printf("MSMesh: %d triangles, %d vertices\n", m_nNumTri, m_nNumVert ); + + for( trino = 0; trino < m_nNumTri; trino++ ) + { + if( m_aTri[trino].done ) + continue; + for( dir = 0; dir<3; dir++ ) + { + if( ( len = StripLen( trino, dir, 0, NULL, maxLen ) ) > bestLen ) + { + bestLen = len; + bestStart = trino; + bestDir = dir; + if( bestLen >= maxLen ) + { + // force it to exit + trino = m_nNumTri; + break; + } + } + + } + } + if( bestLen > 0 ) + StripLen( bestStart, bestDir, 1, pwVT, maxLen ); + + return bestLen; +} + +int MSMesh::NextTri( int v1, int v2, int *v3 ) +{ + int subtri; + int trino; + + for( subtri = 0; subtri < m_aVert[v1].nShareCount; subtri++ ) + { + trino = m_aVert[v1].rgSharedTris[subtri]; + if( m_aTri[trino].done ) + continue; + if( m_aTri[trino].v1 == v1 ) + { + if( m_aTri[trino].v2 == v2 ) + { + *v3 = m_aTri[trino].v3; + // printf("found tri %d: %d,%d,%d\n", trino, v1, v2, *v3 ); + return trino; + } + } + else if( m_aTri[trino].v2 == v1 ) + { + if( m_aTri[trino].v3 == v2 ) + { + *v3 = m_aTri[trino].v1; + // printf("found tri %d: %d,%d,%d\n", trino, v1, v2, *v3 ); + return trino; + } + } + else if( m_aTri[trino].v3 == v1 ) + { + if( m_aTri[trino].v1 == v2 ) + { + *v3 = m_aTri[trino].v2; + // printf("found tri %d: %d,%d,%d\n", trino, v1, v2, *v3 ); + return trino; + } + } + } + return -1; // no more in this direction +} + +static MSMesh mesh; + +BOOL MSOptimizeIndexedList( WORD *pwIndices, int nTriangles ) +{ + + if( !mesh.SetSize( nTriangles ) ) + return FALSE; + + mesh.Clear(); + + WORD *pwInd = pwIndices; + + for ( int i = 0; i < nTriangles; i++ ) + { + mesh.AddTri( pwInd[0], pwInd[1], pwInd[2] ); + pwInd += 3; + } + + if( mesh.NumVertices() == 0 ) + return FALSE; + + int nLength = nTriangles; + int nTotal = 0; + + while ( nTotal < nTriangles ) + { + nLength = mesh.GetStrip( pwIndices, nLength ); + pwIndices += ( nLength * 3 ); + nTotal += nLength; + } + + return TRUE; +} + + +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + + + +/* + + +// D3D lighting fucntions. +#define MAX_NUM_OF_LIGHTS 10 +LPDIRECT3DLIGHT m_pLight[MAX_NUM_OF_LIGHTS]; +bool m_bLightInScene[MAX_NUM_OF_LIGHTS]; +int m_iNumLights = 0; + +int FindMeAFreeLightAndPutItInTheScene ( void ) +{ + int i = 0; + while ( TRUE ) + { + ASSERT ( i < MAX_NUM_OF_LIGHTS ); + if ( !m_bLightInScene[i] ) + { + // Found one. + break; + } + i++; + } + + if ( m_pLight[i] == NULL ) + { + // Haven't created this one yet. + HRESULT hres = (the_display.lp_D3D)->CreateLight ( &(m_pLight[i]), NULL ); + ASSERT ( SUCCEEDED ( hres ) ); + } + // Add the light in. + HRESULT hres = (the_display.lp_D3D_Viewport)->AddLight ( m_pLight[i] ); + ASSERT ( SUCCEEDED ( hres ) ); + m_bLightInScene[i] = TRUE; + return ( i ); +} + +void MakeThisLightLikeThis ( int iLightNum, D3DLIGHT *pd3dLight ) +{ + ASSERT ( m_bLightInScene[iLightNum] ); + ASSERT ( m_pLight[iLightNum] != NULL ); + HRESULT hres = (m_pLight[iLightNum])->SetLight ( (D3DLIGHT *)pd3dLight ); + ASSERT ( SUCCEEDED ( hres ) ); +} + +void MakeThisLightLikeThis ( int iLightNum, D3DLIGHT2 *pd3dLight ) +{ + MakeThisLightLikeThis ( iLightNum, (D3DLIGHT *)pd3dLight ); +} + +void RemoveThisLightFromScene ( int iLightNum ) +{ + ASSERT ( m_bLightInScene[iLightNum] ); + ASSERT ( m_pLight[iLightNum] != NULL ); + HRESULT hres = (the_display.lp_D3D_Viewport)->DeleteLight ( m_pLight[iLightNum] ); + ASSERT ( SUCCEEDED ( hres ) ); + m_bLightInScene[iLightNum] = FALSE; +} + +#if 0 +int AddThisSortOfLightToTheScene ( D3DLIGHT *pd3dLight ) +{ + int iLightNum = FindMeAFreeLightAndPutItInTheScene(); + MakeThisLightLikeThis ( iLightNum, pd3dLight ); + return ( iLightNum ); +} + +int AddThisSortOfLightToTheScene ( D3DLIGHT2 *pd3dLight ) +{ + return ( AddThisSortOfLightToTheScene ( (D3DLIGHT *)pd3dLight ) ); +} +void RemoveAllLightsFromScene ( void ) +{ + for ( int i = 0; i < MAX_NUM_OF_LIGHTS; i++ ) + { + if ( m_bLightInScene[i] ) + { + RemoveThisLightFromScene ( i ); + } + } +} + +#else +// HACKED! +int AddThisSortOfLightToTheScene ( D3DLIGHT2 *pd3dLight ) +{ + if ( m_pLight[0] == NULL ) + { + FindMeAFreeLightAndPutItInTheScene(); + MakeThisLightLikeThis ( 0, pd3dLight ); + } + return ( 0 ); +} +void RemoveAllLightsFromScene ( void ) +{ +} +#endif + + +*/ + + + +SLONG get_steam_rand(void) +{ + steam_seed*=31415965; + steam_seed+=123456789; + return(steam_seed>>8); +} + +extern int AENG_detail_crinkles; + +#define MAX_STEAM 100 +void draw_steam(SLONG x,SLONG y,SLONG z,SLONG lod) +{ + SLONG c0; + float u,v; + SLONG trans; + // + // waft gently up from x,y,z + // + + // Internal gubbins. + POLY_set_local_rotation_none(); + + steam_seed=54321678; + if(lod>40) + lod=40; + + for(c0=0;c0>2)+80))>>9; + dz=(((get_steam_rand()&0xff)-128)*((dy>>2)+80))>>9; + + + if(dy>16) + { +// dx+=COS(GAME_TURN*10)%(dy>>4); +// dz+=SIN(GAME_TURN*10)%(dy>>4); + } + + if(c0&4) + { + dx+=COS(dy*4); + dz+=SIN(dy*4); + + } + +/* trans=(c0*128)/MAX_STEAM; + if(dy>300) + trans=(trans*5)/(dy-295);*/ +/* + if (dy<40) + trans=dy*3; + else +// trans=(256-dy)*0.5; + trans=(256-dy) / 2; // JCL - changed to fix an annoying warning (don't think it worked anyway...) +*/ +/* + trans=128-(dy>>2); + if(trans<1) + trans=1; +*/ + + if(dy>500-(13*16)) + { + trans=(500-dy)>>4; + } + if(dy<13*4) + { + trans=dy>>2; + } + else + { + trans=13; + } + + + dx+=x; + dy+=y; + dz+=z; + + + if(trans>=1) + { +// trans*=0x010101; + trans |= trans << 8; + trans |= trans << 8; + + SPRITE_draw_tex( + float(dx), + float(dy), + float(dz), + float(((dy-y)>>2)+150), + trans, + 0, + POLY_PAGE_STEAM, + u,v,0.5,0.5, + SPRITE_SORT_NORMAL); + } + } +} + + +UBYTE fire_pal[768]; + +void init_flames() +{ + MFFileHandle handle = FILE_OPEN_ERROR; + + handle=FileOpen("data\\flames1.pal"); + + if(handle!=FILE_OPEN_ERROR) + { + FileRead(handle,(UBYTE*)&fire_pal,768); + + FileClose(handle); + } else TRACE("Missing flame palette file.\n"); +} + +extern int AENG_detail_skyline; + +void draw_flames(SLONG x,SLONG y,SLONG z,SLONG lod,SLONG offset) +{ + SLONG c0; + SLONG trans; + SLONG page; + float scale; + float u,v,w,h; + UBYTE* palptr; + SLONG palndx; + float wx1,wy1,wx2,wy2,wx3,wy3,wx4,wy4; + UBYTE type; + // + // waft gently up from x,y,z + // + + steam_seed=54321678+offset; + +#if 0 + // Now moved to the actual callers instead. + SLONG lod_mul; + +#ifndef TARGET_DC + extern UBYTE sw_hack; + + if (sw_hack || !AENG_detail_skyline)//||ShiftFlag) +#else + if (!AENG_detail_skyline)//||ShiftFlag) +#endif + { + lod_mul = 2; + } + else + { + lod_mul = 5; + } +#endif + + //for(c0=0;c0>2)+150))>>9; + dz=(((get_steam_rand()&0xff)-128)*((dy>>2)+150))>>9; + if (type==2) { + dx>>=2; dz>>=2; + } + if (type==1) { + dx>>=1; dz>>=1; + } + + wy1=wy2=wy3=wy4=0; + wx1=(float)COS(((dy+c0)*11)&1023)*0.0001f; + wx2=(float)COS(((dy+c0)*10)&1023)*0.0001f; + wx3=(float)COS(((dy+c0)*8)&1023)*0.0001f; + wx4=(float)COS(((dy+c0)*9)&1023)*0.0001f; + + + trans=255-dy; + + dx+=x; + dy+=y; + dz+=z; + + + if(trans>=1) + { + switch (type) { +/* case 0: // smoke + trans+=(trans<<8)|(trans<<16)|(trans<<24); + scale=float(((dy-y)>>1)+80); + dy+=50; + palptr=(trans*3)+fire_pal; + palndx=(256-trans)*3; + trans<<=24; + trans+=(fire_pal[palndx]<<16)+(fire_pal[palndx+1]<<8)+fire_pal[palndx+2];*/ +// break; + case 1: // outer + dy>>=1; + case 2: // innter + palptr=(trans*3)+fire_pal; + palndx=(256-trans)*3; +// trans=0xff; + trans<<=24; +// trans+=0xffffff; +// trans+=((*palptr++)<<8)|((*palptr++)<<16)|((*palptr++)<<24); + trans+=(fire_pal[palndx]<<16)+(fire_pal[palndx+1]<<8)+fire_pal[palndx+2]; + //scale=(dy>>2)+50; + scale=50; + break; + case 0: + case 3: // flame + trans=abs(dy-y)*20; + trans=SIN(trans); + trans|=0x00FFFFFF; + scale=100; + dy=y; + break; + } + +// SPRITE_draw_tex( +#ifdef TARGET_DC + SPRITE_draw_tex_distorted_params Params; +#define SET_IN_PARAMS(argname) Params.argname = argname + SET_IN_PARAMS(u); + SET_IN_PARAMS(v); + SET_IN_PARAMS(w); + SET_IN_PARAMS(h); + SET_IN_PARAMS(wx1); + SET_IN_PARAMS(wy1); + SET_IN_PARAMS(wx2); + SET_IN_PARAMS(wy2); + SET_IN_PARAMS(wx3); + SET_IN_PARAMS(wy3); + SET_IN_PARAMS(wx4); + SET_IN_PARAMS(wy4); +#undef SET_IN_PARAMS + + SPRITE_draw_tex_distorted( + float(dx), + float(dy), + float(dz), + float(scale), + trans, + 0xff000000, + page, + SPRITE_SORT_NORMAL, + &Params); + +#else //#ifdef TARGET_DC + SPRITE_draw_tex_distorted( + float(dx), + float(dy), + float(dz), + float(scale), + trans, + 0xff000000, + page, + u, v, w, h, + wx1,wy1,wx2,wy2,wx3,wy3,wx4,wy4, + SPRITE_SORT_NORMAL); +#endif //#else //#ifdef TARGET_DC + + } + } +} + +#ifndef PSX +void draw_flame_element(SLONG x,SLONG y,SLONG z,SLONG c0,UBYTE base,UBYTE rand) +{ +// SLONG c0; + SLONG trans; + SLONG page; + float scale; + float u,v,w,h; + UBYTE* palptr; + SLONG palndx; + float wx1,wy1,wx2,wy2,wx3,wy3,wx4,wy4; + SLONG dx,dy,dz; + // + // waft gently up from x,y,z + // + + if (rand) + steam_seed=54321678+(c0*get_steam_rand()); + else + steam_seed=54321678+c0; + + + w=h=1.0; + u=v=0.0; + + if(!(c0&3)) + page=POLY_PAGE_FLAMES; + else + if (c0&4) + page=POLY_PAGE_SMOKE; + else { + if (!base) { + page=POLY_PAGE_FLAMES; + } else { + page=POLY_PAGE_FLAMES2; + dy=(GAME_TURN+c0)/2; + u=0.25f*(dy&3); +// v=0.25f*((dy&~3)/4); + v=0.25f*((dy>>2)&3); + w=h=0.25f; + } + } + + dy=get_steam_rand()&0x1ff; + dy+=(GAME_TURN*5); + dy%=500; + dx=(((get_steam_rand()&0xff)-128)*((dy>>2)+150))>>9; + dz=(((get_steam_rand()&0xff)-128)*((dy>>2)+150))>>9; + if (page==POLY_PAGE_FLAMES) { + dx>>=2; dz>>=2; + } + + wx1=wx2=wx3=wx4=0; + wy1=wy2=wy3=wy4=0; +/* wx1=COS(((dy+c0)*11)%1024)*0.0001; + wx2=COS(((dy+c0)*10)%1024)*0.0001; + wx3=COS(((dy+c0)*8)%1024)*0.0001; + wx4=COS(((dy+c0)*9)%1024)*0.0001; +*/ + wx1=(float)COS(((dy+c0)*11)&1023)*0.0001f; + wx2=(float)COS(((dy+c0)*10)&1023)*0.0001f; + wx3=(float)COS(((dy+c0)*8)&1023)*0.0001f; + wx4=(float)COS(((dy+c0)*9)&1023)*0.0001f; + + trans=255-dy; + + dx+=x; + dy+=y; + dz+=z; + + + if(trans>=1) + { + switch (page) { + case POLY_PAGE_FLAMES: + palptr=(trans*3)+fire_pal; + palndx=(256-trans)*3; + trans<<=24; + trans+=(fire_pal[palndx]<<16)+(fire_pal[palndx+1]<<8)+fire_pal[palndx+2]; + scale=50; + break; + case POLY_PAGE_FLAMES2: +// trans=0xFFFFFFFF; + palptr=(trans*3)+fire_pal; + palndx=(256-trans)*3; + trans<<=24; + trans+=(fire_pal[palndx]<<16)+(fire_pal[palndx+1]<<8)+fire_pal[palndx+2]; + scale=100; + dy=50; + break; + case POLY_PAGE_SMOKE: + trans+=(trans<<8)|(trans<<16)|(trans<<24); + scale=float(((dy-y)>>1)+50); + dy+=50; + break; + } + +#ifdef TARGET_DC + SPRITE_draw_tex_distorted_params Params; +#define SET_IN_PARAMS(argname) Params.argname = argname + SET_IN_PARAMS(u); + SET_IN_PARAMS(v); + SET_IN_PARAMS(w); + SET_IN_PARAMS(h); + SET_IN_PARAMS(wx1); + SET_IN_PARAMS(wy1); + SET_IN_PARAMS(wx2); + SET_IN_PARAMS(wy2); + SET_IN_PARAMS(wx3); + SET_IN_PARAMS(wy3); + SET_IN_PARAMS(wx4); + SET_IN_PARAMS(wy4); +#undef SET_IN_PARAMS + + SPRITE_draw_tex_distorted( + float(dx), + float(dy), + float(dz), + float(scale), + trans, + 0xff000000, + page, + SPRITE_SORT_NORMAL, + &Params); + +#else //#ifdef TARGET_DC + + SPRITE_draw_tex_distorted( + float(dx), + float(dy), + float(dz), + float(scale), + trans, + 0xff000000, + page, + u, v, w, h, + wx1,wy1,wx2,wy2,wx3,wy3,wx4,wy4, + SPRITE_SORT_NORMAL); +#endif //#else //#ifdef TARGET_DC + } + +} +#endif + + + +//void FIGURE_rotate_obj2(SLONG matrix[9], SLONG yaw, SLONG pitch, SLONG roll) +void FIGURE_rotate_obj2(SLONG pitch,SLONG yaw,SLONG roll, Matrix33 *r3) +{ + SLONG cy, cp, cr; + SLONG sy, sp, sr; + + cy = COS(yaw & 2047); + cp = COS(pitch & 2047); + cr = COS(roll & 2047); + + sy = SIN(yaw & 2047); + sp = SIN(pitch & 2047); + sr = SIN(roll & 2047); + + // + // Jan I trust you... but only becuase I've already seen it working! + // + + r3->M[0][0]= (MUL64( cy, cr) + MUL64(MUL64(sy, sp), sr))>>1; + r3->M[0][1]= (MUL64( cy, sr) - MUL64(MUL64(sy, sp), cr))>>1; + r3->M[0][2]= (MUL64( sy, cp))>>1; + r3->M[1][0]= (MUL64(-cp, sr))>>1; + r3->M[1][1]= (MUL64( cp, cr))>>1; + r3->M[1][2]= (sp)>>1; + r3->M[2][0]= (MUL64(-sy, cr) + MUL64(MUL64(cy, sp), sr))>>1; + r3->M[2][1]= (MUL64(-sy, sr) - MUL64(MUL64(cy, sp), cr))>>1; + r3->M[2][2]= (MUL64( cy, cp))>>1; +} + +void FIGURE_rotate_obj(SLONG xangle,SLONG yangle,SLONG zangle, Matrix33 *r3) +{ + SLONG sinx, cosx, siny, cosy, sinz, cosz; + SLONG cxcz,sysz,sxsycz,sxsysz,sysx,cxczsy,sxsz,cxsysz,czsx,cxsy,sycz,cxsz; + + FIGURE_rotate_obj2(xangle,yangle,zangle,r3); + return; + + sinx = SIN(xangle & (2048-1)) >>1; // 15's + cosx = COS(xangle & (2048-1)) >>1; + siny = SIN(yangle & (2048-1)) >>1; + cosy = COS(yangle & (2048-1)) >>1; + sinz = SIN(zangle & (2048-1)) >>1; + cosz = COS(zangle & (2048-1)) >>1; + + cxsy = (cosx*cosy); // 30's + sycz = (cosy*cosz); + cxcz = (cosx*cosz); + cxsz = (cosx*sinz); + czsx = (cosz*sinx); + sysx = (cosy*sinx); + sysz = (cosy*sinz); + sxsz = (sinx*sinz); + sxsysz = (sxsz>>15)*siny; + cxczsy = (cxcz>>15)*siny; + cxsysz = ((cosx*siny)>>15)*sinz; + sxsycz = (czsx>>15)*siny; + + // Define rotation matrix r3. + + r3->M[0][0] = (sycz)>>15; // 14's + r3->M[0][1] = (-sysz)>>15; + r3->M[0][2] = siny; + r3->M[1][0] = (sxsycz+cxsz)>>15; + r3->M[1][1] = (cxcz-sxsysz)>>15; + r3->M[1][2] = (-sysx)>>15; + r3->M[2][0] = (sxsz-cxczsy)>>15; + r3->M[2][1] = (cxsysz+czsx)>>15; + r3->M[2][2] = (cxsy)>>15; +} + + +//UBYTE store_dprod[500]; +extern UBYTE TEXTURE_dontexist[]; + +// 0->3 +// 4->7 +// 8->11 +// 12->15 + +UWORD jacket_lookup[4][8]= +{ + {64+21,10*64+2,10*64+2,10*64+32}, + {64+22,10*64+3,10*64+3,10*64+33}, + {64+24,10*64+4,10*64+4,10*64+36}, + {64+25,10*64+5,10*64+5,10*64+37} + +}; + + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + +// A huge number!!!! +#define MAX_NUMBER_D3D_PRIMS MAX_PRIM_OBJECTS +TomsPrimObject D3DObj[MAX_NUMBER_D3D_PRIMS]; +float m_fObjectBoundingSphereRadius[MAX_NUMBER_D3D_PRIMS]; + + +// 16 people types, 32 types of civ, and 6 different Roper ones (five weapons + no weapon). +// Oh - number eight is his magic hip-flask! +#define NUM_ROPERS_THINGIES 8 +#define MAX_NUMBER_D3D_PEOPLE (32 + 16 + NUM_ROPERS_THINGIES) +TomsPrimObject D3DPeopleObj[MAX_NUMBER_D3D_PEOPLE]; + + +// iFaceNum: the face number +// bTri: TRUE if it's a tri, FALSE if it's a quad. +UWORD FIGURE_find_face_D3D_texture_page ( int iFaceNum, bool bTri ) +{ + // Find the texture page/shading info. + UWORD wTexturePage; + DWORD dwDrawFlags, dwFaceFlags; + if ( bTri ) + { + PrimFace3 *p_f3 = &prim_faces3[iFaceNum]; + dwDrawFlags = p_f3->DrawFlags; + dwFaceFlags = p_f3->FaceFlags; + + wTexturePage = p_f3->UV[0][0] & 0xc0; + wTexturePage <<= 2; + wTexturePage |= p_f3->TexturePage; + } + else + { + PrimFace4 *p_f4 = &prim_faces4[iFaceNum]; + dwDrawFlags = p_f4->DrawFlags; + dwFaceFlags = p_f4->FaceFlags; + + wTexturePage = p_f4->UV[0][0] & 0xc0; + wTexturePage <<= 2; + wTexturePage |= p_f4->TexturePage; + } + + if ( ( dwDrawFlags & POLY_FLAG_TEXTURED ) == 0 ) + { + // Untextured. + wTexturePage = TEXTURE_PAGE_FLAG_NOT_TEXTURED | POLY_PAGE_COLOUR; + } + else + { + // Textured. + if(dwFaceFlags&FACE_FLAG_THUG_JACKET) + { + switch(wTexturePage) + { + case 64+21: + case 10*64+2: + case 10*64+32: + wTexturePage = 0 | TEXTURE_PAGE_FLAG_JACKET; + //page=jacket_lookup[0][GET_SKILL(p_thing)>>2]; + break; + case 64+22: + case 10*64+3: + case 10*64+33: + wTexturePage = 1 | TEXTURE_PAGE_FLAG_JACKET; + //page=jacket_lookup[1][GET_SKILL(p_thing)>>2]; + break; + case 64+24: + case 10*64+4: + case 10*64+36: + wTexturePage = 2 | TEXTURE_PAGE_FLAG_JACKET; + //page=jacket_lookup[2][GET_SKILL(p_thing)>>2]; + break; + case 64+25: + case 10*64+5: + case 10*64+37: + wTexturePage = 3 | TEXTURE_PAGE_FLAG_JACKET; + //page=jacket_lookup[3][GET_SKILL(p_thing)>>2]; + break; + default: + ASSERT(FALSE); + break; + } + //page+=FACE_PAGE_OFFSET; + } + else if ( ( wTexturePage > 10*64 ) && ( alt_texture[wTexturePage-10*64] != 0 ) ) + { + // An "offset" texture. This will be offset by a certain amount to + // allow each prim to have different coloured clothes on. + // Store the original value in the page number, because if tex_offset is zero + // at runtime, we just add on FACE_PAGE_OFFSET. + ASSERT ( ( wTexturePage & ~TEXTURE_PAGE_MASK ) == 0 ); + + wTexturePage |= TEXTURE_PAGE_FLAG_OFFSET; + } + else + { + wTexturePage += FACE_PAGE_OFFSET; + // Make sure it actually fits in the available bit space. + ASSERT ( ( wTexturePage & ~TEXTURE_PAGE_MASK ) == 0 ); + } + } + + if (dwFaceFlags & FACE_FLAG_TINT) + { + wTexturePage |= TEXTURE_PAGE_FLAG_TINT; + } + + return ( wTexturePage ); + +} + + + + +// The LRU queue for the prims. +// Psycho Park is the most hungry. +// Actually, Day of Reckoning is pretty bad too. + +// Max length of actual queue in TomsPrimObjects +// MUST BE LESS THAN 256! +#define PRIM_LRU_QUEUE_LENGTH 250 +// Max size in number of vertices in queue. +#define PRIM_LRU_QUEUE_SIZE 6000 + +int m_iLRUQueueSize = 0; +TomsPrimObject *ptpoLRUQueue[PRIM_LRU_QUEUE_LENGTH]; +DWORD dwGameTurnLastUsed[PRIM_LRU_QUEUE_LENGTH]; + +// Size of the queue in vertices. +DWORD m_dwSizeOfQueue = 0; + +// "Cleans" a slot. +void FIGURE_clean_LRU_slot ( int iSlot ) +{ + TomsPrimObject *ptpo = ptpoLRUQueue[iSlot]; + + ASSERT ( ptpo != NULL ); + if ( ptpo == NULL ) + { + // Toast aversion. This will cause it to leak memory, + // but at least it won't die immediately. + return; + } + + m_dwSizeOfQueue -= (DWORD)ptpo->wTotalSizeOfObj; + // Make sure it doesn't go negative! + ASSERT ( ( m_dwSizeOfQueue & 0x80000000 ) == 0 ); + + ASSERT ( ptpo != NULL ); + ASSERT ( ptpo->bLRUQueueNumber == iSlot ); + ASSERT ( ptpo->wNumMaterials > 0 ); + ASSERT ( ptpo->pMaterials != NULL ); + ASSERT ( ptpo->pwListIndices != NULL ); + MemFree ( ptpo->pMaterials ); + // This block include pwStripIndices and pD3DVertices. + MemFree ( ptpo->pwListIndices ); + + ptpo->pMaterials = NULL; + ptpo->pwListIndices = NULL; + ptpo->pD3DVertices = NULL; + ptpo->pwStripIndices = NULL; + ptpo->bLRUQueueNumber = 0xff; + ptpo->wNumMaterials = 0; + ptpo->wTotalSizeOfObj = 0; + + ptpoLRUQueue[iSlot] = NULL; +} + + +// This is suitable for calling at end of level. +void FIGURE_clean_all_LRU_slots ( void ) +{ + for ( int i = 0; i < m_iLRUQueueSize; i++ ) + { + if ( ptpoLRUQueue[i] != NULL ) + { + FIGURE_clean_LRU_slot ( i ); + } + } + // And zero-length the queue. + m_iLRUQueueSize = 0; + + // Make sure the queue is actually zero length, + // or some accounting has screwed up somewhere. + ASSERT ( m_dwSizeOfQueue == 0 ); +} + + +#ifdef DEBUG +int g_iCacheReplacements = 0; +bool g_bCacheReplacementThrash = FALSE; +#endif + +// Adds the primobj to the LRU queue somewhere, evicting something else if need be. +void FIGURE_find_and_clean_prim_queue_item ( TomsPrimObject *pPrimObj, int iThrashIndex = 0 ) +{ + int iQueuePos; + + // Make sure nothing even gets close to filling all the space - that would be a disaster. + // If this happens, the queue is far too small. + // Roper is the biggest so far, at 529 vertices. + ASSERT ( (DWORD)pPrimObj->wTotalSizeOfObj * 5< PRIM_LRU_QUEUE_SIZE ); + + // Silly man! + ASSERT ( (DWORD)pPrimObj->wTotalSizeOfObj > 0 ); + + + if ( ( m_iLRUQueueSize < PRIM_LRU_QUEUE_LENGTH ) && + ( ( (DWORD)pPrimObj->wTotalSizeOfObj + m_dwSizeOfQueue ) < PRIM_LRU_QUEUE_SIZE ) ) + { + // That's easy then. + iQueuePos = m_iLRUQueueSize; + m_iLRUQueueSize++; + } + else + { + // No more free slots, or not enough free "memory" (vertices). Find the oldest one then. + + // First find enough memory. + while ( ( (DWORD)pPrimObj->wTotalSizeOfObj + m_dwSizeOfQueue ) >= PRIM_LRU_QUEUE_SIZE ) + { + #ifdef DEBUG + g_iCacheReplacements++; + #endif + + DWORD dwMostTurns = 0; + int iOldestSlot = -1; + for ( int i = 0; i < m_iLRUQueueSize; i++ ) + { + if ( ptpoLRUQueue[i] != NULL ) + { + // Careful of wrap-arounds! + DWORD dwTurnsAgo = ( GAME_TURN - dwGameTurnLastUsed[i] ); + if ( dwMostTurns <= dwTurnsAgo ) + { + // This is older. + dwMostTurns = dwTurnsAgo; + iOldestSlot = i; + } + } + } + ASSERT ( ( iOldestSlot > -1 ) && ( iOldestSlot < m_iLRUQueueSize ) ); + if ( dwMostTurns < 3 ) + { + // Shit - this is probably about to thrash. + // There is nothing we can do to prevent it in this case really. + // Could try binning the _newest_ instead, but that's a real pain. + // Just try not to. + // iOldestSlot = iThrashIndex; + + #ifdef DEBUG + // And warn us. + g_bCacheReplacementThrash = TRUE; + #endif + } + + // Clean out this prim & slot. + FIGURE_clean_LRU_slot ( iOldestSlot ); + + iQueuePos = iOldestSlot; + } + + + // Now check there is a queue space free. + if ( m_iLRUQueueSize >= PRIM_LRU_QUEUE_LENGTH ) + { + // Nope - bin oldest. + #ifdef DEBUG + g_iCacheReplacements++; + #endif + + DWORD dwMostTurns = 0; + int iOldestSlot = -1; + for ( int i = 0; i < m_iLRUQueueSize; i++ ) + { + if ( ptpoLRUQueue[i] != NULL ) + { + // Careful of wrap-arounds! + DWORD dwTurnsAgo = ( GAME_TURN - dwGameTurnLastUsed[i] ); + if ( dwMostTurns <= dwTurnsAgo ) + { + // This is older. + dwMostTurns = dwTurnsAgo; + iOldestSlot = i; + } + } + } + ASSERT ( ( iOldestSlot > -1 ) && ( iOldestSlot < m_iLRUQueueSize ) ); + if ( dwMostTurns < 3 ) + { + // Shit - this is probably about to thrash. Prevent too much thrashing by always using the same slot. + // FIRST CHECK THAT THIS SLOW IS ACTUALLY USED. + if ( ptpoLRUQueue[iThrashIndex] == NULL ) + { + // No, it isn't actually used. + // Allow the thrash then. + } + else + { + // Yes, it's used - bin it. + iOldestSlot = iThrashIndex; + } + + #ifdef DEBUG + // And warn us. + g_bCacheReplacementThrash = TRUE; + #endif + } + + + // In some cases, we may have decided to clean a cache position that + // isn't ocupied, which will die nicely. + // In this case, just find the first that is occupied and clean it instead. + if ( ptpoLRUQueue[iOldestSlot] == NULL ) + { + // Warn me. + ASSERT ( FALSE ); + + // And recover gracefully... + + + // Nads. Find the first used one. + iOldestSlot = -1; + for ( int i = 0; i < m_iLRUQueueSize; i++ ) + { + if ( ptpoLRUQueue[i] != NULL ) + { + // Found one. + iOldestSlot = i; + break; + } + } + } + + // Clean out this prim & slot. + FIGURE_clean_LRU_slot ( iOldestSlot ); + + iQueuePos = iOldestSlot; + } + } + + + ptpoLRUQueue[iQueuePos] = pPrimObj; + pPrimObj->bLRUQueueNumber = iQueuePos; + dwGameTurnLastUsed[iQueuePos] = GAME_TURN; + m_dwSizeOfQueue += (DWORD)pPrimObj->wTotalSizeOfObj; + ASSERT ( m_dwSizeOfQueue < PRIM_LRU_QUEUE_SIZE ); +} + +void FIGURE_touch_LRU_of_object ( TomsPrimObject *pPrimObj ) +{ + ASSERT ( ( pPrimObj->bLRUQueueNumber >= 0 ) && ( pPrimObj->bLRUQueueNumber < m_iLRUQueueSize ) ); + ASSERT ( ptpoLRUQueue[pPrimObj->bLRUQueueNumber] == pPrimObj ); + dwGameTurnLastUsed[pPrimObj->bLRUQueueNumber] = GAME_TURN; +} + + + +#ifdef DEBUG +int m_iMaxNumVertsUsed = 0; +int m_iMaxNumIndicesUsed = 0; +#endif + + + + +// Used by the FIGURE_TPO lot. +static D3DVERTEX *TPO_pVert = NULL; +static UWORD *TPO_pStripIndices = NULL; +static UWORD *TPO_pListIndices = NULL; +static int *TPO_piVertexRemap = NULL; +static int *TPO_piVertexLinks = NULL; +static D3DVERTEX *TPO_pCurVertex = NULL; +static UWORD *TPO_pCurStripIndex = NULL; +static UWORD *TPO_pCurListIndex = NULL; +static TomsPrimObject *TPO_pPrimObj = NULL; +static int TPO_iNumListIndices = 0; +static int TPO_iNumStripIndices = 0; +static int TPO_iNumVertices = 0; + +#define TPO_MAX_NUMBER_PRIMS 16 +static int TPO_iNumPrims = 0; +//static PrimObject *TPO_PrimObjects[TPO_MAX_NUMBER_PRIMS]; +static SLONG TPO_PrimObjects[TPO_MAX_NUMBER_PRIMS]; +static UBYTE TPO_ubPrimObjMMIndex[TPO_MAX_NUMBER_PRIMS]; +static int TPO_iPrimObjIndexOffset[TPO_MAX_NUMBER_PRIMS+1]; + + +// Starts off a 3D object. +// iThrashIndex - can be ignored normally. +void FIGURE_TPO_init_3d_object ( TomsPrimObject *pPrimObj /*, int iThrashIndex = 0 */ ) +{ + //PrimObject *p_obj = &prim_objects[prim]; + //ASSERT ( prim < MAX_NUMBER_D3D_PRIMS ); + + + TRACE("Started conversion 0x%x...", pPrimObj); + + + // Make sure we're not in the middle of compiling and object already. + ASSERT ( TPO_pVert == NULL ); + ASSERT ( TPO_pStripIndices == NULL ); + ASSERT ( TPO_pListIndices == NULL ); + ASSERT ( TPO_piVertexRemap == NULL ); + ASSERT ( TPO_piVertexLinks == NULL ); + ASSERT ( TPO_pCurVertex == NULL ); + ASSERT ( TPO_pCurStripIndex == NULL ); + ASSERT ( TPO_pCurListIndex == NULL ); + ASSERT ( TPO_pPrimObj == NULL ); + ASSERT ( TPO_iNumListIndices == 0 ); + ASSERT ( TPO_iNumStripIndices == 0 ); + ASSERT ( TPO_iNumVertices == 0 ); + ASSERT ( TPO_iNumPrims == 0 ); + + + // Temporary space that gets freed at the end. +#ifdef HIGH_REZ_PEOPLE_PLEASE_BOB + +#define MAX_VERTS 4096 +#define MAX_INDICES (MAX_VERTS * 4) + +#else + +#define MAX_VERTS 1024 +#define MAX_INDICES (MAX_VERTS * 4) + +#endif + + TPO_pVert = (D3DVERTEX *)MemAlloc ( MAX_VERTS * sizeof ( D3DVERTEX ) ); + ASSERT ( TPO_pVert != NULL ); + if ( TPO_pVert == NULL ) { DeadAndBuried ( 0xf800f800 ); } + TPO_pStripIndices = (UWORD *)MemAlloc ( MAX_INDICES * sizeof ( UWORD ) ); + ASSERT ( TPO_pStripIndices != NULL ); + if ( TPO_pStripIndices == NULL ) { DeadAndBuried ( 0xf800f800 ); } + TPO_pListIndices = (UWORD *)MemAlloc ( MAX_INDICES * sizeof ( UWORD ) ); + ASSERT ( TPO_pListIndices != NULL ); + if ( TPO_pListIndices == NULL ) { DeadAndBuried ( 0xf800f800 ); } + + TPO_piVertexRemap = (int *)MemAlloc ( MAX_VERTS * sizeof ( int ) ); + ASSERT ( TPO_piVertexRemap != NULL ); + if ( TPO_piVertexRemap == NULL ) { DeadAndBuried ( 0xf800f800 ); } + TPO_piVertexLinks = (int *)MemAlloc ( MAX_VERTS * sizeof ( int ) ); + ASSERT ( TPO_piVertexLinks != NULL ); + if ( TPO_piVertexLinks == NULL ) { DeadAndBuried ( 0xf800f800 ); } + + TPO_pCurVertex = TPO_pVert; + TPO_pCurStripIndex = TPO_pStripIndices; + TPO_pCurListIndex = TPO_pListIndices; + + + //TomsPrimObject *pPrimObj = &(D3DObj[prim]); + // Make sure it's not been initialised. + ASSERT ( pPrimObj->pD3DVertices == NULL ); + ASSERT ( pPrimObj->pMaterials == NULL ); + ASSERT ( pPrimObj->pwListIndices == NULL ); + ASSERT ( pPrimObj->pwStripIndices == NULL ); + ASSERT ( pPrimObj->wNumMaterials == 0 ); + + TPO_pPrimObj = pPrimObj; + +#if 0 +// Do this after the object has been compiled, so we know how big it is. + // Add this to a good place in the LRU queue. + FIGURE_find_and_clean_prim_queue_item ( pPrimObj, iThrashIndex ); +#endif + + // No index offset for the first object + TPO_iPrimObjIndexOffset[0] = 0; + + + pPrimObj->wFlags = 0; + pPrimObj->fBoundingSphereRadius = 0.0f; + + TPO_iNumListIndices = 0; + TPO_iNumStripIndices = 0; + TPO_iNumVertices = 0; + TPO_iNumPrims = 0; + + // Ready for action. + +} + + +// Add a prim to this 3D object. +// prim = the prim number to add. +// iSubObjectNumber = sub-object number, used for multimatrix stuff. +// Start at 0 and go up by one for each object. +//void FIGURE_TPO_add_prim_to_current_object ( PrimObject *p_obj, UBYTE ubSubObjectNumber ) +void FIGURE_TPO_add_prim_to_current_object ( SLONG prim, UBYTE ubSubObjectNumber ) +{ + // Make sure it's been properly prepped. + ASSERT ( TPO_pVert != NULL ); + ASSERT ( TPO_pStripIndices != NULL ); + ASSERT ( TPO_pListIndices != NULL ); + ASSERT ( TPO_piVertexRemap != NULL ); + ASSERT ( TPO_piVertexLinks != NULL ); + ASSERT ( TPO_pCurVertex != NULL ); + ASSERT ( TPO_pCurStripIndex != NULL ); + ASSERT ( TPO_pCurListIndex != NULL ); + ASSERT ( TPO_pPrimObj != NULL ); + + ASSERT ( prim < MAX_NUMBER_D3D_PRIMS ); + PrimObject *p_obj = &prim_objects[prim]; + ASSERT ( p_obj != NULL ); + TRACE("added prim 0x%x...", p_obj); + + TPO_PrimObjects[TPO_iNumPrims] = prim; + TPO_ubPrimObjMMIndex[TPO_iNumPrims] = ubSubObjectNumber; + + + // Work out what index offset to add to the _next_ object. + // It's this object's offset plus the number of points + // in this object. + TPO_iPrimObjIndexOffset[TPO_iNumPrims+1] = TPO_iPrimObjIndexOffset[TPO_iNumPrims] + ( p_obj->EndPoint - p_obj->StartPoint ); + + TPO_iNumPrims++; + ASSERT ( TPO_iNumPrims <= TPO_MAX_NUMBER_PRIMS ); + +} + + + + +// Compile the object - this actually does all the work. +// pPrimObj the prim obj that was passed to FIGURE_TPO_init_3d_object +// iThrashIndex - can be ignored normally. +void FIGURE_TPO_finish_3d_object ( TomsPrimObject *pPrimObj, int iThrashIndex = 0 ) +{ + // Make sure one has actually been started. + ASSERT ( TPO_pVert != NULL ); + ASSERT ( TPO_pStripIndices != NULL ); + ASSERT ( TPO_pListIndices != NULL ); + ASSERT ( TPO_piVertexRemap != NULL ); + ASSERT ( TPO_piVertexLinks != NULL ); + ASSERT ( TPO_pCurVertex != NULL ); + ASSERT ( TPO_pCurStripIndex != NULL ); + ASSERT ( TPO_pCurListIndex != NULL ); + ASSERT ( TPO_pPrimObj != NULL ); + + ASSERT ( pPrimObj == TPO_pPrimObj ); + + + TRACE ( "compiling %i prims...", TPO_iNumPrims ); + + // OK, now scan through the faces. Check to see if the face uses a new material. + // If so, create this new material and add in this face and all subsequent faces + // that use it. + // If not, then this face should already have been added, so ignore it. + // + // This sequence is, of course, complicated by there being both quads and tris. :-( + + for ( int iOuterPrimNumber = 0; iOuterPrimNumber < TPO_iNumPrims; iOuterPrimNumber++ ) + { + PrimObject *pOuterObj = &prim_objects[TPO_PrimObjects[iOuterPrimNumber]]; + + ASSERT ( pOuterObj != NULL ); + + bool bOuterTris = FALSE; + do + { + int iOuterFaceNum; + int iOuterFaceEnd; + if ( bOuterTris ) + { + iOuterFaceNum = pOuterObj->StartFace3; + iOuterFaceEnd = pOuterObj->EndFace3; + } + else + { + iOuterFaceNum = pOuterObj->StartFace4; + iOuterFaceEnd = pOuterObj->EndFace4; + } + + for ( ; iOuterFaceNum < iOuterFaceEnd; iOuterFaceNum++ ) + { + UWORD wTexturePage = FIGURE_find_face_D3D_texture_page ( iOuterFaceNum, bOuterTris ); + + // Find the _rendered_ page, to allow texture paging to do its stuff. + UWORD wRealPage = wTexturePage & TEXTURE_PAGE_MASK; + + PolyPage *pRenderedPage = NULL; + + #ifdef TEX_EMBED + + if ( ( wTexturePage & ~TEXTURE_PAGE_MASK ) != 0 ) + { + // Something special about this page, e.g. jacket, special shading, etc. + // Don't try to combine them. + pRenderedPage = NULL; + } + else + { + pRenderedPage = POLY_Page[wTexturePage & TEXTURE_PAGE_MASK].pTheRealPolyPage; + } + + #endif + + // OK, now we have a material description in wTexturePage. + // Look for an existing material with this. + PrimObjectMaterial *pMaterial = pPrimObj->pMaterials; + int iMatNum; + for ( iMatNum = pPrimObj->wNumMaterials; iMatNum > 0; iMatNum-- ) + { + #if 1 + #ifdef TEX_EMBED + if ( pRenderedPage != NULL ) + { + if ( ( pMaterial->wTexturePage & ~TEXTURE_PAGE_MASK ) == 0 ) + { + // Nothing special about this page. + if ( pRenderedPage == ( POLY_Page[pMaterial->wTexturePage & TEXTURE_PAGE_MASK].pTheRealPolyPage ) ) + { + // The textures match! + break; + } + } + } + #endif + #endif + + if ( pMaterial->wTexturePage == wTexturePage ) + { + // Exactly the same page. + break; + } + pMaterial++; + } + if ( iMatNum != 0 ) + { + // Found one. So this face should be in it somewhere already. Ignore. + } + else + { + // Didn't find this material, so add it. + + pPrimObj->wNumMaterials++; + // Yes, this is a horrible way to do things - memory fragmented all over the place. Tough. Deal with it. + // And yes, I could use realloc(), but it doesn't seem to be very happy on the DC, so I won't. + void *pOldMats = (void *)pPrimObj->pMaterials; + pPrimObj->pMaterials = (PrimObjectMaterial *)MemAlloc ( pPrimObj->wNumMaterials * sizeof ( *pMaterial ) ); + ASSERT ( pPrimObj->pMaterials != NULL ); + if ( pPrimObj->pMaterials == NULL ) { DeadAndBuried ( 0x001f001f ); } + + if ( pOldMats != NULL ) + { + memcpy ( pPrimObj->pMaterials, pOldMats, ( pPrimObj->wNumMaterials - 1 ) * sizeof ( *pMaterial ) ); + MemFree ( pOldMats ); + } + + pMaterial = pPrimObj->pMaterials + pPrimObj->wNumMaterials - 1; + pMaterial->wNumListIndices = 0; + pMaterial->wNumStripIndices = 0; + pMaterial->wNumVertices = 0; + pMaterial->wTexturePage = wTexturePage; + + D3DVERTEX *pFirstVertex = TPO_pCurVertex; + + WORD *pFirstListIndex = TPO_pCurListIndex; + WORD *pFirstStripIndex = TPO_pCurStripIndex; + + // Renit the vertex remapping. + for ( int i = 0; i < MAX_VERTS; i++ ) + { + // The first D3Dvertex that has the right posnorm. + TPO_piVertexRemap[i] = -1; + // A possible next vertex that uses this posnorm. + TPO_piVertexLinks[i] = -1; + } + + + // Now scan all the rest of the faces and add any that have this page. + // Just scan from this face onwards. + + for ( int iInnerPrimNumber = iOuterPrimNumber; iInnerPrimNumber < TPO_iNumPrims; iInnerPrimNumber++ ) + { + PrimObject *pInnerObj = &prim_objects[TPO_PrimObjects[iInnerPrimNumber]]; + + float *pfBoundingSphereRadius = &(m_fObjectBoundingSphereRadius[TPO_PrimObjects[iInnerPrimNumber]]); + *pfBoundingSphereRadius = 0.0f; + + ASSERT ( pInnerObj != NULL ); + + bool bInnerTris; + if ( iInnerPrimNumber == iOuterPrimNumber ) + { + // Just scan this object from where the outer one is. + bInnerTris = bOuterTris; + } + else + { + bInnerTris = FALSE; + } + + do + { + int iInnerFaceEnd; + int iInnerFaceNum; + if ( iInnerPrimNumber == iOuterPrimNumber ) + { + // Just scan from where we are onwards + if ( bInnerTris ) + { + if ( bOuterTris ) + { + iInnerFaceNum = iOuterFaceNum; + } + else + { + iInnerFaceNum = pInnerObj->StartFace3; + } + iInnerFaceEnd = pInnerObj->EndFace3; + } + else + { + if ( bOuterTris ) + { + // If the outer loop was scanning tris, + // it did so after scanning all quads, + // so why are we scanning quads in the inner loop? + ASSERT ( FALSE ); + iInnerFaceNum = pInnerObj->StartFace4; + } + else + { + iInnerFaceNum = iOuterFaceNum; + } + iInnerFaceEnd = pInnerObj->EndFace4; + } + } + else + { + if ( bInnerTris ) + { + iInnerFaceNum = pInnerObj->StartFace3; + iInnerFaceEnd = pInnerObj->EndFace3; + } + else + { + iInnerFaceNum = pInnerObj->StartFace4; + iInnerFaceEnd = pInnerObj->EndFace4; + } + } + + ASSERT ( iInnerFaceNum <= iInnerFaceEnd ); + for ( ; iInnerFaceNum < iInnerFaceEnd; iInnerFaceNum++ ) + { + UWORD wTexturePage = FIGURE_find_face_D3D_texture_page ( iInnerFaceNum, bInnerTris ); + + bool bSamePage = FALSE; + + if ( pMaterial->wTexturePage == wTexturePage ) + { + // Exactly the same page. + bSamePage = TRUE; + } + #if 1 + #ifdef TEX_EMBED + else if ( pRenderedPage != NULL ) + { + //if ( ( ( pMaterial->wTexturePage & ~TEXTURE_PAGE_MASK ) == 0 ) && + // ( ( wTexturePage & ~TEXTURE_PAGE_MASK ) == 0 ) + if ( ( ( pMaterial->wTexturePage | wTexturePage ) & ~TEXTURE_PAGE_MASK ) == 0 ) + { + // Nothing special about either page. + if ( pRenderedPage == ( POLY_Page[wTexturePage & TEXTURE_PAGE_MASK].pTheRealPolyPage ) ) + { + // The textures match! + bSamePage = TRUE; + } + } + } + #endif + #endif + + if ( bSamePage ) + { + // This uses this material, so add it. + + + // Find the actual polypage, because that will give us UV offsets. + // NOTE! This means that all thug jackets must have the same offsets * scales. + // Shouldn't be too hard to arrange. + // Ditto for offset tetxures. + UWORD wRealPage = wTexturePage & TEXTURE_PAGE_MASK; + if ( wTexturePage & TEXTURE_PAGE_FLAG_JACKET ) + { + // Find the real jacket page. + // Assume skill of 0 + wRealPage = jacket_lookup [ wRealPage ][0]; + wRealPage += FACE_PAGE_OFFSET; + } + else if ( wTexturePage & TEXTURE_PAGE_FLAG_OFFSET ) + { + // An "offset" texture. This will be offset by a certain amount to + // allow each prim to have different coloured clothes on. + // For now, assume no offset. + wRealPage += FACE_PAGE_OFFSET; + } + + #ifdef DEBUG + if ( wTexturePage & TEXTURE_PAGE_FLAG_NOT_TEXTURED ) + { + ASSERT ( wRealPage == POLY_PAGE_COLOUR ); + } + #endif + + PolyPage *pa = &(POLY_Page[wRealPage]); + + + + // Add the vertices. + int iIndices[4]; + PrimFace3 *p_f3; + PrimFace4 *p_f4; + int iVerts; + if ( bInnerTris ) + { + p_f3 = &prim_faces3[iInnerFaceNum]; + iVerts = 3; + } + else + { + p_f4 = &prim_faces4[iInnerFaceNum]; + iVerts = 4; + } + for ( int i = 0; i < iVerts; i++ ) + { + const float fNormScale = 1.0f / 256.0f; + + D3DVERTEX d3dvert; + + int pt; + if ( bInnerTris ) + { + pt = p_f3->Points[i]; + d3dvert.dvTU = float(p_f3->UV[i][0] & 0x3f) * (1.0F / 32.0F); + d3dvert.dvTV = float(p_f3->UV[i][1] ) * (1.0F / 32.0F); + } + else + { + pt = p_f4->Points[i]; + d3dvert.dvTU = float(p_f4->UV[i][0] & 0x3f) * (1.0F / 32.0F); + d3dvert.dvTV = float(p_f4->UV[i][1] ) * (1.0F / 32.0F); + } + #ifdef TEX_EMBED + // Clamp if they go out of range. + // This can produce a little bit of distortion, but it's better than nothing. + if ( d3dvert.dvTU < 0.0f ) + { + TRACE("Clamped a U coord to 0"); + d3dvert.dvTU = 0.0f; + } + else if ( d3dvert.dvTU > 1.0f ) + { + TRACE("Clamped a U coord to 1"); + d3dvert.dvTU = 1.0f; + } + if ( d3dvert.dvTV < 0.0f ) + { + TRACE("Clamped a V coord to 0"); + d3dvert.dvTV = 0.0f; + } + else if ( d3dvert.dvTV > 1.0f ) + { + TRACE("Clamped a V coord to 1"); + d3dvert.dvTV = 1.0f; + } + + d3dvert.dvTU = d3dvert.dvTU * pa->m_UScale + pa->m_UOffset; + d3dvert.dvTV = d3dvert.dvTV * pa->m_VScale + pa->m_VOffset; + + // Now scale by the page offset and scale + #endif + d3dvert.dvX = AENG_dx_prim_points[pt].X; + d3dvert.dvY = AENG_dx_prim_points[pt].Y; + d3dvert.dvZ = AENG_dx_prim_points[pt].Z; + d3dvert.dvNX = prim_normal[pt].X * fNormScale; + d3dvert.dvNY = prim_normal[pt].Y * fNormScale; + d3dvert.dvNZ = prim_normal[pt].Z * fNormScale; + // This must be done after setting the rest up, since it blats the 12th byte of the vertex. + SET_MM_INDEX ( d3dvert, TPO_ubPrimObjMMIndex[iInnerPrimNumber] ); + + // Look for this vertex. + ASSERT ( pt >= pInnerObj->StartPoint ); + ASSERT ( pt < pInnerObj->EndPoint ); + ASSERT ( ( pt - pInnerObj->StartPoint ) < MAX_VERTS ); + + if ( ( pt - pInnerObj->StartPoint ) >= MAX_VERTS ) { DeadAndBuried ( 0xffffffff ); } + + + int iPtIndex = TPO_iPrimObjIndexOffset[iInnerPrimNumber] + ( pt - pInnerObj->StartPoint ); + int iVertIndex = TPO_piVertexRemap[iPtIndex]; + if ( iVertIndex == -1 ) + { + // Never-referenced vertex. Add it. + TPO_piVertexRemap[iPtIndex] = pMaterial->wNumVertices; + TPO_piVertexLinks[pMaterial->wNumVertices] = -1; + + iIndices[i] = pMaterial->wNumVertices; + + *TPO_pCurVertex = d3dvert; + TPO_pCurVertex++; + pMaterial->wNumVertices++; + TPO_iNumVertices++; + ASSERT ( TPO_iNumVertices < MAX_VERTS ); + + if ( TPO_iNumVertices >= MAX_VERTS ) { DeadAndBuried ( 0xffffffff ); } + + + #ifdef DEBUG + if ( m_iMaxNumVertsUsed < TPO_iNumVertices ) + { + //ASSERT ( TPO_iNumVertices < 256 ); + m_iMaxNumVertsUsed = TPO_iNumVertices; + } + #endif + + // Grow the bounding sphere if need be. + +#if 0 + // THIS IS NOT BEING DONE RIGHT! + float fDistSqu = ( d3dvert.dvX * d3dvert.dvX ) + ( d3dvert.dvY * d3dvert.dvY ) + ( d3dvert.dvZ * d3dvert.dvZ ); + if ( pPrimObj->fBoundingSphereRadius < fDistSqu ) + { + pPrimObj->fBoundingSphereRadius = fDistSqu; + } +#else + float fDistSqu = ( d3dvert.dvX * d3dvert.dvX ) + ( d3dvert.dvY * d3dvert.dvY ) + ( d3dvert.dvZ * d3dvert.dvZ ); + if ( ( *pfBoundingSphereRadius * *pfBoundingSphereRadius ) < fDistSqu ) + { + *pfBoundingSphereRadius = sqrtf(fDistSqu); + } +#endif + } + else + { + // OK, try the links. + int iLastIndex = iVertIndex; + while ( iVertIndex != -1 ) + { + ASSERT ( pFirstVertex[iVertIndex].dvX == d3dvert.dvX ); + ASSERT ( pFirstVertex[iVertIndex].dvY == d3dvert.dvY ); + ASSERT ( pFirstVertex[iVertIndex].dvZ == d3dvert.dvZ ); + ASSERT ( pFirstVertex[iVertIndex].dvNX == d3dvert.dvNX ); + ASSERT ( pFirstVertex[iVertIndex].dvNY == d3dvert.dvNY ); + ASSERT ( pFirstVertex[iVertIndex].dvNZ == d3dvert.dvNZ ); + #define CLOSE_ENOUGH(a,b) ( fabsf ( (a) - (b) ) < 0.00001f ) + if ( CLOSE_ENOUGH ( pFirstVertex[iVertIndex].dvTU, d3dvert.dvTU ) && + CLOSE_ENOUGH ( pFirstVertex[iVertIndex].dvTV, d3dvert.dvTV ) ) + { + // Yes, this is a match. + iIndices[i] = iVertIndex; + break; + } + else + { + // Nope - try the next one. + iLastIndex = iVertIndex; + iVertIndex = TPO_piVertexLinks[iVertIndex]; + } + } + if ( iVertIndex == -1 ) + { + // Didn't find one, so add new one. + TPO_piVertexLinks[iLastIndex] = pMaterial->wNumVertices; + TPO_piVertexLinks[pMaterial->wNumVertices] = -1; + + iIndices[i] = pMaterial->wNumVertices; + + *TPO_pCurVertex = d3dvert; + TPO_pCurVertex++; + pMaterial->wNumVertices++; + TPO_iNumVertices++; + ASSERT ( TPO_iNumVertices < MAX_VERTS ); + + if ( TPO_iNumVertices >= MAX_VERTS ) { DeadAndBuried ( 0xffffffff ); } + + #ifdef DEBUG + if ( m_iMaxNumVertsUsed < TPO_iNumVertices ) + { + //ASSERT ( TPO_iNumVertices < 256 ); + m_iMaxNumVertsUsed = TPO_iNumVertices; + } + #endif + } + } + } + + // Now add the indices. + // This is a braindead method - we will optimise it afterwards. + if ( bInnerTris ) + { + ASSERT ( ( iIndices[0] >= 0 ) && ( iIndices[0] < pMaterial->wNumVertices ) ); + ASSERT ( ( iIndices[1] >= 0 ) && ( iIndices[1] < pMaterial->wNumVertices ) ); + ASSERT ( ( iIndices[2] >= 0 ) && ( iIndices[2] < pMaterial->wNumVertices ) ); + + #if 0 + // Strip indices. + *TPO_pCurStripIndex++ = iIndices[0]; + *TPO_pCurStripIndex++ = iIndices[1]; + *TPO_pCurStripIndex++ = iIndices[2]; + *TPO_pCurStripIndex++ = -1; + TPO_iNumStripIndices += 4; + pMaterial->wNumStripIndices += 4; + ASSERT ( TPO_iNumStripIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + #endif + // List indices. + *TPO_pCurListIndex++ = iIndices[0]; + *TPO_pCurListIndex++ = iIndices[1]; + *TPO_pCurListIndex++ = iIndices[2]; + TPO_iNumListIndices += 3; + pMaterial->wNumListIndices += 3; + ASSERT ( TPO_iNumListIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + + #ifdef DEBUG + if ( m_iMaxNumIndicesUsed < TPO_iNumListIndices ) + { + m_iMaxNumIndicesUsed = TPO_iNumListIndices; + } + #endif + + } + else + { + ASSERT ( ( iIndices[0] >= 0 ) && ( iIndices[0] < pMaterial->wNumVertices ) ); + ASSERT ( ( iIndices[1] >= 0 ) && ( iIndices[1] < pMaterial->wNumVertices ) ); + ASSERT ( ( iIndices[2] >= 0 ) && ( iIndices[2] < pMaterial->wNumVertices ) ); + ASSERT ( ( iIndices[3] >= 0 ) && ( iIndices[3] < pMaterial->wNumVertices ) ); + + #if 0 + // Strip indices. + *TPO_pCurStripIndex++ = iIndices[0]; + *TPO_pCurStripIndex++ = iIndices[1]; + *TPO_pCurStripIndex++ = iIndices[2]; + *TPO_pCurStripIndex++ = iIndices[3]; + *TPO_pCurStripIndex++ = -1; + TPO_iNumStripIndices += 5; + pMaterial->wNumStripIndices += 5; + ASSERT ( TPO_iNumStripIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + #endif + // List indices. + *TPO_pCurListIndex++ = iIndices[0]; + *TPO_pCurListIndex++ = iIndices[1]; + *TPO_pCurListIndex++ = iIndices[2]; + *TPO_pCurListIndex++ = iIndices[2]; + *TPO_pCurListIndex++ = iIndices[1]; + *TPO_pCurListIndex++ = iIndices[3]; + TPO_iNumListIndices += 6; + pMaterial->wNumListIndices += 6; + ASSERT ( TPO_iNumListIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + #ifdef DEBUG + if ( m_iMaxNumIndicesUsed < TPO_iNumListIndices ) + { + m_iMaxNumIndicesUsed = TPO_iNumListIndices; + } + #endif + + } + } + } + + bInnerTris = !bInnerTris; + } while ( bInnerTris ); + } + + + // And that's that material fully done. + + + #ifdef HIGH_REZ_PEOPLE_PLEASE_BOB + + // Do they need inflating? + if ( m_bPleaseInflatePeople ) + { + + TRACE("Inflate"); + // Make a list of all edges. + + // At most 3 edges per tri. + EdgeList *pEdgeList = (EdgeList *)MemAlloc ( sizeof ( EdgeList ) * pMaterial->wNumListIndices ); + ASSERT ( pEdgeList != NULL ); + if ( pEdgeList == NULL ) { DeadAndBuried ( 0x0000001f ); } + + // Add the edges. + int iNumEdges = 0; + WORD *pSrcIndex = pFirstListIndex; + WORD wI1, wI2, wI3, wI4; + for ( i = pMaterial->wNumListIndices / 3; i > 0; i-- ) + { + wI1 = pSrcIndex[0]; + wI2 = pSrcIndex[1]; + wI3 = pSrcIndex[2]; + wI4 = pSrcIndex[0]; + + for ( int j = 0; j < 3; j++ ) + { + // Look for edge wI1, wI2. + bool bFound = FALSE; + for ( int k = 0; k < iNumEdges; k++ ) + { + if ( ( ( pEdgeList[k].wPt1 == wI1 ) && ( pEdgeList[k].wPt2 == wI2 ) ) || + ( ( pEdgeList[k].wPt1 == wI2 ) && ( pEdgeList[k].wPt2 == wI1 ) ) ) + { + // Found the edge. + bFound = TRUE; + break; + } + } + if ( !bFound ) + { + // Make the edge. + EdgeList *pEdgeCur = &(pEdgeList[iNumEdges]); + pEdgeCur->wPt1 = wI1; + pEdgeCur->wPt2 = wI2; + iNumEdges++; + } + + // Next edge. + wI1 = wI2; + wI2 = wI3; + wI3 = wI4; + } + + pSrcIndex += 3; + } + + // Now scan the edges, creating the midpoints. + EdgeList *pEdgeCur = pEdgeList; + for ( i = 0; i < iNumEdges; i++ ) + { + D3DVERTEX *pvertMid, *pvert1, *pvert2; + + pvert1 = &pFirstVertex[pEdgeCur->wPt1]; + pvert2 = &pFirstVertex[pEdgeCur->wPt2]; + pEdgeCur->wMidPt = pMaterial->wNumVertices; + pvertMid = TPO_pCurVertex; + + // Make the midpoint. + D3DVECTOR vPos1, vPos2; + vPos1.x = pvert1->x; + vPos1.y = pvert1->y; + vPos1.z = pvert1->z; + vPos2.x = pvert2->x; + vPos2.y = pvert2->y; + vPos2.z = pvert2->z; + D3DVECTOR vNorm1, vNorm2; + vNorm1.x = pvert1->nx; + vNorm1.y = pvert1->ny; + vNorm1.z = pvert1->nz; + vNorm2.x = pvert2->nx; + vNorm2.y = pvert2->ny; + vNorm2.z = pvert2->nz; + + // The edge's vector. + D3DVECTOR vEdge = vPos1 - vPos2; + D3DVECTOR vAvNorm = vNorm1 + vNorm2; + + float fLenAvNorm = Magnitude ( vAvNorm ); + if ( fLenAvNorm < 0.00001f ) + { + // Panic. + vAvNorm = vNorm1; + } + else + { + vAvNorm *= ( 1.0f / fLenAvNorm ); + } + + // Find the normal to the edge. + D3DVECTOR vNormToEdge = CrossProduct ( vEdge, vAvNorm ); + vNormToEdge = CrossProduct ( vNormToEdge, vEdge ); + + float fLenNormToEdge = Magnitude ( vNormToEdge ); + if ( fLenNormToEdge < 0.00001f ) + { + // Panic. + vNormToEdge = vNorm1; + } + else + { + vNormToEdge *= ( 1.0f / fLenNormToEdge ); + } + + // Find the new midpoint. + // Adjust lambda until it's a "nice" value. + D3DVECTOR vPos3; + if ( fLenAvNorm < 0.75f * 2.0f ) + { + // No curve - just make it flat. + vPos3 = ( vPos1 + vPos2 ) * 0.5; + } + else + { + // Curve. + const float fLambda = 0.15f; + vPos3 = ( vPos1 + vPos2 ) * 0.5 + ( ( fLambda * DotProduct ( ( vNorm1 - vNorm2 ), vEdge ) ) * vAvNorm ); + } + + #if 0 + // And find the new mid normal. + // This is theoretically more "correct", but tends to give unstable behaviour. + D3DVECTOR vNorm3 = ( 2 * vNormToEdge ) - vAvNorm; + #elif 0 + // Much more stable, but produces nasty edges. + D3DVECTOR vNorm3 = vAvNorm; + #elif 0 + // A compromise between the two. + D3DVECTOR vNorm3 = vNormToEdge; + #else + // A blend of above, but hopefully more stable. + D3DVECTOR vNorm3 = ( 4 * vNormToEdge ) - vAvNorm; + #endif + + float fLenNorm3 = Magnitude ( vNorm3 ); + if ( fLenNorm3 < 0.00001f ) + { + // Panic. + vNorm3 = vNorm1; + } + else + { + vNorm3 *= ( 1.0f / fLenNorm3 ); + } + + pvertMid->x = vPos3.x; + pvertMid->y = vPos3.y; + pvertMid->z = vPos3.z; + pvertMid->nx = vNorm3.x; + pvertMid->ny = vNorm3.y; + pvertMid->nz = vNorm3.z; + + pvertMid->tu = ( pvert1->tu + pvert2->tu ) * 0.5f; + pvertMid->tv = ( pvert1->tv + pvert2->tv ) * 0.5f; + //pvertMid->dif = ( ( ( pvert1->dif & 0xfefefefe ) >> 1 ) + ( ( pvert2->dif & 0xfefefefe ) >> 1 ) ); + //pvertMid->spec = ( ( ( pvert1->spec & 0xfefefefe ) >> 1 ) + ( ( pvert2->spec & 0xfefefefe ) >> 1 ) ); + + // This must be done after setting the rest up, since it blats the 12th byte of the vertex. + // Just pick either of the vertices - in theory they should all be the same. + SET_MM_INDEX ( (*pvertMid), GET_MM_INDEX(*pvert1) ); + + + // Add it officially. + TPO_pCurVertex++; + pMaterial->wNumVertices++; + TPO_iNumVertices++; + ASSERT ( TPO_iNumVertices < MAX_VERTS ); + + if ( TPO_iNumVertices >= MAX_VERTS ) { DeadAndBuried ( 0xffffffff ); } + + #ifdef DEBUG + if ( m_iMaxNumVertsUsed < TPO_iNumVertices ) + { + //ASSERT ( TPO_iNumVertices < 256 ); + m_iMaxNumVertsUsed = TPO_iNumVertices; + } + #endif + + pEdgeCur++; + } + + + // Now scan all the tris, find their edges, and carve them up into 4 tris. + // If we scan the list backwards, we can use the same list. + + // Add the new indices first, then work out what they are. + int iNewNumListIndices = TPO_iNumListIndices + 3 * pMaterial->wNumListIndices; + int iNewMatNumListIndices = 4 * pMaterial->wNumListIndices; + TPO_pCurListIndex += 3 * pMaterial->wNumListIndices; + ASSERT ( iNewNumListIndices < MAX_INDICES ); + + if ( iNewNumListIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + + #ifdef DEBUG + if ( m_iMaxNumIndicesUsed < iNewNumListIndices ) + { + m_iMaxNumIndicesUsed = iNewNumListIndices; + } + #endif + + + pSrcIndex = pFirstListIndex + pMaterial->wNumListIndices; + WORD *pDstIndex = pFirstListIndex + iNewMatNumListIndices; + WORD wMid[3]; + for ( i = pMaterial->wNumListIndices / 3; i > 0; i-- ) + { + pSrcIndex -= 3; + pDstIndex -= 3 * 4; + + wI1 = pSrcIndex[0]; + wI2 = pSrcIndex[1]; + wI3 = pSrcIndex[2]; + wI4 = pSrcIndex[0]; + for ( int j = 0; j < 3; j++ ) + { + // Look for edge wI1, wI2. + for ( int k = 0; k < iNumEdges; k++ ) + { + if ( ( ( pEdgeList[k].wPt1 == wI1 ) && ( pEdgeList[k].wPt2 == wI2 ) ) || + ( ( pEdgeList[k].wPt1 == wI2 ) && ( pEdgeList[k].wPt2 == wI1 ) ) ) + { + // Found the edge - store the midpoint. + wMid[j] = pEdgeList[k].wMidPt; + break; + } + } + ASSERT ( k != iNumEdges ); + + // Next edge. + wI1 = wI2; + wI2 = wI3; + wI3 = wI4; + } + + ASSERT ( wI1 < pMaterial->wNumVertices ); + ASSERT ( wI2 < pMaterial->wNumVertices ); + ASSERT ( wI3 < pMaterial->wNumVertices ); + ASSERT ( wMid[0] < pMaterial->wNumVertices ); + ASSERT ( wMid[1] < pMaterial->wNumVertices ); + ASSERT ( wMid[2] < pMaterial->wNumVertices ); + + // OK, so we now create 4 tris from wI1-3 and wMid[0-2]. + // wMid[0] will be between wI1 and wI2 + // wMid[1] will be between wI2 and wI3 + // wMid[2] will be between wI3 and wI1 + + // Copy these, coz the very last 4 tris overwrites them. + WORD wSrcIndex0 = pSrcIndex[0]; + WORD wSrcIndex1 = pSrcIndex[1]; + WORD wSrcIndex2 = pSrcIndex[2]; + + pDstIndex[0*3+0] = wSrcIndex0; + pDstIndex[0*3+1] = wMid[0]; + pDstIndex[0*3+2] = wMid[2]; + + pDstIndex[1*3+0] = wSrcIndex1; + pDstIndex[1*3+1] = wMid[1]; + pDstIndex[1*3+2] = wMid[0]; + + pDstIndex[2*3+0] = wSrcIndex2; + pDstIndex[2*3+1] = wMid[2]; + pDstIndex[2*3+2] = wMid[1]; + + pDstIndex[3*3+0] = wMid[0]; + pDstIndex[3*3+1] = wMid[1]; + pDstIndex[3*3+2] = wMid[2]; + } + + ASSERT ( pSrcIndex == pDstIndex ); + + + TPO_iNumListIndices = iNewNumListIndices; + pMaterial->wNumListIndices = iNewMatNumListIndices; + + // Inflation done! + MemFree ( pEdgeList ); + } + +#endif //#ifdef HIGH_REZ_PEOPLE_PLEASE_BOB + + WORD *pSrcIndex; + + + TRACE("Optimise"); + // Optimise the lists using MS's optimiser. Ta, MS. Saves me the hassle. + int iRes = MSOptimizeIndexedList ( pFirstListIndex, pMaterial->wNumListIndices / 3 ); + ASSERT ( iRes != 0 ); + + TRACE("Stripify"); + + // And convert back to the strip format. + ASSERT ( TPO_pCurStripIndex == pFirstStripIndex ); + pSrcIndex = pFirstListIndex; + // Previous edge. + WORD wIndex0 = -1; + WORD wIndex1 = -1; + bool bOdd = FALSE; + bool bFirst = TRUE; + for ( i = pMaterial->wNumListIndices / 3; i > 0; i-- ) + { + // Can we continue the list? + WORD wNextIndex = -1; + if ( ( wIndex0 == pSrcIndex[2] ) && ( wIndex1 == pSrcIndex[0] ) ) + { + wNextIndex = pSrcIndex[1]; + } + else if ( ( wIndex0 == pSrcIndex[0] ) && ( wIndex1 == pSrcIndex[1] ) ) + { + wNextIndex = pSrcIndex[2]; + } + else if ( ( wIndex0 == pSrcIndex[1] ) && ( wIndex1 == pSrcIndex[2] ) ) + { + wNextIndex = pSrcIndex[0]; + } + if ( wNextIndex != (WORD)-1 ) + { + // We can continue the strip. + *TPO_pCurStripIndex++ = wNextIndex; + TPO_iNumStripIndices += 1; + pMaterial->wNumStripIndices += 1; + ASSERT ( TPO_iNumStripIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + #ifdef DEBUG + if ( m_iMaxNumIndicesUsed < TPO_iNumStripIndices ) + { + m_iMaxNumIndicesUsed = TPO_iNumStripIndices; + } + #endif + + if ( bOdd ) + { + wIndex0 = wNextIndex; + } + else + { + wIndex1 = wNextIndex; + } + bOdd = !bOdd; + } + else + { + // No. Start a new one. + if ( !bFirst ) + { + *TPO_pCurStripIndex++ = -1; + TPO_iNumStripIndices += 1; + pMaterial->wNumStripIndices += 1; + ASSERT ( TPO_iNumStripIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + #ifdef DEBUG + if ( m_iMaxNumIndicesUsed < TPO_iNumStripIndices ) + { + m_iMaxNumIndicesUsed = TPO_iNumStripIndices; + } + #endif + + } + else + { + bFirst = FALSE; + } + *TPO_pCurStripIndex++ = pSrcIndex[0]; + *TPO_pCurStripIndex++ = pSrcIndex[1]; + *TPO_pCurStripIndex++ = pSrcIndex[2]; + TPO_iNumStripIndices += 3; + pMaterial->wNumStripIndices += 3; + ASSERT ( TPO_iNumStripIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + #ifdef DEBUG + if ( m_iMaxNumIndicesUsed < TPO_iNumStripIndices ) + { + m_iMaxNumIndicesUsed = TPO_iNumStripIndices; + } + #endif + wIndex0 = pSrcIndex[2]; + wIndex1 = pSrcIndex[1]; + bOdd = FALSE; + } + pSrcIndex += 3; + } + // Finish with a final -1 + *TPO_pCurStripIndex++ = -1; + TPO_iNumStripIndices += 1; + pMaterial->wNumStripIndices += 1; + ASSERT ( TPO_iNumStripIndices < MAX_INDICES ); + + if ( TPO_iNumStripIndices >= MAX_INDICES ) { DeadAndBuried ( 0x07ff07ff ); } + + #ifdef DEBUG + if ( m_iMaxNumIndicesUsed < TPO_iNumStripIndices ) + { + m_iMaxNumIndicesUsed = TPO_iNumStripIndices; + } + #endif + + + ASSERT ( pMaterial->wNumStripIndices == ( TPO_pCurStripIndex - pFirstStripIndex ) ); + + TRACE("Done "); + + + } + + } + + bOuterTris = !bOuterTris; + } while ( bOuterTris ); + } + + + // Set up the total number of vertices used. + pPrimObj->wTotalSizeOfObj = TPO_iNumVertices; + + + + + // Copy the vertices and indices. + // These vertices much be aligned properly for the MM stuff, remember! + + + + // Do the alloc in one block to be nice to the TLB. + DWORD dwTotalSize = 0; + dwTotalSize += TPO_iNumListIndices * sizeof ( UWORD ); + dwTotalSize += 32 + TPO_iNumVertices * sizeof ( D3DVERTEX ); + dwTotalSize += TPO_iNumStripIndices * sizeof ( UWORD ); + + // NOTE! I allocate an extra bit of space on the end because the MM code + // actually reads the index just after the end, so that must be valid memory, + // or you get a page fault. Now _that_ was a tricky bug to find, and had + // been happening on and off for ages, and I could never track it down + // (coz it would crash in the D3D driver, and the stack gets scrogged + // in there, so I can't back-trace to find out what happened). + dwTotalSize += 4 * sizeof (WORD); + + // Now that it's a unified block, TPO_pListIndices is the thing that needs to + // be freed. Obviously, don't free the others - they don't own memory. + char *pcBlock = (char *)MemAlloc ( dwTotalSize ); + ASSERT ( pcBlock != NULL ); + if ( pcBlock == NULL ) { DeadAndBuried ( 0xffe0ffe0 ); } + + pPrimObj->pwListIndices = (UWORD *)pcBlock; + memcpy ( pPrimObj->pwListIndices, TPO_pListIndices, TPO_iNumListIndices * sizeof ( UWORD ) ); + pcBlock += TPO_iNumListIndices * sizeof ( UWORD ); + + // Now the verts, aligned to 32 bytes lines. + pPrimObj->pD3DVertices = (void *)( ( (DWORD)pcBlock + 31 ) & ~31 ); + memcpy ( pPrimObj->pD3DVertices , TPO_pVert, TPO_iNumVertices * sizeof ( D3DVERTEX ) ); + pcBlock = (char *)pPrimObj->pD3DVertices + TPO_iNumVertices * sizeof ( D3DVERTEX ); + + pPrimObj->pwStripIndices = (UWORD *)pcBlock; + memcpy ( pPrimObj->pwStripIndices, TPO_pStripIndices, TPO_iNumStripIndices * sizeof ( UWORD ) ); + pcBlock += TPO_iNumStripIndices * sizeof ( UWORD ); + + ASSERT ( (DWORD)pcBlock < (DWORD)pPrimObj->pwListIndices + dwTotalSize ); + + +#if 0 + //void *pPermanentVerts = MemAlloc ( 32 + TPO_iNumVertices * sizeof ( D3DVERTEX ) ); + pPermanentVerts = (void *)( ( (DWORD)pPermanentVerts + 31 ) & ~31 ); + ASSERT ( pPermanentVerts != NULL ); + memcpy ( pPermanentVerts, TPO_pVert, TPO_iNumVertices * sizeof ( D3DVERTEX ) ); + pPrimObj->pD3DVertices = pPermanentVerts; + + //UWORD *pPermanentIndices = (UWORD *)MemAlloc ( TPO_iNumListIndices * sizeof ( UWORD ) ); + ASSERT ( pPermanentIndices != NULL ); + memcpy ( pPermanentIndices, TPO_pListIndices, TPO_iNumListIndices * sizeof ( UWORD ) ); + pPrimObj->pwListIndices = pPermanentIndices; + + //pPermanentIndices = (UWORD *)MemAlloc ( TPO_iNumStripIndices * sizeof ( UWORD ) ); + ASSERT ( pPermanentIndices != NULL ); + memcpy ( pPermanentIndices, TPO_pStripIndices, TPO_iNumStripIndices * sizeof ( UWORD ) ); + pPrimObj->pwStripIndices = pPermanentIndices; +#endif + + // Free the temporary spaces. + MemFree ( TPO_piVertexLinks ); + MemFree ( TPO_piVertexRemap ); + MemFree ( TPO_pListIndices ); + MemFree ( TPO_pStripIndices ); + MemFree ( TPO_pVert ); + + + // And remember to take the square-root of this to make it an actual radius. + pPrimObj->fBoundingSphereRadius = sqrtf ( pPrimObj->fBoundingSphereRadius ); + + + // Add this to a good place in the LRU queue. + FIGURE_find_and_clean_prim_queue_item ( pPrimObj, iThrashIndex ); + + + // Clean up. + TPO_pVert = NULL; + TPO_pStripIndices = NULL; + TPO_pListIndices = NULL; + TPO_piVertexRemap = NULL; + TPO_piVertexLinks = NULL; + TPO_pCurVertex = NULL; + TPO_pCurStripIndex = NULL; + TPO_pCurListIndex = NULL; + TPO_pPrimObj = NULL; + TPO_iNumListIndices = 0; + TPO_iNumStripIndices = 0; + TPO_iNumVertices = 0; + TPO_iNumPrims = 0; + + TRACE("done all.\n"); + +#ifdef DEBUG + TRACE ( "Max so far: verts %i, indices %i\n", m_iMaxNumVertsUsed, m_iMaxNumIndicesUsed ); +#endif + +} + + + + + +// Takes a "prim" description and generates D3D-style data for a single prim. +void FIGURE_generate_D3D_object ( SLONG prim ) +{ + PrimObject *p_obj = &prim_objects[prim]; + TomsPrimObject *pPrimObj = &(D3DObj[prim]); + + // Set it up. + FIGURE_TPO_init_3d_object ( pPrimObj ); + + // Add this prim to it as object 0. + //FIGURE_TPO_add_prim_to_current_object ( p_obj, 0 ); + FIGURE_TPO_add_prim_to_current_object ( prim, 0 ); + + + // And clean it all up. + FIGURE_TPO_finish_3d_object ( pPrimObj ); +} + + + + + +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + + + + + +void FIGURE_draw_prim_tween( + SLONG prim, + SLONG x, + SLONG y, + SLONG z, + SLONG tween, + struct GameKeyFrameElement *anim_info, + struct GameKeyFrameElement *anim_info_next, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + ULONG colour, + ULONG specular, + CMatrix33 *parent_base_mat, + Matrix31 *parent_base_pos, + Matrix33 *parent_curr_mat, + Matrix31 *parent_curr_pos, + Matrix33 *end_mat, + Matrix31 *end_pos, + Thing *p_thing, + SLONG part_number = 0xffffffff, + ULONG colour_and = 0xffffffff) +{ + + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG nx; + SLONG ny; + SLONG nz; + + SLONG red; + SLONG green; + SLONG blue; + SLONG dprod; + SLONG r; + SLONG g; + SLONG b; + + SLONG dr; + SLONG dg; + SLONG db; + + SLONG face_colour; + + SLONG page; + + Matrix31 offset; + Matrix33 mat2; + Matrix33 mat_final; + + ULONG qc0; + ULONG qc1; + ULONG qc2; + ULONG qc3; + + SVector temp; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + NIGHT_Found *nf; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + SLONG tex_page_offset; + + + LOG_ENTER ( Figure_Draw_Prim_Tween ) + + tex_page_offset=p_thing->Genus.Person->pcom_colour&0x3; + + // + // Matrix functions we use. + // + + void matrix_transform (Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_mult33 (Matrix33* result, Matrix33* mat1, Matrix33* mat2); + + if (parent_base_mat) + { + // we've got hierarchy info! + + Matrix31 p; + p.M[0] = anim_info->OffsetX; + p.M[1] = anim_info->OffsetY; + p.M[2] = anim_info->OffsetZ; + + HIERARCHY_Get_Body_Part_Offset(&offset, &p, + parent_base_mat, parent_base_pos, + parent_curr_mat, parent_curr_pos); + + // pass data up the hierarchy + if (end_pos) + *end_pos = offset; + } + else + { + // process at highter resolution + offset.M[0] = (anim_info->OffsetX << 8) + ((anim_info_next->OffsetX + off_dx - anim_info->OffsetX) * tween); + offset.M[1] = (anim_info->OffsetY << 8) + ((anim_info_next->OffsetY + off_dy - anim_info->OffsetY) * tween); + offset.M[2] = (anim_info->OffsetZ << 8) + ((anim_info_next->OffsetZ + off_dz - anim_info->OffsetZ) * tween); + +/* We don't have bikes. + if (p_thing->Class == CLASS_BIKE && part_number == 3) + { + //offset.M[0] = 0x0; + //offset.M[1] = 0x900; + offset.M[2] = 0x3500; + } +*/ + if (end_pos) + { + *end_pos = offset; + } + } + +// matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + // convert pos to floating point here to preserve accuracy and prevent overflow. + float off_x = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[0][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[0][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[0][2]) / 32768.f); + float off_y = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[1][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[1][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[1][2]) / 32768.f); + float off_z = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[2][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[2][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[2][2]) / 32768.f); + + + SLONG character_scale = person_get_scale(p_thing); + float character_scalef = float(character_scale) / 256.f; + + off_x *= character_scalef; + off_y *= character_scalef; + off_z *= character_scalef; + + /* + + if (p_thing->Class == CLASS_BIKE) + { + off_x = 0; + off_y = 0; + off_z = 0; + } + + */ + + off_x += float(x); + off_y += float(y); + off_z += float(z); + + // + // Do everything in floats. + // + + float fmatrix[9]; + SLONG imatrix[9]; + + { + // + // Create a temporary "tween" matrix between current and next + // + + CMatrix33 m1, m2; + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + CQuaternion::BuildTween(&mat2, &m1, &m2, tween); + + // pass data up the hierarchy + if (end_mat) + *end_mat = mat2; + + // + // Apply local rotation matrix to get mat_final that rotates + // the point into world space. + // + + matrix_mult33(&mat_final, rot_mat, &mat2); + + //! yeehaw! + mat_final.M[0][0] = (mat_final.M[0][0] * character_scale) / 256; + mat_final.M[0][1] = (mat_final.M[0][1] * character_scale) / 256; + mat_final.M[0][2] = (mat_final.M[0][2] * character_scale) / 256; + mat_final.M[1][0] = (mat_final.M[1][0] * character_scale) / 256; + mat_final.M[1][1] = (mat_final.M[1][1] * character_scale) / 256; + mat_final.M[1][2] = (mat_final.M[1][2] * character_scale) / 256; + mat_final.M[2][0] = (mat_final.M[2][0] * character_scale) / 256; + mat_final.M[2][1] = (mat_final.M[2][1] * character_scale) / 256; + mat_final.M[2][2] = (mat_final.M[2][2] * character_scale) / 256; + + fmatrix[0] = float(mat_final.M[0][0]) * (1.0F / 32768.0F); + fmatrix[1] = float(mat_final.M[0][1]) * (1.0F / 32768.0F); + fmatrix[2] = float(mat_final.M[0][2]) * (1.0F / 32768.0F); + fmatrix[3] = float(mat_final.M[1][0]) * (1.0F / 32768.0F); + fmatrix[4] = float(mat_final.M[1][1]) * (1.0F / 32768.0F); + fmatrix[5] = float(mat_final.M[1][2]) * (1.0F / 32768.0F); + fmatrix[6] = float(mat_final.M[2][0]) * (1.0F / 32768.0F); + fmatrix[7] = float(mat_final.M[2][1]) * (1.0F / 32768.0F); + fmatrix[8] = float(mat_final.M[2][2]) * (1.0F / 32768.0F); + + imatrix[0] = mat_final.M[0][0] * 2; + imatrix[1] = mat_final.M[0][1] * 2; + imatrix[2] = mat_final.M[0][2] * 2; + imatrix[3] = mat_final.M[1][0] * 2; + imatrix[4] = mat_final.M[1][1] * 2; + imatrix[5] = mat_final.M[1][2] * 2; + imatrix[6] = mat_final.M[2][0] * 2; + imatrix[7] = mat_final.M[2][1] * 2; + imatrix[8] = mat_final.M[2][2] * 2; + } + + /* + + if (part_number == SUB_OBJECT_HEAD) + { + fmatrix[0]= +0.131534; + fmatrix[1]= -0.000000; + fmatrix[2]= +0.991312; + fmatrix[3]= +0.00133604; + fmatrix[4]= +0.999999; + fmatrix[5]= -0.000177275; + fmatrix[6]= -0.991311; + fmatrix[7]= 0.00134775; + fmatrix[8]= 0.131534;; + } + + */ + + if (prim == 267) + { + static count = 0; + + count += 1; + +#ifndef FINAL +#ifndef TARGET_DC + if (ControlFlag&&allow_debug_keys) + { + LOG_EXIT ( Figure_Draw_Prim_Tween ) + return; + } +#endif +#endif + } + + LOG_ENTER ( Figure_Set_Rotation ) + + POLY_set_local_rotation( + off_x, + off_y, + off_z, + fmatrix); + + LOG_ENTER ( Figure_Set_Rotation ) + + + // + // Rotate all the points into the POLY_buffer. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + POLY_buffer_upto = 0; + + // Check for being a gun +#ifndef BUILD_PSX + if (prim==256) + { + i=sp; + } + else + // Or a shotgun + if (prim==258) + { + i=sp+15; + } + // or an AK + else + if (prim==260) + { + i=sp+32; + } + else goto no_muzzle_calcs; // which skips... + + + // + // this bit, which only executes if one of the above tests is true. + // + pp = &POLY_buffer[POLY_buffer_upto]; // no ++, so reused + pp->x=AENG_dx_prim_points[i].X; + pp->y=AENG_dx_prim_points[i].Y; + pp->z=AENG_dx_prim_points[i].Z; + MATRIX_MUL( + fmatrix, + pp->x, + pp->y, + pp->z); + + pp->x+=off_x; pp->y+=off_y; pp->z+=off_z; + p_thing->Genus.Person->GunMuzzle.X=pp->x*256; + p_thing->Genus.Person->GunMuzzle.Y=pp->y*256; + p_thing->Genus.Person->GunMuzzle.Z=pp->z*256; +// x=pp->x*256; y=pp->y*256; z=pp->z*256; + + +#endif +no_muzzle_calcs: + + + + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + if ( !MM_bLightTableAlreadySetUp ) + { + +#if 0 + + // Set it up then. + ASSERT ( MM_pcFadeTable == NULL ); + ASSERT ( MM_pcFadeTableTint == NULL ); + ASSERT ( MM_pMatrix == NULL ); + ASSERT ( MM_Vertex == NULL ); + ASSERT ( MM_pNormal == NULL ); + // Set up some data for the MM rendering thing if it's not already been done. + +// #define ALIGNED_STATIC_ARRAY(name,number,mytype,align) \ +// static char c##name##mytype##align##StaticArray [ align + number * sizeof ( mytype ) ]; \ +// name = (mytype *)( ( (DWORD)c##name##mytype##align##StaticArray + (align-1) ) & ~(align-1) ) + + ALIGNED_STATIC_ARRAY ( MM_pcFadeTable, 128, D3DCOLOR, 4 ); + ALIGNED_STATIC_ARRAY ( MM_pcFadeTableTint, 128, D3DCOLOR, 4 ); + ALIGNED_STATIC_ARRAY ( MM_pMatrix, 1, D3DMATRIX, 32 ); + ALIGNED_STATIC_ARRAY ( MM_Vertex, 4, D3DVERTEX, 32 ); + ALIGNED_STATIC_ARRAY ( MM_pNormal, 4, float, 8 ); + +#endif + + } + +#endif + + + + if (WITHIN(prim, 261, 263)) + { + // + // This is a muzzle flash! They don't have any lighting! + // + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform_using_local_rotation( + AENG_dx_prim_points[i].X, + AENG_dx_prim_points[i].Y, + AENG_dx_prim_points[i].Z, + pp); + + pp->colour = 0xff808080; + pp->specular = 0xff000000; + } + + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + + LOG_EXIT ( Figure_Draw_Prim_Tween ) + return; + } + else + { + + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + if ( !MM_bLightTableAlreadySetUp ) + { + + Pyro *p = NULL; + if (p_thing->Class == CLASS_PERSON && p_thing->Genus.Person->BurnIndex) + { + p = TO_PYRO(p_thing->Genus.Person->BurnIndex-1); + if (p->PyroType != PYRO_IMMOLATE) + { + p = NULL; + } + } + BuildMMLightingTable ( p, colour_and ); + + } + + + + LOG_ENTER ( Figure_Build_Matrices ) + + extern float POLY_cam_matrix_comb[9]; + extern float POLY_cam_off_x; + extern float POLY_cam_off_y; + extern float POLY_cam_off_z; + + + extern D3DMATRIX g_matProjection; + extern D3DMATRIX g_matWorld; + extern D3DVIEWPORT2 g_viewData; + + + D3DMATRIX matTemp; + + { + //_Multiply4dM((float *)pResultMatrix, (float *)g_matWorld, (float *)g_matProjection); + + matTemp._11 = g_matWorld._11*g_matProjection._11 + g_matWorld._12*g_matProjection._21 + g_matWorld._13*g_matProjection._31 + g_matWorld._14*g_matProjection._41; + matTemp._12 = g_matWorld._11*g_matProjection._12 + g_matWorld._12*g_matProjection._22 + g_matWorld._13*g_matProjection._32 + g_matWorld._14*g_matProjection._42; + matTemp._13 = g_matWorld._11*g_matProjection._13 + g_matWorld._12*g_matProjection._23 + g_matWorld._13*g_matProjection._33 + g_matWorld._14*g_matProjection._43; + matTemp._14 = g_matWorld._11*g_matProjection._14 + g_matWorld._12*g_matProjection._24 + g_matWorld._13*g_matProjection._34 + g_matWorld._14*g_matProjection._44; + + matTemp._21 = g_matWorld._21*g_matProjection._11 + g_matWorld._22*g_matProjection._21 + g_matWorld._23*g_matProjection._31 + g_matWorld._24*g_matProjection._41; + matTemp._22 = g_matWorld._21*g_matProjection._12 + g_matWorld._22*g_matProjection._22 + g_matWorld._23*g_matProjection._32 + g_matWorld._24*g_matProjection._42; + matTemp._23 = g_matWorld._21*g_matProjection._13 + g_matWorld._22*g_matProjection._23 + g_matWorld._23*g_matProjection._33 + g_matWorld._24*g_matProjection._43; + matTemp._24 = g_matWorld._21*g_matProjection._14 + g_matWorld._22*g_matProjection._24 + g_matWorld._23*g_matProjection._34 + g_matWorld._24*g_matProjection._44; + + matTemp._31 = g_matWorld._31*g_matProjection._11 + g_matWorld._32*g_matProjection._21 + g_matWorld._33*g_matProjection._31 + g_matWorld._34*g_matProjection._41; + matTemp._32 = g_matWorld._31*g_matProjection._12 + g_matWorld._32*g_matProjection._22 + g_matWorld._33*g_matProjection._32 + g_matWorld._34*g_matProjection._42; + matTemp._33 = g_matWorld._31*g_matProjection._13 + g_matWorld._32*g_matProjection._23 + g_matWorld._33*g_matProjection._33 + g_matWorld._34*g_matProjection._43; + matTemp._34 = g_matWorld._31*g_matProjection._14 + g_matWorld._32*g_matProjection._24 + g_matWorld._33*g_matProjection._34 + g_matWorld._34*g_matProjection._44; + + matTemp._41 = g_matWorld._41*g_matProjection._11 + g_matWorld._42*g_matProjection._21 + g_matWorld._43*g_matProjection._31 + g_matWorld._44*g_matProjection._41; + matTemp._42 = g_matWorld._41*g_matProjection._12 + g_matWorld._42*g_matProjection._22 + g_matWorld._43*g_matProjection._32 + g_matWorld._44*g_matProjection._42; + matTemp._43 = g_matWorld._41*g_matProjection._13 + g_matWorld._42*g_matProjection._23 + g_matWorld._43*g_matProjection._33 + g_matWorld._44*g_matProjection._43; + matTemp._44 = g_matWorld._41*g_matProjection._14 + g_matWorld._42*g_matProjection._24 + g_matWorld._43*g_matProjection._34 + g_matWorld._44*g_matProjection._44; + } + + + + + + + + // Now make up the matrices. + +#if 0 + // Officially correct version. + DWORD dwWidth = g_viewData.dwWidth >> 1; + DWORD dwHeight = g_viewData.dwHeight >> 1; + DWORD dwX = g_viewData.dwX; + DWORD dwY = g_viewData.dwY; +#else + // Version that knows about the letterbox mode hack. +extern DWORD g_dw3DStuffHeight; +extern DWORD g_dw3DStuffY; + DWORD dwWidth = g_viewData.dwWidth >> 1; + DWORD dwHeight = g_dw3DStuffHeight >> 1; + DWORD dwX = g_viewData.dwX; + DWORD dwY = g_dw3DStuffY; +#endif + MM_pMatrix[0]._11 = 0.0f; + MM_pMatrix[0]._12 = matTemp._11 * (float)dwWidth + matTemp._14 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._13 = matTemp._12 * - (float)dwHeight + matTemp._14 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._14 = matTemp._14; + MM_pMatrix[0]._21 = 0.0f; + MM_pMatrix[0]._22 = matTemp._21 * (float)dwWidth + matTemp._24 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._23 = matTemp._22 * - (float)dwHeight + matTemp._24 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._24 = matTemp._24; + MM_pMatrix[0]._31 = 0.0f; + MM_pMatrix[0]._32 = matTemp._31 * (float)dwWidth + matTemp._34 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._33 = matTemp._32 * - (float)dwHeight + matTemp._34 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._34 = matTemp._34; + // Validation magic number. + unsigned long EVal = 0xe0001000; + MM_pMatrix[0]._41 = *(float *)&EVal; + MM_pMatrix[0]._42 = matTemp._41 * (float)dwWidth + matTemp._44 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._43 = matTemp._42 * - (float)dwHeight + matTemp._44 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._44 = matTemp._44; + + + + // 251 is a magic number for the DIP call! + const float fNormScale = 251.0f; + + // Transform the lighting direction(s) by the inverse object matrix to get it into object space. + // Assume inverse=transpose. + D3DVECTOR vTemp; + vTemp.x = MM_vLightDir.x * fmatrix[0] + MM_vLightDir.y * fmatrix[3] + MM_vLightDir.z * fmatrix[6]; + vTemp.y = MM_vLightDir.x * fmatrix[1] + MM_vLightDir.y * fmatrix[4] + MM_vLightDir.z * fmatrix[7]; + vTemp.z = MM_vLightDir.x * fmatrix[2] + MM_vLightDir.y * fmatrix[5] + MM_vLightDir.z * fmatrix[8]; + + MM_pNormal[0] = 0.0f; + MM_pNormal[1] = vTemp.x * fNormScale; + MM_pNormal[2] = vTemp.y * fNormScale; + MM_pNormal[3] = vTemp.z * fNormScale; + + LOG_EXIT ( Figure_Build_Matrices ) + + +#else //#if USE_TOMS_ENGINE_PLEASE_BOB + + + Pyro *p = NULL; + + if (p_thing->Class == CLASS_PERSON && p_thing->Genus.Person->BurnIndex) + { + p = TO_PYRO(p_thing->Genus.Person->BurnIndex-1); + + if (p->PyroType != PYRO_IMMOLATE) + { + p = NULL; + } + } + + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform_using_local_rotation( + AENG_dx_prim_points[i].X, + AENG_dx_prim_points[i].Y, + AENG_dx_prim_points[i].Z, + pp); + + // + // Do the lighting... + // + + { + nx = prim_normal[i].X; + ny = prim_normal[i].Y; + nz = prim_normal[i].Z; + + FMATRIX_MUL( + imatrix, + nx, + ny, + nz); + + dprod = + nx * NIGHT_amb_norm_x + + ny * NIGHT_amb_norm_y + + nz * NIGHT_amb_norm_z; + + r = NIGHT_amb_red << 0; + g = NIGHT_amb_green << 0; + b = NIGHT_amb_blue << 0; + +#ifndef TARGET_DC + extern UBYTE sw_hack; +#endif + + if (dprod > 0) + { + dr = NIGHT_amb_red * dprod >> 15; + dg = NIGHT_amb_green * dprod >> 15; + db = NIGHT_amb_blue * dprod >> 15; + + r += dr;// + (dr >> 1); + g += dg;// + (dg >> 1); + b += db;// + (db >> 1); + } + + // + // Now for the lights... + // + + for (j = 0; j < NIGHT_found_upto; j++) + { + nf = &NIGHT_found[j]; + + dprod = + nx * nf->dx + + ny * nf->dy + + nz * nf->dz; + + if (dprod < 0) + { + dr = nf->r * dprod >> 15; + dg = nf->g * dprod >> 15; + db = nf->b * dprod >> 15; + + r -= dr;// + (dr >> 1); + g -= dg;// + (dg >> 1); + b -= db;// + (db >> 1); + } + } + + if (p) + { + r = (r > p->counter) ? (r - p->counter) : 10; + g = (g > p->counter) ? (g - p->counter) : 4; + b = (b > p->counter) ? (b - p->counter) : 3; + } + +#ifndef TARGET_DC + if (sw_hack) + { + r <<= 1; + g <<= 1; + b <<= 1; + } +#endif + + SATURATE(r, 0, 255); + SATURATE(g, 0, 255); + SATURATE(b, 0, 255); + + pp->colour = (r << 16) | (g << 8) | (b << 0); + pp->colour |= FIGURE_alpha << 24; + pp->specular = 0xff000000; + } + } +#endif //#else //#if USE_TOMS_ENGINE_PLEASE_BOB + + } + + + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + + +#if 1 + +#if 1 + + // The wonderful NEW system! + + + LOG_ENTER ( Figure_Draw_Polys ) + +#if 1 + // The MM stuff doesn't like specular to be enabled. + (the_display.lp_D3D_Device)->SetRenderState ( D3DRENDERSTATE_SPECULARENABLE, FALSE ); +#endif + + + // For now, just calculate as-and-when. + TomsPrimObject *pPrimObj = &(D3DObj[prim]); + if ( pPrimObj->wNumMaterials == 0 ) + { + // Not initialised. Do so. + // It's not fair to count this as part of the drawing! :-) + LOG_EXIT ( Figure_Draw_Polys ) + + FIGURE_generate_D3D_object ( prim ); + LOG_ENTER ( Figure_Draw_Polys ) + } + + // Tell the LRU cache we used this one. + FIGURE_touch_LRU_of_object ( pPrimObj ); + + ASSERT ( pPrimObj->pD3DVertices != NULL ); + ASSERT ( pPrimObj->pMaterials != NULL ); + ASSERT ( pPrimObj->pwListIndices != NULL ); + ASSERT ( pPrimObj->pwStripIndices != NULL ); + ASSERT ( pPrimObj->wNumMaterials != 0 ); + + PrimObjectMaterial *pMat = pPrimObj->pMaterials; + + D3DMULTIMATRIX d3dmm; + d3dmm.lpd3dMatrices = MM_pMatrix; + d3dmm.lpvLightDirs = MM_pNormal; + + D3DVERTEX *pVertex = (D3DVERTEX *)pPrimObj->pD3DVertices; + UWORD *pwListIndices = pPrimObj->pwListIndices; + UWORD *pwStripIndices = pPrimObj->pwStripIndices; + for ( int iMatNum = pPrimObj->wNumMaterials; iMatNum > 0; iMatNum-- ) + { + // Set up the right texture for this material. + + UWORD wPage = pMat->wTexturePage; + UWORD wRealPage = wPage & TEXTURE_PAGE_MASK; + + if ( wPage & TEXTURE_PAGE_FLAG_JACKET ) + { + // Find the real jacket page. + wRealPage = jacket_lookup [ wRealPage ][GET_SKILL(p_thing)>>2]; + wRealPage += FACE_PAGE_OFFSET; + } + else if ( wPage & TEXTURE_PAGE_FLAG_OFFSET ) + { + // An "offset" texture. This will be offset by a certain amount to + // allow each prim to have different coloured clothes on. + if ( tex_page_offset == 0 ) + { + // No lookup offset. + // This has not been offset yet. + wRealPage += FACE_PAGE_OFFSET; + } + else + { + // Look this up. + wRealPage = alt_texture[wRealPage-(10*64)]+tex_page_offset-1; + } + } + +#ifdef DEBUG + if ( wPage & TEXTURE_PAGE_FLAG_NOT_TEXTURED ) + { + ASSERT ( wRealPage == POLY_PAGE_COLOUR ); + } +#endif + +extern D3DMATRIX g_matWorld; + + PolyPage *pa = &(POLY_Page[wRealPage]); + // Not sure if I'm using character_scalef correctly... + ASSERT ( ( character_scalef < 1.2f ) && ( character_scalef > 0.8f ) ); + if ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) && + ( ( ( g_matWorld._43 * 32768.0f ) - ( pPrimObj->fBoundingSphereRadius * character_scalef ) ) > ( POLY_ZCLIP_PLANE * 32768.0f ) ) ) + { + // Non-alpha path. + if ( wPage & TEXTURE_PAGE_FLAG_TINT ) + { + // Tinted colours. + d3dmm.lpLightTable = MM_pcFadeTableTint; + } + else + { + // Normal. + d3dmm.lpLightTable = MM_pcFadeTable; + } + d3dmm.lpvVertices = pVertex; + + + +#if 1 + + + +#ifdef DEBUG +static int iCounter = 0; + if ( iCounter != 0 ) + { + iCounter--; + ASSERT ( iCounter != 0 ); + } +#endif + + // Fast as lightning. + LOG_ENTER ( Figure_Set_RenderState ) + pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + LOG_EXIT ( Figure_Set_RenderState ) + LOG_ENTER ( Figure_DrawIndPrimMM ) + + +#if 0 + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); + //TRACE("Drew %i vertices, %i indices\n", (int)( pMat->wNumVertices ), (int)( pMat->wNumStripIndices ) ); +#else + // Use platform-independent version. + + HRESULT hres; + + + + +#define SHOW_ME_FIGURE_DEBUGGING_PLEASE_BOB defined + +#ifdef SHOW_ME_FIGURE_DEBUGGING_PLEASE_BOB +#ifdef DEBUG +#ifdef TARGET_DC +#define BUTTON_IS_PRESSED(value) ((value&0x80)!=0) +extern DIJOYSTATE the_state; + bool bShowDebug = FALSE; + if ( BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_LTRIGGER] ) && BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_RTRIGGER] ) ) + { + DWORD dwColour = (DWORD)pwStripIndices; + dwColour = ( dwColour >> 2 ) ^ ( dwColour >> 6 ) ^ ( dwColour ) ^ ( dwColour << 3 ); + dwColour = ( dwColour << 9 ) ^ ( dwColour << 19 ) ^ ( dwColour ) ^ ( dwColour << 29 ) ^ ( dwColour >> 3 ); + dwColour &= 0x7f7f7f7f; + for ( int i = 0; i < 128; i++ ) + { + d3dmm.lpLightTable[i] = dwColour; + } + + // And NULL texture (i.e. white). + the_display.lp_D3D_Device->SetTexture ( 0, NULL ); + } +#endif +#endif +#endif + + + + //if (pMat->wNumVertices && + // pMat->wNumStripIndices) + { + //TRACE ( "S4" ); + hres = DrawIndPrimMM ( + (the_display.lp_D3D_Device), + D3DFVF_VERTEX, + &d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices ); + //TRACE ( "F4" ); + } +#endif + + + + +#else + + // Do some performance tracing. +#ifndef DTRACE +#error Don't use this codepath unless DTRACING, fool! +#endif + + LOG_ENTER ( Figure_Set_RenderState ) + pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + + WORD wTempVerts[4]; + wTempVerts[0] = 0; + wTempVerts[1] = 1; + wTempVerts[2] = 2; + wTempVerts[3] = -1; + (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + 3, + wTempVerts, + 4, + D3DDP_MULTIMATRIX ); + LOG_EXIT ( Figure_Set_RenderState ) + + LOG_ENTER ( Figure_DrawIndPrimMM ) + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); + //TRACE("Drew %i vertices, %i indices\n", (int)( pMat->wNumVertices ), (int)( pMat->wNumStripIndices ) ); + +#endif + + +// ASSERT ( SUCCEEDED ( hres ) ); //triggers all the time when inside on start of RTA +#if 0 + // Can we have 4x polys for free? Oh go on.... + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); +#endif + LOG_EXIT ( Figure_DrawIndPrimMM ) + + } + else + { + // Alpha/clipped path - do with standard non-MM calls. + // FIXME. Needs to be done. + + // Actually, the fast-accept works very well, and it's only when the camera somehow gets REALLY close + // that this happens. And actually a pop-reject seems a bit better than a clip. Certainly + // there is no visually "right" thing to do. So leave it for now until someone complains. ATF. + //TRACE ( "Tried to draw an alpha/clipped prim!" ); + } + + + + // Next material + pVertex += pMat->wNumVertices; + pwListIndices += pMat->wNumListIndices; + pwStripIndices += pMat->wNumStripIndices; + + pMat++; + } + +#if 1 + // The MM stuff doesn't like specular to be enabled. + (the_display.lp_D3D_Device)->SetRenderState ( D3DRENDERSTATE_SPECULARENABLE, TRUE ); +#endif + + LOG_EXIT ( Figure_Draw_Polys ) + + +#endif + +#else + + // + // The quads. + // + + + float fMyU[4], fMyV[4]; + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + fMyU[0] = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + fMyV[0] = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + fMyU[1] = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + fMyV[1] = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + fMyU[2] = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + fMyV[2] = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + fMyU[3] = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + fMyV[3] = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + if(p_f4->FaceFlags&FACE_FLAG_THUG_JACKET) + { + switch(page) + { + case 64+21: + case 10*64+2: + case 10*64+32: + page=jacket_lookup[0][GET_SKILL(p_thing)>>2]; + break; + case 64+22: + case 10*64+3: + case 10*64+33: + page=jacket_lookup[1][GET_SKILL(p_thing)>>2]; + break; + case 64+24: + case 10*64+4: + case 10*64+36: + page=jacket_lookup[2][GET_SKILL(p_thing)>>2]; + break; + case 64+25: + case 10*64+5: + case 10*64+37: + page=jacket_lookup[3][GET_SKILL(p_thing)>>2]; + break; + default: +// ASSERT(0); + break; + } + page+=FACE_PAGE_OFFSET; + } + else + + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) +// if(alt_texture[page-512]&&page<1024) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + +#ifndef TARGET_DC + extern UBYTE sw_hack; +#endif + + PolyPage *pa = &(POLY_Page[page]); + if ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) ) + { + // Unlit untransformed vertices! + WORD wIndices[5] = {0,1,2,3,-1}; + for ( int i = 0; i < 4; i++ ) + { + const float fNormScale = 1.0f / 256.0f; + + int pt = p_f4->Points[i]; + ASSERT(WITHIN(pt, sp, ep)); + + MM_Vertex[i].dvX = AENG_dx_prim_points[pt].X; + MM_Vertex[i].dvY = AENG_dx_prim_points[pt].Y; + MM_Vertex[i].dvZ = AENG_dx_prim_points[pt].Z; + MM_Vertex[i].dvNX = prim_normal[pt].X * fNormScale; + MM_Vertex[i].dvNY = prim_normal[pt].Y * fNormScale; + MM_Vertex[i].dvNZ = prim_normal[pt].Z * fNormScale; + MM_Vertex[i].dvTU = fMyU[i]; + MM_Vertex[i].dvTV = fMyV[i]; + // This must be done after setting the rest up, since it blats the 12th byte of the vertex. + SET_MM_INDEX ( (MM_Vertex[i]), 0 ); + } + + D3DMULTIMATRIX d3dmm; + d3dmm.lpd3dMatrices = MM_pMatrix; + d3dmm.lpvLightDirs = MM_pNormal; + if (p_f4->FaceFlags & FACE_FLAG_TINT) + { + // Tinted colours. + d3dmm.lpLightTable = MM_pcFadeTableTint; + } + else + { + // Normal. + d3dmm.lpLightTable = MM_pcFadeTable; + } + d3dmm.lpvVertices = MM_Vertex; + + + + // Although in theory this might happen, I've never actually seen it. + ASSERT ( ( p_f4->DrawFlags & POLY_FLAG_TEXTURED ) != 0 ); + + + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, (void *)&d3dmm, 4, wIndices, 5, D3DDP_MULTIMATRIX ); + ASSERT ( SUCCEEDED ( hres ) ); + } + else + { + // Alpha-blended, clipped, or otherwise special-cased. Ignore for now, but need to be handled. + } + } + + + // + // The tris. + // + + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + fMyU[0] = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + fMyV[0] = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + fMyU[1] = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + fMyV[1] = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + fMyU[2] = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + fMyV[2] = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + + if(p_f3->FaceFlags&FACE_FLAG_THUG_JACKET) + { + switch(page) + { + case 64+21: + case 10*64+2: + case 10*64+32: + page=jacket_lookup[0][GET_SKILL(p_thing)>>2]; + break; + case 64+22: + case 10*64+3: + case 10*64+33: + page=jacket_lookup[1][GET_SKILL(p_thing)>>2]; + break; + case 64+24: + case 10*64+4: + case 10*64+36: + page=jacket_lookup[2][GET_SKILL(p_thing)>>2]; + break; + case 64+25: + case 10*64+5: + case 10*64+37: + page=jacket_lookup[3][GET_SKILL(p_thing)>>2]; + break; + default: +// ASSERT(0); + break; + } + page+=FACE_PAGE_OFFSET; + } + else + + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) +// if(alt_texture[page-512]&&page<1024) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + +#ifndef TARGET_DC + extern UBYTE sw_hack; +#endif + + PolyPage *pa = &(POLY_Page[page]); + if ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) ) + { + // Unlit untransformed vertices! + WORD wIndices[4] = {0,1,2,-1}; + for ( int i = 0; i < 3; i++ ) + { + const float fNormScale = 1.0f / 256.0f; + + int pt = p_f3->Points[i]; + ASSERT(WITHIN(pt, sp, ep)); + + MM_Vertex[i].dvX = AENG_dx_prim_points[pt].X; + MM_Vertex[i].dvY = AENG_dx_prim_points[pt].Y; + MM_Vertex[i].dvZ = AENG_dx_prim_points[pt].Z; + MM_Vertex[i].dvNX = prim_normal[pt].X * fNormScale; + MM_Vertex[i].dvNY = prim_normal[pt].Y * fNormScale; + MM_Vertex[i].dvNZ = prim_normal[pt].Z * fNormScale; + MM_Vertex[i].dvTU = fMyU[i]; + MM_Vertex[i].dvTV = fMyV[i]; + // This must be done after setting the rest up, since it blats the 12th byte of the vertex. + SET_MM_INDEX ( (MM_Vertex[i]), 0 ); + } + + D3DMULTIMATRIX d3dmm; + d3dmm.lpd3dMatrices = MM_pMatrix; + d3dmm.lpvLightDirs = MM_pNormal; + if (p_f3->FaceFlags & FACE_FLAG_TINT) + { + // Tinted colours. + d3dmm.lpLightTable = MM_pcFadeTableTint; + } + else + { + // Normal. + d3dmm.lpLightTable = MM_pcFadeTable; + } + d3dmm.lpvVertices = MM_Vertex; + + + + // Although in theory this might happen, I've never actually seen it. + ASSERT ( ( p_f3->DrawFlags & POLY_FLAG_TEXTURED ) != 0 ); + + + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, (void *)&d3dmm, 3, wIndices, 4, D3DDP_MULTIMATRIX ); + ASSERT ( SUCCEEDED ( hres ) ); + } + else + { + // Alpha-blended, clipped, or otherwise special-cased. Ignore for now, but need to be handled. + } + } + + +#endif + + +#else //#if USE_TOMS_ENGINE_PLEASE_BOB + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); +/* + p_f4->Bright[0]=store_dprod[p0]; + p_f4->Bright[1]=store_dprod[p1]; + p_f4->Bright[2]=store_dprod[p2]; + p_f4->Bright[4]=store_dprod[p3]; +*/ + + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + if (p_f4->DrawFlags & POLY_FLAG_TEXTURED) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + if (p_f4->FaceFlags & FACE_FLAG_TINT) + { + qc0 = quad[0]->colour; + qc1 = quad[1]->colour; + qc2 = quad[2]->colour; + qc3 = quad[3]->colour; + + quad[0]->colour &= colour_and; + quad[1]->colour &= colour_and; + quad[2]->colour &= colour_and; + quad[3]->colour &= colour_and; + } + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + if(p_f4->FaceFlags&FACE_FLAG_THUG_JACKET) + { + switch(page) + { + case 64+21: + case 10*64+2: + case 10*64+32: + page=jacket_lookup[0][GET_SKILL(p_thing)>>2]; + break; + case 64+22: + case 10*64+3: + case 10*64+33: + page=jacket_lookup[1][GET_SKILL(p_thing)>>2]; + break; + case 64+24: + case 10*64+4: + case 10*64+36: + page=jacket_lookup[2][GET_SKILL(p_thing)>>2]; + break; + case 64+25: + case 10*64+5: + case 10*64+37: + page=jacket_lookup[3][GET_SKILL(p_thing)>>2]; + break; + default: +// ASSERT(0); + break; + } + page+=FACE_PAGE_OFFSET; + } + else + + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) +// if(alt_texture[page-512]&&page<1024) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + +#ifndef TARGET_DC + extern UBYTE sw_hack; +#endif + + PolyPage *pa = &(POLY_Page[page]); +#if USE_TOMS_ENGINE_PLEASE_BOB + if ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) ) + { + // Do an immediate render, not a deferred one. + + // + // and render the polygons + // + +#if 0 + WORD wIndices[6] = {0,1,2,2,1,3}; + D3DTLVERTEX tlVertex[4]; + for ( int i = 0; i < 4; i++ ) + { + tlVertex[i].dvSX = quad[i]->X * PolyPage::s_XScale; + tlVertex[i].dvSY = quad[i]->Y * PolyPage::s_YScale; + tlVertex[i].dvSZ = 1.0f - quad[i]->Z; + tlVertex[i].dvTU = quad[i]->u; + tlVertex[i].dvTV = quad[i]->v; + tlVertex[i].dcColor = quad[i]->colour; + tlVertex[i].dcSpecular = quad[i]->specular; + tlVertex[i].dvRHW = quad[i]->Z; + } + + HRESULT hres; + + if (FALSE && the_display.GetDeviceInfo()->AdamiLightingSupported()) + { + // Draw lighting triangle + PolyPage *tpa = &(POLY_Page[POLY_PAGE_COLOUR]); + //tpa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + tpa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, tlVertex, 4, wIndices, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetChanged(); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, tlVertex, 4, wIndices, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); +#else + + static iCount = 0; + + if ( FALSE ) + { + + // LVertex. + WORD wIndices[6] = {0,1,2,2,1,3}; + D3DLVERTEX lVertex[4]; + for ( int i = 0; i < 4; i++ ) + { + + int pt = p_f4->Points[i]; + ASSERT(WITHIN(pt, sp, ep)); + lVertex[i].dvX = AENG_dx_prim_points[pt].X; + lVertex[i].dvY = AENG_dx_prim_points[pt].Y; + lVertex[i].dvZ = AENG_dx_prim_points[pt].Z; + lVertex[i].dvTU = quad[i]->u; + lVertex[i].dvTV = quad[i]->v; + lVertex[i].dcColor = quad[i]->colour; + lVertex[i].dcSpecular = quad[i]->specular; + } + + HRESULT hres; + + if (FALSE && the_display.GetDeviceInfo()->AdamiLightingSupported()) + { + // Draw lighting triangle + PolyPage *tpa = &(POLY_Page[POLY_PAGE_COLOUR]); + tpa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + tpa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_LVERTEX, lVertex, 4, wIndices, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_LVERTEX, lVertex, 4, wIndices, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } +#ifdef TARGET_DC + else + { + + // Use the MM stuff. + + // Unlit untransformed vertices! + WORD wIndices[5] = {0,1,2,3,-1}; + for ( int i = 0; i < 4; i++ ) + { + const float fNormScale = 1.0f / 256.0f; + + int pt = p_f4->Points[i]; + ASSERT(WITHIN(pt, sp, ep)); + + MM_Vertex[i].dvX = AENG_dx_prim_points[pt].X; + MM_Vertex[i].dvY = AENG_dx_prim_points[pt].Y; + MM_Vertex[i].dvZ = AENG_dx_prim_points[pt].Z; + MM_Vertex[i].dvNX = prim_normal[pt].X * fNormScale; + MM_Vertex[i].dvNY = prim_normal[pt].Y * fNormScale; + MM_Vertex[i].dvNZ = prim_normal[pt].Z * fNormScale; + MM_Vertex[i].dvTU = quad[i]->u; + MM_Vertex[i].dvTV = quad[i]->v; + // This must be done after setting the rest up, since it blats the 12th byte of the vertex. + SET_MM_INDEX ( (MM_Vertex[i]), 0 ); + } + +#if 0 + if ( FALSE && the_display.GetDeviceInfo()->AdamiLightingSupported() ) + { + // Draw lighting triangle + PolyPage *tpa = &(POLY_Page[POLY_PAGE_COLOUR]); + //tpa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + tpa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, MM_Vertex, 3, wIndices, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } +#endif + + D3DMULTIMATRIX d3dmm; + d3dmm.lpd3dMatrices = MM_pMatrix; + d3dmm.lpvLightDirs = MM_pNormal; + d3dmm.lpLightTable = MM_pcFadeTable; + d3dmm.lpvVertices = MM_Vertex; + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetChanged(); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, (void *)&d3dmm, 4, wIndices, 5, D3DDP_MULTIMATRIX ); + ASSERT ( SUCCEEDED ( hres ) ); + + + + } +#endif +#endif + } + else +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + { + if (FIGURE_alpha != 255) + { + POLY_Page[page].RS.SetTempTransparent(); + } + #ifndef TARGET_DC + else if (the_display.GetDeviceInfo()->AdamiLightingSupported() && !sw_hack) + #else + else if (the_display.GetDeviceInfo()->AdamiLightingSupported()) + #endif + { + // draw lighting quad + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + + // draw texture quad + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + + if (p_f4->FaceFlags & FACE_FLAG_TINT) + { + quad[0]->colour = qc0; + quad[1]->colour = qc1; + quad[2]->colour = qc2; + quad[3]->colour = qc3; + } + } + else + { + #if 0 + + // + // The colour of the face. + // + + r = ENGINE_palette[p_f4->Col2].red; + g = ENGINE_palette[p_f4->Col2].green; + b = ENGINE_palette[p_f4->Col2].blue; + + r = r * red >> 8; + g = g * green >> 8; + b = b * blue >> 8; + + face_colour = (r << 16) | (g << 8) | (b << 0); +#ifdef TARGET_DC + face_colour |= 0xff000000; +#endif + + quad[0]->colour = face_colour; + quad[1]->colour = face_colour; + quad[2]->colour = face_colour; + quad[3]->colour = face_colour; + + if (FIGURE_alpha != 255) + { + ASSERT(0); + } + + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + +#ifdef TARGET_DC + colour |= 0xff000000; +#endif + quad[0]->colour = colour; + quad[1]->colour = colour; + quad[2]->colour = colour; + quad[3]->colour = colour; + + #endif + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + +/* + p_f3->Bright[0]=store_dprod[p0]; + p_f3->Bright[1]=store_dprod[p1]; + p_f3->Bright[2]=store_dprod[p2]; +*/ + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + if (p_f3->DrawFlags & POLY_FLAG_TEXTURED) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + if (p_f3->FaceFlags & FACE_FLAG_TINT) + { + qc0 = tri[0]->colour; + qc1 = tri[1]->colour; + qc2 = tri[2]->colour; + + tri[0]->colour &= colour_and; + tri[1]->colour &= colour_and; + tri[2]->colour &= colour_and; + } + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + if(p_f3->FaceFlags&FACE_FLAG_THUG_JACKET) + { + switch(page) + { + case 64+21: + case 10*64+2: + case 10*64+32: + page=jacket_lookup[0][GET_SKILL(p_thing)>>2]; + break; + case 64+22: + case 10*64+3: + case 10*64+33: + page=jacket_lookup[1][GET_SKILL(p_thing)>>2]; + break; + case 64+24: + case 10*64+4: + case 10*64+36: + page=jacket_lookup[2][GET_SKILL(p_thing)>>2]; + break; + case 64+25: + case 10*64+5: + case 10*64+37: + page=jacket_lookup[3][GET_SKILL(p_thing)>>2]; + break; + default: +// ASSERT(0); + break; + } + page+=FACE_PAGE_OFFSET; + } + else + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + //ASSERT(TEXTURE_dontexist[page]==0); + +#ifndef TARGET_DC + extern UBYTE sw_hack; +#endif + + + + PolyPage *pa = &(POLY_Page[page]); + +#if USE_TOMS_ENGINE_PLEASE_BOB + if ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) ) + { + // Do an immediate render, not a deferred one. + + // + // and render the polygons + // + +#if 0 + // TLVERTEX stuff. + WORD wIndices[3] = {0,1,2}; + D3DTLVERTEX tlVertex[3]; + bool bBinned = FALSE; + for ( int i = 0; i < 3; i++ ) + { + tlVertex[i].dvSX = tri[i]->X * PolyPage::s_XScale; + tlVertex[i].dvSY = tri[i]->Y * PolyPage::s_YScale; + tlVertex[i].dvSZ = 1.0f - tri[i]->Z; + tlVertex[i].dvTU = tri[i]->u; + tlVertex[i].dvTV = tri[i]->v; + tlVertex[i].dcColor = tri[i]->colour; + tlVertex[i].dcSpecular = tri[i]->specular; + tlVertex[i].dvRHW = tri[i]->Z; + + if ( ( tri[i]->Z <= 0.0f ) || ( tri[i]->Z >= 1.0f ) ) + { + bBinned = TRUE; + } + } + + if ( !bBinned ) + { + HRESULT hres; + + if ( FALSE && the_display.GetDeviceInfo()->AdamiLightingSupported()) + { + // Draw lighting triangle + PolyPage *tpa = &(POLY_Page[POLY_PAGE_COLOUR]); + //tpa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + tpa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, tlVertex, 3, wIndices, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, tlVertex, 3, wIndices, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } +#else + + static int iCount = 0; + if ( FALSE ) + { + // LVertex. + WORD wIndices[3] = {0,1,2}; + D3DLVERTEX lVertex[3]; + for ( int i = 0; i < 3; i++ ) + { + + int pt = p_f3->Points[i]; + ASSERT(WITHIN(pt, sp, ep)); + + lVertex[i].dvX = AENG_dx_prim_points[pt].X; + lVertex[i].dvY = AENG_dx_prim_points[pt].Y; + lVertex[i].dvZ = AENG_dx_prim_points[pt].Z; + lVertex[i].dvTU = tri[i]->u; + lVertex[i].dvTV = tri[i]->v; + lVertex[i].dcColor = tri[i]->colour; + lVertex[i].dcSpecular = tri[i]->specular; + } + //lVertex[2].dcColor = ( ( lVertex[2].dcColor + 0x00400000 ) & 0x00ff0000 ) | ( lVertex[2].dcColor & ~0x00ff0000 ); + + HRESULT hres; + + if ( FALSE && the_display.GetDeviceInfo()->AdamiLightingSupported()) + { + // Draw lighting triangle + PolyPage *tpa = &(POLY_Page[POLY_PAGE_COLOUR]); + //tpa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + tpa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_LVERTEX, lVertex, 3, wIndices, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_LVERTEX, lVertex, 3, wIndices, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } +#ifdef TARGET_DC + else + { + + + // Use the MM stuff. + + // Unlit untransformed vertices! + WORD wIndices[4] = {0,1,2,-1}; + for ( int i = 0; i < 3; i++ ) + { + const float fNormScale = 1.0f / 256.0f; + + int pt = p_f3->Points[i]; + ASSERT(WITHIN(pt, sp, ep)); + + MM_Vertex[i].dvX = AENG_dx_prim_points[pt].X; + MM_Vertex[i].dvY = AENG_dx_prim_points[pt].Y; + MM_Vertex[i].dvZ = AENG_dx_prim_points[pt].Z; + MM_Vertex[i].dvNX = prim_normal[pt].X * fNormScale; + MM_Vertex[i].dvNY = prim_normal[pt].Y * fNormScale; + MM_Vertex[i].dvNZ = prim_normal[pt].Z * fNormScale; + MM_Vertex[i].dvTU = tri[i]->u; + MM_Vertex[i].dvTV = tri[i]->v; + // This must be done after setting the rest up, since it blats the 12th byte of the vertex. + SET_MM_INDEX ( (MM_Vertex[i]), 0 ); + } + +#if 0 + if ( FALSE && the_display.GetDeviceInfo()->AdamiLightingSupported() ) + { + // Draw lighting triangle + PolyPage *tpa = &(POLY_Page[POLY_PAGE_COLOUR]); + //tpa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + tpa->RS.SetChanged(); + hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, MM_Vertex, 3, wIndices, 3, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT ); + } +#endif + + D3DMULTIMATRIX d3dmm; + d3dmm.lpd3dMatrices = MM_pMatrix; + d3dmm.lpvLightDirs = MM_pNormal; + d3dmm.lpLightTable = MM_pcFadeTable; + d3dmm.lpvVertices = MM_Vertex; + + //pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetChanged(); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, (void *)&d3dmm, 3, wIndices, 4, D3DDP_MULTIMATRIX ); + ASSERT ( SUCCEEDED ( hres ) ); + + } +#endif +#endif + } + else + +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + { + if (FIGURE_alpha != 255) + { + POLY_Page[page].RS.SetTempTransparent(); + } + + + #ifndef TARGET_DC + else if (the_display.GetDeviceInfo()->AdamiLightingSupported() && !sw_hack) + #else + else if (the_display.GetDeviceInfo()->AdamiLightingSupported()) + #endif + { + // add lighting triangle + POLY_add_triangle(tri, POLY_PAGE_COLOUR, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + + + if (p_f3->FaceFlags & FACE_FLAG_TINT) + { + tri[0]->colour = qc0; + tri[1]->colour = qc1; + tri[2]->colour = qc2; + } + } + else + { + #if 0 + + // + // The colour of the face. + // + + r = ENGINE_palette[p_f3->Col2].red; + g = ENGINE_palette[p_f3->Col2].green; + b = ENGINE_palette[p_f3->Col2].blue; + + r = r * red >> 8; + g = g * green >> 8; + b = b * blue >> 8; + + face_colour = (r << 16) | (g << 8) | (b << 0); + + tri[0]->colour = face_colour; + tri[1]->colour = face_colour; + tri[2]->colour = face_colour; + + if (FIGURE_alpha != 255) + { + ASSERT(0); + } + + POLY_add_triangle(tri, POLY_PAGE_COLOUR, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + + tri[0]->colour = colour; + tri[1]->colour = colour; + tri[2]->colour = colour; + + #endif + } + } + } +#endif //#else //#if USE_TOMS_ENGINE_PLEASE_BOB + + +#if USE_TOMS_ENGINE_PLEASE_BOB + // Not done yet. +#else //#if USE_TOMS_ENGINE_PLEASE_BOB + + // + // Environment mapping! + // + + if (p_thing && p_thing->Class == CLASS_VEHICLE) + { + float nx; + float ny; + float nz; + + float dx; + float dy; + float dz; + + float comb[9]; + float cam_matrix[9]; + + SLONG num_points = ep - sp; + + extern float AENG_cam_yaw; + extern float AENG_cam_pitch; + extern float AENG_cam_roll; + + MATRIX_calc(cam_matrix, AENG_cam_yaw, AENG_cam_pitch, AENG_cam_roll); + MATRIX_3x3mul(comb, cam_matrix, fmatrix); + + // + // Environment map the van. Work out the uv coords at all the points. + // + + for (i = 0; i < num_points; i++) + { + nx = prim_normal[sp + i].X * (2.0F / 256.0F); + ny = prim_normal[sp + i].Y * (2.0F / 256.0F); + nz = prim_normal[sp + i].Z * (2.0F / 256.0F); + + MATRIX_MUL( + comb, + nx, + ny, + nz); + + dx = POLY_buffer[i].x; + dy = POLY_buffer[i].y; + dz = POLY_buffer[i].z; + + POLY_buffer[i].u = (nx * 0.5F) + 0.5F; + POLY_buffer[i].v = (ny * 0.5F) + 0.5F; + + POLY_buffer[i].colour = 0xff888888; + } + + // + // Add the triangles and quads. + // + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + if (p_f4->FaceFlags & (FACE_FLAG_ENVMAP|FACE_FLAG_TINT)) + { + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + if ((p_f4->FaceFlags & (FACE_FLAG_ENVMAP|FACE_FLAG_TINT)) == (FACE_FLAG_ENVMAP|FACE_FLAG_TINT)) + { + page = POLY_PAGE_WINMAP; + } + else + { + page = POLY_PAGE_ENVMAP; + } + + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + if (p_f3->FaceFlags & (FACE_FLAG_ENVMAP|FACE_FLAG_TINT)) + { + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + if ((p_f3->FaceFlags & (FACE_FLAG_ENVMAP|FACE_FLAG_TINT)) == (FACE_FLAG_ENVMAP|FACE_FLAG_TINT)) + { + page = POLY_PAGE_WINMAP; + } + else + { + page = POLY_PAGE_ENVMAP; + } + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + } +#endif //#else //#if USE_TOMS_ENGINE_PLEASE_BOB + + +#if USE_TOMS_ENGINE_PLEASE_BOB + if ( !MM_bLightTableAlreadySetUp ) + { +#if 0 + // Clean up after ourselves. + MM_pcFadeTable = NULL; + MM_pcFadeTableTint = NULL; + MM_pMatrix = NULL; + MM_Vertex = NULL; + MM_pNormal = NULL; +#endif + } +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + + LOG_EXIT ( Figure_Draw_Prim_Tween ) + +} + +void FIGURE_draw_prim_tween_warped( + SLONG prim, + SLONG x, + SLONG y, + SLONG z, + SLONG tween, + struct GameKeyFrameElement *anim_info, + struct GameKeyFrameElement *anim_info_next, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + ULONG colour, + ULONG specular, + Thing *p_thing) +{ + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + ULONG red; + ULONG green; + ULONG blue; + ULONG r; + ULONG g; + ULONG b; + ULONG face_colour; + + SLONG page; + + Matrix31 offset; + Matrix33 mat2; + float local_mat[9]; + float angle,sint,cost,tmpx,tmpz; + + SVector temp; + SVector_F temp2; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + red = (colour >> 16) & 0xff; + green = (colour >> 8) & 0xff; + blue = (colour >> 0) & 0xff; + + // + // Matrix functions we use. + // + + void matrix_transform (Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_mult33 (Matrix33* result, Matrix33* mat1, Matrix33* mat2); + + offset.M[0] = anim_info->OffsetX + ((anim_info_next->OffsetX + off_dx - anim_info->OffsetX) * tween >> 8); + offset.M[1] = anim_info->OffsetY + ((anim_info_next->OffsetY + off_dy - anim_info->OffsetY) * tween >> 8); + offset.M[2] = anim_info->OffsetZ + ((anim_info_next->OffsetZ + off_dz - anim_info->OffsetZ) * tween >> 8); + + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + + SLONG character_scale = person_get_scale(p_thing); + + temp.X = (temp.X * character_scale) / 256; + temp.Y = (temp.Y * character_scale) / 256; + temp.Z = (temp.Z * character_scale) / 256; + + x += temp.X; + y += temp.Y; + z += temp.Z; + + // + // Create a temporary "tween" matrix between current and next + // + CMatrix33 m1, m2; + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + build_tween_matrix(&mat2, &m1, &m2, tween); + normalise_matrix(&mat2); + + mat2.M[0][0] = (mat2.M[0][0] * character_scale) / 256; + mat2.M[0][1] = (mat2.M[0][1] * character_scale) / 256; + mat2.M[0][2] = (mat2.M[0][2] * character_scale) / 256; + mat2.M[1][0] = (mat2.M[1][0] * character_scale) / 256; + mat2.M[1][1] = (mat2.M[1][1] * character_scale) / 256; + mat2.M[1][2] = (mat2.M[1][2] * character_scale) / 256; + mat2.M[2][0] = (mat2.M[2][0] * character_scale) / 256; + mat2.M[2][1] = (mat2.M[2][1] * character_scale) / 256; + mat2.M[2][2] = (mat2.M[2][2] * character_scale) / 256; + // + // Apply local rotation matrix to get mat_final that rotates + // the point into world space. + // +// matrix_mult33(&mat_final, rot_mat, &mat2); + // ^- we don't do this. + // instead we need to apply mat2 seperately, then apply the xform, then pass onwards + + // + // Do everything in floats. + // + + float off_x; + float off_y; + float off_z; + float fmatrix[9]; + + off_x = float(x); + off_y = float(y); + off_z = float(z); + + // scale! + + fmatrix[0] = float(rot_mat->M[0][0]) * (1.0F / 32768.0F); + fmatrix[1] = float(rot_mat->M[0][1]) * (1.0F / 32768.0F); + fmatrix[2] = float(rot_mat->M[0][2]) * (1.0F / 32768.0F); + fmatrix[3] = float(rot_mat->M[1][0]) * (1.0F / 32768.0F); + fmatrix[4] = float(rot_mat->M[1][1]) * (1.0F / 32768.0F); + fmatrix[5] = float(rot_mat->M[1][2]) * (1.0F / 32768.0F); + fmatrix[6] = float(rot_mat->M[2][0]) * (1.0F / 32768.0F); + fmatrix[7] = float(rot_mat->M[2][1]) * (1.0F / 32768.0F); + fmatrix[8] = float(rot_mat->M[2][2]) * (1.0F / 32768.0F); + + local_mat[0] = float(mat2.M[0][0]) * (1.0F / 32768.0F); + local_mat[1] = float(mat2.M[0][1]) * (1.0F / 32768.0F); + local_mat[2] = float(mat2.M[0][2]) * (1.0F / 32768.0F); + local_mat[3] = float(mat2.M[1][0]) * (1.0F / 32768.0F); + local_mat[4] = float(mat2.M[1][1]) * (1.0F / 32768.0F); + local_mat[5] = float(mat2.M[1][2]) * (1.0F / 32768.0F); + local_mat[6] = float(mat2.M[2][0]) * (1.0F / 32768.0F); + local_mat[7] = float(mat2.M[2][1]) * (1.0F / 32768.0F); + local_mat[8] = float(mat2.M[2][2]) * (1.0F / 32768.0F); + + POLY_set_local_rotation( + off_x, + off_y, + off_z, + fmatrix); + + // + // Rotate all the points into the POLY_buffer. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + POLY_buffer_upto = 0; + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + temp2=AENG_dx_prim_points[i]; + + +// temp2.X-=offset.M[0]; +// temp2.Y-=offset.M[1]; +// temp2.Z-=offset.M[2]; + + angle=(temp2.Z+offset.M[2])*2; + angle=angle*PI/180; + sint=sin(angle); + cost=cos(angle); + + tmpx = (temp2.X*cost)+(temp2.Z*sint); + tmpz =-(temp2.X*sint)+(temp2.Z*cost); + temp2.X=tmpx; temp2.Z=tmpz; + +// temp2.X+=offset.M[0]; +// temp2.Y+=offset.M[1]; +// temp2.Z+=offset.M[2]; + + + + + // apply the local (tweening) matrix + + MATRIX_MUL(local_mat,temp2.X,temp2.Y,temp2.Z); + + // do some testy gnasty warp effect + + //... +/* + angle=(temp2.Z+offset.M[2])*2; + angle=angle*PI/180; + sint=sin(angle); + cost=cos(angle); + + tmpx = (temp2.X*cost)+(temp2.Z*sint); + tmpz =-(temp2.X*sint)+(temp2.Z*cost); + temp2.X=tmpx; temp2.Z=tmpz; + */ + //temp2.X+=(temp2.Z-off_z)/4.0; + + + + // do the global matrix (ofs_x/y/z, rot_mat and camera) + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform_using_local_rotation(temp2.X, temp2.Y, temp2.Z, pp); + +#ifdef TARGET_DC + colour |= 0xff000000; +#endif + pp->colour = colour; +// use_global_cloud(&pp->colour); + pp->specular = specular; + } + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + if (p_f4->DrawFlags & POLY_FLAG_TEXTURED) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + page+=FACE_PAGE_OFFSET; + + + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + else + { + // + // The colour of the face. + // + + r = ENGINE_palette[p_f4->Col2].red; + g = ENGINE_palette[p_f4->Col2].green; + b = ENGINE_palette[p_f4->Col2].blue; + + r = r * red >> 8; + g = g * green >> 8; + b = b * blue >> 8; + + face_colour = (r << 16) | (g << 8) | (b << 0); + +#ifdef TARGET_DC + face_colour |= 0xff000000; + colour |= 0xff000000; +#endif + quad[0]->colour = face_colour; + quad[1]->colour = face_colour; + quad[2]->colour = face_colour; + quad[3]->colour = face_colour; + + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + + quad[0]->colour = colour; + quad[1]->colour = colour; + quad[2]->colour = colour; + quad[3]->colour = colour; + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + if (p_f3->DrawFlags & POLY_FLAG_TEXTURED) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + page+=FACE_PAGE_OFFSET; + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + else + { + // + // The colour of the face. + // + + r = ENGINE_palette[p_f3->Col2].red; + g = ENGINE_palette[p_f3->Col2].green; + b = ENGINE_palette[p_f3->Col2].blue; + + r = r * red >> 8; + g = g * green >> 8; + b = b * blue >> 8; + + face_colour = (r << 16) | (g << 8) | (b << 0); + +#ifdef TARGET_DC + face_colour |= 0xff000000; + colour |= 0xff000000; +#endif + tri[0]->colour = face_colour; + tri[1]->colour = face_colour; + tri[2]->colour = face_colour; + + POLY_add_triangle(tri, POLY_PAGE_COLOUR, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + + tri[0]->colour = colour; + tri[1]->colour = colour; + tri[2]->colour = colour; + } + } + } +} + +//************************************************************************************************* +//JCL - heirarchical bones drawing... + + +// global structure to prevent actual recursion... + +#define MAX_RECURSION 5 + +struct structFIGURE_dhpr_data +{ + SLONG start_object; + BodyDef *body_def; + Matrix31 *world_pos; + SLONG tween; + GameKeyFrameElement *ae1; + GameKeyFrameElement *ae2; + Matrix33 *world_mat; + Matrix33 *world_mat2; + SLONG dx; + SLONG dy; + SLONG dz; + ULONG colour; + ULONG specular; + BYTE bPersonType; + BYTE bPersonID; +} FIGURE_dhpr_data; + +#if 1 + +// Got to split this up - the compiler is getting very confused. +struct structFIGURE_dhpr_rdata1 +{ + SLONG part_number; + SLONG current_child_number; + CMatrix33 *parent_base_mat; + Matrix31 *parent_base_pos; + Matrix33 *parent_current_mat; + Matrix31 *parent_current_pos; + Matrix31 pos; + //Matrix31 end_pos; + //Matrix33 end_mat; + +} FIGURE_dhpr_rdata1[MAX_RECURSION]; + +struct structFIGURE_dhpr_rdata2 +{ + //SLONG part_number; + //SLONG current_child_number; + //CMatrix33 *parent_base_mat; + //Matrix31 *parent_base_pos; + //Matrix33 *parent_current_mat; + //Matrix31 *parent_current_pos; + //Matrix31 pos; + Matrix31 end_pos; + Matrix33 end_mat; + +} FIGURE_dhpr_rdata2[MAX_RECURSION]; + + +#else +struct +{ + SLONG part_number; + CMatrix33 *parent_base_mat; + Matrix31 *parent_base_pos; + Matrix33 *parent_current_mat; + Matrix31 *parent_current_pos; + Matrix33 end_mat; + Matrix31 end_pos; + Matrix31 pos; + + SLONG current_child_number; +} FIGURE_dhpr_rdata[MAX_RECURSION]; +#endif + + +#define PART_FACE 1 +#define PART_TROUSERS 2 +#define PART_JACKET 3 +#define PART_SHOES 4 +#define PART_PELVIS 5 +#define PART_HANDS 6 + +UBYTE part_type[]= +{ + 2,//5,//"pelvis", + 2,//"lfemur", + 2,//"ltibia", + 4,//"lfoot", + 3,//"torso", + 3,//"rhumorus", + 3,//"rradius", + 6,//"rhand", + 3,//"lhumorus", + 3,//"lradius", + 6,//"lhand", + 1,//"skull", + 2,//"rfemur", + 2,//"rtibia", + 4//"rfoot", +}; + + +ULONG local_seed; + +SLONG mandom(void) +{ + local_seed=local_seed*123456789+314159265; + + return(local_seed); + +} + +void local_set_seed(SLONG seed) +{ + seed=local_seed; +} + +ULONG jacket_col; +ULONG leg_col; + + + + + +#if 1 +// Optimised version + + +//volatile int m_iRecurseLevelDebugging; + + +// Set to 1 for the all-in-one method of drawing things. +#define DRAW_WHOLE_PERSON_AT_ONCE 1 + + + +#define MAX_NUM_BODY_PARTS_AT_ONCE 20 + + + +#if DRAW_WHOLE_PERSON_AT_ONCE +// Static arrays of the things we need for each part of the body. +ALIGNED_STATIC_ARRAY ( static D3DMATRIX *, MMBodyParts_pMatrix, MAX_NUM_BODY_PARTS_AT_ONCE, D3DMATRIX, 32 ); +ALIGNED_STATIC_ARRAY ( static float *, MMBodyParts_pNormal, MAX_NUM_BODY_PARTS_AT_ONCE*4, float, 8 ); + +void FIGURE_draw_hierarchical_prim_recurse_individual_cull ( Thing *p_person ); +#endif + + +#if DRAW_WHOLE_PERSON_AT_ONCE +void FIGURE_draw_hierarchical_prim_recurse(Thing *p_person) +{ + SLONG recurse_level = 0; + SLONG dx,dy,dz; + UWORD f1,f2; + SLONG civ_flag=0,legs,body,shoes,face,hands,pelvis; + //SLONG limb; + struct Matrix33 *rot_mat; + + + LOG_ENTER ( Figure_Draw_Hierarchical ) + + +#ifdef HIGH_REZ_PEOPLE_PLEASE_BOB + // Do I need to toggle inflation? +extern int g_iCheatNumber; + // Well, 0x10f1a7e sort of spells "inflate" :-) + if ( g_iCheatNumber == 0x10f1a7e ) + { + if ( m_bPleaseInflatePeople ) + { + CONSOLE_text("Looks like the inflation is wearing off now D'arci."); + m_bPleaseInflatePeople = FALSE; + } + else + { + CONSOLE_text("The Illinois Enema Bandit has inflated everyone D'arci!"); + m_bPleaseInflatePeople = TRUE; + } + // And rebuild all prims. + FIGURE_clean_all_LRU_slots(); + g_iCheatNumber = 0; + } +#endif + + + f1=p_person->Draw.Tweened->CurrentFrame->Flags; + f2=p_person->Draw.Tweened->NextFrame->Flags; + + dx=((f1&0xe)<<(28))>>21; + dx-=((f2&0xe)<<(28))>>21; + + dy=((f1&0xff00)<<(16))>>16; + dy-=((f2&0xff00)<<(16))>>16; + + dz=((f1&0x70)<<(25))>>21; + dz-=((f1&0x70)<<(25))>>21; + + + ASSERT(p_person->Class == CLASS_PERSON); + + // Find the first "base" prim number and see if it's been created yet. + // Eek - just thought - I hope none of these people share body parts, or it'll get very messy. + // I should put some sort of ASSERT in to check that. + + // Ah - Mike thinks they probably do share stuff. Nads. Well, I only have a small cache, so I can just + // do a brute-force search through it by body_def I guess. Or maybe just an array again. + + ASSERT ( recurse_level == 0 ); + ASSERT ( FIGURE_dhpr_rdata1[0].current_child_number == 0 ); + + + // Make the index of the thing. + int iIndex = (int)( FIGURE_dhpr_data.bPersonType ); + ASSERT ( FIGURE_dhpr_data.bPersonType >= 0 ); + ASSERT ( FIGURE_dhpr_data.bPersonType < PERSON_NUM_TYPES ); + if ( FIGURE_dhpr_data.bPersonType == PERSON_CIV ) + { + // Some variation of civs is done by using bPersonID. + iIndex = (int)( FIGURE_dhpr_data.bPersonID & 0x1f ) + PERSON_NUM_TYPES; + } + else if ( FIGURE_dhpr_data.bPersonType == PERSON_ROPER ) + { + // Treat each version of Roper (with each type of weapon) as a separate mesh, since + // his weapons are not done the same as Darci or Mako. Hope this works. + + // Should be only 6 weapons: none, knife, bat, M16, pistols, shotty. Grenades are done a different way. + // But "weapon" eight is his hip-flask, which he drinks from occasionally. + ASSERT ( ( FIGURE_dhpr_data.bPersonID >> 5 ) < NUM_ROPERS_THINGIES ); + + iIndex = (int)( FIGURE_dhpr_data.bPersonID >> 5 ) + PERSON_NUM_TYPES + 32; + } + + + // Save this for possible restoration later. + structFIGURE_dhpr_rdata1 FIGURE_dhpr_rdata1_0_copy = FIGURE_dhpr_rdata1[0]; + structFIGURE_dhpr_data FIGURE_dhpr_data_copy = FIGURE_dhpr_data_copy; + + + ASSERT ( iIndex < MAX_NUMBER_D3D_PEOPLE ); + ASSERT ( ( PERSON_NUM_TYPES + 32 + NUM_ROPERS_THINGIES ) <= MAX_NUMBER_D3D_PEOPLE ); + TomsPrimObject *pPrimObj = &(D3DPeopleObj[iIndex]); + if ( pPrimObj->wNumMaterials == 0 ) + { + // Meshes have not been created yet - do so. + + // Set up the object. +#if 0 + // Use thrash slot 1 because the gun may bump it out later if it's + // in slot 0! + FIGURE_TPO_init_3d_object ( pPrimObj, 1 ); +#else + FIGURE_TPO_init_3d_object ( pPrimObj ); +#endif + int iTPOPartNumber = 0; + + + + recurse_level = 0; + while (recurse_level >= 0) + { + //m_iRecurseLevelDebugging = recurse_level; + structFIGURE_dhpr_rdata1 *pDHPR1 = FIGURE_dhpr_rdata1 + recurse_level; + int iPartNumber = pDHPR1->part_number; + if (pDHPR1->current_child_number == 0) + { + SLONG body_part; + // draw this level. + + ASSERT ( iPartNumber >= 0 ); + ASSERT ( iPartNumber <= 14 ); + + body_part=FIGURE_dhpr_data.body_def->BodyPart[iPartNumber]; + + // Draw thing with: + SLONG prim = FIGURE_dhpr_data.start_object + body_part; + + // Add this prim to it. + PrimObject *p_obj = &prim_objects[prim]; + //FIGURE_TPO_add_prim_to_current_object ( p_obj, iTPOPartNumber ); + FIGURE_TPO_add_prim_to_current_object ( prim, iTPOPartNumber ); + iTPOPartNumber++; + + + + // Then draw the weapon & muzzle flash if present. However, these are + // not part of the compiled person - they will be drawn individually + // after drawing the person. + } + + // and do children + + if (body_part_children[iPartNumber][pDHPR1->current_child_number] != -1) + { + // Broken up, or the compiler gets very confused. + structFIGURE_dhpr_rdata1 *pDHPR1Inc = FIGURE_dhpr_rdata1 + recurse_level + 1; + + pDHPR1Inc->current_child_number = 0; + + ASSERT ( iPartNumber >= 0 ); + ASSERT ( iPartNumber <= 14 ); + pDHPR1Inc->part_number = body_part_children[iPartNumber][pDHPR1->current_child_number]; + + pDHPR1Inc->current_child_number = 0; + + pDHPR1->current_child_number ++; + + + recurse_level ++; + } + else + { + recurse_level --; + } + } + +#if 0 + // Compile the whole object now. + FIGURE_TPO_finish_3d_object ( pPrimObj ); +#else + // Compile the whole object now. + // Use thrash slot 1 because the gun may bump it out later if it's + // in slot 0! + FIGURE_TPO_finish_3d_object ( pPrimObj, 1 ); +#endif + + // Restore the saved data. + FIGURE_dhpr_rdata1[0] = FIGURE_dhpr_rdata1_0_copy; + FIGURE_dhpr_data_copy = FIGURE_dhpr_data_copy; + + + } + + + + // Gets pre-incremented to 0 before use. + int iTPOPartNumber = -1; + bool bWholePersonVisible = TRUE; + bool bBitsOfPersonVisible = FALSE; + + + recurse_level = 0; + while (recurse_level >= 0) + { + + //m_iRecurseLevelDebugging = recurse_level; + structFIGURE_dhpr_rdata1 *pDHPR1 = FIGURE_dhpr_rdata1 + recurse_level; + int iPartNumber = pDHPR1->part_number; + + if (pDHPR1->current_child_number == 0) + { + { + SLONG body_part; + SLONG id; + // draw this level. + + ASSERT ( iPartNumber >= 0 ); + ASSERT ( iPartNumber <= 14 ); + + + //limb=part_type[iPartNumber]; + + + body_part=FIGURE_dhpr_data.body_def->BodyPart[iPartNumber]; + rot_mat=FIGURE_dhpr_data.world_mat; + + iTPOPartNumber++; + ASSERT ( iTPOPartNumber < MAX_NUM_BODY_PARTS_AT_ONCE ); + bool bVisible = FIGURE_draw_prim_tween_person_only_just_set_matrix ( + iTPOPartNumber, + FIGURE_dhpr_data.start_object + body_part, + rot_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + recurse_level, + p_person + ); + + bWholePersonVisible &= bVisible; + bBitsOfPersonVisible |= bVisible; + +// +// draw a weapon in hand +// + if(p_person->Genus.Person->PersonType!=PERSON_ROPER) + if((id=(p_person->Draw.Tweened->PersonID>>5))) + { + + SLONG hand; + if(id==2) + hand=SUB_OBJECT_RIGHT_HAND; + else + hand=SUB_OBJECT_LEFT_HAND; + + if(iPartNumber==hand) + { + if(p_person->Draw.Tweened->Flags&DT_FLAG_GUNFLASH) + { + SLONG prim; + bool bDrawMuzzleFlash = FALSE; + p_person->Draw.Tweened->Flags&=~DT_FLAG_GUNFLASH; + switch(p_person->Draw.Tweened->PersonID>>5) + { + case 1: // Pistol + prim = 261; + bDrawMuzzleFlash = TRUE; + break; + + case 3: // Shotgun + prim = 262; + bDrawMuzzleFlash = TRUE; + break; + + case 5: // AK + prim = 263; + bDrawMuzzleFlash = TRUE; + break; + + default: + break; + } + + // Why does the DC hate GOTOs so much. + if ( bDrawMuzzleFlash ) + { +#if 0 + FIGURE_draw_prim_tween( prim, + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); +#else + // Muzzle flashes are always drawn "normally" + FIGURE_draw_prim_tween_person_only( + prim, + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + recurse_level, + p_person + ); +#endif + } + } + + +#if 0 + FIGURE_draw_prim_tween( + 255+(p_person->Draw.Tweened->PersonID>>5), + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); +#else + // Weapons are always drawn "normally" + FIGURE_draw_prim_tween_person_only( + 255+(p_person->Draw.Tweened->PersonID>>5), + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + recurse_level, + p_person + ); +#endif + + } + + } + } + } + + // and do children + + if (body_part_children[iPartNumber][pDHPR1->current_child_number] != -1) + { + + // Broken up, or the compiler gets very confused. + //structFIGURE_dhpr_rdata1 *pDHPR1 = FIGURE_dhpr_rdata1 + recurse_level; + structFIGURE_dhpr_rdata1 *pDHPR1Inc = FIGURE_dhpr_rdata1 + recurse_level + 1; + + pDHPR1Inc->current_child_number = 0; + + // really only need to do these next 3 lines once... + pDHPR1->pos.M[0] = FIGURE_dhpr_data.ae1[iPartNumber].OffsetX; + pDHPR1->pos.M[1] = FIGURE_dhpr_data.ae1[iPartNumber].OffsetY; + pDHPR1->pos.M[2] = FIGURE_dhpr_data.ae1[iPartNumber].OffsetZ; + + ASSERT ( iPartNumber >= 0 ); + ASSERT ( iPartNumber <= 14 ); + pDHPR1Inc->part_number = body_part_children[iPartNumber][pDHPR1->current_child_number]; + CMatrix33 tmat; + GetCMatrix(&FIGURE_dhpr_data.ae1[iPartNumber], &tmat); + pDHPR1Inc->parent_base_mat = &tmat; + pDHPR1Inc->parent_base_pos = &(pDHPR1->pos); + pDHPR1Inc->parent_current_mat = &FIGURE_dhpr_rdata2[recurse_level].end_mat; + pDHPR1Inc->parent_current_pos = &FIGURE_dhpr_rdata2[recurse_level].end_pos; + pDHPR1Inc->current_child_number = 0; + + pDHPR1->current_child_number ++; + recurse_level ++; + } + else + { + recurse_level --; + } + }; + + + // And now draw the whole person using the matrices and light vectors set up above. + + if ( !bWholePersonVisible ) + { + if ( bBitsOfPersonVisible ) + { + // Draw the person the slow way. + TRACE ( "Partial person drawn\n" ); + // Restore the saved data. + FIGURE_dhpr_rdata1[0] = FIGURE_dhpr_rdata1_0_copy; + FIGURE_dhpr_data_copy = FIGURE_dhpr_data_copy; + FIGURE_draw_hierarchical_prim_recurse_individual_cull ( p_person ); + } + else + { + // None of the person is visible. Don't draw anything. + //TRACE ( "Person not drawn\n" ); + } + return; + } + + //TRACE ( "Full person drawn\n" ); + + + // This many parts. + iTPOPartNumber++; + ASSERT ( iTPOPartNumber <= MAX_NUM_BODY_PARTS_AT_ONCE ); + + + + + SLONG face_colour; + + SLONG page; + + Matrix31 offset; + Matrix33 mat2; + Matrix33 mat_final; + + ULONG qc0; + ULONG qc1; + ULONG qc2; + ULONG qc3; + + SVector temp; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + NIGHT_Found *nf; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + SLONG tex_page_offset; + + + LOG_ENTER ( Figure_Draw_Prim_Tween ) + + tex_page_offset=p_person->Genus.Person->pcom_colour&0x3; + + +#if !USE_TOMS_ENGINE_PLEASE_BOB +#error Dont use this rout if USE_TOMS_ENGINE_PLEASE_BOB is not 1 +#endif + + + ASSERT ( MM_bLightTableAlreadySetUp ); + + + // The wonderful NEW system! + + + LOG_ENTER ( Figure_Draw_Polys ) + +#if 1 + // The MM stuff doesn't like specular to be enabled. + (the_display.lp_D3D_Device)->SetRenderState ( D3DRENDERSTATE_SPECULARENABLE, FALSE ); +#endif + + + // Tell the LRU cache we used this one. + FIGURE_touch_LRU_of_object ( pPrimObj ); + + + ASSERT ( pPrimObj->pD3DVertices != NULL ); + ASSERT ( pPrimObj->pMaterials != NULL ); + ASSERT ( pPrimObj->pwListIndices != NULL ); + ASSERT ( pPrimObj->pwStripIndices != NULL ); + ASSERT ( pPrimObj->wNumMaterials != 0 ); + + PrimObjectMaterial *pMat = pPrimObj->pMaterials; + + D3DMULTIMATRIX d3dmm; + d3dmm.lpd3dMatrices = MMBodyParts_pMatrix; + d3dmm.lpvLightDirs = MMBodyParts_pNormal; + + + D3DVERTEX *pVertex = (D3DVERTEX *)pPrimObj->pD3DVertices; + UWORD *pwListIndices = pPrimObj->pwListIndices; + UWORD *pwStripIndices = pPrimObj->pwStripIndices; + for ( int iMatNum = pPrimObj->wNumMaterials; iMatNum > 0; iMatNum-- ) + { + // Set up the right texture for this material. + + UWORD wPage = pMat->wTexturePage; + UWORD wRealPage = wPage & TEXTURE_PAGE_MASK; + + if ( wPage & TEXTURE_PAGE_FLAG_JACKET ) + { + // Find the real jacket page. + wRealPage = jacket_lookup [ wRealPage ][GET_SKILL(p_person)>>2]; + wRealPage += FACE_PAGE_OFFSET; + } + else if ( wPage & TEXTURE_PAGE_FLAG_OFFSET ) + { + // An "offset" texture. This will be offset by a certain amount to + // allow each prim to have different coloured clothes on. + if ( tex_page_offset == 0 ) + { + // No lookup offset. + // This has not been offset yet. + wRealPage += FACE_PAGE_OFFSET; + } + else + { + // Look this up. + wRealPage = alt_texture[wRealPage-(10*64)]+tex_page_offset-1; + } + } + +#ifdef DEBUG + if ( wPage & TEXTURE_PAGE_FLAG_NOT_TEXTURED ) + { + ASSERT ( wRealPage == POLY_PAGE_COLOUR ); + } +#endif + +extern D3DMATRIX g_matWorld; + + PolyPage *pa = &(POLY_Page[wRealPage]); +#if 0 + // Near-plane culling! Must implement! + + // Not sure if I'm using character_scalef correctly... + ASSERT ( ( character_scalef < 1.2f ) && ( character_scalef > 0.8f ) ); + ASSERT ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) ); + if ( ( ( ( g_matWorld._43 * 32768.0f ) - ( pPrimObj->fBoundingSphereRadius * character_scalef ) ) > ( POLY_ZCLIP_PLANE * 32768.0f ) ) ) +#endif + { + // Non-alpha path. + if ( wPage & TEXTURE_PAGE_FLAG_TINT ) + { + // Tinted colours. + d3dmm.lpLightTable = MM_pcFadeTableTint; + } + else + { + // Normal. + d3dmm.lpLightTable = MM_pcFadeTable; + } + d3dmm.lpvVertices = pVertex; + + +#if 1 + + + +#ifdef DEBUG +static int iCounter = 0; + if ( iCounter != 0 ) + { + iCounter--; + ASSERT ( iCounter != 0 ); + } +#endif + + // Fast as lightning. + LOG_ENTER ( Figure_Set_RenderState ) + pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + LOG_EXIT ( Figure_Set_RenderState ) + LOG_ENTER ( Figure_DrawIndPrimMM ) + + + HRESULT hres; + +#define SHOW_ME_FIGURE_DEBUGGING_PLEASE_BOB defined + +#ifdef SHOW_ME_FIGURE_DEBUGGING_PLEASE_BOB +#ifdef DEBUG +#ifdef TARGET_DC +#define BUTTON_IS_PRESSED(value) ((value&0x80)!=0) +extern DIJOYSTATE the_state; + bool bShowDebug = FALSE; + if ( BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_LTRIGGER] ) && BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_RTRIGGER] ) ) + { + DWORD dwColour = (DWORD)pwStripIndices; + dwColour = ( dwColour >> 2 ) ^ ( dwColour >> 6 ) ^ ( dwColour ) ^ ( dwColour << 3 ); + dwColour = ( dwColour << 9 ) ^ ( dwColour << 19 ) ^ ( dwColour ) ^ ( dwColour << 29 ) ^ ( dwColour >> 3 ); + dwColour &= 0x7f7f7f7f; + for ( int i = 0; i < 128; i++ ) + { + d3dmm.lpLightTable[i] = dwColour; + } + + // And NULL texture (i.e. white). + the_display.lp_D3D_Device->SetTexture ( 0, NULL ); + } +#endif +#endif +#endif + + + + //if (pMat->wNumVertices && + // pMat->wNumStripIndices) + { + //TRACE ( "S4" ); + hres = DrawIndPrimMM ( + (the_display.lp_D3D_Device), + D3DFVF_VERTEX, + &d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices ); + //TRACE ( "F4" ); + } + + + + +#else + + // Do some performance tracing. +#ifndef DTRACE +#error Don't use this codepath unless DTRACING, fool! +#endif + + LOG_ENTER ( Figure_Set_RenderState ) + pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + + WORD wTempVerts[4]; + wTempVerts[0] = 0; + wTempVerts[1] = 1; + wTempVerts[2] = 2; + wTempVerts[3] = -1; + (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + 3, + wTempVerts, + 4, + D3DDP_MULTIMATRIX ); + LOG_EXIT ( Figure_Set_RenderState ) + + LOG_ENTER ( Figure_DrawIndPrimMM ) + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); + //TRACE("Drew %i vertices, %i indices\n", (int)( pMat->wNumVertices ), (int)( pMat->wNumStripIndices ) ); + +#endif + +// ASSERT ( SUCCEEDED ( hres ) ); //triggers all the time when inside on start of RTA + LOG_EXIT ( Figure_DrawIndPrimMM ) + + } +#if 0 + else + { + // Alpha/clipped path - do with standard non-MM calls. + // FIXME. Needs to be done. + + // Actually, the fast-accept works very well, and it's only when the camera somehow gets REALLY close + // that this happens. And actually a pop-reject seems a bit better than a clip. Certainly + // there is no visually "right" thing to do. So leave it for now until someone complains. ATF. + //TRACE ( "Tried to draw an alpha/clipped prim!" ); + } +#endif + + + + // Next material + pVertex += pMat->wNumVertices; + pwListIndices += pMat->wNumListIndices; + pwStripIndices += pMat->wNumStripIndices; + + pMat++; + } + +#if 1 + // The MM stuff doesn't like specular to be enabled. + (the_display.lp_D3D_Device)->SetRenderState ( D3DRENDERSTATE_SPECULARENABLE, TRUE ); +#endif + + LOG_EXIT ( Figure_Draw_Polys ) + + + + // No environment mapping. + ASSERT ( p_person && ( p_person->Class != CLASS_VEHICLE ) ); + + ASSERT ( MM_bLightTableAlreadySetUp ); + + LOG_EXIT ( Figure_Draw_Prim_Tween ) + +#endif + + // Person drawn! + + LOG_EXIT ( Figure_Draw_Hierarchical ) + +} + + + + + + +// The slower version that can cull individual chunks. +#if DRAW_WHOLE_PERSON_AT_ONCE +void FIGURE_draw_hierarchical_prim_recurse_individual_cull ( Thing *p_person ) +#else +// There can be only one... +void FIGURE_draw_hierarchical_prim_recurse ( Thing *p_person ) +#endif +{ + SLONG recurse_level = 0; + SLONG dx,dy,dz; + UWORD f1,f2; + SLONG civ_flag=0,legs,body,shoes,face,hands,pelvis; + //SLONG limb; + struct Matrix33 *rot_mat; + + + LOG_ENTER ( Figure_Draw_Hierarchical ) + + +#ifdef HIGH_REZ_PEOPLE_PLEASE_BOB + // Do I need to toggle inflation? +extern int g_iCheatNumber; + // Well, 0x10f1a7e sort of spells "inflate" :-) + if ( g_iCheatNumber == 0x10f1a7e ) + { + if ( m_bPleaseInflatePeople ) + { + CONSOLE_text("Looks like the inflation is wearing off now D'arci."); + m_bPleaseInflatePeople = FALSE; + } + else + { + CONSOLE_text("The Illinois Enema Bandit has inflated everyone D'arci!"); + m_bPleaseInflatePeople = TRUE; + } + // And rebuild all prims. + FIGURE_clean_all_LRU_slots(); + g_iCheatNumber = 0; + } +#endif + + + f1=p_person->Draw.Tweened->CurrentFrame->Flags; + f2=p_person->Draw.Tweened->NextFrame->Flags; + + dx=((f1&0xe)<<(28))>>21; + dx-=((f2&0xe)<<(28))>>21; + + dy=((f1&0xff00)<<(16))>>16; + dy-=((f2&0xff00)<<(16))>>16; + + dz=((f1&0x70)<<(25))>>21; + dz-=((f1&0x70)<<(25))>>21; + + + ASSERT(p_person->Class == CLASS_PERSON); + + recurse_level = 0; + while (recurse_level >= 0) + { + + //m_iRecurseLevelDebugging = recurse_level; + structFIGURE_dhpr_rdata1 *pDHPR1 = FIGURE_dhpr_rdata1 + recurse_level; + int iPartNumber = pDHPR1->part_number; + + if (pDHPR1->current_child_number == 0) + { + { + SLONG body_part; + SLONG id; + // draw this level. + + ASSERT ( iPartNumber >= 0 ); + ASSERT ( iPartNumber <= 14 ); + + + //limb=part_type[iPartNumber]; + + + body_part=FIGURE_dhpr_data.body_def->BodyPart[iPartNumber]; + rot_mat=FIGURE_dhpr_data.world_mat; + +#if 0 + FIGURE_draw_prim_tween( FIGURE_dhpr_data.start_object + body_part, //FIGURE_dhpr_data.body_def->BodyPart[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[pDHPR1->part_number], + &FIGURE_dhpr_data.ae2[pDHPR1->part_number], + rot_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, //limb==PART_JACKET?jacket_col:(limb==PART_TROUSERS?leg_col:FIGURE_dhpr_data.colour), + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); +#else + FIGURE_draw_prim_tween_person_only ( + FIGURE_dhpr_data.start_object + body_part, //FIGURE_dhpr_data.body_def->BodyPart[FIGURE_dhpr_rdata1[recurse_level].part_number], + //FIGURE_dhpr_data.world_pos->M[0], + //FIGURE_dhpr_data.world_pos->M[1], + //FIGURE_dhpr_data.world_pos->M[2], + //FIGURE_dhpr_data.tween, + //&FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + //&FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + rot_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + //FIGURE_dhpr_data.colour, //limb==PART_JACKET?jacket_col:(limb==PART_TROUSERS?leg_col:FIGURE_dhpr_data.colour), + //FIGURE_dhpr_data.specular, + recurse_level, + //FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + //FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + //FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + //FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + //&FIGURE_dhpr_rdata2[recurse_level].end_mat, + //&FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person + //FIGURE_dhpr_rdata1[recurse_level].part_number + ); +#endif + +// +// draw a weapon in hand +// + if(p_person->Genus.Person->PersonType!=PERSON_ROPER) + if((id=(p_person->Draw.Tweened->PersonID>>5))) + { + + SLONG hand; + if(id==2) + hand=SUB_OBJECT_RIGHT_HAND; + else + hand=SUB_OBJECT_LEFT_HAND; + + if(iPartNumber==hand) + { + if(p_person->Draw.Tweened->Flags&DT_FLAG_GUNFLASH) + { + SLONG prim; + bool bDrawMuzzleFlash = FALSE; + p_person->Draw.Tweened->Flags&=~DT_FLAG_GUNFLASH; + switch(p_person->Draw.Tweened->PersonID>>5) + { + case 1: // Pistol + prim = 261; + bDrawMuzzleFlash = TRUE; + break; + + case 3: // Shotgun + prim = 262; + bDrawMuzzleFlash = TRUE; + break; + + case 5: // AK + prim = 263; + bDrawMuzzleFlash = TRUE; + break; + + default: + break; + } + + // Why does the DC hate GOTOs so much. + if ( bDrawMuzzleFlash ) + { +#if 0 + FIGURE_draw_prim_tween( prim, + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); +#else + // Muzzle flashes are always drawn "normally" + FIGURE_draw_prim_tween_person_only( + prim, + //FIGURE_dhpr_data.world_pos->M[0], + //FIGURE_dhpr_data.world_pos->M[1], + //FIGURE_dhpr_data.world_pos->M[2], + //FIGURE_dhpr_data.tween, + //&FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + //&FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + //FIGURE_dhpr_data.colour, + //FIGURE_dhpr_data.specular, + recurse_level, + //FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + //FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + //FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + //FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + //&FIGURE_dhpr_rdata2[recurse_level].end_mat, + //&FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person + //FIGURE_dhpr_rdata1[recurse_level].part_number + ); +#endif + } + } + + +#if 0 + FIGURE_draw_prim_tween( + 255+(p_person->Draw.Tweened->PersonID>>5), + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); +#else + // Weapons are always drawn "normally" + FIGURE_draw_prim_tween_person_only( + 255+(p_person->Draw.Tweened->PersonID>>5), + //FIGURE_dhpr_data.world_pos->M[0], + //FIGURE_dhpr_data.world_pos->M[1], + //FIGURE_dhpr_data.world_pos->M[2], + //FIGURE_dhpr_data.tween, + //&FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + //&FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + //FIGURE_dhpr_data.colour, + //FIGURE_dhpr_data.specular, + recurse_level, + //FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + //FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + //FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + //FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + //&FIGURE_dhpr_rdata2[recurse_level].end_mat, + //&FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person + //FIGURE_dhpr_rdata1[recurse_level].part_number + ); +#endif + + } + + } + } + } + + // and do children + + if (body_part_children[iPartNumber][pDHPR1->current_child_number] != -1) + { + +#if 0 + FIGURE_dhpr_rdata1[recurse_level + 1].current_child_number = 0; + + // really only need to do these next 3 lines once... + FIGURE_dhpr_rdata1[recurse_level].pos.M[0] = FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number].OffsetX; + FIGURE_dhpr_rdata1[recurse_level].pos.M[1] = FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number].OffsetY; + FIGURE_dhpr_rdata1[recurse_level].pos.M[2] = FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number].OffsetZ; + ASSERT ( FIGURE_dhpr_rdata1[recurse_level].part_number >= 0 ); + ASSERT ( FIGURE_dhpr_rdata1[recurse_level].part_number <= 14 ); + FIGURE_dhpr_rdata1[recurse_level + 1].part_number = body_part_children[FIGURE_dhpr_rdata1[recurse_level].part_number][FIGURE_dhpr_rdata1[recurse_level].current_child_number]; + CMatrix33 tmat; + GetCMatrix(&FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], &tmat); + FIGURE_dhpr_rdata1[recurse_level + 1].parent_base_mat = &tmat; + FIGURE_dhpr_rdata1[recurse_level + 1].parent_base_pos = &FIGURE_dhpr_rdata1[recurse_level].pos; + FIGURE_dhpr_rdata1[recurse_level + 1].parent_current_mat = &FIGURE_dhpr_rdata2[recurse_level].end_mat; + FIGURE_dhpr_rdata1[recurse_level + 1].parent_current_pos = &FIGURE_dhpr_rdata2[recurse_level].end_pos; + FIGURE_dhpr_rdata1[recurse_level + 1].current_child_number = 0; + + FIGURE_dhpr_rdata1[recurse_level].current_child_number ++ ; +#else + // Broken up, or the compiler gets very confused. + //structFIGURE_dhpr_rdata1 *pDHPR1 = FIGURE_dhpr_rdata1 + recurse_level; + structFIGURE_dhpr_rdata1 *pDHPR1Inc = FIGURE_dhpr_rdata1 + recurse_level + 1; + + pDHPR1Inc->current_child_number = 0; + + // really only need to do these next 3 lines once... + pDHPR1->pos.M[0] = FIGURE_dhpr_data.ae1[iPartNumber].OffsetX; + pDHPR1->pos.M[1] = FIGURE_dhpr_data.ae1[iPartNumber].OffsetY; + pDHPR1->pos.M[2] = FIGURE_dhpr_data.ae1[iPartNumber].OffsetZ; + + ASSERT ( iPartNumber >= 0 ); + ASSERT ( iPartNumber <= 14 ); + pDHPR1Inc->part_number = body_part_children[iPartNumber][pDHPR1->current_child_number]; + CMatrix33 tmat; + GetCMatrix(&FIGURE_dhpr_data.ae1[iPartNumber], &tmat); + pDHPR1Inc->parent_base_mat = &tmat; + pDHPR1Inc->parent_base_pos = &(pDHPR1->pos); + pDHPR1Inc->parent_current_mat = &FIGURE_dhpr_rdata2[recurse_level].end_mat; + pDHPR1Inc->parent_current_pos = &FIGURE_dhpr_rdata2[recurse_level].end_pos; + pDHPR1Inc->current_child_number = 0; + + pDHPR1->current_child_number ++; +#endif + recurse_level ++; + } + else + { + recurse_level --; + } + }; + + + // Person drawn! + + LOG_EXIT ( Figure_Draw_Hierarchical ) + +} + + + + +#else +// Old version +void FIGURE_draw_hierarchical_prim_recurse(Thing *p_person) +{ + SLONG recurse_level = 0; + SLONG dx,dy,dz; + UWORD f1,f2; + SLONG civ_flag=0,legs,body,shoes,face,hands,pelvis; + //SLONG limb; + struct Matrix33 *rot_mat; + + + + +#ifdef HIGH_REZ_PEOPLE_PLEASE_BOB + // Do I need to toggle inflation? +extern int g_iCheatNumber; + // Well, 0x10f1a7e sort of spells "inflate" :-) + if ( g_iCheatNumber == 0x10f1a7e ) + { + if ( m_bPleaseInflatePeople ) + { + CONSOLE_text("Looks like the inflation is wearing off now D'arci."); + m_bPleaseInflatePeople = FALSE; + } + else + { + CONSOLE_text("The Illinois Enema Bandit has inflated everyone D'arci!"); + m_bPleaseInflatePeople = TRUE; + } + // And rebuild all prims. + FIGURE_clean_all_LRU_slots(); + g_iCheatNumber = 0; + } +#endif + + + + + + LOG_ENTER ( Figure_Draw_Hierarchical ) + + f1=p_person->Draw.Tweened->CurrentFrame->Flags; + f2=p_person->Draw.Tweened->NextFrame->Flags; + + dx=((f1&0xe)<<(28))>>21; + dx-=((f2&0xe)<<(28))>>21; + + dy=((f1&0xff00)<<(16))>>16; + dy-=((f2&0xff00)<<(16))>>16; + + dz=((f1&0x70)<<(25))>>21; + dz-=((f1&0x70)<<(25))>>21; +/* + if(p_person->Genus.Person->PersonType==PERSON_CIV ||p_person->Genus.Person->PersonType==PERSON_CIV2) + { + local_set_seed(THING_NUMBER(p_person)); + legs=mandom()&3; + body=mandom()&3; + shoes=mandom()&3; + face=mandom()&3; + hands=mandom()&1; + pelvis=legs; //Random()&3; + if (GAME_FLAGS & GF_RAINING) + { + pelvis=(mandom()%3)+4; + body=pelvis; + } + + civ_flag=1; + + } +*/ + ASSERT(p_person->Class == CLASS_PERSON); + + while (recurse_level >= 0) + { + if (FIGURE_dhpr_rdata1[recurse_level].current_child_number == 0) + { + { + SLONG body_part; + SLONG id; + // draw this level. +/* + if(civ_flag) + { + switch(part_type[FIGURE_dhpr_rdata1[recurse_level].part_number]) + { + case PART_FACE: + body_part=face; + break; + case PART_HANDS: + body_part=hands; + break; + case PART_TROUSERS: + body_part=legs; + break; + case PART_JACKET: + body_part=body; + break; + case PART_SHOES: + body_part=shoes; + break; + case PART_PELVIS: + body_part=pelvis; + break; + default: + ASSERT(0); + break; + + } + body_part=0; + } + else + { + body_part=FIGURE_dhpr_data.body_def->BodyPart[FIGURE_dhpr_rdata1[recurse_level].part_number]; + } +*/ + //limb=part_type[FIGURE_dhpr_rdata1[recurse_level].part_number]; + + body_part=FIGURE_dhpr_data.body_def->BodyPart[FIGURE_dhpr_rdata1[recurse_level].part_number]; +/* if( (p_person->Flags&FLAGS_PERSON_AIM_AND_RUN) && body_part_upper[FIGURE_dhpr_rdata1[recurse_level].part_number]) + { + rot_mat=FIGURE_dhpr_data.world_mat2; + } + else +*/ + { + rot_mat=FIGURE_dhpr_data.world_mat; + } + + FIGURE_draw_prim_tween( FIGURE_dhpr_data.start_object + body_part, //FIGURE_dhpr_data.body_def->BodyPart[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + rot_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, //limb==PART_JACKET?jacket_col:(limb==PART_TROUSERS?leg_col:FIGURE_dhpr_data.colour), + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); + +// +// draw a weapon in hand +// + if(p_person->Genus.Person->PersonType!=PERSON_ROPER) + if((id=(p_person->Draw.Tweened->PersonID>>5))) + { + + SLONG hand; + if(id==2) + hand=SUB_OBJECT_RIGHT_HAND; + else + hand=SUB_OBJECT_LEFT_HAND; + + if(FIGURE_dhpr_rdata1[recurse_level].part_number==hand) + { + if(p_person->Draw.Tweened->Flags&DT_FLAG_GUNFLASH) + { + SLONG prim; + p_person->Draw.Tweened->Flags&=~DT_FLAG_GUNFLASH; + switch(p_person->Draw.Tweened->PersonID>>5) + { + case 1: // Pistol + prim = 261; + break; + + case 3: // Shotgun + prim = 262; + break; + + case 5: // AK + prim = 263; + break; + + default: + goto dont_draw_the_muzzle_flash; + break; + } + + FIGURE_draw_prim_tween( prim, + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); + + dont_draw_the_muzzle_flash:; + + } + + + FIGURE_draw_prim_tween( 255+(p_person->Draw.Tweened->PersonID>>5), + FIGURE_dhpr_data.world_pos->M[0], + FIGURE_dhpr_data.world_pos->M[1], + FIGURE_dhpr_data.world_pos->M[2], + FIGURE_dhpr_data.tween, + &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], + &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number], + FIGURE_dhpr_data.world_mat, + FIGURE_dhpr_data.dx+dx, + FIGURE_dhpr_data.dy+dy, + FIGURE_dhpr_data.dz+dz, + FIGURE_dhpr_data.colour, + FIGURE_dhpr_data.specular, + FIGURE_dhpr_rdata1[recurse_level].parent_base_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_base_pos, + FIGURE_dhpr_rdata1[recurse_level].parent_current_mat, + FIGURE_dhpr_rdata1[recurse_level].parent_current_pos, + &FIGURE_dhpr_rdata2[recurse_level].end_mat, + &FIGURE_dhpr_rdata2[recurse_level].end_pos, + p_person, + FIGURE_dhpr_rdata1[recurse_level].part_number); + + } + + } + } + } + + // and do children + + if (body_part_children[FIGURE_dhpr_rdata1[recurse_level].part_number][FIGURE_dhpr_rdata1[recurse_level].current_child_number] != -1) + { + FIGURE_dhpr_rdata1[recurse_level + 1].current_child_number = 0; + + // really only need to do these next 3 lines once... + FIGURE_dhpr_rdata1[recurse_level].pos.M[0] = FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number].OffsetX; + FIGURE_dhpr_rdata1[recurse_level].pos.M[1] = FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number].OffsetY; + FIGURE_dhpr_rdata1[recurse_level].pos.M[2] = FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number].OffsetZ; + + FIGURE_dhpr_rdata1[recurse_level + 1].part_number = body_part_children[FIGURE_dhpr_rdata1[recurse_level].part_number][FIGURE_dhpr_rdata1[recurse_level].current_child_number]; + CMatrix33 tmat; + GetCMatrix(&FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number], &tmat); + FIGURE_dhpr_rdata1[recurse_level + 1].parent_base_mat = &tmat; + FIGURE_dhpr_rdata1[recurse_level + 1].parent_base_pos = &FIGURE_dhpr_rdata1[recurse_level].pos; + FIGURE_dhpr_rdata1[recurse_level + 1].parent_current_mat = &FIGURE_dhpr_rdata2[recurse_level].end_mat; + FIGURE_dhpr_rdata1[recurse_level + 1].parent_current_pos = &FIGURE_dhpr_rdata2[recurse_level].end_pos; + FIGURE_dhpr_rdata1[recurse_level + 1].current_child_number = 0; + + FIGURE_dhpr_rdata1[recurse_level].current_child_number ++ ; + recurse_level ++; + } + else + recurse_level --; + }; + + LOG_EXIT ( Figure_Draw_Hierarchical ) + +} +#endif + + +//************************************************************************************************* +SLONG get_sort_z_bodge(SLONG px,SLONG pz) +{ + SLONG dx,dz; + UBYTE cap; + dx=px-POLY_cam_x; + dz=pz-POLY_cam_z; + + if(abs(dz)128) + { + cap=MAV_get_caps(px>>8,pz>>8,MAV_DIR_XL); + if(!(cap&MAV_CAPS_GOTO)) + { + return(100); + } + } + + } + else + { + if((px&0xff)<128) + { + cap=MAV_get_caps(px>>8,pz>>8,MAV_DIR_XS); + if(!(cap&MAV_CAPS_GOTO)) + { + return(100); + } + } + + } + + } + else + { + if(dz<0) + { + if((pz&0xff)>128) + { + cap=MAV_get_caps(px>>8,pz>>8,MAV_DIR_ZL); + if(!(cap&MAV_CAPS_GOTO)) + { + return(100); + } + } + + } + else + { + if((pz&0xff)<128) + { + cap=MAV_get_caps(px>>8,pz>>8,MAV_DIR_ZS); + if(!(cap&MAV_CAPS_GOTO)) + { + return(100); + } + } + + } + + } + return(0); + +} + +struct +{ + SWORD r,g,b; +}peep_recol[]= +{ + {12,64,64}, + {64,28,64}, + {64,4,55}, + {54,32,22}, + + {42,14,12}, + {32,42,64}, + {22,64,54}, + {64,14,32}, + + {34,32,64}, + {0,32,64}, + {32,64,0}, + {64,0,32}, + + {56,30,0}, + {0,40,56}, + {33,26,70}, + {56,36,0}, + + +}; + +UBYTE kludge_shrink; + + + + + + + +#ifndef PSX +// New faster version +void FIGURE_draw(Thing *p_thing) +{ + SLONG dx; + SLONG dy; + SLONG dz; + SLONG wx,wy,wz; + + ULONG colour; + ULONG specular; + + Matrix33 r_matrix; + + GameKeyFrameElement *ae1; + GameKeyFrameElement *ae2; + + DrawTween *dt = p_thing->Draw.Tweened; + + LOG_ENTER ( Figure_FIGURE_Draw ) + +// calc_global_cloud(p_thing->WorldPos.X>>8,p_thing->WorldPos.Y>>8,p_thing->WorldPos.Z>>8); + + if (dt->CurrentFrame == 0 || + dt->NextFrame == 0) + { + // + // No frames to tween between. + // + + MSG_add("!!!!!!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure"); + LOG_EXIT ( Figure_FIGURE_Draw ) + return; + } + + // + // The offset to keep the locked limb in the same place. + // + + dx = 0; + dy = 0; + dz = 0; + + // + // The rotation matrix of the whole object. + // + + LOG_ENTER ( Figure_Rotate ) + + FIGURE_rotate_obj( + dt->Tilt, + dt->Angle, + (dt->Roll+2048)&2047, + &r_matrix); + + LOG_EXIT ( Figure_Rotate ) + + wx=0; + wy=0; + wz=0; + + // + // The animation elements for the two frames. + // + + ae1 = dt->CurrentFrame->FirstElement; + ae2 = dt->NextFrame ->FirstElement; + +#ifdef DEBUG + if (!ae1 || !ae2) + { + MSG_add("!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure has no animation elements"); + LOG_EXIT ( Figure_FIGURE_Draw ) + + return; + } +#endif + + // + // What colour do we draw the figure? + // + + // + // All this is done in FIGURE_draw_prim_tween nowadays using the array + // filled in by this call to NIGHT_find.... + // + + colour = 0; + specular = 0; + + SLONG lx; + SLONG ly; + SLONG lz; + + NIGHT_Colour col; + + LOG_ENTER ( Figure_Calc_Sub_Objs ) + + calc_sub_objects_position( + p_thing, + dt->AnimTween, + 0, // 0 is Pelvis + &lx, &ly, &lz); + + lx += p_thing->WorldPos.X >> 8; + ly += p_thing->WorldPos.Y >> 8; + lz += p_thing->WorldPos.Z >> 8; + + LOG_EXIT ( Figure_Calc_Sub_Objs ) + + LOG_ENTER ( Figure_NIGHT_Find ) + + NIGHT_find(lx, ly, lz); + + LOG_EXIT ( Figure_NIGHT_Find ) + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + ASSERT ( !MM_bLightTableAlreadySetUp ); + + // Set up some data for the MM rendering thing. + +#if 0 +//#define ALIGNED_STATIC_ARRAY(name,number,mytype,align) \ +// static char c##name##mytype##align##StaticArray [ align + number * sizeof ( mytype ) ]; \ +// name = (mytype *)( ( (DWORD)c##name##mytype##align##StaticArray + (align-1) ) & ~(align-1) ) + + ALIGNED_STATIC_ARRAY ( MM_pcFadeTable, 128, D3DCOLOR, 4 ); + ALIGNED_STATIC_ARRAY ( MM_pcFadeTableTint, 128, D3DCOLOR, 4 ); + ALIGNED_STATIC_ARRAY ( MM_pMatrix, 1, D3DMATRIX, 32 ); + ALIGNED_STATIC_ARRAY ( MM_Vertex, 4, D3DVERTEX, 32 ); + ALIGNED_STATIC_ARRAY ( MM_pNormal, 4, float, 8 ); +#endif + +//#undef ALIGNED_STATIC_ARRAY + + Pyro *p = NULL; + if (p_thing->Class == CLASS_PERSON && p_thing->Genus.Person->BurnIndex) + { + p = TO_PYRO(p_thing->Genus.Person->BurnIndex-1); + if (p->PyroType != PYRO_IMMOLATE) + { + p = NULL; + } + } + + BuildMMLightingTable ( p, 0 ); + + MM_bLightTableAlreadySetUp = TRUE; + + +#endif + + + + // + // Draw each body part. + // + + //SLONG i; + SLONG ele_count; + SLONG start_object; + SLONG object_offset; + + ele_count = dt->TheChunk->ElementCount; + start_object = prim_multi_objects[dt->TheChunk->MultiObject[dt->MeshID]].StartObject; + + if (ele_count == 15 ) + { + Matrix31 pos; + pos.M[0] = (p_thing->WorldPos.X >> 8)+wx; + pos.M[1] = (p_thing->WorldPos.Y >> 8) + wy; + pos.M[2] = (p_thing->WorldPos.Z >> 8)+wz; + + // assume we've got a person, and draw the object hierarchically + + // fill out data. + + FIGURE_dhpr_rdata1[0].part_number = 0; + FIGURE_dhpr_rdata1[0].current_child_number = 0; + FIGURE_dhpr_rdata1[0].parent_base_mat = NULL; + FIGURE_dhpr_rdata1[0].parent_base_pos = NULL; + FIGURE_dhpr_rdata1[0].parent_current_mat = NULL; + FIGURE_dhpr_rdata1[0].parent_current_pos = NULL; + + FIGURE_dhpr_data.start_object = start_object; + if(p_thing->Genus.Person->PersonType==PERSON_ROPER) + FIGURE_dhpr_data.body_def = &dt->TheChunk->PeopleTypes[(dt->PersonID>>5)]; + else + FIGURE_dhpr_data.body_def = &dt->TheChunk->PeopleTypes[(dt->PersonID&0x1f)]; + FIGURE_dhpr_data.world_pos = &pos; + FIGURE_dhpr_data.tween = dt->AnimTween; + FIGURE_dhpr_data.ae1 = ae1; + FIGURE_dhpr_data.ae2 = ae2; + FIGURE_dhpr_data.world_mat = &r_matrix; +// FIGURE_dhpr_data.world_mat2 = &r_matrix2; + FIGURE_dhpr_data.dx = dx; + FIGURE_dhpr_data.dy = dy; + FIGURE_dhpr_data.dz = dz; + FIGURE_dhpr_data.colour = colour; + FIGURE_dhpr_data.specular = specular; + + // These two are used to find which unique mesh we are drawing. + FIGURE_dhpr_data.bPersonType = p_thing->Genus.Person->PersonType; + FIGURE_dhpr_data.bPersonID = dt->PersonID; + + FIGURE_draw_hierarchical_prim_recurse(p_thing); + } + else + { + for (int i = 0; i < ele_count; i++) + { + object_offset = dt->TheChunk->PeopleTypes[(dt->PersonID & 0x1f)].BodyPart[i]; + + FIGURE_draw_prim_tween( + start_object + object_offset, + p_thing->WorldPos.X >> 8, + (p_thing->WorldPos.Y >> 8), + p_thing->WorldPos.Z >> 8, + dt->AnimTween, + &ae1[i], + &ae2[i], + &r_matrix, + dx,dy,dz, + colour, + specular, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + p_thing); + } + } + +#if USE_TOMS_ENGINE_PLEASE_BOB + // Clean up after ourselves. + ASSERT ( MM_bLightTableAlreadySetUp ); + MM_bLightTableAlreadySetUp = FALSE; +#if 0 + MM_pcFadeTable = NULL; + MM_pcFadeTableTint = NULL; + MM_pMatrix = NULL; + MM_Vertex = NULL; + MM_pNormal = NULL; +#endif +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + + + + // + // In case this thing ain't a person... + // + + if (p_thing->Class == CLASS_PERSON) + { + + // + // Is this person carrying a grenade? + // + + Thing *p_person = p_thing; + + if (p_person->Genus.Person->SpecialUse && TO_THING(p_person->Genus.Person->SpecialUse)->Genus.Special->SpecialType == SPECIAL_GRENADE) + { + SLONG px; + SLONG py; + SLONG pz; + SLONG prim; + + calc_sub_objects_position( + p_person, + p_person->Draw.Tweened->AnimTween, + SUB_OBJECT_LEFT_HAND, + &px, + &py, + &pz); + + px += p_person->WorldPos.X >> 8; + py += p_person->WorldPos.Y >> 8; + pz += p_person->WorldPos.Z >> 8; + + kludge_shrink = TRUE; + + MESH_draw_poly( + PRIM_OBJ_ITEM_GRENADE, + px, + py, + pz, + 0, 0, 0, + NULL,0xff); + + kludge_shrink = FALSE; + } + } + p_thing->Flags&=~FLAGS_PERSON_AIM_AND_RUN; + + LOG_EXIT ( Figure_FIGURE_Draw ) + +} + + +#else +// Old version + +void FIGURE_draw(Thing *p_thing) +{ + SLONG dx; + SLONG dy; + SLONG dz; + SLONG wx,wy,wz; + + ULONG colour; + ULONG specular; + + Matrix33 r_matrix; + + GameKeyFrameElement *ae1; + GameKeyFrameElement *ae2; + + DrawTween *dt = p_thing->Draw.Tweened; + +/* + { + static SLONG turn = 0; + if(turn!=GAME_TURN) + { + if(Keys[KB_T]) + { + peep_recol[0].r+=ShiftFlag?4:-4; + SATURATE(peep_recol[0].r,0,256); + PANEL_new_text(p_thing,200," peep r %d g %d b %d ",peep_recol[0].r,peep_recol[0].g,peep_recol[0].b); + } + if(Keys[KB_Y]) + { + peep_recol[0].g+=ShiftFlag?4:-4; + SATURATE(peep_recol[0].g,0,256); + PANEL_new_text(p_thing,200," peep r %d g %d b %d ",peep_recol[0].r,peep_recol[0].g,peep_recol[0].b); + } + if(Keys[KB_U]) + { + peep_recol[0].b+=ShiftFlag?4:-4; + SATURATE(peep_recol[0].b,0,256); + PANEL_new_text(p_thing,200," peep r %d g %d b %d ",peep_recol[0].r,peep_recol[0].g,peep_recol[0].b); + } + } + turn=GAME_TURN; + } +*/ + + + + LOG_ENTER ( Figure_FIGURE_Draw ) + + +// calc_global_cloud(p_thing->WorldPos.X>>8,p_thing->WorldPos.Y>>8,p_thing->WorldPos.Z>>8); + +#ifdef PSX + // + // test some code out for PSX + // + if(get_sort_z_bodge(p_thing->WorldPos.X>>8,p_thing->WorldPos.Z>>8)) + { + AENG_world_line( + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + 32, 0xffffff, + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y + 0xc000 >> 8, + p_thing->WorldPos.Z >> 8, + 0, 0xffffff, + TRUE); + + } +#endif + + if (dt->CurrentFrame == 0 || + dt->NextFrame == 0) + { + // + // No frames to tween between. + // + + MSG_add("!!!!!!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure"); + LOG_EXIT ( Figure_FIGURE_Draw ) + return; + } + + // + // The offset to keep the locked limb in the same place. + // + +// if (dt->Locked) + if(0) + { + + SLONG x1, y1, z1; + SLONG x2, y2, z2; + + // + // Taken from temp.cpp + // + + calc_sub_objects_position_global(dt->CurrentFrame, dt->NextFrame, 0, dt->Locked, &x1, &y1, &z1); + calc_sub_objects_position_global(dt->CurrentFrame, dt->NextFrame, 256, dt->Locked, &x2, &y2, &z2); + + dx = x1 - x2; + dy = y1 - y2; + dz = z1 - z2; + } + else + { + dx = 0; + dy = 0; + dz = 0; + } + + + // + // The rotation matrix of the whole object. + // + + LOG_ENTER ( Figure_Rotate ) + + FIGURE_rotate_obj( + dt->Tilt, + dt->Angle, + (dt->Roll+2048)&2047, + &r_matrix); +/* + FIGURE_rotate_obj( + dt->Tilt, + dt->AngleTo, + (dt->Roll+2048)&2047, + &r_matrix2); +*/ + LOG_EXIT ( Figure_Rotate ) + + +#ifdef PSX_SIMULATION + { + SLONG index1,index2; + // + // stuff added for more compression of anims + // +extern struct PrimPoint *anim_mids; //[256]; + + index1=dt->CurrentFrame->XYZIndex; + index2=dt->NextFrame->XYZIndex; + + if(index1!=index2) + { +/* +// +// draw some debug lines +// + SVector temp; + Matrix31 offset; + + wx=anim_mids[index1].X; + wy=anim_mids[index1].Y; + wz=anim_mids[index1].Z; + offset.M[0]=wx; + offset.M[1]=wy; + offset.M[2]=wz; + matrix_transformZMY((struct Matrix31*)&temp,&r_matrix, &offset); + wx=temp.X; + wy=temp.Y; + wz=temp.Z; + + AENG_world_line((p_thing->WorldPos.X>>8),(p_thing->WorldPos.Y>>8),(p_thing->WorldPos.Z>>8),6,0xff0000, + (p_thing->WorldPos.X>>8)+wx,(p_thing->WorldPos.Y>>8)+wy,(p_thing->WorldPos.Z>>8)+wz,1,0xffffff,1); + + wx=anim_mids[index2].X; + wy=anim_mids[index2].Y; + wz=anim_mids[index2].Z; + + offset.M[0]=wx; + offset.M[1]=wy; + offset.M[2]=wz; + matrix_transformZMY((struct Matrix31*)&temp,&r_matrix, &offset); + wx=temp.X; + wy=temp.Y; + wz=temp.Z; + AENG_world_line((p_thing->WorldPos.X>>8),(p_thing->WorldPos.Y>>8),(p_thing->WorldPos.Z>>8),6,0xff00, + (p_thing->WorldPos.X>>8)+wx,(p_thing->WorldPos.Y>>8)+wy,(p_thing->WorldPos.Z>>8)+wz,1,0xffffff,1); +*/ + + + + wx=anim_mids[index1].X+(((anim_mids[index2].X-anim_mids[index1].X)*dt->AnimTween)>>8); + wy=anim_mids[index1].Y+(((anim_mids[index2].Y-anim_mids[index1].Y)*dt->AnimTween)>>8); + wz=anim_mids[index1].Z+(((anim_mids[index2].Z-anim_mids[index1].Z)*dt->AnimTween)>>8); + } + else + { + wx=anim_mids[index1].X; + wy=anim_mids[index1].Y; + wz=anim_mids[index1].Z; + } + + // + // put offset into object space + // + { + SVector temp; + Matrix31 offset; + offset.M[0]=wx; + offset.M[1]=wy; + offset.M[2]=wz; + matrix_transformZMY((struct Matrix31*)&temp,&r_matrix, &offset); + wx=temp.X; + wy=temp.Y; + wz=temp.Z; +/* + AENG_world_line((p_thing->WorldPos.X>>8),(p_thing->WorldPos.Y>>8),(p_thing->WorldPos.Z>>8),6,0x808080, + (p_thing->WorldPos.X>>8)+wx,(p_thing->WorldPos.Y>>8)+wy,(p_thing->WorldPos.Z>>8)+wz,1,0xffffff,1); +*/ + } + + + } +#else + wx=0; + wy=0; + wz=0; +#endif + + // + // The animation elements for the two frames. + // + + ae1 = dt->CurrentFrame->FirstElement; + ae2 = dt->NextFrame ->FirstElement; + + if (!ae1 || !ae2) + { + MSG_add("!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure has no animation elements"); + LOG_EXIT ( Figure_FIGURE_Draw ) + + return; + } + + // + // What colour do we draw the figure? + // + + // + // All this is done in FIGURE_draw_prim_tween nowadays using the array + // filled in by this call to NIGHT_find.... + // + + colour = 0; + specular = 0; + + SLONG lx; + SLONG ly; + SLONG lz; + + NIGHT_Colour col; + + LOG_ENTER ( Figure_Calc_Sub_Objs ) + + calc_sub_objects_position( + p_thing, + dt->AnimTween, + 0, // 0 is Pelvis + &lx, &ly, &lz); + + lx += p_thing->WorldPos.X >> 8; + ly += p_thing->WorldPos.Y >> 8; + lz += p_thing->WorldPos.Z >> 8; + + LOG_EXIT ( Figure_Calc_Sub_Objs ) + + LOG_ENTER ( Figure_NIGHT_Find ) + + NIGHT_find(lx, ly, lz); + + LOG_EXIT ( Figure_NIGHT_Find ) + + /* + + SLONG lx; + SLONG ly; + SLONG lz; + + NIGHT_Colour col; + + calc_sub_objects_position( + p_thing, + dt->AnimTween, + 0, // 0 is Pelvis + &lx, &ly, &lz); + + lx += p_thing->WorldPos.X >> 8; + ly += p_thing->WorldPos.Y >> 8; + lz += p_thing->WorldPos.Z >> 8; + + col = NIGHT_get_light_at(lx, ly, lz); + + if (p_thing->Genus.Person->BurnIndex) { + Pyro *p=TO_PYRO(p_thing->Genus.Person->BurnIndex-1); + if (p->PyroType==PYRO_IMMOLATE) { + col.red= (col.red>p->counter) ?col.red-p->counter:0; + col.green=(col.green>p->counter)?col.green-p->counter:0; + col.blue= (col.blue>p->counter) ?col.blue-p->counter:0; + } + } + + if (ControlFlag) + { + // + // Brighten up the person if he is going to be drawn too dark. + // + + if (col.red < 32) {col.red += 32 - col.red >> 1;} + if (col.green < 32) {col.green += 32 - col.green >> 1;} + if (col.blue < 32) {col.blue += 32 - col.blue >> 1;} + } + + */ + +/* + if(p_thing->Genus.Person->PersonType==PERSON_THUG_RED) + { + NIGHT_Colour temp; + SLONG index; + index=THING_NUMBER(p_thing)&15; +// index=0; + + temp.red=(col.red*peep_recol[index].r)>>8; + temp.green=(col.green*peep_recol[index].g)>>8; + temp.blue=(col.blue*peep_recol[index].b)>>8; + NIGHT_get_d3d_colour( + temp, + &jacket_col,&specular); + jacket_col &= ~POLY_colour_restrict; + + index=(PERSON_NUMBER(p_thing->Genus.Person)>>2)%9; + + temp.red=(col.red*peep_recol[index].r)>>8; + temp.green=(col.green*peep_recol[index].g)>>8; + temp.blue=(col.blue*peep_recol[index].b)>>8; + NIGHT_get_d3d_colour( + temp, + &leg_col,&specular); + leg_col &= ~POLY_colour_restrict; + + + } +*/ + /* + + NIGHT_get_d3d_colour( + col, + &colour, + &specular); + + */ +/* + if(p_thing->Genus.Person->PersonType!=PERSON_THUG_RED) + { + jacket_col=colour; + leg_col=colour; + + } +*/ + +/* if (p_thing->Genus.Person->BurnIndex) { + Pyro *p=TO_PYRO(p_thing->Genus.Person->BurnIndex-1); + if (p->PyroType==PYRO_IMMOLATE) { + colour=0; + } + }*/ + + /* + + + colour &= ~POLY_colour_restrict; + specular &= ~POLY_colour_restrict; + + */ + + #if WE_WANT_TO_DARKEN_PEOPLE_IN_SHADOW_ABRUPTLY + + if (SHADOW_in( + (p_thing->WorldPos.X >> 8), + (p_thing->WorldPos.Y >> 8), + (p_thing->WorldPos.Z >> 8))) + { + colour >>= 1; + colour &= 0x7f7f7f7f; + specular = 0xff000000; + } + + #endif + + + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + + ASSERT ( !MM_bLightTableAlreadySetUp ); + + // Set up some data for the MM rendering thing. + +#if 0 +//#define ALIGNED_STATIC_ARRAY(name,number,mytype,align) \ +// static char c##name##mytype##align##StaticArray [ align + number * sizeof ( mytype ) ]; \ +// name = (mytype *)( ( (DWORD)c##name##mytype##align##StaticArray + (align-1) ) & ~(align-1) ) + + ALIGNED_STATIC_ARRAY ( MM_pcFadeTable, 128, D3DCOLOR, 4 ); + ALIGNED_STATIC_ARRAY ( MM_pcFadeTableTint, 128, D3DCOLOR, 4 ); + ALIGNED_STATIC_ARRAY ( MM_pMatrix, 1, D3DMATRIX, 32 ); + ALIGNED_STATIC_ARRAY ( MM_Vertex, 4, D3DVERTEX, 32 ); + ALIGNED_STATIC_ARRAY ( MM_pNormal, 4, float, 8 ); +#endif + +//#undef ALIGNED_STATIC_ARRAY + + Pyro *p = NULL; + if (p_thing->Class == CLASS_PERSON && p_thing->Genus.Person->BurnIndex) + { + p = TO_PYRO(p_thing->Genus.Person->BurnIndex-1); + if (p->PyroType != PYRO_IMMOLATE) + { + p = NULL; + } + } + + BuildMMLightingTable ( p, 0 ); + + MM_bLightTableAlreadySetUp = TRUE; + + +#endif + + + + // + // Draw each body part. + // + + //SLONG i; + SLONG ele_count; + SLONG start_object; + SLONG object_offset; + + ele_count = dt->TheChunk->ElementCount; + start_object = prim_multi_objects[dt->TheChunk->MultiObject[dt->MeshID]].StartObject; + + if (ele_count == 15 ) + { + Matrix31 pos; + pos.M[0] = (p_thing->WorldPos.X >> 8)+wx; + pos.M[1] = (p_thing->WorldPos.Y >> 8) + wy; + pos.M[2] = (p_thing->WorldPos.Z >> 8)+wz; + + // assume we've got a person, and draw the object hierarchically + + // fill out data. + + FIGURE_dhpr_rdata1[0].part_number = 0; + FIGURE_dhpr_rdata1[0].current_child_number = 0; + FIGURE_dhpr_rdata1[0].parent_base_mat = NULL; + FIGURE_dhpr_rdata1[0].parent_base_pos = NULL; + FIGURE_dhpr_rdata1[0].parent_current_mat = NULL; + FIGURE_dhpr_rdata1[0].parent_current_pos = NULL; + + FIGURE_dhpr_data.start_object = start_object; + if(p_thing->Genus.Person->PersonType==PERSON_ROPER) + + FIGURE_dhpr_data.body_def = &dt->TheChunk->PeopleTypes[(dt->PersonID>>5)]; + else + FIGURE_dhpr_data.body_def = &dt->TheChunk->PeopleTypes[(dt->PersonID&0x1f)]; + FIGURE_dhpr_data.world_pos = &pos; + FIGURE_dhpr_data.tween = dt->AnimTween; + FIGURE_dhpr_data.ae1 = ae1; + FIGURE_dhpr_data.ae2 = ae2; + FIGURE_dhpr_data.world_mat = &r_matrix; +// FIGURE_dhpr_data.world_mat2 = &r_matrix2; + FIGURE_dhpr_data.dx = dx; + FIGURE_dhpr_data.dy = dy; + FIGURE_dhpr_data.dz = dz; + FIGURE_dhpr_data.colour = colour; + FIGURE_dhpr_data.specular = specular; + + // These two are used to find which unique mesh we are drawing. + FIGURE_dhpr_data.bPersonType = p_thing->Genus.Person->PersonType; + FIGURE_dhpr_data.bPersonID = dt->PersonID; + + FIGURE_draw_hierarchical_prim_recurse(p_thing); + } + else + { + for (int i = 0; i < ele_count; i++) + { + object_offset = dt->TheChunk->PeopleTypes[(dt->PersonID & 0x1f)].BodyPart[i]; + + FIGURE_draw_prim_tween( + start_object + object_offset, + p_thing->WorldPos.X >> 8, + (p_thing->WorldPos.Y >> 8), + p_thing->WorldPos.Z >> 8, + dt->AnimTween, + &ae1[i], + &ae2[i], + &r_matrix, + dx,dy,dz, + colour, + specular, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + p_thing); + } + } + +#if USE_TOMS_ENGINE_PLEASE_BOB + // Clean up after ourselves. + ASSERT ( MM_bLightTableAlreadySetUp ); + MM_bLightTableAlreadySetUp = FALSE; +#if 0 + MM_pcFadeTable = NULL; + MM_pcFadeTableTint = NULL; + MM_pMatrix = NULL; + MM_Vertex = NULL; + MM_pNormal = NULL; +#endif +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + + + + // + // In case this thing ain't a person... + // + + if (p_thing->Class == CLASS_PERSON) + { + /* + + Thing *p_person = p_thing; + + // + // If this person is holding a coke-can... + // + + if (p_person->Genus.Person->Flags & FLAG_PERSON_CANNING) + { + SLONG px; + SLONG py; + SLONG pz; + SLONG prim; + + calc_sub_objects_position( + p_person, + p_person->Draw.Tweened->AnimTween, + SUB_OBJECT_LEFT_HAND, + &px, + &py, + &pz); + + px += p_person->WorldPos.X >> 8; + py += p_person->WorldPos.Y >> 8; + pz += p_person->WorldPos.Z >> 8; + + if (p_person->Genus.Person->Flags & FLAG_PERSON_HEADING) + { + DIRT_Info ans; + + DIRT_get_info(p_person->Genus.Person->Hold, &ans); + + prim = ans.prim; + } + else + { + prim = PRIM_OBJ_CAN; + } + + MESH_draw_poly( + prim, + px, + py, + pz, + 0, 0, 0, + NULL,0); + } + + */ + + // + // Is this person carrying a grenade? + // + + Thing *p_person = p_thing; + + if (p_person->Genus.Person->SpecialUse && TO_THING(p_person->Genus.Person->SpecialUse)->Genus.Special->SpecialType == SPECIAL_GRENADE) + { + SLONG px; + SLONG py; + SLONG pz; + SLONG prim; + + calc_sub_objects_position( + p_person, + p_person->Draw.Tweened->AnimTween, + SUB_OBJECT_LEFT_HAND, + &px, + &py, + &pz); + + px += p_person->WorldPos.X >> 8; + py += p_person->WorldPos.Y >> 8; + pz += p_person->WorldPos.Z >> 8; + + kludge_shrink = TRUE; + + MESH_draw_poly( + PRIM_OBJ_ITEM_GRENADE, + px, + py, + pz, + 0, 0, 0, + NULL,0xff); + + kludge_shrink = FALSE; + } + } + p_thing->Flags&=~FLAGS_PERSON_AIM_AND_RUN; + + LOG_EXIT ( Figure_FIGURE_Draw ) + +} + +#endif + + + + +void ANIM_obj_draw(Thing *p_thing,DrawTween *dt) +{ + SLONG dx; + SLONG dy; + SLONG dz; + + ULONG colour; + ULONG specular; + + Matrix33 r_matrix; + + GameKeyFrameElement *ae1; + GameKeyFrameElement *ae2; + +// calc_global_cloud(p_thing->WorldPos.X>>8,p_thing->WorldPos.Y>>8,p_thing->WorldPos.Z>>8); + + if (dt->CurrentFrame == 0 || + dt->NextFrame == 0) + { + // + // No frames to tween between. + // + + MSG_add("!!!!!!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure"); + return; + } + + /* + + { + // + // Draw the bounding box. + // + + AnimPrimBbox *apb = &anim_prim_bbox[p_thing->Index]; + + AENG_world_line( + apb->minx + (p_thing->WorldPos.X >> 8), + apb->miny + (p_thing->WorldPos.Y >> 8), + apb->minz + (p_thing->WorldPos.Z >> 8), + 0x16, + 0x00ffffff, + apb->maxx + (p_thing->WorldPos.X >> 8), + apb->maxy + (p_thing->WorldPos.Y >> 8), + apb->maxz + (p_thing->WorldPos.Z >> 8), + 0x16, + 0x000ccccff, + TRUE); + } + + */ + + // + // The offset to keep the locked limb in the same place. + // + + dx = 0; + dy = 0; + dz = 0; + + // + // The animation elements for the two frames. + // + + ae1 = dt->CurrentFrame->FirstElement; + ae2 = dt->NextFrame ->FirstElement; + + if (!ae1 || !ae2) + { + MSG_add("!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure has no animation elements"); + + return; + } + + // + // The rotation matrix of the whole object. + // + + FIGURE_rotate_obj( + dt->Tilt, + dt->Angle, + (dt->Roll+2048)&2047, + &r_matrix); + + // + // What colour do we draw the figure? + // + + colour = 0; + specular = 0; + + SLONG lx; + SLONG ly; + SLONG lz; + + NIGHT_Colour col; + + lx = (p_thing->WorldPos.X >> 8); + ly = (p_thing->WorldPos.Y >> 8) + 0x60; + lz = (p_thing->WorldPos.Z >> 8); + + NIGHT_find(lx, ly, lz); + + /* + + NIGHT_get_d3d_colour( + NIGHT_get_light_at( + (p_thing->WorldPos.X >> 8), + (p_thing->WorldPos.Y >> 8), + (p_thing->WorldPos.Z >> 8)), + &colour, + &specular); + + colour &= ~POLY_colour_restrict; + specular &= ~POLY_colour_restrict; + + */ + + // + // Draw each body part. + // + + SLONG i; + SLONG ele_count; + SLONG start_object; + SLONG object_offset; + + ele_count = dt->TheChunk->ElementCount; + start_object = prim_multi_objects[dt->TheChunk->MultiObject[0]].StartObject; + + for (i = 0; i < ele_count; i++) + { + object_offset = i; //dt->TheChunk->PeopleTypes[dt->PersonID].BodyPart[i]; + FIGURE_draw_prim_tween( + start_object + object_offset, + p_thing->WorldPos.X >> 8, + (p_thing->WorldPos.Y >> 8), + p_thing->WorldPos.Z >> 8, + dt->AnimTween, + &ae1[i], + &ae2[i], + &r_matrix, + dx,dy,dz, + colour, + specular, +// p_thing); + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + p_thing, + i, + 0xffff00ff); + + } +} + + +void ANIM_obj_draw_warped(Thing *p_thing,DrawTween *dt) +{ + SLONG dx; + SLONG dy; + SLONG dz; + + ULONG colour; + ULONG specular; + + Matrix33 r_matrix; + + GameKeyFrameElement *ae1; + GameKeyFrameElement *ae2; + + + if (dt->CurrentFrame == 0 || + dt->NextFrame == 0) + { + // + // No frames to tween between. + // + + MSG_add("!!!!!!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure"); + return; + } + + // + // The offset to keep the locked limb in the same place. + // + + dx = 0; + dy = 0; + dz = 0; + + // + // The animation elements for the two frames. + // + + ae1 = dt->CurrentFrame->FirstElement; + ae2 = dt->NextFrame ->FirstElement; + + if (!ae1 || !ae2) + { + MSG_add("!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure has no animation elements"); + + return; + } + + // + // The rotation matrix of the whole object. + // + + FIGURE_rotate_obj( + dt->Tilt, + dt->Angle, + (dt->Roll+2048)&2047, + &r_matrix); + + // + // What colour do we draw the figure? + // + + NIGHT_get_d3d_colour( + NIGHT_get_light_at( + (p_thing->WorldPos.X >> 8), + (p_thing->WorldPos.Y >> 8), + (p_thing->WorldPos.Z >> 8)), + &colour, + &specular); + + colour &= ~POLY_colour_restrict; + specular &= ~POLY_colour_restrict; + + + // + // Draw each body part. + // + + SLONG i; + SLONG ele_count; + SLONG start_object; + SLONG object_offset; + + ele_count = dt->TheChunk->ElementCount; + start_object = prim_multi_objects[dt->TheChunk->MultiObject[0]].StartObject; + + for (i = 0; i < ele_count; i++) + { + object_offset = i; //dt->TheChunk->PeopleTypes[dt->PersonID].BodyPart[i]; + + FIGURE_draw_prim_tween_warped( + start_object + object_offset, + p_thing->WorldPos.X >> 8, + (p_thing->WorldPos.Y >> 8), + p_thing->WorldPos.Z >> 8, + dt->AnimTween, + &ae1[i], + &ae2[i], + &r_matrix, + dx,dy,dz, + colour, + specular, + p_thing); + } +} + + + +#ifndef TARGET_DC + +// ======================================================== +// +// DRAWING THE REFLECTION +// +// ======================================================== + +// +// The bounding box of the reflected points on screen. +// + +SLONG FIGURE_reflect_x1; +SLONG FIGURE_reflect_y1; +SLONG FIGURE_reflect_x2; +SLONG FIGURE_reflect_y2; + +float FIGURE_reflect_height; + +// +// The points used to create the reflection. +// + +typedef struct +{ + union + { + float distance; + ULONG clip; + }; + + POLY_Point pp; + +} FIGURE_Rpoint; + +#define FIGURE_MAX_RPOINTS 256 + +FIGURE_Rpoint FIGURE_rpoint[FIGURE_MAX_RPOINTS]; +SLONG FIGURE_rpoint_upto; + +void FIGURE_draw_prim_tween_reflection( + SLONG prim, + SLONG x, + SLONG y, + SLONG z, + SLONG tween, + struct GameKeyFrameElement *anim_info, + struct GameKeyFrameElement *anim_info_next, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + ULONG colour, + ULONG specular, + Thing *p_thing) +{ + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG px; + SLONG py; + + ULONG red; + ULONG green; + ULONG blue; + ULONG r; + ULONG g; + ULONG b; + ULONG face_colour; + SLONG fog; + + float world_x; + float world_y; + float world_z; + + SLONG page; + + Matrix31 offset; + Matrix33 mat2; + Matrix33 mat_final; + + SVector temp; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + FIGURE_Rpoint *frp; + + colour >>= 1; + specular >>= 1; + + colour &= 0x7f7f7f7f; + specular &= 0x7f7f7f7f; + + colour |= 0xff000000; + specular |= 0xff000000; + + red = (colour >> 16) & 0xff; + green = (colour >> 8) & 0xff; + blue = (colour >> 0) & 0xff; + + // + // Matrix functions we use. + // + + void matrix_transform (Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_mult33 (Matrix33* result, Matrix33* mat1, Matrix33* mat2); + + offset.M[0] = anim_info->OffsetX + ((anim_info_next->OffsetX + off_dx - anim_info->OffsetX) * tween >> 8); + offset.M[1] = anim_info->OffsetY + ((anim_info_next->OffsetY + off_dy - anim_info->OffsetY) * tween >> 8); + offset.M[2] = anim_info->OffsetZ + ((anim_info_next->OffsetZ + off_dz - anim_info->OffsetZ) * tween >> 8); + + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + + SLONG character_scale = person_get_scale(p_thing); + temp.X = (temp.X * character_scale) / 256; + temp.Y = (temp.Y * character_scale) / 256; + temp.Z = (temp.Z * character_scale) / 256; + + x += temp.X; + y += temp.Y; + z += temp.Z; + + // + // Create a temporary "tween" matrix between current and next + // + + CMatrix33 m1, m2; + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + build_tween_matrix(&mat2, &m1, &m2 ,tween); + normalise_matrix(&mat2); + + // + // Apply local rotation matrix to get mat_final that rotates + // the point into world space. + // + + matrix_mult33(&mat_final, rot_mat, &mat2); + + mat_final.M[0][0] = (mat_final.M[0][0] * character_scale) / 256; + mat_final.M[0][1] = (mat_final.M[0][1] * character_scale) / 256; + mat_final.M[0][2] = (mat_final.M[0][2] * character_scale) / 256; + mat_final.M[1][0] = (mat_final.M[1][0] * character_scale) / 256; + mat_final.M[1][1] = (mat_final.M[1][1] * character_scale) / 256; + mat_final.M[1][2] = (mat_final.M[1][2] * character_scale) / 256; + mat_final.M[2][0] = (mat_final.M[2][0] * character_scale) / 256; + mat_final.M[2][1] = (mat_final.M[2][1] * character_scale) / 256; + mat_final.M[2][2] = (mat_final.M[2][2] * character_scale) / 256; + + // + // Do everything in floats. + // + + float off_x; + float off_y; + float off_z; + float fmatrix[9]; + + off_x = float(x); + off_y = float(y); + off_z = float(z); + + fmatrix[0] = float(mat_final.M[0][0]) * (1.0F / 32768.0F); + fmatrix[1] = float(mat_final.M[0][1]) * (1.0F / 32768.0F); + fmatrix[2] = float(mat_final.M[0][2]) * (1.0F / 32768.0F); + fmatrix[3] = float(mat_final.M[1][0]) * (1.0F / 32768.0F); + fmatrix[4] = float(mat_final.M[1][1]) * (1.0F / 32768.0F); + fmatrix[5] = float(mat_final.M[1][2]) * (1.0F / 32768.0F); + fmatrix[6] = float(mat_final.M[2][0]) * (1.0F / 32768.0F); + fmatrix[7] = float(mat_final.M[2][1]) * (1.0F / 32768.0F); + fmatrix[8] = float(mat_final.M[2][2]) * (1.0F / 32768.0F); + + POLY_set_local_rotation( + off_x, + off_y, + off_z, + fmatrix); + + // + // How deep the reflection can be + // + + #define FIGURE_MAX_DY (128.0F) + #define FIGURE_255_DIVIDED_BY_MAX_DY (255.0F / FIGURE_MAX_DY) + + // + // Rotate all the points into the POLY_buffer. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + FIGURE_rpoint_upto = 0; + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(FIGURE_rpoint_upto, 0, FIGURE_MAX_RPOINTS - 1)); + + frp = &FIGURE_rpoint[FIGURE_rpoint_upto++]; + + POLY_transform_using_local_rotation( + AENG_dx_prim_points[i].X, + AENG_dx_prim_points[i].Y, + AENG_dx_prim_points[i].Z, + &frp->pp); + + if (frp->pp.MaybeValid()) + { + frp->pp.colour = colour; + frp->pp.specular = specular; + + // + // Work out the signed distance of this point from the reflection plane. + // + + world_x = AENG_dx_prim_points[i].X; + world_y = AENG_dx_prim_points[i].Y; + world_z = AENG_dx_prim_points[i].Z; + + MATRIX_MUL( + fmatrix, + world_x, + world_y, + world_z); + + world_x += off_x; + world_y += off_y; + world_z += off_z; + + frp->distance = FIGURE_reflect_height - world_y; + + if (frp->distance >= 0.0F) + { + // + // Update the bounding box. + // + + px = SLONG(frp->pp.X); + py = SLONG(frp->pp.Y); + + if (px < FIGURE_reflect_x1) {FIGURE_reflect_x1 = px;} + if (px > FIGURE_reflect_x2) {FIGURE_reflect_x2 = px;} + if (py < FIGURE_reflect_y1) {FIGURE_reflect_y1 = py;} + if (py > FIGURE_reflect_y2) {FIGURE_reflect_y2 = py;} + + // + // Fade out the point depending on distance from the reflection plane. + // + + fog = frp->pp.specular >> 24; + fog += SLONG(frp->distance * FIGURE_255_DIVIDED_BY_MAX_DY); + + if (fog > 255) {fog = 255;} + + frp->pp.specular &= 0x00ffffff; + frp->pp.specular |= fog << 24; + } + else + { + frp->pp.clip = 0; + } + } + } + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, FIGURE_rpoint_upto - 1)); + ASSERT(WITHIN(p1, 0, FIGURE_rpoint_upto - 1)); + ASSERT(WITHIN(p2, 0, FIGURE_rpoint_upto - 1)); + ASSERT(WITHIN(p3, 0, FIGURE_rpoint_upto - 1)); + + // + // Add the quads backwards... + // + + quad[0] = &FIGURE_rpoint[p0].pp; + quad[2] = &FIGURE_rpoint[p1].pp; + quad[1] = &FIGURE_rpoint[p2].pp; + quad[3] = &FIGURE_rpoint[p3].pp; + + if (POLY_valid_quad(quad)) + { + if (p_f4->DrawFlags & POLY_FLAG_TEXTURED) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + page+=FACE_PAGE_OFFSET; + + if (the_display.GetDeviceInfo()->AdamiLightingSupported()) + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, TRUE); + } + POLY_add_quad(quad, page, TRUE); + } + else + { + /* + + // + // The colour of the face. + // + + r = ENGINE_palette[p_f4->Col2].red; + g = ENGINE_palette[p_f4->Col2].green; + b = ENGINE_palette[p_f4->Col2].blue; + + r = r * red >> 8; + g = g * green >> 8; + b = b * blue >> 8; + + face_colour = (r << 16) | (g << 8) | (b << 0); + + quad[0]->colour = face_colour; + quad[1]->colour = face_colour; + quad[2]->colour = face_colour; + quad[3]->colour = face_colour; + + POLY_add_quad(quad, POLY_PAGE_COLOUR, TRUE); + + quad[0]->colour = colour; + quad[1]->colour = colour; + quad[2]->colour = colour; + quad[3]->colour = colour; + + */ + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, FIGURE_rpoint_upto - 1)); + ASSERT(WITHIN(p1, 0, FIGURE_rpoint_upto - 1)); + ASSERT(WITHIN(p2, 0, FIGURE_rpoint_upto - 1)); + + // + // Add the triangle backwards! + // + + tri[0] = &FIGURE_rpoint[p0].pp; + tri[2] = &FIGURE_rpoint[p1].pp; + tri[1] = &FIGURE_rpoint[p2].pp; + + if (POLY_valid_triangle(tri)) + { + if (p_f3->DrawFlags & POLY_FLAG_TEXTURED) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + page+=FACE_PAGE_OFFSET; + + if (the_display.GetDeviceInfo()->AdamiLightingSupported()) + { + POLY_add_triangle(tri, POLY_PAGE_COLOUR, TRUE); + } + POLY_add_triangle(tri, page, TRUE); + } + else + { + /* + + // + // The colour of the face. + // + + r = ENGINE_palette[p_f3->Col2].red; + g = ENGINE_palette[p_f3->Col2].green; + b = ENGINE_palette[p_f3->Col2].blue; + + r = r * red >> 8; + g = g * green >> 8; + b = b * blue >> 8; + + face_colour = (r << 16) | (g << 8) | (b << 0); + + tri[0]->colour = face_colour; + tri[1]->colour = face_colour; + tri[2]->colour = face_colour; + + POLY_add_triangle(tri, POLY_PAGE_COLOUR, TRUE); + + tri[0]->colour = colour; + tri[1]->colour = colour; + tri[2]->colour = colour; + + */ + } + } + } +} + +void FIGURE_draw_reflection(Thing *p_thing, SLONG height) +{ + SLONG dx; + SLONG dy; + SLONG dz; + + ULONG colour; + ULONG specular; + + POLY_Point *pp; + + Matrix33 r_matrix; + + GameKeyFrameElement *ae1; + GameKeyFrameElement *ae2; + + DrawTween *dt = p_thing->Draw.Tweened; + + if (dt->CurrentFrame == 0 || + dt->NextFrame == 0) + { + // + // No frames to tween between. + // + + MSG_add("!!!!!!!!!!!!!!!!!!!!!!!!ERROR FIGURE_draw_reflection"); + return; + } + + // + // The offset to keep the locked limb in the same place. + // + + //if (dt->Locked) + if (0) + { + SLONG x1, y1, z1; + SLONG x2, y2, z2; + + // + // Taken from temp.cpp + // + + calc_sub_objects_position_global(dt->CurrentFrame, dt->NextFrame, 0, dt->Locked, &x1, &y1, &z1); + calc_sub_objects_position_global(dt->CurrentFrame, dt->NextFrame, 256, dt->Locked, &x2, &y2, &z2); + + dx = x1 - x2; + dy = y1 - y2; + dz = z1 - z2; + } + else + { + dx = 0; + dy = 0; + dz = 0; + } + + // + // The animation elements for the two frames. + // + + ae1 = dt->CurrentFrame->FirstElement; + ae2 = dt->NextFrame ->FirstElement; + + if (!ae1 || !ae2) + { + MSG_add("!!!!!!!!!!!!!!!!!!!ERROR AENG_draw_figure has no animation elements"); + + return; + } + + // + // The rotation matrix of the whole object. + // + + FIGURE_rotate_obj( + dt->Tilt, + dt->Angle, + - dt->Roll, // - = JCL + &r_matrix); + + SLONG posx = p_thing->WorldPos.X >> 8; + SLONG posy = p_thing->WorldPos.Y >> 8; + SLONG posz = p_thing->WorldPos.Z >> 8; + + // + // Reflect about y = height. + // + + posy = height - (posy - height); + dy = -dy; + + r_matrix.M[0][1] = -r_matrix.M[0][1]; + r_matrix.M[1][1] = -r_matrix.M[1][1]; + r_matrix.M[2][1] = -r_matrix.M[2][1]; + + // + // Initialise the bounding box. + // + + FIGURE_reflect_x1 = +INFINITY; + FIGURE_reflect_y1 = +INFINITY; + FIGURE_reflect_x2 = -INFINITY; + FIGURE_reflect_y2 = -INFINITY; + + // + // The height of the plane the body-parts are clipped against. + // + + FIGURE_reflect_height = float(height); + + // + // What colour do we draw the figure? + // + + SLONG lx; + SLONG ly; + SLONG lz; + + NIGHT_Colour col; + + calc_sub_objects_position( + p_thing, + dt->AnimTween, + 0, // 0 is Pelvis + &lx, &ly, &lz); + + lx += p_thing->WorldPos.X >> 8; + ly += p_thing->WorldPos.Y >> 8; + lz += p_thing->WorldPos.Z >> 8; + + col = NIGHT_get_light_at(lx, ly, lz); + + if (!ControlFlag) + { + // + // Brighten up the person if he is going to be drawn too dark. + // + + if (col.red < 32) {col.red += 32 - col.red >> 1;} + if (col.green < 32) {col.green += 32 - col.green >> 1;} + if (col.blue < 32) {col.blue += 32 - col.blue >> 1;} + } + + NIGHT_get_d3d_colour( + col, + &colour, + &specular); + + colour &= ~POLY_colour_restrict; + specular &= ~POLY_colour_restrict; + + // + // Draw each body part. + // + + SLONG i; + SLONG j; + SLONG ele_count; + SLONG start_object; + SLONG object_offset; + SLONG px; + SLONG py; + + ele_count = dt->TheChunk->ElementCount; + start_object = prim_multi_objects[dt->TheChunk->MultiObject[dt->MeshID]].StartObject; + + for (i = 0; i < ele_count; i++) + { + object_offset = dt->TheChunk->PeopleTypes[dt->PersonID&0x1f].BodyPart[i]; +// object_offset = dt->TheChunk->PeopleTypes[0].BodyPart[i]; + + FIGURE_draw_prim_tween_reflection( + start_object + object_offset, + posx, + posy, + posz, + dt->AnimTween, + &ae1[i], + &ae2[i], + &r_matrix, + dx,dy,dz, + colour, + specular, + p_thing); + } +} + +#endif //#ifndef TARGET_DC + + + + + + + +// Like FIGURE_draw_prim_tween, but optimised for the person-only case. +// Also assumes the lighting has been set up, etc. +// This just sets up the matrix and light vector it's asked to - it doesn't +// do anything else. +// Return value is TRUE if this body part is not clipped by the near-Z. +bool FIGURE_draw_prim_tween_person_only_just_set_matrix +( + int iMatrixNum, + SLONG prim, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + SLONG recurse_level, + Thing *p_thing + ) +{ + + + SLONG x = FIGURE_dhpr_data.world_pos->M[0]; + SLONG y = FIGURE_dhpr_data.world_pos->M[1]; + SLONG z = FIGURE_dhpr_data.world_pos->M[2]; + SLONG tween = FIGURE_dhpr_data.tween; + struct GameKeyFrameElement *anim_info = &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number]; + struct GameKeyFrameElement *anim_info_next = &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number]; + ULONG colour = FIGURE_dhpr_data.colour; + ULONG specular = FIGURE_dhpr_data.specular; + CMatrix33 *parent_base_mat = FIGURE_dhpr_rdata1[recurse_level].parent_base_mat; + Matrix31 *parent_base_pos = FIGURE_dhpr_rdata1[recurse_level].parent_base_pos; + Matrix33 *parent_curr_mat = FIGURE_dhpr_rdata1[recurse_level].parent_current_mat; + Matrix31 *parent_curr_pos = FIGURE_dhpr_rdata1[recurse_level].parent_current_pos; + Matrix33 *end_mat = &FIGURE_dhpr_rdata2[recurse_level].end_mat; + Matrix31 *end_pos = &FIGURE_dhpr_rdata2[recurse_level].end_pos; + + + + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG nx; + SLONG ny; + SLONG nz; + + SLONG red; + SLONG green; + SLONG blue; + SLONG dprod; + SLONG r; + SLONG g; + SLONG b; + + SLONG dr; + SLONG dg; + SLONG db; + + SLONG face_colour; + + SLONG page; + + Matrix31 offset; + Matrix33 mat2; + Matrix33 mat_final; + + ULONG qc0; + ULONG qc1; + ULONG qc2; + ULONG qc3; + + SVector temp; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + NIGHT_Found *nf; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + SLONG tex_page_offset; + + + LOG_ENTER ( Figure_Draw_Prim_Tween ) + + tex_page_offset=p_thing->Genus.Person->pcom_colour&0x3; + + // + // Matrix functions we use. + // + + void matrix_transform (Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_mult33 (Matrix33* result, Matrix33* mat1, Matrix33* mat2); + + if (parent_base_mat) + { + // we've got hierarchy info! + + Matrix31 p; + p.M[0] = anim_info->OffsetX; + p.M[1] = anim_info->OffsetY; + p.M[2] = anim_info->OffsetZ; + + HIERARCHY_Get_Body_Part_Offset(&offset, &p, + parent_base_mat, parent_base_pos, + parent_curr_mat, parent_curr_pos); + + // pass data up the hierarchy + if (end_pos) + *end_pos = offset; + } + else + { + // process at highter resolution + offset.M[0] = (anim_info->OffsetX << 8) + ((anim_info_next->OffsetX + off_dx - anim_info->OffsetX) * tween); + offset.M[1] = (anim_info->OffsetY << 8) + ((anim_info_next->OffsetY + off_dy - anim_info->OffsetY) * tween); + offset.M[2] = (anim_info->OffsetZ << 8) + ((anim_info_next->OffsetZ + off_dz - anim_info->OffsetZ) * tween); + + if (end_pos) + { + *end_pos = offset; + } + } + + + // convert pos to floating point here to preserve accuracy and prevent overflow. + // It's also a shitload faster on P2 and SH4. + float off_x = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[0][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[0][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[0][2]) / 32768.f); + float off_y = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[1][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[1][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[1][2]) / 32768.f); + float off_z = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[2][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[2][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[2][2]) / 32768.f); + + + SLONG character_scale = person_get_scale(p_thing); + float character_scalef = float(character_scale) / 256.f; + + off_x *= character_scalef; + off_y *= character_scalef; + off_z *= character_scalef; + + off_x += float(x); + off_y += float(y); + off_z += float(z); + + // + // Do everything in floats. + // + + float fmatrix[9]; + //SLONG imatrix[9]; + + // + // Create a temporary "tween" matrix between current and next + // + + CMatrix33 m1, m2; + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + CQuaternion::BuildTween(&mat2, &m1, &m2, tween); + + // pass data up the hierarchy + if (end_mat) + *end_mat = mat2; + + // + // Apply local rotation matrix to get mat_final that rotates + // the point into world space. + // + + matrix_mult33(&mat_final, rot_mat, &mat2); + + //! yeehaw! + mat_final.M[0][0] = (mat_final.M[0][0] * character_scale) / 256; + mat_final.M[0][1] = (mat_final.M[0][1] * character_scale) / 256; + mat_final.M[0][2] = (mat_final.M[0][2] * character_scale) / 256; + mat_final.M[1][0] = (mat_final.M[1][0] * character_scale) / 256; + mat_final.M[1][1] = (mat_final.M[1][1] * character_scale) / 256; + mat_final.M[1][2] = (mat_final.M[1][2] * character_scale) / 256; + mat_final.M[2][0] = (mat_final.M[2][0] * character_scale) / 256; + mat_final.M[2][1] = (mat_final.M[2][1] * character_scale) / 256; + mat_final.M[2][2] = (mat_final.M[2][2] * character_scale) / 256; + + fmatrix[0] = float(mat_final.M[0][0]) * (1.0F / 32768.0F); + fmatrix[1] = float(mat_final.M[0][1]) * (1.0F / 32768.0F); + fmatrix[2] = float(mat_final.M[0][2]) * (1.0F / 32768.0F); + fmatrix[3] = float(mat_final.M[1][0]) * (1.0F / 32768.0F); + fmatrix[4] = float(mat_final.M[1][1]) * (1.0F / 32768.0F); + fmatrix[5] = float(mat_final.M[1][2]) * (1.0F / 32768.0F); + fmatrix[6] = float(mat_final.M[2][0]) * (1.0F / 32768.0F); + fmatrix[7] = float(mat_final.M[2][1]) * (1.0F / 32768.0F); + fmatrix[8] = float(mat_final.M[2][2]) * (1.0F / 32768.0F); + + + + + + LOG_ENTER ( Figure_Set_Rotation ) + + POLY_set_local_rotation( + off_x, + off_y, + off_z, + fmatrix); + + LOG_ENTER ( Figure_Set_Rotation ) + + + + // Not 100% sure if I'm using character_scalef correctly... + // ...but it seems to work OK. + ASSERT ( ( character_scalef < 1.2f ) && ( character_scalef > 0.8f ) ); + //ASSERT ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) ); + if ( ( ( ( g_matWorld._43 * 32768.0f ) - ( (m_fObjectBoundingSphereRadius[prim]) * character_scalef ) ) < ( POLY_ZCLIP_PLANE * 32768.0f ) ) ) + { + // Clipped by Z-plane. Don't set this matrix up, just return. + return FALSE; + } + + + + // + // Rotate all the points into the POLY_buffer. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + POLY_buffer_upto = 0; + + // Check for being a gun + if (prim==256) + { + i=sp; + } + else if (prim==258) + { + // Or a shotgun + i=sp+15; + } + else if (prim==260) + { + // or an AK + i=sp+32; + } + else + { + goto no_muzzle_calcs; // which skips... + } + + + // + // this bit, which only executes if one of the above tests is true. + // + pp = &POLY_buffer[POLY_buffer_upto]; // no ++, so reused + pp->x=AENG_dx_prim_points[i].X; + pp->y=AENG_dx_prim_points[i].Y; + pp->z=AENG_dx_prim_points[i].Z; + MATRIX_MUL( + fmatrix, + pp->x, + pp->y, + pp->z); + + pp->x+=off_x; pp->y+=off_y; pp->z+=off_z; + p_thing->Genus.Person->GunMuzzle.X=pp->x*256; + p_thing->Genus.Person->GunMuzzle.Y=pp->y*256; + p_thing->Genus.Person->GunMuzzle.Z=pp->z*256; +// x=pp->x*256; y=pp->y*256; z=pp->z*256; + + +no_muzzle_calcs: + + + +#if !USE_TOMS_ENGINE_PLEASE_BOB +#error Dont use this rout if USE_TOMS_ENGINE_PLEASE_BOB is not 1 +#endif + + + ASSERT ( MM_bLightTableAlreadySetUp ); + + ASSERT (!WITHIN(prim, 261, 263)); + + { + + ASSERT ( MM_bLightTableAlreadySetUp ); + + LOG_ENTER ( Figure_Build_Matrices ) + + extern float POLY_cam_matrix_comb[9]; + extern float POLY_cam_off_x; + extern float POLY_cam_off_y; + extern float POLY_cam_off_z; + + + extern D3DMATRIX g_matProjection; + extern D3DMATRIX g_matWorld; + extern D3DVIEWPORT2 g_viewData; + + + D3DMATRIX matTemp; + + matTemp._11 = g_matWorld._11*g_matProjection._11 + g_matWorld._12*g_matProjection._21 + g_matWorld._13*g_matProjection._31 + g_matWorld._14*g_matProjection._41; + matTemp._12 = g_matWorld._11*g_matProjection._12 + g_matWorld._12*g_matProjection._22 + g_matWorld._13*g_matProjection._32 + g_matWorld._14*g_matProjection._42; + matTemp._13 = g_matWorld._11*g_matProjection._13 + g_matWorld._12*g_matProjection._23 + g_matWorld._13*g_matProjection._33 + g_matWorld._14*g_matProjection._43; + matTemp._14 = g_matWorld._11*g_matProjection._14 + g_matWorld._12*g_matProjection._24 + g_matWorld._13*g_matProjection._34 + g_matWorld._14*g_matProjection._44; + + matTemp._21 = g_matWorld._21*g_matProjection._11 + g_matWorld._22*g_matProjection._21 + g_matWorld._23*g_matProjection._31 + g_matWorld._24*g_matProjection._41; + matTemp._22 = g_matWorld._21*g_matProjection._12 + g_matWorld._22*g_matProjection._22 + g_matWorld._23*g_matProjection._32 + g_matWorld._24*g_matProjection._42; + matTemp._23 = g_matWorld._21*g_matProjection._13 + g_matWorld._22*g_matProjection._23 + g_matWorld._23*g_matProjection._33 + g_matWorld._24*g_matProjection._43; + matTemp._24 = g_matWorld._21*g_matProjection._14 + g_matWorld._22*g_matProjection._24 + g_matWorld._23*g_matProjection._34 + g_matWorld._24*g_matProjection._44; + + matTemp._31 = g_matWorld._31*g_matProjection._11 + g_matWorld._32*g_matProjection._21 + g_matWorld._33*g_matProjection._31 + g_matWorld._34*g_matProjection._41; + matTemp._32 = g_matWorld._31*g_matProjection._12 + g_matWorld._32*g_matProjection._22 + g_matWorld._33*g_matProjection._32 + g_matWorld._34*g_matProjection._42; + matTemp._33 = g_matWorld._31*g_matProjection._13 + g_matWorld._32*g_matProjection._23 + g_matWorld._33*g_matProjection._33 + g_matWorld._34*g_matProjection._43; + matTemp._34 = g_matWorld._31*g_matProjection._14 + g_matWorld._32*g_matProjection._24 + g_matWorld._33*g_matProjection._34 + g_matWorld._34*g_matProjection._44; + + matTemp._41 = g_matWorld._41*g_matProjection._11 + g_matWorld._42*g_matProjection._21 + g_matWorld._43*g_matProjection._31 + g_matWorld._44*g_matProjection._41; + matTemp._42 = g_matWorld._41*g_matProjection._12 + g_matWorld._42*g_matProjection._22 + g_matWorld._43*g_matProjection._32 + g_matWorld._44*g_matProjection._42; + matTemp._43 = g_matWorld._41*g_matProjection._13 + g_matWorld._42*g_matProjection._23 + g_matWorld._43*g_matProjection._33 + g_matWorld._44*g_matProjection._43; + matTemp._44 = g_matWorld._41*g_matProjection._14 + g_matWorld._42*g_matProjection._24 + g_matWorld._43*g_matProjection._34 + g_matWorld._44*g_matProjection._44; + + + + + + + + // Now make up the matrices. + +#if 0 + // Officially correct version. + DWORD dwWidth = g_viewData.dwWidth >> 1; + DWORD dwHeight = g_viewData.dwHeight >> 1; + DWORD dwX = g_viewData.dwX; + DWORD dwY = g_viewData.dwY; +#else + // Version that knows about the letterbox mode hack. +extern DWORD g_dw3DStuffHeight; +extern DWORD g_dw3DStuffY; + DWORD dwWidth = g_viewData.dwWidth >> 1; + DWORD dwHeight = g_dw3DStuffHeight >> 1; + DWORD dwX = g_viewData.dwX; + DWORD dwY = g_dw3DStuffY; +#endif + + // Set up the matrix. + D3DMATRIX *pmat = &(MMBodyParts_pMatrix[iMatrixNum]); + pmat->_11 = 0.0f; + pmat->_12 = matTemp._11 * (float)dwWidth + matTemp._14 * (float)( dwX + dwWidth ); + pmat->_13 = matTemp._12 * - (float)dwHeight + matTemp._14 * (float)( dwY + dwHeight ); + pmat->_14 = matTemp._14; + pmat->_21 = 0.0f; + pmat->_22 = matTemp._21 * (float)dwWidth + matTemp._24 * (float)( dwX + dwWidth ); + pmat->_23 = matTemp._22 * - (float)dwHeight + matTemp._24 * (float)( dwY + dwHeight ); + pmat->_24 = matTemp._24; + pmat->_31 = 0.0f; + pmat->_32 = matTemp._31 * (float)dwWidth + matTemp._34 * (float)( dwX + dwWidth ); + pmat->_33 = matTemp._32 * - (float)dwHeight + matTemp._34 * (float)( dwY + dwHeight ); + pmat->_34 = matTemp._34; + // Validation magic number. + unsigned long EVal = 0xe0001000; + pmat->_41 = *(float *)&EVal; + pmat->_42 = matTemp._41 * (float)dwWidth + matTemp._44 * (float)( dwX + dwWidth ); + pmat->_43 = matTemp._42 * - (float)dwHeight + matTemp._44 * (float)( dwY + dwHeight ); + pmat->_44 = matTemp._44; + + + + // 251 is a magic number for the DIP call! + const float fNormScale = 251.0f; + + // Transform the lighting direction(s) by the inverse object matrix to get it into object space. + // Assume inverse=transpose. + D3DVECTOR vTemp; + vTemp.x = MM_vLightDir.x * fmatrix[0] + MM_vLightDir.y * fmatrix[3] + MM_vLightDir.z * fmatrix[6]; + vTemp.y = MM_vLightDir.x * fmatrix[1] + MM_vLightDir.y * fmatrix[4] + MM_vLightDir.z * fmatrix[7]; + vTemp.z = MM_vLightDir.x * fmatrix[2] + MM_vLightDir.y * fmatrix[5] + MM_vLightDir.z * fmatrix[8]; + + // Set up the lighting vector. + float *pnorm = &(MMBodyParts_pNormal[iMatrixNum<<2]); + pnorm[0] = 0.0f; + pnorm[1] = vTemp.x * fNormScale; + pnorm[2] = vTemp.y * fNormScale; + pnorm[3] = vTemp.z * fNormScale; + + + LOG_EXIT ( Figure_Build_Matrices ) + } + + + // No environment mapping. + ASSERT ( p_thing && ( p_thing->Class != CLASS_VEHICLE ) ); + + ASSERT ( MM_bLightTableAlreadySetUp ); + + LOG_EXIT ( Figure_Draw_Prim_Tween ) + + return TRUE; + +} + + + + + + + +// Like FIGURE_draw_prim_tween, but optimised for the person-only case. +// Also assumes the lighting has been set up, etc. +void FIGURE_draw_prim_tween_person_only( + SLONG prim, + //SLONG x, + //SLONG y, + //SLONG z, + //SLONG tween, + //struct GameKeyFrameElement *anim_info, + //struct GameKeyFrameElement *anim_info_next, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + //ULONG colour, + //ULONG specular, + SLONG recurse_level, + //CMatrix33 *parent_base_mat, + //Matrix31 *parent_base_pos, + //Matrix33 *parent_curr_mat, + //Matrix31 *parent_curr_pos, + //Matrix33 *end_mat, + //Matrix31 *end_pos, + Thing *p_thing + //SLONG part_number = 0xffffffff, + //ULONG colour_and = 0xffffffff + ) +{ + + + SLONG x = FIGURE_dhpr_data.world_pos->M[0]; + SLONG y = FIGURE_dhpr_data.world_pos->M[1]; + SLONG z = FIGURE_dhpr_data.world_pos->M[2]; + SLONG tween = FIGURE_dhpr_data.tween; + struct GameKeyFrameElement *anim_info = &FIGURE_dhpr_data.ae1[FIGURE_dhpr_rdata1[recurse_level].part_number]; + struct GameKeyFrameElement *anim_info_next = &FIGURE_dhpr_data.ae2[FIGURE_dhpr_rdata1[recurse_level].part_number]; + ULONG colour = FIGURE_dhpr_data.colour; + ULONG specular = FIGURE_dhpr_data.specular; + CMatrix33 *parent_base_mat = FIGURE_dhpr_rdata1[recurse_level].parent_base_mat; + Matrix31 *parent_base_pos = FIGURE_dhpr_rdata1[recurse_level].parent_base_pos; + Matrix33 *parent_curr_mat = FIGURE_dhpr_rdata1[recurse_level].parent_current_mat; + Matrix31 *parent_curr_pos = FIGURE_dhpr_rdata1[recurse_level].parent_current_pos; + Matrix33 *end_mat = &FIGURE_dhpr_rdata2[recurse_level].end_mat; + Matrix31 *end_pos = &FIGURE_dhpr_rdata2[recurse_level].end_pos; + SLONG part_number = FIGURE_dhpr_rdata1[recurse_level].part_number; + //ULONG colour_and = 0xffffffff; + + + + + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG nx; + SLONG ny; + SLONG nz; + + SLONG red; + SLONG green; + SLONG blue; + SLONG dprod; + SLONG r; + SLONG g; + SLONG b; + + SLONG dr; + SLONG dg; + SLONG db; + + SLONG face_colour; + + SLONG page; + + Matrix31 offset; + Matrix33 mat2; + Matrix33 mat_final; + + ULONG qc0; + ULONG qc1; + ULONG qc2; + ULONG qc3; + + SVector temp; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + NIGHT_Found *nf; + + POLY_Point *pp; + POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + SLONG tex_page_offset; + + + LOG_ENTER ( Figure_Draw_Prim_Tween ) + + tex_page_offset=p_thing->Genus.Person->pcom_colour&0x3; + + // + // Matrix functions we use. + // + + void matrix_transform (Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_mult33 (Matrix33* result, Matrix33* mat1, Matrix33* mat2); + + if (parent_base_mat) + { + // we've got hierarchy info! + + Matrix31 p; + p.M[0] = anim_info->OffsetX; + p.M[1] = anim_info->OffsetY; + p.M[2] = anim_info->OffsetZ; + + HIERARCHY_Get_Body_Part_Offset(&offset, &p, + parent_base_mat, parent_base_pos, + parent_curr_mat, parent_curr_pos); + + // pass data up the hierarchy + if (end_pos) + *end_pos = offset; + } + else + { + // process at highter resolution + offset.M[0] = (anim_info->OffsetX << 8) + ((anim_info_next->OffsetX + off_dx - anim_info->OffsetX) * tween); + offset.M[1] = (anim_info->OffsetY << 8) + ((anim_info_next->OffsetY + off_dy - anim_info->OffsetY) * tween); + offset.M[2] = (anim_info->OffsetZ << 8) + ((anim_info_next->OffsetZ + off_dz - anim_info->OffsetZ) * tween); + + if (end_pos) + { + *end_pos = offset; + } + } + + + // convert pos to floating point here to preserve accuracy and prevent overflow. + // It's also a shitload faster on P2 and SH4. + float off_x = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[0][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[0][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[0][2]) / 32768.f); + float off_y = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[1][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[1][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[1][2]) / 32768.f); + float off_z = (float(offset.M[0]) / 256.f) * (float(rot_mat->M[2][0]) / 32768.f) + + (float(offset.M[1]) / 256.f) * (float(rot_mat->M[2][1]) / 32768.f) + + (float(offset.M[2]) / 256.f) * (float(rot_mat->M[2][2]) / 32768.f); + + + SLONG character_scale = person_get_scale(p_thing); + float character_scalef = float(character_scale) / 256.f; + + off_x *= character_scalef; + off_y *= character_scalef; + off_z *= character_scalef; + + off_x += float(x); + off_y += float(y); + off_z += float(z); + + // + // Do everything in floats. + // + + float fmatrix[9]; + //SLONG imatrix[9]; + + // + // Create a temporary "tween" matrix between current and next + // + + CMatrix33 m1, m2; + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + CQuaternion::BuildTween(&mat2, &m1, &m2, tween); + + // pass data up the hierarchy + if (end_mat) + *end_mat = mat2; + + // + // Apply local rotation matrix to get mat_final that rotates + // the point into world space. + // + + matrix_mult33(&mat_final, rot_mat, &mat2); + + //! yeehaw! + mat_final.M[0][0] = (mat_final.M[0][0] * character_scale) / 256; + mat_final.M[0][1] = (mat_final.M[0][1] * character_scale) / 256; + mat_final.M[0][2] = (mat_final.M[0][2] * character_scale) / 256; + mat_final.M[1][0] = (mat_final.M[1][0] * character_scale) / 256; + mat_final.M[1][1] = (mat_final.M[1][1] * character_scale) / 256; + mat_final.M[1][2] = (mat_final.M[1][2] * character_scale) / 256; + mat_final.M[2][0] = (mat_final.M[2][0] * character_scale) / 256; + mat_final.M[2][1] = (mat_final.M[2][1] * character_scale) / 256; + mat_final.M[2][2] = (mat_final.M[2][2] * character_scale) / 256; + + fmatrix[0] = float(mat_final.M[0][0]) * (1.0F / 32768.0F); + fmatrix[1] = float(mat_final.M[0][1]) * (1.0F / 32768.0F); + fmatrix[2] = float(mat_final.M[0][2]) * (1.0F / 32768.0F); + fmatrix[3] = float(mat_final.M[1][0]) * (1.0F / 32768.0F); + fmatrix[4] = float(mat_final.M[1][1]) * (1.0F / 32768.0F); + fmatrix[5] = float(mat_final.M[1][2]) * (1.0F / 32768.0F); + fmatrix[6] = float(mat_final.M[2][0]) * (1.0F / 32768.0F); + fmatrix[7] = float(mat_final.M[2][1]) * (1.0F / 32768.0F); + fmatrix[8] = float(mat_final.M[2][2]) * (1.0F / 32768.0F); + +#if 0 + imatrix[0] = mat_final.M[0][0] * 2; + imatrix[1] = mat_final.M[0][1] * 2; + imatrix[2] = mat_final.M[0][2] * 2; + imatrix[3] = mat_final.M[1][0] * 2; + imatrix[4] = mat_final.M[1][1] * 2; + imatrix[5] = mat_final.M[1][2] * 2; + imatrix[6] = mat_final.M[2][0] * 2; + imatrix[7] = mat_final.M[2][1] * 2; + imatrix[8] = mat_final.M[2][2] * 2; +#endif + + + LOG_ENTER ( Figure_Set_Rotation ) + + POLY_set_local_rotation( + off_x, + off_y, + off_z, + fmatrix); + + LOG_ENTER ( Figure_Set_Rotation ) + + + // + // Rotate all the points into the POLY_buffer. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + POLY_buffer_upto = 0; + + // Check for being a gun + if (prim==256) + { + i=sp; + } + else if (prim==258) + { + // Or a shotgun + i=sp+15; + } + else if (prim==260) + { + // or an AK + i=sp+32; + } + else + { + goto no_muzzle_calcs; // which skips... + } + + + // + // this bit, which only executes if one of the above tests is true. + // + pp = &POLY_buffer[POLY_buffer_upto]; // no ++, so reused + pp->x=AENG_dx_prim_points[i].X; + pp->y=AENG_dx_prim_points[i].Y; + pp->z=AENG_dx_prim_points[i].Z; + MATRIX_MUL( + fmatrix, + pp->x, + pp->y, + pp->z); + + pp->x+=off_x; pp->y+=off_y; pp->z+=off_z; + p_thing->Genus.Person->GunMuzzle.X=pp->x*256; + p_thing->Genus.Person->GunMuzzle.Y=pp->y*256; + p_thing->Genus.Person->GunMuzzle.Z=pp->z*256; +// x=pp->x*256; y=pp->y*256; z=pp->z*256; + + +no_muzzle_calcs: + + + +#if !USE_TOMS_ENGINE_PLEASE_BOB +#error Dont use this rout if USE_TOMS_ENGINE_PLEASE_BOB is not 1 +#endif + + + ASSERT ( MM_bLightTableAlreadySetUp ); + + if (WITHIN(prim, 261, 263)) + { + // + // This is a muzzle flash! They don't have any lighting! + // + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform_using_local_rotation( + AENG_dx_prim_points[i].X, + AENG_dx_prim_points[i].Y, + AENG_dx_prim_points[i].Z, + pp); + + pp->colour = 0xff808080; + pp->specular = 0xff000000; + } + + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + + if(tex_page_offset && page>10*64 && alt_texture[page-10*64]) + { + page=alt_texture[page-10*64]+tex_page_offset-1; + } + else + page+=FACE_PAGE_OFFSET; + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + + LOG_EXIT ( Figure_Draw_Prim_Tween ) + return; + } + else + { + + + + ASSERT ( MM_bLightTableAlreadySetUp ); + + LOG_ENTER ( Figure_Build_Matrices ) + + extern float POLY_cam_matrix_comb[9]; + extern float POLY_cam_off_x; + extern float POLY_cam_off_y; + extern float POLY_cam_off_z; + + + extern D3DMATRIX g_matProjection; + extern D3DMATRIX g_matWorld; + extern D3DVIEWPORT2 g_viewData; + + + D3DMATRIX matTemp; + + matTemp._11 = g_matWorld._11*g_matProjection._11 + g_matWorld._12*g_matProjection._21 + g_matWorld._13*g_matProjection._31 + g_matWorld._14*g_matProjection._41; + matTemp._12 = g_matWorld._11*g_matProjection._12 + g_matWorld._12*g_matProjection._22 + g_matWorld._13*g_matProjection._32 + g_matWorld._14*g_matProjection._42; + matTemp._13 = g_matWorld._11*g_matProjection._13 + g_matWorld._12*g_matProjection._23 + g_matWorld._13*g_matProjection._33 + g_matWorld._14*g_matProjection._43; + matTemp._14 = g_matWorld._11*g_matProjection._14 + g_matWorld._12*g_matProjection._24 + g_matWorld._13*g_matProjection._34 + g_matWorld._14*g_matProjection._44; + + matTemp._21 = g_matWorld._21*g_matProjection._11 + g_matWorld._22*g_matProjection._21 + g_matWorld._23*g_matProjection._31 + g_matWorld._24*g_matProjection._41; + matTemp._22 = g_matWorld._21*g_matProjection._12 + g_matWorld._22*g_matProjection._22 + g_matWorld._23*g_matProjection._32 + g_matWorld._24*g_matProjection._42; + matTemp._23 = g_matWorld._21*g_matProjection._13 + g_matWorld._22*g_matProjection._23 + g_matWorld._23*g_matProjection._33 + g_matWorld._24*g_matProjection._43; + matTemp._24 = g_matWorld._21*g_matProjection._14 + g_matWorld._22*g_matProjection._24 + g_matWorld._23*g_matProjection._34 + g_matWorld._24*g_matProjection._44; + + matTemp._31 = g_matWorld._31*g_matProjection._11 + g_matWorld._32*g_matProjection._21 + g_matWorld._33*g_matProjection._31 + g_matWorld._34*g_matProjection._41; + matTemp._32 = g_matWorld._31*g_matProjection._12 + g_matWorld._32*g_matProjection._22 + g_matWorld._33*g_matProjection._32 + g_matWorld._34*g_matProjection._42; + matTemp._33 = g_matWorld._31*g_matProjection._13 + g_matWorld._32*g_matProjection._23 + g_matWorld._33*g_matProjection._33 + g_matWorld._34*g_matProjection._43; + matTemp._34 = g_matWorld._31*g_matProjection._14 + g_matWorld._32*g_matProjection._24 + g_matWorld._33*g_matProjection._34 + g_matWorld._34*g_matProjection._44; + + matTemp._41 = g_matWorld._41*g_matProjection._11 + g_matWorld._42*g_matProjection._21 + g_matWorld._43*g_matProjection._31 + g_matWorld._44*g_matProjection._41; + matTemp._42 = g_matWorld._41*g_matProjection._12 + g_matWorld._42*g_matProjection._22 + g_matWorld._43*g_matProjection._32 + g_matWorld._44*g_matProjection._42; + matTemp._43 = g_matWorld._41*g_matProjection._13 + g_matWorld._42*g_matProjection._23 + g_matWorld._43*g_matProjection._33 + g_matWorld._44*g_matProjection._43; + matTemp._44 = g_matWorld._41*g_matProjection._14 + g_matWorld._42*g_matProjection._24 + g_matWorld._43*g_matProjection._34 + g_matWorld._44*g_matProjection._44; + + + + + + + + // Now make up the matrices. + +#if 0 + // Officially correct version. + DWORD dwWidth = g_viewData.dwWidth >> 1; + DWORD dwHeight = g_viewData.dwHeight >> 1; + DWORD dwX = g_viewData.dwX; + DWORD dwY = g_viewData.dwY; +#else + // Version that knows about the letterbox mode hack. +extern DWORD g_dw3DStuffHeight; +extern DWORD g_dw3DStuffY; + DWORD dwWidth = g_viewData.dwWidth >> 1; + DWORD dwHeight = g_dw3DStuffHeight >> 1; + DWORD dwX = g_viewData.dwX; + DWORD dwY = g_dw3DStuffY; +#endif + MM_pMatrix[0]._11 = 0.0f; + MM_pMatrix[0]._12 = matTemp._11 * (float)dwWidth + matTemp._14 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._13 = matTemp._12 * - (float)dwHeight + matTemp._14 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._14 = matTemp._14; + MM_pMatrix[0]._21 = 0.0f; + MM_pMatrix[0]._22 = matTemp._21 * (float)dwWidth + matTemp._24 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._23 = matTemp._22 * - (float)dwHeight + matTemp._24 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._24 = matTemp._24; + MM_pMatrix[0]._31 = 0.0f; + MM_pMatrix[0]._32 = matTemp._31 * (float)dwWidth + matTemp._34 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._33 = matTemp._32 * - (float)dwHeight + matTemp._34 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._34 = matTemp._34; + // Validation magic number. + unsigned long EVal = 0xe0001000; + MM_pMatrix[0]._41 = *(float *)&EVal; + MM_pMatrix[0]._42 = matTemp._41 * (float)dwWidth + matTemp._44 * (float)( dwX + dwWidth ); + MM_pMatrix[0]._43 = matTemp._42 * - (float)dwHeight + matTemp._44 * (float)( dwY + dwHeight ); + MM_pMatrix[0]._44 = matTemp._44; + + + + // 251 is a magic number for the DIP call! + const float fNormScale = 251.0f; + + // Transform the lighting direction(s) by the inverse object matrix to get it into object space. + // Assume inverse=transpose. + D3DVECTOR vTemp; + vTemp.x = MM_vLightDir.x * fmatrix[0] + MM_vLightDir.y * fmatrix[3] + MM_vLightDir.z * fmatrix[6]; + vTemp.y = MM_vLightDir.x * fmatrix[1] + MM_vLightDir.y * fmatrix[4] + MM_vLightDir.z * fmatrix[7]; + vTemp.z = MM_vLightDir.x * fmatrix[2] + MM_vLightDir.y * fmatrix[5] + MM_vLightDir.z * fmatrix[8]; + + MM_pNormal[0] = 0.0f; + MM_pNormal[1] = vTemp.x * fNormScale; + MM_pNormal[2] = vTemp.y * fNormScale; + MM_pNormal[3] = vTemp.z * fNormScale; + + LOG_EXIT ( Figure_Build_Matrices ) + } + + + + // The wonderful NEW system! + + + LOG_ENTER ( Figure_Draw_Polys ) + +#if 1 + // The MM stuff doesn't like specular to be enabled. + (the_display.lp_D3D_Device)->SetRenderState ( D3DRENDERSTATE_SPECULARENABLE, FALSE ); +#endif + + + // For now, just calculate as-and-when. + TomsPrimObject *pPrimObj = &(D3DObj[prim]); + if ( pPrimObj->wNumMaterials == 0 ) + { + // Not initialised. Do so. + // It's not fair to count this as part of the drawing! :-) + LOG_EXIT ( Figure_Draw_Polys ) + + FIGURE_generate_D3D_object ( prim ); + LOG_ENTER ( Figure_Draw_Polys ) + } + + // Tell the LRU cache we used this one. + FIGURE_touch_LRU_of_object ( pPrimObj ); + + ASSERT ( pPrimObj->pD3DVertices != NULL ); + ASSERT ( pPrimObj->pMaterials != NULL ); + ASSERT ( pPrimObj->pwListIndices != NULL ); + ASSERT ( pPrimObj->pwStripIndices != NULL ); + ASSERT ( pPrimObj->wNumMaterials != 0 ); + + PrimObjectMaterial *pMat = pPrimObj->pMaterials; + + D3DMULTIMATRIX d3dmm; + d3dmm.lpd3dMatrices = MM_pMatrix; + d3dmm.lpvLightDirs = MM_pNormal; + + D3DVERTEX *pVertex = (D3DVERTEX *)pPrimObj->pD3DVertices; + UWORD *pwListIndices = pPrimObj->pwListIndices; + UWORD *pwStripIndices = pPrimObj->pwStripIndices; + for ( int iMatNum = pPrimObj->wNumMaterials; iMatNum > 0; iMatNum-- ) + { + // Set up the right texture for this material. + + UWORD wPage = pMat->wTexturePage; + UWORD wRealPage = wPage & TEXTURE_PAGE_MASK; + + if ( wPage & TEXTURE_PAGE_FLAG_JACKET ) + { + // Find the real jacket page. + wRealPage = jacket_lookup [ wRealPage ][GET_SKILL(p_thing)>>2]; + wRealPage += FACE_PAGE_OFFSET; + } + else if ( wPage & TEXTURE_PAGE_FLAG_OFFSET ) + { + // An "offset" texture. This will be offset by a certain amount to + // allow each prim to have different coloured clothes on. + if ( tex_page_offset == 0 ) + { + // No lookup offset. + // This has not been offset yet. + wRealPage += FACE_PAGE_OFFSET; + } + else + { + // Look this up. + wRealPage = alt_texture[wRealPage-(10*64)]+tex_page_offset-1; + } + } + +#ifdef DEBUG + if ( wPage & TEXTURE_PAGE_FLAG_NOT_TEXTURED ) + { + ASSERT ( wRealPage == POLY_PAGE_COLOUR ); + } +#endif + +extern D3DMATRIX g_matWorld; + + PolyPage *pa = &(POLY_Page[wRealPage]); + // Not sure if I'm using character_scalef correctly... + ASSERT ( ( character_scalef < 1.2f ) && ( character_scalef > 0.8f ) ); + ASSERT ( !pa->RS.NeedsSorting() && ( FIGURE_alpha == 255 ) ); + if ( ( ( ( g_matWorld._43 * 32768.0f ) - ( pPrimObj->fBoundingSphereRadius * character_scalef ) ) > ( POLY_ZCLIP_PLANE * 32768.0f ) ) ) + { + // Non-alpha path. + if ( wPage & TEXTURE_PAGE_FLAG_TINT ) + { + // Tinted colours. + d3dmm.lpLightTable = MM_pcFadeTableTint; + } + else + { + // Normal. + d3dmm.lpLightTable = MM_pcFadeTable; + } + d3dmm.lpvVertices = pVertex; + + + +#if 1 + + + +#ifdef DEBUG +static int iCounter = 0; + if ( iCounter != 0 ) + { + iCounter--; + ASSERT ( iCounter != 0 ); + } +#endif + + // Fast as lightning. + LOG_ENTER ( Figure_Set_RenderState ) + pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + LOG_EXIT ( Figure_Set_RenderState ) + LOG_ENTER ( Figure_DrawIndPrimMM ) + + +#if 0 + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); + //TRACE("Drew %i vertices, %i indices\n", (int)( pMat->wNumVertices ), (int)( pMat->wNumStripIndices ) ); +#else + // Use platform-independent version. + + HRESULT hres; + + + + +#define SHOW_ME_FIGURE_DEBUGGING_PLEASE_BOB defined + +#ifdef SHOW_ME_FIGURE_DEBUGGING_PLEASE_BOB +#ifdef DEBUG +#ifdef TARGET_DC +#define BUTTON_IS_PRESSED(value) ((value&0x80)!=0) +extern DIJOYSTATE the_state; + bool bShowDebug = FALSE; + if ( BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_LTRIGGER] ) && BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_RTRIGGER] ) ) + { + DWORD dwColour = (DWORD)pwStripIndices; + dwColour = ( dwColour >> 2 ) ^ ( dwColour >> 6 ) ^ ( dwColour ) ^ ( dwColour << 3 ); + dwColour = ( dwColour << 9 ) ^ ( dwColour << 19 ) ^ ( dwColour ) ^ ( dwColour << 29 ) ^ ( dwColour >> 3 ); + dwColour &= 0x7f7f7f7f; + for ( int i = 0; i < 128; i++ ) + { + d3dmm.lpLightTable[i] = dwColour; + } + + // And NULL texture (i.e. white). + the_display.lp_D3D_Device->SetTexture ( 0, NULL ); + } +#endif +#endif +#endif + + + + //if (pMat->wNumVertices && + // pMat->wNumStripIndices) + { + //TRACE ( "S4" ); + hres = DrawIndPrimMM ( + (the_display.lp_D3D_Device), + D3DFVF_VERTEX, + &d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices ); + //TRACE ( "F4" ); + } +#endif + + + + +#else + + // Do some performance tracing. +#ifndef DTRACE +#error Don't use this codepath unless DTRACING, fool! +#endif + + LOG_ENTER ( Figure_Set_RenderState ) + pa->RS.SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW ); + pa->RS.SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + pa->RS.SetRenderState ( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA ); + pa->RS.SetChanged(); + + WORD wTempVerts[4]; + wTempVerts[0] = 0; + wTempVerts[1] = 1; + wTempVerts[2] = 2; + wTempVerts[3] = -1; + (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + 3, + wTempVerts, + 4, + D3DDP_MULTIMATRIX ); + LOG_EXIT ( Figure_Set_RenderState ) + + LOG_ENTER ( Figure_DrawIndPrimMM ) + HRESULT hres = (the_display.lp_D3D_Device)->DrawIndexedPrimitive ( + D3DPT_TRIANGLELIST, + D3DFVF_VERTEX, + (void *)&d3dmm, + pMat->wNumVertices, + pwStripIndices, + pMat->wNumStripIndices, + D3DDP_MULTIMATRIX ); + //TRACE("Drew %i vertices, %i indices\n", (int)( pMat->wNumVertices ), (int)( pMat->wNumStripIndices ) ); + +#endif + +// ASSERT ( SUCCEEDED ( hres ) ); //triggers all the time when inside on start of RTA + LOG_EXIT ( Figure_DrawIndPrimMM ) + + } + else + { + // Alpha/clipped path - do with standard non-MM calls. + // FIXME. Needs to be done. + + // Actually, the fast-accept works very well, and it's only when the camera somehow gets REALLY close + // that this happens. And actually a pop-reject seems a bit better than a clip. Certainly + // there is no visually "right" thing to do. So leave it for now until someone complains. ATF. + //TRACE ( "Tried to draw an alpha/clipped prim!" ); + } + + + + // Next material + pVertex += pMat->wNumVertices; + pwListIndices += pMat->wNumListIndices; + pwStripIndices += pMat->wNumStripIndices; + + pMat++; + } + +#if 1 + // The MM stuff doesn't like specular to be enabled. + (the_display.lp_D3D_Device)->SetRenderState ( D3DRENDERSTATE_SPECULARENABLE, TRUE ); +#endif + + LOG_EXIT ( Figure_Draw_Polys ) + + + + // No environment mapping. + ASSERT ( p_thing && ( p_thing->Class != CLASS_VEHICLE ) ); + + ASSERT ( MM_bLightTableAlreadySetUp ); + + LOG_EXIT ( Figure_Draw_Prim_Tween ) + +} + + + + + + + + diff --git a/fallen/DDEngine/Source/flamengine.cpp b/fallen/DDEngine/Source/flamengine.cpp new file mode 100644 index 0000000..a2b702f --- /dev/null +++ b/fallen/DDEngine/Source/flamengine.cpp @@ -0,0 +1,793 @@ +/************************************************************ + * + * flamengine.cpp + * 2D flame (and other fx) engine + * + */ + +#ifndef TARGET_DC + + +#include "flamengine.h" +#include "texture.h" +#include "poly.h" +#include + +extern D3DTexture TEXTURE_texture[]; + +// override -- replaces convection/blur combination with feedback routine + +// #define FEEDBACK + +// +// Part The First : Texture lock/unlock/update stuff +// blagged from texture86 stuff +// + +SLONG TEXTURE_flame_lock() +{ + HRESULT res; + + res = TEXTURE_texture[TEXTURE_page_menuflame].LockUser( + &TEXTURE_shadow_bitmap, + &TEXTURE_shadow_pitch); + + if (FAILED(res)) + { + TEXTURE_shadow_bitmap = NULL; + TEXTURE_shadow_pitch = 0; + + return FALSE; + } + else + { + TEXTURE_shadow_mask_red = TEXTURE_texture[TEXTURE_page_menuflame].mask_red; + TEXTURE_shadow_mask_green = TEXTURE_texture[TEXTURE_page_menuflame].mask_green; + TEXTURE_shadow_mask_blue = TEXTURE_texture[TEXTURE_page_menuflame].mask_blue; + TEXTURE_shadow_mask_alpha = TEXTURE_texture[TEXTURE_page_menuflame].mask_alpha; + TEXTURE_shadow_shift_red = TEXTURE_texture[TEXTURE_page_menuflame].shift_red; + TEXTURE_shadow_shift_green = TEXTURE_texture[TEXTURE_page_menuflame].shift_green; + TEXTURE_shadow_shift_blue = TEXTURE_texture[TEXTURE_page_menuflame].shift_blue; + TEXTURE_shadow_shift_alpha = TEXTURE_texture[TEXTURE_page_menuflame].shift_alpha; + + return TRUE; + } +} + +void TEXTURE_flame_unlock() +{ + TEXTURE_texture[TEXTURE_page_menuflame].UnlockUser(); +} + +void TEXTURE_flame_update() +{ +} + +// +// Part The ... er ... First And A Half +// + +int FlameRand(int max) { + return rand()%max; +} + + +// +// Part The Second : The actual flame engine stuff +// + + + + +Flamengine::Flamengine(char *fname) { + MFFileHandle handle = FILE_OPEN_ERROR; + //int c,d,p,q,v; + //UBYTE *pt; + UWORD ver; + +// handle=FileOpen("data\\testfire.pal"); + handle=FileOpen(fname); + + if(handle!=FILE_OPEN_ERROR) { + FileRead(handle,(UBYTE*)&ver,sizeof(ver)); +// FileRead(handle,(UBYTE*)¶ms,sizeof(params)); + // crappy version + ReadHeader(handle); + ReadParts(handle); + FileClose(handle); + } + +/* // flip palette end-from-end + for (c=0,d=255;c<128;c++,d--) { + p=c*3; q=d*3; + v=palette[p]; palette[p]=palette[q]; palette[q]=v; p++; q++; + v=palette[p]; palette[p]=palette[q]; palette[q]=v; p++; q++; + v=palette[p]; palette[p]=palette[q]; palette[q]=v; p++; q++; + }*/ + + memset(data,0,256*256); + memset(work,0,256*256); + +} + +Flamengine::~Flamengine() { +} + +void Flamengine::ReadHeader(MFFileHandle handle) { + UBYTE skip; + + FileRead(handle,(UBYTE*)¶ms.blur,1); + FileRead(handle,(UBYTE*)¶ms.dark,1); + FileRead(handle,(UBYTE*)¶ms.convec,1); + FileRead(handle,(UBYTE*)¶ms.palette,768); + + FileRead(handle,(UBYTE*)&skip,1); + + FileRead(handle,(UBYTE*)¶ms.free,2); + FileRead(handle,(UBYTE*)¶ms.posn,2); +} + +void Flamengine::ReadParts(MFFileHandle handle) { + int i; + FlameParticle *pp; + SLONG skip; + + for (i=2000,pp=params.particles;i;i--,pp++) { + FileRead(handle,(UBYTE*)&pp->pos.loc.x,1); + FileRead(handle,(UBYTE*)&pp->pos.loc.y,1); + FileRead(handle,(UBYTE*)&pp->jx,1); + FileRead(handle,(UBYTE*)&pp->jy,1); + FileRead(handle,(UBYTE*)&pp->ex,1); + FileRead(handle,(UBYTE*)&pp->ey,1); + FileRead(handle,(UBYTE*)&pp->life,1); + + FileRead(handle,(UBYTE*)&skip,1); + + FileRead(handle,(UBYTE*)&pp->pulse,2); + FileRead(handle,(UBYTE*)&pp->prate,1); + FileRead(handle,(UBYTE*)&pp->pmode,1); + FileRead(handle,(UBYTE*)&pp->wmode,1); + + FileRead(handle,(UBYTE*)&skip,3); + + FileRead(handle,(UBYTE*)&pp->pstart,4); + FileRead(handle,(UBYTE*)&pp->pend,4); + } +} + + +void Flamengine::Run() { + +#ifdef FEEDBACK + + AddParticles2(); + Feedback(); + +#else + + AddParticles(); + if (params.blur) + { + if (!params.randomize) + ConvectionBlur(); + else + ConvectionBlur2(); + } + else + Darkening(); + UpdateTexture(); + +#endif + + +} + +// +// Sparkly bits +// + +void Flamengine::AddParticles() { + int i; + //UWORD x,y; + SWORD si; + UBYTE *pt; + FlameXY pos; + FlameParticle *pp; + +/* generic bonfire + for (i=100;i;i--) { + x=rand()&0xff; + y=239+(rand()&0xf); + x+=y<<8; + data[x]=255; + } +*/ + for (i=2000,pp=params.particles;i;i--,pp++) + if (pp->life) { + pos.ofs=pp->pos.ofs; + if (pp->jx) pos.loc.x+=FlameRand(pp->jx)-(pp->jx>>1); + if (pp->jy) pos.loc.y+=FlameRand(pp->jy)-(pp->jy>>1); + pt=data; + pt+=pos.ofs; + *pt=(UBYTE)pp->pulse; + switch (pp->pmode) { + case 0: // Ramp up + pp->pulse+=pp->prate; + if ((ULONG)pp->pulse>=pp->pend) pp->pulse=(SWORD)pp->pstart; + break; + case 1: // Ramp down + pp->pulse-=pp->prate; + if ((ULONG)pp->pulse<=pp->pstart) pp->pulse=(SWORD)pp->pend; + break; + case 2: // Cycle (up phase) + si=pp->pulse+pp->prate; + if (si>(SWORD)pp->pend) { + si=(SWORD)pp->pend; + pp->pmode=3; + } + pp->pulse=si; + break; + case 3: // Cycle (down phase) + si=pp->pulse-pp->prate; + if (si<(SWORD)pp->pstart) { + si=(SWORD)pp->pstart; + pp->pmode=2; + } + pp->pulse=si; + break; + } + + switch (pp->wmode) { + case 1: // fountain + switch (i&3) { + case 0: + if (pp->pos.loc.x>1) pp->pos.loc.x-=2; + break; + case 1: + if (pp->pos.loc.x>0) pp->pos.loc.x--; + break; + case 2: + if (pp->pos.loc.x<254) pp->pos.loc.x+=2; + break; + case 3: + if (pp->pos.loc.x<255) pp->pos.loc.x++; + break; + } + pp->pos.loc.y+=pp->life-10; + pp->life++; + if (pp->life>50) { + pp->life=1; + pp->pos.loc.x=pp->ex; + pp->pos.loc.y=pp->ey; + } + break; + case 2: // cascade + pp->pos.loc.y+=1+(i&3); + if ((pp->pos.loc.y==255)||(pp->pos.loc.yey)) pp->pos.loc.y=pp->ey; + break; + case 3: // gravity + pp->pos.loc.y++; + if ((pp->pos.loc.y==255)||(pp->pos.loc.yey)) pp->pos.loc.y=pp->ey; + break; + case 4: // sparks + switch (i&3) { + case 0: + if (pp->pos.loc.x>1) pp->pos.loc.x-=2; + break; + case 1: + if (pp->pos.loc.x>0) pp->pos.loc.x--; + break; + case 2: + if (pp->pos.loc.x<254) pp->pos.loc.x+=2; + break; + case 3: + if (pp->pos.loc.x<255) pp->pos.loc.x++; + break; + } + switch ((i>>1)&3) { + case 0: + if (pp->pos.loc.y>1) pp->pos.loc.y-=2; + break; + case 1: + if (pp->pos.loc.y>0) pp->pos.loc.y--; + break; + case 2: + if (pp->pos.loc.y<254) pp->pos.loc.y+=2; + break; + case 3: + if (pp->pos.loc.y<255) pp->pos.loc.y++; + break; + } + pp->life++; + if (pp->life>50) { + pp->life=1; + pp->pos.loc.x=pp->ex; + pp->pos.loc.y=pp->ey; + } + break; + case 5: // wander + pp->pos.loc.x+=FlameRand(11)-5; + pp->pos.loc.y+=FlameRand(11)-5; + break; + case 6: // jump + pp->pos.loc.x=FlameRand(256); + pp->pos.loc.y=FlameRand(256); + break; + } + + } + +} + +// +// Moves and/or darkens the image +// + +void Flamengine::Darkening() { + int x,y,i=0; + UBYTE *pt,*dpt; + + dpt=pt=data; + pt+=256; + if (!params.convec) dpt+=256; + if (params.dark) i=1; + for (y=255;y;y--) { + for (x=256;x;x--) { + *dpt++=(*pt++)-i; + } + } + +} + +// +// Straightforward blur box filter but offset one line +// + +void Flamengine::ConvectionBlur() { + UBYTE *pt1,*pt2,*pt3,*pt4,*pt,*wpt; + int x,y,i; + + wpt=work; + pt=data; + pt+=257; + wpt+=1; + if (!params.convec) wpt+=256; + + pt1=pt2=pt3=pt4=pt; + pt1-=1; + pt2+=1; + pt3-=256; + pt4+=256; + + for (y=1;y<254;y++) { +// for (x=1;x<254;x++) { + for (x=0;x<256;x++) { + i=*pt1; + i+=(*pt2)+(*pt3)+(*pt4); + i>>=2; + i+=*pt; + i>>=1; + if (params.dark&&i) i--; + *wpt=i; + + pt++; pt1++; pt2++; pt3++; pt4++; wpt++; + } +// pt++; pt1++; pt2++; pt3++; pt4++; wpt++; +// pt++; pt1++; pt2++; pt3++; pt4++; wpt++; + } + memcpy(data,work,65536); + +/* // debug override + memset(data,0,65536); + pt=data; + for (y=0;y<256;y++) { + for (x=0;x<256;x++) { + *pt=x-y; + if ((!(x&15))||(!(y&15))) *pt=255; + pt++; + } + } +*/ +} + + +// +// H@X0R'd version 1 +// +/* +void Flamengine::ConvectionBlur2() { + UBYTE *pt1,*pt2,*pt3,*pt4,*pt,*wpt,*ptx; + SLONG x,y,i; + static SLONG offset = 0; + SLONG blah,scale; + + wpt=work; + pt=data; + pt+=257; + wpt+=1; + if (!params.convec) wpt+=256; + + pt1=pt2=pt3=pt4=pt; + pt1-=1; + pt2+=1; + pt3-=256; + pt4+=256; + + offset+=160; + for (y=1;y<254;y++) { + blah=(y<<2)+offset; + blah&=2047; +// if (y<240) { +// scale=(240-y)*130; +// scale=(y)*130; +// ptx=wpt+(SIN(blah)/scale); + ptx=wpt+SIN(blah)/32768; +// } else { +// ptx=wpt; +// } + for (x=0;x<256;x++) { + i=*pt1; + i+=(*pt2)+(*pt3)+(*pt4); + i>>=2; + i+=*pt; + i>>=1; + if (params.dark&&i) i--; +// *wpt=i; + *ptx=i; + + pt++; pt1++; pt2++; pt3++; pt4++; wpt++; ptx++; + } + } + memcpy(data,work,65536); + +} +*/ +// +// H@X0R'd version 2 +// + +struct DarkZones { + SLONG offset, offtime, midpnt, width; +}; + +#define ZONES 3 + +void Flamengine::ConvectionBlur2() { + UBYTE *pt1,*pt2,*pt3,*pt4,*pt,*wpt; + SLONG x,y,i,j,dif; + static DarkZones zones[ZONES]; + SLONG difs[256]; + + wpt=work; + pt=data; + pt+=257; + wpt+=1; + if (!params.convec) wpt+=256; + + pt1=pt2=pt3=pt4=pt; + pt1-=1; + pt2+=1; + pt3-=256; + pt4+=256; + + for (j=0;j>=2; + i+=*pt; + i>>=1; +// if (params.dark&&i) i--; + i-=difs[x]; + if (i<0) i=0; + *wpt=(UBYTE)i; + + pt++; pt1++; pt2++; pt3++; pt4++; wpt++; + } + } + memcpy(data,work,65536); + +} + + +// +// Locks, pokes, unlocks and updates a texture with the fire data +// + +void Flamengine::UpdateTexture() { + + if (TEXTURE_flame_lock()) { + SLONG x; + SLONG y; + UWORD *image; + UWORD pixel; + UBYTE *pt,*pt2; + UBYTE red, green, blue; + + + // This version scales down for a 64x64 d3d texture + /* + + for (y = 0; y < 64; y++) { + image = TEXTURE_shadow_bitmap; + image += y * (TEXTURE_shadow_pitch >> 1); + + pt=data; + pt+=256*4*y; + + for (x=0;x<64;x++,image++,pt+=4) { + + pt2=palette+((*pt)*3); + red =*pt2++; + green=*pt2++; + blue =*pt2++; + + pixel = (red >> TEXTURE_shadow_mask_red ) << TEXTURE_shadow_shift_red; + pixel |= (green >> TEXTURE_shadow_mask_green) << TEXTURE_shadow_shift_green; + pixel |= (blue >> TEXTURE_shadow_mask_blue ) << TEXTURE_shadow_shift_blue; + *image = pixel; +// *image = 0xFFFF; + } + +// pt+=256*3; + } +*/ + + // This one doesn't. + + for (y = 0; y < 256; y++) { + image = TEXTURE_shadow_bitmap; + image += y * (TEXTURE_shadow_pitch >> 1); + + pt=data; + pt+=256*y; + + for (x=0;x<256;x++,image++,pt++) { + + pt2=params.palette+((*pt)*3); + red =*pt2++; + green=*pt2++; + blue =*pt2++; + + pixel = (red >> TEXTURE_shadow_mask_red ) << TEXTURE_shadow_shift_red; + pixel |= (green >> TEXTURE_shadow_mask_green) << TEXTURE_shadow_shift_green; + pixel |= (blue >> TEXTURE_shadow_mask_blue ) << TEXTURE_shadow_shift_blue; + *image = pixel; +// *image = 0xFFFF; + } + +// pt+=256*3; + } + + TEXTURE_flame_unlock(); + TEXTURE_flame_update(); + } + +} + +// +// Blit the texture, suitably alpha'd, onto the backbuffer +// + +void Flamengine::Blit() { + POLY_Point pp[4], + *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + pp[0].X = 0; + pp[0].Y = 200; + pp[0].Z = 0.5f; + pp[0].u = 0.0; + pp[0].v = 0.0; + pp[0].colour = 0xffffff; + pp[0].specular= 0xff000000; + + pp[1].X = 640; + pp[1].Y = 200; + pp[1].Z = 0.5f; + pp[1].u = 2.0; + pp[1].v = 0.0; + pp[1].colour = 0xffffff; + pp[1].specular = 0xff000000; + + pp[2].X = 0; + pp[2].Y = 480; + pp[2].Z = 0.5f; + pp[2].u = 0.0; + pp[2].v = 1.0; + pp[2].colour = 0xffffff; + pp[2].specular = 0xff000000; + + pp[3].X = 640; + pp[3].Y = 480; + pp[3].Z = 0.5f; + pp[3].u = 2.0; + pp[3].v = 1.0; + pp[3].colour = 0xffffff; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad,POLY_PAGE_MENUFLAME,FALSE,TRUE); + +} + +void Flamengine::BlitHalf(CBYTE side) { + POLY_Point pp[4], + *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + if (side) { + pp[0].X = 320; + pp[1].X = 640; + pp[2].X = 320; + pp[3].X = 640; + } else { + pp[0].X = 0; + pp[1].X = 320; + pp[2].X = 0; + pp[3].X = 320; + } + + pp[0].Y = 200; + pp[0].Z = 0.5f; + pp[0].u = 0.0; + pp[0].v = 0.0; + pp[0].colour = 0xffffff; + pp[0].specular= 0xff000000; + + pp[1].Y = 200; + pp[1].Z = 0.5f; + pp[1].u = 1.0; + pp[1].v = 0.0; + pp[1].colour = 0xffffff; + pp[1].specular = 0xff000000; + + pp[2].Y = 480; + pp[2].Z = 0.5f; + pp[2].u = 0.0; + pp[2].v = 1.0; + pp[2].colour = 0xffffff; + pp[2].specular = 0xff000000; + + pp[3].Y = 480; + pp[3].Z = 0.5f; + pp[3].u = 1.0; + pp[3].v = 1.0; + pp[3].colour = 0xffffff; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad,POLY_PAGE_MENUFLAME,FALSE,TRUE); + +} + + +// +// Blit the texture, skewed for feedback, onto the backbuffer +// + +void Flamengine::BlitOffset() { + POLY_Point pp[4], + *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + pp[0].X = 0; + pp[0].Y = 0; + pp[0].Z = 0.5f; + pp[0].u = 0.0; + pp[0].v = 0.0; + pp[0].colour = 0xffffff; + pp[0].specular= 0xff000000; + + pp[1].X = 256; + pp[1].Y = 0; + pp[1].Z = 0.5f; + pp[1].u = 1.0; + pp[1].v = 0.0; + pp[1].colour = 0xffffff; + pp[1].specular = 0xff000000; + + pp[2].X = 0; + pp[2].Y = 256; + pp[2].Z = 0.5f; + pp[2].u = 0.0; + pp[2].v = 1.0; + pp[2].colour = 0xffffff; + pp[2].specular = 0xff000000; + + pp[3].X = 256; + pp[3].Y = 256; + pp[3].Z = 0.5f; + pp[3].u = 1.0; + pp[3].v = 1.0; + pp[3].colour = 0xffffff; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad,POLY_PAGE_MENUFLAME,FALSE,TRUE); + + pp[0].u = 0.1f; // L + pp[0].v = 0.2f; // T + pp[1].u = 0.9f; // R + pp[1].v = 0.2f; // T + pp[2].u = 0.1f; // L + pp[2].v = 1.0f; // B + pp[3].u = 0.9f; // R + pp[3].v = 1.0f; // B + pp[0].colour = 0xafafaf; + pp[1].colour = 0xafafaf; + pp[2].colour = 0xafafaf; + pp[3].colour = 0xafafaf; + + POLY_add_quad(quad,POLY_PAGE_MENUFLAME,FALSE,TRUE); + +} + +// +// Funky feedback; must be used BEFORE any other screen draw +// + + +void Flamengine::Feedback() { + RECT rcSource, rcDest; + HRESULT res; + + // step 1 - create poly with flames on, warped, draw to back buffer + + the_display.lp_D3D_Viewport->Clear(1, &the_display.ViewportRect, D3DCLEAR_TARGET); + +#ifndef TARGET_DC + POLY_frame_init(FALSE, FALSE); +#endif +// Blit(); + BlitOffset(); +#ifndef TARGET_DC + POLY_frame_draw(FALSE,TRUE); +#endif + + + // step 2 - blit back buffer back to flames + + + rcSource.top = 0; rcSource.left = 0; + rcSource.bottom = 256; rcSource.right = 256; + rcDest.top = 0; rcDest.left = 0; + rcDest.bottom = 256; rcDest.right = 256; + +// res=TEXTURE_texture[TEXTURE_page_menuflame].GetSurface()->Blt(&rcDest,the_display.lp_DD_BackSurface,&rcSource,DDBLT_WAIT,NULL); + res=TEXTURE_texture[TEXTURE_page_menuflame].GetSurface()->Blt(NULL,the_display.lp_DD_BackSurface,&rcSource,DDBLT_WAIT,NULL); + + +} + +#endif //#ifndef TARGET_DC + + diff --git a/fallen/DDEngine/Source/font2d.cpp b/fallen/DDEngine/Source/font2d.cpp new file mode 100644 index 0000000..d9045eb --- /dev/null +++ b/fallen/DDEngine/Source/font2d.cpp @@ -0,0 +1,1104 @@ +/************************************************************ + * + * font2d.cpp + * 2D text writer + * + */ + +#ifndef TARGET_DC +#include +#endif +#include "font2d.h" +#include "c:\fallen\ddlibrary\headers\tga.h" +#include "noserver.h" +#include +#include "truetype.h" +#include "game.h" + +#ifdef _DEBUG +#define PERHAPS if (!Keys[KB_J]) +#else +#define PERHAPS if (1) +#endif + + +// +// Works out the position and width of each letter. +// + +//#define FONT2D_LETTER_HEIGHT 21 +#define FONT2D_LETTER_HEIGHT 16 + +#define FONT2D_LOWERCASE 0 +#define FONT2D_UPPERCASE 26 +#define FONT2D_NUMBERS 52 +#define FONT2D_PUNCT_PLING 62 +#define FONT2D_PUNCT_DQUOTE 63 +#define FONT2D_PUNCT_POUND 64 +#define FONT2D_PUNCT_DOLLAR 65 +#define FONT2D_PUNCT_PERCENT 66 +#define FONT2D_PUNCT_POWER 67 +#define FONT2D_PUNCT_AMPERSAND 68 +#define FONT2D_PUNCT_ASTERISK 69 +#define FONT2D_PUNCT_OPEN 70 +#define FONT2D_PUNCT_CLOSE 71 +#define FONT2D_PUNCT_COPEN 72 +#define FONT2D_PUNCT_CCLOSE 73 +#define FONT2D_PUNCT_SOPEN 74 +#define FONT2D_PUNCT_SCLOSE 75 +#define FONT2D_PUNCT_LT 76 +#define FONT2D_PUNCT_GT 77 +#define FONT2D_PUNCT_BSLASH 78 +#define FONT2D_PUNCT_FSLASH 79 +#define FONT2D_PUNCT_COLON 80 +#define FONT2D_PUNCT_SEMICOLON 81 +#define FONT2D_PUNCT_QUOTE 82 +#define FONT2D_PUNCT_AT 83 +#define FONT2D_PUNCT_HASH 84 +#define FONT2D_PUNCT_TILDE 85 +#define FONT2D_PUNCT_QMARK 86 +#define FONT2D_PUNCT_MINUS 87 +#define FONT2D_PUNCT_EQUALS 88 +#define FONT2D_PUNCT_PLUS 89 +#define FONT2D_PUNCT_DOT 90 +#define FONT2D_PUNCT_COMMA 91 +#define FONT2D_GERMAN_CHARS 10 +#define FONT2D_FRENCH_CHARS 14 +#define FONT2D_SPANISH_CHARS 11 +#define FONT2D_ITALIAN_CHARS 12 +#define FONT2D_NUM_LETTERS (92 + FONT2D_GERMAN_CHARS + FONT2D_FRENCH_CHARS + FONT2D_SPANISH_CHARS + FONT2D_ITALIAN_CHARS) + +FONT2D_Letter FONT2D_letter[FONT2D_NUM_LETTERS]; + +// +// This is the order the punctuation characters come in. +// + +CBYTE FONT2D_punct[] = +{ + "!\"£$%^&*(){}[]<>\\/:;'@#_?-=+.," + + // + // German characters in decimal and octal! + // + // No, Mark, let's do this right. + // (a) We can type them in directly and this can be physically matched against the bitmap + // (b) We can type them *all* in, instead of missing a few + + "ÄËÏÖØÜßïöø" + + // + // French characters + // + + "ÆÇÔàâçèéêîïôøû" + + // + // Spanish + // + // 161,191,216,225,228,233,237,241,243,248,250 + // + + "¡¿Øáäéíñóøú" + + // + // Italian + // + // 192,200,204,210,217,236,242,249 + // + // + + "ÀÈÌÒÙàìòùü©®" +}; + + + + + +// ARGH! Can't get this sodding type right. Do it with a typedef. +typedef TGA_Pixel MyArrayType[256][256]; +MyArrayType *FONT2D_data; + +// +// Returns TRUE if it finds pixel data at (x,y) +// + +SLONG FONT2D_found_data(SLONG x, SLONG y) +{ + SLONG dy; + + SLONG px; + SLONG py; + + ASSERT ( FONT2D_data != NULL ); + + ASSERT(WITHIN(x, 0, 255)); + + for (dy = -14; dy <= 3; dy++) + { + px = x; + py = y + dy; + + if (WITHIN(py, 0, 255)) + { + if (((*FONT2D_data)[py][px]).alpha) + { + return TRUE; + } + } + } + + return FALSE; +} + + + +void FONT2D_init(SLONG font_id) +{ + TGA_Info ti; + +#ifdef NO_SERVER + #define TEXTURE_EXTRA_DIR "server\\textures\\extras\\" +#else + #define TEXTURE_EXTRA_DIR "u:\\urbanchaos\\textures\\extras\\" +#endif + + + CBYTE fname[256]; + + + FONT2D_data = (MyArrayType *)MemAlloc ( sizeof ( TGA_Pixel ) * 256 * 256 ); + ASSERT ( FONT2D_data != NULL ); + + +#ifdef TARGET_DC + sprintf(fname, "%s%s", TEXTURE_EXTRA_DIR, "multifontPC.tga"); +#else + if (SOFTWARE) + { + sprintf(fname, "%s%s", TEXTURE_EXTRA_DIR, "multifontPC640.tga"); + } + else + { + sprintf(fname, "%s%s", TEXTURE_EXTRA_DIR, "multifontPC.tga"); + } +#endif + + + ti = TGA_load( + fname, + 256, + 256, + &((*FONT2D_data)[0][0]), + font_id, FALSE); + + ASSERT(ti.valid); + ASSERT(ti.width == 256); + ASSERT(ti.height == 256); + + SLONG i; + SLONG y; + SLONG x; + SLONG line; + + FONT2D_Letter *fl; + + #define FONT2D_NUM_BASELINES 8 + + SLONG baseline[FONT2D_NUM_BASELINES] = + { + 17, 37, 57, 77, 97, 117, 137, 157 + }; + + + x = 0; + y = baseline[0]; + line = 0; + + for (i = 0; i < FONT2D_NUM_LETTERS; i++) + { + fl = &FONT2D_letter[i]; + + // + // Look for the start of the letter. + // + + while(!FONT2D_found_data(x,y)) + { + x += 1; + + if (x >= 256) + { + x = 0; + line += 1; + + if (!WITHIN(line, 0, FONT2D_NUM_BASELINES - 1)) + { + return; + } + + y = baseline[line]; + } + } + + fl->u = x; + fl->v = y; + + // + // Look for the end of the letter. + // + + x += 1; + + while(FONT2D_found_data(x,y)) + { + x += 1; + } + + fl->width = x + 1.0F - fl->u; + + // + // Convert the (u,v)s + // + + fl->u *= 1.0F / 256.0F; + fl->v *= 1.0F / 256.0F; + + fl->v -= 14.0F / 256.0F; + } + MemFree ( FONT2D_data ); + FONT2D_data = NULL; +} + + +// +// Returns the index of the given character +// + +SLONG FONT2D_GetIndex(CBYTE chr) +{ + SLONG letter; + + // + // Remap certain characters first + // + + if (chr=='É') chr='E'; + + // + // Find our letter index. + // + + if (WITHIN(chr, 'a', 'z')) + { + letter = FONT2D_LOWERCASE + chr - 'a'; + } + else + if (WITHIN(chr, 'A', 'Z')) + { + letter = FONT2D_UPPERCASE + chr - 'A'; + } + else + if (WITHIN(chr, '0', '9')) + { + letter = FONT2D_NUMBERS + chr - '0'; + } + else + { + // + // Look for the punctuation letter. + // + + letter = FONT2D_PUNCT_PLING; + + for (CBYTE *ch = FONT2D_punct; *ch && *ch != chr; ch++, letter++); + } + + if (!WITHIN(letter, 0, FONT2D_NUM_LETTERS - 1)) + { + letter = FONT2D_PUNCT_QMARK; + } + + return letter; +} + + + +SLONG FONT2D_GetLetterWidth(CBYTE chr) +{ + SLONG letter; + + if ( ( chr == ' ' ) || ( chr == '¬' ) ) + { + // ¬ is a non-wrapping space. + return 8; + } + + letter = FONT2D_GetIndex(chr); + + ASSERT(WITHIN(letter, 0, FONT2D_NUM_LETTERS - 1)); + + return FONT2D_letter[letter].width + 1; +} + + + +void PANEL_draw_quad( + float left, + float top, + float right, + float bottom, + SLONG page, + ULONG colour = 0xffffffff, + float u1 = 0.0F, + float v1 = 0.0F, + float u2 = 1.0F, + float v2 = 1.0F); + + +SLONG FONT2D_DrawLetter(CBYTE chr, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade) +{ + SLONG letter; + + FONT2D_Letter *fl; + + // + // Space is a special case! + // + + if (chr == -110) + { + // + // Meant to be a single quote! + // + + chr = 39; + } + + // ¬ is a non-wrapping space. + if (chr == ' ' || chr == '\n' || chr == '\r' || chr == '\t' || chr=='¬' ) + { + return 8 * scale >> 8; + } + + if (chr == 'y') + { + // + // Wierd eh! The bottom of the 'y' leaks over into the earlier letter. + // + + x -= 2 * scale >> 8; + } + + letter = FONT2D_GetIndex(chr); + + ASSERT(WITHIN(letter, 0, FONT2D_NUM_LETTERS - 1)); + + fl = &FONT2D_letter[letter]; + + SATURATE(fade, 0, 255); + + PANEL_draw_quad( + x, + y - 3, + x + (fl->width * scale >> 8), + y + (15 * scale >> 8), + page, + (rgb & 0xffffff) | ((255 - fade) << 24), + fl->u, + fl->v, + fl->u + float(fl->width) * (1.0F / 256.0F), + fl->v + 18.0F * (1.0F / 256.0F)); + + if (chr == 'y') + { + return ((fl->width + 1) * scale >> 8) - (2 * scale >> 8); + } + else + { + return (fl->width + 1) * scale >> 8; + } +} + + +/* + + + +const CBYTE fontlist[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!\":;'#$@*()[]\\/? +-"; + +FONT2D_DrawLetter(CBYTE chr, ULONG x, ULONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade) { + UBYTE ndx=strchr(fontlist,chr)-fontlist; + float u,v; + SLONG fade2; + + u=(ndx&7); u*=0.125; + ndx>>=3; v=ndx; v*=0.125; + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xff000000; + if (fade) { + if (fade<32) { + fade2=(32-fade)<<3; + pp[0].colour=pp[1].colour=(rgb & 0x00FFFFFF) | (0xff<<24); + pp[2].colour=pp[3].colour=(rgb & 0x00FFFFFF) | (fade2<<24); + } else { + fade2=((64-fade)<<3)-1; + pp[0].colour=pp[1].colour=(rgb & 0x00FFFFFF) | (fade2<<24); + pp[2].colour=pp[3].colour=rgb & 0x00FFFFFF; + } + } else { + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=rgb | (0xff<<24); + } + pp[0].u=u; pp[0].v=v; + pp[1].u=u+0.125; pp[1].v=v; + pp[2].u=u; pp[2].v=v+0.125; + pp[3].u=u+0.125; pp[3].v=v+0.125; + pp[0].X=x; pp[0].Y=y; + pp[1].X=x+scale; pp[1].Y=y; + pp[2].X=x; pp[2].Y=y+scale; + pp[3].X=x+scale; pp[3].Y=y+scale; + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=0.5f; + POLY_add_quad(quad,page,FALSE,TRUE); +} + +*/ + + +SLONG FONT2D_rightmost_x; +SLONG FONT2D_leftmost_x; + + +#define MAKE_FADE_RGB(RGB, FADE) ((RGB & 0x00FFFFFF) | ((255 - FADE) << 24)) + +void FONT2D_DrawString(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade) +{ + UBYTE i; + + if (str == NULL) + { + str = "Null string"; + } + +#ifdef TRUETYPE + PERHAPS + { + SATURATE(fade, 0, 255); + DrawTextTT(str, x, y, 640, scale, MAKE_FADE_RGB(rgb, fade), LeftJustify); + return; + } +#endif + + FONT2D_rightmost_x = x; + + for (i=0;i FONT2D_rightmost_x) + { + FONT2D_rightmost_x = x; + } + } +} + +void FONT2D_DrawString_NoTrueType(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade) +{ + UBYTE i; + + if (str == NULL) + { + str = "Null string"; + } + + for (i=0;i= 600) + { + // + // The next space or EOL is beyond the end of the screen. + // Start a new line. + // + + x = xbase; + y += FONT2D_LETTER_HEIGHT - 1; + } + } + else + { + x += FONT2D_DrawLetter(str[i],x,y,rgb,scale,page,fade); + + if (x > FONT2D_rightmost_x) + { + FONT2D_rightmost_x = x; + } + } + } + + return y; +} +#endif + + +SLONG FONT2D_DrawStringWrapTo(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade, SWORD span) +{ + if (str == NULL) + { + str = "Null string"; + } + +#ifdef TRUETYPE + PERHAPS + { + SATURATE(fade, 0, 255); + return DrawTextTT(str, x, y, span, scale, MAKE_FADE_RGB(rgb, fade), LeftJustify); + } +#endif + + SLONG i; + SLONG xbase = x; + SLONG xlook; + SLONG len = strlen(str); + + CBYTE *ch; + + FONT2D_rightmost_x = x + 8; + + for (i = 0; i < len; i++) + { + if (str[i] == ' ') + { + x += FONT2D_GetLetterWidth(' '); + + // + // Should we go onto the next line? + // + + ch = &str[i + 1]; + xlook = x; + + while(*ch && *ch != ' ') + { + xlook += FONT2D_GetLetterWidth(*ch); + ch += 1; + } + + if (xlook >= span) + { + // + // The next space or EOL is beyond the end of the screen. + // Start a new line. + // + + x = xbase; + y += FONT2D_LETTER_HEIGHT - 1; + } + } + else + { + if (str[i]==13) { + x=xbase; y+=FONT2D_LETTER_HEIGHT - 1; + } else { + x += FONT2D_DrawLetter(str[i],x,y,rgb,scale,page,fade); + } + + if (x > FONT2D_rightmost_x) + { + FONT2D_rightmost_x = x; + } + } + } + + return y; +} + + +SLONG FONT2D_DrawStringRightJustify(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade, bool bDontDraw ) +{ + if (str == NULL) + { + str = "Null string"; + } + +#ifdef TRUETYPE + PERHAPS + { + SATURATE(fade, 0, 255); + return DrawTextTT(str, 10, y, x, scale, MAKE_FADE_RGB(rgb, fade), RightJustify); + } +#endif + + + //str = "Jeez, Miles. I'm a damn ROOKIE an' even I gotta laugh at THAT!"; + + + SLONG i; + SLONG drawn_upto; + SLONG xbase = x - ((scale >> 4) - 7); + SLONG xlook; + SLONG len = strlen(str); + + CBYTE *ch; + CBYTE backup; + + drawn_upto = 0; + x = xbase; + + FONT2D_leftmost_x = x; + + for (i = 0; i <= len; i++) + { + if (str[i] == ' ' || str[i] == '\000') + { + if (str[i] == '\000') + { + // + // Draw the last line. + // + + xlook = -INFINITY; + } + else + { + // + // Should we draw this line and go onto the next line? + // + + ch = &str[i + 1]; + xlook = x; + + while(*ch && *ch != ' ') + { + xlook -= FONT2D_GetLetterWidth(*ch); + ch += 1; + } + } + + if (xlook < 10) + { + // + // Draw upto this space. + // + + backup = str[i]; + str[i] = '\000'; + + if ( !bDontDraw ) + { + FONT2D_DrawString( + &str[drawn_upto], + x, + y, + rgb, + scale, + page, + fade); + } + + str[i] = backup; + + drawn_upto = i + 1; + y += FONT2D_LETTER_HEIGHT - 1; + x = xbase + FONT2D_GetLetterWidth(str[i]); + } + } + + x -= FONT2D_GetLetterWidth(str[i]); + + if (x < FONT2D_leftmost_x) + { + FONT2D_leftmost_x = x; + } + + } + + return y; +} + + +SLONG FONT2D_DrawStringRightJustifyNoWrap(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade) +{ + if (str == NULL) + { + str = "Null string"; + } + + CBYTE *ch; + + for (ch = str; *ch; ch++) + { + x -= FONT2D_GetLetterWidth(*ch); + } + + FONT2D_DrawString(str, x, y, rgb, scale, page, fade); + + return 0; +} + + +//POLY_PAGE_FONT2D +void FONT2D_DrawString_3d(CBYTE*str, ULONG world_x, ULONG world_y, ULONG world_z, ULONG rgb, SLONG text_size, SWORD fade) +{ + if (str == NULL) + { + str = "Null string"; + } + + SLONG screen_size; + SLONG len; + SLONG str_width,str_height; + + POLY_Point mid; + + + + POLY_transform( + world_x, + world_y, + world_z, + &mid); + + if (mid.IsValid()) + { + CBYTE *ch; + + float x = mid.X; + float y = mid.Y; + + float width; + SLONG scale = SLONG(mid.Z * 6 * 256); + + SLONG letter; + + // + // Work out the length of the string. + // + + len = 0; + + for (ch = str; *ch; ch++) + { + len += FONT2D_GetLetterWidth(*ch) * scale >> 8; + } + + x -= len / 2; + + FONT2D_DrawString_NoTrueType( + str, + x,y, + 0xFFFFFF, + scale, + POLY_PAGE_FONT2D, + 0); + + /* + + for (ch = str; *ch; ch++) + { + // + // Draw each letter in turn. + // + + if (*ch == ' ') + { + width = 8.0F; + } + else + { + SLONG letter; + + FONT2D_Letter *fl; + + letter = FONT2D_GetIndex(*ch); + + ASSERT(WITHIN(letter, 0, FONT2D_NUM_LETTERS - 1)); + + fl = &FONT2D_letter[letter]; + + SATURATE(fade, 0, 255); + + PANEL_draw_quad( + x, + y, + x + float(fl->width) * scale, + y + float(FONT2D_LETTER_HEIGHT) * scale, + POLY_PAGE_FONT2D, + (rgb & 0xffffff) | ((255 - fade) << 24), + fl->u, + fl->v, + fl->u + float(fl->width) * (1.0F / 256.0F), + fl->v + float(FONT2D_LETTER_HEIGHT) * (1.0F / 256.0F)); + + width = fl->width + 1; + } + + x += width * scale; + } + + */ + + /* + + + + + len=strlen(str); + screen_size = (SLONG)(POLY_world_length_to_screen(text_size) * mid.Z); + str_width=(screen_size*len)>>1; + str_height=(screen_size)>>1; + + if (mid.X + str_width < 0 || + mid.X - str_width > POLY_screen_width || + mid.Y + str_height < 0 || + mid.Y - str_height > POLY_screen_height) + { + // + // Off screen. + // + } + else + { + FONT2D_DrawString(str, ((ULONG)mid.X)-str_width,((ULONG)mid.Y)-str_height , rgb, screen_size, POLY_PAGE_FONT2D, fade); + + } + + */ + } +} + + +void FONT2D_DrawStringCentred(CBYTE*chr, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade) +{ + SLONG length; + CBYTE *ch; + +#ifdef TRUETYPE + PERHAPS + { + SATURATE(fade, 0, 255); + if (x < 320) + { + DrawTextTT(chr, 0, y, x*2, scale, MAKE_FADE_RGB(rgb, fade), Centred); + } + else + { + DrawTextTT(chr, x*2 - 640, y, 640, scale, MAKE_FADE_RGB(rgb, fade), Centred); + } + return; + } +#endif + + // + // Work out the length of the string. + // + + length = 0; + + for (ch = chr; *ch; ch++) + { + length += FONT2D_GetLetterWidth(*ch) * scale >> 8; + + + + + } + + x -= length / 2; + + FONT2D_DrawString( + chr, + x, y, + rgb, + scale, + page, + fade); +} + + + + +float PANEL_GetNextDepthBodge ( void ); + +SLONG DST_offset1; +SLONG DST_offset2; + + + +void FONT2D_DrawStrikethrough(SLONG x1, SLONG x2, SLONG y, ULONG rgb, SLONG scale, SLONG page, SLONG fade, bool bUseLastOffset) +{ + FONT2D_Letter *fl; + + SLONG letter = FONT2D_GetIndex('-'); + + fl = &FONT2D_letter[letter]; + + SLONG offset; + + // + // Work out the 'random' offset. + // + + SLONG offset1; + SLONG offset2; + + if ( bUseLastOffset ) + { + offset1 = DST_offset1; + offset2 = DST_offset2; + } + else + { + SLONG rx = x1 + x2; + SLONG ry = y; + +#if 0 + if (rgb == 0) + { + rx -= 2; + ry -= 2; + } +#endif + + offset1 = (ry / 5); + offset1 %= 9; + + offset2 = offset1 * (ry / 20); + offset1 >>= 3; + offset2 %= 11; + + DST_offset1 = offset1; + DST_offset2 = offset2; + } + + { + POLY_Point pp [4]; + POLY_Point *quad[4]; + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + pp[0].X = x1; + pp[0].Y = y - 3 + offset1 - 1; + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].u = fl->u; + pp[0].v = fl->v; + pp[0].colour = rgb | ((255 - fade) << 24); + pp[0].specular = 0xff000000; + + pp[1].X = x2; + pp[1].Y = y - 3 + offset2 - 3; + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].u = fl->u + float(fl->width) * (1.0F / 256.0F); + pp[1].v = fl->v; + pp[1].colour = rgb | ((255 - fade) << 24); + pp[1].specular = 0xff000000; + + pp[2].X = x1; + pp[2].Y = y + (15 * scale >> 8) + offset1 - 1; + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].u = fl->u; + pp[2].v = fl->v + 18.0F * (1.0F / 256.0F); + pp[2].colour = rgb | ((255 - fade) << 24); + pp[2].specular = 0xff000000; + + pp[3].X = x2; + pp[3].Y = y + (15 * scale >> 8) + offset2 - 3; + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].u = fl->u + float(fl->width) * (1.0F / 256.0F); + pp[3].v = fl->v + 18.0F * (1.0F / 256.0F); + pp[3].colour = rgb | ((255 - fade) << 24); + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + +} + + + + + diff --git a/fallen/DDEngine/Source/font3d.cpp b/fallen/DDEngine/Source/font3d.cpp new file mode 100644 index 0000000..e47202e --- /dev/null +++ b/fallen/DDEngine/Source/font3d.cpp @@ -0,0 +1,457 @@ + +// THIS IS PANTS! +#if 0 + +/************************************************************ + * + * font3d.cpp + * 3D text writer + * + */ + +#include "font3d.h" +#include +#include +#include +#include "matrix.h" +#include "StdKeybd.h" +#include "poly.h" + +const char fontindex[] = "ABCDEFGHIJKLMNOPQRSTUVWYXZ0123456789"; + +// +// Some crappy vector stuff +// + +float Magnitude(FontVec &vec) { + return sqrt((vec.x*vec.x)+(vec.y*vec.y)+(vec.z*vec.z)); +} + +void Normalize(FontVec &Result) { + float holder; + + holder=Magnitude(Result); + if (holder) { + Result.x/=holder; + Result.y/=holder; + Result.z/=holder; + } + +} + +FontVec Cross(FontVec &Temp1, FontVec &Temp2) { + FontVec Result; + + Result.x=(Temp1.y*Temp2.z)-(Temp1.z*Temp2.y); + Result.y=(Temp1.z*Temp2.x)-(Temp1.x*Temp2.z); + Result.z=(Temp1.x*Temp2.y)-(Temp1.y*Temp2.x); + + return Result; +} + +FontVec CalcSurfaceNormal(FontVec &V0, FontVec &V1, FontVec &V2) { + FontVec Result,Temp1, Temp2; + + Temp1.x=V1.x-V0.x; Temp1.y=V1.y-V0.y; Temp1.z=V1.z-V0.z; + Temp2.x=V1.x-V2.x; Temp2.y=V1.y-V2.y; Temp2.z=V1.z-V2.z; + + Result=Cross(Temp1,Temp2); + Normalize(Result); + return Result; +} + +void MixNorms(FontVec &norm, FontVec &vec) { + +// if (vec.nx==vec.ny==vec.nz==0) { Strange! + + if (vec.nx == 0 && vec.ny == 0 && vec.nz == 0) { + vec.nx=norm.x; vec.ny=norm.y; vec.nz=norm.z; + } else { + vec.nx+=norm.x; vec.ny+=norm.y; vec.nz+=norm.z; + vec.nx/=2; vec.ny/=2; vec.nz/=2; + } +} + +/* +// +// some crappy matrix stuff +// + +void PerspMatrix(float matrix[9]) { + + memset(matrix,0,sizeof(matrix)); + matrix[0]=d; + matrix[5]=d; + matrix[10]=1; + matrix[11]=-d; + matrix[14]=1; + +} +*/ + +// +// construct, destruct.... FLA would be proud :P +// + +Font3D::Font3D(char *path, float scale) { + UBYTE i; + CBYTE fn[400], chr[2]; + + memset(data,0,sizeof(data)); + nextchar=0; + fontscale=scale; + + chr[1]=0; + + for (i=0;inumpts=d; + currchar->pts = vec = new FontVec[d]; + } + + match = sscanf(line, "# Num faces : %d",&d); + if (match==1) { + currchar->numfaces=d; + currchar->faces = face = new FontFace[d]; + } + + // Ignore all other comment lines + + if (line[0] == '#') continue; + + // Add new vertices to pool + + match = sscanf(line, "Vertex: (%f,%f,%f)", &x, &y, &z); + + if ((match==3)&&vec) { + vec->x=x; vec->y=y; vec->z=z; + vec->nx=vec->ny=vec->nz=0; + if (x>maxx) maxx=x; + if (y>maxy) maxy=y; + if (z>maxz) maxz=z; + if (xa=&currchar->pts[p3]; + face->b=&currchar->pts[p2]; + face->c=&currchar->pts[p1]; + face->norm=CalcSurfaceNormal(*face->a,*face->b,*face->c); + MixNorms(face->norm,*face->a); + MixNorms(face->norm,*face->b); + MixNorms(face->norm,*face->c); + face++; + } + + + } + + ctrx=(maxx+minx)/2; ctry=(maxy+miny)/2; ctrz=(maxz+minz)/2; + + for (d=0,vec=currchar->pts;dnumpts;d++,vec++) { + vec->x-=ctrx; vec->y-=ctry; vec->z-=ctrz; + } + + currchar->width=maxx-minx; + + + MF_Fclose(handle); + +} + +// +// Get the width of a character +// + +ULONG Font3D::LetterWidth(CBYTE chr) { + SLONG ndx; + FontData *currchar; + + if (chr==' ') return 10; + ndx=strchr(fontindex,chr)-fontindex; + if ((ndx<0)||(ndx>=strlen(fontindex))) return 0; // out of bounds + return data[ndx].width*fontscale; +} + +// +// Draw a character +// + + +void Font3D::DrawLetter(CBYTE chr, ULONG x, ULONG y, ULONG rgb, float yaw, float roll, float pitch, float scale) { + SLONG ndx; + FontData *currchar; + FontVec *pt; + FontFace *face; + float matrix[9]; + float px,py,pz, az; + POLY_Point pp[3], *tri[3]; + + if (scale<=0) return; // too small + + scale*=fontscale; + + ndx=strchr(fontindex,chr)-fontindex; + if ((ndx<0)||(ndx>=strlen(fontindex))) return; // out of bounds + currchar=&data[ndx]; + + float POLY_screen_mul_x, POLY_screen_mul_y; + + POLY_screen_mul_x = 640 * 0.5F / POLY_ZCLIP_PLANE; + POLY_screen_mul_y = 480 * 0.5F / POLY_ZCLIP_PLANE; + + tri[2] = &pp[0]; + tri[1] = &pp[1]; + tri[0] = &pp[2]; + + MATRIX_calc(matrix, yaw, pitch, roll); + + for (ndx=0,pt=currchar->pts;ndxnumpts;ndx++,pt++) { + pt->tx=pt->x; pt->ty=pt->y; pt->tz=pt->z; + MATRIX_MUL(matrix, pt->tx,pt->ty,pt->tz); + + pt->tnx=pt->nx; pt->tny=pt->ny; pt->tnz=pt->nz; + MATRIX_MUL(matrix, pt->tnx, pt->tny, pt->tnz); + pt->tnx*=0.15; pt->tny*=0.15; pt->tnz*=0.15; + + + // some scale factor or other... + pt->tx*=scale; pt->ty*=scale; pt->tz*=scale; + + + az=((pt->tz*0.25)+75)*0.01; + + pt->tz=150-pt->tz; + pt->tz=1.0/pt->tz; + + pt->tx*=az; + pt->ty*=az; + + pt->tx+=x; pt->ty+=y; + + } + + for (ndx=0,face=currchar->faces;ndxnumfaces;ndx++,face++) { + + // cheesy debug kack: +/* face->a->tx=face->c->tx=0; + face->b->tx=640; + face->a->ty=face->b->ty=200; + face->c->ty=480; +*/ + + //face->a->tz=face->b->tz=face->c->tz=0.5f; + + + // Draw the face... + +#define SPEC 0xff000000 +//#define SPEC 0xff4f0000 + +//////////////////////////////////// + + pp[0].X = face->a->tx; + pp[0].Y = face->a->ty; + pp[0].Z = face->a->tz; + pp[0].u = (face->a->tx/640)+face->a->tnx; + pp[0].v = (face->a->ty/640)+face->a->tny+0.2; + pp[0].colour = rgb;//0xffffff; + pp[0].specular= SPEC; + + pp[1].X = face->b->tx; + pp[1].Y = face->b->ty; + pp[1].Z = face->b->tz; + pp[1].u = (face->b->tx/640)+face->b->tnx; + pp[1].v = (face->b->ty/640)+face->b->tny+0.2; + pp[1].colour = rgb;//0xffffff; + pp[1].specular = SPEC; + + pp[2].X = face->c->tx; + pp[2].Y = face->c->ty; + pp[2].Z = face->c->tz; + pp[2].u = (face->c->tx/640)+face->c->tnx; + pp[2].v = (face->c->ty/640)+face->c->tny+0.2; + pp[2].colour = rgb;//0xffffff; + pp[2].specular = SPEC; + + POLY_add_triangle(tri,POLY_PAGE_MENUTEXT,TRUE,TRUE); + + +/* + // some fucked up second pass shit + + pp[0].X = face->a->tx; + pp[0].Y = face->a->ty; + pp[0].Z = face->a->tz; + pp[0].u = (face->a->tx/640)+face->a->tnx; + pp[0].v = (face->a->ty/960)+face->a->tny+0.5; + pp[0].colour = rgb;//0xffffff; + pp[0].specular= SPEC; + + pp[1].X = face->b->tx; + pp[1].Y = face->b->ty; + pp[1].Z = face->b->tz; + pp[1].u = (face->b->tx/640)+face->b->tnx; + pp[1].v = (face->b->ty/960)+face->b->tny+0.5; + pp[1].colour = rgb;//0xffffff; + pp[1].specular = SPEC; + + pp[2].X = face->c->tx; + pp[2].Y = face->c->ty; + pp[2].Z = face->c->tz; + pp[2].u = (face->c->tx/640)+face->c->tnx; + pp[2].v = (face->c->ty/960)+face->c->tny+0.5; + pp[2].colour = rgb;//0xffffff; + pp[2].specular = SPEC; + + POLY_add_triangle(tri,POLY_PAGE_MENUPASS,FALSE,TRUE); +*/ + + + // Draw the drop shadow... + + pp[0].X = face->a->tx+10; + pp[0].Y = face->a->ty+10; + pp[0].Z = 0.0001; + pp[0].u = 0.2; + pp[0].v = 0.2; + pp[0].colour = 0; + pp[0].specular= 0xff000000; + + pp[1].X = face->b->tx+10; + pp[1].Y = face->b->ty+10; + pp[1].Z = 0.0001; + pp[1].u = 0.8; + pp[1].v = 0.2; + pp[1].colour = 0; + pp[1].specular = 0xff000000; + + pp[2].X = face->c->tx+10; + pp[2].Y = face->c->ty+10; + pp[2].Z = 0.0001; + pp[2].u = 0.2; + pp[2].v = 0.8; + pp[2].colour = 0; + pp[2].specular = 0xff000000; + + POLY_add_triangle(tri,POLY_PAGE_MENUTEXT,TRUE,TRUE); + + + + } + +} + +void Font3D::DrawString(CBYTE *str, ULONG ctrx, ULONG y, ULONG rgb, float scale, CBYTE wibble, UWORD zoom) { + static float rotate=0; + float thisone; + float sep, x, f, zoomctr; + UWORD i; + CBYTE *c; + + //sep=11.5*scale; + + //sep = 9.0F * scale; + + // calculate proportional width + sep=0; + for(i=0,c=str;i90)&&(thisone<180)) + thisone=90+((thisone-180)*4); + else + thisone=90; + thisone*=PI/180; + if (!zoom) { + DrawLetter(*c,x,y,rgb,0,0,thisone,scale); + } else { + f=1+abs(zoomctr-(i*2)); + f/=zoomctr; + f*=zoom; + DrawLetter(*c,x,y,rgb,0,0,thisone,scale-f); + } + x+=LetterWidth(*c)*scale*0.5; + } +} + + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Source/ic.cpp b/fallen/DDEngine/Source/ic.cpp new file mode 100644 index 0000000..2fe0948 --- /dev/null +++ b/fallen/DDEngine/Source/ic.cpp @@ -0,0 +1,319 @@ +// +// Image compression. +// + +#include +#include "ic.h" +#include "tga.h" + + +// +// Converts 24-bit RGB into 5:6:5 +// + +ULONG IC_convert(UBYTE r, UBYTE g, UBYTE b) +{ + SLONG nr = r; + SLONG ng = g; + SLONG nb = b; + + ULONG ans; + + nr = (nr + 4) >> 3; + ng = (ng + 2) >> 2; + nb = (nb + 4) >> 3; + + if (nr > 31) {nr = 31;} + if (ng > 63) {ng = 63;} + if (nb > 31) {nb = 31;} + + ans = (nr << 11) | (ng << 5) | (nb); + + return ans; +} + + +IC_Packet IC_pack( + TGA_Pixel *tga, + SLONG tga_width, + SLONG tga_height, + SLONG px, + SLONG py) +{ + SLONG i; + SLONG j; + SLONG k; + SLONG l; + + SLONG x; + SLONG y; + + SLONG x1; + SLONG y1; + + SLONG x2; + SLONG y2; + + SLONG r1,g1,b1; + SLONG r2,g2,b2; + + SLONG dr; + SLONG dg; + SLONG db; + + SLONG r[4]; + SLONG g[4]; + SLONG b[4]; + + TGA_Pixel *tp; + TGA_Pixel *tp1; + TGA_Pixel *tp2; + + SLONG error; + ULONG bit; + SLONG dist; + SLONG best_dist; + SLONG best_bit; + SLONG best_error = INFINITY; + IC_Packet best_ans; + + // + // Try lines between points i and j. + // + + for (i = 1; i < 16; i++) + for (j = 0; j < i; j++) + { + if (i == j) {continue;} + + x1 = px + (i & 0x3); + y1 = py + (i >> 0x2); + + x2 = px + (j & 0x3); + y2 = py + (j >> 0x2); + + tp1 = &tga[x1 + y1 * tga_width]; + tp2 = &tga[x2 + y2 * tga_width]; + + r1 = tp1->red; + g1 = tp1->green; + b1 = tp1->blue; + + r2 = tp2->red; + g2 = tp2->green; + b2 = tp2->blue; + + if (r1 == r2 && + g1 == g2 && + b1 == b2) + { + // + // Not a valid line. + // + + continue; + } + + // + // Work out the four colours we get from the line. + // + + r[0] = r1; + g[0] = g1; + b[0] = b1; + + dr = r2 - r1; + dg = g2 - g1; + db = b2 - b1; + + r[1] = r1 + (dr * 85 >> 8); + g[1] = g1 + (dg * 85 >> 8); + b[1] = b1 + (db * 85 >> 8); + + r[2] = r1 + (dr * 170 >> 8); + g[2] = g1 + (dg * 170 >> 8); + b[2] = b1 + (db * 170 >> 8); + + r[3] = r2; + g[3] = g2; + b[3] = b2; + + // + // Work out the score of the line- i.e. the amount of + // error and the answer bits while we are at it. + // + + bit = 0; + error = 0; + + for (k = 0; k < 16; k++) + { + x = px + (k & 0x3); + y = py + (k >> 0x2); + + tp = &tga[x + y * tga_width]; + + best_dist = INFINITY; + best_bit = 0; + + for (l = 0; l < 4; l++) + { + dr = r[l] - tp->red; + dg = g[l] - tp->green; + db = b[l] - tp->blue; + + dist = dr * dr * 3 + dg * dg * 2 + db * db; + + if (dist < best_dist) + { + best_dist = dist; + best_bit = l; + } + } + + error += best_dist; + bit <<= 2; + bit |= best_bit; + } + + if (error < best_error) + { + // + // Found a better line. + // + + best_error = error; + best_ans.colour1 = IC_convert(r1,g1,b1); + best_ans.colour2 = IC_convert(r2,g2,b2); + best_ans.bit = bit; + } + } + + if (best_error == INFINITY) + { + // + // There are no lines! All the pixels must be the same colour. + // + + tp = &tga[px + py * tga_width]; + + best_ans.colour1 = IC_convert(tp->red,tp->green,tp->blue); + best_ans.colour2 = IC_convert(tp->red,tp->green,tp->blue); + best_ans.bit = 0; + } + + return best_ans; +} + + + +void IC_unpack( + IC_Packet ip, + TGA_Pixel *tga, + SLONG tga_width, + SLONG tga_height, + SLONG px, + SLONG py) +{ + SLONG i; + SLONG bit; + + SLONG r[4]; + SLONG g[4]; + SLONG b[4]; + + TGA_Pixel *tp; + + r[0] = (((ip.colour1 >> 11) ) << 3) + 4; + g[0] = (((ip.colour1 >> 5) & 0x3f) << 2) + 2; + b[0] = (((ip.colour1 ) & 0x1f) << 3) + 4; + + r[3] = (((ip.colour2 >> 11) ) << 3) + 4; + g[3] = (((ip.colour2 >> 5) & 0x3f) << 2) + 2; + b[3] = (((ip.colour2 ) & 0x1f) << 3) + 4; + + SLONG dr = (r[3] - r[0]) * 85 >> 8; + SLONG dg = (g[3] - g[0]) * 85 >> 8; + SLONG db = (b[3] - b[0]) * 85 >> 8; + + r[1] = r[0] + dr; + g[1] = g[0] + dg; + b[1] = b[0] + db; + + r[2] = r[1] + dr; + g[2] = g[1] + dg; + b[2] = b[1] + db; + + for (i = 0; i < 4; i++) + { + tp = &tga[px + (py + i) * tga_width]; + + // + // Unwind the loop a bit. + // + + #define IC_DECOMPRESS_A_PIXEL() \ + { \ + bit = ip.bit >> 30; \ + ip.bit <<= 2; \ + \ + tp->red = r[bit]; \ + tp->green = g[bit]; \ + tp->blue = b[bit]; \ + \ + tp += 1; \ + } + + IC_DECOMPRESS_A_PIXEL(); + IC_DECOMPRESS_A_PIXEL(); + IC_DECOMPRESS_A_PIXEL(); + IC_DECOMPRESS_A_PIXEL(); + } +} + + +#ifndef TARGET_DC +TGA_Pixel test[256 * 256]; + +void IC_test() +{ + SLONG x; + SLONG y; + + TGA_Info ti; + IC_Packet ip; + + ti = TGA_load("test.tga", 256, 256, test, -1); + + if (!ti.valid) + { + return; + } + + ASSERT((ti.width & 0x3) == 0); + ASSERT((ti.height & 0x3) == 0); + + for (x = 0; x < ti.width; x += 4) + for (y = 0; y < ti.height; y += 4) + { + ip = IC_pack( + test, + ti.width, + ti.height, + x, + y); + + IC_unpack( + ip, + test, + ti.width, + ti.height, + x, + y); + } + + TGA_save("testcomp.tga", ti.width, ti.height, test, FALSE); +} + +#endif + diff --git a/fallen/DDEngine/Source/map.cpp b/fallen/DDEngine/Source/map.cpp new file mode 100644 index 0000000..9fe5799 --- /dev/null +++ b/fallen/DDEngine/Source/map.cpp @@ -0,0 +1,1858 @@ +// +// The new map screen +// + + + +#include +#include +#include +#include "game.h" +#include "poly.h" +#include "text.h" +#include "texture.h" +#include "mav.h" +#include "menufont.h" +#include "matrix.h" +#include "memory.h" +#include "fc.h" +#include "font2d.h" + + +#ifdef TARGET_DC +#include "target.h" +#endif + +extern CBYTE *EWAY_get_mess(SLONG index); + + + + +#ifndef TARGET_DC + + +// +// The size of the physical screen. +// + +float MAP_screen_size_x; +float MAP_screen_size_y; + + +// +// The current mapping from the world to the screen. +// + +float MAP_screen_x = 0.60F; +float MAP_screen_y = 0.55F; +float MAP_world_x; +float MAP_world_z; +float MAP_scale_x = 0.03F; // Virtual p0ixels per mapsquare +float MAP_scale_y = 0.03F * 1.33F; + + + +// +// Returns the screen coord of the given (floating point!) world position. +// + +#define MAP_SCREEN_X(world_x) (MAP_screen_x + ((world_x) - MAP_world_x) * MAP_scale_x) +#define MAP_SCREEN_Y(world_z) (MAP_screen_y + ((world_z) - MAP_world_z) * MAP_scale_y) + +#define MAP_SCREEN_IX(world_x) (MAP_screen_x + (((float)world_x)*(1.0f/256.0f) - MAP_world_x) * MAP_scale_x) +#define MAP_SCREEN_IY(world_z) (MAP_screen_y + (((float)world_z)*(1.0f/256.0f) - MAP_world_z) * MAP_scale_y) + +// +// Returns the world position of the given point on the screen. +// + +#define MAP_WORLD_X(screen_x) (((screen_x) - MAP_screen_x) / MAP_scale_x + MAP_world_x) +#define MAP_WORLD_Z(screen_y) (((screen_y) - MAP_screen_y) / MAP_scale_y + MAP_world_z) + + + + +// +// Returns a shade of grey depending on its virtual screen position. +// + +ULONG MAP_fadeout_colour( + float sx, + float sy) +{ + float dx = (sx - MAP_screen_x) * (1.0F / 0.38F); + float dy = (sy - MAP_screen_y) * (1.0F / 0.48F); + float dist; + float fmul; + SLONG imul; + ULONG colour; + + dist = dx*dx + dy*dy; + dist *= dist; + fmul = 1.0F - dist; + + imul = SLONG(fmul * 255.0F); + + if (imul < 0) + { + imul = 0; + } + + colour = imul | (imul << 8); + colour |= colour << 16; + + return colour; +} + + +// +// Draws a prim. +// + +void MAP_draw_prim( + SLONG prim, + float cx, + float cy, + float yaw, + float scale) +{ + SLONG i; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + SLONG page; + + float x; + float y; + float z; + + float X; + float Y; + float Z; + + float matrix[9]; + + PrimObject *po; + POLY_Point *pp; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + MATRIX_calc( + matrix, + yaw + prim, + -0.5F, + 0.0F); + + // + // Assume maximum dimensions of 1 mapsquare... + // + + matrix[0] *= 1.0F / 256.0F; + matrix[1] *= 1.0F / 256.0F; + matrix[2] *= 1.0F / 256.0F; + matrix[3] *= 1.0F / 256.0F; + matrix[4] *= 1.0F / 256.0F; + matrix[5] *= 1.0F / 256.0F; + matrix[6] *= 1.0F / 256.0F; + matrix[7] *= 1.0F / 256.0F; + matrix[8] *= 1.0F / 256.0F; + + // + // Aspect ratio... + // + + matrix[3] *= 1.0F / 1.33F; + matrix[4] *= 1.0F / 1.33F; + matrix[5] *= 1.0F / 1.33F; + + // + // Rotate the points. + // + + po = &prim_objects[prim]; + pp = &POLY_buffer [0]; + + for (i = po->StartPoint; i < po->EndPoint; i++) + { + x = float(prim_points[i].X); + y = float(prim_points[i].Y); + z = float(prim_points[i].Z); + + MATRIX_MUL( + matrix, + x, + y, + z); + + z += 1.0F; + + ASSERT(z > 0.001F); + + Z = scale / z; + X = x * Z; + Y = y * Z; + X = cx - X; + Y = cy - Y; + + X *= MAP_screen_size_x; + Y *= MAP_screen_size_y; + + pp->x = x; + pp->y = y; + pp->X = X; + pp->Y = Y; + pp->Z = Z; + pp->z = z; +#ifdef TARGET_DC + pp->colour = 0xffffffff; +#else + pp->colour = 0x00ffffff; +#endif + pp->specular = 0xff000000; + + POLY_setclip(pp); + + pp += 1; + } + + POLY_buffer_upto = po->EndPoint - po->StartPoint; + + // + // The quads. + // + + for (i = po->StartFace4; i < po->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - po->StartPoint; + p1 = p_f4->Points[1] - po->StartPoint; + p2 = p_f4->Points[2] - po->StartPoint; + p3 = p_f4->Points[3] - po->StartPoint; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + + // + // The triangles. + // + + for (i = po->StartFace3; i < po->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - po->StartPoint; + p1 = p_f3->Points[1] - po->StartPoint; + p2 = p_f3->Points[2] - po->StartPoint; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } +} + + + +// +// Draws a sprite +// + +void MAP_sprite( + SLONG page, + float x, + float y, + float size_x, + float size_y, + float u0, + float v0, + float u1, + float v1, + float u2, + float v2, + float u3, + float v3, + UBYTE shadow) +{ + float x1 = x; + float y1 = y; + float x2 = x + size_x; + float y2 = y + size_y; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + ULONG colour0 = MAP_fadeout_colour(x1,y1); + ULONG colour1 = MAP_fadeout_colour(x2,y1); + ULONG colour2 = MAP_fadeout_colour(x1,y2); + ULONG colour3 = MAP_fadeout_colour(x2,y2); + + // + // Convert from virtual to real screen coords. + // + + x1 *= MAP_screen_size_x; + y1 *= MAP_screen_size_y; + x2 *= MAP_screen_size_x; + y2 *= MAP_screen_size_y; + + pp[0].X = x1; + pp[0].Y = y1; + pp[0].z = 0.9F; + pp[0].Z = 0.1F; + pp[0].u = u0; + pp[0].v = v0; + pp[0].colour = colour0; + pp[0].specular = 0xff000000; + + pp[1].X = x2; + pp[1].Y = y1; + pp[1].z = 0.9F; + pp[1].Z = 0.1F; + pp[1].u = u1; + pp[1].v = v1; + pp[1].colour = colour1; + pp[1].specular = 0xff000000; + + pp[2].X = x1; + pp[2].Y = y2; + pp[2].z = 0.9F; + pp[2].Z = 0.1F; + pp[2].u = u2; + pp[2].v = v2; + pp[2].colour = colour2; + pp[2].specular = 0xff000000; + + pp[3].X = x2; + pp[3].Y = y2; + pp[3].z = 0.9F; + pp[3].Z = 0.1F; + pp[3].u = u3; + pp[3].v = v3; + pp[3].colour = colour3; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + if (shadow) + { + SLONG i; + + POLY_Point ps [4]; + POLY_Point *tri[3]; + + // + // Create four darkened points. + // + + ps[0] = *(quad[0]); + ps[1] = *(quad[1]); + ps[2] = *(quad[2]); + ps[3] = *(quad[3]); + + // + // Darken the points. + // + + for (i = 0; i < 4; i++) + { + ps[i].colour >>= 1; + ps[i].colour &= 0x7f7f7f7f; + } + + switch(shadow) + { + case 0: + ASSERT(0); // We shouldn't be doing any of this in this case. + break; + + case 1: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + break; + + case 2: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + break; + + case 3: + + //ps[2].colour += 0x00101010; + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + break; + + case 4: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + break; + + case 5: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + break; + + case 6: + + tri[0] = &ps [0]; + tri[1] = quad[1]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + tri[0] = quad[1]; + tri[1] = quad[3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + break; + + case 7: + + tri[0] = quad[0]; + tri[1] = quad[1]; + tri[2] = quad[2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + tri[0] = quad[1]; + tri[1] = &ps [3]; + tri[2] = &ps [2]; + + POLY_add_triangle(tri, page, FALSE, TRUE); + + break; + + default: + ASSERT(0); + break; + } + } + else + { + POLY_add_quad(quad, page, FALSE, TRUE); + } +} + + +// +// Draws a line. +// + +void MAP_draw_line( + float x1, + float y1, + float x2, + float y2, + ULONG colour) +{ + POLY_Point pp [4]; + POLY_Point *quad[4]; + + float dx = fabs(x2 - x1); + float dy = fabs(y2 - y1); + + SLONG colour0 = MAP_fadeout_colour(x1,y1) & colour; + SLONG colour1 = MAP_fadeout_colour(x2,y2) & colour; + + if (!(colour0 | colour1)) + { + return; + } + + // + // Convert to screen coords. + // + + x1 *= MAP_screen_size_x; + y1 *= MAP_screen_size_y; + x2 *= MAP_screen_size_x; + y2 *= MAP_screen_size_y; + + // + // Setup points + // + + pp[0].z = 0.9F; + pp[0].Z = 0.1F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = colour0; + pp[0].specular = 0xff000000; + + pp[1].z = 0.9F; + pp[1].Z = 0.1F; + pp[1].u = 0.0F; + pp[1].v = 0.0F; + pp[1].colour = colour0; + pp[1].specular = 0xff000000; + + pp[2].z = 0.9F; + pp[2].Z = 0.1F; + pp[2].u = 0.0F; + pp[2].v = 0.0F; + pp[2].colour = colour1; + pp[2].specular = 0xff000000; + + pp[3].z = 0.9F; + pp[3].Z = 0.1F; + pp[3].u = 0.0F; + pp[3].v = 0.0F; + pp[3].colour = colour1; + pp[3].specular = 0xff000000; + + if (dx > dy) + { + pp[0].X = x1; + pp[0].Y = y1 - 1.0F; + + pp[1].X = x1; + pp[1].Y = y1 + 1.0F; + + pp[2].X = x2; + pp[2].Y = y2 - 1.0F; + + pp[3].X = x2; + pp[3].Y = y2 + 1.0F; + } + else + { + pp[0].X = x1 - 1.0F; + pp[0].Y = y1; + + pp[1].X = x1 + 1.0F; + pp[1].Y = y1; + + pp[2].X = x2 - 1.0F; + pp[2].Y = y2; + + pp[3].X = x2 + 1.0F; + pp[3].Y = y2; + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE, TRUE); +} + + +// +// Draws an orientated alpha dot with the given colour. +// + +void MAP_draw_dot( + float x, + float y, + float size, + float angle, + ULONG colour) +{ + SLONG mul; + + float dx = size * -(float)sin(angle); + float dy = size * -(float)cos(angle) * 1.33F; + + POLY_Point pp [3]; + POLY_Point *tri[3]; + + mul = MAP_fadeout_colour(x,y) & 0xff; + + { + SLONG a; + SLONG r; + SLONG g; + SLONG b; + + a = (colour >> 24) & 0xff; + r = (colour >> 16) & 0xff; + g = (colour >> 8 ) & 0xff; + b = (colour >> 0 ) & 0xff; + + a = a * mul >> 8; + r = r * mul >> 8; + g = g * mul >> 8; + b = b * mul >> 8; + + colour = a << 24; + colour |= r << 16; + colour |= g << 8; + colour |= b << 0; + } + + // + // Convert from virtual to real screen coords. + // + + x *= MAP_screen_size_x; + y *= MAP_screen_size_y; + dx *= MAP_screen_size_x; + dy *= MAP_screen_size_y; + + pp[0].X = x - dx + dy + dy; + pp[0].Y = y - dy - dx - dx; + pp[0].z = 0.9F; + pp[0].Z = 0.1F; + pp[0].u = 141.0F / 256.0F; + pp[0].v = 167.0F / 256.0F; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = x - dx - dy - dy; + pp[1].Y = y - dy + dx + dx; + pp[1].z = 0.9F; + pp[1].Z = 0.1F; + pp[1].u = 141.0F / 256.0F; + pp[1].v = 187.0F / 256.0F; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = x + dx + dx; + pp[2].Y = y + dy + dy; + pp[2].z = 0.9F; + pp[2].Z = 0.1F; + pp[2].u = 153.0F / 256.0F; + pp[2].v = 177.0F / 256.0F; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + POLY_add_triangle(tri, POLY_PAGE_IC2_ALPHA, FALSE, TRUE); +} + +#endif //#ifndef TARGET_DC + + + + +// +// The pulses... +// + +typedef struct +{ + SLONG life; // 0 => unused + ULONG colour; + float wx; + float wz; + float radius; + +} MAP_Pulse; + +#define MAP_MAX_PULSES 16 + +MAP_Pulse MAP_pulse[MAP_MAX_PULSES]; + + + +// +// Initialises the pulses +// + +void MAP_pulse_init() +{ + memset(MAP_pulse, 0, sizeof(MAP_pulse)); +} + + +// +// Creates a new pulse. +// + +void MAP_pulse_create(float wx, float wz, ULONG colour) +{ + SLONG i; + SLONG best_life = INFINITY; + SLONG best_pulse = INFINITY; + + for (i = 0; i < MAP_MAX_PULSES; i++) + { + if (best_life > MAP_pulse[i].life) + { + best_life = MAP_pulse[i].life; + best_pulse = i; + } + } + + MAP_Pulse *mp; + + ASSERT(WITHIN(best_pulse, 0, MAP_MAX_PULSES - 1)); + + mp = &MAP_pulse[best_pulse]; + + mp->life = 256; + mp->colour = colour; + mp->wx = wx; + mp->wz = wz; + mp->radius = 0.05F; +} + + +#ifndef TARGET_DC + + +// +// Draws an individual pulse +// + +void MAP_pulse_draw(float wx, float wz, float radius, ULONG colour, UBYTE fade) +{ + float x; + float y; + + float x1; + float y1; + float x2; + float y2; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + float dx = MAP_scale_x * radius; + float dy = MAP_scale_y * radius; + + x = MAP_SCREEN_X(wx); + y = MAP_SCREEN_Y(wz); + + x1 = x - dx; + y1 = y - dy; + x2 = x + dx; + y2 = y + dy; + + colour &= MAP_fadeout_colour(x,y); + + if (colour == 0) + { + // + // Don't draw a black pulse... + // + + return; + } + + colour &= 0xffffff; + colour |= fade << 24; + + // + // Convert to screen coords. + // + + x1 *= MAP_screen_size_x; + y1 *= MAP_screen_size_y; + x2 *= MAP_screen_size_x; + y2 *= MAP_screen_size_y; + + // + // Setup points + // + + pp[0].X = x1; + pp[0].Y = y1; + pp[0].z = 0.9F; + pp[0].Z = 0.1F; + pp[0].u = 160.0F / 256.0F; + pp[0].v = 169.0F / 256.0F; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = x2; + pp[1].Y = y1; + pp[1].z = 0.9F; + pp[1].Z = 0.1F; + pp[1].u = 207.0F / 256.0F; + pp[1].v = 169.0F / 256.0F; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = x1; + pp[2].Y = y2; + pp[2].z = 0.9F; + pp[2].Z = 0.1F; + pp[2].u = 160.0F / 256.0F; + pp[2].v = 216.0F / 256.0F; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = x2; + pp[3].Y = y2; + pp[3].z = 0.9F; + pp[3].Z = 0.1F; + pp[3].u = 207.0F / 256.0F; + pp[3].v = 216.0F / 256.0F; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_IC2_ALPHA_END, FALSE, TRUE); +} + +// +// Draws all the pulses. +// + +void MAP_pulse_draw_all() +{ + SLONG i; + + MAP_Pulse *mp; + + for (i = 0; i < MAP_MAX_PULSES; i++) + { + mp = &MAP_pulse[i]; + + if (!mp->life) + { + continue; + } + + MAP_pulse_draw( + mp->wx, + mp->wz, + mp->radius, + mp->colour, + mp->life); + } +} + +#endif //#ifndef TARGET_DC + + +// +// Processes the pulses. +// + +void MAP_process_pulses() +{ + SLONG i; + + MAP_Pulse *mp; + + static SLONG now = 0; + static SLONG last = 0; + + now = GetTickCount(); + + if (last < now - (1000 / 10)) + { + last = now - (1000 / 10); + } + + while(last < now) + { + // + // Process at 20 fps... + // + + last += (1000 / 20); + + for (i = 0; i < MAP_MAX_PULSES; i++) + { + mp = &MAP_pulse[i]; + + if (!mp->life) + { + continue; + } + + mp->life -= 4; + mp->radius += 0.04F; + + if (mp->life < 0) + { + mp->life = 0; + } + } + } +} + + + +#ifndef TARGET_DC + +// +// Draws an arrow in the given direction... +// + +void MAP_draw_arrow(float angle, ULONG colour) +{ + float x; + float y; + + float dx = sin(angle); + float dy = cos(angle); + + float dist = 0.33F + (float)sin(float(GetTickCount()) * 0.005F) * 0.02F; + + x = MAP_screen_x + dx * dist; + y = MAP_screen_y + dy * dist * 1.33F; + + x *= MAP_screen_size_x; + y *= MAP_screen_size_y; + dx *= MAP_screen_size_x * 0.03F; + dy *= MAP_screen_size_y * 0.03F; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + pp[0].X = x + dx - dy; + pp[0].Y = y + dy + dx; + pp[0].z = 0.9F; + pp[0].Z = 0.1F; + pp[0].u = 151.0F / 256.0F; + pp[0].v = 184.0F / 256.0F; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = x + dx + dy; + pp[1].Y = y + dy - dx; + pp[1].z = 0.9F; + pp[1].Z = 0.1F; + pp[1].u = 151.0F / 256.0F; + pp[1].v = 197.0F / 256.0F; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = x - dx - dy; + pp[2].Y = y - dy + dx; + pp[2].z = 0.9F; + pp[2].Z = 0.1F; + pp[2].u = 141.0F / 256.0F; + pp[2].v = 184.0F / 256.0F; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = x - dx + dy; + pp[3].Y = y - dy - dx; + pp[3].z = 0.9F; + pp[3].Z = 0.1F; + pp[3].u = 141.0F / 256.0F; + pp[3].v = 197.0F / 256.0F; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_IC2_ALPHA_END, FALSE, TRUE); +} + +void MAP_draw_3d_arrow( + float angle, + ULONG colour) +{ + SLONG i; + + float vx; + float vy; + float vz; + + float pangle; + float pdist; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + colour &= 0x00ffffff; + colour |= 0x88000000; + + pp[0].u = 151.0F / 256.0F; + pp[0].v = 184.0F / 256.0F; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].u = 151.0F / 256.0F; + pp[1].v = 197.0F / 256.0F; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].u = 141.0F / 256.0F; + pp[2].v = 184.0F / 256.0F; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].u = 141.0F / 256.0F; + pp[3].v = 197.0F / 256.0F; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + static float dangle = 0.25F; + static float ddist = 0.25F; + static float width = 800.0F; + static float below = 0.5F; + + // + // We have our own mini transformation function! + // + + for (i = 0; i < 4; i++) + { + pangle = angle; + pdist = 1.0F; + + #define MAP_3DARROW_DANGLE (dangle) + #define MAP_3DARROW_DDIST (ddist) + + if (i & 1) {pangle -= MAP_3DARROW_DANGLE;} else {pangle += MAP_3DARROW_DANGLE;} + if (i & 2) {pdist += MAP_3DARROW_DDIST ;} + + vx = sin(pangle) * pdist; + vy = below; + vz = cos(pangle) * pdist; + + vz += 2.0F; + + pp[i].Z = 0.5F / vz; + pp[i].z = 0.0F; + pp[i].X = 320.0F + (vx * pp[i].Z * width); + pp[i].Y = 240.0F - (vy * pp[i].Z * width); + } + + POLY_add_quad(quad, POLY_PAGE_IC2_ALPHA_END, FALSE, TRUE); +} + +#endif //#ifndef TARGET_DC + + + + + +// +// The map beacon colours. +// + +#define MAP_MAX_BEACON_COLOURS 6 + +ULONG MAP_beacon_colour[MAP_MAX_BEACON_COLOURS] = +{ + 0xffff00, + 0xff0000, + 0x00ff00, + 0x0000ff, + 0xff00ff, + 0x00ffff +}; + + +// +// Initialise the beacons. +// + +void MAP_beacon_init() +{ + memset(MAP_beacon, 0, sizeof(MAP_Beacon)*MAP_MAX_BEACONS); +} + +// +// Creates a beacon +// + +UBYTE MAP_beacon_create(SLONG x, SLONG z, SLONG index, UWORD track_thing) +{ + SLONG i; + + MAP_Beacon *mb; + + extern SLONG EWAY_mess_upto; + ASSERT(index>=0 && indexused) + { + mb->used = TRUE; + mb->counter = 0; + mb->track_thing = track_thing; + mb->index = index; + mb->wx = x>>0;//float(x) * (1.0F / 256.0F); + mb->wz = z>>0;//float(z) * (1.0F / 256.0F); + mb->ticks = GetTickCount(); + + return i; + } + } + + return 0; +} + +// +// Processes the beacons. +// + +void MAP_process_beacons() +{ + SLONG i; + + MAP_Beacon *mb; + + static SLONG now = 0; + static SLONG last = 0; + + now = GetTickCount(); + + if (last < now - (1000 / 10)) + { + last = now - (1000 / 10); + } + + while(last < now) + { + // + // Process at 20 fps... + // + + last += (1000 / 20); + + for (i = 1; i < MAP_MAX_BEACONS; i++) + { + mb = &MAP_beacon[i]; + + if (!mb->used) + { + continue; + } + + if (mb->track_thing) + { + Thing *p_track = TO_THING(mb->track_thing); + + mb->wx = p_track->WorldPos.X>>8; + mb->wz = p_track->WorldPos.Z>>8; + } + + mb->counter += 1; + + if (mb->counter >= 20) + { + MAP_pulse_create( + ((float) mb->wx)*(1.0f/256.0f), + ((float)mb->wz)*(1.0f/256.0f), + MAP_beacon_colour[i % MAP_MAX_BEACON_COLOURS]); + + mb->counter = 0; + } + } + } +} + + +#ifndef TARGET_DC + + +void MAP_beacon_draw_all() +{ + SLONG i; + + float x; + float y; + + float list = 0.05F; + + float dx; + float dy; + float dist; + float angle; + + SLONG colour; + + MAP_Beacon *mb; + + for (i = 1; i < MAP_MAX_BEACONS; i++) + { + mb = &MAP_beacon[i]; + + if (!mb->used) + { + continue; + } + + x = MAP_SCREEN_IX(mb->wx); + y = MAP_SCREEN_IY(mb->wz); + + colour = MAP_fadeout_colour(x,y); + + if ((colour & 0xff) < 64) + { + dist = + + angle = atan2(x - MAP_screen_x, y - MAP_screen_y); + + colour &= 0xff; + colour *= 4; + colour = 255 - colour; + + colour = MAP_beacon_colour[i % MAP_MAX_BEACON_COLOURS] | (colour << 24); + + MAP_draw_arrow( + angle, + colour); + } + + { + float x1; + float y1; + float x2; + float y2; + + float radius = 0.03F;// + sin(GetTickCount() * 0.005F) * 0.01F; + + SLONG colour; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + x1 = 0.27F * MAP_screen_size_x; + y1 = list * MAP_screen_size_y; + + x2 = x1 + radius * MAP_screen_size_x; + y2 = y1 + radius * MAP_screen_size_y; + + x1 = x1 - radius * MAP_screen_size_x; + y1 = y1 - radius * MAP_screen_size_y; + + colour = MAP_beacon_colour[i % MAP_MAX_BEACON_COLOURS] | 0xff000000; + + // + // Setup points + // + + pp[0].X = x1; + pp[0].Y = y1; + pp[0].z = 0.9F; + pp[0].Z = 0.1F; + pp[0].u = 140.0F / 256.0F; + pp[0].v = 197.0F / 256.0F; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = x2; + pp[1].Y = y1; + pp[1].z = 0.9F; + pp[1].Z = 0.1F; + pp[1].u = 154.0F / 256.0F; + pp[1].v = 197.0F / 256.0F; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = x1; + pp[2].Y = y2; + pp[2].z = 0.9F; + pp[2].Z = 0.1F; + pp[2].u = 140.0F / 256.0F; + pp[2].v = 212.0F / 256.0F; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = x2; + pp[3].Y = y2; + pp[3].z = 0.9F; + pp[3].Z = 0.1F; + pp[3].u = 154.0F / 256.0F; + pp[3].v = 212.0F / 256.0F; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_IC2_ALPHA_END, FALSE, TRUE); + + // + // Draw the text + // + + MENUFONT_Draw( + SLONG(0.3F * MAP_screen_size_x), + SLONG(list * MAP_screen_size_y), + 128, + EWAY_get_mess(mb->index), + MAP_beacon_colour[i % MAP_MAX_BEACON_COLOURS] | 0xff000000, + 0); + + } + + list += 0.03F; + } +} + +#endif //#ifndef TARGET_DC + + +void MAP_beacon_remove(UBYTE beacon) +{ + ASSERT(WITHIN(beacon, 0, MAP_MAX_BEACONS - 1)); + + MAP_beacon[beacon].used = FALSE; +} + + +#ifndef TARGET_DC + + +void MAP_draw_weapons(Thing *p_person) +{ + float x; + float y; + + float yaw = GetTickCount() * 0.004F; + + SLONG index; + + Thing *p_special; + + x = 0.1F; + y = 0.25F; + + if (p_person->Flags & FLAGS_HAS_GUN) + { + MAP_draw_prim( + PRIM_OBJ_ITEM_GUN, + x, + y, + yaw, + 0.5F); + + y += 0.1F; + } + + for (index = p_person->Genus.Person->SpecialList; index; index = p_special->Genus.Special->NextSpecial) + { + yaw += 1.0F; + + p_special = TO_THING(index); + + ASSERT(p_special->Class == CLASS_SPECIAL); + ASSERT(WITHIN(p_special->Genus.Special->SpecialType, 1, SPECIAL_NUM_TYPES - 1)); + + MAP_draw_prim( + SPECIAL_info[p_special->Genus.Special->SpecialType].prim, + x, + y, + yaw, + 0.5F); + + y += 0.1F; + } +} + + + +void MAP_draw() +{ + float x; + float z; + + float u0; + float v0; + float u1; + float v1; + float u2; + float v2; + float u3; + float v3; + + float x1; + float y1; + float x2; + float y2; + + SLONG mx; + SLONG mz; + SLONG mx1; + SLONG mz1; + SLONG mx2; + SLONG mz2; + + SLONG i; + SLONG page; + ULONG colour; + SLONG blue; + SLONG red; + UBYTE opt; + + float scale; + float fx1; + float fz1; + float fx2; + float fz2; + CBYTE str[10]; + + SLONG index; + + Thing *darci = NET_PERSON(0); + Thing *p_thing; + + // + // Clear the screen. + // + + AENG_clear_screen(); + + // + // Clear the buffers. + // + +#ifndef TARGET_DC + POLY_frame_init(FALSE,FALSE); +#endif + + // + // The real screen size. + // + + MAP_screen_size_x = float(DisplayWidth); + MAP_screen_size_y = float(DisplayHeight); + + // + // Centre the map on darci. + // + + MAP_world_x = float(darci->WorldPos.X) * (1.0F / 65536.0F); + MAP_world_z = float(darci->WorldPos.Z) * (1.0F / 65536.0F); + + // + // Find the four points at the edge of the screen. + // + + fx1 = MAP_WORLD_X(0.2F); + fz1 = MAP_WORLD_Z(0.0F); + fx2 = MAP_WORLD_X(1.0F); + fz2 = MAP_WORLD_Z(1.0F); + + mx1 = SLONG(fx1); + mz1 = SLONG(fz1); + mx2 = SLONG(fx2); + mz2 = SLONG(fz2); + + SATURATE(mx1, 1, PAP_SIZE_HI - 2); + SATURATE(mz1, 1, PAP_SIZE_HI - 2); + SATURATE(mx2, 1, PAP_SIZE_HI - 2); + SATURATE(mz2, 1, PAP_SIZE_HI - 2); + + for (mx = mx1; mx <= mx2; mx++) + for (mz = mz1; mz <= mz2; mz++) + { + TEXTURE_get_minitexturebits_uvs( + PAP_2HI(mx,mz).Texture, + &page, + &u0, + &v0, + &u1, + &v1, + &u2, + &v2, + &u3, + &v3); + + MAP_sprite( + page, + MAP_SCREEN_X(float(mx)), + MAP_SCREEN_Y(float(mz)), + MAP_scale_x, + MAP_scale_y, + u0, + v0, + u1, + v1, + u2, + v2, + u3, + v3, + PAP_2HI(mx,mz).Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3)); + + for (i = 0; i < 4; i++) + { + opt = MAV_get_caps(mx,mz,i); + + colour = 0; + + if (!(opt & MAV_CAPS_GOTO )) {colour = 0xffff0000;} + if ( (opt & MAV_CAPS_CLIMB_OVER)) {colour = 0xffffff00;} + if ( (opt & MAV_CAPS_LADDER_UP )) {colour = 0xff00ffff;} + + if (colour) + { + switch(i) + { + case MAV_DIR_XS: + x1 = MAP_SCREEN_X(mx ); + y1 = MAP_SCREEN_Y(mz ); + x2 = MAP_SCREEN_X(mx ); + y2 = MAP_SCREEN_Y(mz+1); + break; + + case MAV_DIR_XL: + x1 = MAP_SCREEN_X(mx+1); + y1 = MAP_SCREEN_Y(mz ); + x2 = MAP_SCREEN_X(mx+1); + y2 = MAP_SCREEN_Y(mz+1); + break; + + case MAV_DIR_ZS: + x1 = MAP_SCREEN_X(mx ); + y1 = MAP_SCREEN_Y(mz ); + x2 = MAP_SCREEN_X(mx+1); + y2 = MAP_SCREEN_Y(mz ); + break; + + case MAV_DIR_ZL: + x1 = MAP_SCREEN_X(mx ); + y1 = MAP_SCREEN_Y(mz+1); + x2 = MAP_SCREEN_X(mx+1); + y2 = MAP_SCREEN_Y(mz+1); + break; + } + + MAP_draw_line( + x1, y1, + x2, y2, + colour); + } + } + } + + // + // Draw the important things... + // + + mx1 >>= 2; + mz1 >>= 2; + mx2 >>= 2; + mz2 >>= 2; + + for (mx = mx1; mx <= mx2; mx++) + for (mz = mz1; mz <= mz2; mz++) + { + index = PAP_2LO(mx,mz).MapWho; + + while(index) + { + p_thing = TO_THING(index); + + switch(p_thing->Class) + { + case CLASS_PERSON: + + switch(p_thing->Genus.Person->PersonType) + { + case PERSON_DARCI: + case PERSON_ROPER: + scale = float(GetTickCount()); + scale *= 0.02F; + scale = sin(scale); + scale *= 0.2F; + scale += 1.0F; + scale *= MAP_scale_x; + colour = 0xffffffff; + break; + + case PERSON_COP: + + red = ((GetTickCount() >> 3) ) & 0x1ff; + blue = ((GetTickCount() >> 3) + 0xff) & 0x1ff; + + if (red > 0xff) {red = 0x1ff - red; } + if (blue > 0xff) {blue = 0x1ff - blue;} + + colour = 0xff000000; + colour |= red << 16; + colour |= blue; + scale = MAP_scale_x * 0.5F; + break; + + case PERSON_THUG_RASTA: + case PERSON_THUG_GREY: + case PERSON_THUG_RED: + scale = MAP_scale_x * 0.5F; + colour = 0xffff0000; + break; + + case PERSON_SLAG_TART: + case PERSON_SLAG_FATUGLY: + scale = MAP_scale_x * 0.5F; + colour = 0xffffff00; + break; + + case PERSON_CIV: + case PERSON_MECHANIC: + scale = MAP_scale_x * 0.5F; + colour = 0xff00ff00; + break; + + case PERSON_HOSTAGE: + scale = MAP_scale_x * 0.5F; + colour = 0xffff00ff; + break; + + default: + scale = MAP_scale_x * 0.5F; + colour = 0xff888888; + break; + } + + MAP_draw_dot( + MAP_SCREEN_X(float(p_thing->WorldPos.X) * (1.0F / 65536.0F)), + MAP_SCREEN_Y(float(p_thing->WorldPos.Z) * (1.0F / 65536.0F)), + scale, + float(p_thing->Draw.Tweened->Angle) * (2.0F * PI / 2048.0F), + colour); + + break; + + case CLASS_VEHICLE: + + MAP_draw_dot( + MAP_SCREEN_X(float(p_thing->WorldPos.X) * (1.0F / 65536.0F)), + MAP_SCREEN_Y(float(p_thing->WorldPos.Z) * (1.0F / 65536.0F)), + MAP_scale_x * 2.0F, + float(p_thing->Genus.Vehicle->Angle) * (2.0F * PI / 2048.0F), + 0xff0000ff); + + break; + + default: + break; + } + + index = p_thing->Child; + } + } + + // + // Use the startscreen code to plonk down a logo... + // + + void STARTSCR_plonk_logo(void); + + // this logo sucks + // STARTSCR_plonk_logo(); + + // + // Draw the stats + // + + FONT2D_DrawString("Strength:",10,10,0xffffff,192,POLY_PAGE_FONT2D,0); + FONT2D_DrawString("Stamina:",10,30,0xffffff,192,POLY_PAGE_FONT2D,0); + FONT2D_DrawString("Skill:",10,50,0xffffff,192,POLY_PAGE_FONT2D,0); + FONT2D_DrawString("Constitution:",10,70,0xffffff,192,POLY_PAGE_FONT2D,0); + itoa(NET_PLAYER(0)->Genus.Player->Strength,str,10); + FONT2D_DrawString(str,100,10,0xffffff,192,POLY_PAGE_FONT2D,0); + itoa(NET_PLAYER(0)->Genus.Player->Stamina,str,10); + FONT2D_DrawString(str,100,30,0xffffff,192,POLY_PAGE_FONT2D,0); + itoa(NET_PLAYER(0)->Genus.Player->Skill,str,10); + FONT2D_DrawString(str,100,50,0xffffff,192,POLY_PAGE_FONT2D,0); + itoa(NET_PLAYER(0)->Genus.Player->Constitution,str,10); + FONT2D_DrawString(str,100,70,0xffffff,192,POLY_PAGE_FONT2D,0); + + // + // Draw the pulses. + // + + MAP_pulse_draw_all(); + MAP_beacon_draw_all(); + + // + // Draw the weapons carried by Darci... + // + + MAP_draw_weapons(darci); + + // + // Draw the frame. + // + +#ifndef TARGET_DC + POLY_frame_draw(FALSE,FALSE); +#endif +} + +#endif //#ifndef TARGET_DC + + +void MAP_process() +{ + MAP_process_beacons(); + MAP_process_pulses (); +} + + +#ifndef TARGET_DC + +void MAP_draw_onscreen_beacons(void) +{ + SLONG i; + + float x; + float y; + + float list = 0.05F; + + float dx; + float dz; + float dist; + float angle; + + SLONG colour; + + MAP_Beacon *mb; + + for (i = 1; i < MAP_MAX_BEACONS; i++) + { + mb = &MAP_beacon[i]; + + if (!mb->used) + { + continue; + } + + dx = float(mb->wx - (FC_cam[0].x >> 8)); + dz = float(mb->wz - (FC_cam[0].z >> 8)); + + angle = -atan2(dx,dz) - float(FC_cam[0].yaw) * (2.0F * PI / (2048.0F * 256.0F)); + dist = fabs(dx) + fabs(dz); + + colour = MAP_beacon_colour[i % MAP_MAX_BEACON_COLOURS]; + + MAP_draw_3d_arrow( + angle, + colour); + } +} + + +#endif //#ifndef TARGET_DC diff --git a/fallen/DDEngine/Source/menufont.cpp b/fallen/DDEngine/Source/menufont.cpp new file mode 100644 index 0000000..384b91a --- /dev/null +++ b/fallen/DDEngine/Source/menufont.cpp @@ -0,0 +1,1004 @@ +/************************************************************ + * + * menufont.cpp + * 2D proportional-font text writer with poncey afterfx + * + */ + +#include "MenuFont.h" +#include "tga.h" +#include "poly.h" +#include "c:\fallen\headers\noserver.h" + +#ifdef TARGET_DC +#include "target.h" +#endif + + + + + +#ifdef TARGET_DC +// The Yanks call them VMUs, Europeans call them VMs. Madness. +bool bWriteVMInsteadOfVMU = FALSE; +#endif + + + + +CharData FontInfo[256]; +CBYTE FontName[_MAX_PATH]; +SLONG FontPage; +SLONG FONT_TICK=0; + +inline BOOL Red(SLONG ofs, TGA_Pixel *data) { + return ((data[ofs].red>200)&&(!data[ofs].blue)&&(!data[ofs].green)); +} +inline BOOL Bloo(SLONG ofs, TGA_Pixel *data) { + return ((data[ofs].blue>200)&&(!data[ofs].red)&&(!data[ofs].green)); +} + +inline BOOL Mata(SLONG ofs, TGA_Pixel *data) { + return (Red(ofs,data)&&Red(ofs+1,data)&&(Red(ofs+256,data))); +} + +void MENUFONT_Page(SLONG page) { + FontPage=page; +} + +// +// oh fuck +// +#ifdef NO_SERVER + #define TEXTURE_EXTRA_DIR "server\\textures\\extras\\" +#else + #define TEXTURE_EXTRA_DIR "u:\\urbanchaos\\textures\\extras\\" + +#endif + +/*void MENUFONT_Load(CBYTE *fn, SLONG page, CBYTE *fontlist) { + TGA_Pixel *temp; + UBYTE *pt; + UWORD x,y,ox,oy,ofs, yofs; + CBYTE tmp[_MAX_PATH]; + + if (!stricmp(fn,FontName)) return; + strcpy(FontName,fn); + FontPage=page; + + // scan the tga... + temp = new TGA_Pixel[256*256]; + strcpy(tmp,TEXTURE_EXTRA_DIR); + strcat(tmp,fn); + TGA_load(tmp,256,256,temp,-1); + + pt=(UBYTE*)fontlist; + + ZeroMemory(FontInfo,sizeof(FontInfo)); + + for (y=0;y<255;y++) + for (x=0;x<255;x++) + if (Mata(ofs=x|(y<<8),temp)) { + FontInfo[*pt].x=ox=x+1; + FontInfo[*pt].y=oy=y+1; + ofs+=257; yofs=0; + while (!Red(ofs+1,temp)) { + ofs++; ox++; + } + FontInfo[*pt].ox=ox; + while (!Red(ofs+256,temp)) { + ofs+=256; oy++; + if (Bloo(ofs+1,temp)) { + FontInfo[*pt].yofs=yofs; + } + yofs++; + } + FontInfo[*pt].oy=oy; + + // extra border space -- avoid redness + FontInfo[*pt].x++; + FontInfo[*pt].y++; +// FontInfo[*pt].ox--; +// FontInfo[*pt].oy--; +// FontInfo[*pt].ox++; +// FontInfo[*pt].oy++; + + +// FontInfo[*pt].width =ox-(x+1); +// FontInfo[*pt].height=oy-(y+1); + FontInfo[*pt].width =ox-(x-1); + FontInfo[*pt].height=oy-(y); + + FontInfo[*pt].x/=256.0; + FontInfo[*pt].y/=256.0; + FontInfo[*pt].ox/=256.0; + FontInfo[*pt].oy/=256.0; + pt++; + } + + delete [] temp; + + if (!FontInfo[32].width) FontInfo[32].width=FontInfo[65].width; + + +} +*/ +void MENUFONT_Load(CBYTE *fn, SLONG page, CBYTE *fontlist) { + TGA_Pixel *temp; + UBYTE *pt; + UWORD x,y,ox,oy,ofs, yofs; + CBYTE tmp[_MAX_PATH]; + + if (!stricmp(fn,FontName)) return; + strcpy(FontName,fn); + FontPage=page; + + // scan the tga... + temp = new TGA_Pixel[256*256]; + ASSERT ( temp != NULL ); + strcpy(tmp,TEXTURE_EXTRA_DIR); + strcat(tmp,fn); + TGA_load(tmp,256,256,temp,-1,FALSE); + + pt=(UBYTE*)fontlist; + + ZeroMemory(FontInfo,sizeof(FontInfo)); + + for (y=0;y<255;y++) + for (x=0;x<255;x++) + if (Mata(ofs=x|(y<<8),temp)) { + FontInfo[*pt].x=ox=x+1; + FontInfo[*pt].y=oy=y+1; + ofs+=257; yofs=0; + while (!Red(ofs+1,temp)) { + ofs++; ox++; + } + FontInfo[*pt].ox=ox; + while (!Red(ofs+256,temp)) { + ofs+=256; oy++; + yofs++; + } + FontInfo[*pt].oy=oy; + + FontInfo[*pt].width =ox-(x-1); + FontInfo[*pt].height=oy-(y); + + FontInfo[*pt].x/=256.0f; + FontInfo[*pt].y/=256.0f; + FontInfo[*pt].ox/=256.0f; + FontInfo[*pt].oy/=256.0f; + pt++; + if (!*pt) break; + } + + delete [] temp; + + if (!FontInfo[32].width) FontInfo[32].width=FontInfo[65].width; + +} + + + + +#ifndef TARGET_DC + +#define SC(a) (SIN(a&2047)>>15) +#define CC(a) (COS(a&2047)>>15) + +void MENUFONT_DrawFlanged(SWORD x, SWORD y, UWORD scale, CBYTE *msg, SLONG alpha, SLONG rgb, UBYTE flags) +{ + SLONG width=0,height,c0,len=strlen(msg), i; + UBYTE *pt; + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + + + + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xff000000; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=rgb | (alpha<<24); + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=0.5f; + + alpha>>=2; + + pt=(UBYTE*)msg; + for (c0=0;c0> 8; + height = (FontInfo[*pt].height * scale) >> 8; + + if ((width>0)&&(height>0)) { + + pp[0].u=FontInfo[*pt].x; pp[0].v=FontInfo[*pt].y; + pp[1].u=FontInfo[*pt].ox; pp[1].v=FontInfo[*pt].y; + pp[2].u=FontInfo[*pt].x; pp[2].v=FontInfo[*pt].oy; + pp[3].u=FontInfo[*pt].ox; pp[3].v=FontInfo[*pt].oy; + + if (flags & MENUFONT_SINED) + for (i=0;i<4;i++) { + pp[0].X=x; pp[0].Y=y+(SIN(((x+FONT_TICK)<>13); + pp[1].X=x+width; pp[1].Y=y+(SIN(((x+width+FONT_TICK)<>13); + pp[2].X=x; pp[2].Y=y+height; + pp[3].X=x+width; pp[3].Y=y+height; + POLY_add_quad(quad,FontPage,FALSE,TRUE); + } + else + for (i=1;i<4;i++) { + pp[0].X=x+SC((x+(i*128)+FONT_TICK)<<2); + pp[0].Y=y+SC((x+(i*194)+FONT_TICK)<<2); + pp[1].X=x+width+CC((x+width+FONT_TICK)<<2); + pp[1].Y=y+SC((x+width+FONT_TICK)<<2); + pp[2].X=x+CC((x+(i*128)+FONT_TICK)<<2); + pp[2].Y=y+height+SC((x+(i*194)+FONT_TICK)<<2); + pp[3].X=x+width+CC((x+width-(i*128)+FONT_TICK)<<2); + pp[3].Y=y+height+CC((x+width+FONT_TICK)<<2); + POLY_add_quad(quad,FontPage,FALSE,TRUE); + } + } + + pt++; + x+=width-1; + } +} + +void MENUFONT_DrawFutzed(SWORD x, SWORD y, UWORD scale, CBYTE *msg, SLONG alpha, SLONG rgb, UBYTE flags) { + SLONG width=0,height,c0,len=strlen(msg), i,j,k; + UBYTE *pt; + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + float uys, ys, uyc, yc; + + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xff000000; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=rgb | (alpha<<24); + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=0.5f; + + j=(!(rand()&0x1f)); + + pt=(UBYTE*)msg; + for (c0=0;c0> 8; + height = (FontInfo[*pt].height * scale) >> 8; + + if ((width>0)&&(height>0)) { + + pp[0].u=FontInfo[*pt].x; + pp[1].u=FontInfo[*pt].ox; + pp[2].u=FontInfo[*pt].x; + pp[3].u=FontInfo[*pt].ox; + pp[0].X=x; + pp[1].X=x+width; + pp[2].X=x; + pp[3].X=x+width; + + uys=FontInfo[*pt].oy-FontInfo[*pt].y; + uys*=0.125f; // 1/8 0.0625; // 1/16 + ys=height*0.125f; + + uyc=FontInfo[*pt].y; + yc=y; + +// j=SIN(TICK<<3)>>8; +// j=(!(rand()&0xff)); + + + for (i=0;i<8;i++) + { + +// if (abs(i-j)<8) +// if (!(rand()%0xff)) + if (j) + { +// k=SIN(((i-j)<<3)&2047)>>14; + k=rand()%7; + pp[0].X=x+k; + pp[1].X=x+width+k; +// k=SIN(((i+1-j)<<3)&2047)>>14; + k=rand()%7; + pp[2].X=x+k; + pp[3].X=x+width+k; + } + + pp[0].v=pp[1].v=uyc; + uyc+=uys; + pp[2].v=pp[3].v=uyc; + pp[0].Y=pp[1].Y=yc; + yc+=ys; + pp[2].Y=pp[3].Y=yc; + POLY_add_quad(quad,FontPage,FALSE,TRUE); + } + } + + pt++; + x+=width-1; + } + +} + +#endif + + +#ifdef TARGET_DC + + +// Actually draws the box. +void MENUFONT_Draw_Selection_Box_Sized(SWORD x, SWORD y, SWORD x2, SWORD y2, SLONG uwLineWidth, SLONG rgb ) +{ + SLONG width=0,height; + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + + width = x2 - x; + height = y2 - y; + + + rgb = 0xa0404040; + + // Draw a grey box behind the text. + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xff000000; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=rgb; + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=0.80f; + + pp[0].u=pp[0].v=0.0f; + pp[1].u=pp[1].v=0.0f; + pp[2].u=pp[2].v=0.0f; + pp[3].u=pp[3].v=0.0f; + + pp[0].X=x; pp[0].Y=y; + pp[1].X=x+width; pp[1].Y=y; + pp[2].X=x; pp[2].Y=y+height; + pp[3].X=x+width; pp[3].Y=y+height; + + POLY_add_quad(quad,POLY_PAGE_ALPHA,FALSE,TRUE); + + // Then draw a pure white frame. + rgb = 0xffffffff; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=rgb; + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=0.82f; + + // Top line. + pp[0].X=x; pp[0].Y=y; + pp[1].X=x+width; pp[1].Y=y; + pp[2].X=x; pp[2].Y=y+uwLineWidth; + pp[3].X=x+width; pp[3].Y=y+uwLineWidth; + + POLY_add_quad(quad,POLY_PAGE_COLOUR,FALSE,TRUE); + + // Bottom line. + pp[0].X=x; pp[0].Y=y+height-uwLineWidth; + pp[1].X=x+width; pp[1].Y=y+height-uwLineWidth; + pp[2].X=x; pp[2].Y=y+height; + pp[3].X=x+width; pp[3].Y=y+height; + + POLY_add_quad(quad,POLY_PAGE_COLOUR,FALSE,TRUE); + + // Left line. + pp[0].X=x; pp[0].Y=y; + pp[1].X=x+uwLineWidth; pp[1].Y=y; + pp[2].X=x; pp[2].Y=y+height; + pp[3].X=x+uwLineWidth; pp[3].Y=y+height; + + POLY_add_quad(quad,POLY_PAGE_COLOUR,FALSE,TRUE); + + // Right line. + pp[0].X=x+width-uwLineWidth; pp[0].Y=y; + pp[1].X=x+width; pp[1].Y=y; + pp[2].X=x+width-uwLineWidth; pp[2].Y=y+height; + pp[3].X=x+width; pp[3].Y=y+height; + + POLY_add_quad(quad,POLY_PAGE_COLOUR,FALSE,TRUE); + +} + + + + +void MENUFONT_Draw_Selection_Box(SWORD x, SWORD y, UWORD scale, CBYTE *msg, SLONG rgb, UWORD flags, SWORD max) +{ + SLONG width=0,height,c0,len=strlen(msg); + UBYTE hchar = (flags&MENUFONT_SUPER_YCTR) ? (UBYTE)*msg : 'M'; + UBYTE *pt; + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + + if (max==-1) max=len; + + +#ifdef TARGET_DC + // Scan for the word "VMU". + // Mark the "U" as not to be drawn. + UBYTE *pDontDrawThisLetter = NULL; + if ( bWriteVMInsteadOfVMU ) + { + pDontDrawThisLetter = (UBYTE *)strstr ( msg, "VMU" ); + if ( pDontDrawThisLetter != NULL ) + { + // Point to the U + pDontDrawThisLetter += 2; + } + } +#endif + + + height = (FontInfo[hchar].height*scale)>>8; + y -= height >> 1; + + pt=(UBYTE*)msg; + for (c0=0;c0>8; + } + } + if (flags&(MENUFONT_CENTRED|MENUFONT_RIGHTALIGN)) + { + x-= ( flags&MENUFONT_CENTRED) ? width>>1 : width; + } + + // Now draw a box slightly bigger. + UWORD uwOffset = height >> 2; + x -= uwOffset; + y -= uwOffset; + height += uwOffset << 1; + width += uwOffset << 1; + + UWORD uwLineWidth = uwOffset >> 1; + + MENUFONT_Draw_Selection_Box_Sized ( x, y, x+width, y+height, uwLineWidth, rgb ); + +} + + +#endif + + +void MENUFONT_Draw(SWORD x, SWORD y, UWORD scale, CBYTE *msg, SLONG rgb, UWORD flags, SWORD max) { + const UBYTE haloscale=3; + SLONG width=0,height,c0,len=strlen(msg); + //SLONG col; + UBYTE *pt; +// float fscale=(float)scale/256.0; + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + UBYTE hchar = (flags&MENUFONT_SUPER_YCTR) ? (UBYTE)*msg : 'M'; + SLONG yofs; + + if (max==-1) max=len; + + +#ifdef TARGET_DC + // Scan for the word "VMU". + // Mark the "U" as not to be drawn. + UBYTE *pDontDrawThisLetter = NULL; + if ( bWriteVMInsteadOfVMU ) + { + pDontDrawThisLetter = (UBYTE *)strstr ( msg, "VMU" ); + if ( pDontDrawThisLetter != NULL ) + { + // Point to the U + pDontDrawThisLetter += 2; + } + } +#endif + + + +#ifdef TARGET_DC + // Make the new font a bit bigger on screen. + //scale *= 1.2f; +#endif + + y-=(FontInfo[hchar].height*scale)>>9; + + if (flags&(MENUFONT_CENTRED|MENUFONT_RIGHTALIGN)) { + pt=(UBYTE*)msg; + for (c0=0;c0>8; + } + } + x-= ( flags&MENUFONT_CENTRED) ? width>>1 : width; + } + +#ifdef TARGET_DC + // Foolish mortal - you doubt the power of DC to use MODULATEALPHA? +#else + { + + SLONG a = (rgb >> 24) & 0xff; + SLONG r = (rgb >> 16) & 0xff; + SLONG g = (rgb >> 8) & 0xff; + SLONG b = (rgb >> 0) & 0xff; + + r = r * a >> 8; + g = g * a >> 8; + b = b * a >> 8; + + rgb = (r << 16) | (g << 8) | (b << 0); + } +#endif + + + ASSERT ( ( flags & ( MENUFONT_GLIMMER | MENUFONT_SHAKE | MENUFONT_FUTZING | MENUFONT_FLANGED | MENUFONT_SINED | MENUFONT_HALOED ) ) == 0 ); + + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xff000000; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=rgb; +#ifdef TARGET_DC + // A bit further forwards please. +extern float PANEL_GetNextDepthBodge ( void ); + + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=PANEL_GetNextDepthBodge(); +#else + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=0.5f; +#endif + + + + + pt=(UBYTE*)msg; + for (c0=0;c0> 8; + height = (FontInfo[*pt].height * scale) >> 8; + + yofs=(FontInfo[*pt].yofs*scale)>>8; + y+=yofs; + + if ((width>0)&&(height>0)) { + + pp[0].u=FontInfo[*pt].x; pp[0].v=FontInfo[*pt].y; + pp[1].u=FontInfo[*pt].ox; pp[1].v=FontInfo[*pt].y; + pp[2].u=FontInfo[*pt].x; pp[2].v=FontInfo[*pt].oy; + pp[3].u=FontInfo[*pt].ox; pp[3].v=FontInfo[*pt].oy; + + if (!(flags&MENUFONT_ONLY)) { + pp[0].X=x; pp[0].Y=y; + pp[1].X=x+width; pp[1].Y=y; + pp[2].X=x; pp[2].Y=y+height; + pp[3].X=x+width; pp[3].Y=y+height; + + POLY_add_quad(quad,FontPage,FALSE,TRUE); + } + } + + y-=yofs; + + pt++; + x+=width-1; + } + } +} + + + + +// I don't want to have to code a VMU->VM skipping thing for every rout, +// so here's a checker. +#ifdef DEBUG +#define CHECKTHEREARENOVMUSINHERE(string) ASSERT ( strstr ( string, "VMU" ) == NULL ) +#else +#define CHECKTHEREARENOVMUSINHERE(string) sizeof ( string ) +#endif + + + + +void MENUFONT_Draw_floats(float x, float y, UWORD scale, CBYTE *msg, SLONG rgb, UWORD flags) { + const UBYTE haloscale=3; + SLONG c0,len=strlen(msg); + //SLONG col; + float width=0,height; + UBYTE *pt; + float fscale=(float)scale/256.0f; + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + UBYTE hchar = (flags&MENUFONT_SUPER_YCTR) ? (UBYTE)*msg : 'M'; + + + CHECKTHEREARENOVMUSINHERE ( msg ); + + + if (flags&MENUFONT_HSCALEONLY) { + y-=FontInfo[hchar].height*0.5f; + } else { + y-=(FontInfo[hchar].height*fscale)*0.5f; + } + + if (flags&(MENUFONT_CENTRED|MENUFONT_RIGHTALIGN)) { + pt=(UBYTE*)msg; + for (c0=0;c0> 24) & 0xff; + SLONG r = (rgb >> 16) & 0xff; + SLONG g = (rgb >> 8) & 0xff; + SLONG b = (rgb >> 0) & 0xff; + + r = r * a >> 8; + g = g * a >> 8; + b = b * a >> 8; + + rgb = (r << 16) | (g << 8) | (b << 0); + } + + + pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xff000000; + pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour = rgb; + pp[0].Z=pp[1].Z=pp[2].Z=pp[3].Z=0.5f; + + pt=(UBYTE*)msg; + for (c0=0;c00)&&(height>0)) { + + pp[0].u=FontInfo[*pt].x; pp[0].v=FontInfo[*pt].y; + pp[1].u=FontInfo[*pt].ox; pp[1].v=FontInfo[*pt].y; + pp[2].u=FontInfo[*pt].x; pp[2].v=FontInfo[*pt].oy; + pp[3].u=FontInfo[*pt].ox; pp[3].v=FontInfo[*pt].oy; + + if (!(flags&MENUFONT_ONLY)) { + pp[0].X=x; pp[0].Y=y; + pp[1].X=x+width; pp[1].Y=y; + pp[2].X=x; pp[2].Y=y+height; + pp[3].X=x+width; pp[3].Y=y+height; + + POLY_add_quad(quad,FontPage,FALSE,TRUE); + } + + } + + y-=FontInfo[*pt].yofs; + + pt++; + x+=width-1; + } +} + +void MENUFONT_Dimensions(CBYTE *fn, SLONG &x, SLONG &y, SWORD max, SWORD scale) { + UBYTE *fn2=(UBYTE*)fn; + + +#ifdef TARGET_DC + // Scan for the word "VMU". + // Mark the "U" as not to be drawn. + UBYTE *pDontDrawThisLetter = NULL; + if ( bWriteVMInsteadOfVMU ) + { + pDontDrawThisLetter = (UBYTE *)strstr ( fn, "VMU" ); + if ( pDontDrawThisLetter != NULL ) + { + // Point to the U + pDontDrawThisLetter += 2; + } + } +#endif + + + if (!fn2[1]) { + x=FontInfo[*fn2].width; + y=FontInfo[*fn2].height; + x*=scale; x>>=8; + y*=scale; y>>=8; + return; + } + x=0; y=FontInfo[*fn2].height; + while (max && *fn2) { + +#ifdef TARGET_DC + if ( fn2 == pDontDrawThisLetter ) + { + // Ignore this letter. + fn2++; + max--; + } + else +#endif + { + if (FontInfo[*fn2].height>y) y=FontInfo[*fn2].height; + x+=FontInfo[*fn2].width-1; + fn2++; + max--; + } + } + x*=scale; x>>=8; + y*=scale; y>>=8; +} + +SLONG MENUFONT_CharWidth(CBYTE fn, UWORD scale) { + return (FontInfo[(UBYTE)fn].width*scale)>>8; +} + +SLONG MENUFONT_CharFit(CBYTE *fn, SLONG x, UWORD scale) { + SLONG ctr=0,width=0; + UBYTE *fn2=(UBYTE*)fn; + + if (! *fn) return 0; + + while (*fn2 && (width>8)-1; + ctr++; + } + if (width>x) ctr--; + return ctr; +} + +void MENUFONT_Free() { + FontName[0]=0; +} + +void MENUFONT_MergeLower() { + UBYTE c; + + for (c='a';c<='z';c++) { + FontInfo[c]=FontInfo[c-32]; + } +/* for (c='à';c<='ý';c++) { + FontInfo[c]=FontInfo[c-32]; + }*/ + for (c=224;c<=252;c++) { + FontInfo[c]=FontInfo[c-32]; + } +} + + + + + +// ======================================================== +// +// Cool line-fade-in text. +// +// ======================================================== + +// +// The line where we fade in. +// + +float MENUFONT_fadein_x; + +// +// The width of the fading in line. +// + +#define MENUFONT_FADEIN_LEFT 256 +#define MENUFONT_FADEIN_RIGHT 16 + + + +void MENUFONT_fadein_init() +{ + MENUFONT_fadein_x = 640.0F; +} + +void MENUFONT_fadein_line(SLONG x) +{ + MENUFONT_fadein_x = float(x) * (1.0F / 256.0F); +} + +// +// Draws a single character to the left of the fadein line. Returns +// the width of the character. +// + +float MENUFONT_fadein_char(float x, float y, UBYTE ch, UBYTE fade) +{ + CharData *cd = &FontInfo[ch]; + + if (x < 0 || x + cd->width >= 640.0F || + y < 0 || y + cd->height >= 480.0F) + { + // + // No clipping allowed. + // + + return cd->width; + } + + void PANEL_draw_quad( + float left, + float top, + float right, + float bottom, + SLONG page, + ULONG colour = 0xffffffff, + float u1 = 0.0F, + float v1 = 0.0F, + float u2 = 1.0F, + float v2 = 1.0F); + + if (x + cd->width < MENUFONT_fadein_x - MENUFONT_FADEIN_LEFT) + { + // + // This character is totally to the left of the fadein line. + // + + PANEL_draw_quad( + x, y, + x + cd->width, + y + cd->height, + FontPage, + (fade << 0) | (fade << 8) | (fade << 16) | (fade << 24), + cd->x, + cd->y, + cd->ox, + cd->oy); + } + else + if (x > MENUFONT_fadein_x + MENUFONT_FADEIN_RIGHT) + { + // + // Totally to the right of the fadein line. + // + } + else + { + // + // Crosses the fadein line. + // + + #define MENUFONT_FADEIN_SEGMENTS 16 + + SLONG i; + + float x1; + float y1; + float x2; + float y2; + + float u1; + float v1; + float u2; + float v2; + + float mx; + float my; + + float expand; + + SLONG bright; + SLONG colour; + + for (i = 0; i < MENUFONT_FADEIN_SEGMENTS; i++) + { + x1 = x + float(i * cd->width) * (1.0F / MENUFONT_FADEIN_SEGMENTS); + y1 = y; + x2 = x1 + float(cd->width) * (1.0F / MENUFONT_FADEIN_SEGMENTS); + y2 = y1 + float(cd->height); + + u1 = cd->x + float(i * (cd->ox - cd->x)) * (1.0F / MENUFONT_FADEIN_SEGMENTS); + v1 = cd->y; + u2 = u1 + float(cd->ox - cd->x) * (1.0F / MENUFONT_FADEIN_SEGMENTS); + v2 = cd->oy; + + // + // Expand this segment a bit... + // + + #define MENUFONT_FADEIN_MAX_EXPAND 16.0F + + if (x1 > MENUFONT_fadein_x) + { + expand = 1.0F - (x1 - MENUFONT_fadein_x) * (1.0F / MENUFONT_FADEIN_RIGHT); + expand *= expand; + expand *= expand; + expand *= expand; + bright = expand * 16.0F; + + expand *= MENUFONT_FADEIN_MAX_EXPAND; + + SATURATE(bright, 0, 16); + } + else + { + expand = 1.0F - (MENUFONT_fadein_x - x1) * (1.0F / MENUFONT_FADEIN_LEFT); + bright = 255 - expand * 224; + expand *= expand; + expand *= expand; + expand *= expand; + + expand *= MENUFONT_FADEIN_MAX_EXPAND; + } + + SATURATE(expand, 0.0F, MENUFONT_FADEIN_MAX_EXPAND); + + mx = (x1 + x2) * 0.5F; + my = (y1 + y2) * 0.5F; + + x1 = x1 + (x1 - mx) * expand * 0.5F; + y1 = y1 + (y1 - my) * expand; + x2 = x2 + (x2 - mx) * expand * 0.25F; + y2 = y2 + (y2 - my) * expand; + + SATURATE(bright, 0, 255); + + colour = bright * fade >> 8; + colour |= colour << 8; + colour |= colour << 8; + colour |= colour << 8; + + PANEL_draw_quad( + x1, y1, + x2, y2, + FontPage, + colour, + u1, v1, + u2, v2); + } + } + + return cd->width; +} + + +// +// Draws centred text. +// + +void MENUFONT_fadein_draw(SLONG x, SLONG y, UBYTE fade, CBYTE *msg) +{ + CBYTE *ch; + + float tx; + + // + // Centre the text. + // + + tx = x; + + if (msg == NULL) + { + msg = ""; + } + + for (ch = msg; *ch; ch++) + { + tx -= float(FontInfo[*ch].width) * 0.5F; + } + + // + // Draw it. + // + + for (ch = msg; *ch; ch++) + { + tx += MENUFONT_fadein_char(tx, y, *ch, fade); + } +} + diff --git a/fallen/DDEngine/Source/mesh.cpp b/fallen/DDEngine/Source/mesh.cpp new file mode 100644 index 0000000..472b967 --- /dev/null +++ b/fallen/DDEngine/Source/mesh.cpp @@ -0,0 +1,2311 @@ +// +// Drawing rotating prims. +// + +#include "game.h" +#include "aeng.h" +#include "matrix.h" +#include "mesh.h" +#include "texture.h" +#include "c:\fallen\headers\night.h" +#include "c:\fallen\headers\light.h" +#include "poly.h" +#include "c:\fallen\headers\animtmap.h" +#include "c:\fallen\headers\morph.h" +#include "memory.h" +#include +#include "polypoint.h" +#include "fastprim.h" + +#define POLY_FLAG_GOURAD (1<<0) +#define POLY_FLAG_TEXTURED (1<<1) +#define POLY_FLAG_MASKED (1<<2) +#define POLY_FLAG_SEMI_TRANS (1<<3) +#define POLY_FLAG_ALPHA (1<<4) +#define POLY_FLAG_TILED (1<<5) +#define POLY_FLAG_DOUBLESIDED (1<<6) +#define POLY_FLAG_CLIPPED (1<<7) + +#define CALC_CAR_CRUMPLE 0 // else use table + +// +// A floating point number between 0 and 1.0F +// + +static inline float frand(void) +{ + SLONG irand = rand(); + float ans = float(irand) * (1.0F / float(RAND_MAX)); + + return ans; +} + +typedef struct +{ + float dx; + float dy; + float dz; + +} MESH_Crumple; + +#define MESH_NUM_CRUMPLES 5 +#define MESH_NUM_CRUMPVALS 8 + +MESH_Crumple MESH_crumple[MESH_NUM_CRUMPLES][MESH_NUM_CRUMPVALS]; + +typedef struct +{ + SBYTE dx,dy,dz; +} MESH_Crumple2; + +#if CALC_CAR_CRUMPLE +MESH_Crumple2 MESH_car_crumples[MESH_NUM_CRUMPLES][MESH_NUM_CRUMPVALS][6]; +#else +MESH_Crumple2 MESH_car_crumples[MESH_NUM_CRUMPLES][MESH_NUM_CRUMPVALS][6] = +{ + { + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, }, + }, + { + { {7,4,3}, {-3,0,8}, {5,5,4}, {-2,3,2}, {5,0,-5}, {-2,2,0}, }, + { {6,2,4}, {-3,0,8}, {7,3,4}, {-2,5,3}, {6,1,-6}, {-4,3,0}, }, + { {7,4,3}, {-2,0,8}, {5,4,2}, {-3,5,3}, {7,0,-5}, {-3,2,0}, }, + { {6,2,4}, {-3,0,8}, {5,4,2}, {-2,5,3}, {7,0,-6}, {-2,2,-1}, }, + { {7,3,3}, {-3,0,9}, {7,4,2}, {-3,3,3}, {5,1,-4}, {-3,3,0}, }, + { {5,2,4}, {-2,0,8}, {5,4,2}, {-3,3,3}, {7,1,-5}, {-2,3,0}, }, + { {5,3,4}, {-3,0,10}, {5,4,3}, {-3,4,2}, {6,0,-4}, {-4,2,0}, }, + { {7,3,4}, {-2,0,10}, {6,5,2}, {-3,4,4}, {5,0,-5}, {-3,1,-1}, }, + }, + { + { {14,4,6}, {-8,2,15}, {10,5,5}, {-4,7,5}, {15,2,-11}, {-5,5,-2}, }, + { {11,3,8}, {-4,0,16}, {13,6,6}, {-4,7,7}, {10,3,-11}, {-5,5,-3}, }, + { {11,5,5}, {-7,-2,18}, {14,5,7}, {-6,8,7}, {13,1,-13}, {-6,6,0}, }, + { {10,7,8}, {-5,-2,18}, {15,5,4}, {-8,10,6}, {11,3,-12}, {-6,3,-3}, }, + { {11,6,10}, {-8,2,17}, {10,9,4}, {-4,9,7}, {11,0,-14}, {-5,3,-2}, }, + { {12,8,5}, {-8,-1,16}, {11,8,7}, {-4,6,7}, {13,1,-9}, {-7,7,-1}, }, + { {11,6,8}, {-7,2,18}, {13,8,4}, {-7,7,3}, {14,0,-14}, {-7,5,-4}, }, + { {11,4,8}, {-7,0,18}, {12,8,5}, {-5,8,4}, {15,2,-12}, {-4,3,0}, }, + }, + { + { {19,8,12}, {-9,-3,25}, {17,11,11}, {-9,13,11}, {18,0,-15}, {-12,6,-2}, }, + { {18,10,13}, {-8,1,24}, {17,10,10}, {-7,10,8}, {16,4,-20}, {-10,8,-3}, }, + { {20,5,8}, {-13,-3,25}, {17,13,6}, {-11,8,10}, {20,-1,-16}, {-9,8,-2}, }, + { {16,9,8}, {-7,0,30}, {20,11,10}, {-9,10,7}, {15,3,-20}, {-14,5,-1}, }, + { {17,7,11}, {-14,0,26}, {20,13,8}, {-11,14,12}, {20,4,-21}, {-10,9,-4}, }, + { {17,7,8}, {-9,-1,23}, {15,11,11}, {-7,11,10}, {20,3,-15}, {-10,7,-6}, }, + { {21,8,12}, {-10,0,29}, {20,10,5}, {-12,10,6}, {21,0,-15}, {-13,8,-2}, }, + { {22,6,12}, {-7,1,30}, {16,14,10}, {-7,14,11}, {20,-1,-17}, {-12,5,-1}, }, + }, + { + { {28,8,17}, {-14,-4,38}, {29,11,9}, {-13,15,14}, {22,3,-19}, {-19,10,-2}, }, + { {22,7,13}, {-12,2,36}, {24,18,8}, {-13,12,8}, {30,0,-29}, {-11,6,-9}, }, + { {20,9,16}, {-16,-1,34}, {21,15,13}, {-16,17,15}, {25,2,-28}, {-14,7,-5}, }, + { {29,11,11}, {-13,1,38}, {29,19,9}, {-10,16,13}, {28,4,-20}, {-10,13,-4}, }, + { {24,7,14}, {-11,-1,32}, {20,17,14}, {-18,11,10}, {27,4,-27}, {-18,4,-6}, }, + { {20,16,16}, {-18,3,36}, {24,10,8}, {-15,17,14}, {20,4,-28}, {-13,10,0}, }, + { {25,8,13}, {-11,-2,35}, {26,11,16}, {-11,12,11}, {27,6,-21}, {-13,10,0}, }, + { {27,9,16}, {-16,0,37}, {22,15,11}, {-9,17,14}, {26,0,-21}, {-12,14,-7}, }, + }, +}; +#endif + +void MESH_init(void) +{ + SLONG i; + SLONG j; + SLONG k; + + float amp; + + for (i = 0; i < MESH_NUM_CRUMPLES; i++) + { + amp = float(i) * 2.5F; + + for (j = 0; j < MESH_NUM_CRUMPVALS; j++) + { + MESH_crumple[i][j].dx = ((frand() * 2.0F) - 1.0F) * amp; + MESH_crumple[i][j].dy = ((frand() * 2.0F) - 1.0F) * amp; + MESH_crumple[i][j].dz = ((frand() * 2.0F) - 1.0F) * amp; + } + } + +#if CALC_CAR_CRUMPLE + // calculate mesh offsets and trace out + static MESH_Crumple car_basic[6] = { {1,0.3,0.5}, {-1,-0.3,1.5}, {1,0.5,0.3}, {-1,0.5,0.3}, {1,-0.2,-1.5}, {-1,0.2,-0.5} }; + + TRACE("MESH_Crumple2 MESH_car_crumples[MESH_NUM_CRUMPLES][MESH_NUM_CRUMPVALS][6] =\n{\n"); + for (i = 0; i < MESH_NUM_CRUMPLES; i++) + { + TRACE(" {\n"); + amp = float(i) * 5.0F; + + for (j = 0; j < MESH_NUM_CRUMPVALS; j++) + { + TRACE(" { "); + for (k = 0; k < 6; k++) + { + float dx = amp * (car_basic[k].dx + frand()/2); + float dy = amp * (car_basic[k].dy + frand()/2); + float dz = amp * (car_basic[k].dz + frand()/2); + + SBYTE idx = SBYTE(dx + 0.5); + SBYTE idy = SBYTE(dy + 0.5); + SBYTE idz = SBYTE(dz + 0.5); + + TRACE("{%d,%d,%d}, ", idx, idy, idz); + + MESH_car_crumples[i][j][k].dx = idx; + MESH_car_crumples[i][j][k].dy = idy; + MESH_car_crumples[i][j][k].dz = idz; + } + TRACE("},\n"); + } + TRACE(" },\n"); + } + TRACE("};\n"); +#endif +} + +// set crumple parameters for ,-1) call to MESH_draw_poly + +static UBYTE* car_crumples = NULL; +static UBYTE* car_assign = NULL; + +void MESH_set_crumple(UBYTE* assignments, UBYTE* crumples) +{ + car_assign = assignments; + car_crumples = crumples; +} + +#ifndef NDEBUG +#define MESH_SHOW_MOUSE_POINT +#endif + + +ULONG MESH_colour_and; + +NIGHT_Colour *MESH_draw_guts( + SLONG prim, + MAPCO16 at_x, + MAPCO16 at_y, + MAPCO16 at_z, + float matrix[9], + NIGHT_Colour *lpc, + ULONG fade, + SLONG crumple = 0) +{ + +#if 0 + if (crumple == 0 || crumple == -1) + { + if (FASTPRIM_draw( + prim, + float(at_x), + float(at_y), + float(at_z), + matrix, + lpc)) + { + PrimObject *po = &prim_objects[prim]; + + if (lpc) + { + lpc += po->EndPoint - po->StartPoint; + } + + return lpc; + } + } +#endif + + /* + + static highlight = 0; + + if (Keys[KB_LBRACE]) + { + Keys[KB_LBRACE] = 0; + + highlight += 1; + } + + */ + + SLONG i; + + SLONG sp; + SLONG ep; + SLONG cv = 0; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + ULONG qc0; + ULONG qc1; + ULONG qc2; + ULONG qc3; + + SLONG page; + ULONG colour_and = MESH_colour_and; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + POLY_Point *pp; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + ULONG default_colour; + ULONG default_specular; + + #ifdef MESH_SHOW_MOUSE_POINT + + SLONG dmx; + SLONG dmy; + SLONG mdist; + SLONG best_mdist = 1024; + POLY_Point *best_mpoint = NULL; + + #endif + + ASSERT(WITHIN(crumple, -1, MESH_NUM_CRUMPLES - 1)); + +// ASSERT(prim!=129); +/* + if(prim==129) + { + TRACE("hello"); + } +*/ + + + if (lpc == NULL) + { + // + // This mesh has not been lit properly... so light it evenly + // from the light at this point. + // + + NIGHT_get_d3d_colour( + NIGHT_get_light_at(at_x,at_y,at_z), + &default_colour, + &default_specular); +#ifdef TARGET_DC + default_colour |= 0xff000000; +#endif + } + + extern UBYTE kludge_shrink; + + if (prim == PRIM_OBJ_SPIKE) + { + // + // Stretch the prim depending on its position. + // + + float angle; + float stretch; + + angle = float(GetTickCount()) * 0.001F; + angle += float(at_x) * 0.67f; + angle += float(at_z) * 0.44f; + + stretch = sin(angle); + stretch += 2.00F; + + matrix[3] *= stretch; + matrix[4] *= stretch; + matrix[5] *= stretch; + } + else + if (prim == 58 || + prim == 59 || + prim == 34 || + prim == 35) + { + ULONG stretch; + + stretch = at_x ^ at_z; + stretch >>= 3; + stretch &= 0xf; + stretch += 0xf; + + float fstretch = float(stretch) * 0.03F + 0.5F; + + matrix[0] *= fstretch; + matrix[1] *= fstretch; + matrix[2] *= fstretch; + + matrix[3] *= fstretch; + matrix[4] *= fstretch; + matrix[5] *= fstretch; + + matrix[6] *= fstretch; + matrix[7] *= fstretch; + matrix[8] *= fstretch; + } + else + if (kludge_shrink) + { + float fstretch; + if (prim == 253) + fstretch = 0.15F; + else + fstretch = 0.7F; + + matrix[0] *= fstretch; + matrix[1] *= fstretch; + matrix[2] *= fstretch; + + matrix[3] *= fstretch; + matrix[4] *= fstretch; + matrix[5] *= fstretch; + + matrix[6] *= fstretch; + matrix[7] *= fstretch; + matrix[8] *= fstretch; + } + + POLY_set_local_rotation( + float(at_x), + float(at_y), + float(at_z), + matrix); + + // + // Rotate all the points into the POLY_buffer and all the + // shadow points in the POLY_shadow. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + POLY_buffer_upto = 0; + POLY_shadow_upto = 0; + + if (crumple >= 0) + { + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform_using_local_rotation( + AENG_dx_prim_points[i].X + MESH_crumple[crumple][cv].dx, + AENG_dx_prim_points[i].Y + MESH_crumple[crumple][cv].dy, + AENG_dx_prim_points[i].Z + MESH_crumple[crumple][cv].dz, + pp); + + cv += 1; + cv &= MESH_NUM_CRUMPVALS - 1; + + if (lpc) + { + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + *lpc, + &pp->colour, + &pp->specular); + } + + lpc += 1; + } + else + { + pp->colour = default_colour; + pp->specular = default_specular; + + // + // A hack to get balloons of different colours- + // check out SHAPE_draw_balloon() + // + +#ifndef TARGET_DC + extern ULONG SHAPE_balloon_colour; + + if (prim == PRIM_OBJ_BALLOON) + { + pp->colour &= SHAPE_balloon_colour; + } +#endif + } + + //POLY_fadeout_point(pp); + //use_global_cloud(&pp->colour); + //pp->colour&=0xffffff; + //pp->colour|=fade; + + #ifdef MESH_SHOW_MOUSE_POINT + + if (pp->clip & POLY_CLIP_TRANSFORMED) + { + dmx = MouseX - pp->X; + dmy = MouseY - pp->Y; + + mdist = dmx*dmx + dmy*dmy; + + if (best_mdist > mdist) + { + best_mdist = mdist; + best_mpoint = pp; + } + } + + #endif + } + } + else + { + UBYTE* assign = car_assign; + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform_using_local_rotation( + AENG_dx_prim_points[i].X + (MESH_car_crumples[car_crumples[*assign]][cv][*assign].dx/2.0f), + AENG_dx_prim_points[i].Y + (MESH_car_crumples[car_crumples[*assign]][cv][*assign].dy/2.0f), + AENG_dx_prim_points[i].Z + (MESH_car_crumples[car_crumples[*assign]][cv][*assign].dz/2.0f), + pp); + + cv += 1; + cv &= MESH_NUM_CRUMPVALS - 1; + + if (lpc) + { + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + *lpc, + &pp->colour, + &pp->specular); + } + + lpc += 1; + } + else + { + pp->colour = default_colour; + pp->specular = default_specular; + } + +// POLY_fadeout_point(pp); +// use_global_cloud(&pp->colour); +// pp->colour&=0xffffff; +// pp->colour|=fade; + +#if 0 // colour-code crumple zones red, green, blue, black + static ULONG colours[5] = {0, 0xFF0000, 0x00FF00, 0x0000FF, 0x000000 }; + if (car_crumples[*assign]) pp->colour = colours[car_crumples[*assign]] | fade; +#endif + + #ifdef MESH_SHOW_MOUSE_POINT + + if (pp->clip & POLY_CLIP_TRANSFORMED) + { + dmx = MouseX - pp->X; + dmy = MouseY - pp->Y; + + mdist = dmx*dmx + dmy*dmy; + + if (best_mdist > mdist) + { + best_mdist = mdist; + best_mpoint = pp; + } + } + + #endif + + assign++; + } + } + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + if (p_f4->DrawFlags & POLY_FLAG_TEXTURED) + { + /* + + if(p_f4->FaceFlags&FACE_FLAG_ANIMATE) + { + struct AnimTmap *p_a; + SLONG cur; + p_a=&anim_tmaps[p_f4->TexturePage]; + cur=p_a->Current; + + quad[0]->u = float(p_a->UV[cur][0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_a->UV[cur][0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_a->UV[cur][1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_a->UV[cur][1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_a->UV[cur][2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_a->UV[cur][2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_a->UV[cur][3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_a->UV[cur][3][1] ) * (1.0F / 32.0F); + + page = p_a->UV[cur][0][0] & 0xc0; + page <<= 2; + page |= p_a->Page[cur]; + } + else + */ + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + page+=FACE_PAGE_OFFSET; + + if (p_f4->FaceFlags & FACE_FLAG_TINT) + { + qc0 = quad[0]->colour; + qc1 = quad[1]->colour; + qc2 = quad[2]->colour; + qc3 = quad[3]->colour; + + quad[0]->colour &= MESH_colour_and; + quad[1]->colour &= MESH_colour_and; + quad[2]->colour &= MESH_colour_and; + quad[3]->colour &= MESH_colour_and; + + // quad[0]->colour = PolyPoint2D::ModulateD3DColours(qc0, MESH_colour_and); + // quad[1]->colour = PolyPoint2D::ModulateD3DColours(qc1, MESH_colour_and); + // quad[2]->colour = PolyPoint2D::ModulateD3DColours(qc2, MESH_colour_and); + // quad[3]->colour = PolyPoint2D::ModulateD3DColours(qc3, MESH_colour_and); + } + + /* + + if (prim == PRIM_OBJ_BIKE_BWHEEL && i - p_obj->StartFace4 == highlight) + { + quad[0]->colour = (GAME_TURN * 55); + quad[1]->colour = (GAME_TURN * 55); + quad[2]->colour = (GAME_TURN * 55); + quad[3]->colour = (GAME_TURN * 55); + } + */ + } + + if (p_f4->FaceFlags & FACE_FLAG_WALKABLE) + { + + quad[0]->colour = (GAME_TURN * 55); + quad[1]->colour = (GAME_TURN * 35); + quad[2]->colour = (GAME_TURN * 25); + quad[3]->colour = (GAME_TURN * 15); + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + else + + { +// POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); +/* + page=i%5; + switch(page) + { + case 0: + page=873; + break; + case 1: + page=825; + break; + case 2: + page=824; + break; + case 3: + page=823; + break; + case 4: + page=872; + break; + } + page=872; +*/ + POLY_add_quad(quad, page,!(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + +/* +void POLY_add_line_tex_uv(POLY_Point *p1, POLY_Point *p2, float width1, float width2, SLONG page, UBYTE sort_to_front); + quad[0]->colour=0xffffff; + quad[1]->colour=0xffffff; + quad[2]->colour=0xffffff; + quad[3]->colour=0xffffff; + POLY_add_line_tex_uv(quad[0],quad[1],0.2,0.2,POLY_PAGE_COLOUR,0); + POLY_add_line_tex_uv(quad[1],quad[3],0.2,0.2,POLY_PAGE_COLOUR,0); + POLY_add_line_tex_uv(quad[3],quad[2],0.2,0.2,POLY_PAGE_COLOUR,0); + POLY_add_line_tex_uv(quad[2],quad[0],0.2,0.2,POLY_PAGE_COLOUR,0); +*/ + } + + if (p_f4->FaceFlags & FACE_FLAG_TINT) + { + quad[0]->colour = qc0; + quad[1]->colour = qc1; + quad[2]->colour = qc2; + quad[3]->colour = qc3; + } + } + else + { + ASSERT(0); + + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + if (p_f3->DrawFlags & POLY_FLAG_TEXTURED) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + if (p_f3->FaceFlags & FACE_FLAG_TINT) + { + qc0 = tri[0]->colour; + qc1 = tri[1]->colour; + qc2 = tri[2]->colour; + + tri[0]->colour = PolyPoint2D::ModulateD3DColours(qc0, MESH_colour_and); + tri[1]->colour = PolyPoint2D::ModulateD3DColours(qc1, MESH_colour_and); + tri[2]->colour = PolyPoint2D::ModulateD3DColours(qc2, MESH_colour_and); + } + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + page+=FACE_PAGE_OFFSET; + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + + if (p_f3->FaceFlags & FACE_FLAG_TINT) + { + tri[0]->colour = qc0; + tri[1]->colour = qc1; + tri[2]->colour = qc2; + } + } + else + { + POLY_add_triangle(tri, POLY_PAGE_COLOUR, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + + if(0) + if (prim == 122) + { + // + // The cinema screen. Find the screen and draw it backwards + // faded out to white + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + // page+=FACE_PAGE_OFFSET; + + if (page == 86) + { + p0 = p_f4->Points[2] - sp; + p1 = p_f4->Points[3] - sp; + p2 = p_f4->Points[0] - sp; + p3 = p_f4->Points[1] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + quad[0]->specular |= (0x00888888 & ~POLY_colour_restrict); + quad[1]->specular |= (0x00888888 & ~POLY_colour_restrict); + quad[2]->specular |= (0x00888888 & ~POLY_colour_restrict); + quad[3]->specular |= (0x00888888 & ~POLY_colour_restrict); + + POLY_add_quad(quad, 86, TRUE); + } + } + } + } + + if (p_obj->flag & PRIM_FLAG_ENVMAPPED) + { + float nx; + float ny; + float nz; + + float dx; + float dy; + float dz; + + float comb[9]; + float cam_matrix[9]; + + SLONG num_points = ep - sp; + + extern float AENG_cam_yaw; + extern float AENG_cam_pitch; + extern float AENG_cam_roll; + + MATRIX_calc(cam_matrix, AENG_cam_yaw, AENG_cam_pitch, AENG_cam_roll); + MATRIX_3x3mul(comb, cam_matrix, matrix); + + // + // Environment map the van. Work out the uv coords at all the points. + // + + if (crumple != -1) + { + for (i = 0; i < num_points; i++) + { + nx = prim_normal[sp + i].X * (2.0F / 256.0F); + ny = prim_normal[sp + i].Y * (2.0F / 256.0F); + nz = prim_normal[sp + i].Z * (2.0F / 256.0F); + + MATRIX_MUL( + comb, + nx, + ny, + nz); + + //dx = POLY_buffer[i].x; + //dy = POLY_buffer[i].y; + //dz = POLY_buffer[i].z; + + POLY_buffer[i].u = (nx * 0.5F) + 0.5F; + POLY_buffer[i].v = (ny * 0.5F) + 0.5F; + + POLY_buffer[i].colour |= 0xff000000; + } + } + else + { + UBYTE* assign = car_assign; + + for (i = 0; i < num_points; i++) + { + nx = prim_normal[sp + i].X * (2.0F / 256.0F); + ny = prim_normal[sp + i].Y * (2.0F / 256.0F); + nz = prim_normal[sp + i].Z * (2.0F / 256.0F); + + nx -= float(MESH_car_crumples[car_crumples[*assign]][cv][*assign].dx) / 32; + ny -= float(MESH_car_crumples[car_crumples[*assign]][cv][*assign].dy) / 32; + nz -= float(MESH_car_crumples[car_crumples[*assign]][cv][*assign].dz) / 32; + + MATRIX_MUL( + comb, + nx, + ny, + nz); + + dx = POLY_buffer[i].x; + dy = POLY_buffer[i].y; + dz = POLY_buffer[i].z; + + POLY_buffer[i].u = (nx * 0.5F) + 0.5F; + POLY_buffer[i].v = (ny * 0.5F) + 0.5F; + + POLY_buffer[i].colour |= 0xff000000; + } + } + // + // Add the triangles and quads. + // + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + if (p_f4->FaceFlags & FACE_FLAG_ENVMAP) + { + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_ENVMAP, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + if (p_f3->FaceFlags & FACE_FLAG_ENVMAP) + { + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_ENVMAP, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + } + + #ifdef MESH_SHOW_MOUSE_POINT + + if (best_mpoint) + { + FONT_buffer_add( + best_mpoint->X, + best_mpoint->Y, + 255, + 225, + 225, + TRUE, + "%d", + best_mpoint - POLY_buffer); + } + + #endif + + return lpc; +} + + +NIGHT_Colour *MESH_draw_poly( + SLONG prim, + MAPCO16 at_x, + MAPCO16 at_y, + MAPCO16 at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll, + NIGHT_Colour *lpc, + UBYTE fade, + SLONG crumple) +{ + float matrix[9]; + float yaw; + float pitch; + float roll; + ULONG alpha_bits=fade<<24; +#ifdef TARGET_DC + ASSERT ( alpha_bits != 0 ); +#endif + + yaw = float(i_yaw) * (2.0F * PI / 2048.0F); + pitch = float(i_pitch) * (2.0F * PI / 2048.0F); + roll = float(i_roll) * (2.0F * PI / 2048.0F); + + //calc_global_cloud(at_x,at_y,at_z); + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + MATRIX_TRANSPOSE(matrix); + + POLY_set_local_rotation( + float(at_x), + float(at_y), + float(at_z), + matrix); + + return MESH_draw_guts(prim, at_x, at_y, at_z, matrix, lpc,alpha_bits, crumple); +} + +NIGHT_Colour *MESH_draw_poly_inv_matrix( + SLONG prim, + MAPCO16 at_x, + MAPCO16 at_y, + MAPCO16 at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll, + NIGHT_Colour *lpc) +{ + float matrix[9]; + float yaw; + float pitch; + float roll; + + //calc_global_cloud(at_x,at_y,at_z); + + yaw = float(i_yaw) * (2.0F * PI / 2048.0F); + pitch = float(i_pitch) * (2.0F * PI / 2048.0F); + roll = float(i_roll) * (2.0F * PI / 2048.0F); + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + +// MATRIX_TRANSPOSE(matrix); + + POLY_set_local_rotation( + float(at_x), + float(at_y), + float(at_z), + matrix); + + return MESH_draw_guts(prim, at_x, at_y, at_z, matrix, lpc,0); +} + + +/* +NIGHT_Colour *MESH_draw_poly( + SLONG prim, + MAPCO16 at_x, + MAPCO16 at_y, + MAPCO16 at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll, + NIGHT_Colour *lpc) +{ + SLONG i; +// SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG page; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + POLY_Point *pp; +// POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + float matrix[9]; + float yaw; + float pitch; + float roll; + + yaw = float(i_yaw) * (2.0F * PI / 2048.0F); + pitch = float(i_pitch) * (2.0F * PI / 2048.0F); + roll = float(i_roll) * (2.0F * PI / 2048.0F); + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + MATRIX_TRANSPOSE(matrix); + + POLY_set_local_rotation( + float(at_x), + float(at_y), + float(at_z), + matrix); + + // + // Rotate all the points into the POLY_buffer and all the + // shadow points in the POLY_shadow. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + POLY_buffer_upto = 0; + POLY_shadow_upto = 0; + + for (i = sp; i < ep; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + POLY_transform_using_local_rotation( + AENG_dx_prim_points[i].X, + AENG_dx_prim_points[i].Y, + AENG_dx_prim_points[i].Z, + pp); + + if (lpc) + { + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + *lpc, + &pp->colour, + &pp->specular); + } + + lpc += 1; + } + else + { + pp->colour = NIGHT_amb_d3d_colour; + pp->specular = NIGHT_amb_d3d_specular; + } + + POLY_fadeout_point(pp); + } + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + if (p_f4->DrawFlags & POLY_FLAG_TEXTURED) + { + if(p_f4->FaceFlags&FACE_FLAG_ANIMATE) + { + struct AnimTmap *p_a; + SLONG cur; + p_a=&anim_tmaps[p_f4->TexturePage]; + cur=p_a->Current; + + + quad[0]->u = float(p_a->UV[cur][0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_a->UV[cur][0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_a->UV[cur][1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_a->UV[cur][1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_a->UV[cur][2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_a->UV[cur][2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_a->UV[cur][3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_a->UV[cur][3][1] ) * (1.0F / 32.0F); + + page = p_a->UV[cur][0][0] & 0xc0; + page <<= 2; + page |= p_a->Page[cur]; + } + else + { + + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + } + + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + else + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + if (p_f3->DrawFlags & POLY_FLAG_TEXTURED) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + else + { + POLY_add_triangle(tri, POLY_PAGE_COLOUR, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + + return lpc; +} +*/ + + + + + +void MESH_draw_morph( + SLONG prim, + UBYTE morph1, + UBYTE morph2, + UWORD tween, // 0 - 256 + MAPCO16 at_x, + MAPCO16 at_y, + MAPCO16 at_z, + SLONG i_yaw, + SLONG i_pitch, + SLONG i_roll, + NIGHT_Colour *lpc) +{ + SLONG i; +// SLONG j; + + SLONG sp; + SLONG ep; + + SLONG p0; + SLONG p1; + SLONG p2; + SLONG p3; + + float px; + float py; + float pz; + + float px1, px2; + float py1, py2; + float pz1, pz2; + + float ptween; + + SLONG page; + + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + MORPH_Point *mp1 = MORPH_get_points(morph1); + MORPH_Point *mp2 = MORPH_get_points(morph2); + + SLONG num_points; + + POLY_Point *pp; +// POLY_Point *ps; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + float matrix[9]; + float yaw; + float pitch; + float roll; + + yaw = float(i_yaw) * (2.0F * PI / 2048.0F); + pitch = float(i_pitch) * (2.0F * PI / 2048.0F); + roll = float(i_roll) * (2.0F * PI / 2048.0F); + + //calc_global_cloud(at_x,at_y,at_z); + + MATRIX_calc( + matrix, + yaw, + pitch, + roll); + + MATRIX_TRANSPOSE(matrix); + + POLY_set_local_rotation( + float(at_x), + float(at_y), + float(at_z), + matrix); + + // + // Rotate all the points into the POLY_buffer. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + POLY_buffer_upto = 0; + POLY_shadow_upto = 0; + + ASSERT( + MORPH_get_num_points(morph1) == + MORPH_get_num_points(morph2)); + + num_points = MORPH_get_num_points(morph1); + ptween = float(tween) * (1.0F / 256.0F); + + for (i = 0; i < num_points; i++) + { + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + pp = &POLY_buffer[POLY_buffer_upto++]; + + px1 = float(mp1->x); + py1 = float(mp1->y); + pz1 = float(mp1->z); + + px2 = float(mp2->x); + py2 = float(mp2->y); + pz2 = float(mp2->z); + + px = px1 + (px2 - px1) * ptween; + py = py1 + (py2 - py1) * ptween; + pz = pz1 + (pz2 - pz1) * ptween; + + POLY_transform_using_local_rotation(px, py, pz, pp); + + if (lpc) + { + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + *lpc, + &pp->colour, + &pp->specular); + } + + lpc += 1; + } + else + { + pp->colour = NIGHT_amb_d3d_colour; + pp->specular = NIGHT_amb_d3d_specular; + + pp->colour &= ~POLY_colour_restrict; + pp->specular &= ~POLY_colour_restrict; + } + + //use_global_cloud(&pp->colour); + mp1 += 1; + mp2 += 1; + } + + // + // The quads. + // + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + p0 = p_f4->Points[0] - sp; + p1 = p_f4->Points[1] - sp; + p2 = p_f4->Points[2] - sp; + p3 = p_f4->Points[3] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p3, 0, POLY_buffer_upto - 1)); + + quad[0] = &POLY_buffer[p0]; + quad[1] = &POLY_buffer[p1]; + quad[2] = &POLY_buffer[p2]; + quad[3] = &POLY_buffer[p3]; + + if (POLY_valid_quad(quad)) + { + if (p_f4->DrawFlags & POLY_FLAG_TEXTURED) + { + if(p_f4->FaceFlags&FACE_FLAG_ANIMATE) + { + struct AnimTmap *p_a; + SLONG cur; + p_a=&anim_tmaps[p_f4->TexturePage]; + cur=p_a->Current; + + + quad[0]->u = float(p_a->UV[cur][0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_a->UV[cur][0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_a->UV[cur][1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_a->UV[cur][1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_a->UV[cur][2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_a->UV[cur][2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_a->UV[cur][3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_a->UV[cur][3][1] ) * (1.0F / 32.0F); + + page = p_a->UV[cur][0][0] & 0xc0; + page <<= 2; + page |= p_a->Page[cur]; + + + + } + else + { + + quad[0]->u = float(p_f4->UV[0][0] & 0x3f) * (1.0F / 32.0F); + quad[0]->v = float(p_f4->UV[0][1] ) * (1.0F / 32.0F); + + quad[1]->u = float(p_f4->UV[1][0] ) * (1.0F / 32.0F); + quad[1]->v = float(p_f4->UV[1][1] ) * (1.0F / 32.0F); + + quad[2]->u = float(p_f4->UV[2][0] ) * (1.0F / 32.0F); + quad[2]->v = float(p_f4->UV[2][1] ) * (1.0F / 32.0F); + + quad[3]->u = float(p_f4->UV[3][0] ) * (1.0F / 32.0F); + quad[3]->v = float(p_f4->UV[3][1] ) * (1.0F / 32.0F); + + page = p_f4->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f4->TexturePage; + page+=FACE_PAGE_OFFSET; + } + + POLY_add_quad(quad, page, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + else + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, !(p_f4->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } + + // + // The triangles. + // + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + p0 = p_f3->Points[0] - sp; + p1 = p_f3->Points[1] - sp; + p2 = p_f3->Points[2] - sp; + + ASSERT(WITHIN(p0, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p1, 0, POLY_buffer_upto - 1)); + ASSERT(WITHIN(p2, 0, POLY_buffer_upto - 1)); + + tri[0] = &POLY_buffer[p0]; + tri[1] = &POLY_buffer[p1]; + tri[2] = &POLY_buffer[p2]; + + if (POLY_valid_triangle(tri)) + { + if (p_f3->DrawFlags & POLY_FLAG_TEXTURED) + { + tri[0]->u = float(p_f3->UV[0][0] & 0x3f) * (1.0F / 32.0F); + tri[0]->v = float(p_f3->UV[0][1] ) * (1.0F / 32.0F); + + tri[1]->u = float(p_f3->UV[1][0] ) * (1.0F / 32.0F); + tri[1]->v = float(p_f3->UV[1][1] ) * (1.0F / 32.0F); + + tri[2]->u = float(p_f3->UV[2][0] ) * (1.0F / 32.0F); + tri[2]->v = float(p_f3->UV[2][1] ) * (1.0F / 32.0F); + + page = p_f3->UV[0][0] & 0xc0; + page <<= 2; + page |= p_f3->TexturePage; + page+=FACE_PAGE_OFFSET; + + POLY_add_triangle(tri, page, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + else + { + POLY_add_triangle(tri, POLY_PAGE_COLOUR, !(p_f3->DrawFlags & POLY_FLAG_DOUBLESIDED)); + } + } + } +} + + +// +// The reflected-object data structures. +// + +typedef struct +{ + float x; + float y; + float z; + SLONG fade; + +} MESH_Point; + +typedef struct +{ + UWORD p[3]; + float u[3]; + float v[3]; + UWORD page; + UWORD padding; + +} MESH_Face; + +typedef struct +{ + SLONG calculated; + + SLONG max_points; + SLONG max_faces; + + SLONG num_points; + SLONG num_faces; + + MESH_Point *mp; + MESH_Face *mf; + +} MESH_Reflection; + +#define MESH_MAX_REFLECTIONS 256 + +MESH_Reflection MESH_reflection[MESH_MAX_REFLECTIONS]; + +void MESH_init_reflections() +{ + SLONG i; + + MESH_Reflection *mr; + + for (i = 0; i < MESH_MAX_REFLECTIONS; i++) + { + mr = &MESH_reflection[i]; + + if (mr->calculated) + { + mr->calculated = FALSE; + + MemFree(mr->mp); + MemFree(mr->mf); + + mr->num_points = 0; + mr->num_faces = 0; + + mr->max_points = 0; + mr->max_faces = 0; + } + } +} + + +// +// Grows the points or faces arrays. +// + +void MESH_grow_points(MESH_Reflection *mr) +{ + mr->max_points *= 2; + mr->mp = (MESH_Point *) realloc(mr->mp, sizeof(MESH_Point) * mr->max_points); +} + +void MESH_grow_faces(MESH_Reflection *mr) +{ + mr->max_faces *= 2; + mr->mf = (MESH_Face *) realloc(mr->mf, sizeof(MESH_Face) * mr->max_faces); +} + +// +// Returns the index of a point with the given position. +// + +SLONG MESH_add_point( + MESH_Reflection *mr, + float x, + float y, + float z, + float fade) +{ + SLONG i; + + float dx; + float dy; + float dz; + float dist; + + SLONG ans; + + for (i = mr->num_points - 1; i >= 0; i--) + { + dx = fabs(mr->mp[i].x - x); + dy = fabs(mr->mp[i].y - y); + dz = fabs(mr->mp[i].z - z); + + dist = dx + dy + dz; + + if (dist < 0.1F) + { + // + // These points are just about the same! + // + + return i; + } + } + + // + // We must create a new point. + // + + if (mr->num_points >= mr->max_points) + { + MESH_grow_points(mr); + } + + ans = mr->num_points; + + mr->mp[ans].x = x; + mr->mp[ans].y = y; + mr->mp[ans].z = z; + mr->mp[ans].fade = MIN(255,(SLONG)fade); + + mr->num_points += 1; + + return ans; +} + +// +// Adds a face. +// + +void MESH_add_face( + MESH_Reflection *mr, + SLONG p1, + float u1, + float v1, + SLONG p2, + float u2, + float v2, + SLONG p3, + float u3, + float v3, + SLONG page) +{ + if (mr->num_faces >= mr->max_faces) + { + MESH_grow_faces(mr); + } + + mr->mf[mr->num_faces].p[0] = p1; + mr->mf[mr->num_faces].p[1] = p2; + mr->mf[mr->num_faces].p[2] = p3; + + mr->mf[mr->num_faces].u[0] = u1; + mr->mf[mr->num_faces].u[1] = u2; + mr->mf[mr->num_faces].u[2] = u3; + + mr->mf[mr->num_faces].v[0] = v1; + mr->mf[mr->num_faces].v[1] = v2; + mr->mf[mr->num_faces].v[2] = v3; + + mr->mf[mr->num_faces].page = page; + + mr->num_faces += 1; +} + + +// +// Adds a polygon to the given reflection. Give the points in +// clockwise (or anti-clockwise) order. +// + +typedef struct +{ + float x; + float y; + float z; + float u; + float v; + float fade; // 0 - 255 indicating how deep the point is under water. + SLONG index; // Dont worry about this field when calling MESH_add_poly() + +} MESH_Add; + +#define MESH_MAX_ADD 256 + +MESH_Add MESH_add[MESH_MAX_ADD]; +SLONG MESH_add_upto; + +void MESH_add_poly(MESH_Reflection *mr, MESH_Add poly[], SLONG num_points, SLONG page) +{ + SLONG i; + SLONG bot; + SLONG top; + SLONG p1; + SLONG p2; + SLONG last; + SLONG count; + + float f; + float tween; + float top_height; + float bot_height; + float dx; + float dy; + float dz; + float du; + float dv; + float dfade; + float x; + float y; + float z; + float u; + float v; + float fade; + float mul; + + MESH_Add *ma; + MESH_Add *mp1; + MESH_Add *mp2; + MESH_Add *mpl; + + ASSERT(num_points > 2); + + // + // Work out all the points going around the poly. + // + + MESH_add_upto = 0; + + for (i = 0; i < num_points; i++) + { + p1 = i + 0; + p2 = i + 1; + + if (p2 >= num_points) {p2 = 0;} + + mp1 = &poly[p1]; + mp2 = &poly[p2]; + + dx = mp2->x - mp1->x; + dy = mp2->y - mp1->y; + dz = mp2->z - mp1->z; + du = mp2->u - mp1->u; + dv = mp2->v - mp1->v; + dfade = mp2->fade - mp1->fade; + + // + // Make that each point is not too far in y from the previous one. + // + + tween = fabs(dy * (1.0F / 8.0F)); + tween = floor(tween); + + if (tween < 1.0F) {tween = 1.0F;} + + for (f = 0.0F; f < tween; f += 1.0F) + { + mul = f * (1.0F / tween); + + x = mp1->x + mul * dx; + y = mp1->y + mul * dy; + z = mp1->z + mul * dz; + u = mp1->u + mul * du; + v = mp1->v + mul * dv; + fade = mp1->fade + mul * dfade; + + ASSERT(WITHIN(MESH_add_upto, 0, MESH_MAX_ADD - 1)); + + ma = &MESH_add[MESH_add_upto++]; + + ma->x = x; + ma->y = y; + ma->z = z; + ma->u = u; + ma->v = v; + ma->fade = fade; + ma->index = INFINITY; // Mark as not having an index. + } + } + + // + // Which is the highest and lowest point? + // + + top = 0; + bot = 0; + top_height = MESH_add[0].y; + bot_height = MESH_add[0].y; + + for (i = 1; i < MESH_add_upto; i++) + { + if (MESH_add[i].y > top_height) + { + top = i; + top_height = MESH_add[i].y; + } + + if (MESH_add[i].y < bot_height) + { + bot = i; + bot_height = MESH_add[i].y; + } + } + + #define MESH_NEXT_CLOCK(p) (((p) + 1 >= MESH_add_upto) ? 0 : (p) + 1) + #define MESH_NEXT_ANTI(p) (((p) - 1 >= 0) ? (p) - 1 : MESH_add_upto - 1) + + // + // Create triangles from the points. + // + + p1 = top; + p2 = MESH_NEXT_ANTI(top); + + count = 0; + + while(1) + { + ASSERT(count++ < 2048); + + ASSERT(WITHIN(p1, 0, MESH_add_upto - 1)); + ASSERT(WITHIN(p2, 0, MESH_add_upto - 1)); + + mp1 = &MESH_add[p1]; + mp2 = &MESH_add[p2]; + + // + // Move on the highest point. + // + + if (p1 != bot && mp1->y >= mp2->y) + { + last = p1; + p1 = MESH_NEXT_CLOCK(p1); + } + else + { + last = p2; + p2 = MESH_NEXT_ANTI(p2); + } + + ASSERT(WITHIN(p1, 0, MESH_add_upto - 1)); + ASSERT(WITHIN(p2, 0, MESH_add_upto - 1)); + ASSERT(WITHIN(last, 0, MESH_add_upto - 1)); + + mp1 = &MESH_add[p1]; + mp2 = &MESH_add[p2]; + mpl = &MESH_add[last]; + + if (mp1->fade >= 255.0F && + mp2->fade >= 255.0F && + mpl->fade >= 255.0F) + { + // + // This face is completely faded out- and since we are moving + // deeper into the reflection, there is no need to fade out + // any other points. + // + + break; + } + + + // + // Make sure each of the points has been added to the object. + // + + if (mp1->index == INFINITY) {mp1->index = MESH_add_point(mr, mp1->x, mp1->y, mp1->z, mp1->fade);} + if (mp2->index == INFINITY) {mp2->index = MESH_add_point(mr, mp2->x, mp2->y, mp2->z, mp2->fade);} + if (mpl->index == INFINITY) {mpl->index = MESH_add_point(mr, mpl->x, mpl->y, mpl->z, mpl->fade);} + + // + // Create a new triangle. + // + + MESH_add_face( + mr, + mpl->index, + mpl->u, + mpl->v, + mp1->index, + mp1->u, + mp1->v, + mp2->index, + mp2->u, + mp2->v, + page); + + if (p1 == bot && + p2 == bot) + { + break; + } + } +} + + + +// +// Creates a reflection for the given mesh prim. +// + +void MESH_create_reflection(SLONG prim) +{ + SLONG i; + SLONG j; + SLONG pt; + SLONG page; + + UBYTE order3[3] = {0, 2, 1}; + UBYTE order4[4] = {0, 2, 3, 1}; + + float dy; + float fade; + float reflect_height; + + PrimInfo *pi; + PrimObject *po; + PrimFace3 *f3; + PrimFace4 *f4; + MESH_Reflection *mr; + + MESH_Add ma[4]; + + ASSERT(WITHIN(prim, 0, MESH_MAX_REFLECTIONS - 1)); + + mr = &MESH_reflection[prim]; + + ASSERT(!mr->calculated); + + po = &prim_objects[prim]; + pi = get_prim_info(prim); + + // + // Initialise it. + // + + mr->max_points = 32; + mr->max_faces = 32; + + mr->num_points = 0; + mr->num_faces = 0; + + mr->mp = (MESH_Point *) MemAlloc(mr->max_points * sizeof(MESH_Point)); + mr->mf = (MESH_Face *) MemAlloc(mr->max_faces * sizeof(MESH_Face )); + + // + // The height about which the reflection takes place. + // + + reflect_height = float(pi->miny); + + // + // The maximum height of a reflection. + // + + #define MESH_MAX_DY (128.0F) + #define MESH_255_DIVIDED_BY_MAX_DY (255.0F / MESH_MAX_DY) + + // + // Triangles. + // + + for (i = po->StartFace3; i < po->EndFace3; i++) + { + f3 = &prim_faces3[i]; + + for (j = 0; j < 3; j++) + { + pt = order3[j]; + + ma[j].x = AENG_dx_prim_points[f3->Points[pt]].X; + ma[j].y = AENG_dx_prim_points[f3->Points[pt]].Y; + ma[j].z = AENG_dx_prim_points[f3->Points[pt]].Z; + ma[j].u = float(f3->UV[pt][0] & 0x3f) * (1.0F / 32.0F); + ma[j].v = float(f3->UV[pt][1] ) * (1.0F / 32.0F); + dy = ma[j].y - reflect_height; + fade = dy * MESH_255_DIVIDED_BY_MAX_DY; + ma[j].fade = fade; + ma[j].y = reflect_height - dy; + + ASSERT(ma[j].fade >= 0.0F); + } + + if (ma[0].fade >= 255.0F && + ma[1].fade >= 255.0F && + ma[2].fade >= 255.0F) + { + // + // This whole poly is faded out. + // + } + else + { + page = f3->UV[0][0] & 0xc0; + page <<= 2; + page |= f3->TexturePage; + page+=FACE_PAGE_OFFSET; + + MESH_add_poly(mr, ma, 3, page); + } + } + + // + // Quads. + // + + for (i = po->StartFace4; i < po->EndFace4; i++) + { + f4 = &prim_faces4[i]; + + for (j = 0; j < 4; j++) + { + pt = order4[j]; + + ma[j].x = AENG_dx_prim_points[f4->Points[pt]].X; + ma[j].y = AENG_dx_prim_points[f4->Points[pt]].Y; + ma[j].z = AENG_dx_prim_points[f4->Points[pt]].Z; + ma[j].u = float(f4->UV[pt][0] & 0x3f) * (1.0F / 32.0F); + ma[j].v = float(f4->UV[pt][1] ) * (1.0F / 32.0F); + dy = ma[j].y - reflect_height; + fade = dy * MESH_255_DIVIDED_BY_MAX_DY; + ma[j].fade = fade; + ma[j].y = reflect_height - dy; + + ASSERT(ma[j].fade >= 0.0F); + } + + if (ma[0].fade >= 255.0F && + ma[1].fade >= 255.0F && + ma[2].fade >= 255.0F && + ma[3].fade >= 255.0F) + { + // + // This whole poly is faded out. + // + } + else + { + page = f4->UV[0][0] & 0xc0; + page <<= 2; + page |= f4->TexturePage; + page+=FACE_PAGE_OFFSET; + + MESH_add_poly(mr, ma, 4, page); + } + } + + mr->calculated = TRUE; +} + + + +void MESH_draw_reflection( + SLONG prim, + SLONG at_x, + SLONG at_y, + SLONG at_z, + SLONG yaw, + NIGHT_Colour *lpc) +{ + SLONG i; +// SLONG j; + SLONG fog; + + float px; + float py; + float pz; + + float matrix[9]; + + POLY_Point *pp; + POLY_Point *tri[3]; + MESH_Face *mf; + MESH_Reflection *mr; + + if(prim==83) + { + return; + } + + ASSERT(WITHIN(prim, 0, MESH_MAX_REFLECTIONS - 1)); + + mr = &MESH_reflection[prim]; + + // + // If we haven't worked out the reflection mesh, + // then do so now. + // + + if (!mr->calculated) + { + MESH_create_reflection(prim); + } + + // + // This mesh's rotation matrix. + // + + MATRIX_calc( + matrix, + float(yaw) * (2.0F * PI / 2048.0F), + 0, + 0); + + MATRIX_TRANSPOSE(matrix); + + POLY_set_local_rotation( + float(at_x), + float(at_y), + float(at_z), + matrix); + + // + // Rotate all the points into the POLY_buffer. + // + + for (i = 0; i < mr->num_points; i++) + { + pp = &POLY_buffer[i]; + + px = mr->mp[i].x; + py = mr->mp[i].y; + pz = mr->mp[i].z; + + POLY_transform_using_local_rotation_and_wibble( + px, + py, + pz, + pp, + mr->mp[i].fade); + + if (lpc) + { + if (pp->MaybeValid()) + { + NIGHT_get_d3d_colour( + *lpc, + &pp->colour, + &pp->specular); + } + + lpc += 1; + } + else + { + pp->colour = NIGHT_amb_d3d_colour; + pp->specular = NIGHT_amb_d3d_specular; + } + + if (pp->MaybeValid()) + { + //POLY_fadeout_point(pp); + + // + // Fade out with depth too. + // + + fog = pp->specular >> 24; + fog *= 255 - mr->mp[i].fade; + fog >>= 8; + + pp->specular &= 0x00ffffff; + pp->specular |= fog << 24; + } + } + + // + // Add all the faces. + // + + for (i = 0; i < mr->num_faces; i++) + { + mf = &mr->mf[i]; + + ASSERT(WITHIN(mf->p[0], 0, mr->num_points - 1)); + ASSERT(WITHIN(mf->p[1], 0, mr->num_points - 1)); + ASSERT(WITHIN(mf->p[2], 0, mr->num_points - 1)); + + tri[0] = &POLY_buffer[mf->p[0]]; + tri[1] = &POLY_buffer[mf->p[1]]; + tri[2] = &POLY_buffer[mf->p[2]]; + + if (POLY_valid_triangle(tri)) + { + tri[0]->u = mf->u[0]; + tri[0]->v = mf->v[0]; + + tri[1]->u = mf->u[1]; + tri[1]->v = mf->v[1]; + + tri[2]->u = mf->u[2]; + tri[2]->v = mf->v[2]; + + POLY_add_triangle(tri, mf->page, TRUE); + } + } +} + diff --git a/fallen/DDEngine/Source/oval.cpp b/fallen/DDEngine/Source/oval.cpp new file mode 100644 index 0000000..e02adac --- /dev/null +++ b/fallen/DDEngine/Source/oval.cpp @@ -0,0 +1,310 @@ +// +// Simple ovals underneath people, barrels etc... +// + +#include "game.h" +#include "ddlib.h" +#include "mav.h" +#include "poly.h" +#include "oval.h" + +#include + + +// +// The current oval. +// + +float OVAL_mid_x; +float OVAL_mid_y; +float OVAL_mid_z; +float OVAL_dudx; +float OVAL_dvdx; +float OVAL_dudz; +float OVAL_dvdz; + + +// +// Returns the oval (u,v) at the given position. +// + +void OVAL_get_uv( + float world_x, + float world_z, + float *u, + float *v) +{ + float dx; + float dz; + + dx = world_x - OVAL_mid_x; + dz = world_z - OVAL_mid_z; + + float ans_u; + float ans_v; + + ans_u = 0.5F; + ans_v = 0.5F; + + ans_u += dx * OVAL_dudx; + ans_u += dz * OVAL_dudz; + + ans_v += dx * OVAL_dvdx; + ans_v += dz * OVAL_dvdz; + + *u = ans_u; + *v = ans_v; +} + + +// +// Projects the oval onto the given mapsquare and adds it +// to the POLY stuff. +// + +void OVAL_project_onto_mapsquare(UBYTE map_x, UBYTE map_z, SLONG page) +{ + SLONG i; + + PAP_Hi *ph = &PAP_2HI(map_x,map_z); + + if (!WITHIN(map_x, 1, 126) || + !WITHIN(map_z, 1, 126)) + { + // + // Out of bounds... + // + + return; + } + + // + // Work out the height at the four corners of this square. + // + + float world_y[4]; + + if (ph->Flags & PAP_FLAG_ROOF_EXISTS) + { + world_y[0] = + world_y[1] = + world_y[2] = + world_y[3] = MAVHEIGHT(map_x,map_z) << 6; + } + else + if (ph->Flags & PAP_FLAG_HIDDEN) + { + // + // Damn... this'll be annoying! + // + + return; + } + else + { + world_y[0] = ph[0 ].Alt << PAP_ALT_SHIFT; + world_y[1] = ph[0 + PAP_SIZE_HI].Alt << PAP_ALT_SHIFT; + world_y[2] = ph[1 ].Alt << PAP_ALT_SHIFT; + world_y[3] = ph[1 + PAP_SIZE_HI].Alt << PAP_ALT_SHIFT; + + if (ph->Flags & PAP_FLAG_SINK_SQUARE) + { + world_y[0] -= 32.0F; + world_y[1] -= 32.0F; + world_y[2] -= 32.0F; + world_y[3] -= 32.0F; + } + } + + // + // The average y coordinate... + // + + float av_y; + + av_y = world_y[0]; + av_y += world_y[1]; + av_y += world_y[2]; + av_y += world_y[3]; + + av_y *= 0.25F; + + // + // How dark we make the shadow. + // + + float dy = OVAL_mid_y - av_y; + + if (dy < -48.0F) + { + // + // This oval is above the person causing the shadow! + // + + return; + } + + float dark; + + if (dy < 128.0F) + { + dark = 1.0F; // Maximum darkness... + } + else + { + dark = 1.0F - (dy - 128) * (1.0F / 128.0F); + } + + if (dark <= 0.0F) + { + // + // Too faded out. + // + + return; + } + + // + // Convert the darkness into a colour. + // + + SLONG colour; + + colour = ftol(dark * 128.0F); + colour |= colour << 8; + colour |= colour << 16; + + // + // Create the quad. + // + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + // The old order, that doesn't match the landscape. + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + for (i = 0; i < 4; i++) + { + POLY_transform( + float(map_x + (i & 1) << 8), + world_y[i], + float(map_z + (i >> 1) << 8), + quad[i], + TRUE); + +#ifdef TARGET_DC + // "Z-bias" bodge to stop Z-fighting. + quad[i]->Z += 0.0001f; +#endif + } + + if (POLY_valid_quad(quad)) + { + // + // Add in the uv coords and colour. + // + + for (i = 0; i < 4; i++) + { + OVAL_get_uv( + float(map_x + (i & 1) << 8), + float(map_z + (i >> 1) << 8), + &pp[i].u, + &pp[i].v); + + pp[i].colour = colour; + pp[i].specular = 0xff000000; + } + +#if 1 + // A reordering that matches the way the land is drawn, and avoids Z-fights. + quad[0] = &pp[1]; + quad[1] = &pp[3]; + quad[2] = &pp[0]; + quad[3] = &pp[2]; +#endif + + + POLY_add_quad(quad, page, FALSE); + } +} + + +void OVAL_add( + SLONG x, // 8 bits per mapsquare + SLONG y, + SLONG z, + SLONG size, + float elongate, + float angle, + SLONG type) +{ + SLONG mx; + SLONG mz; + + SLONG mx1; + SLONG mz1; + SLONG mx2; + SLONG mz2; + + // + // Work out roughly the bounding box we need to project the oval into/ + // + + SLONG msize = ftol(float(size) * elongate + 8.0F); + + mx1 = x - msize >> PAP_SHIFT_HI; + mz1 = z - msize >> PAP_SHIFT_HI; + mx2 = x + msize >> PAP_SHIFT_HI; + mz2 = z + msize >> PAP_SHIFT_HI; + + SATURATE(mx1, 1, 126); + SATURATE(mz1, 1, 126); + + SATURATE(mx2, 1, 126); + SATURATE(mz2, 1, 126); + + // + // Work out the oval mapping. + // + + OVAL_mid_x = float(x); + OVAL_mid_y = float(y); + OVAL_mid_z = float(z); + + OVAL_dudx = (sin(angle) / float(size)) / elongate; + OVAL_dvdx = (cos(angle) / float(size)); + + OVAL_dudz = (sin(angle + PI / 2) / float(size)) / elongate; + OVAL_dvdz = (cos(angle + PI / 2) / float(size)); + + // + // Which page are we using? + // + + SLONG page; + + switch(type) + { + case OVAL_TYPE_OVAL: page = POLY_PAGE_SHADOW_OVAL; break; + case OVAL_TYPE_SQUARE: page = POLY_PAGE_SHADOW_SQUARE; break; + + default: + ASSERT(0); + break; + } + + // + // Project the oval onto these squares. + // + + for (mx = mx1; mx <= mx2; mx++) + for (mz = mz1; mz <= mz2; mz++) + { + OVAL_project_onto_mapsquare(mx,mz,page); + } +} diff --git a/fallen/DDEngine/Source/pack.cpp b/fallen/DDEngine/Source/pack.cpp new file mode 100644 index 0000000..279da6c --- /dev/null +++ b/fallen/DDEngine/Source/pack.cpp @@ -0,0 +1,1492 @@ +// +// Looks at all the textures loaded and packs similar ones +// onto 256x256s... +// + +#include +#include "game.h" +#include "tga.h" +#include "texture.h" + + +#ifndef TARGET_DC + + +// +// From elev.cpp... +// + +extern CBYTE ELEV_fname_level[]; + + +// +// From texture.cpp +// + +extern D3DTexture TEXTURE_texture[]; + + +// +// The current texture we are creating. +// + +TGA_Pixel PACK_tga[256 * 256]; + + +// +// Temporary buffer for a texture we've loaded in. +// + +TGA_Pixel PACK_buffer[64 * 64]; + + +// +// The files packed onto our current texture. +// + +CBYTE PACK_fname[9][256]; +CBYTE PACK_fname_dir[256]; +SLONG PACK_fname_upto; + +SLONG PACK_texture_upto; + +CBYTE PACK_output_directory[256]; +CBYTE PACK_fname_array[256]; + +FILE *PACK_fname_array_handle; + + + + +#define MAX_NUM_PACKED_PAGES 100 + +int iNumPackedPages; +D3DPage pagePacking[MAX_NUM_PACKED_PAGES]; + + +// +// Outputs the current packing texture. +// + +UBYTE save_out_the_vqs; + +#if 0 +void PACK_output() +{ + SLONG i; + + CBYTE texture_filename[256]; + + sprintf(texture_filename, "%s\\PackedTexture%03d.tga", PACK_output_directory, PACK_texture_upto); + + // + // Got a whole new texture. + // + + TGA_save(texture_filename, 256, 256, (TGA_Pixel *) PACK_tga, FALSE); + + + // + // If you want to run this bit of code then do a search for 'save_out_the_vqs' + // in d3dtexture.cpp and re-enable if (save_out_the_vqs) + // + + save_out_the_vqs = TRUE; + + { + D3DTexture *pTex; + + #define DO_DC_CONVERT(name) pTex = MFnew(); pTex->LoadTextureTGA ( (name), -1, TRUE ); MFdelete ( pTex ) + + DO_DC_CONVERT(texture_filename); + } + + save_out_the_vqs = FALSE; + + + // + // Write out the array. + // + + fprintf(PACK_fname_array_handle, "\t\"***64_3:"); + + // + // Now output the directory containing the texture. Becuase this is 'C' code we + // are generating, each '\' must be written out as '\\'. + // + + CBYTE *ch; + + for (ch = PACK_fname_dir; *ch; ch++) + { + if (*ch == '\\') + { + fprintf(PACK_fname_array_handle, "\\\\"); + } + else + { + fprintf(PACK_fname_array_handle, "%c", *ch); + } + } + + // + // Write in the rest of the line. + // + + fprintf(PACK_fname_array_handle, "\\\\\", \""); + + for (ch = texture_filename; *ch; ch++) + { + if (*ch == '\\') + { + fprintf(PACK_fname_array_handle, "\\\\"); + } + else + { + fprintf(PACK_fname_array_handle, "%c", *ch); + } + } + + fprintf(PACK_fname_array_handle, "\",\n"); + + for (i = 0; i < 9; i++) + { + fprintf(PACK_fname_array_handle, "\t\"%s\",\n", PACK_fname[i]); + } + + fprintf(PACK_fname_array_handle, "\n"); + + PACK_texture_upto += 1; + PACK_fname_upto = 0; + + memset(PACK_fname, 0, sizeof(PACK_fname )); + memset(PACK_fname_dir, 0, sizeof(PACK_fname_dir)); + + memset(PACK_tga, 0, sizeof(PACK_tga)); +} +#endif + + +void read_string ( FILE *handle, char *string ) +{ + char *pch = string; + while ( TRUE ) + { + int character = fgetc ( handle ); + // Silly person - didn't finish your file properly. + ASSERT ( character != EOF ); + if ( ( character == '\0' ) || ( character == '\n' ) || ( character == EOF ) ) + { + *pch = '\0'; + break; + } + *pch++ = (char)character; + } +} + +char *copy_string ( char *input ) +{ + char *temp = (char *)MemAlloc ( strlen ( input ) + 1 ); + ASSERT ( temp != NULL ); + strcpy ( temp, input ); + return temp; +} + +void PACK_do() +{ + SLONG i; + SLONG j; + + SLONG reqd_page_type; + SLONG page_size; + SLONG texture_size; + SLONG border_size; + + TGA_Info ti; + D3DTexture *tt; + + CBYTE level_name [256]; + CBYTE texture_dir[256]; + + // + // The level name without spaces and without the extension... + // + + CBYTE *ch; + CBYTE *just_filename; + + + TRACE ( "PACKing level %s", ELEV_fname_level ); + + + + for (ch = ELEV_fname_level; *ch; ch++); + + while(1) + { + ch -= 1; + + if (ch == ELEV_fname_level) + { + break; + } + + if (*ch == '\\') + { + ch += 1; + + break; + } + } + + CBYTE *src; + CBYTE *dest; + + src = ch; + dest = level_name; + + while(1) + { + if (*src == '.' || *src == '\000') + { + *dest = '\000'; + + break; + } + + if (*src == ' ') + { + src++; + } + else + { + *dest++ = *src++; + } + } + + char PACK_text_array[100]; + FILE *PACK_text_array_handle; + + sprintf(PACK_output_directory, "PackedTextures\\%s", level_name); + sprintf(PACK_fname_array, "%s\\array_%s.cpp", PACK_output_directory, level_name); + sprintf(PACK_text_array, "%s\\text_%s.txt", PACK_output_directory, level_name); + + // + // Create the directory we will be outputting into. + // + + CreateDirectory(PACK_output_directory, NULL); + + // + // Start off the array... + // + + PACK_fname_array_handle = fopen(PACK_fname_array, "wb"); + if (!PACK_fname_array_handle) + { + ASSERT ( FALSE ); + return; + } + PACK_text_array_handle = fopen(PACK_text_array, "wt"); + if (!PACK_text_array_handle) + { + ASSERT ( FALSE ); + return; + } + + fprintf(PACK_fname_array_handle, "//\n"); + fprintf(PACK_fname_array_handle, "// Packing array for \"%s\"\n", ELEV_fname_level); + fprintf(PACK_fname_array_handle, "//\n"); + fprintf(PACK_fname_array_handle, "\n"); + fprintf(PACK_fname_array_handle, "CBYTE *packed_array_%s[] = \n", level_name); + fprintf(PACK_fname_array_handle, "{\n"); + + // + // Go through all the textures. + // + + + + // Read in any hand-done ones first & construct the corresponding textures. + // The filename is int he same directory, called "hand_done_[levname].txt". + // It has the same format as the included ones, except one-per-line, + // and there is no explicit texture name - that's auto-generated. + // + // ***64_4:server\\textures\\extras\\DC\\ + // button_A.tga + // button_B.tga + // button_C.tga + // button_X.tga + // button_Y.tga + // button_Z.tga + // button_LEFT.tga + // button_RIGHT.tga + // button_PADLEFT.tga + // button_PADRIGHT.tga + // button_PADDOWN.tga + // button_PADUP.tga + + iNumPackedPages = 0; + + // Find the list. + + char PACK_file_in[100]; + sprintf(PACK_file_in, "%s\\hand_done_%s.txt", PACK_output_directory, level_name); + + // + // Start off the array... + // + + FILE *PACK_file_in_handle = fopen(PACK_file_in, "rt"); + if (PACK_file_in_handle) + { + // Scan my text list, initialising the D3DPages as we go. + int iPageType = 0; + int iPagePos = 0; + int iSafetyTimeout = 1000; + + char pcCurString[500]; + // Read the first string. + read_string ( PACK_file_in_handle, pcCurString ); + while ( TRUE ) + { + + iSafetyTimeout--; + if ( iSafetyTimeout <= 0 ) + { + // Oops. + ASSERT ( FALSE ); + break; + } + + // This should be a command. + //char *pcCurString = *ppcList; + ASSERT ( ( pcCurString[0] == '*' ) && ( pcCurString[1] == '*' ) && ( pcCurString[2] == '*' ) ); + if ( 0 == stricmp ( pcCurString+3, "END" ) ) + { + // End of list. + break; + } + + // Find the page type + if ( 0 == strncmp ( pcCurString, "***64_4:", 8 ) ) + { + iPageType = D3DPAGE_64_4X4; + } + else if ( 0 == strncmp ( pcCurString, "***32_4:", 8 ) ) + { + iPageType = D3DPAGE_32_4X4; + } + else if ( 0 == strncmp ( pcCurString, "***64_3:", 8 ) ) + { + iPageType = D3DPAGE_64_3X3; + } + else if ( 0 == strncmp ( pcCurString, "***32_3:", 8 ) ) + { + iPageType = D3DPAGE_32_3X3; + } + else + { + ASSERT ( FALSE ); + } + + // Set up the texture page. + pagePacking[iNumPackedPages].bPageType = (UBYTE)iPageType; + pagePacking[iNumPackedPages].bNumTextures = 0; + pagePacking[iNumPackedPages].pcDirectory = copy_string ( pcCurString + 8 ); + + // Name it. + char pcTemp[100]; + sprintf ( pcTemp, "%s\\PackedTexture%03d.tga", PACK_output_directory, iNumPackedPages); + pagePacking[iNumPackedPages].pcFilename = copy_string ( pcTemp ); + + //pagePacking[iNumPackedPages].ppcTextureList = ppcList; + pagePacking[iNumPackedPages].pTex = NULL; + + // See how many textures there are. + pagePacking[iNumPackedPages].ppcTextureList = (char **)MemAlloc ( 16 * sizeof ( char * ) ); + for ( int iTemp = 0; iTemp < 16; iTemp++ ) + { + pagePacking[iNumPackedPages].ppcTextureList[iTemp] = NULL; + } + + read_string ( PACK_file_in_handle, pcCurString ); + while ( pcCurString[0] != '*' ) + { + if ( pcCurString[0] == '\0' ) + { + // Empty slot. + pagePacking[iNumPackedPages].ppcTextureList[pagePacking[iNumPackedPages].bNumTextures] = NULL; + } + else + { + // Make sure it hasn't already been added. + for ( int i = 0; i <= iNumPackedPages; i++ ) + { + if ( 0 == stricmp ( pagePacking[i].pcDirectory, pagePacking[iNumPackedPages].pcDirectory ) ) + { + for ( int j = 0; j < pagePacking[i].bNumTextures; j++ ) + { + if ( ( pagePacking[i].ppcTextureList[j] != NULL ) && + ( 0 == stricmp ( pagePacking[i].ppcTextureList[j], pcCurString ) ) ) + { + // Silly person. + ASSERT ( FALSE ); + // Skip it. + goto try_the_next_texture_coz_this_is_not_needed; + } + } + } + } + // Also make sure we actually need it for this level. + { + bool bFound = FALSE; + for (i = 0; i < 512; i++) + { + tt = &TEXTURE_texture[i]; + + if (tt->Type == D3DTEXTURE_TYPE_UNUSED) + { + continue; + } + if (POLY_page_flag[i]) + { + // We can't pack this page because it's a funny one. + continue; + } + + // Extract directory name. + strcpy(texture_dir, tt->texture_name); + + for (ch = texture_dir; *ch; ch++); + while(ch > texture_dir && *ch != '\\') {ch--;} + + if (*ch == '\\') + { + *ch = '\000'; + } + + just_filename = ch + 1; + + if ( 0 == stricmp ( just_filename, pcCurString ) ) + { + // Right name. + + SLONG strlen_texture_dir = strlen(texture_dir); + SLONG strlen_pagepack_dir = strlen(pagePacking[iNumPackedPages].pcDirectory); + + if (strlen_pagepack_dir == strlen_texture_dir + 1) + { + if ( 0 == strnicmp ( texture_dir, pagePacking[iNumPackedPages].pcDirectory, strlen_texture_dir ) ) + { + // And same directory. + bFound = TRUE; + break; + } + } + } + } + if ( !bFound ) + { + // No, this doesn't need to be loaded. + ASSERT ( FALSE ); + goto try_the_next_texture_coz_this_is_not_needed; + } + } + + pagePacking[iNumPackedPages].ppcTextureList[pagePacking[iNumPackedPages].bNumTextures] = copy_string ( pcCurString ); + } + //pagePacking[iNumPackedPages].pTextures[pagePacking[iNumPackedPages].bNumTextures] = NULL; + pagePacking[iNumPackedPages].bNumTextures++; +try_the_next_texture_coz_this_is_not_needed: + read_string ( PACK_file_in_handle, pcCurString ); + } + + switch ( iPageType ) + { + case D3DPAGE_64_4X4: + case D3DPAGE_32_4X4: + ASSERT ( pagePacking[iNumPackedPages].bNumTextures <= 16 ); + break; + case D3DPAGE_64_3X3: + case D3DPAGE_32_3X3: + ASSERT ( pagePacking[iNumPackedPages].bNumTextures <= 9 ); + break; + default: + ASSERT ( FALSE ); + break; + } + + iNumPackedPages++; + } + + fclose(PACK_file_in_handle); + } + + + + PACK_fname_upto = 0; + PACK_texture_upto = 0; + + memset(PACK_fname, 0, sizeof(PACK_fname )); + memset(PACK_fname_dir, 0, sizeof(PACK_fname_dir)); + + for (i = 0; i < 64 * 22; i++) + { + tt = &TEXTURE_texture[i]; + + if (tt->Type == D3DTEXTURE_TYPE_UNUSED) + { + continue; + } + + if (POLY_page_flag[i]) + { + // We can't pack this page because it's a funny one. + continue; + } + + + // Extract directory name. + strcpy(texture_dir, tt->texture_name); + + for (ch = texture_dir; *ch; ch++); + while(ch > texture_dir && *ch != '\\') {ch--;} + + if (*ch == '\\') + { + *ch = '\000'; + } + + just_filename = ch + 1; + + + // See if it's in a texture page already + bool bFound = FALSE; + for ( int iPageNum = 0; iPageNum < iNumPackedPages; iPageNum++ ) + { + // + // The texture_dir doesn't have a final backslash whereas + // the packPacking directory does... + // + + SLONG strlen_texture_dir = strlen(texture_dir); + SLONG strlen_pagepack_dir = strlen(pagePacking[iPageNum].pcDirectory); + + if (strlen_pagepack_dir == strlen_texture_dir + 1) + { + if ( strnicmp ( texture_dir, pagePacking[iPageNum].pcDirectory, strlen_texture_dir) == 0 ) + { + for ( int iTexNum = 0; iTexNum < pagePacking[iPageNum].bNumTextures; iTexNum++ ) + { + if ( ( pagePacking[iPageNum].ppcTextureList[iTexNum] != NULL ) && + ( 0 == stricmp ( pagePacking[iPageNum].ppcTextureList[iTexNum], just_filename ) ) ) + { + bFound = TRUE; + break; + } + } + } + } + + if ( bFound ) + { + break; + } + } + if ( bFound ) + { + // Already got it. + continue; + } + + // + // What size of texture do we have and which page type + // do we need? + // + + texture_size = tt->size; + + if (texture_size == 64) + { + if (strstr(texture_dir, "people")) + { + // + // This is a people page, pack it 4x4 + // + + reqd_page_type = D3DPAGE_64_4X4; + } + else + { + // + // Put world textures on a 3x3 because of wrapping... + // + + reqd_page_type = D3DPAGE_64_3X3; + + if (i >= 64 * 8) + { + // + // Try squeezing in the prims! + // + + reqd_page_type = D3DPAGE_64_4X4; + } + } + } + else + if (texture_size == 32) + { + if (strstr(texture_dir, "people")) + { + // + // This is a people page, pack it 4x4 + // + + reqd_page_type = D3DPAGE_32_4X4; + } + else + { + // + // Put world textures on a 3x3 because of wrapping... + // + + reqd_page_type = D3DPAGE_32_3X3; + + if (i >= 64 * 8) + { + // + // Try squeezing in the prims! + // + + reqd_page_type = D3DPAGE_32_4X4; + } + } + } + else + { + // + // We don't support funny sizes... + // + + continue; + } + + ASSERT(reqd_page_type != 0); + + // OK, try to pack it into an existing page in the right directory with a gap. + bFound = FALSE; + for ( iPageNum = 0; iPageNum < iNumPackedPages; iPageNum++ ) + { + // Only auto-pack into 3x3s + if ( pagePacking[iPageNum].bPageType == reqd_page_type ) + { + // + // The texture_dir doesn't have a final backslash whereas + // the packPacking directory does... + // + + SLONG strlen_texture_dir = strlen(texture_dir); + SLONG strlen_pagepack_dir = strlen(pagePacking[iPageNum].pcDirectory); + + if (strlen_pagepack_dir == strlen_texture_dir + 1) + { + if ( strnicmp ( texture_dir, pagePacking[iPageNum].pcDirectory, strlen_texture_dir ) == 0 ) + { + // + // What's the max number of textures this pagepage can hold? + // + + SLONG max_textures_in_this_page; + + if (reqd_page_type == D3DPAGE_32_3X3 || + reqd_page_type == D3DPAGE_64_3X3) + { + max_textures_in_this_page = 9; + } + else + { + max_textures_in_this_page = 16; + } + + // Has it got a gap? + + if ( pagePacking[iPageNum].bNumTextures < max_textures_in_this_page ) + { + // Yes, there's a gap. + bFound = TRUE; + break; + } + } + } + } + } + + if ( !bFound ) + { + // Make a new page then. + iPageNum = iNumPackedPages; + // Set up the texture page. + pagePacking[iNumPackedPages].bPageType = reqd_page_type; + pagePacking[iNumPackedPages].bNumTextures = 0; + char pcTemp[100]; + strcpy ( pcTemp, texture_dir ); + strcat ( pcTemp, "\\" ); + pagePacking[iNumPackedPages].pcDirectory = copy_string ( pcTemp ); + + //pagePacking[iNumPackedPages].ppcTextureList = ppcList; + pagePacking[iNumPackedPages].pTex = NULL; + + // Allocate space for the source texture names. + pagePacking[iNumPackedPages].ppcTextureList = (char **)MemAlloc ( 16 * sizeof ( char * ) ); + + // Name it. + sprintf ( pcTemp, "%s\\PackedTexture%03d.tga", PACK_output_directory, iNumPackedPages); + pagePacking[iNumPackedPages].pcFilename = copy_string ( pcTemp ); + + + iNumPackedPages++; + } + + // Add to this page. + ASSERT ( pagePacking[iPageNum].bNumTextures < 16 ); + pagePacking[iPageNum].ppcTextureList[pagePacking[iPageNum].bNumTextures] = copy_string ( just_filename ); + pagePacking[iPageNum].bNumTextures++; + + } + + + // OK, so we've compiled our pages. Now write them out. + + for ( int iPageNum = 0; iPageNum < iNumPackedPages; iPageNum++ ) + { + // First write the cpp file data. + switch ( pagePacking[iPageNum].bPageType ) + { + case D3DPAGE_64_4X4: + fprintf ( PACK_fname_array_handle, "\"***64_4:" ); + fprintf ( PACK_text_array_handle, "***64_4:" ); + break; + case D3DPAGE_32_4X4: + fprintf ( PACK_fname_array_handle, "\"***32_4:" ); + fprintf ( PACK_text_array_handle, "***32_4:" ); + break; + case D3DPAGE_64_3X3: + fprintf ( PACK_fname_array_handle, "\"***64_3:" ); + fprintf ( PACK_text_array_handle, "***64_3:" ); + break; + case D3DPAGE_32_3X3: + fprintf ( PACK_fname_array_handle, "\"***32_3:" ); + fprintf ( PACK_text_array_handle, "***32_3:" ); + break; + default: + ASSERT ( FALSE ); + break; + } + + // + // Now output the directory containing the texture. Becuase this is 'C' code we + // are generating, each '\' must be written out as '\\'. + // + + CBYTE *ch; + for (ch = pagePacking[iPageNum].pcDirectory; *ch; ch++) + { + if (*ch == '\\') + { + fprintf(PACK_fname_array_handle, "\\\\"); + fprintf(PACK_text_array_handle, "\\"); + } + else + { + fprintf(PACK_fname_array_handle, "%c", *ch); + fprintf(PACK_text_array_handle, "%c", *ch); + } + } + + // + // Write in the rest of the line. + // + fprintf(PACK_fname_array_handle, "\", \""); + fprintf(PACK_text_array_handle, " "); + + for (ch = pagePacking[iPageNum].pcFilename; *ch; ch++) + { + if (*ch == '\\') + { + fprintf(PACK_fname_array_handle, "\\\\"); + fprintf(PACK_text_array_handle, "\\"); + } + else + { + fprintf(PACK_fname_array_handle, "%c", *ch); + fprintf(PACK_text_array_handle, "%c", *ch); + } + } + + fprintf(PACK_fname_array_handle, "\",\n"); + fprintf(PACK_text_array_handle, "\n"); + + // Now write out the texture names. + + for (i = 0; i < pagePacking[iPageNum].bNumTextures; i++) + { + if ( pagePacking[iPageNum].ppcTextureList[i] == NULL ) + { + fprintf(PACK_fname_array_handle, "\t\"\",\n" ); + fprintf(PACK_text_array_handle, "\n" ); + } + else + { + fprintf(PACK_fname_array_handle, "\t\"%s\",\n", pagePacking[iPageNum].ppcTextureList[i]); + fprintf(PACK_text_array_handle, "%s\n", pagePacking[iPageNum].ppcTextureList[i]); + } + } + + fprintf(PACK_fname_array_handle, "\n"); + + // + // How big are the page, the individual textures + // and the border? + // + + switch(pagePacking[iPageNum].bPageType) + { + case D3DPAGE_64_4X4: page_size = 256; break; + case D3DPAGE_32_4X4: page_size = 128; break; + case D3DPAGE_64_3X3: page_size = 256; break; + case D3DPAGE_32_3X3: page_size = 128; break; + + default: + ASSERT(0); + break; + } + + texture_size = page_size >> 2; + border_size = texture_size >> 2; + + + #define PLOT_PIX(fx,fy,tx,ty) if (WITHIN((tx), 0, page_size - 1) && WITHIN((ty), 0, page_size - 1) && WITHIN((fx), 0, page_size - 1) && WITHIN((fy), 0, page_size - 1)) PACK_tga[(tx) + (ty) * page_size] = PACK_tga[(fx) + (fy) * page_size] + + // Clear the page - don't want old data confusing the VQ rout & chewing palette entries. + for ( int iY = 0; iY < 256; iY++ ) + { + for ( int iX = 0; iX < 256; iX++ ) + { + PACK_tga[iX + iY * 256].alpha = 0xff; + PACK_tga[iX + iY * 256].blue = 0; + PACK_tga[iX + iY * 256].green = 0; + PACK_tga[iX + iY * 256].red = 0; + } + } + + // And now construct this page's texture. + for ( int iTexNum = 0; iTexNum < pagePacking[iPageNum].bNumTextures; iTexNum++) + { + if ( pagePacking[iPageNum].ppcTextureList[iTexNum] == NULL ) + { + // Empty slot. + continue; + } + + // Load up the tga. + char pcTemp[100]; + strcpy ( pcTemp, pagePacking[iPageNum].pcDirectory ); + strcat ( pcTemp, pagePacking[iPageNum].ppcTextureList[iTexNum] ); + ti = TGA_load ( pcTemp, 64, 64, (TGA_Pixel *) PACK_buffer, 0, 0); + if (!ti.valid) + { + // Nads. + ASSERT ( FALSE ); + } + + ASSERT(ti.width == texture_size); + ASSERT(ti.height == texture_size); + + if (ti.valid) + { + + // + // Copy over the texture to the right place. + // + + SLONG x; + SLONG y; + + SLONG fx; + SLONG fy; + + SLONG tx; + SLONG ty; + + SLONG base_x; + SLONG base_y; + + // + // What is the base (x,y) for this position? + // + + switch ( pagePacking[iPageNum].bPageType ) + { + case D3DPAGE_64_4X4: + base_x = (iTexNum % 4) * 64; + base_y = (iTexNum / 4) * 64; + break; + case D3DPAGE_32_4X4: + base_x = (iTexNum % 4) * 32; + base_y = (iTexNum / 4) * 32; + break; + case D3DPAGE_64_3X3: + base_x = (iTexNum % 3) * 96; + base_y = (iTexNum / 3) * 96; + break; + case D3DPAGE_32_3X3: + base_x = (iTexNum % 3) * 48; + base_y = (iTexNum / 3) * 48; + break; + default: + ASSERT ( FALSE ); + break; + } + + // + // Copy over the main body of the texture. + // + + for (x = 0; x < texture_size; x++) + { + for (y = 0; y < texture_size; y++) + { + fx = x; + fy = y; + + tx = base_x + x; + ty = base_y + y; + + PACK_tga[tx + ty * page_size] = PACK_buffer[fx + fy * texture_size]; + } + } + } + } + + if ( pagePacking[iPageNum].bPageType == D3DPAGE_64_3X3 || + pagePacking[iPageNum].bPageType == D3DPAGE_32_3X3) + { + + for ( int iTexNum = 0; iTexNum < pagePacking[iPageNum].bNumTextures; iTexNum++) + { + + SLONG fx; + SLONG fy; + + SLONG tx; + SLONG ty; + + SLONG base_x; + SLONG base_y; + + switch (pagePacking[iPageNum].bPageType) + { + case D3DPAGE_64_3X3: + base_x = (iTexNum % 3) * 96; + base_y = (iTexNum / 3) * 96; + break; + + case D3DPAGE_32_3X3: + base_x = (iTexNum % 3) * 48; + base_y = (iTexNum / 3) * 48; + break; + + default: + ASSERT(0); + break; + } + + // Now do the edges so we effectively have clamping... + for ( int iBorder = 1; iBorder <= border_size; iBorder++ ) + { + for (j = 0; j < texture_size; j++) + { + // + // Top... + // + + fx = base_x + j; + fy = base_y; + + tx = base_x + j; + ty = base_y - iBorder; + + PLOT_PIX ( fx, fy, tx, ty ); + + // + // Bottom... + // + + fx = base_x + j; + fy = base_y + texture_size - 1; + + tx = base_x + j; + ty = base_y + texture_size - 1 + iBorder; + + PLOT_PIX ( fx, fy, tx, ty ); + + // + // Left... + // + + fx = base_x; + fy = base_y + j; + + tx = base_x - iBorder; + ty = base_y + j; + + PLOT_PIX ( fx, fy, tx, ty ); + + // + // Right... + // + + fx = base_x + texture_size - 1; + fy = base_y + j; + + tx = base_x + texture_size - 1 + iBorder; + ty = base_y + j; + + PLOT_PIX ( fx, fy, tx, ty ); + } + } + + + for ( int iBordX = 1; iBordX <= border_size; iBordX++ ) + { + for ( int iBordY = 1; iBordY <= border_size; iBordY++ ) + { + // + // Now do the corners. + // + + // + // Top left... + // + + fx = base_x; + fy = base_y; + + tx = base_x - iBordX; + ty = base_y - iBordY; + + PLOT_PIX ( fx, fy, tx, ty ); + + // + // Bottom right... + // + + fx = base_x + texture_size - 1; + fy = base_y + texture_size - 1; + + tx = base_x + texture_size - 1 + iBordX; + ty = base_y + texture_size - 1 + iBordY; + + PLOT_PIX ( fx, fy, tx, ty ); + + // + // Top right... + // + + fx = base_x + texture_size - 1; + fy = base_y; + + tx = base_x + texture_size - 1 + iBordX; + ty = base_y - iBordY; + + PLOT_PIX ( fx, fy, tx, ty ); + + // + // Bottom left... + // + + fx = base_x; + fy = base_y + texture_size - 1; + + tx = base_x - iBordX; + ty = base_y + texture_size - 1 + iBordY; + + PLOT_PIX ( fx, fy, tx, ty ); + } + } + } + } + else + { + // 4x4s often have gaps - fill them in too, but in a more cunning way. + // Look for empty spaces. + for ( int iTexNum = 0; iTexNum < 16; iTexNum++ ) + { + if ( pagePacking[iPageNum].ppcTextureList[iTexNum] == NULL ) + { + // Found a gap. + // What surroundings does it have? + bool bHasU = FALSE; + bool bHasD = FALSE; + bool bHasL = FALSE; + bool bHasR = FALSE; + if ( iTexNum >= 4 ) + { + if ( pagePacking[iPageNum].ppcTextureList[iTexNum-4] != NULL ) + { + bHasU = TRUE; + } + } + if ( iTexNum <= 11 ) + { + if ( pagePacking[iPageNum].ppcTextureList[iTexNum+4] != NULL ) + { + bHasD = TRUE; + } + } + if ( ( iTexNum % 4 ) > 0 ) + { + if ( pagePacking[iPageNum].ppcTextureList[iTexNum-1] != NULL ) + { + bHasL = TRUE; + } + } + if ( ( iTexNum % 4 ) < 3 ) + { + if ( pagePacking[iPageNum].ppcTextureList[iTexNum+1] != NULL ) + { + bHasR = TRUE; + } + } + + SLONG base_x; + SLONG base_y; + + switch (pagePacking[iPageNum].bPageType) + { + case D3DPAGE_64_4X4: + base_x = (iTexNum % 4) * 64; + base_y = (iTexNum / 4) * 64; + break; + + case D3DPAGE_32_4X4: + base_x = (iTexNum % 4) * 32; + base_y = (iTexNum / 4) * 32; + break; + + default: + ASSERT(0); + break; + } + + SLONG diag_size = texture_size >> 1; + + + // Do top-left corner. + if ( bHasU ) + { + if ( bHasL ) + { + // Has both - fill both, diagonal join. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + if ( iPixY > iPixX ) + { + // Copy from left. + PLOT_PIX ( base_x - 1, base_y + iPixY, base_x + iPixX, base_y + iPixY ); + } + else + { + // Copy from top. + PLOT_PIX ( base_x + iPixX, base_y - 1, base_x + iPixX, base_y + iPixY ); + } + } + } + } + else + { + // Has top - fill from that. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from top. + PLOT_PIX ( base_x + iPixX, base_y - 1, base_x + iPixX, base_y + iPixY ); + } + } + } + } + else + { + if ( bHasL ) + { + // Has left. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from left. + PLOT_PIX ( base_x - 1, base_y + iPixY, base_x + iPixX, base_y + iPixY ); + } + } + } + else + { + // Has neither - copy from top-left. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + PLOT_PIX ( base_x - 1, base_y - 1, base_x + iPixX, base_y + iPixY ); + } + } + } + } + + // Do top-right corner. + if ( bHasU ) + { + if ( bHasR ) + { + // Has both - fill both, diagonal join. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + if ( iPixY > iPixX ) + { + // Copy from right. + PLOT_PIX ( base_x + texture_size, base_y + iPixY, base_x + texture_size - 1 - iPixX, base_y + iPixY ); + } + else + { + // Copy from top. + PLOT_PIX ( base_x + texture_size - 1 - iPixX, base_y - 1, base_x + texture_size - 1 - iPixX, base_y + iPixY ); + } + } + } + } + else + { + // Has top - fill from that. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from top. + PLOT_PIX ( base_x + texture_size - 1 - iPixX, base_y - 1, base_x + texture_size - 1 - iPixX, base_y + iPixY ); + } + } + } + } + else + { + if ( bHasR ) + { + // Has right. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from right. + PLOT_PIX ( base_x + texture_size, base_y + iPixY, base_x + texture_size - 1 - iPixX, base_y + iPixY ); + } + } + } + else + { + // Has neither - copy from top-right. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + PLOT_PIX ( base_x + texture_size, base_y - 1, base_x + texture_size - 1 - iPixX, base_y + iPixY ); + } + } + } + } + + // Do bottom-left corner. + if ( bHasD ) + { + if ( bHasL ) + { + // Has both - fill both, diagonal join. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + if ( iPixY > iPixX ) + { + // Copy from left. + PLOT_PIX ( base_x - 1, base_y + texture_size - 1 - iPixY, base_x + iPixX, base_y + texture_size - 1 - iPixY ); + } + else + { + // Copy from bottom. + PLOT_PIX ( base_x + iPixX, base_y + texture_size, base_x + iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + } + else + { + // Has bottom - fill from that. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from bottom. + PLOT_PIX ( base_x + iPixX, base_y + texture_size, base_x + iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + } + else + { + if ( bHasL ) + { + // Has left. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from left. + PLOT_PIX ( base_x - 1, base_y + texture_size - 1 - iPixY, base_x + iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + else + { + // Has neither - copy from bottom-left. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + PLOT_PIX ( base_x - 1, base_y + texture_size, base_x + iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + } + + // Do bottom-right corner. + if ( bHasD ) + { + if ( bHasR ) + { + // Has both - fill both, diagonal join. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + if ( iPixY > iPixX ) + { + // Copy from right. + PLOT_PIX ( base_x + texture_size, base_y + texture_size - 1 - iPixY, base_x + texture_size - 1 - iPixX, base_y + texture_size - 1 - iPixY ); + } + else + { + // Copy from bottom. + PLOT_PIX ( base_x + texture_size - 1 - iPixX, base_y + texture_size, base_x + texture_size - 1 - iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + } + else + { + // Has bottom - fill from that. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from bottom. + PLOT_PIX ( base_x + texture_size - 1 - iPixX, base_y + texture_size, base_x + texture_size - 1 - iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + } + else + { + if ( bHasR ) + { + // Has right. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + // Copy from right. + PLOT_PIX ( base_x + texture_size, base_y + texture_size - 1 - iPixY, base_x + texture_size - 1 - iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + else + { + // Has neither - copy from bottom-right. + for ( int iPixX = 0; iPixX < diag_size; iPixX++ ) + { + for ( int iPixY = 0; iPixY < diag_size; iPixY++ ) + { + PLOT_PIX ( base_x + texture_size, base_y + texture_size, base_x + texture_size - 1 - iPixX, base_y + texture_size - 1 - iPixY ); + } + } + } + } + + + } + } + } + + + + // And finally write it out. + + + CBYTE texture_filename[256]; + + sprintf(texture_filename, "%s\\PackedTexture%03d.tga", PACK_output_directory, iPageNum ); + + // + // Got a whole new texture. + // + + TGA_save(texture_filename, page_size, page_size, (TGA_Pixel *) PACK_tga, FALSE); + + + // + // If you want to run this bit of code then do a search for 'save_out_the_vqs' + // in d3dtexture.cpp and re-enable if (save_out_the_vqs) + // + + save_out_the_vqs = TRUE; + + { + D3DTexture *pTex; + + #define DO_DC_CONVERT(name) pTex = MFnew(); pTex->LoadTextureTGA ( (name), -1, TRUE ); MFdelete ( pTex ) + + DO_DC_CONVERT(texture_filename); + } + + save_out_the_vqs = FALSE; + + } + + fprintf(PACK_fname_array_handle, "\t\"***END\"\n"); + fprintf(PACK_text_array_handle, "***END\n\n\n"); + fprintf(PACK_fname_array_handle, "};\n\n"); + + fclose(PACK_fname_array_handle); + fclose(PACK_text_array_handle); + + TRACE ( "Finished PACKing level %s", ELEV_fname_level ); + +} + + + +#endif //#ifndef TARGET_DC diff --git a/fallen/DDEngine/Source/panel.cpp b/fallen/DDEngine/Source/panel.cpp new file mode 100644 index 0000000..3667de0 --- /dev/null +++ b/fallen/DDEngine/Source/panel.cpp @@ -0,0 +1,6689 @@ +#include "game.h" + +#include "aeng.h" +#include "poly.h" +#include "sprite.h" +#include "c:\fallen\headers\supermap.h" +#include "c:\fallen\headers\cam.h" +#include "fc.h" +#include +#include "panel.h" +#include "drawxtra.h" +#include "statedef.h" +#include "font2d.h" +#include "eway.h" +#include "DDLib.h" +#include "c:\fallen\ddengine\headers\map.h" +#include "memory.h" +#include "mfx.h" +#include "xlat_str.h" +#include "sound_id.h" +#include "pcom.h" +#include "env.h" + +#ifdef TARGET_DC +#include "target.h" +#endif + + +#ifdef TARGET_DC +// intrinsic maths +#include +#endif + + +#define HEALTH_BAR_WIDTH 100 +#define HEALTH_BAR_HEIGHT 10 +#define HEALTH_BAR_VERT_GAP 2 +#define HEALTH_BAR_HORIZ_GAP 2 + + +#ifdef TARGET_DC +// Slightly shifts each line of text a bit closer than the last to get correct +// drawing behaviour on autosort cards (i.e. the DC). +// This might also be a good idea on the PC, you never know. +#define BODGE_MY_PANELS_PLEASE_BOB Yes please +#endif + + +#ifdef TARGET_DC +void PANEL_draw_VMU_ammo_counts ( void ); +#endif + + + + + + +// Coords of the bottom-left corner. +#ifdef TARGET_DC +// Got to keep away from the edges. +int m_iPanelXPos = 32; +int m_iPanelYPos = 480 - 32; + +#else +int m_iPanelXPos = 0; +int m_iPanelYPos = 480; +#endif + + + + + +#ifdef BODGE_MY_PANELS_PLEASE_BOB +#define DEPTH_BODGE_START (0.95f) +#define DEPTH_BODGE_INC (0.00001f) +float PANEL_fDepthBodgeValue; + +#endif + + + +#ifdef BODGE_MY_PANELS_PLEASE_BOB +void PANEL_ResetDepthBodge ( void ) +{ + PANEL_fDepthBodgeValue = DEPTH_BODGE_START; +} + +float PANEL_GetNextDepthBodge ( void ) +{ + PANEL_fDepthBodgeValue += DEPTH_BODGE_INC; + ASSERT ( PANEL_fDepthBodgeValue < 1.0f ); + return ( PANEL_fDepthBodgeValue ); +} +#else +// Just use 0.9 as a goodish value. +float PANEL_GetNextDepthBodge ( void ) +{ + return ( 0.9f ); +} + +void PANEL_ResetDepthBodge ( void ) +{ + // Do nothing. +} + +#endif + + + + +UBYTE PANEL_scanner_poo=0; + + +void PANEL_draw_quad( + float left, + float top, + float right, + float bottom, + SLONG page, + ULONG colour, + float u1, + float v1, + float u2, + float v2) +{ + POLY_Point pp [4]; + POLY_Point *quad[4]; + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + + pp[0].X = left; + pp[0].Y = top; + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].u = u1; + pp[0].v = v1; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = right; + pp[1].Y = top; + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].u = u2; + pp[1].v = v1; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = left; + pp[2].Y = bottom; + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].u = u1; + pp[2].v = v2; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = right; + pp[3].Y = bottom; + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].u = u2; + pp[3].v = v2; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); +} + + +void PANEL_crap_text ( int x, int y, char *string ) +{ + FONT2D_DrawString( + string, + x + 1, + y + 1, + 0x000000, + 256, + POLY_PAGE_FONT2D, + 0); + + FONT2D_DrawString( + string, + x, + y, + 0xffffee, + 256, + POLY_PAGE_FONT2D, + 0); +} + + + +void PANEL_draw_face(SLONG x,SLONG y,SLONG face,SLONG size) +{ + float left; + float right; + float top; + float bottom; + + left = (float) x; + top = (float) y; + right = left + (float) size; + bottom = top + (float) size; + + SATURATE(face, 1, 6); + + PANEL_draw_quad( + left, + top, + right, + bottom, + POLY_PAGE_FACE1+face-1); +} + + +#if 0 +// No longer used! +void PANEL_draw_angelic_status(SLONG x, SLONG y, SLONG size, SLONG am_i_an_angel) +{ + float left; + float right; + float top; + float bottom; + + left = (float) x; + top = (float) y; + right = left + (float) size; + bottom = top + (float) size; + + SLONG page; + + page = (am_i_an_angel) ? POLY_PAGE_ANGEL : POLY_PAGE_DEVIL; + + PANEL_draw_quad( + left, + top, + right, + bottom, + page); +} + +void PANEL_draw_press_button(SLONG x, SLONG y, SLONG size, SLONG frame) +{ + float left; + float right; + float top; + float bottom; + + left = (float) x; + top = (float) y; + right = left + (float) size; + bottom = top + (float) size; + + SLONG page; + + page = (frame & 1) ? POLY_PAGE_PRESS1 : POLY_PAGE_PRESS2; + + PANEL_draw_quad( + left, + top, + right, + bottom, + page); +} +#endif + + +#ifndef TARGET_DC +extern UBYTE sw_hack; +#endif + +void PANEL_draw_health_bar(SLONG x,SLONG y,SLONG percentage) +{ +#ifndef TARGET_DC + if (!sw_hack) +#endif + { + AENG_draw_rect(x,y,HEALTH_BAR_WIDTH,HEALTH_BAR_HEIGHT,0x000000,2,POLY_PAGE_COLOUR); + } + + if(percentage<0) + { + percentage=0; + } + else + if(percentage>100) + { + percentage=100; + } + + AENG_draw_rect(x+HEALTH_BAR_HORIZ_GAP,y+HEALTH_BAR_VERT_GAP,((HEALTH_BAR_WIDTH-HEALTH_BAR_HORIZ_GAP*2)*percentage)/100,6,0xff0000,1,POLY_PAGE_COLOUR); + +} + +#define B0 (1 << 0) +#define B1 (1 << 1) +#define B2 (1 << 2) +#define B3 (1 << 3) +#define B4 (1 << 4) +#define B5 (1 << 5) +#define B6 (1 << 6) + +#define PANEL_SEG_L (16.0F) +#define PANEL_SEG_W ( 4.0F) + +void PANEL_draw_number(float x, float y, UBYTE digit) // 0 <= digit <= 9... Not ASCII! +{ + UBYTE number[10] = + { + B0|B1|B2|B4|B5|B6, + B2|B5, + B0|B2|B3|B4|B6, + B0|B2|B3|B5|B6, + B1|B2|B3|B5, + B0|B1|B3|B5|B6, + B0|B1|B3|B4|B5|B6, + B0|B2|B5, + B0|B1|B2|B3|B4|B5|B6, + B0|B1|B2|B3|B5 + }; + + struct + { + UBYTE d1; + UBYTE d2; + float dx; + float dy; + + } bit[7] = + { + {0,1,0.0F,PANEL_SEG_W/2.0F}, + {0,2,PANEL_SEG_W/2.0F,0.0F}, + {1,3,PANEL_SEG_W/2.0F,0.0F}, + {2,3,0.0F,PANEL_SEG_W/2.0F}, + {2,4,PANEL_SEG_W/2.0F,0.0F}, + {3,5,PANEL_SEG_W/2.0F,0.0F}, + {4,5,0.0F,PANEL_SEG_W/2.0F}, + }; + + float x1; + float y1; + + float x2; + float y2; + + float dx; + float dy; + + SLONG b; + ULONG colour; + + POLY_Point pp[4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + ASSERT(WITHIN(digit, 0, 9)); + + for (b = 0; b < 7; b++) + { + // + // Work out the positions of the two points. + // + + x1 = x + ((bit[b].d1 & 1) ? PANEL_SEG_L : 0.0F); + y1 = y + (bit[b].d1 >> 1) * PANEL_SEG_L; + + x2 = x + ((bit[b].d2 & 1) ? PANEL_SEG_L : 0.0F); + y2 = y + (bit[b].d2 >> 1) * PANEL_SEG_L; + + // + // What colour? + // + + colour = (number[digit] & (1 << b)) ? 0xeeff0000 : 0x88110000; + + // + // The offset vector to make a rect from a line. + // + + dx = bit[b].dx; + dy = bit[b].dy; + + // + // The four POLY_Points... + // + + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + + pp[0].X = x1 + dx; + pp[0].Y = y1 + dy; + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = x1 - dx; + pp[1].Y = y1 - dy; + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = x2 + dx; + pp[2].Y = y2 + dy; + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = x2 - dx; + pp[3].Y = y2 - dy; + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE); + } +} + +#ifndef TARGET_DC + +typedef struct +{ + float time; + float x; + float y; + +} PANEL_Store; + +#define PANEL_MAX_STORES 8 + +PANEL_Store PANEL_store[PANEL_MAX_STORES]; +SLONG PANEL_store_upto; + +#endif + +/* +void PANEL_draw_timer_do(float time, float x, float y) +{ + CBYTE countdown[32]; + CBYTE *ch; + + SLONG mins = 0; + + ASSERT(time < 1000.0F); + + while(time >= 60.0F) + { + mins += 1; + time -= 60.0F; + } + + sprintf(countdown, "%02d %05.2f", mins, time); + + for (ch = countdown; *ch; ch++) + { + if (WITHIN(*ch, '0', '9')) + { + x -= 11.0F; + } + else + { + x -= 6.0F; + } + } + + float x_start = x; + + for (ch = countdown; *ch; ch++) + { + if (WITHIN(*ch, '0', '9')) + { + PANEL_draw_number(x, y, *ch - '0'); + + x += 22.0F; + } + else + { + x += 12.0F; + } + } + + // + // An alpha overlay over it all. + // + + PANEL_draw_quad( + x_start - 4.0F, + y - 4.0F, + x + 4.0F, + y + 36.0F, + POLY_PAGE_ALPHA_OVERLAY, + 0xaa000000); +} +*/ + +#ifndef TARGET_DC +void PANEL_draw_buffered() +{ + + SLONG i; + + for (i = 0; i < PANEL_store_upto; i++) + { + /* + + PANEL_draw_timer_do( + PANEL_store[i].time, + PANEL_store[i].x, + PANEL_store[i].y); + + */ + + float time = PANEL_store[i].time; + float x = PANEL_store[i].x; + float y = PANEL_store[i].y; + + CBYTE countdown[32]; + + SLONG mins = 0; + + ASSERT(time < 1000.0F); + + while(time >= 60.0F) + { + mins += 1; + time -= 60.0F; + } + + sprintf(countdown, "%02d:%02d", mins, SLONG(time)); + + if ((time<30)&&!mins) + { + static UWORD pulse=0; + SLONG colour; + pulse+=(TICK_RATIO*80)>>TICK_SHIFT; + colour=(SIN(pulse&2047)>>9)+128; + colour=colour|(colour<<8); + FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xff0000|colour, 256 + 64); + + } + else + { + FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xffffff, 256 + 64); + } + } + + PANEL_store_upto = 0; + +} +#endif + +#ifdef TARGET_DC +SLONG slPANEL_draw_timer_time = -1; +void PANEL_draw_timer(SLONG time, SLONG x, SLONG y) +{ + slPANEL_draw_timer_time = time; +} + +#else + +void PANEL_draw_timer(SLONG time, SLONG x, SLONG y) +{ + if (WITHIN(PANEL_store_upto, 0, PANEL_MAX_STORES - 1)) + { + PANEL_store[PANEL_store_upto].time = float(time) * (1.0F / 100.0F); + PANEL_store[PANEL_store_upto].x = float(x); + PANEL_store[PANEL_store_upto].y = float(y); + + PANEL_store_upto += 1; + } +} +#endif + + +extern void POLY_add_rect(POLY_Point *p1, SLONG width,SLONG height, SLONG page, UBYTE sort_to_front); + +void PANEL_draw_local_health(SLONG mx,SLONG my,SLONG mz,SLONG percentage,SLONG radius=60) +{ + POLY_Point p1; + + float dx,dy,dz,len; + +// ASSERT(percentage>=0 && percentage<=100); + + + dx=POLY_cam_x-(float)mx; + dy=POLY_cam_y-(float)my; + dz=POLY_cam_z-(float)mz; + +#ifdef TARGET_DC + len=_InvSqrtA(dx*dx+dy*dy+dz*dz); + + dx=(dx*((float)radius))*len; + dy=(dy*((float)radius))*len; + dz=(dz*((float)radius))*len; +#else + len=sqrt(dx*dx+dy*dy+dz*dz); + + dx=(dx*((float)radius))/len; + dy=(dy*((float)radius))/len; + dz=(dz*((float)radius))/len; +#endif + + // + // move towards the camera a bit so you sort infront of the person + // + + + + POLY_transform(float(mx+dx), float(my+dy-10), float(mz+dz), &p1); + + + // Roper and others have >100% health - clamp it. + if ( percentage > 100 ) + { + percentage = 100; + } + + +#ifdef TARGET_DC + + + p1.X-=27.0f; + + // Drag it forwards, otherwise at distance it becomes hidden in the pavement. + p1.Z+=0.02F; + + + p1.colour=0xc0000000|0x0f; + p1.specular=0xff000000; + + if(p1.IsValid()) + { + POLY_add_rect(&p1, 54,8,POLY_PAGE_COLOUR,0); + } + else + { + return; + } + + p1.X+=2.0f; + + p1.colour=0x40000000|0xff0000; + p1.specular=0xff000000; + + p1.Y+=2.0F; + + // Only very slightly forwards - the DC is nice and accurate. + p1.Z+=0.00001F; + + if(p1.IsValid()) + { + POLY_add_rect(&p1,percentage>>1,4,POLY_PAGE_COLOUR,0); +// AENG_draw_rect(p1.X,p1.Y,percentage>>1,2,0xb0000000,3,POLY_PAGE_COLOUR); +// POLY_add_line(&p1, &p2, (float)2.0, 2.0, POLY_PAGE_COLOUR, 0); + } + + + + + +#else + + + // PC version + + p1.X-=27.0f; + + p1.colour=0xc0000000|0x0f; + p1.specular=0xff000000; + + if(p1.IsValid()) + { + if (!sw_hack) + { + POLY_add_rect(&p1, 54,4,POLY_PAGE_COLOUR,0); + } + } + else + return; + + p1.X+=2.0f; + + p1.colour=0x40000000|0xff0000; + p1.specular=0xff000000; + + p1.Y+=1.0F; + + p1.Z+=0.01F; + + if(p1.IsValid()) + { + POLY_add_rect(&p1,percentage>>1,2,POLY_PAGE_COLOUR,0); +// AENG_draw_rect(p1.X,p1.Y,percentage>>1,2,0xb0000000,3,POLY_PAGE_COLOUR); +// POLY_add_line(&p1, &p2, (float)2.0, 2.0, POLY_PAGE_COLOUR, 0); + } + +#endif + + +} + +void PANEL_draw_gun_sight(SLONG mx,SLONG my,SLONG mz,SLONG accuracy,SLONG scale) +{ + SLONG angle,cangle; + SLONG c0; + SLONG dx1,dy1,dx2,dy2; + POLY_Point p1,p2,pstart; + SLONG r_in,r_out; + ULONG col; + SLONG sat_acc; + +#define RADIUS_OUT 164 +#define RADIUS_IN 84 + + angle=accuracy; + POLY_transform(float(mx), float(my-36), float(mz), &pstart); + r_in = (POLY_world_length_to_screen(RADIUS_IN) * pstart.Z*scale)/256; + r_out = (POLY_world_length_to_screen(RADIUS_OUT) * pstart.Z*scale)/256; + + sat_acc=accuracy; + SATURATE(sat_acc,0,255) + + + + + col = sat_acc<<8; + col |= (255-sat_acc)<<16; + + for(c0=0;c0<4;c0++) + { + + p2=p1=pstart; + switch(c0) + { + case 0: + cangle=+angle; + break; + case 1: + cangle=-angle; + break; + case 2: + cangle=1024+angle; + break; + case 3: + cangle=1024-angle; + break; + } + +// cangle+=GAME_TURN<<5; + dx1=((COS(cangle&2047)*r_out)>>16); + dy1=((SIN(cangle&2047)*r_out)>>16); + dx2=((COS(cangle&2047)*r_in)>>16); + dy2=((SIN(cangle&2047)*r_in)>>16); + + p1.X+=(float)dx1; + p1.Y+=(float)dy1; + p2.X+=(float)dx2; + p2.Y+=(float)dy2; + + p1.colour=0x40000000|col; + p2.colour=0x40000000|col; + p1.specular=0xff000000; + p2.specular=0xff000000; + + if(p1.IsValid() && p2.IsValid()) + { + SLONG width; + width=(30*scale)>>8; + POLY_add_line(&p1, &p2, (float)width, 0.0F, POLY_PAGE_COLOUR_ALPHA, 0); +// POLY_add_line(&p1, &p2, 20.0F, 0.0F, POLY_PAGE_COLOUR_ALPHA, 0); + } + + } + +// r_out=(r_out*270)>>8; +// r_out*=(270+256-SATURATE(accuracy,0,256))>>3; + r_in=20+(sat_acc>>2); + r_in=(r_in*scale)>>8; + r_out=r_in+((80*scale)>>8); + + r_in = POLY_world_length_to_screen(r_in) * pstart.Z; + r_out = POLY_world_length_to_screen(r_out) * pstart.Z; + + for(c0=0;c0<4;c0++) + { + + p2=p1=pstart; + switch(c0) + { + case 0: + cangle=512; + break; + case 1: + cangle=-512; + break; + case 2: + cangle=1024; + break; + case 3: + cangle=0; + break; + } + +// cangle+=GAME_TURN<<5; + dx1=((COS(cangle&2047)*(r_out))>>16); + dy1=((SIN(cangle&2047)*(r_out))>>16); + dx2=((COS(cangle&2047)*(r_in))>>16); + dy2=((SIN(cangle&2047)*(r_in))>>16); + + p1.X+=(float)dx1; + p1.Y+=(float)dy1; + p2.X+=(float)dx2; + p2.Y+=(float)dy2; + + p1.colour=0x40000000|col; + p2.colour=0x40000000|col; + p1.specular=0xff000000; + p2.specular=0xff000000; + + if(p1.IsValid() && p2.IsValid()) + { + SLONG width; + + width=(5*scale)>>8; + POLY_add_line(&p1, &p2, (float)width, (float)width,POLY_PAGE_COLOUR_ALPHA, 0); + } +// POLY_add_line(&p1, &p2, 5.0F, 5.0F, POLY_PAGE_COLOUR_ALPHA, 0); + + } + +} + + +#if 0 + + +#define COMPASS_MID_X 600.0f +#define COMPASS_MID_Y 40.0f +#define COMPASS_RAD 40.0f + +void PANEL_draw_compass_angle(float dx,float dy,ULONG col) +{ + float x=0,y=1.0; + POLY_Point p1; + POLY_Point p2; + + p1.X = COMPASS_MID_X; + p1.Y = COMPASS_MID_Y; + p1.z = 0.0F; + p1.Z = 1.0F; + p1.u = 1.0F; + p1.v = 1.0F; + p1.colour = col; + p1.specular = 0xff000000; + + p2.X = COMPASS_MID_X+dx*COMPASS_RAD; + p2.Y = COMPASS_MID_Y+dy*COMPASS_RAD; + p2.z = 0.0F; + p2.Z = 1.0F; + p2.u = 1.0F; + p2.v = 1.0F; + p2.colour = 0xff0000; + p2.specular = col; + + POLY_setclip(&p1); + POLY_setclip(&p2); + + if (POLY_valid_line(&p1, &p2)) + { + POLY_add_line(&p1, &p2, 1.0, 0.0, POLY_PAGE_COLOUR, 1); + } + +/* + p2.X = COMPASS_MID_X+dx*(COMPASS_RAD-10.0); + p2.Y = COMPASS_MID_Y+dy*(COMPASS_RAD-10.0); + p1.z = 0.0F; + p1.Z = 1.0F; + p1.u = 1.0F; + p1.v = 1.0F; + p1.colour = 0xff0000; + p1.specular = 0xff000000; + + p2.X = COMPASS_MID_X+dx*COMPASS_RAD; + p2.Y = COMPASS_MID_Y+dy*COMPASS_RAD; + p2.z = 0.0F; + p2.Z = 1.0F; + p2.u = 1.0F; + p2.v = 1.0F; + p2.colour = 0xff0000; + p2.specular = 0xff000000; + + POLY_setclip(&p1); + POLY_setclip(&p2); + + if (POLY_valid_line(&p1, &p2)) + { + POLY_add_line(&p1, &p2, 3.0, 0.0, POLY_PAGE_COLOUR, 1); + } +*/ + + +} + +void PANEL_draw_compass_north(void) +{ + float x=0,y=1.0; + float dx,dy; + float angle; + POLY_Point p1; + POLY_Point p2; +#ifdef OLD_CAM + angle=CAM_get_ryaw(); + angle=PI+angle; + + dx=x*cos(angle)-y*sin(angle); + dy=x*sin(angle)+y*cos(angle); + + PANEL_draw_compass_angle(dx,dy,0xff0000); +#endif +} + + +void PANEL_draw_compass_to(SLONG dx,SLONG dy) +{ + float fdx,fdy; + float dist; + + fdx=dx; + fdy=dy; + + dist=sqrt(fdx*fdx+fdy*fdy); + + fdx=fdx/dist; + fdy=fdy/dist; + + PANEL_draw_compass_angle(dx,dy,0xffff00); +} + + + +#endif + + +// +// The positions of all the icons on the IC page. +// + +#define PANEL_IC_BACKBOX 0 // These are on page 1 +#define PANEL_IC_AK47 1 +#define PANEL_IC_GRENADE 2 +#define PANEL_IC_AK47_AMMO_ONE 3 +#define PANEL_IC_AK47_AMMO_GROUP 4 +#define PANEL_IC_PISTOL 5 +#define PANEL_IC_DARCI_OUTLINE 6 +#define PANEL_IC_ROPER_OUTLINE 7 +#define PANEL_IC_DARCI 8 +#define PANEL_IC_ROPER 9 +#define PANEL_IC_SHOTGUN 10 + +#define PANEL_IC_ROPER_HAND 11 +#define PANEL_IC_DARCI_HAND 12 +#define PANEL_IC_KNIFE 13 +#define PANEL_IC_SHOTGUN_AMMO_GROUP 14 +#define PANEL_IC_SHOTGUN_AMMO_ONE 15 +#define PANEL_IC_PISTOL_AMMO_GROUP 16 +#define PANEL_IC_PISTOL_AMMO_ONE 17 +#define PANEL_IC_BIG_AMMO_GROUP 18 +#define PANEL_IC_BIG_AMMO_ONE 19 +#define PANEL_IC_GRENADE_AMMO_GROUP 20 +#define PANEL_IC_GRENADE_AMMO_ONE 21 + +#define PANEL_IC_DIGIT_0 22 +#define PANEL_IC_DIGIT_1 23 +#define PANEL_IC_DIGIT_2 24 +#define PANEL_IC_DIGIT_3 25 +#define PANEL_IC_DIGIT_4 26 +#define PANEL_IC_DIGIT_5 27 +#define PANEL_IC_DIGIT_6 28 +#define PANEL_IC_DIGIT_7 29 +#define PANEL_IC_DIGIT_8 30 +#define PANEL_IC_DIGIT_9 31 + +#define PANEL_IC_BASEBALLBAT 32 +#define PANEL_IC_EXPLOSIVES 33 +#define PANEL_IC_GRIMREAPER 34 +#define PANEL_IC_DANGERMETER 35 + +#define PANEL_IC_BUBBLE_START 36 +#define PANEL_IC_BUBBLE_MIDDLE 37 +#define PANEL_IC_BUBBLE_END 38 + +#define PANEL_IC_DOT 39 + +#define PANEL_IC_CLIP_PISTOL 40 +#define PANEL_IC_CLIP_SHOTGUN 41 +#define PANEL_IC_CLIP_AK47 42 + +#define PANEL_IC_GEAR_BOX 43 +#define PANEL_IC_GEAR_LOW 44 +#define PANEL_IC_GEAR_HIGH 45 + +#define PANEL_IC_NUMBER 46 + +typedef struct +{ + float u1; + float v1; + float u2; + float v2; + SLONG page; + +} PANEL_Ic; + +#define PIC(uv) ((uv) / 256.0F) + +PANEL_Ic PANEL_ic[PANEL_IC_NUMBER] = +{ + {PIC( 0), PIC( 0), PIC( 99), PIC( 81), 0}, // Backbox + {PIC( 1), PIC( 83), PIC(191), PIC(137), 0}, // AK47 + {PIC(100), PIC( 1), PIC(140), PIC( 64), 0}, // Grenade + {PIC(141), PIC( 1), PIC(146), PIC( 13), 0}, // Single ammo + {PIC(158), PIC( 1), PIC(208), PIC( 13), 0}, // 10 ammos + {PIC(142), PIC( 15), PIC(221), PIC( 75), 0}, // Pistol + {PIC( 0), PIC(144), PIC( 55), PIC(255), 0}, // Darci outline + {PIC( 55), PIC(144), PIC(109), PIC(256), 0}, // Roper outline + {PIC(110), PIC(149), PIC(160), PIC(255), 0}, // Darci + {PIC(160), PIC(148), PIC(210), PIC(255), 0}, // Roper + {PIC(210), PIC( 95), PIC(254), PIC(256), 0}, // Shotgun + + // + // These are all on the second page. + // + + #define PICALL1(a,b,c,d) {PIC(a),PIC(b),PIC(c),PIC(d),1} + + PICALL1( 1, 1, 75, 50), + PICALL1( 75, 5, 151, 46), + PICALL1( 1, 55, 97, 70), + PICALL1( 5, 81, 45, 93), + PICALL1( 48, 81, 53, 93), + PICALL1( 16, 95, 66, 104), + PICALL1( 5, 95, 10, 104), + PICALL1( 15, 108, 39, 122), + PICALL1( 5, 108, 13, 122), + PICALL1( 18, 123, 54, 141), + PICALL1( 4, 123, 16, 141), + + #define PICALL0(a,b,c,d) {PIC(a),PIC(b),PIC(c),PIC(d),0} + + // + // These are all squeezed in on the first page. + // + + PICALL0(241, 77, 255, 94), // Digit 0 + PICALL0(225, 3, 240, 20), // 1 + PICALL0(225, 21, 240, 38), // 2 + PICALL0(225, 40, 240, 57), // 3 + PICALL0(240, 3, 256, 20), // 4 + PICALL0(241, 21, 255, 38), // 5 + PICALL0(241, 40, 255, 57), // 6 + PICALL0(226, 59, 240, 76), // 7 + PICALL0(241, 59, 255, 76), // 8, + PICALL0(226, 77, 240, 94), // 9 + + // + // On the second page. + // + + PICALL1( 3, 141, 170, 164), // Baseball bat + PICALL1( 11, 176, 44, 223), // The explosives + PICALL1(208, 187, 236, 214), // The grim reaper + PICALL1(190, 125, 221, 256), // The danger meter + + PICALL1(224, 108, 242, 172), // Bubble start + PICALL1(242, 108, 243, 172), // Bubble middle + PICALL1(243, 108, 256, 172), // Bubble end + + PICALL1(140, 197, 154, 211), // Dot + + PICALL1( 79, 225, 100, 252), // Clips for pistol, shotgun and AK47 + PICALL1(121, 227, 143, 252), + PICALL1(152, 225, 174, 250), + + PICALL1(205, 215, 254, 256), // Gearbox + PICALL1(178, 225, 199, 249), // Low gear + PICALL1(240, 182, 254, 205), // High gear + +}; + +#define PANEL_PAGE_NORMAL 0 +#define PANEL_PAGE_ALPHA 1 +#define PANEL_PAGE_ADDITIVE 2 +#define PANEL_PAGE_ALPHA_END 3 +#define PANEL_PAGE_NUMBER 4 + +UWORD PANEL_page[4][PANEL_PAGE_NUMBER] = +{ + { + POLY_PAGE_IC_NORMAL, + POLY_PAGE_IC_ALPHA, + POLY_PAGE_IC_ADDITIVE, + POLY_PAGE_IC_ALPHA_END + }, + + { + POLY_PAGE_IC2_NORMAL, + POLY_PAGE_IC2_ALPHA, + POLY_PAGE_IC2_ADDITIVE, + POLY_PAGE_IC2_ALPHA_END + } +}; + + + +void PANEL_funky_quad( + SLONG which, + SLONG x, + SLONG y, + SLONG panel_page, + ULONG colour, + float width = -1.0F, + float height = -1.0F) +{ + float left; + float top; + float right; + float bottom; + + SLONG page; + + ASSERT(WITHIN(which, 0, PANEL_IC_NUMBER - 1)); + ASSERT(WITHIN(panel_page, 0, PANEL_PAGE_NUMBER - 1)); + + PANEL_Ic *pi = &PANEL_ic[which]; + + page = PANEL_page[pi->page][panel_page]; + + if (which == PANEL_IC_SHOTGUN) + { + // + // The shotgun is on its side. + // + + left = float(x); + top = float(y); + + if (width == -1.0F) {width = (pi->v2 - pi->v1) * 256.0F;} + if (height == -1.0F) {height = (pi->u2 - pi->u1) * 256.0F;} + + right = left + width; + bottom = top + height; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + + + pp[0].X = left; + pp[0].Y = top; + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].u = pi->u2; + pp[0].v = pi->v1; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = right; + pp[1].Y = top; + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].u = pi->u2; + pp[1].v = pi->v2; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = left; + pp[2].Y = bottom; + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].u = pi->u1; + pp[2].v = pi->v1; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = right; + pp[3].Y = bottom; + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].u = pi->u1; + pp[3].v = pi->v2; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + else + { + left = float(x); + top = float(y); + + if (width == -1.0F) {width = (pi->u2 - pi->u1) * 256.0F;} + if (height == -1.0F) {height = (pi->v2 - pi->v1) * 256.0F;} + + right = left + width; + bottom = top + height; + + PANEL_draw_quad( + left, + top, + right, + bottom, + page, + colour, + pi->u1, + pi->v1, + pi->u2, + pi->v2); + } +} + + + +#ifdef PSX + +// +// The global base of the funky panel (useful for splitscreen mode) +// + +SLONG PANEL_funky_ybase; + +// +// Where to draw bits of the panel. +// + +#define PANEL_IC_BBX 30 +#define PANEL_IC_BBY (PANEL_funky_ybase - 110) + +#define PANEL_IC_PX 10 +#define PANEL_IC_PY (PANEL_funky_ybase - 135) + +#define PANEL_IC_GX 55 +#define PANEL_IC_GY (PANEL_funky_ybase - 67) + +#define PANEL_IC_AX 75 +#define PANEL_IC_AY (PANEL_funky_ybase - 30) + +#define PANEL_IC_MBX 50 +#define PANEL_IC_MBY (PANEL_funky_ybase - 100) + +#define PANEL_IC_SPLX 40 +#define PANEL_IC_SPLY (PANEL_funky_ybase - 124) + +#define PANEL_IC_DMX 600 +#define PANEL_IC_DMY (PANEL_funky_ybase - 40) + +#define PANEL_IC_MESX 140 +#define PANEL_IC_MESY (PANEL_funky_ybase - 124) + +#define PANEL_IC_CRX 320 +#define PANEL_IC_CRY 60 + +#define PANEL_IC_SCANX (PANEL_IC_BBX + 64) +#define PANEL_IC_SCANY (PANEL_IC_BBY + 25) + +#define PANEL_IC_BTX (PANEL_IC_BBX + 30) +#define PANEL_IC_BTY (PANEL_IC_BBY - 20) + +#define PANEL_IC_CLIPX 120 +#define PANEL_IC_CLIPY (PANEL_funky_ybase - 32) + +#define PANEL_IC_GBX (130) +#define PANEL_IC_GBY (PANEL_funky_ybase - 50) + +#endif + +// +// The funky hearbeat. A circular buffer. +// + +typedef struct +{ + float x; // Normalised from 0 to 1 + float y; // Normalised from -1 to 1 + ULONG colour; + +} PANEL_Beat; + +#define PANEL_NUM_BEATS 32 + +PANEL_Beat PANEL_beat[2][PANEL_NUM_BEATS]; +SLONG PANEL_beat_head[2]; +ULONG PANEL_beat_tick[2]; +SLONG PANEL_beat_last_ammo[2]; +SLONG PANEL_beat_last_specialtype[2]; +float PANEL_beat_x[2]; + + + +#if 0 + +// +// Processes and draws the heartbeat. Stamina goes from 0 to 1- where 1 means no +// stamina left... i.e. heart beating amazingly fast. +// + +void PANEL_do_heartbeat(SLONG which, float stamina, SLONG death) +{ + SLONG i; + SLONG b1; + SLONG b2; + + float amp; + float phase; + + ULONG beat_colour; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + PANEL_Beat *pb1; + PANEL_Beat *pb2; + + SLONG r; + SLONG g; + SLONG c1; + SLONG c2; + SLONG mul; + + // + // How fast the ticker sweeps across the display. + // + + float dx = 0.02F + stamina * 0.03F; + + // + // The amplitude of the two beats. + // + + float amp1 = 0.6F + stamina * 0.3F; + float amp2 = 0.3F + stamina * 0.5F; + + ULONG now = GetTickCount(); + + // + // Process the heatbeat 20 times a second. But no more than 4 times a + // gameturn. + // + + if (PANEL_beat_tick[which] < now - (1000 / 20) * 4) + { + PANEL_beat_tick[which] = now - (1000 / 20) * 4; + } + + // + // The colour fades from green to red depending on your health. + // + + if (stamina < 0.5F) + { + beat_colour = 0x00ff00; + } + else + if (stamina < 0.75F) + { + r = SLONG((stamina - 0.5F) * 255.0F / 0.25F); + + SATURATE(r, 0, 255); + + beat_colour = 0x00ff00 | (r << 16); + } + else + { + g = 255 - SLONG((stamina - 0.75f) * 255.0F / 0.25F); + + SATURATE(g, 0, 255); + + beat_colour = 0xff0000 | (g << 8); + } + + // + // Process the beats. + // + + while(PANEL_beat_tick[which] < now) + { + PANEL_beat_tick[which] += 1000 / 20; + PANEL_beat_head[which] += 1; + PANEL_beat_head[which] &= PANEL_NUM_BEATS - 1; + PANEL_beat_x[which] += dx; + + if (PANEL_beat_x[which] > 1.0F) + { + PANEL_beat_x[which] -= 1.0F; + } + + if (death) + { + // + // The next beat is a dead beat. FLATLINE + // + + PANEL_beat[which][PANEL_beat_head[which]].x = PANEL_beat_x[which]; + PANEL_beat[which][PANEL_beat_head[which]].y = 0; + PANEL_beat[which][PANEL_beat_head[which]].colour = 0xff0000; + } + else + { + // + // What is the amplitude here? + // + + if (WITHIN(PANEL_beat_x[which], 0.1F, 0.5F)) + { + amp = 1.0F + (float)sin((-PI * 0.5F) + (PANEL_beat_x[which] - 0.1F) * (2.0F * PI / 0.4F)); + amp *= 0.5F * amp1; + } + else + if (WITHIN(PANEL_beat_x[which], 0.6F, 0.9F)) + { + amp = 1.0F + (float)sin((-PI * 0.5F) + (PANEL_beat_x[which] - 0.6F) * (2.0F * PI / 0.3F)); + amp *= 0.5F * amp2; + } + else + { + amp = 0.00F; + } + + // + // How about phase? + // + + phase = PANEL_beat_x[which] * 30.0F; + + // + // The next beat. + // + + PANEL_beat[which][PANEL_beat_head[which]].x = PANEL_beat_x[which]; + PANEL_beat[which][PANEL_beat_head[which]].y = sin(phase) * amp; + PANEL_beat[which][PANEL_beat_head[which]].colour = beat_colour; + } + } + + // + // Set up the beat quad. + // + + pp[0].z = 0.0F; + pp[0].Z = 1.0F; + pp[0].u = 214.0F / 256.0F; + pp[0].v = 2.0F / 256.0F; + pp[0].specular = 0xff000000; + + pp[1].z = 0.0F; + pp[1].Z = 1.0F; + pp[1].u = 214.0F / 256.0F; + pp[1].v = 13.0F / 256.0F; + pp[1].specular = 0xff000000; + + pp[2].z = 0.0F; + pp[2].Z = 1.0F; + pp[2].u = 220.0F / 256.0F; + pp[2].v = 2.0F / 256.0F; + pp[2].specular = 0xff000000; + + pp[3].z = 0.0F; + pp[3].Z = 1.0F; + pp[3].u = 220.0F / 256.0F; + pp[3].v = 13.0F / 256.0F; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + // + // Draw the beats now. + // + + b1 = PANEL_beat_head[which]; + b2 = PANEL_beat_head[which] - 1; + + b1 &= PANEL_NUM_BEATS - 1; + b2 &= PANEL_NUM_BEATS - 1; + + // + // Mapping from beat space to screen space. + // + + #define PANEL_BEAT_SX(x) (PANEL_IC_BBX + 35 + (x) * 55.0F) + #define PANEL_BEAT_SY(y) (PANEL_IC_BBY + 23 + (y) * 15.0F) + + //#define PANEL_BEAT_SX(x) (PANEL_IC_BBX + 35 + (x) * 600.0F) + //#define PANEL_BEAT_SY(y) (PANEL_IC_BBY - 123 + (y) * 100.0F) + + for (i = 0; i < PANEL_NUM_BEATS - 1; i++) + { + pb1 = &PANEL_beat[which][b1]; + pb2 = &PANEL_beat[which][b2]; + + // + // Work out the colours of the beats... fading away. + // + + r = (pb1->colour >> 16) & 0xff; + g = (pb1->colour >> 8) & 0xff; + + mul = PANEL_NUM_BEATS - i; + + r = r * mul >> 5; + g = g * mul >> 5; + + c1 = (r << 16) | (g << 8); + + r = (pb2->colour >> 16) & 0xff; + g = (pb2->colour >> 8) & 0xff; + + mul = PANEL_NUM_BEATS - i - 1; + + if (mul <= 0) + { + c2 = 0; + } + else + { + r = r * mul >> 5; + g = g * mul >> 5; + + c2 = (r << 16) | (g << 8); + } + + if (pb1->x > pb2->x) + { + pp[0].X = PANEL_BEAT_SX(pb1->x); + pp[0].Y = PANEL_BEAT_SY(pb1->y) - 5.5F; + pp[0].colour = c1; + + pp[1].X = PANEL_BEAT_SX(pb1->x); + pp[1].Y = PANEL_BEAT_SY(pb1->y) + 5.5F; + pp[1].colour = c1; + + pp[2].X = PANEL_BEAT_SX(pb2->x); + pp[2].Y = PANEL_BEAT_SY(pb2->y) - 5.5F; + pp[2].colour = c2; + + pp[3].X = PANEL_BEAT_SX(pb2->x); + pp[3].Y = PANEL_BEAT_SY(pb2->y) + 5.5F; + pp[3].colour = c2; + + POLY_add_quad(quad, POLY_PAGE_IC_ADDITIVE, FALSE, TRUE); + } + + b1 -= 1; + b2 -= 1; + + b1 &= PANEL_NUM_BEATS - 1; + b2 &= PANEL_NUM_BEATS - 1; + } +} + +#endif + +// +// The different types of ammo. +// + +#define PANEL_AMMO_PISTOL 0 +#define PANEL_AMMO_SHOTGUN 1 +#define PANEL_AMMO_AK47 2 +#define PANEL_AMMO_GRENADE 3 +#define PANEL_AMMO_NUMBER 4 + +typedef struct +{ + float width; + float height; + SLONG size_group; + SLONG page_group; + SLONG page_one; + +} PANEL_Ammo; + +PANEL_Ammo PANEL_ammo[PANEL_AMMO_NUMBER] = +{ + { + 5.0F, + 9.0F, + 10, + PANEL_IC_PISTOL_AMMO_GROUP, + PANEL_IC_PISTOL_AMMO_ONE + }, + + { + 5.0F, + 12.0F, + 8, + PANEL_IC_SHOTGUN_AMMO_GROUP, + PANEL_IC_SHOTGUN_AMMO_ONE + }, + + { + 5.0F, + 12.0F, + 10, + PANEL_IC_AK47_AMMO_GROUP, + PANEL_IC_AK47_AMMO_ONE, + }, + + { + 12.0F, + 18.0F, + 3, + PANEL_IC_GRENADE_AMMO_GROUP, + PANEL_IC_GRENADE_AMMO_ONE + }, +}; + + + +// +// Ammo that has been used up getting tossed off the screen. +// + +typedef struct +{ + UWORD used; + UWORD type; + float x; + float y; + float angle; + float dx; + float dy; + +} PANEL_Toss; + +#define PANEL_MAX_TOSSES 8 + +PANEL_Toss PANEL_toss[PANEL_MAX_TOSSES]; +SLONG PANEL_toss_last; +ULONG PANEL_toss_tick; + + +// +// A floating point number between 0 and 1.0F +// + +static inline float frand(void) +{ + SLONG irand = rand(); + float ans = float(irand) * (1.0F / float(RAND_MAX)); + + return ans; +} + +// +// Creates a new toss. +// + +void PANEL_new_toss( + SLONG type, + float sx, + float sy) +{ + PANEL_Toss *pt; + PANEL_Ammo *pa; + + ASSERT(WITHIN(type, 0, PANEL_AMMO_NUMBER - 1)); + + PANEL_toss_last += 1; + PANEL_toss_last &= PANEL_MAX_TOSSES - 1; + + pt = &PANEL_toss[PANEL_toss_last]; + pa = &PANEL_ammo[type]; + + pt->used = TRUE; + pt->type = type; + pt->x = sx + pa->width * 0.5F; + pt->y = sy + pa->height * 0.5F; + pt->dx = 3.5F + frand(); + pt->dy = -5.0F - frand(); + pt->angle = 0.0F; +} + +// +// Processes and tosses and draws them. +// + +void PANEL_do_tosses(void) +{ + SLONG i; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + PANEL_Toss *pt; + + ULONG now = GetTickCount(); + + // + // Process 20 times a second but no more than 4 times a frame. + // + + if (PANEL_toss_tick < now - (1000 / 20) * 4) + { + PANEL_toss_tick = now - (1000 / 20) * 4; + } + + while(PANEL_toss_tick < now) + { + PANEL_toss_tick += 1000 / 20; + + for (i = 0; i < PANEL_MAX_TOSSES; i++) + { + pt = &PANEL_toss[i]; + + if (pt->used) + { + pt->x += pt->dx; + pt->y += pt->dy; + pt->angle += 0.8F; + pt->dx *= 0.9F; + pt->dy += 1.5F; + + if (pt->y > 490.0F) + { + pt->used = FALSE; + } + } + } + } + + // + // Set up the toss quad. + // + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].colour = 0xffffffff; + pp[0].specular = 0xff000000; + + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].colour = 0xffffffff; + pp[1].specular = 0xff000000; + + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].colour = 0xffffffff; + pp[2].specular = 0xff000000; + + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].colour = 0xffffffff; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + // + // Draw them. + // + + { + float ax; + float ay; + + float bx; + float by; + + SLONG page; + + PANEL_Ammo *pa; + + for (i = 0; i < PANEL_MAX_TOSSES; i++) + { + pt = &PANEL_toss[i]; + + if (pt->used) + { + ASSERT(WITHIN(pt->type, 0, PANEL_AMMO_NUMBER - 1)); + + pa = &PANEL_ammo[pt->type]; + + ax = (float)sin(pt->angle) * pa->height * 0.5F; + ay = (float)cos(pt->angle) * pa->height * 0.5F; + + bx = (float)sin(pt->angle + PI * 0.5F) * pa->width * 0.5F; + by = (float)cos(pt->angle + PI * 0.5F) * pa->width * 0.5F; + + pp[0].X = pt->x - bx - ax; + pp[0].Y = pt->y - by - ay; + pp[0].u = PANEL_ic[pa->page_one].u1; + pp[0].v = PANEL_ic[pa->page_one].v1; + + pp[1].X = pt->x + bx - ax; + pp[1].Y = pt->y + by - ay; + pp[1].u = PANEL_ic[pa->page_one].u2; + pp[1].v = PANEL_ic[pa->page_one].v1; + + pp[2].X = pt->x - bx + ax; + pp[2].Y = pt->y - by + ay; + pp[2].u = PANEL_ic[pa->page_one].u1; + pp[2].v = PANEL_ic[pa->page_one].v2; + + pp[3].X = pt->x + bx + ax; + pp[3].Y = pt->y + by + ay; + pp[3].u = PANEL_ic[pa->page_one].u2; + pp[3].v = PANEL_ic[pa->page_one].v2; + + page = PANEL_page[PANEL_ic[pa->page_one].page][PANEL_PAGE_ALPHA_END]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + } + } +} +extern UBYTE estate; + +// +// Draws a face at (x,y). The face is given by the Thing. NULL => Radio message. +// + +#define PANEL_FACE_LARGE 1 +#define PANEL_FACE_SMALL 2 + +void PANEL_new_face( + Thing *who, + float x, + float y, + SLONG size) +{ + SLONG face; + SLONG page; + float u; + float v; + float width; + float uvwidth; + + #define PANEL_FACE_RADIO 0 + #define PANEL_FACE_DARCI 1 + #define PANEL_FACE_ROPER 2 + #define PANEL_FACE_THUG_RASTA 3 + #define PANEL_FACE_THUG_GREY 4 + #define PANEL_FACE_THUG_RED 5 + #define PANEL_FACE_CIV_1 6 + #define PANEL_FACE_CIV_2 7 + #define PANEL_FACE_CIV_3 8 + #define PANEL_FACE_CIV_4 9 + #define PANEL_FACE_SLAG 10 + #define PANEL_FACE_FAT_SLAG 11 + #define PANEL_FACE_HOSTAGE 12 + #define PANEL_FACE_WORKMAN 13 + #define PANEL_FACE_BOSS_GOATIE 14 + #define PANEL_FACE_BOSS_SHAVEN 15 + #define PANEL_FACE_COP 16 + #define PANEL_FACE_COMMISSIONER 17 + #define PANEL_FACE_MIB 18 + #define PANEL_FACE_1920S_MAN 19 + #define PANEL_FACE_1920S_GIRL 20 + #define PANEL_FACE_TRAMP 21 + #define PANEL_FACE_NUMBER 22 + + // + // The position of the faces on each page given in 32 pixel steps. + // + + typedef struct + { + UBYTE page; + UBYTE u; + UBYTE v; + + } PANEL_Face; + + PANEL_Face face_large[PANEL_FACE_NUMBER] = + { + {0,4,4}, // Radio + {0,0,0}, // Darci + {0,2,0}, // Roper + {0,4,0}, // Thug rasta + {1,0,4}, // Thug grey + {0,4,2}, // Thug red + {0,6,2}, // Civ1 + {0,6,4}, // Civ2 + {0,4,6}, // Civ3 + {0,6,6}, // Civ4 + {0,0,6}, // Slag + {0,2,6}, // Fat ugly slag + {0,2,4}, // Hostage + {1,2,4}, // Workman, + {0,6,0}, // Boss with a goatie + {0,6,0}, // Boss with no goatie + {0,0,4}, // Cop + {0,6,0}, // Commissioner + {0,0,2}, // MIB + {1,2,6}, // 1920s man + {1,4,6}, // 1920s girl + {1,0,6}, // Tramp + }; + + PANEL_Face face_small[PANEL_FACE_NUMBER] = + { + {1,2,2}, // Radio + {1,0,0}, // Darci + {1,1,0}, // Roper + {1,2,0}, // Thug rasta + {1,4,0}, // Thug grey + {1,2,1}, // Thug red + {1,3,1}, // Civ1 + {1,3,2}, // Civ2 + {1,2,3}, // Civ3 + {1,3,3}, // Civ4 + {1,0,3}, // Slag + {1,1,3}, // Fat ugly slag + {1,1,2}, // Hostage + {1,5,0}, // Workman, + {1,3,0}, // Boss with a goatee + {1,3,0}, // Boss with no goatee + {1,0,2}, // Cop + {1,0,3}, // Commissioner + {1,0,1}, // MIB + {1,6,0}, // 1920s man + {1,7,0}, // 1920s girl + {1,4,1}, // Tramp + }; + + if (who == NULL || who->Class != CLASS_PERSON) + { + face = PANEL_FACE_RADIO; + } + else + { + switch(who->Genus.Person->PersonType) + { + case PERSON_DARCI: + face = PANEL_FACE_DARCI; + break; + + case PERSON_ROPER: + face = PANEL_FACE_ROPER; + break; + + case PERSON_COP: + face = PANEL_FACE_COP; + break; + + case PERSON_CIV: + + switch(who->Draw.Tweened->MeshID) + { + case 7: + + // + // Normal (i.e. non-wandering) civs. + // + + switch(who->Draw.Tweened->PersonID - 6) + { + case 0: + + // + // Pinhead. + // + + face = PANEL_FACE_CIV_3; + + break; + + case 2: + + // + // Oriental chap. + // + + face = PANEL_FACE_CIV_4; + + break; + + case 1: + case 3: + + // + // Black bloke with moustache. + // + + face = PANEL_FACE_CIV_1; + + break; + + default: + ASSERT(0); + break; + } + + break; + + case 8: + + // + // Male fake wandering civ. + // + + face = PANEL_FACE_1920S_MAN; + + break; + + case 9: + + // + // Female fake wandering civ. + // + + face = PANEL_FACE_1920S_GIRL; + + break; + + default: + ASSERT(0); + break; + } + break; + + case PERSON_THUG_RASTA: + face = PANEL_FACE_THUG_RASTA; + break; + + case PERSON_THUG_GREY: + face = PANEL_FACE_THUG_GREY; + break; + + case PERSON_THUG_RED: + face = PANEL_FACE_THUG_RED; + break; + + case PERSON_SLAG_TART: + face = PANEL_FACE_SLAG; + break; + + case PERSON_SLAG_FATUGLY: + face = PANEL_FACE_FAT_SLAG; + break; + + case PERSON_HOSTAGE: + face = PANEL_FACE_HOSTAGE; + break; + + case PERSON_MECHANIC: + face = PANEL_FACE_WORKMAN; + break; + + case PERSON_TRAMP: + if(estate) + { + face = PANEL_FACE_BOSS_GOATIE; + } + else + { + face = PANEL_FACE_TRAMP; + + } + break; + + case PERSON_MIB1: + case PERSON_MIB2: + case PERSON_MIB3: + face = PANEL_FACE_MIB; //I'm in disguise as a fat slag + break; + + default: + ASSERT(0); + break; + } + } + + ASSERT(WITHIN(face, 0, PANEL_FACE_NUMBER - 1)); + + PANEL_Face *pf; + + switch(size) + { + case PANEL_FACE_LARGE: + pf = &face_large[face]; + width = 64; + uvwidth = 64 / 256.0F; + break; + + case PANEL_FACE_SMALL: + pf = &face_small[face]; + width = 32; + uvwidth = 32 / 256.0F; + break; + + default: + ASSERT(0); + break; + } + + u = float(pf->u) * (32.0F / 256.0F); + v = float(pf->v) * (32.0F / 256.0F); + page = (pf->page) ? POLY_PAGE_FACE2 : POLY_PAGE_FACE1; + + PANEL_draw_quad( + x, + y, + x + width, + y + width, + page, + 0xffffffff, + u, + v, + u + uvwidth, + v + uvwidth); +} + + +// +// A circular queue of text messages. +// + +// The French actually has a 257-character message. Grrrr. +#define PANEL_TEXT_MAX_LENGTH 300 +typedef struct +{ + Thing *who; // Who is saying the message. NULL => computer message + CBYTE text[PANEL_TEXT_MAX_LENGTH+2]; + SLONG delay; // 0 => unused. + SLONG turns; // The number of turns this message has been alive for. + +} PANEL_Text; + +#define PANEL_MAX_TEXTS 8 // Power of 2 please! + +PANEL_Text PANEL_text[PANEL_MAX_TEXTS]; +SLONG PANEL_text_head; // Always acces PANEL_text[PANEL_text_head & (PANEL_MAX_TEXTS - 1)] +SLONG PANEL_text_tail; // Always acces PANEL_text[PANEL_text_tail & (PANEL_MAX_TEXTS - 1)] +ULONG PANEL_text_tick; + + +void PANEL_new_text_init(void) +{ + memset(PANEL_text, 0, sizeof(PANEL_text)); + + PANEL_text_head = 0; + PANEL_text_tail = 0; + PANEL_text_tick = 0; +} + + + +void PANEL_new_text(Thing *who, SLONG delay, CBYTE *fmt, ...) +{ + CBYTE *ch; + + PANEL_Text *pt; + + // + // Early out on NULL strings or strings with just spaces in them. + // + + if (fmt == NULL) + { + return; + } + + for (ch = fmt; *ch; ch++) + { + if (!isspace(*ch)) + { + goto found_non_white_space; + } + } + + return; + + found_non_white_space:; + + // + // Work out the real message. + // + + CBYTE message[1024]; + va_list ap; + + va_start(ap, fmt); + vsprintf(message, fmt, ap); + va_end (ap); + + // + // Make sure the message isn't too long. + // + + if (strlen(message) >= PANEL_TEXT_MAX_LENGTH) + { + ASSERT(0); + + // + // strlen doesn't include the NULL byte. + // + + return; + } + + /* + + // + // Convert to uppercase. + // + + for (ch = message; *ch; *ch++ = toupper(*ch)); + + */ + + // + // Do we already have this message? + // + + SLONG i; + + for (i = 0; i < PANEL_MAX_TEXTS; i++) + { + pt = &PANEL_text[i]; + + if (pt->delay) + { + if (pt->who == who) + { + if (strcmp(pt->text, message) == 0) + { + // + // Don't put up the same message twice. + // + + pt->delay = delay; + + return; + } + } + } + } + + + // + // Create a new message at the tail of the queue. + // + + pt = &PANEL_text[PANEL_text_tail & (PANEL_MAX_TEXTS - 1)]; + + pt->who = who; + pt->delay = delay; + pt->turns = 0; + + strcpy(pt->text, message); + + // + // Process the message so we put in vertical '|'s + // + + PANEL_text_tail += 1; + + if (!who) MFX_play_ambient(0,S_RADIO_MESSAGE,0); + +} + +void PANEL_new_text_process() +{ + SLONG i; + + PANEL_Text *pt; + + ULONG now = GetTickCount(); + + // + // Process 20 times a second but no more than 4 times a frame. + // + + if (PANEL_text_tick < now - (1000 / 10) * 4) + { + PANEL_text_tick = (now - (1000 / 10) * 4); + } + + while(PANEL_text_tick < now) + { + PANEL_text_tick += 1000 / 10; + + for (i = 0; i < PANEL_MAX_TEXTS; i++) + { + pt = &PANEL_text[i]; + + if (pt->delay) + { + pt->delay -= 1000 / 10; + + if (pt->delay < 0) + { + pt->delay = 0; + } + } + } + } + + for (i = 0; i < PANEL_MAX_TEXTS; i++) + { + pt = &PANEL_text[i]; + + pt->turns += 1; + } +} + +#ifdef PSX +void PANEL_new_text_draw() +{ + SLONG i; + SLONG ybase; + SLONG y = PANEL_IC_MESY; + SLONG height; + + PANEL_Text *pt; + + for (i = PANEL_text_head; i < PANEL_text_tail; i++) + { + pt = &PANEL_text[i & (PANEL_MAX_TEXTS - 1)]; + + if (i == PANEL_text_head) + { + if (pt->delay == 0) + { + PANEL_text_head += 1; + } + } + + if (pt->delay != 0) + { + // + // Draw this message. Start off with the face. + // + + ybase = y; + + PANEL_new_face( + pt->who, + PANEL_IC_MESX, + ybase - 3, + PANEL_FACE_SMALL); + + /* + + PANEL_funky_quad( + pt->face, + PANEL_IC_MESX, + ybase - 3, + PANEL_PAGE_NORMAL, + 0xffffff); + + */ + + // + // The text.... + // + + height = FONT2D_DrawStringWrap(pt->text, PANEL_IC_MESX + 36 + 18, y, 0x00ff00) - y; + height += 25; + + // + // The speech bubble. + // + + PANEL_funky_quad( + PANEL_IC_BUBBLE_START, + PANEL_IC_MESX + 36, + ybase - 3, + PANEL_PAGE_ALPHA, + 0xffffffff, + 18.0F, + height); + + PANEL_funky_quad( + PANEL_IC_BUBBLE_MIDDLE, + PANEL_IC_MESX + 36 + 18, + ybase - 3, + PANEL_PAGE_ALPHA, + 0xffffffff, + float(FONT2D_rightmost_x) - (PANEL_IC_MESX + 36 + 18), + height); + + PANEL_funky_quad( + PANEL_IC_BUBBLE_END, + float(FONT2D_rightmost_x), + ybase - 3, + PANEL_PAGE_ALPHA, + 0xffffffff, + -1.0F, + height); + + if (height < 34) + { + height = 34; + } + + y += height; + } + } +} +#endif + + +// +// The help message. +// + + +CBYTE PANEL_help_message[256]; +SLONG PANEL_help_timer; + +void PANEL_new_help_message(CBYTE *fmt, ...) +{ + // + // Work out the real message. + // + + va_list ap; + + va_start(ap, fmt); + vsprintf(PANEL_help_message, fmt, ap); + va_end (ap); + + // + // How long the message lasts for. + // + + PANEL_help_timer = 160 * 20 * 5; // 5 seconds.... +} + +void PANEL_help_message_do() +{ + PANEL_help_timer -= 160 * TICK_RATIO >> TICK_SHIFT; + + if (PANEL_help_timer <= 0) + { + PANEL_help_timer = 0; + } + else + { + // + // Draw the help text in a speech bubble at the top of the screen. + // + + SLONG height; + + #define PANEL_IC_HELPX 10 + #define PANEL_IC_HELPY 10 + + height = FONT2D_DrawStringWrap(PANEL_help_message, PANEL_IC_HELPX + 18, PANEL_IC_HELPY, 0x00ff00) - PANEL_IC_HELPY; + height += 25; + + // + // The speech bubble. + // + + PANEL_funky_quad( + PANEL_IC_BUBBLE_START, + PANEL_IC_HELPX, + PANEL_IC_HELPY - 3, + PANEL_PAGE_ALPHA, + 0xffffffff, + 18.0F, + height); + + PANEL_funky_quad( + PANEL_IC_BUBBLE_MIDDLE, + PANEL_IC_HELPX + 18, + PANEL_IC_HELPY - 3, + PANEL_PAGE_ALPHA, + 0xffffffff, + float(FONT2D_rightmost_x) - (PANEL_IC_HELPX + 18), + height); + + PANEL_funky_quad( + PANEL_IC_BUBBLE_END, + float(FONT2D_rightmost_x), + PANEL_IC_HELPY - 3, + PANEL_PAGE_ALPHA, + 0xffffffff, + -1.0F, + height); + } +} + + + + +// +// The panel in widscreen cut-scene mode. +// + +THING_INDEX PANEL_wide_top_person; +THING_INDEX PANEL_wide_bot_person; +SLONG PANEL_wide_top_is_talking; // TRUE/FALSE for who is talking now +CBYTE PANEL_wide_text[256]; + +void PANEL_new_widescreen() +{ + // + // We have to stop the clipping getting rid of whatever we are doing! + // + + extern float POLY_screen_clip_top; + extern float POLY_screen_clip_bottom; + + POLY_screen_clip_top = 0.0F; + POLY_screen_clip_bottom = float(DisplayHeight); + + // + // Clear the widescreen borders to black. + // + + PANEL_draw_quad( + 0.0F, + 0.0F, + float(DisplayWidth), + 80.0F, + POLY_PAGE_COLOUR, + 0x00000000); + + PANEL_draw_quad( + 0.0F, + float(DisplayHeight) - 80.0F, + float(DisplayWidth), + float(DisplayHeight), + POLY_PAGE_COLOUR, + 0x00000000); + + // + // Who is talking? + // + + if (EWAY_conversation_happening( + &PANEL_wide_top_person, + &PANEL_wide_bot_person)) + { + // + // Sort in thing number order! + // + + if (PANEL_wide_top_person > PANEL_wide_bot_person) + { + SWAP(PANEL_wide_top_person, PANEL_wide_bot_person); + } + } + + // + // Steal new_text messages! + // + + SLONG i; + + PANEL_Text *pt; + + for (i = 0; i < PANEL_MAX_TEXTS; i++) + { + pt = &PANEL_text[i]; + + if (pt->delay && pt->turns <= 1) + { + if (pt->who == NULL) + { + // + // This is a message that goes on the bottom. + // + + strcpy(PANEL_wide_text, pt->text); + + PANEL_wide_top_is_talking = FALSE; + + pt->delay = 0; + } + else + { + if (THING_NUMBER(pt->who) == PANEL_wide_top_person) + { + // + // This is a message that goes on the top. + // + + strcpy(PANEL_wide_text, pt->text); + + PANEL_wide_top_is_talking = TRUE; + + pt->delay = 0; + } + else + { + // + // This is a message that goes on the bottom. + // + + strcpy(PANEL_wide_text, pt->text); + + PANEL_wide_top_is_talking = FALSE; + PANEL_wide_bot_person = THING_NUMBER(pt->who); + + pt->delay = 0; + } + } + } + } + + // + // Draw the two faces. + // + + if (PANEL_wide_top_person != NULL) + { + PANEL_new_face( + TO_THING(PANEL_wide_top_person), + float(DisplayWidth) - 72.0F, + 8.0F, + PANEL_FACE_LARGE); + } + + // + // Draw the text for who is speaking. + // + + if (PANEL_wide_text[0]) + { + PANEL_new_face( + (PANEL_wide_bot_person) ? TO_THING(PANEL_wide_bot_person) : NULL, + 8.0F, + float(DisplayHeight) - 72.0F, + PANEL_FACE_LARGE); + + if (PANEL_wide_top_is_talking) + { + // Need to move this down so the bottom line is on the bottom of the black bit. + // This keeps the first line out of the 32-pixel "danger zone" that may not be + // shown on crap TV. + + SLONG iYpos = FONT2D_DrawStringRightJustify( + PANEL_wide_text, + DisplayWidth - 80, + 0, + 0xff0ffff, + 256, + POLY_PAGE_FONT2D, + 0, + TRUE); + iYpos = 75 - iYpos; + FONT2D_DrawStringRightJustify( + PANEL_wide_text, + DisplayWidth - 80, + iYpos, + 0xff0ffff, + 256, + POLY_PAGE_FONT2D, + 0, + FALSE); + } + else + { + FONT2D_DrawStringWrap( + PANEL_wide_text, + 80, + DisplayHeight - 80 + 5, + 0xffffff); + } + } +} + +#define PANEL_MAX_BEACON_COLOURS 12 + +ULONG PANEL_beacon_colour[PANEL_MAX_BEACON_COLOURS] = +{ + 0xffff00, + 0xccff00, + 0x4488ff, + 0xff0000, + 0x00ff00, + 0x0000ff, + 0xff4400, + 0xffffff, + 0xff00ff, + 0xaaffaa, + 0x00ffff, + 0xff4488 +}; + + + +#ifdef PSX + +// +// Draws the map beacons... +// + +void PANEL_draw_beacons(void) +{ + SLONG i; + + float dx; + float dz; + float dist; + float dangle; + float score; + + float ax; + float ay; + + float bx; + float by; + + float cx; + float cy; + + POLY_Point pp [3]; + POLY_Point *tri[3]; + + MAP_Beacon *mb; + + ULONG colour; + + Thing *darci = NET_PERSON(0); + + SLONG best_beacon = NULL; + float best_score = float(INFINITY); + + for (i = 1; i < MAP_MAX_BEACONS; i++) + { + mb = &MAP_beacon[i]; + + if (!mb->used) + { + continue; + } + + if (mb->track_thing) + { + Thing *p_track = TO_THING(mb->track_thing); + + mb->wx = p_track->WorldPos.X >> 8; + mb->wz = p_track->WorldPos.Z >> 8; + + extern SLONG is_person_dead(Thing *p_person); + + if (p_track->Class == CLASS_PERSON && p_track->State == STATE_DEAD) + { + // + // Don't draw beacons to dead people. + // + + if (p_track->SubState == SUB_STATE_DEAD_INJURED) + { + // + // Except if they're only injured... + // + } + else + { + continue; + } + } + } + + colour = PANEL_beacon_colour[i % PANEL_MAX_BEACON_COLOURS] | (0xff000000); + + // + // Work out the distance and relative angle of this beacon from darci. + // + + dx = float(mb->wx - (darci->WorldPos.X >> 8)); + dz = float(mb->wz - (darci->WorldPos.Z >> 8)); + + dist = fabs(dx) + fabs(dz); + + if (dist < 256.0F * 4.0F) + { + score = dist * (1.0F / (256.0F * 4.0F)); + score *= 2.0F * PI * 22.0F / 360.0F; + + PANEL_funky_quad( + PANEL_IC_DOT, + PANEL_IC_SCANX - 7.0F, + PANEL_IC_SCANY - 7.0F, + PANEL_PAGE_ALPHA_END, + colour); + } + else + { + if (PANEL_scanner_poo) + dangle = (float)atan2(dx,dz) - float(darci->Draw.Tweened->Angle) * (2.0F * PI / 2048.0F); + else + dangle = (float)atan2(dx,dz) - float(FC_cam[0].yaw>>8) * (2.0F * PI / 2048.0F); + score = (float)fmod(dangle, 2.0F * PI) - PI; + + if (score > +PI) {score -= 2.0F * PI;} + if (score < -PI) {score += 2.0F * PI;} + + // + // The arrow positions... + // + + ax = (float)sin(dangle - 0.5F) * 33.0F * 1.5F; + ay = (float)cos(dangle - 0.5F) * 20.0F * 1.5F; + + bx = (float)sin(dangle + 0.5F) * 33.0F * 1.5F; + by = (float)cos(dangle + 0.5F) * 20.0F * 1.5F; + + cx = (float)sin(dangle) * 33.0F * -0.25F; + cy = (float)cos(dangle) * 20.0F * -0.25F; + + // + // Draw an arrow in this direction. + // + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + + pp[0].X = PANEL_IC_SCANX + cx; + pp[0].Y = PANEL_IC_SCANY + cy; + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].u = 134.0F / 256.0F; + pp[0].v = 189.0F / 256.0F; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = PANEL_IC_SCANX + ax; + pp[1].Y = PANEL_IC_SCANY + ay; + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].u = 153.0F / 256.0F; + pp[1].v = 180.0F / 256.0F; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = PANEL_IC_SCANX + bx; + pp[2].Y = PANEL_IC_SCANY + by; + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].u = 153.0F / 256.0F; + pp[2].v = 198.0F / 256.0F; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + POLY_add_triangle(tri, POLY_PAGE_IC2_ALPHA_END, FALSE, TRUE); + } + + if (fabs(score) < best_score) + { + best_score = fabs(score); + best_beacon = i; + } + } + + if (best_beacon) + { + ASSERT(WITHIN(best_beacon, 1, MAP_MAX_BEACONS - 1)); + + mb = &MAP_beacon[best_beacon]; + + extern CBYTE *EWAY_get_mess(SLONG index); + + FONT2D_DrawString( + EWAY_get_mess(mb->index), + PANEL_IC_BTX + 2, + PANEL_IC_BTY + 2, + 0x00000000, + 192); + + FONT2D_DrawString( + EWAY_get_mess(mb->index), + PANEL_IC_BTX, + PANEL_IC_BTY, + PANEL_beacon_colour[best_beacon % PANEL_MAX_BEACON_COLOURS], + 192); + + } +} + +#endif + + +#define PANEL_WHO_DARCI 0 +#define PANEL_WHO_ROPER 1 + +#ifdef PSX +void PANEL_new_funky_do(SLONG which, SLONG where) +{ + if (EWAY_stop_player_moving()) + { + // + // There is a widescreen cutscene playing. + // + + PANEL_new_widescreen(); + + return; + } + else + { + PANEL_wide_top_person = NULL; + PANEL_wide_bot_person = NULL; + PANEL_wide_top_is_talking = FALSE; + PANEL_wide_text[0] = '\000'; + } + + SLONG i; + + ULONG health_colour; + SLONG which_gun; + SLONG which_ammo; + SLONG which_dx = 0; + SLONG which_dy = 0; + SLONG clip_which = 0; + SLONG clip_number = 0; + + SLONG who; // One of PANEL_WHO_* + SLONG health; // From 0 to 256 + SLONG stamina; // From 0 to 256 + SLONG specialtype; // The gun in use or NULL if not using a special, + SLONG ammo; // The amount of ammo used by the gun + + ASSERT(WITHIN(which, 0, 1)); + + Thing *darci = NET_PERSON(which); + Thing *player = NET_PLAYER(which); + Thing *p_special; + + if (darci->Genus.Person->SpecialUse) + { + p_special = TO_THING(darci->Genus.Person->SpecialUse); + + specialtype = p_special->Genus.Special->SpecialType; + ammo = p_special->Genus.Special->ammo; + } + else + { + specialtype = NULL; + ammo = 0; + } + + if (darci->Genus.Person->Flags & FLAG_PERSON_GUN_OUT) + { + specialtype = SPECIAL_GUN; + ammo = darci->Genus.Person->Ammo; + } + + who = (darci->Genus.Person->PersonType == PERSON_ROPER) ? PANEL_WHO_ROPER : PANEL_WHO_DARCI; + health = darci->Genus.Person->Health; + stamina = darci->Genus.Person->Stamina; + + // + // Set where the bottom of the panel should be. + // + + PANEL_funky_ybase = (where & 1) ? (DisplayHeight >> 1) : DisplayHeight; + + // + // The background and the character. + // + + PANEL_funky_quad( + PANEL_IC_BACKBOX, + PANEL_IC_BBX, + PANEL_IC_BBY, + PANEL_PAGE_NORMAL, + 0xffffffff); + + PANEL_funky_quad( + (who == PANEL_WHO_DARCI) ? PANEL_IC_DARCI : PANEL_IC_ROPER, + PANEL_IC_PX, + PANEL_IC_PY, + PANEL_PAGE_ALPHA, + 0xffffffff); + + // + // The colour we draw the health outline. + // + + { + SLONG r = 0; + SLONG g = 0; + SLONG b = 0; + + if (health > 133) + { + r = 255 - ((health - 133) * 255) / 67; + g = 255; + } + else + if (health < 66) + { + r = 100 + (health * 155) / 66; + g = 0; + } + else + { + r = 255; + g = ((health - 66) * 255) / 66; + } + + SATURATE(r, 0, 255); + SATURATE(g, 0, 255); + + health_colour = (r << 16) | (g << 8) | 0x10; // A little bit of blue... + } + + PANEL_funky_quad( + (who == PANEL_WHO_DARCI) ? PANEL_IC_DARCI_OUTLINE : PANEL_IC_ROPER_OUTLINE, + PANEL_IC_PX - 6, + PANEL_IC_PY - 3, + PANEL_PAGE_ADDITIVE, + health_colour); + + #if WEVE_REPLACED_THE_HEARTBEAT_WITH_A_SCANNER + + // + // No heart beat any more :( + // + + PANEL_do_heartbeat(which, 1.0F - float(stamina) * (1.0F / 256.0F), darci->State == STATE_DEAD); + + #endif + + // + // If the player is holding a grenade that has had its pin pulled then + // show how long the grenade has before it goes off. + // + + { + Thing *p_special; + + if (darci->Genus.Person->SpecialUse) + { + p_special = TO_THING(darci->Genus.Person->SpecialUse); + + if (p_special->Genus.Special->SpecialType == SPECIAL_GRENADE && + p_special->SubState == SPECIAL_SUBSTATE_ACTIVATED) + { + // + // Alert! The player is holding a primed grenade! + // + + ULONG colour; + SLONG secsleft; + + + secsleft = p_special->Genus.Special->timer / (16 * 20) + 1; + + if (secsleft > 6) + { + secsleft = 6; + } + + switch(secsleft) + { + case 0: + case 1: + colour = 0xff3300; + break; + + case 2: + colour = 0xff8800; + break; + + case 3: + colour = 0x88ff00; + break; + + default: + colour = 0x00ff00; + break; + } + + PANEL_funky_quad( + PANEL_IC_DIGIT_0 + secsleft, + PANEL_IC_MBX, + PANEL_IC_MBY, + PANEL_PAGE_ADDITIVE, + colour); + } + } + } + + // + // Which gun shall we draw. + // + + switch(specialtype) + { + default: + + if (who == PANEL_WHO_DARCI) + { + which_gun = PANEL_IC_DARCI_HAND; + } + else + { + which_gun = PANEL_IC_ROPER_HAND; + } + + which_ammo = -1; + + break; + + case SPECIAL_GUN: + which_gun = PANEL_IC_PISTOL; + which_ammo = PANEL_AMMO_PISTOL; + clip_which = PANEL_IC_CLIP_PISTOL; + clip_number = darci->Genus.Person->ammo_packs_pistol; + break; + + case SPECIAL_AK47: + which_gun = PANEL_IC_AK47; + which_ammo = PANEL_AMMO_AK47; + which_dx = -45; + clip_which = PANEL_IC_CLIP_AK47; + clip_number = darci->Genus.Person->ammo_packs_ak47; + break; + + case SPECIAL_BASEBALLBAT: + which_gun = PANEL_IC_BASEBALLBAT; + which_ammo = -1; + which_dx = -50; + break; + + case SPECIAL_KNIFE: + which_gun = PANEL_IC_KNIFE; + which_ammo = -1; + which_dy = 15; + break; + + case SPECIAL_SHOTGUN: + which_gun = PANEL_IC_SHOTGUN; + which_ammo = PANEL_AMMO_SHOTGUN; + which_dx = -35; + which_dy = 10; + clip_which = PANEL_IC_CLIP_SHOTGUN; + clip_number = darci->Genus.Person->ammo_packs_shotgun; + break; + + case SPECIAL_GRENADE: + which_gun = PANEL_IC_GRENADE; + which_ammo = PANEL_AMMO_GRENADE; + break; + + case SPECIAL_EXPLOSIVES: + which_gun = PANEL_IC_EXPLOSIVES; + which_ammo = PANEL_AMMO_GRENADE; + break; + } + + PANEL_funky_quad( + which_gun, + PANEL_IC_GX + which_dx, + PANEL_IC_GY + which_dy, + PANEL_PAGE_ALPHA_END, + 0xffffffff); + + if (which_ammo == -1) + { + // + // This weapon has no ammo. + // + } + else + { + SLONG ax = PANEL_IC_AX; + SLONG ay = PANEL_IC_AY; + + ASSERT(WITHIN(which_ammo, 0, PANEL_AMMO_NUMBER - 1)); + + PANEL_Ammo *pa = &PANEL_ammo[which_ammo]; + + while(ammo >= pa->size_group) + { + PANEL_funky_quad( + pa->page_group, + ax, + ay, + PANEL_PAGE_ALPHA_END, + 0xffffffff); + + ax += 2; + ay += 7; + + ammo -= pa->size_group; + } + + for (i = 0; i < ammo; i++) + { + PANEL_funky_quad( + pa->page_one, + ax, + ay, + PANEL_PAGE_ALPHA_END, + 0xffffffff); + + ax += pa->width; + } + + if (PANEL_beat_last_specialtype[which] == specialtype && PANEL_beat_last_ammo[which] > ammo) + { + while(i < PANEL_beat_last_ammo[which]) + { + PANEL_new_toss( + which_ammo, + float(ax), + float(ay)); + + ax += pa->width; + + if (i % pa->size_group == 0) + { + ax -= pa->width * pa->size_group - 2; + ay += 7; + } + else + { + } + + i += 1; + } + } + } + + + if (clip_number) + { + PANEL_funky_quad( + clip_which, + PANEL_IC_CLIPX, + PANEL_IC_CLIPY, + PANEL_PAGE_ALPHA_END, + 0xffffffff); + + { + CBYTE text[16]; + + sprintf(text, "x%d", clip_number); + +extern void FONT2D_DrawString_NoTrueType(CBYTE*str, SLONG x, SLONG y, ULONG rgb, SLONG scale, SLONG page, SWORD fade); + + FONT2D_DrawString_NoTrueType( + text, + PANEL_IC_CLIPX + 20, + PANEL_IC_CLIPY + 4, + 0x00ff00, + 256, + POLY_PAGE_FONT2D, + 0); + } + } + +// skip_the_gun_and_ammo:; + + PANEL_do_tosses(); + + PANEL_beat_last_specialtype[which] = specialtype; + PANEL_beat_last_ammo[which] = ammo; + + // + // The grimreapers for the number of civs you've killed. + // + + { + float x; + + x = PANEL_IC_SPLX; + + for (i = 0; i < player->Genus.Player->RedMarks; i++) + { + PANEL_funky_quad( + PANEL_IC_GRIMREAPER, + x, + PANEL_IC_SPLY, + PANEL_PAGE_ALPHA_END, + 0xffffffff); + + x += 20.0F; + + if (i == 4) + { + x += 12.0F; + } + } + } + + // + // The danger meter. + // + + { + ULONG danger_colour; + + switch(player->Genus.Player->Danger) + { + case 0: + goto no_danger_meter; + + case 1: danger_colour = 0xffff0000; break; + case 2: danger_colour = 0xffffdd00; break; + case 3: danger_colour = 0xff00dd00; break; + + default: + break; + } + + PANEL_funky_quad( + PANEL_IC_DANGERMETER, + PANEL_IC_DMX, + PANEL_IC_DMY, + PANEL_PAGE_ALPHA, + danger_colour); + } + + no_danger_meter:; + + // + // The crime rate. + // + + if (GAME_FLAGS & GF_SHOW_CRIMERATE) + { + CBYTE crimerate[128]; + + sprintf(crimerate, "%d%% ", CRIME_RATE); + + FONT2D_DrawStringCentred( + crimerate, + PANEL_IC_CRX, + PANEL_IC_CRY, + 0x00ff00); + + FONT2D_DrawStringCentred( + XLAT_str(X_CRIME_RATE,crimerate), + PANEL_IC_CRX, + PANEL_IC_CRY - 20, + 0x00ff00); + } + + // + // The text. + // + + PANEL_new_text_process(); + PANEL_new_text_draw(); + PANEL_help_message_do(); + + if (darci->Genus.Person->Flags & FLAG_PERSON_DRIVING) + { + // + // Draw the gear you are in. + // + + Thing *p_vehicle = TO_THING(darci->Genus.Person->InCar); + + PANEL_funky_quad( + PANEL_IC_GEAR_BOX, + PANEL_IC_GBX, + PANEL_IC_GBY, + PANEL_PAGE_ALPHA, + 0xffffffff); + + if (p_vehicle->Genus.Vehicle->Siren) + { + // + // High gear. + // + + PANEL_funky_quad( + PANEL_IC_GEAR_HIGH, + PANEL_IC_GBX + 25 - 3, + PANEL_IC_GBY + 18 - 21, + PANEL_PAGE_ALPHA_END, + 0xffffffff); + } + else + { + // + // Low gear. + // + + PANEL_funky_quad( + PANEL_IC_GEAR_LOW, + PANEL_IC_GBX + 25 - 17, + PANEL_IC_GBY + 18 - 20, + PANEL_PAGE_ALPHA_END, + 0xffffffff); + } + } + + // + // The on-screen map beacons. + // + + PANEL_draw_beacons(); +} + +void PANEL_new_funky() +{ + // + // We have to stop the clipping getting rid of whatever we are doing! + // + + extern float POLY_screen_clip_top; + extern float POLY_screen_clip_bottom; + + POLY_screen_clip_top = 0.0F; + POLY_screen_clip_bottom = float(DisplayHeight); + + if (FC_cam[1].focus) + { + // + // We are in splitscreen mode. + // + + PANEL_new_funky_do(0,1); +// PANEL_new_funky_do(1,0); + } + else + { + // + // One player mode. + // + + PANEL_new_funky_do(0,0); + } +} +#endif //#ifdef PSX + + +void PANEL_start(void) +{ +#ifndef TARGET_DC + POLY_frame_init(FALSE, FALSE); +#endif +} + +void PANEL_finish(void) +{ +#ifndef TARGET_DC + POLY_frame_draw(TRUE,TRUE); +#endif +} + + +// ======================================================== +// +// FADEOUT STUFF +// +// ======================================================== + +SLONG PANEL_fadeout_time; // 0 => No fadeout currently active. + + +void PANEL_fadeout_init() +{ + PANEL_fadeout_time = 0; +} + +void PANEL_fadeout_start() +{ + if (!PANEL_fadeout_time) + { + PANEL_fadeout_time = GetTickCount(); + } +} + +float angle_mul = 0.004F; +float zoom_mul = 0.500F; + +void PANEL_fadeout_draw() +{ + if (PANEL_fadeout_time) + { +#ifndef TARGET_DC + POLY_frame_init(FALSE,FALSE); +#endif + + // + // Make the fadeout zoom in and turn. + // + + float angle = float(GetTickCount() - PANEL_fadeout_time) * angle_mul; + float zoom = angle * zoom_mul; + + float xdu = -(float)cos(angle) * zoom * 1.33F; + float xdv = (float)sin(angle) * zoom * 1.33F; + + float ydu = (float)sin(angle) * zoom; + float ydv = (float)cos(angle) * zoom; + + SLONG colour; + + colour = 0xffffffff; + + // + // Add a single crappy poly! + // + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + pp[0].X = 0.0F; + pp[0].Y = 0.0F; + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].u = 0.5F - xdu - ydu; + pp[0].v = 0.5F - xdv - ydv; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = 640.0F; + pp[1].Y = 0.0F; + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].u = 0.5F + xdu - ydu; + pp[1].v = 0.5F + xdv - ydv; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = 0.0F; + pp[2].Y = 480.0F; + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].u = 0.5F - xdu + ydu; + pp[2].v = 0.5F - xdv + ydv; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = 640.0F; + pp[3].Y = 480.0F; + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].u = 0.5F + xdu + ydu; + pp[3].v = 0.5F + xdv + ydv; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_FADECAT, FALSE, TRUE); + + // + // Darken the screen at the end. + // + + if (GetTickCount() > (unsigned)PANEL_fadeout_time + 768) + { + SLONG bright; + + // + // Fadeout the colour. + // + + bright = GetTickCount() - (PANEL_fadeout_time + 768); + + SATURATE(bright, 0, 255); + + colour = bright << 24; + +#ifdef TARGET_DC + // On the DC, there's a hardware bug that means the UV clamp down't quite work. + // So we need to darken the whole screen this way. + PANEL_draw_quad( + 0.0f, + 0.0f, + 640.0f, + 480.0f, + POLY_PAGE_ALPHA, + colour); +#else + #define PANEL_BLACKEN_WIDTH 70 + + PANEL_draw_quad( + 320.0F - PANEL_BLACKEN_WIDTH, + 240.0F - PANEL_BLACKEN_WIDTH, + 320.0F + PANEL_BLACKEN_WIDTH, + 240.0F + PANEL_BLACKEN_WIDTH, + POLY_PAGE_ALPHA, + colour); +#endif + } + +#ifndef TARGET_DC + POLY_frame_draw(FALSE,FALSE); +#endif + } +} + +SLONG PANEL_fadeout_finished() +{ + if (PANEL_fadeout_time) + { + if (GetTickCount() > (unsigned)PANEL_fadeout_time + 1024) + { + return TRUE; + } + } + + return FALSE; +} + + +// +// The coordinates of each sprite +// + +#define PANEL_LSPRITE_BACKGROUND 0 +#define PANEL_LSPRITE_AK47 1 +#define PANEL_LSPRITE_SHOTGUN 2 +#define PANEL_LSPRITE_LOW_GEAR 3 +#define PANEL_LSPRITE_HIGH_GEAR 4 +#define PANEL_LSPRITE_GRENADE 5 +#define PANEL_LSPRITE_ARROW 6 +#define PANEL_LSPRITE_QMARK 7 +#define PANEL_LSPRITE_DOT 8 +#define PANEL_LSPRITE_PISTOL 9 +#define PANEL_LSPRITE_TEXT_BOX 10 +#define PANEL_LSPRITE_BBB 11 +#define PANEL_LSPRITE_FIST 12 +#define PANEL_LSPRITE_EXPLOSIVES 13 +#define PANEL_LSPRITE_KNIFE 14 +#define PANEL_LSPRITE_NUMBER 15 + +typedef struct +{ + SLONG page; + float u1; + float v1; + float u2; + float v2; + +} PANEL_Lsprite; + +/* +PANEL_Lsprite PANEL_lsprite[PANEL_LSPRITE_NUMBER] = +{ + #define PLS(a,b,c,d) {float(a) / 256.0F, float(b) / 256.F, float(c) / 256.F, float(d) / 256.F} + + #if THE_REAL_POSITIONS + + PLS(0,114, 142,256), + PLS(1,1, 76,44), + PLS(0,46, 77,87), + PLS(77,1, 149,51), + PLS(78,56, 148,106), + PLS(182,32, 220,79), // Grenade + PLS(223,42, 247,68), + PLS(226,76, 246,103), + PLS(189,83, 211,105), // Dot + PLS(186,106, 256,158), + PLS(144,112, 180,148), + PLS(145,157, 217,204), // BBB + PLS(219,160, 255,204), + PLS(146, 207, 195,246), + PLS(1,95, 75,111), + + #else + + // + // Made all coordinates even. + // + + PLS(0,114, 142,256), + PLS(0,0, 76,44), + PLS(0,46, 78,88), + PLS(76,0, 150,52), + PLS(78,56, 148,106), + PLS(182,32, 220,80), // Grenade + PLS(222,42, 248,68), + PLS(226,76, 246,104), + PLS(188,82, 212,106), // Dot + PLS(186,106, 256,158), + PLS(144,112, 180,148), +// PLS(144,156, 218,204), // BBB + PLS(145,157, 219,205), // BBB 2 + PLS(218,160, 256,204), + PLS(146, 206, 196,246), + PLS(0,94, 76,112), + + #endif +}; +*/ + +PANEL_Lsprite PANEL_lsprite[PANEL_LSPRITE_NUMBER] = +{ +#define PLS(p, a,b,c,d) { p, float(a) / 256.0F, float(b) / 256.F, float(c) / 256.F, float(d) / 256.F} + + /* + + PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 90, 212, 256), // display + PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 50, 142, 90), // AK + PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 50, 70, 88), // Shotgun + PLS(POLY_PAGE_LASTPANEL_ALPHA, 174, 0, 246, 50), // LoGear + PLS(POLY_PAGE_LASTPANEL_ALPHA, 104, 0, 174, 50), // HiGear + PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 0, 104, 46), // Grenade + PLS(POLY_PAGE_LASTPANEL_ALPHA, 224, 102, 242, 114), // Arrow + PLS(POLY_PAGE_LASTPANEL_ALPHA, 226, 76, 246, 104), // ? + PLS(POLY_PAGE_LASTPANEL_ALPHA, 230, 176, 238, 184), // Dot + PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 0, 70, 50), // Pistol + PLS(POLY_PAGE_LASTPANEL_ALPHA, 218, 128, 250, 160), // TxtBox + PLS(POLY_PAGE_LASTPANEL2_ALPHA, 0, 122, 72, 168), // BBB + PLS(POLY_PAGE_LASTPANEL2_ALPHA,126, 122, 162, 168), // Fist + PLS(POLY_PAGE_LASTPANEL2_ALPHA, 72, 122, 120, 162), // splosive + PLS(POLY_PAGE_LASTPANEL_ALPHA, 140, 62, 212, 84), // knife + + */ + + PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 90, 212, 256), // display + PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 52, 141, 89), // AK + PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 52, 69, 88), // Shotgun + PLS(POLY_PAGE_LASTPANEL_ALPHA, 175, 0, 246, 50), // LoGear + PLS(POLY_PAGE_LASTPANEL_ALPHA, 104, 0, 174, 50), // HiGear + PLS(POLY_PAGE_LASTPANEL_ALPHA, 70, 0, 104, 46), // Grenade + PLS(POLY_PAGE_LASTPANEL_ALPHA, 224, 102, 242, 114), // Arrow + PLS(POLY_PAGE_LASTPANEL_ALPHA, 226,76, 246,103), // ? + PLS(POLY_PAGE_LASTPANEL_ALPHA, 230, 176, 238, 184), // Dot + PLS(POLY_PAGE_LASTPANEL_ALPHA, 0, 0, 69, 50), // Pistol + PLS(POLY_PAGE_LASTPANEL_ALPHA, 218, 128, 250, 160), // TxtBox + PLS(POLY_PAGE_LASTPANEL2_ALPHA, 0, 124, 71, 168), // BBB + PLS(POLY_PAGE_LASTPANEL2_ALPHA,126, 124, 162, 168), // Fist + PLS(POLY_PAGE_LASTPANEL2_ALPHA, 72, 123, 120, 161), // splosive + PLS(POLY_PAGE_LASTPANEL_ALPHA, 141, 62, 212, 84), // knife + +}; + + + +// +// Draws an arrow. +// + +void PANEL_last_arrow(float x, float y, float angle, float size, ULONG colour, UBYTE is_dot=0) +{ + PANEL_Lsprite *pls; + if (is_dot) + pls = &PANEL_lsprite[PANEL_LSPRITE_DOT]; + else + pls = &PANEL_lsprite[PANEL_LSPRITE_ARROW]; + + float dx = sin(angle) * size; + float dy = cos(angle) * size; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + pp[0].X = x + dx + (-dy); + pp[0].Y = y + dy + (+dx); + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].x = 0.0F; + pp[0].y = 0.0F; + pp[0].u = pls->u1; + pp[0].v = pls->v1; + pp[0].colour = colour; + pp[0].specular = 0xff000000; + + pp[1].X = x + dx - (-dy); + pp[1].Y = y + dy - (+dx); + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].x = 0.0F; + pp[1].y = 0.0F; + pp[1].u = pls->u2; + pp[1].v = pls->v1; + pp[1].colour = colour; + pp[1].specular = 0xff000000; + + pp[2].X = x - dx + (-dy); + pp[2].Y = y - dy + (+dx); + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].x = 0.0F; + pp[2].y = 0.0F; + pp[2].u = pls->u1; + pp[2].v = pls->v2; + pp[2].colour = colour; + pp[2].specular = 0xff000000; + + pp[3].X = x - dx - (-dy); + pp[3].Y = y - dy - (+dx); + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].x = 0.0F; + pp[3].y = 0.0F; + pp[3].u = pls->u2; + pp[3].v = pls->v2; + pp[3].colour = colour; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad, pls->page, FALSE, TRUE); +} + + +void PANEL_last_bubble(float x1, float y1, float x2, float y2) +{ + POLY_Point pp[16]; + + #define SET_PP(qn, qx,qy, qu,qv) \ + { \ + pp[qn].x = 0.0F; \ + pp[qn].y = 0.0F; \ + pp[qn].X = qx; \ + pp[qn].Y = qy; \ + pp[qn].z = fZDepthBodge; \ + pp[qn].Z = fWDepthBodge; \ + pp[qn].u = qu; \ + pp[qn].v = qv; \ + pp[qn].colour = 0xffffffff; \ + pp[qn].specular = 0xff000000; \ + } + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + PANEL_Lsprite *pls = &PANEL_lsprite[PANEL_LSPRITE_TEXT_BOX]; + + SET_PP(0, x1, y1, pls->u1, pls->v1); + SET_PP(1, x1 + 8.0F, y1, pls->u1 + (8.0F / 256.0F), pls->v1); + SET_PP(2, x2 - 8.0F, y1, pls->u2 - (8.0F / 256.0F), pls->v1); + SET_PP(3, x2, y1, pls->u2, pls->v1); + + SET_PP(4, x2, y1 + 8.0F, pls->u2, pls->v1 + (8.0F / 256.0F)); + SET_PP(5, x2, y2 - 8.0F, pls->u2, pls->v2 - (8.0F / 256.0F)); + + SET_PP(6, x2, y2, pls->u2, pls->v2); + SET_PP(7, x2 - 8.0F, y2, pls->u2 - (8.0F / 256.0F), pls->v2); + SET_PP(8, x1 + 8.0F, y2, pls->u1 + (8.0F / 256.0F), pls->v2); + SET_PP(9, x1, y2, pls->u1, pls->v2); + + SET_PP(10, x1, y2 - 8.0F, pls->u1, pls->v2 - (8.0F / 256.0F)); + SET_PP(11, x1, y1 + 8.0F, pls->u1, pls->v1 + (8.0F / 256.0F)); + + SET_PP(12, x1 + 8.0F, y1 + 8.0F, pls->u1 + (8.0F / 256.0F), pls->v1 + (8.0F / 256.0F)); + SET_PP(13, x2 - 8.0F, y1 + 8.0F, pls->u2 - (8.0F / 256.0F), pls->v1 + (8.0F / 256.0F)); + SET_PP(14, x2 - 8.0F, y2 - 8.0F, pls->u2 - (8.0F / 256.0F), pls->v2 - (8.0F / 256.0F)); + SET_PP(15, x1 + 8.0F, y2 - 8.0F, pls->u1 + (8.0F / 256.0F), pls->v2 - (8.0F / 256.0F)); + + SLONG i; + + SLONG p1; + SLONG p2; + + POLY_Point *quad[4]; + + struct + { + UBYTE p1; + UBYTE p2; + UBYTE p3; + UBYTE p4; + + } blah[9] = + { + {0,1,11,12}, + {1,2,12,13}, + {2,3,13,4}, + {11,12,10,15}, + {12,13,15,14}, + {13,4,14,5}, + {10,15,9,8}, + {15,14,8,7}, + {14,5,7,6} + }; + + for (i = 0; i < 9; i++) + { + quad[0] = &pp[blah[i].p1]; + quad[1] = &pp[blah[i].p2]; + quad[2] = &pp[blah[i].p3]; + quad[3] = &pp[blah[i].p4]; + + POLY_add_quad(quad, pls->page, FALSE, TRUE); + } +} + + + +SLONG PANEL_sign_which; +SLONG PANEL_sign_flip; +SLONG PANEL_sign_time; + +void PANEL_flash_sign(SLONG sign, SLONG flip) +{ + PANEL_sign_time = GetTickCount(); + PANEL_sign_flip = flip; + PANEL_sign_which = sign; +} + + + +CBYTE PANEL_info_message[512]; +ULONG PANEL_info_time; + +void PANEL_new_info_message(CBYTE *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsprintf(PANEL_info_message, fmt, ap); + va_end (ap); + + PANEL_info_time = GetTickCount(); +} + + + +void PANEL_darken_screen(SLONG x) +{ + PANEL_draw_quad(640.0F - float(x), 0.0F, 640.0F, 480.0F, POLY_PAGE_ALPHA_OVERLAY, 0x88000000); +} + +// this sucks! +inline SLONG BodgePageIntoAddAlpha(SLONG oldpage) +{ + if (oldpage==POLY_PAGE_LASTPANEL_ALPHA) return POLY_PAGE_LASTPANEL_ADDALPHA; + return POLY_PAGE_LASTPANEL2_ADDALPHA; +} +// this sucks too! +inline SLONG BodgePageIntoAdd(SLONG oldpage) +{ + if (oldpage==POLY_PAGE_LASTPANEL_ALPHA) return POLY_PAGE_LASTPANEL_ADD; + return POLY_PAGE_LASTPANEL2_ADD; +} +// this sucks as well! +inline SLONG BodgePageIntoSub(SLONG oldpage) +{ + if (oldpage==POLY_PAGE_LASTPANEL_ALPHA) return POLY_PAGE_LASTPANEL_SUB; + return POLY_PAGE_LASTPANEL2_SUB; +} + + +/************************************************************* + * + * Pop-up inventory panel + * + */ + +void PANEL_inv_weapon(SLONG x, SLONG y, SLONG item, UBYTE who, SLONG rgb, UBYTE sel) { +/* SLONG which_gun, which_dx=0; + + // + // Which gun shall we draw. + // + switch(item) + { + default: + if (who == PANEL_WHO_DARCI) + which_gun = PANEL_IC_DARCI_HAND; + else + which_gun = PANEL_IC_ROPER_HAND; + break; + + case SPECIAL_GUN: + which_gun = PANEL_IC_PISTOL; + break; + + case SPECIAL_AK47: + which_gun = PANEL_IC_AK47; + which_dx = -45; + break; + + case SPECIAL_BASEBALLBAT: + which_gun = PANEL_IC_BASEBALLBAT; + which_dx = -50; + break; + + case SPECIAL_KNIFE: + which_gun = PANEL_IC_KNIFE; +// which_dy = 15; + break; + + case SPECIAL_SHOTGUN: + which_gun = PANEL_IC_SHOTGUN; + which_dx = -35; + break; + + case SPECIAL_GRENADE: + which_gun = PANEL_IC_GRENADE; + break; + + case SPECIAL_EXPLOSIVES: + which_gun = PANEL_IC_EXPLOSIVES; + break; + case SPECIAL_WIRE_CUTTER: + which_gun = PANEL_IC_EXPLOSIVES; + break; + } + + PANEL_funky_quad( + which_gun, + x + which_dx, + y, + PANEL_PAGE_ALPHA_END, + 0x00ffffff|alpha); + */ + + SLONG sprite = -1, faded; + + switch(item) + { + case SPECIAL_GUN: + sprite = PANEL_LSPRITE_PISTOL; + break; + case SPECIAL_SHOTGUN: + sprite = PANEL_LSPRITE_SHOTGUN; + break; + case SPECIAL_AK47: + sprite = PANEL_LSPRITE_AK47; + break; + case SPECIAL_EXPLOSIVES: + sprite = PANEL_LSPRITE_EXPLOSIVES; + break; + case SPECIAL_GRENADE: + sprite = PANEL_LSPRITE_GRENADE; + break; + case SPECIAL_KNIFE: + sprite = PANEL_LSPRITE_KNIFE; + break; + case SPECIAL_BASEBALLBAT: + sprite = PANEL_LSPRITE_BBB; + break; + default: + sprite = PANEL_LSPRITE_FIST; + break; + } + + // + // Centre the sprite. + // + + ASSERT(WITHIN(sprite, 0, PANEL_LSPRITE_NUMBER - 1)); + + PANEL_Lsprite *pls = &PANEL_lsprite[sprite]; + + float uwidth = (pls->u2 - pls->u1) * 256.0F; + float vwidth = (pls->v2 - pls->v1) * 256.0F; + +#ifdef TARGET_DC + // Got to make it much more obvious which weapon is selected. + if (sel) + { + // Enlarge it. + uwidth *= 2.0f; + vwidth *= 2.0f; + } + else + { + // Dark red + faded=(rgb&0xff)>>1; + faded|=(faded<<8)|(faded<<16)|(faded<<24); + rgb = faded; + } +#else + faded=(rgb&0xff)>>1; + faded|=(faded<<8)|(faded<<16)|(faded<<24); + if (!sel) rgb=faded; +#endif + + + +/* PANEL_draw_quad( + (float)x - uwidth * 0.35F, + (float)y - vwidth * 0.35F, + (float)x + uwidth * 0.35F, + (float)y + vwidth * 0.35F, + POLY_PAGE_LASTPANEL_SUB, +// 0x7f007fff, + faded, + pls->u1, + pls->v1, + pls->u2, + pls->v2);*/ +/* PANEL_draw_quad( + (float)x - 30, + (float)y - 30, + (float)x + 30, + (float)y + 30, + POLY_PAGE_SHADOW_OVAL, + faded, + 0.0, 0.0, 1.0, 1.0 + );*/ +/* PANEL_draw_quad( + (float)x + 2 - uwidth * 0.25F, + (float)y + 2 - vwidth * 0.25F, + (float)x + 2 + uwidth * 0.25F, + (float)y + 2 + vwidth * 0.25F, + BodgePageIntoSub(pls->page), +// 0x7f007fff, + faded, + pls->u1, + pls->v1, + pls->u2, + pls->v2);*/ + + PANEL_draw_quad( + (float)x - uwidth * 0.25F, + (float)y - vwidth * 0.25F, + (float)x + uwidth * 0.25F, + (float)y + vwidth * 0.25F, + BodgePageIntoAdd/*Alpha*/(pls->page), + rgb, + pls->u1, + pls->v1, + pls->u2, + pls->v2); +} + + +#define PANEL_ADDWEAPON(item) { draw_list[draw_count]=item; draw_count++; } +#define ITEM_SEPERATION (150) + +void PANEL_inventory(Thing *darci, Thing *player) { + SLONG rgb,rgb2; + CBYTE draw_list[10]; + UBYTE draw_count=0; + Thing *p_special = NULL; + SLONG x,c0; + UBYTE current_item = 0; + SLONG sel; + + UWORD CONTROLS_inv_fade = player->Genus.Player->PopupFade; + + if (!CONTROLS_inv_fade) return; + if (darci->Genus.Person->Flags & FLAG_PERSON_DRIVING) return; + + + +// Bad Dog! Obsolete code. +//extern SLONG EWAY_cam_active; + //if (EWAY_cam_active) return; + + if ( EWAY_stop_player_moving() ) + { + return; + } + + +/* rgb=((SLONG)(CONTROLS_inv_fade-1))<<24; + rgb2=((SLONG)(CONTROLS_inv_fade-1)>>1)<<24; + DRAW2D_Box_Page(0, 20, 640, 80, rgb2|0xAFA583, POLY_PAGE_ALPHA_OVERLAY, 128); + DRAW2D_Box_Page(0,20,CONTROLS_inv_fade*3,21,rgb|0xFFFFFF,POLY_PAGE_ALPHA_OVERLAY,128); + DRAW2D_Box_Page(640-(CONTROLS_inv_fade*3),79,640,80,rgb|0xFFFFFF,POLY_PAGE_ALPHA_OVERLAY,128); + + CBYTE stat_up[10]; + sprintf(stat_up,"%s: %d",XLAT_str(X_STR),player->Genus.Player->Strength); + FONT2D_DrawString(stat_up,0,1,0xffffff,256,POLY_PAGE_FONT2D,rgb); + sprintf(stat_up,"%s: %d",XLAT_str(X_CON),player->Genus.Player->Constitution); + FONT2D_DrawString(stat_up,80,1,0xffffff,256,POLY_PAGE_FONT2D,rgb); + sprintf(stat_up,"%s: %d",XLAT_str(X_STA),player->Genus.Player->Stamina); + FONT2D_DrawString(stat_up,160,1,0xffffff,256,POLY_PAGE_FONT2D,rgb); + sprintf(stat_up,"%s: %d",XLAT_str(X_DEX),player->Genus.Player->Skill); + FONT2D_DrawString(stat_up,240,1,0xffffff,256,POLY_PAGE_FONT2D,rgb); +*/ + PANEL_ADDWEAPON(0); + + sel=darci->Genus.Person->SpecialUse; + + if (darci->Genus.Person->SpecialList) + { + p_special = TO_THING(darci->Genus.Person->SpecialList); + + while(p_special) + { + ASSERT(p_special->Class == CLASS_SPECIAL); + if (SPECIAL_info[p_special->Genus.Special->SpecialType].group == SPECIAL_GROUP_ONEHANDED_WEAPON || + SPECIAL_info[p_special->Genus.Special->SpecialType].group == SPECIAL_GROUP_TWOHANDED_WEAPON || + p_special->Genus.Special->SpecialType == SPECIAL_EXPLOSIVES || + p_special->Genus.Special->SpecialType == SPECIAL_WIRE_CUTTER) + { + if (THING_NUMBER(p_special)==darci->Genus.Person->SpecialUse) + { + current_item=draw_count; + sel=p_special->Genus.Special->SpecialType; + } + PANEL_ADDWEAPON(p_special->Genus.Special->SpecialType); + } + if (p_special->Genus.Special->NextSpecial) + p_special = TO_THING(p_special->Genus.Special->NextSpecial); + else + p_special = NULL; + } + } + + if (darci->Flags & FLAGS_HAS_GUN) + { + if (darci->Genus.Person->Flags & FLAG_PERSON_GUN_OUT) + { + current_item=draw_count; + sel=SPECIAL_GUN; + } + PANEL_ADDWEAPON(SPECIAL_GUN); + } + + current_item = player->Genus.Player->ItemFocus; + + if (current_item==-1) return; + +// x = 320 - (50*draw_count) - (current_item*50); +/* x = 320 - (current_item*ITEM_SEPERATION); + for (c0=0;c0 300 ) + { + // Inventory starts above and goes upwards. + iYPos = m_iPanelYPos - 150; //330 + iYInc = -35; + } + else + { + // Inventory starts below and goes down. + iYPos = m_iPanelYPos + 20; + iYInc = 35; + } + + + rgb=CONTROLS_inv_fade-1; + rgb2=rgb|(rgb<<8)|(rgb<<24); + rgb|=(rgb<<8)|(rgb<<16)|(rgb<<24); + for (c0=0;c0Genus.Person->SpecialUse)) + if (draw_list[c0]!=sel) + { + PANEL_inv_weapon(m_iPanelXPos+170,iYPos,draw_list[c0],0,rgb, 0); + } + else + { + PANEL_inv_weapon(m_iPanelXPos+170,iYPos,draw_list[c0],0,rgb ,1); + } + iYPos += iYInc; + } +} + + +#define PANEL_LAST_HEIGHT 165 +#define SCANNER_LAST_CTR_X 74 +#define SCANNER_LAST_CTR_Y (480 - PANEL_LAST_HEIGHT + 74) +#define SCANNER_LAST_CTR_U 74 +#define SCANNER_LAST_CTR_V 74 + + + + + +void PANEL_last() +{ + + + //TRACE ( "PDi" ); + + bool bPanelIsAtBottomOfScreen = ( m_iPanelYPos > 300 ); + + +#ifdef TARGET_DC + PANEL_draw_VMU_ammo_counts(); +#endif + + + if (EWAY_tutorial_string) + { + // + // Darken the whole screen... + // + + PANEL_darken_screen(640); + +#ifndef TARGET_DC + POLY_frame_draw(FALSE, FALSE); + POLY_frame_init(FALSE, FALSE); +#endif + + // + // Draw a speech bubble in the top left of the screen. + // + +#ifdef TARGET_DC + // We have to keep stuff away from the edges by 32 pixels. Waaa. + SLONG height = FONT2D_DrawStringWrapTo( + EWAY_tutorial_string, + 32, + 32, + 0xffffff, + 256, + POLY_PAGE_FONT2D, + 0, + 640-32*2); + + PANEL_last_bubble( + 32 - 6, + 32 - 4, + float(FONT2D_rightmost_x) + 6.0F, + height + 18); + + // Do it again so it's brighter. + FONT2D_DrawStringWrapTo( + EWAY_tutorial_string, + 32, + 32, + 0xffffff, + 256, + POLY_PAGE_FONT2D, + 0, + 640-32*2); + + +#else + #define PANEL_TUT_X 16 + #define PANEL_TUT_Y 16 + + SLONG height = FONT2D_DrawStringWrap( + EWAY_tutorial_string, + PANEL_TUT_X, + PANEL_TUT_Y, + 0xffffff); + + PANEL_last_bubble( + PANEL_TUT_X - 6, + PANEL_TUT_Y - 4, + float(FONT2D_rightmost_x) + 6.0F, + PANEL_TUT_Y + height + 4); + +#endif + + return; + } + + + Thing *darci = NET_PERSON(0); + + if (darci == NULL) + { + return; + } + + if (EWAY_stop_player_moving()) + { + // + // There is a widescreen cutscene playing. + // + + PANEL_new_widescreen(); + + return; + } + else + { + PANEL_wide_top_person = NULL; + PANEL_wide_bot_person = NULL; + PANEL_wide_top_is_talking = FALSE; + PANEL_wide_text[0] = '\000'; + } + + // + // Draw the background first. + // + + /* + PANEL_draw_quad( + 0.0F, + 480.0F - 165.0F, + 212.0F, + 480.0F, + POLY_PAGE_LASTPANEL_ALPHA, + 0xffffffff, + 0.0F, + 90.0F / 256.0F, + 212.0F / 256.0F, + 1.0F);*/ + + PANEL_draw_quad( + (float)( m_iPanelXPos + 0 ), + (float)( m_iPanelYPos - 165 ), + (float)( m_iPanelXPos + 212 ), + (float)( m_iPanelYPos - 0 ), + POLY_PAGE_LASTPANEL_ALPHA, + 0xffffffff, + 0.0F, + 90.0F / 256.0F, + 212.0F / 256.0F, + 1.0F); + + +/* PANEL_draw_quad( + 0.0F, + 480.0F - 142.0F, + 126.0F, + 480.0F, + POLY_PAGE_LASTPANEL_ALPHA, + 0xffffffff, + 0.0F, + 114.0F / 256.0F, + 126.0F / 256.0F, + 1.0F); + + PANEL_draw_quad( + 126.0F, + 480.0F - 142.0F, + 186.0F, + 480.0F, + POLY_PAGE_LASTPANEL_ALPHA, + 0xffffffff, + 126.0F / 256.0F, + 114.0F / 256.0F, + 127.0F / 256.0F, + 1.0F); + + PANEL_draw_quad( + 186.0F, + 480.0F - 142.0F, + 186.0F + 142.0F - 127.0F, + 480.0F, + POLY_PAGE_LASTPANEL_ALPHA, + 0xffffffff, + 127.0F / 256.0F, + 114.0F / 256.0F, + 142.0F / 256.0F, + 1.0F); +*/ + // + // The weapon/ammo box. + // + + SLONG sprite = -1; + CBYTE text[64]; + + text[0] = '\000'; + + int iGrenadeCountdown = -1; + + if (darci->Genus.Person->Flags & FLAG_PERSON_DRIVING) + { + Thing *p_vehicle = TO_THING(darci->Genus.Person->InCar); + + sprite = PANEL_LSPRITE_LOW_GEAR; + +/* if (p_vehicle->Genus.Vehicle->Siren) + { + sprite = PANEL_LSPRITE_HIGH_GEAR; + + sprintf(text, "High"); + } + else + { + sprite = PANEL_LSPRITE_LOW_GEAR; + + sprintf(text, "Low"); + }*/ + } + else + { + if (darci->Genus.Person->Flags & FLAG_PERSON_GUN_OUT) + { + sprite = PANEL_LSPRITE_PISTOL; + + if (darci->Genus.Person->ammo_packs_pistol) + { + sprintf(text, "%d\\%d", darci->Genus.Person->Ammo, darci->Genus.Person->ammo_packs_pistol/15); + } + else + { + sprintf(text, "%d", darci->Genus.Person->Ammo); + } + } + else + if (darci->Genus.Person->SpecialUse) + { + Thing *p_special = TO_THING(darci->Genus.Person->SpecialUse); + + switch(p_special->Genus.Special->SpecialType) + { + case SPECIAL_SHOTGUN: + + sprite = PANEL_LSPRITE_SHOTGUN; + + if (darci->Genus.Person->ammo_packs_shotgun) + { + sprintf(text, "%d\\%d", p_special->Genus.Special->ammo, darci->Genus.Person->ammo_packs_shotgun/SPECIAL_AMMO_IN_A_SHOTGUN); + } + else + { + sprintf(text, "%d", p_special->Genus.Special->ammo); + } + + break; + + case SPECIAL_AK47: + + sprite = PANEL_LSPRITE_AK47; + + if (darci->Genus.Person->ammo_packs_ak47) + { + sprintf(text, "%d\\%d", p_special->Genus.Special->ammo, darci->Genus.Person->ammo_packs_ak47/SPECIAL_AMMO_IN_A_AK47); + } + else + { + sprintf(text, "%d", p_special->Genus.Special->ammo); + } + break; + + case SPECIAL_EXPLOSIVES: + sprite = PANEL_LSPRITE_EXPLOSIVES; + sprintf(text, "%d", p_special->Genus.Special->ammo); + break; + + case SPECIAL_GRENADE: + sprite = PANEL_LSPRITE_GRENADE; + // + // If the player is holding a grenade that has had its pin pulled then + // show how long the grenade has before it goes off. + // + if (p_special->SubState == SPECIAL_SUBSTATE_ACTIVATED) + { + SLONG secsleft; + + + secsleft = p_special->Genus.Special->timer / (16 * 20) + 1; + SATURATE(secsleft,0,6); + +#ifdef TARGET_DC + // This gets done later, over the grenade icon. + iGrenadeCountdown = secsleft; +#else + ULONG colour, colours[]={0xff3300,0xff8800,0x88ff00,0x888888}; + if (secsleft<1) + colour=*colours; + else + if (secsleft>3) + colour=colours[3]; + else + colour=colours[secsleft]; + + itoa(secsleft,text,10); + + FONT2D_DrawString( + text, + m_iPanelXPos + 141, + m_iPanelYPos - 53, + colour, + 256); +#endif + + } +#ifdef TARGET_DC + else + { + iGrenadeCountdown = -1; + } +#endif + + itoa(p_special->Genus.Special->ammo,text,10); + break; + + case SPECIAL_KNIFE: + sprite = PANEL_LSPRITE_KNIFE; + break; + + case SPECIAL_BASEBALLBAT: + sprite = PANEL_LSPRITE_BBB; + break; + + default: + sprite = PANEL_LSPRITE_QMARK; + break; + } + } + else + { + sprite = PANEL_LSPRITE_FIST; + } + } + + // + // Centre the sprite. + // + + { + ASSERT(WITHIN(sprite, 0, PANEL_LSPRITE_NUMBER - 1)); + + PANEL_Lsprite *pls = &PANEL_lsprite[sprite]; + + float uwidth = (pls->u2 - pls->u1) * 256.0F; + float vwidth = (pls->v2 - pls->v1) * 256.0F; + + /* + float x1 = 170.0F - uwidth * 0.5F; + float y1 = 417.0F - vwidth * 0.5F; + float x2 = 170.0F + uwidth * 0.5F; + float y2 = 417.0F + vwidth * 0.5F; + */ + float x1 = (float)( m_iPanelXPos + 170 ) - uwidth * 0.5F; + float y1 = (float)( m_iPanelYPos - 63 ) - vwidth * 0.5F; + float x2 = (float)( m_iPanelXPos + 170 ) + uwidth * 0.5F; + float y2 = (float)( m_iPanelYPos - 63 ) + vwidth * 0.5F; + + if (ftol(uwidth) & 0x1) + { + x1 -= 0.5F; + x2 -= 0.5F; + } + + if (ftol(vwidth) & 0x1) + { + y1 -= 0.5F; + y2 -= 0.5F; + } + + // And move the M16 up a bit, so it doesn't cover the ammo count. + if ( sprite == PANEL_LSPRITE_AK47 ) + { + y1 -= 8.0F; + y2 -= 8.0F; + } + + PANEL_draw_quad( + x1, y1, + x2, y2, + BodgePageIntoAdd/*Alpha*/(pls->page), + 0xFFffffff, + pls->u1, + pls->v1, + pls->u2, + pls->v2); + } + + // + // Draw the ammo. + // + + if (text) + { + FONT2D_DrawStringRightJustify( + text, + m_iPanelXPos + 215, // 214, + m_iPanelYPos - 50, // 427, + 0xffffff, + 256 + 64); + + /* + + FONT2D_DrawStringRightJustify( + text, + m_iPanelXPos + 217, // 214, + m_iPanelYPos - 51, // 427, + 0x000000, + 384); + + */ + + /* + + FONT2D_DrawStringRightJustify( + text, + m_iPanelXPos + 214, // 214, + m_iPanelYPos - 53, // 427, + 0xffffff, + 256); + + */ + } + + +#ifdef TARGET_DC + if ( iGrenadeCountdown >= 0 ) + { + // Draw the countdown over the grenade. + ULONG colour = 0xff3300; + if ( iGrenadeCountdown <= 4 ) + { + static int iFlash = 0; + iFlash += ( 5 - iGrenadeCountdown ); + if ( ( iFlash & 0x4 ) == 0 ) + { + // Flash it. + colour = 0x000000; + } + } + itoa(iGrenadeCountdown,text,10); + + // BRIGHTER! BIGGER! MORE! You can barely see the damn countdown on the PC. + FONT2D_DrawString( + text, + m_iPanelXPos + 160 + 2, + m_iPanelYPos - 73 + 2, + 0x00000000, + 512); + + FONT2D_DrawString( + text, + m_iPanelXPos + 160 - 2, + m_iPanelYPos - 73 - 2, + 0x00000000, + 512); + + FONT2D_DrawString( + text, + m_iPanelXPos + 160 - 2, + m_iPanelYPos - 73 + 2, + 0x00000000, + 512); + + FONT2D_DrawString( + text, + m_iPanelXPos + 160 + 2, + m_iPanelYPos - 73 - 2, + 0x00000000, + 512); + + FONT2D_DrawString( + text, + m_iPanelXPos + 160, + m_iPanelYPos - 73, + colour, + 512); + } +#endif + + + // + // And the crime rate, if applicable + // + if (GAME_FLAGS & GF_SHOW_CRIMERATE) + { + CBYTE crimerate[64]; + sprintf(crimerate, "%d%%", CRIME_RATE); + + if (CRIME_RATE>=95) + { + static UWORD pulse=0; + SLONG colour; + pulse+=(TICK_RATIO*80)>>TICK_SHIFT; + colour=(SIN(pulse&2047)>>9)+128; + colour=colour|(colour<<8); + FONT2D_DrawStringCentred( + crimerate, + m_iPanelXPos + 170, //170, + m_iPanelYPos - 116, //364, + 0xff0000|colour); + } else + FONT2D_DrawStringCentred( + crimerate, + m_iPanelXPos + 170, //170, + m_iPanelYPos - 116, //364, + 0xffffff); + } + + #ifndef TARGET_DC + { + CBYTE timing[256]; + float strip; + SLONG c; + + extern ULONG AENG_draw_time; + extern ULONG AENG_poly_add_quad_time; + +#ifdef STRIP_STATS +extern ULONG strip_stats[]; + if(strip_stats[0]) + strip=(float)strip_stats[1]/(float)strip_stats[0]; + + + + sprintf( + timing, + "Frame time %d strip len %f", + AENG_draw_time >> 12,strip); + + FONT2D_DrawString( + timing, + 50, + 65, + 0xffffff); + + for(c=2;c<34;c++) + { + sprintf( + timing, + "(%d)%d",c-1, + strip_stats[c]); + + FONT2D_DrawString( + timing, + 10+(((c-2)&7))*75, + 120+(((c-2)&0xf8)>>3)*20, + 0xffffff); + + } +#endif + + sprintf( + timing, + "Poly add quad %d", + AENG_poly_add_quad_time >> 12); + + FONT2D_DrawString( + timing, + 50, + 80, + 0xffffff); + } + #endif + + // + // Draw the health bar. + // + + { + SLONG i; + + float angle; + + float du; + float dv; + + float u1; + float v1; + float u2; + float v2; + + float last_u1; + float last_v1; + float last_u2; + float last_v2; + + POLY_Point pp [4]; + POLY_Point *quad[4]; + POLY_Point *tri [3]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + tri[0] = &pp[0]; + tri[1] = &pp[1]; + tri[2] = &pp[2]; + + static float blah1 = ( -43 * 2.0F * PI / 360.0F); + static float blah2 = (-227 * 2.0F * PI / 360.0F); + UBYTE is_in_car = darci->Genus.Person->InCar ? 1 : 0; + float car_offset = is_in_car ? 130.0F : 0.0F; + + Thing *the_car=is_in_car? TO_THING(darci->Genus.Person->InCar) : 0; + + #define PLH_MID_U (71.0F + car_offset) + #define PLH_MID_V (71.0F) + #define PLH_RADIUS (66.0F) + + #define PLH_WIDTH (10.0F) + #define PLH_ANGLE1 blah1 + #define PLH_ANGLE2 blah2 + #define PLH_SEGS (8) + + //#define PLH_MID_X (74.0F) + //#define PLH_MID_Y (480.0F - (256.0F - 166.0F)) + + #define PLH_MID_X ((float)(m_iPanelXPos + 74)) + #define PLH_MID_Y ((float)(m_iPanelYPos - (256 - 166))) + + angle = PLH_ANGLE1; + + float dangle; + float fraction; + + dangle = (PLH_ANGLE2 - PLH_ANGLE1) / PLH_SEGS; + + // + // What fraction of health does Darci have? + // + + fraction = is_in_car ? float(the_car->Genus.Vehicle->Health) * (1.0F / 300.0F) : float(darci->Genus.Person->Health) * ((darci->Genus.Person->PersonType == PERSON_ROPER) ? (1.0F / 400.0F) : (1.0F / 200.0F)); + + SATURATE(fraction, 0.0F, 1.0F); + + dangle *= fraction; + + for (i = 0; i <= PLH_SEGS; i++) + { + du = sin(angle); + dv = cos(angle); + + u1 = (PLH_MID_U + du * (PLH_RADIUS + PLH_WIDTH)); + v1 = (PLH_MID_V + dv * (PLH_RADIUS + PLH_WIDTH)); + + u2 = (PLH_MID_U + du * (PLH_RADIUS - PLH_WIDTH)); + v2 = (PLH_MID_V + dv * (PLH_RADIUS - PLH_WIDTH)); + + if (i > 0) + { + + float fWDepthBodge = PANEL_GetNextDepthBodge(); + float fZDepthBodge = 1.0f - fWDepthBodge; + + pp[0].X = PLH_MID_X + (u1 - PLH_MID_U); + pp[0].Y = PLH_MID_Y + (v1 - PLH_MID_V); + pp[0].z = fZDepthBodge; + pp[0].Z = fWDepthBodge; + pp[0].x = 0.0F; + pp[0].y = 0.0F; + pp[0].u = u1 * (1.0F / 256.0F); + pp[0].v = v1 * (1.0F / 256.0F); + pp[0].colour = 0xffffffff; + pp[0].specular = 0xff000000; + + pp[1].X = PLH_MID_X + (u2 - PLH_MID_U); + pp[1].Y = PLH_MID_Y + (v2 - PLH_MID_V); + pp[1].z = fZDepthBodge; + pp[1].Z = fWDepthBodge; + pp[1].x = 0.0F; + pp[1].y = 0.0F; + pp[1].u = u2 * (1.0F / 256.0F); + pp[1].v = v2 * (1.0F / 256.0F); + pp[1].colour = 0xffffffff; + pp[1].specular = 0xff000000; + + pp[2].X = PLH_MID_X + (last_u1 - PLH_MID_U); + pp[2].Y = PLH_MID_Y + (last_v1 - PLH_MID_V); + pp[2].z = fZDepthBodge; + pp[2].Z = fWDepthBodge; + pp[2].x = 0.0F; + pp[2].y = 0.0F; + pp[2].u = last_u1 * (1.0F / 256.0F); + pp[2].v = last_v1 * (1.0F / 256.0F); + pp[2].colour = 0xffffffff; + pp[2].specular = 0xff000000; + + pp[3].X = PLH_MID_X + (last_u2 - PLH_MID_U); + pp[3].Y = PLH_MID_Y + (last_v2 - PLH_MID_V); + pp[3].z = fZDepthBodge; + pp[3].Z = fWDepthBodge; + pp[3].x = 0.0F; + pp[3].y = 0.0F; + pp[3].u = last_u2 * (1.0F / 256.0F); + pp[3].v = last_v2 * (1.0F / 256.0F); + pp[3].colour = 0xffffffff; + pp[3].specular = 0xff000000; + + POLY_add_quad(quad, POLY_PAGE_LASTPANEL2_ALPHA, FALSE, TRUE); + } + + last_u1 = u1; + last_v1 = v1; + last_u2 = u2; + last_v2 = v2; + + angle += dangle; + } + } + + // + // Draw the stamina marks + // + + { + UBYTE i, stamina = darci->Genus.Person->Stamina / 25; + //SLONG x = 107; + //SLONG y = 480 - 36; + SLONG x = m_iPanelXPos + 107; + SLONG y = m_iPanelYPos - 36; + SLONG rgb[] = { 0x00FF0000, 0x00C04000, 0x00808000, 0x0040C000, 0x0000ff00 }; + + SATURATE(stamina,0,5); + + for (i=0;iused) + { + continue; + } + + thugly=FALSE; + + if (mb->track_thing) + { + Thing *p_track = TO_THING(mb->track_thing); + + mb->wx = p_track->WorldPos.X >> 8; + mb->wz = p_track->WorldPos.Z >> 8; + + extern SLONG is_person_dead(Thing *p_person); + + if (p_track->Class == CLASS_PERSON) + { + switch(p_track->Genus.Person->PersonType) + { + case PERSON_THUG_RASTA: + case PERSON_THUG_GREY: + case PERSON_THUG_RED: + case PERSON_MIB1: + case PERSON_MIB2: + case PERSON_MIB3: + thugly=TRUE; + } + if (p_track->State == STATE_DEAD) + { + + // + // Don't draw beacons to dead people. + // + + if (p_track->SubState == SUB_STATE_DEAD_INJURED) + { + // + // Except if they're only injured... + // + + if (p_track->Genus.Person->pcom_ai == PCOM_AI_FIGHT_TEST) + { + // + // Except if they're fight test dummies! + // + + continue; + } + } + else + { + continue; + } + } + } + } + + colour = PANEL_beacon_colour[i % PANEL_MAX_BEACON_COLOURS] | (0xff000000); + + // + // Work out the distance and relative angle of this beacon from darci. + // + + dx = float(mb->wx - (darci->WorldPos.X >> 8)); + dz = float(mb->wz - (darci->WorldPos.Z >> 8)); + + dist = sqrt(dx*dx + dz*dz); + + /* + + if (dist < 256.0F * 4.0F) + { + score = dist * (1.0F / (256.0F * 4.0F)); + score *= 2.0F * PI * 22.0F / 360.0F; + + PANEL_funky_quad( + PANEL_IC_DOT, + PANEL_IC_SCANX - 7.0F, + PANEL_IC_SCANY - 7.0F, + PANEL_PAGE_ALPHA_END, + colour); + } + else + */ + { + UBYTE is_dot=0; + + if (PANEL_scanner_poo) + dangle = atan2(dx,dz) - float(darci->Draw.Tweened->Angle) * (2.0F * PI / 2048.0F); + else + dangle = atan2(dx,dz) - float(FC_cam[0].yaw>>8) * (2.0F * PI / 2048.0F); + score = (float)fmod(dangle, 2.0F * PI) - PI; + + if (score > +PI) {score -= 2.0F * PI;} + if (score < -PI) {score += 2.0F * PI;} + + //dist -= 3.0F * 256.0F; + dist /= 16.0F * 256.0F; + + if (dist < 1.0F) is_dot=1; + + SATURATE(dist, 0.0F, 1.0F); + + #define PLS_MID_X PLH_MID_X + #define PLS_MID_Y PLH_MID_Y + #define PLS_RADIUS 50.0F + + //if (!(is_dot&&thugly)) // it'll get drawn by the thug scanner below + { + x = PLS_MID_X + (float)sin(dangle) * PLS_RADIUS * dist; + y = PLS_MID_Y + (float)cos(dangle) * PLS_RADIUS * dist; + + float size = (mb->pad&&!is_dot) ? 9.0F : 6.0F; + + + SLONG alive = GetTickCount() - mb->ticks; + + if (alive < 4096) + { + alive &= 0x100; + + SATURATE(alive, 0, 255); + + colour &= 0x00ffffff; + colour |= alive << 24; + + + /* + + SLONG r = (colour >> 16) & 0xff; + SLONG g = (colour >> 8) & 0xff; + SLONG b = (colour >> 0) & 0xff; + + r = r * alive >> 8; + g = g * alive >> 8; + b = b * alive >> 8; + + colour = 0xff000000 | (r << 16) | (g << 8) | b; + + */ + } + + PANEL_last_arrow(x,y, dangle, size, colour, is_dot); + } + } + + if (fabs(score) < best_score) + { + best_score = fabs(score); + best_beacon = i; + } + + mb->pad = FALSE; + } + + if (PANEL_info_time > GetTickCount() - 2000) + { + SLONG x_right; + + SLONG colour_main; + SLONG colour_shad; + +// if (!WITHIN(PANEL_info_time, GetTickCount() - 1100, GetTickCount() - 900)) + + + SLONG now = GetTickCount(); + SLONG onfor = now - PANEL_info_time; + + if (onfor < 255) + { + colour_main = onfor; + colour_shad = onfor; + } + else + if (onfor < 768) + { + colour_main = 0xff; + colour_shad = 255 - (onfor - 256 >> 1); + } + else + { + colour_main = 0xff; + colour_shad = 0x00; + } + + x_right = onfor >> 1; + + SATURATE(colour_main, 0, 255); + SATURATE(colour_shad, 0, 255); + //SATURATE(x_right, 16, 205); + SATURATE(x_right, 16, 205); + + x_right += m_iPanelXPos; + + colour_main = colour_main | (colour_main << 8) | (colour_main << 16); + colour_shad = colour_shad | (colour_shad << 8) | (colour_shad << 16); + + { + FONT2D_DrawStringRightJustifyNoWrap( + PANEL_info_message, + x_right + 2, + m_iPanelYPos - 23 + 2, //457 + 2, + colour_shad, + 256); + + FONT2D_DrawStringRightJustifyNoWrap( + PANEL_info_message, + x_right, + m_iPanelYPos - 23, //457, + colour_main, + 256); + } + } + else + { + if (best_beacon) + { + ASSERT(WITHIN(best_beacon, 1, MAP_MAX_BEACONS - 1)); + + mb = &MAP_beacon[best_beacon]; + + extern CBYTE *EWAY_get_mess(SLONG index); +#ifndef TARGET_DC + extern UBYTE sw_hack; + + if (!sw_hack) +#endif + { + FONT2D_DrawString( + EWAY_get_mess(mb->index), + m_iPanelXPos + 12 + 2, //12 + 2, + m_iPanelYPos - 23 + 2, //457 + 2, + 0x00000000, + 256); + } + + FONT2D_DrawString( + EWAY_get_mess(mb->index), + m_iPanelXPos + 12, //12 + m_iPanelYPos - 23, //457, + PANEL_beacon_colour[best_beacon % PANEL_MAX_BEACON_COLOURS], + 256); + + mb->pad = TRUE; + } + } + } + + // + // Draw the thugs on the scanner. + // + + { + SLONG i; + + float x; + float y; + float dx; + float dz; + float dist; + float dangle; + float size; + float flash = fabs(sin(float(GAME_TURN) * 0.2F)); + SLONG display; + ULONG colour; + + PANEL_Lsprite *pls = &PANEL_lsprite[PANEL_LSPRITE_DOT]; + + SLONG num_found = THING_find_sphere( + darci->WorldPos.X >> 8, + darci->WorldPos.Y >> 8, + darci->WorldPos.Z >> 8, + 0x1000, + THING_array, + THING_ARRAY_SIZE, + 1 << CLASS_PERSON); + + Thing *p_found; + + for (i = 0; i < num_found; i++) + { + p_found = TO_THING(THING_array[i]); + + if (p_found == darci) + { + continue; + } + + if (p_found->State == STATE_DEAD) + { + continue; + } + + display = FALSE; + + switch(p_found->Genus.Person->PersonType) + { + case PERSON_THUG_RASTA: + case PERSON_THUG_GREY: + case PERSON_THUG_RED: + display = TRUE; + size = 0.5F; + colour = 0xdd2222; + break; + + case PERSON_MIB1: + case PERSON_MIB2: + case PERSON_MIB3: + display = TRUE; + size = 0.5F; + colour = 0xdddddd; + break; + + default: + break; + } + + if (PCOM_person_wants_to_kill(p_found) == THING_NUMBER(darci)) + { + display = TRUE; + size = flash; + } + + if (display) + { + dx = float(p_found->WorldPos.X - darci->WorldPos.X >> 8); + dz = float(p_found->WorldPos.Z - darci->WorldPos.Z >> 8); + + dist = sqrt(dx*dx + dz*dz); + dist *= 1.0F / (16.0F * 256.0F); + + if (dist < 1.0F) + { + if (PANEL_scanner_poo) + { + dangle = atan2(dx,dz) - float(darci->Draw.Tweened->Angle) * (2.0F * PI / 2048.0F); + } + else + { + dangle = atan2(dx,dz) - float(FC_cam[0].yaw>>8) * (2.0F * PI / 2048.0F); + } + + x = PLS_MID_X + (float)sin(dangle) * PLS_RADIUS * dist; + y = PLS_MID_Y + (float)cos(dangle) * PLS_RADIUS * dist; + + size += 0.5F; + size *= 2.0F; + + PANEL_draw_quad( + x - size, y - size, + x + size, y + size, + POLY_PAGE_LASTPANEL_ADD, + colour, + pls->u1, + pls->v1, + pls->u2, + pls->v2); + } + } + } + } + + // + // Draw the text messages. + // + + PANEL_new_text_process(); + + { + #define PLT_X 214 + #define PLT_Y 360 + + SLONG i; + SLONG ybase; + SLONG y = m_iPanelYPos - ( 480 - PLT_Y ); + // Left edge. + SLONG x1 = ( m_iPanelXPos < 260 ) ? ( m_iPanelXPos + PLT_X ) : ( 32 ); + // Right edge. + SLONG x2 = ( m_iPanelXPos < 260 ) ? ( 640 - 32 ) : ( m_iPanelXPos - 16 ); + SLONG height; + + PANEL_Text *pt; + + + + // This is a very clunky bodge, in coversations multiple lines + // of text are added but none are removed from the tail, so when + // we come back the difference between head and tail can be over + // the maximum buffer length, which will then wrap around and display + // the same message multiple times, therefore if we have more than + // PANEL_MAX_TEXTS messages we need to shift our head forwards.to + // remove those bogus messages. + + // Nicked from the PSX. Oh, and "klunky" is spelled thusly - TomF. + + if ((PANEL_text_tail-PANEL_text_head)>PANEL_MAX_TEXTS) + { + PANEL_text_head=PANEL_text_tail-(PANEL_MAX_TEXTS-1); + } + + + + for (i = PANEL_text_head; i < PANEL_text_tail; i++) + { + pt = &PANEL_text[i & (PANEL_MAX_TEXTS - 1)]; + + if (i == PANEL_text_head) + { + if (pt->delay == 0) + { + PANEL_text_head += 1; + } + } + + if (pt->delay != 0) + { + // + // Draw this message. Start off with the face. + // + + ybase = y; + + PANEL_new_face( + pt->who, + x1, + ybase - 2, + PANEL_FACE_SMALL); + + // + // The text.... + // + + height = FONT2D_DrawStringWrapTo ( pt->text, + x1 + 36 + 6, + y+2, + 0xffffff, + 256, + POLY_PAGE_FONT2D, + 0, + x2 + ) - y; + height += 20; + + // + // The speech bubble. + // + + PANEL_last_bubble( + x1 + 36, + ybase - 4, + float(FONT2D_rightmost_x) + 6.0F, + ybase - 2 + height); + +#ifdef TARGET_DC + // draw it again, so it's brighter. + FONT2D_DrawStringWrapTo ( pt->text, + x1 + 36 + 6, + y+2, + 0xffffff, + 256, + POLY_PAGE_FONT2D, + 0, + x2 + ); + +#endif + + if (height < 34) + { + height = 34; + } + + y += height; + } + } + } + + +#ifdef TARGET_DC + // This is instead of that wank PANEL_draw_buffered tripe. + if ( slPANEL_draw_timer_time >= 0 ) + { + float time = slPANEL_draw_timer_time * ( 1.0f / 100.0f ); + + CBYTE countdown[8]; + + SLONG mins = 0; + + ASSERT(time < 1000.0F); + + while(time >= 60.0F) + { + mins += 1; + time -= 60.0F; + } + + sprintf(countdown, "%02d:%02d", mins, SLONG(time)); + + if ((time<30)&&!mins) + { + static UWORD pulse=0; + SLONG colour; + pulse+=(TICK_RATIO*80)>>TICK_SHIFT; + colour=(SIN(pulse&2047)>>9)+128; + colour=colour|(colour<<8); + FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xff0000|colour, 256 + 64); + } + else + { + FONT2D_DrawStringCentred(countdown, m_iPanelXPos + 171, m_iPanelYPos - 118, 0xffffff, 256 + 64); + } + + slPANEL_draw_timer_time = -1; + } +#endif + + + // + // Draw the signs. + // + + SLONG dtime = GetTickCount() - PANEL_sign_time; + + if (dtime < 3000) + { + dtime %= 600; + + if (dtime < 400) + { + float du; + float dv; + + float u_mid; + float v_mid; + + u_mid = (PANEL_sign_which & 1) ? 0.75F : 0.25F; + v_mid = (PANEL_sign_which & 2) ? 0.75F : 0.25F; + + du = (PANEL_sign_flip & PANEL_SIGN_FLIP_LEFT_AND_RIGHT) ? -0.25F : +0.25F; + dv = (PANEL_sign_flip & PANEL_SIGN_FLIP_TOP_AND_BOTTOM) ? -0.25F : +0.25F; + + #define PANEL_SIGN_X 320 + //#define PANEL_SIGN_Y 100 + int iYPos; + if ( bPanelIsAtBottomOfScreen ) + { + iYPos = 100; + } + else + { + iYPos = 480 - 100; + } + + PANEL_draw_quad( + PANEL_SIGN_X - 64, + iYPos - 64, + PANEL_SIGN_X + 64, + iYPos + 64, + POLY_PAGE_SIGN, + 0xffffffff, + u_mid - du, + v_mid - dv, + u_mid + du, + v_mid + dv); + } + } + + // + // The panel search mode. + // + + { + Thing *darci = NET_PERSON(0); + + if(darci) + { + if(darci->State==STATE_SEARCH) + { + // + // Percentage complete... + // + + float percent; + + percent = darci->Genus.Person->Timer1 * (1.0F / (100.0F * 256.0F)); + + SATURATE(percent, 0.0F, 1.0F); + + // + // Draw the background box... + // + + PANEL_last_bubble( + 320 - 80, + 220 - 16, + 320 + 80, + 220 + 16); + + // + // The completion bar... + // + + PANEL_draw_quad( + 320 - 75, + 220 - 12, + 320 - 75 + 151 * percent, + 220 + 13, + POLY_PAGE_COLOUR, + 0x7788bb); + + if ((darci->Genus.Person->Timer1 & 0xfff) < 3000 || percent == 1.0F) + { + CBYTE *text; + + if (percent == 1.0F) + { + text = XLAT_str(X_COMPLETE); + } + else + { + text = XLAT_str(X_SEARCHING); + } + + FONT2D_DrawStringCentred(text, 320, 220 - 8, 0xffffff); + } + } + } + } + + { + + int iYPos = bPanelIsAtBottomOfScreen ? 0 : 360; + + +#ifdef TARGET_DC + extern bool g_bShowDarcisPositionOnScreen; + CBYTE text[64]; + if ( g_bShowDarcisPositionOnScreen ) + { + sprintf(text, "Darci is at (%d,%d)", NET_PERSON(0)->WorldPos.X >> 16, NET_PERSON(0)->WorldPos.Z >> 16); + PANEL_crap_text ( 320, iYPos + 40, text ); + } + + extern bool g_bCheatsEnabled; + if ( g_bCheatsEnabled ) + { + sprintf(text, "Cheats are enabled" ); + PANEL_crap_text ( 320, iYPos + 20, text ); + } + + extern bool m_bTweakFramerates; + extern int m_iDCFramerateMin; + extern int m_iDCFramerateMax; + extern SLONG CurDrawDistance; + if ( m_bTweakFramerates ) + { + sprintf(text, "Lo %i, hi %i, draw %f", m_iDCFramerateMin, m_iDCFramerateMax, (float)CurDrawDistance / 256.0f ); + PANEL_crap_text ( 320, iYPos + 100, text ); + } + +#endif + +#ifdef DEBUG +#ifdef TARGET_DC + // Show the cheat string on screen. + extern char cCheatString[]; + if ( cCheatString[0] != '\0' ) + { + sprintf(text, "Cheat string: <%s>", cCheatString ); + PANEL_crap_text ( 320, iYPos + 80, text ); + } +#endif + +#if 0 + // Show the fog table mode stuff. +extern float m_fFogTableDebugStart; +extern float m_fFogTableDebugEnd; +extern float m_fFogTableDebugDensity; +extern DWORD m_dwFogTableDebugFogTableMode; + char *pcMode; + switch ( m_dwFogTableDebugFogTableMode ) + { + case D3DFOG_LINEAR: + pcMode = "Lin"; + break; + case D3DFOG_EXP: + pcMode = "Exp"; + break; + case D3DFOG_EXP2: + pcMode = "Exp2"; + break; + case D3DFOG_NONE: + pcMode = "None"; + break; + default: + pcMode = "None"; + break; + } + sprintf ( text, "Start %f, end %f, density %f, mode %s", + m_fFogTableDebugStart, + m_fFogTableDebugEnd, + m_fFogTableDebugDensity, + pcMode ); + PANEL_crap_text ( 20, iYPos + 100, text ); +#endif + +#endif + + +#ifdef TARGET_DC +#ifdef _DEBUG +extern int g_iCacheReplacements; +extern bool g_bCacheReplacementThrash; + // Show the cache performance. + static char cCacheHistory[31] = "\0"; + + for ( int i = 29; i > 0; i-- ) + { + cCacheHistory[i] = cCacheHistory[i-1]; + } + cCacheHistory[30] = '\0'; + if ( g_iCacheReplacements > 0 ) + { + if ( g_iCacheReplacements < 100 ) + { + cCacheHistory[0] = "0123456789"[g_iCacheReplacements/10]; + } + else + { + // Nads - way too many. + cCacheHistory[0] = '+'; + } + } + else + { + cCacheHistory[0] = ' '; + } + + PANEL_crap_text ( 320, iYPos + 60, cCacheHistory ); + if ( g_bCacheReplacementThrash ) + { + // Thrash! + PANEL_crap_text ( 310, iYPos + 60, "T" ); + } + g_iCacheReplacements = 0; + g_bCacheReplacementThrash = FALSE; + + // And show the actual cache behaviour. +extern int m_iLRUQueueSize; +extern DWORD m_dwSizeOfQueue; + sprintf ( text, "Length %i, size %i", + m_iLRUQueueSize, + m_dwSizeOfQueue ); + PANEL_crap_text ( 310, iYPos + 80, text ); + +#endif +#endif + } + + + #ifndef TARGET_DC + + extern SLONG FARFACET_num_squares_drawn; + + { + CBYTE text[64]; + + sprintf(text, "FARFACET squares drawn: %d", FARFACET_num_squares_drawn); + + + + FONT2D_DrawString( + text, + 51, + 51, + 0x000000, + 256, + POLY_PAGE_FONT2D, + 0); + + FONT2D_DrawString( + text, + 50, + 50, + 0xffffff, + 256, + POLY_PAGE_FONT2D, + 0); + + } + + + extern UBYTE just_asked_for_mode_now; + extern UBYTE just_asked_for_mode_number; + extern float music_volume; + extern SLONG MUSIC_is_playing(void); + + + #ifdef _DEBUG + if (just_asked_for_mode_now) + { + just_asked_for_mode_now = FALSE; + + CBYTE text[64]; + + sprintf(text, "music mode %d vol %f %s", just_asked_for_mode_number, music_volume, (MUSIC_is_playing()) ? "Playing" : "Silence"); + + FONT2D_DrawString( + text, + 320, + 200, + 0xffff, + 256, + POLY_PAGE_FONT2D, + 0); + } + #endif + #endif + + + +#ifndef TARGET_DC + static SLONG i_know = 0; + static SLONG the_answer = 0; + + if (!i_know) + { + the_answer = ENV_get_value_number("iamapsx",FALSE); + i_know = TRUE; + } + + if (the_answer) + { + FONT2D_DrawString("PSX mode", 7, 17, 0x000000); + FONT2D_DrawString("PSX mode", 5, 15, 0xff2288); + } +#endif + +#ifndef TARGET_DC + { + static ULONG timestamp_colour = 0; + static CBYTE version_number[128]; + + if (Keys[KB_V]) + { + timestamp_colour = 0xf0f0f0f0; + } + + if (timestamp_colour) + { + if (!version_number[0]) + { + CBYTE ts[256]; + float vn; + + sprintf(ts, __DATE__); + + CBYTE *month[12] = + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + SLONG i; + + vn = 0.0F; + + for (i = 0; i < 12; i++) + { + if (toupper(ts[0]) == toupper(month[i][0]) && + toupper(ts[1]) == toupper(month[i][1]) && + toupper(ts[2]) == toupper(month[i][2])) + { + vn = i - 8.0F; + } + } + + SLONG day = atoi(ts + 4); + + vn += day * 0.03F; + + SLONG year = atoi(ts + 7); + + vn += (year - 1999) * 12; + + sprintf(version_number, "Version number %.2f : Compiled %s", vn, __DATE__); + } + + timestamp_colour -= 0x10101010; + + // + // Show the version number. + // + + FONT2D_DrawString( + version_number, + 22, + 22, + 0x00000000); + + FONT2D_DrawString( + version_number, + 20, + 20, + timestamp_colour); + } + } +#endif + + + + +#if 0 + // FINAL BUILD DONE! HOORAY! + +#ifdef TARGET_DC + // Just for non-final builds. + static CBYTE version_number[64] = ""; + + if ( version_number[0] == '\0' ) + { + CBYTE ts[40] = __DATE__; + float vn; + + CBYTE *month[12] = + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + SLONG i; + + vn = 0.0F; + + for (i = 0; i < 12; i++) + { + if (toupper(ts[0]) == toupper(month[i][0]) && + toupper(ts[1]) == toupper(month[i][1]) && + toupper(ts[2]) == toupper(month[i][2])) + { + vn = i - 8.0F; + } + } + + SLONG day = atoi(ts + 4); + + vn += day * 0.03F; + + SLONG year = atoi(ts + 7); + + vn += (year - 1999) * 12; + + sprintf(version_number, "Version %.2f", vn ); + } + + +extern bool bDontShowThePauseScreen; + if ( !bDontShowThePauseScreen ) + { + FONT2D_DrawString( + "(C)2000 Mucky Foot Productions", + 20, + 20, + 0xffffffff); + + FONT2D_DrawString( + "Test version - not for release", + 20, + 35, + 0xffffffff); + + FONT2D_DrawString( + version_number, + 20, + 50, + 0xffffffff); + } + +#endif + +#endif + + + //TRACE ( "PDo" ); + +} + + +#ifdef TARGET_DC + +static int iVMUAmmoDrawCountdown = 0; + +static VMU_Screen vmuscreenTemp; + + +// The byte patterns of numbers. +#define FROM_BINARY(a,b,c,d,e) ( (a<<4) | (b<<3) | (c<<2) | (d<<1) | (e<<0) ) +UBYTE bNumberPattern[11][7] = +{ + { // 0 + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,1,1,1,0 ), + }, + { // 1 + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,1,1,1,1 ), + }, + { // 2 + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,1,1,0,0 ), + FROM_BINARY ( 1,1,0,0,0 ), + FROM_BINARY ( 1,1,1,1,1 ), + }, + { // 3 + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,1,1,1,0 ), + }, + { // 4 + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,1,1,1 ), + FROM_BINARY ( 0,1,1,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,1,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + }, + { // 5 + FROM_BINARY ( 1,1,1,1,1 ), + FROM_BINARY ( 1,1,0,0,0 ), + FROM_BINARY ( 1,1,1,1,0 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,1,1,1,0 ), + }, + { // 6 + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 1,1,0,0,0 ), + FROM_BINARY ( 1,1,1,1,0 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,1,1,1,0 ), + }, + { // 7 + FROM_BINARY ( 1,1,1,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,1,1,1 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 0,1,1,0,0 ), + FROM_BINARY ( 0,1,1,0,0 ), + }, + { // 8 + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,1,1,1,0 ), + }, + { // 9 + FROM_BINARY ( 0,1,1,1,0 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 1,1,0,1,1 ), + FROM_BINARY ( 0,1,1,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,1,1,1,0 ), + }, + { // separator dot. + FROM_BINARY ( 0,0,0,0,0 ), + FROM_BINARY ( 0,0,0,0,0 ), + FROM_BINARY ( 0,0,0,1,1 ), + FROM_BINARY ( 0,0,1,1,1 ), + FROM_BINARY ( 0,0,1,1,0 ), + FROM_BINARY ( 0,0,0,0,0 ), + FROM_BINARY ( 0,0,0,0,0 ), + }, +}; + +void Panel_Draw_VMU_Character ( int iCharacter, UBYTE *pbScanline, int iXpos ) +{ + // Can't do anything too close to the left edge. + ASSERT ( iXpos < ( 48 - 16 ) ); + // Go to correct X pos (right-hand byte). + pbScanline += 5 - ( iXpos >> 3 ); + + UBYTE *pbSrc = bNumberPattern[iCharacter]; + int iShift = iXpos & 0x7; + + for ( int i = 0; i < 7; i++ ) + { + UWORD uwSrc = (UWORD)*pbSrc++; + uwSrc <<= iShift; + + *(pbScanline-0) |= (UBYTE)( uwSrc & 0xff ); + *(pbScanline-1) |= (UBYTE)( uwSrc >> 8 ); + + pbScanline += 6; + } +} + + +void PANEL_draw_VMU_ammo_counts ( void ) +{ + iVMUAmmoDrawCountdown--; + if ( iVMUAmmoDrawCountdown > 0 ) + { + return; + } + + iVMUAmmoDrawCountdown = 30; + + + + // OK, find out how much ammo of each sort we have, and whether we have the weapons or not. + + + // This order matches the order on the VMU screen. + enum eWeaponNumber + { + WEAP_PISTOL = 0, + WEAP_SHOTGUN = 1, + WEAP_M16 = 2, + WEAP_GRENADE = 3, + }; + + int i; + bool bHaveWeapon[4]; + int iAmmo[4]; + int iMags[4]; + for ( i = 0; i < 4; i++ ) + { + bHaveWeapon[i] = FALSE; + iAmmo[i] = 0; + iMags[i] = 0; + } + + // Run through the weapons. + Thing *darci = NET_PERSON(0); + Thing *p_special = NULL; + + // The pistol is special. + if (darci->Flags & FLAGS_HAS_GUN) + { + bHaveWeapon[WEAP_PISTOL] = TRUE; + } + + + // THIS IS FUCKING INSANE GUYS. So I'm just going to type it in, and if it doesn't work, it's your fault. + iMags[WEAP_PISTOL] = darci->Genus.Person->ammo_packs_pistol / 15; + iAmmo[WEAP_PISTOL] = darci->Genus.Person->Ammo; + + iMags[WEAP_SHOTGUN] = darci->Genus.Person->ammo_packs_shotgun / SPECIAL_AMMO_IN_A_SHOTGUN; + iMags[WEAP_M16] = darci->Genus.Person->ammo_packs_ak47 / SPECIAL_AMMO_IN_A_AK47; + + ASSERT ( ( darci->Genus.Person->ammo_packs_pistol % 15 ) == 0 ); + ASSERT ( ( darci->Genus.Person->ammo_packs_ak47 % SPECIAL_AMMO_IN_A_AK47 ) == 0 ); + ASSERT ( ( darci->Genus.Person->ammo_packs_shotgun % SPECIAL_AMMO_IN_A_SHOTGUN ) == 0 ); + + if ( darci->Genus.Person->SpecialList != NULL ) + { + p_special = TO_THING(darci->Genus.Person->SpecialList); + + while(p_special) + { + ASSERT(p_special->Class == CLASS_SPECIAL); + switch ( p_special->Genus.Special->SpecialType ) + { + case SPECIAL_SHOTGUN: + // We have a shotty. + ASSERT ( !bHaveWeapon[WEAP_SHOTGUN] ); + bHaveWeapon[WEAP_SHOTGUN] = TRUE; + iAmmo[WEAP_SHOTGUN] = p_special->Genus.Special->ammo; + break; + case SPECIAL_AK47: + // We have an AK47, which we now call an M16. + ASSERT ( !bHaveWeapon[WEAP_M16] ); + bHaveWeapon[WEAP_M16] = TRUE; + iAmmo[WEAP_M16] = p_special->Genus.Special->ammo; + break; + case SPECIAL_GRENADE: + // Should only have one grenade special. + ASSERT ( !bHaveWeapon[WEAP_GRENADE] ); + bHaveWeapon[WEAP_GRENADE] = TRUE; + iAmmo[WEAP_GRENADE] = p_special->Genus.Special->ammo; + if ( iAmmo[WEAP_GRENADE] == 0 ) + { + // Er... this means we don't have grenades. + bHaveWeapon[WEAP_GRENADE] = FALSE; + } + break; + default: + // You think I care? + break; + } + + if (p_special->Genus.Special->NextSpecial) + p_special = TO_THING(p_special->Genus.Special->NextSpecial); + else + p_special = NULL; + } + } + + + // Crappy fudge. Driving Bronze and other training missions start you off + // with 15 pistol rounds, but no pistol, which is silly. So if we don't have a + // a pistol, pretend we have no rounds or clips as well. + if ( !bHaveWeapon[WEAP_PISTOL] ) + { + iAmmo[WEAP_PISTOL] = 0; + iMags[WEAP_PISTOL] = 0; + } + +extern VMU_Screen *pvmuscreenAmmo; + + // Copy the weapon bitmaps over. + memcpy ( vmuscreenTemp.bData, pvmuscreenAmmo->bData, 32 * 6 ); + vmuscreenTemp.bRotated = FALSE; + +#define WEAPON_BAR_SCANLINE_SIZE 8 + for ( i = 0; i < 4; i++ ) + { + if ( !bHaveWeapon[i] ) + { + if ( ( iAmmo[i] == 0 ) && ( iMags[i] == 0 ) ) + { + // No ammo or mags and we don't have it. So blank it. + memset ( vmuscreenTemp.bData + 6 * WEAPON_BAR_SCANLINE_SIZE * i, 0, 6 * WEAPON_BAR_SCANLINE_SIZE ); + } + else + { + // We have some ammo, but don't actually have the weapon yet. Grey it out. + UBYTE *pbScreen = vmuscreenTemp.bData + 6 * WEAPON_BAR_SCANLINE_SIZE * i; + UBYTE bMask = 0x55; + for ( int j = 0; j < WEAPON_BAR_SCANLINE_SIZE; j++ ) + { + *pbScreen++ &= bMask; + *pbScreen++ &= bMask; + *pbScreen++ &= bMask; + *pbScreen++ &= bMask; + *pbScreen++ &= bMask; + *pbScreen++ &= bMask; + bMask = ~bMask; + } + } + } + + +// X positions of the left side of the char, counted from the left of the screen. +#define WEAPON_MAGS_TENS 22 +#define WEAPON_MAGS_UNIT 16 +#define WEAPON_SEPARATOR 12 +#define WEAPON_AMMO_TENS 6 +#define WEAPON_AMMO_UNIT 0 + + UBYTE *pbScreen = vmuscreenTemp.bData + 6 * WEAPON_BAR_SCANLINE_SIZE * i; + if ( iMags[i] > 0 ) + { + // Draw mag number. + if ( iMags[i] >= 10 ) + { + Panel_Draw_VMU_Character ( ( iMags[i] / 10 ), pbScreen, WEAPON_MAGS_TENS ); + } + Panel_Draw_VMU_Character ( ( iMags[i] % 10 ), pbScreen, WEAPON_MAGS_UNIT ); + // The separator - character 10. + Panel_Draw_VMU_Character ( 10, pbScreen, WEAPON_SEPARATOR ); + } + + if ( ( iMags[i] > 0 ) || ( iAmmo[i] > 0 ) || bHaveWeapon[i] ) + { + // Draw ammo number. + if ( iAmmo[i] >= 10 ) + { + Panel_Draw_VMU_Character ( ( iAmmo[i] / 10 ), pbScreen, WEAPON_AMMO_TENS ); + } + Panel_Draw_VMU_Character ( ( iAmmo[i] % 10 ), pbScreen, WEAPON_AMMO_UNIT ); + } + } + + // And write the screen out. + WriteLCDScreenToCurrentController ( &vmuscreenTemp ); + +#undef WEAPON_BAR_SCANLINE_SIZE +#undef WEAPON_MAGS_TENS +#undef WEAPON_MAGS_UNIT +#undef WEAPON_SEPARATOR +#undef WEAPON_AMMO_TENS +#undef WEAPON_AMMO_UNIT + +} + + +#endif + + +#ifndef TARGET_DC + +void PANEL_draw_completion_bar(SLONG completion) +{ + #define START_R 50 + #define START_G 59 + #define START_B 80 + + #define END_R 210 + #define END_G 216 + #define END_B 208 + + SLONG along; + + SLONG r; + SLONG g; + SLONG b; + +#ifndef TARGET_DC + POLY_frame_init(FALSE,FALSE); +#endif + + SLONG i; + + SLONG colour; + + for (i = 0; i < (completion >> 3); i += 1) + { + r = START_R + (END_R - START_R) * i >> 5; + g = START_G + (END_G - START_G) * i >> 5; + b = START_B + (END_B - START_B) * i >> 5; + + colour = (r << 16) | (g << 8) | (b << 0); + + PANEL_draw_quad( + 5 + i * 20, 455, + 23 + i * 20, 475, + POLY_PAGE_COLOUR, + colour); + } + +#ifndef TARGET_DC + POLY_frame_draw(FALSE,FALSE); +#endif +} + +#endif + + + + + + +bool bScreensaverEnabled = FALSE; +// Darkness of screensaver, from 0(off)->0xffff(full on) +int iScreenSaverDarkness = 0; + +int iScreensaverXPos = 320; +int iScreensaverYPos = 240; +int iScreensaverXInc = 4; +int iScreensaverYInc = 4; +int iScreensaverAngle = 0; +int iScreensaverAngleInc = 0x2ff; + +DWORD dwPseudorandomSeed = 0; + +DWORD dwGetRandomishNumber ( void ) +{ + dwPseudorandomSeed *= 51929; + dwPseudorandomSeed ^= dwPseudorandomSeed >> 3; + dwPseudorandomSeed ^= dwPseudorandomSeed << 8; + dwPseudorandomSeed += 31415; + + return ( dwPseudorandomSeed >> 8 ); +} + + +#define SCREENSAVER_SIZE 128 + +void PANEL_enable_screensaver ( void ) +{ + if ( !bScreensaverEnabled ) + { + bScreensaverEnabled = TRUE; + iScreensaverXPos = 320; + iScreensaverYPos = 240; + iScreensaverXInc = 4; + iScreensaverYInc = 4; + } +} + +void PANEL_disable_screensaver ( bool bImmediately ) +{ + bScreensaverEnabled = FALSE; + if ( bImmediately ) + { + // Bin the fade in. + iScreenSaverDarkness = 0; + } +} + +void PANEL_screensaver_draw ( void ) +{ + if ( bScreensaverEnabled ) + { + iScreenSaverDarkness += 100; + if ( iScreenSaverDarkness > 0xffff ) + { + iScreenSaverDarkness = 0xffff; + } + } + else + { + iScreenSaverDarkness -= 10000; + if ( iScreenSaverDarkness < 0 ) + { + iScreenSaverDarkness = 0; + } + } + + if ( iScreenSaverDarkness == 0 ) + { + // don't do it. + return; + } + + +#ifndef TARGET_DC + POLY_frame_init(FALSE,FALSE); +#endif + + + + // Bounce around the screen. + iScreensaverXPos += iScreensaverXInc; + iScreensaverYPos += iScreensaverYInc; + iScreensaverAngle += iScreensaverAngleInc; + if ( iScreensaverXPos > 640 - SCREENSAVER_SIZE ) + { + iScreensaverXPos = 640 - SCREENSAVER_SIZE; + iScreensaverXInc = -( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 ); + iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff ); + } + else if ( iScreensaverXPos < 0 ) + { + iScreensaverXPos = 0; + iScreensaverXInc = ( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 ); + iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff ); + } + + if ( iScreensaverYPos > 480 - SCREENSAVER_SIZE ) + { + iScreensaverYPos = 480 - SCREENSAVER_SIZE; + iScreensaverYInc = -( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 ); + iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff ); + } + else if ( iScreensaverYPos < 0 ) + { + iScreensaverYPos = 0; + iScreensaverYInc = ( (signed)( dwGetRandomishNumber() & 0x3 ) + 2 ); + iScreensaverAngleInc = ( (signed)( dwGetRandomishNumber() & 0xfff ) - 0x7ff ); + } + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + DWORD dwColour = ( ( iScreenSaverDarkness & 0xff00 ) << 16 ); + + float fSinAngle, fCosAngle; + float fAngle = (float)( iScreensaverAngle & 0xffff ) * ( 2.0f * 3.1415927f / 65536.0f ); +#ifdef TARGET_DC + _SinCosA ( &fSinAngle, &fCosAngle, fAngle ); +#else + fSinAngle = sinf ( fAngle ); + fCosAngle = cosf ( fAngle ); +#endif + fSinAngle *= 0.65f; + fCosAngle *= 0.65f; + + // First draw the "spotlight" logo. + pp[0].X = (float)iScreensaverXPos; + pp[0].Y = (float)iScreensaverYPos; + pp[0].z = 0.0f; + pp[0].Z = 0.99999f; + pp[0].u = 0.5f + fSinAngle; + pp[0].v = 0.5f + fCosAngle; + pp[0].colour = dwColour; + pp[0].specular = 0xff000000; + + pp[1].X = (float)iScreensaverXPos + SCREENSAVER_SIZE; + pp[1].Y = (float)iScreensaverYPos; + pp[1].z = 0.0f; + pp[1].Z = 0.99999f; + pp[1].u = 0.5f - fCosAngle; + pp[1].v = 0.5f + fSinAngle; + pp[1].colour = dwColour; + pp[1].specular = 0xff000000; + + pp[2].X = (float)iScreensaverXPos; + pp[2].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + pp[2].z = 0.0f; + pp[2].Z = 0.99999f; + pp[2].u = 0.5f + fCosAngle; + pp[2].v = 0.5f - fSinAngle; + pp[2].colour = dwColour; + pp[2].specular = 0xff000000; + + pp[3].X = (float)iScreensaverXPos + SCREENSAVER_SIZE; + pp[3].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + pp[3].z = 0.0f; + pp[3].Z = 0.99999f; + pp[3].u = 0.5f - fSinAngle; + pp[3].v = 0.5f - fCosAngle; + pp[3].colour = dwColour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_FADE_MF, FALSE, TRUE); + + // Now draw the darkener around it. + // Top block. + pp[0].X = 0.0f; + pp[0].Y = 0.0f; + pp[1].X = 640.0f; + pp[1].Y = 0.0f; + pp[2].X = 0.0f; + pp[2].Y = (float)iScreensaverYPos; + pp[3].X = 640.0f; + pp[3].Y = (float)iScreensaverYPos; + POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE); + + // Bottom block. + pp[0].X = 0.0f; + pp[0].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + pp[1].X = 640.0f; + pp[1].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + pp[2].X = 0.0f; + pp[2].Y = 480.0f; + pp[3].X = 640.0f; + pp[3].Y = 480.0f; + POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE); + + // Left block. + pp[0].X = 0.0f; + pp[0].Y = (float)iScreensaverYPos; + pp[1].X = (float)iScreensaverXPos; + pp[1].Y = (float)iScreensaverYPos; + pp[2].X = 0.0f; + pp[2].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + pp[3].X = (float)iScreensaverXPos; + pp[3].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE); + + // Right block. + pp[0].X = (float)iScreensaverXPos + SCREENSAVER_SIZE; + pp[0].Y = (float)iScreensaverYPos; + pp[1].X = 640.0f; + pp[1].Y = (float)iScreensaverYPos; + pp[2].X = (float)iScreensaverXPos + SCREENSAVER_SIZE; + pp[2].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + pp[3].X = 640.0f; + pp[3].Y = (float)iScreensaverYPos + SCREENSAVER_SIZE; + POLY_add_quad(quad, POLY_PAGE_COLOUR_ALPHA, FALSE, TRUE); + + +#ifndef TARGET_DC + POLY_frame_draw(FALSE,FALSE); +#endif + +} diff --git a/fallen/DDEngine/Source/planmap.cpp b/fallen/DDEngine/Source/planmap.cpp new file mode 100644 index 0000000..acd675c --- /dev/null +++ b/fallen/DDEngine/Source/planmap.cpp @@ -0,0 +1,478 @@ +#include +#include +#include +#include "aeng.h" +#include "game.h" +#include "c:\fallen\headers\pap.h" +#include "c:\fallen\headers\road.h" +#include "planmap.h" + + + + +#define EDGE_LEFT (1<<0) +#define EDGE_TOP (1<<1) +#define EDGE_RIGHT (1<<2) +#define EDGE_BOTTOM (1<<3) + +extern UBYTE player_visited[16][128]; + + + +UBYTE *screenmem; +SLONG clip_left,clip_right,clip_top,clip_bot; + + + +void draw_quick_rect(SLONG csx,SLONG csy,SLONG pixelw,SLONG red,SLONG green,SLONG blue) +{ + SLONG right,bot; + SLONG dx,dy; + UBYTE *mem; + ULONG mod; + + if(csy>=clip_bot || csx>=clip_right) + return; + + right=csx+pixelw; + bot =csy+pixelw; + + if(bot>=clip_bot) + bot=clip_bot-1; + + if(csy=clip_right) + { + right=clip_right-1; + } + + mod= (640*3) -(right-csx)*3; + mem = &screenmem[csx*3+csy*640*3]; + + for(dy=csy;dyclip_left && csx+pixelw < clip_right && csy>clip_top && csy+pixelw=clip_right||py=clip_bot) + continue; + } + + if(dx==0&& (edge&EDGE_LEFT)) + { + r=0; + g=0; + b=0; + } +/* + if(dx==pixelw-1&& (edge&EDGE_RIGHT)) + { + r=0; + g=0; + b=0; + } +*/ + if(dy==0&& (edge&EDGE_TOP)) + { + r=0; + g=0; + b=0; + } +/* + if(dy==pixelw-1&& (edge&EDGE_BOTTOM)) + { + r=0; + g=0; + b=0; + } +*/ + + + switch(shadow) + { + case 0: + break; + case 1: + // ..X + // .oX + // ,oX + + if(dx+dy>1)) + { + r>>=1; + g>>=1; + b>>=1; + } + break; + + case 6: + case 2: + // ,ox + // ,ox + // ,ox + if(dx<(pixelw>>1)) + { + r>>=1; + g>>=1; + b>>=1; + } + + break; + case 3: + // ,ox + // ,oo + // .,, + if(dx<(pixelw>>1) && dy>(pixelw>>1)) + { + r>>=1; + g>>=1; + b>>=1; + } + break; + case 4: + // xxx + // ooo + // ,,, + if(dy>(pixelw>>1)) + { + r>>=1; + g>>=1; + b>>=1; + } + break; + case 5: + // ... + // .. + // ... + if(dx<(pixelw>>1) || dy>(pixelw>>1)) + { + r>>=1; + g>>=1; + b>>=1; + } + break; + case 7: + // ... + // ... + // ... + if(dx+dy>pixelw && dy>(pixelw>>1)) + { + r>>=1; + g>>=1; + b>>=1; + } + break; + + } + + screenmem[px*3+2+py*640*3]=(UBYTE)r; + screenmem[px*3+1+py*640*3]=(UBYTE)g; + screenmem[px*3+0+py*640*3]=(UBYTE)b; + } + } +} + + + +UWORD screen_x,screen_y,screen_width,screen_height,block_size,screen_mx,screen_mz; +SLONG screen_pitch; + + +void get_screen_xy(SLONG *x,SLONG *z) +{ + SLONG rx,rz; + + rx=(*x); + rz=(*z); + + rx-=screen_mx; + rx*=block_size; + rx>>=8; + + rx+=screen_x+(screen_width>>1); + + rz-=screen_mz; + rz*=block_size; //screen_pitch; + rz>>=8; + + rz+=screen_y+(screen_height>>1); + + *x=rx; + *z=rz; + +} + +void map_beacon_draw(SLONG x,SLONG z,ULONG col,ULONG flag,UWORD dir) +{ + UBYTE radius; + SLONG screen_pitch; + SLONG mx,mz; + SLONG size=3; + + mx=x>>8; + mz=z>>8; + + // + // how many pixels per mapwho + // + + if(!(player_visited[mx>>3][mz]&(1<<(mx&7)))) + { + if (flag & BEACON_FLAG_BEACON) + { + // + // Always draw beacons. + // + } + else + { + return; + } + } + + get_screen_xy(&x,&z); + + if (flag & BEACON_FLAG_BEACON) + { + if(GAME_TURN&1) + size=6; + else + size=3; + } + + draw_shadow_rect(x-size,z-size,size<<1,0,0,0 ,0,0); + draw_shadow_rect(x-size+1,z-size+1,(size-1)<<1,col>>16,(col&0xff00)>>8,(col&0xff) ,0,0); + + if (flag & BEACON_FLAG_POINTY) + { + SLONG dx = -SIN(dir); + SLONG dz = -COS(dir); + + SLONG px; + SLONG pz; + + px = x + (dx >> 14); + pz = z + (dz >> 14); + + size -= 1; + + draw_shadow_rect(px-size,pz-size,size<<1,0,0,0 ,0,0); + + px = x + (dx >> 13); + pz = z + (dz >> 13); + + size -= 1; + + draw_shadow_rect(px-size,pz-size,size<<1,0,0,0 ,0,0); + } +} + +void plan_view_shot(SLONG wx,SLONG wz,SLONG pixelw,SLONG sx,SLONG sy,SLONG w,SLONG h,UBYTE *mem) +{ + SLONG minx,maxx,minz,maxz; + SLONG lminx,lmaxx,lminz,lmaxz; + SLONG x,z,csx,csy,c0; + SLONG r,g,b,shadow; + SLONG edge; + UBYTE *m; + + MFFileHandle image_file; + SLONG height; + UBYTE *image; + +extern UBYTE* image_mem; + memcpy(mem,image_mem,640*480*3); + // yay for disk caches :-p + + + screen_width=w; + screen_height=h; + screen_x=sx; + screen_y=sy; + screen_pitch=(screen_width<<8)/pixelw; + screen_mx=wx; + screen_mz=wz; + block_size=pixelw; + + m=mem; + + +/* for(c0=0;c0<640*480;c0++) + { + *m++=244; + *m++=231; + *m++=177; + }*/ + + clip_left=sx; + clip_right=sx+w; + clip_top=sy; + clip_bot=sy+h; + screenmem=mem; + + csx=sx; + csy=sy; + + minx=(wx>>8)-(w/(pixelw<<1))-1; + maxx=(wx>>8)+(w/(pixelw<<1))+1; + + minz=(wz>>8)-(h/(pixelw<<1))-1; + maxz=(wz>>8)+(h/(pixelw<<1))+1; + +// SATURATE(minx,0,127); +// SATURATE(minz,0,127); +// SATURATE(maxx,0,127); +// SATURATE(maxz,0,127); + + for(z=minz;z1&&x<127&&z>1&&z<127) + { + if(player_visited[x>>3][z]&(1<<(x&7))) + { + SLONG mh; + edge=0; + + mh=PAP_2HI(x,z).Height; + if(mh!=PAP_2HI(x-1,z).Height) + { + edge|=EDGE_LEFT; + } + if(mh!=PAP_2HI(x+1,z).Height) + { + edge|=EDGE_RIGHT; + } + if(mh!=PAP_2HI(x,z-1).Height) + { + edge|=EDGE_TOP; + } + if(mh!=PAP_2HI(x,z+1).Height) + { + edge|=EDGE_BOTTOM; + } + + + if((PAP_2HI(x,z).Flags&PAP_FLAG_HIDDEN)==0) + { + // + // draw the floor + // + + if (ROAD_is_road(x,z)) + { + r = 100; + g = 100; + b = 100; + + draw_shadow_rect(csx,csy,pixelw,r,g,b,0,edge); + } + else + { + shadow = PAP_2HI(x,z).Flags & 0x7; + + r = 177; + g = 231; + b = 244; + + if (shadow) + { + draw_shadow_rect(csx,csy,pixelw,r,g,b,shadow,edge); + } + } + + + + + } + else + { + r=((PAP_2HI(x,z).Height))+140; + if(r>255) + r=255; + g=r; + b=r; + if(player_visited[x>>3][z]&(1<<(x&7))) + { + // r=255; + } + + shadow = PAP_2HI(x,z).Flags & 0x7; + draw_shadow_rect(csx,csy,pixelw,r,g,b,shadow,edge); + } + } + else + ;// draw_quick_rect(csx,csy,pixelw,0,0,0); + + } + csx+=pixelw; + } + csx=sx; + csy+=pixelw; + } + + +} + + + diff --git a/fallen/DDEngine/Source/poly.cpp b/fallen/DDEngine/Source/poly.cpp new file mode 100644 index 0000000..b96ec05 --- /dev/null +++ b/fallen/DDEngine/Source/poly.cpp @@ -0,0 +1,5028 @@ +// +// Drawing polygons with D3D +// + +#include +#include +#include +#include "Game.h" // Guy - 4 DEMO +#include "matrix.h" +#include "poly.h" +#include "texture.h" +#include "message.h" +#include "night.h" +#ifndef TARGET_DC +#include "clip.h" +#endif +#include "vertexbuffer.h" +#include "polypoint.h" +#include "renderstate.h" +#include "polypage.h" +#include "eway.h" +#include "font2d.h" +#include "crinkle.h" +#include "night.h" +#include "BreakTimer.h" +#include "sw.h" +#include "superfacet.h" + + +#ifndef TARGET_DC + +#define LOG_ENTER(x) {} +#define LOG_EXIT(x) {} + +#endif + + + +extern D3DTexture TEXTURE_texture[]; + + +int iPolyNumPagesRender = 0; + + +#define COMBO_FALSE 0 +#define COMBO_TRUE 1 +#define COMBO_DIRTY 2 +int m_iCurrentCombo = COMBO_DIRTY; + +// +// position of near clipping plane +// + +#define POLY_Z_NEARPLANE POLY_ZCLIP_PLANE + +static UBYTE s_ClipMask; // the clip bits we care about + +#if USE_D3D_VBUF +#define STD_CLIPMASK (POLY_CLIP_LEFT | POLY_CLIP_RIGHT | POLY_CLIP_TOP | POLY_CLIP_BOTTOM | POLY_CLIP_NEAR) +#else +#define STD_CLIPMASK (POLY_CLIP_NEAR) +#endif + +#ifdef TARGET_DC +// DC clips sideways and up and down anyway. +#define NO_CLIPPING_TO_THE_SIDES_PLEASE_BOB 1 +// Can't enable this - problems. :-( +#define NO_BACKFACE_CULL_PLEASE_BOB 0 +#else +// PC should clip to sides fo screen +#define NO_CLIPPING_TO_THE_SIDES_PLEASE_BOB 0 +#define NO_BACKFACE_CULL_PLEASE_BOB 0 +#endif + +#ifdef EDITOR +// poly has ugly key stuff which makes a mess in the editors so cut it out awright? +extern HWND CUTSCENE_edit_wnd; +#endif + +// +// Flags for each standard texture page. +// + +UWORD POLY_page_flag[POLY_NUM_PAGES]; + +// +// some extern from somewhere which someone should put in a header file +// + +extern SLONG draw_3d; + +// +// The handy buffer +// + +POLY_Point POLY_buffer[POLY_BUFFER_SIZE]; +SLONG POLY_buffer_upto; + +POLY_Point POLY_shadow[POLY_SHADOW_SIZE]; +SLONG POLY_shadow_upto; + +// +// The vertex buffers for each texture page. +// + +RenderState DefRenderState; +PolyPage POLY_Page[POLY_NUM_PAGES]; + +// utility + +#define POLY_SWAP(pp1,pp2) {POLY_Point *pp_spare; pp_spare = (pp1); (pp1) = (pp2); (pp2) = pp_spare;} + +// +// The camera and the screen. +// + +float POLY_cam_x; +float POLY_cam_y; +float POLY_cam_z; +float POLY_cam_aspect; +float POLY_cam_lens; +float POLY_cam_view_dist; +float POLY_cam_over_view_dist; +float POLY_cam_matrix[9]; + +float POLY_screen_width; +float POLY_screen_height; +float POLY_screen_mid_x; +float POLY_screen_mid_y; +float POLY_screen_mul_x; +float POLY_screen_mul_y; + +float POLY_screen_clip_left=0; // these default values +float POLY_screen_clip_right=640; +float POLY_screen_clip_bottom=480; +float POLY_screen_clip_top=0; + +SLONG POLY_splitscreen; +ULONG POLY_colour_restrict; +ULONG POLY_force_additive_alpha; + +SLONG fade_point_more(POLY_Point *pp) +{ + SLONG fade; + + fade=(((SLONG)(pp->y))>>0); + + //fade=2000; +// fade=-fade; + + return(fade); + +} + + +// POLY_init +// +// init engine + +void POLY_init(void) +{ +#ifdef TEX_EMBED +#if !USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + SLONG i; + + for (int ii = 0; ii < 512; ii++) + { + float u_off = (ii & 3) * 0.25f; + float v_off = ((ii >> 2) & 3) * 0.25f; + POLY_Page[ii].SetTexEmbed(0.25f, u_off, 0.25f, v_off); + } +#endif +#endif +} + + +// Clears all poly pages. +void POLY_ClearAllPages ( void ) +{ + for ( int i = 0; i < POLY_NUM_PAGES; i++ ) + { + POLY_Page[i].Clear(); + } +} + + + + + + + + + +SLONG POLY_wibble_y1; +SLONG POLY_wibble_y2; +SLONG POLY_wibble_g1; +SLONG POLY_wibble_g2; +SLONG POLY_wibble_s1; +SLONG POLY_wibble_s2; +SLONG POLY_wibble_turn; +SLONG POLY_wibble_dangle1; +SLONG POLY_wibble_dangle2; + +void POLY_set_wibble( + UBYTE wibble_y1, + UBYTE wibble_y2, + UBYTE wibble_g1, + UBYTE wibble_g2, + UBYTE wibble_s1, + UBYTE wibble_s2) +{ + POLY_wibble_y1 = wibble_y1; + POLY_wibble_y2 = wibble_y2; + POLY_wibble_g1 = wibble_g1; + POLY_wibble_g2 = wibble_g2; + POLY_wibble_s1 = wibble_s1; + POLY_wibble_s2 = wibble_s2; + + POLY_wibble_turn += 256 * TICK_RATIO >> TICK_SHIFT; + + POLY_wibble_dangle1 = POLY_wibble_turn * POLY_wibble_g1 >> 9; + POLY_wibble_dangle2 = POLY_wibble_turn * POLY_wibble_g2 >> 9; +} + + +SLONG POLY_page_is_masked_self_illuminating(SLONG page) +{ + if (WITHIN(page, 0, POLY_NUM_PAGES - 1) && + (POLY_page_flag[page] & POLY_PAGE_FLAG_2PASS)) + { + return TRUE; + } + else + { + return FALSE; + } +} + + +#if USE_TOMS_ENGINE_PLEASE_BOB +D3DMATRIX g_matProjection; +D3DVIEWPORT2 g_viewData; +// Used to hack in letterbox mode. +DWORD g_dw3DStuffHeight; +DWORD g_dw3DStuffY; +#endif + + + + + +float POLY_cam_matrix_comb[9]; +float POLY_cam_off_x; +float POLY_cam_off_y; +float POLY_cam_off_z; + + + +#ifdef TARGET_DC + + +_inline void EnsureFTRVMatrix ( int iCombo ) +{ + // If this fails, you need to put POLY_flush_local_rot() just before it somewhere. + ASSERT ( m_iCurrentCombo == iCombo ); +} + + +_inline void SetupFTRVMatrix ( int iCombo ) +{ + D3DMATRIX matTemp; + if ( m_iCurrentCombo == iCombo ) + { + // Already done. + return; + } + else + { + m_iCurrentCombo = iCombo; + if ( iCombo != COMBO_FALSE ) + { + matTemp._11 = POLY_cam_matrix_comb[0]; + matTemp._12 = POLY_cam_matrix_comb[1]; + matTemp._13 = POLY_cam_matrix_comb[2]; + matTemp._14 = POLY_cam_off_x; + matTemp._21 = POLY_cam_matrix_comb[3]; + matTemp._22 = POLY_cam_matrix_comb[4]; + matTemp._23 = POLY_cam_matrix_comb[5]; + matTemp._24 = POLY_cam_off_y; + matTemp._31 = POLY_cam_matrix_comb[6]; + matTemp._32 = POLY_cam_matrix_comb[7]; + matTemp._33 = POLY_cam_matrix_comb[8]; + matTemp._34 = POLY_cam_off_z; + matTemp._41 = 0.0f; + matTemp._42 = 0.0f; + matTemp._43 = 0.0f; + matTemp._44 = 1.0f; + _LoadMatrix( &(matTemp._11) ); + } + else + { + matTemp._11 = POLY_cam_matrix[0]; + matTemp._12 = POLY_cam_matrix[1]; + matTemp._13 = POLY_cam_matrix[2]; + matTemp._14 = 0.0f; + matTemp._21 = POLY_cam_matrix[3]; + matTemp._22 = POLY_cam_matrix[4]; + matTemp._23 = POLY_cam_matrix[5]; + matTemp._24 = 0.0f; + matTemp._31 = POLY_cam_matrix[6]; + matTemp._32 = POLY_cam_matrix[7]; + matTemp._33 = POLY_cam_matrix[8]; + matTemp._34 = 0.0f; + matTemp._41 = 0.0f; + matTemp._42 = 0.0f; + matTemp._43 = 0.0f; + matTemp._44 = 1.0f; + _LoadMatrix( &(matTemp._11) ); + } + } +} + + +#endif //#ifdef TARGET_DC + + + + +void POLY_camera_set( + float x, + float y, + float z, + float yaw, + float pitch, + float roll, + float view_dist, + float lens, + SLONG splitscreen) +{ + + +#ifdef TARGET_DC + // DC has plenty of Z-buffer precision, and the view_dist stuff breaks the fogging. + // So set it to a typical constant. + view_dist = 6000.0f; +#endif + + + POLY_splitscreen = splitscreen; + + POLY_screen_width = float(DisplayWidth); + POLY_screen_clip_left = 0.0; + POLY_screen_clip_right = POLY_screen_width-00.0; + POLY_screen_mid_x = POLY_screen_width * 0.5F; + POLY_screen_mul_x = POLY_screen_width * 0.5F / POLY_ZCLIP_PLANE; + + switch(POLY_splitscreen) + { + case POLY_SPLITSCREEN_NONE: + POLY_screen_height = float(DisplayHeight); + + POLY_screen_clip_top = 00.0; + POLY_screen_clip_bottom = POLY_screen_height-00.0; + + { + static float wideify = 0.0f; + + /* + + if (EWAY_stop_player_moving()) + { + wideify += (80.0F - wideify) * 0.125F; + } + else + { + wideify += (0.0F - wideify) * 0.125F; + } + + if (wideify < 1) wideify = 0; + + */ + + if (EWAY_stop_player_moving()) + { + wideify = 80.0F; + } + else + { + wideify = 0.0F; + } + + POLY_screen_clip_top += wideify; + POLY_screen_clip_bottom -= wideify; + + POLY_screen_height -= wideify * 2.0F; + } + + POLY_screen_mid_y = POLY_screen_height * 0.5F + POLY_screen_clip_top; + POLY_screen_mul_y = POLY_screen_height * 0.5F / POLY_ZCLIP_PLANE; + + s_ClipMask = STD_CLIPMASK; + break; + + case POLY_SPLITSCREEN_TOP: + POLY_screen_height = float(DisplayHeight >> 1); + + POLY_screen_clip_top = 0.0F; + POLY_screen_clip_bottom = POLY_screen_height; + + POLY_screen_mid_y = POLY_screen_height * 0.50F; + POLY_screen_mul_y = POLY_screen_height * 0.50F / POLY_ZCLIP_PLANE; + + s_ClipMask = STD_CLIPMASK | POLY_CLIP_BOTTOM; + break; + + case POLY_SPLITSCREEN_BOTTOM: + POLY_screen_height = float(DisplayHeight >> 1); + + POLY_screen_clip_top = POLY_screen_height; + POLY_screen_clip_bottom = float(DisplayHeight); + + POLY_screen_mid_y = POLY_screen_height * 1.50F; + POLY_screen_mul_y = POLY_screen_height * 0.50F / POLY_ZCLIP_PLANE; + + s_ClipMask = STD_CLIPMASK | POLY_CLIP_TOP; + break; + + default: + ASSERT(0); + break; + } + +// POLY_screen_clip_left += 32; +// POLY_screen_clip_right -= 32; +// POLY_screen_clip_top += 32; +// POLY_screen_clip_bottom -= 32; + + POLY_cam_x = x; + POLY_cam_y = y; + POLY_cam_z = z; + + POLY_cam_lens = lens; + POLY_cam_view_dist = view_dist; + POLY_cam_over_view_dist = 1.0F / view_dist; + POLY_cam_aspect = POLY_screen_height / POLY_screen_width; + + MATRIX_calc( + POLY_cam_matrix, + yaw, + pitch, + roll); + + + { + // + // Tell the crinkle code about the view-space light vector. + // + + float dx = float(NIGHT_amb_norm_x) * (1.0F / 256.0F); + float dy = float(NIGHT_amb_norm_y) * (1.0F / 256.0F); + float dz = float(NIGHT_amb_norm_z) * (1.0F / 256.0F); + + CRINKLE_light(dx,dy,dz); + } + + { + // + // Tell the crinkle module about the view space skewing. + // + + CRINKLE_skew( + POLY_cam_aspect, + POLY_cam_lens); + } + + MATRIX_skew( + POLY_cam_matrix, + POLY_cam_aspect, + POLY_cam_lens, + POLY_cam_over_view_dist); // Shrink the matrix down so the furthest point has a view distance z of 1.0F + + +#if USE_TOMS_ENGINE_PLEASE_BOB + + HRESULT hres; + + // View matrix is just unit - we concatenate everything + // into the world matrix. + D3DMATRIX matTemp; + matTemp._11 = 1.0f; + matTemp._21 = 0.0f; + matTemp._31 = 0.0f; + matTemp._41 = 0.0f; + matTemp._12 = 0.0f; + matTemp._22 = 1.0f; + matTemp._32 = 0.0f; + matTemp._42 = 0.0f; + matTemp._13 = 0.0f; + matTemp._23 = 0.0f; + matTemp._33 = 1.0f; + matTemp._43 = 0.0f; + matTemp._14 = 0.0f; + matTemp._24 = 0.0f; + matTemp._34 = 0.0f; + matTemp._44 = 1.0f; + hres = (the_display.lp_D3D_Device)->SetTransform ( D3DTRANSFORMSTATE_VIEW, &matTemp ); + + + // Set up the projection matrix - should be done infrequently enough not to matter. +#ifdef TARGET_DC + const float fOneOverPZP = 1.0f / POLY_ZCLIP_PLANE; + + g_matProjection._11 = -fOneOverPZP; + g_matProjection._21 = 0.0f; + g_matProjection._31 = 0.0f; + g_matProjection._41 = 0.0f; + g_matProjection._12 = 0.0f; + g_matProjection._22 = fOneOverPZP; + g_matProjection._32 = 0.0f; + g_matProjection._42 = 0.0f; + g_matProjection._13 = 0.0f; + g_matProjection._23 = 0.0f; + g_matProjection._33 = fOneOverPZP; + g_matProjection._43 = -1.0f; + g_matProjection._14 = 0.0f; + g_matProjection._24 = 0.0f; + g_matProjection._34 = fOneOverPZP; + g_matProjection._44 = 0.0f; +#else + g_matProjection._11 = -1.0f; + g_matProjection._21 = 0.0f; + g_matProjection._31 = 0.0f; + g_matProjection._41 = 0.0f; + g_matProjection._12 = 0.0f; + g_matProjection._22 = 1.0f; + g_matProjection._32 = 0.0f; + g_matProjection._42 = 0.0f; + g_matProjection._13 = 0.0f; + g_matProjection._23 = 0.0f; + g_matProjection._33 = 1.0f; + g_matProjection._43 = -POLY_ZCLIP_PLANE; + g_matProjection._14 = 0.0f; + g_matProjection._24 = 0.0f; + g_matProjection._34 = 1.0f; + g_matProjection._44 = 0.0f; +#endif + + hres = (the_display.lp_D3D_Device)->SetTransform ( D3DTRANSFORMSTATE_PROJECTION, &g_matProjection ); + + + // And set up the viewport. + memset(&g_viewData, 0, sizeof(D3DVIEWPORT2)); + g_viewData.dwSize = sizeof(D3DVIEWPORT2); + float fMyMulX = POLY_screen_mul_x * POLY_ZCLIP_PLANE; + float fMyMulY = POLY_screen_mul_y * POLY_ZCLIP_PLANE; +#if 1 + g_dw3DStuffHeight = fMyMulY * PolyPage::s_YScale * 2; + g_dw3DStuffY = ( POLY_screen_mid_y - fMyMulY ) * PolyPage::s_YScale; + g_viewData.dwWidth = fMyMulX * PolyPage::s_XScale * 2; + g_viewData.dwHeight = fMyMulY * PolyPage::s_YScale * 2; + g_viewData.dwX = ( POLY_screen_mid_x - fMyMulX ) * PolyPage::s_XScale; + g_viewData.dwY = ( POLY_screen_mid_y - fMyMulY ) * PolyPage::s_YScale; + g_viewData.dvClipX = -1.0f; + g_viewData.dvClipY = 1.0; + g_viewData.dvClipWidth = 2.0f; + g_viewData.dvClipHeight = 2.0f; + g_viewData.dvMinZ = 0.0f; + g_viewData.dvMaxZ = 1.0f; +#else +#ifdef TARGET_DC + // A horrible hack for letterbox mode, otherwise the text doesn't get drawn. + g_dw3DStuffHeight = fMyMulY * PolyPage::s_YScale * 2; + g_dw3DStuffY = ( POLY_screen_mid_y - fMyMulY ) * PolyPage::s_YScale; + g_viewData.dwWidth = 640; + g_viewData.dwHeight = 480; + g_viewData.dwX = 0; + g_viewData.dwY = 0; + g_viewData.dvClipX = -1.0f; + g_viewData.dvClipY = 1.0f; + g_viewData.dvClipWidth = 2.0f; + g_viewData.dvClipHeight = 2.0f; + g_viewData.dvMinZ = 0.0f; + g_viewData.dvMaxZ = 1.0f; +#else + // A horrible hack for letterbox mode. + g_dw3DStuffHeight = fMyMulY * PolyPage::s_YScale * 2; + g_dw3DStuffY = ( POLY_screen_mid_y - fMyMulY ) * PolyPage::s_YScale; + g_viewData.dwWidth = POLY_screen_width; + g_viewData.dwHeight = POLY_screen_height; + g_viewData.dwX = 0; + g_viewData.dwY = 0; + g_viewData.dvClipX = -1.0f; + g_viewData.dvClipY = 1.0f; + g_viewData.dvClipWidth = 2.0f; + g_viewData.dvClipHeight = 2.0f; + g_viewData.dvMinZ = 0.0f; + g_viewData.dvMaxZ = 1.0f; +#endif +#endif +#ifdef TARGET_DC + // Viewport must be 32-pixel aligned on DC, apparently. + // But sod it for now - actually seems to work just fine! + ASSERT ( ( g_viewData.dwWidth & 31 ) == 0 ); + ASSERT ( ( g_viewData.dwHeight & 31 ) == 0 ); + ASSERT ( ( g_viewData.dwX & 31 ) == 0 ); + /* + if ( ( g_viewData.dwY & 31 ) != 0 ) + { + // Round to nearest. + g_viewData.dwY = ( g_viewData.dwY + 16 ) & ~31; + } + */ +#endif + + hres = (the_display.lp_D3D_Viewport)->SetViewport2 ( &g_viewData ); + +#endif //#if USE_TOMS_ENGINE_PLEASE_BOB + + +#ifdef TARGET_DC + m_iCurrentCombo = COMBO_DIRTY; + SetupFTRVMatrix ( COMBO_FALSE ); +#endif + + SUPERFACET_start_frame(); + +} + +// +// set clipping flags assuming point is not near- or far-clipped +// --- DON'T just set pt->clip to TRANSFORMED! --- +// + +extern inline void POLY_setclip(POLY_Point* pt) +{ + pt->clip = POLY_CLIP_TRANSFORMED; + + if (pt->X < POLY_screen_clip_left) pt->clip |= POLY_CLIP_LEFT; + else if (pt->X > POLY_screen_clip_right) pt->clip |= POLY_CLIP_RIGHT; + + if (pt->Y < POLY_screen_clip_top) pt->clip |= POLY_CLIP_TOP; + else if (pt->Y > POLY_screen_clip_bottom) pt->clip |= POLY_CLIP_BOTTOM; +} + +// +// project camera coords onto screen +// + +inline void POLY_perspective(POLY_Point *pt, UBYTE wibble_key) +{ + if (pt->z < POLY_Z_NEARPLANE) + { + pt->clip = POLY_CLIP_NEAR; + } + else + if (pt->z > 1.0F) + { + pt->clip = POLY_CLIP_FAR; + } + else + { + // + // The z-range of the point is okay. + // + + pt->Z = POLY_ZCLIP_PLANE / pt->z; + + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + + // + // Wibble! + // + + if (wibble_key) + { + SLONG offset; + SLONG angle1; + SLONG angle2; + + angle1 = wibble_key * POLY_wibble_y1 >> 2; + angle2 = wibble_key * POLY_wibble_y2 >> 2; + angle1 += POLY_wibble_dangle1; + angle2 += POLY_wibble_dangle2; + + angle1 &= 2047; + angle2 &= 2047; + + offset = SIN(angle1) * POLY_wibble_s1 >> 19; + offset += COS(angle2) * POLY_wibble_s2 >> 19; + + pt->X += offset; + } + + // + // Set the clipping flags. + // + + POLY_setclip(pt); + } +} + + + + + +#ifdef TARGET_DC + + + +void POLY_flush_local_rot ( void ) +{ + m_iCurrentCombo = COMBO_DIRTY; + SetupFTRVMatrix ( COMBO_FALSE ); +} + + +void POLY_transform_c( + float world_x, + float world_y, + float world_z, + POLY_Point *pt, + bool bResetTheFTRV) +{ + + + LOG_ENTER ( Poly_Transform_c ) + + if ( bResetTheFTRV ) + { + SetupFTRVMatrix ( COMBO_FALSE ); + } + else + { + EnsureFTRVMatrix ( COMBO_FALSE ); + } + pt->x = world_x - POLY_cam_x; + pt->y = world_y - POLY_cam_y; + pt->z = world_z - POLY_cam_z; + _XDXform3dV( &(pt->x), &(pt->x) ); + +#ifdef DEBUG + // Check the results. + POLY_Point mypt; + mypt.x = world_x - POLY_cam_x; + mypt.y = world_y - POLY_cam_y; + mypt.z = world_z - POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + mypt.x, + mypt.y, + mypt.z); + + // If these trigger, you probably need to call POLY_set_local_rotation_none() sometime before. + ASSERT ( fabs ( mypt.x - pt->x ) < 0.01f ); + ASSERT ( fabs ( mypt.y - pt->y ) < 0.01f ); + ASSERT ( fabs ( mypt.z - pt->z ) < 0.01f ); + +#endif + + + static int iCount = 0; + iCount++; + + + if (pt->z < POLY_Z_NEARPLANE) + { + pt->clip = POLY_CLIP_NEAR; + } + else if (pt->z > 1.0F) + { + pt->clip = POLY_CLIP_FAR; + } + else + { + // + // The z-range of the point is okay. + // + + pt->Z = POLY_ZCLIP_PLANE / pt->z; + + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + + // + // Set the clipping flags. + // + + pt->clip = POLY_CLIP_TRANSFORMED; + + if (pt->X < POLY_screen_clip_left) pt->clip |= POLY_CLIP_LEFT; + else if (pt->X > POLY_screen_clip_right) pt->clip |= POLY_CLIP_RIGHT; + + if (pt->Y < POLY_screen_clip_top) pt->clip |= POLY_CLIP_TOP; + else if (pt->Y > POLY_screen_clip_bottom) pt->clip |= POLY_CLIP_BOTTOM; + } + + LOG_EXIT ( Poly_Transform_c ) +} + + + + +#else //#ifdef TARGET_DC + + + + + + +void POLY_transform_c( + float world_x, + float world_y, + float world_z, + POLY_Point *pt, + bool bUnused) +{ + pt->x = world_x - POLY_cam_x; + pt->y = world_y - POLY_cam_y; + pt->z = world_z - POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + pt->x, + pt->y, + pt->z); + +#if 0 + POLY_perspective(pt); +#else + if (pt->z < POLY_Z_NEARPLANE) + { + pt->clip = POLY_CLIP_NEAR; + } + else + if (pt->z > 1.0F) + { + pt->clip = POLY_CLIP_FAR; + } + else + { + // + // The z-range of the point is okay. + // + + pt->Z = POLY_ZCLIP_PLANE / pt->z; + +#if 1 + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + + // + // Set the clipping flags. + // + pt->clip = POLY_CLIP_TRANSFORMED; + + if (pt->X < POLY_screen_clip_left) pt->clip |= POLY_CLIP_LEFT; + else if (pt->X > POLY_screen_clip_right) pt->clip |= POLY_CLIP_RIGHT; + + if (pt->Y < POLY_screen_clip_top) pt->clip |= POLY_CLIP_TOP; + else if (pt->Y > POLY_screen_clip_bottom) pt->clip |= POLY_CLIP_BOTTOM; +#else + ASSERT(POLY_CLIP_LEFT == 1); + ASSERT(POLY_CLIP_RIGHT == 2); + ASSERT(POLY_CLIP_TOP == 4); + ASSERT(POLY_CLIP_BOTTOM == 8); + + float xml, rmx, ymt, bmy; + + pt->clip = POLY_CLIP_TRANSFORMED; + + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + xml = pt->X - POLY_screen_clip_left; + rmx = POLY_screen_clip_right - pt->X; + + pt->clip |= *((ULONG*)&xml) >> 31; + pt->clip |= (*((ULONG*)&rmx) >> 31) << 1; + + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + ymt = pt->Y - POLY_screen_clip_top; + bmy = POLY_screen_clip_bottom - pt->Y; + + pt->clip |= (*((ULONG*)&ymt) >> 31) << 2; + pt->clip |= (*((ULONG*)&bmy) >> 31) << 3; +#endif + } +#endif +} + +#endif //#else //#ifdef TARGET_DC + + +void POLY_transform_c_saturate_z( + float world_x, + float world_y, + float world_z, + POLY_Point *pt) +{ + LOG_ENTER ( Poly_Transform_c_sat_z ) + + pt->x = world_x - POLY_cam_x; + pt->y = world_y - POLY_cam_y; + pt->z = world_z - POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + pt->x, + pt->y, + pt->z); + +#if 0 + POLY_perspective(pt); +#else + if (pt->z < POLY_Z_NEARPLANE) + { + pt->clip = POLY_CLIP_NEAR; + } + else + { + + // + // The z-range of the point is okay. + // + + pt->Z = POLY_ZCLIP_PLANE / pt->z; + +#if 1 + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + + + // + // Set the clipping flags. + // + pt->clip = POLY_CLIP_TRANSFORMED; + + if (pt->X < POLY_screen_clip_left) pt->clip |= POLY_CLIP_LEFT; + else if (pt->X > POLY_screen_clip_right) pt->clip |= POLY_CLIP_RIGHT; + + if (pt->Y < POLY_screen_clip_top) pt->clip |= POLY_CLIP_TOP; + else if (pt->Y > POLY_screen_clip_bottom) pt->clip |= POLY_CLIP_BOTTOM; +#else + ASSERT(POLY_CLIP_LEFT == 1); + ASSERT(POLY_CLIP_RIGHT == 2); + ASSERT(POLY_CLIP_TOP == 4); + ASSERT(POLY_CLIP_BOTTOM == 8); + + float xml, rmx, ymt, bmy; + + pt->clip = POLY_CLIP_TRANSFORMED; + + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + xml = pt->X - POLY_screen_clip_left; + rmx = POLY_screen_clip_right - pt->X; + + pt->clip |= *((ULONG*)&xml) >> 31; + pt->clip |= (*((ULONG*)&rmx) >> 31) << 1; + + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + ymt = pt->Y - POLY_screen_clip_top; + bmy = POLY_screen_clip_bottom - pt->Y; + + pt->clip |= (*((ULONG*)&ymt) >> 31) << 2; + pt->clip |= (*((ULONG*)&bmy) >> 31) << 3; +#endif + } +#endif + LOG_EXIT ( Poly_Transform_c_sat_z ) +} + + + + + +void POLY_transform_from_view_space(POLY_Point *pt) +{ + LOG_ENTER ( Poly_Transform_from_view_space ) + if (pt->z < POLY_Z_NEARPLANE) + { + pt->clip = POLY_CLIP_NEAR; + } + else + { + // + // The z-range of the point is okay. + // + + pt->Z = POLY_ZCLIP_PLANE / pt->z; + + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + + // + // Set the clipping flags. + // + + pt->clip = POLY_CLIP_TRANSFORMED; + + if (pt->X < POLY_screen_clip_left ) {pt->clip |= POLY_CLIP_LEFT; } + else if (pt->X > POLY_screen_clip_right) {pt->clip |= POLY_CLIP_RIGHT;} + + if (pt->Y < POLY_screen_clip_top ) {pt->clip |= POLY_CLIP_TOP; } + else if (pt->Y > POLY_screen_clip_bottom) {pt->clip |= POLY_CLIP_BOTTOM;} + } + LOG_EXIT ( Poly_Transform_from_view_space ) +} + + + + +void POLY_transform_abs( + float world_x, + float world_y, + float world_z, + POLY_Point *pt) +{ + pt->x = world_x; //- POLY_cam_x; + pt->y = world_y; //- POLY_cam_y; + pt->z = world_z; //- POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + pt->x, + pt->y, + pt->z); + + POLY_perspective(pt); +} + +SLONG POLY_get_screen_pos( + float world_x, + float world_y, + float world_z, + float *screen_x, + float *screen_y) +{ + float vx = world_x - POLY_cam_x; + float vy = world_y - POLY_cam_y; + float vz = world_z - POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + vx, + vy, + vz); + + if (vz < POLY_Z_NEARPLANE) + { + return FALSE; + } + else + { + float Z = POLY_ZCLIP_PLANE / vz; + + *screen_x = POLY_screen_mid_x - POLY_screen_mul_x * vx * Z; + *screen_y = POLY_screen_mid_y - POLY_screen_mul_y * vy * Z; + + return TRUE; + } +} + + + + + +// +// The combined rotation matrix. +// + +#if USE_TOMS_ENGINE_PLEASE_BOB +D3DMATRIX g_matWorld; +#endif + +void POLY_set_local_rotation( + float off_x, + float off_y, + float off_z, + float matrix[9]) +{ + LOG_ENTER ( Poly_set_local_rotation ) + + POLY_cam_off_x = off_x - POLY_cam_x; + POLY_cam_off_y = off_y - POLY_cam_y; + POLY_cam_off_z = off_z - POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + POLY_cam_off_x, + POLY_cam_off_y, + POLY_cam_off_z); + + MATRIX_3x3mul( + POLY_cam_matrix_comb, + POLY_cam_matrix, + matrix); + + +#if USE_TOMS_ENGINE_PLEASE_BOB + // Dump into the WORLD matrix. + g_matWorld._11 = POLY_cam_matrix_comb[0]; + g_matWorld._21 = POLY_cam_matrix_comb[1]; + g_matWorld._31 = POLY_cam_matrix_comb[2]; + g_matWorld._41 = POLY_cam_off_x; + g_matWorld._12 = POLY_cam_matrix_comb[3]; + g_matWorld._22 = POLY_cam_matrix_comb[4]; + g_matWorld._32 = POLY_cam_matrix_comb[5]; + g_matWorld._42 = POLY_cam_off_y; + g_matWorld._13 = POLY_cam_matrix_comb[6]; + g_matWorld._23 = POLY_cam_matrix_comb[7]; + g_matWorld._33 = POLY_cam_matrix_comb[8]; + g_matWorld._43 = POLY_cam_off_z; + g_matWorld._14 = 0.0f; + g_matWorld._24 = 0.0f; + g_matWorld._34 = 0.0f; + g_matWorld._44 = 1.0f; + HRESULT hres = (the_display.lp_D3D_Device)->SetTransform ( D3DTRANSFORMSTATE_WORLD, &g_matWorld ); +#endif + +#ifdef TARGET_DC + m_iCurrentCombo = COMBO_DIRTY; + SetupFTRVMatrix ( COMBO_TRUE ); +#endif + + LOG_EXIT ( Poly_set_local_rotation ) + +} + +// Sets up a null local rotation, i.e. none. +// Only useful for setting the current camera rotation into the D3D ones. +void POLY_set_local_rotation_none ( void ) +{ + LOG_ENTER ( Poly_set_local_rotation ) + + POLY_cam_off_x = -POLY_cam_x; + POLY_cam_off_y = -POLY_cam_y; + POLY_cam_off_z = -POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + POLY_cam_off_x, + POLY_cam_off_y, + POLY_cam_off_z); + +#if USE_TOMS_ENGINE_PLEASE_BOB + // Dump into the WORLD matrix. + g_matWorld._11 = POLY_cam_matrix[0]; + g_matWorld._21 = POLY_cam_matrix[1]; + g_matWorld._31 = POLY_cam_matrix[2]; + g_matWorld._41 = POLY_cam_off_x; + g_matWorld._12 = POLY_cam_matrix[3]; + g_matWorld._22 = POLY_cam_matrix[4]; + g_matWorld._32 = POLY_cam_matrix[5]; + g_matWorld._42 = POLY_cam_off_y; + g_matWorld._13 = POLY_cam_matrix[6]; + g_matWorld._23 = POLY_cam_matrix[7]; + g_matWorld._33 = POLY_cam_matrix[8]; + g_matWorld._43 = POLY_cam_off_z; + g_matWorld._14 = 0.0f; + g_matWorld._24 = 0.0f; + g_matWorld._34 = 0.0f; + g_matWorld._44 = 1.0f; + HRESULT hres = (the_display.lp_D3D_Device)->SetTransform ( D3DTRANSFORMSTATE_WORLD, &g_matWorld ); +#endif + +#ifdef TARGET_DC + m_iCurrentCombo = COMBO_DIRTY; + SetupFTRVMatrix ( COMBO_FALSE ); +#endif + + LOG_EXIT ( Poly_set_local_rotation ) +} + + +#ifdef TARGET_DC + +void POLY_transform_using_local_rotation_c( + float local_x, + float local_y, + float local_z, + POLY_Point *pt) +{ + LOG_ENTER ( Poly_transform_using_local_rotation_c ) + +#if 0 + pt->x = local_x; + pt->y = local_y; + pt->z = local_z; + + MATRIX_MUL( + POLY_cam_matrix_comb, + pt->x, + pt->y, + pt->z); + + pt->x += POLY_cam_off_x; + pt->y += POLY_cam_off_y; + pt->z += POLY_cam_off_z; +#else + float fVec[4]; + EnsureFTRVMatrix ( COMBO_TRUE ); + fVec[0] = local_x; + fVec[1] = local_y; + fVec[2] = local_z; + fVec[3] = 1.0f; + + _XDXform4dV( fVec, fVec ); + + pt->x = fVec[0]; + pt->y = fVec[1]; + pt->z = fVec[2]; +#endif + + + static int iCount = 0; + iCount++; + + + if (pt->z < POLY_Z_NEARPLANE) + { + pt->clip = POLY_CLIP_NEAR; + } + else if (pt->z > 1.0F) + { + pt->clip = POLY_CLIP_FAR; + } + else + { + // + // The z-range of the point is okay. + // + + pt->Z = POLY_ZCLIP_PLANE / pt->z; + + pt->X = POLY_screen_mid_x - POLY_screen_mul_x * pt->x * pt->Z; + pt->Y = POLY_screen_mid_y - POLY_screen_mul_y * pt->y * pt->Z; + + // + // Set the clipping flags. + // + + pt->clip = POLY_CLIP_TRANSFORMED; + + if (pt->X < POLY_screen_clip_left) pt->clip |= POLY_CLIP_LEFT; + else if (pt->X > POLY_screen_clip_right) pt->clip |= POLY_CLIP_RIGHT; + + if (pt->Y < POLY_screen_clip_top) pt->clip |= POLY_CLIP_TOP; + else if (pt->Y > POLY_screen_clip_bottom) pt->clip |= POLY_CLIP_BOTTOM; + } + LOG_EXIT ( Poly_transform_using_local_rotation_c ) + +} + + +#else + + + +void POLY_transform_using_local_rotation_c( + float local_x, + float local_y, + float local_z, + POLY_Point *pt) +{ + pt->x = local_x; + pt->y = local_y; + pt->z = local_z; + + MATRIX_MUL( + POLY_cam_matrix_comb, + pt->x, + pt->y, + pt->z); + + pt->x += POLY_cam_off_x; + pt->y += POLY_cam_off_y; + pt->z += POLY_cam_off_z; + + POLY_perspective(pt); +} + + +#endif + +void POLY_transform_using_local_rotation_and_wibble( + float local_x, + float local_y, + float local_z, + POLY_Point *pt, + UBYTE wibble_key) +{ + pt->x = local_x; + pt->y = local_y; + pt->z = local_z; + + MATRIX_MUL( + POLY_cam_matrix_comb, + pt->x, + pt->y, + pt->z); + + pt->x += POLY_cam_off_x; + pt->y += POLY_cam_off_y; + pt->z += POLY_cam_off_z; + + POLY_perspective(pt, wibble_key); +} + + + +SLONG POLY_sphere_visible( + float world_x, + float world_y, + float world_z, + float radius) +{ + float view_x; + float view_y; + float view_z; + + // + // Rotate into viewspace. + // + + view_x = world_x - POLY_cam_x; + view_y = world_y - POLY_cam_y; + view_z = world_z - POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + view_x, + view_y, + view_z); + + if (view_z + radius <= POLY_Z_NEARPLANE) + { + // + // Behind the view pyramid. + // + + return FALSE; + } + + if (view_x + radius < -view_z || + view_x - radius > +view_z) + { + return FALSE; + } + + if (view_y + radius * 1.4F < -view_z || + view_y - radius * 1.4F > +view_z) + { + return FALSE; + } + + return TRUE; +} + + +void POLY_fadeout_buffer() +{ + SLONG i; + + for (i = 0; i < POLY_buffer_upto; i++) + { + POLY_fadeout_point(&POLY_buffer[i]); + } +} + + +extern UWORD fade_black; + + + +void POLY_frame_init(SLONG keep_shadow_page, SLONG keep_text_page) +{ + SLONG i; +// TRACE("poly frame init\n"); + + + +#ifdef TARGET_DC + ASSERT (!keep_shadow_page); + ASSERT (!keep_text_page); + for (i = 0; i < POLY_NUM_PAGES; i++) + { + { + // Check that the page is empty. + ASSERT ( POLY_Page[i].m_VBUsed == 0 ); + ASSERT ( POLY_Page[i].m_iNumIndicesUsed == 0 ); + } + } + + +#else + + // This is going to cost serious performance - it bins all the VBs and IBs that we allocate, + // so they all need allocating again. Madness. + for (i = 0; i < POLY_NUM_PAGES; i++) + { + if (keep_shadow_page && i == POLY_PAGE_SHADOW) + { + // + // Keep this stuff... + // + } + else + if (keep_text_page && i == POLY_PAGE_TEXT) + { + // + // Keep this stuff... + // + } + else + { + POLY_Page[i].Clear(); + } + } +// TRACE("poly frame init EXIT\n"); +#endif + + // SPONG +#if USE_TOMS_ENGINE_PLEASE_BOB + // Start the frame - we may draw polys at any time. + //TRACE("Dodgy one!\n"); + POLY_init_render_states(); + + ULONG fog_colour; + if ((GAME_FLAGS & GF_SEWERS) || (GAME_FLAGS & GF_INDOORS)) + { + fog_colour = 0; + } + else + { + if(fade_black) + { + fog_colour=0; + } + else + { + fog_colour = + (NIGHT_sky_colour.red << 16) | + (NIGHT_sky_colour.green << 8) | + (NIGHT_sky_colour.blue << 0); + } + + if (draw_3d) + { + SLONG white = NIGHT_sky_colour.red + NIGHT_sky_colour.green + NIGHT_sky_colour.blue; + + white /= 3; + + fog_colour = + (white << 16) | + (white << 8) | + (white << 0); + } + } + + + // set default render state + DefRenderState.InitScene(fog_colour); +// BreakTime("FRAMEDRAW init scene"); + + BEGIN_SCENE; +#endif + +} + +SLONG POLY_valid_triangle(POLY_Point *pp[3]) +{ + // all points must be either near-clipped or fully transformed + if (!pp[0]->MaybeValid()) return FALSE; + if (!pp[1]->MaybeValid()) return FALSE; + if (!pp[2]->MaybeValid()) return FALSE; + + // if all points are clipped in one direction, polygon is invalid + if ((pp[0]->clip & pp[1]->clip & pp[2]->clip) & POLY_CLIP_OFFSCREEN) + { + return FALSE; + } + + return TRUE; +} + +SLONG POLY_valid_quad(POLY_Point *pp[4]) +{ + // all points must be either near-clipped or fully transformed + if (!pp[0]->MaybeValid()) return FALSE; + if (!pp[1]->MaybeValid()) return FALSE; + if (!pp[2]->MaybeValid()) return FALSE; + if (!pp[3]->MaybeValid()) return FALSE; + + // if all points are clipped in one direction, polygon is invalid + if ((pp[0]->clip & pp[1]->clip & pp[2]->clip & pp[3]->clip) & POLY_CLIP_OFFSCREEN) + { + return FALSE; + } + + return TRUE; +} + +SLONG POLY_valid_line(POLY_Point *p1, POLY_Point *p2) +{ + // all points must be either near-clipped or fully transformed + if (!p1->IsValid()) return FALSE; + if (!p2->IsValid()) return FALSE; + + // if all points are clipped in one direction, line is invalid + // (wrong: line thickness might revalidate it; but we don't care too much) + if ((p1->clip & p2->clip) & POLY_CLIP_OFFSCREEN) + { + return FALSE; + } + + return TRUE; +} + +// POLY_tri_backfacing +// +// returns true if triangle is backfacing + +inline bool POLY_tri_backfacing(POLY_Point *pp1, POLY_Point *pp2, POLY_Point *pp3) +{ + float x12,y12,z12; // 1->2 vector + float x13,y13,z13; // 1->3 vector + float cx,cy,cz; // normal vector (not normalized) + float dp; // dot product + + LOG_ENTER ( Poly_tri_backfacing ) + + ASSERT(pp1->MaybeValid()); + ASSERT(pp2->MaybeValid()); + ASSERT(pp3->MaybeValid()); + + // get 1->2 vector + x12 = pp2->x - pp1->x; + y12 = pp2->y - pp1->y; + z12 = pp2->z - pp1->z; + + // get 1->3 vector + x13 = pp3->x - pp1->x; + y13 = pp3->y - pp1->y; + z13 = pp3->z - pp1->z; + + // get cross product + cx = y12 * z13 - z12 * y13; + cy = z12 * x13 - x12 * z13; + cz = x12 * y13 - y12 * x13; + + // dot with eye vector + dp = cx * pp1->x + cy * pp1->y + cz * pp1->z; + + LOG_EXIT ( Poly_tri_backfacing ) + + return (dp < 0); +} + +// TweenD3DColour +// +// create a new tweened colour from two given colours +// +// (supercedes POLY_interpolate_colour - bugs fixed and speed increased) + +static inline ULONG TweenD3DColour(ULONG c1, ULONG c2, ULONG lambda8) +{ + // quick check + if (c1 == c2) return c1; + if (lambda8 == 0) return c1; + if (lambda8 == 256) return c2; + + // lerp R & B + SLONG rb1 = c1 & 0x00FF00FF; + SLONG rb2 = c2 & 0x00FF00FF; + + if (rb1 != rb2) + { + rb2 -= rb1; + rb2 *= lambda8; + rb1 += rb2 >> 8; + rb1 &= 0x00FF00FF; + } + + // lerp A & G + SLONG ag1 = (c1 >> 8) & 0x00FF00FF; + SLONG ag2 = (c2 >> 8) & 0x00FF00FF; + + if (ag1 != ag2) + { + ag2 -= ag1; + ag2 *= lambda8; + ag1 += ag2 >> 8; + ag1 &= 0x00FF00FF; + } + + return rb1 + (ag1 << 8); +} + +// +// add a polygon (defined by a string of vertices) +// no backface culling is performed here, but nearplane and splitscreen clipping is +// + +static POLY_Point s_PointBuffer[32]; +static ULONG s_PointBufferOffset; + +// NewTweenVertex3D +// +// create and project a new vertex between two others + +POLY_Point* NewTweenVertex3D(POLY_Point* p1, POLY_Point* p2, float lambda) +{ + ULONG lambda8; + + // extract 8-bit modulation index using fast float cast + // note: lambda *must* be between 0.0F and 1.0F inclusive + // mapping to 0 and 256 inclusive + *(float*)&lambda8 = lambda + 32768.0F; + lambda8 &= 0x1FF; + + POLY_Point* np = &s_PointBuffer[s_PointBufferOffset++]; + + np->x = p1->x + lambda * (p2->x - p1->x); + np->y = p1->y + lambda * (p2->y - p1->y); +// np->z = p1->z + lambda * (p2->z - p1->z); + np->z = POLY_Z_NEARPLANE; + + np->u = p1->u + lambda * (p2->u - p1->u); + np->v = p1->v + lambda * (p2->v - p1->v); + + np->colour = TweenD3DColour(p1->colour, p2->colour, lambda8); + np->specular = TweenD3DColour(p1->specular, p2->specular, lambda8); + + // project + POLY_perspective(np); + ASSERT(np->IsValid()); + + return np; +} + +// NewTweenVertex2D_X +// +// create a new vertex between two others + +POLY_Point* NewTweenVertex2D_X(POLY_Point* p1, POLY_Point* p2, float lambda, float xcoord) +{ + ULONG lambda8; + + // extract 8-bit modulation index using fast float cast + // note: lambda *must* be between 0.0F and 1.0F inclusive + // mapping to 0 and 256 inclusive + *(float*)&lambda8 = lambda + 32768.0F; + lambda8 &= 0x1FF; + + POLY_Point* np = &s_PointBuffer[s_PointBufferOffset++]; + + np->X = xcoord; + np->Y = p1->Y + lambda * (p2->Y - p1->Y); + np->Z = p1->Z + lambda * (p2->Z - p1->Z); + + // do u,v perspective correct + float u1 = p1->u * p1->Z; + float v1 = p1->v * p1->Z; + float u2 = p2->u * p2->Z; + float v2 = p2->v * p2->Z; + float rz = 1.0F / np->Z; + + np->u = rz * (u1 + lambda * (u2 - u1)); + np->v = rz * (v1 + lambda * (v2 - v1)); + + np->colour = TweenD3DColour(p1->colour, p2->colour, lambda8); + np->specular = TweenD3DColour(p1->specular, p2->specular, lambda8); + + // set clip flags + POLY_setclip(np); + + return np; +} + +// NewTweenVertex2D_Y +// +// create a new vertex between two others + +POLY_Point* NewTweenVertex2D_Y(POLY_Point* p1, POLY_Point* p2, float lambda, float ycoord) +{ + ULONG lambda8; + + // extract 8-bit modulation index using fast float cast + // note: lambda *must* be between 0.0F and 1.0F inclusive + // mapping to 0 and 256 inclusive + *(float*)&lambda8 = lambda + 32768.0F; + lambda8 &= 0x1FF; + + POLY_Point* np = &s_PointBuffer[s_PointBufferOffset++]; + + np->X = p1->X + lambda * (p2->X - p1->X); + np->Y = ycoord; + np->Z = p1->Z + lambda * (p2->Z - p1->Z); + + // do u,v perspective correct + float u1 = p1->u * p1->Z; + float v1 = p1->v * p1->Z; + float u2 = p2->u * p2->Z; + float v2 = p2->v * p2->Z; + float rz = 1.0F / np->Z; + + np->u = rz * (u1 + lambda * (u2 - u1)); + np->v = rz * (v1 + lambda * (v2 - v1)); + + np->colour = TweenD3DColour(p1->colour, p2->colour, lambda8); + np->specular = TweenD3DColour(p1->specular, p2->specular, lambda8); + + // set clip flags + POLY_setclip(np); + + return np; +} + +// POLY_clip_against_nearplane +// +// clip poly against near clipping plane + +SLONG POLY_clip_against_nearplane(POLY_Point** rptr, float* dptr, SLONG count, POLY_Point** wbuf) +{ + POLY_Point** wptr = wbuf; + + POLY_Point* p1; + POLY_Point* p2; + + for (SLONG ii = 0; ii < count - 1; ii++) + { + p1 = rptr[ii]; + p2 = rptr[ii+1]; + + if (dptr[ii] >= 0) + { + // good side + *wptr++ = p1; + if (dptr[ii+1] >= 0) + { + // also on good side + continue; + } + } + else + { + if (dptr[ii+1] < 0) + { + // also on bad side + continue; + } + } + + *wptr++ = NewTweenVertex3D(p1, p2, dptr[ii] / (dptr[ii] - dptr[ii+1])); + } + + p1 = rptr[ii]; + p2 = rptr[0]; + + if (dptr[ii] >= 0) + { + *wptr++ = p1; + if (dptr[0] < 0) + { + *wptr++ = NewTweenVertex3D(p1, p2, dptr[ii] / (dptr[ii] - dptr[0])); + } + } + else + { + if (dptr[0] >= 0) + { + *wptr++ = NewTweenVertex3D(p1, p2, dptr[ii] / (dptr[ii] - dptr[0])); + } + } + + return wptr - wbuf; +} + + + +#ifndef TARGET_DC + +// POLY_clip_against_side_X +// +// clip poly against a side (left or right) + +SLONG POLY_clip_against_side_X(POLY_Point** rptr, float* dptr, SLONG count, POLY_Point** wbuf, float xcoord) +{ + POLY_Point** wptr = wbuf; + + POLY_Point* p1; + POLY_Point* p2; + + for (SLONG ii = 0; ii < count - 1; ii++) + { + p1 = rptr[ii]; + p2 = rptr[ii+1]; + + if (dptr[ii] >= 0) + { + // good side + *wptr++ = p1; + if (dptr[ii+1] >= 0) + { + // also on good side + continue; + } + } + else + { + if (dptr[ii+1] < 0) + { + // also on bad side + continue; + } + } + + *wptr++ = NewTweenVertex2D_X(p1, p2, dptr[ii] / (dptr[ii] - dptr[ii+1]), xcoord); + } + + p1 = rptr[ii]; + p2 = rptr[0]; + + if (dptr[ii] >= 0) + { + *wptr++ = p1; + if (dptr[0] < 0) + { + *wptr++ = NewTweenVertex2D_X(p1, p2, dptr[ii] / (dptr[ii] - dptr[0]), xcoord); + } + } + else + { + if (dptr[0] >= 0) + { + *wptr++ = NewTweenVertex2D_X(p1, p2, dptr[ii] / (dptr[ii] - dptr[0]), xcoord); + } + } + + return wptr - wbuf; +} + +// POLY_clip_against_side_Y +// +// clip poly against a side (top or bottom) + +SLONG POLY_clip_against_side_Y(POLY_Point** rptr, float* dptr, SLONG count, POLY_Point** wbuf, float ycoord) +{ + POLY_Point** wptr = wbuf; + + POLY_Point* p1; + POLY_Point* p2; + + for (SLONG ii = 0; ii < count - 1; ii++) + { + p1 = rptr[ii]; + p2 = rptr[ii+1]; + + if (dptr[ii] >= 0) + { + // good side + *wptr++ = p1; + if (dptr[ii+1] >= 0) + { + // also on good side + continue; + } + } + else + { + if (dptr[ii+1] < 0) + { + // also on bad side + continue; + } + } + + *wptr++ = NewTweenVertex2D_Y(p1, p2, dptr[ii] / (dptr[ii] - dptr[ii+1]), ycoord); + } + + p1 = rptr[ii]; + p2 = rptr[0]; + + if (dptr[ii] >= 0) + { + *wptr++ = p1; + if (dptr[0] < 0) + { + *wptr++ = NewTweenVertex2D_Y(p1, p2, dptr[ii] / (dptr[ii] - dptr[0]), ycoord); + } + } + else + { + if (dptr[0] >= 0) + { + *wptr++ = NewTweenVertex2D_Y(p1, p2, dptr[ii] / (dptr[ii] - dptr[0]), ycoord); + } + } + + return wptr - wbuf; +} + +#endif //#ifndef TARGET_DC + + + +#ifndef TARGET_DC +extern UBYTE sw_hack; +#endif + + + +static float s_DistBuffer[128]; +static POLY_Point* s_PtrBuffer[128]; + + +// POLY_add_poly no longer works - system's been changed. +#if 0 + +// POLY_add_poly +// +// clip poly and write to the vertex buffer + +void POLY_add_poly(POLY_Point** poly, SLONG poly_points, SLONG page) +{ + + UBYTE clip_or; + UBYTE clip_and; + SLONG ii; + + // get aggregate clip flags + clip_or = 0; + clip_and = 0xFF; + for (ii = 0; ii < poly_points; ii++) + { + ASSERT(poly[ii]->MaybeValid()); + clip_or |= poly[ii]->clip; + clip_and &= poly[ii]->clip; + } + + if (clip_and & (POLY_CLIP_NEAR | POLY_CLIP_LEFT | POLY_CLIP_RIGHT | POLY_CLIP_TOP | POLY_CLIP_BOTTOM)) + { + return; // is this triggering? + } + + // initialize state for clipping + POLY_Point** rptr = poly; + POLY_Point** wptr = s_PtrBuffer; + + s_PointBufferOffset = 0; + + // remove flags that we don't care about + clip_or &= s_ClipMask; + + // clip to nearplane + if (clip_or & POLY_CLIP_NEAR) + { + for (ii = 0; ii < poly_points; ii++) + { + s_DistBuffer[ii] = rptr[ii]->z - POLY_Z_NEARPLANE; + } + + poly_points = POLY_clip_against_nearplane(rptr, s_DistBuffer, poly_points, wptr); + rptr = wptr; + wptr += poly_points; + + if (!poly_points) + { + return; + } + + // refresh clip flags + clip_or = 0; + clip_and = 0xFF; + for (ii = 0; ii < poly_points; ii++) + { + ASSERT(rptr[ii]->MaybeValid()); + clip_or |= rptr[ii]->clip; + clip_and &= rptr[ii]->clip; + } + clip_or &= s_ClipMask; + } + +#ifndef TARGET_DC + if (sw_hack) + { + SLONG R[16]; + SLONG G[16]; + SLONG B[16]; + SLONG X[16]; + SLONG Y[16]; + SLONG Z[16]; + + SLONG fog; + + SLONG fogout[16]; + + ASSERT(poly_points <= 16); + + for (ii = 0; ii < poly_points; ii++) + { + fog = rptr[ii]->specular >> 24; + + R[ii] = ((rptr[ii]->colour >> 16) & 0xff) * fog >> 8; + G[ii] = ((rptr[ii]->colour >> 8) & 0xff) * fog >> 8; + B[ii] = ((rptr[ii]->colour >> 0) & 0xff) * fog >> 8; + + extern float not_private_smiley_xscale; + extern float not_private_smiley_yscale; + + X[ii] = rptr[ii]->X * not_private_smiley_xscale; + Y[ii] = rptr[ii]->Y * not_private_smiley_yscale; + Z[ii] = rptr[ii]->z * 1024.0F; + + fogout[ii] = (fog == 0); + } + + // + // Add the fan a triangle at a time. + // + + for (ii = 1; ii < poly_points - 1; ii++) + { + if (fogout[0] & fogout[ii] & fogout[ii + 1]) + { + continue; + } + + SW_add_triangle( + X[ 0], Y[ 0], Z[ 0], R[ 0],G[ 0],B[ 0], rptr[ 0]->u * 256, rptr[ 0]->v * 256, + X[ii + 0], Y[ii + 0], Z[ii + 0], R[ii + 0],G[ii + 0],B[ii + 0], rptr[ii + 0]->u * 256, rptr[ii + 0]->v * 256, + X[ii + 1], Y[ii + 1], Z[ii + 1], R[ii + 1],G[ii + 1],B[ii + 1], rptr[ii + 1]->u * 256, rptr[ii + 1]->v * 256, + page, + rptr[ii]->colour >> 24); + } + + return; + } +#endif + +#if _DEBUG + // check that clip flags are correctly set + for (ii = 0; ii < poly_points; ii++) + { + UBYTE tmp = rptr[ii]->clip; + POLY_setclip(rptr[ii]); + if (tmp != rptr[ii]->clip) + { + TRACE("ERROR! Polygon vertex clip flags not set\n(Hint: add ,TRUE parameter to the add polygon call if you set screen coordinates by hand, or call POLY_setclip())\n"); + ASSERT(0); + // now trace through the call - I've just realized this won't necessarily work ;-( + POLY_transform(rptr[ii]->x, rptr[ii]->y, rptr[ii]->z, rptr[ii]); + } + } +#endif + +#if !NO_CLIPPING_TO_THE_SIDES_PLEASE_BOB + if (clip_or & (POLY_CLIP_LEFT | POLY_CLIP_RIGHT | POLY_CLIP_TOP | POLY_CLIP_BOTTOM)) + { + if (clip_or & POLY_CLIP_LEFT) + { + LOG_ENTER ( POLY_side_clip ) + for (ii = 0; ii < poly_points; ii++) + { + s_DistBuffer[ii] = rptr[ii]->X - POLY_screen_clip_left; + } + + poly_points = POLY_clip_against_side_X(rptr, s_DistBuffer, poly_points, wptr, POLY_screen_clip_left); + rptr = wptr; + wptr += poly_points; + + LOG_EXIT ( POLY_side_clip ) + if (!poly_points) return; + } + + if (clip_or & POLY_CLIP_RIGHT) + { + LOG_ENTER ( POLY_side_clip ) + for (ii = 0; ii < poly_points; ii++) + { + s_DistBuffer[ii] = POLY_screen_clip_right - rptr[ii]->X; + } + + poly_points = POLY_clip_against_side_X(rptr, s_DistBuffer, poly_points, wptr, POLY_screen_clip_right); + rptr = wptr; + wptr += poly_points; + + LOG_EXIT ( POLY_side_clip ) + if (!poly_points) return; + } + + if (clip_or & POLY_CLIP_TOP) + { + LOG_ENTER ( POLY_side_clip ) + for (ii = 0; ii < poly_points; ii++) + { + s_DistBuffer[ii] = rptr[ii]->Y - POLY_screen_clip_top; + } + + poly_points = POLY_clip_against_side_Y(rptr, s_DistBuffer, poly_points, wptr, POLY_screen_clip_top); + rptr = wptr; + wptr += poly_points; + + LOG_EXIT ( POLY_side_clip ) + if (!poly_points) return; + } + + if (clip_or & POLY_CLIP_BOTTOM) + { + LOG_ENTER ( POLY_side_clip ) + for (ii = 0; ii < poly_points; ii++) + { + s_DistBuffer[ii] = POLY_screen_clip_bottom - rptr[ii]->Y; + } + + poly_points = POLY_clip_against_side_Y(rptr, s_DistBuffer, poly_points, wptr, POLY_screen_clip_bottom); + rptr = wptr; + wptr += poly_points; + + LOG_EXIT ( POLY_side_clip ) + if (!poly_points) return; + } + } +#endif //#if !NO_CLIPPING_TO_THE_SIDES_PLEASE_BOB + + // + // add to appropriate pages + // + + POLY_Page[page].AddFan(rptr, poly_points); + + if (POLY_page_flag[page] & POLY_PAGE_FLAG_2PASS) + { + POLY_Page[page + 1].AddFan(rptr, poly_points); + } +} + +#endif // #if 1 ????! + + +void POLY_add_nearclipped_triangle(POLY_Point *pt[3], SLONG page, SLONG backface_cull) +{ + // + // initialize state for clipping + // + + + POLY_Point** rptr = pt; + POLY_Point** wptr = s_PtrBuffer; + + s_PointBufferOffset = 0; + + { + SLONG i; + SLONG j; + SLONG laura; + + SLONG poly_points; + + s_DistBuffer[0] = rptr[0]->z - POLY_Z_NEARPLANE; + s_DistBuffer[1] = rptr[1]->z - POLY_Z_NEARPLANE; + s_DistBuffer[2] = rptr[2]->z - POLY_Z_NEARPLANE; + + poly_points = POLY_clip_against_nearplane(rptr, s_DistBuffer, 3, wptr); + + if (!poly_points) + { + return; + } + + rptr = wptr; + + // + // refresh clip flags + // + + SLONG clip_and = 0xffffffff; + + for (i = 0; i < poly_points; i++) + { + POLY_setclip(rptr[i]); + + clip_and &= rptr[i]->clip; + } + + if (clip_and & POLY_CLIP_OFFSCREEN) + { + return; + } + + if (backface_cull && POLY_tri_backfacing(rptr[0], rptr[1], rptr[2])) + { + // + // This triangle is backface culled. + // + + return; + } + + second_page:; + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + PolyPage *pp = &POLY_Page[page]; +#ifdef TEX_EMBED + // Do the indirection to the real poly page. + PolyPage *ppDrawn = pp->pTheRealPolyPage; +#else + PolyPage *ppDrawn = pp; +#endif + + PolyPoint2D *pv = ppDrawn->PointAlloc(3 + (poly_points - 3) * 3); + + POLY_Point *ppt; + PolyPoint2D *pv_first = pv; + + ppt = rptr[0]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + laura = 2; + + while(1) + { + ppt = rptr[laura - 1]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = rptr[laura]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + laura++; + + if (laura >= poly_points) + { + break; + } + + pv++; + + *pv = *pv_first; + + pv++; + } + +#else //#if WE_NEED_POLYBUFFERS_PLEASE_BOB +// The version with index buffers + + PolyPage *pp = &POLY_Page[page]; +#ifdef TEX_EMBED + // Do the indirection to the real poly page. + PolyPage *ppDrawn = pp->pTheRealPolyPage; +#else + PolyPage *ppDrawn = pp; +#endif + + PolyPoint2D *pv = ppDrawn->FanAlloc( poly_points ); + + POLY_Point *ppt; + PolyPoint2D *pv_first = pv; + + + for ( i = 0; i < poly_points; i++ ) + { + ppt = rptr[i]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); + #ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); + #else + pv->SetUV (ppt->u, ppt->v); + #endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + } + +#endif //#else //#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + if (POLY_page_flag[page] & POLY_PAGE_FLAG_2PASS) + { + page += 1; + + goto second_page; + } + + } + + return; +} + + + +#ifdef TARGET_DC +void POLY_add_triangle(POLY_Point *pt[3], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +#else +void POLY_add_triangle_fast(POLY_Point *pt[3], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +#endif +{ + + LOG_ENTER ( POLY_add_tri ) + + if (generate_clip_flags) + { + POLY_setclip(pt[0]); + POLY_setclip(pt[1]); + POLY_setclip(pt[2]); + } + + if (pt[0]->clip & pt[1]->clip & pt[2]->clip & POLY_CLIP_OFFSCREEN) + { + // + // Offscreen. + // + + LOG_EXIT ( POLY_add_tri ) + return; + } + + if ((pt[0]->clip | pt[1]->clip | pt[2]->clip) & POLY_CLIP_NEAR) + { + // + // Needs near-clipping... + // + + POLY_add_nearclipped_triangle(pt, page, backface_cull); + + LOG_EXIT ( POLY_add_tri ) + return; + } + + if (backface_cull && POLY_tri_backfacing(pt[0], pt[1], pt[2])) + { + // + // This triangle is backface culled. + // + + LOG_EXIT ( POLY_add_tri ) + return; + } + + second_page:; + + PolyPage *pp = &POLY_Page[page]; +#ifdef TEX_EMBED + // Do the indirection to the real poly page. + PolyPage *ppDrawn = pp->pTheRealPolyPage; +#else + PolyPage *ppDrawn = pp; +#endif + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + PolyPoint2D *pv = ppDrawn->PointAlloc(3); +#else + PolyPoint2D *pv = ppDrawn->FanAlloc(3); +#endif + + POLY_Point *ppt; +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + PolyPoly* ppoly = ppDrawn->PolyBufAlloc(); + if (!ppoly) return; + ppoly->first_vertex = pv - ppDrawn->m_VertexPtr; + ppoly->num_vertices = 3; +#endif + + ASSERT(pv); + + ppt = pt[0]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[1]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[2]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + + if (POLY_page_flag[page] & POLY_PAGE_FLAG_2PASS) + { + page += 1; + + goto second_page; + } + LOG_EXIT ( POLY_add_tri ) +} + +#ifdef TARGET_DC +void POLY_add_quad(POLY_Point *pt[4], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +#else +void POLY_add_quad_fast(POLY_Point *pt[4], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +#endif +{ + + LOG_ENTER ( POLY_add_quad ) + + if (generate_clip_flags) + { + POLY_setclip(pt[0]); + POLY_setclip(pt[1]); + POLY_setclip(pt[2]); + POLY_setclip(pt[3]); + } + + if (pt[0]->clip & pt[1]->clip & pt[2]->clip & pt[3]->clip & POLY_CLIP_OFFSCREEN) + { + // + // Offscreen. + // + + LOG_EXIT ( POLY_add_quad ) + return; + } + + if ((pt[0]->clip | pt[1]->clip | pt[2]->clip | pt[3]->clip) & POLY_CLIP_NEAR) + { + POLY_Point *pt2[3] = {pt[1],pt[3],pt[2]}; + + // + // Needs near-clipping... + // + + POLY_add_triangle(pt, page, backface_cull, FALSE); + POLY_add_triangle(pt2, page, backface_cull, FALSE); + + LOG_EXIT ( POLY_add_quad ) + return; + } + + if (backface_cull) + { + SLONG cull; + + cull = 0; + + if (POLY_tri_backfacing(pt[0], pt[1], pt[2])) {cull |= 1;} + if (POLY_tri_backfacing(pt[1], pt[3], pt[2])) {cull |= 2;} + + if (cull == 0) + { + // + // Draw the whole quad. + // + } + else + if (cull == 3) + { + // + // Backface cull the whole quad. + // + + LOG_EXIT ( POLY_add_quad ) + return; + } + else + if (cull == 1) + { + // + // Draw just the second triangle. + // + + LOG_EXIT ( POLY_add_quad ) + POLY_add_triangle(pt + 1, page, FALSE, FALSE); + + return; + } + else + if (cull == 2) + { + // + // Draw just the first triangle. + // + + LOG_EXIT ( POLY_add_quad ) + POLY_add_triangle(pt, page, FALSE, FALSE); + + return; + } + } + + second_page:; + + PolyPage *pp = &POLY_Page[page]; +#ifdef TEX_EMBED + // Do the indirection to the real poly page. + PolyPage *ppDrawn = pp->pTheRealPolyPage; +#else + PolyPage *ppDrawn = pp; +#endif + + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + PolyPoint2D *pv = ppDrawn->PointAlloc(6); + POLY_Point *ppt; +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + PolyPoly* ppoly = ppDrawn->PolyBufAlloc(); + if (!ppoly) return; + ppoly->first_vertex = pv - ppDrawn->m_VertexPtr; + ppoly->num_vertices = 3; + ppoly = pp->PolyBufAlloc(); + if (!ppoly) return; + ppoly->first_vertex = pv - ppDrawn->m_VertexPtr + 3; + ppoly->num_vertices = 3; +#endif + + ASSERT(pv); + + ppt = pt[0]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[1]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[2]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[3]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + + pv[1] = pv[-1]; + pv[2] = pv[-2]; + +#else //#if WE_NEED_POLYBUFFERS_PLEASE_BOB +// The version with index buffers. + + PolyPoint2D *pv = ppDrawn->FanAlloc(4); + POLY_Point *ppt; +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + PolyPoly* ppoly = ppDrawn->PolyBufAlloc(); + if (!ppoly) return; + ppoly->first_vertex = pv - ppDrawn->m_VertexPtr; + ppoly->num_vertices = 3; + ppoly = ppDrawn->PolyBufAlloc(); + if (!ppoly) return; + ppoly->first_vertex = pv - ppDrawn->m_VertexPtr + 3; + ppoly->num_vertices = 3; +#endif + + ASSERT(pv); + + ppt = pt[0]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[1]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[3]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + + pv++; + + ppt = pt[2]; + + pv->SetSC (ppt->X * pp->s_XScale, ppt->Y * pp->s_YScale, 1.0F - ppt->Z); +#ifdef TEX_EMBED + pv->SetUV2 (ppt->u * pp->m_UScale + pp->m_UOffset, ppt->v * pp->m_VScale + pp->m_VOffset); +#else + pv->SetUV (ppt->u, ppt->v); +#endif + pv->SetColour (ppt->colour); + pv->SetSpecular(ppt->specular); + +#endif //#else //#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + if (POLY_page_flag[page] & POLY_PAGE_FLAG_2PASS) + { + page += 1; + + goto second_page; + } + LOG_EXIT ( POLY_add_quad ) +} + + + + +#if 0 +// +// add a triangle to the poly list +// + +void POLY_add_triangle_slow(POLY_Point *pp[3], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +{ + ULONG counter_start; + ULONG counter_end; + + _asm + { + rdtsc + mov counter_start, eax + } + + { + if (generate_clip_flags) + { + POLY_setclip(pp[0]); + POLY_setclip(pp[1]); + POLY_setclip(pp[2]); + } + else + { + ASSERT(pp[0]->MaybeValid()); + ASSERT(pp[1]->MaybeValid()); + ASSERT(pp[2]->MaybeValid()); + } + + if (backface_cull && POLY_tri_backfacing(pp[0], pp[1], pp[2])) + { + // + // This triangle is backface culled. + // + } + else + { + POLY_add_poly(pp, 3, page); + } + } + + _asm + { + rdtsc + mov counter_end, eax + } + + extern ULONG AENG_poly_add_quad_time; + + AENG_poly_add_quad_time += counter_end - counter_start; +} + +// +// add a quad to the poly list; note that vertices clockwise go 0,1,3,2 in this call +// + +extern SLONG TEXTURE_set; +extern UBYTE TEXTURE_dontexist[]; + +void POLY_add_quad_slow(POLY_Point *pp[4], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +{ + + LOG_ENTER ( POLY_add_quad ) + +#if 0 // or #ifdef _DEBUG or something, you lazy gits + if(ShiftFlag && Keys[KB_Q]) + if(pp[0]->z<0.3) + if(page<64*8) + { + CBYTE str[10]; + if(page<256) + sprintf(str,"W%d %d",TEXTURE_set,page); + else + sprintf(str,"W%d S%d",TEXTURE_set,page); +//extern FONT2D_DrawString(CBYTE*chr, ULONG x, ULONG y, ULONG rgb=0xffffff, SLONG scale=16, SLONG page=POLY_PAGE_FONT2D, SWORD fade=0); + FONT2D_DrawString(str,pp[0]->X,pp[0]->Y,0xff0000); + } +#endif + + +/* + if(ShiftFlag) + { + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + ASSERT(0); + if(TEXTURE_dontexist[page]) + ASSERT(0); + } +*/ + +// if(page!=128) +// return; + + { + if (generate_clip_flags) + { + POLY_setclip(pp[0]); + POLY_setclip(pp[1]); + POLY_setclip(pp[2]); + POLY_setclip(pp[3]); + } + else + { + ASSERT(pp[0]->MaybeValid()); + ASSERT(pp[1]->MaybeValid()); + ASSERT(pp[2]->MaybeValid()); + ASSERT(pp[3]->MaybeValid()); + } + + if (backface_cull) + { + bool first; + bool second; + + first = POLY_tri_backfacing(pp[0], pp[1], pp[2]); + second = POLY_tri_backfacing(pp[1], pp[3], pp[2]); + + if (first && second) + { + } + else + { + if (!first) POLY_add_poly(pp, 3, page); + if (!second) POLY_add_poly(pp+1, 3, page); + } + } + else + { + #if USE_D3D_VBUF + // bent quads break clipping - submit as two triangles + POLY_add_poly(pp, 3, page); + POLY_add_poly(pp+1, 3, page); + #else + POLY_Point* tmp; + + tmp = pp[2]; pp[2] = pp[3]; pp[3] = tmp; + POLY_add_poly(pp, 4, page); + tmp = pp[2]; pp[2] = pp[3]; pp[3] = tmp; + #endif + } + } + +} + + +#endif //#if 0 + + +#ifndef TARGET_DC + +void POLY_add_quad(POLY_Point *pp[4], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +{ + ULONG counter_start; + ULONG counter_end; + + _asm + { + rdtsc + mov counter_start, eax + } + +#if 0 + if (!Keys[KB_F8]) + { + POLY_add_quad_slow(pp, page, backface_cull, generate_clip_flags); + } + else +#endif + { + POLY_add_quad_fast(pp, page, backface_cull, generate_clip_flags); + } + + _asm + { + rdtsc + mov counter_end, eax + } + + extern ULONG AENG_poly_add_quad_time; + + AENG_poly_add_quad_time += counter_end - counter_start; +} + +void POLY_add_triangle(POLY_Point *pp[4], SLONG page, SLONG backface_cull, SLONG generate_clip_flags) +{ + ULONG counter_start; + ULONG counter_end; + + _asm + { + rdtsc + mov counter_start, eax + } + +#if 0 + if (!Keys[KB_F8]) + { + POLY_add_triangle_slow(pp, page, backface_cull, generate_clip_flags); + } + else +#endif + { + POLY_add_triangle_fast(pp, page, backface_cull, generate_clip_flags); + } + + _asm + { + rdtsc + mov counter_end, eax + } + + extern ULONG AENG_poly_add_quad_time; + + AENG_poly_add_quad_time += counter_end - counter_start; +} + +#endif //#ifndef TARGET_DC + + + + +float POLY_world_length_to_screen(float world_length) +{ + float view_length = world_length * POLY_cam_over_view_dist; + float screen_length = view_length * POLY_screen_mul_x; + + return screen_length; +} + +float POLY_approx_len(float dx, float dy) +{ + // + // Hmm... I guess that .414F is better than 0.500F + // + + return (fabsf(dx) > fabsf(dy)) ? fabsf(dx) + 0.414F * fabsf(dy) : fabsf(dy) + 0.414F * fabsf(dx); +} + +// +// create 4 points for a cylinder; only X,Y,Z, colour & specular are set up +// + +void POLY_create_cylinder_points(POLY_Point* p1, POLY_Point* p2, float width, POLY_Point* pout) +{ + float dx,dy; // screen normal vector for line + float len,overlen; // line length/reciprocal + float dx1,dy1; // perturbation vector for p1 + float dx2,dy2; // perturbation vector for p2 + + ASSERT(p1->IsValid()); + ASSERT(p2->IsValid()); + + width *= POLY_cam_over_view_dist; // move to view space + + // + // get normalized vector along the line + // + + dx = p2->X - p1->X; + dy = p2->Y - p1->Y; + + len = POLY_approx_len(dx, dy); + overlen = 1.0F / len; + + dx *= overlen; + dy *= overlen; + + // + // get perturbation vectors + // + + dx1 = -dy * width * p1->Z; + dy1 = dx * width * p1->Z; + + dx2 = -dy * width * p2->Z; + dy2 = dx * width * p2->Z; + + // + // copy and shift points + // + + pout[0] = *p1; + pout[0].X += dx1; + pout[0].Y += dy1; + + pout[1] = *p1; + pout[1].X -= dx1; + pout[1].Y -= dy1; + + pout[2] = *p2; + pout[2].X += dx2; + pout[2].Y += dy2; + + pout[3] = *p2; + pout[3].X -= dx2; + pout[3].Y -= dy2; +} + +void POLY_add_line_tex_uv(POLY_Point *p1, POLY_Point *p2, float width1, float width2, SLONG page, UBYTE sort_to_front) +{ + float dx; + float dy; + + float dx1; + float dy1; + + float dx2; + float dy2; + + float vw1; + float vw2; + + float sw1; + float sw2; + + float len; + float overlen; + + // + // Both points must be transformed + // + + if (p1->NearClip() || p2->NearClip()) return; + + ASSERT(p1->IsValid()); + ASSERT(p2->IsValid()); + + POLY_Point pt[4]; + POLY_Point* ppt[4]; + + dx = p2->X - p1->X; + dy = p2->Y - p1->Y; + + // + // Hmm... I guess that .414F is better than 0.500F + // + + len = (fabsf(dx) > fabsf(dy)) ? fabsf(dx) + 0.414F * fabsf(dy) : fabsf(dy) + 0.414F * fabsf(dx); + overlen = 1.0F / len; + + dx *= overlen; + dy *= overlen; + + // + // Convert widths in the world to widths in view space. + // + + vw1 = width1 * POLY_cam_over_view_dist; + vw2 = width2 * POLY_cam_over_view_dist; + + // + // Convert widths in view space to widths on screen. + // + + sw1 = POLY_screen_mul_x * vw1 * p1->Z; + sw2 = POLY_screen_mul_x * vw2 * p2->Z; + + dx1 = -dy * sw1; + dy1 = +dx * sw1; + + dx2 = -dy * sw2; + dy2 = +dx * sw2; + + if (sort_to_front) + { + p1->Z = 1.0F; + p1->z = 0.0F; + + p2->Z = 1.0F; + p2->z = 0.0F; + } + + // + // Create the four points. + // + + pt[0] = *p1; + pt[1] = *p1; + + pt[0].X -= dx1; + pt[0].Y -= dy1; + + pt[1].X += dx1; + pt[1].Y += dy1; + + pt[0].u = p2->u; + + pt[2] = *p2; + pt[3] = *p2; + + pt[2].X += dx2; + pt[2].Y += dy2; + + pt[3].X -= dx2; + pt[3].Y -= dx2; + + pt[2].u = p1->u; + + ppt[0] = &pt[0]; + ppt[1] = &pt[1]; + ppt[2] = &pt[3]; + ppt[3] = &pt[2]; + +#if 0 + POLY_setclip(ppt[0]); + POLY_setclip(ppt[1]); + POLY_setclip(ppt[2]); + POLY_setclip(ppt[3]); +#endif + + POLY_add_quad(ppt, page, FALSE, TRUE); +} + + +void POLY_add_line_tex(POLY_Point *p1, POLY_Point *p2, float width1, float width2, SLONG page, UBYTE sort_to_front) +{ + p1->u = p1->v = 0; + p2->u = p2->v = 1; + + POLY_add_line_tex_uv(p1, p2, width1, width2, page, sort_to_front); +} + + +void POLY_add_line(POLY_Point *p1, POLY_Point *p2, float width1, float width2, SLONG page, UBYTE sort_to_front) +{ + float dx; + float dy; + + float dx1; + float dy1; + + float dx2; + float dy2; + + float vw1; + float vw2; + + float sw1; + float sw2; + + float len; + float overlen; + + // + // Both points must be transformed + // + + if (p1->NearClip() || p2->NearClip()) return; + + ASSERT(p1->IsValid() & p2->IsValid()); + + POLY_Point pt[4]; + POLY_Point* ppt[4]; + + dx = p2->X - p1->X; + dy = p2->Y - p1->Y; + + // + // Hmm... I guess that .414F is better than 0.500F + // + + len = (fabsf(dx) > fabsf(dy)) ? fabsf(dx) + 0.414F * fabsf(dy) : fabsf(dy) + 0.414F * fabsf(dx); + overlen = 1.0F / len; + + dx *= overlen; + dy *= overlen; + + // + // Convert widths in the world to widths in view space. + // + + vw1 = width1 * POLY_cam_over_view_dist; + vw2 = width2 * POLY_cam_over_view_dist; + + // + // Convert widths in view space to widths on screen. + // + + sw1 = POLY_screen_mul_x * vw1 * p1->Z; + sw2 = POLY_screen_mul_x * vw2 * p2->Z; + + dx1 = -dy * sw1; + dy1 = +dx * sw1; + + dx2 = -dy * sw2; + dy2 = +dx * sw2; + + if (sort_to_front) + { +#ifdef TARGET_DC + p1->Z = 0.9999F; + p1->z = 0.0001F; + + p2->Z = 0.9999F; + p2->z = 0.0001F; +#else + p1->Z = 1.0F; + p1->z = 0.0F; + + p2->Z = 1.0F; + p2->z = 0.0F; +#endif + } + + // + // Create the four points. + // + + pt[0] = *p1; + pt[1] = *p1; + pt[2] = *p2; + pt[3] = *p2; + + for (int ii = 0; ii < 4; ii++) + { + pt[ii].u = 0; + pt[ii].v = 0; + } + + pt[0].X -= dx1; + pt[0].Y -= dy1; + pt[1].X += dx1; + pt[1].Y += dy1; + + pt[2].X += dx2; + pt[2].Y += dy2; + pt[3].X -= dx2; + pt[3].Y -= dy2; + + ppt[0] = &pt[0]; + ppt[1] = &pt[1]; + ppt[2] = &pt[3]; + ppt[3] = &pt[2]; + +#if 0 + POLY_setclip(ppt[0]); + POLY_setclip(ppt[1]); + POLY_setclip(ppt[2]); + POLY_setclip(ppt[3]); +#endif + + POLY_add_quad(ppt, page, FALSE, TRUE); +} + +// +// p1 is top left +// +void POLY_add_rect(POLY_Point *p1, SLONG width,SLONG height, SLONG page, UBYTE sort_to_front) +{ + + // + // Both points must be transformed + // + + if (p1->NearClip() ) return; + + ASSERT(p1->IsValid() ); + + POLY_Point pt[4]; + POLY_Point* ppt[4]; + + + if (sort_to_front) + { + p1->Z = 1.0F; + p1->z = 0.0F; + + } + + // + // Create the four points. + // + + pt[0] = *p1; + pt[1] = *p1; + pt[2] = *p1; + pt[3] = *p1; + + for (int ii = 0; ii < 4; ii++) + { + pt[ii].u = 0; + pt[ii].v = 0; + } + + + + pt[1].X += (float)width; + pt[3].Y += (float)height; + pt[2].X += (float)width; + pt[2].Y += (float)height; + + ppt[0] = &pt[0]; + ppt[1] = &pt[1]; + ppt[2] = &pt[3]; + ppt[3] = &pt[2]; + +#if 0 + POLY_setclip(ppt[0]); + POLY_setclip(ppt[1]); + POLY_setclip(ppt[3]); +#endif + + POLY_add_quad(ppt, page, FALSE, TRUE); +} + +void POLY_add_line_2d(float sx1, float sy1, float sx2, float sy2, ULONG colour) +{ + float dx; + float dy; + + float len; + float overlen; + + POLY_Point pt[4]; + POLY_Point* ppt[4]; + + dx = sx2 - sx1; + dy = sy2 - sy1; + + // + // Hmm... I guess that .414F is better than 0.500F + // + + len = (fabsf(dx) > fabsf(dy)) ? fabsf(dx) + 0.414F * fabsf(dy) : fabsf(dy) + 0.414F * fabsf(dx); + overlen = 0.5F / len; + + dx *= overlen; + dy *= overlen; + + // + // Create the four points. + // + + for (int ii = 0; ii < 4; ii++) + { + pt[ii].u = 0; + pt[ii].v = 0; + pt[ii].colour = colour; + pt[ii].specular = 0; + } + + pt[0].X = sx1 - dy; + pt[0].Y = sy1 + dx; + pt[1].X = sx1 + dy; + pt[1].Y = sy1 - dx; + pt[2].X = sx2 + dy; + pt[2].Y = sy2 - dx; + pt[3].X = sx2 - dy; + pt[3].Y = sy2 + dx; + + ppt[0] = &pt[0]; + ppt[1] = &pt[1]; + ppt[2] = &pt[3]; + ppt[3] = &pt[2]; + +#if 0 + POLY_setclip(ppt[0]); + POLY_setclip(ppt[1]); + POLY_setclip(ppt[3]); +#endif + + POLY_add_quad(ppt, POLY_PAGE_COLOUR, FALSE, TRUE); +} + + +float POLY_clip_left; +float POLY_clip_right; +float POLY_clip_top; +float POLY_clip_bottom; + +void POLY_clip_line_box(float sx1, float sy1, float sx2, float sy2) +{ + POLY_clip_left = sx1; + POLY_clip_right = sx2; + POLY_clip_top = sy1; + POLY_clip_bottom = sy2; +} + +void POLY_clip_line_add(float sx1, float sy1, float sx2, float sy2, ULONG colour) +{ + UBYTE clip1 = 0; + UBYTE clip2 = 0; + UBYTE clip_and; + UBYTE clip_or; + UBYTE clip_xor; + + float along; + + if (sx1 < POLY_clip_left) {clip1 |= POLY_CLIP_LEFT;} + else if (sx1 > POLY_clip_right) {clip1 |= POLY_CLIP_RIGHT;} + + if (sx2 < POLY_clip_left) {clip2 |= POLY_CLIP_LEFT;} + else if (sx2 > POLY_clip_right) {clip2 |= POLY_CLIP_RIGHT;} + + if (sy1 < POLY_clip_top) {clip1 |= POLY_CLIP_TOP;} + else if (sy1 > POLY_clip_bottom) {clip1 |= POLY_CLIP_BOTTOM;} + + if (sy2 < POLY_clip_top) {clip2 |= POLY_CLIP_TOP;} + else if (sy2 > POLY_clip_bottom) {clip2 |= POLY_CLIP_BOTTOM;} + + clip_and = clip1 & clip2; + clip_or = clip1 | clip2; + clip_xor = clip1 ^ clip2; + + if (clip_and) + { + // + // Reject the line. + // + + return; + } + + #define SWAP_UB(q,w) {UBYTE temp = (q); (q) = (w); (w) = temp;} + + if (clip_or) + { + // + // The line needs clipping. + // + + if (clip_xor & POLY_CLIP_LEFT) + { + if (clip2 & POLY_CLIP_LEFT) + { + SWAP_FL(sx1, sx2); + SWAP_FL(sy1, sy2); + SWAP_UB(clip1, clip2); + } + + along = (POLY_clip_left - sx1) / (sx2 - sx1); + sx1 = POLY_clip_left; + sy1 = sy1 + along * (sy2 - sy1); + clip1 &= ~POLY_CLIP_LEFT; + + if (sy1 < POLY_clip_top) {clip1 |= POLY_CLIP_TOP;} + else if (sy1 > POLY_clip_bottom) {clip1 |= POLY_CLIP_BOTTOM;} + + if (clip1 & clip2) + { + return; + } + + clip_xor = clip1 ^ clip2; + } + + if (clip_xor & POLY_CLIP_RIGHT) + { + if (clip2 & POLY_CLIP_RIGHT) + { + SWAP_FL(sx1, sx2); + SWAP_FL(sy1, sy2); + SWAP_UB(clip1, clip2); + } + + along = (POLY_clip_right - sx1) / (sx2 - sx1); + sx1 = POLY_clip_right; + sy1 = sy1 + along * (sy2 - sy1); + clip1 &= ~POLY_CLIP_RIGHT; + + if (sy1 < POLY_clip_top) {clip1 |= POLY_CLIP_TOP;} + else if (sy1 > POLY_clip_bottom) {clip1 |= POLY_CLIP_BOTTOM;} + + if (clip1 & clip2) + { + return; + } + + clip_xor = clip1 ^ clip2; + } + + if (clip_xor & POLY_CLIP_TOP) + { + if (clip2 & POLY_CLIP_TOP) + { + SWAP_FL(sx1, sx2); + SWAP_FL(sy1, sy2); + SWAP_UB(clip1, clip2); + } + + along = (POLY_clip_top - sy1) / (sy2 - sy1); + sx1 = sx1 + along * (sx2 - sx1); + sy1 = POLY_clip_top; + clip1 &= ~POLY_CLIP_TOP; + + if (sx1 < POLY_clip_left) {clip1 |= POLY_CLIP_LEFT;} + else if (sx1 > POLY_clip_right) {clip1 |= POLY_CLIP_RIGHT;} + + if (clip1 & clip2) + { + return; + } + + clip_xor = clip1 ^ clip2; + } + + if (clip_xor & POLY_CLIP_BOTTOM) + { + if (clip2 & POLY_CLIP_BOTTOM) + { + SWAP_FL(sx1, sx2); + SWAP_FL(sy1, sy2); + SWAP_UB(clip1, clip2); + } + + along = (POLY_clip_bottom - sy1) / (sy2 - sy1); + sx1 = sx1 + along * (sx2 - sx1); + sy1 = POLY_clip_bottom; + clip1 &= ~POLY_CLIP_BOTTOM; + + if (sx1 < POLY_clip_left) {clip1 |= POLY_CLIP_LEFT;} + else if (sx1 > POLY_clip_right) {clip1 |= POLY_CLIP_RIGHT;} + + if (clip1 & clip2) + { + return; + } + + clip_xor = clip1 ^ clip2; + } + } + + if (clip1 | clip2) + { + return; + } + + // + // Phew! Add the clipped line. + // + + POLY_add_line_2d(sx1, sy1, sx2, sy2, colour); +} + +#if 0 + +SLONG POLY_shared_page; +SLONG POLY_shared_base_index; + +void POLY_add_shared_start(SLONG page) +{ + POLY_Page *pa; + D3DTLVERTEX *tl; + + ASSERT(WITHIN(page, 0, POLY_NUM_PAGES - 1)); + + pa = &POLY_page[page]; + + POLY_shared_page = page; + POLY_shared_base_index = pa->vertex_upto; +} + +void POLY_add_shared_point(POLY_Point *pp) +{ + POLY_Page *pa; + D3DTLVERTEX *tl; + + ASSERT(WITHIN(POLY_shared_page, 0, POLY_NUM_PAGES - 1)); + + pa = &POLY_page[POLY_shared_page]; + + // + // Is there enough room in the buffers for this point? + // + + if (pa->vertex_upto >= pa->size) + { + if (!POLY_grow_page(pa)) + { + return; + } + } + + tl = &pa->vertex[pa->vertex_upto]; + + tl->sx = pp->X; + tl->sy = pp->Y; + tl->sz = 1.0F - pp->Z; // 1 - 1/z z-buffer... + tl->rhw = pp->Z; + tl->tu = pp->u; + tl->tv = pp->v; + tl->color = pp->colour; // Bloody Americans! + tl->specular = pp->specular; + + pa->vertex_upto += 1; +} + +void POLY_add_shared_tri(UWORD p1, UWORD p2, UWORD p3) +{ + POLY_Page *pa; + D3DTLVERTEX *tl; + + ASSERT(WITHIN(POLY_shared_page, 0, POLY_NUM_PAGES - 1)); + + pa = &POLY_page[POLY_shared_page]; + + // + // Is there enough room in the buffers for this point? + // + + if (pa->index_upto + 3 > pa->size) + { + if (!POLY_grow_page(pa)) + { + return; + } + } + + ASSERT(WITHIN(POLY_shared_base_index + p1, 0, pa->vertex_upto - 1)); + ASSERT(WITHIN(POLY_shared_base_index + p2, 0, pa->vertex_upto - 1)); + ASSERT(WITHIN(POLY_shared_base_index + p3, 0, pa->vertex_upto - 1)); + + pa->index[pa->index_upto + 0] = POLY_shared_base_index + p1; + pa->index[pa->index_upto + 1] = POLY_shared_base_index + p2; + pa->index[pa->index_upto + 2] = POLY_shared_base_index + p3; + + pa->index_upto += 3; +} + +#endif + +// POLY_frame_draw +// +// draw all the poly pages + +#ifdef TEX_EMBED +extern SLONG PageOrder[POLY_NUM_PAGES]; +#endif + + +void POLY_frame_draw(SLONG draw_shadow_page, SLONG draw_text_page) +{ + SLONG i; + SLONG j; + SLONG k; + + PolyPage *pa; + + + static int iPageNumberToClear = 0; + + + // SPONG +#if USE_TOMS_ENGINE_PLEASE_BOB + + +// These will have been done in POLY_frame_init(). + //POLY_init_render_states(); +//#ifndef TARGET_DC + //BEGIN_SCENE; +//#endif + + +#else + ULONG fog_colour; + + // Already done if using Tom's engine. +// BreakTime("FRAMEDRAW start"); + POLY_init_render_states(); +// BreakTime("FRAMEDRAW init render states"); + + // + // Start the scene. + // + BEGIN_SCENE; + + if ((GAME_FLAGS & GF_SEWERS) || (GAME_FLAGS & GF_INDOORS)) + { + fog_colour = 0; + } + else + { + if(fade_black) + { + fog_colour=0; + } + else + { + fog_colour = + (NIGHT_sky_colour.red << 16) | + (NIGHT_sky_colour.green << 8) | + (NIGHT_sky_colour.blue << 0); + } + + if (draw_3d) + { + SLONG white = NIGHT_sky_colour.red + NIGHT_sky_colour.green + NIGHT_sky_colour.blue; + + white /= 3; + + fog_colour = + (white << 16) | + (white << 8) | + (white << 0); + } + } + + + // set default render state + DefRenderState.InitScene(fog_colour); +// BreakTime("FRAMEDRAW init scene"); + + +#endif + + // + // Draw the sky first... + // + +#ifndef TARGET_DC + pa = &POLY_Page[POLY_PAGE_SKY]; + + if (pa->NeedsRendering()) + { + pa->RS.SetChanged(); + pa->Render(the_display.lp_D3D_Device); + } +#endif +// BreakTime("FRAMEDRAW done sky"); + +#ifndef TARGET_DC +// DC sorts for us. + + if (PolyPage::AlphaSortEnabled()) + { + // + // Draw opaque polygon pages + // +// BreakTime("FRAMEDRAW start alphasort"); + + +#ifdef TEX_EMBED + for (i = 0; i <= iPolyNumPagesRender; i++) // <= because we skip POLY_PAGE_COLOUR... + { + k = PageOrder[i]; +#else + for (i = 0; i <= POLY_NUM_PAGES; i++) // <= because we skip POLY_PAGE_COLOUR... + { + k = i; +#endif + // + // Do POLY_PAGE_COLOUR first! + // + + if (i == 0) + { + k = POLY_PAGE_COLOUR; + } + else + { + k = i - 1; + + if (k == POLY_PAGE_COLOUR) + { + continue; + } + } + + pa = &POLY_Page[k]; + + if (!pa->NeedsRendering()) + { + continue; + } + + if (k == POLY_PAGE_TEXT && !draw_text_page) + { + // + // Ignore the text page. + // + + continue; + } + + if (!pa->RS.NeedsSorting() || (k == POLY_PAGE_PUDDLE)) + { + // set render state + pa->RS.SetChanged(); + + if (POLY_force_additive_alpha) + { + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZBIAS, 2); + } +/* + if(INDOORS_INDEX) + { + //poo poo poo for fadeing current floor of building + + + + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + } +*/ + +#ifndef TARGET_DC +#ifndef FINAL +#ifdef EDITOR + if (Keys[KB_P1]&&!CUTSCENE_edit_wnd) +#else + if (Keys[KB_P1])//&&allow_debug_keys) +#endif + { + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + } +#endif +#endif + + // + // and render the polygons + // + + pa->Render(the_display.lp_D3D_Device); + } + } +// BreakTime("FRAMEDRAW end alphasort"); + + // + // now draw the alpha polygons + // + +#if 1 // do it the bucket-sort way globally + + // + // generate the buckets + // + +// BreakTime("FRAMEDRAW start buckets"); + PolyPoly* buckets[2048]; + + for (i = 0; i < 2048; i++) buckets[i] = NULL; + + for (i = 0; i < POLY_NUM_PAGES; i++) + { + pa = &POLY_Page[i]; + + if (!pa->NeedsRendering()) continue; + if (i == POLY_PAGE_SHADOW && !draw_shadow_page) continue; + if (!pa->RS.NeedsSorting()) continue; + if (i == POLY_PAGE_PUDDLE) continue; + + pa->AddToBuckets(buckets, 2048); + } +// BreakTime("FRAMEDRAW mid buckets"); + + // + // render the buckets + // + + for (i = 0; i < 2048; i++) + { + PolyPoly* p = buckets[i]; + + while (p) + { + p->page->RS.SetChanged(); + p->page->DrawSinglePoly(p, the_display.lp_D3D_Device); + p = p->next; + } + } + + for (i = 0; i < POLY_NUM_PAGES; i++) + { + pa = &POLY_Page[i]; + + if (pa->RS.NeedsSorting()) pa->RS.ResetTempTransparent(); + } +// BreakTime("FRAMEDRAW end buckets"); + +#else // do it page by page +// BreakTime("FRAMEDRAW start page by page"); + + +#ifdef TEX_EMBED + for (i = 0; i <= iPolyNumPagesRender; i++) // <= because we skip POLY_PAGE_COLOUR... + { + k = PageOrder[i]; +#else + for (i = 0; i < POLY_NUM_PAGES; i++) + { + k = i; +#endif + + pa = &POLY_Page[k]; + + if (!pa->NeedsRendering()) + { + continue; + } + + if (k == POLY_PAGE_SHADOW && !draw_shadow_page) + { + // + // Ignore the shadow page. + // + + continue; + } + + if (pa->RS.NeedsSorting()) + { + // set render state + pa->RS.SetChanged(); + + if (POLY_force_additive_alpha) + { + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZBIAS, 2); + } + + if(INDOORS_INDEX) + { + //poo poo poo for fadeing current floor of building + + + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + } + +#ifdef EDITOR + if (Keys[KB_P1]&&!CUTSCENE_edit_wnd) + { + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + } +#endif + + // + // sort and render the polygons + // + + pa->SortBackFirst(); + pa->Render(the_display.lp_D3D_Device); + } + } +// BreakTime("FRAMEDRAW end page by page"); + +#endif + + } + else +#endif //#ifndef TARGET_DC + { + // + // draw all the polygons at once + // +// BreakTime("FRAMEDRAW start all polys at once"); + + +#ifdef TEX_EMBED + for (i = 0; i < iPolyNumPagesRender; i++) + { + k = PageOrder[i]; +#else + for (i = 0; i < POLY_NUM_PAGES; i++) + { + k = i; +#endif + + pa = &POLY_Page[k]; + + if (!pa->NeedsRendering()) + { + continue; + } + +// ASSERT ( draw_text_page ); +// ASSERT ( draw_shadow_page ); + + // set render state + pa->RS.SetChanged(); + + // + // render the polygons + // + + pa->Render(the_display.lp_D3D_Device); + } +// BreakTime("FRAMEDRAW end all polys at once"); + + } + + END_SCENE; + + + // And clear out a few pages' VBs and IBs. + // This stops a page that was drawing a lot a while ago from + // hogging all the memory when it goes out of scene. + for ( i = 0; i < 3; i++ ) + { + iPageNumberToClear++; + if ( iPageNumberToClear >= POLY_NUM_PAGES ) + { + iPageNumberToClear = 0; + } + POLY_Page[iPageNumberToClear].Clear(); + } + + + /* + +// +// Guy Demo Dodge!!! +// + + if(GAME_STATE&GS_ATTRACT_MODE) + { +extern void draw_text_at(float x,float y,CBYTE *message,SLONG font_id); + extern BOOL text_fudge; + extern ULONG text_colour; + + text_fudge = FALSE; + text_colour = 0x00ffffff; + draw_text_at(200,150,"Press Anything To Play",0); + +extern void show_text(void); + show_text(); + } + + */ +// TRACE("poly frame draw EXIT\n"); +} + + +void POLY_frame_draw_odd() +{ + SLONG i; + SLONG j; + + PolyPage *pa; + + +#ifdef TARGET_DC + // I'd like to know. + ASSERT ( FALSE ); +#endif + + // + // Start the scene. + // + + + BEGIN_SCENE; + + + // Sets the actual hardware RS, and also keeps the cache informed. +#define FORCE_SET_RENDER_STATE(t,s) RenderState::s_State.SetRenderState(t,s); REALLY_SET_RENDER_STATE(t,s) +#define FORCE_SET_TEXTURE(s) RenderState::s_State.SetTexture(s); REALLY_SET_TEXTURE(s) + + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_SHADEMODE,D3DSHADE_GOURAUD); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREPERSPECTIVE,TRUE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_DITHERENABLE,TRUE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_SPECULARENABLE,TRUE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_SUBPIXEL,TRUE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_ZFUNC,D3DCMP_LESSEQUAL); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_CULLMODE,D3DCULL_NONE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE);//ALPHA); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_CLAMP); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE);//SRCALPHA); + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE);//INVSRCALPHA); + + for (i = 0; i < TEXTURE_page_num_standard; i++) + { + ASSERT(WITHIN(i, 0, POLY_NUM_PAGES - 1)); + + pa = &POLY_Page[i]; + + if (!pa->NeedsRendering()) + { + continue; + } + + // + // The is one of the TEXTURE modules pages... + // + + FORCE_SET_TEXTURE(TEXTURE_get_handle(i)); + + // + // Do the actual draw primitive call. + // + + pa->Render(the_display.lp_D3D_Device); + } + + if (POLY_Page[POLY_PAGE_SKY].NeedsRendering()) + { + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE, FALSE); + FORCE_SET_TEXTURE(TEXTURE_get_handle(TEXTURE_page_sky)); + + POLY_Page[POLY_PAGE_SKY].Render(the_display.lp_D3D_Device); + } + + if (POLY_Page[POLY_PAGE_MOON].NeedsRendering()) + { + FORCE_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE, FALSE); + FORCE_SET_TEXTURE(TEXTURE_get_handle(TEXTURE_page_moon)); + + POLY_Page[POLY_PAGE_MOON].Render(the_display.lp_D3D_Device); + } + + END_SCENE; +} + + +void POLY_frame_draw_puddles() +{ + + + PolyPage *pp = &POLY_Page[POLY_PAGE_PUDDLE]; +#ifdef TEX_EMBED + // Do the indirection to the real poly page. + PolyPage *ppDrawn = pp->pTheRealPolyPage; +#else + PolyPage *ppDrawn = pp; +#endif + +#ifdef TARGET_DC + // I'd like to know. + ASSERT ( FALSE ); +#endif + + + if (pp->NeedsRendering()) + { + BEGIN_SCENE; + + // state in polyrenderstate.cpp + pp->RS.InitScene(0); + + // + // Do the actual draw primitive call. + // + + pp->Render(the_display.lp_D3D_Device); + + END_SCENE; + } +} + + +// No sewers - just here for error-checking. +#ifdef DEBUG + +// +// Comparison function for sewer water polygons. +// + +void POLY_sort_sewater_page() +{ +#ifndef TARGET_DC + POLY_Page[POLY_PAGE_SEWATER].SortBackFirst(); +#endif +} + +void POLY_frame_draw_sewater() +{ + PolyPage *pa = &POLY_Page[POLY_PAGE_SEWATER]; + + if (pa->NeedsRendering()) + { +#if 1 + // Shouldn't be any sewers. + ASSERT(FALSE); +#else + BEGIN_SCENE; + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZFUNC,D3DCMP_LESSEQUAL); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + REALLY_SET_TEXTURE(TEXTURE_get_handle(TEXTURE_page_water)); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + + // + // Do the actual draw primitive call. + // + + pa->Render(the_display.lp_D3D_Device); + + END_SCENE; +#endif + } +} + +#endif + + +SLONG POLY_get_sphere_circle( + float world_x, + float world_y, + float world_z, + float world_radius, + SLONG *screen_x, + SLONG *screen_y, + SLONG *screen_radius) +{ + float vw; + float width; + + POLY_Point pp; + + POLY_transform( + world_x, + world_y, + world_z, + &pp); + + if (pp.IsValid()) + { + // + // Find the screen width for this world width. + // + + vw = world_radius * POLY_cam_over_view_dist; + width = vw * pp.Z * POLY_screen_mul_x; + + *screen_x = SLONG(pp.X); + *screen_y = SLONG(pp.Y); + *screen_radius = SLONG(width); + + return TRUE; + } + else + { + return FALSE; + } +} + + +#if 0 + +void POLY_frame_draw_focused(float focus) +{ + SLONG i; + SLONG j; + + float df; + + PolyPage *pa; + + // + // Set-up renderstates. + // + + SET_RENDER_STATE(D3DRENDERSTATE_SHADEMODE,D3DSHADE_GOURAUD); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREPERSPECTIVE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,FILTER_TYPE); //l + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,FILTER_TYPE); //l + SET_RENDER_STATE(D3DRENDERSTATE_DITHERENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SPECULARENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SUBPIXEL,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZFUNC,D3DCMP_LESSEQUAL); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_CULLMODE,D3DCULL_NONE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGCOLOR, 0x00000000); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE, FALSE); +#ifndef TARGET_DC + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,FALSE); +#endif + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_CLAMP); + + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + + // + // Draw each standard texture page unfocused one way. + // + + for (i = 0; i < TEXTURE_page_num_standard; i++) + { + ASSERT(WITHIN(i, 0, POLY_NUM_PAGES - 1)); + + pa = &POLY_Page[i]; + + // + // Darken all the vertices and move them to the left. + // + + for (j = 0; j < pa->vertex_upto; j++) + { + tl = &pa->vertex[j]; + + //tl->color &= 0x7f7f7f7f; + //tl->specular &= 0xff7f7f7f; + + tl->sz -= 1.0F / 65536.0F; + + df = fabsf(tl->sz - focus); + + tl->sx -= df * 80.0F; + tl->sy -= df * 80.0F; + + } + + // + // The correct texture page. + // + + REALLY_SET_TEXTURE(TEXTURE_get_handle(i)); + + if (POLY_page_flag[i] & POLY_PAGE_FLAG_TRANSPARENT) + { +#ifndef TARGET_DC + TEXTURE_set_colour_key(i); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); +#endif + } + + // + // Render the polys. + // + + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_TLVERTEX, + (LPVOID) pa->vertex, + pa->vertex_upto, + pa->index, + pa->index_upto, + D3DDP_DONOTUPDATEEXTENTS); + + if (POLY_page_flag[i] & POLY_PAGE_FLAG_TRANSPARENT) + { +#ifndef TARGET_DC + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,FALSE); +#endif + } + } + + // + // Draw each standard texture page unfocused the other way. + // + + for (i = 0; i < TEXTURE_page_num_standard; i++) + { + ASSERT(WITHIN(i, 0, POLY_NUM_PAGES - 1)); + + pa = &POLY_page[i]; + + // + // Darken all the vertices and move them to the right + // + + for (j = 0; j < pa->vertex_upto; j++) + { + tl = &pa->vertex[j]; + + df = fabsf(tl->sz - focus); + + tl->sx += df * 160.0F; + tl->sy += df * 160.0F; + } + + // + // The correct texture page. + // + + REALLY_SET_TEXTURE(TEXTURE_get_handle(i)); + + if (POLY_page_flag[i] & POLY_PAGE_FLAG_TRANSPARENT) + { +#ifndef TARGET_DC + TEXTURE_set_colour_key(i); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); +#endif + } + + + // + // Render the polys. + // + + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_TLVERTEX, + (LPVOID) pa->vertex, + pa->vertex_upto, + pa->index, + pa->index_upto, + D3DDP_DONOTUPDATEEXTENTS); + + if (POLY_page_flag[i] & POLY_PAGE_FLAG_TRANSPARENT) + { +#ifndef TARGET_DC + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,FALSE); +#endif + } + } +} + +#endif + + +SLONG POLY_inside_quad( + float screen_x, + float screen_y, + POLY_Point *quad[3], + float *along_01, + float *along_02) +{ + float ax = quad[1]->X - quad[0]->X; + float ay = quad[1]->Y - quad[0]->Y; + + float bx = quad[2]->X - quad[0]->X; + float by = quad[2]->Y - quad[0]->Y; + + float dx = screen_x - quad[0]->X; + float dy = screen_y - quad[0]->Y; + + float dproda = ax*dx + ay*dy; + float dprodb = bx*dx + by*dy; + + float lena2 = ax*ax + ay*ay; + float lenb2 = bx*bx + by*by; + + float alonga = dproda / lena2; + float alongb = dprodb / lenb2; + + if (WITHIN(alonga, 0.0f, 1.0f) && + WITHIN(alongb, 0.0f, 1.0f)) + { + *along_01 = alonga; + *along_02 = alongb; + + return TRUE; + } + else + { + *along_01 = alonga; + *along_02 = alongb; + + return FALSE; + } +} + + + + + +#if !defined(TARGET_DC) + + + +// ftol replacements +extern "C" +{ + +// The Borg's original version + +__declspec(naked) long _ftol_borg(float arg) +{ + __asm + { + push ebp + mov ebp,esp + add esp, -12 + wait + fnstcw WORD PTR [ebp-2] + wait + mov ax, WORD PTR [ebp-2] + or ah, 0ch + mov WORD PTR [ebp-4], ax + fldcw WORD PTR [ebp-4] + fistp QWORD PTR [ebp-12] + fldcw WORD PTR [ebp-2] + mov eax, DWORD PTR [ebp-12] + mov edx, DWORD PTR [ebp-8] + leave + ret + } +} + +// Quick-and-dirty version + +__declspec(naked) long _ftol_fasteddie(float arg) +{ + static double temp = 0; + + __asm + { + fistp QWORD PTR temp; + mov eax,DWORD PTR temp + mov edx,DWORD PTR temp+4 + ret + } +} + +// Intel's crappy "I don't work" version +// -- fixed so it does! ;-) +// +// I mean, Jesus, it's all very well giving us +// code that does some quite clever manipulations +// of IEEE floats as ints, BUT the code as provided +// had 2 typos and 1 major bug - for fucks sake! + +__declspec(naked) long _ftol(float arg) +{ + static double temp = 0; + + __asm + { + // store as a quadword int and reload + fld st(0) // X X + fistp QWORD PTR temp // X + fild QWORD PTR temp // X [X] + mov edx,DWORD PTR temp+4 + mov eax,DWORD PTR temp + test eax,eax + je maybe_zero + + // number isn't zero, so get X - [X] +not_zero: + fsubp st(1),st // X - [X] + test edx,edx + jns positive + + // number < 0 - inc eax if X - [X] is >0 + fstp DWORD PTR temp + mov ecx,DWORD PTR temp // get IEEE rep + xor ecx,80000000h // now <0 if diff >0 + add ecx,7FFFFFFFh // carry if it was 00000001 to 7FFFFFFF + adc eax,0 // add carry in + ret + +positive: + // number > 0 - dec eax if X - [X] is <0 + fstp DWORD PTR temp + mov ecx,DWORD PTR temp // get IEEE rep + add ecx,7FFFFFFFh // carry if it was 80000001 to FFFFFFFF + sbb eax,0 // sub carry + ret + +maybe_zero: + test edx,7FFFFFFFh + jnz not_zero + + // number is zero - clear the stack + fstp st(0) + fstp st(0) + ret + } +} + +} + +// from the Intel compiler: + +void POLY_transform( + float world_x, + float world_y, + float world_z, + POLY_Point *pt, + bool bUnused) +{ + static const float _nearz = POLY_Z_NEARPLANE; + static const float _farz = 1.0F; + static const float _zplane = POLY_ZCLIP_PLANE; + + __asm + { + fld world_x // wx + mov eax, pt + fsub POLY_cam_x // cx + mov edx,eax + fld world_z // cx | wz + fld world_y // cx | wz | wy + fxch st(2) // wy | wz | cx + fstp DWORD PTR [edx] // wy | wz + fld DWORD PTR [edx] // wy | wz | cx + fxch st(2) // cx | wz | wy + fsub POLY_cam_y // cx | wz | cy + fld _nearz // cx | wz | cy | Zn + fxch st(1) // cx | wz | Zn | cy + fstp DWORD PTR [edx+4] // cx | wz | Zn + fld DWORD PTR [edx+4] // cx | wz | Zn | cy + fxch st(2) // cx | cy | Zn | wz + fsub POLY_cam_z // cx | cy | Zn | cz + fld DWORD PTR [edx+4] // cx | cy | Zn | cz | cy + fxch st(1) // cx | cy | Zn | cy | cz + fst DWORD PTR [edx+8] // cx | cy | Zn | cy | cz + fld DWORD PTR POLY_cam_matrix + 32 // cx | cy | Zn | cy | cz | M[8] + fmul st,st(1) // cx | cy | Zn | cy | cz | cz * M[8] + fld DWORD PTR [edx] // cx | cy | Zn | cy | cz | cz * M[8] | cx + fmul DWORD PTR POLY_cam_matrix // cx | cy | Zn | cy | cz | cz * M[8] | cx * M[0] + fld DWORD PTR POLY_cam_matrix + 8 // cx | cy | Zn | cy | cz | cz * M[8] | cx * M[0] | M[2] + fmul st,st(3) // cx | cy | Zn | cy | cz | cz * M[8] | cx * M[0] | cz * M[2] + fxch st(6) // cx | cz * M[2] | Zn | cy | cz | cz * M[8] | cx * M[0] | cy + fmul DWORD PTR POLY_cam_matrix + 28 // cx | cz * M[2] | Zn | cy | cz | cz * M[8] | cx * M[0] | cy * M[7] + fxch st(7) // cy * M[7] | cz * M[2] | Zn | cy | cz | cz * M[8] | cx * M[0] | cx + fmul DWORD PTR POLY_cam_matrix + 24 // cy * M[7] | cz * M[2] | Zn | cy | cz | cz * M[8] | cx * M[0] | cx * M[6] + faddp st(7),st // cx * M[6] + cy * M[7] | cz * M[2] | Zn | cy | cz | cz * M[8] | cx * M[0] + fxch st(3) // cx * M[6] + cy * M[7] | cz * M[2] | Zn | cx * M[0] | cz | cz * M[8] | cy + fmul DWORD PTR POLY_cam_matrix + 4 // cx * M[6] + cy * M[7] | cz * M[2] | Zn | cx * M[0] | cz | cz * M[8] | cy * M[1] + faddp st(3),st // cx * M[6] + cy * M[7] | cz * M[2] | Zn | cx * M[0] + cy * M[1] | cz | cz * M[8] + faddp st(5),st // Z | cz * M[2] | Zn | cx * M[0] + cy * M[1] | cz + fmul DWORD PTR POLY_cam_matrix + 20 // Z | cz * M[2] | Zn | cx * M[0] + cy * M[1] | cz * M[5] + fxch st(2) // Z | cz * M[2] | cz * M[5] | cx * M[0] + cy * M[1] | Zn + fcomp st(4) // Z | cz * M[2] | cz * M[5] | cx * M[0] + cy * M[1] (COMPARE WITH Z) + fnstsw ax + faddp st(2),st // Z | X | cz * M[5] + fld DWORD PTR POLY_cam_matrix + 12 // Z | X | cz * M[5] | M[3] + fmul DWORD PTR [edx] // Z | X | cz * M[5] | cx * M[3] + fld DWORD PTR POLY_cam_matrix + 16 // Z | X | cz * M[5] | cx * M[3] | M[4] + fmul DWORD PTR [edx+4] // Z | X | cz * M[5] | cx * M[3] | cz * M[4] + faddp st(1),st // Z | X | cz * M[5] | cx * M[3] + cz * M[4] + faddp st(1),st // Z | X | Y + fxch st(1) // Z | Y | X + fstp DWORD PTR [edx] // Z | Y + fstp DWORD PTR [edx+4] // Z + fst DWORD PTR [edx+8] // Z + sahf + jbe LABEL4 + +LABEL2: // too near + fstp st(0) + mov eax,64 + mov WORD PTR [edx+24],ax + +LABEL3: // return + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL4: // not too near + fld _farz // Z | Zf + fcomp // Z + fnstsw ax + sahf + jae LABEL6 + +LABEL5: // too far + fstp st(0) + mov eax,32 + mov WORD PTR [edx+24],ax + + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL6: // not too near or too far + fdivr DWORD PTR _zplane // sz + fld DWORD PTR [edx] // sz | X + fld DWORD PTR [edx+4] // sz | X | Y + fxch st(2) // Y | X | sz + mov eax,16 + fmul st(1),st // Y | X * sz | sz + fstp DWORD PTR [edx+20] // Y | X * sz + fmul POLY_screen_mul_x // Y | X * sz * smx + fsubr POLY_screen_mid_x // Y | sx + fstp DWORD PTR [edx+12] // Y + fmul DWORD PTR [edx+20] // Y * sz + fld POLY_screen_mid_y // Y * sz | smy + fxch st(1) // smidy | Y * sz + fmul POLY_screen_mul_y // smidy | Y * sz * smy + fsubp st(1),st // sy + mov WORD PTR [edx+24],ax + fstp DWORD PTR [edx+16] + fld POLY_screen_clip_left + fcomp DWORD PTR [edx+12] + fnstsw ax + fld DWORD PTR [edx+12] // sx + sahf + jbe LABEL12 + +LABEL7: // left clip + fstp st(0) + movzx eax,WORD PTR [edx+24] + or eax,1 + mov WORD PTR [edx+24],ax + +LABEL8: // try top clip + fld DWORD PTR [edx+16] // sy + fld POLY_screen_clip_top // sy | top +// fldz + fcomp // sy + fnstsw ax + sahf + jbe LABEL10 + +LABEL9: // top clip + fstp st(0) + movzx eax,WORD PTR [edx+24] + or eax,4 + mov WORD PTR [edx+24],ax + + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL10: // try bottom clip + fcomp POLY_screen_clip_bottom + fnstsw ax + sahf + jbe LABEL3 + +LABEL11: // bottom clip + movzx eax,WORD PTR [edx+24] + or eax,8 + mov WORD PTR [edx+24],ax + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL12: // try right clip + fcomp POLY_screen_clip_right + fnstsw ax + sahf + jbe LABEL8 + +LABEL13: // right clip + movzx eax,WORD PTR [edx+24] + or eax,2 + mov WORD PTR [edx+24],ax + jmp LABEL8 + } +} + +void POLY_transform_using_local_rotation( + float local_x, + float local_y, + float local_z, + POLY_Point *pt) +{ + static const float _nearz = POLY_Z_NEARPLANE; + static const float _farz = 1.0F; + static const float _zplane = POLY_ZCLIP_PLANE; + + __asm + { +// push ebx + mov edx,pt + mov eax,local_y + mov ecx,local_z + fld local_z // lz + fld local_z // lz | lz + fld local_z // lz | lz | lz + mov ebx,local_x + mov DWORD PTR [edx+4],eax // <- ly + fld DWORD PTR [edx+4] // lz | lz | lz | ly + mov DWORD PTR [edx+8],ecx // <- lz + mov DWORD PTR [edx],ebx // <- lx + fmul DWORD PTR POLY_cam_matrix_comb + 4 // lz | lz | lz | ly * M[1] + fld DWORD PTR [edx] // lz | lz | lz | ly * M[1] | lx + fmul DWORD PTR POLY_cam_matrix_comb // lz | lz | lz | ly * M[1] | lx * M[0] + faddp st(1),st // lz | lz | lz | ly * M[1] + lx * M[0] + fld DWORD PTR POLY_cam_matrix_comb + 12 // lz | lz | lz | ly * M[1] + lx * M[0] | M[3] + fmul DWORD PTR [edx] // lz | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] + fld DWORD PTR POLY_cam_matrix_comb + 24 // lz | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] | M[6] + fmul DWORD PTR [edx] // lz | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] | lx * M[6] + fld DWORD PTR POLY_cam_matrix_comb + 16 // lz | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] | lx * M[6] | M[4] + fmul DWORD PTR [edx+4] // lz | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] | lx * M[6] | ly * M[4] + faddp st(2),st // lz | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] + ly * M[4] | lx * M[6] + fxch st(5) // lx * M[6] | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] + ly * M[4] | lz + fmul DWORD PTR POLY_cam_matrix_comb + 8 // lx * M[6] | lz | lz | ly * M[1] + lx * M[0] | lx * M[3] + ly * M[4] | lz * M[2] + faddp st(2),st // lx * M[6] | lz | lz | rx | lx * M[3] + ly * M[4] + fld DWORD PTR POLY_cam_matrix_comb + 28 // lx * M[6] | lz | lz | rx | lx * M[3] + ly * M[4] | M[7] + fmul DWORD PTR [edx+4] // lx * M[6] | lz | lz | rx | lx * M[3] + ly * M[4] | ly * M[7] + faddp st(5),st // lx * M[6] + ly * M[7] | lz | lz | rx | lx * M[3] + ly * M[4] + fld DWORD PTR _nearz // lx * M[6] + ly * M[7] | lz | lz | rx | lx * M[3] + ly * M[4] | Zn + fxch st(3) // lx * M[6] + ly * M[7] | lz | Zn | rx | lx * M[3] + ly * M[4] | lz + fmul DWORD PTR POLY_cam_matrix_comb + 20 // lx * M[6] + ly * M[7] | lz | Zn | rx | lx * M[3] + ly * M[4] | lz * M[5] + faddp st(1),st // lx * M[6] + ly * M[7] | lz | Zn | rx | ry + fxch st(3) // lx * M[6] + ly * M[7] | ry | Zn | rx | lz + fmul DWORD PTR POLY_cam_matrix_comb + 32 // lx * M[6] + ly * M[7] | ry | Zn | rx | lz * M[8] + faddp st(4),st // rz | ry | Zn | rx + fstp DWORD PTR [edx] // rz | ry | Zn + fld DWORD PTR [edx] // rz | ry | Zn | rx + fxch st(3) // rx | ry | Zn | rz + fstp DWORD PTR [edx+8] // rx | ry | Zn + fld DWORD PTR [edx+8] // rx | ry | Zn | rz + fxch st(2) // rx | rz | Zn | ry + fstp DWORD PTR [edx+4] // rx | rz | Zn + fld DWORD PTR [edx+4] // rx | rz | Zn | ry + fxch st(3) // ry | rz | Zn | rx + fadd DWORD PTR POLY_cam_off_x // ry | rz | Zn | trx + fstp DWORD PTR [edx] // ry | rz | Zn + fxch st(2) // Zn | rz | ry + fadd DWORD PTR POLY_cam_off_y // Zn | rz | try + fstp DWORD PTR [edx+4] // Zn | rz + fadd DWORD PTR POLY_cam_off_z // Zn | trz + fxch st(1) // trz | Zn + fcomp // trz + fnstsw ax + fst DWORD PTR [edx+8] // trz + sahf + jbe LABEL4 + +LABEL2: + fstp st(0) // + mov eax,64 + mov WORD PTR [edx+24],ax + +LABEL3: + pop ebx + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL4: + fld _farz // trz | Zf + fcomp // trz + fnstsw ax + sahf + jae LABEL6 + +LABEL5: + fstp st(0) + mov eax,32 + mov WORD PTR [edx+24],ax + + pop ebx + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL6: + fdivr _zplane // sz + fld DWORD PTR [edx] // sz | trx + fld DWORD PTR [edx+4] // sz | trx | try + fxch st(2) // try | trx | sz + mov eax,16 + fmul st(1),st // try | trx * sz | sz + fstp DWORD PTR [edx+20] // try | trx * sz + fmul POLY_screen_mul_x // try | trx * sz * smx + fsubr POLY_screen_mid_x // try | sx + fstp DWORD PTR [edx+12] // try + fmul DWORD PTR [edx+20] // try * sz + fld POLY_screen_mid_y // try * sz | smidy + fxch st(1) // smidy | try * sz + fmul POLY_screen_mul_y // smidy | try * sz * smy + fsubp st(1),st // sy + mov WORD PTR [edx+24],ax + fstp DWORD PTR [edx+16] // + fld POLY_screen_clip_left + fcomp DWORD PTR [edx+12] + fnstsw ax + fld DWORD PTR [edx+12] // sx + sahf + jbe LABEL12 + +LABEL7: + fstp st(0) + movzx eax,WORD PTR [edx+24] + or eax,1 + mov WORD PTR [edx+24],ax + +LABEL8: + fld DWORD PTR [edx+16] // sy + fld POLY_screen_clip_top // sy | top + fcomp // sy + fnstsw ax + sahf + jbe LABEL10 + +LABEL9: + fstp st(0) + movzx eax,WORD PTR [edx+24] + or eax,4 + mov WORD PTR [edx+24],ax + pop ebx + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL10: + fcomp POLY_screen_clip_bottom + fnstsw ax + sahf + jbe LABEL3 + +LABEL11: + movzx eax,WORD PTR [edx+24] + or eax,8 + mov WORD PTR [edx+24],ax + pop ebx + +#ifdef _DEBUG + pop edi + pop esi + pop ebx + mov esp, ebp +#endif + pop ebp + ret + +LABEL12: + fcomp POLY_screen_clip_right + fnstsw ax + sahf + jbe LABEL8 + +LABEL13: + movzx eax,WORD PTR [edx+24] + or eax,2 + mov WORD PTR [edx+24],ax + jmp LABEL8 + } +} + + +#else //#if !defined(TARGET_DC) + + +// DC version. + + +// These are all just wrapped up for now, just to get it working. + +long _ftol_borg(float arg) +{ + return ( (int)arg ); +} + +long _ftol_fasteddie(float arg) +{ + return ( (int)arg ); +} + +long _ftol(float arg) +{ + return ( (int)arg ); +} + + +#if 0 +// Now done in poly.h and inlined. +void POLY_transform( + float world_x, + float world_y, + float world_z, + POLY_Point *pt, + bool bUnused) +{ + POLY_transform_c(world_x,world_y,world_z,pt); +} + +void POLY_transform_using_local_rotation( + float local_x, + float local_y, + float local_z, + POLY_Point *pt) +{ + POLY_transform_using_local_rotation_c(local_x,local_y,local_z,pt); +} +#endif + + +#endif //#else //#if !defined(TARGET_DC) + + + + + + + diff --git a/fallen/DDEngine/Source/polypage.cpp b/fallen/DDEngine/Source/polypage.cpp new file mode 100644 index 0000000..b282aee --- /dev/null +++ b/fallen/DDEngine/Source/polypage.cpp @@ -0,0 +1,1168 @@ +// polypage.cpp +// +// PolyPage class - main low-level rendering + +#include +#include +#include +#include "poly.h" +#include "vertexbuffer.h" +#include "polypoint.h" +#include "renderstate.h" +#include "game.h" +#include "matrix.h" + +#include "polypage.h" + +#define VERIFY_SORT 0 // debug - check mergesort gives correct result +#define WIREFRAME 0 // enable wireframe + +#if WIREFRAME && !USE_D3D_VBUF +#error Can't define WIREFRAME and not USE_D3D_VBUF +#endif + +extern int AENG_total_polys_drawn; + + + + +//----------------------------- +// PolyPage +//----------------------------- + +// static members + +#ifndef TARGET_DC +bool PolyPage::s_AlphaSort = true; +#endif +ULONG PolyPage::s_ColourMask = 0xFFFFFFFF; +float PolyPage::s_XScale = 1.0; +float PolyPage::s_YScale = 1.0; + +float not_private_smiley_xscale; +float not_private_smiley_yscale; + + +// constructor & destructor + +PolyPage::PolyPage(ULONG logsize) +{ + m_VertexBuffer = NULL; + m_VertexPtr = NULL; + m_VBLogSize = logsize; + m_VBUsed = 0; + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + m_PolyBuffer = NULL; + m_PolyBufSize = 1 << logsize; + m_PolyBufUsed = 0; + + m_PolySortBuffer = NULL; + m_PolySortBufSize = 0; +#else + m_pwIndexBuffer = NULL; + m_iNumIndicesAlloc = 0; + m_iNumIndicesUsed = 0; +#endif + +#ifdef TEX_EMBED + m_UScale = 1; + m_UOffset = 0; + m_VScale = 1; + m_VOffset = 0; + pTheRealPolyPage = this; +#endif + + ASSERT(sizeof(PolyPoint2D) == sizeof(D3DTLVERTEX)); +} + +PolyPage::~PolyPage() +{ +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + delete[] m_PolyBuffer; + delete[] m_PolySortBuffer; +#else + if ( m_pwIndexBuffer != NULL ) + { + MemFree ( m_pwIndexBuffer ); + } +#endif + + if ( m_VertexBuffer != NULL ) + { + if ( TheVPool != NULL ) + { + TheVPool->ReleaseBuffer(m_VertexBuffer); + } + } +} + +// SetTexEmbed +// +// set texture embedding + +#ifdef TEX_EMBED + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +void PolyPage::SetTexOffset ( D3DTexture *src ) +{ + src->GetTexOffsetAndScale ( &m_UScale, &m_UOffset, &m_VScale, &m_VOffset ); +} + +#else //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + +void PolyPage::SetTexEmbed(float u_scale, float u_offset, float v_scale, float v_offset) +{ + m_UScale = u_scale; + m_UOffset = u_offset; + m_VScale = v_scale; + m_VOffset = v_offset; +} + +void PolyPage::SetTexOffset(UBYTE offset) +{ + // Kludgy test. + //offset = 1; + + if (offset) + { + int x = offset & 3; + int y = (offset >> 2) & 3; + + m_UScale = 0.25f; + m_VScale = 0.25f; + m_UOffset = x * 0.25f; + m_VOffset = y * 0.25f; + } + else + { + m_UScale = 1.0f; + m_VScale = 1.0f; + m_UOffset = 0.0f; + m_VOffset = 0.0f; + } +} +#endif //#else //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + +#endif + +// SetGreenScreen +// +// set green screen (or not) + +void PolyPage::SetGreenScreen(bool enabled) +{ + s_ColourMask = enabled ? 0xFF00FF00 : 0xFFFFFFFF; +} + +// PolyPage::SetScaling +// +// set screen scaling factors + +void PolyPage::SetScaling(float xmul, float ymul) +{ + not_private_smiley_xscale = s_XScale = xmul; + not_private_smiley_yscale = s_YScale = ymul; +} + + +// PointAlloc +// +// allocate some points + +PolyPoint2D* PolyPage::PointAlloc(ULONG num_points) +{ + +#if defined(DEBUG) && defined(TEX_EMBED) + // Make sure this is a "real" page. + ASSERT ( this == pTheRealPolyPage ); +#endif + + if (!m_VertexBuffer) + { + ASSERT(!m_VBUsed); + + m_VertexBuffer = TheVPool->GetBuffer(m_VBLogSize); + + if (!m_VertexBuffer) return NULL; + + m_VertexPtr = (PolyPoint2D*)m_VertexBuffer->GetPtr(); + m_VBLogSize = m_VertexBuffer->GetLogSize(); + } + + if (m_VBUsed + num_points > GetVBSize()) + { + m_VertexBuffer = TheVPool->ExpandBuffer(m_VertexBuffer); + m_VertexPtr = (PolyPoint2D*)m_VertexBuffer->GetPtr(); + m_VBLogSize = m_VertexBuffer->GetLogSize(); + + if (m_VBUsed + num_points > GetVBSize()) + { + ASSERT ( FALSE ); + return NULL; + } + } + + PolyPoint2D* ptr = m_VertexPtr + m_VBUsed; + m_VBUsed += num_points; + + return ptr; +} + + + +#if !WE_NEED_POLYBUFFERS_PLEASE_BOB +// Allocates points for a fan, and adds the correct indices to the list to make a fan. +PolyPoint2D* PolyPage::FanAlloc(ULONG num_points) +{ + +#if defined(DEBUG) && defined(TEX_EMBED) + // Make sure this is a "real" page. + ASSERT ( this == pTheRealPolyPage ); +#endif + + // Allocate the indices. + int iNumNewTris = num_points - 2; + int iNumNewIndices = iNumNewTris * 3; + if ( iNumNewIndices + m_iNumIndicesUsed > m_iNumIndicesAlloc ) + { + // Grow it. + ULONG ulNewSize = iNumNewIndices + m_iNumIndicesUsed; + // Plus a quarter to reduce thrashing. + ulNewSize += ulNewSize >> 2; + // And round up to the nearest 4k chunk. + ulNewSize = ( ulNewSize + 4095 ) & ~4095; + WORD *pwNewBuffer = (WORD *)MemAlloc ( sizeof ( WORD ) * ulNewSize ); + ASSERT ( pwNewBuffer != NULL ); + if ( m_pwIndexBuffer != NULL ) + { + memcpy ( pwNewBuffer, m_pwIndexBuffer, sizeof ( WORD ) * m_iNumIndicesUsed ); + MemFree ( (void *)m_pwIndexBuffer ); + } + m_pwIndexBuffer = pwNewBuffer; + m_iNumIndicesAlloc = ulNewSize; + } + // Now add the indices. + WORD iIndex0 = m_VBUsed + 0; + WORD iIndex1 = m_VBUsed + 1; + WORD iIndex2 = m_VBUsed + 2; + for ( ULONG i = 2; i < num_points; i++ ) + { + m_pwIndexBuffer[m_iNumIndicesUsed+0] = iIndex0; + m_pwIndexBuffer[m_iNumIndicesUsed+1] = iIndex1; + m_pwIndexBuffer[m_iNumIndicesUsed+2] = iIndex2; + m_iNumIndicesUsed += 3; + iIndex1++; + iIndex2++; + } + + // And actually allocate the vertices. + return PointAlloc ( num_points ); +} +#endif + + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + +// PolyBufAlloc +// +// allocate a polygon in the buffer + +PolyPoly* PolyPage::PolyBufAlloc() +{ + +#if defined(DEBUG) && defined(TEX_EMBED) + // Make sure this is a "real" page. + ASSERT ( this == pTheRealPolyPage ); +#endif + + if (!m_PolyBuffer) + { + ASSERT(!m_PolyBufUsed); + + m_PolyBuffer = new PolyPoly[m_PolyBufSize]; + if (!m_PolyBuffer) return NULL; + } + + if (m_PolyBufUsed == m_PolyBufSize) + { + PolyPoly* newbuf = new PolyPoly[m_PolyBufSize * 2]; + if (!newbuf) return NULL; + + memcpy(newbuf, m_PolyBuffer, m_PolyBufSize * sizeof(PolyPoly)); + + delete[] m_PolyBuffer; + m_PolyBuffer = newbuf; + m_PolyBufSize *= 2; + } + + return m_PolyBuffer + (m_PolyBufUsed++); +} + +#endif //#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + +static inline void AlphaPremult(UBYTE* color) +{ + color[0] = UBYTE((ULONG(color[0]) * ULONG(color[3])) >> 8); + color[1] = UBYTE((ULONG(color[1]) * ULONG(color[3])) >> 8); + color[2] = UBYTE((ULONG(color[2]) * ULONG(color[3])) >> 8); +} + +static inline void InvAlphaPremult(UBYTE* color) +{ + color[0] = UBYTE((ULONG(color[0]) * ULONG(255 - color[3])) >> 8); + color[1] = UBYTE((ULONG(color[1]) * ULONG(255 - color[3])) >> 8); + color[2] = UBYTE((ULONG(color[2]) * ULONG(255 - color[3])) >> 8); +} + +// AddFan +// +// submit a fan + +static PolyPage* ppLastPolyPageSetup = NULL; + + +#ifdef TEX_EMBED +#define DRAWN_PP ppDrawn +#else +#define DRAWN_PP this +#endif + + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + +void PolyPage::AddFan(POLY_Point** pts, ULONG num_vertices) +{ + ULONG ii; + +#ifdef TEX_EMBED + PolyPage *ppDrawn = pTheRealPolyPage; +#endif + + PolyPoly* pp = DRAWN_PP->PolyBufAlloc(); + ASSERT ( pp != NULL ); + + PolyPoint2D* pv = DRAWN_PP->PointAlloc(num_vertices); + ASSERT ( pv != NULL ); + + + pp->first_vertex = pv - DRAWN_PP->m_VertexPtr; + pp->num_vertices = num_vertices; + + float zmax = pts[0]->Z; + + // apply Z bias (doesn't seem to work in D3D) + if (RS.ZLift()) + { + float zbias = float(RS.ZLift()) / 65536.0F; + for (ii = 0; ii < num_vertices; ii++) + { + pv[ii].SetSC(pts[ii]->X * s_XScale, pts[ii]->Y * s_YScale, 1.0F - pts[ii]->Z - zbias); +#ifdef TEX_EMBED + pv[ii].SetUV2(pts[ii]->u * m_UScale + m_UOffset, + pts[ii]->v * m_VScale + m_VOffset); +#else + pv[ii].SetUV(pts[ii]->u, pts[ii]->v); +#endif + pv[ii].SetColour(pts[ii]->colour & s_ColourMask); + pv[ii].SetSpecular(pts[ii]->specular); + + if (pts[ii]->Z > zmax) zmax = pts[ii]->Z; + } + + pp->sort_z = zmax + zbias; + } + else + { + float zmax = pts[0]->Z; + + for (ii = 0; ii < num_vertices; ii++) + { + pv[ii].SetSC(pts[ii]->X * s_XScale, pts[ii]->Y * s_YScale, 1.0F - pts[ii]->Z); +#ifdef TEX_EMBED + pv[ii].SetUV2(pts[ii]->u * m_UScale + m_UOffset, + pts[ii]->v * m_VScale + m_VOffset); +#else + pv[ii].SetUV(pts[ii]->u, pts[ii]->v); +#endif + pv[ii].SetColour(pts[ii]->colour & s_ColourMask); + pv[ii].SetSpecular(pts[ii]->specular); + + if (pts[ii]->Z > zmax) zmax = pts[ii]->Z; + } + + pp->sort_z = zmax; + } + +#if WIREFRAME + AddWirePoly(pts, num_vertices); +#endif + +} + + +// AddWirePoly +// +// submit a wireframe polygon + +void PolyPage::AddWirePoly(POLY_Point** pts, ULONG num_vertices) +{ +#if WIREFRAME + ULONG ii; + +#ifdef TEX_EMBED + PolyPage *ppDrawn = pTheRealPolyPage; +#endif + + + PolyPoly* pp = DRAWN_PP->PolyBufAlloc(); + if (!pp) return; + + PolyPoint2D* pv = DRAWN_PP->PointAlloc(num_vertices); + if (!pv) return; + + pp->first_vertex = pv - DRAWN_PP->m_VertexPtr; + pp->num_vertices = num_vertices | 0x8000; + + // apply Z bias (doesn't seem to work in D3D) + float zbias = float(RS.ZLift() + 8) / 65536.0F; + + for (ii = 0; ii < num_vertices; ii++) + { + pv[ii].SetSC(pts[ii]->X * s_XScale, pts[ii]->Y * s_YScale, 1.0F - pts[ii]->Z - zbias); + pv[ii].SetUV(pts[ii]->u, pts[ii]->v); + pv[ii].SetColour(0x00808080); + pv[ii].SetSpecular(0xFF000000); + } + + pp->sort_z = pts[0]->Z + zbias; +#endif +} + +#endif //#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + + +// MassageVertices +// +// change vertices to match RS.GetEffect() + +void PolyPage::MassageVertices() +{ +#ifdef TEX_EMBED + if ( pTheRealPolyPage != this ) + { + // Don't do this to non-drawn pages. + return; + } +#endif + + if (RS.GetEffect()) + { + ULONG ii; + D3DTLVERTEX* vptr = m_VertexBuffer->GetPtr(); + + switch (RS.GetEffect()) + { + case RS_AlphaPremult: + for (ii = 0; ii < m_VBUsed; ii++) + { + AlphaPremult((UBYTE*)&vptr[ii].color); + } + break; + + case RS_BlackWithAlpha: + for (ii = 0; ii < m_VBUsed; ii++) + { + vptr[ii].color &= 0xFF000000; + } + break; + + case RS_InvAlphaPremult: + for (ii = 0; ii < m_VBUsed; ii++) + { + InvAlphaPremult((UBYTE*)&vptr[ii].color); + } + break; + + case RS_DecalMode: + for (ii = 0; ii < m_VBUsed; ii++) + { + vptr[ii].color = 0xFFFFFFFF; + } + break; + } + } +} + +// Render +// +// render to card (render state should already be set up) + +static UWORD IxBuffer[65536]; + +void PolyPage::Render(IDirect3DDevice3* dev) +{ + ULONG ii; + + if (!m_VertexBuffer/* || !m_PolyBufUsed*/) return; + +#if defined(DEBUG) && defined(TEX_EMBED) + // Should only be rendering stuff from polypages that are real ones, + // i.e. they are not just living on another page. + // So this should just map back to itself. + ASSERT ( this == pTheRealPolyPage ); +#endif + + // apply vertex FX + MassageVertices(); + +#if USE_D3D_VBUF + IDirect3DVertexBuffer* vb = TheVPool->PrepareBuffer(m_VertexBuffer); + m_VertexBuffer = NULL; + m_VertexPtr = NULL; + + PolyPoly* src = m_PolyBuffer; + UWORD* dst = IxBuffer; + + for (ii = 0; ii < m_PolyBufUsed; ii++) + { + UWORD v1 = src->first_vertex; + + ASSERT(dst - IxBuffer + 3 < 65536); + + #if WIREFRAME + if (!(src->num_vertices & 0x8000)) + #endif + { + for (ULONG jj = 2; jj < src->num_vertices; jj++) + { + *dst++ = v1; + *dst++ = v1 + jj - 1; + *dst++ = v1 + jj; + } + } + src++; + } + + dev->DrawIndexedPrimitiveVB(D3DPT_TRIANGLELIST, vb, IxBuffer, dst - IxBuffer, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT); + +#if WIREFRAME + src = m_PolyBuffer; + dst = IxBuffer; + + for (ii = 0; ii < m_PolyBufUsed; ii++) + { + UWORD v1 = src->first_vertex; + + if (src->num_vertices & 0x8000) + { + for (ULONG jj = 1; jj < (src->num_vertices & 0x7FFF); jj++) + { + *dst++ = v1 + jj - 1; + *dst++ = v1 + jj; + } + *dst++ = v1 + jj - 1; + *dst++ = v1; + } + src++; + } + + dev->SetTexture(0, NULL); + dev->DrawIndexedPrimitiveVB(D3DPT_LINELIST, vb, IxBuffer, dst - IxBuffer, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT); +#endif + +#else // !USE_D3D_VBUF + + + #ifndef TARGET_DC + if (!Keys[KB_F8]) + { + PolyPoly* src = m_PolyBuffer; + UWORD* dst = IxBuffer; + + for (ii = 0; ii < m_PolyBufUsed; ii++) + { + UWORD v1 = src->first_vertex; + + for (ULONG jj = 2; jj < src->num_vertices; jj++) + { + *dst++ = v1; + *dst++ = v1 + jj - 1; + *dst++ = v1 + jj; + } + src++; + } + + + HRESULT hres; + + hres = dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, m_VertexPtr, m_VBUsed, IxBuffer, dst - IxBuffer, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + + // ASSERT(hres == D3D_OK); + } + else + #endif + { + HRESULT hres; + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + hres = dev->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, m_VertexPtr, m_VBUsed, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); +#else + hres = dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, m_VertexPtr, m_VBUsed, m_pwIndexBuffer, m_iNumIndicesUsed, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); +#endif + + ASSERT(hres == D3D_OK); + } + +#endif + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + AENG_total_polys_drawn += m_PolyBufUsed; + m_PolyBufUsed = 0; +#else + //AENG_total_polys_drawn += m_VBUsed / 3; + AENG_total_polys_drawn += m_iNumIndicesUsed / 3; + m_iNumIndicesUsed = 0; +#endif + + m_VBUsed = 0; +} + + + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + +// DrawSinglePoly +// +// draw a single polygon + +void PolyPage::DrawSinglePoly(PolyPoly* poly, IDirect3DDevice3* dev) +{ + UWORD* dst = IxBuffer; + + UWORD v1 = poly->first_vertex; + + for (ULONG jj = 2; jj < poly->num_vertices; jj++) + { + *dst++ = v1; + *dst++ = v1 + jj - 1; + *dst++ = v1 + jj; + } + +#if USE_D3D_VBUF +// dev->DrawIndexedPrimitiveVB(D3DPT_TRIANGLELIST, m_VB, IxBuffer, dst - IxBuffer, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT); +#endif +} + +// AddToBuckets +// +// add polygons to buckets + +void PolyPage::AddToBuckets(PolyPoly* buckets[], int count) +{ + if (!m_VertexBuffer || !m_PolyBufUsed) return; + + // apply vertex effects + MassageVertices(); + + // obtain vertex buffer pointer +#if USE_D3D_VBUF + m_VB = TheVPool->PrepareBuffer(m_VertexBuffer); +#endif + + // add to buckets + for (DWORD ii = 0; ii < m_PolyBufUsed; ii++) + { + PolyPoly* poly = &m_PolyBuffer[ii]; + + int bucket = int(poly->sort_z * count); + if (bucket < 0) bucket = 0; + if (bucket >= count) bucket = count - 1; + + poly->page = this; + poly->next = buckets[bucket]; + buckets[bucket] = poly; + } + + // clear everything else +#if USE_D3D_VBUF + m_VertexBuffer = NULL; + m_VertexPtr = NULL; +#endif + m_VBUsed = 0; + m_PolyBufUsed = 0; +} + +#endif //#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + +// Clear +// +// clear buffer + +void PolyPage::Clear() +{ + if (!m_VertexBuffer) return; + +//#if USE_D3D_VBUF + TheVPool->ReleaseBuffer(m_VertexBuffer); + m_VertexBuffer = NULL; + m_VertexPtr = NULL; +//#endif + + m_VBUsed = 0; +#if WE_NEED_POLYBUFFERS_PLEASE_BOB +#ifdef TARGET_DC +#error Don't use this on a DC you fool! +#endif + m_PolyBufUsed = 0; +#else + // Free up the index buffer + if ( m_pwIndexBuffer != NULL ) + { + MemFree ( m_pwIndexBuffer ); + ASSERT ( m_iNumIndicesAlloc != 0 ); + } + else + { + ASSERT ( m_iNumIndicesAlloc == 0 ); + } + m_pwIndexBuffer = NULL; + m_iNumIndicesAlloc = 0; + m_iNumIndicesUsed = 0; +#endif //#if WE_NEED_POLYBUFFERS_PLEASE_BOB +} + +// SortBackFirst +// +// sort polygons (approx) by Z + +#if WE_NEED_POLYBUFFERS_PLEASE_BOB + +void PolyPage::SortBackFirst() +{ + if (!m_PolyBufUsed || !PolyPage::AlphaSortEnabled()) return; + + // delete old sort array if buffer has been resized + if (m_PolySortBuffer && (m_PolySortBufSize != m_PolyBufSize)) + { + delete[] m_PolySortBuffer; + m_PolySortBuffer = NULL; + } + + // allocate a sort array if necessary + // (lazy allocation so unsorted pages don't waste RAM) + if (!m_PolySortBuffer) + { + m_PolySortBufSize = m_PolyBufSize; + m_PolySortBuffer = new PolyPoly[m_PolySortBufSize]; + + if (!m_PolySortBuffer) return; // erk + } + + // run the merge sort (non-recursive for speed) + ULONG sort_len = 1; // sort pairs first + + while (sort_len < m_PolyBufUsed) + { + // sort each items by merging 2 sets of items + MergeSortIteration(sort_len); + + // switch arrays + PolyPoly* tmp = m_PolyBuffer; + m_PolyBuffer = m_PolySortBuffer; + m_PolySortBuffer = tmp; + + // now merge pairs of these sets + sort_len *= 2; + } + +#if VERIFY_SORT + for (ULONG jj = 0; jj < m_PolyBufUsed - 1; jj++) + { + ASSERT(m_PolyBuffer[jj] <= m_PolyBuffer[jj+1]); + } +#endif +} + +// DoMerge +// +// merge a single set (class T must have a < & <= operator, hopefully inline) + +template +inline static void DoMerge(const T* src, T* dst, ULONG len1, ULONG len2) +{ + ULONG pos1 = 0; + ULONG pos2 = len1; + ULONG wpos = 0; + ULONG end = len1 + len2; + + for (;;) + { + if (src[pos2] < src[pos1]) + { + // write from 2nd array + dst[wpos++] = src[pos2++]; + if (pos2 == end) break; // end of 2nd input array + } + else + { + // write from 1st array + dst[wpos++] = src[pos1++]; + if (pos1 == len1) break; // end of 1st input array + } + } + + // append the rest of the other array + if (pos1 == len1) + { + while (pos2 < end) + { + dst[wpos++] = src[pos2++]; + } + } + else + { + while (pos1 < len1) + { + dst[wpos++] = src[pos1++]; + } + } + +#if VERIFY_SORT + ASSERT(wpos == end); + ASSERT(pos1 == len1); + ASSERT(pos2 == end); + + for (ULONG jj = 0; jj < end - 1; jj++) + { + ASSERT(dst[jj] <= dst[jj+1]); + } +#endif +} + +// MergeSortIteration +// +// merge pairs of size sort_len + +void PolyPage::MergeSortIteration(ULONG sort_len) +{ + ULONG ii; + ULONG set_len = sort_len * 2; + ULONG limit = m_PolyBufUsed - set_len; // inclusive + PolyPoly* src = m_PolyBuffer; + PolyPoly* dst = m_PolySortBuffer; + + if (sort_len == 1) + { + // zip through pair-sorts + for (ii = 0; ii <= limit; ii += set_len) + { + if (src[0].sort_z > src[1].sort_z) + { + // wrong order + dst[0] = src[1]; + dst[1] = src[0]; + } + else + { + // right order + dst[0] = src[0]; + dst[1] = src[1]; + } + src += set_len; + dst += set_len; + } + // last bit + if (ii != m_PolyBufUsed) + { + dst[0] = src[0]; + } + } + else + { + // merge each pair of sets + for (ii = 0; ii <= limit; ii += set_len) + { + DoMerge(src, dst, sort_len, sort_len); + src += set_len; + dst += set_len; + } + // last bit + if (ii != m_PolyBufUsed) + { + if (ii + sort_len >= m_PolyBufUsed) + { + // only 1 part - just copy + while (ii < m_PolyBufUsed) + { + *dst++ = *src++; + ii++; + } + } + else + { + // 2 parts - merge + DoMerge(src, dst, sort_len, m_PolyBufUsed - (ii + sort_len)); + } + } + } +} + + +#endif //#if WE_NEED_POLYBUFFERS_PLEASE_BOB + + + + +// A routine to emulate the DC's DrawPrimtiveMM call on the PC, so +// that people can use it when developing on the PC. + +// See polypage.h for more details. + + +void GenerateMMMatrixFromStandardD3DOnes ( D3DMATRIX *pmOutput, + const D3DMATRIX *mProjectionMatrix, + const D3DMATRIX *mWorldMatrix, + const D3DVIEWPORT2 *d3dvpt ) +{ + // Matrices must be 32-byte aligned. + ASSERT ( ( (DWORD)(pmOutput) & 31 ) == 0 ); + + D3DMATRIX mMyPrivateWorld; + if ( mWorldMatrix == NULL ) + { + // Use the standard camera matrix, rather than anything custom. + // This is faster than calling POLY_set_local_rotation_none first. + float POLY_cam_off_x = -POLY_cam_x; + float POLY_cam_off_y = -POLY_cam_y; + float POLY_cam_off_z = -POLY_cam_z; + + MATRIX_MUL( + POLY_cam_matrix, + POLY_cam_off_x, + POLY_cam_off_y, + POLY_cam_off_z); + + mMyPrivateWorld._11 = POLY_cam_matrix[0]; + mMyPrivateWorld._21 = POLY_cam_matrix[1]; + mMyPrivateWorld._31 = POLY_cam_matrix[2]; + mMyPrivateWorld._41 = POLY_cam_off_x; + mMyPrivateWorld._12 = POLY_cam_matrix[3]; + mMyPrivateWorld._22 = POLY_cam_matrix[4]; + mMyPrivateWorld._32 = POLY_cam_matrix[5]; + mMyPrivateWorld._42 = POLY_cam_off_y; + mMyPrivateWorld._13 = POLY_cam_matrix[6]; + mMyPrivateWorld._23 = POLY_cam_matrix[7]; + mMyPrivateWorld._33 = POLY_cam_matrix[8]; + mMyPrivateWorld._43 = POLY_cam_off_z; + mMyPrivateWorld._14 = 0.0f; + mMyPrivateWorld._24 = 0.0f; + mMyPrivateWorld._34 = 0.0f; + mMyPrivateWorld._44 = 1.0f; + mWorldMatrix = &mMyPrivateWorld; + } + + D3DMATRIX matTemp; + { + //_Multiply4dM((float *)pResultMatrix, (float *)g_matWorld, (float *)g_matProjection); + + matTemp._11 = mWorldMatrix->_11*mProjectionMatrix->_11 + mWorldMatrix->_12*mProjectionMatrix->_21 + mWorldMatrix->_13*mProjectionMatrix->_31 + mWorldMatrix->_14*mProjectionMatrix->_41; + matTemp._12 = mWorldMatrix->_11*mProjectionMatrix->_12 + mWorldMatrix->_12*mProjectionMatrix->_22 + mWorldMatrix->_13*mProjectionMatrix->_32 + mWorldMatrix->_14*mProjectionMatrix->_42; + matTemp._13 = mWorldMatrix->_11*mProjectionMatrix->_13 + mWorldMatrix->_12*mProjectionMatrix->_23 + mWorldMatrix->_13*mProjectionMatrix->_33 + mWorldMatrix->_14*mProjectionMatrix->_43; + matTemp._14 = mWorldMatrix->_11*mProjectionMatrix->_14 + mWorldMatrix->_12*mProjectionMatrix->_24 + mWorldMatrix->_13*mProjectionMatrix->_34 + mWorldMatrix->_14*mProjectionMatrix->_44; + + matTemp._21 = mWorldMatrix->_21*mProjectionMatrix->_11 + mWorldMatrix->_22*mProjectionMatrix->_21 + mWorldMatrix->_23*mProjectionMatrix->_31 + mWorldMatrix->_24*mProjectionMatrix->_41; + matTemp._22 = mWorldMatrix->_21*mProjectionMatrix->_12 + mWorldMatrix->_22*mProjectionMatrix->_22 + mWorldMatrix->_23*mProjectionMatrix->_32 + mWorldMatrix->_24*mProjectionMatrix->_42; + matTemp._23 = mWorldMatrix->_21*mProjectionMatrix->_13 + mWorldMatrix->_22*mProjectionMatrix->_23 + mWorldMatrix->_23*mProjectionMatrix->_33 + mWorldMatrix->_24*mProjectionMatrix->_43; + matTemp._24 = mWorldMatrix->_21*mProjectionMatrix->_14 + mWorldMatrix->_22*mProjectionMatrix->_24 + mWorldMatrix->_23*mProjectionMatrix->_34 + mWorldMatrix->_24*mProjectionMatrix->_44; + + matTemp._31 = mWorldMatrix->_31*mProjectionMatrix->_11 + mWorldMatrix->_32*mProjectionMatrix->_21 + mWorldMatrix->_33*mProjectionMatrix->_31 + mWorldMatrix->_34*mProjectionMatrix->_41; + matTemp._32 = mWorldMatrix->_31*mProjectionMatrix->_12 + mWorldMatrix->_32*mProjectionMatrix->_22 + mWorldMatrix->_33*mProjectionMatrix->_32 + mWorldMatrix->_34*mProjectionMatrix->_42; + matTemp._33 = mWorldMatrix->_31*mProjectionMatrix->_13 + mWorldMatrix->_32*mProjectionMatrix->_23 + mWorldMatrix->_33*mProjectionMatrix->_33 + mWorldMatrix->_34*mProjectionMatrix->_43; + matTemp._34 = mWorldMatrix->_31*mProjectionMatrix->_14 + mWorldMatrix->_32*mProjectionMatrix->_24 + mWorldMatrix->_33*mProjectionMatrix->_34 + mWorldMatrix->_34*mProjectionMatrix->_44; + + matTemp._41 = mWorldMatrix->_41*mProjectionMatrix->_11 + mWorldMatrix->_42*mProjectionMatrix->_21 + mWorldMatrix->_43*mProjectionMatrix->_31 + mWorldMatrix->_44*mProjectionMatrix->_41; + matTemp._42 = mWorldMatrix->_41*mProjectionMatrix->_12 + mWorldMatrix->_42*mProjectionMatrix->_22 + mWorldMatrix->_43*mProjectionMatrix->_32 + mWorldMatrix->_44*mProjectionMatrix->_42; + matTemp._43 = mWorldMatrix->_41*mProjectionMatrix->_13 + mWorldMatrix->_42*mProjectionMatrix->_23 + mWorldMatrix->_43*mProjectionMatrix->_33 + mWorldMatrix->_44*mProjectionMatrix->_43; + matTemp._44 = mWorldMatrix->_41*mProjectionMatrix->_14 + mWorldMatrix->_42*mProjectionMatrix->_24 + mWorldMatrix->_43*mProjectionMatrix->_34 + mWorldMatrix->_44*mProjectionMatrix->_44; + } + +#if 0 + // Officially correct version. + DWORD dwWidth = d3dvpt.dwWidth >> 1; + DWORD dwHeight = d3dvpt.dwHeight >> 1; + DWORD dwX = d3dvpt.dwX; + DWORD dwY = d3dvpt.dwY; +#else + // Version that knows about the letterbox mode hack. +extern DWORD g_dw3DStuffHeight; +extern DWORD g_dw3DStuffY; + DWORD dwWidth = d3dvpt->dwWidth >> 1; + DWORD dwHeight = g_dw3DStuffHeight >> 1; + DWORD dwX = d3dvpt->dwX; + DWORD dwY = g_dw3DStuffY; +#endif + pmOutput->_11 = 0.0f; + pmOutput->_12 = matTemp._11 * (float)dwWidth + matTemp._14 * (float)( dwX + dwWidth ); + pmOutput->_13 = matTemp._12 * - (float)dwHeight + matTemp._14 * (float)( dwY + dwHeight ); + pmOutput->_14 = matTemp._14; + pmOutput->_21 = 0.0f; + pmOutput->_22 = matTemp._21 * (float)dwWidth + matTemp._24 * (float)( dwX + dwWidth ); + pmOutput->_23 = matTemp._22 * - (float)dwHeight + matTemp._24 * (float)( dwY + dwHeight ); + pmOutput->_24 = matTemp._24; + pmOutput->_31 = 0.0f; + pmOutput->_32 = matTemp._31 * (float)dwWidth + matTemp._34 * (float)( dwX + dwWidth ); + pmOutput->_33 = matTemp._32 * - (float)dwHeight + matTemp._34 * (float)( dwY + dwHeight ); + pmOutput->_34 = matTemp._34; + // Validation magic number. + unsigned long EVal = 0xe0001000; + pmOutput->_41 = *(float *)&EVal; + pmOutput->_42 = matTemp._41 * (float)dwWidth + matTemp._44 * (float)( dwX + dwWidth ); + pmOutput->_43 = matTemp._42 * - (float)dwHeight + matTemp._44 * (float)( dwY + dwHeight ); + pmOutput->_44 = matTemp._44; +} + + + + + + + + + +// You can usually get the standard data from these globals - I keep them +// all current, and update g_matWorld when you call POLY_set_local_rotation +// and similar calls. You can use a different matrix of course and not call +// POLY_set_local_rotation, which is probably slightly faster. +extern D3DMATRIX g_matProjection; +extern D3DMATRIX g_matWorld; +extern D3DVIEWPORT2 g_viewData; + + +#ifndef TARGET_DC + +// The DC version is just #defined in the header. + +// dwFVFType must be D3DFVF_VERTEX or D3DFVF_LVERTEX. +// d3dmm is the multimatrix info block: +HRESULT DrawIndPrimMM ( LPDIRECT3DDEVICE3 lpDevice, + DWORD dwFVFType, + D3DMULTIMATRIX *d3dmm, + WORD wNumVertices, + WORD *pwIndices, + DWORD dwNumIndices ) +{ + // Check alignments. + ASSERT ( ( (DWORD)(d3dmm->lpd3dMatrices) & 31 ) == 0 ); + ASSERT ( ( (DWORD)(d3dmm->lpvVertices) & 31 ) == 0 ); + ASSERT ( ( (DWORD)(d3dmm->lpLightTable) & 3 ) == 0 ); + ASSERT ( ( (DWORD)(d3dmm->lpvLightDirs) & 7 ) == 0 ); + + ASSERT ( ( dwFVFType == D3DFVF_LVERTEX ) || ( dwFVFType == D3DFVF_VERTEX ) ); + + D3DTLVERTEX pTLVert[3]; + D3DLVERTEX *pLVert = (D3DLVERTEX *)d3dmm->lpvVertices; + + WORD *pwCurIndex = pwIndices; + while ( TRUE ) + { + WORD wIndex[3]; + // Start a strip. + wIndex[1] = *pwCurIndex++; + wIndex[2] = *pwCurIndex++; + ASSERT ( dwNumIndices > 1 ); + dwNumIndices -= 2; + bool bEven = TRUE; + while ( TRUE ) + { + bEven = !bEven; + wIndex[0] = wIndex[1]; + wIndex[1] = wIndex[2]; + wIndex[2] = *pwCurIndex++; + ASSERT ( dwNumIndices > 0 ); + dwNumIndices--; + + if ( wIndex[2] == 0xffff ) + { + // End of list. + break; + } + + + // Load & transform the verts. + for ( int i = 0; i < 3; i++ ) + { + WORD wVertIndex = wIndex[i]; + ASSERT ( wVertIndex < wNumVertices ); + D3DLVERTEX *pLVertCur = pLVert + wVertIndex; + + BYTE bMatIndex = ((unsigned char*)(pLVertCur))[12]; + + D3DMATRIX *pmCur = &(d3dmm->lpd3dMatrices[bMatIndex]); + ASSERT ( *((DWORD*)(&(pmCur->_41))) == 0xe0001000 ); + + pTLVert[i].dvSX = pLVertCur->dvX * pmCur->_12 + pLVertCur->dvY * pmCur->_22 + pLVertCur->dvZ * pmCur->_32 + pmCur->_42; + pTLVert[i].dvSY = pLVertCur->dvX * pmCur->_13 + pLVertCur->dvY * pmCur->_23 + pLVertCur->dvZ * pmCur->_33 + pmCur->_43; + pTLVert[i].dvSZ = pLVertCur->dvX * pmCur->_14 + pLVertCur->dvY * pmCur->_24 + pLVertCur->dvZ * pmCur->_34 + pmCur->_44; + pTLVert[i].dvRHW = 1.0f / pTLVert[i].dvSZ; + pTLVert[i].dvSX *= pTLVert[i].dvRHW; + pTLVert[i].dvSY *= pTLVert[i].dvRHW; + pTLVert[i].dvSZ *= ( POLY_ZCLIP_PLANE ); + + + pTLVert[i].dvTU = pLVert[wIndex[i]].dvTU; + pTLVert[i].dvTV = pLVert[wIndex[i]].dvTV; + + + if ( dwFVFType == D3DFVF_VERTEX ) + { + // I don't actually do lighting yet - just make sure it's visible. + pTLVert[i].dcColor = 0xffffffff; + pTLVert[i].dcSpecular = 0xffffffff; + } + else + { + pTLVert[i].dcColor = pLVert[wIndex[i]].dcColor; + pTLVert[i].dcSpecular = pLVert[wIndex[i]].dcSpecular; + } + } + + // And draw the thing. + WORD wMyIndices[3]; + if ( bEven ) + { + wMyIndices[0] = 0; + wMyIndices[1] = 2; + wMyIndices[2] = 1; + } + else + { + wMyIndices[0] = 0; + wMyIndices[1] = 1; + wMyIndices[2] = 2; + } + //HRESULT hres = lpDevice->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DVT_TLVERTEX, pTLVert, 3, wMyIndices, 3, 0 ); + HRESULT hres = lpDevice->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, pTLVert, 3, wMyIndices, 3, 0 ); + if ( FAILED ( hres ) ) + { + return ( hres ); + } + } + if ( dwNumIndices == 0 ) + { + // No more indices. + break; + } + } + + // Check that the next index exists to work around MS driver bug. + //ASSERT ( *pwCurIndex == 0x1234 ); + + return ( DD_OK ); +} + + +#endif diff --git a/fallen/DDEngine/Source/polypoint.cpp b/fallen/DDEngine/Source/polypoint.cpp new file mode 100644 index 0000000..af05064 --- /dev/null +++ b/fallen/DDEngine/Source/polypoint.cpp @@ -0,0 +1,12 @@ +// polypoint.cpp +// +// PolyPoint class, encapsulating a D3DTLVERTEX + +#include +#include +#include +#include "poly.h" +#include "vertexbuffer.h" + +#include "polypoint.h" + diff --git a/fallen/DDEngine/Source/polyrenderstate.cpp b/fallen/DDEngine/Source/polyrenderstate.cpp new file mode 100644 index 0000000..57a1edc --- /dev/null +++ b/fallen/DDEngine/Source/polyrenderstate.cpp @@ -0,0 +1,1776 @@ +// +// Drawing polygons with D3D +// + +#include +#include +#include +#include "Game.h" // Guy - 4 DEMO +#include "matrix.h" +#include "poly.h" +#include "texture.h" +#include "message.h" +#include "night.h" +#ifndef TARGET_DC +#include "clip.h" +#endif +#include "vertexbuffer.h" +#include "polypoint.h" +#include "renderstate.h" +#include "polypage.h" +#include "env.h" +#include "sw.h" + +extern RenderState DefRenderState; +extern PolyPage POLY_Page[POLY_NUM_PAGES]; + +#ifdef TEX_EMBED +SLONG PageOrder[POLY_NUM_PAGES]; +static bool PageOrdered[POLY_NUM_PAGES]; +#endif + +// static flag for render state setup + +static bool RenderStates_OK = false; + +// #define interface for setting state in a PolyPage instead +// of to the card + +#undef SET_TEXTURE +#undef SET_NO_TEXTURE +#undef SET_RENDER_STATE + +#ifdef TEX_EMBED + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +#define SET_TEXTURE(PAGE) { pa->RS.SetTexture(TEXTURE_get_handle(PAGE)); pa->SetTexOffset(TEXTURE_get_D3DTexture(PAGE)); } +#else +#define SET_TEXTURE(PAGE) { pa->RS.SetTexture(TEXTURE_get_handle(PAGE)); pa->SetTexOffset(TEXTURE_get_offset(PAGE)); } +#endif + +#else + +#define SET_TEXTURE(PAGE) pa->RS.SetTexture(TEXTURE_get_handle(PAGE)) +#endif +#define SET_NO_TEXTURE pa->RS.SetTexture(NULL) +#define SET_RENDER_STATE(I,V) pa->RS.SetRenderState(I,V) +#define SET_EFFECT(FX) pa->RS.SetEffect(FX) + +// POLY_reset_render_states +// +// reset render states + +void POLY_reset_render_states() +{ + RenderStates_OK = false; +} + +// POLY_init_texture_flags +// +// clear everything + +void POLY_init_texture_flags(void) +{ + POLY_reset_render_states(); + memset(POLY_page_flag, 0, sizeof(POLY_page_flag)); +} + +// POLY_load_texture_flags +// +// load flags from file + +void POLY_load_texture_flags(CBYTE *fname, SLONG offset) +{ + FILE *handle = MF_Fopen(fname, "rb"); + + if (handle) + { + CBYTE line[256]; + SLONG match; + SLONG page = 0; + + while(fgets(line, 256, handle)) + { + match = sscanf(line, "Page %d:", &page); + + page += offset; + + if (match == 1 && WITHIN(page, 0, POLY_NUM_PAGES - 1)) + { + CBYTE *c; + + for (c = line; *c; c++); // Zoom to the end of the line. + + while(1) + { + c--; + + if (*c == 'T' || *c == 't') + { + POLY_page_flag[page] |= POLY_PAGE_FLAG_TRANSPARENT; + } + else + if (*c == 'W' || *c == 'w') + { + POLY_page_flag[page] |= POLY_PAGE_FLAG_WRAP; + } + else + if (*c == 'A' || *c == 'a') + { + POLY_page_flag[page] |= POLY_PAGE_FLAG_ADD_ALPHA; + } + else + if (*c == 'I' || *c == 'i') + { + if (WITHIN(page, 0, POLY_NUM_PAGES - 2)) + { + POLY_page_flag[page + 0] |= POLY_PAGE_FLAG_2PASS; + POLY_page_flag[page + 1] |= POLY_PAGE_FLAG_TRANSPARENT; + POLY_page_flag[page + 1] |= POLY_PAGE_FLAG_SELF_ILLUM; + } + } + else + if (*c == 'S' || *c == 's') + { + POLY_page_flag[page] |= POLY_PAGE_FLAG_SELF_ILLUM; + } + else + if (*c == 'F' || *c == 'f') + { + POLY_page_flag[page] |= POLY_PAGE_FLAG_NO_FOG; + } + else + if (*c == 'D' || *c == 'd') + { + if (WITHIN(page, 0, POLY_NUM_PAGES - 2)) + { + POLY_page_flag[page + 0] |= POLY_PAGE_FLAG_2PASS | POLY_PAGE_FLAG_WINDOW; + POLY_page_flag[page + 1] |= POLY_PAGE_FLAG_WINDOW_2ND; + } + } + else + if (*c == 'M' || *c == 'm') + { + POLY_page_flag[page] |= POLY_PAGE_FLAG_ALPHA; + } + else + if (*c == ':') + { + break; + } + } + } + } + + MF_Fclose(handle); + } +} + +// POLY_init_render_states +// +// initialize all the render states for each page + +#ifdef TARGET_DC +int iPolyRenderStateFrameNum = 0; +#endif + +#define HOW_MANY_FRAMES_TO_WAIT 0 + +void POLY_init_render_states() +{ + SLONG sw_page; + +#if 0 +//#ifdef TARGET_DC + iPolyRenderStateFrameNum++; + + if ( !RenderStates_OK ) + { + iPolyRenderStateFrameNum = 0; + } + + //if (RenderStates_OK) return; + if ( iPolyRenderStateFrameNum > HOW_MANY_FRAMES_TO_WAIT ) return; +#else + if ( RenderStates_OK ) return; +#endif + + // create default + extern int AENG_detail_filter; + + if (!AENG_detail_filter) + { + DefRenderState = RenderState(D3DFILTER_NEAREST, D3DFILTER_NEAREST); + } + else + { + DefRenderState = RenderState(D3DFILTER_LINEAR, D3DFILTER_LINEAR); + } + + //TRACE("Phase %i\n", iPhase); + + // set each page to the default + for (int ii = 0; ii < POLY_NUM_PAGES; ii++) + { + POLY_Page[ii].RS = DefRenderState; + } + + // set defaults for each page + PolyPage* pa; + + + for (ii = 0; ii < POLY_NUM_PAGES; ii++) + { + pa = &POLY_Page[ii]; + +#if 0 +//#ifdef TARGET_DC + if ( iPolyRenderStateFrameNum < HOW_MANY_FRAMES_TO_WAIT ) + { + // Don't do anything - leave them all as default. + // This is a horrible kludge, and I don't know why I need to + // wait but I do. Grrrr... + } + else +#endif //#ifdef TARGET_DC + { + + sw_page = SW_PAGE_IGNORE; + + + // Default is on! + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + + + + // set using the old interface + switch (ii) + { + case POLY_PAGE_LADSHAD: + SET_TEXTURE((TEXTURE_page_ladshad)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + break; + + case POLY_PAGE_SIGN: + SET_TEXTURE((TEXTURE_page_sign)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + break; + + case POLY_PAGE_LASTPANEL_ALPHA: + SET_TEXTURE((TEXTURE_page_lastpanel)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SPECULARENABLE,TRUE); + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_LASTPANEL_ADDALPHA: + SET_TEXTURE((TEXTURE_page_lastpanel)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SPECULARENABLE,TRUE); + SET_EFFECT(RS_AlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_LASTPANEL_ADD: + SET_TEXTURE((TEXTURE_page_lastpanel)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_LASTPANEL_SUB: + SET_TEXTURE((TEXTURE_page_lastpanel)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_EFFECT(RS_BlackWithAlpha); + break; + + case POLY_PAGE_LASTPANEL2_ADD: + SET_TEXTURE((TEXTURE_page_lastpanel2)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_LASTPANEL2_ADDALPHA: + SET_TEXTURE((TEXTURE_page_lastpanel2)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_EFFECT(RS_AlphaPremult); + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_LASTPANEL2_SUB: + SET_TEXTURE((TEXTURE_page_lastpanel2)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_EFFECT(RS_BlackWithAlpha); + break; + + case POLY_PAGE_LASTPANEL2_ALPHA: + SET_TEXTURE((TEXTURE_page_lastpanel2)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_LITE_BOLT: + SET_TEXTURE((TEXTURE_page_litebolt)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + // SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + // SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_SHADOW_OVAL: + SET_TEXTURE((TEXTURE_page_shadowoval)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + // sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_SHADOW_SQUARE: + SET_TEXTURE((TEXTURE_page_shadowsquare)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_FADECAT: + SET_TEXTURE((TEXTURE_page_fadecat)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_FADE_MF: + SET_TEXTURE((TEXTURE_page_fade_MF)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_LADDER: + SET_TEXTURE((TEXTURE_page_ladder)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + + sw_page = SW_PAGE_NORMAL; + + break; + + case POLY_PAGE_FINALGLOW: + SET_TEXTURE((TEXTURE_page_finalglow)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + break; + + case POLY_PAGE_IC2_NORMAL: + SET_TEXTURE((TEXTURE_page_ic2)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + break; + + case POLY_PAGE_IC_NORMAL: + SET_TEXTURE((TEXTURE_page_ic)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + break; + + case POLY_PAGE_IC2_ALPHA: + case POLY_PAGE_IC2_ALPHA_END: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_TEXTURE((TEXTURE_page_ic2)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + break; + + case POLY_PAGE_IC_ALPHA: + case POLY_PAGE_IC_ALPHA_END: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_TEXTURE((TEXTURE_page_ic)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + break; + + case POLY_PAGE_IC2_ADDITIVE: + SET_TEXTURE((TEXTURE_page_ic2)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + break; + + case POLY_PAGE_IC_ADDITIVE: + SET_TEXTURE((TEXTURE_page_ic)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + break; + + case POLY_PAGE_PRESS1: + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + #ifndef TARGET_DC + TEXTURE_set_colour_key(TEXTURE_page_press1); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + #endif + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_press1)); + break; + + case POLY_PAGE_PRESS2: + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + #ifndef TARGET_DC + TEXTURE_set_colour_key(TEXTURE_page_press2); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + #endif + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_press2)); + break; + + case POLY_PAGE_TARGET: + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + #ifndef TARGET_DC + TEXTURE_set_colour_key(TEXTURE_page_target); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + #endif + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_target)); + break; + + case POLY_PAGE_DEVIL: + SET_TEXTURE((TEXTURE_page_devil)); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_DECAL); + break; + + case POLY_PAGE_ANGEL: + SET_TEXTURE((TEXTURE_page_angel)); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_DECAL); + break; + + case POLY_PAGE_LEAF: + SET_TEXTURE((TEXTURE_page_leaf)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAREF,0); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,TRUE); + + sw_page = SW_PAGE_MASKED; + + break; + + case POLY_PAGE_RUBBISH: + SET_TEXTURE((TEXTURE_page_rubbish)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAREF,0); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,TRUE); + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_WINMAP: + + // + // Draw the environment map additive alpha. + // + + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_winmap)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + + break; + + case POLY_PAGE_ENVMAP: + + // + // Draw the environment map additive alpha. + // + + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_envmap)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + break; + + case POLY_PAGE_SEWATER: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_TEXTURE((TEXTURE_page_water)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE, FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + break; + + case POLY_PAGE_SKY: + SET_TEXTURE((TEXTURE_page_sky)); + #if USE_TOMS_ENGINE_PLEASE_BOB + // This now needs to be Z-buffered, because it is no longer the first thing drawn any more. + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE, TRUE); + #else + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE, FALSE); + #endif + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE, FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_SHADOW: + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + + #ifdef TARGET_DC + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCCOLOR); + #else + if (the_display.GetDeviceInfo()->DestInvSourceColourSupported()) + { + // use a density greyscale shadowmap + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCCOLOR); + } + else + { + // use a density alpha (+black) shadowmap + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + } + #endif + + SET_TEXTURE((TEXTURE_page_shadow)); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZBIAS, 8); + break; + + case POLY_PAGE_TEST_SHADOWMAP: + if (the_display.GetDeviceInfo()->DestInvSourceColourSupported()) + { + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE); + SET_TEXTURE(TEXTURE_page_shadow); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + } + break; + + case POLY_PAGE_PUDDLE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_puddle)); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAREF,0); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_MOON: + // SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_moon)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + // TEXTURE_set_colour_key(TEXTURE_page_moon); + // SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + break; + + case POLY_PAGE_MANONMOON: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_TEXTURE((571)); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + break; + + case POLY_PAGE_CLOUDS: + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_clouds)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_ALPHA: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_NO_TEXTURE; + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_ALPHA_OVERLAY: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_NO_TEXTURE; + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + break; + + case POLY_PAGE_ADDITIVE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_NO_TEXTURE; + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_ADDITIVEALPHA: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_NO_TEXTURE; + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_MASKED: + SET_TEXTURE(-1); + #ifndef TARGET_DC + TEXTURE_set_colour_key(0); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + #endif + break; + + case POLY_PAGE_FACE1: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_NEAREST); + SET_TEXTURE((TEXTURE_page_face1)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + sw_page = SW_PAGE_ALPHA; // So it'll be sorted to the front... + + break; + + case POLY_PAGE_FACE2: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_NEAREST); + SET_TEXTURE((TEXTURE_page_face2)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + sw_page = SW_PAGE_ALPHA; // So it'll be sorted to the front... + + break; + + case POLY_PAGE_FACE3: + SET_TEXTURE((TEXTURE_page_face3)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_FACE4: + SET_TEXTURE((TEXTURE_page_face4)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_FACE5: + SET_TEXTURE((TEXTURE_page_face5)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_FACE6: + SET_TEXTURE((TEXTURE_page_face6)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_COLOUR_ALPHA: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_NO_TEXTURE; + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_COLOUR: + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_NO_TEXTURE; + + sw_page = SW_PAGE_MASKED; + + break; + + case POLY_PAGE_COLOUR_WITH_FOG: + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + SET_NO_TEXTURE; + break; + + case POLY_PAGE_WATER: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_water)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_DRIP: + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_drip)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_FOG: + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_fog)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_STEAM: + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_steam)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_BANG: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_bang)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_TEXT: + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_font)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_LOGO: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_logo)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_DROPLET: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_droplet)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + break; + + case POLY_PAGE_RAINDROP: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_TEXTURE((TEXTURE_page_raindrop)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + break; + + case POLY_PAGE_SPARKLE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_sparkle)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + break; + + case POLY_PAGE_FLAMES: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_flames)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_FLAMES2: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_flame2)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_SMOKE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCCOLOR); + SET_TEXTURE((TEXTURE_page_smoke)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_MENUFLAME: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_menuflame)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + break; + + case POLY_PAGE_MENUTEXT: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZBIAS,0); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_flames)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + break; + + case POLY_PAGE_MENUPASS: + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_moon)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + #ifndef TARGET_DC + TEXTURE_set_colour_key(TEXTURE_page_moon); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + #endif + break; + + case POLY_PAGE_BARBWIRE: + //SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_barbwire)); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_FOOTPRINT: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_footprint)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + break; + + case POLY_PAGE_FONT2D: + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_font2d)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + //SET_RENDER_STATE(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL); + //SET_RENDER_STATE(D3DRENDERSTATE_ALPHAREF,0); + //SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_LINEAR); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_LINEAR); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_BIGBANG: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_bigbang)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + SET_EFFECT(RS_InvAlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_FLAMES3: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_flames3)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + SET_EFFECT(RS_InvAlphaPremult); + break; + + case POLY_PAGE_DUSTWAVE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_dustwave)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + //SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + SET_EFFECT(RS_InvAlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_BLOODSPLAT: + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_bloodsplat)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_BLOOM1: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_bloom1)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_BLOOM2: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_bloom2)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_SNOWFLAKE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_snowflake)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + sw_page = SW_PAGE_ADDITIVE; + + break; + case POLY_PAGE_HITSPANG: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_hitspang)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_LENSFLARE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_lensflare)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_TYRETRACK: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_tyretrack_alpha)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + break; + + case POLY_PAGE_TYRESKID: + /* SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCCOLOR); + SET_TEXTURE((TEXTURE_page_tyretrack)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); */ + + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + // SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_tyretrack)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZBIAS, 4); + SET_EFFECT(RS_BlackWithAlpha); + break; + + case POLY_PAGE_NEWFONT_INVERSE: + + + + /* SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + // SET_TEXTURE((TEXTURE_page_newfont)); + SET_TEXTURE((TEXTURE_page_lcdfont)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE);*/ + + + /* + + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + // SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREHANDLE,TEXTURE_get_handle(TEXTURE_page_lcdfont)); + SET_TEXTURE((TEXTURE_page_lcdfont)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + + */ + + // + // I want to try a special effect that needs additive alpha! + // + +#ifdef TARGET_DC + // We use the new font on the DC that is just alpha-blended on. + SET_TEXTURE((TEXTURE_page_lcdfont)); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); +#else + SET_TEXTURE((TEXTURE_page_lcdfont)); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); +#endif + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_MENULOGO: + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + // SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREHANDLE,TEXTURE_get_handle(TEXTURE_page_menulogo)); + SET_TEXTURE((TEXTURE_page_menulogo)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_POLAROID: + SET_TEXTURE((TEXTURE_page_polaroid)); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_DECAL); + + break; + + case POLY_PAGE_SMOKER: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_smoker)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_NEWFONT: + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_lcdfont)); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_BlackWithAlpha); + break; + + case POLY_PAGE_EXPLODE1: + + /* + + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_explode1)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + */ + + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_explode1)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_EXPLODE2: + + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_explode2)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + break; + + case POLY_PAGE_EXPLODE1_ADDITIVE: + + // SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_NEAREST); + // SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_explode1)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_EXPLODE2_ADDITIVE: + + // SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_NEAREST); + // SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_NEAREST); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_explode2)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + case POLY_PAGE_SPLASH: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_splash)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + SET_EFFECT(RS_InvAlphaPremult); + break; + + case POLY_PAGE_METEOR: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_meteor)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_SUBTRACTIVEALPHA: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_NO_TEXTURE; + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_BlackWithAlpha); + break; + + case POLY_PAGE_SMOKECLOUD: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_smokecloud)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_BlackWithAlpha); + break; + + case POLY_PAGE_SMOKECLOUD2: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_smokecloud)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + + sw_page = SW_PAGE_ALPHA; + + break; + + case POLY_PAGE_BIG_BUTTONS: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_DECAL); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_bigbutton)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_TINY_BUTTONS: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_tinybutt)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + + case POLY_PAGE_BIG_LEAF: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((TEXTURE_page_bigleaf)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + break; + case POLY_PAGE_BIG_RAIN: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_bigrain)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_EFFECT(RS_AlphaPremult); + break; + + case POLY_PAGE_PCFLAMER: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVSRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + SET_TEXTURE((TEXTURE_page_pcflamer)); + //SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + SET_EFFECT(RS_InvAlphaPremult); + + sw_page = SW_PAGE_ADDITIVE; + + break; + + #ifdef TARGET_DC + case POLY_PAGE_BACKGROUND_IMAGE: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_background_use_instead)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + //SET_EFFECT(RS_InvAlphaPremult); + break; + + case POLY_PAGE_BACKGROUND_IMAGE2: + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE); + SET_TEXTURE((TEXTURE_page_background_use_instead2)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + //SET_EFFECT(RS_InvAlphaPremult); + break; + + case POLY_PAGE_JOYPAD_A: + case POLY_PAGE_JOYPAD_B: + case POLY_PAGE_JOYPAD_C: + case POLY_PAGE_JOYPAD_X: + case POLY_PAGE_JOYPAD_Y: + case POLY_PAGE_JOYPAD_Z: + case POLY_PAGE_JOYPAD_L: + case POLY_PAGE_JOYPAD_R: + case POLY_PAGE_JOYPAD_PAD_L: + case POLY_PAGE_JOYPAD_PAD_R: + case POLY_PAGE_JOYPAD_PAD_D: + case POLY_PAGE_JOYPAD_PAD_U: + { + int iPage = ( ii - POLY_PAGE_JOYPAD_A ) + TEXTURE_page_joypad_a; + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + SET_TEXTURE((iPage)); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE); + } + break; + #endif + + default: + + if (ii < TEXTURE_page_num_standard && !(draw_3d && (ii == 510 || ii == 511))) + { + sw_page = SW_PAGE_NORMAL; + + SET_TEXTURE((ii)); + + if (POLY_page_flag[ii]) + { + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_TRANSPARENT) + { + #ifndef TARGET_DC + bool use_chroma = false; + + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_SELF_ILLUM) + { + if (the_display.GetDeviceInfo()->DestInvSourceColourSupported() && + !the_display.GetDeviceInfo()->ModulateAlphaSupported()) + { + // it's a RagePro, so use chroma keying + use_chroma = true; + } + } + + if (use_chroma) + { + // use colour keying to make the windows work on the Rage Pro + TEXTURE_set_colour_key(ii); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + } + else + #endif + { + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAREF,0); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,TRUE); + } + + sw_page = SW_PAGE_MASKED; + } + + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_WRAP) + { + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + } + + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_ADD_ALPHA) + { + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + } + + if ((POLY_page_flag[ii] & POLY_PAGE_FLAG_SELF_ILLUM) && !draw_3d) + { + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_DECAL); + } + + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_NO_FOG) + { + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE, FALSE); + } + + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_WINDOW) + { + /* + + TEXTURE_set_colour_key(ii); + SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE,TRUE); + + */ + + + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAFUNC,D3DCMP_NOTEQUAL); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHAREF,0); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,TRUE); + + + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + } + + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_WINDOW_2ND) + { + SET_RENDER_STATE(D3DRENDERSTATE_ZFUNC,D3DCMP_LESS); + } + + if (POLY_page_flag[ii] & POLY_PAGE_FLAG_ALPHA) + { + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA); + + sw_page = SW_PAGE_MASKED; + } + } + + if (the_display.GetDeviceInfo()->AdamiLightingSupported()) + { + switch(ii >> 6) + { + case 9: + case 10: + case 18: + case 19: + case 20: + case 21: + + // + // This is a people texture page! + // + + SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_DESTCOLOR); + SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_SRCCOLOR); + + // SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND,D3DBLEND_DESTCOLOR); + // SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND,D3DBLEND_SRCCOLOR); + + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_DECAL); + + break; + } + } + } + /* + else + if (ii > TEXTURE_page_people3 && !draw_3d && iiRS) ) ) + { + // Yes, they are the same, so this is a ghost page. + POLY_Page[ii].pTheRealPolyPage = pPolyPage; + } + else + { + // Nope - this is a separate one. + POLY_Page[ii].pTheRealPolyPage = &(POLY_Page[ii]); + //TRACE(" %d", ii); + PageOrder[pos++] = ii; + } + PageOrdered[ii] = true; + } + } + } +#ifdef DEBUG + else + { + iNullTextureCount++; + } +#endif + + //TRACE("\n"); + } + +#ifdef DEBUG + TRACE ( "Number of NULL pages %i\n", iNullTextureCount ); +#endif + +extern int iPolyNumPagesRender; + iPolyNumPagesRender = pos; + + +#endif + +#ifndef TARGET_DC +#ifdef _DEBUG + for (ii = 0; ii < POLY_NUM_PAGES; ii++) + { + if (char* err = POLY_Page[ii].RS.Validate()) + { + TRACE("Page %d : %s\n", ii, err); + } + } +#endif +#endif + + + + RenderStates_OK = TRUE; + +} + + + + + diff --git a/fallen/DDEngine/Source/qeng.cpp b/fallen/DDEngine/Source/qeng.cpp new file mode 100644 index 0000000..19df9b4 --- /dev/null +++ b/fallen/DDEngine/Source/qeng.cpp @@ -0,0 +1,240 @@ +#include +#include +#include "poly.h" +#include "qeng.h" +#include "vertexbuffer.h" + +// +// Once at the start of the whole program. +// + +void QENG_init() +{ + POLY_init(); +} + +SLONG QENG_cam_x; +SLONG QENG_cam_y; +SLONG QENG_cam_z; + + +// +// Where everything is drawn from. +// + +void QENG_set_camera( + float x, + float y, + float z, + float yaw, + float pitch, + float roll) +{ + QENG_cam_x = SLONG(x); + QENG_cam_y = SLONG(y); + QENG_cam_z = SLONG(z); + + POLY_camera_set(x, y, z, yaw, pitch, roll, 128.0F * 256.0F, 8.0F); + POLY_frame_init(FALSE, FALSE); +} + +// +// Draws a line in the world. Sets QENG_mouse_over and QENG_mouse_pos if the +// mouse is over the line. +// + +SLONG QENG_mouse_over; +float QENG_mouse_pos_x; // Position in the world +float QENG_mouse_pos_y; +float QENG_mouse_pos_z; + +void QENG_world_line( + SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1, + SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2, + bool sort_to_front) +{ + POLY_Point pp1; + POLY_Point pp2; + + QENG_mouse_over = FALSE; + + POLY_transform( + float(x1), + float(y1), + float(z1), + &pp1); + + if (pp1.IsValid()) + { + POLY_transform( + float(x2), + float(y2), + float(z2), + &pp2); + + if (pp2.IsValid()) + { + if (POLY_valid_line(&pp1, &pp2)) + { + pp1.colour = colour1; + pp2.colour = colour2; + + pp1.specular = 0x00000000; + pp2.specular = 0x00000000; + + pp1.u = 0.0F; + pp1.v = 0.0F; + pp2.u = 0.0F; + pp2.v = 0.0F; + + POLY_add_line(&pp1, &pp2, float(width1), float(width2), POLY_PAGE_COLOUR, sort_to_front); + + // + // Is the mouse over the line? + // + } + } + } +} + +void QENG_draw(QMAP_Draw *qd) +{ + SLONG i; + + UWORD point; + UWORD face; + + SLONG mx; + SLONG mz; + + QMAP_Point *qp; + QMAP_Face *qf; + + POLY_Point *pp; + POLY_Point *quad[4]; + + ASSERT(QMAP_MAX_POINTS <= POLY_BUFFER_SIZE); + + // + // The origin of the points. + // + + mx = qd->map_x << 13; + mz = qd->map_z << 13; + + // + // The counter for which points have already been transformed. + // + + qd->trans += 1; + + if (qd->trans == 0) + { + qd->trans = 1; + + // + // Clear the trans field in all this squares points. + // + + for (point = qd->next_point; point; point = qp->next) + { + ASSERT(WITHIN(point, 1, QMAP_MAX_POINTS - 1)); + + qp = &QMAP_point[point]; + + qp->trans = 0; + } + } + + // + // Create all the faces. + // + + for (face = qd->next_face; face; face = qf->next) + { + ASSERT(WITHIN(face, 1, QMAP_MAX_FACES - 1)); + + qf = &QMAP_face[face]; + + // + // Reject the face because of its normal? + // + + // + // Make sure all the points are transformed. + // + + for (i = 0; i < 4; i++) + { + ASSERT(WITHIN(qf->point[i], 1, QMAP_MAX_POINTS - 1)); + + qp = &QMAP_point [qf->point[i]]; + pp = &POLY_buffer[qf->point[i]]; + + if (qp->trans == qd->trans) + { + // + // This point is already transformed. + // + } + else + { + // + // Transform the point. + // + + POLY_transform( + float(mx + qp->x), + float( qp->y), + float(mz + qp->z), + pp); + + qp->trans = qd->trans; + } + + if (!pp->MaybeValid()) + { + goto abandon_this_face; + } + + pp->colour = qf->texture * 111; + pp->specular = 0x00000000; + pp->u = 0.0F; + pp->v = 0.0F; + + quad[i] = pp; + } + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE); + } + + abandon_this_face:; + } +} + +void QENG_render() +{ + POLY_frame_draw(TRUE, TRUE); +} + +void QENG_flip() +{ + FLIP(NULL,DDFLIP_WAIT); +} + +void QENG_clear_screen() +{ + SET_BLACK_BACKGROUND; + CLEAR_VIEWPORT; + TheVPool->ReclaimBuffers(); +} + +void QENG_fini() +{ +} + + + + diff --git a/fallen/DDEngine/Source/ray.cpp b/fallen/DDEngine/Source/ray.cpp new file mode 100644 index 0000000..22c334c --- /dev/null +++ b/fallen/DDEngine/Source/ray.cpp @@ -0,0 +1,1426 @@ +#include +#include +#include "game.h" +#include "ray.h" +#include "poly.h" +#include "inline.h" +#include + +#if 0 // Intel C compiler barfs + +D3DTexture RAY_screen1; +D3DTexture RAY_screen2; + + +// +// The current locked RAY_screen. +// + +#define RAY_SCREEN_SIZE 256 + +SLONG RAY_which_screen; + +UWORD *RAY_screen_bitmap; +SLONG RAY_screen_pitch; // In bytes! + +SLONG RAY_screen_mask_red; +SLONG RAY_screen_mask_green; +SLONG RAY_screen_mask_blue; +SLONG RAY_screen_mask_alpha; + +SLONG RAY_screen_shift_red; +SLONG RAY_screen_shift_green; +SLONG RAY_screen_shift_blue; +SLONG RAY_screen_shift_alpha; + + +#define RAY_LIGHT_X (+0x77B0) +#define RAY_LIGHT_Y (+0x77B0) +#define RAY_LIGHT_Z (-0xC000) + + + +#define LOOKUP_MAX 65536 +#define LOOKUP_SHIFT 8 + +SLONG RAY_sqrt[LOOKUP_MAX]; + + + + + +typedef struct +{ + SLONG dx; + SLONG dy; + SLONG dz; + SLONG sky_r; + SLONG sky_b; + SLONG ground_ix; + SLONG ground_iz; + SLONG ground_distr; + +} RAY_Vector; + +RAY_Vector RAY_pixel[RAY_SCREEN_SIZE][RAY_SCREEN_SIZE]; + + +void RAY_pixel_calc(void) +{ + SLONG x; + SLONG y; + + SLONG dx; + SLONG dy; + SLONG dz; + + SLONG sky_r; + SLONG sky_b; + + SLONG ground_ix; + SLONG ground_iz; + SLONG ground_distr; + + SLONG length; + float flen; + SLONG overlength; + + for (y = 0; y < RAY_SCREEN_SIZE; y++) + for (x = 0; x < RAY_SCREEN_SIZE; x++) + { + dx = (x - (RAY_SCREEN_SIZE / 2)) * ((0x15555 * 20 / 20) / (RAY_SCREEN_SIZE / 2)); + dy = (y - (RAY_SCREEN_SIZE / 2)) * -((0x10000 * 5 / 4) / (RAY_SCREEN_SIZE / 2)); + dz = 0x10000; + + length = MUL64(dx,dx) + MUL64(dy,dy) + MUL64(dz,dz); + + flen = float(length); + flen *= 1.0F / 65536.0F; + flen = 1.0F / sqrt(flen); + flen *= 65536.0F; + + overlength = SLONG(flen); + + dx = MUL64(dx, overlength); + dy = MUL64(dy, overlength); + dz = MUL64(dz, overlength); + + if (dy > -0x1400) + { + sky_r = MAX(0, ((dy + 0x1400 + 0x200) >> 8) - 1); + sky_b = MAX(0, ((dy + 0x1400 + 0x588) >> 10) - 1); + } + else + { + // + // Intersect the ground plane at (dx/dy) (dz/dy) + // + + ground_ix = DIV64(dx,-dy) << 1; + ground_iz = DIV64(dz,-dy) << 1; + ground_distr = 255 - ((MUL64(dx,dx) + MUL64(dz,dz) >> 7) & 0xff); + + if (ground_distr < 0) + { + ground_distr = 0; + } + } + + RAY_pixel[y][x].dx = dx; + RAY_pixel[y][x].dy = dy; + RAY_pixel[y][x].dz = dz; + + RAY_pixel[y][x].sky_r = sky_r; + RAY_pixel[y][x].sky_b = sky_b; + + + RAY_pixel[y][x].ground_ix = ground_ix; + RAY_pixel[y][x].ground_iz = ground_iz; + RAY_pixel[y][x].ground_distr = ground_distr; + } +} + + +// +// Returns the 16:16 square root. +// + +SLONG SQRT64_slow(SLONG x) +{ + float f = float(x); + + f *= (1.0F / 65536.0F); + f = sqrt(f); + f *= 65536.0F; + + SLONG ans; + + ans = SLONG(f); + + return ans; +} + +SLONG SQRT64(SLONG x) +{ + SLONG i = x >> LOOKUP_SHIFT; + + ASSERT(WITHIN(i, 0, LOOKUP_MAX - 1)); + + return RAY_sqrt[i]; +} + + +// +// D3D Poly stuff... +// + +#define RAY_D3D_SIZE 32 + +D3DTLVERTEX RAY_d3d_vertex[RAY_D3D_SIZE]; +SLONG RAY_d3d_vertex_upto; +UWORD RAY_d3d_index [RAY_D3D_SIZE]; +SLONG RAY_d3d_index_upto; + + +// +// The spheres... +// + +#define RAY_SPHERE_SPECULAR (1 << 0) +#define RAY_SPHERE_REFLECTIVE (1 << 1) + +typedef struct +{ + SLONG x; + SLONG y; + SLONG z; + SLONG radius; // Always 1? + SLONG dist2; // Distance from origin squared. + SLONG minx; + SLONG maxx; + SLONG miny; + SLONG maxy; + SLONG minz; + SLONG maxz; + SLONG dx; + SLONG dy; + SLONG dz; + UBYTE r; + UBYTE g; + UBYTE b; + UBYTE flag; + + SLONG sx; + SLONG sy; + + SLONG sxmin; + SLONG sxmax; + + SLONG symin; + SLONG symax; + +} RAY_Sphere; + +#define RAY_MAX_SPHERES 4 + +RAY_Sphere RAY_sphere[RAY_MAX_SPHERES]; +SLONG RAY_sphere_upto = 0; + + + +// +// Initialises everything. +// + +void RAY_init() +{ + // + // Sets up the screen. + // + + RAY_screen1.CreateUserPage(RAY_SCREEN_SIZE, FALSE); + RAY_screen2.CreateUserPage(RAY_SCREEN_SIZE, FALSE); + + // + // Precalc. + // + + RAY_pixel_calc(); + + + // + // Sqrt precalc. + // + + SLONG i; + + for (i = 0; i < LOOKUP_MAX; i++) + { + RAY_sqrt[i] = SQRT64_slow(i << LOOKUP_SHIFT); + } + + + // + // Setup world. + // + + RAY_sphere[0].x =-0x18000; + RAY_sphere[0].y = 0x25000; + RAY_sphere[0].z = 0x38000; + RAY_sphere[0].radius = 0x10000; // HARDCODED! + RAY_sphere[0].r = 30; + RAY_sphere[0].g = 150; + RAY_sphere[0].b = 21; + RAY_sphere[0].flag = RAY_SPHERE_SPECULAR; +// RAY_sphere[0].flag = RAY_SPHERE_REFLECTIVE|RAY_SPHERE_SPECULAR; + + RAY_sphere[1].x = 0x10000; + RAY_sphere[1].y = 0x18000; + RAY_sphere[1].z = 0x39000; + RAY_sphere[1].radius = 0x10000; // HARDCODED! + RAY_sphere[1].r = 0; + RAY_sphere[1].g = 225; + RAY_sphere[1].b = 200; + RAY_sphere[1].flag = 0; +// RAY_sphere[1].flag = RAY_SPHERE_REFLECTIVE|RAY_SPHERE_SPECULAR; + + + RAY_sphere[2].x =-0x10000; + RAY_sphere[2].y = 0x50000; + RAY_sphere[2].z = 0x58000; + RAY_sphere[2].radius = 0x10000; // HARDCODED! + RAY_sphere[2].dx = 0x2000; + RAY_sphere[2].r = 225; + RAY_sphere[2].g = 225; + RAY_sphere[2].b = 225; + RAY_sphere[2].flag = RAY_SPHERE_REFLECTIVE|RAY_SPHERE_SPECULAR; + + RAY_sphere_upto = 3; +} + + +void RAY_screen_lock(void) +{ + HRESULT res; + + D3DTexture *rs; + + RAY_which_screen ^= 1; + + rs = (RAY_which_screen) ? &RAY_screen1 : &RAY_screen2; + + res = rs->LockUser( + &RAY_screen_bitmap, + &RAY_screen_pitch); + + ASSERT(SUCCEEDED(res)); + + RAY_screen_mask_red = rs->mask_red; + RAY_screen_mask_green = rs->mask_green; + RAY_screen_mask_blue = rs->mask_blue; + RAY_screen_mask_alpha = rs->mask_alpha; + RAY_screen_shift_red = rs->shift_red; + RAY_screen_shift_green = rs->shift_green; + RAY_screen_shift_blue = rs->shift_blue; + RAY_screen_shift_alpha = rs->shift_alpha; +} + +void RAY_screen_unlock(void) +{ + D3DTexture *rs; + + rs = (RAY_which_screen) ? &RAY_screen1 : &RAY_screen2; + + rs->UnlockUser(); +} + +void RAY_screen_update(void) +{ +} + + + + +struct +{ + SLONG x1; + SLONG x2; + SLONG y1; + SLONG y2; + +} offset[3] = +{ + {-22,+55,-37,+45}, + {-40,+31,-36,+38}, + {-46,+46,-30,+45} +}; + + + +void RAY_animate(void) +{ + SLONG i; + + static animate = 1; + + if (Keys[KB_A]) + { + Keys[KB_A] = 0; + + animate ^= 1; + } + + RAY_Sphere *rs; + + { + rs = &RAY_sphere[0]; + + if (Keys[KB_LEFT ]) {rs->x -= 0x1000;} + if (Keys[KB_RIGHT]) {rs->x += 0x1000;} + + if (Keys[KB_UP ]) {rs->z += 0x1000;} + if (Keys[KB_DOWN]) {rs->z -= 0x1000;} + } + + for (i = 0; i < RAY_sphere_upto; i++) + { + rs = &RAY_sphere[i]; + + if (animate) + { + rs->dy -= 0x300; + + rs->x += rs->dx; + rs->y += rs->dy; + rs->z += rs->dz; + + if (rs->y < -0x10000) + { + rs->dy = abs(rs->dy);// - (abs(rs->dy) >> 14); + rs->y = -0x10000; + } + } + + if (rs->x > 0x48000) {rs->dx = -abs(rs->dx);} + if (rs->x < -0x48000) {rs->dx = +abs(rs->dx);} + + rs->minx = rs->x - rs->radius; + rs->maxx = rs->x + rs->radius; + rs->miny = rs->y - rs->radius; + rs->maxy = rs->y + rs->radius; + rs->minz = rs->z - rs->radius; + rs->maxz = rs->z + rs->radius; + + rs->dist2 = MUL64(rs->x,rs->x) + MUL64(rs->y,rs->y) + MUL64(rs->z, rs->z); + + rs->sx = 128 + (DIV64(rs->x, rs->z) * 128 >> 16); + rs->sy = 128 - (DIV64(rs->y, rs->z) * 128 >> 16); + } + + SLONG a = 0; + + if (ShiftFlag) a = 1; + if (ControlFlag) a= 2; + + if (Keys[KB_P7]) {offset[a].y1 -= 1;} + if (Keys[KB_P8]) {offset[a].y1 += 1;} + + if (Keys[KB_P9]) {offset[a].x2 -= 1;} + if (Keys[KB_P6]) {offset[a].x2 += 1;} + + if (Keys[KB_P4]) {offset[a].x1 -= 1;} + if (Keys[KB_P1]) {offset[a].x1 += 1;} + + if (Keys[KB_P2]) {offset[a].y2 -= 1;} + if (Keys[KB_P3]) {offset[a].y2 += 1;} + + for (i = 0; i < 3; i++) + { + RAY_sphere[i].sxmin = RAY_sphere[i].sx + offset[i].x1; + RAY_sphere[i].sxmax = RAY_sphere[i].sx + offset[i].x2; + + RAY_sphere[i].symin = RAY_sphere[i].sy + offset[i].y1; + RAY_sphere[i].symax = RAY_sphere[i].sy + offset[i].y2; + + if (Keys[KB_D]) + { + TRACE("Vals(%d) = %d,%d,%d,%d\n", i, + offset[i].x1, + offset[i].x2, + offset[i].y1, + offset[i].y2); + } + } + + if (Keys[KB_B]) + { + Keys[KB_B] = 0; + + for (i = 0; i < RAY_sphere_upto; i++) + { + rs = &RAY_sphere[i]; + + rs->dy += rs->dy >> 4; + } + } +} + + +// +// Secondary intersection... +// + +void RAY_intersect2( + SLONG x1, SLONG y1, SLONG z1, + SLONG dx, SLONG dy, SLONG dz, + ULONG use, + UBYTE *r, + UBYTE *g, + UBYTE *b) +{ + SLONG i; + + SLONG v; + SLONG disc; + SLONG dist; + + SLONG dsx; + SLONG dsy; + SLONG dsz; + + SLONG ground_ix; + SLONG ground_iz; + SLONG ground_distr; + + RAY_Sphere *rs; + + for (i = RAY_sphere_upto - 1; i >= 0; i--) + { + rs = &RAY_sphere[i]; + + if (!(use & (1 << i))) + { + continue; + } + + // + // Simple reject? + // + + if (dx < 0) + { + if (rs->minx > x1) {continue;} + } + else + { + if (rs->maxx < x1) {continue;} + } + + if (dy < 0) + { + if (rs->miny > y1) {continue;} + } + else + { + if (rs->maxy < y1) {continue;} + } + + if (dz < 0) + { + if (rs->minz > z1) {continue;} + } + else + { + if (rs->maxz < z1) {continue;} + } + + dsx = rs->x - x1; + dsy = rs->y - y1; + dsz = rs->z - z1; + + v = MUL64(dsx, dx) + MUL64(dsy, dy) + MUL64(dsz, dz); + dist = MUL64(dsx, dsx) + MUL64(dsy, dsy) + MUL64(dsz, dsz); + + disc = 0x10000 - (dist - MUL64(v,v)); + + if (disc <= 0) + { + // + // No intersection. + // + } + else + { + *r = rs->r >> 1; + *g = rs->g >> 1; + *b = rs->b >> 1; + + return; + } + } + + if (dy > -0x1400) + { + SLONG sr = ((dy + 0x1400 + 0x200) >> 8) - 1; + SLONG sb = ((dy + 0x1400 + 0x588) >> 10) - 1; + + SATURATE(sr, 0, 255); + SATURATE(sb, 0, 255); + + *r = sr; + *g = 0; + *b = sb; + } + else + { + // + // Intersect the ground plane at (dx/dy) (dz/dy) + // + + SLONG overdy = DIV64(0x10000, -dy); + + ground_ix = MUL64(dx,overdy) << 1; + ground_iz = MUL64(dz,overdy) << 1; + ground_distr = 255 - ((MUL64(dx,dx) + MUL64(dz,dz) >> 8) & 0xff); + + if ((ground_ix ^ ground_iz) & 0x10000) + { + *r = ground_distr; + *g = ground_distr; + *b = 0; + } + else + { + *r = 0; + *g = 0; + *b = ground_distr; + } + } +} + + + + + +// +// Returns TRUE if the given point is in shadow. +// + +SLONG RAY_in_shadow( + SLONG x, + SLONG y, + SLONG z, + SLONG start_sphere) +{ + SLONG i; + + SLONG dsx; + SLONG dsy; + SLONG dsz; + + SLONG v; + SLONG disc; + SLONG dist2; + + RAY_Sphere *rs; + + for (i = start_sphere; i >= 0; i--) + { + rs = &RAY_sphere[i]; + + // + // Early outs? + // + + dsx = rs->x - x; + dsy = rs->y - y; + dsz = rs->z - z; + + v = MUL64(dsx, -RAY_LIGHT_X) + MUL64(dsy, -RAY_LIGHT_Y) + MUL64(dsz, -RAY_LIGHT_Z); + dist2 = MUL64(dsx, dsx) + MUL64(dsy,dsy) + MUL64(dsz,dsz); + + disc = 0x10000 - (dist2 - MUL64(v,v)); + + if (disc <= 0) + { + // + // No intersection. + // + } + else + { + // + // In shadow. + // + + return TRUE; + } + } + + return FALSE; +} + + +// +// Gives the colour of the given NORMALISED! ray. It has a bitfield for which +// sphere to ignore and a max_recursion level too. Returns FALSE if no +// intersection occured. +// + +SLONG RAY_get_colour_from_origin( + SLONG dx, SLONG dy, SLONG dz, + ULONG use, + UBYTE *ray_r, + UBYTE *ray_g, + UBYTE *ray_b) +{ + SLONG i; + + SLONG d; + SLONG v; + SLONG dist; + SLONG disc; + SLONG len; + + RAY_Sphere *rs; + + SLONG ix; + SLONG iy; + SLONG iz; + + SLONG r; + SLONG g; + SLONG b; + + SLONG nx; + SLONG ny; + SLONG nz; + + SLONG dsx; + SLONG dsy; + SLONG dsz; + + // + // Check the spheres. + // + + for (i = 0; i < RAY_sphere_upto; i++) + { + rs = &RAY_sphere[i]; + + if (!(use & (1 << i))) + { + continue; + } + + // + // Simple reject? + // + + if (dx < 0) + { + if (rs->minx > 0) {continue;} + } + else + { + if (rs->maxx < 0) {continue;} + } + + if (dy < 0) + { + if (rs->miny > 0) {continue;} + } + else + { + if (rs->maxy < 0) {continue;} + } + + if (dz < 0) + { + if (rs->minz > 0) {continue;} + } + else + { + if (rs->maxz < 0) {continue;} + } + + dsx = rs->x; + dsy = rs->y; + dsz = rs->z; + + v = MUL64(dsx, dx) + MUL64(dsy, dy) + MUL64(dsz, dz); + + disc = 0x10000 - (rs->dist2 - MUL64(v,v)); + + if (disc <= 0) + { + // + // No intersection. + // + } + else + { + // + // Intersection! But where? + // + + SLONG along; + SLONG bright; + + d = SQRT64(disc); + + along = v - d; + + ix = MUL64(along, dx); + iy = MUL64(along, dy); + iz = MUL64(along, dz); + + nx = ix - rs->x; + ny = iy - rs->y; + nz = iz - rs->z; + + #define RT 0x93cd + + bright = MUL64(nx,RAY_LIGHT_X) + MUL64(ny,RAY_LIGHT_Y) + MUL64(nz,RAY_LIGHT_Z); + + if (bright < 0 || RAY_in_shadow(ix, iy, iz, i - 1)) + { + *ray_r = rs->r >> 1; + *ray_g = rs->g >> 1; + *ray_b = rs->b >> 1; + } + else + { + bright = 0x8000 + (bright >> 1); + + if (rs->flag & RAY_SPHERE_SPECULAR) + { + r = MUL64(bright, rs->r); + g = MUL64(bright, rs->g); + b = MUL64(bright, rs->b); + + bright = MUL64(bright, bright); + bright = MUL64(bright, bright); + bright = MUL64(bright, bright); + bright = MUL64(bright, bright); + + r += bright >> 8; + g += bright >> 8; + b += bright >> 8; + + if (r > 255) {r = 255;} + if (g > 255) {g = 255;} + if (b > 255) {b = 255;} + + *ray_r = r; + *ray_g = g; + *ray_b = b; + } + else + { + *ray_r = MUL64(bright, rs->r); + *ray_g = MUL64(bright, rs->g); + *ray_b = MUL64(bright, rs->b); + } + } + + if (rs->flag & RAY_SPHERE_REFLECTIVE) + { + UBYTE rr; + UBYTE rg; + UBYTE rb; + + SLONG rx; + SLONG ry; + SLONG rz; + + SLONG dprod = MUL64(nx,dx) + MUL64(ny, dy) + MUL64(nz, dz); + + dprod <<= 1; + + rx = dx - MUL64(nx, dprod); + ry = dy - MUL64(ny, dprod); + rz = dz - MUL64(nz, dprod); + + RAY_intersect2( + ix, iy, iz, + rx, ry, rz, + 0x3, + &rr, + &rg, + &rb); + + *ray_r = (*ray_r * rr >> 8); + *ray_g = (*ray_g * rg >> 8); + *ray_b = (*ray_b * rb >> 8); + } + + return TRUE; + } + } + + return FALSE; +} + + +typedef struct span +{ + ULONG in; + ULONG out; + SLONG x; + + struct span *next; + +} Span; + +#define MAX_SPANS 8 + +Span span[MAX_SPANS]; +SLONG span_upto; + +Span *span_head; + + + +void RAY_render_scene(void) +{ + SLONG i; + + SLONG x; + SLONG y; + + SLONG span_minx; + SLONG span_maxx; + SLONG span_width; + + SLONG dx; + SLONG dy; + SLONG dz; + + SLONG index; + UWORD *pixel; + + Span *s1; + Span *s2; + + UBYTE r; + UBYTE g; + UBYTE b; + + ULONG in; + + RAY_Sphere *rs; + RAY_Vector *rv; + + Span **prev; + Span *next; + + #define BB_SIZE_X 50 + #define BB_SIZE_Y 60 + + for (y = 0; y < 205; y++) + { + // + // Create the spans... + // + + span_head = &span[0]; + + span[0].in = 0; + span[0].out = 0; + span[0].x = 0; + span[0].next = &span[1]; + + span[1].in = 0; + span[1].out = 0; + span[1].x = RAY_SCREEN_SIZE; + span[1].next = NULL; + + span_upto = 2; + + // + // Go through the bounding boxes of the spheres. + // + + for (i = 0; i < RAY_sphere_upto; i++) + { + rs = &RAY_sphere[i]; + + if (WITHIN(y, rs->symin, rs->symax)) + { + span_minx = rs->sxmin; + span_maxx = rs->sxmax; + + // + // Insert MIN span + // + + span[span_upto].in = 1 << i; + span[span_upto].out = 0; + span[span_upto].x = span_minx; + + prev = &span_head; + next = span_head; + + while(1) + { + if (next != NULL && span_minx > next->x) + { + // + // Don't insert it here. + // + + prev = &next->next; + next = next->next; + } + else + { + // + // Insert here. + // + + span[span_upto].next = next; + *prev = &span[span_upto]; + + break; + } + } + + span_upto += 1; + + // + // Insert MAX span. + // + + span[span_upto].in = 0; + span[span_upto].out = 1 << i; + span[span_upto].x = span_maxx; + + prev = &span_head; + next = span_head; + + while(1) + { + if (next != NULL && span_maxx > next->x) + { + // + // Don't insert it here. + // + + prev = &next->next; + next = next->next; + } + else + { + // + // Insert here. + // + + span[span_upto].next = next; + *prev = &span[span_upto]; + + break; + } + } + + span_upto += 1; + + + } + } + + // + // Go through all the spans on this line. + // + + s1 = span_head; + s2 = span_head->next; + + in = 0; + + while(s2) + { + in |= s1->in; + in &= ~s1->out; + + span_minx = s1->x; + span_maxx = s2->x; + + SATURATE(span_minx, 0, RAY_SCREEN_SIZE); + SATURATE(span_maxx, 0, RAY_SCREEN_SIZE); + + span_width = span_maxx - span_minx; + + index = span_minx + (y * RAY_screen_pitch >> 1); + pixel = &RAY_screen_bitmap[index]; + rv = &RAY_pixel[y][span_minx]; + + if (in == 0) + { + // + // Easy! + // + + if (y < 150) + { + while(span_width--) + { + *pixel = (rv->sky_r >> RAY_screen_mask_red) << RAY_screen_shift_red; + *pixel |= (rv->sky_b >> RAY_screen_mask_blue) << RAY_screen_shift_blue; + + rv++; + pixel++; + } + } + else + { + while(span_width--) + { + SLONG distr = rv->ground_distr; + + if (distr == 0) + { + *pixel = 0; + } + else + { + if (y <= 188 && span_minx < 180 && RAY_in_shadow(rv->ground_ix, -0x20000, rv->ground_iz, RAY_sphere_upto - 2)) + { + distr >>= 1; + } + + if ((rv->ground_ix ^ rv->ground_iz) & 0x10000) + { + r = distr; + g = distr; + b = 0; + } + else + { + r = 0; + g = 0; + b = distr; + } + + + *pixel = (r >> RAY_screen_mask_red) << RAY_screen_shift_red; + *pixel |= (g >> RAY_screen_mask_green) << RAY_screen_shift_green; + *pixel |= (b >> RAY_screen_mask_blue) << RAY_screen_shift_blue; + } + + span_minx++; + + rv++; + pixel++; + } + } + } + else + { + // + // We actually have to RayTrace :-( + // + + while(span_width--) + { + if (!RAY_get_colour_from_origin( + rv->dx, + rv->dy, + rv->dz, + in, + &r, + &g, + &b)) + { + //if (rv->dy > -0x1400) + + if (y < 150) + { + r = rv->sky_r; + g = 0; + b = rv->sky_b; + } + else + { + SLONG distr = rv->ground_distr; + + { + if (distr && RAY_in_shadow(rv->ground_ix, -0x20000, rv->ground_iz, RAY_sphere_upto - 2)) + { + distr >>= 1; + } + + if ((rv->ground_ix ^ rv->ground_iz) & 0x10000) + { + r = distr; + g = distr; + b = 0; + } + else + { + r = 0; + g = 0; + b = distr; + } + } + } + } + + /* + static lookat = 1; + + if(in & lookat) + { + r += 16; + g += 16; + b += 16; + } + */ + + *pixel = (r >> RAY_screen_mask_red) << RAY_screen_shift_red; + *pixel |= (g >> RAY_screen_mask_green) << RAY_screen_shift_green; + *pixel |= (b >> RAY_screen_mask_blue) << RAY_screen_shift_blue; + + rv++; + pixel++; + } + } + + s1 = s2; + s2 = s2->next; + } + } + + /* + + + + + + + + + rv = &RAY_pixel[0][0]; + + for (y = 0; y < RAY_SCREEN_SIZE; y++) + { + for (x = 0; x < RAY_SCREEN_SIZE; x++, rv++) + { + if (!RAY_get_colour_from_origin( + rv->dx, + rv->dy, + rv->dz, + 0xffffffff, + &r, + &g, + &b)) + { + if (rv->dy > -0x1400) + { + r = rv->sky_r; + g = 0; + b = rv->sky_b; + } + else + { + SLONG distr = rv->ground_distr; + + if (RAY_in_shadow(rv->ground_ix, -0x20000, rv->ground_iz, RAY_sphere_upto - 1)) + { + distr >>= 1; + } + + if ((rv->ground_ix ^ rv->ground_iz) & 0x10000) + { + r = distr; + g = distr; + b = 0; + } + else + { + r = 0; + g = 0; + b = distr; + } + } + } + + + if (x == RAY_sphere[0].sx - BB_SIZE_X || + x == RAY_sphere[0].sx + BB_SIZE_X || + y == RAY_sphere[0].sy - BB_SIZE_Y || + y == RAY_sphere[0].sy + BB_SIZE_Y) + { + r = 255; + g = 255; + b = 255; + } + + if (y == 150) + { + r = 255; + g = 255; + b = (x & 1) << 7; + } + + if (y == 140) + { + r = 255; + g = 255; + b = (x & 2) << 7; + } + + if (y == 160) + { + r = 255; + g = 255; + b = (x & 4) << 7; + } + + + + index = x + (y * RAY_screen_pitch >> 1); + + RAY_screen_bitmap[index] = (r >> RAY_screen_mask_red) << RAY_screen_shift_red; + RAY_screen_bitmap[index] |= (g >> RAY_screen_mask_green) << RAY_screen_shift_green; + RAY_screen_bitmap[index] |= (b >> RAY_screen_mask_blue) << RAY_screen_shift_blue; + } + } + + */ +} + + +void RAY_render_polys(void) +{ + D3DTexture *rs; + + rs = (RAY_which_screen) ? &RAY_screen1 : &RAY_screen2; + + // + // Setup vertices and indices... + // + + RAY_d3d_vertex[0].sx = 0.0F; + RAY_d3d_vertex[0].sy = 0.0F; + RAY_d3d_vertex[0].sz = 0.5F; + RAY_d3d_vertex[0].rhw = 0.5F; + RAY_d3d_vertex[0].tu = 0.0F; + RAY_d3d_vertex[0].tv = 0.0F; + RAY_d3d_vertex[0].color = 0x00ffffff; + RAY_d3d_vertex[0].specular = 0x00000000; + + RAY_d3d_vertex[1].sx = 640.0F; + RAY_d3d_vertex[1].sy = 0.0F; + RAY_d3d_vertex[1].sz = 0.5F; + RAY_d3d_vertex[1].rhw = 0.5F; + RAY_d3d_vertex[1].tu = 1.0F; + RAY_d3d_vertex[1].tv = 0.0F; + RAY_d3d_vertex[1].color = 0x00ffffff; + RAY_d3d_vertex[1].specular = 0x00000000; + + RAY_d3d_vertex[2].sx = 640.0F; + RAY_d3d_vertex[2].sy = 480.0F; + RAY_d3d_vertex[2].sz = 0.5F; + RAY_d3d_vertex[2].rhw = 0.5F; + RAY_d3d_vertex[2].tu = 1.0F; + RAY_d3d_vertex[2].tv = 0.8F; + RAY_d3d_vertex[2].color = 0x00ffffff; + RAY_d3d_vertex[2].specular = 0x00000000; + + RAY_d3d_vertex[3].sx = 0.0F; + RAY_d3d_vertex[3].sy = 480.0F; + RAY_d3d_vertex[3].sz = 0.5F; + RAY_d3d_vertex[3].rhw = 0.5F; + RAY_d3d_vertex[3].tu = 0.0F; + RAY_d3d_vertex[3].tv = 0.8F; + RAY_d3d_vertex[3].color = 0x00ffffff; + RAY_d3d_vertex[3].specular = 0x00000000; + + RAY_d3d_index[0] = 0; + RAY_d3d_index[1] = 1; + RAY_d3d_index[2] = 2; + + RAY_d3d_index[3] = 0; + RAY_d3d_index[4] = 2; + RAY_d3d_index[5] = 3; + + // + // Setup renderstates. + // + + SET_RENDER_STATE(D3DRENDERSTATE_SHADEMODE,D3DSHADE_GOURAUD); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREPERSPECTIVE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG,D3DFILTER_LINEAR); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN,D3DFILTER_LINEAR); + SET_RENDER_STATE(D3DRENDERSTATE_DITHERENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SPECULARENABLE,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_SUBPIXEL,TRUE); + SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ZFUNC,D3DCMP_LESSEQUAL); + SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_CULLMODE,D3DCULL_NONE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE); + SET_RENDER_STATE(D3DRENDERSTATE_FOGCOLOR, 0x008890ee); + SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE, FALSE); +// SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREHANDLE, rs->GetTextureHandle()); + SET_TEXTURE(rs->GetD3DTexture()); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE); + SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); + + // + // Do the draw primitive call! + // + + DRAW_INDEXED_PRIMITIVE( + D3DPT_TRIANGLELIST, + D3DFVF_TLVERTEX, + RAY_d3d_vertex, + 4, + RAY_d3d_index, + 6, + D3DDP_DONOTUPDATEEXTENTS); +} + + +void RAY_do() +{ + SLONG i; + + RAY_init(); + + while(1) + { + SHELL_ACTIVE; + + if (Keys[KB_Q]) {return;} + + for (i = 0; i < 256; i++) + { + Keys[i] = 0; + } + + + /* + the_display.SetUserColour(0, 0, 0); + the_display.SetUserBackground(); + the_display.ClearViewport(); + */ + + RAY_animate(); + RAY_screen_lock(); + RAY_render_scene(); + RAY_screen_unlock(); + RAY_screen_update(); + + BEGIN_SCENE; + RAY_render_polys(); + END_SCENE; + + AENG_flip(); + } +} + + +#endif \ No newline at end of file diff --git a/fallen/DDEngine/Source/renderstate.cpp b/fallen/DDEngine/Source/renderstate.cpp new file mode 100644 index 0000000..a4ee102 --- /dev/null +++ b/fallen/DDEngine/Source/renderstate.cpp @@ -0,0 +1,1101 @@ +// renderstate.cpp +// +// RenderState class + +#include +#include +#include +#include "poly.h" +#include "env.h" + +#include "renderstate.h" + + + + + +#ifdef TARGET_DC +// Not sure whether to have trilinear or nearest - spped is not much different +// at the moment, but may be important later. +#define MIPMAP_MODE_PLEASE_BOB D3DTFP_LINEAR +//#define MIPMAP_MODE_PLEASE_BOB D3DTFP_POINT +#else +// PC doesn't want any mipmapping. +#define MIPMAP_MODE_PLEASE_BOB D3DTFP_NONE +#endif + + + +// s_State +// +// current state of the 3D card + +RenderState RenderState::s_State; + +#ifdef EDITOR +bool RenderState::AllowFadeOut = false; +#endif + + + + +_inline DWORD FloatAsDword ( float fArg ) +{ + return ( *((DWORD *)(&fArg)) ); +} + + + + +// config handlers + +#ifndef TARGET_DC +int UseDX5Fix = 0; + +void RS_read_config() +{ + UseDX5Fix = ENV_get_value_number("fix_directx", 0, "Render"); +} + +void RS_get_config(int* fix_directx) +{ + *fix_directx = UseDX5Fix; +} + +void RS_set_config(int fix_directx) +{ + ENV_set_value_number("fix_directx", fix_directx, "Render"); + RS_read_config(); +} +#endif + +// RenderState +// +// construct a default render state + +RenderState::RenderState(DWORD mag_filter, DWORD min_filter) +{ + TextureMap = NULL; + TextureAddress = D3DTADDRESS_CLAMP; + TextureMag = mag_filter; + TextureMin = min_filter; + TextureMapBlend = D3DTBLEND_MODULATE; + +#ifndef TARGET_DC + ZEnable = D3DZB_TRUE; + ZWriteEnable = TRUE; + ZFunc = D3DCMP_LESSEQUAL; + ColorKeyEnable = FALSE; +#endif + FogEnable = TRUE; + AlphaTestEnable = FALSE; + SrcBlend = D3DBLEND_ONE; + DestBlend = D3DBLEND_ZERO; + AlphaBlendEnable = FALSE; + CullMode = D3DCULL_NONE; + +//md FogEnable = FALSE; + + ZBias = 0; + WrapOnce = false; + +#ifndef TARGET_DC + TempTransparent = false; + TempSrcBlend = 0; + TempDestBlend = 0; + TempAlphaBlendEnable = 0; + TempZWriteEnable = 0; + TempTextureMapBlend = 0; +#endif + + Effect = RS_None; +} + +// SetTempTransparent +// +// set to be transparent for this cycle only + +#ifndef TARGET_DC +void RenderState::SetTempTransparent() +{ + if (!TempTransparent) + { + TempTransparent = true; + TempSrcBlend = SrcBlend; + TempDestBlend = DestBlend; + TempAlphaBlendEnable = AlphaBlendEnable; + TempZWriteEnable = ZWriteEnable; + TempTextureMapBlend = TextureMapBlend; + TempEffect = Effect; + + SrcBlend = D3DBLEND_SRCALPHA; + DestBlend = D3DBLEND_INVSRCALPHA; + AlphaBlendEnable = TRUE; + ZWriteEnable = FALSE; + TextureMapBlend = D3DTBLEND_MODULATEALPHA; + Effect = RS_None; + } +} +#endif + +// ResetTempTransparent +// +// reset transparency + +#ifndef TARGET_DC +void RenderState::ResetTempTransparent() +{ + if (TempTransparent) + { + TempTransparent = false; + SrcBlend = TempSrcBlend; + DestBlend = TempDestBlend; + AlphaBlendEnable = TempAlphaBlendEnable; + ZWriteEnable = TempZWriteEnable; + TextureMapBlend = TempTextureMapBlend; + Effect = TempEffect; + } +} +#endif + +// SetTexture +// +// set texture + +void RenderState::SetTexture(LPDIRECT3DTEXTURE2 texture) +{ + TextureMap = texture; +} + +// SetRenderState +// +// emulate SetRenderState() call + +void RenderState::SetRenderState(DWORD ix, DWORD value) +{ + if ((ix == D3DRENDERSTATE_TEXTUREMAPBLEND) && (value == D3DTBLEND_MODULATEALPHA) && !the_display.GetDeviceInfo()->ModulateAlphaSupported()) + { + value = D3DTBLEND_MODULATE; // why doesn't DX do this? + } + + if ((ix == D3DRENDERSTATE_TEXTUREMAPBLEND) && (value == D3DTBLEND_DECAL)) + { + if (the_display.GetDeviceInfo()->DestInvSourceColourSupported() && + !the_display.GetDeviceInfo()->ModulateAlphaSupported()) + { + // Rage Pro - don't do this + } + else + { + value = D3DTBLEND_MODULATE; + Effect = RS_DecalMode; + } + } + + switch (ix) + { + // things we can set + case D3DRENDERSTATE_TEXTUREADDRESS: TextureAddress = value; break; + case D3DRENDERSTATE_TEXTUREMAG: TextureMag = value; break; + case D3DRENDERSTATE_TEXTUREMIN: TextureMin = value; break; + case D3DRENDERSTATE_TEXTUREMAPBLEND: TextureMapBlend = value; break; +#ifdef TARGET_DC + // These states are ignored on DC. + case D3DRENDERSTATE_ZENABLE: break; + case D3DRENDERSTATE_ZWRITEENABLE: break; + case D3DRENDERSTATE_ZFUNC: break; + case D3DRENDERSTATE_COLORKEYENABLE: break; +#else + case D3DRENDERSTATE_ZENABLE: ZEnable = value; break; + case D3DRENDERSTATE_ZWRITEENABLE: ZWriteEnable = value; break; + case D3DRENDERSTATE_ZFUNC: ZFunc = value; break; + case D3DRENDERSTATE_COLORKEYENABLE: ColorKeyEnable = value; break; +#endif + + case D3DRENDERSTATE_FOGENABLE: FogEnable = value; break; + case D3DRENDERSTATE_ALPHATESTENABLE: AlphaTestEnable = value; break; + case D3DRENDERSTATE_SRCBLEND: SrcBlend = value; break; + case D3DRENDERSTATE_DESTBLEND: DestBlend = value; break; + case D3DRENDERSTATE_ALPHABLENDENABLE: AlphaBlendEnable = value; break; + case D3DRENDERSTATE_ZBIAS: ZBias = value; break; + case D3DRENDERSTATE_CULLMODE: CullMode = value; break; + + // defaults which can't change + case D3DRENDERSTATE_TEXTUREPERSPECTIVE: ASSERT(value == TRUE); break; + case D3DRENDERSTATE_ALPHAREF: ASSERT(value == 0); break; + case D3DRENDERSTATE_ALPHAFUNC: ASSERT(value == D3DCMP_NOTEQUAL); break; + case D3DRENDERSTATE_DITHERENABLE: ASSERT(value == TRUE); break; + case D3DRENDERSTATE_SPECULARENABLE: ASSERT(value == TRUE); break; + case D3DRENDERSTATE_SUBPIXEL: ASSERT(value == TRUE); break; + case D3DRENDERSTATE_SHADEMODE: ASSERT(value == D3DSHADE_GOURAUD); break; + + default: ASSERT(0); + } +} + +// SetEffect +// +// set a special vertex effect + +void RenderState::SetEffect(DWORD effect) +{ + Effect = effect; + + switch (effect) + { + case RS_AlphaPremult: + case RS_InvAlphaPremult: + SrcBlend = D3DBLEND_ONE; + DestBlend = D3DBLEND_ONE; + TextureMapBlend = D3DTBLEND_MODULATE; + break; + + case RS_BlackWithAlpha: + SrcBlend = D3DBLEND_SRCALPHA; + DestBlend = D3DBLEND_INVSRCALPHA; + TextureMapBlend = D3DTBLEND_MODULATEALPHA; + break; + + case RS_DecalMode: + TextureMapBlend = D3DTBLEND_MODULATE; + break; + } +} + +#ifdef _DEBUG +// Validate +// +// validate the render state for the PerMedia 2 ;) + +char* RenderState::Validate() +{ + // check which alpha modes are used + if (AlphaBlendEnable) + { + if ((SrcBlend == D3DBLEND_ONE) && (DestBlend == D3DBLEND_ZERO)) return NULL; + if ((SrcBlend == D3DBLEND_ZERO) && (DestBlend == D3DBLEND_ONE)) return NULL; + if ((SrcBlend == D3DBLEND_ONE) && (DestBlend == D3DBLEND_ONE)) return NULL; + if ((SrcBlend == D3DBLEND_SRCALPHA) && (DestBlend == D3DBLEND_INVSRCALPHA)) return NULL; + if ((SrcBlend == D3DBLEND_ONE) && (DestBlend == D3DBLEND_SRCALPHA)) return NULL; + + //TRACE("SrcBlend = %d DestBlend = %d\n", SrcBlend, DestBlend); + //return "Renderstate has a bad alpha blend mode"; + return ""; + } + + return NULL; +} +#endif + +#if 0 +/* + +NOTES: + +Rs == Rv * Rt +As == Av * At + +TODO: + +Add textures in (change filenames loaded for the pages shown) + +SRCALPHA:ONE + +(As,As,As,As):(1,1,1,1) + +SrcBlend = 5 DestBlend = 2 Page 1353 : Renderstate has a bad alpha blend mode BIG_RAIN raindrop2.tga bigrain - +SrcBlend = 5 DestBlend = 2 Page 1362 : Renderstate has a bad alpha blend mode NEWFONT_INVERSE olyfont2.tga lcdfont_alpha + +SrcBlend = 5 DestBlend = 2 Page 1375 : Renderstate has a bad alpha blend mode SMOKER smoker2.tga smoker - +SrcBlend = 5 DestBlend = 2 Page 1378 : Renderstate has a bad alpha blend mode ADDITIVEALPHA n/a +SrcBlend = 5 DestBlend = 2 Page 1383 : Renderstate has a bad alpha blend mode HITSPANG hitspang.tga hitspang - +SrcBlend = 5 DestBlend = 2 Page 1384 : Renderstate has a bad alpha blend mode BLOOM2 bloom4.tga bloom1 - +SrcBlend = 5 DestBlend = 2 Page 1385 : Renderstate has a bad alpha blend mode BLOOM1 bloom2.tga bloom2 - +SrcBlend = 5 DestBlend = 2 Page 1402 : Renderstate has a bad alpha blend mode FLAMES2 explode4.tga flame2 - +SrcBlend = 5 DestBlend = 2 Page 1406 : Renderstate has a bad alpha blend mode FLAMES flame1.tga flames_alpha + + +SOLUTION: + +Premultiply vertex colour by vertex alpha, set vertex alpha to 0 +Premultiply texture colour by texture alpha, set texture alpha to 0 +Use TBLEND_MODULATE and ONE:ONE + +So blender red = (Rv*Av*Rt*At*1) + Rd == Rs*As + Rd + +ZERO:INVSRCALPHA + +(0,0,0,0):(1-As,1-As,1-As,1-As) + +SrcBlend = 1 DestBlend = 6 Page 1349 : Renderstate has a bad alpha blend mode SMOKECLOUD +SrcBlend = 1 DestBlend = 6 Page 1357 : Renderstate has a bad alpha blend mode TYRESKID +SrcBlend = 1 DestBlend = 6 Page 1361 : Renderstate has a bad alpha blend mode SUBTRACTIVEALPHA +SrcBlend = 1 DestBlend = 6 Page 1373 : Renderstate has a bad alpha blend mode NEWFONT +SrcBlend = 1 DestBlend = 6 Page 1432 : Renderstate has a bad alpha blend mode (POLY_NUM_PAGES - 2) + +Set vertex colour to (0,0,0,Av) +Set texture colour to (Rt,Gt,Bt,At) (do nothing!) +Use TBLEND_MODULATEALPHA and SRCALPHA:INVSRCALPHA + +So blender red = (0*0*Av*At) + (1-Av*At)*Rd == 0 + (1-As)*Rd + +SRCALPHA:INVSRCCOLOR + +(As,As,As,As):(1-Rs,1-Gs,1-Bs,1-As) + +SrcBlend = 5 DestBlend = 4 Page 1379 : Renderstate has a bad alpha blend mode TYRETRACK tyremark.tga tyretrack_alpha + +SrcBlend = 5 DestBlend = 4 Page 1397 : Renderstate has a bad alpha blend mode FOOTPRINT footprint.tga footprint - + +Use a white+alpha texture, TBLEND_MODULATEALPHA and SRCALPHA:INVSRCALPHA +Diffuse colour sets colour; diffuse alpha sets fade-out + +INVSRCALPHA:ONE + +(1-As,1-As,1-As,1-As):(1,1,1,1) + +SrcBlend = 6 DestBlend = 2 Page 1387 : Renderstate has a bad alpha blend mode FLAMES3 flame3.tga flames3 - +SrcBlend = 6 DestBlend = 2 Page 1388 : Renderstate has a bad alpha blend mode DUSTWAVE dustwave.tga dustwave - +SrcBlend = 6 DestBlend = 2 Page 1389 : Renderstate has a bad alpha blend mode BIGBANG exp_gunk.tga bigbang - + +Premultiply vertex colour by 1 - vertex alpha, set vertex alpha to 0 +Premultiply texture colour by 1 - texture alpha, set texture colour to 0 +Use TBLEND_MODULATE and ONE:ONE + +So blender red = (Rv*(1-Av)*Rt*(1-At)*1) + Rd = Rs*(1-Av-At+Av*At) + Rd +We want (Rv*Rt*(1-Av*At)) + Rd + +ZERO:SRCCOLOR + +(0,0,0,0):(Rs,Gs,Bs,As) + +SrcBlend = 1 DestBlend = 3 Page 1398 : Renderstate has a bad alpha blend mode BARBWIRE barbed.tga barbwire - + +Use an alpha texture and invert (so white is wire, black is space) and the RGB of the texture is all black, then +use TBLEND_MODULATEALPHA and SRCALPHA:INVSRCALPHA + +ZERO:INVSRCCOLOR + +(0,0,0,0):(1-Rs,1-Gs,1-Bs,1-As) + +SrcBlend = 1 DestBlend = 4 Page 1403 : Renderstate has a bad alpha blend mode SMOKE + +Never used. Fuck it off. + +*/ +#endif + +// InitScene +// +// set all state variables and remember + +void RenderState::InitScene(DWORD fog_colour) +{ + // set constant state variables + + extern int AENG_detail_perspective; + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREPERSPECTIVE, AENG_detail_perspective ? TRUE : FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_CULLMODE, CullMode); + + // we use > 0x07 instead of != 0x00 because it's + // (a) more robust + // (b) works on the Permedia 2 drivers + // (c) looks better when alpha is interpolated + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHAREF, 0x07); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER); + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DITHERENABLE, TRUE); + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SPECULARENABLE, TRUE); +// REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SPECULARENABLE, FALSE); + + + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SUBPIXEL, TRUE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGCOLOR, fog_colour); +#ifdef TARGET_DC + // These really should have been set up for the PC as well! +#ifdef FAKE_UP_VERTEX_FOG_PLEASE_BOB + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_NONE); +#else + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_LINEAR); +#endif + + + // Tweak these to your liking. + +#if 0 + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGTABLESTART, FloatAsDword(30.0f)); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGTABLEEND, FloatAsDword(60.0f)); +#else +extern SLONG CurDrawDistance; + float fFogDist = CurDrawDistance * ( 60.0f / ( 22.f * 256.0f ) ); + float fFogDistNear = fFogDist * 0.7f; + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGTABLESTART, FloatAsDword(fFogDistNear)); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGTABLEEND, FloatAsDword(fFogDist)); +#endif + // Density isn't actually used. + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGTABLEDENSITY, FloatAsDword(0.5f)); +#endif + + // set variable state variables + +#ifdef TARGET_DC + // Don't use these blends - use the TSS ones instead. + switch ( TextureMapBlend ) + { + case D3DTBLEND_MODULATE: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + // Erk - how do you do this then? + //if ( the_texture_has_an_alpha_channel ) + //{ + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + //} + //else + //{ + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + //} + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + case D3DTBLEND_MODULATEALPHA: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + break; + case D3DTBLEND_ADD: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_ADD); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + break; + case D3DTBLEND_COPY: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + break; + default: + // If this triggers, I'll need to add the blend mode. + ASSERT ( FALSE ); + break; + } + + // Also sets up some default multitexture stuff, coz there now is some in the game. + switch ( TextureMin ) + { + case D3DFILTER_NEAREST: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MINFILTER, D3DTFN_POINT); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MIPFILTER, D3DTFP_POINT); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_MINFILTER, D3DTFN_POINT); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_MIPFILTER, D3DTFP_POINT); + break; + case D3DFILTER_LINEAR: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MIPFILTER, MIPMAP_MODE_PLEASE_BOB); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_MINFILTER, D3DTFN_LINEAR); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_MIPFILTER, MIPMAP_MODE_PLEASE_BOB); + break; + default: + // Need to add the others. + ASSERT ( FALSE ); + break; + } + switch ( TextureMag ) + { + case D3DFILTER_NEAREST: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MAGFILTER, D3DTFG_POINT); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_MAGFILTER, D3DTFG_POINT); + break; + case D3DFILTER_LINEAR: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + break; + default: + // Need to add the others. + ASSERT ( FALSE ); + break; + } + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_TEXCOORDINDEX, 0); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ADDRESS, TextureAddress); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_TEXCOORDINDEX, 0); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_ADDRESS, TextureAddress); + + REALLY_SET_TEXTURE_STATE(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + REALLY_SET_TEXTURE(TextureMap); + + + + // Set the mipmap LOD bias. + static float fTemp = 0.0f; + DWORD dwTemp = *((DWORD*) (&fTemp)); + REALLY_SET_TEXTURE_STATE ( 0, D3DTSS_MIPMAPLODBIAS, dwTemp ); + REALLY_SET_TEXTURE_STATE ( 1, D3DTSS_MIPMAPLODBIAS, dwTemp ); + + + +#else + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND, TextureMapBlend); + REALLY_SET_TEXTURE(TextureMap); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS, TextureAddress); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG, TextureMag); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN, TextureMin); +#endif + +#ifndef TARGET_DC + // Ignored on DC. + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE, ZEnable); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE, ZWriteEnable); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZFUNC, ZFunc); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_COLORKEYENABLE, ColorKeyEnable); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE, FogEnable); +#else //#ifndef TARGET_DC + + // Hack the fog off - it doesn't seem to work ATM. + // Does now. +#ifndef FAKE_UP_VERTEX_FOG_PLEASE_BOB + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE, FogEnable); +#endif + +#endif //#else //#ifndef TARGET_DC + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHATESTENABLE, AlphaTestEnable); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND, SrcBlend); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND, DestBlend); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE, AlphaBlendEnable); + +// REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZBIAS, ZBias); // doesn't work - done in PolyPage::AddFan instead + + // remember the state + + s_State = *this; +} + +#define MAYBE_SET(CAPS, SMALL) if (s_State.SMALL != SMALL) { REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ ## CAPS, SMALL); s_State.SMALL = SMALL; } + +// SetChanged +// +// set just the different render states + + + + +#ifndef TARGET_DC + + +void RenderState::SetChanged() +{ + DWORD old_texture_address = TextureAddress; + + if (WrapOnce) + { + TextureAddress = D3DTADDRESS_WRAP; + } + + if (s_State.TextureMap != TextureMap) + { + REALLY_SET_TEXTURE(TextureMap); + s_State.TextureMap = TextureMap; + } + +#ifdef EDITOR + DWORD old_TextureMapBlend = TextureMapBlend; + DWORD old_AlphaBlendEnable = AlphaBlendEnable; + DWORD old_SrcBlend = SrcBlend; + DWORD old_DestBlend = DestBlend; + + if (AllowFadeOut) + { + TextureMapBlend = D3DTBLEND_MODULATEALPHA; + AlphaBlendEnable = TRUE; + SrcBlend = D3DBLEND_SRCALPHA; + DestBlend = D3DBLEND_INVSRCALPHA; + } +#endif + + + + +#ifdef TARGET_DC + if ( TextureMapBlend != s_State.TextureMapBlend ) + { + s_State.TextureMapBlend = TextureMapBlend; + switch ( TextureMapBlend ) + { + case D3DTBLEND_MODULATE: +#if 1 + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + // Erk - how do you do this then? + //if ( the_texture_has_an_alpha_channel ) + //{ + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + //} + //else + //{ + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + //} + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); +#else + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); +#endif + + + case D3DTBLEND_MODULATEALPHA: +#if 1 + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); +#else + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); +#endif + break; + case D3DTBLEND_ADD: + // Does anyone use this? + ASSERT(FALSE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_ADD); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + break; + case D3DTBLEND_COPY: + // Does anyone use this? + ASSERT(FALSE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + break; + default: + // If this triggers, I'll need to add the blend mode. + ASSERT ( FALSE ); + break; + } + } + + if ( TextureMin != s_State.TextureMin ) + { + s_State.TextureMin = TextureMin; + switch ( TextureMin ) + { + case D3DFILTER_NEAREST: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MINFILTER, D3DTFN_POINT); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MIPFILTER, D3DTFP_POINT); + break; + case D3DFILTER_LINEAR: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MIPFILTER, MIPMAP_MODE_PLEASE_BOB); + break; + default: + // Need to add the others. + ASSERT ( FALSE ); + break; + } + } + + if ( TextureMag != s_State.TextureMag ) + { + s_State.TextureMag = TextureMag; + switch ( TextureMag ) + { + case D3DFILTER_NEAREST: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MAGFILTER, D3DTFG_POINT); + break; + case D3DFILTER_LINEAR: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + break; + default: + // Need to add the others. + ASSERT ( FALSE ); + break; + } + } + + if ( TextureAddress != s_State.TextureAddress ) + { + s_State.TextureAddress = TextureAddress; + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ADDRESS, TextureAddress); + } + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_TEXCOORDINDEX, 0); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + +#else + + MAYBE_SET(TEXTUREADDRESS, TextureAddress); + MAYBE_SET(TEXTUREMAG, TextureMag); + MAYBE_SET(TEXTUREMIN, TextureMin); +#ifndef TARGET_DC + if (!UseDX5Fix) + { + MAYBE_SET(TEXTUREMAPBLEND, TextureMapBlend); + } + else +#endif + { + if (s_State.TextureMapBlend != TextureMapBlend) + { + if (TextureMapBlend == D3DTBLEND_MODULATEALPHA) + { + // This makes MODULATEALPHA work on the Permedia 2 + // DO NOT CHANGE THE ORDER OF THESE LINES + // They work around a bug in DirectX 6 + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + + REALLY_SET_TEXTURE_STATE(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + } + else + { + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND, TextureMapBlend); + } + s_State.TextureMapBlend = TextureMapBlend; + } + } +#endif + + MAYBE_SET(ZENABLE, ZEnable); + MAYBE_SET(ZWRITEENABLE, ZWriteEnable); + MAYBE_SET(ALPHATESTENABLE, AlphaTestEnable); + MAYBE_SET(SRCBLEND, SrcBlend); + MAYBE_SET(DESTBLEND, DestBlend); + MAYBE_SET(ALPHABLENDENABLE, AlphaBlendEnable); + MAYBE_SET(ZFUNC, ZFunc); + MAYBE_SET(CULLMODE, CullMode); + + + // Hack the fog off for the DC - it doesn't seem to work ATM. + // Does now. + MAYBE_SET(FOGENABLE, FogEnable); + +#ifndef TARGET_DC + MAYBE_SET(COLORKEYENABLE, ColorKeyEnable); +#endif +// MAYBE_SET(ZBIAS, ZBias); // doesn't work - done in PolyPage::AddFan instead + + if (WrapOnce) + { + TextureAddress = old_texture_address; + WrapOnce = false; + } + +#ifdef EDITOR + TextureMapBlend = old_TextureMapBlend; + AlphaBlendEnable = old_AlphaBlendEnable; + SrcBlend = old_SrcBlend; + DestBlend = old_DestBlend; +#endif +} + + + + +#else + + +float fMipMapLodBias = 0.0f; + + +void RenderState::SetChanged() +{ + DWORD old_texture_address = TextureAddress; + + if (WrapOnce) + { + TextureAddress = D3DTADDRESS_WRAP; + } + + if (s_State.TextureMap != TextureMap) + { + // Do I need this line? + // I have a vague feeling that the DC doesn't like you sending NULL textures down. Not sure. + // FIXME! Why does this fall over on the first frame? + //char cTemp[30]; + //sprintf ( cTemp, "TM:0x%x ", TextureMap ); + //OutputDebugString ( cTemp ); + //MAKE_MY_TEXTURES_WORK_PLEASE_BOB_YOU_SCUMBAG + +#if 0 +extern int iPolyRenderStateFrameNum; + if ( iPolyRenderStateFrameNum < 100 ) + { + char cTemp[30]; + sprintf ( cTemp, "TM:0x%x\n", TextureMap ); + OutputDebugString ( cTemp ); + REALLY_SET_TEXTURE(NULL); + } + else +#endif + { + REALLY_SET_TEXTURE(TextureMap); + } + s_State.TextureMap = TextureMap; + } + else + { + //char cTemp[30]; + //sprintf ( cTemp, "TMx:0x%x\n", TextureMap ); + //OutputDebugString ( cTemp ); + } + + + if ( AlphaTestEnable ) + { + // Override - use alpha blend instead. + if ( AlphaBlendEnable && ( SrcBlend != D3DBLEND_SRCALPHA ) && ( DestBlend != D3DBLEND_INVSRCALPHA ) ) + { + // Oh - that's a shame. + ASSERT ( FALSE ); + } + AlphaBlendEnable = TRUE; + SrcBlend = D3DBLEND_SRCALPHA; + DestBlend = D3DBLEND_INVSRCALPHA; + //AlphaBlendEnable = TRUE; + //SrcBlend = D3DBLEND_ONE; + //DestBlend = D3DBLEND_ONE; + AlphaTestEnable = FALSE; + } + + +#ifndef TARGET_DC + // Ignored states on DC. + MAYBE_SET(ZENABLE, ZEnable); + MAYBE_SET(ZFUNC, ZFunc); + MAYBE_SET(ZWRITEENABLE, ZWriteEnable); + REALLY_SET_RENDER_STATE ( D3DRENDERSTATE_COLORKEYENABLE, FALSE ); + MAYBE_SET(COLORKEYENABLE, ColorKeyEnable); +#else + // Hack the fog off for the DC - it doesn't seem to work ATM. + // Does now! + //FogEnable = FALSE; + MAYBE_SET(FOGENABLE, FogEnable); +#endif + + MAYBE_SET(ALPHATESTENABLE, AlphaTestEnable); + MAYBE_SET(SRCBLEND, SrcBlend); + MAYBE_SET(DESTBLEND, DestBlend); + MAYBE_SET(ALPHABLENDENABLE, AlphaBlendEnable); + + // Forgot this one last time! + MAYBE_SET(CULLMODE, CullMode); + + + if ( TextureMapBlend != s_State.TextureMapBlend ) + { + s_State.TextureMapBlend = TextureMapBlend; + switch ( TextureMapBlend ) + { + case D3DTBLEND_MODULATE: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + // Erk - how do you do this then? + //if ( the_texture_has_an_alpha_channel ) + //{ + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + //} + //else + //{ + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + // REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + //} + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + //REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + + case D3DTBLEND_MODULATEALPHA: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + break; + default: + // If this triggers, I'll need to add the blend mode. + ASSERT ( FALSE ); + break; + } + + REALLY_SET_TEXTURE_STATE(0, D3DTSS_TEXCOORDINDEX, 0); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + REALLY_SET_TEXTURE_STATE(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + } + + if ( TextureMin != s_State.TextureMin ) + { + s_State.TextureMin = TextureMin; + switch ( TextureMin ) + { + case D3DFILTER_NEAREST: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MINFILTER, D3DTFN_POINT); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MIPFILTER, D3DTFP_POINT); + break; + case D3DFILTER_LINEAR: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MIPFILTER, MIPMAP_MODE_PLEASE_BOB); + break; + default: + // Need to add the others. + ASSERT ( FALSE ); + break; + } + } + + if ( TextureMag != s_State.TextureMag ) + { + s_State.TextureMag = TextureMag; + switch ( TextureMag ) + { + case D3DFILTER_NEAREST: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MAGFILTER, D3DTFG_POINT); + break; + case D3DFILTER_LINEAR: + REALLY_SET_TEXTURE_STATE(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); + break; + default: + // Need to add the others. + ASSERT ( FALSE ); + break; + } + } + + if ( TextureAddress != s_State.TextureAddress ) + { + s_State.TextureAddress = TextureAddress; + REALLY_SET_TEXTURE_STATE(0, D3DTSS_ADDRESS, TextureAddress); + } + + + + + if (WrapOnce) + { + TextureAddress = old_texture_address; + WrapOnce = false; + } + + +} + + + + + + + +#endif + +// Returns TRUE if the renderstates are equivalent, +// ie you don't need any renderstate changes to go from one to the other. +bool RenderState::IsSameRenderState ( RenderState *pRS ) +{ + bool bRes = TRUE; + +#define CHECK_RS(name) if ( name != pRS->name ) { bRes = FALSE; } + + + CHECK_RS ( TextureMap ); + CHECK_RS ( TextureAddress ); + CHECK_RS ( TextureMag ); + CHECK_RS ( TextureMin ); + CHECK_RS ( TextureMapBlend ); + +#ifndef TARGET_DC + CHECK_RS ( ZEnable ); + CHECK_RS ( ZWriteEnable ); +#endif + CHECK_RS ( AlphaTestEnable ); + CHECK_RS ( SrcBlend ); + CHECK_RS ( DestBlend ); +#ifndef TARGET_DC + CHECK_RS ( ZFunc ); +#endif + CHECK_RS ( AlphaBlendEnable ); + CHECK_RS ( FogEnable ); +#ifndef TARGET_DC + CHECK_RS ( ColorKeyEnable ); +#endif + + CHECK_RS ( CullMode ); + CHECK_RS ( ZBias ); + CHECK_RS ( Effect ); +#if 0 + CHECK_RS ( WrapOnce ); +#endif + +#if 0 + CHECK_RS ( TempTransparent ); + CHECK_RS ( TempSrcBlend ); + CHECK_RS ( TempDestBlend ); + CHECK_RS ( TempAlphaBlendEnable ); + CHECK_RS ( TempZWriteEnable ); + CHECK_RS ( TempTextureMapBlend ); + CHECK_RS ( TempEffect ); +#endif + + +#undef CHECK_RS + + return ( bRes ); +} diff --git a/fallen/DDEngine/Source/shape.cpp b/fallen/DDEngine/Source/shape.cpp new file mode 100644 index 0000000..7dc021c --- /dev/null +++ b/fallen/DDEngine/Source/shape.cpp @@ -0,0 +1,2178 @@ +#include +#include +#include +#include "aeng.h" +#include "c:\fallen\headers\balloon.h" +#include "poly.h" +#include "shape.h" +#include "night.h" +#include "matrix.h" +#include "c:\fallen\editor\headers\prim.h" +#include "mesh.h" +#include "game.h" + + + +// How much to shift the W value up by to prevent Z-fighting. +#define DC_SHADOW_Z_ADJUST 0.0001f + + +// +// Multiplies the two colours together. +// + +ULONG SHAPE_colour_mult(ULONG c1, ULONG c2) +{ + SLONG r1; + SLONG g1; + SLONG b1; + + SLONG r2; + SLONG g2; + SLONG b2; + + SLONG r; + SLONG g; + SLONG b; + + ULONG ans; + + r1 = (c1 >> 16) & 0xff; + g1 = (c1 >> 8) & 0xff; + b1 = (c1 >> 0) & 0xff; + + r2 = (c2 >> 16) & 0xff; + g2 = (c2 >> 8) & 0xff; + b2 = (c2 >> 0) & 0xff; + + r = r1 * r2 >> 8; + g = g1 * g2 >> 8; + b = b1 * b2 >> 8; + + ans = (r << 16) | (g << 8) | (b << 0); + + return ans; +} + + + + +void SHAPE_semisphere( + SLONG x, + SLONG y, + SLONG z, + SLONG dx, // Gives the and direction of the semi-sphere. + SLONG dy, + SLONG dz, + SLONG radius, + SLONG page, + UBYTE red, + UBYTE green, + UBYTE blue) +{ + SLONG i; + SLONG j; + + SLONG px; + SLONG py; + SLONG pz; + + SLONG ax; + SLONG ay; + SLONG az; + + SLONG bx; + SLONG by; + SLONG bz; + + SLONG ox; + SLONG oy; + SLONG oz; + + SLONG c_num; + SLONG c_points; + SLONG c_red; + SLONG c_green; + SLONG c_blue; + ULONG c_colour; + + SLONG angle; + SLONG width; + SLONG height; + SLONG elevation; + SLONG along_a; + SLONG along_b; + + SLONG p1; + SLONG p2; + + POLY_Point *pp; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + // + // Construct two vectors orthogonal to (dx,dy,dz) and to eachother. + // + + px = dy; + py = dz; + pz = dx; + + // + // (px,py,pz) is not paralell to (dx,dy,dz) so (d x p) will be + // orthogonal to (dx,dy,dz) + // + + ax = dy*pz - dz*py >> 8; + ay = dz*px - dx*pz >> 8; + az = dx*py - dy*px >> 8; + + // + // Create a vector parallel to both a and d. + // + + bx = dy*az - dz*ay >> 8; + by = dz*ax - dx*az >> 8; + bz = dx*ay - dy*ax >> 8; + + // + // Make the three vectors 'radius' long. + // + + bx = bx * radius >> 8; + by = by * radius >> 8; + bz = bz * radius >> 8; + + ax = ax * radius >> 8; + ay = ay * radius >> 8; + az = az * radius >> 8; + + dx = dx * radius >> 8; + dy = dy * radius >> 8; + dz = dz * radius >> 8; + + // + // Decide how detailed the semi-sphere should be. We need the number + // of concentric circles and the number of points per circle. + // + + c_points = 6; // Constants for now! + c_num = 4; + + // + // Build the points in the POLY_buffer. + // + + ASSERT(WITHIN(c_points * c_num + 1, 0, POLY_BUFFER_SIZE)); + + for (i = 0; i < c_num; i++) + { + // + // The width and height of this circle. + // + + elevation = i * (512 / c_num); + width = COS(elevation) >> 8; + height = SIN(elevation) >> 8; + + // + // The centre of the circle. + // + + ox = x + (dx * height >> 8); + oy = y + (dy * height >> 8); + oz = z + (dz * height >> 8); + + // + // The colour of the points along this circle. + // + + c_red = red * height >> 8; + c_green = green * height >> 8; + c_blue = blue * height >> 8; + + c_colour = (c_red << 16) | (c_green << 8) | (c_blue << 0); + + for (j = 0; j < c_points; j++) + { + angle = j * (2048 / c_points); + + along_a = SIN(angle) * width >> 8; + along_b = COS(angle) * width >> 8; + + px = ox; + py = oy; + pz = oz; + + px += ax * along_a >> 16; + py += ay * along_a >> 16; + pz += az * along_a >> 16; + + px += bx * along_b >> 16; + py += by * along_b >> 16; + pz += bz * along_b >> 16; + + // + // Build the point. + // + + pp = &POLY_buffer[i * c_points + j]; + + POLY_transform( + (float) px, + (float) py, + (float) pz, + pp); + + if (!pp->IsValid()) + { + // + // Abandon the whole thing if one of the points is behind us! + // + + return; + } + + pp->colour = c_colour; + pp->specular = 0; + pp->u = 0.0F; + pp->v = 0.0F; + } + } + + // + // Finally the uppermost point. + // + + px = x + dx; + py = y + dy; + pz = z + dz; + + pp = &POLY_buffer[c_num * c_points]; + + POLY_transform( + (float) px, + (float) py, + (float) pz, + pp); + + if (!pp->IsValid()) + { + // + // Abandon the whole thing if one of the points is behind us! + // + + return; + } + + pp->colour = (red << 16) | (green << 8) | (blue << 0); + pp->specular = 0; + pp->u = 0.0F; + pp->v = 0.0F; + + // + // Now create the polygons. + // + + for (i = 0; i < c_num - 1; i++) + { + if (i == c_num - 2) + { + // + // Triangles connecting to the uppermost point. + // + + tri[2] = &POLY_buffer[c_num * c_points]; // Constant. + + for (j = 0; j < c_points; j++) + { + p1 = j + 0; + p2 = j + 1; + + if (p2 == c_points) {p2 = 0;} + + tri[0] = &POLY_buffer[(i + 0) * c_points + p1]; + tri[1] = &POLY_buffer[(i + 0) * c_points + p2]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, page, TRUE); + } + } + } + else + { + // + // Quads between this level and the one above. + // + + for (j = 0; j < c_points; j++) + { + p1 = j + 0; + p2 = j + 1; + + if (p2 == c_points) {p2 = 0;} + + quad[0] = &POLY_buffer[(i + 0) * c_points + p1]; + quad[1] = &POLY_buffer[(i + 0) * c_points + p2]; + quad[2] = &POLY_buffer[(i + 1) * c_points + p1]; + quad[3] = &POLY_buffer[(i + 1) * c_points + p2]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, page, TRUE); + } + } + } + } +} + + + +void SHAPE_semisphere_textured( + SLONG x, + SLONG y, + SLONG z, + SLONG dx, // Gives the and direction of the semi-sphere. + SLONG dy, + SLONG dz, + SLONG radius, + float u_mid, + float v_mid, + float uv_radius, + SLONG page, + UBYTE red, + UBYTE green, + UBYTE blue) +{ + SLONG i; + SLONG j; + + SLONG px; + SLONG py; + SLONG pz; + + SLONG ax; + SLONG ay; + SLONG az; + + SLONG bx; + SLONG by; + SLONG bz; + + SLONG ox; + SLONG oy; + SLONG oz; + + SLONG c_num; + SLONG c_points; + SLONG c_red; + SLONG c_green; + SLONG c_blue; + ULONG c_colour; + float f_angle; + float uv_width; + + SLONG angle; + SLONG width; + SLONG height; + SLONG elevation; + SLONG along_a; + SLONG along_b; + + SLONG p1; + SLONG p2; + + POLY_Point *pp; + + POLY_Point *tri [3]; + POLY_Point *quad[4]; + + // + // Construct two vectors orthogonal to (dx,dy,dz) and to eachother. + // + + px = dy; + py = dz; + pz = dx; + + // + // (px,py,pz) is not paralell to (dx,dy,dz) so (d x p) will be + // orthogonal to (dx,dy,dz) + // + + ax = dy*pz - dz*py >> 8; + ay = dz*px - dx*pz >> 8; + az = dx*py - dy*px >> 8; + + // + // Create a vector parallel to both a and d. + // + + bx = dy*az - dz*ay >> 8; + by = dz*ax - dx*az >> 8; + bz = dx*ay - dy*ax >> 8; + + // + // Make the three vectors 'radius' long. + // + + bx = bx * radius >> 8; + by = by * radius >> 8; + bz = bz * radius >> 8; + + ax = ax * radius >> 8; + ay = ay * radius >> 8; + az = az * radius >> 8; + + dx = dx * radius >> 8; + dy = dy * radius >> 8; + dz = dz * radius >> 8; + + // + // Decide how detailed the semi-sphere should be. We need the number + // of concentric circles and the number of points per circle. + // + + c_points = 9; // Constants for now! + c_num = 5; + + // + // Build the points in the POLY_buffer. + // + + ASSERT(WITHIN(c_points * c_num + 1, 0, POLY_BUFFER_SIZE)); + + for (i = 0; i < c_num; i++) + { + // + // The width and height of this circle. + // + + elevation = i * (512 / c_num); + width = COS(elevation) >> 8; + height = SIN(elevation) >> 8; + + // + // The radius of the circle in uv space. + // + + uv_width = float(width) * uv_radius * (1.0F / 256.0F); + + // + // The centre of the circle. + // + + ox = x + (dx * height >> 8); + oy = y + (dy * height >> 8); + oz = z + (dz * height >> 8); + + // + // The colour of the points along this circle. + // + + c_red = red * height >> 8; + c_green = green * height >> 8; + c_blue = blue * height >> 8; + + c_colour = (c_red << 16) | (c_green << 8) | (c_blue << 0); + + for (j = 0; j < c_points; j++) + { + angle = j * (2048 / c_points); + f_angle = float(angle) * (2.0F * PI / 2048.0F); + + along_a = SIN(angle) * width >> 8; + along_b = COS(angle) * width >> 8; + + px = ox; + py = oy; + pz = oz; + + px += ax * along_a >> 16; + py += ay * along_a >> 16; + pz += az * along_a >> 16; + + px += bx * along_b >> 16; + py += by * along_b >> 16; + pz += bz * along_b >> 16; + + // + // Build the point. + // + + pp = &POLY_buffer[i * c_points + j]; + + POLY_transform( + (float) px, + (float) py, + (float) pz, + pp); + + if (!pp->IsValid()) + { + // + // Abandon the whole thing if one of the points is behind us! + // + + return; + } + + pp->colour = c_colour; + pp->specular = 0; + pp->u = (u_mid + sin(f_angle) * uv_width); + pp->v = (v_mid + cos(f_angle) * uv_width); + } + } + + // + // Finally the uppermost point. + // + + px = x + dx; + py = y + dy; + pz = z + dz; + + pp = &POLY_buffer[c_num * c_points]; + + POLY_transform( + (float) px, + (float) py, + (float) pz, + pp); + + if (!pp->IsValid()) + { + // + // Abandon the whole thing if one of the points is behind us! + // + + return; + } + + pp->colour = (red << 16) | (green << 8) | (blue << 0); + pp->specular = 0; + pp->u = u_mid; + pp->v = v_mid; + + // + // Now create the polygons. + // + + for (i = 0; i < c_num; i++) + { + if (i == c_num - 1) + { + // + // Triangles connecting to the uppermost point. + // + + tri[2] = &POLY_buffer[c_num * c_points]; // Constant. + + for (j = 0; j < c_points; j++) + { + p1 = j + 0; + p2 = j + 1; + + if (p2 == c_points) {p2 = 0;} + + tri[0] = &POLY_buffer[(i + 0) * c_points + p1]; + tri[1] = &POLY_buffer[(i + 0) * c_points + p2]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, page, TRUE); + } + } + } + else + { + // + // Quads between this level and the one above. + // + + for (j = 0; j < c_points; j++) + { + p1 = j + 0; + p2 = j + 1; + + if (p2 == c_points) {p2 = 0;} + + quad[0] = &POLY_buffer[(i + 0) * c_points + p1]; + quad[1] = &POLY_buffer[(i + 0) * c_points + p2]; + quad[2] = &POLY_buffer[(i + 1) * c_points + p1]; + quad[3] = &POLY_buffer[(i + 1) * c_points + p2]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, page, TRUE); + } + } + } + } +} + + +void SHAPE_sphere( + SLONG ix, + SLONG iy, + SLONG iz, + SLONG iradius, + ULONG colour) +{ + SLONG i; + SLONG j; + + SLONG p1; + SLONG p2; + + SLONG index1; + SLONG index2; + SLONG index3; + SLONG index4; + + SLONG line1; + SLONG line2; + + float px; + float py; + float pz; + + float pitch; + float yaw; + + float sx = float(ix); + float sy = float(iy); + float sz = float(iz); + + float sradius = float(iradius); + + float vector[3]; + + POLY_Point pp_top; + POLY_Point pp_bot; + POLY_Point *pp; + POLY_Point *quad[4]; + POLY_Point *tri [3]; + + // + // The top and bottom points. + // + + POLY_transform(sx, sy + sradius, sz, &pp_top); + POLY_transform(sx, sy - sradius, sz, &pp_bot); + + if (!pp_top.IsValid() || !pp_bot.IsValid()) + { + return; + } + + NIGHT_get_d3d_colour( + NIGHT_ambient_at_point(0, +256, 0), + &pp_top.colour, + &pp_top.specular); + + NIGHT_get_d3d_colour( + NIGHT_ambient_at_point(0, -256, 0), + &pp_bot.colour, + &pp_bot.specular); + + pp_top.colour = SHAPE_colour_mult(pp_top.colour, colour); + pp_bot.colour = SHAPE_colour_mult(pp_bot.colour, colour); + + // + // All the points in the middle. + // + + #define SHAPE_SPHERE_NUM_UPDOWN 8 + #define SHAPE_SPHERE_NUM_AROUND 8 + + pp = &POLY_buffer[0]; + + pitch = PI / 2.0F; + + for (i = 1; i < SHAPE_SPHERE_NUM_UPDOWN; i++) + { + pitch -= PI / float(SHAPE_SPHERE_NUM_UPDOWN); + yaw = 0.0F; + + for (j = 0; j < SHAPE_SPHERE_NUM_AROUND; j++) + { + MATRIX_vector( + vector, + yaw, + pitch); + + px = sx + vector[0] * sradius; + py = sy + vector[1] * sradius; + pz = sz + vector[2] * sradius; + + ASSERT(WITHIN(pp, &POLY_buffer[0], &POLY_buffer[POLY_BUFFER_SIZE - 1])); + + POLY_transform( + px, + py, + pz, + pp); + + if (!pp->IsValid()) + { + return; + } + + NIGHT_get_d3d_colour( + NIGHT_ambient_at_point( + SLONG(vector[0] * 256.0F), + SLONG(vector[1] * 256.0F), + SLONG(vector[2] * 256.0F)), + &pp->colour, + &pp->specular); + + pp->colour = SHAPE_colour_mult(pp->colour, colour); + + yaw += 2.0F * PI / float(SHAPE_SPHERE_NUM_AROUND); + pp += 1; + } + } + + // + // The triangles at the top and bottom. + // + + for (i = 0; i < SHAPE_SPHERE_NUM_AROUND; i++) + { + p1 = i; + p2 = i + 1; + + if (p2 == SHAPE_SPHERE_NUM_AROUND) {p2 = 0;} + + // + // Top... + // + + index1 = p1; + index2 = p2; + + tri[0] = &pp_top; + tri[1] = &POLY_buffer[index1]; + tri[2] = &POLY_buffer[index2]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_COLOUR, FALSE); + } + + // + // Bottom... + // + + index1 = p1 + SHAPE_SPHERE_NUM_AROUND * (SHAPE_SPHERE_NUM_UPDOWN - 2); + index2 = p2 + SHAPE_SPHERE_NUM_AROUND * (SHAPE_SPHERE_NUM_UPDOWN - 2); + + tri[0] = &pp_bot; + tri[1] = &POLY_buffer[index1]; + tri[2] = &POLY_buffer[index2]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_COLOUR, FALSE); + } + } + + // + // The quads in the middle. + // + + for (i = 1; i < SHAPE_SPHERE_NUM_UPDOWN - 1; i++) + { + line1 = (i - 1) * SHAPE_SPHERE_NUM_AROUND; + line2 = (i - 0) * SHAPE_SPHERE_NUM_AROUND; + + for (j = 0; j < SHAPE_SPHERE_NUM_AROUND; j++) + { + p1 = j; + p2 = j + 1; + + if (p2 == SHAPE_SPHERE_NUM_AROUND) {p2 = 0;} + + quad[0] = &POLY_buffer[line1 + p1]; + quad[1] = &POLY_buffer[line1 + p2]; + quad[2] = &POLY_buffer[line2 + p1]; + quad[3] = &POLY_buffer[line2 + p2]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE); + } + } + } +} + + +void SHAPE_sparky_line( + SLONG num_points, + SLONG px[], + SLONG py[], + SLONG pz[], + ULONG colour, + float width) +{ + ASSERT(WITHIN(num_points, 2, SHAPE_MAX_SPARKY_POINTS)); + + SLONG i; + + SLONG p1; + SLONG p2; + + float dx; + float dy; + float len; + float overlen; + float size; + + float pnx; + float pny; + SLONG n1_valid; + SLONG n2_valid; + + POLY_Point pp1; + POLY_Point pp2; + + float nx[SHAPE_MAX_SPARKY_POINTS]; + float ny[SHAPE_MAX_SPARKY_POINTS]; + + POLY_Point pp[SHAPE_MAX_SPARKY_POINTS]; + + POLY_Point *quad[4]; + + // + // Transform all the points along the middle of the line. + // + + for (i = 0; i < num_points; i++) + { + POLY_transform( + float(px[i]), + float(py[i]), + float(pz[i]), + &pp[i]); + + pp[i].colour = colour | 0xff000000; + pp[i].specular = 0x00000000; + pp[i].u = 0.0F; + pp[i].v = 0.0F; + } + + // + // Work out the 2d point 'normals' + // + + for (i = 0; i < num_points; i++) + { + if (pp[i].IsValid()) + { + if (i == 0 && width == 20.0F) + { + size = POLY_world_length_to_screen(width * 2.0F) * pp[i].Z; + } + else + if (i == num_points - 1) + { + size = 2.0F; + } + else + { + size = POLY_world_length_to_screen(width) * pp[i].Z; + } + + p1 = i - 1; + p2 = i + 1; + + n1_valid = FALSE; + n2_valid = FALSE; + + if (p1 > 0 && pp[p1].IsValid()) + { + dx = pp[i].X - pp[p1].X; + dy = pp[i].Y - pp[p1].Y; + + // + // Hmm... I guess that .414F is better than 0.500F + // + + len = (fabsf(dx) > fabs(dy)) ? fabs(dx) + 0.414F * fabsf(dy) : fabsf(dy) + 0.414F * fabsf(dx); + overlen = size / len; + + dx *= overlen; + dy *= overlen; + + pnx = -dy; + pny = dx; + + n1_valid = TRUE; + } + + if (p2 < num_points && pp[p2].IsValid()) + { + dx = pp[p2].X - pp[i].X; + dy = pp[p2].Y - pp[i].Y; + + // + // Hmm... I guess that .414F is better than 0.500F + // + + len = (fabsf(dx) > fabsf(dy)) ? fabsf(dx) + 0.414F * fabsf(dy) : fabsf(dy) + 0.414F * fabsf(dx); + overlen = size / len; + + dx *= overlen; + dy *= overlen; + + if (n1_valid) + { + pnx = (pnx + -dy) * 0.5F; + pny = (pny + dx) * 0.5F; + + // + // Normlise (pnx,pny); + // + + len = (fabsf(pnx) > fabsf(pny)) ? fabsf(pnx) + 0.414F * fabsf(pny) : fabsf(pny) + 0.414F * fabsf(pnx); + overlen = size / len; + + pnx *= overlen; + pny *= overlen; + } + else + { + pnx = -dy; + pny = dx; + } + + n2_valid = TRUE; + } + + nx[i] = pnx; + ny[i] = pny; + } + } + + // + // The quads... + // + + for (i = 0; i < num_points - 1; i++) + { + if (pp[i + 0].IsValid() && pp[i + 1].IsValid()) + { + quad[0] = &pp[i + 0]; + quad[1] = &pp[i + 1]; + quad[2] = &pp1; + quad[3] = &pp2; + + // + // The two auxillary points. + // + + pp1 = pp[i + 0]; + pp2 = pp[i + 1]; + + if (!POLY_valid_quad(quad)) + { + continue; + } + + pp1.X += nx[i + 0]; + pp1.Y += ny[i + 0]; + + pp2.X += nx[i + 1]; + pp2.Y += ny[i + 1]; + + UBYTE which=(GAME_TURN+i)&3; + float which_v = (float)which*0.25f; + + pp[i + 0].colour = colour | 0xff000000; + pp[i + 1].colour = colour | 0xff000000; +/* pp1.colour = colour & 0x00ffffff; + pp2.colour = colour & 0x00ffffff;*/ + pp1.colour = colour | 0x00ffffff; + pp2.colour = colour | 0x00ffffff; + + pp[i + 0].u = 0.0f; + pp[i + 0].v = which_v; + pp[i + 1].u = 2.0f; + pp[i + 1].v = which_v; + pp1.u = 0.0f; + pp1.v = which_v+0.25f; + pp2.u = 2.0f; + pp2.v = which_v+0.25f; + + POLY_add_quad(quad, POLY_PAGE_LITE_BOLT, FALSE, true); + +/* pp1.X = pp[i + 0].X + (nx[i + 0] * 0.25F); + pp1.Y = pp[i + 0].Y + (ny[i + 0] * 0.25F); + + pp2.X = pp[i + 1].X + (nx[i + 1] * 0.25F); + pp2.Y = pp[i + 1].Y + (ny[i + 1] * 0.25F); + + pp[i + 0].colour = 0xffffffff; + pp[i + 1].colour = 0xffffffff; + pp1.colour = colour; + pp2.colour = colour; + + POLY_add_quad(quad, POLY_PAGE_ADDITIVE, FALSE, true);*/ + +/* pp1.X = pp[i + 0].X - nx[i + 0]; + pp1.Y = pp[i + 0].Y - ny[i + 0]; + + pp2.X = pp[i + 1].X - nx[i + 1]; + pp2.Y = pp[i + 1].Y - ny[i + 1]; + + pp[i + 0].colour = colour | 0xff000000; + pp[i + 1].colour = colour | 0xff000000; + pp1.colour = colour & 0x00ffffff; + pp2.colour = colour & 0x00ffffff; + + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, true); + + pp1.X = pp[i + 0].X - (nx[i + 0] * 0.25F); + pp1.Y = pp[i + 0].Y - (ny[i + 0] * 0.25F); + + pp2.X = pp[i + 1].X - (nx[i + 1] * 0.25F); + pp2.Y = pp[i + 1].Y - (ny[i + 1] * 0.25F); + + pp[i + 0].colour = 0xffffffff; + pp[i + 1].colour = 0xffffffff; + pp1.colour = colour; + pp2.colour = colour; + + POLY_add_quad(quad, POLY_PAGE_ADDITIVE, FALSE, true);*/ + } + } +} + +void SHAPE_glitter( + SLONG x1, + SLONG y1, + SLONG z1, + SLONG x2, + SLONG y2, + SLONG z2, + ULONG colour) +{ + float dpx; + float dpy; + + float dx = float(x2 - x1); + float dy = float(y2 - y1); + float dz = float(z2 - z1); + + float adpx; + float adpy; + + float len; + float mul; + + float size; + + POLY_Point pp1; + POLY_Point pp2; + + POLY_Point top; + POLY_Point bot; + + POLY_Point *tri[3]; + + POLY_transform( + float(x1), + float(y1), + float(z1), + &pp1); + + if (!pp1.IsValid()) + { + return; + } + + POLY_transform( + float(x2 + dx), + float(y2 + dy), + float(z2 + dz), + &pp2); + + if (!pp2.IsValid()) + { + return; + } + + dpx = pp1.X - pp2.X; + dpy = pp1.Y - pp2.Y; + + adpx = fabs(dpx); + adpy = fabs(dpy); + + if (adpx > adpy) + { + len = adpx + (adpy * 0.5F); + } + else + { + len = adpy + (adpx * 0.5F); + } + + size = POLY_world_length_to_screen(30.0F) * pp1.Z; + mul = size / len; + + dpx *= mul; + dpy *= mul; + + top = pp1; + bot = pp1; + + top.X += dpy; + top.Y -= dpx; + + bot.X -= dpy; + bot.Y += dpx; + + tri[0] = ⊤ + tri[1] = ⊥ + tri[2] = &pp2; + + if (POLY_valid_triangle(tri)) + { + pp2.colour = colour; + pp2.specular = 0xff000000; + pp2.u = 1.0F; + pp2.v = 0.5F; + + top.colour = colour; + top.specular = 0xff000000; + top.u = 0.0F; + top.v = 0.0F; + + bot.colour = colour; + bot.specular = 0xff000000; + bot.u = 0.0F; + bot.v = 1.0F; + + POLY_add_triangle(tri, POLY_PAGE_SPARKLE, FALSE, true); + } +} + +// +// Sets uv coordinates depending on the frame counter. +// + +void SHAPE_tripwire_uvs( + UWORD counter, + float *u1, + float *v1, + float *u2, + float *v2, + float *u3, + float *v3, + float *u4, + float *v4) +{ + float v = float(counter & 0x7fff) * (1.0F / (128.0F * 256.0F)); + + if (counter & 0x8000) + { + *u1 = 0.6F; + *u2 = 0.6F; + *u3 = 0.9F; + *u4 = 0.9F; + } + else + { + *u1 = 0.1F; + *u2 = 0.1F; + *u3 = 0.4F; + *u4 = 0.4F; + } + + *v1 = *v3 = v; + *v2 = *v4 = v + (16.0F / 256.0F); +} + +void SHAPE_tripwire( + SLONG ix1, + SLONG iy1, + SLONG iz1, + SLONG ix2, + SLONG iy2, + SLONG iz2, + SLONG width, + ULONG colour, + UWORD counter, + UBYTE along) +{ + float x1 = float(ix1); + float y1 = float(iy1); + float z1 = float(iz1); + float x2 = float(ix2); + float y2 = float(iy2); + float z2 = float(iz2); + + POLY_Point pp[4]; + POLY_Point *quad[4]; + + float dx = x2 - x1; + float dy = y2 - y1; + float dz = z2 - z1; + + if (along == 0) + { + return; + } + else + if (along != 255) + { + float falong = float(along) * (1.0F / 256.0F); + + // + // Change (x2,y2,z2). + // + + x2 = x1 + dx * falong; + y2 = y1 + dy * falong; + z2 = z1 + dz * falong; + } + + float len; + + if (fabs(dx) > fabs(dz)) + { + len = fabsf(dx) + 0.5F * fabsf(dz); + } + else + { + len = fabsf(dz) + 0.5F * fabsf(dx); + } + + float overlen = float(width) / len; + + dx *= overlen; + dz *= overlen; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + // + // Transform the four point. If any of them fail abandon + // the whole line. + // + + POLY_transform( + x1 + dz, + y1, + z1 - dx, + &pp[0]); + + if (!pp[0].MaybeValid()) + { + return; + } + + POLY_transform( + x1 - dz, + y1, + z1 + dx, + &pp[1]); + + if (!pp[1].MaybeValid()) + { + return; + } + + POLY_transform( + x2 + dz, + y2, + z2 - dx, + &pp[2]); + + if (!pp[2].MaybeValid()) + { + return; + } + + POLY_transform( + x2 - dz, + y2, + z2 + dx, + &pp[3]); + + if (!pp[3].MaybeValid()) + { + return; + } + + if (POLY_valid_quad(quad)) + { + // + // Draw two overlapping lines. + // + + pp[0].colour = colour; + pp[1].colour = colour; + pp[2].colour = colour; + pp[3].colour = colour; + + pp[0].specular = 0x00000000; + pp[1].specular = 0x00000000; + pp[2].specular = 0x00000000; + pp[3].specular = 0x00000000; + + SHAPE_tripwire_uvs( + counter, + &pp[0].u, &pp[0].v, + &pp[1].u, &pp[1].v, + &pp[2].u, &pp[2].v, + &pp[3].u, &pp[3].v); + + POLY_add_quad(quad, POLY_PAGE_FOG, FALSE); + + SHAPE_tripwire_uvs( + 0x2345 - counter, + &pp[0].u, &pp[0].v, + &pp[1].u, &pp[1].v, + &pp[2].u, &pp[2].v, + &pp[3].u, &pp[3].v); + + POLY_add_quad(quad, POLY_PAGE_FOG, FALSE); + } +} + + + + +void SHAPE_waterfall( + SLONG map_x, + SLONG map_z, + SLONG dx, + SLONG dz, + SLONG top, + SLONG bot) +{ + SLONG i; + SLONG y; + ULONG colour; + + SLONG mid_x = (map_x << 8) + 0x80; + SLONG mid_z = (map_z << 8) + 0x80; + + SLONG px1 = mid_x + (dx << 7) + (-dz << 7); + SLONG pz1 = mid_z + (dz << 7) + (+dx << 7); + + SLONG px2 = mid_x + (dx << 7) + (+dz << 7); + SLONG pz2 = mid_z + (dz << 7) + (-dx << 7); + + POLY_Point pp [6]; + POLY_Point *quad[4]; + + for (i = 0; i < 3; i++) + { + switch(i) + { + case 0: y = top; colour = 0xaa4488aa; break; + case 1: y = top - 0x10; colour = 0x884488aa; break; + case 2: y = top - 0x40; colour = 0x004488aa; break; + default: + ASSERT(0); + break; + } + + POLY_transform( + float(px1), + float(y), + float(pz1), + &pp[0 + i]); + + pp[0 + i].colour = colour; + pp[0 + i].specular = 0xff000000; + pp[0 + i].u = 0.0F; + pp[0 + i].v = 0.0F; + + POLY_transform( + float(px2), + float(y), + float(pz2), + &pp[3 + i]); + + pp[3 + i].colour = colour; + pp[3 + i].specular = 0xff000000; + pp[3 + i].u = 0.0F; + pp[3 + i].v = 0.0F; + + px1 -= dx << 4; + pz1 -= dz << 4; + + px2 -= dx << 4; + pz2 -= dz << 4; + } + + quad[0] = &pp[3]; + quad[1] = &pp[0]; + quad[2] = &pp[4]; + quad[3] = &pp[1]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_SEWATER, TRUE); + } + + quad[0] = &pp[4]; + quad[1] = &pp[1]; + quad[2] = &pp[5]; + quad[3] = &pp[2]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_SEWATER, TRUE); + } +} + + + +void SHAPE_droplet( + SLONG x, + SLONG y, + SLONG z, + SLONG dx, + SLONG dy, + SLONG dz, + ULONG colour, + SLONG page) +{ + float dpx; + float dpy; + + float adpx; + float adpy; + + float len; + float mul; + + float size; + + POLY_Point pp1; + POLY_Point pp2; + + POLY_Point top; + POLY_Point bot; + + POLY_Point *tri[3]; + + POLY_flush_local_rot(); + + POLY_transform( + float(x), + float(y), + float(z), + &pp1); + + if (!pp1.IsValid()) + { + return; + } + + POLY_transform( + float(x - dx), + float(y - dy), + float(z - dz), + &pp2); + + if (!pp2.IsValid()) + { + return; + } + + dpx = pp1.X - pp2.X; + dpy = pp1.Y - pp2.Y; + + adpx = fabs(dpx); + adpy = fabs(dpy); + + if (adpx > adpy) + { + len = adpx + (adpy * 0.5F); + } + else + { + len = adpy + (adpx * 0.5F); + } + + size = POLY_world_length_to_screen(10.0F) * pp1.Z; + mul = size / len; + + dpx *= mul; + dpy *= mul; + + top = pp1; + bot = pp1; + + top.X += dpy; + top.Y -= dpx; + + bot.X -= dpy; + bot.Y += dpx; + + tri[0] = ⊤ + tri[1] = ⊥ + tri[2] = &pp2; + + if (POLY_valid_triangle(tri)) + { + pp2.colour = colour; + pp2.specular = 0xff000000; + pp2.u = 1.0F; + pp2.v = 0.5F; + + top.colour = colour; + top.specular = 0xff000000; + top.u = 0.0F; + top.v = 0.0F; + + bot.colour = colour; + bot.specular = 0xff000000; + bot.u = 0.0F; + bot.v = 1.0F; + + POLY_add_triangle(tri, page, FALSE, TRUE); + } +} + + +// +// Draws a cylindrical shadow +// + +void SHADOW_cylindrical_shadow(float px, float py, float pz, float radius, float length) +{ + POLY_Point pp [6]; + POLY_Point *quad[4]; + + POLY_transform( + px - radius * -0.707F, + py + 2.0F, + pz - radius * -0.707F, + &pp[0], + TRUE); + + if (!pp[0].IsValid()) + { + return; + } + + POLY_transform( + px - radius * +0.707F, + py + 2.0F, + pz - radius * +0.707F, + &pp[1]); + + if (!pp[1].IsValid()) + { + return; + } + + POLY_transform( + px - radius * -0.707F + length * +0.707F, + py + 2.0F, + pz - radius * -0.707F + length * -0.707F, + &pp[2]); + + if (!pp[2].IsValid()) + { + return; + } + + POLY_transform( + px - radius * +0.707F + length * +0.707F, + py + 2.0F, + pz - radius * +0.707F + length * -0.707F, + &pp[3]); + + if (!pp[3].IsValid()) + { + return; + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + if (POLY_valid_quad(quad)) + { + pp[0].colour = 0x88000000; + pp[0].specular = 0xff000000; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].Z += DC_SHADOW_Z_ADJUST; + + pp[1].colour = 0x88000000; + pp[1].specular = 0xff000000; + pp[1].u = 0.0F; + pp[1].v = 0.0F; + pp[1].Z += DC_SHADOW_Z_ADJUST; + + pp[2].colour = 0x00000000; + pp[2].specular = 0xff000000; + pp[2].u = 0.0F; + pp[2].v = 0.0F; + pp[2].Z += DC_SHADOW_Z_ADJUST; + + pp[3].colour = 0x00000000; + pp[3].specular = 0xff000000; + pp[3].u = 0.0F; + pp[3].v = 0.0F; + pp[3].Z += DC_SHADOW_Z_ADJUST; + + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE); + } +} + + + + +void SHAPE_prim_shadow(OB_Info *oi) +{ + POLY_Point pp [6]; + POLY_Point *quad[4]; + + #define SHAPE_PRIM_SHADOW_RADIUS (24.0F) + #define SHAPE_PRIM_SHADOW_LENGTH (128.0F) + + float px = float(oi->x); + float py = float(oi->y); + float pz = float(oi->z); + + SLONG i; + + PrimInfo *pi; + + float angle; + + float sin_yaw; + float cos_yaw; + + float matrix[4]; + + float wx; + float wz; + + struct + { + float x; + float z; + + } world[4]; + + UBYTE order[3]; + + POLY_Point *pp_upto; + + switch(prim_get_shadow_type(oi->prim)) + { + case PRIM_SHADOW_NONE: + return; + + case PRIM_SHADOW_CYLINDER: + + // + // Circular shadow. + // + + SHADOW_cylindrical_shadow( + px, py, pz, + SHAPE_PRIM_SHADOW_RADIUS, + SHAPE_PRIM_SHADOW_LENGTH); + + break; + + case PRIM_SHADOW_FULLBOX: + + // + // A shadow of shadow under the prim. + // + + pi = get_prim_info(oi->prim); + + angle = float(-oi->yaw) * (2.0F * PI / 2048.0F); + + sin_yaw = sin(angle); + cos_yaw = cos(angle); + + matrix[0] = cos_yaw; + matrix[1] = -sin_yaw; + matrix[2] = sin_yaw; + matrix[3] = cos_yaw; + + for (i = 0; i < 4; i++) + { + wx = (i & 0x1) ? float(pi->maxx) : float(pi->minx); + wz = (i & 0x2) ? float(pi->maxz) : float(pi->minz); + + world[i].x = wx * matrix[0] + wz * matrix[1]; + world[i].z = wx * matrix[2] + wz * matrix[3]; + + world[i].x += px; + world[i].z += pz; + + POLY_transform( + world[i].x, + py, + world[i].z, + &pp[i], + TRUE); + + if (!pp[i].MaybeValid()) + { + // + // Abandon the prim shadow. + // + + return; + } + + pp[i].colour = 0x88000000; + pp[i].specular = 0xff000000; + pp[i].u = 0.0F; + pp[i].v = 0.0F; + pp[i].Z += DC_SHADOW_Z_ADJUST; + + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE); + } + + // + // FALLTHROUGH! + // + + case PRIM_SHADOW_BOXEDGE: + + // + // Bounding box shadow. + // + + if (prim_get_shadow_type(oi->prim) == PRIM_SHADOW_FULLBOX) + { + // + // We've fallen through from the case: above... + // no need to work out this stuff. + // + } + else + { + pi = get_prim_info(oi->prim); + + angle = float(-oi->yaw) * (2.0F * PI / 2048.0F); + + sin_yaw = sin(angle); + cos_yaw = cos(angle); + + matrix[0] = cos_yaw; + matrix[1] = -sin_yaw; + matrix[2] = sin_yaw; + matrix[3] = cos_yaw; + + for (i = 0; i < 4; i++) + { + wx = (i & 0x1) ? float(pi->maxx) : float(pi->minx); + wz = (i & 0x2) ? float(pi->maxz) : float(pi->minz); + + world[i].x = wx * matrix[0] + wz * matrix[1]; + world[i].z = wx * matrix[2] + wz * matrix[3]; + + world[i].x += px; + world[i].z += pz; + } + } + + switch(((oi->yaw + 256) & 2047) >> 9) + { + case 0: order[0] = 0; order[1] = 1; order[2] = 3; break; + case 1: order[0] = 1; order[1] = 3; order[2] = 2; break; + case 2: order[0] = 3; order[1] = 2; order[2] = 0; break; + case 3: order[0] = 2; order[1] = 0; order[2] = 1; break; + + default: + ASSERT(0); + break; + } + + pp_upto = &pp[0]; + + for (i = 0; i < 3; i++) + { + POLY_transform( + world[order[i]].x, + py + 2.0F, + world[order[i]].z, + pp_upto, + TRUE); + + if (!pp_upto->MaybeValid()) + { + return; + } + + pp_upto->colour = 0x88000000; + pp_upto->specular = 0xff000000; + pp_upto->u = 0.0F; + pp_upto->v = 0.0F; + pp_upto->Z += DC_SHADOW_Z_ADJUST; + + pp_upto++; + + POLY_transform( + world[order[i]].x + SHAPE_PRIM_SHADOW_LENGTH * +0.707F, + py + 2.0F, + world[order[i]].z + SHAPE_PRIM_SHADOW_LENGTH * -0.707F, + pp_upto); + + if (!pp_upto->MaybeValid()) + { + return; + } + + pp_upto->colour = 0x00000000; + pp_upto->specular = 0xff000000; + pp_upto->u = 0.0F; + pp_upto->v = 0.0F; + pp_upto->Z += DC_SHADOW_Z_ADJUST; + + pp_upto++; + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE); + } + + quad[0] = &pp[2]; + quad[1] = &pp[3]; + quad[2] = &pp[4]; + quad[3] = &pp[5]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE); + } + + break; + + case PRIM_SHADOW_FOURLEGS: + + // + // Find the four corner points of the prim. + // + + pi = get_prim_info(oi->prim); + + angle = float(-oi->yaw) * (2.0F * PI / 2048.0F); + + sin_yaw = sin(angle); + cos_yaw = cos(angle); + + matrix[0] = cos_yaw; + matrix[1] = -sin_yaw; + matrix[2] = sin_yaw; + matrix[3] = cos_yaw; + + for (i = 0; i < 4; i++) + { + wx = (i & 0x1) ? float(pi->maxx) : float(pi->minx); + wz = (i & 0x2) ? float(pi->maxz) : float(pi->minz); + + world[i].x = wx * matrix[0] + wz * matrix[1]; + world[i].z = wx * matrix[2] + wz * matrix[3]; + + world[i].x += px; + world[i].z += pz; + } + + // + // Draw a circular shadow at each corner. + // + + for (i = 0; i < 4; i++) + { + SHADOW_cylindrical_shadow( + world[i].x, + py, + world[i].z, + SHAPE_PRIM_SHADOW_RADIUS, + SHAPE_PRIM_SHADOW_LENGTH); + } + + break; + + default: + ASSERT(0); + break; + } +} + + +void SHAPE_alpha_sphere( + SLONG ix, + SLONG iy, + SLONG iz, + SLONG iradius, + ULONG colour, + ULONG alpha) +{ + SLONG i; + SLONG j; + + SLONG p1; + SLONG p2; + + SLONG index1; + SLONG index2; + SLONG index3; + SLONG index4; + + SLONG line1; + SLONG line2; + + float px; + float py; + float pz; + + float pitch; + float yaw; + + float sx = float(ix); + float sy = float(iy); + float sz = float(iz); + + float sradius = float(iradius); + + float vector[3]; + + POLY_Point pp_top; + POLY_Point pp_bot; + POLY_Point *pp; + POLY_Point *quad[4]; + POLY_Point *tri [3]; + + // + // The top and bottom points. + // + + POLY_transform(sx, sy + sradius, sz, &pp_top); + POLY_transform(sx, sy - sradius, sz, &pp_bot); + + if (!pp_top.MaybeValid() || !pp_bot.MaybeValid()) + { + return; + } + + NIGHT_get_d3d_colour( + NIGHT_ambient_at_point(0, +256, 0), + &pp_top.colour, + &pp_top.specular); + + NIGHT_get_d3d_colour( + NIGHT_ambient_at_point(0, -256, 0), + &pp_bot.colour, + &pp_bot.specular); + + pp_top.colour = SHAPE_colour_mult(pp_top.colour, colour); + pp_bot.colour = SHAPE_colour_mult(pp_bot.colour, colour); + + pp_top.colour |= alpha; + pp_bot.colour |= alpha; + + // + // All the points in the middle. + // + + #define SHAPE_SPHERE_NUM_UPDOWN 8 + #define SHAPE_SPHERE_NUM_AROUND 8 + + pp = &POLY_buffer[0]; + + pitch = PI / 2.0F; + + for (i = 1; i < SHAPE_SPHERE_NUM_UPDOWN; i++) + { + pitch -= PI / float(SHAPE_SPHERE_NUM_UPDOWN); + yaw = 0.0F; + + for (j = 0; j < SHAPE_SPHERE_NUM_AROUND; j++) + { + MATRIX_vector( + vector, + yaw, + pitch); + + px = sx + vector[0] * sradius; + py = sy + vector[1] * sradius; + pz = sz + vector[2] * sradius; + + ASSERT(WITHIN(pp, &POLY_buffer[0], &POLY_buffer[POLY_BUFFER_SIZE - 1])); + + POLY_transform( + px, + py, + pz, + pp); + + if (!pp->MaybeValid()) + { + return; + } + + NIGHT_get_d3d_colour( + NIGHT_ambient_at_point( + SLONG(vector[0] * 256.0F), + SLONG(vector[1] * 256.0F), + SLONG(vector[2] * 256.0F)), + &pp->colour, + &pp->specular); + + pp->colour = SHAPE_colour_mult(pp->colour, colour); + pp->colour |= alpha; + + yaw += 2.0F * PI / float(SHAPE_SPHERE_NUM_AROUND); + pp += 1; + } + } + + // + // The triangles at the top and bottom. + // + + for (i = 0; i < SHAPE_SPHERE_NUM_AROUND; i++) + { + p1 = i; + p2 = i + 1; + + if (p2 == SHAPE_SPHERE_NUM_AROUND) {p2 = 0;} + + // + // Top... + // + + index1 = p1; + index2 = p2; + + tri[0] = &pp_top; + tri[1] = &POLY_buffer[index1]; + tri[2] = &POLY_buffer[index2]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_ALPHA, FALSE); + } + + // + // Bottom... + // + + index1 = p1 + SHAPE_SPHERE_NUM_AROUND * (SHAPE_SPHERE_NUM_UPDOWN - 2); + index2 = p2 + SHAPE_SPHERE_NUM_AROUND * (SHAPE_SPHERE_NUM_UPDOWN - 2); + + tri[0] = &pp_bot; + tri[1] = &POLY_buffer[index1]; + tri[2] = &POLY_buffer[index2]; + + if (POLY_valid_triangle(tri)) + { + POLY_add_triangle(tri, POLY_PAGE_ALPHA, FALSE); + } + } + + // + // The quads in the middle. + // + + for (i = 1; i < SHAPE_SPHERE_NUM_UPDOWN - 1; i++) + { + line1 = (i - 1) * SHAPE_SPHERE_NUM_AROUND; + line2 = (i - 0) * SHAPE_SPHERE_NUM_AROUND; + + for (j = 0; j < SHAPE_SPHERE_NUM_AROUND; j++) + { + p1 = j; + p2 = j + 1; + + if (p2 == SHAPE_SPHERE_NUM_AROUND) {p2 = 0;} + + quad[0] = &POLY_buffer[line1 + p1]; + quad[1] = &POLY_buffer[line1 + p2]; + quad[2] = &POLY_buffer[line2 + p1]; + quad[3] = &POLY_buffer[line2 + p2]; + + if (POLY_valid_quad(quad)) + { + POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE); + } + } + } +} + + + +#ifndef TARGET_DC +ULONG SHAPE_balloon_colour; + +void SHAPE_draw_balloon(SLONG balloon) +{ + SLONG i; + + POLY_Point pp[BALLOON_POINTS_PER_BALLOON]; + + ASSERT(WITHIN(balloon, 1, BALLOON_balloon_upto - 1)); + + BALLOON_Balloon *bb; + + bb = &BALLOON_balloon[balloon]; + + for (i = 0; i < BALLOON_POINTS_PER_BALLOON - 1; i++) + { + AENG_world_line( + bb->bp[i + 0].x >> 8, + bb->bp[i + 0].y >> 8, + bb->bp[i + 0].z >> 8, + 4, 0x558845, + bb->bp[i + 1].x >> 8, + bb->bp[i + 1].y >> 8, + bb->bp[i + 1].z >> 8, + 4, 0x558845, + FALSE); + } + + static ULONG balloon_colours[4] = {0xffff0000, 0xffffff00, 0xff00ff00, 0xff0000ff}; + + SHAPE_balloon_colour = balloon_colours[balloon & 3]; + + MESH_draw_poly( + PRIM_OBJ_BALLOON, + bb->bp[BALLOON_POINTS_PER_BALLOON - 1].x >> 8, + bb->bp[BALLOON_POINTS_PER_BALLOON - 1].y >> 8, + bb->bp[BALLOON_POINTS_PER_BALLOON - 1].z >> 8, + bb->yaw, bb->pitch, 0, NULL,0xff); + + +} +#endif diff --git a/fallen/DDEngine/Source/sky.cpp b/fallen/DDEngine/Source/sky.cpp new file mode 100644 index 0000000..249eff7 --- /dev/null +++ b/fallen/DDEngine/Source/sky.cpp @@ -0,0 +1,1195 @@ +// +// Sky... +// + +#include +#include +#include "game.h" +#include "matrix.h" +#include "poly.h" +#include "aeng.h" +#include +#include "cam.h" + + + +#define SKY_STAR_T_DIM 1 +#define SKY_STAR_T_MEDIUM 2 +#define SKY_STAR_T_BRIGHT 3 +#define SKY_STAR_T_PLANET 4 + +#ifndef TARGET_DC +typedef struct +{ + UBYTE colour; + UBYTE spread; + UWORD shit; + float yaw; + float pitch; + float vector[3]; + +} SKY_Star; + +#define SKY_MAX_STARS 4096 + +SKY_Star SKY_star[SKY_MAX_STARS]; +SLONG SKY_star_upto; + +// +// Each cloud texture... +// + + +typedef struct +{ + float u1, v1; + float u2, v2; + +} SKY_Texture; + +#define SKY_NUM_TEXTURES 5 + +SKY_Texture SKY_texture[SKY_NUM_TEXTURES] = +{ + {0.000F, 0.000F, 1.000F, 0.234F}, + {0.000F, 0.234F, 0.566F, 0.375F}, + {0.566F, 0.234F, 1.000F, 0.375F}, + {0.000F, 0.375F, 1.000F, 0.648F}, + {0.000F, 0.648F, 1.000F, 1.000F} +}; + + +typedef struct +{ + UBYTE texture; + UBYTE flip; // 1 => Reflect the cloud texture in u. + UBYTE width; + UBYTE height; + float yaw; + float pitch; + float dyaw; + +} SKY_Cloud; + +#define SKY_NUM_CLOUDS 200 + +SKY_Cloud SKY_cloud[SKY_NUM_CLOUDS]; + +#endif + + + +#define SKY_wibble_y1 62 +#define SKY_wibble_y2 137 +#define SKY_wibble_g1 17 +#define SKY_wibble_g2 78 +#define SKY_wibble_s1 40 +#define SKY_wibble_s2 45 + + + + + +void SKY_init(CBYTE *star_file) +{ + +#ifndef TARGET_DC + + SLONG i; + + float twidth; + float theight; + + SLONG yaw; + SLONG pitch; + SLONG bright; + SLONG red; + SLONG green; + SLONG blue; + ULONG colour; + ULONG spread; + SLONG match; + + FILE *handle; + + CBYTE line[128]; + + SKY_Cloud *sc; + SKY_Texture *st; + + // + // Create all the clouds. + // + + for (i = 0; i < SKY_NUM_CLOUDS; i++) + { + sc = &SKY_cloud[i]; + + sc->texture = rand() % SKY_NUM_TEXTURES; + sc->flip = rand() & 0x8; + sc->yaw = (float(rand()) / float(RAND_MAX)) * (2.0F * PI); + sc->pitch = (float(rand()) / float(RAND_MAX)) * (PI / 3.0F) + (PI / 64.0F); + sc->dyaw = (float(rand()) / float(RAND_MAX)) * 0.0005F + 0.0001F; + + ASSERT(WITHIN(sc->texture, 0, SKY_NUM_TEXTURES - 1)); + + st = &SKY_texture[sc->texture]; + + twidth = (st->u2 - st->u1) * 256.0F; + theight = (st->v2 - st->v1) * 256.0F; + + // + // Randomise the height and width of the cloud, but always make the + // texels more than one pixel so we get the benefit of filtering. + // + + twidth *= 0.3F + (float(rand()) * 0.5F / float(RAND_MAX)); + theight *= 0.3F + (float(rand()) * 0.5F / float(RAND_MAX)); + + sc->width = UBYTE(twidth); + sc->height = UBYTE(theight); + } + + // + // Place down the stars. + // + + if (star_file == NULL) + { + handle = NULL; + } + else + { + handle = MF_Fopen(star_file, "rb"); + } + + if (handle == NULL) + { + // + // Randomly generate the stars... + // + + for (i = 0; i < SKY_MAX_STARS; i++) + { + yaw = rand() % 360; + pitch = rand() % 60; + pitch += 10; + + bright = rand() % (pitch + 0x3f); + bright += 0x1f; + + SKY_star[i].colour = bright; + SKY_star[i].spread = (bright < 100) ? 0 : bright >> 2; + SKY_star[i].yaw = float(yaw) * 2.0F * PI / 360.0F; + SKY_star[i].pitch = float(pitch) * 2.0F * PI / 360.0F; + } + + SKY_star_upto = SKY_MAX_STARS; + } + else + { + SKY_star_upto = 0; + + while(fgets(line, 128, handle)) + { + if (SKY_star_upto >= SKY_MAX_STARS) + { + // + // Can't read in any more stars. + // + + break; + } + + match = sscanf(line, "Star: %d, %d, %d", &yaw, &pitch, &bright); + + if (match == 3) + { + // + // Make sure that the brightness isn't out of range. + // + + SATURATE(bright, 0, 255); + + SKY_star[SKY_star_upto].colour = bright; + SKY_star[SKY_star_upto].spread = (bright < 100) ? 0 : bright >> 2; + SKY_star[SKY_star_upto].yaw = float(yaw) * 2.0F * PI / 2048.0F; + SKY_star[SKY_star_upto].pitch = float(pitch) * 2.0F * PI / 2048.0F; + + SKY_star_upto += 1; + } + } + + MF_Fclose(handle); + } + + // + // London, England. + // + + SKY_Star *ss; + + float dpitch = 39.0F * 2.0F * PI / 360.0F; + + for (i = 0; i < SKY_star_upto; i++) + { + ss = &SKY_star[i]; + + MATRIX_vector( + ss->vector, + ss->yaw, + ss->pitch + dpitch); + } +#endif +} + + +#ifndef TARGET_DC +void SKY_draw_stars( + float mid_x, // The world camera position + float mid_y, + float mid_z, + float max_dist) // How far away anything is drawn. +{ + SLONG i; + + float yaw; + float pitch; + + SVector_F temp; + SVector_F pos; + POLY_Point pp; + + SKY_Star *ss; + + float xmul = float(RealDisplayWidth) / float(DisplayWidth); + float ymul = float(RealDisplayHeight) / float(DisplayHeight); + + for (i = 0; i < SKY_star_upto; i++) + { + ss = &SKY_star[i]; + + // + // Draw it. + // + + #define SKY_STAR_DIST (max_dist - 256.0F) + + temp.X = ss->vector[0] * SKY_STAR_DIST + mid_x; + temp.Y = ss->vector[1] * SKY_STAR_DIST + (mid_y * 0.5F); + temp.Z = ss->vector[2] * SKY_STAR_DIST + mid_z; + + POLY_transform( + temp.X, + temp.Y, + temp.Z, + &pp); + + if (!(pp.clip & (POLY_CLIP_LEFT | POLY_CLIP_RIGHT | POLY_CLIP_TOP | POLY_CLIP_BOTTOM | POLY_CLIP_NEAR | POLY_CLIP_FAR))) + { + SLONG px = SLONG(pp.X * xmul); + SLONG py = SLONG(pp.Y * ymul); + + if ((rand() & 0x7f) == (i & 0x7f)) + { + // + // Make the star twinkle! + // + } + else + { + the_display.PlotPixel( + px, py, + ss->colour, + ss->colour, + ss->colour); + + if (ss->spread) + { + ULONG col = the_display.GetFormattedPixel(ss->spread, ss->spread, ss->spread); + + the_display.PlotFormattedPixel(px - 1, py, col); + the_display.PlotFormattedPixel(px + 1, py, col); + the_display.PlotFormattedPixel(px, py - 1, col); + the_display.PlotFormattedPixel(px, py + 1, col); + } + } + } + } +} +#endif + +#ifndef TARGET_DC +void SKY_draw_poly_clouds( + float mid_x, + float mid_y, + float mid_z, + float max_dist) +{ + + SLONG i; + SLONG j; + + float yaw; + float pitch; + float vector[3]; + + SVector_F temp; + SVector_F pos; + ULONG flag; + + float screen_width = float(DisplayWidth); + float screen_height = float(DisplayHeight); + + float width; + float height; + + SKY_Cloud *sc; + SKY_Texture *st; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + // + // Draw and animate the cloud quads. + // + + #define SKY_CLOUD_DIST (max_dist - 512.0F) + + for (i = 0; i < SKY_NUM_CLOUDS; i++) + { + sc = &SKY_cloud[i]; + + // + // Animate it. + // + + sc->yaw += sc->dyaw; + + // + // Draw it. + // + + yaw = sc->yaw; + pitch = sc->pitch; + + MATRIX_vector( + vector, + yaw, + pitch); + + temp.X = vector[0] * SKY_CLOUD_DIST + mid_x; + temp.Y = vector[1] * SKY_CLOUD_DIST + mid_y * 0.5F; + temp.Z = vector[2] * SKY_CLOUD_DIST + mid_z; + + POLY_transform( + temp.X, + temp.Y, + temp.Z, + &mid); + + if (!mid.IsValid()) + { + // + // Abandon this cloud. + // + + continue; + } + + width = float(sc->width); + height = float(sc->height); + + if (mid.X + width < 0 || mid.X - width > screen_width || + mid.Y + height < 0 || mid.Y - width > screen_height) + { + // + // Abandon this cloud. + // + + continue; + } + + // + // The very end of the zbuffer... + // + + #define SKY_VERY_FAR_AWAY (1.0F / 65536.0F) + + mid.Z = SKY_VERY_FAR_AWAY; + mid.colour = 0xff333333 + 0x00010101 * SLONG(sc->dyaw * (128.0F / 0.0005F));; + mid.specular = 0x000000; + + for (j = 0; j < 4; j++) + { + pp[j] = mid; + + pp[j].X += (j & 1) ? width : -width; + pp[j].Y += (j >> 1) ? height : -height; + } + + // + // The sky texture. + // + + SKY_Texture *st; + + ASSERT(WITHIN(sc->texture, 0, SKY_NUM_TEXTURES - 1)); + + st = &SKY_texture[sc->texture]; + + if (sc->flip) + { + pp[0].u = st->u1; + pp[0].v = st->v1; + pp[1].u = st->u2; + pp[1].v = st->v1; + pp[2].u = st->u1; + pp[2].v = st->v2; + pp[3].u = st->u2; + pp[3].v = st->v2; + } + else + { + pp[0].u = st->u2; + pp[0].v = st->v1; + pp[1].u = st->u1; + pp[1].v = st->v1; + pp[2].u = st->u2; + pp[2].v = st->v2; + pp[3].u = st->u1; + pp[3].v = st->v2; + } + + POLY_add_quad(quad, POLY_PAGE_CLOUDS, FALSE, TRUE); + } + + return; +} +#endif + + + + + +void SKY_draw_poly_moon( + float mid_x, + float mid_y, + float mid_z, + float max_dist) +{ + static SLONG on_screen_for = 0; + static SLONG last_cam_dyaw = 0; + static SLONG last_cam_dpitch = 0; + static SLONG draw_man = 0; + + SLONG i; + SLONG j; + + float yaw; + float pitch; + float vector[3]; + + SVector_F temp; + SVector_F pos; + ULONG flag; + + float screen_width = float(DisplayWidth); + float screen_height = float(DisplayHeight); + + float width; + float height; + + //SKY_Cloud *sc; + //SKY_Texture *st; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + // + // Create the moon quad. + // + + #define SKY_MOON_YAW (0) + #define SKY_MOON_PITCH (PI / 8.0F) + #define SKY_MOON_DIST (max_dist - 128.0F) +#ifdef TARGET_DC + // This is slightly more sensible. + #define SKY_MOON_RADIUS (screen_width * 0.09F) +#else + // This is hooooooooooj. + #define SKY_MOON_RADIUS (screen_width * 0.15F) +#endif + #define SKY_MOON_UV_IN (0.02F) + + const struct + { + float u; + float v; + + } moon_uv[4] = + { + { SKY_MOON_UV_IN, SKY_MOON_UV_IN}, + {1.0F - SKY_MOON_UV_IN, SKY_MOON_UV_IN}, + { SKY_MOON_UV_IN, 1.0F - SKY_MOON_UV_IN}, + {1.0F - SKY_MOON_UV_IN, 1.0F - SKY_MOON_UV_IN} + }; + + yaw = SKY_MOON_YAW; + pitch = SKY_MOON_PITCH; + + MATRIX_vector( + vector, + yaw, + pitch); + + temp.X = vector[0] * SKY_MOON_DIST + mid_x; + temp.Y = vector[1] * SKY_MOON_DIST + mid_y * 0.5f; + temp.Z = vector[2] * SKY_MOON_DIST + mid_z; + + +#ifdef TARGET_DC + // Workaround. + POLY_flush_local_rot(); +#endif + + POLY_transform( + temp.X, + temp.Y, + temp.Z, + &mid); + + if (!mid.IsValid()) + { + // + // Abandon the moon. - you can't see the whole of it + // + + on_screen_for = 0; + } + else + { + if (mid.X + SKY_MOON_RADIUS < 0 || mid.X - SKY_MOON_RADIUS > screen_width || + mid.Y + SKY_MOON_RADIUS < 0 || mid.Y - SKY_MOON_RADIUS > screen_height) + { + // + // Abandon the moon. + // + + on_screen_for = 0; + } + else + { +#ifdef TARGET_DC + // Got to get it just in front of the sky, but behind the far facets. + mid.Z = 0.001f; + mid.z = 0.999f; +#else + mid.Z = SKY_VERY_FAR_AWAY; +#endif + mid.colour = 0xffaaaa88; + mid.specular = 0x00000000; + + for (j = 0; j < 4; j++) + { + pp[j] = mid; + + pp[j].X += (j & 1) ? SKY_MOON_RADIUS : -SKY_MOON_RADIUS; + pp[j].Y += (j >> 1) ? SKY_MOON_RADIUS : -SKY_MOON_RADIUS; + + pp[j].u = moon_uv[j].u; + pp[j].v = moon_uv[j].v; + } + + POLY_add_quad(quad, POLY_PAGE_MOON, FALSE, TRUE); + + on_screen_for += 1; + +#if 0 +// This no longer works. + if (draw_man) + { + // + // Fade in and out. + // + + SLONG man_alpha; + SLONG man_colour; + + if (draw_man > 120) + { + man_alpha = 180 - draw_man; + } + else + if (draw_man < 60) + { + man_alpha = draw_man; + } + else + { + man_alpha = 60; + } + + man_colour = (man_alpha << 24) | 0x00ffffff; + + // + // Set the new colours. + // + + for (j = 0; j < 4; j++) + { + pp[j].colour = man_colour; + } + + // + // Draw the man on the moon. + // + + POLY_add_quad(quad, POLY_PAGE_MANONMOON, FALSE, TRUE); + } +#endif + } + } + +#if 0 +// No longer works. + + // + // Is the player looking at the moon? + // +#ifdef CAM_OLD + if (CAM_get_mode() == CAM_MODE_FIRST_PERSON) + { + SLONG cam_dyaw; + SLONG cam_dpitch; + + CAM_get_dangle(&cam_dyaw, &cam_dpitch); + + if (cam_dyaw == last_cam_dyaw && + cam_dpitch == last_cam_dpitch) + { + if (on_screen_for == 200) + { + draw_man = 180; + } + } + else + { + on_screen_for = 0; + } + + last_cam_dyaw = cam_dyaw; + last_cam_dpitch = cam_dpitch; + } + else +#endif + { + on_screen_for = 0; + } + + if (draw_man > 0) + { + draw_man -= 1; + } +#endif + + return; +} + + + +#ifndef TARGET_DC +SLONG SKY_draw_moon_reflection( + float mid_x, + float mid_y, + float mid_z, + float max_dist, + float *moon_x1, + float *moon_y1, + float *moon_x2, + float *moon_y2) +{ + + SLONG i; + SLONG j; + + float x; + float y; + float v; + + float yaw; + float pitch; + float vector[3]; + + SVector_F temp; + SVector_F pos; + ULONG flag; + + float screen_width = float(DisplayWidth); + float screen_height = float(DisplayHeight); + + float width; + float height; + + //SKY_Cloud *sc; + //SKY_Texture *st; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + + SLONG angle1; + SLONG angle2; + SLONG offset1; + SLONG offset2; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + + // + // Create the moon quad. + // + + const struct + { + float u; + float v; + + } moon_uv[4] = + { + { SKY_MOON_UV_IN, SKY_MOON_UV_IN}, + {1.0F - SKY_MOON_UV_IN, SKY_MOON_UV_IN}, + { SKY_MOON_UV_IN, 1.0F - SKY_MOON_UV_IN}, + {1.0F - SKY_MOON_UV_IN, 1.0F - SKY_MOON_UV_IN} + }; + + yaw = SKY_MOON_YAW; + pitch = SKY_MOON_PITCH; + + MATRIX_vector( + vector, + yaw, + pitch); + + temp.X = vector[0] * SKY_MOON_DIST + mid_x; + temp.Y = -vector[1] * SKY_MOON_DIST + mid_y * 0.5f; + temp.Z = vector[2] * SKY_MOON_DIST + mid_z; + + POLY_transform( + temp.X, + temp.Y, + temp.Z, + &mid); + + if (!mid.IsValid()) + { + // + // Abandon the moon. + // + + return FALSE; + } + else + { + if (mid.X + SKY_MOON_RADIUS < 8 || mid.X - SKY_MOON_RADIUS > screen_width + 8 || + mid.Y + SKY_MOON_RADIUS < 8 || mid.Y - SKY_MOON_RADIUS > screen_height + 8) + { + // + // Abandon the moon. + // + + return FALSE; + } + else + { +#ifdef TARGET_DC + mid.Z = 0.9999f; + mid.z = 0.0001f; +#else + mid.Z = SKY_VERY_FAR_AWAY; +#endif + mid.colour = 0xffaaaa88; + mid.specular = 0x00000000; + + #define SKY_MOON_SEGMENTS 16 + + y = mid.Y - SKY_MOON_RADIUS; + v = moon_uv[0].v; + + // + // What's the first lines' wibble? + // + + angle1 = SLONG(y) * SKY_wibble_y1; + angle2 = SLONG(y) * SKY_wibble_y2; + angle1 += GAME_TURN * SKY_wibble_g1; + angle2 += GAME_TURN * SKY_wibble_g2; + + angle1 &= 2047; + angle2 &= 2047; + + offset2 = SIN(angle1) * SKY_wibble_s1 >> 19; + offset2 += COS(angle2) * SKY_wibble_s2 >> 19; + + // + // The amount of 'y' and 'v' in each segment. + // + + #define SKY_MOON_SEG_DY (float(SKY_MOON_RADIUS) / float(SKY_MOON_SEGMENTS)) + #define SKY_MOON_SEG_DV ((moon_uv[2].v - moon_uv[0].v) / float(SKY_MOON_SEGMENTS)) + + for (i = 0; i < SKY_MOON_SEGMENTS; i++) + { + offset1 = offset2; + + // + // What's the next lines' wibble? + // + + angle1 = SLONG(y + SKY_MOON_SEG_DY) * SKY_wibble_y1; + angle2 = SLONG(y + SKY_MOON_SEG_DY) * SKY_wibble_y2; + angle1 += GAME_TURN * SKY_wibble_g1; + angle2 += GAME_TURN * SKY_wibble_g2; + + angle1 &= 2047; + angle2 &= 2047; + + offset2 = SIN(angle1) * SKY_wibble_s1 >> 19; + offset2 += COS(angle2) * SKY_wibble_s2 >> 19; + + for (j = 0; j < 4; j++) + { + pp[j] = mid; + + pp[j].X += (j & 1) ? SKY_MOON_RADIUS : -SKY_MOON_RADIUS; + pp[j].u = moon_uv[j].u; + + if (j & 2) + { + pp[j].Y = y + SKY_MOON_SEG_DY; + pp[j].v = v + SKY_MOON_SEG_DV; + pp[j].X += offset2; + } + else + { + pp[j].Y = y; + pp[j].v = v; + pp[j].X += offset1; + } + } + + POLY_add_quad(quad, POLY_PAGE_MOON, FALSE, TRUE); + + if (i == 0) + { + *moon_x1 = pp[0].X; + *moon_y1 = pp[2].Y; + } + + if (i == SKY_MOON_SEGMENTS - 1) + { + *moon_x2 = pp[1].X; + *moon_y2 = pp[0].Y; + } + + y += SKY_MOON_SEG_DY; + v += SKY_MOON_SEG_DV; + } + } + } + + return TRUE; +} +#endif //#ifndef TARGET_DC + + +#ifndef TARGET_DC +void SKY_draw_poly_sky( + float world_camera_x, + float world_camera_y, + float world_camera_z, + float world_camera_yaw, + float max_dist, + ULONG bot_colour, + ULONG top_colour) +{ + float px; + float py; + float pz; + + float screen_x; + float screen_y; + + float vector[3]; + + MATRIX_vector( + vector, + world_camera_yaw, + 0.0F); + + px = world_camera_x + vector[0] * max_dist; + py = -256.0F; + pz = world_camera_z + vector[2] * max_dist; + + if (!POLY_get_screen_pos( + px, py, pz, + &screen_x, + &screen_y)) + { + // + // Can't see the horizon. + // + + return; + } + + POLY_Point pp [4]; + POLY_Point *quad[4]; + + pp[0].X = 0.0F; + pp[0].Y = screen_y - 256.0F; + pp[0].Z = 0.5F; + pp[0].z = 0.5F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = bot_colour; + pp[0].specular = 0xff000000; + + pp[1].X = 640.0F; + pp[1].Y = screen_y - 256.0F; + pp[1].Z = 0.5F; + pp[1].z = 0.5F; + pp[1].u = 0.0F; + pp[1].v = 0.0F; + pp[1].colour = bot_colour; + pp[1].specular = 0xff000000; + + pp[2].X = 0.0F; + pp[2].Y = screen_y; + pp[2].Z = 0.5F; + pp[2].z = 0.5F; + pp[2].u = 0.0F; + pp[2].v = 0.0F; + pp[2].colour = bot_colour; + pp[2].specular = 0xff000000; + + pp[3].X = 640.0F; + pp[3].Y = screen_y; + pp[3].Z = 0.5F; + pp[3].z = 0.5F; + pp[3].u = 0.0F; + pp[3].v = 0.0F; + pp[3].colour = bot_colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_SKY, FALSE, TRUE); + + pp[0].X = 0.0F; + pp[0].Y = screen_y - 1024.0F; + pp[0].Z = 0.5F; + pp[0].z = 0.5F; + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[0].colour = top_colour; + pp[0].specular = 0xff000000; + + pp[1].X = 640.0F; + pp[1].Y = screen_y - 1024.0F; + pp[1].Z = 0.5F; + pp[1].z = 0.5F; + pp[1].u = 0.0F; + pp[1].v = 0.0F; + pp[1].colour = top_colour; + pp[1].specular = 0xff000000; + + pp[2].X = 0.0F; + pp[2].Y = screen_y - 256.0F; + pp[2].Z = 0.5F; + pp[2].z = 0.5F; + pp[2].u = 0.0F; + pp[2].v = 0.0F; + pp[2].colour = bot_colour; + pp[2].specular = 0xff000000; + + pp[3].X = 640.0F; + pp[3].Y = screen_y - 256.0F; + pp[3].Z = 0.5F; + pp[3].z = 0.5F; + pp[3].u = 0.0F; + pp[3].v = 0.0F; + pp[3].colour = bot_colour; + pp[3].specular = 0xff000000; + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, POLY_PAGE_SKY, FALSE, TRUE); + +} +#endif + + +// 0 1 +// +// 2 3 + +void SKY_draw_poly_sky_old(float world_camera_x,float world_camera_y,float world_camera_z,float world_camera_yaw,float max_dist,ULONG bot_colour,ULONG top_colour) +{ + SLONG i; + + SLONG p1; + SLONG p2; + + float x; + float y; + float z; + + float angle; + + #define SKY_CIRCLE_STEPS 30 + //30 + + #define SKY_HORIZON 0.0F + //(world_camera_y * 0.0 - 256.0F) + #define SKY_MAXUP (world_camera_y * 0.0f + 12072.0F) + + POLY_Point pp_bot[SKY_CIRCLE_STEPS]; + POLY_Point pp_top[SKY_CIRCLE_STEPS]; + + POLY_Point *quad[4]; + + angle = 0.0F; + max_dist=66.0F*256.0F; + +// max_dist-=2256; + + for (i = 0; i < SKY_CIRCLE_STEPS; i++) + { + x = world_camera_x + (float)sin(angle) * (max_dist);// - 378.0F); + z = world_camera_z + (float)cos(angle) * (max_dist);// - 378.0F); + + POLY_transform_c_saturate_z(x,SKY_HORIZON,z,&pp_bot[i]); + + // + // Only bother transforming the higher point if the lower point + // wasn't behind you. + // + + if (pp_bot[i].IsValid()) + { + pp_bot[i].colour = bot_colour; + pp_bot[i].specular = 0xff000000; + + x = world_camera_x + (float)sin(angle) * (max_dist);// - 1024.0F); + z = world_camera_z + (float)cos(angle) * (max_dist);// - 1024.0F); + + POLY_transform_c_saturate_z( + x, + SKY_MAXUP, + z, + &pp_top[i]); + + pp_top[i].colour = top_colour; + pp_top[i].specular = 0xff000000; + } + else + pp_top[i].clip=0; + + +#ifdef TARGET_DC + // Bodge the RHW so that the moon actually shows up. + pp_top[i].Z *= 0.05f; + pp_bot[i].Z *= 0.05f; +#endif + angle += 2.0F * PI / SKY_CIRCLE_STEPS; + } + + // + // Draw the sky quads. + // + + for (i = 0; i < SKY_CIRCLE_STEPS; i++) +// for (i = 0; i < 1; i++) + { + p1 = i + 0; + p2 = i + 1; + + if (p2 == SKY_CIRCLE_STEPS) {p2 = 0;} + + + quad[0] = &pp_top[p1]; + quad[1] = &pp_top[p2]; + quad[2] = &pp_bot[p1]; + quad[3] = &pp_bot[p2]; + if((quad[0]->clip & quad[1]->clip & quad[1]->clip & quad[2]->clip)&POLY_CLIP_TRANSFORMED) + if (POLY_valid_quad(quad)) + { + float pos; + + switch(i%5) + { + case 0: + pos=0.0F; + break; + case 1: + pos=0.2F; + break; + case 2: + pos=0.4F; + break; + case 3: + pos=0.6F; + break; + case 4: + pos=0.8F; + break; + + } + + + + quad[0]->u = pos; + quad[1]->u = pos+0.2F; + quad[2]->u = pos; + quad[3]->u = pos+0.2F; + + quad[0]->v = 0.0F; + quad[1]->v = 0.0F; + quad[2]->v = 1.0F; + quad[3]->v = 1.0F; + +#ifdef TARGET_DC + // These can trip in mad cases - ignore them. + //ASSERT ( quad[0]->Z < 0.0009f ); + //ASSERT ( quad[1]->Z < 0.0009f ); + //ASSERT ( quad[2]->Z < 0.0009f ); + //ASSERT ( quad[3]->Z < 0.0009f ); +#endif + + POLY_add_quad(quad, POLY_PAGE_SKY, FALSE,1); + } + } +} + diff --git a/fallen/DDEngine/Source/smap.cpp b/fallen/DDEngine/Source/smap.cpp new file mode 100644 index 0000000..44fea25 --- /dev/null +++ b/fallen/DDEngine/Source/smap.cpp @@ -0,0 +1,1667 @@ +// +// Shadow maps! +// + +#include "game.h" +#include "smap.h" +#include "aa.h" +#include "c:\fallen\headers\person.h" +#include "c:\fallen\headers\fmatrix.h" +#include "matrix.h" +#include "memory.h" +#include + +// ======================================================== +// +// THE SHADOW MAPPER PROTOTYPE +// +// ======================================================== + + +// +// The shadow-mapper. +// +// First initialise the shadow mapper by giving it the direction of +// the parallel light you want to shadow and the bitmap the shadow +// map is going to be drawn into. +// + +void SMAP_init( + float light_dx, // The light vector doesn't have to be normalised + float light_dy, + float light_dz, + UBYTE *bitmap, + UBYTE res_u, + UBYTE res_v); + +// +// Add world space points. Each point is given an index that is used +// to identify it when you add triangles. When there are no more points +// left, call SMAP_point_finished(). The first point you add has index +// 0, then they go up by one each time. +// + +SLONG SMAP_point_add( + float world_x, + float world_y, + float world_z); + +void SMAP_point_finished(void); + +// +// Add each triangle. Each triangle is rendered into the current shadow map. +// + +void SMAP_tri_add( + SLONG p1, + SLONG p2, + SLONG p3); + +// +// After you have called SMAP_point_finished(), you can get the shadow maps +// position in world space. +// + +void SMAP_get_world_pos( + + // + // Position of (0,0) of the shadow map. + // + + float *world_x, + float *world_y, + float *world_z, + + // + // The vector along on pixel in the u and v direction. + // + + float *world_dxdu, + float *world_dydu, + float *world_dzdu, + + float *world_dxdv, + float *world_dydv, + float *world_dzdv); + + +// ======================================================== +// +// THE SHADOW MAPPER CODE +// +// ======================================================== + +// +// While adding points, we project them on the plane whose normal is +// the light vector and which goes through the origin of the world. It +// point is given in terms of two vectors, plane_u and plane_v. +// + +// +// The plane, passing through the origin of the world. +// + +float SMAP_plane_ux; +float SMAP_plane_uy; +float SMAP_plane_uz; + +float SMAP_plane_vx; +float SMAP_plane_vy; +float SMAP_plane_vz; + +float SMAP_plane_nx; +float SMAP_plane_ny; +float SMAP_plane_nz; + +// +// The bounding values in all the points. +// + + +float SMAP_u_min; +float SMAP_u_max; + +float SMAP_v_min; +float SMAP_v_max; + +float SMAP_n_min; +float SMAP_n_max; + +float SMAP_u_map_mul_float; +float SMAP_v_map_mul_float; + +float SMAP_u_map_add_float; +float SMAP_v_map_add_float; + +float SMAP_u_map_mul_slong; +float SMAP_v_map_mul_slong; + +// +// The bitmap. +// + +UBYTE *SMAP_bitmap; +SLONG SMAP_res_u; +SLONG SMAP_res_v; + + +// +// The points. +// + +typedef struct +{ + float along_u; + float along_v; + float along_n; + + float world_x; + float world_y; + float world_z; + + SLONG u; // Coordinates on the bitmap in fixed-point 16. + SLONG v; + +} SMAP_Point; + +#define SMAP_MAX_POINTS 2048 + +SMAP_Point SMAP_point[SMAP_MAX_POINTS]; +SLONG SMAP_point_upto; + + +// +// Normlises the given vector. +// + +void inline SMAP_vector_normalise( + float *x, + float *y, + float *z) // First time I have ever used references. + // You haven't used references, you've used pointers. +{ + float len2 = *x**x + *y**y + *z**z; + float len = sqrt(len2); + float lenr = 1.0F / len; + + *x *= lenr; + *y *= lenr; + *z *= lenr; +} + + + +void SMAP_init( + float light_dx, + float light_dy, + float light_dz, + UBYTE *bitmap, + UBYTE res_u, + UBYTE res_v) +{ + float len; + float overlen; + + // + // Store the bitmap. + // + + SMAP_bitmap = bitmap; + SMAP_res_u = res_u; + SMAP_res_v = res_v; + + memset(bitmap, 0, res_u * res_v); + + // + // Calculate the plane definition. + // + + SMAP_plane_nx = -light_dx; // I like to think of the plane as 'facing' the light! + SMAP_plane_ny = -light_dy; + SMAP_plane_nz = -light_dz; + + SMAP_vector_normalise( + &SMAP_plane_nx, + &SMAP_plane_ny, + &SMAP_plane_nz); + + // + // Work out the u-vector from the light vector. + // + + if (fabsf(light_dx) + fabsf(light_dz) < 0.001F) + { + // + // An arbitrary direction... + // + + SMAP_plane_ux = 1.0F; + SMAP_plane_uy = 0.0F; + SMAP_plane_uz = 0.0F; + } + else + { + SMAP_plane_ux = -light_dz; + SMAP_plane_uy = 0; + SMAP_plane_uz = light_dx; + + SMAP_vector_normalise( + &SMAP_plane_ux, + &SMAP_plane_uy, + &SMAP_plane_uz); + } + + // + // The third vector is just the cross-product. + // + + SMAP_plane_vx = SMAP_plane_ny*SMAP_plane_uz - SMAP_plane_nz*SMAP_plane_uy; + SMAP_plane_vy = SMAP_plane_nz*SMAP_plane_ux - SMAP_plane_nx*SMAP_plane_uz; + SMAP_plane_vz = SMAP_plane_nx*SMAP_plane_uy - SMAP_plane_ny*SMAP_plane_ux; + + // + // Clear all the points and initialise the bounding values. + // + + #define FINFINITY ((float) INFINITY) + + SMAP_point_upto = 0; + + SMAP_u_min = +FINFINITY; + SMAP_u_max = -FINFINITY; + + SMAP_v_min = +FINFINITY; + SMAP_v_max = -FINFINITY; + + SMAP_n_min = +FINFINITY; + SMAP_n_max = -FINFINITY; +} + + +SLONG SMAP_point_add( + float world_x, + float world_y, + float world_z) +{ + SMAP_Point *sp; + + ASSERT(WITHIN(SMAP_point_upto, 0, SMAP_MAX_POINTS - 1)); + + sp = &SMAP_point[SMAP_point_upto]; + + sp->world_x = world_x; + sp->world_y = world_y; + sp->world_z = world_z; + + sp->along_n = world_x*SMAP_plane_nx + world_y*SMAP_plane_ny + world_z*SMAP_plane_nz; + sp->along_u = world_x*SMAP_plane_ux + world_y*SMAP_plane_uy + world_z*SMAP_plane_uz; + sp->along_v = world_x*SMAP_plane_vx + world_y*SMAP_plane_vy + world_z*SMAP_plane_vz; + + // + // Update the bounding values. + // + + if (sp->along_n < SMAP_n_min) {SMAP_n_min = sp->along_n;} + if (sp->along_n > SMAP_n_max) {SMAP_n_max = sp->along_n;} + + if (sp->along_u < SMAP_u_min) {SMAP_u_min = sp->along_u;} + if (sp->along_u > SMAP_u_max) {SMAP_u_max = sp->along_u;} + + if (sp->along_v < SMAP_v_min) {SMAP_v_min = sp->along_v;} + if (sp->along_v > SMAP_v_max) {SMAP_v_max = sp->along_v;} + + return SMAP_point_upto++; +} + + +void SMAP_point_finished() +{ + SLONG i; + + SMAP_Point *sp; + + float along_bu; + float along_bv; + + float res_u = float(SMAP_res_u); + float res_v = float(SMAP_res_v); + + // + // Push the image a pixel in from the edge of the bitmap. + // + + SMAP_u_map_mul_float = (res_u - 2.0F) / (SMAP_u_max - SMAP_u_min); + SMAP_v_map_mul_float = (res_v - 2.0F) / (SMAP_v_max - SMAP_v_min); + + SMAP_u_map_mul_slong = SMAP_u_map_mul_float * 65536.0F; + SMAP_v_map_mul_slong = SMAP_v_map_mul_float * 65536.0F; + + SMAP_u_map_add_float = 1.0F / res_u; + SMAP_v_map_add_float = 1.0F / res_v; + + SMAP_u_map_mul_float *= SMAP_u_map_add_float; + SMAP_v_map_mul_float *= SMAP_v_map_add_float; + + // + // Calculate the positions of the points on the bitmap. + // + + for (i = 0; i < SMAP_point_upto; i++) + { + sp = &SMAP_point[i]; + + along_bu = 65536.0F + (sp->along_u - SMAP_u_min) * SMAP_u_map_mul_slong; + along_bv = 65536.0F + (sp->along_v - SMAP_v_min) * SMAP_v_map_mul_slong; + + sp->u = SLONG(along_bu); + sp->v = SLONG(along_bv); + + ASSERT(WITHIN(sp->u, 0, SMAP_res_u << 16)); + ASSERT(WITHIN(sp->v, 0, SMAP_res_v << 16)); + } +} + +void SMAP_tri_add( + SLONG p1, + SLONG p2, + SLONG p3) +{ + SLONG du1; + SLONG dv1; + + SLONG du2; + SLONG dv2; + + ASSERT(WITHIN(p1, 0, SMAP_point_upto - 1)); + ASSERT(WITHIN(p2, 0, SMAP_point_upto - 1)); + ASSERT(WITHIN(p3, 0, SMAP_point_upto - 1)); + + // + // Backface cull... + // + + du1 = SMAP_point[p2].u - SMAP_point[p1].u; + dv1 = SMAP_point[p2].v - SMAP_point[p1].v; + + du2 = SMAP_point[p3].u - SMAP_point[p1].u; + dv2 = SMAP_point[p3].v - SMAP_point[p1].v; + + if (MUL64(du1,dv2) - MUL64(dv1,du2) <= 0) + { + // + // Backface culled. + // + } + else + { + AA_draw( + SMAP_bitmap, + SMAP_res_u, + SMAP_res_v, + SMAP_res_v, + SMAP_point[p1].u, + SMAP_point[p1].v, + SMAP_point[p2].u, + SMAP_point[p2].v, + SMAP_point[p3].u, + SMAP_point[p3].v); + } +} + + + + +// ======================================================== +// +// FEEDING PRIMS AND BIKES TO THE SHADOW MAPPER +// +// ======================================================== + +// +// Add the triangles and quads of the given prim to the shadow mapper given the +// index of its first point. +// + +void SMAP_add_prim_triangles( + SLONG prim, + SLONG index) +{ + PrimFace4 *p_f4; + PrimFace3 *p_f3; + PrimObject *p_obj; + + p_obj = &prim_objects[prim]; + + SLONG i; + + index -= p_obj->StartPoint; + + for (i = p_obj->StartFace3; i < p_obj->EndFace3; i++) + { + p_f3 = &prim_faces3[i]; + + SMAP_tri_add( + p_f3->Points[0] + index, + p_f3->Points[1] + index, + p_f3->Points[2] + index); + } + + for (i = p_obj->StartFace4; i < p_obj->EndFace4; i++) + { + p_f4 = &prim_faces4[i]; + + SMAP_tri_add( + p_f4->Points[0] + index, + p_f4->Points[1] + index, + p_f4->Points[2] + index); + + SMAP_tri_add( + p_f4->Points[1] + index, + p_f4->Points[3] + index, + p_f4->Points[2] + index); + } +} + +// +// Adds a prims points to the shadow mapper and returns the index of the points. +// + +SLONG SMAP_prim_points( + SLONG prim, + SLONG world_x, + SLONG world_y, + SLONG world_z, + SLONG yaw, + SLONG pitch, + SLONG roll) +{ + SLONG i; + float px; + float py; + float pz; + float ox = float(world_x); + float oy = float(world_y); + float oz = float(world_z); + SLONG base = -1; + SLONG index; + float matrix[9]; + + PrimObject *p_obj = &prim_objects[prim]; + + // + // Calculate the objects rotation matrix. + // + + MATRIX_calc( + matrix, + float(yaw) * (2.0F * PI / 2048.0F), + float(pitch) * (2.0F * PI / 2048.0F), + float(roll) * (2.0F * PI / 2048.0F)); + + // + // Add all the points to the shadow mapper. + // + + for (i = p_obj->StartPoint; i < p_obj->EndPoint; i++) + { + px = AENG_dx_prim_points[i].X; + py = AENG_dx_prim_points[i].Y; + pz = AENG_dx_prim_points[i].Z; + + MATRIX_MUL_BY_TRANSPOSE( + matrix, + px, + py, + pz); + + px += world_x; + py += world_y; + pz += world_z; + + index = SMAP_point_add( + px, + py, + pz); + + if (base == -1) + { + base = index; + } + } + + return base; +} + +#ifdef BIKE + +void SMAP_bike( + Thing *p_bike, + UBYTE *bitmap, // 0 => transparent 255 => opaque + UBYTE u_res, + UBYTE v_res, + SLONG light_dx, // This vector need not be normalised + SLONG light_dy, + SLONG light_dz) +{ + SLONG i_frame; + SLONG i_steer; + SLONG i_fwheel; + SLONG i_bwheel; + + BIKE_Drawinfo bdi = BIKE_get_drawinfo(p_bike); + + // + // Initialise the shadow mapper. + // + + SMAP_init( + float(light_dx), + float(light_dy), + float(light_dz), + bitmap, + u_res, + v_res); + + // + // Add the points for each bit of the bike. + // + + i_frame = SMAP_prim_points( + PRIM_OBJ_BIKE_FRAME, + p_bike->WorldPos.X >> 8, + p_bike->WorldPos.Y >> 8, + p_bike->WorldPos.Z >> 8, + bdi.yaw, + bdi.pitch, + bdi.roll); + + /* + + // + // The front of the bike is where we physically model the wheel + // it is not at the correct place for the pivot point of the front wheel + // or the steering column. + // + + i_steer = SMAP_prim_points( + PRIM_OBJ_BIKE_STEER, + bdi.steer_x, + bdi.steer_y, + bdi.steer_z, + bdi.steer, + bdi.pitch, + bdi.roll); + + i_fwheel = SMAP_prim_points( + PRIM_OBJ_BIKE_FWHEEL, + bdi.front_x, + bdi.front_y, + bdi.front_z, + bdi.steer, + bdi.pitch, + bdi.roll); + + i_bwheel = SMAP_prim_points( + PRIM_OBJ_BIKE_BWHEEL, + bdi.back_x, + bdi.back_y, + bdi.back_z, + bdi.yaw, + 0, + bdi.roll); + + */ + + // + // Finished adding the points. + // + + SMAP_point_finished(); + + // + // Add the triangles and quads for each bit of the bike. + // + + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_FRAME, i_frame); + + /* + + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_STEER, i_steer); + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_FWHEEL, i_fwheel); + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_BWHEEL, i_bwheel); + + */ +} + +#endif + + + +// ======================================================== +// +// FEEDING PERSON COORDINATES TO THE SHADOW MAPPER +// +// ======================================================== + + +// +// Rotates all the points of the prim into world space and adds them +// to the Shadow mapper. Returns the index of the last point it +// added to the shadow mapper. +// + +UWORD SMAP_add_tweened_points( + SLONG prim, + SLONG x, + SLONG y, + SLONG z, + SLONG tween, + struct GameKeyFrameElement *anim_info, + struct GameKeyFrameElement *anim_info_next, + struct Matrix33 *rot_mat, + SLONG off_dx, + SLONG off_dy, + SLONG off_dz, + Thing *p_thing) +{ + SLONG i; + SLONG j; + + SLONG sp; + SLONG ep; + + Matrix31 offset; + Matrix33 mat2; + Matrix33 mat_final; + Matrix33 *mat; + Matrix33 *mat_next; + + UWORD ans; + + SVector temp; + + PrimObject *p_obj; + + // + // Matrix functions we use. + // + + void matrix_transform (Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); + void matrix_mult33 (Matrix33* result, Matrix33* mat1, Matrix33* mat2); + +// mat = &anim_info ->Matrix; +// mat_next = &anim_info_next->Matrix; + + offset.M[0] = anim_info->OffsetX + ((anim_info_next->OffsetX + off_dx - anim_info->OffsetX) * tween >> 8); + offset.M[1] = anim_info->OffsetY + ((anim_info_next->OffsetY + off_dy - anim_info->OffsetY) * tween >> 8); + offset.M[2] = anim_info->OffsetZ + ((anim_info_next->OffsetZ + off_dz - anim_info->OffsetZ) * tween >> 8); + + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + + SLONG character_scale = person_get_scale(p_thing); + + temp.X = (temp.X * character_scale) / 256; + temp.Y = (temp.Y * character_scale) / 256; + temp.Z = (temp.Z * character_scale) / 256; + + x += temp.X; + y += temp.Y; + z += temp.Z; + + // + // Create a temporary "tween" matrix between current and next + // +/* + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + mat2.M[i][j] = mat->M[i][j] + ((mat_next->M[i][j] - mat->M[i][j]) * tween >> 8); + } + } + */ + // + // Stop the matrix flattening... do we have to bother? + // + + CMatrix33 m1, m2; + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + build_tween_matrix(&mat2 ,&m1, &m2, tween); + + + normalise_matrix(&mat2); + + mat2.M[0][0] = (mat2.M[0][0] * character_scale) / 256; + mat2.M[0][1] = (mat2.M[0][1] * character_scale) / 256; + mat2.M[0][2] = (mat2.M[0][2] * character_scale) / 256; + mat2.M[1][0] = (mat2.M[1][0] * character_scale) / 256; + mat2.M[1][1] = (mat2.M[1][1] * character_scale) / 256; + mat2.M[1][2] = (mat2.M[1][2] * character_scale) / 256; + mat2.M[2][0] = (mat2.M[2][0] * character_scale) / 256; + mat2.M[2][1] = (mat2.M[2][1] * character_scale) / 256; + mat2.M[2][2] = (mat2.M[2][2] * character_scale) / 256; + + // + // Apply local rotation matrix to get mat_final that rotates + // the point into world space. + // + + matrix_mult33(&mat_final, rot_mat, &mat2); + + // + // Put all the points into the shadow mapper. + // + + p_obj = &prim_objects[prim]; + + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + // + // Transform the shadow coordinates. + // + + for (i = sp; i < ep; i++) + { + // + // Find the world-space position of this point. + // + + matrix_transform_small((struct Matrix31*)&temp, &mat_final, (struct SMatrix31*)&prim_points[i]); + + temp.X += x; + temp.Y += y; + temp.Z += z; + + ans = SMAP_point_add( + float(temp.X), + float(temp.Y), + float(temp.Z)); + } + + return ans; +} + + +void SMAP_person( + Thing *p_thing, + UBYTE *bitmap, // 0 => transparent 255 => opaque + UBYTE u_res, + UBYTE v_res, + SLONG light_dx, + SLONG light_dy, + SLONG light_dz) +{ + SLONG dx; + SLONG dy; + SLONG dz; + + SLONG i_frame; + SLONG i_steer; + SLONG i_fwheel; + SLONG i_bwheel; + + Matrix33 r_matrix; + + GameKeyFrameElement *ae1; + GameKeyFrameElement *ae2; + + DrawTween *dt = p_thing->Draw.Tweened; + + if (dt->CurrentFrame == 0 || + dt->NextFrame == 0) + { + // + // No frames to tween between. + // + + MSG_add("!!!!!!!!!!!!!!!!!!!!!!!!ERROR SMAP_person"); + return; + } + + // + // The offset to keep the locked limb in the same place. + // + + if (dt->Locked) + { + SLONG x1, y1, z1; + SLONG x2, y2, z2; + + // + // Taken from temp.cpp + // + + calc_sub_objects_position_global(dt->CurrentFrame, dt->NextFrame, 0, dt->Locked, &x1, &y1, &z1); + calc_sub_objects_position_global(dt->CurrentFrame, dt->NextFrame, 256, dt->Locked, &x2, &y2, &z2); + + dx = x1 - x2; + dy = y1 - y2; + dz = z1 - z2; + } + else + { + dx = 0; + dy = 0; + dz = 0; + } + + // + // The animation elements for the two frames. + // + + ae1 = dt->CurrentFrame->FirstElement; + ae2 = dt->NextFrame ->FirstElement; + + if (!ae1 || !ae2) + { + MSG_add("!!!!!!!!!!!!!!!!!!!ERROR SMAP_person has no animation elements"); + + return; + } + + // + // The rotation matrix of the whole object. + // + + void FIGURE_rotate_obj( + SLONG xangle, + SLONG yangle, + SLONG zangle, + Matrix33 *r3); + + FIGURE_rotate_obj( + dt->Tilt, + dt->Angle, + dt->Roll, + &r_matrix); + + // + // Initialise the shadow mapper. + // + + SMAP_init( + float(light_dx), + float(light_dy), + float(light_dz), + bitmap, + u_res, + v_res); + + // + // Draw each body part. + // + + SLONG i; + SLONG ele_count; + SLONG start_object; + SLONG object_offset; + + ele_count = dt->TheChunk->ElementCount; + start_object = prim_multi_objects[dt->TheChunk->MultiObject[0]].StartObject; + + // + // Add all the points to the shadow mapper. + // + + #define SMAP_MAX_PARTS 20 + + SLONG indices[SMAP_MAX_PARTS]; + + for (i = 0; i < ele_count; i++) + { + ASSERT(WITHIN(i, 0, SMAP_MAX_PARTS - 1)); + + object_offset = dt->TheChunk->PeopleTypes[dt->PersonID&0x1f].BodyPart[i]; + + indices[i] = SMAP_add_tweened_points( + start_object + object_offset, + p_thing->WorldPos.X >> 8, + p_thing->WorldPos.Y >> 8, + p_thing->WorldPos.Z >> 8, + dt->AnimTween, + &ae1[i], + &ae2[i], + &r_matrix, + dx,dy,dz, p_thing); + } + + #ifdef BIKE + + if (p_thing->Genus.Person->Flags & FLAG_PERSON_BIKING) + { + Thing *p_bike = TO_THING(p_thing->Genus.Person->InCar); + BIKE_Drawinfo bdi = BIKE_get_drawinfo(p_bike); + + // + // Draw the shadow of the bike too! + // + + /* + + i_frame = SMAP_prim_points( + PRIM_OBJ_BIKE_FRAME, + p_bike->WorldPos.X >> 8, + p_bike->WorldPos.Y >> 8, + p_bike->WorldPos.Z >> 8, + bdi.yaw, + bdi.pitch, + bdi.roll); + + // + // The front of the bike is where we physically model the wheel + // it is not at the correct place for the pivot point of the front wheel + // or the steering column. + // + + i_steer = SMAP_prim_points( + PRIM_OBJ_BIKE_STEER, + bdi.steer_x, + bdi.steer_y, + bdi.steer_z, + bdi.steer, + bdi.pitch, + bdi.roll); + + */ + + i_fwheel = SMAP_prim_points( + PRIM_OBJ_BIKE_FWHEEL, + bdi.front_x, + bdi.front_y, + bdi.front_z, + bdi.steer, + bdi.pitch, + bdi.roll); + + i_bwheel = SMAP_prim_points( + PRIM_OBJ_BIKE_BWHEEL, + bdi.back_x, + bdi.back_y, + bdi.back_z, + bdi.yaw, + 0, + bdi.roll); + } + + #endif + + SMAP_point_finished(); + + // + // Add all the triangles to the shadow mapper. + // + + SLONG index = 0; + + for (i = 0; i < ele_count; i++) + { + ASSERT(WITHIN(i, 0, SMAP_MAX_PARTS - 1)); + + + object_offset = dt->TheChunk->PeopleTypes[dt->PersonID&0x1f].BodyPart[i]; +// object_offset = dt->TheChunk->PeopleTypes[dt->PersonID].BodyPart[i]; +// object_offset = dt->TheChunk->PeopleTypes[0].BodyPart[i]; + + SMAP_add_prim_triangles( + start_object + object_offset, + index); + + index = indices[i] + 1; + } + + #ifdef BIKE + + if (p_thing->Genus.Person->Flags & FLAG_PERSON_BIKING) + { + // + // Add the triangles and quads for each bit of the bike. + // + + /* + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_FRAME, i_frame); + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_STEER, i_steer); + */ + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_BWHEEL, i_fwheel); + SMAP_add_prim_triangles(PRIM_OBJ_BIKE_BWHEEL, i_bwheel); + } + + #endif +} + + + + + +// ======================================================== +// +// PROJECTING THE SHADOW MAP ONTO A QUAD IN WORLD SPACE +// +// ======================================================== + +#define SMAP_CLIP_U_LESS (1 << 0) +#define SMAP_CLIP_U_MORE (1 << 1) +#define SMAP_CLIP_V_LESS (1 << 2) +#define SMAP_CLIP_V_MORE (1 << 3) + +#define SMAP_MAX_LINKS 16 + +SMAP_Link SMAP_link[SMAP_MAX_LINKS]; +SLONG SMAP_link_upto; + +// +// Returns TRUE if the poly is the wrong side of the +// shadow map... i.e. nearer to the light. +// + +SLONG SMAP_wrong_side(SMAP_Link *sl) +{ + float order = 0.0F; + float overorder; + + float av_wx = 0.0F; + float av_wy = 0.0F; + float av_wz = 0.0F; + + float av_n; + + while(sl) + { + av_wx += sl->wx; + av_wy += sl->wy; + av_wz += sl->wz; + + order += 1.0F; + + sl = sl->next; + } + + overorder = 1.0F / order; + + av_wx *= overorder; + av_wy *= overorder; + av_wz *= overorder; + + av_n = av_wx*SMAP_plane_nx + av_wy*SMAP_plane_ny + av_wz*SMAP_plane_nz; + + if (av_n >= SMAP_n_min + (SMAP_n_max - SMAP_n_min) * 0.75F) + { + return TRUE; + } + else + { + return FALSE; + } +} + +// +// Converts the u,v in the polys to the texture uvs. +// + +void SMAP_convert_uvs(SMAP_Link *sl) +{ + while(sl) + { + sl->u -= SMAP_u_min; + sl->v -= SMAP_v_min; + + sl->u *= SMAP_u_map_mul_float; + sl->v *= SMAP_v_map_mul_float; + + sl->u += SMAP_u_map_add_float; + sl->v += SMAP_v_map_add_float; + + sl = sl->next; + } +} + + + +SMAP_Link *SMAP_project_onto_poly(SVector_F quad[], SLONG num_points) +{ + SLONG i; + ULONG clip_and; + ULONG clip_or; + + float along; + + SMAP_Link *poly; + SMAP_Link *sl; + SMAP_Link *sl1; + SMAP_Link *sl2; + SMAP_Link *sc; + + SMAP_Link **prev; + SMAP_Link *next; + + // + // Clear the old points. + // + + SMAP_link_upto = 0; + + // + // Create the un-clipped poly. + // + + clip_or = 0; + clip_and = 0xffffffff; + + for (i = 0; i < num_points; i++) + { + sl = &SMAP_link[SMAP_link_upto++]; + + sl->wx = quad[i].X; + sl->wy = quad[i].Y; + sl->wz = quad[i].Z; + + sl->u = sl->wx*SMAP_plane_ux + sl->wy*SMAP_plane_uy + sl->wz*SMAP_plane_uz; + sl->v = sl->wx*SMAP_plane_vx + sl->wy*SMAP_plane_vy + sl->wz*SMAP_plane_vz; + + sl->next = &SMAP_link[SMAP_link_upto]; + + if (SMAP_link_upto == num_points) + { + sl->next = NULL; + } + + sl->clip = 0; + + if (sl->u < SMAP_u_min) {sl->clip |= SMAP_CLIP_U_LESS;} + if (sl->u > SMAP_u_max) {sl->clip |= SMAP_CLIP_U_MORE;} + if (sl->v < SMAP_v_min) {sl->clip |= SMAP_CLIP_V_LESS;} + if (sl->v > SMAP_v_max) {sl->clip |= SMAP_CLIP_V_MORE;} + + clip_or |= sl->clip; + clip_and &= sl->clip; + } + + if (clip_and) + { + // + // No part of the shadow map falls on this poly. + // + + return NULL; + } + + // + // Backface cull? + // + + { + float vec1u; + float vec1v; + float vec2u; + float vec2v; + + float cross; + + SMAP_Link *p1 = &SMAP_link[0]; + SMAP_Link *p2 = &SMAP_link[1]; + SMAP_Link *p3 = &SMAP_link[2]; + + vec1u = p2->u - p1->u; + vec1v = p2->v - p1->v; + vec2u = p3->u - p1->u; + vec2v = p3->v - p1->v; + + cross = vec1u*vec2v - vec1v*vec2u; + + if (cross >= 0) + { + return NULL; + } + } + + poly = &SMAP_link[0]; + + if (clip_or == 0) + { + // + // We dont have to do any clipping! + // + + if (SMAP_wrong_side(poly)) + { + return NULL; + } + else + { + SMAP_convert_uvs(poly); + + return poly; + } + } + + // ====================== + // + // CLIP TO SMAP_u_min + // + // ====================== + + for (sl = poly; sl; sl = sl->next) + { + sl1 = sl; + sl2 = sl->next; + + if (sl2 == NULL) {sl2 = poly;} + + if ((sl1->clip ^ sl2->clip) & SMAP_CLIP_U_LESS) + { + along = (SMAP_u_min - sl1->u) / (sl2->u - sl1->u); + + // + // Create a new point on the line u = SMAP_u_min + // + + ASSERT(WITHIN(SMAP_link_upto, 0, SMAP_MAX_LINKS - 1)); + + sc = &SMAP_link[SMAP_link_upto++]; + + sc->wx = sl1->wx + along * (sl2->wx - sl1->wx); + sc->wy = sl1->wy + along * (sl2->wy - sl1->wy); + sc->wz = sl1->wz + along * (sl2->wz - sl1->wz); + + sc->u = SMAP_u_min; + sc->v = sl1->v + along * (sl2->v - sl1->v); + + // + // Set its clipping flags. + // + + sc->clip = 0; + + if (sc->u < SMAP_u_min) {sc->clip |= SMAP_CLIP_U_LESS;} + if (sc->u > SMAP_u_max) {sc->clip |= SMAP_CLIP_U_MORE;} + if (sc->v < SMAP_v_min) {sc->clip |= SMAP_CLIP_V_LESS;} + if (sc->v > SMAP_v_max) {sc->clip |= SMAP_CLIP_V_MORE;} + + // + // Insert it in the linked list. + // + + sc->next = sl->next; + sl->next = sc; + + // + // Don't clip this point again... + // + + sl = sl->next; + } + } + + // + // Take out all points in the linked list outside the SMAP_u_min boundary. + // + + prev = &poly; + next = poly; + + clip_and = 0xffffffff; + clip_or = 0; + + while(1) + { + if (next == NULL) + { + break; + } + + if (next->clip & SMAP_CLIP_U_LESS) + { + // + // Get rid of this point. + // + + *prev = next->next; + next = next->next; + } + else + { + // + // Keep this point. + // + + clip_and &= next->clip; + clip_or |= next->clip; + + prev = &next->next; + next = next->next; + } + } + + // + // Early outs? + // + + if ( clip_and) {return NULL;} + if (!clip_or) {if (SMAP_wrong_side(poly)) {return NULL;} else {SMAP_convert_uvs(poly); return poly;}} + + // ====================== + // + // CLIP TO SMAP_u_max + // + // ====================== + + for (sl = poly; sl; sl = sl->next) + { + sl1 = sl; + sl2 = sl->next; + + if (sl2 == NULL) {sl2 = poly;} + + if ((sl1->clip ^ sl2->clip) & SMAP_CLIP_U_MORE) + { + along = (SMAP_u_max - sl1->u) / (sl2->u - sl1->u); + + // + // Create a new point on the line u = SMAP_u_max + // + + ASSERT(WITHIN(SMAP_link_upto, 0, SMAP_MAX_LINKS - 1)); + + sc = &SMAP_link[SMAP_link_upto++]; + + sc->wx = sl1->wx + along * (sl2->wx - sl1->wx); + sc->wy = sl1->wy + along * (sl2->wy - sl1->wy); + sc->wz = sl1->wz + along * (sl2->wz - sl1->wz); + + sc->u = SMAP_u_max; + sc->v = sl1->v + along * (sl2->v - sl1->v); + + // + // Set its clipping flags. + // + + sc->clip = 0; + + if (sc->u < SMAP_u_min) {sc->clip |= SMAP_CLIP_U_LESS;} + if (sc->u > SMAP_u_max) {sc->clip |= SMAP_CLIP_U_MORE;} + if (sc->v < SMAP_v_min) {sc->clip |= SMAP_CLIP_V_LESS;} + if (sc->v > SMAP_v_max) {sc->clip |= SMAP_CLIP_V_MORE;} + + // + // Insert it in the linked list. + // + + sc->next = sl->next; + sl->next = sc; + + // + // Don't clip this point again... + // + + sl = sl->next; + } + } + + // + // Take out all points in the linked list outside the SMAP_u_max boundary. + // + + prev = &poly; + next = poly; + + clip_and = 0xffffffff; + clip_or = 0; + + while(1) + { + if (next == NULL) + { + break; + } + + if (next->clip & SMAP_CLIP_U_MORE) + { + // + // Get rid of this point. + // + + *prev = next->next; + next = next->next; + } + else + { + // + // Keep this point. + // + + clip_and &= next->clip; + clip_or |= next->clip; + + prev = &next->next; + next = next->next; + } + } + + // + // Early outs? + // + + if ( clip_and) {return NULL;} + if (!clip_or) {if (SMAP_wrong_side(poly)) {return NULL;} else {SMAP_convert_uvs(poly); return poly;}} + + // ====================== + // + // CLIP TO SMAP_v_min + // + // ====================== + + for (sl = poly; sl; sl = sl->next) + { + sl1 = sl; + sl2 = sl->next; + + if (sl2 == NULL) {sl2 = poly;} + + if ((sl1->clip ^ sl2->clip) & SMAP_CLIP_V_LESS) + { + along = (SMAP_v_min - sl1->v) / (sl2->v - sl1->v); + + // + // Create a new point on the line v = SMAP_v_min + // + + ASSERT(WITHIN(SMAP_link_upto, 0, SMAP_MAX_LINKS - 1)); + + sc = &SMAP_link[SMAP_link_upto++]; + + sc->wx = sl1->wx + along * (sl2->wx - sl1->wx); + sc->wy = sl1->wy + along * (sl2->wy - sl1->wy); + sc->wz = sl1->wz + along * (sl2->wz - sl1->wz); + + sc->u = sl1->u + along * (sl2->u - sl1->u); + sc->v = SMAP_v_min; + + // + // Set its clipping flags. + // + + sc->clip = 0; + + if (sc->u < SMAP_u_min) {sc->clip |= SMAP_CLIP_U_LESS;} + if (sc->u > SMAP_u_max) {sc->clip |= SMAP_CLIP_U_MORE;} + if (sc->v < SMAP_v_min) {sc->clip |= SMAP_CLIP_V_LESS;} + if (sc->v > SMAP_v_max) {sc->clip |= SMAP_CLIP_V_MORE;} + + // + // Insert it in the linked list. + // + + sc->next = sl->next; + sl->next = sc; + + // + // Don't clip this point again... + // + + sl = sl->next; + } + } + + // + // Take out all points in the linked list outside the SMAP_v_min boundary. + // + + prev = &poly; + next = poly; + + clip_and = 0xffffffff; + clip_or = 0; + + while(1) + { + if (next == NULL) + { + break; + } + + if (next->clip & SMAP_CLIP_V_LESS) + { + // + // Get rid of this point. + // + + *prev = next->next; + next = next->next; + } + else + { + // + // Keep this point. + // + + clip_and &= next->clip; + clip_or |= next->clip; + + prev = &next->next; + next = next->next; + } + } + + // + // Early outs? + // + + if ( clip_and) {return NULL;} + if (!clip_or) {if (SMAP_wrong_side(poly)) {return NULL;} else {SMAP_convert_uvs(poly); return poly;}} + + // ====================== + // + // CLIP TO SMAP_v_max + // + // ====================== + + for (sl = poly; sl; sl = sl->next) + { + sl1 = sl; + sl2 = sl->next; + + if (sl2 == NULL) {sl2 = poly;} + + if ((sl1->clip ^ sl2->clip) & SMAP_CLIP_V_MORE) + { + along = (SMAP_v_max - sl1->v) / (sl2->v - sl1->v); + + // + // Create a new point on the line v = SMAP_v_max + // + + ASSERT(WITHIN(SMAP_link_upto, 0, SMAP_MAX_LINKS - 1)); + + sc = &SMAP_link[SMAP_link_upto++]; + + sc->wx = sl1->wx + along * (sl2->wx - sl1->wx); + sc->wy = sl1->wy + along * (sl2->wy - sl1->wy); + sc->wz = sl1->wz + along * (sl2->wz - sl1->wz); + + sc->u = sl1->u + along * (sl2->u - sl1->u); + sc->v = SMAP_v_max; + + // + // Set its clipping flags. + // + + sc->clip = 0; + + if (sc->u < SMAP_u_min) {sc->clip |= SMAP_CLIP_U_LESS;} + if (sc->u > SMAP_u_max) {sc->clip |= SMAP_CLIP_U_MORE;} + if (sc->v < SMAP_v_min) {sc->clip |= SMAP_CLIP_V_LESS;} + if (sc->v > SMAP_v_max) {sc->clip |= SMAP_CLIP_V_MORE;} + + // + // Insert it in the linked list. + // + + sc->next = sl->next; + sl->next = sc; + + // + // Don't clip this point again... + // + + sl = sl->next; + } + } + + // + // Take out all points in the linked list outside the SMAP_v_max boundary. + // + + prev = &poly; + next = poly; + + clip_and = 0xffffffff; + clip_or = 0; + + while(1) + { + if (next == NULL) + { + break; + } + + if (next->clip & SMAP_CLIP_V_MORE) + { + // + // Get rid of this point. + // + + *prev = next->next; + next = next->next; + } + else + { + // + // Keep this point. + // + + clip_and &= next->clip; + clip_or |= next->clip; + + prev = &next->next; + next = next->next; + } + } + + // + // Early outs? + // + + if ( clip_and) {return NULL;} + if (!clip_or) {if (SMAP_wrong_side(poly)) {return NULL;} else {SMAP_convert_uvs(poly); return poly;}} + + // + // Hmm! Done clipping and still not clipped! + // + + ASSERT(0); + + return NULL; +} diff --git a/fallen/DDEngine/Source/sprite.cpp b/fallen/DDEngine/Source/sprite.cpp new file mode 100644 index 0000000..8f9ec16 --- /dev/null +++ b/fallen/DDEngine/Source/sprite.cpp @@ -0,0 +1,357 @@ +#include +#include "poly.h" +#include "sprite.h" + + + + +#ifdef TARGET_DC +// The DC is having real problems with this many arguments. +void SPRITE_draw_tex_distorted( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + SLONG sort, + SPRITE_draw_tex_distorted_params *pParams) +{ +#define GET_FROM_PARAMS(argname) float argname = pParams->argname + GET_FROM_PARAMS(u); + GET_FROM_PARAMS(v); + GET_FROM_PARAMS(w); + GET_FROM_PARAMS(h); + GET_FROM_PARAMS(wx1); + GET_FROM_PARAMS(wy1); + GET_FROM_PARAMS(wx2); + GET_FROM_PARAMS(wy2); + GET_FROM_PARAMS(wx3); + GET_FROM_PARAMS(wy3); + GET_FROM_PARAMS(wx4); + GET_FROM_PARAMS(wy4); +#undef GET_FROM_PARAMS + +#else //#ifdef TARGET_DC +void SPRITE_draw_tex_distorted( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + float u,float v,float w,float h, + float wx1, float wy1, float wx2, float wy2, float wx3, float wy3, float wx4, float wy4, + SLONG sort) +{ +#endif //#else //#ifdef TARGET_DC + + float screen_size; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + + POLY_transform( + world_x, + world_y, + world_z, + &mid); + + if (mid.IsValid()) + { + screen_size = POLY_world_length_to_screen(world_size) * mid.Z; + + if (mid.X + screen_size < 0 || + mid.X - screen_size > POLY_screen_width || + mid.Y + screen_size < 0 || + mid.Y - screen_size > POLY_screen_height) + { + // + // Off screen. + // + } + else + { + pp[0].X = mid.X - screen_size +wx1; + pp[0].Y = mid.Y - screen_size +wy1; + pp[1].X = mid.X + screen_size +wx2; + pp[1].Y = mid.Y - screen_size +wy2; + pp[2].X = mid.X - screen_size +wx3; + pp[2].Y = mid.Y + screen_size +wy3; + pp[3].X = mid.X + screen_size +wx4; + pp[3].Y = mid.Y + screen_size +wy4; + + pp[0].u = u; + pp[0].v = v; + pp[1].u = u+w; + pp[1].v = v; + pp[2].u = u; + pp[2].v = v+h; + pp[3].u = u+w; + pp[3].v = v+h; + + pp[0].colour = colour; + pp[1].colour = colour; + pp[2].colour = colour; + pp[3].colour = colour; + + pp[0].specular = specular; + pp[1].specular = specular; + pp[2].specular = specular; + pp[3].specular = specular; + + switch(sort) + { + case SPRITE_SORT_NORMAL: + pp[0].z = mid.z; + pp[0].Z = mid.Z; + pp[1].z = mid.z; + pp[1].Z = mid.Z; + pp[2].z = mid.z; + pp[2].Z = mid.Z; + pp[3].z = mid.z; + pp[3].Z = mid.Z; + break; + + case SPRITE_SORT_FRONT: + pp[0].z = 0.01F; + pp[0].Z = 1.00F; + pp[1].z = 0.01F; + pp[1].Z = 1.00F; + pp[2].z = 0.01F; + pp[2].Z = 1.00F; + pp[3].z = 0.01F; + pp[3].Z = 1.00F; + break; + + default: + ASSERT(0); + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + } +} + + + + + +void SPRITE_draw( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + SLONG sort) +{ + float screen_size; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + + POLY_transform( + world_x, + world_y, + world_z, + &mid); + + if (mid.IsValid()) + { + screen_size = POLY_world_length_to_screen(world_size) * mid.Z; + + if (mid.X + screen_size < 0 || + mid.X - screen_size > POLY_screen_width || + mid.Y + screen_size < 0 || + mid.Y - screen_size > POLY_screen_height) + { + // + // Off screen. + // + } + else + { + pp[0].X = mid.X - screen_size; + pp[0].Y = mid.Y - screen_size; + pp[1].X = mid.X + screen_size; + pp[1].Y = mid.Y - screen_size; + pp[2].X = mid.X - screen_size; + pp[2].Y = mid.Y + screen_size; + pp[3].X = mid.X + screen_size; + pp[3].Y = mid.Y + screen_size; + + pp[0].u = 0.0F; + pp[0].v = 0.0F; + pp[1].u = 1.0F; + pp[1].v = 0.0F; + pp[2].u = 0.0F; + pp[2].v = 1.0F; + pp[3].u = 1.0F; + pp[3].v = 1.0F; + + pp[0].colour = colour; + pp[1].colour = colour; + pp[2].colour = colour; + pp[3].colour = colour; + + pp[0].specular = specular; + pp[1].specular = specular; + pp[2].specular = specular; + pp[3].specular = specular; + + switch(sort) + { + case SPRITE_SORT_NORMAL: + pp[0].z = mid.z; + pp[0].Z = mid.Z; + pp[1].z = mid.z; + pp[1].Z = mid.Z; + pp[2].z = mid.z; + pp[2].Z = mid.Z; + pp[3].z = mid.z; + pp[3].Z = mid.Z; + break; + + case SPRITE_SORT_FRONT: + pp[0].z = 0.01F; + pp[0].Z = 1.00F; + pp[1].z = 0.01F; + pp[1].Z = 1.00F; + pp[2].z = 0.01F; + pp[2].Z = 1.00F; + pp[3].z = 0.01F; + pp[3].Z = 1.00F; + break; + + default: + ASSERT(0); + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + } +} + +void SPRITE_draw_tex( + float world_x, + float world_y, + float world_z, + float world_size, + ULONG colour, + ULONG specular, + SLONG page, + float u,float v,float w,float h, + SLONG sort) +{ + float screen_size; + + POLY_Point mid; + POLY_Point pp[4]; + POLY_Point *quad[4]; + + POLY_transform( + world_x, + world_y, + world_z, + &mid, + TRUE); + + if (mid.IsValid()) + { + screen_size = POLY_world_length_to_screen(world_size) * mid.Z; + + if (mid.X + screen_size < 0 || + mid.X - screen_size > POLY_screen_width || + mid.Y + screen_size < 0 || + mid.Y - screen_size > POLY_screen_height) + { + // + // Off screen. + // + } + else + { + pp[0].X = mid.X - screen_size; + pp[0].Y = mid.Y - screen_size; + pp[1].X = mid.X + screen_size; + pp[1].Y = mid.Y - screen_size; + pp[2].X = mid.X - screen_size; + pp[2].Y = mid.Y + screen_size; + pp[3].X = mid.X + screen_size; + pp[3].Y = mid.Y + screen_size; + + pp[0].u = u; + pp[0].v = v; + pp[1].u = u+w; + pp[1].v = v; + pp[2].u = u; + pp[2].v = v+h; + pp[3].u = u+w; + pp[3].v = v+h; + + pp[0].colour = colour; + pp[1].colour = colour; + pp[2].colour = colour; + pp[3].colour = colour; + + pp[0].specular = specular; + pp[1].specular = specular; + pp[2].specular = specular; + pp[3].specular = specular; + + switch(sort) + { + case SPRITE_SORT_NORMAL: + pp[0].z = mid.z; + pp[0].Z = mid.Z; + pp[1].z = mid.z; + pp[1].Z = mid.Z; + pp[2].z = mid.z; + pp[2].Z = mid.Z; + pp[3].z = mid.z; + pp[3].Z = mid.Z; + break; + + case SPRITE_SORT_FRONT: + pp[0].z = 0.01F; + pp[0].Z = 1.00F; + pp[1].z = 0.01F; + pp[1].Z = 1.00F; + pp[2].z = 0.01F; + pp[2].Z = 1.00F; + pp[3].z = 0.01F; + pp[3].Z = 1.00F; + break; + + default: + ASSERT(0); + } + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + POLY_add_quad(quad, page, FALSE, TRUE); + } + } +} + + + diff --git a/fallen/DDEngine/Source/supercrinkle.cpp b/fallen/DDEngine/Source/supercrinkle.cpp new file mode 100644 index 0000000..bd84992 --- /dev/null +++ b/fallen/DDEngine/Source/supercrinkle.cpp @@ -0,0 +1,1105 @@ +// +// SUPERCRINKLES! +// + +#include "game.h" +#include "ddlib.h" +#include "poly.h" +#include "polypoint.h" +#include "polypage.h" +#include "supercrinkle.h" +#include + + + + +#if SUPERCRINKLES_ENABLED + + +// +// The D3DLVERTEX array. +// + +#define SUPERCRINKLE_MAX_LVERTS 16384 + +//D3DLVERTEX SUPERCRINKLE_lvert_buffer[SUPERCRINKLE_MAX_LVERTS + 1]; +D3DLVERTEX *SUPERCRINKLE_lvert_buffer = NULL; +D3DLVERTEX *SUPERCRINKLE_lvert; +SLONG SUPERCRINKLE_lvert_upto; + +// +// Colour interpolations for each lvert. +// + +typedef struct +{ + UBYTE i[4]; + +} SUPERCRINKLE_Colour; + +#define SUPERCRINKLE_MAX_COLOURS SUPERCRINKLE_MAX_LVERTS + +SUPERCRINKLE_Colour SUPERCRINKLE_colour[SUPERCRINKLE_MAX_COLOURS]; +SLONG SUPERCRINKLE_colour_upto; + + +// +// The indices. +// + +#define SUPERCRINKLE_MAX_INDICES (SUPERCRINKLE_MAX_LVERTS * 2) + +UWORD SUPERCRINKLE_index_buffer[SUPERCRINKLE_MAX_INDICES + 16]; +UWORD *SUPERCRINKLE_index; +SLONG SUPERCRINKLE_index_upto; + + + +// +// Whether each page is crinkled or not. +// + +UBYTE SUPERCRINKLE_is_crinkled[512]; + + + +// +// The size of the lighting texure for a crinkle. +// + +#define SUPERCRINKLE_TEXTURE_SIZE 128 + + + +// +// A supercrinkle! +// + +typedef struct +{ + UWORD lvert; // Index into the D3DLVERTEX array. + UWORD num_lverts; // Number of lverts used by this crinkle. + + UWORD index; // DrawIndexedPrimitive indices into the vert array + UWORD num_indices; // for this crinkle. + + ULONG hash; // The colours in this crinkle. + +} SUPERCRINKLE_Crinkle; + +#define SUPERCRINKLE_MAX_CRINKLES 512 + +SUPERCRINKLE_Crinkle SUPERCRINKLE_crinkle[SUPERCRINKLE_MAX_CRINKLES]; + + + +// +// A SUPERCRINKLE_Colour +// + +typedef struct +{ + ULONG colour; + ULONG specular; + +} SUPERCRINKLE_Precalc; + + + + +// +// Cached lighting. +// + +typedef struct supercrinkle_cache +{ + ULONG hash; + + struct supercrinkle_cache *next; + + SUPERCRINKLE_Precalc precalc[2]; // Not really 2! + +} SUPERCRINKLE_Cache; + + + +// +// Three arrays, with different numbers of points... This is about 256k +// + +#define SUPERCRINKLE_MAX_CACHE64 128 +#define SUPERCRINKLE_MAX_CACHE128 96 +#define SUPERCRINKLE_MAX_CACHE384 32 + +union +{ + UBYTE padding[sizeof(SUPERCRINKLE_Cache) + sizeof(SUPERCRINKLE_Precalc) * 64]; + SUPERCRINKLE_Cache cache; + +} SUPERCRINKLE_cache64[SUPERCRINKLE_MAX_CACHE64]; + +union +{ + UBYTE padding[sizeof(SUPERCRINKLE_Cache) + sizeof(SUPERCRINKLE_Precalc) * 128]; + SUPERCRINKLE_Cache cache; + +} SUPERCRINKLE_cache128[SUPERCRINKLE_MAX_CACHE128]; + +union +{ + UBYTE padding[sizeof(SUPERCRINKLE_Cache) + sizeof(SUPERCRINKLE_Precalc) * 384]; + SUPERCRINKLE_Cache cache; + +} SUPERCRINKLE_cache384[SUPERCRINKLE_MAX_CACHE384]; + +// +// A free list for each size. +// + +SUPERCRINKLE_Cache *SUPERCRINKLE_free64; +SUPERCRINKLE_Cache *SUPERCRINKLE_free128; +SUPERCRINKLE_Cache *SUPERCRINKLE_free384; + + +// +// A hash table for each size. +// + +#define SUPERCRINKLE_HASH_SIZE 256 // Power of 2 please. + +SUPERCRINKLE_Cache *SUPERCRINKLE_hash_table64 [SUPERCRINKLE_HASH_SIZE]; +SUPERCRINKLE_Cache *SUPERCRINKLE_hash_table128[SUPERCRINKLE_HASH_SIZE]; +SUPERCRINKLE_Cache *SUPERCRINKLE_hash_table384[SUPERCRINKLE_HASH_SIZE]; + + + + +// +// The hash function. +// + +ULONG SUPERCRINKLE_hash_function(SLONG crinkle, ULONG colour[4], ULONG specular[4]) +{ + ULONG ans; + + ans = crinkle; + + ans ^= _rotr(colour[0], 2); + ans ^= _rotr(colour[1], 7); + ans ^= _rotr(colour[2], 12); + ans ^= _rotr(colour[3], 17); + + ans ^= _rotl(specular[0], 3); + ans ^= _rotl(specular[1], 8); + ans ^= _rotl(specular[2], 13); + ans ^= _rotl(specular[3], 18); + + return ans; +} + + + + + +// +// Loads the given SUPERCRINKLE from the .SEX file. +// + +void SUPERCRINKLE_load(SLONG crinkle, CBYTE *fname) +{ + // + // Temporary buffer for holding points and faces. + // + + typedef struct + { + float x; + float y; + float z; + + float nx; + float ny; + float nz; + + UBYTE i[4]; // The colour interpolations for this point. + + UBYTE light; // How much darker/brigher this point should be than normal... 128 => Same as before. + UBYTE padding; + UWORD duplicate; + + } SUPERCRINKLE_Point; + + #define SUPERCRINKLE_MAX_POINTS 1536 + + SUPERCRINKLE_Point point[SUPERCRINKLE_MAX_POINTS]; + SLONG point_upto; + + typedef struct + { + UWORD p[3]; + + float nx; + float ny; + float nz; + + } SUPERCRINKLE_Face; + + #define SUPERCRINKLE_MAX_FACES 512 + + SUPERCRINKLE_Face face[SUPERCRINKLE_MAX_FACES]; + SLONG face_upto; + + + SLONG i; + SLONG j; + + SLONG o; + SLONG f; + + float x; + float y; + float z; + + float ax; + float ay; + float az; + + float bx; + float by; + float bz; + + float dx; + float dy; + float dz; + + float nx; + float ny; + float nz; + + float dprod; + float length; + float overlength; + + SLONG a; + SLONG b; + SLONG c; + + SLONG p1; + SLONG p2; + SLONG p3; + + SLONG match; + SLONG index; + + CBYTE line[512]; + + SUPERCRINKLE_Crinkle *sc; + SUPERCRINKLE_Face *sf; + SUPERCRINKLE_Point *sp; + D3DLVERTEX *tl; + PolyPage *pp; + + FILE *handle; + + // + // Clear the temporary buffers. + // + + memset(point, 0, sizeof(point)); + memset(face, 0, sizeof(face )); + + point_upto = 0; + face_upto = 0; + + // + // Open the file. + // + + handle = MF_Fopen(fname, "rb"); + + if (!handle) + { + TRACE("Could not open crinkle file \"%s\"\n", fname); + + return; + } + + ASSERT(WITHIN(crinkle, 0, SUPERCRINKLE_MAX_CRINKLES - 1)); + + // + // The new crinkle. + // + + sc = &SUPERCRINKLE_crinkle[crinkle]; + + sc->num_lverts = 0; + sc->num_indices = 0; + sc->lvert = SUPERCRINKLE_lvert_upto; + sc->index = SUPERCRINKLE_index_upto; + + // + // Assume the crinkle index is the same as the POLY_Page index. + // + + pp = &POLY_Page[crinkle]; + + // + // Load the asc. Put the points into the buffer and the faces + // into the CRINKLE_face array. + // + + while(fgets(line, 512, handle)) + { + match = sscanf(line, "Vertex: (%f, %f, %f)", &x, &y, &z); + + if (match == 3) + { + ASSERT(WITHIN(point_upto, 0, SUPERCRINKLE_MAX_POINTS - 1)); + + // + // Found a point. Add it to the buffer. + // + + SWAP_FL(y, z); + x = -x; + + point[point_upto].x = -x; + point[point_upto].y = -y; + point[point_upto].z = z; + + point_upto += 1; + + continue; + } + + match = sscanf(line, "Face: Material %d xyz (%d, %d, %d)", &f, &a, &b, &c); + + if (match == 4) + { + ASSERT(WITHIN(face_upto, 0, SUPERCRINKLE_MAX_FACES - 1)); + + face[face_upto].p[0] = a; + face[face_upto].p[1] = b; + face[face_upto].p[2] = c; + + face_upto += 1; + + continue; + } + } + + // + // Finished with the file. + // + + MF_Fclose(handle); + + // + // What is the bounding rectangle? + // + + float minx = +float(INFINITY); + float miny = +float(INFINITY); + float minz = +float(INFINITY); + + float maxx = -float(INFINITY); + float maxy = -float(INFINITY); + float maxz = -float(INFINITY); + + for (i = 0; i < point_upto; i++) + { + sp = &point[i]; + + if (sp->x < minx) {minx = sp->x;} + if (sp->y < miny) {miny = sp->y;} + if (sp->z < minz) {minz = sp->z;} + + if (sp->x > maxx) {maxx = sp->x;} + if (sp->y > maxy) {maxy = sp->y;} + if (sp->z > maxz) {maxz = sp->z;} + } + + float sizex = maxx - minx; + float sizey = maxy - miny; + float sizez = maxz - minz; + + if (sizey < sizex && sizey < sizez) + { + // + // This is a ground crinkle. ABORT! + // + + SUPERCRINKLE_lvert_upto = sc->lvert; + SUPERCRINKLE_index_upto = sc->index; + + memset(sc, 0, sizeof(SUPERCRINKLE_Crinkle)); + + return; + } + + // + // This is a wall crinkle. + // + + for (i = 0; i < point_upto; i++) + { + sp = &point[i]; + + x = sp->x; + y = sp->y; + z = sp->z; + + x -= minx; + y -= miny; + + x *= 1.0F / 100.0F; + y *= 1.0F / 100.0F; + z *= 1.0F / 100.0F; + + SATURATE(x, 0.0F, 1.0F); + SATURATE(y, 0.0F, 1.0F); + + sp->x = x; + sp->y = y; + sp->z = z; // z is the extrusion coordinate... + } + + // + // Work out the normal of each face. + // + + for (i = 0; i < face_upto; i++) + { + sf = &face[i]; + + ASSERT(WITHIN(sf->p[0], 0, point_upto - 1)); + ASSERT(WITHIN(sf->p[1], 0, point_upto - 1)); + ASSERT(WITHIN(sf->p[2], 0, point_upto - 1)); + + // + // The two vectors of the triangle. + // + + ax = point[sf->p[1]].x - point[sf->p[0]].x; + ay = point[sf->p[1]].y - point[sf->p[0]].y; + az = point[sf->p[1]].z - point[sf->p[0]].z; + + bx = point[sf->p[2]].x - point[sf->p[0]].x; + by = point[sf->p[2]].y - point[sf->p[0]].y; + bz = point[sf->p[2]].z - point[sf->p[0]].z; + + // + // Normal of the triangle. + // + + nx = ay*bz - az*by; + ny = az*bx - ax*bz; + nz = ax*by - ay*bx; + + // + // Normalise the normal. + // + + length = sqrtf(nx*nx + ny*ny + nz*nz); + overlength = 1.0F / length; + + sf->nx = nx * overlength; + sf->ny = ny * overlength; + sf->nz = nz * overlength; + } + + // + // Set the colour interpolations. + // + + float v[4]; + + for (i = 0; i < point_upto; i++) + { + sp = &point[i]; + + v[0] = (1.0F - sp->x) * (1.0F - sp->y); + v[1] = ( sp->x) * (1.0F - sp->y); + v[2] = (1.0F - sp->x) * ( sp->y); + v[3] = ( sp->x) * ( sp->y); + + ASSERT(WITHIN(v[0] + v[1] + v[2] + v[3], 0.9F, 1.1F)); + + sp->i[0] = (UBYTE)(v[0] * 128.0F); + sp->i[1] = (UBYTE)(v[1] * 128.0F); + sp->i[2] = (UBYTE)(v[2] * 128.0F); + sp->i[3] = (UBYTE)(v[3] * 128.0F); + } + + // + // Create duplicate points so that only points with the + // same normals are shared. + // + + for (i = 0; i < face_upto; i++) + { + sf = &face[i]; + + for (j = 0; j < 3; j++) + { + sp = &point[sf->p[j]]; + + if (sp->nx == 0.0F && + sp->ny == 0.0F && + sp->nz == 0.0F) + { + // + // The normal of this point hasn't been set yet. + // Make is equal to this face normal. + // + + sp->nx = sf->nx; + sp->ny = sf->ny; + sp->nz = sf->nz; + } + else + { + // + // Is the normal of this point similar enough to our face? + // + + dprod = + sp->nx * sf->nx + + sp->ny * sf->ny + + sp->nz * sf->nz; + + if (dprod > 0.94F) + { + // + // These normals are similar enough. About 20degrees different. + // + } + else + { + // + // We must create a new point. + // + + ASSERT(WITHIN(point_upto, 0, SUPERCRINKLE_MAX_POINTS - 1)); + + point[point_upto].x = sp->x; + point[point_upto].y = sp->y; + point[point_upto].z = sp->z; + + point[point_upto].nx = sf->nx; + point[point_upto].ny = sf->ny; + point[point_upto].nz = sf->nz; + + point[point_upto].i[0] = sp->i[0]; + point[point_upto].i[1] = sp->i[1]; + point[point_upto].i[2] = sp->i[2]; + point[point_upto].i[3] = sp->i[3]; + + point[point_upto].duplicate = sf->p[j]; + + // + // An index into this new point from the face. + // + + sf->p[j] = point_upto++; + } + } + } + } + + // + // Work out how each point should be lit. + // + + for (i = 0; i < point_upto; i++) + { + sp = &point[i]; + + // + // Kludged so that faces that point to the front are the same brightness + // as normal and other faces aren't! + // + + sp->light = 128; + sp->light += SLONG(sp->nx * 64.0F); + sp->light += SLONG(sp->ny * 64.0F); + } + + // + // Create the DrawIndexedPrim lvert data and the colour interpolation data. + // + + for (i = 0; i < point_upto; i++) + { + sp = &point[i]; + + ASSERT(WITHIN(SUPERCRINKLE_lvert_upto, 0, SUPERCRINKLE_MAX_LVERTS - 1)); + + tl = &SUPERCRINKLE_lvert[SUPERCRINKLE_lvert_upto]; + + tl->x = 256.0F - sp->x * 256.0F; + tl->y = 256.0F - sp->y * 256.0F; + tl->z = sp->z * 256.0F; + + // + // Initialise lighting to reasonable values. + // + + tl->color = 0xff000000 | (sp->light << 16) | (sp->light << 8) | (sp->light << 0); + tl->specular = 0xff000000; + + tl->tu = sp->x; + tl->tv = sp->y; + + #ifdef TEX_EMBED + + // + // UV's depend on the paging... + // + + tl->tu = pp->m_UOffset + tl->tu * pp->m_UScale; + tl->tv = pp->m_VOffset + tl->tv * pp->m_VScale; + + #endif + + ASSERT(SUPERCRINKLE_colour_upto == SUPERCRINKLE_lvert_upto); + + SUPERCRINKLE_colour[SUPERCRINKLE_colour_upto].i[0] = sp->i[0] * sp->light >> 7; + SUPERCRINKLE_colour[SUPERCRINKLE_colour_upto].i[1] = sp->i[1] * sp->light >> 7; + SUPERCRINKLE_colour[SUPERCRINKLE_colour_upto].i[2] = sp->i[2] * sp->light >> 7; + SUPERCRINKLE_colour[SUPERCRINKLE_colour_upto].i[3] = sp->i[3] * sp->light >> 7; + + SUPERCRINKLE_lvert_upto += 1; + SUPERCRINKLE_colour_upto += 1; + + } + + sc->num_lverts = point_upto; + + // + // Create the DrawIndexedPrim face data. + // + + for (i = 0; i < face_upto; i++) + { + sf = &face[i]; + + ASSERT(WITHIN(SUPERCRINKLE_index_upto + 4, 0, SUPERCRINKLE_MAX_INDICES - 1)); + + SUPERCRINKLE_index[SUPERCRINKLE_index_upto + 0] = sf->p[0]; + SUPERCRINKLE_index[SUPERCRINKLE_index_upto + 1] = sf->p[1]; + SUPERCRINKLE_index[SUPERCRINKLE_index_upto + 2] = sf->p[2]; + SUPERCRINKLE_index[SUPERCRINKLE_index_upto + 3] = 0xffff; + + SUPERCRINKLE_index_upto += 4; + } + + sc->num_indices = face_upto * 4; // Four indices per face. + + // + // Mark this page as crinkled. + // + + SUPERCRINKLE_is_crinkled[crinkle] = TRUE; +} + + +void SUPERCRINKLE_init() +{ + SLONG i; + CBYTE fname[512]; + + PolyPage *pp; + + // + // Initalise all the data. + // + + + if ( SUPERCRINKLE_lvert_buffer == NULL ) + { + SUPERCRINKLE_lvert_buffer = (D3DLVERTEX*)MemAlloc ( sizeof(D3DLVERTEX) * ( SUPERCRINKLE_MAX_LVERTS + 1 ) ); + } + + memset(SUPERCRINKLE_lvert_buffer, 0, sizeof(SUPERCRINKLE_lvert_buffer )); + memset(SUPERCRINKLE_index_buffer, 0, sizeof(SUPERCRINKLE_index_buffer )); + memset(SUPERCRINKLE_crinkle, 0, sizeof(SUPERCRINKLE_crinkle )); + memset(SUPERCRINKLE_colour, 0, sizeof(SUPERCRINKLE_colour )); + memset(SUPERCRINKLE_is_crinkled, 0, sizeof(SUPERCRINKLE_is_crinkled )); + memset(SUPERCRINKLE_cache64, 0, sizeof(SUPERCRINKLE_cache64 )); + memset(SUPERCRINKLE_cache128, 0, sizeof(SUPERCRINKLE_cache128 )); + memset(SUPERCRINKLE_cache384, 0, sizeof(SUPERCRINKLE_cache384 )); + memset(SUPERCRINKLE_hash_table64, 0, sizeof(SUPERCRINKLE_hash_table64 )); + memset(SUPERCRINKLE_hash_table128, 0, sizeof(SUPERCRINKLE_hash_table128)); + memset(SUPERCRINKLE_hash_table384, 0, sizeof(SUPERCRINKLE_hash_table384)); + + SUPERCRINKLE_lvert = (D3DLVERTEX *) ((SLONG(SUPERCRINKLE_lvert_buffer) + 31) & ~0x1f); + SUPERCRINKLE_index = (UWORD *) ((SLONG(SUPERCRINKLE_index_buffer) + 31) & ~0x1f); + + SUPERCRINKLE_lvert_upto = 0; + SUPERCRINKLE_index_upto = 0; + SUPERCRINKLE_colour_upto = 0; + + // + // Setup the freelists of cache entries. + // + + for (i = 0; i < SUPERCRINKLE_MAX_CACHE64 - 1; i++) {SUPERCRINKLE_cache64 [i].cache.next = &SUPERCRINKLE_cache64 [i + 1].cache;} + for (i = 0; i < SUPERCRINKLE_MAX_CACHE128 - 1; i++) {SUPERCRINKLE_cache128[i].cache.next = &SUPERCRINKLE_cache128[i + 1].cache;} + for (i = 0; i < SUPERCRINKLE_MAX_CACHE384 - 1; i++) {SUPERCRINKLE_cache384[i].cache.next = &SUPERCRINKLE_cache384[i + 1].cache;} + + SUPERCRINKLE_free64 = &SUPERCRINKLE_cache64 [0].cache; + SUPERCRINKLE_free128 = &SUPERCRINKLE_cache128[0].cache; + SUPERCRINKLE_free384 = &SUPERCRINKLE_cache384[0].cache; + + // + // Load all the crinkles we need. + // + + for (i = 0; i < 512; i++) + { + pp = &POLY_Page[i]; + + if (pp->RS.GetTexture()) + { + // + // This poly page is used. + // + + extern CBYTE TEXTURE_world_dir[]; + extern CBYTE TEXTURE_shared_dir[]; + + if (i < 256) + { + sprintf(fname, "%ssex%03dhi.sex", TEXTURE_world_dir, i); + } + else + { + sprintf(fname, "%ssex%03dhi.sex", TEXTURE_shared_dir, i); + } + + SUPERCRINKLE_load(i,fname); + } + } +} + + + + +// +// Relights the given crinkle. +// + +void SUPERCRINKLE_relight(SLONG crinkle, ULONG colour[4], ULONG specular[4]) +{ + SLONG i; + SLONG j; + + ULONG index; + ULONG hash; + + SLONG cr; + SLONG cg; + SLONG cb; + + SLONG sr; + SLONG sg; + SLONG sb; + + SUPERCRINKLE_Crinkle *sc; + SUPERCRINKLE_Cache *sh; + SUPERCRINKLE_Colour *sl; + SUPERCRINKLE_Precalc *sp; + D3DLVERTEX *lv; + + ASSERT(WITHIN(crinkle, 0, SUPERCRINKLE_MAX_CRINKLES - 1)); + + sc = &SUPERCRINKLE_crinkle[crinkle]; + + // + // The hash value of this lighting. + // + + hash = SUPERCRINKLE_hash_function(crinkle, colour, specular); + + if (sc->hash == hash) + { + // + // This crinkle already has this lighting! (probably...) + // + + return; + } + + // + // Where is our freelist and hashtable? + // + + SUPERCRINKLE_Cache **hash_table; + SUPERCRINKLE_Cache **free_list; + SLONG cache_table_size; + + if (sc->num_lverts <= 64 ) {hash_table = SUPERCRINKLE_hash_table64 ; free_list = &SUPERCRINKLE_free64; cache_table_size = SUPERCRINKLE_MAX_CACHE64; } + else if (sc->num_lverts <= 128) {hash_table = SUPERCRINKLE_hash_table128; free_list = &SUPERCRINKLE_free128; cache_table_size = SUPERCRINKLE_MAX_CACHE128;} + else if (sc->num_lverts <= 384) {hash_table = SUPERCRINKLE_hash_table384; free_list = &SUPERCRINKLE_free384; cache_table_size = SUPERCRINKLE_MAX_CACHE384;} + else + { + // + // More than 384 points in a single crinkle! Yikes! + // + +#ifdef TARGET_DC + // Don't want to know during level builds. + ASSERT(0); +#endif + + return; + } + + // + // Do we have the lighting handy? + // + + index = hash & (SUPERCRINKLE_HASH_SIZE - 1); + + for (sh = hash_table[index]; sh; sh = sh->next) + { + if (sh->hash == hash) + { + // + // Don't bother actually checking the color[] and specular[] value! + // Assume this is correct! + // + + goto found_cached_info; + } + } + + // + // No cached info found. Create it! + // + + if (*free_list == NULL) + { + // + // We must free up a structure. Pick a random one. + // + + ULONG free = rand() % (cache_table_size - 1); + + if (sc->num_lverts <= 64 ) {sh = &SUPERCRINKLE_cache64 [free].cache;} + else if (sc->num_lverts <= 128) {sh = &SUPERCRINKLE_cache128[free].cache;} + else if (sc->num_lverts <= 384) {sh = &SUPERCRINKLE_cache384[free].cache;} + + // + // Remove this from the hash table. + // + + SUPERCRINKLE_Cache **prev; + SUPERCRINKLE_Cache *next; + + prev = &hash_table[sh->hash & (SUPERCRINKLE_HASH_SIZE - 1)]; + next = hash_table[sh->hash & (SUPERCRINKLE_HASH_SIZE - 1)]; + + while(1) + { + if (next == NULL) + { + // + // Reached the end of the list without finding our cache element! + // + + ASSERT(0); + } + + if (next == sh) + { + // + // This is the one to delete. + // + + *prev = next->next; + + break; + } + + prev = &next->next; + next = next->next; + } + } + else + { + // + // Take this element out of the free list. + // + + sh = *free_list; + *free_list = sh->next; + } + + // + // Build the lighting info and put it into *sh. + // + + sh->hash = hash; + sh->next = NULL; + + for (i = 0; i < sc->num_lverts; i++) + { + sl = &SUPERCRINKLE_colour[sc->lvert + i]; + sp = &sh->precalc[i]; + + cr = 0; + cg = 0; + cb = 0; + + sr = 0; + sg = 0; + sb = 0; + + for (j = 0; j < 4; j++) + { + cr += ((colour[j] >> 16) & 0xff) * sl->i[j]; + cg += ((colour[j] >> 8) & 0xff) * sl->i[j]; + cb += ((colour[j] >> 0) & 0xff) * sl->i[j]; + + sr += ((specular[j] >> 16) & 0xff) * sl->i[j]; + sg += ((specular[j] >> 8) & 0xff) * sl->i[j]; + sb += ((specular[j] >> 0) & 0xff) * sl->i[j]; + } + + cr >>= 7; + cg >>= 7; + cb >>= 7; + + sr >>= 7; + sg >>= 7; + sb >>= 7; + + if (cr > 255) {cr = 255;} + if (cg > 255) {cg = 255;} + if (cb > 255) {cb = 255;} + + if (sr > 255) {sr = 255;} + if (sg > 255) {sg = 255;} + if (sb > 255) {sb = 255;} + + sp->colour = (cr << 16) | (cg << 8) | (cb << 0); + sp->specular = (sr << 16) | (sg << 8) | (sb << 0); + + // + // Assume no fogging and that the alpha is the same across the poly. + // + + sp->colour |= colour[0] & 0xff000000; + sp->specular |= 0xff000000; + } + + // + // Add it to the correct hash table. + // + + sh->next = hash_table[index]; + hash_table[index] = sh; + + found_cached_info:; + + // + // Put the lighting into our crinkle. + // + + for (i = 0; i < sc->num_lverts; i++) + { + sp = &sh->precalc[i]; + lv = &SUPERCRINKLE_lvert[sc->lvert + i]; + + lv->color = sp->colour; + lv->specular = sp->specular; + } + + // + // Remember which sort of lighting the crinkle has. + // + + sc->hash = hash; +} + + + + + + +// +// A 32-byte aligned matrix. +// + +UBYTE SUPERCRINKLE_matrix_buffer[sizeof(D3DMATRIX) + 32]; +D3DMATRIX *SUPERCRINKLE_matrix; + + +SLONG SUPERCRINKLE_draw(SLONG page, ULONG colour[4], ULONG specular[4]) +{ + PolyPage *pp; + SUPERCRINKLE_Crinkle *sc; + D3DMULTIMATRIX d3dmm; + + return(0); + + ASSERT(WITHIN(page, 0, SUPERCRINKLE_MAX_CRINKLES - 1)); + ASSERT(SUPERCRINKLE_is_crinkled[page]); + + // + // Light it. + // + + SUPERCRINKLE_relight(page, colour, specular); + + // + // Setup the matrix. + // + + SUPERCRINKLE_matrix = (D3DMATRIX *) ((SLONG(SUPERCRINKLE_matrix_buffer) + 31) & ~0x1f); + + pp = &POLY_Page[page]; + sc = &SUPERCRINKLE_crinkle[page]; + + // + // Set the renderstate. + // + + pp->RS.SetChanged(); + + // + // Setup the multi-matrix stuff... + // + + d3dmm.lpvVertices = SUPERCRINKLE_lvert + sc->lvert; + d3dmm.lpd3dMatrices = SUPERCRINKLE_matrix; + d3dmm.lpvLightDirs = NULL; + d3dmm.lpLightTable = NULL; + + GenerateMMMatrixFromStandardD3DOnes( + SUPERCRINKLE_matrix, + &g_matProjection, + &g_matWorld, + &g_viewData); + + // + // Do the call. + // + + DrawIndPrimMM( + the_display.lp_D3D_Device, + D3DFVF_LVERTEX, + &d3dmm, + sc->num_lverts, + SUPERCRINKLE_index + sc->index, + sc->num_indices); + + return TRUE; +} + + + +#endif + diff --git a/fallen/DDEngine/Source/superfacet.cpp b/fallen/DDEngine/Source/superfacet.cpp new file mode 100644 index 0000000..3b68185 --- /dev/null +++ b/fallen/DDEngine/Source/superfacet.cpp @@ -0,0 +1,2341 @@ +// +// Converts facets to draw indexed primitive calls... +// + +#include "game.h" +#include "ddlib.h" +#include "poly.h" +#include "polypoint.h" +#include "polypage.h" +#include "night.h" +#include "supermap.h" +#include "memory.h" +#include "interfac.h" +#include "supercrinkle.h" +#include "matrix.h" + + + + +#ifndef TARGET_DC +// Only do this on the PC! +#define SUPERFACET_PERFORMANCE +#define POLY_set_local_rotation_none() {} +#else +extern void POLY_set_local_rotation_none(void); + +#endif + +#ifdef SUPERFACET_PERFORMANCE +FILE *SUPERFACET_handle; +SLONG SUPERFACET_total_freed; +SLONG SUPERFACET_total_converted; +SLONG SUPERFACET_total_already_cached; +SLONG SUPERFACET_total_drawn; +SLONG SUPERFACET_num_gameturns; +#endif + + + +// A hack to test the speed of theoretical crinkles. +#undef TESSELATE_DEGREE +//#define TESSELATE_DEGREE 1 + + +#ifdef DEBUG +// Some interesting colouring. +#define SHOW_ME_SUPERFACET_DEBUGGING_PLEASE_BOB defined +#endif + +// +// The verts.... +// + +SLONG SUPERFACET_max_lverts; + +#define SUPERFACET_MAX_LVERTS (SUPERFACET_max_lverts) + +UBYTE *SUPERFACET_lvert_buffer; +D3DLVERTEX *SUPERFACET_lvert; +SLONG SUPERFACET_lvert_upto; + +// +// The indices.... +// + +SLONG SUPERFACET_max_indices; + +#define SUPERFACET_MAX_INDICES (SUPERFACET_max_indices) + +UWORD *SUPERFACET_index; +SLONG SUPERFACET_index_upto; + + +// +// The lvert buffer has an unused range. The beginning +// of the range is where we allocate new data. When +// we free data the end of the range is moved on forwards. +// + +SLONG SUPERFACET_free_range_start; +SLONG SUPERFACET_free_range_end; + + + +#define SUPERFACET_CALL_FLAG_USED (1 << 0) +#define SUPERFACET_CALL_FLAG_2PASS (1 << 1) +#define SUPERFACET_CALL_FLAG_CRINKLED (1 << 2) + +#ifdef SHOW_ME_SUPERFACET_DEBUGGING_PLEASE_BOB +bool m_bShowDebuggingInfo = FALSE; +#endif + + + +typedef struct +{ + UBYTE flag; // TRUE => this call is in use. + UBYTE dir; // The direction of the facet... + UWORD quads; // The number of quads this call draws. + UWORD lvert; + UWORD lvertcount; + UWORD index; + UWORD indexcount; + UWORD index2; // For the 2-pass textures... + UWORD crinkle; // The PolyPage or SUPERCRINKLE for this call... + + LPDIRECT3DTEXTURE2 texture; + LPDIRECT3DTEXTURE2 texture_2pass; // For the 2-pass textures... + +} SUPERFACET_Call; + +#define SUPERFACET_MAX_CALLS 2048 + +SUPERFACET_Call SUPERFACET_call[SUPERFACET_MAX_CALLS]; +SLONG SUPERFACET_call_upto; + + +// +// Incides into the calllist array. +// + +SLONG SUPERFACET_max_facets; + +#define SUPERFACET_MAX_FACETS SUPERFACET_max_facets + +typedef struct +{ + UWORD call; // Index into the SUPERFACET_call[] array + UWORD num; + +} SUPERFACET_Facet; + +SUPERFACET_Facet *SUPERFACET_facet; + + +// +// A circular queue of facets. It remembers the order the +// facets were cached so they can be uncached in the same +// order. +// + +#define SUPERFACET_QUEUE_SIZE 512 // Power of 2 please... + +UWORD SUPERFACET_queue[SUPERFACET_QUEUE_SIZE]; +SLONG SUPERFACET_queue_start; +SLONG SUPERFACET_queue_end; + + + + +// +// A 32-byte aligned matrix. +// + +UBYTE SUPERFACET_matrix_buffer[sizeof(D3DMATRIX) + 32]; +D3DMATRIX *SUPERFACET_matrix; + + + + +// +// The direction matrices for each direction of facet. +// + +float SUPERFACET_direction_matrix[4][9]; + + + + +// +// From facet.cpp +// + +extern ULONG facet_rand (void); +extern void set_facet_seed(SLONG seed); +extern SLONG texture_quad(POLY_Point *quad[4],SLONG texture_style,SLONG pos,SLONG count,SLONG flipx=0); + + + + + + +// +// Frees up the memory for the facet at the end of a queue. +// + +void SUPERFACET_free_end_of_queue(void) +{ + SLONG i; + SLONG facet; + + SUPERFACET_Facet *sf; + SUPERFACET_Call *sc; + + #ifdef SUPERFACET_PERFORMANCE + SUPERFACET_total_freed += 1; + #endif + + ASSERT(SUPERFACET_queue_end < SUPERFACET_queue_start); + + facet = SUPERFACET_queue[SUPERFACET_queue_end & (SUPERFACET_QUEUE_SIZE - 1)]; + + ASSERT(WITHIN(facet, 0, SUPERFACET_MAX_FACETS - 1)); + + sf = &SUPERFACET_facet[facet]; + + // + // Free up all the call structures. + // + + for (i = 0; i < sf->num; i++) + { + ASSERT(WITHIN(sf->call + i, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + i]; + + ASSERT(sc->flag & SUPERFACET_CALL_FLAG_USED); + + sc->flag = 0; + } + + // + // Upto the end of the last call structure is now free. + // + + SUPERFACET_free_range_end = sc->lvert + sc->lvertcount; + + ASSERT(WITHIN(SUPERFACET_free_range_end, 0, SUPERFACET_MAX_LVERTS)); + + // + // If the next call structure is used and is at the beginning of the + // array then all the memory to the end of the lvert array is free. + // + + ASSERT(WITHIN(sf->call + sf->num, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + sf->num]; + + if (sc->flag & SUPERFACET_CALL_FLAG_USED) + { + if (sc->lvert == 0) + { + SUPERFACET_free_range_end = SUPERFACET_MAX_LVERTS; + } + } + + + // + // Pop the facet off the end of the queue. + // + + SUPERFACET_queue_end += 1; + + #ifdef SUPERFACET_PERFORMANCE + fprintf(SUPERFACET_handle, "Game turn %5d freed up facet %4d\n", GAME_TURN, facet); + fflush(SUPERFACET_handle); + #endif + + // + // Mark as unused. + // + + sf->call = 0; + sf->num = 0; +} + + + + + + + + +// +// Returns the actual page used, and converts the texture +// coordinates in the quad. +// + +LPDIRECT3DTEXTURE2 SUPERFACET_convert_texture(SLONG page, POLY_Point *quad[4]) +{ + SLONG i; + + ASSERT(WITHIN(page, 0, 511)); // Special subset of pages just for facets... + + PolyPage *pp = &POLY_Page[page]; + + #ifdef TEX_EMBED + + // + // Convert texture coordinates. + // + + for (i = 0; i < 4; i++) + { + quad[i]->u = quad[i]->u * pp->m_UScale + pp->m_UOffset; + quad[i]->v = quad[i]->v * pp->m_VScale + pp->m_VOffset; + } + + #endif + + return pp->RS.GetTexture(); +} + + + + + +// +// The start of the NIGHT_Colour[] array for this facet. +// So we can work out the index into the NIGHT_Colour[] array +// for each point. +// + +NIGHT_Colour *SUPERFACET_colour_base; + +// +// Stolen from facet.cpp. Fills in POLY_buffer[] with the points +// of the facet. +// + +extern SWORD FacetRows [100]; +extern float FacetDiffY[128]; + +void SUPERFACET_make_facet_points( + float sx, + float sy, + float sz, + float dx, + float dz, + float block_height, + SLONG height, + NIGHT_Colour *col, + SLONG foundation, + SLONG count, + SLONG hug) +{ + SLONG hf = 0; + + POLY_buffer_upto = 0; // or else FacetDiffY is accessed wrongly + + ASSERT(WITHIN(block_height, 32.0F, 256.0F)); + + while (height >= 0) + { + float x = sx; + float y = sy; + float z = sz; + + FacetRows[hf] = POLY_buffer_upto; + + for (SLONG c0 = count; c0 > 0; c0--) + { + float ty; + + ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1)); + + POLY_Point *pp = &POLY_buffer[POLY_buffer_upto++]; + + if (hug) + { + ty = float(PAP_2HI(SLONG(x) >> 8, SLONG(z) >> 8).Alt << 3); + ty += y; + } + else + if (foundation != 2) + { + ty = y; + } + else + { + ty = float(PAP_2HI(SLONG(x) >> 8, SLONG(z) >> 8).Alt << 3); + + FacetDiffY[POLY_buffer_upto - 1] = ( ( y - ty ) * ( 1.0f / 256.0f ) ) + 1.0f; + } + + pp->x = x; + pp->y = ty; + pp->z = z; + + // + // The index into the dfcache array for this facet. + // + + pp->user = col - SUPERFACET_colour_base; + + NIGHT_get_d3d_colour(*col, &pp->colour, &pp->specular); + + x += dx; + z += dz; + col += 1; + } + sy += block_height; + height -= 4; + hf += 1; + foundation -= 1; + } + + FacetRows[hf] = POLY_buffer_upto; +} + + +// +// Generates the points for for the facet. +// + +int m_iFacetDirection; + +void SUPERFACET_create_points(SLONG facet) +{ + SLONG i; + SLONG j; + SLONG dx; + SLONG dz; + SLONG hf; + SLONG height; + SLONG count; + SLONG foundation; + + float sx; + float sy; + float sz; + float block_height; + + LPDIRECT3DTEXTURE2 texture; + DFacet *df; + SUPERFACET_Facet *sf; + SUPERFACET_Call *sc; + POLY_Point *quad[4]; + NIGHT_Colour *col; + + ASSERT(WITHIN(facet, 0, next_dfacet - 1)); + ASSERT(WITHIN(facet, 0, SUPERFACET_MAX_FACETS - 1)); + + df = &dfacets [facet]; + sf = &SUPERFACET_facet[facet]; + + // + // Set the seed for the random facet texture system. + // + + set_facet_seed(df->x[0] * df->z[0] + df->Y[0]); + + // + // How long is the wall? No diagonal walls allowed. + // + + ASSERT(WITHIN(df->Dfcache, 1, NIGHT_MAX_DFCACHES - 1)); + + SUPERFACET_colour_base = col = NIGHT_dfcache[df->Dfcache].colour; + + dx = df->x[1] - df->x[0] << 8; + dz = df->z[1] - df->z[0] << 8; + + sx = float(df->x[0] << 8); + sy = float(df->Y[0] ); + sz = float(df->z[0] << 8); + + ASSERT(!(dx && dz)); + + if (dx) {count = abs(dx) >> 8;} + else {count = abs(dz) >> 8;} + +#ifdef TESSELATE_DEGREE + if ( dx == 0 ) + { + if ( dz > 0 ) + { + m_iFacetDirection = 3; + } + else + { + m_iFacetDirection = 2; + } + } + else if ( dx > 0 ) + { + m_iFacetDirection = 0; + } + else + { + m_iFacetDirection = 1; + } +#endif + + count++; // Count is the number of points, not the number of texture squares... + + if (df->FHeight) + { + foundation = 2; + } + else + { + foundation = 0; + } + + block_height = float(df->BlockHeight << 4); + height = df->Height; + + SUPERFACET_make_facet_points( + sx,sy,sz, + SIGN(dx) * 256.0F, + SIGN(dz) * 256.0F, + block_height, + height, + col, + foundation, + count, + df->FacetFlags & FACET_FLAG_HUG_FLOOR); +} + + + + + + +void SUPERFACET_fill_facet_points( + SLONG count, + ULONG base_row, + SLONG foundation, + SLONG style_index, + float block_height, + SUPERFACET_Call *sc) +{ + SLONG i; + SLONG j; + SLONG page; + float vheight = float(block_height) * ( 1.0f / 256.0f ); + + POLY_Point *quad[4]; + LPDIRECT3DTEXTURE2 texture; + D3DLVERTEX *lv; + + SLONG row1 = FacetRows[base_row]; + SLONG row2 = FacetRows[base_row+1]; + + ASSERT(row2 - row1 == count); + + for (i = 0; i < row2 - row1 - 1; i++) + { + // + // The four points of this quad. + // + + quad[0] = &POLY_buffer[row2 + i + 1]; + quad[1] = &POLY_buffer[row2 + i ]; + quad[2] = &POLY_buffer[row1 + i + 1]; + quad[3] = &POLY_buffer[row1 + i ]; + + page = texture_quad(quad, dstyles[style_index], i, count); + + // + // Scale for block height. + // + + // MASSIVE FUDGE. + if ( quad[0]->v >= 0.9999f ) + { + quad[0]->v = 0.0f; + } + if ( quad[1]->v >= 0.9999f ) + { + quad[1]->v = 0.0f; + } + + + quad[2]->v = vheight; + quad[3]->v = vheight; + + if (foundation == 2) + { + quad[3]->v = FacetDiffY[i ]; + quad[2]->v = FacetDiffY[i + 1]; + + // + // OH MY GOD! FACET FOUNDATION TEXTURES WRAP!!! + // + + // As a panic measure which might sort-of work, clamp the coords to 1. + if ( quad[3]->v > 1.0f ) + { + quad[3]->v = 1.0f; + } + if ( quad[2]->v > 1.0f ) + { + quad[2]->v = 1.0f; + } + } + + // + // Is this texture used in our call? + // + + texture = SUPERFACET_convert_texture(page, quad); + + if (texture == sc->texture) + { + // + // Add this quad to the call structure. First four points. + // + + + #ifdef TESSELATE_DEGREE + //Make some more. + + float fXNorm, fZNorm; + switch ( m_iFacetDirection ) + { + case 0: + fZNorm = 1.0f; + fXNorm = 0.0f; + break; + case 1: + fZNorm = -1.0f; + fXNorm = 0.0f; + break; + case 2: + fZNorm = 0.0f; + fXNorm = 1.0f; + break; + case 3: + fZNorm = 0.0f; + fXNorm = -1.0f; + break; + } + // Random scale. + fXNorm *= 64.0f; + fZNorm *= 64.0f; + + + j = 0; + int iX, iY; + for ( iY = 0; iY <= TESSELATE_DEGREE; iY++ ) + { + for ( iX = 0; iX <= TESSELATE_DEGREE; iX++ ) + { + float fXLerp = (float)iX / (float)TESSELATE_DEGREE; + float fYLerp = (float)iY / (float)TESSELATE_DEGREE; + int iPerturb = ( iX << 6 ) ^ ( iX << 3 ) ^ ( iY << 5 ) ^ ( iY << 1 ) ^ ( page << 1 ) ^ ( page << 5 ); + float fPerturb = (float)( iPerturb & 0xff ) * ( 1.0f / 256.0f ) - 0.5f; + // Stop boring flat perturbs. + if ( ( fPerturb > -0.2f ) || ( fPerturb < 0.2f ) ) + { + fPerturb *= 5.0f; + } + if ( ( iX == 0 ) || ( iX == TESSELATE_DEGREE ) || ( iY == 0 ) || ( iY == TESSELATE_DEGREE ) ) + { + // Edges smooth. + fPerturb = 0.0f; + } + + float fX1 = ( quad[0]->x * fXLerp ) + ( quad[1]->x * ( 1.0f - fXLerp ) ); + float fX2 = ( quad[2]->x * fXLerp ) + ( quad[3]->x * ( 1.0f - fXLerp ) ); + float fY1 = ( quad[0]->y * fXLerp ) + ( quad[1]->y * ( 1.0f - fXLerp ) ); + float fY2 = ( quad[2]->y * fXLerp ) + ( quad[3]->y * ( 1.0f - fXLerp ) ); + float fZ1 = ( quad[0]->z * fXLerp ) + ( quad[1]->z * ( 1.0f - fXLerp ) ); + float fZ2 = ( quad[2]->z * fXLerp ) + ( quad[3]->z * ( 1.0f - fXLerp ) ); + float fU1 = ( quad[0]->u * fXLerp ) + ( quad[1]->u * ( 1.0f - fXLerp ) ); + float fU2 = ( quad[2]->u * fXLerp ) + ( quad[3]->u * ( 1.0f - fXLerp ) ); + float fV1 = ( quad[0]->v * fXLerp ) + ( quad[1]->v * ( 1.0f - fXLerp ) ); + float fV2 = ( quad[2]->v * fXLerp ) + ( quad[3]->v * ( 1.0f - fXLerp ) ); + float fX = ( fX1 * fYLerp ) + ( fX2 * ( 1.0f - fYLerp ) ); + float fY = ( fY1 * fYLerp ) + ( fY2 * ( 1.0f - fYLerp ) ); + float fZ = ( fZ1 * fYLerp ) + ( fZ2 * ( 1.0f - fYLerp ) ); + float fU = ( fU1 * fYLerp ) + ( fU2 * ( 1.0f - fYLerp ) ); + float fV = ( fV1 * fYLerp ) + ( fV2 * ( 1.0f - fYLerp ) ); + + ASSERT(WITHIN(SUPERFACET_lvert_upto+j, 0, SUPERFACET_MAX_LVERTS - 1)); + + lv = &SUPERFACET_lvert[SUPERFACET_lvert_upto + j]; + + lv->x = fX + fPerturb * fXNorm; + lv->y = fY; + lv->z = fZ + fPerturb * fZNorm; + #ifdef SHOW_ME_SUPERFACET_DEBUGGING_PLEASE_BOB + if ( m_bShowDebuggingInfo ) + { + // Make a pretty colour from the call pointer, + // so we can see the efficiency. + DWORD dwColour = (DWORD)sc; + dwColour = ( dwColour >> 2 ) ^ ( dwColour >> 6 ) ^ ( dwColour ) ^ ( dwColour << 3 ); + dwColour = ( dwColour << 9 ) ^ ( dwColour << 19 ) ^ ( dwColour ) ^ ( dwColour << 29 ) ^ ( dwColour >> 3 ); + dwColour &= 0x7f7f7f7f; + lv->color = dwColour; + lv->specular = dwColour; + } + else + #endif + { + lv->specular = quad[0]->specular; + lv->color = quad[0]->colour; + } + lv->tu = fU; + lv->tv = fV; + + j++; + } + } + + // + // Now strip indices. + // + + ASSERT(WITHIN(SUPERFACET_index_upto + j, 0, SUPERFACET_MAX_INDICES - 1)); + + int iCurStart = 0; + for ( iY = 0; iY < TESSELATE_DEGREE; iY++ ) + { + // Do the first two indices. + SUPERFACET_index[SUPERFACET_index_upto + 0] = SUPERFACET_lvert_upto - sc->lvert + iCurStart + 0; + SUPERFACET_index[SUPERFACET_index_upto + 1] = SUPERFACET_lvert_upto - sc->lvert + iCurStart + (TESSELATE_DEGREE+1); + SUPERFACET_index_upto += 2; + for ( iX = 0; iX < TESSELATE_DEGREE; iX++ ) + { + SUPERFACET_index[SUPERFACET_index_upto + 0] = SUPERFACET_lvert_upto - sc->lvert + iCurStart + iX + 1; + SUPERFACET_index[SUPERFACET_index_upto + 1] = SUPERFACET_lvert_upto - sc->lvert + iCurStart + iX + 1 + (TESSELATE_DEGREE+1); + SUPERFACET_index_upto += 2; + } + // Terminate the strip. + SUPERFACET_index[SUPERFACET_index_upto] = -1; + SUPERFACET_index_upto++; + iCurStart += (TESSELATE_DEGREE+1); + } + + sc->lvertcount += (TESSELATE_DEGREE+1)*(TESSELATE_DEGREE+1); + sc->indexcount += (TESSELATE_DEGREE)*( (TESSELATE_DEGREE+1) * 2 + 1 ); + + SUPERFACET_lvert_upto += (TESSELATE_DEGREE+1)*(TESSELATE_DEGREE+1); + + ASSERT(sc->lvert + sc->lvertcount == SUPERFACET_lvert_upto); + ASSERT(sc->index + sc->indexcount == SUPERFACET_index_upto); + #else + + //ASSERT(abs(quad[0]->y - quad[2]->y) <= 257); + + for (j = 0; j < 4; j++) + { + ASSERT(WITHIN(SUPERFACET_lvert_upto, 0, SUPERFACET_MAX_LVERTS - 1)); + + lv = &SUPERFACET_lvert[SUPERFACET_lvert_upto + j]; + + lv->x = quad[j]->x; + lv->y = quad[j]->y; + lv->z = quad[j]->z; + + #ifdef SHOW_ME_SUPERFACET_DEBUGGING_PLEASE_BOB + if ( m_bShowDebuggingInfo || ( abs(quad[0]->y - quad[2]->y) > 257 ) ) + { + // Make a pretty colour from the call pointer, + // so we can see the efficiency. + + // It also shows up things that won't repeat properly. There aren't many, and we can ignore them. + // (e.g. wall of the + DWORD dwColour = (DWORD)sc; + dwColour = ( dwColour >> 2 ) ^ ( dwColour >> 6 ) ^ ( dwColour ) ^ ( dwColour << 3 ); + dwColour = ( dwColour << 9 ) ^ ( dwColour << 19 ) ^ ( dwColour ) ^ ( dwColour << 29 ) ^ ( dwColour >> 3 ); + dwColour &= 0x7f7f7f7f; + lv->color = dwColour; + lv->specular = dwColour; + } + else + #endif + { + lv->color = quad[j]->colour; + lv->specular = quad[j]->specular; + } + lv->tu = quad[j]->u; + lv->tv = quad[j]->v; + lv->dwReserved = quad[j]->user << 16; + } + + // + // Now six indices. + // + + ASSERT(WITHIN(SUPERFACET_index_upto + 4, 0, SUPERFACET_MAX_INDICES - 1)); + +#if 0 + // Striplists + SUPERFACET_index[SUPERFACET_index_upto + 0] = SUPERFACET_lvert_upto - sc->lvert + 0; + SUPERFACET_index[SUPERFACET_index_upto + 1] = SUPERFACET_lvert_upto - sc->lvert + 2; + SUPERFACET_index[SUPERFACET_index_upto + 2] = SUPERFACET_lvert_upto - sc->lvert + 1; + SUPERFACET_index[SUPERFACET_index_upto + 3] = SUPERFACET_lvert_upto - sc->lvert + 3; + SUPERFACET_index[SUPERFACET_index_upto + 4] = 0xffff; + + sc->lvertcount += 4; + sc->indexcount += 5; + + SUPERFACET_lvert_upto += 4; + SUPERFACET_index_upto += 5; +#else + // Lists + SUPERFACET_index[SUPERFACET_index_upto + 0] = SUPERFACET_lvert_upto - sc->lvert + 0; + SUPERFACET_index[SUPERFACET_index_upto + 1] = SUPERFACET_lvert_upto - sc->lvert + 2; + SUPERFACET_index[SUPERFACET_index_upto + 2] = SUPERFACET_lvert_upto - sc->lvert + 1; + SUPERFACET_index[SUPERFACET_index_upto + 3] = SUPERFACET_lvert_upto - sc->lvert + 1; + SUPERFACET_index[SUPERFACET_index_upto + 4] = SUPERFACET_lvert_upto - sc->lvert + 2; + SUPERFACET_index[SUPERFACET_index_upto + 5] = SUPERFACET_lvert_upto - sc->lvert + 3; + + sc->lvertcount += 4; + sc->indexcount += 6; + + SUPERFACET_lvert_upto += 4; + SUPERFACET_index_upto += 6; +#endif + + ASSERT(sc->lvert + sc->lvertcount == SUPERFACET_lvert_upto); + ASSERT(sc->index + sc->indexcount == SUPERFACET_index_upto); + + #endif + } + } + +// for (;i < count; i++) + { + facet_rand(); + } +} + + + + + + + + + + +// +// Builds the 'call'th call structure for the given facet. +// + +void SUPERFACET_build_call(SLONG facet, SLONG call) +{ + SLONG i; + SLONG j; + SLONG dx; + SLONG dz; + SLONG hf; + SLONG height; + SLONG count; + SLONG foundation; + SLONG style_index; + SLONG style_index_step; + + float block_height; + + LPDIRECT3DTEXTURE2 texture; + DFacet *df; + SUPERFACET_Facet *sf; + SUPERFACET_Call *sc; + POLY_Point *quad[4]; + + ASSERT(WITHIN(facet, 0, next_dfacet - 1)); + ASSERT(WITHIN(facet, 0, SUPERFACET_MAX_FACETS - 1)); + + df = &dfacets [facet]; + sf = &SUPERFACET_facet[facet]; + + ASSERT(WITHIN(call, 0, sf->num - 1)); + ASSERT(WITHIN(sf->call + call, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + call]; + + // + // Initialise this call. This texture should already be setup. + // + + sc->index = SUPERFACET_index_upto; + sc->lvert = SUPERFACET_lvert_upto; + sc->indexcount = 0; + sc->lvertcount = 0; + + // + // Set the seed for the random facet texture system. + // + + set_facet_seed(df->x[0] * df->z[0] + df->Y[0]); + + // + // How long is the wall? No diagonal walls allowed. + // + + dx = (df->x[1] - df->x[0]) << 8; + dz = (df->z[1] - df->z[0]) << 8; + + ASSERT(!(dx && dz)); + + if (dx) {count = abs(dx) >> 8;} + else {count = abs(dz) >> 8;} + + count++; // Count is the number of points, not the number of texture squares... + + // + // Set up the styles... + // + + style_index = df->StyleIndex; + + if (df->FacetFlags & FACET_FLAG_2TEXTURED) + { + style_index -= 1; + } + + if (!(df->FacetFlags & FACET_FLAG_HUG_FLOOR) && (df->FacetFlags & (FACET_FLAG_2TEXTURED | FACET_FLAG_2SIDED))) + { + style_index_step = 2; + } + else + { + style_index_step = 1; + } + + // + // Do we have a foundation? + // + + if (df->FHeight) + { + foundation = 2; + } + + block_height = float(df->BlockHeight << 4); + height = df->Height; + + // + // Go through the facet and find all the quads that use + // this call's texture. + // + + hf = 0; + + while (height >= 0) + { + if (hf) + { + SUPERFACET_fill_facet_points( + count, + hf - 1, + foundation + 1, + style_index - 1, + block_height, + sc); + } + + height -= 4; + hf += 1; + foundation -= 1; + style_index += style_index_step; + } + +#ifdef TESSELATE_DEGREE + ASSERT(sc->lvertcount == sc->quads * (TESSELATE_DEGREE+1)*(TESSELATE_DEGREE+1)); +#else + ASSERT(sc->lvertcount == sc->quads * 4); +#endif + + /* + + #ifndef TARGET_DC + + ASSERT(sc->indexcount); + ASSERT(sc->lvertcount); + + #endif + + */ + + SUPERFACET_free_range_start = sc->lvert + sc->lvertcount; + + return; +} + + + +// +// Create a call for each new texture page. +// + +void SUPERFACET_create_calls(SLONG facet, SLONG direction) +{ + SLONG i; + SLONG j; + SLONG dx; + SLONG dz; + SLONG hf; + SLONG page; + SLONG count; + SLONG height; + SLONG style_index; + SLONG style_index_step; + + LPDIRECT3DTEXTURE2 texture; + DFacet *df; + SUPERFACET_Facet *sf; + SUPERFACET_Call *sc; + POLY_Point *quad[4]; + + ASSERT(WITHIN(facet, 0, next_dfacet - 1)); + ASSERT(WITHIN(facet, 0, SUPERFACET_MAX_FACETS - 1)); + + df = &dfacets [facet]; + sf = &SUPERFACET_facet[facet]; + + // + // Set the seed for the random facet texture system. + // + + set_facet_seed(df->x[0] * df->z[0] + df->Y[0]); + + // + // How long is the wall? No diagonal walls allowed. + // + + dx = (df->x[1] - df->x[0]) << 8; + dz = (df->z[1] - df->z[0]) << 8; + + ASSERT(!(dx && dz)); + + if (dx) {count = abs(dx) >> 8;} + else {count = abs(dz) >> 8;} + + count++; // Count is the number of points, not the number of texture squares... + + // + // Set up the styles... + // + + style_index = df->StyleIndex; + + if (df->FacetFlags & FACET_FLAG_2TEXTURED) + { + style_index -= 1; + } + + if (!(df->FacetFlags & FACET_FLAG_HUG_FLOOR) && (df->FacetFlags & (FACET_FLAG_2TEXTURED | FACET_FLAG_2SIDED))) + { + style_index_step = 2; + } + else + { + style_index_step = 1; + } + + // + // Make 'quad' point to a junk bit of memory. + // + + POLY_Point pp[4]; + + memset(pp, 0, sizeof(pp)); + + quad[0] = &pp[0]; + quad[1] = &pp[1]; + quad[2] = &pp[2]; + quad[3] = &pp[3]; + + // + // Go through the facet and find all the textures used by the + // facet. + // + + hf = 0; + height = df->Height; + + while (height >= 0) + { + if (hf) + { + for (i = 0; i < count - 1; i++) + { + page = texture_quad(quad, dstyles[style_index - 1], i, count); + + // + // Find the actual d3d texture used. + // + + texture = SUPERFACET_convert_texture(page, quad); + + // Some textures are indeed NULL, if they are missing. + //ASSERT ( texture != NULL ); + + // + // Do we already have this texture? + // + + for (j = 0; j < sf->num; j++) + { + ASSERT(WITHIN(sf->call + j, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + j]; + + if (sc->texture == texture) + { + // + // Already have a SUPERFACET_Call for this texture. + // + + if (SUPERCRINKLE_IS_CRINKLED(page)) + { + // + // We need the exact page. + // + + if ((sc->flag & SUPERFACET_CALL_FLAG_CRINKLED) && sc->crinkle == page) + { + sc->quads += 1; + + goto already_got_a_call; + } + } + else + { + sc->quads += 1; + + goto already_got_a_call; + } + } + } + + // + // Create a new call structure for this facet. + // + + ASSERT(WITHIN(SUPERFACET_call_upto, 0, SUPERFACET_MAX_CALLS - 1)); + ASSERT(SUPERFACET_call_upto == sf->call + sf->num); + + sc = &SUPERFACET_call[SUPERFACET_call_upto++]; + + ASSERT(!(sc->flag & SUPERFACET_CALL_FLAG_USED)); + + sc->flag = SUPERFACET_CALL_FLAG_USED; + sc->texture = texture; + sc->quads = 1; // Just to be sure... + sc->dir = direction; + + if (POLY_page_flag[page] & POLY_PAGE_FLAG_2PASS) + { + sc->flag |= SUPERFACET_CALL_FLAG_2PASS; + sc->texture_2pass = SUPERFACET_convert_texture(page + 1, quad); + } + + if (page < 512 && SUPERCRINKLE_IS_CRINKLED(page)) + { + sc->flag |= SUPERFACET_CALL_FLAG_CRINKLED; + sc->crinkle = page; + } + + sf->num += 1; + + already_got_a_call:; + } + + facet_rand(); + } + + height -= 4; + hf += 1; + style_index += style_index_step; + } + + return; +} + + + + + + + + +void SUPERFACET_convert_facet(SLONG facet) +{ + SLONG i; + SLONG room; + SLONG memory; + SLONG direction; + + DFacet *df; + SUPERFACET_Facet *sf; + SUPERFACET_Call *sc; + + #ifdef SUPERFACET_PERFORMANCE + SUPERFACET_total_converted += 1; + #endif + + ASSERT(WITHIN(facet, 1, next_dfacet - 1)); + + df = &dfacets[facet]; + + if (df->Dfcache == NULL) + { + // + // Create cached lighting for the facet. + // + + df->Dfcache = NIGHT_dfcache_create(facet); + + ASSERT(df->Dfcache); + } + + // + // What direction does this facet point in? + // + + if (df->z[0] == df->z[1]) + { + if (df->x[0] < df->x[1]) + { + direction = 0; + } + else + { + direction = 2; + } + } + else + { + if (df->z[0] > df->z[1]) + { + direction = 3; + } + else + { + direction = 1; + } + } + + // + // Make sure there'll be enough call structures... On RTA + // there was a max of 12 call structures per facet- use + // 32 just in case. + // + + if (SUPERFACET_call_upto > SUPERFACET_MAX_CALLS - 32) + { + SUPERFACET_call_upto = 0; + } + + // + // Find all the texture pages used by the facet and + // create a SUPERFACET_call for each one of them. + // + + ASSERT(WITHIN(facet, 0, SUPERFACET_MAX_FACETS - 1)); + + sf = &SUPERFACET_facet[facet]; + + sf->call = SUPERFACET_call_upto; + sf->num = 0; + + SUPERFACET_create_calls(facet, direction); + + // + // How much lvert/index memory do we need? + // + + memory = 0; + + for (i = 0; i < sf->num; i++) + { + ASSERT(WITHIN(sf->call + i, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + i]; + + memory += sc->quads * 4; // 4 verts per quad. + } + +// ASSERT(memory < 200 * 4); + + // + // Free up old facets until we have enough room. + // + + while(1) + { + if (SUPERFACET_free_range_start <= SUPERFACET_free_range_end) + { + room = SUPERFACET_free_range_end - SUPERFACET_free_range_start; + } + else + { + room = SUPERFACET_MAX_LVERTS - SUPERFACET_free_range_start; + } + + if (room >= memory) + { + break; + } + + if (SUPERFACET_free_range_start > SUPERFACET_free_range_end) + { + // + // We've looped around... + // + + SUPERFACET_free_range_start = 0; + SUPERFACET_lvert_upto = 0; + SUPERFACET_index_upto = 0; + } + + SUPERFACET_free_end_of_queue(); + } + + // + // Build the points. + // + + SUPERFACET_create_points(facet); + + // + // Create each call. + // + + for (i = 0; i < sf->num; i++) + { + SUPERFACET_build_call(facet, i); + } + + // + // Get rid of the cached lighting. + // + + NIGHT_dfcache_destroy(df->Dfcache); + + df->Dfcache = NULL; + + // + // Add to the queue of facets. + // + + ASSERT(SUPERFACET_queue_start < SUPERFACET_queue_end + SUPERFACET_QUEUE_SIZE); + + SUPERFACET_queue[SUPERFACET_queue_start & (SUPERFACET_QUEUE_SIZE - 1)] = facet; + + SUPERFACET_queue_start++; + + #ifdef SUPERFACET_PERFORMANCE + fprintf(SUPERFACET_handle, "Game turn %5d converted facet %4d\n", GAME_TURN, facet); + fflush(SUPERFACET_handle); + #endif +} + + +void SUPERFACET_init() +{ + #ifdef SUPERFACET_PERFORMANCE + + if (SUPERFACET_handle == NULL) + { + SUPERFACET_handle = fopen("facetcache.txt", "wb"); + } + + SUPERFACET_total_freed = 0; + SUPERFACET_total_converted = 0; + SUPERFACET_total_already_cached = 0; + SUPERFACET_num_gameturns = 0; + + #endif + + // + // How big should our arrays be? + // + + SUPERFACET_max_facets = next_dfacet; +#ifdef TESSELATE_DEGREE + // Mad amount of memory. + SUPERFACET_max_lverts = 40000; +#else + SUPERFACET_max_lverts = 8192; +#endif + +#if 0 + // For striplists + SUPERFACET_max_indices = SUPERFACET_max_lverts * 5 / 4; +#else + // For lists + SUPERFACET_max_indices = SUPERFACET_max_lverts * 6 / 4; +#endif + + // + // Allocate memory. + // + + SUPERFACET_lvert_buffer = (UBYTE *) MemAlloc(sizeof(D3DLVERTEX) * SUPERFACET_MAX_LVERTS + 32); + ASSERT ( SUPERFACET_lvert_buffer != NULL ); + SUPERFACET_index = (UWORD *) MemAlloc(sizeof(UWORD) * SUPERFACET_MAX_INDICES ); + ASSERT ( SUPERFACET_index != NULL ); + SUPERFACET_facet = (SUPERFACET_Facet *) MemAlloc(sizeof(SUPERFACET_Facet) * SUPERFACET_MAX_FACETS ); + ASSERT ( SUPERFACET_facet != NULL ); + + // + // Initialise data. + // + + memset(SUPERFACET_lvert_buffer, 0, sizeof(D3DLVERTEX) * SUPERFACET_MAX_LVERTS + 32); + memset(SUPERFACET_index, 0, sizeof(UWORD) * SUPERFACET_MAX_INDICES ); + memset(SUPERFACET_call, 0, sizeof(SUPERFACET_call)); + memset(SUPERFACET_facet, 0, sizeof(SUPERFACET_Facet) * SUPERFACET_MAX_FACETS); + memset(SUPERFACET_queue, 0, sizeof(SUPERFACET_queue)); + + SUPERFACET_queue_start = 0; + SUPERFACET_queue_end = 0; + + SUPERFACET_free_range_start = 0; + SUPERFACET_free_range_end = SUPERFACET_MAX_LVERTS; + + SUPERFACET_lvert = (D3DLVERTEX *) ((SLONG(SUPERFACET_lvert_buffer) + 31) & ~0x1f); + + SUPERFACET_lvert_upto = 0; + SUPERFACET_index_upto = 0; + SUPERFACET_call_upto = 0; + SUPERFACET_queue_start = 0; + SUPERFACET_queue_end = 0; + + SUPERFACET_matrix = (D3DMATRIX *) ((SLONG(SUPERFACET_matrix_buffer) + 31) & ~0x1f); + + // + // Build the direction matrices. + // + + SLONG i; + + for (i = 0; i < 4; i++) + { + MATRIX_calc( + SUPERFACET_direction_matrix[i], + float(i) * (PI / 2), + 0.0F, + 0.0F); + } + + // + // This bit of code pre-converts all the suitable facets... + // + + #if 0 + + // + // Now go through and find 'common' facets. + // + + SLONG i; + + DFacet *df; + + for (i = 1; i < next_dfacet; i++) + { + df = &dfacets[i]; + + if (df->FacetFlags & FACET_FLAG_INVISIBLE) + { + continue; + } + + if (df->FacetType != STOREY_TYPE_NORMAL) + { + continue; + } + + if (df->FacetFlags & (FACET_FLAG_BARB_TOP | FACET_FLAG_2SIDED | FACET_FLAG_INSIDE)) + { + continue; + } + + if (df->Open) + { + continue; + } + + // + // Now convert each of these 'common' facets. + // + + SUPERFACET_convert_facet(i); + } + + #endif +} + + + +void SUPERFACET_redo_lighting(SLONG facet) +{ + SLONG i; + SLONG j; + + DFacet *df; + SUPERFACET_Call *sc; + SUPERFACET_Facet *sf; + D3DLVERTEX *lv; + + df = &dfacets [facet]; + sf = &SUPERFACET_facet[facet]; + + ASSERT(0); + if (df->Dfcache == NULL) + { + // + // Create cached lighting for the facet. + // + + df->Dfcache = NIGHT_dfcache_create(facet); + + ASSERT(df->Dfcache); + } + + // + // Go through each call structure + // + + NIGHT_Colour *col = NIGHT_dfcache[df->Dfcache].colour; + + for (i = 0; i < sf->num; i++) + { + ASSERT(WITHIN(sf->call + i, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + i]; + + ASSERT(sc->flag & SUPERFACET_CALL_FLAG_USED); + + // + // Go through all this SUPERFACET's points and change their lighting. + // + + for (j = 0; j < sc->lvertcount; j++) + { + lv = &SUPERFACET_lvert[sc->lvert + j]; + + ASSERT(WITHIN(lv->dwReserved >> 16, 0, 2048)); // Sensible number of vertices??? + + NIGHT_get_d3d_colour(col[lv->dwReserved >> 16], &lv->color, &lv->specular); + } + } +} + + + + + +void SUPERFACET_start_frame() +{ + // + // Initialise Tom's doberries... + // + + + +#ifdef SHOW_ME_SUPERFACET_DEBUGGING_PLEASE_BOB +#ifdef DEBUG +#ifdef TARGET_DC + #define BUTTON_IS_PRESSED(value) ((value&0x80)!=0) +extern DIJOYSTATE the_state; + bool bShowDebug = FALSE; + if ( BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_LTRIGGER] ) && BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_RTRIGGER] ) ) + { + bShowDebug = TRUE; + } + + if ( m_bShowDebuggingInfo != bShowDebug ) + { + m_bShowDebuggingInfo = bShowDebug; + // And clear all the facets, so they can be remade in the right colours. + + memset(SUPERFACET_lvert_buffer, 0, sizeof(D3DLVERTEX) * SUPERFACET_MAX_LVERTS + 32); + memset(SUPERFACET_index, 0, sizeof(UWORD) * SUPERFACET_MAX_INDICES ); + memset(SUPERFACET_call, 0, sizeof(SUPERFACET_call)); + memset(SUPERFACET_facet, 0, sizeof(SUPERFACET_Facet) * SUPERFACET_MAX_FACETS); + memset(SUPERFACET_queue, 0, sizeof(SUPERFACET_queue)); + + SUPERFACET_queue_start = 0; + SUPERFACET_queue_end = 0; + + SUPERFACET_free_range_start = 0; + SUPERFACET_free_range_end = SUPERFACET_MAX_LVERTS; + + SUPERFACET_lvert = (D3DLVERTEX *) ((SLONG(SUPERFACET_lvert_buffer) + 31) & ~0x1f); + + SUPERFACET_lvert_upto = 0; + SUPERFACET_index_upto = 0; + SUPERFACET_call_upto = 0; + SUPERFACET_queue_start = 0; + SUPERFACET_queue_end = 0; + + SUPERFACET_matrix = (D3DMATRIX *) ((SLONG(SUPERFACET_matrix_buffer) + 31) & ~0x1f); + + } +#endif +#endif +#endif + + + + +//#ifdef TARGET_DC +//extern void POLY_set_local_rotation_none ( void ); +// POLY_set_local_rotation_none(); +// //POLY_flush_local_rot(); +//#endif +#if 0 + GenerateMMMatrixFromStandardD3DOnes( + SUPERFACET_matrix, + &g_matProjection, + //g_matWorld, + NULL, + &g_viewData); +#endif + #ifdef SUPERFACET_PERFORMANCE + SUPERFACET_num_gameturns += 1; + #endif + + // + // We are using DrawIndexedPrimitive so must call this... + // + + POLY_set_local_rotation_none(); + + POLY_flush_local_rot(); +} + + +#if 0 +// +// The INDEX buffer we use for the 2-pass calls. +// + +#define SUPERFACET_MAX_2PASS_INDICES (6 * 256) // 256 lit windows per facet maximum... + +UWORD SUPERFACET_2pass_index[SUPERFACET_MAX_2PASS_INDICES]; +SLONG SUPERFACET_2pass_index_upto; +#endif + + +SLONG SUPERFACET_draw(SLONG facet) +{ + SLONG i; + SLONG j; + + SUPERFACET_Facet *sf; + SUPERFACET_Call *sc; + + D3DMULTIMATRIX d3dmm; + + #ifdef SUPERFACET_PERFORMANCE + SUPERFACET_total_drawn += 1; + #endif + + #ifndef TARGET_DC + + // + // Not on the PC! + // + + if (Keys[KB_R]) + { + return FALSE; + } + + #endif + + // + // Do we have any pre-calculated info for this facet? + // + + ASSERT(WITHIN(facet, 0, SUPERFACET_MAX_FACETS - 1)); + + sf = &SUPERFACET_facet[facet]; + + if (sf->num == 0) + { + // + // No cached info, create it! + // + + SUPERFACET_convert_facet(facet); + } + #ifdef SUPERFACET_PERFORMANCE + else + { + SUPERFACET_total_already_cached += 1; + } + #endif + + if (dfacets[facet].FacetFlags & FACET_FLAG_DLIT) + { + // + // We must re-create the lighting for this facet. :( + // + + SUPERFACET_redo_lighting(facet); + } + + + POLY_set_local_rotation_none(); + POLY_flush_local_rot(); + + // + // Do a drawindexprim call per 'call' + // + + + // Some default settings, for later. +#if 0 + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA ); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA ); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE ); +#else + // Should do this properly. + the_display.SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + the_display.SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA ); + the_display.SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA ); + the_display.SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE ); +#endif + + + + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_TEXCOORDINDEX, 0 ); + + the_display.lp_D3D_Device->SetTextureStageState ( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + the_display.lp_D3D_Device->SetTextureStageState ( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + + + +#if 1 + // Using DrawIndPrim all the time, not MM. + // Means we don't have to clip. + + + for (i = 0; i < sf->num; i++) + { + ASSERT(WITHIN(sf->call + i, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + i]; + + ASSERT(sc->flag & SUPERFACET_CALL_FLAG_USED); + + if (!sc->indexcount) + { + // + // Oh dear... + // + + continue; + } + + // + // Setup renderstates...? + // + + the_display.lp_D3D_Device->SetTexture(0, sc->texture); + + //ASSERT ( sc->texture != NULL ); + + if (sc->flag & SUPERFACET_CALL_FLAG_CRINKLED) + { + // + // Draw each quad separately... + // + + // Doesn't work yet. + ASSERT ( FALSE ); + + ULONG colour [4]; + ULONG specular[4]; + + SLONG index[4]; + + for (j = 0; j < sc->indexcount; j += 6) + { + index[0] = sc->lvert + SUPERFACET_index[sc->index + j + 0]; + index[1] = sc->lvert + SUPERFACET_index[sc->index + j + 1]; + index[2] = sc->lvert + SUPERFACET_index[sc->index + j + 2]; + index[3] = sc->lvert + SUPERFACET_index[sc->index + j + 5]; + + //ASSERT(SUPERFACET_index[sc->index + j + 4] == 0xffff); + + ASSERT(WITHIN(index[0], 0, SUPERFACET_MAX_LVERTS - 1)); + ASSERT(WITHIN(index[1], 0, SUPERFACET_MAX_LVERTS - 1)); + ASSERT(WITHIN(index[2], 0, SUPERFACET_MAX_LVERTS - 1)); + ASSERT(WITHIN(index[3], 0, SUPERFACET_MAX_LVERTS - 1)); + + float world_x; + float world_y; + float world_z; + + if (SUPERFACET_lvert[index[0]].tu > SUPERFACET_lvert[index[2]].tu) + { + // + // We must x-flip the crinkle... + // + + ASSERT(WITHIN(sc->dir, 0, 3)); + + world_x = SUPERFACET_lvert[index[1]].x; + world_y = SUPERFACET_lvert[index[1]].y; + world_z = SUPERFACET_lvert[index[1]].z; + + SUPERFACET_direction_matrix[sc->dir][0] = -SUPERFACET_direction_matrix[sc->dir][0]; + SUPERFACET_direction_matrix[sc->dir][1] = -SUPERFACET_direction_matrix[sc->dir][1]; + SUPERFACET_direction_matrix[sc->dir][2] = -SUPERFACET_direction_matrix[sc->dir][2]; + + POLY_set_local_rotation( + world_x, + world_y, + world_z, + SUPERFACET_direction_matrix[sc->dir]); + + SUPERFACET_direction_matrix[sc->dir][0] = -SUPERFACET_direction_matrix[sc->dir][0]; + SUPERFACET_direction_matrix[sc->dir][1] = -SUPERFACET_direction_matrix[sc->dir][1]; + SUPERFACET_direction_matrix[sc->dir][2] = -SUPERFACET_direction_matrix[sc->dir][2]; + + + static UBYTE order[4] = {2,0,3,1}; + + + /* + if ((GAME_TURN & 0x1f) == 0) + { + SLONG a; + SLONG b; + + SLONG twizzle; + + for (twizzle = 0; twizzle < 5; twizzle++) + { + a = rand() & 3; + b = rand() & 3; + + SWAP(order[a],order[b]); + } + } + */ + + colour[0] = SUPERFACET_lvert[index[order[0]]].color; + colour[1] = SUPERFACET_lvert[index[order[1]]].color; + colour[2] = SUPERFACET_lvert[index[order[2]]].color; + colour[3] = SUPERFACET_lvert[index[order[3]]].color; + + specular[0] = SUPERFACET_lvert[index[order[0]]].specular; + specular[1] = SUPERFACET_lvert[index[order[1]]].specular; + specular[2] = SUPERFACET_lvert[index[order[2]]].specular; + specular[3] = SUPERFACET_lvert[index[order[3]]].specular; + + } + else + { + world_x = SUPERFACET_lvert[index[3]].x; + world_y = SUPERFACET_lvert[index[3]].y; + world_z = SUPERFACET_lvert[index[3]].z; + + ASSERT(WITHIN(sc->dir, 0, 3)); + + POLY_set_local_rotation( + world_x, + world_y, + world_z, + SUPERFACET_direction_matrix[sc->dir]); + + static UBYTE order[4] = {0,2,1,3}; + + /* + + if ((GAME_TURN & 0x1f) == 0) + { + SLONG a; + SLONG b; + + SLONG twizzle; + + for (twizzle = 0; twizzle < 5; twizzle++) + { + a = rand() & 3; + b = rand() & 3; + + SWAP(order[a],order[b]); + } + } + + */ + + colour[0] = SUPERFACET_lvert[index[order[0]]].color; + colour[1] = SUPERFACET_lvert[index[order[1]]].color; + colour[2] = SUPERFACET_lvert[index[order[2]]].color; + colour[3] = SUPERFACET_lvert[index[order[3]]].color; + + specular[0] = SUPERFACET_lvert[index[order[0]]].specular; + specular[1] = SUPERFACET_lvert[index[order[1]]].specular; + specular[2] = SUPERFACET_lvert[index[order[2]]].specular; + specular[3] = SUPERFACET_lvert[index[order[3]]].specular; + + + } + + SUPERCRINKLE_draw( + sc->crinkle, + colour, + specular); + + + POLY_set_local_rotation_none(); + POLY_flush_local_rot(); + + } + } + else + { + +#if 0 + // + // Setup transform states...? + // + + D3DMULTIMATRIX d3dmm = + { + SUPERFACET_lvert + sc->lvert, + SUPERFACET_matrix, + NULL, + NULL + }; +#endif + + + +#if 1 + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + SUPERFACET_lvert + sc->lvert, + sc->lvertcount, + SUPERFACET_index + sc->index, + sc->indexcount, + 0); + +#else + DrawIndPrimMM( + the_display.lp_D3D_Device, + D3DFVF_LVERTEX, + &d3dmm, + sc->lvertcount, + SUPERFACET_index + sc->index, + sc->indexcount); +#endif + } + + // + // What about those 2-pass texture pages??? + // + + if (sc->flag & SUPERFACET_CALL_FLAG_2PASS) + { + // + // Create a 2pass index list from this index list. + // + +#if 0 + SUPERFACET_2pass_index_upto = 0; + for (j = 0; j < sc->indexcount; j += 5) + { + ASSERT(WITHIN(SUPERFACET_2pass_index_upto + 5, 0, SUPERFACET_MAX_2PASS_INDICES - 1)); + + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 0] = SUPERFACET_index[sc->index + j + 0]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 1] = SUPERFACET_index[sc->index + j + 1]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 2] = SUPERFACET_index[sc->index + j + 2]; + + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 3] = SUPERFACET_index[sc->index + j + 3]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 4] = SUPERFACET_index[sc->index + j + 2]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 5] = SUPERFACET_index[sc->index + j + 1]; + + SUPERFACET_2pass_index_upto += 6; + } +#endif + + // Switch the modes for the windows. + the_display.lp_D3D_Device->SetTexture(0, sc->texture_2pass); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); + +#if 1 + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + SUPERFACET_lvert + sc->lvert, + sc->lvertcount, + SUPERFACET_index + sc->index, + sc->indexcount, + 0); +#else + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + SUPERFACET_lvert + sc->lvert, + sc->lvertcount, + SUPERFACET_2pass_index, + SUPERFACET_2pass_index_upto, + //SUPERFACET_index + sc->index, + //sc->indexcount, + 0); +#endif + + // And go back to sanity. + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + + + } + } + + + +#else + // Using DrawIndPrimMM - a pain in the arse. + +#define USING_MULTITEX_FOR_WINDOWS 0 + + + for (i = 0; i < sf->num; i++) + { + ASSERT(WITHIN(sf->call + i, 0, SUPERFACET_MAX_CALLS - 1)); + + sc = &SUPERFACET_call[sf->call + i]; + + ASSERT(sc->flag & SUPERFACET_CALL_FLAG_USED); + + if (!sc->indexcount) + { + // + // Oh dear... + // + + continue; + } + + // + // Setup renderstates...? + // + + the_display.lp_D3D_Device->SetTexture(0, sc->texture); + + //ASSERT ( sc->texture != NULL ); + + if (sc->flag & SUPERFACET_CALL_FLAG_CRINKLED) + { + // + // Draw each quad separately... + // + + ULONG colour [4]; + ULONG specular[4]; + + SLONG index[4]; + + for (j = 0; j < sc->indexcount; j += 5) + { + index[0] = sc->lvert + SUPERFACET_index[sc->index + j + 0]; + index[1] = sc->lvert + SUPERFACET_index[sc->index + j + 1]; + index[2] = sc->lvert + SUPERFACET_index[sc->index + j + 2]; + index[3] = sc->lvert + SUPERFACET_index[sc->index + j + 3]; + + ASSERT(SUPERFACET_index[sc->index + j + 4] == 0xffff); + + ASSERT(WITHIN(index[0], 0, SUPERFACET_MAX_LVERTS - 1)); + ASSERT(WITHIN(index[1], 0, SUPERFACET_MAX_LVERTS - 1)); + ASSERT(WITHIN(index[2], 0, SUPERFACET_MAX_LVERTS - 1)); + ASSERT(WITHIN(index[3], 0, SUPERFACET_MAX_LVERTS - 1)); + + float world_x; + float world_y; + float world_z; + + if (SUPERFACET_lvert[index[0]].tu > SUPERFACET_lvert[index[2]].tu) + { + // + // We must x-flip the crinkle... + // + + ASSERT(WITHIN(sc->dir, 0, 3)); + + world_x = SUPERFACET_lvert[index[1]].x; + world_y = SUPERFACET_lvert[index[1]].y; + world_z = SUPERFACET_lvert[index[1]].z; + + SUPERFACET_direction_matrix[sc->dir][0] = -SUPERFACET_direction_matrix[sc->dir][0]; + SUPERFACET_direction_matrix[sc->dir][1] = -SUPERFACET_direction_matrix[sc->dir][1]; + SUPERFACET_direction_matrix[sc->dir][2] = -SUPERFACET_direction_matrix[sc->dir][2]; + + POLY_set_local_rotation( + world_x, + world_y, + world_z, + SUPERFACET_direction_matrix[sc->dir]); + + SUPERFACET_direction_matrix[sc->dir][0] = -SUPERFACET_direction_matrix[sc->dir][0]; + SUPERFACET_direction_matrix[sc->dir][1] = -SUPERFACET_direction_matrix[sc->dir][1]; + SUPERFACET_direction_matrix[sc->dir][2] = -SUPERFACET_direction_matrix[sc->dir][2]; + + + static UBYTE order[4] = {2,0,3,1}; + + + /* + if ((GAME_TURN & 0x1f) == 0) + { + SLONG a; + SLONG b; + + SLONG twizzle; + + for (twizzle = 0; twizzle < 5; twizzle++) + { + a = rand() & 3; + b = rand() & 3; + + SWAP(order[a],order[b]); + } + } + */ + + colour[0] = SUPERFACET_lvert[index[order[0]]].color; + colour[1] = SUPERFACET_lvert[index[order[1]]].color; + colour[2] = SUPERFACET_lvert[index[order[2]]].color; + colour[3] = SUPERFACET_lvert[index[order[3]]].color; + + specular[0] = SUPERFACET_lvert[index[order[0]]].specular; + specular[1] = SUPERFACET_lvert[index[order[1]]].specular; + specular[2] = SUPERFACET_lvert[index[order[2]]].specular; + specular[3] = SUPERFACET_lvert[index[order[3]]].specular; + + } + else + { + world_x = SUPERFACET_lvert[index[3]].x; + world_y = SUPERFACET_lvert[index[3]].y; + world_z = SUPERFACET_lvert[index[3]].z; + + ASSERT(WITHIN(sc->dir, 0, 3)); + + POLY_set_local_rotation( + world_x, + world_y, + world_z, + SUPERFACET_direction_matrix[sc->dir]); + + static UBYTE order[4] = {0,2,1,3}; + + /* + + if ((GAME_TURN & 0x1f) == 0) + { + SLONG a; + SLONG b; + + SLONG twizzle; + + for (twizzle = 0; twizzle < 5; twizzle++) + { + a = rand() & 3; + b = rand() & 3; + + SWAP(order[a],order[b]); + } + } + + */ + + colour[0] = SUPERFACET_lvert[index[order[0]]].color; + colour[1] = SUPERFACET_lvert[index[order[1]]].color; + colour[2] = SUPERFACET_lvert[index[order[2]]].color; + colour[3] = SUPERFACET_lvert[index[order[3]]].color; + + specular[0] = SUPERFACET_lvert[index[order[0]]].specular; + specular[1] = SUPERFACET_lvert[index[order[1]]].specular; + specular[2] = SUPERFACET_lvert[index[order[2]]].specular; + specular[3] = SUPERFACET_lvert[index[order[3]]].specular; + + + } + + SUPERCRINKLE_draw( + sc->crinkle, + colour, + specular); + + extern void POLY_set_local_rotation_none(void); + + POLY_set_local_rotation_none(); + POLY_flush_local_rot(); + + } + } + else + { + // + // Setup transform states...? + // + + #if 0 + // I keep getting "datatype misalignment" errors on this on the DC. Let's do something more conventional. + D3DMULTIMATRIX d3dmm = + { + SUPERFACET_lvert + sc->lvert, + SUPERFACET_matrix, + NULL, + NULL + }; + #else + d3dmm.lpvVertices = SUPERFACET_lvert + sc->lvert; + d3dmm.lpd3dMatrices = SUPERFACET_matrix; + d3dmm.lpvLightDirs = NULL; + d3dmm.lpLightTable = NULL; + #endif + + /* + + + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + SUPERFACET_lvert + sc->lvert, + sc->lvertcount, + SUPERFACET_index + sc->index, + sc->indexcount, + 0); + */ + + //TRACE ( "S5" ); + DrawIndPrimMM( + the_display.lp_D3D_Device, + D3DFVF_LVERTEX, + &d3dmm, + sc->lvertcount, + SUPERFACET_index + sc->index, + sc->indexcount); + //TRACE ( "F5" ); + } + + // + // What about those 2-pass texture pages??? + // + + if (sc->flag & SUPERFACET_CALL_FLAG_2PASS) + { + // + // Create a 2pass index list from this index list. + // + + SUPERFACET_2pass_index_upto = 0; + + for (j = 0; j < sc->indexcount; j += 5) + { + ASSERT(WITHIN(SUPERFACET_2pass_index_upto + 5, 0, SUPERFACET_MAX_2PASS_INDICES - 1)); + + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 0] = SUPERFACET_index[sc->index + j + 0]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 1] = SUPERFACET_index[sc->index + j + 1]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 2] = SUPERFACET_index[sc->index + j + 2]; + + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 3] = SUPERFACET_index[sc->index + j + 3]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 4] = SUPERFACET_index[sc->index + j + 2]; + SUPERFACET_2pass_index[SUPERFACET_2pass_index_upto + 5] = SUPERFACET_index[sc->index + j + 1]; + + SUPERFACET_2pass_index_upto += 6; + } + + the_display.lp_D3D_Device->SetTexture(0, sc->texture_2pass); + + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_NOTEQUAL); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHAREF, 0 ); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE ); + + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_DECAL); + + /* + + DrawIndPrimMM( + the_display.lp_D3D_Device, + D3DFVF_LVERTEX, + &d3dmm, + sc->lvertcount, + SUPERFACET_index + sc->index, + sc->indexcount); + + */ + + the_display.lp_D3D_Device->DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + D3DFVF_LVERTEX, + SUPERFACET_lvert + sc->lvert, + sc->lvertcount, + SUPERFACET_2pass_index, + SUPERFACET_2pass_index_upto, + //SUPERFACET_index + sc->index, + //sc->indexcount, + 0); + + // And go back to sanity. + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + the_display.lp_D3D_Device->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + } + } + + +#endif + + return TRUE; +} + + +void SUPERFACET_fini() +{ + // + // Free memory. + // + + MemFree(SUPERFACET_lvert_buffer); + MemFree(SUPERFACET_index ); + MemFree(SUPERFACET_facet ); + + #ifdef SUPERFACET_PERFORMANCE + + fprintf(SUPERFACET_handle, "Number of gameturns = %5d\n", SUPERFACET_num_gameturns ); + fprintf(SUPERFACET_handle, "Total facets freed = %5d\n", SUPERFACET_total_freed ); + fprintf(SUPERFACET_handle, "Total facets converted = %5d\n", SUPERFACET_total_converted ); + fprintf(SUPERFACET_handle, "Total facets drawn = %5d\n", SUPERFACET_total_drawn ); + fprintf(SUPERFACET_handle, "Total facets precached = %5d\n", SUPERFACET_total_already_cached); + fprintf(SUPERFACET_handle, "Percentage cached = %5f%%\n", float(SUPERFACET_total_already_cached) * 100.0F / float(SUPERFACET_total_drawn)); + + fflush(SUPERFACET_handle); + + #endif +} + diff --git a/fallen/DDEngine/Source/sw.cpp b/fallen/DDEngine/Source/sw.cpp new file mode 100644 index 0000000..a1d53e1 --- /dev/null +++ b/fallen/DDEngine/Source/sw.cpp @@ -0,0 +1,6438 @@ +// +// Sofware renderer hacked in! +// + +#include "ddlib.h" +#include "sw.h" +#include "poly.h" +#include "texture.h" +#include "elev.h" +#include "game.h" + + +#ifndef TARGET_DC + + +#define THIS_IS_INCLUDED_FROM_SW + + +// +// Tom's swizzling! +// + +static char swizzle_table[16] = { + 0x00, 0x01, 0x04, 0x05, + 0x10, 0x11, 0x14, 0x15, + 0x40, 0x41, 0x44, 0x45, + 0x50, 0x51, 0x54, 0x55 }; + + +// +// In texture.cpp... +// + +extern D3DTexture TEXTURE_texture[]; + + +// +// Our back-buffer. +// + +ULONG *SW_buffer; +#ifdef TARGET_DC +// Spoof that sucker! +ULONG SW_buffer_memory[1]; +#else +ULONG SW_buffer_memory[SW_MAX_WIDTH * SW_MAX_HEIGHT + 2]; // + 2 to ensure quadword alignment. +#endif +SLONG SW_buffer_width; +SLONG SW_buffer_height; +SLONG SW_buffer_pitch; // In ULONGs + +#define SW_PIXEL(x,y) (SW_buffer + (x) + (y) * SW_buffer_pitch) + + +// +// The lines we are rendering to for widescreen. +// + +SLONG SW_render_top; +SLONG SW_render_bot; + + +// +// Our textures. +// + +typedef struct +{ + CBYTE name[256]; + SLONG size; + TGA_Pixel *data; + UBYTE blurred; + UBYTE halved; + +} SW_Texture; + +#ifdef TARGET_DC +#define SW_MAX_TEXTURES 1 +#else +#define SW_MAX_TEXTURES (22 * 64 + 110) +#endif + +SW_Texture SW_texture[SW_MAX_TEXTURES]; + + +// +// How we draw each texture page. +// + +UBYTE SW_page[SW_MAX_TEXTURES]; + + +// +// For alpha pages, this is the z-sort they are forced to have. +// + +UWORD SW_bucket[SW_MAX_TEXTURES]; + + +// +// The 'masked' triangles. +// + +typedef struct sw_masked +{ + SLONG x1, y1, z1, r1, g1, b1, u1, v1; + SLONG x2, y2, z2, r2, g2, b2, u2, v2; + SLONG x3, y3, z3, r3, g3, b3, u3, v3; + + TGA_Pixel *tga; + SLONG tga_size; + + struct sw_masked *next; + +} SW_Masked; + +#ifdef TARGET_DC +#define SW_MAX_MASKED 1 +#else +#define SW_MAX_MASKED 4096 +#endif + +SW_Masked SW_masked[SW_MAX_MASKED]; +SLONG SW_masked_upto; + + +// +// The masked triangle buckets... +// + +#ifdef TARGET_DC +#define SW_MAX_BUCKETS 1 +#else +#define SW_MAX_BUCKETS 256 +#endif + +SW_Masked *SW_masked_bucket[SW_MAX_BUCKETS]; + + + + + + +// +// The alpha sprites. +// + +typedef struct sw_alpha +{ + SLONG x1, y1, u1, v1; + SLONG x2, y2, u2, v2; + SLONG x3, y3, u3, v3; + + SLONG wz, wa, wr, wg, wb; + + TGA_Pixel *tga; + UWORD tga_size; + UWORD mode; + + sw_alpha *next; + +} SW_Alpha; + +#ifdef TARGET_DC +#define SW_MAX_ALPHAS 1 +#else +#define SW_MAX_ALPHAS 2048 +#endif + +SW_Alpha SW_alpha[SW_MAX_ALPHAS]; +SLONG SW_alpha_upto; + +// +// The sprite buckets. +// + +SW_Alpha *SW_alpha_bucket [SW_MAX_BUCKETS]; +SW_Alpha **SW_alpha_bucket_end[SW_MAX_BUCKETS]; // The address of the last pointer of the linked list- so we can add sprites at the end! + + + + + + + + +void SW_set_page(SLONG page, SLONG type) +{ + if (!WITHIN(page, 0, SW_MAX_TEXTURES - 1)) + { + return; + } + + SW_page[page] = type; +} + + + + + +// +// The spans. +// + +typedef struct sw_span +{ + UWORD x1; // 0-bit fixed point + UWORD x2; // 0-bit fixed point + + SLONG z; // 16-bit fixed point and between 0.0F and 1.0F + SLONG dz; // 16-bit fixed point and between 0.0F and 1.0F + + SLONG r; // 16-bit fixed point. + SLONG dr; // 16-bit fixed point. + + SLONG g; // 16-bit fixed point. + SLONG dg; // 16-bit fixed point. + + SLONG b; // 16-bit fixed point. + SLONG db; // 16-bit fixed point. + + SLONG u; // 16-bit fixed point. + SLONG du; // 16-bit fixed point. + + SLONG v; // 16-bit fixed point. + SLONG dv; // 16-bit fixed point. + + TGA_Pixel *tga; + UWORD tga_size; + UWORD a; // a is for alpha + + struct sw_span *next; + +} SW_Span; + + +#ifdef TARGET_DC + +// I'm not wasting 8Mb for something we'll never need! +#define SW_MAX_SPANS 1 + +#else + +#define SW_MAX_SPANS 0x20000 + +#endif + +SW_Span SW_span[SW_MAX_SPANS]; +SLONG SW_span_upto; + + + + +// +// The spans for each line of the screen. +// + +// Defined in the header +//#define SW_MAX_HEIGHT 480 + +SW_Span *SW_line[SW_MAX_HEIGHT]; + + + + + +#ifndef TARGET_DC + + +// ======================================================== +// +// Assembler fixed point thingies from T.A.C. +// +// ======================================================== + +static inline SLONG DIV16(SLONG a, SLONG b) +{ + SLONG v; + _asm + { + mov edx,a + mov ebx,b + mov eax,edx + shl eax,16 + sar edx,16 + idiv ebx + mov v,eax + } + return v; +} + +#pragma warning( disable : 4035 ) +// stop warning of no return value : eax is valid +static inline SLONG MUL16(SLONG a, SLONG b) +// MSVC++ version, params:ecx,edx, return:eax +// this is as fast on 486/Pentium as the old version +// and 2.5* faster on Pentium Pro +{ + __asm + { + mov eax, a + imul b // result in edx:eax + shl edx,16 + shr eax,16 + or eax,edx + // return in eax + } +} +#pragma warning( default : 4035 ) + + + + +#else //#ifndef TARGET_DC + + +// Dreamcast versions. Might be inlined later, just C for now. +// Also very approximate - DC compiler doesn't like long long, so trash the accuracy. +static inline SLONG DIV16(SLONG a, SLONG b) +{ + SLONG ta, tb; + int iShift; + + // return ( ( a << 16 ) / b ); + + + iShift = 0; + + if ( a < 0x10000 ) + { + return ( ( a << 16 ) / b ); + } + else if ( a < 0x1000000 ) + { + return ( ( a << 8 ) / ( b >> 8 ) ); + } + else + { + return ( a / ( b >> 16 ) ); + } + +} + +static inline SLONG MUL16(SLONG a, SLONG b) +{ + // return ( ( a * b ) >> 16 ); + + if ( a < 0x10000 ) + { + // a is small, b might be big. + return ( ( a * ( b >> 16 ) ) ); + } + else if ( a < 0x1000000 ) + { + // both are about the same size. + return ( ( a >> 8 ) * ( b >> 8 ) ); + } + else + { + // a is big, b should be small. + return ( ( a >> 16 ) * b ); + } +} + + +#endif //#else //#ifndef TARGET_DC + + + +// ======================================================== +// +// RECIPROCAL CODE +// +// ======================================================== + + +// +// Reciprocals are useful... so we store loads of them! The reciprocals are +// in 16bit fixed point. 1 / 0 = 1 ... apparently! +// + +// These reciprocals are such that recip[x] = DIV16(0x10000, x << 16). + +// There is no need ever to access recipminus yourself, just do recip[-5] for +// example, and it will work... honest! +// + +// DONT ACCESS THESE DIRECTLY- GO THROUGH THE #defines! + +#define ALWAYS_HOW_MANY_RECIPS_MINUS 1024 +#define ALWAYS_HOW_MANY_RECIPS 32768 + +extern SLONG ALWAYS_recipminus[ALWAYS_HOW_MANY_RECIPS_MINUS]; +extern SLONG ALWAYS_recip [ALWAYS_HOW_MANY_RECIPS]; + +// +// These reciprocals are such that recippt[x] = DIV16(0x10000, x), as such +// some values cannot be held in an int so recippt[0] and recippt[1] and +// recippt[2] are all set to 0x10000. +// + +#ifdef TARGET_DC +#define ALWAYS_HOW_MANY_RECIPPT 1024 +#else +#define ALWAYS_HOW_MANY_RECIPPT 65536 +#endif + +extern SLONG ALWAYS_recippt[ALWAYS_HOW_MANY_RECIPPT]; + + +#ifndef NDEBUG + +SLONG ALWAYS_recip_slow (SLONG x, CBYTE *file, SLONG line); +SLONG ALWAYS_recippt_slow(SLONG x, CBYTE *file, SLONG line); + +#define RECIPPT(x) (ALWAYS_recippt_slow(x, __FILE__, __LINE__)) +#define RECIP(x) (ALWAYS_recip_slow (x, __FILE__, __LINE__)) + +#else + +#define RECIP(x) (ALWAYS_recip[x]) +#define RECIPPT(x) (ALWAYS_recippt[x]) + +#endif + + + +// These two should be kept next to eachother compiler! + +SLONG ALWAYS_recipminus[ALWAYS_HOW_MANY_RECIPS_MINUS]; +SLONG ALWAYS_recip [ALWAYS_HOW_MANY_RECIPS]; +SLONG ALWAYS_recippt [ALWAYS_HOW_MANY_RECIPPT]; + + + +void ALWAYS_init() +{ + SLONG i; + + + // Calculate the reciprocals... + + for (i = 1; i < ALWAYS_HOW_MANY_RECIPS; i++) + { + ALWAYS_recip[i] = DIV16(1 << 16, i << 16); + } + + for (i = 1; i < ALWAYS_HOW_MANY_RECIPS_MINUS; i++) + { + ALWAYS_recipminus[ALWAYS_HOW_MANY_RECIPS_MINUS - i] = DIV16(-1 << 16, i << 16); + } + + for (i = 3; i < ALWAYS_HOW_MANY_RECIPPT; i++) + { + ALWAYS_recippt[i] = DIV16(1 << 16, i); + } + + // 1 / 0 = 1 ... apparently! + + ALWAYS_recip[0] = 0x10000; + + ALWAYS_recippt[0] = 0x10000; + ALWAYS_recippt[1] = 0x10000; + ALWAYS_recippt[2] = 0x10000; +} + +#ifndef NDEBUG + +SLONG ALWAYS_recip_slow(SLONG x, CBYTE *file, SLONG line) +{ + if (x <= -ALWAYS_HOW_MANY_RECIPS_MINUS || + x >= ALWAYS_HOW_MANY_RECIPS) + { + ASSERT(0); + + return (0x10000); + } + + return ALWAYS_recip[x]; +} + +SLONG ALWAYS_recippt_slow(SLONG x, CBYTE *file, SLONG line) +{ + if (x < 0 || + x >= ALWAYS_HOW_MANY_RECIPPT) + { + ASSERT(0); + + return (0x10000); + } + + return ALWAYS_recippt[x]; +} + + +#endif + + + + + + + + + + + + + + + + + +void SW_init( + SLONG width, + SLONG height) +{ + SLONG i; + + ASSERT(WITHIN(width, 16, SW_MAX_WIDTH )); + ASSERT(WITHIN(height, 16, SW_MAX_HEIGHT)); + + SW_buffer_width = width; + SW_buffer_height = height; + SW_buffer_pitch = width; + SW_buffer = SW_buffer_memory; + + // + // Initialise the spans. + // + + memset(SW_line, 0, sizeof(SW_line)); + + SW_span_upto = 0; + + // + // Clear the masked triangle and sprites. + // + + SW_alpha_upto = 0; + SW_masked_upto = 0; + + memset(SW_alpha_bucket, 0, sizeof(SW_alpha_bucket )); + memset(SW_masked_bucket, 0, sizeof(SW_masked_bucket)); + + for (i = 0; i < SW_MAX_BUCKETS; i++) + { + SW_alpha_bucket_end[i] = &SW_alpha_bucket[i]; + } + + // + // Make sure the reciprocals are initialised + // + + { + static int recips_initialised = 0; + + if (!recips_initialised) + { + recips_initialised = TRUE; + + ALWAYS_init(); + } + } +} + + + + + +// +// Inserts a new span. WARNING! This function will allocate +// new spans from the arrays. +// + +void SW_insert_span(SW_Span *ss, SLONG line) +{ + SLONG pixels; + + SW_Span *ss_next; + SW_Span **ss_prev; + + // + // Valid span? + // + + ASSERT(WITHIN(line, 0, SW_buffer_height - 1)); + + ASSERT(WITHIN(ss->x1, 0, SW_buffer_width)); + ASSERT(WITHIN(ss->x2, 0, SW_buffer_width)); + + ss_prev = &SW_line[line]; + ss_next = SW_line[line]; + + while(1) + { + if (ss_next == NULL || ss->x2 <= ss_next->x1) + { + // + // This is where to insert the span. + // + + *ss_prev = ss; + ss->next = ss_next; + + return; + } + + // + // Does the new span overlap with the existing span? + // + + if (ss->x1 < ss_next->x2) + { + // + // The spans do overlap! Only one can survive! + // + + // + // Some very rough z-sort values! + // + + SLONG ss_sort = ss->z; + SLONG ss_next_sort = ss_next->z; + + if (ss_sort < ss_next_sort) + { + // + // The new span is in front of the old one. So we must + // clip the old span to the new one. + // + + if (ss->x1 > ss_next->x1) + { + // + // The left bit of the old span survives. + // + + if (ss->x2 >= ss_next->x2) + { + // + // OOOOOOO (Old span) + // NNNNNNNNNNN (New span) + // + // We only need to make the old span end sooner! + // + + ss_next->x2 = ss->x1; + + // + // Continue to check the next span... + // + + ss_prev = &ss_next->next; + ss_next = ss_next->next; + } + else + { + // + // OOOOOOOOOOOOOOO + // NNNNNNNNN + // + // We need to split the old span into two and put the + // new one in the middle. + // + + // + // Create a new span (the second bit of the old one) + // + + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + SW_Span *ss_extra; + + ss_extra = &SW_span[SW_span_upto++]; + + pixels = ss->x2 - ss_next->x1; + + ss_extra->x1 = ss->x2; + ss_extra->x2 = ss_next->x2; + ss_extra->du = ss_next->du; + ss_extra->dv = ss_next->dv; + ss_extra->dr = ss_next->dr; + ss_extra->dg = ss_next->dg; + ss_extra->db = ss_next->db; + ss_extra->dz = ss_next->dz; + ss_extra->u = ss_next->u + ss_next->du * pixels; + ss_extra->v = ss_next->v + ss_next->dv * pixels; + ss_extra->r = ss_next->r + ss_next->dr * pixels; + ss_extra->g = ss_next->g + ss_next->dg * pixels; + ss_extra->b = ss_next->b + ss_next->db * pixels; + ss_extra->z = ss_next->z + ss_next->dz * pixels; + ss_extra->tga = ss_next->tga; + ss_extra->tga_size = ss_next->tga_size; + + // + // Shorten the old one. + // + + ss_next->x2 = ss->x1; + + // + // Put the three spans in the correct order. + // + + ss_extra->next = ss_next->next; + ss_next->next = ss; + ss->next = ss_extra; + + // + // They should follow on from one-another. + // + + ASSERT(ss_next->x2 == ss_next->next->x1 && ss_next->next->x2 == ss_next->next->next->x1); + + return; + } + } + else + { + // + // The left hand edge of the old span doesn't survive. + // + + if (ss->x2 >= ss_next->x2) + { + // + // OOOOOOOOOO + // NNNNNNNNNNNNNNNNNNN + // + // The right hand edge of the old span doesn't survive either. + // The old span is completely engulfed by the new one. + // + + *ss_prev = ss_next->next; + ss_next = ss_next->next; + } + else + { + // + // OOOOOOOOOOO + // NNNNNNNNN + // + // Make the old span start later. + // + + pixels = ss->x2 - ss_next->x1; + + ss_next->x1 = ss->x2; + ss_next->u += ss_next->du * pixels; + ss_next->v += ss_next->dv * pixels; + ss_next->r += ss_next->dr * pixels; + ss_next->g += ss_next->dg * pixels; + ss_next->b += ss_next->db * pixels; + ss_next->z += ss_next->dz * pixels; + + // + // Put the new span in before this one. + // + + *ss_prev = ss; + ss->next = ss_next; + + return; + } + } + } + else + { + // + // The old span is in front of the new one. + // + + if (ss_next->x1 > ss->x1) + { + // + // The left hand bit of the new span survives. + // + + if (ss_next->x2 >= ss->x2) + { + // + // NNNNNNNNNN + // OOOOOOOOOOOOOOOO + // + // Just make the new span end sooner. + // + + ss->x2 = ss_next->x1; + + // + // Insert it before the old span. + // + + *ss_prev = ss; + ss->next = ss_next; + + return; + } + else + { + // + // NNNNNNNNNNNNNNN + // OOOOOOOOO + // + // Spilt the new span into two. + // + + // + // The second bit of the new span. + // + + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + SW_Span *ss_extra; + + ss_extra = &SW_span[SW_span_upto++]; + + pixels = ss_next->x2 - ss->x1; + + ss_extra->x1 = ss_next->x2; + ss_extra->x2 = ss->x2; + ss_extra->du = ss->du; + ss_extra->dv = ss->dv; + ss_extra->dr = ss->dr; + ss_extra->dg = ss->dg; + ss_extra->db = ss->db; + ss_extra->dz = ss->dz; + ss_extra->u = ss->u + ss->du * pixels; + ss_extra->v = ss->v + ss->dv * pixels; + ss_extra->r = ss->r + ss->dr * pixels; + ss_extra->g = ss->g + ss->dg * pixels; + ss_extra->b = ss->b + ss->db * pixels; + ss_extra->z = ss->z + ss->dz * pixels; + ss_extra->tga = ss->tga; + ss_extra->tga_size = ss->tga_size; + + // + // Shorten the old bit. + // + + ss->x2 = ss_next->x1; + + // + // Insert the shortened bit. + // + + *ss_prev = ss; + ss->next = ss_next; + + // + // Continue to insert the extra bit... + // + + ss = ss_extra; + + ss_prev = &ss_next->next; + ss_next = ss_next->next; + } + } + else + { + // + // The left hand edge of the new span doesn't survive. + // + + if (ss_next->x2 >= ss->x2) + { + // + // NNNNNNNN + // OOOOOOOOOOOOO + // + // The old span completely engulfs the new one. + // + + return; + } + else + { + // + // NNNNNNNNNNNN + // OOOOOOOOO + // + // Just make the new span start later. + // + + pixels = ss_next->x2 - ss->x1; + + ss->x1 = ss_next->x2; + ss->u += ss->du * pixels; + ss->v += ss->dv * pixels; + ss->r += ss->dr * pixels; + ss->g += ss->dg * pixels; + ss->b += ss->db * pixels; + ss->z += ss->dz * pixels; + + // + // Continue clipping against the other spans... + // + + ss_prev = &ss_next->next; + ss_next = ss_next->next; + } + } + + } + } + else + { + ss_prev = &ss_next->next; + ss_next = ss_next->next; + } + } +} + + + + + +// +// Toms mmx code. +// + + + + + +// +// Draws an alpha span with the given mode. +// + +#define SW_MODE_MASKED 0 +#define SW_MODE_ALPHA 1 +#define SW_MODE_ADDITIVE 2 +#define SW_MODE_ALPHA_NOZ 3 +#define SW_MODE_ADDITIVE_NOZ 4 + +void SW_draw_span_reference(SW_Span *ss, SLONG line, SLONG mode) +{ + SLONG i; + SLONG x; + + ULONG *dest; + ULONG pixel; + SLONG a; + SLONG r; + SLONG g; + SLONG b; + SLONG R; + SLONG G; + SLONG B; + SLONG pr; + SLONG pg; + SLONG pb; + SLONG pa; + SLONG u; + SLONG v; + SLONG U; + SLONG V; + SLONG oa; + SLONG or; + SLONG og; + SLONG ob; + SLONG br; + SLONG bg; + SLONG bb; + + switch(mode) + { + case SW_MODE_MASKED: + + r = ss->r; + g = ss->g; + b = ss->b; + u = ss->u; + v = ss->v; + + dest = SW_buffer + ss->x1 + line * SW_buffer_pitch; + + for (x = ss->x1; x < ss->x2; x++) + { + R = r >> 16; + G = g >> 16; + B = b >> 16; + U = u >> 16; + V = v >> 16; + U &= ss->tga_size - 1; + V &= ss->tga_size - 1; + + pa = ss->tga[U + V * ss->tga_size].alpha; + pr = ss->tga[U + V * ss->tga_size].red; + pg = ss->tga[U + V * ss->tga_size].green; + pb = ss->tga[U + V * ss->tga_size].blue; + + if (pa <= 128) + { + dest++; + } + else + { + ASSERT(WITHIN(R, 0, 255)); + ASSERT(WITHIN(G, 0, 255)); + ASSERT(WITHIN(B, 0, 255)); + + pr = pr * R >> 7; + pg = pg * G >> 7; + pb = pb * B >> 7; + + if (pr > 255) {pr = 255;} + if (pg > 255) {pg = 255;} + if (pb > 255) {pb = 255;} + + *dest++ = (pr << 16) | (pg << 8) | pb; + } + + r += ss->dr; + g += ss->dg; + b += ss->db; + u += ss->du; + v += ss->dv; + } + + break; + + case SW_MODE_ALPHA: + + // + // Constant rgba... + // + + a = ss->a; + r = ss->r; + g = ss->g; + b = ss->b; + u = ss->u; + v = ss->v; + + dest = SW_buffer + ss->x1 + line * SW_buffer_pitch; + + for (x = ss->x1; x < ss->x2; x++) + { + U = u >> 16; + V = v >> 16; + U &= ss->tga_size - 1; + V &= ss->tga_size - 1; + + pa = ss->tga[U + V * ss->tga_size].alpha; + pr = ss->tga[U + V * ss->tga_size].red; + pg = ss->tga[U + V * ss->tga_size].green; + pb = ss->tga[U + V * ss->tga_size].blue; + + if (pa == 0) + { + // + // Optimisation? Maybe not! + // + + dest++; + } + else + { + // + // Source values. + // + + pa = pa * a >> 8; + pr = pr * r >> 8; + pg = pg * g >> 8; + pb = pb * b >> 8; + + if (pr > 255) {pr = 255;} + if (pg > 255) {pg = 255;} + if (pb > 255) {pb = 255;} + + if (pa == 255) + { + *dest++ = (pr << 16) | (pg << 8) | pb; + } + else + { + // + // The rgb of the pixel now. + // + + or = (*dest >> 16) & 0xff; + og = (*dest >> 8) & 0xff; + ob = (*dest >> 0) & 0xff; + + // + // Blend! + // + + br = or * (255 - pa) + pr * pa >> 8; + bg = og * (255 - pa) + pg * pa >> 8; + bb = ob * (255 - pa) + pb * pa >> 8; + + ASSERT(WITHIN(br, 0, 255)); + ASSERT(WITHIN(bg, 0, 255)); + ASSERT(WITHIN(bb, 0, 255)); + + // + // Plot! + // + + *dest++ = (br << 16) | (bg << 8) | bb; + } + } + + u += ss->du; + v += ss->dv; + } + + break; + + case SW_MODE_ADDITIVE: + + // + // Constant rgba... + // + + r = ss->r; + g = ss->g; + b = ss->b; + u = ss->u; + v = ss->v; + + dest = SW_buffer + ss->x1 + line * SW_buffer_pitch; + + for (x = ss->x1; x < ss->x2; x++) + { + U = u >> 16; + V = v >> 16; + U &= ss->tga_size - 1; + V &= ss->tga_size - 1; + + pr = ss->tga[U + V * ss->tga_size].red; + pg = ss->tga[U + V * ss->tga_size].green; + pb = ss->tga[U + V * ss->tga_size].blue; + + pr = pr * r >> 7; + pg = pg * g >> 7; + pb = pb * b >> 7; + + // + // The rgb of the pixel now. + // + + or = (*dest >> 16) & 0xff; + og = (*dest >> 8) & 0xff; + ob = (*dest >> 0) & 0xff; + + pr += or; + pg += og; + pb += ob; + + if (pr > 255) {pr = 255;} + if (pg > 255) {pg = 255;} + if (pb > 255) {pb = 255;} + + *dest++ = (pr << 16) | (pg << 8) | pb; + + u += ss->du; + v += ss->dv; + } + + break; + + default: + ASSERT(0); + break; + } +} + + + + +#ifndef TARGET_DC + + + + +#define SWIZZLE 1 + +#define ALPHA_NONE 0 +#define ALPHA_TEST 1 +#define ALPHA_ADD 2 +#define ALPHA_BLEND 3 + + +inline void SW_draw_span_masked(SW_Span *ss, SLONG line, SLONG mode) +{ + #undef ALPHA_MODE + #define ALPHA_MODE ALPHA_TEST + + #include "tom.cpp" +} + +inline void SW_draw_span_alpha(SW_Span *ss, SLONG line, SLONG mode) +{ + #undef ALPHA_MODE + #define ALPHA_MODE ALPHA_BLEND + + #include "tom.cpp" +} + + +inline void SW_draw_span_additive(SW_Span *ss, SLONG line, SLONG mode) +{ + #undef ALPHA_MODE + #define ALPHA_MODE ALPHA_ADD + + #include "tom.cpp" +} + +void SW_draw_span(SW_Span *ss, SLONG line, SLONG mode) +{ + switch(mode) + { + case SW_MODE_MASKED: + SW_draw_span_masked(ss, line, mode); + break; + + case SW_MODE_ALPHA: + + ss->r <<= 16; + ss->g <<= 16; + ss->b <<= 16; + + SW_draw_span_alpha(ss, line, mode); + + break; + + case SW_MODE_ADDITIVE: + + ss->r <<= 16; + ss->g <<= 16; + ss->b <<= 16; + + SW_draw_span_additive(ss, line, mode); + + break; + + default: + ASSERT(0); + break; + } +} + + +#else //#ifndef TARGET_DC + + +// Cheezily wrapped for now. +void SW_draw_span(SW_Span *ss, SLONG line, SLONG mode) +{ + SW_draw_span_reference(ss, line, mode); +} + + +#endif //#else //#ifndef TARGET_DC + + + + + +void SW_add_masked_triangle( + SLONG x1, SLONG y1, SLONG z1, SLONG r1, SLONG g1, SLONG b1, SLONG u1, SLONG v1, + SLONG x2, SLONG y2, SLONG z2, SLONG r2, SLONG g2, SLONG b2, SLONG u2, SLONG v2, + SLONG x3, SLONG y3, SLONG z3, SLONG r3, SLONG g3, SLONG b3, SLONG u3, SLONG v3, + TGA_Pixel *tga, + SLONG tga_size) +{ + // + // The zsort value of the triangle. + // + + z1 -= 4; + z2 -= 4; + z3 -= 4; + + SLONG zsort = z1 + z2 + z2 + z3 >> 4; + + SATURATE(zsort, 0, SW_MAX_BUCKETS - 1); + + // + // Create a masked triangle structure. + // + + ASSERT(WITHIN(SW_masked_upto, 0, SW_MAX_MASKED - 1)); + + SW_Masked *sm = &SW_masked[SW_masked_upto++]; + + sm->x1 = x1; sm->y1 = y1; sm->z1 = z1; sm->r1 = r1; sm->g1 = g1; sm->b1 = b1; sm->u1 = u1; sm->v1 = v1; + sm->x2 = x2; sm->y2 = y2; sm->z2 = z2; sm->r2 = r2; sm->g2 = g2; sm->b2 = b2; sm->u2 = u2; sm->v2 = v2; + sm->x3 = x3; sm->y3 = y3; sm->z3 = z3; sm->r3 = r3; sm->g3 = g3; sm->b3 = b3; sm->u3 = u3; sm->v3 = v3; + sm->tga = tga; + sm->tga_size = tga_size; + + // + // Add it to the bucket list. + // + + sm->next = SW_masked_bucket[zsort]; + SW_masked_bucket[zsort] = sm; +} + +void SW_add_alpha_sprite( + SLONG x1, SLONG y1, SLONG u1, SLONG v1, + SLONG x2, SLONG y2, SLONG u2, SLONG v2, + SLONG x3, SLONG y3, SLONG u3, SLONG v3, + SLONG wz, SLONG wa, SLONG wr, SLONG wg, SLONG wb, // For the whole triangle. + TGA_Pixel *tga, + SLONG tga_size, + SLONG mode) +{ + // + // The zsort value of the triangle. + // + + SLONG zsort = wz >> 2; + + SATURATE(zsort, 0, SW_MAX_BUCKETS - 1); + + // + // Create a masked triangle structure. + // + + ASSERT(WITHIN(SW_alpha_upto, 0, SW_MAX_ALPHAS - 1)); + + SW_Alpha *sa = &SW_alpha[SW_alpha_upto++]; + + sa->x1 = x1; sa->y1 = y1; sa->u1 = u1; sa->v1 = v1; + sa->x2 = x2; sa->y2 = y2; sa->u2 = u2; sa->v2 = v2; + sa->x3 = x3; sa->y3 = y3; sa->u3 = u3; sa->v3 = v3; + sa->tga = tga; + sa->tga_size = tga_size; + sa->wz = wz; + sa->wa = wa; + sa->wr = wr; + sa->wg = wg; + sa->wb = wb; + sa->mode = mode; + + // + // Add it to the end of the bucket list- so the polys are drawn in the + // order they are submitted! + // + + sa->next = NULL; + *(SW_alpha_bucket_end[zsort]) = sa; + SW_alpha_bucket_end[zsort] = &sa->next; +} + + + + + +// +// Clips the span and then draws the bits that survive. +// + +void SW_clip_and_draw_span(SW_Span *ss, SLONG line, SLONG mode) +{ + SLONG ss_sort; + SLONG ss_next_sort; + SLONG pixels; + + SW_Span *ss_next; + + // + // Valid span? + // + + ASSERT(WITHIN(line, 0, SW_buffer_height - 1)); + + ASSERT(WITHIN(ss->x1, 0, SW_buffer_width)); + ASSERT(WITHIN(ss->x2, 0, SW_buffer_width)); + + ss_next = SW_line[line]; + + // + // The sort value of this span. + // + + ss_sort = ss->z; + + while(1) + { + if (ss_next == NULL || ss->x2 <= ss_next->x1) + { + // + // Draw the span. + // + + SW_draw_span(ss, line, mode); + + return; + } + + // + // Does the alpha span overlap with the existing span? + // + + if (ss->x1 < ss_next->x2) + { + // + // Yes! What is the zsort of the two spans? + // + + ss_sort = ss->z; + ss_next_sort = ss_next->z; + + if (ss_sort > ss_next_sort) + { + // + // The alpha span is behind- so we must clip it. + // + + if (ss->x1 < ss_next->x1) + { + // + // The left hand edge of the alpha span survives. + // + + if (ss->x2 > ss_next->x2) + { + // + // AAAAAAAAAAAAAAAAA + // OOOOOOOOOO + // + // There is also another bit to the right, that + // survives as well. + // + + // + // OPTIMISATION REQUIRED? THERE IS PROBABLY ANOTHER SPAN + // AFTER THIS ONE SO WE COULD NOT BOTHER CREATING THE + // EXTRA SPAN... + // + + // + // Create the new span to the right. + // + + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + SW_Span *ss_extra = &SW_span[SW_span_upto++]; + + pixels = ss_next->x2 - ss->x1; + + ss_extra->x1 = ss_next->x2; + ss_extra->x2 = ss->x2; + ss_extra->u = ss->u + ss->du * pixels; + ss_extra->v = ss->v + ss->dv * pixels; + ss_extra->du = ss->du; + ss_extra->dv = ss->dv; + ss_extra->tga = ss->tga; + ss_extra->tga_size = ss->tga_size; + + if (mode == SW_MODE_MASKED) + { + ss_extra->z = ss->z + ss->dz * pixels; + ss_extra->r = ss->r + ss->dr * pixels; + ss_extra->g = ss->g + ss->dg * pixels; + ss_extra->b = ss->b + ss->db * pixels; + ss_extra->dz = ss->dz; + ss_extra->dr = ss->dr; + ss_extra->dg = ss->dg; + ss_extra->db = ss->db; + } + else + { + ss_extra->z = ss->z; + ss_extra->r = ss->r; + ss_extra->g = ss->g; + ss_extra->b = ss->b; + ss_extra->a = ss->a; + } + + // + // Shorten the left-hand span and draw it. + // + + ss->x2 = ss_next->x1; + + SW_draw_span(ss, line, mode); + + // + // Continue checking the next span. + // + + ss = ss_extra; + } + else + { + // + // AAAAAAAAA + // OOOOOOOOOO + // + // Easy just shorten the length of the alpha span and draw it. + // + + ss->x2 = ss_next->x1; + + SW_draw_span(ss, line, mode); + + return; + } + } + else + { + // + // The left hand edge of the alpha span doesn't survive. + // + + if (ss->x2 < ss_next->x2) + { + // + // The right hand edge doesn't survive either. It it + // completely z-buffered out. + // + + return; + } + else + { + // + // AAAAAAAAAAAAA + // OOOOOOOOOO + // + // Only the right hand edge of the alpha span survives. + // + + pixels = ss_next->x2 - ss->x1; + + ss->x1 = ss_next->x2; + ss->u += ss->du * pixels; + ss->v += ss->dv * pixels; + + if (mode == SW_MODE_MASKED) + { + ss->z += ss->dz * pixels; + ss->r += ss->dr * pixels; + ss->g += ss->dg * pixels; + ss->b += ss->db * pixels; + } + + // + // Carry on checking the other spans... + // + } + } + } + } + + ss_next = ss_next->next; + } +} + + + +// +// Swizzles a texture. +// + +void SW_swizzle(TGA_Pixel *tga, SLONG size) +{ + SLONG i; + + SLONG x; + SLONG y; + + SLONG index_normal; + SLONG index_swizzle; + + TGA_Pixel *buffer; + + // + // Use the back buffer memory as a temporary swizzle buffer. + // + + ASSERT(size <= 256); + + buffer = (TGA_Pixel *) SW_buffer_memory; + + memcpy(buffer, tga, size * size * sizeof(TGA_Pixel)); + + // + // Swizzle the texture. + // + + for (x = 0; x < size; x++) + for (y = 0; y < size; y++) + { + // + // The index of the unswizzled pixel. + // + + index_normal = x + y * size; + + // + // The index of the swizzled pixel. + // + + index_swizzle = 0; + + for (i = 0; i < 10; i++) + { + if (x & (1 << i)) + { + index_swizzle |= (1 << (i * 2)); + } + + if (y & (1 << i)) + { + index_swizzle |= (1 << (i * 2 + 1)); + } + } + + tga[index_swizzle] = buffer[index_normal]; + } +} + + + + +void SW_blur(TGA_Pixel *tga, SLONG size) +{ + SLONG i; + + SLONG x; + SLONG y; + + SLONG dx; + SLONG dy; + + SLONG px; + SLONG py; + + SLONG r; + SLONG g; + SLONG b; + SLONG a; + SLONG dist; + SLONG samples; + SLONG index; + + TGA_Pixel *buffer; + + // + // Use the back buffer memory as a temporary blur buffer. + // + + ASSERT(size <= 256); + + buffer = (TGA_Pixel *) SW_buffer_memory; + + memcpy(buffer, tga, size * size * sizeof(TGA_Pixel)); + + // + // blur the texture. + // + + for (x = 0; x < size; x++) + for (y = 0; y < size; y++) + { + r = 0; + g = 0; + b = 0; + a = 0; + + samples = 0; + + for (dx = -1; dx <= +1; dx++) + for (dy = -1; dy <= +1; dy++) + { + px = x + dx; + py = y + dy; + + if (WITHIN(px, 0, size - 1) && + WITHIN(py, 0, size - 1)) + { + static SLONG mul[3] = + { + 664, + 260, + 150, + }; + + dist = abs(dx) + abs(dy); + index = px + py * size; + + r += buffer[index].red * mul[dist] >> 8; + g += buffer[index].green * mul[dist] >> 8; + b += buffer[index].blue * mul[dist] >> 8; + a += buffer[index].alpha * mul[dist] >> 8; + + samples += 1; + } + } + + r /= samples; + g /= samples; + b /= samples; + a /= samples; + + if (r > 128) {r += 64;} + if (g > 128) {g += 64;} + if (b > 128) {b += 64;} + + SATURATE(r, 0, 255); + SATURATE(g, 0, 255); + SATURATE(b, 0, 255); + SATURATE(a, 0, 255); + + index = x + y * size; + + tga[index].red = r; + tga[index].green = g; + tga[index].blue = b; + tga[index].alpha = a; + } +} + + +void SW_halfsize(TGA_Pixel *tga, SLONG size) +{ + SLONG i; + + SLONG x; + SLONG y; + + SLONG dx; + SLONG dy; + + SLONG px; + SLONG py; + + SLONG r; + SLONG g; + SLONG b; + SLONG a; + SLONG dist; + SLONG samples; + SLONG index; + SLONG index1; + SLONG index2; + + TGA_Pixel *buffer; + + ASSERT(size >= 32); + + // + // Use the back buffer memory as a temporary blur buffer. + // + + ASSERT(size <= 256); + + buffer = (TGA_Pixel *) SW_buffer_memory; + + memcpy(buffer, tga, size * size * sizeof(TGA_Pixel)); + + // + // Half the size of the texture. + // + + index1 = 0; + + for (x = 0; x < size; x += 2) + for (y = 0; y < size; y += 2) + { + index = x + y * size; + + r = buffer[index].red; + g = buffer[index].green; + b = buffer[index].blue; + a = buffer[index].alpha; + + r += buffer[index + 1].red; + g += buffer[index + 1].green; + b += buffer[index + 1].blue; + a += buffer[index + 1].alpha; + + r += buffer[index + size].red; + g += buffer[index + size].green; + b += buffer[index + size].blue; + a += buffer[index + size].alpha; + + r += buffer[index + size + 1].red; + g += buffer[index + size + 1].green; + b += buffer[index + size + 1].blue; + a += buffer[index + size + 1].alpha; + + r >>= 2; + g >>= 2; + b >>= 2; + a >>= 2; + + index = (x >> 1) + (y >> 1) * (size >> 1); + + tga[index].red = r; + tga[index].green = g; + tga[index].blue = b; + tga[index].alpha = a; + } +} + + + + +SLONG mulshift; + + +void SW_reload_textures() +{ + SLONG i; + SLONG j; + SLONG flat_page_hack; + SLONG tt_index; + TGA_Info ti; + + SW_Texture *st; + + // + // Is this the last level? + // + + extern SLONG playing_level(const CBYTE *name); + + if (playing_level("Finale1.ucm")) + { + mulshift = 1; + } + else + { + mulshift = 2; + } + + // + // Load from clumps where required. + // + + extern void TEXTURE_initialise_clumping(CBYTE *fname_level); + + TEXTURE_initialise_clumping(ELEV_fname_level); + + for (i = 0; i < SW_MAX_TEXTURES; i++) + { + st = &SW_texture[i]; + + // + // Which TEXTURE_texture do we use for this SW_texture? + // + + flat_page_hack = FALSE; + + if (i < 22 * 64) + { + tt_index = i; + } + else + { + switch(i) + { + case POLY_PAGE_SMOKECLOUD2: + tt_index = TEXTURE_page_smokecloud; + break; + + case POLY_PAGE_BIGBANG: + tt_index = TEXTURE_page_bigbang; + break; + + case POLY_PAGE_EXPLODE1: + tt_index = TEXTURE_page_explode1; + break; + + case POLY_PAGE_EXPLODE1_ADDITIVE: + tt_index = TEXTURE_page_explode1; + break; + + case POLY_PAGE_EXPLODE2_ADDITIVE: + tt_index = TEXTURE_page_explode2; + break; + + case POLY_PAGE_DUSTWAVE: + tt_index= TEXTURE_page_dustwave; + break; + + case POLY_PAGE_FACE1: + tt_index = TEXTURE_page_face1; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_FACE2: + tt_index = TEXTURE_page_face2; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_NEWFONT_INVERSE: + tt_index = TEXTURE_page_lcdfont; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_COLOUR: + flat_page_hack = TRUE; + break; + + case POLY_PAGE_LADDER: + tt_index = TEXTURE_page_ladder; + break; + + case POLY_PAGE_LEAF: + tt_index = TEXTURE_page_leaf; + break; + + case POLY_PAGE_RUBBISH: + tt_index = TEXTURE_page_rubbish; + break; + + /* + + case POLY_PAGE_SHADOW_OVAL: + tt_index = TEXTURE_page_shadowoval; + break; + + */ + + case POLY_PAGE_FONT2D: + tt_index = TEXTURE_page_font2d; + SW_bucket[i] = 1; // Force to have a zsort of 1. + break; + + case POLY_PAGE_LASTPANEL_ALPHA: + tt_index = TEXTURE_page_lastpanel; + SW_bucket[i] = 5; + break; + + case POLY_PAGE_LASTPANEL_ADDALPHA: + tt_index = TEXTURE_page_lastpanel; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_LASTPANEL_ADD: + tt_index = TEXTURE_page_lastpanel; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_LASTPANEL2_ADD: + tt_index = TEXTURE_page_lastpanel2; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_LASTPANEL2_ADDALPHA: + tt_index = TEXTURE_page_lastpanel2; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_LASTPANEL2_ALPHA: + tt_index = TEXTURE_page_lastpanel2; + SW_bucket[i] = 1; + break; + + case POLY_PAGE_FLAMES2: + tt_index = TEXTURE_page_flame2; + break; + + case POLY_PAGE_PCFLAMER: + tt_index = TEXTURE_page_pcflamer; + break; + + case POLY_PAGE_BLOOM1: + tt_index = TEXTURE_page_bloom1; + break; + + case POLY_PAGE_BLOODSPLAT: + tt_index = TEXTURE_page_bloodsplat; + break; + + case POLY_PAGE_COLOUR_ALPHA: + flat_page_hack = TRUE; + SW_bucket[i] = 9; + break; + +#ifdef TARGET_DC + case POLY_PAGE_BACKGROUND_IMAGE: + tt_index = TEXTURE_page_background_use_instead; + break; + case POLY_PAGE_BACKGROUND_IMAGE2: + tt_index = TEXTURE_page_background_use_instead2; + break; +#endif + + default: + + // + // Unsupported texture. + // + ASSERT ( FALSE ); + + continue; + } + } + + if (flat_page_hack) + { + if (st->data) + { + // + // We already have data here... + // + } + else + { + st->data = (TGA_Pixel *) MemAlloc(32 * 32 * sizeof(TGA_Pixel)); + st->size = 32; + + memset(st->data, -1, 32 * 32 * sizeof(TGA_Pixel)); + } + } + else + if (TEXTURE_texture[tt_index].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We should unload our SW_texture if it is used. + // + + if (st->data) + { + TGA_Pixel *no_longer_valid = st->data; + + MemFree(st->data); + + if (i >= 64 * 22) + { + // + // This texture might be shared... + // + + for (j = 64 * 22; j < SW_MAX_TEXTURES; j++) + { + if (SW_texture[j].data == no_longer_valid) + { + memset(&SW_texture[j], 0, sizeof(SW_Texture)); + } + } + } + + memset(st, 0, sizeof(SW_Texture)); + } + } + else + { + // + // Do we already have this texture loaded? + // + + if (strcmp(TEXTURE_texture[tt_index].texture_name, st->name) == 0) + { + // + // Yes! Do nothing. + // + } + else + { + if (st->data) + { + // + // We have the wrong texture loaded. + // + + MemFree(st->data); + + memset(st, 0, sizeof(SW_Texture)); + } + + if (i >= 64 * 22) + { + // + // Do we share this texture with another page? + // + + for (j = 64 * 22; j < SW_MAX_TEXTURES; j++) + { + if (strcmp(TEXTURE_texture[tt_index].texture_name, SW_texture[j].name) == 0) + { + // + // Just use this tga. + // + + ASSERT(SW_texture[j].data); + + *st = SW_texture[j]; + + continue; + } + } + } + + // + // No. We should load this texture. + // + + st->size = TEXTURE_texture[tt_index].size; + + if (st->size == 0) + { + st->size = 128; + } + + st->data = (TGA_Pixel *) MemAlloc(st->size * st->size * sizeof(TGA_Pixel)); + st->blurred = FALSE; + + strcpy(st->name, TEXTURE_texture[tt_index].texture_name); + + ti = TGA_load(st->name, st->size, st->size, st->data, TEXTURE_texture[tt_index].ID); + + if (!ti.valid) + { + // + // Error loading texture TGA. + // + + MemFree(st->data); + + memset(st, 0, sizeof(SW_Texture)); + } + else + { + if (ti.width < st->size) + { + st->size = ti.width; + + st->data = (TGA_Pixel *) realloc(st->data, st->size * st->size * sizeof(TGA_Pixel)); + } + + if (i < 64 * 22) + { + if (RealDisplayWidth < 640 || + RealDisplayHeight < 480) + { + // + // Half the size of the texture! + // + + ASSERT(!st->halved); + + SW_halfsize(st->data, st->size); + + st->size >>= 1; + st->halved = TRUE; + st->data = (TGA_Pixel *) realloc(st->data, st->size * st->size * sizeof(TGA_Pixel)); + } + } + + if (tt_index == TEXTURE_page_font2d || tt_index == TEXTURE_page_lastpanel || tt_index == TEXTURE_page_lastpanel2) + { + extern SLONG RealDisplayWidth; + extern SLONG RealDisplayHeight; + + if (RealDisplayWidth < 640 || + RealDisplayHeight < 480) + { + // + // Blur the texture! + // + + if (!st->blurred) + { + SW_blur(st->data, st->size); + + st->blurred = TRUE; + } + } + } + + // + // Swizzle the texture. + // + + SW_swizzle(st->data, st->size); + } + } + } + } + + CloseTGAClump(); +} + + + +#if !defined (TARGET_DC) + + +// +// Thanks, Tom. +// + +void SW_render_spans_tom(void) +{ + SLONG i; + SLONG x; + + ULONG *dest, addr, *tex; + ULONG pixel; + SLONG r, rd; + SLONG g, gd; + SLONG b, bd; + SLONG R; + SLONG G; + SLONG B; + SLONG pr; + SLONG pg; + SLONG pb; + SLONG u, ud, tempu; + SLONG v, vd, tempv; + SLONG U; + SLONG V; + ULONG wrap, wrap1, wrap2; + int tempx1,tempx2; + + SW_Span *ss; + + + ULONG *last_dest; + _int64 mmt1, mmt2, mmt3, mmt4, umask, vmask, wrapmask, uinc, vinc, notumask, notvmask, alpha_test_value, alpha_mask; + ULONG utemp, vtemp; + + umask = 0x5555ffff5555ffff; + vmask = 0xaaaaffffaaaaffff; + notumask = ~0x5555ffff5555ffff; + notvmask = ~0xaaaaffffaaaaffff; + alpha_test_value = 0xff000000ff000000; + alpha_mask = 0x00007fff00000000; + +#define SWIZZLE 1 + + +#define ALPHA_BLEND_NOT_DOUBLE_LIGHTING 1 + +#undef ALPHA_MODE +#define ALPHA_MODE ALPHA_NONE + + for (i = SW_render_top; i < SW_render_bot; i++) + { + for (ss = SW_line[i]; ss; ss = ss->next) + { + //r = ss->r; + //g = ss->g; + //b = ss->b; + //u = ss->u; + //v = ss->v; + //ud = ss->du; + //vd = ss->dv; + + tempx1 = ss->x1; + tempx2 = ss->x2; + + if ( tempx2 > tempx1 ) + { + + dest = SW_buffer + i * SW_buffer_pitch; + last_dest = dest + tempx2; + dest += tempx1; + if ( ( tempx2 & 0x1 ) != 0 ) + { + // Last pixel is odd - go one less so the loop ends properly. + // Remember that we are stepping two pixels at a time, and + // ending when we hit this one, then maybe drawing the last pixel. + + // (e.g. x2 is 7, so last pixel to draw is 6, so terminate when we get to 6 - then do one more) + // (e.g. x2 is 8, so last pixel to draw is 7, so terminate when we get to 8) + + last_dest--; + } + + r = (ss->r )>>1; + g = (ss->g )>>1; + b = (ss->b )>>1; +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + rd = (ss->dr)>>1; + gd = (ss->dg)>>1; + bd = (ss->db)>>1; +#endif + // Swizzle interpolators + u = ss->u; + v = ss->v; + ud = ss->du; + vd = ss->dv; + tex = (ULONG *)(ss->tga); + + // Remember this is for DWORDS - assembler doesn't automagically scale. +#if SWIZZLE + wrap = ((ss->tga_size * ss->tga_size) - 1)<<2; +#else + wrap = ss->tga_size; +#endif + + __asm { + + push esi + push edi + push eax + push ebx + push ecx + push edx + +#if SWIZZLE + movd mm0,[wrap] + movq mm1,mm0 + psllq mm0,32 + por mm0,mm1 + movq [wrapmask],mm0 +#else + mov eax,[wrap] + mov ebx,0x200 + mov ecx,9 +wrap_loop: + dec ecx + shr ebx,1 + cmp ebx,eax + jne wrap_loop + + mov eax,[v] + mov ebx,[vd] + shl eax,cl + shl ebx,cl + mov [v],eax + mov [vd],ebx + + mov eax,[wrap] + dec eax + movd mm0,eax + psllq mm0,16 + movq mm1,mm0 + psllq mm0,32 + por mm0,mm1 + movq [umask],mm0 + movd mm1,ecx + psllq mm0,mm1 + movq [vmask],mm0 +#endif + + mov eax,[r] + mov ebx,[g] + mov ecx,[b] + and eax,0x00ffff00 + and ebx,0x00ffff00 + and ecx,0x00ffff00 + movd mm0,ebx + movd mm1,ecx + shr eax,8 + psllq mm0,8 + psrlq mm1,8 + por mm0,mm1 + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + or eax,0x7fff0000 +#else + or eax,0x40000000 +#endif + movd mm1,eax + psllq mm1,32 + por mm0,mm1 + movq [mmt1],mm0 + + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + mov eax,[rd] + mov ebx,[gd] + mov ecx,[bd] + and eax,0x00ffff00 + and ebx,0x00ffff00 + and ecx,0x00ffff00 + movd mm0,ebx + movd mm1,ecx + shr eax,8 + psllq mm0,8 + psrlq mm1,8 + por mm0,mm1 + movd mm1,eax + psllq mm1,32 + por mm0,mm1 + movq [mmt2],mm0 +#endif + +#if SWIZZLE + mov eax,[u] + mov ebx,[v] + lea esi,[swizzle_table] + mov ecx,eax + mov edx,ebx + shr ecx,16 + shr edx,16 + and ecx,0xf + and edx,0xf + shr eax,20 + shr ebx,20 + and eax,0xf + and ebx,0xf + mov ah,[esi+eax] + mov bh,[esi+ebx] + mov al,[esi+ecx] + mov bl,[esi+edx] + shl ebx,1 + mov WORD PTR[u+2],ax + mov WORD PTR[v+2],bx + + mov eax,[ud] + mov ebx,[vd] + mov ecx,eax + mov edx,ebx + shr ecx,16 + shr edx,16 + and ecx,0xf + and edx,0xf + shr eax,20 + shr ebx,20 + and eax,0xf + and ebx,0xf + mov ah,[esi+eax] + mov bh,[esi+ebx] + mov al,[esi+ecx] + mov bl,[esi+edx] + shl ebx,1 + or eax,0xaaaa + or ebx,0x5555 + mov WORD PTR[ud+2],ax + mov WORD PTR[vd+2],bx +#endif + + + + movq mm0, [mmt1] +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + movq mm2, [mmt2] +#endif + mov edi, [dest] + mov esi, [tex] + + + // Set up the integer texel fetcher + mov eax,[u] + mov ebx,[v] + + + + ;Is the first pixel odd? + mov ecx,[tempx1] + test ecx,0x1 + jnz first_pixel_odd + + + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + // Calculate r1g1b1, and double up the increments + movq mm1,mm0 + paddsw mm1,mm2 + psllw mm2,1 +#endif + + + + +#if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + or ecx,ebx + add ebx,DWORD PTR [vd] + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + + mov edx,eax + add eax,DWORD PTR [ud] + or edx,ebx + add ebx,DWORD PTR [vd] + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff +#else + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + or ecx,edx + shr ecx,16-2 + push ecx + + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + or edx,ecx + shr edx,16-2 + pop ecx +#endif + movd mm7,[esi+ecx] + movd mm6,[esi+edx] + + + jmp setup_main_loop + + +first_pixel_odd: + + +#if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + or ecx,ebx + add ebx,DWORD PTR [vd] + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff +#else + mov ecx,eax + mov edx,ebx + add eax,DWORD PTR [ud] + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + or ecx,edx + shr ecx,16-2 +#endif + movd mm7,[esi+ecx] + + + + +#if ALPHA_MODE==ALPHA_BLEND + + + punpcklbw mm7,mm7 ;unpack + #if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + #else + mov ecx,eax + add eax,DWORD PTR [ud] + #endif + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + psrlw mm7,8-1 +#else + psrlw mm7,8-2 +#endif + #if SWIZZLE + or ecx,ebx + add ebx,DWORD PTR [vd] + #else + mov edx,ebx + add ebx,DWORD PTR [vd] + #endif + pmulhw mm7,mm0 ;colour modulate + movq mm6,mm7 + + #if SWIZZLE + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + #endif + psrlq mm6,8+1 ;half required value (creates a sign bit) + pand mm6,[alpha_mask] + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or ecx,edx + shr ecx,16-2 + #endif + movq mm5,mm6 + #if SWIZZLE + mov edx,eax + add eax,DWORD PTR [ud] + #else + push ecx + mov ecx,eax + #endif + + psrlq mm5,16 + #if SWIZZLE + or edx,ebx + add ebx,DWORD PTR [vd] + #else + add eax,DWORD PTR [ud] + mov edx,ebx + #endif + + por mm5,mm6 + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + #endif + psrlq mm5,16 + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + and edx,DWORD PTR [vmask] + or edx,ecx + #endif + por mm5,mm6 ;alpha channel replicated to r,g,b + #if SWIZZLE + #else + pop ecx + shr edx,16-2 + #endif + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + // Remember that mm2 is spare - no gouard shading on alpha-blenders. + + movd mm6,[edi] + + punpcklbw mm6,mm6 ;unpack dest + psrlw mm6,8 + + psubsw mm7,mm6 ;src-dest + pmulhw mm7,mm5 ;alpha*(src-dest) + + paddsw mm7,mm7 ;*2 + paddsw mm7,mm6 ;dest+alpha*(src-dest) + + packuswb mm7,mm7 ;re-pack + + + movd [edi],mm7 ;store pixel + + add edi,4 + + + +#else //#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;unpack + #if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + or ecx,ebx + #else + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + #endif + psrlw mm7,8-2 + #if SWIZZLE + add ebx,DWORD PTR [vd] + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + #endif + pmulhw mm7,mm0 ;colour modulate + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or ecx,edx + shr ecx,16-2 + push ecx + #endif +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + paddsw mm0,mm2 ;inc rgb +#endif + #if SWIZZLE + mov edx,eax + add eax,DWORD PTR [ud] + #else + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + #endif + packuswb mm7,mm7 ;re-pack + #if SWIZZLE + or edx,ebx + add ebx,DWORD PTR [vd] + #else + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + #endif + +#if ALPHA_MODE==ALPHA_ADD + movd mm6,[edi] + paddusb mm7,mm6 +#elif ALPHA_MODE==ALPHA_TEST + movq mm5,mm7 + movq mm6,[edi] + pcmpgtb mm7,[alpha_test_value] ;SIGNED compare! + psrad mm7,24 ;propogate compare result down. + pand mm6,mm7 + pandn mm7,mm5 ;mask (mm7 = (mm5 AND ~mm7)) + por mm7,mm6 ;...and merge +#endif + + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + and edx,DWORD PTR [vmask] + or edx,ecx + #endif + + movd [edi],mm7 ;store pixel + + +// KLUDGE! +// mov DWORD PTR [edi],0x7f7f7f7f + + + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + pop ecx + shr edx,16-2 + #endif + + add edi,4 + + +#endif //#else //#if ALPHA_MODE==ALPHA_BLEND + + + + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + // Calculate r1g1b1, and double up the increments + movq mm1,mm0 + paddsw mm1,mm2 + psllw mm2,1 +#endif + + + + + +#if SWIZZLE +// mov ecx,eax +// add eax,DWORD PTR [ud] +// or ecx,ebx +// add ebx,DWORD PTR [vd] +// shr ecx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and ecx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +// +// mov edx,eax +// add eax,DWORD PTR [ud] +// or edx,ebx +// add ebx,DWORD PTR [vd] +// shr edx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and edx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +#else +// mov ecx,eax +// add eax,DWORD PTR [ud] +// mov edx,ebx +// add ebx,DWORD PTR [vd] +// and ecx,DWORD PTR [umask] +// and edx,DWORD PTR [vmask] +// or ecx,edx +// shr ecx,16-2 +// push ecx +// +// mov ecx,eax +// add eax,DWORD PTR [ud] +// mov edx,ebx +// add ebx,DWORD PTR [vd] +// and ecx,DWORD PTR [umask] +// and edx,DWORD PTR [vmask] +// or edx,ecx +// pop ecx +// shr edx,16-2 +#endif + + movd mm7,[esi+ecx] + movd mm6,[esi+edx] + + +setup_main_loop: + + cmp edi,[last_dest] + je main_loop_done + + + + + +hor_loop: + // Map: + // MM0: (all 8.8): xx,r0,g0,b0 + // MM1: (all 8.8): xx,r1,g1,b1 (not for blend+add) + // MM2: (all 8.8): xx,r,g,b deltas (not for blend+add) + // eax: (16.16): u + // ebx: (16.16): v + // esi: texture base addr + // edi: dest addr + + + + +#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;unpack + #if SWIZZLE + mov ecx,eax + #else + mov ecx,eax + #endif + punpcklbw mm6,mm6 ;unpack + #if SWIZZLE + add eax,DWORD PTR [ud] + #else + mov edx,ebx + #endif + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + psrlw mm7,8-1 + #if SWIZZLE + or ecx,ebx + #else + and ecx,DWORD PTR [umask] + #endif + psrlw mm6,8-1 + #if SWIZZLE + add ebx,DWORD PTR [vd] + #else + and edx,DWORD PTR [vmask] + #endif +#else + psrlw mm7,8-2 + #if SWIZZLE + or ecx,ebx + #else + and ecx,DWORD PTR [umask] + #endif + psrlw mm6,8-2 + #if SWIZZLE + add ebx,DWORD PTR [vd] + #else + and edx,DWORD PTR [vmask] + #endif +#endif + pmulhw mm7,mm0 ;colour modulate + #if SWIZZLE + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + #endif + pmulhw mm6,mm0 ;colour modulate + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or ecx,edx + add eax,DWORD PTR [ud] + #endif + + // Extract and replicate the alpha parts + // Texel 0 + movq mm2,mm7 + #if SWIZZLE + mov edx,eax + #else + shr ecx,16-2 + add ebx,DWORD PTR [vd] + #endif + psrlq mm2,8+1 ;half required value (creates a sign bit) + #if SWIZZLE + add eax,DWORD PTR [ud] + #else + push ecx + mov edx,ebx + #endif + pand mm2,[alpha_mask] + #if SWIZZLE + or edx,ebx + #else + mov ecx,eax + and edx,DWORD PTR [vmask] + #endif + movq mm5,mm2 + #if SWIZZLE + add ebx,DWORD PTR [vd] + #else + and ecx,DWORD PTR [umask] + add eax,DWORD PTR [ud] + #endif + psrlq mm5,16 + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + or edx,ecx + add ebx,DWORD PTR [vd] + #endif + por mm5,mm2 + psrlq mm5,16 + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + shr edx,16-2 + pop ecx + #endif + por mm5,mm2 ;alpha channel replicated to r,g,b + + // Texel 0 + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + + movq mm2,[edi] + movq mm1,mm2 + punpcklbw mm2,mm2 ;unpack dest + punpckhbw mm1,mm1 ;unpack dest + + psrlw mm2,8 + + psubsw mm7,mm2 ;src-dest + pmulhw mm7,mm5 ;alpha*(src-dest) + + + + paddsw mm7,mm7 ;*2 + paddsw mm7,mm2 ;dest0+alpha0*(src0-dest0) + + // Texel 1 + movq mm2,mm6 + psrlq mm2,8+1 ;half required value (creates a sign bit) + pand mm2,[alpha_mask] + movq mm5,mm2 + psrlq mm5,16 + por mm5,mm2 + psrlq mm5,16 + por mm5,mm2 ;alpha channel replicated to r,g,b + + // Texel 1 + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + + // Already unpacked above. + psrlw mm1,8 + + psubsw mm6,mm1 ;src-dest + pmulhw mm6,mm5 ;alpha*(src-dest) + + + paddsw mm6,mm6 ;*2 + paddsw mm6,mm1 ;dest1+alpha1*(src1-dest1) + + // Pack. + packuswb mm7,mm6 ;re-pack + +#else //#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;texel0 + #if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + #else + mov ecx,eax + mov edx,ebx + #endif + punpcklbw mm6,mm6 ;texel1 + #if SWIZZLE + or ecx,ebx + add ebx,DWORD PTR [vd] + #else + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + #endif + psrlw mm7,8-2 + #if SWIZZLE + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + or ecx,edx + add eax,DWORD PTR [ud] + #endif + psrlw mm6,8-2 + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + shr ecx,16-2 + add ebx,DWORD PTR [vd] + #endif + pmulhw mm7,mm0 + #if SWIZZLE + mov edx,eax + add eax,DWORD PTR [ud] + #else + push ecx + mov edx,ebx + #endif +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + pmulhw mm6,mm1 +#else + pmulhw mm6,mm0 +#endif + #if SWIZZLE + or edx,ebx + add ebx,DWORD PTR [vd] + #else + mov ecx,eax + and edx,DWORD PTR [vmask] + #endif + + packuswb mm7,mm6 + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + and ecx,DWORD PTR [umask] + add eax,DWORD PTR [ud] + #endif + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + paddsw mm0,mm2 +#endif +#if ALPHA_MODE==ALPHA_ADD + paddusb mm7,[edi] +#elif ALPHA_MODE==ALPHA_BLEND +#elif ALPHA_MODE==ALPHA_TEST + movq mm5,mm7 + movq mm6,[edi] + pcmpgtb mm7,[alpha_test_value] ;SIGNED compare! + psrad mm7,24 ;propogate compare result down. + pand mm6,mm7 + pandn mm7,mm5 ;mask (mm7 = (mm5 AND ~mm7)) + por mm7,mm6 ;...and merge +#endif + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or edx,ecx + add ebx,DWORD PTR [vd] + #endif +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + paddsw mm1,mm2 +#endif + + + #if SWIZZLE + #else + shr edx,16-2 + pop ecx + #endif + + + +#endif //#else //#if ALPHA_MODE==ALPHA_BLEND + + movq [edi],mm7 + +#if SWIZZLE +// mov ecx,eax +// add eax,DWORD PTR [ud] +// or ecx,ebx +// add ebx,DWORD PTR [vd] +// shr ecx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and ecx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +// +// mov edx,eax +// add eax,DWORD PTR [ud] +// or edx,ebx +// add ebx,DWORD PTR [vd] +// shr edx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and edx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +#else +// mov ecx,eax +// mov edx,ebx +// and ecx,DWORD PTR [umask] +// and edx,DWORD PTR [vmask] +// or ecx,edx +// add eax,DWORD PTR [ud] +// shr ecx,16-2 +// add ebx,DWORD PTR [vd] +// push ecx +// +// mov edx,ebx +// mov ecx,eax +// and edx,DWORD PTR [vmask] +// and ecx,DWORD PTR [umask] +// add eax,DWORD PTR [ud] +// or edx,ecx +// add ebx,DWORD PTR [vd] +// shr edx,16-2 +// pop ecx +#endif + movd mm7,[esi+ecx] + movd mm6,[esi+edx] + + add edi,8 + + cmp edi,[last_dest] + jne hor_loop + +main_loop_done: + + // Do we need to do the last pixel? + ;Is the last pixel odd? + mov ecx,[tempx2] + test ecx,0x1 + jz finished + + + // Do the last pixel + +#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;unpack + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + psrlw mm7,8-1 +#else + psrlw mm7,8-2 +#endif + pmulhw mm7,mm0 ;colour modulate + + movq mm6,mm7 + + psrlq mm6,8+1 ;half required value (creates a sign bit) + pand mm6,[alpha_mask] + movq mm5,mm6 + psrlq mm5,16 + por mm5,mm6 + psrlq mm5,16 + por mm5,mm6 ;alpha channel replicated to r,g,b + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + // Remember that mm2 is spare - no gouard shading on alpha-blenders. + + movd mm6,[edi] + //mov eax,0x10806050 + //movd mm6,eax + + punpcklbw mm6,mm6 ;unpack dest + psrlw mm6,8 + + psubsw mm7,mm6 ;src-dest + pmulhw mm7,mm5 ;alpha*(src-dest) + paddsw mm7,mm7 ;*2 + paddsw mm7,mm6 ;dest+alpha*(src-dest) + + packuswb mm7,mm7 ;re-pack + + + //paddd mm3,[uinc] ;inc u + //paddd mm4,[vinc] ;inc v + //pand mm3,[umask] ;fix swizzle + //pand mm4,[vmask] ;fix swizzle + + +#else //#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 + psrlw mm7,8-2 + pmulhw mm7,mm0 + packuswb mm7,mm7 +#if ALPHA_MODE==ALPHA_ADD + movd mm6,[edi] + paddusb mm7,mm6 +#elif ALPHA_MODE==ALPHA_BLEND +#elif ALPHA_MODE==ALPHA_TEST + movq mm5,mm7 + movq mm6,[edi] + pcmpgtb mm7,[alpha_test_value] ;SIGNED compare! + psrad mm7,24 ;propogate compare result down. + pand mm6,mm7 + pandn mm7,mm5 ;mask (mm7 = (mm5 AND ~mm7)) + por mm7,mm6 ;...and merge +#endif + +#endif //#else //#if ALPHA_MODE==ALPHA_BLEND + + movd [edi],mm7 + +finished: + + pop edx + pop ecx + pop ebx + pop eax + pop edi + pop esi + + // Clean up the MMX state + emms + + } + } + } + } +} + + + + + +void SW_render_spans_eddie(void) +{ + SLONG i; + SLONG x; + + ULONG pixel; + SLONG pr; + SLONG pg; + SLONG pb; + + SW_Span *ss; + + for (i = SW_render_top; i < SW_render_bot; i++) + { + for (ss = SW_line[i]; ss; ss = ss->next) + { + ULONG count = ss->x2 - ss->x1; + + if (!count) continue; + + ULONG gr = ((ss->g >> 8) << 16) | ((ss->r >> 8) & 0xFFFF); + ULONG zb = (ss->b >> 8) & 0xFFFF; + + ULONG dgdr = ((ss->dg >> 8) << 16) | ((ss->dr >> 8) & 0xFFFF); + ULONG dzdb = (ss->db >> 8) & 0xFFFF; + + ULONG* dest = SW_buffer/*_screen*/ + ss->x1 + i * SW_buffer_pitch; + ULONG* src = (ULONG*)ss->tga; + + if (ss->tga_size == 64) + { +#define SHIFT 6 +#define USH (30 - SHIFT) +#define VSH (30 - 2*SHIFT) +#define UMSK ((0xFFFFFFFFu >> (32 - SHIFT)) << 2) +#define VMSK (UMSK << SHIFT) + + ULONG u = ss->u << (16 - SHIFT); + ULONG v = ss->v << (16 - SHIFT); + ULONG du = ss->du << (16 - SHIFT); + ULONG dv = ss->dv << (16 - SHIFT); + + __asm + { + mov eax,gr + mov ebx,zb + movd mm7,eax // mm7 = 00|00|GG|RR + movd mm0,ebx // mm0 = 00|00|00|BB + + mov eax,dgdr + mov ebx,dzdb + movd mm6,eax // mm6 = 00|00|dG|dR + movd mm1,ebx // mm1 = 00|00|00|dB + + xor eax,eax + movd mm5,eax // mm5 = 00000000 + + punpckldq mm7,mm0 // mm7 = 00|BB|GG|RR + punpckldq mm6,mm1 // mm6 = 00|dB|dG|dR + + mov esi,dest // esi = destination pointer + mov eax,u // eax = U + mov ebx,v // ebx = V + mov ecx,count + +myloop64: + // get U + V * 64 + mov edi,ebx // edi = V (6:26) + mov edx,eax // edx = U (6:26) + + shr edi,VSH // edi = VVVVVVxxxxxxxx + shr edx,USH // edx = UUUUUUxx + + and edi,VMSK // edi = VVVVVV00000000 + and edx,UMSK // edx = UUUUUU00 + + add edi,src + + add eax,[du] + add ebx,[dv] + + // load texel + mov edx,DWORD PTR [edx + edi] + + // get shade + movq mm1,mm7 // mm1 = 00|BB|GG|RR + psrlw mm1,8 // mm1 = 00|0B|0G|0R + + // expand + movd mm0,edx + punpcklbw mm0,mm5 // mm0 = 00|0B|0G|0R + + // multiply + pmullw mm1,mm0 // mm1 = 00|BB|GG|RR shaded colour + + // increment colour + paddw mm7,mm6 // increment R,G,B + + // double with saturation + paddusw mm1,mm1 + + // shift down + psrlw mm1,8 // mm1 = 00|0B|0G|0R + + // pack back to 00000GBR + packuswb mm1,mm5 // mm1 = 00000BGR + + // mov back to integer unit + movd edx,mm1 + + mov [esi],edx + add esi,4 + + dec ecx + jnz myloop64 + } + } + else if (ss->tga_size == 32) + { +#undef SHIFT +#undef USH +#undef VSH +#undef UMSK +#undef VMSK +#define SHIFT 5 +#define USH (30 - SHIFT) +#define VSH (30 - 2*SHIFT) +#define UMSK ((0xFFFFFFFFu >> (32 - SHIFT)) << 2) +#define VMSK (UMSK << SHIFT) + + ULONG u = ss->u << (16 - SHIFT); + ULONG v = ss->v << (16 - SHIFT); + ULONG du = ss->du << (16 - SHIFT); + ULONG dv = ss->dv << (16 - SHIFT); + + // the code below is identical to the code above + + __asm + { + mov eax,gr + mov ebx,zb + movd mm7,eax // mm7 = 00|00|GG|RR + movd mm0,ebx // mm0 = 00|00|00|BB + + mov eax,dgdr + mov ebx,dzdb + movd mm6,eax // mm6 = 00|00|dG|dR + movd mm1,ebx // mm1 = 00|00|00|dB + + xor eax,eax + movd mm5,eax // mm5 = 00000000 + + punpckldq mm7,mm0 // mm7 = 00|BB|GG|RR + punpckldq mm6,mm1 // mm6 = 00|dB|dG|dR + + mov esi,dest // esi = destination pointer + mov eax,u // eax = U + mov ebx,v // ebx = V + mov ecx,count + +myloop32: + // get U + V * 32 + mov edi,ebx // edi = V (6:26) + mov edx,eax // edx = U (6:26) + + shr edi,VSH // edi = VVVVVVxxxxxxxx + shr edx,USH // edx = UUUUUUxx + + and edi,VMSK // edi = VVVVVV00000000 + and edx,UMSK // edx = UUUUUU00 + + add edi,src + + add eax,[du] + add ebx,[dv] + + // load texel + mov edx,DWORD PTR [edx + edi] + + // get shade + movq mm1,mm7 // mm1 = 00|BB|GG|RR + psrlw mm1,8 // mm1 = 00|0B|0G|0R + + // expand + movd mm0,edx + punpcklbw mm0,mm5 // mm0 = 00|0B|0G|0R + + // multiply + pmullw mm1,mm0 // mm1 = 00|BB|GG|RR shaded colour + + // increment colour + paddw mm7,mm6 // increment R,G,B + + // double with saturation + paddusw mm1,mm1 + + // shift down + psrlw mm1,8 // mm1 = 00|0B|0G|0R + + // pack back to 00000GBR + packuswb mm1,mm5 // mm1 = 00000BGR + + // mov back to integer unit + movd edx,mm1 + + mov [esi],edx + add esi,4 + + dec ecx + jnz myloop32 + } + } + else + { + ULONG width = 0; + ULONG tgawidth = ss->tga_size; + while (tgawidth > 1) + { + width++; + tgawidth >>= 1; + } + + ULONG shift1 = 30 - width; + ULONG shift2 = 30 - 2 * width; + ULONG mask1 = (0xFFFFFFFFu >> (32 - width)) << 2; + ULONG mask2 = mask1 << width; + + ULONG u = ss->u << (16 - width); + ULONG v = ss->v << (16 - width); + ULONG du = ss->du << (16 - width); + ULONG dv = ss->dv << (16 - width); + + // the code below has differences: + // (1) doesn't use ecx to keep [count] + // (2) // get U + V*64 is different code + + __asm + { + mov eax,gr + mov ebx,zb + movd mm7,eax // mm7 = 00|00|GG|RR + movd mm0,ebx // mm0 = 00|00|00|BB + + mov eax,dgdr + mov ebx,dzdb + movd mm6,eax // mm6 = 00|00|dG|dR + movd mm1,ebx // mm1 = 00|00|00|dB + + xor eax,eax + movd mm5,eax // mm5 = 00000000 + + punpckldq mm7,mm0 // mm7 = 00|BB|GG|RR + punpckldq mm6,mm1 // mm6 = 00|dB|dG|dR + + mov esi,dest // esi = destination pointer + mov eax,u // eax = U + mov ebx,v // ebx = V + mov edi,count + +myloopany: + mov count,edi + + // get U + V * + mov edi,ebx + mov ecx,[shift1] + shr edi,cl + add ebx,[dv] + + mov edx,eax + mov ecx,[shift2] + shr edx,cl + add eax,[du] + + and edi,[mask1] + and edx,[mask2] + + add edi,src + + // load texel + mov edx,DWORD PTR [edx + edi] + + // get shade + movq mm1,mm7 // mm1 = 00|BB|GG|RR + psrlw mm1,8 // mm1 = 00|0B|0G|0R + + // expand + movd mm0,edx + punpcklbw mm0,mm5 // mm0 = 00|0B|0G|0R + + // multiply + pmullw mm1,mm0 // mm1 = 00|BB|GG|RR shaded colour + + // increment colour + paddw mm7,mm6 // increment R,G,B + + // double with saturation + paddusw mm1,mm1 + + // shift down + psrlw mm1,8 // mm1 = 00|0B|0G|0R + + // pack back to 00000GBR + packuswb mm1,mm5 // mm1 = 00000BGR + + // mov back to integer unit + movd edx,mm1 + + mov edi,count + + mov [esi],edx + add esi,4 + + dec edi + jnz myloopany + } + } + } + } + + __asm + { + emms + } +} + + + +void SW_render_spans() +{ + static int which = 0; + + if (Keys[KB_P0]) + { + Keys[KB_P0] = 0; + + which ^= 1; + } + + if (which) + { + SW_render_spans_eddie(); + } + else + { + SW_render_spans_tom(); + } +} + + + +#else //#if !defined (TARGET_DC) + +// DC stuff. + + + +void SW_render_spans() +{ + // Stubbed - shouldn't be used anyway. + ASSERT(FALSE); +} + + +#endif //#else //#if !defined (TARGET_DC) + + + + +void SW_add_triangle( + SLONG x1, SLONG y1, SLONG z1, SLONG r1, SLONG g1, SLONG b1, SLONG u1, SLONG v1, + SLONG x2, SLONG y2, SLONG z2, SLONG r2, SLONG g2, SLONG b2, SLONG u2, SLONG v2, + SLONG x3, SLONG y3, SLONG z3, SLONG r3, SLONG g3, SLONG b3, SLONG u3, SLONG v3, + SLONG page, + SLONG alpha) +{ + if (!WITHIN(page, 0, SW_MAX_TEXTURES - 1)) + { + // + // Invalid texture page. + // + + return; + } + + SW_Texture *st; + + st = &SW_texture[page]; + + if (st->data == NULL) + { + // + // No texture loaded. + // + + return; + } + + extern SLONG GAMEMENU_background; + + if (GAMEMENU_background > 640 - 512) + { + if (page != POLY_PAGE_NEWFONT_INVERSE) + { + SLONG mul; + + mul = GAMEMENU_background - (640 - 512); + mul >>= mulshift; + mul = 256 - mul; + + r1 = r1 * mul >> 8; + g1 = g1 * mul >> 8; + b1 = b1 * mul >> 8; + + r2 = r2 * mul >> 8; + g2 = g2 * mul >> 8; + b2 = b2 * mul >> 8; + + r3 = r3 * mul >> 8; + g3 = g3 * mul >> 8; + b3 = b3 * mul >> 8; + + alpha = alpha * mul >> 8; + } + } + + TGA_Pixel *tga = st->data; + SLONG tga_size = st->size; + + if (tga_size != 256) + { + if (tga_size == 64) + { + u1 >>= 2; + v1 >>= 2; + + u2 >>= 2; + v2 >>= 2; + + u3 >>= 2; + v3 >>= 2; + } + else + if (tga_size == 32) + { + u1 >>= 3; + v1 >>= 3; + + u2 >>= 3; + v2 >>= 3; + + u3 >>= 3; + v3 >>= 3; + } + else + if (tga_size == 16) + { + u1 >>= 4; + v1 >>= 4; + + u2 >>= 4; + v2 >>= 4; + + u3 >>= 4; + v3 >>= 4; + } + else + if (tga_size == 128) + { + u1 >>= 1; + v1 >>= 1; + + u2 >>= 1; + v2 >>= 1; + + u3 >>= 1; + v3 >>= 1; + } + else + { + ASSERT(0); + } + } + + switch(SW_page[page]) + { + case SW_PAGE_IGNORE: + return; + + case SW_PAGE_NORMAL: + + // + // Continue with the triangle draw. + // + + break; + + case SW_PAGE_MASKED: + + // + // Add to the masked buckets... + // + + SW_add_masked_triangle( + x1, y1, z1, r1, g1, b1, u1, v1, + x2, y2, z2, r2, g2, b2, u2, v2, + x3, y3, z3, r3, g3, b3, u3, v3, + tga, + tga_size); + + return; + + case SW_PAGE_ALPHA: + + // + // Add the sprite. + // + + { + SLONG mode; + + mode = SW_MODE_ALPHA; + + if (SW_bucket[page]) + { + z1 = SW_bucket[page]; + + mode = SW_MODE_ALPHA_NOZ; + } + + SW_add_alpha_sprite( + x1, y1, u1, v1, + x2, y2, u2, v2, + x3, y3, u3, v3, + z1, alpha, r1, g1, b1, + tga, + tga_size, + mode); + } + + return; + + case SW_PAGE_ADDITIVE: + + + // + // Add the sprite. + // + + { + SLONG mode; + + mode = SW_MODE_ADDITIVE; + + if (SW_bucket[page]) + { + z1 = SW_bucket[page]; + + mode = SW_MODE_ADDITIVE_NOZ; + } + + SW_add_alpha_sprite( + x1, y1, u1, v1, + x2, y2, u2, v2, + x3, y3, u3, v3, + z1, alpha, r1 >> 1, g1 >> 1, b1 >> 1, + tga, + tga_size, + mode); + } + + return; + + default: + ASSERT(0); + break; + } + + SLONG xa, xb, za, zb, ra, rb, ga, gb, ba, bb, ua, ub, va, vb; + SLONG dax, dbx, daz, dbz, dar, dbr, dag, dbg, dab, dbb, dau, dbu, dav, dbv; + SLONG xmid, zmid, rmid, gmid, bmid, umid, vmid; + SLONG dz, dr, dg, db, du, dv; + SLONG z, r, g, b, u, v; + SLONG U,V; + SLONG xl, xr; + SLONG w; + SLONG x, y; + SLONG i, j; + SLONG shade; + ULONG *dest; + UBYTE colour; + + SLONG recip_y3y1; + SLONG recip_y2y1; + + SW_Span *ss; + + // Sort the points so that y1 <= y2 <= y3 + + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(z1,z2); SWAP(r1,r2); SWAP(g1,g2); SWAP(b1,b2); SWAP(u1,u2); SWAP(v1,v2);} + if (y2>y3) {SWAP(x2,x3); SWAP(y2,y3); SWAP(z2,z3); SWAP(r2,r3); SWAP(g2,g3); SWAP(b2,b3); SWAP(u2,u3); SWAP(v2,v3);} + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(z1,z2); SWAP(r1,r2); SWAP(g1,g2); SWAP(b1,b2); SWAP(u1,u2); SWAP(v1,v2);} + + if (abs(y3 - y1) >= ALWAYS_HOW_MANY_RECIPS) + { + return; + } + + recip_y3y1 = RECIP(y3 - y1); + recip_y2y1 = RECIP(y2 - y1); + + if (y1 == y2) + { + if (y2 == y3) return; + + if (x1 < x2) + { + // The a dda runs down the left hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xb - xa; + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + db = 0; + dg = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + dz = DIV16((z2 << 16) - (z1 << 16), w); + dr = DIV16((r2 << 16) - (r1 << 16), w); + dg = DIV16((g2 << 16) - (g1 << 16), w); + db = DIV16((b2 << 16) - (b1 << 16), w); + du = DIV16((u2 << 16) - (u1 << 16), w); + dv = DIV16((v2 << 16) - (v1 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + ra = r1 << 16; + dar = MUL16(r3 - r1 << 16, recip_y3y1); + ga = g1 << 16; + dag = MUL16(g3 - g1 << 16, recip_y3y1); + ba = b1 << 16; + dab = MUL16(b3 - b1 << 16, recip_y3y1); + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + goto bottom_pointy_right; + } + else + { + + // The a dda runs down the right hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xa - xb; + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + dg = 0; + db = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + dz = DIV16((z1 << 16) - (z2 << 16), w); + dr = DIV16((r1 << 16) - (r2 << 16), w); + dg = DIV16((g1 << 16) - (g2 << 16), w); + db = DIV16((b1 << 16) - (b2 << 16), w); + du = DIV16((u1 << 16) - (u2 << 16), w); + dv = DIV16((v1 << 16) - (v2 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + zb = z2 << 16; + dbz = MUL16(z3 - z2 << 16, recip_y3y1); + rb = r2 << 16; + dbr = MUL16(r3 - r2 << 16, recip_y3y1); + gb = g2 << 16; + dbg = MUL16(g3 - g2 << 16, recip_y3y1); + bb = b2 << 16; + dbb = MUL16(b3 - b2 << 16, recip_y3y1); + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, recip_y3y1); + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, recip_y3y1); + + goto bottom_pointy_left; + } + } + + // The a dda's run along the unbroken side of the triangle... + // i.e. from y1 to y3. + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x2 - x1 << 16, recip_y2y1); + + // Is the a dda along the left side or the right side of the triangle? + + if (dax < dbx) + { + // The a dda runs along the left side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + ra = r1 << 16; + dar = MUL16(r3 - r1 << 16, recip_y3y1); + ga = g1 << 16; + dag = MUL16(g3 - g1 << 16, recip_y3y1); + ba = b1 << 16; + dab = MUL16(b3 - b1 << 16, recip_y3y1); + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + zmid = za + daz * (y2 - y1); + rmid = ra + dar * (y2 - y1); + gmid = ga + dag * (y2 - y1); + bmid = ba + dab * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = (x2 << 16) - xmid; + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + dg = 0; + db = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + dz = DIV16((z2 << 16) - zmid, w); + dr = DIV16((r2 << 16) - rmid, w); + dg = DIV16((g2 << 16) - gmid, w); + db = DIV16((b2 << 16) - bmid, w); + du = DIV16((u2 << 16) - umid, w); + dv = DIV16((v2 << 16) - vmid, w); + } + + y = y1; + + while (y < y2) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + z = za; + r = ra; + g = ga; + b = ba; + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xa & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xa & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_insert_span(ss, y); + } + } + + xa += dax; + xb += dbx; + za += daz; + ra += dar; + ga += dag; + ba += dab; + ua += dau; + va += dav; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + bottom_pointy_right: + + while (y < y3) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + z = za; + r = ra; + g = ga; + b = ba; + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xa & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xa & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_insert_span(ss, y); + } + } + + xa += dax; + xb += dbx; + za += daz; + ra += dar; + ga += dag; + ba += dab; + ua += dau; + va += dav; + y += 1; + } + + } + else + { + // The a dda runs along the right side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + // BILINEAR STUFF... + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + zb = z1 << 16; + dbz = MUL16(z2 - z1 << 16, recip_y2y1); + + ra = r1 << 16; + dar = MUL16(r3 - r1 << 16, recip_y3y1); + rb = r1 << 16; + dbr = MUL16(r2 - r1 << 16, recip_y2y1); + + ga = g1 << 16; + dag = MUL16(g3 - g1 << 16, recip_y3y1); + gb = g1 << 16; + dbg = MUL16(g2 - g1 << 16, recip_y2y1); + + ba = b1 << 16; + dab = MUL16(b3 - b1 << 16, recip_y3y1); + bb = b1 << 16; + dbb = MUL16(b2 - b1 << 16, recip_y2y1); + + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + ub = u1 << 16; + dbu = MUL16(u2 - u1 << 16, recip_y2y1); + + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + vb = v1 << 16; + dbv = MUL16(v2 - v1 << 16, recip_y2y1); + + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + zmid = za + daz * (y2 - y1); + rmid = ra + dar * (y2 - y1); + gmid = ga + dag * (y2 - y1); + bmid = ba + dab * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = xmid - (x2 << 16); + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + dg = 0; + db = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + dz = DIV16(zmid - (z2 << 16), w); + dr = DIV16(rmid - (r2 << 16), w); + dg = DIV16(gmid - (g2 << 16), w); + db = DIV16(bmid - (b2 << 16), w); + du = DIV16(umid - (u2 << 16), w); + dv = DIV16(vmid - (v2 << 16), w); + } + + bottom_pointy_left: + + y = y1; + + while (y < y2) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + z = zb; + r = rb; + g = gb; + b = bb; + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xb & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xb & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_insert_span(ss, y); + } + } + + xa += dax; + xb += dbx; + zb += dbz; + rb += dbr; + gb += dbg; + bb += dbb; + ub += dbu; + vb += dbv; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + zb = z2 << 16; + dbz = MUL16(z3 - z2 << 16, RECIP(y3 - y2)); + + rb = r2 << 16; + dbr = MUL16(r3 - r2 << 16, RECIP(y3 - y2)); + + gb = g2 << 16; + dbg = MUL16(g3 - g2 << 16, RECIP(y3 - y2)); + + bb = b2 << 16; + dbb = MUL16(b3 - b2 << 16, RECIP(y3 - y2)); + + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, RECIP(y3 - y2)); + + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, RECIP(y3 - y2)); + + while (y < y3) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + z = zb; + r = rb; + g = gb; + b = bb; + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xb & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xb & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_insert_span(ss, y); + } + } + + xa += dax; + xb += dbx; + zb += dbz; + rb += dbr; + gb += dbg; + bb += dbb; + ub += dbu; + vb += dbv; + y += 1; + } + } +} + + + + + +void SW_draw_masked_triangle( + SLONG x1, SLONG y1, SLONG z1, SLONG r1, SLONG g1, SLONG b1, SLONG u1, SLONG v1, + SLONG x2, SLONG y2, SLONG z2, SLONG r2, SLONG g2, SLONG b2, SLONG u2, SLONG v2, + SLONG x3, SLONG y3, SLONG z3, SLONG r3, SLONG g3, SLONG b3, SLONG u3, SLONG v3, + TGA_Pixel *tga, + SLONG tga_size) +{ + SLONG xa, xb, za, zb, ra, rb, ga, gb, ba, bb, ua, ub, va, vb; + SLONG dax, dbx, daz, dbz, dar, dbr, dag, dbg, dab, dbb, dau, dbu, dav, dbv; + SLONG xmid, zmid, rmid, gmid, bmid, umid, vmid; + SLONG dz, dr, dg, db, du, dv; + SLONG z, r, g, b, u, v; + SLONG U,V; + SLONG xl, xr; + SLONG w; + SLONG x, y; + SLONG i, j; + SLONG shade; + ULONG *dest; + UBYTE colour; + + SLONG recip_y3y1; + SLONG recip_y2y1; + + SW_Span *ss; + + // Sort the points so that y1 <= y2 <= y3 + + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(z1,z2); SWAP(r1,r2); SWAP(g1,g2); SWAP(b1,b2); SWAP(u1,u2); SWAP(v1,v2);} + if (y2>y3) {SWAP(x2,x3); SWAP(y2,y3); SWAP(z2,z3); SWAP(r2,r3); SWAP(g2,g3); SWAP(b2,b3); SWAP(u2,u3); SWAP(v2,v3);} + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(z1,z2); SWAP(r1,r2); SWAP(g1,g2); SWAP(b1,b2); SWAP(u1,u2); SWAP(v1,v2);} + + if (abs(y3 - y1) >= ALWAYS_HOW_MANY_RECIPS) + { + return; + } + + recip_y3y1 = RECIP(y3 - y1); + recip_y2y1 = RECIP(y2 - y1); + + if (y1 == y2) + { + if (y2 == y3) return; + + if (x1 < x2) + { + // The a dda runs down the left hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xb - xa; + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + db = 0; + dg = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16((z2 << 16) - (z1 << 16), w); + dr = DIV16((r2 << 16) - (r1 << 16), w); + dg = DIV16((g2 << 16) - (g1 << 16), w); + db = DIV16((b2 << 16) - (b1 << 16), w); + du = DIV16((u2 << 16) - (u1 << 16), w); + dv = DIV16((v2 << 16) - (v1 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + ra = r1 << 16; + dar = MUL16(r3 - r1 << 16, recip_y3y1); + ga = g1 << 16; + dag = MUL16(g3 - g1 << 16, recip_y3y1); + ba = b1 << 16; + dab = MUL16(b3 - b1 << 16, recip_y3y1); + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + goto bottom_pointy_right; + } + else + { + + // The a dda runs down the right hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xa - xb; + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + dg = 0; + db = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16((z1 << 16) - (z2 << 16), w); + dr = DIV16((r1 << 16) - (r2 << 16), w); + dg = DIV16((g1 << 16) - (g2 << 16), w); + db = DIV16((b1 << 16) - (b2 << 16), w); + du = DIV16((u1 << 16) - (u2 << 16), w); + dv = DIV16((v1 << 16) - (v2 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + zb = z2 << 16; + dbz = MUL16(z3 - z2 << 16, recip_y3y1); + rb = r2 << 16; + dbr = MUL16(r3 - r2 << 16, recip_y3y1); + gb = g2 << 16; + dbg = MUL16(g3 - g2 << 16, recip_y3y1); + bb = b2 << 16; + dbb = MUL16(b3 - b2 << 16, recip_y3y1); + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, recip_y3y1); + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, recip_y3y1); + + goto bottom_pointy_left; + } + } + + // The a dda's run along the unbroken side of the triangle... + // i.e. from y1 to y3. + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x2 - x1 << 16, recip_y2y1); + + // Is the a dda along the left side or the right side of the triangle? + + if (dax < dbx) + { + // The a dda runs along the left side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + ra = r1 << 16; + dar = MUL16(r3 - r1 << 16, recip_y3y1); + ga = g1 << 16; + dag = MUL16(g3 - g1 << 16, recip_y3y1); + ba = b1 << 16; + dab = MUL16(b3 - b1 << 16, recip_y3y1); + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + zmid = za + daz * (y2 - y1); + rmid = ra + dar * (y2 - y1); + gmid = ga + dag * (y2 - y1); + bmid = ba + dab * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = (x2 << 16) - xmid; + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + dg = 0; + db = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16((z2 << 16) - zmid, w); + dr = DIV16((r2 << 16) - rmid, w); + dg = DIV16((g2 << 16) - gmid, w); + db = DIV16((b2 << 16) - bmid, w); + du = DIV16((u2 << 16) - umid, w); + dv = DIV16((v2 << 16) - vmid, w); + } + + y = y1; + + while (y < y2) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + z = za; + r = ra; + g = ga; + b = ba; + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xa & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xa & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_clip_and_draw_span(ss, y, SW_MODE_MASKED); + } + } + + xa += dax; + xb += dbx; + za += daz; + ra += dar; + ga += dag; + ba += dab; + ua += dau; + va += dav; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + bottom_pointy_right: + + while (y < y3) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + z = za; + r = ra; + g = ga; + b = ba; + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xa & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xa & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_clip_and_draw_span(ss, y, SW_MODE_MASKED); + } + } + + xa += dax; + xb += dbx; + za += daz; + ra += dar; + ga += dag; + ba += dab; + ua += dau; + va += dav; + y += 1; + } + + } + else + { + // The a dda runs along the right side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + // BILINEAR STUFF... + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + zb = z1 << 16; + dbz = MUL16(z2 - z1 << 16, recip_y2y1); + + ra = r1 << 16; + dar = MUL16(r3 - r1 << 16, recip_y3y1); + rb = r1 << 16; + dbr = MUL16(r2 - r1 << 16, recip_y2y1); + + ga = g1 << 16; + dag = MUL16(g3 - g1 << 16, recip_y3y1); + gb = g1 << 16; + dbg = MUL16(g2 - g1 << 16, recip_y2y1); + + ba = b1 << 16; + dab = MUL16(b3 - b1 << 16, recip_y3y1); + bb = b1 << 16; + dbb = MUL16(b2 - b1 << 16, recip_y2y1); + + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + ub = u1 << 16; + dbu = MUL16(u2 - u1 << 16, recip_y2y1); + + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + vb = v1 << 16; + dbv = MUL16(v2 - v1 << 16, recip_y2y1); + + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + zmid = za + daz * (y2 - y1); + rmid = ra + dar * (y2 - y1); + gmid = ga + dag * (y2 - y1); + bmid = ba + dab * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = xmid - (x2 << 16); + + if (w < (1 << 16)) + { + dz = 0; + dr = 0; + dg = 0; + db = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16(zmid - (z2 << 16), w); + dr = DIV16(rmid - (r2 << 16), w); + dg = DIV16(gmid - (g2 << 16), w); + db = DIV16(bmid - (b2 << 16), w); + du = DIV16(umid - (u2 << 16), w); + dv = DIV16(vmid - (v2 << 16), w); + } + + bottom_pointy_left: + + y = y1; + + while (y < y2) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + z = zb; + r = rb; + g = gb; + b = bb; + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xb & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xb & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_clip_and_draw_span(ss, y, SW_MODE_MASKED); + } + } + + xa += dax; + xb += dbx; + zb += dbz; + rb += dbr; + gb += dbg; + bb += dbb; + ub += dbu; + vb += dbv; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + zb = z2 << 16; + dbz = MUL16(z3 - z2 << 16, RECIP(y3 - y2)); + + rb = r2 << 16; + dbr = MUL16(r3 - r2 << 16, RECIP(y3 - y2)); + + gb = g2 << 16; + dbg = MUL16(g3 - g2 << 16, RECIP(y3 - y2)); + + bb = b2 << 16; + dbb = MUL16(b3 - b2 << 16, RECIP(y3 - y2)); + + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, RECIP(y3 - y2)); + + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, RECIP(y3 - y2)); + + while (y < y3) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + z = zb; + r = rb; + g = gb; + b = bb; + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + r += dxl * dr; + g += dxl * dg; + b += dxl * db; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->r = r; + ss->dr = dr; + ss->g = g; + ss->dg = dg; + ss->b = b; + ss->db = db; + ss->z = z; + ss->dz = dz; + ss->u = u - MUL16((xb & 0xffff), du);; + ss->du = du; + ss->v = v - MUL16((xb & 0xffff), dv);; + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + SW_clip_and_draw_span(ss, y, SW_MODE_MASKED); + } + } + + xa += dax; + xb += dbx; + zb += dbz; + rb += dbr; + gb += dbg; + bb += dbb; + ub += dbu; + vb += dbv; + y += 1; + } + } +} + + + + + +void SW_draw_alpha_sprite( + SLONG x1, SLONG y1, SLONG u1, SLONG v1, + SLONG x2, SLONG y2, SLONG u2, SLONG v2, + SLONG x3, SLONG y3, SLONG u3, SLONG v3, + SLONG wz, SLONG wa, SLONG wr, SLONG wg, SLONG wb, + SLONG mode, + TGA_Pixel *tga, + SLONG tga_size) +{ + SLONG xa, xb, ua, ub, va, vb; + SLONG dax, dbx, dau, dbu, dav, dbv; + SLONG xmid, umid, vmid; + SLONG du, dv; + SLONG u, v; + SLONG U,V; + SLONG xl, xr; + SLONG w; + SLONG x, y; + SLONG i, j; + SLONG shade; + ULONG *dest; + UBYTE colour; + + SLONG recip_y3y1; + SLONG recip_y2y1; + + SW_Span *ss; + + // + // Make the zed compatible with the other triangle draws. + // + + wz -= 5; + + if (wz < 2) + { + wz = 2; + } + + wz <<= 16; + + // Sort the points so that y1 <= y2 <= y3 + + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(u1,u2); SWAP(v1,v2);} + if (y2>y3) {SWAP(x2,x3); SWAP(y2,y3); SWAP(u2,u3); SWAP(v2,v3);} + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(u1,u2); SWAP(v1,v2);} + + if (abs(y3 - y1) >= ALWAYS_HOW_MANY_RECIPS) + { + return; + } + + recip_y3y1 = RECIP(y3 - y1); + recip_y2y1 = RECIP(y2 - y1); + + if (y1 == y2) + { + if (y2 == y3) return; + + if (x1 < x2) + { + // The a dda runs down the left hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xb - xa; + + if (w < (1 << 16)) + { + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + du = DIV16((u2 << 16) - (u1 << 16), w); + dv = DIV16((v2 << 16) - (v1 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + goto bottom_pointy_right; + } + else + { + + // The a dda runs down the right hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xa - xb; + + if (w < (1 << 16)) + { + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + du = DIV16((u1 << 16) - (u2 << 16), w); + dv = DIV16((v1 << 16) - (v2 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, recip_y3y1); + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, recip_y3y1); + + goto bottom_pointy_left; + } + } + + // The a dda's run along the unbroken side of the triangle... + // i.e. from y1 to y3. + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x2 - x1 << 16, recip_y2y1); + + // Is the a dda along the left side or the right side of the triangle? + + if (dax < dbx) + { + // The a dda runs along the left side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = (x2 << 16) - xmid; + + if (w < (1 << 16)) + { + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + du = DIV16((u2 << 16) - umid, w); + dv = DIV16((v2 << 16) - vmid, w); + } + + y = y1; + + while (y < y2) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->a = wa; + ss->r = wr; + ss->g = wg; + ss->b = wb; + ss->z = wz; + ss->u = u - MUL16((xa & 0xffff), du); + ss->du = du; + ss->v = v - MUL16((xa & 0xffff), dv); + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + if (mode == SW_MODE_ALPHA_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ALPHA); + } + else + if (mode == SW_MODE_ADDITIVE_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ADDITIVE); + } + else + { + SW_clip_and_draw_span(ss, y, mode); + } + } + } + + xa += dax; + xb += dbx; + ua += dau; + va += dav; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + bottom_pointy_right: + + while (y < y3) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->a = wa; + ss->r = wr; + ss->g = wg; + ss->b = wb; + ss->z = wz; + ss->u = u - MUL16((xa & 0xffff), du); + ss->du = du; + ss->v = v - MUL16((xa & 0xffff), dv); + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + if (mode == SW_MODE_ALPHA_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ALPHA); + } + else + if (mode == SW_MODE_ADDITIVE_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ADDITIVE); + } + else + { + SW_clip_and_draw_span(ss, y, mode); + } + } + } + + xa += dax; + xb += dbx; + ua += dau; + va += dav; + y += 1; + } + + } + else + { + // The a dda runs along the right side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + // BILINEAR STUFF... + + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + ub = u1 << 16; + dbu = MUL16(u2 - u1 << 16, recip_y2y1); + + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + vb = v1 << 16; + dbv = MUL16(v2 - v1 << 16, recip_y2y1); + + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = xmid - (x2 << 16); + + if (w < (1 << 16)) + { + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + w += 0x10000; + + du = DIV16(umid - (u2 << 16), w); + dv = DIV16(vmid - (v2 << 16), w); + } + + bottom_pointy_left: + + y = y1; + + while (y < y2) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->a = wa; + ss->r = wr; + ss->g = wg; + ss->b = wb; + ss->z = wz; + ss->u = u - MUL16((xb & 0xffff), du); + ss->du = du; + ss->v = v - MUL16((xb & 0xffff), dv); + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + if (mode == SW_MODE_ALPHA_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ALPHA); + } + else + if (mode == SW_MODE_ADDITIVE_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ADDITIVE); + } + else + { + SW_clip_and_draw_span(ss, y, mode); + } + } + } + + xa += dax; + xb += dbx; + ub += dbu; + vb += dbv; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, RECIP(y3 - y2)); + + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, RECIP(y3 - y2)); + + while (y < y3) + { + if (y >= SW_render_top && y < SW_render_bot) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + // + // Create a new span. + // + + if (w > 0) + { + ASSERT(WITHIN(SW_span_upto, 0, SW_MAX_SPANS - 1)); + + ss = &SW_span[SW_span_upto++]; + + ss->x1 = xl; + ss->x2 = xl + w; + ss->a = wa; + ss->r = wr; + ss->g = wg; + ss->b = wb; + ss->z = wz; + ss->u = u - MUL16((xb & 0xffff), du); + ss->du = du; + ss->v = v - MUL16((xb & 0xffff), dv); + ss->dv = dv; + ss->tga = tga; + ss->tga_size = tga_size; + + if (mode == SW_MODE_ALPHA_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ALPHA); + } + else + if (mode == SW_MODE_ADDITIVE_NOZ) + { + SW_draw_span(ss, y, SW_MODE_ADDITIVE); + } + else + { + SW_clip_and_draw_span(ss, y, mode); + } + } + } + + xa += dax; + xb += dbx; + ub += dbu; + vb += dbv; + y += 1; + } + } +} + + + + +#if !defined(TARGET_DC) +// +// Returns the number of processor ticks since the processor was reset / 65536 +// + +ULONG SW_rdtsc(void) +{ + ULONG hi; + ULONG lo; + + _asm + { + rdtsc + mov hi, edx + mov lo, eax + } + + ULONG ans; + + ans = lo >> 16; + ans |= hi << 16; + + return ans; +} + +#else //#if !defined(TARGET_DC) + +ULONG SW_rdtsc(void) +{ + return 1; +} + +#endif //#else //#if !defined(TARGET_DC) + + +SLONG SW_tick1; +SLONG SW_tick2; + +void SW_render() +{ + extern SLONG EWAY_stop_player_moving(void); + + if (EWAY_stop_player_moving()) + { + SW_render_top = 80 * SW_buffer_height / 480; + SW_render_bot = 400 * SW_buffer_height / 480; + } + else + { + SW_render_top = 0; + SW_render_bot = SW_buffer_height; + } + + SW_tick1 = SW_rdtsc(); + + SW_render_spans(); + + SW_tick2 = SW_rdtsc(); + + // + // Now render the buckets! + // + + SLONG i; + SLONG mode; + + SW_Masked *sm; + SW_Alpha *sa; + + for (i = SW_MAX_BUCKETS - 1; i >= 0; i--) + { + if (i == 2) + { + // + // The first few buckets... + // + + SW_render_top = 0; + SW_render_bot = SW_buffer_height; + } + + for (sm = SW_masked_bucket[i]; sm; sm = sm->next) + { + SW_draw_masked_triangle( + sm->x1, sm->y1, sm->z1, sm->r1, sm->g1, sm->b1, sm->u1, sm->v1, + sm->x2, sm->y2, sm->z2, sm->r2, sm->g2, sm->b2, sm->u2, sm->v2, + sm->x3, sm->y3, sm->z3, sm->r3, sm->g3, sm->b3, sm->u3, sm->v3, + sm->tga, + sm->tga_size); + } + + for (sa = SW_alpha_bucket[i]; sa; sa = sa->next) + { + SW_draw_alpha_sprite( + sa->x1, sa->y1, sa->u1, sa->v1, + sa->x2, sa->y2, sa->u2, sa->v2, + sa->x3, sa->y3, sa->u3, sa->v3, + sa->wz, sa->wa, sa->wr, sa->wg, sa->wb, + sa->mode, + sa->tga, + sa->tga_size); + } + } +} + + + + +void SW_test_triangle( + SLONG x1, SLONG y1, SLONG z1, SLONG s1, SLONG u1, SLONG v1, + SLONG x2, SLONG y2, SLONG z2, SLONG s2, SLONG u2, SLONG v2, + SLONG x3, SLONG y3, SLONG z3, SLONG s3, SLONG u3, SLONG v3, + SLONG page) +{ + if (!WITHIN(page, 0, SW_MAX_TEXTURES - 1)) + { + // + // Invalid texture page. + // + + return; + } + + SW_Texture *st; + + st = &SW_texture[page]; + + if (st->data == NULL) + { + // + // No texture loaded. + // + + return; + } + + TGA_Pixel *tga = st->data; + SLONG tga_size = st->size; + + if (tga_size != 256) + { + if (tga_size == 64) + { + u1 >>= 2; + v1 >>= 2; + + u2 >>= 2; + v2 >>= 2; + + u3 >>= 2; + v3 >>= 2; + } + else + if (tga_size == 32) + { + u1 >>= 3; + v1 >>= 3; + + u2 >>= 3; + v2 >>= 3; + + u3 >>= 3; + v3 >>= 3; + } + else + if (tga_size == 128) + { + u1 >>= 1; + v1 >>= 1; + + u2 >>= 1; + v2 >>= 1; + + u3 >>= 1; + v3 >>= 1; + } + } + + // + // This is code ripped from the software testbed. + // + + { + SLONG xa, xb, za, zb, sa, sb, ua, ub, va, vb; + SLONG dax, dbx, daz, dbz, das, dbs, dau, dbu, dav, dbv; + SLONG xmid, zmid, smid, umid, vmid; + SLONG dz, ds, du, dv; + SLONG z, s, u, v; + SLONG U,V; + SLONG xl, xr; + SLONG w; + SLONG x, y; + SLONG i, j; + SLONG r,g,b; + SLONG shade; + ULONG *dest; + UBYTE colour; + + SLONG recip_y3y1; + SLONG recip_y2y1; + + // Sort the points so that y1 <= y2 <= y3 + + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(z1,z2); SWAP(s1,s2); SWAP(u1,u2); SWAP(v1,v2);} + if (y2>y3) {SWAP(x2,x3); SWAP(y2,y3); SWAP(z2,z3); SWAP(s2,s3); SWAP(u2,u3); SWAP(v2,v3);} + if (y1>y2) {SWAP(x1,x2); SWAP(y1,y2); SWAP(z1,z2); SWAP(s1,s2); SWAP(u1,u2); SWAP(v1,v2);} + + recip_y3y1 = RECIP(y3 - y1); + recip_y2y1 = RECIP(y2 - y1); + + if (y1 == y2) + { + if (y2 == y3) return; + + if (x1 < x2) + { + // The a dda runs down the left hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xb - xa; + + if (w < (1 << 16)) + { + dz = 0; + ds = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16((z2 << 16) - (z1 << 16), w); + ds = DIV16((s2 << 16) - (s1 << 16), w); + du = DIV16((u2 << 16) - (u1 << 16), w); + dv = DIV16((v2 << 16) - (v1 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + sa = s1 << 16; + das = MUL16(s3 - s1 << 16, recip_y3y1); + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + goto bottom_pointy_right; + } + else + { + + // The a dda runs down the right hand side... + + xa = x1 << 16; + xb = x2 << 16; + w = xa - xb; + + if (w < (1 << 16)) + { + dz = 0; + ds = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16((z1 << 16) - (z2 << 16), w); + ds = DIV16((s1 << 16) - (s2 << 16), w); + du = DIV16((u1 << 16) - (u2 << 16), w); + dv = DIV16((v1 << 16) - (v2 << 16), w); + } + + y = y1; + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x3 - x2 << 16, recip_y3y1); + + zb = z2 << 16; + dbz = MUL16(z3 - z2 << 16, recip_y3y1); + sb = s2 << 16; + dbs = MUL16(s3 - s2 << 16, recip_y3y1); + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, recip_y3y1); + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, recip_y3y1); + + goto bottom_pointy_left; + } + } + + // The a dda's run along the unbroken side of the triangle... + // i.e. from y1 to y3. + + dax = MUL16(x3 - x1 << 16, recip_y3y1); + dbx = MUL16(x2 - x1 << 16, recip_y2y1); + + // Is the a dda along the left side or the right side of the triangle? + + if (dax < dbx) + { + // The a dda runs along the left side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + sa = s1 << 16; + das = MUL16(s3 - s1 << 16, recip_y3y1); + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + zmid = za + daz * (y2 - y1); + smid = sa + das * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = (x2 << 16) - xmid; + + if (w < (1 << 16)) + { + dz = 0; + ds = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16((z2 << 16) - smid, w); + ds = DIV16((s2 << 16) - smid, w); + du = DIV16((u2 << 16) - umid, w); + dv = DIV16((v2 << 16) - vmid, w); + } + + y = y1; + + while (y < y2) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + z = za; + s = sa; + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + s += dxl * ds; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + for (x = xl; w-- > 0; x++) + { + shade = s >> 16; + U = u >> 16; + V = v >> 16; + U &= tga_size - 1; + V &= tga_size - 1; + + ASSERT(WITHIN(shade, 0, 255)); + + r = tga[U + V * tga_size].red; + g = tga[U + V * tga_size].green; + b = tga[U + V * tga_size].blue; + + r = r * shade >> 8; + g = g * shade >> 8; + b = b * shade >> 8; + + *dest = (r << 16) | (g << 8) | b; + + z += dz; + s += ds; + u += du; + v += dv; + dest += 1; + } + } + + xa += dax; + xb += dbx; + za += daz; + sa += das; + ua += dau; + va += dav; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + bottom_pointy_right: + + while (y < y3) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xl = xa >> 16; + xr = xb >> 16; + w = xr - xl; + + z = za; + s = sa; + u = ua; + v = va; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + s += dxl * ds; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + for (x = xl; w-- > 0; x++) + { + shade = s >> 16; + U = u >> 16; + V = v >> 16; + U &= tga_size - 1; + V &= tga_size - 1; + + ASSERT(WITHIN(shade, 0, 255)); + + r = tga[U + V * tga_size].red; + g = tga[U + V * tga_size].green; + b = tga[U + V * tga_size].blue; + + r = r * shade >> 8; + g = g * shade >> 8; + b = b * shade >> 8; + + *dest = (r << 16) | (g << 8) | b; + + z += dz; + s += ds; + u += du; + v += dv; + dest += 1; + } + } + + xa += dax; + xb += dbx; + za += daz; + sa += das; + ua += dau; + va += dav; + y += 1; + } + + } + else + { + // The a dda runs along the right side of the triangle. + + xa = x1 << 16; + xb = x1 << 16; + + // BILINEAR STUFF... + + za = z1 << 16; + daz = MUL16(z3 - z1 << 16, recip_y3y1); + zb = z1 << 16; + dbz = MUL16(z2 - z1 << 16, recip_y2y1); + + sa = s1 << 16; + das = MUL16(s3 - s1 << 16, recip_y3y1); + sb = s1 << 16; + dbs = MUL16(s2 - s1 << 16, recip_y2y1); + + ua = u1 << 16; + dau = MUL16(u3 - u1 << 16, recip_y3y1); + ub = u1 << 16; + dbu = MUL16(u2 - u1 << 16, recip_y2y1); + + va = v1 << 16; + dav = MUL16(v3 - v1 << 16, recip_y3y1); + vb = v1 << 16; + dbv = MUL16(v2 - v1 << 16, recip_y2y1); + + + // Work out xa, ua, and va along the middle horizontal crease. + + xmid = xa + dax * (y2 - y1); + zmid = za + daz * (y2 - y1); + smid = sa + das * (y2 - y1); + umid = ua + dau * (y2 - y1); + vmid = va + dav * (y2 - y1); + + // w is the width of the horizontal crease. + + w = xmid - (x2 << 16); + + if (w < (1 << 16)) + { + dz = 0; + ds = 0; + du = 0; + dv = 0; + } + else + { + // Work out du and dv as divides of two 16:16 fixed points. + + dz = DIV16(zmid - (z2 << 16), w); + ds = DIV16(smid - (s2 << 16), w); + du = DIV16(umid - (u2 << 16), w); + dv = DIV16(vmid - (v2 << 16), w); + } + + bottom_pointy_left: + + y = y1; + + while (y < y2) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + z = zb; + s = sb; + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + s += dxl * ds; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + for (x = xl; w-- > 0; x++) + { + shade = s >> 16; + U = u >> 16; + V = v >> 16; + U &= tga_size - 1; + V &= tga_size - 1; + + ASSERT(WITHIN(shade, 0, 255)); + + r = tga[U + V * tga_size].red; + g = tga[U + V * tga_size].green; + b = tga[U + V * tga_size].blue; + + r = r * shade >> 8; + g = g * shade >> 8; + b = b * shade >> 8; + + *dest = (r << 16) | (g << 8) | b; + + z += dz; + s += ds; + u += du; + v += dv; + dest += 1; + } + } + + xa += dax; + xb += dbx; + zb += dbz; + sb += dbs; + ub += dbu; + vb += dbv; + y += 1; + } + + // Reinitialise the b dda so it 'turns the corner' of the triangle. + + if (y2 == y3) return; + + xb = x2 << 16; + dbx = MUL16(x3 - x2 << 16, RECIP(y3 - y2)); + + zb = z2 << 16; + dbz = MUL16(z3 - z2 << 16, RECIP(y3 - y2)); + + sb = s2 << 16; + dbs = MUL16(s3 - s2 << 16, RECIP(y3 - y2)); + + ub = u2 << 16; + dbu = MUL16(u3 - u2 << 16, RECIP(y3 - y2)); + + vb = v2 << 16; + dbv = MUL16(v3 - v2 << 16, RECIP(y3 - y2)); + + while (y < y3) + { + if (y >= 0 && y <= SW_buffer_height - 1) + { + xr = xa >> 16; + xl = xb >> 16; + w = xr - xl; + + z = zb; + s = sb; + u = ub; + v = vb; + + if (xl < 0) + { + SLONG dxl; + + dxl = 0 - xl; + + w -= dxl; + z += dxl * dz; + s += dxl * ds; + u += dxl * du; + v += dxl * dv; + xl = 0; + } + + dest = SW_PIXEL(xl, y); + + if (xl + w > SW_buffer_width - 1 + 1) {w = SW_buffer_width - 1 + 1 - xl;} + + for (x = xl; w-- > 0; x++) + { + shade = s >> 16; + U = u >> 16; + V = v >> 16; + U &= tga_size - 1; + V &= tga_size - 1; + + r = tga[U + V * tga_size].red; + g = tga[U + V * tga_size].green; + b = tga[U + V * tga_size].blue; + + ASSERT(WITHIN(shade, 0, 255)); + + r = r * shade >> 8; + g = g * shade >> 8; + b = b * shade >> 8; + + *dest = (r << 16) | (g << 8) | b; + + z += dz; + s += ds; + u += du; + v += dv; + dest += 1; + } + } + + xa += dax; + xb += dbx; + zb += dbz; + sb += dbs; + ub += dbu; + vb += dbv; + y += 1; + } + } + } +} + + + + + + + + + + +void SW_copy_to_bb() +{ + SLONG x; + SLONG y; + ULONG *source; + ULONG *dest_l; + UWORD *dest_w; + + // + // Render the scene anc copy over the back buffer. + // + + the_display.screen_lock(); + + if (the_display.screen) + { + SLONG width = MIN(the_display.screen_width, SW_buffer_width); + SLONG height = MIN(the_display.screen_height, SW_buffer_height); + + if (the_display.screen_bbp == 32) + { + // + // This should be easy! + // + + SW_buffer = (ULONG *) the_display.screen; + SW_buffer_pitch = the_display.screen_pitch >> 2; + + SW_render(); + + /* + + for (y = 0; y < height; y++) + { + source = SW_PIXEL(0,y); + dest_l = (ULONG *) (the_display.screen + y * the_display.screen_pitch); + + memcpy(dest_l, source, 4 * width); + } + + */ + } + else + if (the_display.screen_bbp == 16) + { + SW_buffer = SW_buffer_memory; + + memset(SW_buffer_memory, 0, SW_buffer_width * SW_buffer_height * sizeof(ULONG)); + + SW_render(); + + for (y = 0; y < height; y++) + { + source = SW_PIXEL(0,y); + dest_w = (UWORD *) (the_display.screen + y * the_display.screen_pitch); + + for (x = 0; x < width; x++) + { + *dest_w = the_display.GetFormattedPixel(*source >> 16, (*source >> 8) & 0xff, *source & 0xff); + + dest_w += 1; + source += 1; + } + } + } + + the_display.screen_unlock(); + } +} + + + +#endif //#ifndef TARGET_DC + + diff --git a/fallen/DDEngine/Source/texture.cpp b/fallen/DDEngine/Source/texture.cpp new file mode 100644 index 0000000..239bc2b --- /dev/null +++ b/fallen/DDEngine/Source/texture.cpp @@ -0,0 +1,3391 @@ +// +// Texture handling. +// + +#include "game.h" +#include +#include "c:\fallen\ddlibrary\headers\tga.h" +#include "texture.h" +#include "c:\fallen\headers\animtmap.h" +#include "c:\fallen\headers\supermap.h" +#include "poly.h" +#include "pap.h" +#include "ns.h" +#include "memory.h" +#include "c:\fallen\headers\io.h" +#include "c:\fallen\headers\inside2.h" +#include "sound.h" +#include "c:\fallen\headers\noserver.h" +#include "ware.h" +#include "truetype.h" +#include "font2d.h" +#include "env.h" +#include "drive.h" +#include "c:\fallen\headers\attract.h" +#include "crinkle.h" +#ifdef TARGET_DC +#include "c:\fallen\ddlibrary\headers\GDisplay.h" +#endif +int TEXTURE_create_clump = 0; + +// +// The current texture set and the current texture directory +// for first four texture pages. +// + +CBYTE TEXTURE_shared_dir [_MAX_PATH]; +CBYTE TEXTURE_world_dir [_MAX_PATH]; +CBYTE TEXTURE_fx_inifile [_MAX_PATH]; +CBYTE TEXTURE_shared_fx_inifile [_MAX_PATH]; +CBYTE TEXTURE_prims_dir [_MAX_PATH]; +CBYTE TEXTURE_inside_dir [_MAX_PATH]; +CBYTE TEXTURE_people_dir [_MAX_PATH]; +CBYTE TEXTURE_people_dir2[_MAX_PATH]; +SLONG TEXTURE_set; + + + +// +// Are we using normal or fiddled pages? +// + +SLONG TEXTURE_fiddled; + +UWORD *TEXTURE_shadow_bitmap; +SLONG TEXTURE_shadow_pitch; // In bytes! +SLONG TEXTURE_shadow_mask_red; +SLONG TEXTURE_shadow_mask_green; +SLONG TEXTURE_shadow_mask_blue; +SLONG TEXTURE_shadow_mask_alpha; +SLONG TEXTURE_shadow_shift_red; +SLONG TEXTURE_shadow_shift_green; +SLONG TEXTURE_shadow_shift_blue; +SLONG TEXTURE_shadow_shift_alpha; + + +// +// Hmm... +// + +extern UWORD floor_texture_sizes[]; + +#ifdef TARGET_DC +// Lower numbers so it actually fits. +#define TEXTURE_NUM_STANDARD (22 * 64) +#define TEXTURE_MAX_TEXTURES (TEXTURE_NUM_STANDARD+160) +#define TEXTURE_NORM_SIZE 32 +#define TEXTURE_NORM_SQUARES 8 +#define PEOPLE3_ALT 21*64 +#else +#define TEXTURE_NUM_STANDARD (22 * 64) +#define TEXTURE_MAX_TEXTURES (TEXTURE_NUM_STANDARD+160) +#define TEXTURE_NORM_SIZE 32 +#define TEXTURE_NORM_SQUARES 8 +#define PEOPLE3_ALT 21*64 +#endif + +// +// Texutre pages that don't exist. +// + +UBYTE TEXTURE_dontexist[TEXTURE_MAX_TEXTURES]; + +// Texture pages that are "needed", i.e. used by the frontend. +UBYTE TEXTURE_needed[TEXTURE_MAX_TEXTURES]; + +// +// The texture pages. +// + +D3DTexture TEXTURE_texture[TEXTURE_MAX_TEXTURES]; + +// +// The crinkle for each standard texture page. +// + +CRINKLE_Handle TEXTURE_crinkle[22 * 64]; + + +// +// The textures. +// + +SLONG TEXTURE_page_num_standard; + +#ifdef TARGET_DC +SLONG TEXTURE_page_background_use_instead; +SLONG TEXTURE_page_background_use_instead2; + +SLONG TEXTURE_page_joypad_a; +SLONG TEXTURE_page_joypad_b; +SLONG TEXTURE_page_joypad_c; +SLONG TEXTURE_page_joypad_x; +SLONG TEXTURE_page_joypad_y; +SLONG TEXTURE_page_joypad_z; +SLONG TEXTURE_page_joypad_l; +SLONG TEXTURE_page_joypad_r; +SLONG TEXTURE_page_joypad_pad_l; +SLONG TEXTURE_page_joypad_pad_r; +SLONG TEXTURE_page_joypad_pad_d; +SLONG TEXTURE_page_joypad_pad_u; +#endif + +SLONG TEXTURE_page_snowflake; +SLONG TEXTURE_page_sparkle; +SLONG TEXTURE_page_explode2; +SLONG TEXTURE_page_explode1; +SLONG TEXTURE_page_bigbang; +SLONG TEXTURE_page_face1; +SLONG TEXTURE_page_face2; +SLONG TEXTURE_page_face3; +SLONG TEXTURE_page_face4; +SLONG TEXTURE_page_face5; +SLONG TEXTURE_page_face6; +SLONG TEXTURE_page_fog; +SLONG TEXTURE_page_moon; +SLONG TEXTURE_page_clouds; +SLONG TEXTURE_page_water; +SLONG TEXTURE_page_puddle; +SLONG TEXTURE_page_drip; +SLONG TEXTURE_page_shadow; +SLONG TEXTURE_page_bang; +SLONG TEXTURE_page_font; +SLONG TEXTURE_page_logo; +SLONG TEXTURE_page_sky; +SLONG TEXTURE_page_flames; +SLONG TEXTURE_page_smoke; +SLONG TEXTURE_page_flame2; +SLONG TEXTURE_page_steam; +SLONG TEXTURE_page_menuflame; +SLONG TEXTURE_page_barbwire; +SLONG TEXTURE_page_font2d; +SLONG TEXTURE_page_dustwave; +SLONG TEXTURE_page_flames3; +SLONG TEXTURE_page_bloodsplat; +SLONG TEXTURE_page_bloom1; +SLONG TEXTURE_page_bloom2; +SLONG TEXTURE_page_hitspang; +SLONG TEXTURE_page_lensflare; +SLONG TEXTURE_page_envmap; +SLONG TEXTURE_page_tyretrack; +SLONG TEXTURE_page_winmap; +SLONG TEXTURE_page_leaf; +SLONG TEXTURE_page_raindrop; +SLONG TEXTURE_page_footprint; +SLONG TEXTURE_page_angel; +SLONG TEXTURE_page_devil; +SLONG TEXTURE_page_smoker; +SLONG TEXTURE_page_target; +SLONG TEXTURE_page_newfont; +SLONG TEXTURE_page_droplet; +SLONG TEXTURE_page_press1; +SLONG TEXTURE_page_press2; +SLONG TEXTURE_page_ic; +SLONG TEXTURE_page_ic2; +SLONG TEXTURE_page_lcdfont; +SLONG TEXTURE_page_smokecloud; +SLONG TEXTURE_page_menulogo; +SLONG TEXTURE_page_polaroid; +SLONG TEXTURE_page_bigbutton; +SLONG TEXTURE_page_bigleaf; +SLONG TEXTURE_page_bigrain; +SLONG TEXTURE_page_finalglow; +SLONG TEXTURE_page_tinybutt; +SLONG TEXTURE_page_tyretrack_alpha; +SLONG TEXTURE_page_people3; +SLONG TEXTURE_page_ladder; +SLONG TEXTURE_page_fadecat; +SLONG TEXTURE_page_fade_MF; +SLONG TEXTURE_page_shadowoval; +SLONG TEXTURE_page_rubbish; +SLONG TEXTURE_page_lastpanel; +SLONG TEXTURE_page_lastpanel2; +SLONG TEXTURE_page_sign; +SLONG TEXTURE_page_pcflamer; +SLONG TEXTURE_page_shadowsquare; +SLONG TEXTURE_page_litebolt; +SLONG TEXTURE_page_ladshad; +SLONG TEXTURE_page_meteor; +SLONG TEXTURE_page_splash; + + + + +// ======================================================== +// +// THE DC PAGING SYSTEM +// + +#define TEXTURE_ENABLE_DC_PACKING 0 +#define TEXTURE_DC_PACK_POS_WHOLE_PAGE 42 + +typedef struct +{ + UBYTE page; + UBYTE pos; // 0 - 8 or TEXTURE_DC_PACK_POS_WHOLE_PAGE + +} TEXTURE_DC_Pack; + +TEXTURE_DC_Pack TEXTURE_DC_pack[256]; + +SLONG TEXTURE_DC_pack_page_upto; // Which page we are packing into +SLONG TEXTURE_DC_pack_page_pos; // The position on the pack page that is free (0 - 8) +SLONG TEXTURE_DC_pack_normal_upto; // Goes up in increments of 2 so we have a gap after each page. + +// +// Where normal textures start from. +// + +#define TEXTURE_DC_NORMAL_START 128 + + + +// +// Initialise the packing. +// + +void TEXTURE_DC_pack_init(void) +{ + memset(TEXTURE_DC_pack, 0, sizeof(TEXTURE_DC_pack)); + + TEXTURE_DC_pack_page_upto = 0; + TEXTURE_DC_pack_page_pos = 0; + TEXTURE_DC_pack_normal_upto = TEXTURE_DC_NORMAL_START; +} + +void TEXTURE_DC_pack_load_page(SLONG page) +{ + SLONG i; + SLONG actual_page; + CBYTE name_res64[64]; + + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_world_dir, page); + + // + // The packing only works for the world textures. + // + + ASSERT(WITHIN(page, 0, 255)); + + // + // Does this page get packed or does it become a normal page? + // + + if (POLY_page_flag[page]) + { + // + // This is a normal page because it is drawn in a strange way. If + // this page is drawn as the second pass of a 2-pass texture, then + // it must be the actual_page after the preceeding page.... + // + + if (page > 0 && (POLY_page_flag[page - 1] & POLY_PAGE_FLAG_2PASS)) + { + // + // Find the preceeding page. + // + + ASSERT(TEXTURE_DC_pack[page - 1].pos == TEXTURE_DC_PACK_POS_WHOLE_PAGE); + + actual_page = TEXTURE_DC_pack[page - 1].page + 1; + } + else + { + // + // Use the next normal gap. + // + + page = TEXTURE_DC_pack_normal_upto; + TEXTURE_DC_pack_normal_upto += 2; + } + + ASSERT(WITHIN(actual_page, 0, 255)); + + TEXTURE_texture[actual_page].LoadTextureTGA(name_res64, actual_page); + + TEXTURE_DC_pack[page].page = actual_page; + TEXTURE_DC_pack[page].pos = TEXTURE_DC_PACK_POS_WHOLE_PAGE; + } + else + { + D3DTexture *tt; + + ASSERT(WITHIN(TEXTURE_DC_pack_page_upto, 0, TEXTURE_DC_NORMAL_START - 1)); + + tt = &TEXTURE_texture[TEXTURE_DC_pack_page_upto]; + + // + // We can pack this texture. + // + + if (TEXTURE_DC_pack_page_pos == 0) + { + // + // Create a new 256x256 texture. + // + + tt->CreateUserPage(256, FALSE); + } + + // + // Load the TGA. + // + + TGA_Pixel *tga = (TGA_Pixel *) malloc(sizeof(TGA_Pixel) * 64 * 64); + TGA_Info ti = TGA_load(name_res64, 64, 64, tga, 0, FALSE); + + if (ti.valid) + { + UWORD *bitmap; + SLONG pitch; + + // + // Lock the texture and copy over the data into the texture. + // + + tt->LockUser(&bitmap, &pitch); + + if (bitmap) + { + SLONG x; + SLONG y; + + SLONG fx; + SLONG fy; + + SLONG tx; + SLONG ty; + + SLONG base_x; + SLONG base_y; + + SLONG pixel; + + // + // What is the base (x,y) for this pos? + // + + ASSERT(WITHIN(TEXTURE_DC_pack_page_pos, 0, 8)); + + base_x = (TEXTURE_DC_pack_page_pos % 3) * 64 + 32; + base_y = (TEXTURE_DC_pack_page_pos / 3) * 64 + 32; + + // + // The pitch is returned in bytes! + // + + pitch >>= 1; + + // + // Copy over the texture. + // + + for (x = 0; x < 64; x++) + for (y = 0; y < 64; y++) + { + fx = x; + fy = y; + + tx = base_x + x; + ty = base_y + y; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + } + + // + // Now do the edges... + // + + for (i = 0; i < 64; i++) + { + // + // Top... + // + + fx = i; + fy = 0; + + tx = base_x + i; + ty = base_y - 1; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + + // + // Bottom... + // + + fx = i; + fy = 63; + + tx = base_x + i; + ty = base_y + 64; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + + // + // Left... + // + + fx = 0; + fy = i; + + tx = base_x - 1; + ty = base_y + i; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + + // + // Right... + // + + fx = 63; + fy = i; + + tx = base_x + 64; + ty = base_y + i; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + } + + // + // Now do the corners. + // + + // + // Top left... + // + + fx = 0; + fy = 0; + + tx = base_x - 1; + ty = base_y - 1; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + + // + // Bottom right... + // + + fx = 63; + fy = 63; + + tx = base_x + 64; + ty = base_y + 64; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + + // + // Top right... + // + + fx = 63; + fy = 0; + + tx = base_x + 64; + ty = base_y - 1; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + + // + // Bottom left... + // + + fx = 0; + fy = 63; + + tx = base_x - 1; + ty = base_y + 64; + + pixel = 0; + pixel |= (tga[fx + fy * 64].red >> tt->mask_red) << tt->mask_red; + pixel |= (tga[fx + fy * 64].green >> tt->mask_red) << tt->mask_green; + pixel |= (tga[fx + fy * 64].blue >> tt->mask_red) << tt->mask_blue; + + bitmap[tx + ty * pitch] = pixel; + + tt->UnlockUser(); + } + } + + free(tga); + + // + // Remember where we've put this page. + // + + TEXTURE_DC_pack[page].page = TEXTURE_DC_pack_page_upto; + TEXTURE_DC_pack[page].pos = TEXTURE_DC_pack_page_pos; + + // + // Go onto the next hole... + // + + TEXTURE_DC_pack_page_pos += 1; + + if (TEXTURE_DC_pack_page_pos >= 9) + { + TEXTURE_DC_pack_page_pos = 0; + TEXTURE_DC_pack_page_upto += 1; + + ASSERT(WITHIN(TEXTURE_DC_pack_page_upto, 0, TEXTURE_DC_NORMAL_START - 1)); + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + +// +// Mark all standard textures as not-to-be-loaded in SOFTWARE mode. +// + +void this_may_well_be_the_last_ever_function_call_put_into_the_game(void) +{ + SLONG i; + + if (!SOFTWARE) + { + return; + } + + for (i = 0; i < TEXTURE_NUM_STANDARD; i++) + { + TEXTURE_texture[i].DontBotherLoadingInSoftwareMode = TRUE; + } +} + + + +// +// The number of textures. +// + +SLONG TEXTURE_num_textures; + +void TEXTURE_choose_set(SLONG number) +{ + SLONG i; + CBYTE textures[]="textures"; + + if(FileExists("psx.txt")) + { + sprintf(textures,"gary16"); + } + + // + // Set the directories. + // + + +#ifdef NO_SERVER + sprintf(TEXTURE_inside_dir, "server\\%s\\world%d\\insides\\",textures, number); + sprintf(TEXTURE_prims_dir, "server\\%s\\shared\\prims\\",textures); + sprintf(TEXTURE_people_dir, "server\\%s\\shared\\people\\",textures); + sprintf(TEXTURE_people_dir2, "server\\%s\\shared\\people2\\",textures); + sprintf(TEXTURE_world_dir, "server\\%s\\world%d\\",textures, number); + sprintf(TEXTURE_shared_dir, "server\\%s\\shared\\",textures, number); +#else + sprintf(TEXTURE_inside_dir, "u:\\urbanchaos\\%s\\world%d\\insides\\",textures, number); + sprintf(TEXTURE_prims_dir, "u:\\urbanchaos\\%s\\shared\\prims\\",textures); + sprintf(TEXTURE_people_dir, "u:\\urbanchaos\\%s\\shared\\people\\",textures); + sprintf(TEXTURE_people_dir2, "u:\\urbanchaos\\%s\\shared\\people2\\",textures); + sprintf(TEXTURE_world_dir, "u:\\urbanchaos\\%s\\world%d\\",textures, number); + sprintf(TEXTURE_shared_dir, "u:\\urbanchaos\\%s\\shared\\",textures); +#endif + strcpy(TEXTURE_WORLD_DIR,TEXTURE_world_dir); + sprintf(TEXTURE_fx_inifile, "%ssoundfx.ini", TEXTURE_world_dir); + sprintf(TEXTURE_shared_fx_inifile, "%ssoundfx.ini", TEXTURE_shared_dir); + SOUND_InitFXGroups(TEXTURE_shared_fx_inifile); + + if (number != TEXTURE_set) + { + // + // Initialise all the crinkles. + // + + CRINKLE_init(); + + // + // Free up all the world textures we have loaded so far. + // + + + for (i = 0; i < 64 * 4; i++) + { + if (TEXTURE_texture[i].Type != D3DTEXTURE_TYPE_UNUSED) + { + // + // Free this texture. + // + + TEXTURE_texture[i].Destroy(); + + // + // Mark as unused. + // + + TEXTURE_texture[i].Type = D3DTEXTURE_TYPE_UNUSED; + } + } + + memset ( TEXTURE_dontexist, 0, sizeof ( TEXTURE_dontexist ) ); + memset ( TEXTURE_crinkle, 0, sizeof ( TEXTURE_crinkle ) ); + + // + // Load the new poly-page flags. + // + + { + CBYTE world_texture_flags[256]; + CBYTE shared_texture_flags[256]; + + sprintf(world_texture_flags, "%stextype.txt", TEXTURE_world_dir); + sprintf(shared_texture_flags, "%stextype.txt", TEXTURE_shared_dir); + + POLY_init_texture_flags(); + POLY_load_texture_flags(world_texture_flags); + POLY_load_texture_flags(shared_texture_flags); +#ifdef NO_SERVER + POLY_load_texture_flags("server\\textures\\shared\\prims\\textype.txt", 11 * 64); +#else + POLY_load_texture_flags("u:\\urbanchaos\\textures\\shared\\prims\\textype.txt", 11 * 64); +#endif + } + + // + // Load in the style defs. + // + + load_texture_styles(FALSE, number); +extern void load_texture_instyles(UBYTE editor, UBYTE world); + load_texture_instyles(FALSE, number); + TEXTURE_fix_texture_styles(); + + } + + TEXTURE_set = number; +} + + + + + +// +// Loads the highest res version of the given page that it can find. +// + +bool IndividualTextures = false; + +static void TEXTURE_load_page(SLONG page) +{ + CBYTE name_res32[64]; + CBYTE name_res64[64]; + CBYTE name_res128[64]; +#ifdef TARGET_DC + CBYTE name_mvq32[64]; + CBYTE name_mvq64[64]; + CBYTE name_mvq128[64]; +#endif + CBYTE name_sex [64] = ""; + CBYTE shortname_res32[14]; + CBYTE shortname_res64[14]; + CBYTE shortname_res128[14]; + SLONG fxref; + + FILE *exists32; + FILE *exists64; + FILE *exists128; + + ASSERT(TEXTURE_set); + ASSERT(WITHIN(page, 0, TEXTURE_MAX_TEXTURES - 1)); + + if (TEXTURE_dontexist[page]) + { + return; + } + + if (page < 64 * 4) + { + // + // This is a world texture. + // + + #if TEXTURE_ENABLE_DC_PACKING + + TEXTURE_DC_pack_load_page(page); + + return; + + #endif + + sprintf(name_res32, "%stex%03d.tga", TEXTURE_world_dir, page); + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_world_dir, page); + sprintf(name_res128,"%stex%03dto.tga", TEXTURE_world_dir, page); + sprintf(name_sex, "%ssex%03dhi.sex", TEXTURE_world_dir, page); + + sprintf(shortname_res32, "tex%03d.tga", page); + sprintf(shortname_res64, "tex%03dhi.tga", page); + sprintf(shortname_res128,"tex%03dto.tga", page); + +#ifndef TARGET_DC + fxref=GetPrivateProfileInt("Textures",shortname_res64,-1,TEXTURE_fx_inifile); + if (fxref==-1) { + fxref=GetPrivateProfileInt("Textures",shortname_res32,-1,TEXTURE_fx_inifile); + } +#else //#ifndef TARGET_DC + // Dreamcast - GetPrivateProfile* don't exist. Spoof them for now. + fxref = -1; +#endif //#else //#ifndef TARGET_DC + +#ifndef TARGET_DC + if ( SOUND_FXMapping != NULL ) + { + SOUND_FXMapping[page]=fxref; + }; +#endif + + } + else + if (page < 64 * 8) + { + // + // This is a shared texture. + // + + sprintf(name_res32, "%stex%03d.tga", TEXTURE_shared_dir, page); + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_shared_dir, page); + sprintf(name_res128,"%stex%03dto.tga", TEXTURE_shared_dir, page); + sprintf(name_sex, "%ssex%03dhi.sex", TEXTURE_shared_dir, page); + sprintf(shortname_res32, "tex%03d.tga", page); + sprintf(shortname_res64, "tex%03dhi.tga", page); + sprintf(shortname_res128,"tex%03dto.tga", page); + +#ifndef TARGET_DC + fxref=GetPrivateProfileInt("Textures",shortname_res64,-1,TEXTURE_shared_fx_inifile); + if (fxref==-1) { + fxref=GetPrivateProfileInt("Textures",shortname_res32,-1,TEXTURE_shared_fx_inifile); + } +#else //#ifndef TARGET_DC + // Dreamcast - GetPrivateProfile* don't exist. Spoof them for now. + fxref = -1; +#endif //#else //#ifndef TARGET_DC + +#ifndef TARGET_DC + if ( SOUND_FXMapping != NULL ) + { + SOUND_FXMapping[page]=fxref; + } +#endif + } + else + if (page < 64 * 9) + { +/* +// +// people2 has been promoted to 18+ +// + if(page>=64*8+32) + { + sprintf(name_res32, "%stex%03d.tga", TEXTURE_people_dir2, page-64*8); + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_people_dir2, page-64*8); + } + else +*/ + { + sprintf(name_res32, "%stex%03d.tga", TEXTURE_inside_dir, page-64*8); + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_inside_dir, page-64*8); + sprintf(name_res128,"%stex%03dto.tga", TEXTURE_inside_dir, page-64*8); + } + } + else + if (page < 64 * 11) + { + sprintf(name_res32, "%stex%03d.tga", TEXTURE_people_dir, page-64*9); + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_people_dir, page-64*9); + sprintf(name_res128,"%stex%03dto.tga", TEXTURE_people_dir, page-64*9); + DebugText("people page %d offset %d \n",page/64,page-64*9); + } + else + if (page < 64 * 18) + { + sprintf(name_res32, "%stex%03d.tga", TEXTURE_prims_dir, page-64*11); + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_prims_dir, page-64*11); + sprintf(name_res128,"%stex%03dto.tga", TEXTURE_prims_dir, page-64*11); + DebugText("prims page %d offset %d fname %s\n",page/64,page-64*11,name_res64); + } + else + if (page < 64 * 21) + { + sprintf(name_res32, "%stex%03d.tga", TEXTURE_people_dir2, page-64*18); + sprintf(name_res64, "%stex%03dhi.tga", TEXTURE_people_dir2, page-64*18); + sprintf(name_res128,"%stex%03dto.tga", TEXTURE_people_dir2, page-64*18); + } + else + { + ASSERT(0); + } + + +#ifdef TARGET_DC + strcpy ( name_mvq32, name_res32 ); + char *pch = name_mvq32 + strlen ( name_res32 ) - 3; + *pch++ = 'm'; + *pch++ = 'v'; + *pch++ = 'q'; + strcpy ( name_mvq64, name_res64 ); + pch = name_mvq64 + strlen ( name_res64 ) - 3; + *pch++ = 'm'; + *pch++ = 'v'; + *pch++ = 'q'; + strcpy ( name_mvq128, name_res128 ); + pch = name_mvq128 + strlen ( name_res128 ) - 3; + *pch++ = 'm'; + *pch++ = 'v'; + *pch++ = 'q'; + +#endif + + if (IndividualTextures || TEXTURE_create_clump) + { +#ifdef TARGET_DC + HRESULT hres; + if ( FileExists(name_res128) || FileExists(name_mvq128) ) + { + hres = TEXTURE_texture[page].LoadTextureTGA(name_res128, page); + } + else if ( FileExists(name_res64) || FileExists(name_mvq64) ) + { + hres = TEXTURE_texture[page].LoadTextureTGA(name_res64, page); + } + else if ( FileExists(name_res32) || FileExists(name_mvq32) ) + { + hres = TEXTURE_texture[page].LoadTextureTGA(name_res32, page); + } + else + { + hres = DDERR_INVALIDOBJECT; + } + + if ( FAILED ( hres ) ) + { + TRACE ( "Page %s not found", name_res32 ); + TEXTURE_dontexist[page] = TRUE; + } + + +#else + + exists128 = MF_Fopen(name_res128, "rb"); + if (exists128) + { + MF_Fclose(exists128); + TEXTURE_texture[page].LoadTextureTGA(name_res128, page); + } + else + { + exists64 = MF_Fopen(name_res64, "rb"); + + if (exists64) + { + MF_Fclose(exists64); + + TEXTURE_texture[page].LoadTextureTGA(name_res64, page); + } + else + { + exists32 = MF_Fopen(name_res32, "rb"); + + if (exists32) + { + MF_Fclose(exists32); + + TEXTURE_texture[page].LoadTextureTGA(name_res32, page); + } + else + { + // + // This texture doesn't exist ! + // + DebugText(" cant find page %d name64 %s \n",page,name_res64); + + TEXTURE_dontexist[page] = TRUE; + } + } + } +#endif + } + else + { + +#ifdef TARGET_DC + HRESULT hres; + if ( FileExists(name_res128) || FileExists(name_mvq128) ) + { + hres = TEXTURE_texture[page].LoadTextureTGA(name_res128, page); + } + else if ( FileExists(name_res64) || FileExists(name_mvq64) ) + { + hres = TEXTURE_texture[page].LoadTextureTGA(name_res64, page); + } + else if ( FileExists(name_res32) || FileExists(name_mvq32) ) + { + hres = TEXTURE_texture[page].LoadTextureTGA(name_res32, page); + } + else + { + hres = DDERR_INVALIDOBJECT; + } + + if ( FAILED ( hres ) ) + { + TRACE ( "Page %s not found", name_res32 ); + ASSERT ( FALSE ); + TEXTURE_dontexist[page] = TRUE; + } +#else + + if (DoesTGAExist(name_res64, page)) + { + TEXTURE_texture[page].LoadTextureTGA(name_res64, page); + } + else + if (DoesTGAExist(name_res32, page)) + { + TEXTURE_texture[page].LoadTextureTGA(name_res32, page); + } + else + { + TEXTURE_dontexist[page] = TRUE; + } +#endif + } + + // crinkles + + if (page < 64 * 8) + { +#ifdef TARGET_DC + ASSERT ( IndividualTextures ); +#endif + if (IndividualTextures || TEXTURE_create_clump) + { + TEXTURE_crinkle[page] = CRINKLE_load(name_sex); +#ifdef TARGET_DC + ASSERT ( !TEXTURE_create_clump ); +#else + if (TEXTURE_create_clump && TEXTURE_crinkle[page]) + { + CRINKLE_write_bin(GetTGAClump(), TEXTURE_crinkle[page], TEXTURE_MAX_TEXTURES + page); + } +#endif + } + else + { +#ifdef TARGET_DC + // Shouldn't get here. + ASSERT ( FALSE ); +#else + if (!DoesTGAExist("", TEXTURE_MAX_TEXTURES + page)) + { + TEXTURE_crinkle[page] = NULL; + } + else + { + TEXTURE_crinkle[page] = CRINKLE_read_bin(GetTGAClump(), TEXTURE_MAX_TEXTURES + page); + } +#endif + } + } + + if (POLY_page_is_masked_self_illuminating(page)) + { + if (TEXTURE_texture[page + 1].Type == D3DTEXTURE_TYPE_UNUSED) + { + TEXTURE_load_page(page + 1); + } + } +} + + +void TEXTURE_initialise_clumping(CBYTE *fname_level) +{ + +#ifdef TARGET_DC + const int clumping = 0; +#else //#ifdef TARGET_DC + +#undef FINAL +#ifdef FINAL + int clumping = 1; +#else + int clumping = ENV_get_value_number("enable_clumps", 0, "TextureClumps"); +#endif + +#endif //#else //#ifdef TARGET_DC + + +extern void SetLastClumpfile(char* file, size_t size); // in GDisplay.cpp, horrible bodge + + if (!clumping) + { + // load textures directly + IndividualTextures = true; + SetLastClumpfile("", 0); + } + else + { + +#ifdef TARGET_DC + // Shouldn't be coming here. + ASSERT ( FALSE ); +#else + + // load textures from the clump + char filename[256]; + char* leafname; + + do + { + leafname = fname_level; + while (*fname_level && (*fname_level != '\\')) fname_level++; + } while (*fname_level++ == '\\'); + + // write out + sprintf(filename, "%sclumps\\", GetTexturePath()); + char* fptr = filename + strlen(filename); + while (*leafname != '.') *fptr++ = *leafname++; + strcpy(fptr, ".txc"); + + OpenTGAClump(filename, TEXTURE_MAX_TEXTURES + 64*8, !TEXTURE_create_clump); + IndividualTextures = false; + SetLastClumpfile(filename, TEXTURE_MAX_TEXTURES + 64*8); +#endif + } +} + + + +void TEXTURE_load_needed(CBYTE* fname_level, + int iStartCompletionBar, + int iEndCompletionBar, + int iNumberTexturesProbablyLoaded + ) +{ + SLONG i,j,k; + SLONG x; + SLONG z; + + PrimFace3 *f3; + PrimFace4 *f4; + + SLONG page; + float u[4]; + float v[4]; + + SLONG c0,c1; + + MapElement *me; + +extern UBYTE loading_screen_active; // ! + + + +#define HOW_MANY_UPDATES 20 + int iNumTexturesLoaded = 0; + int iNumTexturesToDoNextChunk = iNumberTexturesProbablyLoaded / HOW_MANY_UPDATES; + int iCurChunkVal = iStartCompletionBar; + +extern void ATTRACT_loadscreen_draw(SLONG completion); + +#define LOADED_THIS_MANY_TEXTURES(numtex) \ + iNumTexturesLoaded += numtex; \ + while ( iNumTexturesLoaded > iNumTexturesToDoNextChunk ) \ + { \ + iNumTexturesToDoNextChunk += iNumberTexturesProbablyLoaded / HOW_MANY_UPDATES; \ + iCurChunkVal += ( iEndCompletionBar - iStartCompletionBar ) / HOW_MANY_UPDATES; \ + ATTRACT_loadscreen_draw ( iCurChunkVal ); \ + } + + + + TEXTURE_free(); + + D3DTexture::BeginLoading(); + + TEXTURE_initialise_clumping(fname_level); + +#ifdef TARGET_DC + bool bFrontEnd = FALSE; + if ( ( fname_level == NULL ) || ( 0 == strcmp ( fname_level, "levels\\frontend.ucm" ) ) ) + { + // Not actually a level - no level stuff loaded. + bFrontEnd = TRUE; + } + // This should agree in theory. + ASSERT ( loading_screen_active == !bFrontEnd ); +#endif + + TEXTURE_load_page(1); + + // + // Load all the unusual pages. + // + + TEXTURE_page_num_standard = TEXTURE_NUM_STANDARD + 0; + + TEXTURE_page_fog = TEXTURE_NUM_STANDARD + 0; + TEXTURE_page_moon = TEXTURE_NUM_STANDARD + 1; + TEXTURE_page_clouds = TEXTURE_NUM_STANDARD + 2; + TEXTURE_page_water = TEXTURE_NUM_STANDARD + 3; + TEXTURE_page_puddle = TEXTURE_NUM_STANDARD + 4; + TEXTURE_page_drip = TEXTURE_NUM_STANDARD + 5; + TEXTURE_page_shadow = TEXTURE_NUM_STANDARD + 6; + TEXTURE_page_bang = TEXTURE_NUM_STANDARD + 7; + TEXTURE_page_font = TEXTURE_NUM_STANDARD + 8; + TEXTURE_page_logo = TEXTURE_NUM_STANDARD + 9; + TEXTURE_page_sky = TEXTURE_NUM_STANDARD + 10; + TEXTURE_page_flames = TEXTURE_NUM_STANDARD + 11; + TEXTURE_page_smoke = TEXTURE_NUM_STANDARD + 12; + TEXTURE_page_flame2 = TEXTURE_NUM_STANDARD + 13; + TEXTURE_page_steam = TEXTURE_NUM_STANDARD + 14; + TEXTURE_page_menuflame = TEXTURE_NUM_STANDARD + 15; + TEXTURE_page_barbwire = TEXTURE_NUM_STANDARD + 16; + TEXTURE_page_font2d = TEXTURE_NUM_STANDARD + 17; + TEXTURE_page_face1 = TEXTURE_NUM_STANDARD + 18; + TEXTURE_page_face2 = TEXTURE_NUM_STANDARD + 19; + TEXTURE_page_face3 = TEXTURE_NUM_STANDARD + 20; + TEXTURE_page_face4 = TEXTURE_NUM_STANDARD + 21; + TEXTURE_page_face5 = TEXTURE_NUM_STANDARD + 22; + TEXTURE_page_face6 = TEXTURE_NUM_STANDARD + 23; + TEXTURE_page_bigbang = TEXTURE_NUM_STANDARD + 24; + TEXTURE_page_dustwave = TEXTURE_NUM_STANDARD + 25; + TEXTURE_page_flames3 = TEXTURE_NUM_STANDARD + 26; + TEXTURE_page_bloodsplat = TEXTURE_NUM_STANDARD + 27; + TEXTURE_page_bloom1 = TEXTURE_NUM_STANDARD + 28; + TEXTURE_page_bloom2 = TEXTURE_NUM_STANDARD + 29; + TEXTURE_page_hitspang = TEXTURE_NUM_STANDARD + 30; + TEXTURE_page_lensflare = TEXTURE_NUM_STANDARD + 31; + TEXTURE_page_envmap = TEXTURE_NUM_STANDARD + 32; + TEXTURE_page_tyretrack = TEXTURE_NUM_STANDARD + 33; + TEXTURE_page_winmap = TEXTURE_NUM_STANDARD + 34; + TEXTURE_page_leaf = TEXTURE_NUM_STANDARD + 35; + TEXTURE_page_raindrop = TEXTURE_NUM_STANDARD + 36; + TEXTURE_page_footprint = TEXTURE_NUM_STANDARD + 37; + TEXTURE_page_angel = TEXTURE_NUM_STANDARD + 38; + TEXTURE_page_devil = TEXTURE_NUM_STANDARD + 39; + TEXTURE_page_smoker = TEXTURE_NUM_STANDARD + 40; + TEXTURE_page_target = TEXTURE_NUM_STANDARD + 41; + TEXTURE_page_newfont = TEXTURE_NUM_STANDARD + 42; + TEXTURE_page_droplet = TEXTURE_NUM_STANDARD + 43; + TEXTURE_page_press1 = TEXTURE_NUM_STANDARD + 44; + TEXTURE_page_press2 = TEXTURE_NUM_STANDARD + 45; + TEXTURE_page_ic = TEXTURE_NUM_STANDARD + 46; + TEXTURE_page_ic2 = TEXTURE_NUM_STANDARD + 47; + TEXTURE_page_explode1 = TEXTURE_NUM_STANDARD + 48; + TEXTURE_page_explode2 = TEXTURE_NUM_STANDARD + 49; + TEXTURE_page_lcdfont = TEXTURE_NUM_STANDARD + 50; + TEXTURE_page_smokecloud = TEXTURE_NUM_STANDARD + 51; + TEXTURE_page_menulogo = TEXTURE_NUM_STANDARD + 52; + TEXTURE_page_polaroid = TEXTURE_NUM_STANDARD + 53; + TEXTURE_page_sparkle = TEXTURE_NUM_STANDARD + 54; + TEXTURE_page_bigbutton = TEXTURE_NUM_STANDARD + 55; + TEXTURE_page_bigleaf = TEXTURE_NUM_STANDARD + 56; + TEXTURE_page_bigrain = TEXTURE_NUM_STANDARD + 57; + TEXTURE_page_finalglow = TEXTURE_NUM_STANDARD + 58; + TEXTURE_page_tinybutt = TEXTURE_NUM_STANDARD + 59; + TEXTURE_page_tyretrack_alpha = TEXTURE_NUM_STANDARD + 60; + TEXTURE_page_ladder = TEXTURE_NUM_STANDARD + 61; + TEXTURE_page_fadecat = TEXTURE_NUM_STANDARD + 62; + TEXTURE_page_shadowoval = TEXTURE_NUM_STANDARD + 63; + TEXTURE_page_rubbish = TEXTURE_NUM_STANDARD + 64; + TEXTURE_page_lastpanel = TEXTURE_NUM_STANDARD + 65; + TEXTURE_page_pcflamer = TEXTURE_NUM_STANDARD + 66; + TEXTURE_page_sign = TEXTURE_NUM_STANDARD + 67; + TEXTURE_page_shadowsquare = TEXTURE_NUM_STANDARD + 68; + TEXTURE_page_lastpanel2 = TEXTURE_NUM_STANDARD + 69; + TEXTURE_page_litebolt = TEXTURE_NUM_STANDARD + 70; + TEXTURE_page_ladshad = TEXTURE_NUM_STANDARD + 71; + TEXTURE_page_meteor = TEXTURE_NUM_STANDARD + 72; + TEXTURE_page_splash = TEXTURE_NUM_STANDARD + 73; + TEXTURE_page_snowflake = TEXTURE_NUM_STANDARD + 74; + TEXTURE_page_fade_MF = TEXTURE_NUM_STANDARD + 75; + +#ifdef TARGET_DC + TEXTURE_page_joypad_a = TEXTURE_NUM_STANDARD + 76; + TEXTURE_page_joypad_b = TEXTURE_NUM_STANDARD + 77; + TEXTURE_page_joypad_c = TEXTURE_NUM_STANDARD + 78; + TEXTURE_page_joypad_x = TEXTURE_NUM_STANDARD + 79; + TEXTURE_page_joypad_y = TEXTURE_NUM_STANDARD + 80; + TEXTURE_page_joypad_z = TEXTURE_NUM_STANDARD + 81; + TEXTURE_page_joypad_l = TEXTURE_NUM_STANDARD + 82; + TEXTURE_page_joypad_r = TEXTURE_NUM_STANDARD + 83; + TEXTURE_page_joypad_pad_l = TEXTURE_NUM_STANDARD + 84; + TEXTURE_page_joypad_pad_r = TEXTURE_NUM_STANDARD + 85; + TEXTURE_page_joypad_pad_d = TEXTURE_NUM_STANDARD + 86; + TEXTURE_page_joypad_pad_u = TEXTURE_NUM_STANDARD + 87; + + // Special-cased one. + TEXTURE_page_background_use_instead = TEXTURE_NUM_STANDARD + 88; + TEXTURE_page_background_use_instead2 = TEXTURE_NUM_STANDARD + 89; +#endif + TEXTURE_num_textures = TEXTURE_NUM_STANDARD + 90 + 20; + + + + // + // Where we load the extra textures from. + // + +#ifdef NO_SERVER + #define TEXTURE_EXTRA_DIR "server\\textures\\extras\\" + #define TEXTURE_PEOPLE3_DIR "server\\textures\\shared\\people3\\" +#else + #define TEXTURE_EXTRA_DIR "u:\\urbanchaos\\textures\\extras\\" + #define TEXTURE_PEOPLE3_DIR "u:\\urbanchaos\\textures\\shared\\people3\\" + +#endif + + // + // Tell the font page its a font page. + // + + TEXTURE_texture[TEXTURE_page_font].FontOn(); + TEXTURE_needed[TEXTURE_page_font] = 1; + + + // + // Tell the NEWFONT page it's a font page mark 2 + // (to remove red borders) + // + + TEXTURE_texture[TEXTURE_page_lcdfont].Font2On(); + TEXTURE_needed[TEXTURE_page_lcdfont] = 1; + + TEXTURE_texture[TEXTURE_page_fog ].LoadTextureTGA(TEXTURE_EXTRA_DIR"fog.tga", TEXTURE_page_fog); + TEXTURE_texture[TEXTURE_page_moon ].LoadTextureTGA(TEXTURE_EXTRA_DIR"moon.tga", TEXTURE_page_moon); + TEXTURE_texture[TEXTURE_page_clouds ].LoadTextureTGA(TEXTURE_EXTRA_DIR"clouds.tga", TEXTURE_page_clouds); + TEXTURE_texture[TEXTURE_page_water ].LoadTextureTGA(TEXTURE_EXTRA_DIR"water.tga", TEXTURE_page_water); + TEXTURE_texture[TEXTURE_page_puddle ].LoadTextureTGA(TEXTURE_EXTRA_DIR"puddle01.tga", TEXTURE_page_puddle); +LOADED_THIS_MANY_TEXTURES(5); + TEXTURE_texture[TEXTURE_page_drip ].LoadTextureTGA(TEXTURE_EXTRA_DIR"drip.tga", TEXTURE_page_drip); + TEXTURE_texture[TEXTURE_page_shadow ].CreateUserPage(TEXTURE_SHADOW_SIZE, the_display.GetDeviceInfo()->DestInvSourceColourSupported() ? FALSE : TRUE); + TEXTURE_texture[TEXTURE_page_bang ].LoadTextureTGA(TEXTURE_EXTRA_DIR"fireball.tga", TEXTURE_page_bang); + TEXTURE_texture[TEXTURE_page_font ].LoadTextureTGA(TEXTURE_EXTRA_DIR"font.tga", TEXTURE_page_font,FALSE); + TEXTURE_needed[TEXTURE_page_font] = 1; +LOADED_THIS_MANY_TEXTURES(5); + //TEXTURE_texture[TEXTURE_page_logo ].LoadTextureTGA(TEXTURE_EXTRA_DIR"logo3.tga", TEXTURE_page_logo); + { + CBYTE str[100]; +// sprintf(str,TEXTURE_EXTRA_DIR"sky%d.tga",Random()&3); + sprintf(str, "%ssky.tga", TEXTURE_world_dir); + + // Until the VQ quality improves, don't VQ the sky - it looks pretty grim. + TEXTURE_texture[TEXTURE_page_sky ].LoadTextureTGA(str,TEXTURE_page_sky,FALSE); + } +// TEXTURE_texture[TEXTURE_page_sky ].LoadTextureTGA(TEXTURE_EXTRA_DIR"sky2.tga", TEXTURE_page_sky); + + TEXTURE_texture[TEXTURE_page_flames ].LoadTextureTGA(TEXTURE_EXTRA_DIR"flame1.tga", TEXTURE_page_flames); + TEXTURE_texture[TEXTURE_page_smoke ].LoadTextureTGA(TEXTURE_EXTRA_DIR"smoke1.tga", TEXTURE_page_smoke); +// TEXTURE_texture[TEXTURE_page_flame2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"flame2.tga", TEXTURE_page_flame2); + TEXTURE_texture[TEXTURE_page_flame2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"explode4.tga", TEXTURE_page_flame2); + TEXTURE_texture[TEXTURE_page_steam ].LoadTextureTGA(TEXTURE_EXTRA_DIR"fog_na.tga", TEXTURE_page_steam); + TEXTURE_texture[TEXTURE_page_barbwire ].LoadTextureTGA(TEXTURE_EXTRA_DIR"barbed.tga", TEXTURE_page_barbwire); +LOADED_THIS_MANY_TEXTURES(6); + +#ifdef TARGET_DC + TEXTURE_texture[TEXTURE_page_font2d ].LoadTextureTGA(TEXTURE_EXTRA_DIR"multifontPC.tga", TEXTURE_page_font2d, FALSE); +#else + if (SOFTWARE) + { + TEXTURE_texture[TEXTURE_page_font2d ].LoadTextureTGA(TEXTURE_EXTRA_DIR"multifontPC640.tga", TEXTURE_page_font2d); + } + else + { + TEXTURE_texture[TEXTURE_page_font2d ].LoadTextureTGA(TEXTURE_EXTRA_DIR"multifontPC.tga", TEXTURE_page_font2d, FALSE); + } +#endif + TEXTURE_needed[TEXTURE_page_font2d] = 1; + + // TEXTURE_texture[TEXTURE_page_lcdfont ].LoadTextureTGA(TEXTURE_EXTRA_DIR"font3.tga", TEXTURE_page_ +#ifdef TARGET_DC + TEXTURE_texture[TEXTURE_page_lcdfont ].LoadTextureTGA(TEXTURE_EXTRA_DIR"olyfont2dc.tga", TEXTURE_page_lcdfont, FALSE); +#else + TEXTURE_texture[TEXTURE_page_lcdfont ].LoadTextureTGA(TEXTURE_EXTRA_DIR"olyfont2.tga", TEXTURE_page_lcdfont, FALSE); +#endif + TEXTURE_needed[TEXTURE_page_lcdfont] = 1; + + + TEXTURE_texture[TEXTURE_page_lastpanel ].LoadTextureTGA(TEXTURE_EXTRA_DIR"PCdisplay.tga", TEXTURE_page_lastpanel, FALSE); + TEXTURE_needed[TEXTURE_page_lastpanel] = 1; + + FONT2D_init(TEXTURE_page_font2d); // do it now so it's still in the CD-ROM cache + TEXTURE_texture[TEXTURE_page_face1 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"face1.tga", TEXTURE_page_face1); + TEXTURE_texture[TEXTURE_page_face2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"face2.tga", TEXTURE_page_face2); +LOADED_THIS_MANY_TEXTURES(5); + //TEXTURE_texture[TEXTURE_page_face3 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"face3.tga", TEXTURE_page_face3); + //TEXTURE_texture[TEXTURE_page_face4 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"face4.tga", TEXTURE_page_face4); + //TEXTURE_texture[TEXTURE_page_face5 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"face5.tga", TEXTURE_page_face5); + //TEXTURE_texture[TEXTURE_page_face6 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"face6.tga", TEXTURE_page_face6); + TEXTURE_texture[TEXTURE_page_bigbang ].LoadTextureTGA(TEXTURE_EXTRA_DIR"exp_gunk.tga", TEXTURE_page_bigbang); +// TEXTURE_texture[TEXTURE_page_dustwave ].LoadTextureTGA(TEXTURE_EXTRA_DIR"dustwave.tga", TEXTURE_page_dustwave); + TEXTURE_texture[TEXTURE_page_dustwave ].LoadTextureTGA(TEXTURE_EXTRA_DIR"shockwave.tga", TEXTURE_page_dustwave); + TEXTURE_texture[TEXTURE_page_flames3 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"flame3.tga", TEXTURE_page_flames3); + TEXTURE_texture[TEXTURE_page_bloodsplat].LoadTextureTGA(TEXTURE_EXTRA_DIR"bludsplt.tga", TEXTURE_page_bloodsplat); +// TEXTURE_texture[TEXTURE_page_bloom1 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"bloom1.tga", TEXTURE_page_bloom1); +// TEXTURE_texture[TEXTURE_page_bloom1 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"bloom3.tga", TEXTURE_page_bloom1); + TEXTURE_texture[TEXTURE_page_bloom1 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"bloom4.tga", TEXTURE_page_bloom1); +LOADED_THIS_MANY_TEXTURES(5); + TEXTURE_texture[TEXTURE_page_bloom2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"bloom2.tga", TEXTURE_page_bloom2); + TEXTURE_texture[TEXTURE_page_hitspang ].LoadTextureTGA(TEXTURE_EXTRA_DIR"hitspang.tga", TEXTURE_page_hitspang); + TEXTURE_texture[TEXTURE_page_lensflare ].LoadTextureTGA(TEXTURE_EXTRA_DIR"lensflar.tga", TEXTURE_page_lensflare); + TEXTURE_texture[TEXTURE_page_envmap ].LoadTextureTGA(TEXTURE_EXTRA_DIR"envmap.tga", TEXTURE_page_envmap); + TEXTURE_texture[TEXTURE_page_tyretrack ].LoadTextureTGA(TEXTURE_EXTRA_DIR"tyremark.tga", TEXTURE_page_tyretrack); +LOADED_THIS_MANY_TEXTURES(5); + TEXTURE_texture[TEXTURE_page_winmap ].LoadTextureTGA(TEXTURE_EXTRA_DIR"winmap.tga", TEXTURE_page_winmap); + TEXTURE_texture[TEXTURE_page_leaf ].LoadTextureTGA(TEXTURE_EXTRA_DIR"leaf.tga", TEXTURE_page_leaf); + TEXTURE_texture[TEXTURE_page_raindrop ].LoadTextureTGA(TEXTURE_EXTRA_DIR"raindrop.tga", TEXTURE_page_raindrop); + TEXTURE_texture[TEXTURE_page_footprint ].LoadTextureTGA(TEXTURE_EXTRA_DIR"footprint.tga", TEXTURE_page_footprint); + //TEXTURE_texture[TEXTURE_page_angel ].LoadTextureTGA(TEXTURE_EXTRA_DIR"angel.tga", TEXTURE_page_angel); + //TEXTURE_texture[TEXTURE_page_devil ].LoadTextureTGA(TEXTURE_EXTRA_DIR"devil.tga", TEXTURE_page_devil); + TEXTURE_texture[TEXTURE_page_smoker ].LoadTextureTGA(TEXTURE_EXTRA_DIR"smoker2.tga", TEXTURE_page_smoker); + TEXTURE_texture[TEXTURE_page_target ].LoadTextureTGA(TEXTURE_EXTRA_DIR"targ1.tga", TEXTURE_page_target); + //TEXTURE_texture[TEXTURE_page_newfont ].LoadTextureTGA(TEXTURE_EXTRA_DIR"multifontPC.tga", TEXTURE_page_newfont); + TEXTURE_texture[TEXTURE_page_droplet ].LoadTextureTGA(TEXTURE_EXTRA_DIR"droplet.tga", TEXTURE_page_droplet); +LOADED_THIS_MANY_TEXTURES(7); + //TEXTURE_texture[TEXTURE_page_press1 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"press1.tga", TEXTURE_page_press1); + //TEXTURE_texture[TEXTURE_page_press2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"press2.tga", TEXTURE_page_press2); + //TEXTURE_texture[TEXTURE_page_ic ].LoadTextureTGA(TEXTURE_EXTRA_DIR"ic5.tga", TEXTURE_page_ic); + //TEXTURE_texture[TEXTURE_page_ic2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"ic2_6.tga", TEXTURE_page_ic2); + TEXTURE_texture[TEXTURE_page_explode1 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"explode1.tga", TEXTURE_page_explode1); + TEXTURE_texture[TEXTURE_page_explode2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"explode2.tga", TEXTURE_page_explode2); + TEXTURE_texture[TEXTURE_page_smokecloud].LoadTextureTGA(TEXTURE_EXTRA_DIR"explode3.tga", TEXTURE_page_smokecloud); + TEXTURE_texture[TEXTURE_page_menulogo ].LoadTextureTGA(TEXTURE_EXTRA_DIR"menulogo.tga", TEXTURE_page_menulogo); + TEXTURE_needed[TEXTURE_page_menulogo] = 1; +LOADED_THIS_MANY_TEXTURES(4); + //TEXTURE_texture[TEXTURE_page_polaroid ].LoadTextureTGA(TEXTURE_EXTRA_DIR"photos\\police1.tga", TEXTURE_page_polaroid); + TEXTURE_texture[TEXTURE_page_sparkle ].LoadTextureTGA(TEXTURE_EXTRA_DIR"sparkle.tga", TEXTURE_page_sparkle); + TEXTURE_texture[TEXTURE_page_pcflamer ].LoadTextureTGA(TEXTURE_EXTRA_DIR"PCflamer.tga", TEXTURE_page_pcflamer); + TEXTURE_texture[TEXTURE_page_litebolt ].LoadTextureTGA(TEXTURE_EXTRA_DIR"litebolt2.tga", TEXTURE_page_litebolt); + TEXTURE_texture[TEXTURE_page_splash ].LoadTextureTGA(TEXTURE_EXTRA_DIR"splashALL.tga", TEXTURE_page_splash); +LOADED_THIS_MANY_TEXTURES(4); + + // frontend stuff... + TEXTURE_texture[TEXTURE_page_bigbutton ].LoadTextureTGA(TEXTURE_EXTRA_DIR"bigbutt.tga", TEXTURE_page_bigbutton, FALSE); + TEXTURE_needed [TEXTURE_page_bigbutton] = 1; + TEXTURE_texture[TEXTURE_page_bigleaf ].LoadTextureTGA(TEXTURE_EXTRA_DIR"bigleaf.tga", TEXTURE_page_bigleaf); + TEXTURE_needed [TEXTURE_page_bigleaf] = 1; + TEXTURE_texture[TEXTURE_page_bigrain ].LoadTextureTGA(TEXTURE_EXTRA_DIR"raindrop2.tga", TEXTURE_page_bigrain); + TEXTURE_needed [TEXTURE_page_bigrain] = 1; + TEXTURE_texture[TEXTURE_page_tinybutt ].LoadTextureTGA(TEXTURE_EXTRA_DIR"tinybutt.tga", TEXTURE_page_tinybutt, FALSE); + TEXTURE_needed [TEXTURE_page_tinybutt] = 1; + TEXTURE_texture[TEXTURE_page_snowflake ].LoadTextureTGA(TEXTURE_EXTRA_DIR"snowflake.tga", TEXTURE_page_snowflake); + TEXTURE_needed [TEXTURE_page_snowflake] = 1; + + TEXTURE_texture[TEXTURE_page_finalglow ].LoadTextureTGA(TEXTURE_EXTRA_DIR"finalglow.tga", TEXTURE_page_finalglow); + TEXTURE_needed [TEXTURE_page_finalglow] = 1; + + // Used for the screensaver. Don't use the MVQ - it doesn't get 100% black. + TEXTURE_texture[TEXTURE_page_fade_MF ].LoadTextureTGA(TEXTURE_EXTRA_DIR"fade_MF.tga", TEXTURE_page_fade_MF, FALSE); + TEXTURE_needed [TEXTURE_page_fade_MF] = 1; + +LOADED_THIS_MANY_TEXTURES(7); + + +#ifdef TARGET_DC + // The joypad button textures. + TEXTURE_texture[TEXTURE_page_joypad_a].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_A.tga", TEXTURE_page_joypad_a); + TEXTURE_needed [TEXTURE_page_joypad_a] = 1; + TEXTURE_texture[TEXTURE_page_joypad_b].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_B.tga", TEXTURE_page_joypad_b); + TEXTURE_needed [TEXTURE_page_joypad_b] = 1; + TEXTURE_texture[TEXTURE_page_joypad_c].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_C.tga", TEXTURE_page_joypad_c); + TEXTURE_needed [TEXTURE_page_joypad_c] = 1; + TEXTURE_texture[TEXTURE_page_joypad_x].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_X.tga", TEXTURE_page_joypad_x); + TEXTURE_needed [TEXTURE_page_joypad_x] = 1; + TEXTURE_texture[TEXTURE_page_joypad_y].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_Y.tga", TEXTURE_page_joypad_y); + TEXTURE_needed [TEXTURE_page_joypad_y] = 1; + TEXTURE_texture[TEXTURE_page_joypad_z].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_Z.tga", TEXTURE_page_joypad_z); + TEXTURE_needed [TEXTURE_page_joypad_z] = 1; +LOADED_THIS_MANY_TEXTURES(6); + TEXTURE_texture[TEXTURE_page_joypad_l].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_LEFT.tga", TEXTURE_page_joypad_l); + TEXTURE_needed [TEXTURE_page_joypad_l] = 1; + TEXTURE_texture[TEXTURE_page_joypad_r].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_RIGHT.tga", TEXTURE_page_joypad_r); + TEXTURE_needed [TEXTURE_page_joypad_r] = 1; + TEXTURE_texture[TEXTURE_page_joypad_pad_l].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_PADLEFT.tga", TEXTURE_page_joypad_pad_l); + TEXTURE_needed [TEXTURE_page_joypad_pad_l] = 1; + TEXTURE_texture[TEXTURE_page_joypad_pad_r].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_PADRIGHT.tga", TEXTURE_page_joypad_pad_r); + TEXTURE_needed [TEXTURE_page_joypad_pad_r] = 1; + TEXTURE_texture[TEXTURE_page_joypad_pad_d].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_PADDOWN.tga", TEXTURE_page_joypad_pad_d); + TEXTURE_needed [TEXTURE_page_joypad_pad_d] = 1; + TEXTURE_texture[TEXTURE_page_joypad_pad_u].LoadTextureTGA(TEXTURE_EXTRA_DIR"DC\\button_PADUP.tga", TEXTURE_page_joypad_pad_u); + TEXTURE_needed [TEXTURE_page_joypad_pad_u] = 1; +LOADED_THIS_MANY_TEXTURES(6); +#endif + + +#ifdef TARGET_DC + // Only loaded during an actual level. + if ( !bFrontEnd ) +#endif + { + + TEXTURE_texture[TEXTURE_page_fadecat ].LoadTextureTGA(TEXTURE_EXTRA_DIR"fadecat.tga", TEXTURE_page_fadecat, FALSE); + + TEXTURE_texture[TEXTURE_page_tyretrack_alpha ].LoadTextureTGA(TEXTURE_EXTRA_DIR"tyremark_alpha.tga", TEXTURE_page_tyretrack_alpha); + + TEXTURE_texture[TEXTURE_page_ladder ].LoadTextureTGA(TEXTURE_EXTRA_DIR"secret.tga", TEXTURE_page_ladder); + TEXTURE_texture[TEXTURE_page_shadowoval ].LoadTextureTGA(TEXTURE_EXTRA_DIR"shadow.tga", TEXTURE_page_shadowoval); + TEXTURE_texture[TEXTURE_page_rubbish ].LoadTextureTGA(TEXTURE_EXTRA_DIR"rubbish.tga", TEXTURE_page_rubbish); + +LOADED_THIS_MANY_TEXTURES(5); + + // Done above. + //TEXTURE_texture[TEXTURE_page_lastpanel ].LoadTextureTGA(TEXTURE_EXTRA_DIR"PCdisplay.tga", TEXTURE_page_lastpanel, FALSE); + TEXTURE_texture[TEXTURE_page_lastpanel2 ].LoadTextureTGA(TEXTURE_EXTRA_DIR"PCdisplay01.tga", TEXTURE_page_lastpanel2, FALSE); + + TEXTURE_texture[TEXTURE_page_sign ].LoadTextureTGA(TEXTURE_EXTRA_DIR"signs.tga", TEXTURE_page_sign); + TEXTURE_texture[TEXTURE_page_shadowsquare].LoadTextureTGA(TEXTURE_EXTRA_DIR"shadowsquare.tga", TEXTURE_page_shadowsquare); + TEXTURE_texture[TEXTURE_page_ladshad ].LoadTextureTGA(TEXTURE_EXTRA_DIR"ladshad.tga", TEXTURE_page_ladshad); + TEXTURE_texture[TEXTURE_page_meteor ].LoadTextureTGA(TEXTURE_EXTRA_DIR"meteorALL.tga", TEXTURE_page_meteor); + +LOADED_THIS_MANY_TEXTURES(5); + + // + // Male civs + // + TEXTURE_page_people3 = 21*64; + TEXTURE_texture[TEXTURE_page_people3+0 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"crotch1.tga", TEXTURE_page_people3+0); + TEXTURE_texture[TEXTURE_page_people3+1 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"crotch2.tga", TEXTURE_page_people3+1); + TEXTURE_texture[TEXTURE_page_people3+2 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"crotch3.tga", TEXTURE_page_people3+2); + TEXTURE_texture[TEXTURE_page_people3+3 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"front1.tga", TEXTURE_page_people3+3); + TEXTURE_texture[TEXTURE_page_people3+4 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"front2.tga", TEXTURE_page_people3+4); +LOADED_THIS_MANY_TEXTURES(5); + TEXTURE_texture[TEXTURE_page_people3+5 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"front3.tga", TEXTURE_page_people3+5); + TEXTURE_texture[TEXTURE_page_people3+6 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"hatside1.tga", TEXTURE_page_people3+6); + TEXTURE_texture[TEXTURE_page_people3+7 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"hatside2.tga", TEXTURE_page_people3+7); + TEXTURE_texture[TEXTURE_page_people3+8 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"hatside3.tga", TEXTURE_page_people3+8); + TEXTURE_texture[TEXTURE_page_people3+9 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"hattop1.tga", TEXTURE_page_people3+9); + TEXTURE_texture[TEXTURE_page_people3+10 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"hattop2.tga", TEXTURE_page_people3+10); +LOADED_THIS_MANY_TEXTURES(5); + TEXTURE_texture[TEXTURE_page_people3+11 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"hattop3.tga", TEXTURE_page_people3+11); + TEXTURE_texture[TEXTURE_page_people3+12 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"leg1.tga", TEXTURE_page_people3+12); + TEXTURE_texture[TEXTURE_page_people3+13 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"leg2.tga", TEXTURE_page_people3+13); + TEXTURE_texture[TEXTURE_page_people3+14 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"leg3.tga", TEXTURE_page_people3+14); +LOADED_THIS_MANY_TEXTURES(4); + + // + // Female Civs + // + TEXTURE_texture[TEXTURE_page_people3+15 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMARSE1.tga", TEXTURE_page_people3+15); + TEXTURE_texture[TEXTURE_page_people3+16 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMARSE2.tga", TEXTURE_page_people3+16); + TEXTURE_texture[TEXTURE_page_people3+17 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMARSE3.tga", TEXTURE_page_people3+17); + + TEXTURE_texture[TEXTURE_page_people3+18 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMCHEST1.tga", TEXTURE_page_people3+18); + TEXTURE_texture[TEXTURE_page_people3+19 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMCHEST2.tga", TEXTURE_page_people3+19); + TEXTURE_texture[TEXTURE_page_people3+20 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMCHEST3.tga", TEXTURE_page_people3+20); +LOADED_THIS_MANY_TEXTURES(6); + TEXTURE_texture[TEXTURE_page_people3+21 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"SEAM1.tga", TEXTURE_page_people3+21); + TEXTURE_texture[TEXTURE_page_people3+22 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"SEAM2.tga", TEXTURE_page_people3+22); + TEXTURE_texture[TEXTURE_page_people3+23 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"SEAM3.tga", TEXTURE_page_people3+23); + + TEXTURE_texture[TEXTURE_page_people3+24 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMSHOO1.tga", TEXTURE_page_people3+24); + TEXTURE_texture[TEXTURE_page_people3+25 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMSHOO2.tga", TEXTURE_page_people3+25); + TEXTURE_texture[TEXTURE_page_people3+26 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMSHOO3.tga", TEXTURE_page_people3+26); +LOADED_THIS_MANY_TEXTURES(6); + + TEXTURE_texture[TEXTURE_page_people3+27 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMBAK1.tga", TEXTURE_page_people3+27); + TEXTURE_texture[TEXTURE_page_people3+28 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMBAK2.tga", TEXTURE_page_people3+28); + TEXTURE_texture[TEXTURE_page_people3+29 ].LoadTextureTGA(TEXTURE_PEOPLE3_DIR"FEMBAK3.tga", TEXTURE_page_people3+29); +LOADED_THIS_MANY_TEXTURES(3); + } + + + +#ifdef TARGET_DC + // Set this up, but don't do anything with it. The actual texture is overridden later. + the_display.AddLoadedTexture(&TEXTURE_texture[TEXTURE_page_background_use_instead]); + TEXTURE_needed [TEXTURE_page_background_use_instead] = 1; + the_display.AddLoadedTexture(&TEXTURE_texture[TEXTURE_page_background_use_instead2]); + TEXTURE_needed [TEXTURE_page_background_use_instead2] = 1; +#endif + + + + + +#ifndef TARGET_DC +#if 1 + // Load and bin a load of textures used by the DC, but not the PC. + // This makes sure they get converted to MVQ format. + D3DTexture *pTex; + +#define DO_DC_CONVERT(name) pTex = MFnew(); pTex->LoadTextureTGA ( (name), -1, TRUE ); MFdelete ( pTex ) + + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button A.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button B.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button C.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button X.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button Y.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button Z.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button LEFT.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button RIGHT.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button PADLEFT.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button PADRIGHT.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button PADDOWN.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\button PADUP.tga" ); + DO_DC_CONVERT(TEXTURE_EXTRA_DIR"DC\\page_joybutts.tga" ); + + + DO_DC_CONVERT("server\\textures\\shared\\people\\page_darci1.tga"); + DO_DC_CONVERT("server\\textures\\extras\\page_misc_alpha.tga"); + +#undef DO_DC_CONVERT + +#endif +#endif + + + +#if 0 + if (loading_screen_active) + { + ATTRACT_loadscreen_draw(70 * 256 / 100); + } +#endif + + // + // The video page. + // + +//not used anymore? TEXTURE_texture[86].CreateUserPage(TEXTURE_VIDEO_SIZE, FALSE); + + // + // The flames on the main menu + // + +//not used anymore? TEXTURE_texture[TEXTURE_page_menuflame].CreateUserPage(256,FALSE); + + + // + // The leaves! + // + // Fins' glows above the traffic cones... + // The water droplets and the sparkles, the sewer water and the raindrops. + // The man on the moon! + // And the muckyfootprints + // Texture 560 is one component of the digital timer. + // + + TRACE("Loaded extras\n"); + + // + // The warehouse textures. + // +#ifdef TARGET_DC + // Only loaded during an actual level. + if ( !bFrontEnd ) +#endif + { + + for (i = 0; i < WARE_rooftex_upto; i++) + { + TEXTURE_get_minitexturebits_uvs( + WARE_rooftex[i], + &page, + u + 0, + v + 0, + u + 1, + v + 1, + u + 2, + v + 2, + u + 3, + v + 3); + + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We must load this texture. + // + + TEXTURE_load_page(page); +LOADED_THIS_MANY_TEXTURES(1); + } + } + + /* + + // + // do all the inside styles for now + // + + for(c0=0;c0<64;c0++) + { + for(c1=0;c1<16;c1++) + { + page=inside_tex[c0][c1]+START_PAGE_FOR_FLOOR*64; + + if(page<8*64) + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + TEXTURE_load_page(page); + + } + } + } + + */ + + TRACE("Loaded inside styles\n"); + + + // + // Load the individual pages that we need. + // + + for (x = 0; x < MAP_WIDTH - 1; x++) + for (z = 0; z < MAP_HEIGHT - 1; z++) + { + TEXTURE_get_minitexturebits_uvs( + PAP_2HI(x,z).Texture, + &page, + u + 0, + v + 0, + u + 1, + v + 1, + u + 2, + v + 2, + u + 3, + v + 3); + + ASSERT(WITHIN(page, 0, TEXTURE_page_num_standard - 1)); + + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We must load this texture. + // + + TEXTURE_load_page(page); +LOADED_THIS_MANY_TEXTURES(1); + } + } + // TEXTURE_load_page(156); + // TEXTURE_load_page(157); + + TRACE("Loaded floor textures\n"); + +#if 0 + if (loading_screen_active) + { + ATTRACT_loadscreen_draw(75 * 256 / 100); + } +#endif + + for (i = 1; i < MAX_ANIM_TMAPS; i++) + { + struct AnimTmap *p_a; + + p_a=&anim_tmaps[i]; + + for(k=0;kUV[k][0][0] & 0xc0; + page <<= 2; + page |= p_a->Page[k]; + } + } + + TRACE("Loaded anim tmaps\n"); + + // + // force jacket alternatives to be loaded thugs + // + + + TEXTURE_load_page(18*64+2); + TEXTURE_load_page(18*64+32); + + TEXTURE_load_page(18*64+3); + TEXTURE_load_page(18*64+33); +LOADED_THIS_MANY_TEXTURES(4); + + TEXTURE_load_page(18*64+4); + TEXTURE_load_page(18*64+36); + + TEXTURE_load_page(18*64+5); + TEXTURE_load_page(18*64+37); +LOADED_THIS_MANY_TEXTURES(4); + + for (i = 1; i < next_prim_face3; i++) + { + f3 = &prim_faces3[i]; + + page = f3->UV[0][0] & 0xc0; + page <<= 2; + page |= f3->TexturePage; + page+=FACE_PAGE_OFFSET; + + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We must load this texture. + // + + TEXTURE_load_page(page); +LOADED_THIS_MANY_TEXTURES(1); + } + } + +#if 0 + if (loading_screen_active) + { + ATTRACT_loadscreen_draw(80 * 256 / 100); + } +#endif + + TRACE("Loaded prim 3s\n"); + + for (i = 1; i < next_prim_face4; i++) + { + f4 = &prim_faces4[i]; + + page = f4->UV[0][0] & 0xc0; + page <<= 2; + page |= f4->TexturePage; + page+=FACE_PAGE_OFFSET; + + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We must load this texture. + // + + TEXTURE_load_page(page); +LOADED_THIS_MANY_TEXTURES(1); + } + } + + TRACE("Loaded prim 4s\n"); + +#if 0 + if (loading_screen_active) + { + ATTRACT_loadscreen_draw(85 * 256 / 100); + } +#endif + + TEXTURE_load_page(156); + + for(i=1;i>2)*((dfacets[i].FacetFlags&FACET_FLAG_2SIDED)?2:1);c0++) + { + SLONG dstyle; + dstyle=dstyles[style+c0]; + + if(dstyle>0) + { + for(c1=0;c1Count;pos++) + { + page=paint_mem[p_storey->Index+pos]; + if(page) + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We must load this texture. + // + + TEXTURE_load_page(page); +LOADED_THIS_MANY_TEXTURES(1); + } + + } + dstyle=p_storey->Style; + if(dstyle>0) + { + for(c1=0;c10) + for(c1=0;c1> 6) << 3; + + PANEL_draw_quad( + x, y, + x + 2, y + 6, + i); + } + } + + POLY_frame_draw(TRUE, TRUE); + + END_SCENE; + + ATTRACT_loadscreen_draw(90 * 256 / 100); + } + + #endif + +#ifndef TARGET_DC + // this is a good point to estimate the + // graphics card's capabilities +extern void AENG_guess_detail_levels(); + + AENG_guess_detail_levels(); +#endif + + + // Guess what this does. + NotGoingToLoadTexturesForAWhileNowSoYouCanCleanUpABit(); + + +#if USE_TOMS_ENGINE_PLEASE_BOB + // Start a new frame, so that the new textures get set up and sorted. + // Yes, it is crufty why starting a new frame does this. But it's historical. + // Just trust me, OK? + POLY_frame_init(FALSE,FALSE); +#endif + +} + +void TEXTURE_load_needed_object(SLONG prim) +{ + SLONG i; + SLONG page; + + PrimObject *po; + PrimFace3 *f3; + PrimFace4 *f4; + + po = &prim_objects[prim]; + + for (i = po->StartFace3; i < po->EndFace3; i++) + { + f3 = &prim_faces3[i]; + + page = f3->UV[0][0] & 0xc0; + page <<= 2; + page |= f3->TexturePage; + + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We must load this texture. + // + + TEXTURE_load_page(page); + } + } + + for (i = po->StartFace4; i < po->EndFace4; i++) + { + f4 = &prim_faces4[i]; + + page = f4->UV[0][0] & 0xc0; + page <<= 2; + page |= f4->TexturePage; + + if (TEXTURE_texture[page].Type == D3DTEXTURE_TYPE_UNUSED) + { + // + // We must load this texture. + // + + TEXTURE_load_page(page); + } + } +} + + + +void TEXTURE_free() +{ + SLONG i; + + // + // Initialise all the crinkles. + // + + CRINKLE_init(); + + for (i = 0; i < TEXTURE_num_textures; i++) + { + TEXTURE_texture[i].Destroy(); + TEXTURE_texture[i].Type = D3DTEXTURE_TYPE_UNUSED; + } + + the_display.RemoveAllLoadedTextures(); + + memset(TEXTURE_dontexist, 0, sizeof(TEXTURE_dontexist)); + memset ( TEXTURE_needed, 0, sizeof ( TEXTURE_needed ) ); + + POLY_reset_render_states(); + + TEXTURE_DC_pack_init(); + +#ifdef TRUETYPE + TT_Term(); +#endif +} + + +// Destroys all the non-needed (i.e. non-frontend) textures. +void TEXTURE_free_unneeded ( void ) +{ + SLONG i; + + // + // Initialise all the crinkles. + // + + CRINKLE_init(); + +#ifdef DEBUG + DDSCAPS2 ddsc; + ddsc.dwCaps = DDSCAPS_TEXTURE; + ddsc.dwCaps2 = 0; + ddsc.dwCaps3 = 0; + ddsc.dwCaps4 = 0; + DWORD dwFree, dwTotal; + HRESULT hres = the_display.lp_DD4->GetAvailableVidMem ( &ddsc, &dwTotal, &dwFree ); + TRACE ( "Memory before TEXTURE_free_unneeded: %ikb\n", dwFree / 1024 ); +#endif + + for (i = 0; i < TEXTURE_num_textures; i++) + { + //if ( !TEXTURE_needed[i] ) + { + TEXTURE_texture[i].Destroy(); + TEXTURE_texture[i].Type = D3DTEXTURE_TYPE_UNUSED; + TEXTURE_dontexist[i] = 0; + } + } + + // Now free all the texture pages. +extern void FreeAllD3DPages ( void ); + FreeAllD3DPages(); + +#ifdef DEBUG + ddsc.dwCaps = DDSCAPS_TEXTURE; + ddsc.dwCaps2 = 0; + ddsc.dwCaps3 = 0; + ddsc.dwCaps4 = 0; + dwFree, dwTotal; + hres = the_display.lp_DD4->GetAvailableVidMem ( &ddsc, &dwTotal, &dwFree ); + ASSERT ( SUCCEEDED ( hres ) ); + TRACE ( "After freeing: %ikb\n", dwFree / 1024 ); +#endif + + POLY_reset_render_states(); +} + + +#if 0 // not DX6 + +D3DTEXTUREHANDLE TEXTURE_get_handle(SLONG page) +{ + D3DTEXTUREHANDLE ans; + + ASSERT(WITHIN(page, 0, TEXTURE_num_textures - 1)); + + ans = TEXTURE_texture[page].GetTextureHandle(); + + return ans; +} + +#endif + + + +LPDIRECT3DTEXTURE2 TEXTURE_get_handle(SLONG page) +{ +#ifdef TARGET_DC + if ( page == TEXTURE_page_background_use_instead ) + { + // Special-cased for the background replacement. + return ( the_display.lp_DD_Background_use_instead_texture ); + } + else if ( page == TEXTURE_page_background_use_instead2 ) + { + // Special-cased for the background replacement. + return ( the_display.lp_DD_Background_use_instead_texture2 ); + } +#endif + if ( page == -1 ) + { + return ( NULL ); + } +#ifdef TARGET_DC + ASSERT(WITHIN(page, 0, TEXTURE_num_textures - 1)); +#endif + return TEXTURE_texture[page].GetD3DTexture(); +} + + + + + +#ifdef TEX_EMBED +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + +D3DTexture *TEXTURE_get_D3DTexture(SLONG page) +{ + return &(TEXTURE_texture[page]); +} + +#else //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + +UBYTE TEXTURE_get_offset(SLONG page) +{ +#ifdef TARGET_DC + if ( ( page == TEXTURE_page_background_use_instead ) || ( page == TEXTURE_page_background_use_instead2 ) ) + { + // Special-cased for the background replacement. + return ( 0 ); + } +#endif + if ( page == -1 ) + { + return ( 0 ); + } + ASSERT(WITHIN(page, 0, TEXTURE_num_textures - 1)); + return TEXTURE_texture[page].GetTexOffset(); +} +#endif //#else //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + +#endif + +void TEXTURE_get_minitexturebits_uvs( + UWORD texture, + SLONG *page, + float *u0, + float *v0, + float *u1, + float *v1, + float *u2, + float *v2, + float *u3, + float *v3) +{ + SLONG tx; + SLONG ty; + SLONG tpage; + SLONG trot; + SLONG tflip; + SLONG tsize; + + SLONG num; + + #if TEXTURE_ENABLE_DC_PACKING + + float base_u; + float base_v; + + float base_size; + + #else + + static const float base_u = 0.0F; + static const float base_v = 0.0F; + + static const float base_size = 1.0F; + + #endif + + num = texture & 0x3ff; + + trot = (texture >> 0xa) & 0x3; + tflip = (texture >> 0xc) & 0x3; + tsize = (texture >> 0xe) & 0x3; + + // + // The page is easy! + // + + *page = num; + + #if TEXTURE_ENABLE_DC_PACKING + + if (num < 256) + { + // + // Remap this texture? + // + + *page = TEXTURE_DC_pack[num].page; + + if (TEXTURE_DC_pack[num].pos == TEXTURE_DC_PACK_POS_WHOLE_PAGE) + { + base_u = 0.0F; + base_v = 0.0F; + base_size = 1.0F; + } + else + { + static struct + { + float base_u; + float base_v; + + } pos_base[9] = + { + {0.125F + 0.25F * 0, 0.125F + 0.25F * 0}, + {0.125F + 0.25F * 1, 0.125F + 0.25F * 0}, + {0.125F + 0.25F * 2, 0.125F + 0.25F * 0}, + + {0.125F + 0.25F * 0, 0.125F + 0.25F * 1}, + {0.125F + 0.25F * 1, 0.125F + 0.25F * 1}, + {0.125F + 0.25F * 2, 0.125F + 0.25F * 1}, + + {0.125F + 0.25F * 0, 0.125F + 0.25F * 2}, + {0.125F + 0.25F * 1, 0.125F + 0.25F * 2}, + {0.125F + 0.25F * 2, 0.125F + 0.25F * 2}, + }; + + ASSERT(WITHIN(TEXTURE_DC_pack[num].pos, 0, 8)); + + base_u = pos_base[TEXTURE_DC_pack[num].pos].base_u; + base_v = pos_base[TEXTURE_DC_pack[num].pos].base_v; + base_size = 64.0F / 256.0F; + } + } + + #endif + + if (*page >= TEXTURE_page_num_standard) + { + *page = 0; + } + + // + // The texture coordinates depend of the rotation. + // + + switch(trot) + { + case 0: + *u0 = base_u; + *v0 = base_v; + *u1 = base_u + base_size; + *v1 = base_v; + *u2 = base_u; + *v2 = base_v + base_size; + *u3 = base_u + base_size; + *v3 = base_v + base_size; + break; + + case 1: + *u2 = base_u; + *v2 = base_v; + *u0 = base_u + base_size; + *v0 = base_v; + *u3 = base_u; + *v3 = base_v + base_size; + *u1 = base_u + base_size; + *v1 = base_v + base_size; + break; + + case 2: + *u3 = base_u; + *v3 = base_v; + *u2 = base_u + base_size; + *v2 = base_v; + *u1 = base_u; + *v1 = base_v + base_size; + *u0 = base_u + base_size; + *v0 = base_v + base_size; + break; + + case 3: + *u1 = base_u; + *v1 = base_v; + *u3 = base_u + base_size; + *v3 = base_v; + *u0 = base_u; + *v0 = base_v + base_size; + *u2 = base_u + base_size; + *v2 = base_v + base_size; + break; + } +} + + +extern UWORD local_next_prim_face3; +extern UWORD local_next_prim_face4; + +void TEXTURE_fix_texture_styles(void) +{ + SLONG style,piece; + + SLONG page; + + SLONG av_u; + SLONG av_v; + + SLONG base_u; + SLONG base_v; + + for(style=0;style<200;style++) + { + for(piece=0;piece<5;piece++) + { + base_u = textures_xy[style][piece].Tx*32; + base_v = textures_xy[style][piece].Ty*32; + + av_u = base_u/TEXTURE_NORM_SIZE; + av_v = base_v/TEXTURE_NORM_SIZE; + + page = av_u + av_v * TEXTURE_NORM_SQUARES + textures_xy[style][piece].Page * TEXTURE_NORM_SQUARES * TEXTURE_NORM_SQUARES; + dx_textures_xy[style][piece].Page=page; + dx_textures_xy[style][piece].Flip=textures_xy[style][piece].Flip; + + + } + } +} + +void TEXTURE_fix_prim_textures() +{ + SLONG i; + SLONG j; + SLONG k; + + PrimFace3 *f3; + PrimFace4 *f4; + struct AnimTmap *p_a; + + SLONG page; + + SLONG av_u; + SLONG av_v; + SLONG u; + SLONG v; + + SLONG base_u; + SLONG base_v; + + for (i = 1; i < next_prim_face3; i++) + { + f3 = &prim_faces3[i]; + + if (!(f3->FaceFlags & FACE_FLAG_FIXED)) + { + av_u = (f3->UV[0][0] + f3->UV[1][0] + f3->UV[2][0]) / 3; + av_v = (f3->UV[0][1] + f3->UV[1][1] + f3->UV[2][1]) / 3; + + av_u /= TEXTURE_NORM_SIZE; + av_v /= TEXTURE_NORM_SIZE; + + base_u = av_u * TEXTURE_NORM_SIZE; + base_v = av_v * TEXTURE_NORM_SIZE; + + // + // All coordinates relative to the base now... + // + + for (j = 0; j < 3; j++) + { + u = f3->UV[j][0]; + v = f3->UV[j][1]; + + u -= base_u; + v -= base_v; + + SATURATE(u, 0, 32); + SATURATE(v, 0, 32); + + if (u == 31) {u = 32;} + if (v == 31) {v = 32;} + + f3->UV[j][0] = u; + f3->UV[j][1] = v; + } + + page = av_u + av_v * TEXTURE_NORM_SQUARES + f3->TexturePage * TEXTURE_NORM_SQUARES * TEXTURE_NORM_SQUARES; + f3->FaceFlags&=~FACE_FLAG_THUG_JACKET; + + switch(page) + { + // + // pages 9, 10 , 11 are people + // + case 9*64+21: + case 18*64+2: + case 18*64+32: +// ASSERT(0); + f3->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+21; + + break; + + case 9*64+22: + case 18*64+3: + case 18*64+33: + f3->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+22; + break; + + case 9*64+24: + case 18*64+4: + case 18*64+36: + f3->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+24; + break; + + + case 9*64+25: + case 18*64+5: + case 18*64+37: + f3->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+25; + break; + + } + page-=FACE_PAGE_OFFSET; + +// DebugText(" saturate prim page tri page %d \n",page); + SATURATE(page, 0, 64*14); +// ASSERT(page<64*8); + + // + // The 9th and 10th bits of page go in the top two bits of UV[0][0]! + // + + f3->UV[0][0] |= (page >> 2) & 0xc0; + f3->TexturePage = (page >> 0) & 0xff; + + // + // Mark as fixed. + // + + f3->FaceFlags |= FACE_FLAG_FIXED; + } + } + + for (i = 1; i < next_prim_face4; i++) + { + f4 = &prim_faces4[i]; + + if(!(f4->FaceFlags&FACE_FLAG_ANIMATE)) + { + if(!(f4->FaceFlags&FACE_FLAG_FIXED)) + { + av_u = (f4->UV[0][0] + f4->UV[1][0] + f4->UV[2][0] + f4->UV[3][0]) >> 2; + av_v = (f4->UV[0][1] + f4->UV[1][1] + f4->UV[2][1] + f4->UV[3][1]) >> 2; + + av_u /= TEXTURE_NORM_SIZE; + av_v /= TEXTURE_NORM_SIZE; + + base_u = av_u * TEXTURE_NORM_SIZE; + base_v = av_v * TEXTURE_NORM_SIZE; + + // + // All coordinates relative to the base now... + // + + for (j = 0; j < 4; j++) + { + u = f4->UV[j][0]; + v = f4->UV[j][1]; + + u -= base_u; + v -= base_v; + + SATURATE(u, 0, 32); + SATURATE(v, 0, 32); + + if (u == 31) {u = 32;} + if (v == 31) {v = 32;} + + f4->UV[j][0] = u; + f4->UV[j][1] = v; + } + + page = av_u + av_v * TEXTURE_NORM_SQUARES + f4->TexturePage * TEXTURE_NORM_SQUARES * TEXTURE_NORM_SQUARES; + f4->FaceFlags&=~FACE_FLAG_THUG_JACKET; + switch(page) + { + // + // pages 9, 10 , 11 are people + // + case 9*64+21: + case 18*64+2: + case 18*64+32: + f4->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+21; + + break; + + case 9*64+22: + case 18*64+3: + case 18*64+33: + f4->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+22; + break; + + case 9*64+24: + case 18*64+4: + case 18*64+36: + f4->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+24; + break; + + + case 9*64+25: + case 18*64+5: + case 18*64+37: + f4->FaceFlags|=FACE_FLAG_THUG_JACKET; + page=9*64+25; + break; + + } + page-=FACE_PAGE_OFFSET; + + SATURATE(page, 0,14*64 ); + + // + // The 9th and 10th bits of page go in the top two bits of UV[0][0]! + // + + f4->UV[0][0] |= (page >> 2) & 0xc0; + f4->TexturePage = (page >> 0) & 0xff; + + // + // Mark as fixed. + // + + f4->FaceFlags |= FACE_FLAG_FIXED; + } + else + { +// ASSERT(0); + } + } + } + + for (i = 1; i < MAX_ANIM_TMAPS; i++) + { + p_a=&anim_tmaps[i]; + + for(k=0;kUV[k][0][0] + p_a->UV[k][1][0] + p_a->UV[k][2][0] + p_a->UV[k][3][0]) >> 2; + av_v = (p_a->UV[k][0][1] + p_a->UV[k][1][1] + p_a->UV[k][2][1] + p_a->UV[k][3][1]) >> 2; + + av_u /= TEXTURE_NORM_SIZE; + av_v /= TEXTURE_NORM_SIZE; + + base_u = av_u * TEXTURE_NORM_SIZE; + base_v = av_v * TEXTURE_NORM_SIZE; + + // + // All coordinates relative to the base now... + // + + for (j = 0; j < 4; j++) + { + p_a->UV[k][j][0] -= base_u; + p_a->UV[k][j][1] -= base_v; + + SATURATE(p_a->UV[k][j][0], 0, 32); + SATURATE(p_a->UV[k][j][1], 0, 32); + + if (p_a->UV[k][j][0] == 31) {p_a->UV[k][j][0] = 32;} + if (p_a->UV[k][j][1] == 31) {p_a->UV[k][j][1] = 32;} + } + + page = av_u + av_v * TEXTURE_NORM_SQUARES + p_a->Page[k] * TEXTURE_NORM_SQUARES * TEXTURE_NORM_SQUARES; + + SATURATE(page, 0, 575); + + // + // The 9th and 10th bits of page go in the top two bits of UV[0][0]! + // + + p_a->UV[k][0][0] |= (page >> 2) & 0xc0; + p_a->Page[k] = (page >> 0) & 0xff; + } + } +} + + + +#ifndef TARGET_DC +void TEXTURE_set_colour_key(SLONG page) +{ + DDCOLORKEY ck; + + return; + + + ASSERT(WITHIN(page, 0, TEXTURE_num_textures - 1)); + + if (TEXTURE_fiddled) + { + // + // Ranges don't work :o( + // + + ck.dwColorSpaceLowValue = 0x00000000; + ck.dwColorSpaceHighValue = 0x00000000; + } + else + { + ck.dwColorSpaceLowValue = 0; + ck.dwColorSpaceHighValue = 0; + } + + TEXTURE_texture[page].SetColorKey(DDCKEY_SRCBLT,&ck); +} +#endif + + + +SLONG TEXTURE_shadow_lock(void) +{ + HRESULT res; + + res = TEXTURE_texture[TEXTURE_page_shadow].LockUser( + &TEXTURE_shadow_bitmap, + &TEXTURE_shadow_pitch); + + if (FAILED(res)) + { + TEXTURE_shadow_bitmap = NULL; + TEXTURE_shadow_pitch = 0; + + return FALSE; + } + else + { + TEXTURE_shadow_mask_red = TEXTURE_texture[TEXTURE_page_shadow].mask_red; + TEXTURE_shadow_mask_green = TEXTURE_texture[TEXTURE_page_shadow].mask_green; + TEXTURE_shadow_mask_blue = TEXTURE_texture[TEXTURE_page_shadow].mask_blue; + TEXTURE_shadow_mask_alpha = TEXTURE_texture[TEXTURE_page_shadow].mask_alpha; + TEXTURE_shadow_shift_red = TEXTURE_texture[TEXTURE_page_shadow].shift_red; + TEXTURE_shadow_shift_green = TEXTURE_texture[TEXTURE_page_shadow].shift_green; + TEXTURE_shadow_shift_blue = TEXTURE_texture[TEXTURE_page_shadow].shift_blue; + TEXTURE_shadow_shift_alpha = TEXTURE_texture[TEXTURE_page_shadow].shift_alpha; + + return TRUE; + } +} + +void TEXTURE_shadow_unlock() +{ + TEXTURE_texture[TEXTURE_page_shadow].UnlockUser(); +} + +void TEXTURE_shadow_update(void) +{ +} + + + +void TEXTURE_set_greyscale(SLONG is_greyscale) +{ + SLONG i; + + for (i = 0; i < TEXTURE_MAX_TEXTURES; i++) + { + TEXTURE_texture[i].set_greyscale(is_greyscale); + } +} + + + + +SLONG TEXTURE_86_lock() +{ + HRESULT res; + + res = TEXTURE_texture[86].LockUser( + &TEXTURE_shadow_bitmap, + &TEXTURE_shadow_pitch); + + if (FAILED(res)) + { + TEXTURE_shadow_bitmap = NULL; + TEXTURE_shadow_pitch = 0; + + return FALSE; + } + else + { + TEXTURE_shadow_mask_red = TEXTURE_texture[86].mask_red; + TEXTURE_shadow_mask_green = TEXTURE_texture[86].mask_green; + TEXTURE_shadow_mask_blue = TEXTURE_texture[86].mask_blue; + TEXTURE_shadow_mask_alpha = TEXTURE_texture[86].mask_alpha; + TEXTURE_shadow_shift_red = TEXTURE_texture[86].shift_red; + TEXTURE_shadow_shift_green = TEXTURE_texture[86].shift_green; + TEXTURE_shadow_shift_blue = TEXTURE_texture[86].shift_blue; + TEXTURE_shadow_shift_alpha = TEXTURE_texture[86].shift_alpha; + + return TRUE; + } +} + +void TEXTURE_86_unlock() +{ + TEXTURE_texture[86].UnlockUser(); +} + +void TEXTURE_86_update() +{ +} + + +void TEXTURE_set_tga(SLONG page, CBYTE *fn) { + CBYTE fn2[_MAX_PATH]; + MFFileHandle file; + + strcpy(fn2,TEXTURE_EXTRA_DIR); + strcat(fn2,fn); + file = FileOpen(fn2); + if (file!=FILE_OPEN_ERROR) { + TEXTURE_texture[page].ChangeTextureTGA(fn2); + FileClose(file); + } +} + +SLONG TEXTURE_liney; +SLONG TEXTURE_av_r; +SLONG TEXTURE_av_g; +SLONG TEXTURE_av_b; + +#ifndef TARGET_DC +SLONG TEXTURE_looks_like(SLONG page) +{ + SLONG i; + SLONG j; + + SLONG px; + SLONG py; + + SLONG dx; + SLONG dy; + + SLONG px1; + SLONG py1; + + SLONG px2; + SLONG py2; + + UWORD *bitmap; + SLONG pitch; + + UWORD pixel; + + SLONG r; + SLONG g; + SLONG b; + + SLONG r1; + SLONG g1; + SLONG b1; + + SLONG r2; + SLONG g2; + SLONG b2; + + SLONG av_r; + SLONG av_g; + SLONG av_b; + + SLONG diff_r; + SLONG diff_g; + SLONG diff_b; + + SLONG dir; + + SLONG diff; + + SLONG pdiff_r; + SLONG pdiff_g; + SLONG pdiff_b; + + SLONG diff_along; + SLONG diff_left; + SLONG diff_right; + + SLONG ddiff_l; + SLONG ddiff_r; + + SLONG lines; + + ASSERT(WITHIN(page, 0, 511)); + + D3DTexture *dt = &TEXTURE_texture[page]; + + TEXTURE_liney = 0; + TEXTURE_av_r = 0; + TEXTURE_av_g = 0; + TEXTURE_av_b = 0; + + // + // Try to lock the page. + // + + if (SUCCEEDED(dt->LockUser(&bitmap, &pitch))) + { + // + // Work out the average colour of the texture. + // + + av_r = 0; + av_g = 0; + av_b = 0; + + for (px = 0; px < TEXTURE_texture[page].size; px++) + for (py = 0; py < TEXTURE_texture[page].size; py++) + { + pixel = bitmap[px + py * pitch]; + + r = ((pixel >> dt->shift_red ) & (0xff >> dt->mask_red )) << dt->mask_red ; + g = ((pixel >> dt->shift_green) & (0xff >> dt->mask_green)) << dt->mask_green; + b = ((pixel >> dt->shift_blue ) & (0xff >> dt->mask_blue )) << dt->mask_blue ; + + av_r += r; + av_g += g; + av_b += b; + } + + av_r /= dt->size * dt->size; + av_g /= dt->size * dt->size; + av_b /= dt->size * dt->size; + + TEXTURE_av_r = av_r; + TEXTURE_av_g = av_g; + TEXTURE_av_b = av_b; + + // + // Is the texture green? + // + + if (av_g > av_r && av_g > av_b) + { + SLONG rb; + + rb = av_r + av_b; + rb >>= 1; + rb += rb >> 1; + + if (av_g > rb) + { + // + // This is a green texture- assume it is grass. + // + + dt->UnlockUser(); + + return TEXTURE_LOOK_GRASS; + } + } + + // + // Get a number of the random variation inherent in the texture. + // + + diff_r = 0; + diff_g = 0; + diff_b = 0; + + #define TEXTURE_SAMPLE_DIFF1 128 + #define TEXTURE_SAMPLE_DIFF2 4 + + for (i = 0; i < TEXTURE_SAMPLE_DIFF1; i++) + { + px1 = rand() & (dt->size - 1); + py1 = rand() & (dt->size - 1); + + pixel = bitmap[px1 + py1 * pitch]; + + r1 = ((pixel >> dt->shift_red ) & (0xff >> dt->mask_red )) << dt->mask_red ; + g1 = ((pixel >> dt->shift_green) & (0xff >> dt->mask_green)) << dt->mask_green; + b1 = ((pixel >> dt->shift_blue ) & (0xff >> dt->mask_blue )) << dt->mask_blue ; + + for (j = 0; j < TEXTURE_SAMPLE_DIFF2; j++) + { + px2 = px1 + (rand() & 0x7) - 0x3; + py2 = py1 + (rand() & 0x7) - 0x3; + + px2 &= dt->size - 1; + py2 &= dt->size - 1; + + pixel = bitmap[px2 + py2 * pitch]; + + r2 = ((pixel >> dt->shift_red ) & (0xff >> dt->mask_red )) << dt->mask_red ; + g2 = ((pixel >> dt->shift_green) & (0xff >> dt->mask_green)) << dt->mask_green; + b2 = ((pixel >> dt->shift_blue ) & (0xff >> dt->mask_blue )) << dt->mask_blue ; + + // + // The difference in colour between the two pixels. + // + + diff_r += abs(r2 - r1); + diff_g += abs(g2 - g1); + diff_b += abs(b2 - b1); + } + } + + diff_r /= TEXTURE_SAMPLE_DIFF1 * TEXTURE_SAMPLE_DIFF2; + diff_g /= TEXTURE_SAMPLE_DIFF1 * TEXTURE_SAMPLE_DIFF2; + diff_b /= TEXTURE_SAMPLE_DIFF1 * TEXTURE_SAMPLE_DIFF2; + diff = diff_r + diff_g + diff_b; + + // + // Find out how many straight lines there are in the texture. + // + + lines = 0; + + #define TEXTURE_SAMPLE_STRAIGHT1 2048 + #define TEXTURE_SAMPLE_STRAIGHT2 16 + + static struct + { + SBYTE dx; + SBYTE dy; + + } offset[4] = + { + {-1,0}, + {+1,0}, + {0,-1}, + {0,+1} + }; + + dir = 0; + + for (px = 0; px < dt->size; px++) + for (py = 0; py < dt->size; py++) + { + px1 = px & (dt->size - 1); + py1 = py & (dt->size - 1); + + pixel = bitmap[px1 + py1 * pitch]; + + r1 = ((pixel >> dt->shift_red ) & (0xff >> dt->mask_red )) << dt->mask_red ; + g1 = ((pixel >> dt->shift_green) & (0xff >> dt->mask_green)) << dt->mask_green; + b1 = ((pixel >> dt->shift_blue ) & (0xff >> dt->mask_blue )) << dt->mask_blue ; + + // + // Work out the average difference in colour to the left/right/along the line. + // + + diff_left = 0; + diff_right = 0; + diff_along = 0; + + // + // What direction do we scan for a straight line? + // + + dx = offset[dir & 0x3].dx; + dy = offset[dir & 0x3].dy; + + dir += 1; + + for (j = 0; j < TEXTURE_SAMPLE_STRAIGHT2; j++) + { + // + // The difference in colour to the left... + // + + px2 = px1 - (dy * 4); + py2 = py1 + (dx * 4); + + px2 &= dt->size - 1; + py2 &= dt->size - 1; + + pixel = bitmap[px2 + py2 * pitch]; + + r2 = ((pixel >> dt->shift_red ) & (0xff >> dt->mask_red )) << dt->mask_red ; + g2 = ((pixel >> dt->shift_green) & (0xff >> dt->mask_green)) << dt->mask_green; + b2 = ((pixel >> dt->shift_blue ) & (0xff >> dt->mask_blue )) << dt->mask_blue ; + + pdiff_r = abs(r2 - r1); + pdiff_g = abs(g2 - g1); + pdiff_b = abs(b2 - b1); + + diff_left += pdiff_r + pdiff_g + pdiff_b; + + // + // The difference in colour to the right... + // + + px2 = px1 + (dy * 4); + py2 = py1 - (dx * 4); + + px2 &= dt->size - 1; + py2 &= dt->size - 1; + + pixel = bitmap[px2 + py2 * pitch]; + + r2 = ((pixel >> dt->shift_red ) & (0xff >> dt->mask_red )) << dt->mask_red ; + g2 = ((pixel >> dt->shift_green) & (0xff >> dt->mask_green)) << dt->mask_green; + b2 = ((pixel >> dt->shift_blue ) & (0xff >> dt->mask_blue )) << dt->mask_blue ; + + pdiff_r = abs(r2 - r1); + pdiff_g = abs(g2 - g1); + pdiff_b = abs(b2 - b1); + + diff_right += pdiff_r + pdiff_g + pdiff_b; + + // + // The difference in colour along the line. + // + + px2 = px1 + dx; + py2 = py1 + dy; + + px2 &= dt->size - 1; + py2 &= dt->size - 1; + + pixel = bitmap[px2 + py2 * pitch]; + + r2 = ((pixel >> dt->shift_red ) & (0xff >> dt->mask_red )) << dt->mask_red ; + g2 = ((pixel >> dt->shift_green) & (0xff >> dt->mask_green)) << dt->mask_green; + b2 = ((pixel >> dt->shift_blue ) & (0xff >> dt->mask_blue )) << dt->mask_blue ; + + pdiff_r = abs(r2 - r1); + pdiff_g = abs(g2 - g1); + pdiff_b = abs(b2 - b1); + + diff_along += pdiff_r + pdiff_g + pdiff_b; + + // + // The next pixel along the line... + // + + px1 = px2; + py1 = py2; + + r1 = r2; + g1 = g2; + b1 = b2; + } + + diff_along /= TEXTURE_SAMPLE_STRAIGHT2; + diff_left /= TEXTURE_SAMPLE_STRAIGHT2; + diff_right /= TEXTURE_SAMPLE_STRAIGHT2; + + // + // A line to the left. + // + + if (diff_left > 0x60 && diff_along < 0x10) + { + lines += 1; + } + + // + // A line to the right. + // + + if (diff_right > 0x60 && diff_along < 0x10) + { + lines += 1; + } + } + + TEXTURE_liney = lines; + + dt->UnlockUser(); + + // + // Is the texture brown? + // + + if (av_r > av_g && av_g > av_b) + { + // + // Colours are in the right order... Make sure they aren't too similar. + // + + if (av_r > (av_b + (av_b >> 1))) + { + // + // This is a brown texture. How liney is it? + // + + if (lines > 30) + { + // + // It has some lines... + // + + return TEXTURE_LOOK_ROAD; + } + else + { + return TEXTURE_LOOK_DIRT; + } + } + } + + // + // Is the texture white? + // + + if (av_r > 215 && av_g > 215 && av_b > 215) + { + // + // White. + // + + if (lines > 30) + { + // + // Too liney. + // + + return TEXTURE_LOOK_ROAD; + } + else + { + // + // Must be ice. + // + + return TEXTURE_LOOK_SLIPPERY; + } + } + + // + // Assume it is road! + // + + return TEXTURE_LOOK_ROAD; + } + + return TEXTURE_LOOK_ROAD; +} +#endif //#ifndef TARGET_DC + +#define PEOPLE3_CROTCH 0 +#define PEOPLE3_FRONT 3 +#define PEOPLE3_HAT_SIDE 6 +#define PEOPLE3_HAT_FRONT 9 +#define PEOPLE3_LEG 12 + +#define PEOPLE3_F_ARSE 15 +#define PEOPLE3_F_SEAM 21 +#define PEOPLE3_F_BACK 27 +#define PEOPLE3_F_CHEST 18 +#define PEOPLE3_F_SHOE 24 + +UWORD alt_texture[]= +{ +/* + 0,0,0,0,0,0,0,0, //0 + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 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,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + + 0,0,0,0,0,0,0,0, //128 + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, +*/ + + 0,0,0,0,0,0,0,0, //0 + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 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,0,0,0,0,0, //72 + 0,0,0,0,0,0,0,0, //80 + 0,0,0,0,0,0,0,0, //88 + 0,0,0,0,0,0,0,0, //96 + 0,0,0,0,PEOPLE3_ALT+PEOPLE3_LEG,PEOPLE3_ALT+PEOPLE3_CROTCH,0,PEOPLE3_ALT+PEOPLE3_FRONT, //104 + PEOPLE3_ALT+PEOPLE3_HAT_SIDE,PEOPLE3_ALT+PEOPLE3_HAT_FRONT,PEOPLE3_ALT+PEOPLE3_F_ARSE,PEOPLE3_ALT+PEOPLE3_F_SEAM,PEOPLE3_ALT+PEOPLE3_F_SHOE,PEOPLE3_ALT+PEOPLE3_F_CHEST,PEOPLE3_ALT+PEOPLE3_F_BACK,0, //112 + 0,0,0,0,0,0,0,0, //120 + + 0,0,0,0,0,0,0,0, //128 + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + + + +}; + diff --git a/fallen/DDEngine/Source/tom.cpp b/fallen/DDEngine/Source/tom.cpp new file mode 100644 index 0000000..b90a426 --- /dev/null +++ b/fallen/DDEngine/Source/tom.cpp @@ -0,0 +1,1037 @@ +#ifdef THIS_IS_INCLUDED_FROM_SW + + +{ + SLONG i; + SLONG x; + + ULONG *dest, addr, *tex; + ULONG pixel; + SLONG a; + SLONG r, rd; + SLONG g, gd; + SLONG b, bd; + SLONG R; + SLONG G; + SLONG B; + SLONG pr; + SLONG pg; + SLONG pb; + SLONG u, ud, tempu; + SLONG v, vd, tempv; + SLONG U; + SLONG V; + ULONG wrap, wrap1, wrap2; + int tempx1,tempx2; + + i = line; + + + ULONG *last_dest; + _int64 mmt1, mmt2, mmt3, mmt4, umask, vmask, wrapmask, uinc, vinc, notumask, notvmask, alpha_test_value, alpha_mask; + ULONG utemp, vtemp; + + umask = 0x5555ffff5555ffff; + vmask = 0xaaaaffffaaaaffff; + notumask = ~0x5555ffff5555ffff; + notvmask = ~0xaaaaffffaaaaffff; + alpha_test_value = 0xff000000ff000000; + alpha_mask = 0x00007fff00000000; + +#define SWIZZLE 1 + + +#define ALPHA_BLEND_NOT_DOUBLE_LIGHTING 1 + + { + { + //r = ss->r; + //g = ss->g; + //b = ss->b; + //u = ss->u; + //v = ss->v; + //ud = ss->du; + //vd = ss->dv; + + tempx1 = ss->x1; + tempx2 = ss->x2; + + if ( tempx2 > tempx1 ) + { + + dest = SW_buffer + i * SW_buffer_pitch; + last_dest = dest + tempx2; + dest += tempx1; + if ( ( tempx2 & 0x1 ) != 0 ) + { + // Last pixel is odd - go one less so the loop ends properly. + // Remember that we are stepping two pixels at a time, and + // ending when we hit this one, then maybe drawing the last pixel. + + // (e.g. x2 is 7, so last pixel to draw is 6, so terminate when we get to 6 - then do one more) + // (e.g. x2 is 8, so last pixel to draw is 7, so terminate when we get to 8) + + last_dest--; + } + + a = (ss->a ); + r = (ss->r )>>1; + g = (ss->g )>>1; + b = (ss->b )>>1; +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + rd = (ss->dr)>>1; + gd = (ss->dg)>>1; + bd = (ss->db)>>1; +#endif + // Swizzle interpolators + u = ss->u; + v = ss->v; + ud = ss->du; + vd = ss->dv; + tex = (ULONG *)(ss->tga); + + // Remember this is for DWORDS - assembler doesn't automagically scale. +#if SWIZZLE + wrap = ((ss->tga_size * ss->tga_size) - 1)<<2; +#else + wrap = ss->tga_size; +#endif + + __asm { + + push esi + push edi + push eax + push ebx + push ecx + push edx + +#if SWIZZLE + movd mm0,[wrap] + movq mm1,mm0 + psllq mm0,32 + por mm0,mm1 + movq [wrapmask],mm0 +#else + mov eax,[wrap] + mov ebx,0x200 + mov ecx,9 +wrap_loop: + dec ecx + shr ebx,1 + cmp ebx,eax + jne wrap_loop + + mov eax,[v] + mov ebx,[vd] + shl eax,cl + shl ebx,cl + mov [v],eax + mov [vd],ebx + + mov eax,[wrap] + dec eax + movd mm0,eax + psllq mm0,16 + movq mm1,mm0 + psllq mm0,32 + por mm0,mm1 + movq [umask],mm0 + movd mm1,ecx + psllq mm0,mm1 + movq [vmask],mm0 +#endif + + mov eax,[r] + mov ebx,[g] + mov ecx,[b] + and eax,0x00ffff00 + and ebx,0x00ffff00 + and ecx,0x00ffff00 + movd mm0,ebx + movd mm1,ecx + shr eax,8 + psllq mm0,8 + psrlq mm1,8 + por mm0,mm1 + +#if (ALPHA_MODE==ALPHA_BLEND) + mov ecx,[a] +// and ecx,0x00ff00 +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + shl ecx,23 +#else + shl ecx,23-1 +#endif + or eax,ecx +#else + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + or eax,0x7fff0000 +#else + or eax,0x40000000 +#endif +#endif + movd mm1,eax + psllq mm1,32 + por mm0,mm1 + movq [mmt1],mm0 + + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + mov eax,[rd] + mov ebx,[gd] + mov ecx,[bd] + and eax,0x00ffff00 + and ebx,0x00ffff00 + and ecx,0x00ffff00 + movd mm0,ebx + movd mm1,ecx + shr eax,8 + psllq mm0,8 + psrlq mm1,8 + por mm0,mm1 + movd mm1,eax + psllq mm1,32 + por mm0,mm1 + movq [mmt2],mm0 +#endif + +#if SWIZZLE + mov eax,[u] + mov ebx,[v] + lea esi,[swizzle_table] + mov ecx,eax + mov edx,ebx + shr ecx,16 + shr edx,16 + and ecx,0xf + and edx,0xf + shr eax,20 + shr ebx,20 + and eax,0xf + and ebx,0xf + mov ah,[esi+eax] + mov bh,[esi+ebx] + mov al,[esi+ecx] + mov bl,[esi+edx] + shl ebx,1 + mov WORD PTR[u+2],ax + mov WORD PTR[v+2],bx + + mov eax,[ud] + mov ebx,[vd] + mov ecx,eax + mov edx,ebx + shr ecx,16 + shr edx,16 + and ecx,0xf + and edx,0xf + shr eax,20 + shr ebx,20 + and eax,0xf + and ebx,0xf + mov ah,[esi+eax] + mov bh,[esi+ebx] + mov al,[esi+ecx] + mov bl,[esi+edx] + shl ebx,1 + or eax,0xaaaa + or ebx,0x5555 + mov WORD PTR[ud+2],ax + mov WORD PTR[vd+2],bx +#endif + + + + movq mm0, [mmt1] +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + movq mm2, [mmt2] +#endif + mov edi, [dest] + mov esi, [tex] + + + // Set up the integer texel fetcher + mov eax,[u] + mov ebx,[v] + + + + ;Is the first pixel odd? + mov ecx,[tempx1] + test ecx,0x1 + jnz first_pixel_odd + + + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + // Calculate r1g1b1, and double up the increments + movq mm1,mm0 + paddsw mm1,mm2 + psllw mm2,1 +#endif + + + + +#if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + or ecx,ebx + add ebx,DWORD PTR [vd] + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + + mov edx,eax + add eax,DWORD PTR [ud] + or edx,ebx + add ebx,DWORD PTR [vd] + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff +#else + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + or ecx,edx + shr ecx,16-2 + push ecx + + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + or edx,ecx + shr edx,16-2 + pop ecx +#endif + movd mm7,[esi+ecx] + movd mm6,[esi+edx] + + + jmp setup_main_loop + + +first_pixel_odd: + + +#if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + or ecx,ebx + add ebx,DWORD PTR [vd] + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff +#else + mov ecx,eax + mov edx,ebx + add eax,DWORD PTR [ud] + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + or ecx,edx + shr ecx,16-2 +#endif + movd mm7,[esi+ecx] + + + + +#if ALPHA_MODE==ALPHA_BLEND + + + punpcklbw mm7,mm7 ;unpack + #if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + #else + mov ecx,eax + add eax,DWORD PTR [ud] + #endif + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + psrlw mm7,8-1 +#else + psrlw mm7,8-2 +#endif + #if SWIZZLE + or ecx,ebx + add ebx,DWORD PTR [vd] + #else + mov edx,ebx + add ebx,DWORD PTR [vd] + #endif + pmulhw mm7,mm0 ;colour modulate + movq mm6,mm7 + + #if SWIZZLE + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + #endif + psrlq mm6,8+1 ;half required value (creates a sign bit) + pand mm6,[alpha_mask] + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or ecx,edx + shr ecx,16-2 + #endif + movq mm5,mm6 + #if SWIZZLE + mov edx,eax + add eax,DWORD PTR [ud] + #else + push ecx + mov ecx,eax + #endif + + psrlq mm5,16 + #if SWIZZLE + or edx,ebx + add ebx,DWORD PTR [vd] + #else + add eax,DWORD PTR [ud] + mov edx,ebx + #endif + + por mm5,mm6 + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + #endif + psrlq mm5,16 + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + and edx,DWORD PTR [vmask] + or edx,ecx + #endif + por mm5,mm6 ;alpha channel replicated to r,g,b + #if SWIZZLE + #else + pop ecx + shr edx,16-2 + #endif + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + // Remember that mm2 is spare - no gouard shading on alpha-blenders. + + movd mm6,[edi] + + punpcklbw mm6,mm6 ;unpack dest + psrlw mm6,8 + + psubsw mm7,mm6 ;src-dest + pmulhw mm7,mm5 ;alpha*(src-dest) + + paddsw mm7,mm7 ;*2 + paddsw mm7,mm6 ;dest+alpha*(src-dest) + + packuswb mm7,mm7 ;re-pack + + + movd [edi],mm7 ;store pixel + + add edi,4 + + + +#else //#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;unpack + #if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + or ecx,ebx + #else + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + #endif + psrlw mm7,8-2 + #if SWIZZLE + add ebx,DWORD PTR [vd] + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + #endif + pmulhw mm7,mm0 ;colour modulate + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or ecx,edx + shr ecx,16-2 + push ecx + #endif +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + paddsw mm0,mm2 ;inc rgb +#endif + #if SWIZZLE + mov edx,eax + add eax,DWORD PTR [ud] + #else + mov ecx,eax + add eax,DWORD PTR [ud] + mov edx,ebx + #endif + packuswb mm7,mm7 ;re-pack + #if SWIZZLE + or edx,ebx + add ebx,DWORD PTR [vd] + #else + add ebx,DWORD PTR [vd] + and ecx,DWORD PTR [umask] + #endif + +#if ALPHA_MODE==ALPHA_ADD + movd mm6,[edi] + paddusb mm7,mm6 +#elif ALPHA_MODE==ALPHA_TEST + movq mm5,mm7 + movq mm6,[edi] + pcmpgtb mm7,[alpha_test_value] ;SIGNED compare! + psrad mm7,24 ;propogate compare result down. + pand mm6,mm7 + pandn mm7,mm5 ;mask (mm7 = (mm5 AND ~mm7)) + por mm7,mm6 ;...and merge +#endif + + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + and edx,DWORD PTR [vmask] + or edx,ecx + #endif + + movd [edi],mm7 ;store pixel + + +// KLUDGE! +// mov DWORD PTR [edi],0x7f7f7f7f + + + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + pop ecx + shr edx,16-2 + #endif + + add edi,4 + + +#endif //#else //#if ALPHA_MODE==ALPHA_BLEND + + + + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + // Calculate r1g1b1, and double up the increments + movq mm1,mm0 + paddsw mm1,mm2 + psllw mm2,1 +#endif + + + + + +#if SWIZZLE +// mov ecx,eax +// add eax,DWORD PTR [ud] +// or ecx,ebx +// add ebx,DWORD PTR [vd] +// shr ecx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and ecx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +// +// mov edx,eax +// add eax,DWORD PTR [ud] +// or edx,ebx +// add ebx,DWORD PTR [vd] +// shr edx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and edx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +#else +// mov ecx,eax +// add eax,DWORD PTR [ud] +// mov edx,ebx +// add ebx,DWORD PTR [vd] +// and ecx,DWORD PTR [umask] +// and edx,DWORD PTR [vmask] +// or ecx,edx +// shr ecx,16-2 +// push ecx +// +// mov ecx,eax +// add eax,DWORD PTR [ud] +// mov edx,ebx +// add ebx,DWORD PTR [vd] +// and ecx,DWORD PTR [umask] +// and edx,DWORD PTR [vmask] +// or edx,ecx +// pop ecx +// shr edx,16-2 +#endif + + movd mm7,[esi+ecx] + movd mm6,[esi+edx] + + +setup_main_loop: + + cmp edi,[last_dest] + je main_loop_done + + + + + +hor_loop: + // Map: + // MM0: (all 8.8): xx,r0,g0,b0 + // MM1: (all 8.8): xx,r1,g1,b1 (not for blend+add) + // MM2: (all 8.8): xx,r,g,b deltas (not for blend+add) + // eax: (16.16): u + // ebx: (16.16): v + // esi: texture base addr + // edi: dest addr + + + + +#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;unpack + #if SWIZZLE + mov ecx,eax + #else + mov ecx,eax + #endif + punpcklbw mm6,mm6 ;unpack + #if SWIZZLE + add eax,DWORD PTR [ud] + #else + mov edx,ebx + #endif + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + psrlw mm7,8-1 + #if SWIZZLE + or ecx,ebx + #else + and ecx,DWORD PTR [umask] + #endif + psrlw mm6,8-1 + #if SWIZZLE + add ebx,DWORD PTR [vd] + #else + and edx,DWORD PTR [vmask] + #endif +#else + psrlw mm7,8-2 + #if SWIZZLE + or ecx,ebx + #else + and ecx,DWORD PTR [umask] + #endif + psrlw mm6,8-2 + #if SWIZZLE + add ebx,DWORD PTR [vd] + #else + and edx,DWORD PTR [vmask] + #endif +#endif + pmulhw mm7,mm0 ;colour modulate + #if SWIZZLE + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + #endif + pmulhw mm6,mm0 ;colour modulate + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or ecx,edx + add eax,DWORD PTR [ud] + #endif + + // Extract and replicate the alpha parts + // Texel 0 + movq mm2,mm7 + #if SWIZZLE + mov edx,eax + #else + shr ecx,16-2 + add ebx,DWORD PTR [vd] + #endif + psrlq mm2,8+1 ;half required value (creates a sign bit) + #if SWIZZLE + add eax,DWORD PTR [ud] + #else + push ecx + mov edx,ebx + #endif + pand mm2,[alpha_mask] + #if SWIZZLE + or edx,ebx + #else + mov ecx,eax + and edx,DWORD PTR [vmask] + #endif + movq mm5,mm2 + #if SWIZZLE + add ebx,DWORD PTR [vd] + #else + and ecx,DWORD PTR [umask] + add eax,DWORD PTR [ud] + #endif + psrlq mm5,16 + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + or edx,ecx + add ebx,DWORD PTR [vd] + #endif + por mm5,mm2 + psrlq mm5,16 + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + shr edx,16-2 + pop ecx + #endif + por mm5,mm2 ;alpha channel replicated to r,g,b + + // Texel 0 + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + + movq mm2,[edi] + movq mm1,mm2 + punpcklbw mm2,mm2 ;unpack dest + punpckhbw mm1,mm1 ;unpack dest + + psrlw mm2,8 + + psubsw mm7,mm2 ;src-dest + pmulhw mm7,mm5 ;alpha*(src-dest) + + + + paddsw mm7,mm7 ;*2 + paddsw mm7,mm2 ;dest0+alpha0*(src0-dest0) + + // Texel 1 + movq mm2,mm6 + psrlq mm2,8+1 ;half required value (creates a sign bit) + pand mm2,[alpha_mask] + movq mm5,mm2 + psrlq mm5,16 + por mm5,mm2 + psrlq mm5,16 + por mm5,mm2 ;alpha channel replicated to r,g,b + + // Texel 1 + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + + // Already unpacked above. + psrlw mm1,8 + + psubsw mm6,mm1 ;src-dest + pmulhw mm6,mm5 ;alpha*(src-dest) + + + paddsw mm6,mm6 ;*2 + paddsw mm6,mm1 ;dest1+alpha1*(src1-dest1) + + // Pack. + packuswb mm7,mm6 ;re-pack + +#else //#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;texel0 + #if SWIZZLE + mov ecx,eax + add eax,DWORD PTR [ud] + #else + mov ecx,eax + mov edx,ebx + #endif + punpcklbw mm6,mm6 ;texel1 + #if SWIZZLE + or ecx,ebx + add ebx,DWORD PTR [vd] + #else + and ecx,DWORD PTR [umask] + and edx,DWORD PTR [vmask] + #endif + psrlw mm7,8-2 + #if SWIZZLE + shr ecx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + or ecx,edx + add eax,DWORD PTR [ud] + #endif + psrlw mm6,8-2 + #if SWIZZLE + and ecx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + shr ecx,16-2 + add ebx,DWORD PTR [vd] + #endif + pmulhw mm7,mm0 + #if SWIZZLE + mov edx,eax + add eax,DWORD PTR [ud] + #else + push ecx + mov edx,ebx + #endif +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + pmulhw mm6,mm1 +#else + pmulhw mm6,mm0 +#endif + #if SWIZZLE + or edx,ebx + add ebx,DWORD PTR [vd] + #else + mov ecx,eax + and edx,DWORD PTR [vmask] + #endif + + packuswb mm7,mm6 + #if SWIZZLE + shr edx,16-2 ;DWORD offset needed + and eax,0x5555ffff + #else + and ecx,DWORD PTR [umask] + add eax,DWORD PTR [ud] + #endif + +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + paddsw mm0,mm2 +#endif +#if ALPHA_MODE==ALPHA_ADD + paddusb mm7,[edi] +#elif ALPHA_MODE==ALPHA_BLEND +#elif ALPHA_MODE==ALPHA_TEST + movq mm5,mm7 + movq mm6,[edi] + pcmpgtb mm7,[alpha_test_value] ;SIGNED compare! + psrad mm7,24 ;propogate compare result down. + pand mm6,mm7 + pandn mm7,mm5 ;mask (mm7 = (mm5 AND ~mm7)) + por mm7,mm6 ;...and merge +#endif + #if SWIZZLE + and edx,DWORD PTR [wrapmask] + and ebx,0xaaaaffff + #else + or edx,ecx + add ebx,DWORD PTR [vd] + #endif +#if (ALPHA_MODE!=ALPHA_ADD) && (ALPHA_MODE!=ALPHA_BLEND) + paddsw mm1,mm2 +#endif + + + #if SWIZZLE + #else + shr edx,16-2 + pop ecx + #endif + + + +#endif //#else //#if ALPHA_MODE==ALPHA_BLEND + + movq [edi],mm7 + +#if SWIZZLE +// mov ecx,eax +// add eax,DWORD PTR [ud] +// or ecx,ebx +// add ebx,DWORD PTR [vd] +// shr ecx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and ecx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +// +// mov edx,eax +// add eax,DWORD PTR [ud] +// or edx,ebx +// add ebx,DWORD PTR [vd] +// shr edx,16-2 ;DWORD offset needed +// and eax,0x5555ffff +// and edx,DWORD PTR [wrapmask] +// and ebx,0xaaaaffff +#else +// mov ecx,eax +// mov edx,ebx +// and ecx,DWORD PTR [umask] +// and edx,DWORD PTR [vmask] +// or ecx,edx +// add eax,DWORD PTR [ud] +// shr ecx,16-2 +// add ebx,DWORD PTR [vd] +// push ecx +// +// mov edx,ebx +// mov ecx,eax +// and edx,DWORD PTR [vmask] +// and ecx,DWORD PTR [umask] +// add eax,DWORD PTR [ud] +// or edx,ecx +// add ebx,DWORD PTR [vd] +// shr edx,16-2 +// pop ecx +#endif + movd mm7,[esi+ecx] + movd mm6,[esi+edx] + + add edi,8 + + cmp edi,[last_dest] + jne hor_loop + +main_loop_done: + + // Do we need to do the last pixel? + ;Is the last pixel odd? + mov ecx,[tempx2] + test ecx,0x1 + jz finished + + + // Do the last pixel + +#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 ;unpack + +#if ALPHA_BLEND_NOT_DOUBLE_LIGHTING + psrlw mm7,8-1 +#else + psrlw mm7,8-2 +#endif + pmulhw mm7,mm0 ;colour modulate + + movq mm6,mm7 + + psrlq mm6,8+1 ;half required value (creates a sign bit) + pand mm6,[alpha_mask] + movq mm5,mm6 + psrlq mm5,16 + por mm5,mm6 + psrlq mm5,16 + por mm5,mm6 ;alpha channel replicated to r,g,b + // Now we need to do alpha*src + (1-alpha)*dest + // = dest + alpha*(src-dest) + // which is quicker (only one multiply) + // Precision is not a problem here - 8.8 format + // Remember that mm2 is spare - no gouard shading on alpha-blenders. + + movd mm6,[edi] + //mov eax,0x10806050 + //movd mm6,eax + + punpcklbw mm6,mm6 ;unpack dest + psrlw mm6,8 + + psubsw mm7,mm6 ;src-dest + pmulhw mm7,mm5 ;alpha*(src-dest) + paddsw mm7,mm7 ;*2 + paddsw mm7,mm6 ;dest+alpha*(src-dest) + + packuswb mm7,mm7 ;re-pack + + + //paddd mm3,[uinc] ;inc u + //paddd mm4,[vinc] ;inc v + //pand mm3,[umask] ;fix swizzle + //pand mm4,[vmask] ;fix swizzle + + +#else //#if ALPHA_MODE==ALPHA_BLEND + + punpcklbw mm7,mm7 + psrlw mm7,8-2 + pmulhw mm7,mm0 + packuswb mm7,mm7 +#if ALPHA_MODE==ALPHA_ADD + movd mm6,[edi] + paddusb mm7,mm6 +#elif ALPHA_MODE==ALPHA_BLEND +#elif ALPHA_MODE==ALPHA_TEST + movq mm5,mm7 + movq mm6,[edi] + pcmpgtb mm7,[alpha_test_value] ;SIGNED compare! + psrad mm7,24 ;propogate compare result down. + pand mm6,mm7 + pandn mm7,mm5 ;mask (mm7 = (mm5 AND ~mm7)) + por mm7,mm6 ;...and merge +#endif + +#endif //#else //#if ALPHA_MODE==ALPHA_BLEND + + movd [edi],mm7 + +finished: + + pop edx + pop ecx + pop ebx + pop eax + pop edi + pop esi + + // Clean up the MMX state + emms + + } + } + } + } +} +#endif diff --git a/fallen/DDEngine/Source/truetype.cpp b/fallen/DDEngine/Source/truetype.cpp new file mode 100644 index 0000000..8bfd87c --- /dev/null +++ b/fallen/DDEngine/Source/truetype.cpp @@ -0,0 +1,869 @@ +// truetype.cpp +// +// TrueType font drawing code + +// This module handles drawing text to the screen in any given TrueType font +// It draws text to a 1280x64 bitmap, then scales it down and antialiases it into a texture +// A list is maintained of all the text draw calls (with wrapping parameters, etc.) made in the last frame, +// the single lines of text these map to and where they are stored in the texture cache +// +// At the beginning of a frame, all text draw calls are marked Pending +// Every call to DrawTextTT is stored; if it already was in the list, it is marked Active. If not, it is measured and +// placed into the list. +// At the end of a frame, the process goes: +// +// 1. Remove from the draw list any text no longer required; free its cachelines etc. +// 2. If any drawing is required: +// 2a. Create the DC and set it up +// 2b. Measure the text and break it into lines +// 2c. Draw each line of text onto the shadow screen +// 2d. Close the memory DC and lock the shadow surface +// 2e. Blit from the shadow surface to the texture surfaces +// 2f. Unlock everything +// 3. Draw polygons to blit the text to the screen + +#include +#include "texture.h" +#ifndef TARGET_DC +#include // MBCS crap +#include // more MBCS crap +#endif + +#ifdef TARGET_DC +#include "target.h" +#endif + +#include "truetype.h" +#include "polypoint.h" +#include "env.h" + +#define ANTIALIAS_BY_HAND 1 // antialias by hand? +#define AA_SIZE (ANTIALIAS_BY_HAND ? 2 : 1) // multiplier +#define NUM_TT_PAGES 4 // number of 256x256 texture pages to allocate +#define MIN_TT_HEIGHT 8 // minimum height of a line of text +#define MAX_TT_HEIGHT 64 // maximum height of a line of text +#define MAX_LINES_PER_PAGE (256 / MIN_TT_HEIGHT) // maximum number of cachelines per texture page +#define MAX_CACHELINES (MAX_LINES_PER_PAGE * NUM_TT_PAGES) // maximum number of cachelines +#define MAX_TEXTCOMMANDS 32 // maximum number of current & pending text commands +#define TYPEFACE NULL // typeface name + +static int FontHeight; // height of font + +static IDirectDrawSurface4* pShadowSurface; // drawing surface +static IDirectDrawPalette* pShadowPalette; // palette for surface +static HFONT hFont; // font for DC +static HFONT hMidFont; // 3/4 font +static HFONT hSmallFont; // 1/2 font +static HFONT hOldFont; // old font for DC + +static D3DTexture Texture[NUM_TT_PAGES]; // texture pages +static CacheLine Cache[MAX_CACHELINES]; // cache lines +static int NumCacheLines; // actual number of cache lines +static UWORD PixMapping[256]; // maps 8bpp greyscale to texture format + +static TextCommand Commands[MAX_TEXTCOMMANDS]; // text commands + +// measure a TextCommand +static void MeasureTextCommand(TextCommand* tcmd); + +// run a TextCommand +static void DoTextCommand(TextCommand* tcmd); + +// draw and cache a single line of text +static void CreateTextLine(char* string, int nchars, int width, int x, int y, TextCommand* owner); + +// allocate a new cache line +static int NewCacheLine(); + +// copy from 8bpp to texture +static void CopyToCache(CacheLine* cptr, UBYTE* sptr, int spitch, int width); + +// blit text across +static void BlitText(); + +// draw the textures to the screen +static void ShowTextures(); + +// blit an area of the current texture to the screen +static void TexBlit(int x1, int y1, int x2, int y2, int dx, int dy, ULONG rgb, ULONG scale); + +// copy the shadow buffer & textures to the screen +static void ShowDebug(); + +// TT_Init +// +// create: +// +// a drawing surface +// the Shift-JIS font +// the texture pages + +void TT_Init() +{ + int ii; + + if (pShadowSurface) return; + + FontHeight = ENV_get_value_number("FontHeight", 32, "TrueType"); + if (FontHeight < MIN_TT_HEIGHT) FontHeight = MIN_TT_HEIGHT; + if (FontHeight > MAX_TT_HEIGHT) FontHeight = MAX_TT_HEIGHT; + +#ifndef TARGET_DC + // set MBCS support + _setmbcp(_MB_CP_LOCALE); // set locale-specific codepage +#endif + + // create the memory surface for drawing + HRESULT hres; + DDSURFACEDESC2 desc; + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_CAPS; + desc.dwWidth = 640 * AA_SIZE; + desc.dwHeight = FontHeight * AA_SIZE; + desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8; + desc.ddpfPixelFormat.dwRGBBitCount = 8; + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_OWNDC | DDSCAPS_SYSTEMMEMORY; + desc.ddsCaps.dwCaps2 = 0; + desc.ddsCaps.dwCaps3 = 0; + desc.ddsCaps.dwCaps4 = 0; + + hres = the_display.lp_DD4->CreateSurface(&desc, &pShadowSurface, NULL); + + ASSERT(!FAILED(hres)); + + // create palette + PALETTEENTRY palette[256]; + + for (ii = 0; ii < 256; ii++) + { + palette[ii].peRed = ii; + palette[ii].peGreen = ii; + palette[ii].peBlue = ii; + palette[ii].peFlags = NULL; + } + + hres = the_display.lp_DD4->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE, palette, &pShadowPalette, NULL); + ASSERT(!FAILED(hres)); + + hres = pShadowSurface->SetPalette(pShadowPalette); + ASSERT(!FAILED(hres)); + +#ifdef TARGET_DC + // Got to do it the long way round for DreamCast - don't know why. + LOGFONT logfont; + logfont.lfHeight = FontHeight * AA_SIZE; + logfont.lfWeight = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfWeight = FW_BOLD; + logfont.lfItalic = FALSE; + logfont.lfUnderline = FALSE; + logfont.lfStrikeOut = FALSE; + logfont.lfCharSet = SHIFTJIS_CHARSET; + logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = DEFAULT_QUALITY; + logfont.lfPitchAndFamily = FF_DONTCARE | DEFAULT_PITCH; + logfont.lfFaceName[0] = TEXT('\0'); + hFont = CreateFontIndirect ( &logfont ); +#else //#ifdef TARGET_DC + // create the font - hey, a function with fourteen parameters! + hFont = CreateFont(FontHeight * AA_SIZE, + 0,0,0, + FW_BOLD, // weight + FALSE,FALSE,FALSE, + SHIFTJIS_CHARSET, // charset + OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, // quality + FF_DONTCARE | DEFAULT_PITCH, + TYPEFACE); // typeface name +#endif //#else //#ifdef TARGET_DC + + ASSERT(hFont); + + // create the texture cache + NumCacheLines = 0; + + for (ii = 0; ii < NUM_TT_PAGES; ii++) + { + // create a page + Texture[ii].CreateUserPage(256, TRUE); + + // create cacheline mappings + for (int jj = 0; jj + FontHeight <= 256; jj += FontHeight) + { + Cache[NumCacheLines].owner = NULL; + Cache[NumCacheLines].texture = &Texture[ii]; + Cache[NumCacheLines].y = jj; + + NumCacheLines++; + } + } + + // set up pixmap + int rr = Texture[0].mask_red; + int lr = Texture[0].shift_red; + int rg = Texture[0].mask_green; + int lg = Texture[0].shift_green; + int rb = Texture[0].mask_blue; + int lb = Texture[0].shift_blue; + int ra = Texture[0].mask_alpha; + int la = Texture[0].shift_alpha; + + for (ii = 0; ii < 256; ii++) + { + PixMapping[ii] = 0; + PixMapping[ii] |= (255 >> rr) << lr; + PixMapping[ii] |= (255 >> rg) << lg; + PixMapping[ii] |= (255 >> rb) << lb; + PixMapping[ii] |= (ii >> ra) << la; + } + + // initialize the textcommands + for (ii = 0; ii < MAX_TEXTCOMMANDS; ii++) + { + Commands[ii].validity = Free; + } + + // initialize the DC (since it's owned, this is remembered) + HDC hDC; + + hres = pShadowSurface->GetDC(&hDC); + ASSERT(!FAILED(hres)); + + // prepare the DC + SetBkColor(hDC, RGB(0,0,0)); + SetBkMode(hDC, OPAQUE); +#ifndef TARGET_DC + SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP); + SetTextCharacterExtra(hDC, ENV_get_value_number("ExtraSpaceX", 0, "TrueType")); +#endif + SetTextColor(hDC, RGB(255,255,255)); + + HFONT hOldFont = (HFONT)SelectObject(hDC, hFont); + ASSERT(hOldFont); + + hres = pShadowSurface->ReleaseDC(hDC); + ASSERT(!FAILED(hres)); +} + +// TT_Term +// +// release the resources + +void TT_Term() +{ + if (!pShadowSurface) return; + + // unprepare the DC + HDC hDC; + HRESULT hres; + + hres = pShadowSurface->GetDC(&hDC); + ASSERT(!FAILED(hres)); + + SelectObject(hDC, hOldFont); + + hres = pShadowSurface->ReleaseDC(hDC); + ASSERT(!FAILED(hres)); + + pShadowSurface->SetPalette(NULL); + + pShadowPalette->Release(); + pShadowPalette = NULL; + + pShadowSurface->Release(); + pShadowSurface = NULL; + + DeleteObject(hFont); + hFont = NULL; + + for (int ii = 0; ii < NUM_TT_PAGES; ii++) + { + Texture[ii].Destroy(); + Texture[ii].Type = D3DTEXTURE_TYPE_UNUSED; + } +} + +// DrawTextTT +// +// exported function to draw formatted text + +int DrawTextTT(char* string, int x, int y, int rx, int scale, ULONG rgb, int command, long* width) +{ + int nbytes; + + ASSERT(rx > x); + + if (scale > 256) scale = 256; // no zooming up, it looks poo + + // check string length + nbytes = strlen(string); + ASSERT(nbytes < MAX_TT_TEXT - 1); + + // look for command + TextCommand* tcmd = Commands; + TextCommand* best = NULL; + bool exact = false; + + for (int ii = 0; ii < MAX_TEXTCOMMANDS; ii++) + { + if (tcmd->validity == Pending) + { + if ((tcmd->x == x) && (tcmd->y == y) && (tcmd->rx == rx) && (tcmd->command == command) && (tcmd->nbytes == nbytes)) + { + if (!strcmp(string, tcmd->data)) + { + // exact match + best = tcmd; + exact = true; + break; + } + } + } + else if (tcmd->validity == Free) + { + if (!best) + { + best = tcmd; + } + } + + tcmd++; + } + + if (!best) return y; // no space + + if (!exact) + { + best->x = x; + best->y = y; + best->rx = rx; + best->scale = scale; + best->command = command; + best->nbytes = nbytes; + strcpy(best->data, string); +#ifdef TARGET_DC + best->nchars = strlen(string); +#else + best->nchars = _mbslen((unsigned char*)string); +#endif + best->in_cache = false; + MeasureTextCommand(best); + } + + best->rgb = rgb; + best->validity = Current; + + if (width) *width = best->x + best->fwidth; + + return y + best->lines * FontHeight * scale / 256; +} + +// GetTextHeightTT +// +// get height of TT text + +int GetTextHeightTT() +{ + return FontHeight; +} + +// PreFlipTT +// +// end a frame + +void PreFlipTT() +{ + if (!pShadowSurface) return; // not initialized + + int ii; + bool work = false; + + // release all unused text commands + for (ii = 0; ii < MAX_TEXTCOMMANDS; ii++) + { + if (Commands[ii].validity == Pending) Commands[ii].validity = Free; + else if ((Commands[ii].validity == Current) && !Commands[ii].in_cache) work = true; + } + + // check cachelines and release if owned by a deleted text command + for (ii = 0; ii < NumCacheLines; ii++) + { + if (Cache[ii].owner && (Cache[ii].owner->validity == Free)) Cache[ii].owner = NULL; + } + + // draw text if there is any to do + if (work) + { + TextCommand* tcmd = Commands; + + for (ii = 0; ii < MAX_TEXTCOMMANDS; ii++) + { + if ((tcmd->validity == Current) && !tcmd->in_cache) + { + DoTextCommand(tcmd); + tcmd->in_cache = true; + } + tcmd++; + } + } + + // set all Current commands to Pending + for (ii = 0; ii < MAX_TEXTCOMMANDS; ii++) + { + if (Commands[ii].validity == Current) Commands[ii].validity = Pending; + } + + // copy to the screen + BlitText(); + +#ifdef _DEBUG + if (ControlFlag) ShowDebug(); +#endif +} + +// MeasureTextCommand +// +// count how many lines is in a text command, and the maximum width + +static void MeasureTextCommand(TextCommand* tcmd) +{ + char* string = tcmd->data; + int clen = tcmd->nchars; + + HDC hDC; + HRESULT res; + + res = pShadowSurface->GetDC(&hDC); + ASSERT(!FAILED(res)); + + tcmd->lines = 0; + tcmd->fwidth = tcmd->rx - tcmd->x; + + while (clen) + { + SIZE size; + int chars; + +#ifdef TARGET_DC + static TCHAR cTempString[64+1]; + ASSERT ( strlen ( string ) < 64 ); + textConvertCharToUni ( cTempString, string ); + GetTextExtentExPoint(hDC,cTempString,clen,tcmd->fwidth*AA_SIZE,&chars,NULL,&size); +#else + GetTextExtentExPoint(hDC,string,clen,tcmd->fwidth*AA_SIZE,&chars,NULL,&size); +#endif + + if ((chars < clen) && (clen - chars < 3)) chars = clen - 3; + ASSERT(chars); + if (!chars) break; + + tcmd->lines++; + clen -= chars; +#ifdef TARGET_DC + string += chars; +#else + string = (char*)_mbsninc((unsigned char*)string, chars); +#endif + } + + res = pShadowSurface->ReleaseDC(hDC); + ASSERT(!FAILED(res)); +} + +// DoTextCommand +// +// run a text command - split into lines, draw and cache them + +static void DoTextCommand(TextCommand* tcmd) +{ + char* string = tcmd->data; + int clen = tcmd->nchars; + int y = tcmd->y; + + while (clen) + { + // set up the DC so we can measure strings etc. + HDC hDC; + HRESULT res; + + res = pShadowSurface->GetDC(&hDC); + ASSERT(!FAILED(res)); + + // measure string + SIZE size; + int chars; + +#ifdef TARGET_DC + static TCHAR cTempString[64+1]; + ASSERT ( strlen ( string ) < 64 ); + textConvertCharToUni ( cTempString, string ); + GetTextExtentExPoint(hDC,cTempString,clen,tcmd->fwidth*AA_SIZE,&chars,NULL,&size); +#else + GetTextExtentExPoint(hDC,string,clen,tcmd->fwidth*AA_SIZE,&chars,NULL,&size); +#endif + + // fix up for 1 or 2 characters over + if ((chars < clen) && (clen - chars < 3)) chars = clen - 3; + + ASSERT(chars); + if (!chars) return; + + // get width +#ifdef TARGET_DC + GetTextExtentExPoint(hDC,cTempString,chars,0,NULL,NULL,&size); +#else + GetTextExtentExPoint(hDC,string,chars,0,NULL,NULL,&size); +#endif + int width = size.cx / AA_SIZE; + + // release the DC + res = pShadowSurface->ReleaseDC(hDC); + ASSERT(!FAILED(res)); + +#ifdef _DEBUG + static char buffer[256]; + memcpy(buffer, string, chars); + buffer[chars] = '\0'; + TRACE("Line: %s\n", buffer); +#endif + + // draw this line + switch (tcmd->command) + { + case LeftJustify: + CreateTextLine(string, chars, width, tcmd->x, y, tcmd); + break; + + case RightJustify: + CreateTextLine(string, chars, width, tcmd->rx - width, y, tcmd); + break; + + case Centred: + CreateTextLine(string, chars, width, (tcmd->x + tcmd->rx - width * tcmd->scale / 256) / 2, y, tcmd); + break; + + default: + ASSERT(0); + break; + } + + y += FontHeight * tcmd->scale >> 8; + clen -= chars; +#ifdef TARGET_DC + string += chars; +#else + string = (char*)_mbsninc((unsigned char*)string, chars); +#endif + } +} + +// CreateTextLine +// +// create a TextLine and draw it into the DC + +static void CreateTextLine(char* string, int nchars, int width, int x, int y, TextCommand* owner) +{ + ASSERT(width <= 640); + + // set up the DC + HDC hDC; + HRESULT res; + + res = pShadowSurface->GetDC(&hDC); + ASSERT(!FAILED(res)); + + // set up drawing rectangle + RECT rect; + + rect.left = 0; + rect.right = width * AA_SIZE; + rect.top = 0; + rect.bottom = FontHeight * AA_SIZE; + + // draw text +#ifdef TARGET_DC + static TCHAR cTempString[64+1]; + ASSERT ( strlen ( string ) < 64 ); + textConvertCharToUni ( cTempString, string ); + res = ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rect, cTempString, nchars, NULL); +#else + res = ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rect, string, nchars, NULL); +#endif + ASSERT ( res != 0 ); + + res = pShadowSurface->ReleaseDC(hDC); + ASSERT(!FAILED(res)); + + // + // copy to cache + // + + // lock the surface + DDSURFACEDESC2 ddsdesc; + + InitStruct(ddsdesc); + + res = pShadowSurface->Lock(NULL, &ddsdesc, DDLOCK_WAIT, NULL); + ASSERT(!FAILED(res)); + + UBYTE* sptr = (UBYTE*)ddsdesc.lpSurface; + int spitch = ddsdesc.lPitch; + + // copy to cache + int line; + int seg = 0; + + while (width >= 0) + { + ASSERT(seg < 3); + + line = NewCacheLine(); + if (line != -1) + { + CopyToCache(&Cache[line], sptr, spitch, width); + Cache[line].owner = owner; + Cache[line].sx = x; + Cache[line].sy = y; + } + + width -= 256; + x += owner->scale; + seg++; + sptr += 256 * AA_SIZE; + } + + // unlock the surface + res = pShadowSurface->Unlock(NULL); + ASSERT(!FAILED(res)); +} + +// NewCacheLine +// +// allocate a new cache line, and return its index + +static int NewCacheLine() +{ + for (int ii = 0; ii < NumCacheLines; ii++) + { + if (!Cache[ii].owner) return ii; + } + return -1; +} + +// CopyToCache +// +// copy from the shadow surface to a texture + +static void CopyToCache(CacheLine* cptr, UBYTE* sptr, int spitch, int width) +{ + if (width > 256) width = 256; + + HRESULT res; + UWORD* dptr; + SLONG dpitch; + + res = cptr->texture->LockUser(&dptr, &dpitch); + if (FAILED(res)) return; + + dpitch /= 2; + dptr += cptr->y * dpitch; + +#if ANTIALIAS_BY_HAND + for (int y = 0; y < FontHeight; y++) + { + for (int x = 0; x < width; x++) + { + int acc = sptr[0] + sptr[1] + sptr[spitch + 0] + sptr[spitch + 1]; + dptr[x] = PixMapping[acc / 4]; + sptr += 2; + } + sptr += (spitch-width)*2; + dptr += dpitch; + } +#else + for (int y = 0; y < FontHeight; y++) + { + for (int x = 0; x < width; x++) + { + dptr[x] = PixMapping[sptr[x]]; + } + dptr += dpitch; + sptr += spitch; + } +#endif + + cptr->texture->UnlockUser(); + cptr->width = width; +} + +// BlitText +// +// blit all the text on + +static void BlitText() +{ + int ii; + D3DTexture* ctex = NULL; + CacheLine* cptr = Cache; + + // go through in texture order + for (ii = 0; ii < NumCacheLines; ii++) + { + if (cptr->owner) + { + // set render states + if (!ctex) + { + BEGIN_SCENE; + + // Fixme! I need to be updated if this ever gets called - TomF. + ASSERT ( FALSE ); + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_NEAREST); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_NEAREST); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE, FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE, FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + } + if (ctex != cptr->texture) + { + ctex = cptr->texture; + REALLY_SET_TEXTURE(ctex->GetD3DTexture()); + } + + // blit area + TexBlit(0, cptr->y, cptr->width, cptr->y + FontHeight, cptr->sx, cptr->sy, cptr->owner->rgb, cptr->owner->scale); + } + cptr++; + } + + if (ctex) + { + END_SCENE; + } +} + +// ShowTextures +// +// draw to screen + +static void ShowTextures() +{ + BEGIN_SCENE; + + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_NEAREST); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_NEAREST); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE, FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE, FALSE); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); + REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + + REALLY_SET_TEXTURE(Texture[0].GetD3DTexture()); + + TexBlit(0,0,256,256,0,FontHeight*AA_SIZE,0xFFFFFFFF,256); + + END_SCENE; +} + +// TexBlit +// +// "blit" from texture to screen + +static void TexBlit(int x1, int y1, int x2, int y2, int dx, int dy, ULONG rgb, ULONG scale) +{ + PolyPoint2D vert[4], *vp = vert; + + float u1 = float(x1) / 256; + float u2 = float(x2) / 256; + float v1 = float(y1) / 256; + float v2 = float(y2) / 256; + + int width = (x2 - x1) * scale / 256; + int height = (y2 - y1) * scale / 256; + + vp->SetSC(dx,dy); + vp->SetColour(rgb); + vp->SetSpecular(0xFF000000); + vp->SetUV(u1,v1); + vp++; + + vp->SetSC(dx + width,dy); + vp->SetColour(rgb); + vp->SetSpecular(0xFF000000); + vp->SetUV(u2,v1); + vp++; + + vp->SetSC(dx + width,dy + height); + vp->SetColour(rgb); + vp->SetSpecular(0xFF000000); + vp->SetUV(u2,v2); + vp++; + + vp->SetSC(dx,dy + height); + vp->SetColour(rgb); + vp->SetSpecular(0xFF000000); + vp->SetUV(u1,v2); + vp++; + + static WORD indices[6] = { 0, 3, 1, 1, 2, 3 }; + + //HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, vert->GetTLVert(), 4, indices, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, (D3DTLVERTEX*)vert, 4, indices, 6, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT); + ASSERT(!FAILED(res)); +} + +// ShowDebug +// +// display shadow screen & textures + +static void ShowDebug() +{ + UWORD mapping[256]; + + for (int ii = 0; ii < 256; ii++) + { + UBYTE col = ii >> 3; + mapping[ii] = (col << 10) | (col << 5) | col; + } + + // lock the shadow surface + DDSURFACEDESC2 ddsdesc; + HRESULT ret; + + InitStruct(ddsdesc); + + ret = pShadowSurface->Lock(NULL, &ddsdesc, DDLOCK_WAIT, NULL); + + if (FAILED(ret)) return; + + UBYTE* sptr = (UBYTE*)ddsdesc.lpSurface; + int spitch = ddsdesc.lPitch; + + UWORD* dptr = (UWORD*)the_display.screen_lock(); + int dpitch = the_display.screen_pitch / 2; + + for (int y = 0; y < FontHeight * AA_SIZE; y++) + { + for (int x = 0; x < 640; x++) + { + dptr[x] = mapping[sptr[x]]; + } + sptr += spitch; + dptr += dpitch; + } + + the_display.screen_unlock(); + pShadowSurface->Unlock(NULL); + + ShowTextures(); +} diff --git a/fallen/DDEngine/Source/vertexbuffer.cpp b/fallen/DDEngine/Source/vertexbuffer.cpp new file mode 100644 index 0000000..aca0689 --- /dev/null +++ b/fallen/DDEngine/Source/vertexbuffer.cpp @@ -0,0 +1,463 @@ +// vertexbuffer.cpp +// +// Vertex buffer stuff (DX6) + +#include +#include +#include +#include "console.h" +#include "poly.h" +#ifdef TARGET_DC +#include "target.h" +#endif + +#include "vertexbuffer.h" + +VertexBufferPool* TheVPool = NULL; + +void VB_Init() +{ + if (!TheVPool) TheVPool = MFnew(); +} + +void VB_Term() +{ + MFdelete(TheVPool); + TheVPool = NULL; +} + +//----------------------------- +// VertexBuffer +//----------------------------- + +// constructor / destructor + +VertexBuffer::VertexBuffer() +{ + m_LogSize = 0; + m_LockedPtr = NULL; + m_Prev = NULL; + m_Next = NULL; +#if USE_D3D_VBUF + m_TheBuffer = NULL; +#endif +} + +VertexBuffer::~VertexBuffer() +{ + ASSERT(!m_Next); + ASSERT(!m_Prev); + + if (m_LockedPtr) + { +#if !USE_D3D_VBUF + //delete[] m_LockedPtr; + MemFree ( m_LockedPtr ); + #endif + Unlock(); + } + +#if USE_D3D_VBUF + if (m_TheBuffer) + { + m_TheBuffer->Release(); + m_TheBuffer = NULL; + } +#endif +} + +// Create +// +// create the vertex buffer + +HRESULT VertexBuffer::Create(IDirect3D3* d3d, bool force_system, ULONG logsize) +{ + ASSERT(!m_LockedPtr); + ASSERT(d3d); + +#if USE_D3D_VBUF + + ASSERT(!m_TheBuffer); + + TRACE("Create vertex buffer\n"); + + D3DVERTEXBUFFERDESC desc; + + InitStruct(desc); + + desc.dwCaps = force_system ? D3DVBCAPS_SYSTEMMEMORY : 0; +// desc.dwCaps |= D3DVBCAPS_WRITEONLY; // oops ... can't expand with this flag set ;-) + desc.dwFVF = D3DFVF_TLVERTEX; + desc.dwNumVertices = 1 << logsize; + + HRESULT res = d3d->CreateVertexBuffer(&desc, &m_TheBuffer, 0, NULL); + + if (FAILED(res)) + { + m_TheBuffer = NULL; + return res; + } + +#else + + //m_LockedPtr = new D3DTLVERTEX[1 << logsize]; + m_LockedPtr = (D3DTLVERTEX*)MemAlloc ( (1 << logsize) * sizeof (D3DTLVERTEX ) ); + if (!m_LockedPtr) return DDERR_OUTOFMEMORY; + +#endif + + m_LogSize = logsize; + + return DD_OK; +} + +// Lock +// +// lock the vertex buffer + +D3DTLVERTEX* VertexBuffer::Lock() +{ +#if USE_D3D_VBUF + + ASSERT(m_TheBuffer); + ASSERT(!m_LockedPtr); + + HRESULT res = m_TheBuffer->Lock(DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK, (LPVOID*)&m_LockedPtr, NULL); + + if (FAILED(res)) + { + ASSERT(res != DDERR_SURFACELOST); + m_LockedPtr = NULL; + return NULL; + } + +#endif + + return m_LockedPtr; +} + +// Unlock +// +// unlock the vertex buffer + +void VertexBuffer::Unlock() +{ +#if USE_D3D_VBUF + + ASSERT(m_TheBuffer); + ASSERT(m_LockedPtr); + + HRESULT res = m_TheBuffer->Unlock(); + + if (FAILED(res)) + { + ASSERT(res != DDERR_SURFACELOST); + ASSERT(0); + } + + m_LockedPtr = NULL; + +#endif +} + +//----------------------------- +// VertexBufferPool +//----------------------------- + +// constructor & destructor + +VertexBufferPool::VertexBufferPool() +{ + m_D3D = NULL; + m_SysMem = false; + + for (int ii = 0; ii < 16; ii++) + { + m_FreeList[ii] = NULL; + m_BusyListLRU[ii] = NULL; + m_BusyListMRU[ii] = NULL; + m_Count[ii] = 0; + } +} + +VertexBufferPool::~VertexBufferPool() +{ + VertexBuffer* p; + + for (int ii = 0; ii < 16; ii++) + { + while (p = m_FreeList[ii]) + { + m_FreeList[ii] = p->m_Next; + p->m_Next = NULL; + p->m_Prev = NULL; + delete p; + } + while (p = m_BusyListLRU[ii]) + { + m_BusyListLRU[ii] = p->m_Next; + p->m_Next = NULL; + p->m_Prev = NULL; + delete p; + } + } +} + +// Create +// +// create an initial pool of buffers + +void VertexBufferPool::Create(IDirect3D3* d3d, bool force_system) +{ +#ifdef TARGET_DC + // A quarter of the size. + static int Allocations[16] = {0,0,0,0, 0,0,128,64,32,16, 8,4, 0,0,0,0}; +#else + static int Allocations[16] = {0,0,0,0, 0,0,128,64, 32,16,8,4, 0,0,0,0}; // total 48,000 vertices +#endif + + ASSERT(!m_D3D); + ASSERT(d3d); + + m_D3D = d3d; + m_SysMem = force_system; + + // create a variety of buffers + for (int ii = 0; ii < 16; ii++) + { + for (int jj = 0; jj < Allocations[ii]; jj++) + { + CreateBuffer(ii); + } + } +} + +// CreateBuffer +// +// try to create a new VertexBuffer and put it on the free list + +void VertexBufferPool::CreateBuffer(ULONG logsize) +{ + ASSERT(logsize < 16); + + VertexBuffer* p = new VertexBuffer; + if (!p) return; + + HRESULT res = p->Create(m_D3D, m_SysMem, logsize); + + if (FAILED(res)) + { + delete p; + return; + } + + if (p->Lock()) + { + p->m_Next = m_FreeList[logsize]; + m_FreeList[logsize] = p; + + m_Count[logsize]++; + } + else + { + ASSERT(0); + } +} + +// CheckBuffers +// +// try to lock the buffers in the busy list + +void VertexBufferPool::CheckBuffers(ULONG logsize, bool time_critical) +{ + VertexBuffer* list = m_BusyListLRU[logsize]; + + while (list) + { + VertexBuffer* next = list->m_Next; + + if (list->Lock()) + { + // remove from busy list + if (list->m_Prev == NULL) m_BusyListLRU[logsize] = list->m_Next; + else list->m_Prev->m_Next = list->m_Next; + if (list->m_Next == NULL) m_BusyListMRU[logsize] = list->m_Prev; + else list->m_Next->m_Prev = list->m_Prev; + // add to free list + list->m_Prev = NULL; + list->m_Next = m_FreeList[logsize]; + m_FreeList[logsize] = list; + + if (time_critical) return; // don't check any more + } + + list = next; + } +} + +// GetBuffer +// +// get a buffer with the given size + +VertexBuffer* VertexBufferPool::GetBuffer(ULONG logsize) +{ + ASSERT(logsize < 16); + + if (!m_FreeList[logsize]) + { + // try and lock a busy buffer + CheckBuffers(logsize, true); + + if (!m_FreeList[logsize]) + { + // try and create a new buffer + CreateBuffer(logsize); + + if (!m_FreeList[logsize]) + { + if (m_BusyListLRU[logsize]) + { + // wait for a busy buffer + ASSERT(0); + while (!m_FreeList[logsize]) CheckBuffers(logsize, true); + } + else + { + return NULL; + } + } + } + } + + VertexBuffer* p = m_FreeList[logsize]; + m_FreeList[logsize] = p->m_Next; + p->m_Next = NULL; + + ASSERT(p->m_LockedPtr); + + return p; +} + +// ReleaseBuffer +// +// release a buffer back to the free list + +void VertexBufferPool::ReleaseBuffer(VertexBuffer* buffer) +{ + ASSERT(buffer); + ASSERT(buffer->m_LockedPtr); + ASSERT(!buffer->m_Next); + + buffer->m_Next = m_FreeList[buffer->m_LogSize]; + m_FreeList[buffer->m_LogSize] = buffer; +} + +// ExpandBuffer +// +// expand a buffer by swapping with a bigger one + +VertexBuffer* VertexBufferPool::ExpandBuffer(VertexBuffer* buffer) +{ + ASSERT(buffer); + ASSERT(buffer->m_LockedPtr); + ASSERT(!buffer->m_Next); + ASSERT(buffer->m_LogSize < 16); + + VertexBuffer* p = GetBuffer(buffer->m_LogSize + 1); + + if (p) + { + memcpy(p->GetPtr(), buffer->GetPtr(), buffer->GetSize() * sizeof(D3DTLVERTEX)); + ReleaseBuffer(buffer); + } + else + { + p = buffer; + } + + return p; +} + +// PrepareBuffer +// +// prepare a buffer for rendering + +#if USE_D3D_VBUF + +IDirect3DVertexBuffer* VertexBufferPool::PrepareBuffer(VertexBuffer* buffer) +{ + ASSERT(buffer); + ASSERT(buffer->m_LockedPtr); + ASSERT(!buffer->m_Next); + + buffer->Unlock(); + + // add to end (MRU) of busy list + buffer->m_Next = NULL; + buffer->m_Prev = m_BusyListMRU[buffer->m_LogSize]; + if (buffer->m_Prev) + { + buffer->m_Prev->m_Next = buffer; + } + else + { + m_BusyListLRU[buffer->m_LogSize] = buffer; + } + m_BusyListMRU[buffer->m_LogSize] = buffer; + + return buffer->m_TheBuffer; +} + +#endif + +// DumpInfo +// +// dump info to a file + +#ifndef TARGET_DC +void VertexBufferPool::DumpInfo(FILE* fd) +{ + ReclaimBuffers(); + + for (int ii = 0; ii < 16; ii++) + { + if (m_Count[ii]) + { + fprintf(fd, "Buffer size %d vertices (1 << %d)\n\n", 1 << ii, ii); + fprintf(fd, "Allocated ever = %d\n", m_Count[ii]); + + VertexBuffer* p; + int busy = 0; + int free = 0; + + p = m_FreeList[ii]; + while (p) { free++; p = p->m_Next; } + + p = m_BusyListLRU[ii]; + while (p) { busy++; p = p->m_Next; } + + fprintf(fd, "Free now = %d\n", free); + fprintf(fd, "Used now = %d\n", m_Count[ii] - free - busy); + fprintf(fd, "Busy now = %d\n", busy); + } + else + { + fprintf(fd, "Buffer size %d vertices - never allocated\n", 1 << ii); + } + + fprintf(fd, "\n"); + } +} +#endif + +// ReclaimBuffers +// +// run CheckBuffer on each pool + +void VertexBufferPool::ReclaimBuffers() +{ + for (int ii = 0; ii < 16; ii++) + { + CheckBuffers(ii, false); + } +} diff --git a/fallen/DDEngine/Source/wibble.cpp b/fallen/DDEngine/Source/wibble.cpp new file mode 100644 index 0000000..d2cc8b2 --- /dev/null +++ b/fallen/DDEngine/Source/wibble.cpp @@ -0,0 +1,155 @@ +#include "game.h" +#include + + +SLONG mul_y1; +SLONG mul_y2; +SLONG mul_g1; +SLONG mul_g2; + +SLONG shift1; +SLONG shift2; + +void WIBBLE_simple( + SLONG x1, SLONG y1, + SLONG x2, SLONG y2, + UBYTE wibble_y1, + UBYTE wibble_y2, + UBYTE wibble_g1, + UBYTE wibble_g2, + UBYTE wibble_s1, + UBYTE wibble_s2) +{ + SLONG y; + SLONG offset; + SLONG count; + SLONG angle1; + SLONG angle2; + + x1 = x1 * RealDisplayWidth / DisplayWidth; + x2 = x2 * RealDisplayWidth / DisplayWidth; + y1 = y1 * RealDisplayHeight / DisplayHeight; + y2 = y2 * RealDisplayHeight / DisplayHeight; + + if (the_display.CurrMode->GetBPP() == 16) + { + UWORD *dest; + UWORD *src; + UBYTE *base = &the_display.screen[x1 + x1 + y1 * the_display.screen_pitch]; + + for (y = y1; y < y2; y++) + { + angle1 = y * wibble_y1; + angle2 = y * wibble_y2; + angle1 += GAME_TURN * wibble_g1; + angle2 += GAME_TURN * wibble_g2; + + angle1 &= 2047; + angle2 &= 2047; + + offset = SIN(angle1) * wibble_s1 >> 19; + offset += COS(angle2) * wibble_s2 >> 19; + + if (offset == 0) + { + // + // Easy! + // + } + else + if (offset > 0) + { + dest = (UWORD *) base; + src = (UWORD *) base; + src += offset; + + count = x2 - x1; + + while(count-- > 0) + { + *dest++ = *src++; + } + } + else + { + count = x2 - x1; + + dest = (UWORD *) base; + src = (UWORD *) base; + + dest += count - 1; + src += count - 1; + + src += offset; + + while(count-- > 0) + { + *dest-- = *src--; + } + } + + base += the_display.screen_pitch; + } + } + else + { + // cut-and-paste, but I don't care anymore + ULONG *dest; + ULONG *src; + UBYTE *base = &the_display.screen[x1 * 4 + y1 * the_display.screen_pitch]; + + for (y = y1; y < y2; y++) + { + angle1 = y * wibble_y1; + angle2 = y * wibble_y2; + angle1 += GAME_TURN * wibble_g1; + angle2 += GAME_TURN * wibble_g2; + + angle1 &= 2047; + angle2 &= 2047; + + offset = SIN(angle1) * wibble_s1 >> 19; + offset += COS(angle2) * wibble_s2 >> 19; + + if (offset == 0) + { + // + // Easy! + // + } + else + if (offset > 0) + { + dest = (ULONG *)base; + src = (ULONG *)base; + src += offset; + + count = x2 - x1; + + while(count-- > 0) + { + *dest++ = *src++; + } + } + else + { + count = x2 - x1; + + dest = (ULONG *)base; + src = (ULONG *)base; + + dest += count - 1; + src += count - 1; + + src += offset; + + while(count-- > 0) + { + *dest-- = *src--; + } + } + + base += the_display.screen_pitch; + } + } +} diff --git a/fallen/DDLibrary/DDlib.rc b/fallen/DDLibrary/DDlib.rc new file mode 100644 index 0000000..54a10b8 --- /dev/null +++ b/fallen/DDLibrary/DDlib.rc @@ -0,0 +1,2231 @@ +//Microsoft Developer Studio generated resource script. +// +#include "Headers\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "Headers\\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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MAIN_MENU MENU DISCARDABLE +BEGIN + POPUP "&Display" + BEGIN + MENUITEM "&Full Screen..\tF1", ID_DISPLAY_FULLSCREEN + MENUITEM "&Drivers..\tF2", ID_DISPLAY_DRIVERS + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_DISPLAY_EXIT + END + POPUP "&Modes" + BEGIN + MENUITEM "320x200", ID_MODES_320X200 + MENUITEM "512x384", ID_MODES_512X384 + MENUITEM "640x480", ID_MODES_640X480 + MENUITEM "800x600", ID_MODES_800X600 + MENUITEM "1024x768", ID_MODES_1024X768 + END + POPUP "&Editor" + BEGIN + MENUITEM "&Mission Editor...", ID_EDITOR_MISSIONEDITOR + END + POPUP "&Help" + BEGIN + MENUITEM "&About Mucky Foot Shell", ID_ABOUT + END +END + +IDR_LEDIT_MENU MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Open map\tCtrl+O", ID_FILE_OPEN_ARSE + MENUITEM "&Load Lighting\tCtrl+L", ID_FILE_LOAD_ARSE, GRAYED + MENUITEM "&Save lighting\tCtrl+S", ID_FILE_SAVE_ARSE, GRAYED + MENUITEM SEPARATOR + MENUITEM "E&xit\tCtrl+Q", ID_FILE_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO_ARSE, GRAYED + MENUITEM "&Redo\tCtrl+Y", ID_EDIT_REDO_ARSE, GRAYED + MENUITEM SEPARATOR + MENUITEM "Delete\tBackSpace", ID_EDIT_DELETE_ARSE, GRAYED + MENUITEM "&Clear all", ID_EDIT_CLEARALL, GRAYED + MENUITEM SEPARATOR + MENUITEM "&Inside\tI", ID_EDIT_INSIDES, GRAYED + MENUITEM SEPARATOR + MENUITEM "&Place light\tP", ID_EDIT_PLACELIGHT, GRAYED + MENUITEM "&Edit lights\tE", ID_EDIT_EDITLIGHTS, GRAYED + MENUITEM "Set &ambient\tA", ID_EDIT_SETAMBIENT, GRAYED + MENUITEM "Set &lampost colour\tL", ID_EDIT_SETLAMPOSTCOLOUR + , GRAYED + MENUITEM "Set &sky colour\tK", ID_EDIT_SETSKYCOLOUR, GRAYED + END + POPUP "&Map" + BEGIN + MENUITEM "&Night sky", ID_MAP_NIGHTSKY, GRAYED + MENUITEM "&Daytime", ID_MAP_DAYTIME, GRAYED + MENUITEM SEPARATOR + MENUITEM "Lights under &lamposts", ID_MAP_LIGHTSUNDERLAMPOSTS + , GRAYED + MENUITEM "Darken &bottoms of buildings", + ID_MAP_DARKENBOTTOMSOFBUILDINGS + , GRAYED + MENUITEM SEPARATOR + MENUITEM "Info", ID_MAP_INFO, GRAYED + END + POPUP "&Help" + BEGIN + MENUITEM "About", ID_HELP_ABOUT + END +END + +IDR_LEDIT_POPUPS MENU DISCARDABLE +BEGIN + POPUP "Frame" + BEGIN + MENUITEM "Place light", ID_FRAME_PLACEANEWLIGHT + MENUITEM "Edit light", ID_FRAME_EDITLIGHT + MENUITEM "Set ambient", ID_FRAME_SETAMBIENT + END +END + +IDR_SEDIT_MENU MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Open\tCtrl+O", ID_FILE_OPEN_ARSE + MENUITEM SEPARATOR + MENUITEM "&Load sewers\tCtrl+L", ID_FILE_LOAD_SEWERS, GRAYED + MENUITEM "&Save sewers\tCtrl+S", ID_FILE_SAVE_SEWERS, GRAYED + MENUITEM SEPARATOR + MENUITEM "E&xit\tCtrl+Q", ID_FILE_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO_ARSE, GRAYED + MENUITEM "&Redo\tCtrl+Y", ID_FILE_REDO_ARSE, GRAYED + MENUITEM SEPARATOR + MENUITEM "Place &sewers\tS", ID_EDIT_PLACE_SEWERS, GRAYED + MENUITEM "Place &ground\tG", ID_EDIT_PLACE_GROUND, GRAYED + MENUITEM "Place &rock\tR", ID_EDIT_PLACE_ROCK, GRAYED + MENUITEM "Place &water\tW", ID_EDIT_PLACE_WATER, GRAYED + MENUITEM "Place &hole\tH", ID_EDIT_PLACE_HOLE, GRAYED + MENUITEM "Place &entrance\tE", ID_EDIT_PLACE_ENTRANCE + , GRAYED + MENUITEM "Place gra&ting\tT", ID_EDIT_PLACE_GRATING + , GRAYED + MENUITEM "Place &prim\tP", ID_EDIT_PLACE_PRIM, GRAYED + MENUITEM "Place lad&der\tD", ID_EDIT_PLACE_LADDER, GRAYED + MENUITEM "Edit &light\tL", ID_EDIT_EDIT_LIGHT, GRAYED + END + POPUP "View" + BEGIN + MENUITEM "Sewer &engine\tCtrl+E", ID_VIEW_SEWER_ENGINE, GRAYED + MENUITEM "Sewer e&ditor\tCtrl+D", ID_VIEW_SEWER_EDITOR, GRAYED + MENUITEM "&City engine\tCtrl+C", ID_VIEW_CITY_ENGINE, GRAYED + MENUITEM SEPARATOR + MENUITEM "Show &buildings\tCtrl+B", ID_VIEW_SHOW_BUILDINGS + , GRAYED + END + POPUP "Help" + BEGIN + MENUITEM "About...", ID_HELP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 214, 124 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About Mucky Foot Shell" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,82,103,50,14 + CTEXT "Mucky Foot Shell v0.3",IDC_STATIC,55,7,105,8, + SS_CENTERIMAGE | NOT WS_GROUP + CTEXT "Copyright (c) Mucky Foot Proctions Ltd.",IDC_STATIC,31, + 84,153,8,SS_CENTERIMAGE + CONTROL 103,IDC_STATIC,"Static",SS_BITMAP,82,25,50,49 +END + +IDD_DRIVERS DIALOG DISCARDABLE 0, 0, 249, 98 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,132,77,50,14 + PUSHBUTTON "Cancel",IDCANCEL,192,77,50,14 + COMBOBOX IDC_DEVICES,47,32,195,58,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_DRIVERS,47,8,195,35,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MODES,47,56,195,40,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + LTEXT "Drivers",IDC_STATIC,8,10,23,8 + LTEXT "Devices",IDC_STATIC,8,34,26,8 + LTEXT "Modes",IDC_STATIC,8,58,22,8,SS_CENTERIMAGE +END + +IDD_CHOOSE_PRIM DIALOG DISCARDABLE 0, 0, 136, 74 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Choose prim" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,7,53,50,14 + PUSHBUTTON "Cancel",IDCANCEL,79,53,50,14 + LISTBOX IDC_PRIM_LIST,7,7,122,40,LBS_SORT | LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP +END + +IDD_MKTDRIVERS DIALOG DISCARDABLE 0, 0, 262, 126 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Urban Chaos Launch Panel" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Run Urban Chaos",IDOK,10,100,80,14 + PUSHBUTTON "Exit",IDCANCEL,185,100,65,14 + COMBOBOX IDC_MKTCOMBO_MODE,75,15,175,110,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_MKTCOMBO_CARD,75,35,175,90,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + RTEXT "Screen mode",IDC_STATIC,10,15,60,10 + RTEXT "Hardware card",IDC_STATIC,10,35,60,10 + CONTROL 103,IDC_STATIC,"Static",SS_BITMAP,105,60,67,60 +END + +IDD_TRANSFER_SETUP DIALOGEX 0, 0, 186, 46 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Transfer player" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + CONTROL "Spin2",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,95,15,10,14 + EDITTEXT IDC_EDIT1,55,15,40,14,ES_AUTOHSCROLL + LTEXT "Transfer to",IDC_STATIC,5,15,45,15,0,WS_EX_RIGHT +END + +IDD_LOCK_SETUP DIALOG DISCARDABLE 0, 0, 186, 101 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Lock/unlock vehicle" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,30,80,50,14 + EDITTEXT IDC_EDIT1,55,10,40,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,95,10,11,14 + GROUPBOX "Lock/unlock?",IDC_STATIC,10,30,165,40 + CONTROL "Locked",IDC_LOCKED,"Button",BS_AUTORADIOBUTTON,15,45,80, + 10 + CONTROL "Unlocked",IDC_UNLOCKED,"Button",BS_AUTORADIOBUTTON,15, + 55,47,10 + LTEXT "The vehicle",IDC_STATIC,10,10,50,13 + PUSHBUTTON "Cancel",IDCANCEL,95,80,50,14 +END + +IDD_RESET_SETUP DIALOG DISCARDABLE 0, 0, 186, 106 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Reset a counter" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,30,50,14 + PUSHBUTTON "Cancel",IDCANCEL,130,55,50,14 + EDITTEXT IDC_EDIT1,5,20,60,59,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,65,20,60,60 + CTEXT "Choose which counter to reset",IDC_STATIC,5,5,175,10 + CTEXT "He that resets counter 0 resets all counters!", + IDC_STATIC,5,90,175,8 +END + +IDD_STALL_SETUP DIALOG DISCARDABLE 0, 0, 177, 266 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Choose the car to stall" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,120,5,50,14 + PUSHBUTTON "Cancel",IDCANCEL,5,245,50,14 + EDITTEXT IDC_EDIT1,60,10,45,250,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,105,10,10,250 +END + +IDD_EXTEND_SETUP DIALOG DISCARDABLE 0, 0, 186, 66 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Extend timer" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + EDITTEXT IDC_EDIT1,5,10,40,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,45,10,10,14 + EDITTEXT IDC_EDIT2,5,40,40,14,ES_AUTOHSCROLL + CONTROL "Spin2",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,45,40,10,14 + LTEXT "Countdown see timer to change",IDC_STATIC,60,10,60,20 + LTEXT "How many seconds to add on",IDC_STATIC,60,40,65,20 +END + +IDD_MOVE_SETUP DIALOG DISCARDABLE 0, 0, 252, 26 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Move thing" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,140,5,50,14 + PUSHBUTTON "Cancel",IDCANCEL,195,5,50,14 + EDITTEXT IDC_EDIT1,5,5,40,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,45,5,10,14 + LTEXT "Pick the thing to move",IDC_STATIC,60,5,75,15, + SS_CENTERIMAGE +END + +IDD_PEE_SETUP DIALOG DISCARDABLE 0, 0, 62, 236 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Pee" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,5,100,50,80 + PUSHBUTTON "Cancel",IDCANCEL,5,185,50,45 + CTEXT "The waypoint creating the person who is going to pee", + IDC_STATIC,5,5,50,35 + EDITTEXT IDC_EDIT1,10,45,40,20,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,10,70,40,20 +END + +IDD_SIGN_SETUP DIALOG DISCARDABLE 0, 0, 192, 201 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Signs..." +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,135,10,50,14 + PUSHBUTTON "Cancel",IDCANCEL,135,30,50,14 + GROUPBOX "Choose your sign",IDC_STATIC,5,5,110,190 + CONTROL 193,IDC_STATIC,"Static",SS_BITMAP,10,15,20,20 + CONTROL 195,IDC_STATIC,"Static",SS_BITMAP,10,60,20,20 + CONTROL 196,IDC_STATIC,"Static",SS_BITMAP,10,105,20,20 + CONTROL 197,IDC_STATIC,"Static",SS_BITMAP,10,150,20,20 + CONTROL "Ahead",IDC_AHEAD,"Button",BS_AUTORADIOBUTTON,60,30,37, + 10 + CONTROL "Stop",IDC_STOP,"Button",BS_AUTORADIOBUTTON,60,75,31,10 + CONTROL "Right turn",IDC_RIGHT_TURN,"Button",BS_AUTORADIOBUTTON, + 60,120,47,10 + CONTROL "U-Turn",IDC_UTURN,"Button",BS_AUTORADIOBUTTON,60,165,38, + 10 + CONTROL "Flip left/right",IDC_FLIP_LEFT_RIGHT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,125,165,55,10 + CONTROL "Flip top/bottom",IDC_FLIP_TOP_BOTTOM,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,125,180,63,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 207 + TOPMARGIN, 7 + BOTTOMMARGIN, 117 + END + + IDD_DRIVERS, DIALOG + BEGIN + LEFTMARGIN, 8 + RIGHTMARGIN, 242 + VERTGUIDE, 47 + TOPMARGIN, 8 + BOTTOMMARGIN, 91 + HORZGUIDE, 32 + HORZGUIDE, 56 + END + + IDD_CHOOSE_PRIM, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 129 + TOPMARGIN, 7 + BOTTOMMARGIN, 67 + END + + IDD_MKTDRIVERS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 255 + TOPMARGIN, 7 + BOTTOMMARGIN, 119 + END + + IDD_TRANSFER_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 39 + END + + IDD_LOCK_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 94 + END + + IDD_RESET_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END + + IDD_STALL_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 259 + END + + IDD_EXTEND_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 59 + END + + IDD_MOVE_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 245 + TOPMARGIN, 7 + BOTTOMMARGIN, 19 + END + + IDD_PEE_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 55 + TOPMARGIN, 7 + BOTTOMMARGIN, 229 + END + + IDD_SIGN_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 185 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_LEDIT_ACCELERATOR ACCELERATORS DISCARDABLE +BEGIN + "A", ID_EDIT_SETAMBIENT, VIRTKEY, NOINVERT + "E", ID_EDIT_EDITLIGHTS, VIRTKEY, NOINVERT + "I", ID_EDIT_INSIDES, VIRTKEY, NOINVERT + "K", ID_EDIT_SETSKYCOLOUR, VIRTKEY, NOINVERT + "L", ID_EDIT_SETLAMPOSTCOLOUR, VIRTKEY, NOINVERT + "L", ID_FILE_LOAD_ARSE, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPEN_ARSE, VIRTKEY, CONTROL, NOINVERT + "P", ID_EDIT_PLACELIGHT, VIRTKEY, NOINVERT + "Q", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT + "S", ID_FILE_SAVE_ARSE, VIRTKEY, CONTROL, NOINVERT + VK_BACK, ID_EDIT_DELETE_ARSE, VIRTKEY, NOINVERT + "Y", ID_EDIT_REDO_ARSE, VIRTKEY, CONTROL, NOINVERT + "Z", ID_EDIT_UNDO_ARSE, VIRTKEY, CONTROL, NOINVERT +END + +IDR_SEDIT_ACCELERATOR ACCELERATORS DISCARDABLE +BEGIN + "B", ID_VIEW_SHOW_BUILDINGS, VIRTKEY, CONTROL, NOINVERT + "C", ID_VIEW_CITY_ENGINE, VIRTKEY, CONTROL, NOINVERT + "D", ID_EDIT_PLACE_LADDER, VIRTKEY, NOINVERT + "D", ID_VIEW_SEWER_EDITOR, VIRTKEY, CONTROL, NOINVERT + "E", ID_EDIT_PLACE_ENTRANCE, VIRTKEY, NOINVERT + "E", ID_VIEW_SEWER_ENGINE, VIRTKEY, CONTROL, NOINVERT + "G", ID_EDIT_PLACE_GROUND, VIRTKEY, NOINVERT + "H", ID_EDIT_PLACE_HOLE, VIRTKEY, NOINVERT + "L", ID_EDIT_EDIT_LIGHT, VIRTKEY, NOINVERT + "L", ID_FILE_LOAD_SEWERS, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT + "P", ID_EDIT_PLACE_PRIM, VIRTKEY, NOINVERT + "Q", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT + "R", ID_EDIT_PLACE_ROCK, VIRTKEY, NOINVERT + "S", ID_EDIT_PLACE_SEWERS, VIRTKEY, NOINVERT + "S", ID_FILE_SAVE_SEWERS, VIRTKEY, CONTROL, NOINVERT + "T", ID_EDIT_PLACE_GRATING, VIRTKEY, NOINVERT + "W", ID_EDIT_PLACE_WATER, VIRTKEY, NOINVERT + "Y", ID_EDIT_REDO_ARSE, VIRTKEY, CONTROL, NOINVERT + "Z", ID_EDIT_UNDO_ARSE, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +IDC_POINTER_DRAGDROP CURSOR DISCARDABLE "arrowcop.cur" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_AHEAD BITMAP DISCARDABLE "ahead.bmp" +IDB_STOP BITMAP DISCARDABLE "stop.bmp" +IDB_RIGHTTURN BITMAP DISCARDABLE "rightturn.bmp" +IDB_BITMAP4 BITMAP DISCARDABLE "uturn.BMP" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON2 ICON DISCARDABLE "icon2.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_GEDIT_MENU MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New Workspace\tCtrl+N", ID_FILE_NEW_WS + MENUITEM "&Open Workspace...\tCtrl+O", ID_FILE_OPEN_WS + MENUITEM "&Close Workspace", ID_FILE_CLOSE_WS + MENUITEM SEPARATOR + MENUITEM "&Save Workspace\tCtrl+S", ID_FILE_SAVE_WS + MENUITEM "Save Workspace &As...", ID_FILE_SAVE_WS_AS + MENUITEM SEPARATOR + MENUITEM "E&xit editor\tCtrl+X", ID_FILE_EXIT + MENUITEM "&Quit fallen\tCtrl+Q", ID_FILE_EXITALL + END +END + +IDR_GEDIT_POPUPS MENU DISCARDABLE +BEGIN + POPUP "WorkspaceRoot" + BEGIN + MENUITEM "&Add Map to Workspace...", ID_WORKSPACEROOT_ADD + MENUITEM "&Refresh All Missions...", ID_WORKSPACEROOT_REFRESH + END + POPUP "MapRoot" + BEGIN + MENUITEM "Ne&w Mission...", ID_MAPROOT_NEWMISSION + MENUITEM "Import Mission...", ID_MAPROOT_IMPORTMISSION + MENUITEM SEPARATOR + MENUITEM "Count Prims...", ID_MAPROOT_COUNTPRIMS + MENUITEM "Reset Prims...", ID_MAPROOT_RESETPRIMS + MENUITEM "Save Prims...", ID_MAPROOT_SAVEPRIMS + MENUITEM SEPARATOR + MENUITEM "Delete Map...", ID_MAPROOT_DELETEMAP + END + POPUP "MissionRoot" + BEGIN + MENUITEM "Set Mission &Brief...", ID_MISSIONROOT_ADDMISSIONBRIEF + + MENUITEM "Set Light &Map...", ID_MISSIONROOT_ADDLIGHTMAP + MENUITEM "Set &Citsez text...", ID_MISSIONROOT_ADDSEWERMAP + MENUITEM "Set Default Skills...", ID_MISSIONROOT_SETDEFAULTSKILLS + + MENUITEM "Set Crime Rate...", ID_MISSIONROOT_SETCRIMERATE + MENUITEM "Set Fake Wandering People...", + ID_MISSIONROOT_SETCIVVYCOUNT + MENUITEM "Set Wandering Cars...", ID_MISSIONROOT_SETCARSCOUNT + MENUITEM "Set Music World...", ID_MISSIONROOT_SETMUSICWORLD + MENUITEM "Set Crime Rate Visible/Invisible", + ID_MISSIONROOT_CRIMERATE_VISIBILITY + + MENUITEM "Set Boredom Level...", ID_MISSIONROOT_BOREDOM + MENUITEM "Set Car Collision With Road Prims", + ID_MISSIONROOT_SETCARCOLLISIONWITHROADPRIMS + + MENUITEM SEPARATOR + MENUITEM "Delete Extra Wandering Civs...", ID_MISSIONROOT_DELETECIVS + MENUITEM "Delete Extra Wandering Cars...", ID_MISSIONROOT_DELETECARS + MENUITEM "Delete Mission", ID_MISSIONROOT_DELETEMISSION + MENUITEM SEPARATOR + MENUITEM "Show Mission Info", ID_MISSIONROOT_SHOWMISSIONINFO + + MENUITEM "Validate Mission", ID_MISSIONROOT_VALIDATEMISSION + + MENUITEM "Export Mission", ID_MISSIONROOT_EXPORTMISSION + MENUITEM "Refresh Mission from disk...", + ID_MISSIONROOT_REFRESHMISSION + + END + POPUP "EventPointRoot" + BEGIN + MENUITEM "Properties...", ID_EVENTPOINTROOT_PROPERTIES + POPUP "Waypoint Type" + BEGIN + MENUITEM "Normal", ID_EVENTPOINTROOT_NORMAL + , CHECKED + MENUITEM "Inside", ID_EVENTPOINTROOT_INSIDE + MENUITEM "Warehouse", ID_EVENTPOINTROOT_WARE + END + MENUITEM SEPARATOR + POPUP "Dependency" + BEGIN + MENUITEM "Start Link", ID_EVENTPOINTROOT_DEPENDENCY_LINK + + MENUITEM "Cancel", ID_EVENTPOINTROOT_DEPENDENCY_CANCEL + , GRAYED + END + MENUITEM SEPARATOR + MENUITEM "Copy Waypoint", ID_EVENTPOINTROOT_COPYWAYPOINT + + MENUITEM "Delete Waypoint", ID_EVENTPOINTROOT_DELETEWAYPOINT + + MENUITEM SEPARATOR + MENUITEM "Renumber waypoint lower", ID_EVENTPOINTROOT_RENUMBERWAYPOINTLOWER + + MENUITEM "Magic Number...", ID_EVENTPOINTROOT_MAGICNUMBER + + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MISSION_EDITOR DIALOGEX 0, 0, 578, 441 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_NOFAILCREATE | WS_MINIMIZEBOX | + WS_CAPTION | WS_SYSMENU +CAPTION "Mission Editor" +MENU IDR_GEDIT_MENU +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "Custom1",IDC_MAP_VIEW,"Map View",0x0,145,5,426,296, + WS_EX_STATICEDGE + CONTROL "Tree1",IDC_WORKSPACE_TREE,"SysTreeView32", + TVS_HASBUTTONS | TVS_HASLINES | WS_BORDER,5,10,130,290, + WS_EX_CLIENTEDGE + GROUPBOX "Workspace",IDC_STATIC,0,0,140,435 + LTEXT "Visible Waypoint Types:",IDC_STATIC,7,306,76,8 + CONTROL "Simple",IDC_CHECK_1,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,317,37,10 + CONTROL "Player",IDC_CHECK_2,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,327,35,10 + CONTROL "Enemies",IDC_CHECK_3,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,337,43,10 + CONTROL "Items",IDC_CHECK_4,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,347,33,10 + CONTROL "Sound Effects",IDC_CHECK_5,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,357,61,10 + CONTROL "Visual Effects",IDC_CHECK_6,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,367,59,10 + CONTROL "Cut Scenes",IDC_CHECK_7,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,377,53,10 + CONTROL "Messages",IDC_CHECK_8,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,387,48,10 + CONTROL "Custom1",IDC_CUSTOM_1,"BUTTON_CLASS0",0x0,156,390,15,10, + WS_EX_STATICEDGE + CONTROL "Custom1",IDC_CUSTOM_2,"BUTTON_CLASS1",0x0,176,390,15,10, + WS_EX_STATICEDGE + CONTROL "Custom1",IDC_CUSTOM_3,"BUTTON_CLASS2",0x0,196,390,15,10, + WS_EX_STATICEDGE + CONTROL "Custom1",IDC_CUSTOM_4,"BUTTON_CLASS3",0x0,216,390,15,10, + WS_EX_STATICEDGE + CONTROL "Custom1",IDC_CUSTOM_5,"BUTTON_CLASS4",0x0,236,390,15,10, + WS_EX_STATICEDGE + CONTROL "Custom1",IDC_CUSTOM_6,"BUTTON_CLASS5",0x0,256,390,15,10, + WS_EX_STATICEDGE + CONTROL "Custom1",IDC_CUSTOM_7,"BUTTON_CLASS6",0x0,276,390,15,10, + WS_EX_STATICEDGE + CONTROL "Custom1",IDC_CUSTOM_8,"BUTTON_CLASS7",0x0,296,390,15,10, + WS_EX_STATICEDGE + GROUPBOX "Waypoint Info",IDC_WAYPOINT_GROUP,145,305,192,130 + LTEXT "Group:",IDC_STATIC,150,406,22,8 + LTEXT "Colour:",IDC_STATIC,150,380,23,8 + COMBOBOX IDC_COMBO1,155,330,90,160,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Waypoint Type:",IDC_STATIC,150,320,51,8 + EDITTEXT IDC_EDIT1,156,414,25,14,ES_UPPERCASE | ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_WRAP | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY,180,414,11,14 + EDITTEXT IDC_EDIT2,430,320,40,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin2",IDC_SPIN2,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_NOTHOUSANDS,440,320,11,14 + EDITTEXT IDC_EDIT3,155,360,40,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin3",IDC_SPIN3,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS,195,360,11,14 + LTEXT "On Trigger:",IDC_STATIC,355,345,36,8 + COMBOBOX IDC_COMBO2,361,355,90,95,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_EDIT4,455,355,40,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN4,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_NOTHOUSANDS,465,355,11,14 + CONTROL "Proximity Trigger:",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,355,320,69,10 + LTEXT "Dependency:",IDC_STATIC,150,350,44,8 + GROUPBOX "Trigger Info",IDC_STATIC,345,304,165,130 + LTEXT "Draw Trigger Lines:",IDC_STATIC,7,398,62,8 + COMBOBOX IDC_COMBO4,7,410,126,63,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP +END + +IDD_NEWMISSION DIALOG DISCARDABLE 0, 0, 214, 57 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Mission" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "OK",IDOK,157,7,50,14,WS_DISABLED + PUSHBUTTON "Cancel",IDCANCEL,157,24,50,14 + EDITTEXT IDC_EDIT_MNAME,7,21,106,13,ES_AUTOHSCROLL + LTEXT "Mission Name:",IDC_STATIC,8,8,95,13 +END + +IDD_PLAYER_SETUP DIALOG DISCARDABLE 0, 0, 177, 238 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Player Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,64,217,50,14 + CONTROL "List1",IDC_LIST1,"SysListView32",WS_BORDER | WS_TABSTOP, + 16,87,145,123 + LTEXT "Inventory:",IDC_STATIC,5,76,32,8 + LTEXT "Player Type:",IDC_STATIC,5,10,40,8 + CONTROL "No Equipment",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,99,20,71,10 + COMBOBOX IDC_COMBO1,13,22,84,79,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +END + +IDD_ENEMY_SETUP DIALOG DISCARDABLE 0, 0, 302, 326 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Enemy Setup" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Enemy Type:",IDC_STATIC,5,5,42,8 + COMBOBOX IDC_COMBO1,12,15,85,209,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "X",IDC_STATIC,105,17,8,8 + EDITTEXT IDC_EDIT1,115,15,25,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS,140,15,11,14 + LTEXT "Constitution:",IDC_STATIC,5,30,40,8 + EDITTEXT IDC_EDIT2,17,40,63,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin2",IDC_SPIN2,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS | UDS_NOTHOUSANDS,80,40,11,14 + LTEXT "Behaviour:",IDC_STATIC,95,30,35,8 + COMBOBOX IDC_COMBO4,106,40,74,209,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Movement:",IDC_STATIC,7,58,36,8 + COMBOBOX IDC_COMBO2,17,69,74,209,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Flags:",IDC_STATIC,95,58,20,8 + LISTBOX IDC_LIST3,106,68,74,44,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + LTEXT "Target:",IDC_STATIC_ADJUST,7,86,24,8,NOT WS_VISIBLE + EDITTEXT IDC_EDIT3,17,97,63,14,ES_AUTOHSCROLL | ES_NUMBER | NOT + WS_VISIBLE + CONTROL "Spin2",IDC_SPIN3,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS | UDS_NOTHOUSANDS | NOT WS_VISIBLE,80,97, + 11,14 + DEFPUSHBUTTON "OK",IDOK,65,305,50,14 + LTEXT "Guard:",IDC_STATIC_ADJUST2,7,114,22,8,WS_DISABLED + EDITTEXT IDC_EDIT4,17,124,63,14,ES_AUTOHSCROLL | ES_NUMBER | + WS_DISABLED + CONTROL "Spin2",IDC_SPIN4,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS | UDS_NOTHOUSANDS | WS_DISABLED,80,124,11, + 14 + GROUPBOX "Bounty",IDC_STATIC,7,155,173,79 + LISTBOX IDC_LIST1,17,172,73,55,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + LISTBOX IDC_LIST2,97,172,73,55,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + LTEXT "Weapons:",IDC_STATIC,17,163,34,8 + LTEXT "Other:",IDC_STATIC,97,163,20,8 + EDITTEXT IDC_EDIT5,106,124,63,14,ES_AUTOHSCROLL | ES_NUMBER | + WS_DISABLED + CONTROL "Spin2",IDC_SPIN5,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS | UDS_NOTHOUSANDS | WS_DISABLED,169,124,11, + 14 + LTEXT "Follow:",IDC_STATIC_ADJUST3,97,116,23,8,WS_DISABLED + LTEXT "Fighting Ability:",IDC_STATIC_ADJUST4,55,143,48,8 + COMBOBOX IDC_COMBO3,106,141,74,86,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "What this person has",IDC_STATIC,10,240,68,8 + CONTROL "Pistol",IDC_HAS_PISTOL,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,10,250,65,10 + CONTROL "Shotgun",IDC_HAS_SHOTGUN,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,10,260,75,10 + CONTROL "AK47",IDC_HAS_AK47,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,10,270,80,10 + CONTROL "Grenade",IDC_HAS_GRENADE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,10,280,65,10 + CONTROL "Balloon",IDC_HAS_BALLOON,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,10,290,65,10 + CONTROL "Knife",IDC_KNIFE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 98,265,32,10 + CONTROL "BaseBallBat",IDC_BAT,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,97,276,54,10 + GROUPBOX "What can kill me",IDC_STATIC,195,100,90,90 + CONTROL "Slide",IDC_WITH_SLIDE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,115,65,10 + CONTROL "Combo PPP",IDC_WITH_COMBO_PPP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,125,65,10 + CONTROL "Combo KKK",IDC_WITH_COMBO_KKK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,135,65,10 + CONTROL "Any combo",IDC_WITH_COMBO_ANY,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,145,65,10 + CONTROL "Grapple throw or kick",IDC_WITH_GRAPPLE_ATTACK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,200,154,85,10 + CONTROL "Side kick",IDC_WITH_SIDE_KICK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,165,65,10 + CONTROL "Back kick",IDC_WITH_BACK_KICK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,200,175,65,10 + CONTROL 103,IDC_STATIC,"Static",SS_BITMAP,185,250,67,60 + LTEXT "(Only for fight test dummies)",IDC_STATIC,195,195,95,8 +END + +IDD_ITEM_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Item" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + COMBOBOX IDC_COMBO1,15,15,85,205,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + LTEXT "Item Type:",IDC_STATIC,5,5,34,8 + LTEXT "X",IDC_STATIC,105,17,8,8 + EDITTEXT IDC_EDIT1,115,15,25,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS,141,15,11,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + COMBOBOX IDC_COMBO2,47,149,105,205,CBS_DROPDOWN | NOT WS_VISIBLE | + WS_DISABLED | WS_VSCROLL | WS_TABSTOP + RTEXT "Container:",IDC_STATIC,7,149,34,12,SS_CENTERIMAGE | NOT + WS_VISIBLE | WS_DISABLED + LTEXT "Flags:",IDC_STATIC,7,37,20,8 + LISTBOX IDC_LIST1,47,37,105,81,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP +END + +IDD_TRIGGER_SETUP DIALOG DISCARDABLE 0, 0, 186, 121 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Trigger Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,100,50,14 + COMBOBOX IDC_COMBO1,15,15,85,188,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Trigger Type:",IDC_STATIC,5,5,43,8 + LTEXT "Action Trigger On:",IDC_STATIC,5,40,58,8 + COMBOBOX IDC_COMBO3,15,50,85,121,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Action Trigger Off:",IDC_STATIC,5,70,58,8 + COMBOBOX IDC_COMBO4,15,80,85,98,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP +END + +IDD_MESSAGE_SETUP DIALOG DISCARDABLE 0, 0, 187, 146 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Message Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,69,125,50,14 + EDITTEXT IDC_EDIT1,10,15,165,40,ES_MULTILINE | ES_AUTOVSCROLL + LTEXT "Message:",IDC_STATIC,5,5,32,8 + LTEXT "Delay:",IDC_STATIC,7,60,21,14,SS_CENTERIMAGE + EDITTEXT IDC_EDIT2,36,60,81,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,117,60,11,14 + LTEXT "seconds.",IDC_STATIC,140,60,35,14,SS_CENTERIMAGE + COMBOBOX IDC_COMBO1,37,88,91,78,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + LTEXT "Said by:",IDC_STATIC,7,86,24,14,SS_CENTERIMAGE +END + +IDD_VEHICLE_SETUP DIALOG DISCARDABLE 0, 0, 186, 129 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Vehicle Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,67,108,50,14 + LTEXT "Vehicle Type:",IDC_STATIC,5,5,44,8 + COMBOBOX IDC_COMBO1,15,15,85,118,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Vehicle Behaviour:",IDC_STATIC,7,34,60,8 + COMBOBOX IDC_COMBO2,14,45,85,118,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Vehicle Target:",IDC_LABEL1,7,63,49,8,WS_DISABLED + COMBOBOX IDC_COMBO3,14,76,85,118,CBS_DROPDOWNLIST | WS_DISABLED | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO4,109,45,70,118,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Vehicle Key:",IDC_STATIC,103,34,40,8 +END + +IDD_CREATURE_SETUP DIALOG DISCARDABLE 0, 0, 186, 76 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Vehicle Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,67,55,50,14 + LTEXT "Creature Type:",IDC_STATIC,5,5,48,8 + COMBOBOX IDC_COMBO1,15,15,85,118,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "X",IDC_STATIC,105,17,8,8 + EDITTEXT IDC_EDIT1,115,15,25,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS,140,15,11,14 +END + +IDD_CAMERA_TARGET_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Camera Target" +FONT 8, "MS Sans Serif" +BEGIN + RTEXT "Motion:",IDC_STATIC,7,7,28,8 + COMBOBOX IDC_COMBO1,49,7,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Style:",IDC_STATIC,7,27,28,8 + COMBOBOX IDC_COMBO2,49,25,103,68,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Speed:",IDC_STATIC,7,47,28,8 + EDITTEXT IDC_EDIT1,49,47,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,142,47,10,14 + RTEXT "Delay:",IDC_STATIC,7,67,28,8 + EDITTEXT IDC_EDIT2,49,67,92,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,142,67,11,14 + RTEXT "Zoom:",IDC_STATIC,7,87,28,8 + EDITTEXT IDC_EDIT3,49,87,92,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,87,11,14 + CONTROL "Auto-Rotate",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,49,107,103,10 + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 +END + +IDD_CAMERA_SETUP DIALOG DISCARDABLE 0, 0, 172, 191 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Camera" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,60,167,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,167,50,14 + RTEXT "Motion:",IDC_STATIC,25,5,28,8 + RTEXT "Style:",IDC_STATIC,25,25,28,8 + COMBOBOX IDC_COMBO1,62,5,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_COMBO2,62,23,103,68,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_EDIT1,62,44,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,155,44,11,14 + RTEXT "Speed:",IDC_STATIC,25,44,28,8 + EDITTEXT IDC_EDIT2,62,65,92,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,155,65,11,14 + RTEXT "Delay:",IDC_STATIC,25,65,28,8 + CONTROL "Stop Player",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + BS_LEFTTEXT | WS_TABSTOP,20,85,50,10 + CONTROL "Lock Direction",IDC_LOCK_DIRECTION,"Button", + BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,5,100,64,10 + CONTROL "Can't Interrupt",IDC_CANT_INTERRUPT,"Button", + BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,116,62,10 +END + +IDD_MISSION_EDITOR2 DIALOGEX 0, 0, 578, 441 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_NOFAILCREATE | WS_MINIMIZEBOX | + WS_CAPTION | WS_SYSMENU +CAPTION "Mission Editor" +MENU IDR_GEDIT_MENU +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "Custom1",IDC_MAP_VIEW,"Map View",0x0,145,5,426,296, + WS_EX_STATICEDGE + CONTROL "Tree1",IDC_WORKSPACE_TREE,"SysTreeView32", + TVS_HASBUTTONS | TVS_HASLINES | WS_BORDER,5,10,130,264, + WS_EX_CLIENTEDGE + GROUPBOX "Workspace",-1,0,0,140,435 + LTEXT "Visible Waypoint Types:",-1,7,303,76,8 + COMBOBOX IDC_COMBO4,7,410,128,63,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "Tab5",IDC_TAB1,"SysTabControl32",0x0,303,309,231,125 + LISTBOX IDC_LIST1,7,317,128,86,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + LTEXT "",IDC_STATIC_TRAY,7,279,55,22 + CONTROL "Tree1",IDC_WORKSPACE_TREE2,"SysTreeView32",TVS_HASLINES | + TVS_SHOWSELALWAYS | TVS_SINGLEEXPAND | WS_BORDER,145,311, + 150,123,WS_EX_CLIENTEDGE + COMBOBOX IDC_COMBO1,68,278,67,68,CBS_DROPDOWNLIST | + CBS_OWNERDRAWFIXED | NOT WS_VISIBLE | WS_VSCROLL | + WS_TABSTOP + CONTROL "Warehouse",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | NOT WS_VISIBLE | WS_TABSTOP,68,279,42,11 + CONTROL "PSX",IDC_NOPSX_BUTTON,"Button",BS_AUTOCHECKBOX | + BS_PUSHLIKE | NOT WS_VISIBLE | WS_TABSTOP,113,279,22,11 +END + +IDD_EVENTTAB_CONDITION DIALOG DISCARDABLE 0, 0, 227, 104 +STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN +FONT 8, "MS Sans Serif" +BEGIN + COMBOBOX IDC_COMBO1,7,7,218,95,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Dependency:",IDC_STATIC_DEPEND1,7,27,42,12, + SS_CENTERIMAGE | WS_DISABLED + EDITTEXT IDC_EDIT1,57,27,79,12,ES_AUTOHSCROLL | ES_NUMBER | + WS_DISABLED + CONTROL "Spin2",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | WS_DISABLED,137,27,11,12 + PUSHBUTTON "Point to it...",IDC_BUTTON1,154,27,71,12,WS_DISABLED + RTEXT "Boolean:",IDC_STATIC_DEPEND2,7,47,42,12,SS_CENTERIMAGE | + WS_DISABLED + EDITTEXT IDC_EDIT2,57,47,79,12,ES_AUTOHSCROLL | ES_NUMBER | + WS_DISABLED + CONTROL "Spin2",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | WS_DISABLED,136,47,12,12 + PUSHBUTTON "Point to it...",IDC_BUTTON2,154,47,71,12,WS_DISABLED + RTEXT "Time:",IDC_STATIC_TIME,27,67,22,12,SS_CENTERIMAGE | + WS_DISABLED + EDITTEXT IDC_EDIT3,57,67,50,12,ES_AUTOHSCROLL | ES_NUMBER | + WS_DISABLED + CONTROL "Spin2",IDC_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | WS_DISABLED,107,67,11,12 + RTEXT "Radius:",IDC_STATIC_RADIUS,123,67,32,12,SS_CENTERIMAGE | + WS_DISABLED + EDITTEXT IDC_EDIT4,163,67,50,12,ES_AUTOHSCROLL | ES_NUMBER | + WS_DISABLED + CONTROL "Spin2",IDC_SPIN4,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | WS_DISABLED,214,67,11,12 + RTEXT "Listen for:",IDC_STATIC_LISTEN,7,87,42,15, + SS_CENTERIMAGE | WS_DISABLED + EDITTEXT IDC_EDIT5,57,87,50,15,ES_AUTOHSCROLL | WS_DISABLED + CONTROL "Invert result",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + BS_LEFTTEXT | WS_TABSTOP,118,87,53,15 + CONTROL "optional",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | + BS_LEFTTEXT | WS_TABSTOP,183,87,42,15 +END + +IDD_EVENTTAB_ACTION DIALOGEX 0, 0, 227, 104 +STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN +EXSTYLE WS_EX_NOPARENTNOTIFY +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_COMBO1,7,7,218,89,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Properties...",IDC_BUTTON1,7,27,50,12,WS_DISABLED + LTEXT "-",IDC_STATIC_LABEL,67,27,158,12,SS_CENTERIMAGE + RTEXT "Stay active?",IDC_STATIC,7,47,42,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO2,57,47,168,61,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Delay:",IDC_STATIC_DELAY,7,67,42,12,SS_CENTERIMAGE | + WS_DISABLED + EDITTEXT IDC_EDIT1,57,67,80,12,ES_AUTOHSCROLL | WS_DISABLED + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | WS_DISABLED,137,67,11,12 +END + +IDD_EVENTTAB_INFO DIALOG DISCARDABLE 0, 0, 227, 102 +STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "-",IDC_STATIC_INFO,7,47,218,55,SS_SUNKEN + COMBOBOX IDC_COMBO2,177,7,48,111,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_COMBO1,57,7,80,111,CBS_DROPDOWNLIST | + CBS_OWNERDRAWFIXED | WS_VSCROLL | WS_TABSTOP + RTEXT "Colour:",IDC_STATIC,7,7,42,12,SS_CENTERIMAGE + RTEXT "Group:",IDC_STATIC,144,7,29,12,SS_CENTERIMAGE + LTEXT "Height:",IDC_STATIC,25,27,24,8 + EDITTEXT IDC_EDIT1,57,27,69,12,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_NOTHOUSANDS,126,27,11,12 +END + +IDD_MAPEXIT_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Map Exit" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + RTEXT "Mission:",-1,7,7,33,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO1,49,7,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP +END + +IDD_INPUT_BOX DIALOG DISCARDABLE 0, 0, 286, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Generic Input Box" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Generic Input Box Prompt:",IDC_STATIC_PROMPT,7,7,149,8 + EDITTEXT IDC_EDIT1,7,22,272,45,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,84,74,50,14 + PUSHBUTTON "Cancel",IDCANCEL,151,74,50,14 +END + +IDD_ACTIVATE_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Activate Prim" +FONT 8, "MS Sans Serif" +BEGIN + RTEXT "Type:",-1,7,7,28,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO1,49,7,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Anim:",IDC_STATIC_ANIM,7,27,28,12,SS_CENTERIMAGE | NOT + WS_VISIBLE + EDITTEXT IDC_EDIT1,49,27,92,12,ES_AUTOHSCROLL | NOT WS_VISIBLE + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | NOT WS_VISIBLE,141,27,11,12 + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 +END + +IDD_VEFFECT_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Visual Effect" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + RTEXT "Effects:",IDC_STATIC,7,7,35,12,SS_CENTERIMAGE + LISTBOX IDC_LIST1,48,7,104,60,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + RTEXT "Scale:",IDC_STATIC,7,77,35,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT1,48,77,94,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_NOTHOUSANDS,142,77,11,14 +END + +IDD_TRAP_SETUP DIALOG DISCARDABLE 0, 0, 159, 201 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Trap" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,180,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,180,50,14 + RTEXT "Effect:",IDC_STATIC,7,7,28,8 + COMBOBOX IDC_COMBO1,49,7,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_EDIT1,49,27,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,27,11,14 + RTEXT "Speed:",IDC_STATIC,7,27,28,8 + EDITTEXT IDC_EDIT2,49,47,92,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,47,11,14 + RTEXT "Steps:",IDC_STATIC,7,47,28,8 + RTEXT "Timing:",IDC_STATIC,7,67,28,8 + LISTBOX IDC_LIST1,49,67,103,54,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + RTEXT "Axis:",IDC_STATIC,7,127,28,8 + COMBOBOX IDC_COMBO2,49,127,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + RTEXT "Range:",IDC_STATIC,7,147,28,8 + EDITTEXT IDC_EDIT3,49,147,92,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,147,11,14 +END + +IDD_PLATFORM_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Platform" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + RTEXT "Motion:",IDC_STATIC,7,27,28,8 + EDITTEXT IDC_EDIT1,49,7,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,7,11,14 + RTEXT "Speed:",IDC_STATIC,7,7,28,8 + LISTBOX IDC_LIST1,49,26,103,61,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP +END + +IDD_WAYPOINT_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Waypoint" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + EDITTEXT IDC_EDIT1,49,7,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,7,11,14 + RTEXT "Delay:",IDC_STATIC,7,7,28,8 + RTEXT "(in 1/10th's of a second)",IDC_STATIC,7,27,145,8 +END + +IDD_BOMB_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Bomb" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + COMBOBOX IDC_COMBO1,47,7,105,205,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Type:",IDC_STATIC,8,7,30,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT1,47,27,93,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS,141,27,11,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + RTEXT "Strength:",IDC_STATIC,7,27,31,12,SS_CENTERIMAGE + RTEXT "Explosion:",IDC_STATIC,7,47,31,12,SS_CENTERIMAGE + LISTBOX IDC_LIST1,47,47,105,67,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP +END + +IDD_BURN_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Burning Prim" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + RTEXT "Style:",-1,7,7,31,12,SS_CENTERIMAGE + LISTBOX IDC_LIST1,47,7,105,67,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP +END + +IDD_SEFFECT_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Sound Effect" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + RTEXT "Type:",IDC_STATIC,7,7,35,12,SS_CENTERIMAGE + RTEXT "Sound:",IDC_STATIC,7,27,35,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO1,48,7,104,65,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LISTBOX IDC_LIST1,48,27,104,83,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Play",IDC_BUTTON1,48,113,49,14 + PUSHBUTTON "Stop",IDC_BUTTON2,103,113,49,14 +END + +IDD_SPOTFX_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Spot Effect" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + RTEXT "Effect:",IDC_STATIC,7,7,35,12,SS_CENTERIMAGE + LISTBOX IDC_LIST1,48,7,104,60,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + RTEXT "Param:",IDC_STATIC,7,77,35,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT1,48,77,94,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_NOTHOUSANDS,142,77,11,14 +END + +IDD_SET_SKILLS DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Set Default Skills" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + COMBOBOX IDC_COMBO1,47,7,105,106,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LISTBOX IDC_LIST1,47,31,105,128,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + LTEXT "AI Type:",IDC_STATIC,7,7,40,8 + LTEXT "Skill Level:",IDC_STATIC,7,31,40,8 +END + +IDD_BARREL_SETUP DIALOG DISCARDABLE 0, 0, 159, 201 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Barrel-O-Tronic" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,180,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,180,50,14 + RTEXT "Type:",-1,7,7,28,8 + COMBOBOX IDC_COMBO1,49,7,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP +END + +IDD_WAYPOINT_PICKER DIALOG DISCARDABLE 0, 0, 159, 201 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Pick Waypoint" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,180,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,180,50,14 + RTEXT "Waypoint:",IDC_STATIC,7,10,35,8 + EDITTEXT IDC_EDIT1,49,7,51,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,101,7,11, + 14 +END + +IDD_TREASURE_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Treasure" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + EDITTEXT IDC_EDIT1,49,7,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,7,11,14 + RTEXT "Score:",-1,7,7,28,8 +END + +IDD_BONUS_SETUP DIALOG DISCARDABLE 0, 0, 187, 178 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Bonus Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,69,157,50,14 + EDITTEXT IDC_EDIT1,7,15,173,40,ES_MULTILINE | ES_AUTOVSCROLL + LTEXT "Message:",IDC_STATIC,5,5,32,8 + LTEXT "points:",IDC_STATIC,111,60,21,14,SS_CENTERIMAGE + EDITTEXT IDC_EDIT2,7,60,87,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,94,60,11,14 + COMBOBOX IDC_COMBO1,7,84,87,87,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + LTEXT "To help the foreign language translators, is this being", + IDC_STATIC,7,106,166,8 + LTEXT "said by a:",IDC_STATIC,7,116,31,8 + CONTROL "Male",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,63,116,31, + 10 + CONTROL "Female",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,63,128, + 39,10 +END + +IDD_CONVERSATION_SETUP DIALOG DISCARDABLE 0, 0, 187, 165 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Conversation Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,69,144,50,14 + EDITTEXT IDC_EDIT1,10,15,165,40,ES_MULTILINE | ES_AUTOVSCROLL + LTEXT "Conversation:",IDC_STATIC,5,5,44,8 + COMBOBOX IDC_COMBO1,75,60,105,78,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Person 1:",IDC_STATIC,7,60,60,13,SS_CENTERIMAGE + RTEXT "Person 2:",IDC_STATIC,7,88,60,14,SS_CENTERIMAGE + COMBOBOX IDC_COMBO2,75,88,105,86,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + CONTROL "Don't grab the camera",IDC_GRAB_CAMERA,"Button", + BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,52,114,86,10 +END + +IDD_COUNTER_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Counter Increment" +FONT 8, "MS Sans Serif" +BEGIN + RTEXT "Counter:",-1,7,7,31,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT2,47,7,93,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN2,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS,141,7,11,14 + RTEXT "Adjust by:",-1,7,27,31,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT1,47,27,93,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS,141,27,11,14 + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 +END + +IDD_DLIGHT_SETUP DIALOG DISCARDABLE 0, 0, 159, 201 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Dynamic Lighting FX" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,180,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,180,50,14 + RTEXT "Effect:",IDC_STATIC,7,7,28,8 + COMBOBOX IDC_COMBO1,49,7,103,54,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + EDITTEXT IDC_EDIT1,49,27,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,27,11,14 + RTEXT "Speed:",IDC_STATIC,7,27,28,8 + EDITTEXT IDC_EDIT2,49,47,92,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,47,11,14 + RTEXT "Steps:",IDC_STATIC,7,47,28,8 + RTEXT "Timing:",IDC_STATIC,7,67,28,8 + LISTBOX IDC_LIST1,49,67,103,54,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + RTEXT "Colour 1:",IDC_STATIC,7,127,28,8 + RTEXT "Colour 2:",IDC_STATIC,7,147,28,8 + CONTROL "",IDC_BUTTON1,"Button",BS_OWNERDRAW | WS_TABSTOP,49,127, + 34,14 + CONTROL "",IDC_BUTTON2,"Button",BS_OWNERDRAW | WS_TABSTOP,49,147, + 34,14 +END + +IDD_SCENE_EDITOR DIALOGEX 0, 0, 578, 441 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_NOFAILCREATE | WS_MINIMIZEBOX | + WS_CAPTION | WS_SYSMENU +CAPTION "Cutscene Editor" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + CONTROL "Custom1",IDC_MAP_VIEW,"Scene Map View",0x0,145,7,426, + 296,WS_EX_STATICEDGE + CONTROL "Tree1",IDC_TREE1,"SysTreeView32",TVS_HASBUTTONS | + TVS_LINESATROOT | TVS_SHOWSELALWAYS | TVS_SINGLEEXPAND | + WS_BORDER | WS_TABSTOP,7,7,128,156 + CONTROL "List1",IDC_LIST1,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | + WS_TABSTOP,7,170,128,131 + SCROLLBAR IDC_SCROLLBAR1,7,423,552,11 + LISTBOX IDC_LIST2,7,322,564,101,LBS_OWNERDRAWFIXED | + LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | + WS_TABSTOP + CONTROL "",IDC_BUTTON1,"Button",BS_OWNERDRAW | BS_NOTIFY | + WS_TABSTOP,7,312,564,10 +END + +IDD_NAVBEACON_SETUP DIALOG DISCARDABLE 0, 0, 187, 113 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Nav Beacon Setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,69,92,50,14 + EDITTEXT IDC_EDIT1,10,15,165,40,ES_MULTILINE | ES_AUTOVSCROLL + LTEXT "Beacon Label:",-1,5,5,47,8 + COMBOBOX IDC_COMBO1,75,60,105,78,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + RTEXT "Person to track:",-1,7,60,60,13,SS_CENTERIMAGE + LTEXT "(or leave blank for location)",-1,16,74,90,8, + SS_CENTERIMAGE +END + +IDD_ANIMATION_SETUP DIALOG DISCARDABLE 0, 0, 159, 190 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Pick Animation" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,169,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,169,50,14 + EDITTEXT IDC_EDIT1,49,7,93,14,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | + UDS_AUTOBUDDY | UDS_ARROWKEYS,141,7,11,14 + RTEXT "Animation:",-1,7,7,35,8 +END + +IDD_MILESDLG DIALOG DISCARDABLE 0, 0, 300, 183 +STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Miles Sound System setup" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,243,162,50,14 + CTEXT "Please select a 3D sound driver from the list below", + IDC_STATIC_SELECT,7,7,286,17,SS_CENTERIMAGE + LISTBOX IDC_SOUNDDRV,7,28,286,120,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + CONTROL "Do not show this dialog box again",IDC_NOSHOW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,161,186,15 +END + +IDD_ENEMYFLAGS_SETUP DIALOG DISCARDABLE 0, 0, 187, 126 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Enemy Flags Setup" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Flags:",-1,7,36,20,8 + LISTBOX IDC_LIST1,17,48,152,50,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | + WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,68,105,50,14 + LTEXT "Flags:",-1,7,7,20,8 + COMBOBOX IDC_COMBO1,17,18,152,30,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +END + +IDD_WAREFX_SETUP DIALOG DISCARDABLE 0, 0, 159, 50 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Setup Warehouse Ambience" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,47,29,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,29,50,14 + RTEXT "Effect:",-1,7,7,35,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO1,48,7,104,84,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +END + +IDD_GRAPHICSDLG DIALOG DISCARDABLE 0, 0, 216, 207 +STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "Urban Chaos" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,54,187,50,14 + CONTROL "Use primary 3D card",IDC_PRIMARY_3D,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,13,39,100,10 + CONTROL "Use secondary 3D card",IDC_SECONDARY_3D,"Button", + BS_AUTORADIOBUTTON,13,52,100,10 + CONTROL "Use software rendering",IDC_SOFTWARE_3D,"Button", + BS_AUTORADIOBUTTON,13,66,100,10 + GROUPBOX "3D Card Selection ",IDC_STATIC_3DCARD,7,26,108,58 + GROUPBOX "Number of Colours",IDC_STATIC_BITDEPTH,119,26,90,45 + CONTROL "16-bit ""high"" colour",IDC_COLOURS_16,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,129,41,80,10 + CONTROL "32-bit ""true"" colour",IDC_COLOURS_32,"Button", + BS_AUTORADIOBUTTON,129,56,80,10 + GROUPBOX "Resolution",IDC_STATIC_RES,7,89,202,30 + COMBOBOX IDC_RESOLUTION,14,100,189,80,CBS_DROPDOWNLIST | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + GROUPBOX "Please select a 3D sound driver from the list below", + IDC_STATIC_SELECT,7,147,202,33 + PUSHBUTTON "Exit",IDCANCEL,111,187,50,14 + CTEXT "Graphics Options",IDC_GRAPHICS_OPTIONS,7,7,202,13, + SS_CENTERIMAGE | SS_SUNKEN + CTEXT "Sound Options",IDC_SOUND_OPTIONS,7,128,202,13, + SS_CENTERIMAGE | SS_SUNKEN + COMBOBOX IDC_SOUND_DROPDOWN,13,160,190,80,CBS_DROPDOWNLIST | + CBS_SORT | WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_MISSION_EDITOR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 571 + TOPMARGIN, 7 + BOTTOMMARGIN, 434 + END + + IDD_NEWMISSION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 207 + TOPMARGIN, 7 + BOTTOMMARGIN, 50 + END + + IDD_PLAYER_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 231 + END + + IDD_ENEMY_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 295 + VERTGUIDE, 17 + TOPMARGIN, 7 + BOTTOMMARGIN, 319 + HORZGUIDE, 141 + HORZGUIDE, 227 + END + + IDD_ITEM_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 47 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 37 + END + + IDD_TRIGGER_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 114 + END + + IDD_MESSAGE_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + VERTGUIDE, 37 + VERTGUIDE, 117 + VERTGUIDE, 128 + TOPMARGIN, 7 + BOTTOMMARGIN, 139 + HORZGUIDE, 60 + HORZGUIDE, 74 + HORZGUIDE, 88 + HORZGUIDE, 100 + END + + IDD_VEHICLE_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 122 + END + + IDD_CREATURE_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 69 + END + + IDD_CAMERA_TARGET_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 87 + HORZGUIDE, 107 + END + + IDD_CAMERA_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 165 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 184 + HORZGUIDE, 27 + HORZGUIDE, 46 + HORZGUIDE, 67 + HORZGUIDE, 87 + END + + IDD_MISSION_EDITOR2, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 571 + VERTGUIDE, 68 + VERTGUIDE, 135 + TOPMARGIN, 7 + BOTTOMMARGIN, 434 + HORZGUIDE, 279 + HORZGUIDE, 290 + HORZGUIDE, 301 + END + + IDD_EVENTTAB_CONDITION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 225 + VERTGUIDE, 57 + VERTGUIDE, 136 + TOPMARGIN, 7 + BOTTOMMARGIN, 102 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 87 + END + + IDD_EVENTTAB_ACTION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 225 + VERTGUIDE, 49 + VERTGUIDE, 57 + VERTGUIDE, 137 + TOPMARGIN, 7 + BOTTOMMARGIN, 102 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 87 + END + + IDD_EVENTTAB_INFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 225 + VERTGUIDE, 49 + VERTGUIDE, 57 + VERTGUIDE, 137 + TOPMARGIN, 7 + BOTTOMMARGIN, 100 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + END + + IDD_MAPEXIT_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + END + + IDD_INPUT_BOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 279 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END + + IDD_ACTIVATE_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 40 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 87 + HORZGUIDE, 107 + END + + IDD_VEFFECT_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 42 + VERTGUIDE, 48 + VERTGUIDE, 142 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 67 + HORZGUIDE, 77 + HORZGUIDE, 91 + HORZGUIDE, 105 + END + + IDD_TRAP_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 127 + HORZGUIDE, 147 + END + + IDD_PLATFORM_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 46 + HORZGUIDE, 67 + HORZGUIDE, 87 + END + + IDD_WAYPOINT_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 46 + HORZGUIDE, 67 + HORZGUIDE, 87 + END + + IDD_BOMB_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 38 + VERTGUIDE, 47 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 47 + END + + IDD_BURN_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 38 + VERTGUIDE, 47 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + END + + IDD_SEFFECT_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 42 + VERTGUIDE, 48 + VERTGUIDE, 142 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + END + + IDD_SPOTFX_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 42 + VERTGUIDE, 48 + VERTGUIDE, 142 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 67 + HORZGUIDE, 77 + HORZGUIDE, 91 + HORZGUIDE, 105 + END + + IDD_SET_SKILLS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 47 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + END + + IDD_BARREL_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 127 + HORZGUIDE, 147 + END + + IDD_WAYPOINT_PICKER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 127 + HORZGUIDE, 147 + END + + IDD_TREASURE_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 46 + HORZGUIDE, 67 + HORZGUIDE, 87 + END + + IDD_BONUS_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + VERTGUIDE, 94 + TOPMARGIN, 7 + BOTTOMMARGIN, 171 + HORZGUIDE, 60 + HORZGUIDE, 74 + HORZGUIDE, 84 + HORZGUIDE, 124 + END + + IDD_CONVERSATION_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + VERTGUIDE, 69 + TOPMARGIN, 7 + BOTTOMMARGIN, 158 + HORZGUIDE, 60 + HORZGUIDE, 73 + HORZGUIDE, 88 + HORZGUIDE, 102 + END + + IDD_COUNTER_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 38 + VERTGUIDE, 47 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 47 + END + + IDD_DLIGHT_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + HORZGUIDE, 27 + HORZGUIDE, 47 + HORZGUIDE, 67 + HORZGUIDE, 127 + HORZGUIDE, 147 + END + + IDD_SCENE_EDITOR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 571 + VERTGUIDE, 135 + VERTGUIDE, 145 + TOPMARGIN, 7 + BOTTOMMARGIN, 434 + HORZGUIDE, 301 + HORZGUIDE, 312 + HORZGUIDE, 322 + HORZGUIDE, 423 + END + + IDD_NAVBEACON_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + VERTGUIDE, 69 + TOPMARGIN, 7 + BOTTOMMARGIN, 106 + HORZGUIDE, 60 + HORZGUIDE, 73 + END + + IDD_ANIMATION_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 49 + TOPMARGIN, 7 + BOTTOMMARGIN, 183 + HORZGUIDE, 27 + HORZGUIDE, 46 + HORZGUIDE, 67 + HORZGUIDE, 87 + END + + IDD_MILESDLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END + + IDD_ENEMYFLAGS_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + VERTGUIDE, 17 + VERTGUIDE, 169 + TOPMARGIN, 7 + BOTTOMMARGIN, 119 + END + + IDD_WAREFX_SETUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 152 + VERTGUIDE, 42 + VERTGUIDE, 48 + VERTGUIDE, 142 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END + + IDD_GRAPHICSDLG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 209 + TOPMARGIN, 7 + BOTTOMMARGIN, 200 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAIN_ACCELERATOR ACCELERATORS DISCARDABLE +BEGIN + VK_F1, ID_DISPLAY_FULLSCREEN, VIRTKEY, NOINVERT + VK_F2, ID_DISPLAY_DRIVERS, VIRTKEY, NOINVERT +END + +IDR_GEDIT_ACCELERATOR ACCELERATORS DISCARDABLE +BEGIN + "N", ID_FILE_NEW_WS, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPEN_WS, VIRTKEY, CONTROL, NOINVERT + "Q", ID_FILE_EXITALL, VIRTKEY, CONTROL, NOINVERT + "S", ID_FILE_SAVE_WS, VIRTKEY, CONTROL, NOINVERT + VK_BACK, ID_GEDIT_DEL_PRIMS, VIRTKEY, NOINVERT + "X", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT +END + +IDR_CEDIT_ACCELERATORS ACCELERATORS DISCARDABLE +BEGIN + "Q", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT + VK_BACK, ID_CEDIT_ERASE, VIRTKEY, NOINVERT + VK_DECIMAL, ID_CEDIT_CAMERA_PUNCHIN, VIRTKEY, NOINVERT + VK_NUMPAD0, ID_CEDIT_MOUSELOOK, VIRTKEY, NOINVERT + VK_NUMPAD1, ID_CEDIT_REWIND, VIRTKEY, NOINVERT + VK_NUMPAD3, ID_CEDIT_FFWD, VIRTKEY, NOINVERT + VK_SPACE, ID_CEDIT_PLAYBACK, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_MUCKY_LOGO BITMAP DISCARDABLE "mucky_lo.bmp" +IDB_WORKSPACE BITMAP DISCARDABLE "bmp00001.bmp" +IDB_TOOLBAR BITMAP DISCARDABLE "toolbar.bmp" +IDB_BITMAP1 BITMAP DISCARDABLE "bitmap1.bmp" +IDB_SCENE_ICONS BITMAP DISCARDABLE "bitmap2.bmp" +IDB_SCENE_ICONS1 BITMAP DISCARDABLE "scene_ic.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MFLOGO ICON DISCARDABLE "ico00001.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDB_TOOLBAR TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_TOOLBAR_WAYPOINT + BUTTON ID_TOOLBAR_ZONE + BUTTON ID_TOOLBAR_PRIM +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +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 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Muckyfoot\0" + VALUE "FileDescription", "Fallen\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "Fallen\0" + VALUE "LegalCopyright", "Copyright © 1999\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "Fallen.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Muckyfoot Fallen\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + ID_EVENTPOINTROOT_RENUMBERWAYPOINTLOWER "Hello Simon!" + IDS_NODIRECTX "This product requires DirectX version 6.1 or better, and 3D hardware acceleration. You can install DirectX 6.1 from the original CD, if required." +END + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/fallen/DDLibrary/Headers/A3DManager.h b/fallen/DDLibrary/Headers/A3DManager.h new file mode 100644 index 0000000..c91946d --- /dev/null +++ b/fallen/DDLibrary/Headers/A3DManager.h @@ -0,0 +1,244 @@ +// A3DManager.h +// 2nd October 1998 +// +// (experimental) Aureal 3D Manager library +// +// requires either Aureal 3D sound card + drivers, OR normal sound card with A2D installed + + +#ifndef _A3D_MANAGER_H_ +#define _A3D_MANAGER_H_ + + + + + +#ifndef MF_STD_LIB_H + +typedef unsigned char UBYTE; +typedef signed char SBYTE; +typedef char CBYTE; +typedef unsigned short UWORD; +typedef signed short SWORD; +typedef unsigned long ULONG; +typedef signed long SLONG; + +void TraceText(CBYTE *error, ...); +#define TRACE TraceText + +#endif + +#ifndef _A3DPLAY_H_ +//#define INITGUID +#endif + +#include +#include +#include + +#include "C:\fallen\headers\A3D\Ia3dapi.h" + + +#define MAX_QUEUE_LENGTH 5 + +// prototypes + +class A3DManager; +class A3DSource; +class A3DData; +class A3DBase; +class A3DList; + +// globals + +extern IA3d4 *a3droot; +extern A3DManager the_a3d_manager; + +// functions + +void A3D_Check_Init(void); + +// classes + +// +// A3DList -- a linked list thingy +// + +class A3DList { +private: + A3DBase *list, *tail; + SLONG count; +public: + A3DList() { count=0; list=tail=NULL; } + ~A3DList(); + void Add(A3DBase *item); + void Del(A3DBase *item); + void Clear(); + A3DBase *Index(SLONG index); + A3DBase *Find(CBYTE *want); + inline SLONG Count() { return count; } + inline A3DBase *Head() { return list; } + inline A3DBase *Tail() { return tail; } + inline operator+=(A3DBase *item) { Add(item); return ( NULL ); }; + inline operator-=(A3DBase *item) { Del(item); return ( NULL ); }; + inline A3DBase* operator[](SLONG index) { return Index(index); }; +}; + + +// +// A3DManager -- At The Heart Of it All +// + +#define A3D_MAT_COUNT 3 +#define A3D_MAT_CARPET 0 +#define A3D_MAT_STEEL 1 +#define A3D_MAT_SNDPROOF 2 + +class A3DManager { +private: + IA3dListener *a3dlis; + IA3dMaterial *mat_lib[A3D_MAT_COUNT]; + +public: + A3DList srclist,datalist; + + // construct, destruct + A3DManager(SLONG features=0); + ~A3DManager(); + void Init(SLONG features); + void Fini(); + + // listener + inline void ListenPos(float x, float y, float z) { if (a3dlis) a3dlis->SetPosition3f(x,y,z); }; + inline void ListenRot(float head, float roll, float pitch) { if (a3dlis) a3dlis->SetOrientationAngles3f(head,pitch,roll); }; + + // channel play + A3DSource* Play(A3DData *Original, A3DSource* Channel=NULL, UBYTE Looped=0); + + // channel check + BOOL Valid(A3DBase* item); + A3DSource *ValidChannel(A3DBase* item); + A3DBase *ValidWave(A3DBase* item); + + // geom related + void BindMaterial(SLONG material); + + // misc + inline void Render() { a3droot->Flush(); a3droot->Clear(); }; +// inline void Render() { a3droot->Flush(); }; +// inline void Render() { a3droot->Clear(); }; +// inline void BeginFrame() { a3droot->Clear(); }; + +}; + + +// +// A3DBase -- the root of all evil +// + +class A3DBase { +protected: + IA3dSource *a3dsrc; + CBYTE title[_MAX_PATH]; + float length_seconds; + ULONG length_samples; + ULONG last_time; +public: + // blah blah + CBYTE owner, type; + // linked list pointers + A3DBase *last, *next; + + A3DBase() { last=next=NULL; a3dsrc=NULL; title[0]=0; length_samples=0; length_seconds=0; last_time=0; }; + virtual ~A3DBase() { /* why can't it be pure virtual? */ }; + + // data + void FreeWave(); + + // queries + inline IA3dSource *GetSource() { return a3dsrc; }; + inline CBYTE *GetTitle() { return title; }; + ULONG GetLengthSamples(); + float GetLengthSeconds(); + BOOL HasEnded(UBYTE early_out); +// BOOL HasEnded() { float f; a3dsrc->GetWaveTime(&f); return (f>GetLengthSeconds()); }; + + +}; + +// +// A3DData -- stores data, nothing else +// + +class A3DData : public A3DBase { +public: + // construct, destruct + A3DData(CBYTE *fn=0, UBYTE ntype=A3DSOURCE_TYPEDEFAULT); // constructor: load filename, or no data + virtual ~A3DData(); +}; + +// +// A3DSource -- actually does something useful +// + +struct QueueItem { + A3DBase *original; + SLONG x,y,z; + SLONG flags; +}; + +class A3DSource : public A3DBase { +private: + ULONG rendermode; + UBYTE queuepos; + QueueItem queue[MAX_QUEUE_LENGTH]; + void DupeConstruct(A3DBase *original); // duplicate existing source + void DoChange(A3DBase *original); + void SetupParams(); +public: + BOOL autofree; + ULONG Flags; + SLONG User; // random user-defined var + A3DBase *cloned_from; + + // construct, destruct + A3DSource(CBYTE *fn=0); // constructor: load filename, or no data + A3DSource(A3DBase *original); // constructor: duplicate existing source + virtual ~A3DSource(); + + // configuration + inline void SetPriority(float priority) { if (a3dsrc) a3dsrc->SetPriority(priority); }; + void SetMute(UBYTE mute); + void Set3D(UBYTE is3d); + inline void SetGain(UBYTE vol) { if (a3dsrc) a3dsrc->SetGain(((float)vol)/255.0f); }; + void Change(A3DBase *original); // reset to a new source file (& flush queue) + void Queue(A3DBase *original, SLONG x, SLONG y, SLONG z, SLONG flags);// queue for a new source at end of current + inline void QueueFlush() { queuepos=0; }; + + // callback + UBYTE CBEnded(); + + + // 3D + inline void SetPositionf(float x, float y, float z) { if (a3dsrc) a3dsrc->SetPosition3f(x,y,z); }; + inline void SetPositionl(SLONG x, SLONG y, SLONG z) { if (a3dsrc) a3dsrc->SetPosition3f((float)x,(float)y,(float)z); }; + inline void SetRotationf(float h, float r, float p) { if (a3dsrc) a3dsrc->SetOrientationAngles3f(h,r,p); }; + inline void SetRotationl(SLONG h, SLONG r, SLONG p) { if (a3dsrc) a3dsrc->SetOrientationAngles3f((float)h,(float)r,(float)p); }; + inline void SetVelocityf(float x, float y, float z) { if (a3dsrc) a3dsrc->SetVelocity3f(x,y,z); }; + inline void SetVelocityl(SLONG x, SLONG y, SLONG z) { if (a3dsrc) a3dsrc->SetVelocity3f((float)x,(float)y,(float)z); }; + + // audio properties + inline void SetPitchf(float pitchbend) { if (a3dsrc) a3dsrc->SetPitch(pitchbend); }; + inline void SetGainf(float gain) { if (a3dsrc) a3dsrc->SetGain(gain); }; + + // transport controls + void Play(UBYTE looped); + void Stop(); + void Rewind(); + inline void Pause() { if (a3dsrc) a3dsrc->Stop(); }; + +}; + + + +#endif \ No newline at end of file diff --git a/fallen/DDLibrary/Headers/AsyncFile.h b/fallen/DDLibrary/Headers/AsyncFile.h new file mode 100644 index 0000000..d70fb80 --- /dev/null +++ b/fallen/DDLibrary/Headers/AsyncFile.h @@ -0,0 +1,48 @@ +// AsyncFile +// +// asynchronous file loading + +// InitAsyncFile +// +// initialize + +void InitAsyncFile(void); + +// TermAsyncFile +// +// terminate + +void TermAsyncFile(void); + +// LoadAsyncFile +// +// load into buffer + +bool LoadAsyncFile(char* filename, void* buffer, DWORD blen, void* key); + +// GetNextCompletedAsyncFile +// +// return key of next completed file, else NULL + +void* GetNextCompletedAsyncFile(void); + +// CancelAsyncFile +// +// cancel async file loading - if NULL, cancels all files + +void CancelAsyncFile(void* key); + +// AsyncFile +// +// control block + +struct AsyncFile +{ + HANDLE hFile; // file handle + OVERLAPPED Control; // control block + void* hKey; // user key + AsyncFile* prev; // previous in chain + AsyncFile* next; // next in chain +}; + +#define MAX_ASYNC_FILES 16 diff --git a/fallen/DDLibrary/Headers/AsyncFile2.h b/fallen/DDLibrary/Headers/AsyncFile2.h new file mode 100644 index 0000000..353829a --- /dev/null +++ b/fallen/DDLibrary/Headers/AsyncFile2.h @@ -0,0 +1,49 @@ +// AsyncFile2 +// +// asynchronous file loading for Win95 + +// InitAsyncFile +// +// initialize + +void InitAsyncFile(void); + +// TermAsyncFile +// +// terminate + +void TermAsyncFile(void); + +// LoadAsyncFile +// +// load into buffer + +bool LoadAsyncFile(char* filename, void* buffer, DWORD blen, void* key); + +// GetNextCompletedAsyncFile +// +// return key of next completed file, else NULL + +void* GetNextCompletedAsyncFile(void); + +// CancelAsyncFile +// +// cancel async file loading - if NULL, cancels all files + +void CancelAsyncFile(void* key); + +// AsyncFile +// +// control block + +struct AsyncFile +{ + HANDLE hFile; // file handle + UBYTE* buffer; // buffer for data + int blen; // amount to read + void* hKey; // user key + AsyncFile* prev; // previous in chain + AsyncFile* next; // next in chain +}; + +#define MAX_ASYNC_FILES 16 diff --git a/fallen/DDLibrary/Headers/BinkClient.h b/fallen/DDLibrary/Headers/BinkClient.h new file mode 100644 index 0000000..e571298 --- /dev/null +++ b/fallen/DDLibrary/Headers/BinkClient.h @@ -0,0 +1,7 @@ +// BinkClient.h +// +// simple client for BINK file playback + +extern void BinkPlay(const char* filename, IDirectDrawSurface* lpdds, bool (*flip)()); + +extern void BinkMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); \ No newline at end of file diff --git a/fallen/DDLibrary/Headers/D3DTexture.h b/fallen/DDLibrary/Headers/D3DTexture.h new file mode 100644 index 0000000..27a59dc --- /dev/null +++ b/fallen/DDLibrary/Headers/D3DTexture.h @@ -0,0 +1,297 @@ +// D3DTexture.h +// Guy Simmons, 29th November 1997. + +#ifndef D3DTEXTURE_H +#define D3DTEXTURE_H + +#ifndef TARGET_DC + +// PC + +// this makes absolutely fuck-all difference to speed (tested) +//#define TEX_EMBED // must be set the same in PolyPage.h +// Don't page. +#define USE_FANCY_TEXTURE_PAGES_PLEASE_BOB 1 +#else + +// DREAMCAST + +// But it makes the VQ much more efficient, so do it! +#define TEX_EMBED // must be set the same in PolyPage.h +// And use the new snazzy system. +#define USE_FANCY_TEXTURE_PAGES_PLEASE_BOB 1 +#endif + + +#ifndef TARGET_DC +// Create VQ'd textures and save them out. Only on the PC version, obviously. +//#define SAVE_MY_VQ_TEXTURES_PLEASE_BOB defined +#endif + + + +// Call after doing lots of loading. +void NotGoingToLoadTexturesForAWhileNowSoYouCanCleanUpABit ( void ); + +// handle = file opened with FileOpen +// dwSize = number of bytes to load. +// return = where the file was loaded. +// You _must_ copy this or do something with it before loading another file. +void *FastLoadFileSomewhere ( MFFileHandle handle, DWORD dwSize ); + + + + +#include "tga.h" +#include "FileClump.h" + +//--------------------------------------------------------------- + +struct Char +{ + SLONG X, + Y, + Height, + Width; +}; + +//--------------------------------------------------------------- + +struct Font +{ + SLONG StartLine; + Char CharSet[96]; + Font *NextFont; +}; + +//--------------------------------------------------------------- + +#define D3D_TEXTURE_FONT (1<<0) +#define D3D_TEXTURE_FONT2 (1<<1) // texture is a font with red borders + +//--------------------------------------------------------------- + +#define D3DTEXTURE_TYPE_UNUSED 0 +#define D3DTEXTURE_TYPE_8 1 +#define D3DTEXTURE_TYPE_TGA 2 +#define D3DTEXTURE_TYPE_USER 3 // The user updates the contents- it doesn't have a file. + + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +// First number is size of subtextures, second is number of subtextures in page. +// 3x3 means the page is 4x as big in each direction, with lots of pixel padding. +#define D3DPAGE_NONE 0 +#define D3DPAGE_64_3X3 1 +#define D3DPAGE_64_4X4 2 +#define D3DPAGE_32_3X3 3 +#define D3DPAGE_32_4X4 4 + +#endif + + + +class D3DTexture +{ + public: + +#ifdef TARGET_DC + CBYTE texture_name[64]; +#else + CBYTE palette_name[256]; + CBYTE texture_name[256]; +#endif + ULONG ID; // texture ID for FileClump + // Allow the texture to be shrunk or replaced with junk for faster loading. + BOOL bCanShrink; + SLONG TextureFlags; + Font *FontList; + LPDIRECT3DTEXTURE2 lp_Texture; + LPDIRECTDRAWSURFACE4 lp_Surface; +#ifndef TARGET_DC + LPDIRECTDRAWPALETTE lp_Palette; + HRESULT Reload_8 (void); +#endif + HRESULT Reload_TGA (void); + HRESULT Reload_user(void); + BOOL DontBotherLoadingInSoftwareMode; + BOOL GreyScale; + BOOL UserWantsAlpha; // The user page needs an alpha-channel. +#ifdef TEX_EMBED +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + //char *name; // Texture file name. + UBYTE bPagePos; // Position in page. + UBYTE bPageType; // One of D3DPAGE_xxx + WORD wPageNum; // The D3Dpage this is in. +#else + UBYTE TexOffset; // 128 + (0-15) for the subareas of a texture page else zero + UBYTE Padding[3]; // MSVC BUG!!!! + D3DTexture* TexSource; // if TexOffset & 128, it's the source D3DTexture +#endif +#endif + + D3DTexture *NextTexture; + + + D3DTexture() { + TextureFlags = 0; + FontList = NULL; + NextTexture=NULL; + #ifndef TARGET_DC + lp_Palette=NULL; + #endif + lp_Surface=NULL; + lp_Texture=NULL; + Type = D3DTEXTURE_TYPE_UNUSED; +#ifdef TEX_EMBED +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + wPageNum = -1; // None. + bPagePos = 0; + bPageType = D3DPAGE_NONE; +#else + TexOffset = 0; + TexSource = this; +#endif +#endif + // IT WOULD FUCKING HELP IF SOME OF THESE ACTUALLY GOT SET UP WITH DEFAULTS + DontBotherLoadingInSoftwareMode = FALSE; + GreyScale = FALSE; + UserWantsAlpha = FALSE; + ID = -1; + bCanShrink = FALSE; + } + + // + // The format used. + // + +#ifdef TARGET_DC + UBYTE mask_red; + UBYTE mask_green; + UBYTE mask_blue; + UBYTE mask_alpha; + + UBYTE shift_red; + UBYTE shift_green; + UBYTE shift_blue; + UBYTE shift_alpha; +#else + SLONG mask_red; + SLONG mask_green; + SLONG mask_blue; + SLONG mask_alpha; + + SLONG shift_red; + SLONG shift_green; + SLONG shift_blue; + SLONG shift_alpha; +#endif + + SLONG Type; + SLONG size; // The size in pixels of the texture page. + SLONG ContainsAlpha; // TRUE or FALSE? Always false for TYPE_8 textures. + +#ifndef TARGET_DC + HRESULT LoadTexture8 (CBYTE *tex_file,CBYTE *pal_file); +#endif + HRESULT LoadTextureTGA(CBYTE *tga_file,ULONG texid,BOOL bCanShrink=TRUE); + + HRESULT ChangeTextureTGA(CBYTE *tga_file); + + HRESULT CreateUserPage(SLONG size, BOOL i_want_an_alpha_channel); // Power of two between 32 and 256 inclusive + HRESULT LockUser (UWORD **bitmap, SLONG *pitch); // Returns the texture page on success. The pitch is in bytes! + void UnlockUser (void); + + HRESULT Reload(void); + HRESULT Destroy(void); + + HRESULT CreateFonts(TGA_Info *tga_info,TGA_Pixel *tga_data); + Font *GetFont(SLONG id); + + // resets texture page for loading + static void BeginLoading(); + + // + // Makes the texture grey-scale. If it is already loaded, it + // is re-loaded. + // + + void set_greyscale(BOOL is_greyscale); + + LPDIRECT3DTEXTURE2 GetD3DTexture() { return lp_Texture; } +#ifndef TARGET_DC + LPDIRECTDRAWPALETTE GetPalette(void) { return lp_Palette; } +#endif + LPDIRECTDRAWSURFACE4 GetSurface(void) { return lp_Surface; } +#ifdef TEX_EMBED +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + void GetTexOffsetAndScale ( float *pfUScale, float *pfUOffset, float *pfVScale, float *pfVOffset ); +#else //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + + UBYTE GetTexOffset() { return TexOffset; } + D3DTexture* GetTexSource() { return TexSource; } +#endif //#else //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +#endif + +#ifndef TARGET_DC + HRESULT SetColorKey(SLONG flags,LPDDCOLORKEY key) { + if (lp_Surface) + { + return lp_Surface->SetColorKey(flags,key); + } + else + { + return DDERR_GENERIC; + } + } +#endif + + inline BOOL IsFont(void) { return TextureFlags&D3D_TEXTURE_FONT; } + inline void FontOn(void) { TextureFlags |= D3D_TEXTURE_FONT; } + inline void FontOff(void) { TextureFlags &= ~D3D_TEXTURE_FONT; } + + inline BOOL IsFont2(void) { return TextureFlags&D3D_TEXTURE_FONT2; } + inline void Font2On(void) { TextureFlags |= D3D_TEXTURE_FONT2; } + inline void Font2Off(void) { TextureFlags &= ~D3D_TEXTURE_FONT2; } +}; + + + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +class D3DPage +{ +public: + UBYTE bPageType; // One of D3DPAGE_xxx + UBYTE bNumTextures; // Number of textures in page. + char *pcDirectory; // The page's directory. THIS IS STATIC - don't free it. + char *pcFilename; // The page's filename. THIS IS STATIC - don't free it. + char **ppcTextureList; // A pointer to an array of pointers to strings of the texture names :-) + D3DTexture *pTex; // The texture page texture itself. + //D3DTexture *pTextures[16]; // The textures in this page, in order. + + D3DPage ( void ) + { + bPageType = 0; + bNumTextures = 0; + pcDirectory = NULL; + pcFilename = NULL; + pTex = NULL; + ppcTextureList = NULL; + } + + // Call this when linking a standard D3DTexture to the page - it will demand-load the page's texture. + void D3DPage::EnsureLoaded ( void ); + // Call this when unloading everything. + void D3DPage::Unload ( void ); + +}; +#endif + + +//--------------------------------------------------------------- + + + + +#endif + + diff --git a/fallen/DDLibrary/Headers/DCLowLevel.h b/fallen/DDLibrary/Headers/DCLowLevel.h new file mode 100644 index 0000000..0f82322 --- /dev/null +++ b/fallen/DDLibrary/Headers/DCLowLevel.h @@ -0,0 +1,149 @@ +// +// Dreamcast low-level functions, ripped from the example docs. +// + +#ifndef _DCLL_ +#define _DCLL_ + + + + +// +// A dreamcast sound buffer... +// + +typedef struct dcll_sound DCLL_Sound; + + + +// +// Initialises the DC sound system. +// + +void DCLL_init(void); + + + + +// ======================================================== +// +// PLAYING SFX +// +// ======================================================== + +// +// Loads a sound from a file. +// + +DCLL_Sound *DCLL_load_sound(CBYTE *fname); + + +// Call this when a bunch of sounds have finished loading. +// Can be called whenever you like really. +void DCLL_ProbablyDoneMostOfMySoundLoadingForAWhile ( void ); + + +// +// Sets the volume of the sample. 0.0F <= volume <= 1.0F +// + +void DCLL_set_volume(DCLL_Sound *ds, float volume); + + + +// +// Plays a 2D sound. +// + +#define DCLL_FLAG_INTERRUPT (1 << 0) +#define DCLL_FLAG_LOOP (1 << 1) + +void DCLL_2d_play_sound(DCLL_Sound *ds, SLONG flag = 0); + + +// +// Plays a 3D sound. +// + +void DCLL_3d_play_sound(DCLL_Sound *ds, float x, float y, float z, SLONG flag = 0); + + +// +// The 'head' for 3d sounds. +// + +void DCLL_3d_set_listener( + float x, + float y, + float z, + float matrix[9]); + +// +// Stop the sound from playing (2D or 3D) +// + +void DCLL_stop_sound(DCLL_Sound *ds); + + +// +// Frees up the given sound. +// + +void DCLL_free_sound(DCLL_Sound *ds); + + +// +// Shuts down the sound system. +// + +void DCLL_fini(void); + + + +// ======================================================== +// +// STREAMING FILES FROM CD +// +// ======================================================== + +// +// Sets the range of DCLL_stream_volume. +// + +void DCLL_stream_set_volume_range(float max_vol); // 0.0F to 1.0F + + +SLONG DCLL_stream_play(CBYTE *fname, SLONG loop = FALSE); // Play the file streaming off CD. Looping samples have a lower priority. Returns FALSE if it doesn't issue the play. +void DCLL_stream_wait(void); // Wait until the streaming file has finished playing +void DCLL_stream_stop(void); // Stop the streaming sound. +SLONG DCLL_stream_is_playing(void); // Returns TRUE if the streaming sound is still playing. +void DCLL_stream_volume(float volume); // 0.0F <= volume <= 1.0F + + +// ======================================================== +// +// STREAMING FILES FROM MEMORY +// +// ======================================================== + +void DCLL_memstream_load (CBYTE *fname); // Loads the file. +void DCLL_memstream_volume(float volume); // 0.0F <= volume <= 1.0F +void DCLL_memstream_play (void); // Loops and plays the file +void DCLL_memstream_stop (void); // Stops playing the file +void DCLL_memstream_unload(void); // Frees memory. + + + + +#ifdef DEBUG + +void DumpTracies ( void ); + +#else + +static void DumpTracies ( void ){} + +#endif + + +#endif diff --git a/fallen/DDLibrary/Headers/DDManager.h b/fallen/DDLibrary/Headers/DDManager.h new file mode 100644 index 0000000..ba5b376 --- /dev/null +++ b/fallen/DDLibrary/Headers/DDManager.h @@ -0,0 +1,309 @@ +// DDManager.h +// Guy Simmons, 12th November 1997. + +#ifndef DDMANAGER_H +#define DDMANAGER_H + +// #include "Types.h" + +//--------------------------------------------------------------- + +#define DD_DRIVER_INIT (1<<0) + +#define DD_DRIVER_VALID (1<<0) +#define DD_DRIVER_PRIMARY (1<<1) +#define DD_DRIVER_D3D (1<<2) +#define DD_DRIVER_M_LOADED (1<<3) +#define DD_DRIVER_D_LOADED (1<<4) +#define DD_DRIVER_SUPPORTS_16BIT (1<<5) // Screen modes... +#define DD_DRIVER_SUPPORTS_32BIT (1<<6) +#define DD_DRIVER_RENDERS_TO_16BIT (1<<7) // Harware rendering... +#define DD_DRIVER_RENDERS_TO_32BIT (1<<8) +#define DD_DRIVER_MODE_320 (1<<9) +#define DD_DRIVER_MODE_512 (1<<10) +#define DD_DRIVER_MODE_640 (1<<11) +#define DD_DRIVER_MODE_800 (1<<12) +#define DD_DRIVER_MODE_1024 (1<<13) +#define DD_DRIVER_LOW_MEMORY (1<<14) + +#define D3D_DEVICE_VALID (1<<0) +#define D3D_DEVICE_F_LOADED (1<<1) + +//--------------------------------------------------------------- + +typedef struct +{ + BOOL Result; // Success/Failure + DWORD Count; // Current count + void *Extra; // Current Driver/Device/Etc. +}CallbackInfo; + +//--------------------------------------------------------------- + +class DDModeInfo; +class D3DDeviceInfo; +class DDDriverInfo; +class DDDriverManager; + +//--------------------------------------------------------------- + +SLONG FlagsToBitDepth(SLONG flags); +ULONG FlagsToMask(SLONG flags); +SLONG BitDepthToFlags(SLONG bpp); +BOOL IsPalettized(LPDDPIXELFORMAT lp_dd_pf); +BOOL GetDesktopMode(DDDriverInfo *the_driver,LPGUID D3D_guid,DDModeInfo **the_mode,D3DDeviceInfo **the_device); +BOOL GetFullscreenMode(DDDriverInfo *the_driver,GUID *D3D_guid,SLONG w,SLONG h,SLONG bpp,SLONG refresh,DDModeInfo **the_mode,D3DDeviceInfo **the_device); +DDDriverInfo *ValidateDriver(GUID *DD_guid); +D3DDeviceInfo *ValidateDevice(DDDriverInfo *the_driver,GUID *D3D_guid,DDModeInfo *the_filter=NULL); +DDModeInfo *ValidateMode(DDDriverInfo *the_driver,DWORD w,DWORD h,DWORD bpp,DWORD refresh,D3DDeviceInfo *the_filter=NULL); + +//--------------------------------------------------------------- + +class DDModeInfo +{ + private: + protected: + public: + DDSURFACEDESC2 ddSurfDesc; // Complete Surface Description + DDModeInfo *Next, // Next Node. + *Prev; // Prev Node. + + DDModeInfo(); + DDModeInfo(const DDSURFACEDESC & ddDesc); + ~DDModeInfo(); + + SLONG GetWidth(void); + SLONG GetHeight(void); + SLONG GetBPP(void); + HRESULT GetMode(SLONG *w,SLONG *h,SLONG *bpp,SLONG *refresh); + BOOL ModeSupported(D3DDeviceInfo *the_device); + BOOL Match(SLONG w,SLONG h,SLONG bpp); + BOOL Match(SLONG bpp); +}; + +//--------------------------------------------------------------- + +class D3DDeviceInfo +{ + private: + protected: + public: + ULONG D3DFlags; // Flags + + // D3D Info + GUID guid; // GUID + LPTSTR szName; // Driver Name + LPTSTR szDesc; // Driver Description + D3DDEVICEDESC d3dHalDesc; // HAL info + D3DDEVICEDESC d3dHelDesc; // HEL info + + // Texture Formats + ULONG FormatCount; // Count of Texture Formats + DDModeInfo *FormatList, // List of Texture Formats. + *FormatListEnd; + + DDModeInfo* OpaqueTexFmt; // preferred format for opaque textures + DDModeInfo* AlphaTexFmt; // preferred format for alpha textures + + // Z Format + DDPIXELFORMAT ZFormat; + + // caps +#ifndef TARGET_DC + bool CanDoModulateAlpha; // can do TBLEND_MODULATEALPHA mode? + bool CanDoDestInvSourceColour; // can do BLEND_SRCCOLOR? + bool CanDoAdamiLighting; // can do Adami lighting? + bool CanDoForsythLighting; // can do Forsyth lighting? +#endif + + // Node Info + D3DDeviceInfo *Next, // Next Node + *Prev; // Prev Node + + + D3DDeviceInfo(); + ~D3DDeviceInfo(); + + // Methods + HRESULT Create(LPGUID lpD3DGuid,LPTSTR lpD3DName,LPTSTR lpD3DDesc,LPD3DDEVICEDESC lpD3DHal,LPD3DDEVICEDESC lpD3DHel); + void Destroy(void); + + BOOL IsHardware(void); + BOOL Match(GUID *the_guid); + + inline BOOL IsValid(void) { return D3DFlags&D3D_DEVICE_VALID; } + inline void ValidOn(void) { D3DFlags |= D3D_DEVICE_VALID; } + inline void ValidOff(void) { D3DFlags &= ~D3D_DEVICE_VALID; } + + // Texure Format Methods + HRESULT LoadFormats(LPDIRECT3DDEVICE3 the_d3d_device); + HRESULT DestroyFormats(void); + HRESULT AddFormat(DDModeInfo *the_format); + HRESULT DelFormat(DDModeInfo *the_format); + + void FindOpaqueTexFmt(); + void FindAlphaTexFmt(); + + DDModeInfo *FindFormat(SLONG bpp,DDModeInfo **next_best_format,DDModeInfo *start=NULL); + + inline SLONG CountFormats(void) { return FormatCount; } + inline BOOL FormatsLoaded(void) { return ((D3DFlags&D3D_DEVICE_F_LOADED) ? TRUE : FALSE); } + inline void TurnFormatsLoadedOn(void) { D3DFlags |= D3D_DEVICE_F_LOADED; } + inline void TurnFormatsLoadedOff(void) { D3DFlags &= ~D3D_DEVICE_F_LOADED; } + + // Z Format methods + HRESULT LoadZFormats(LPDIRECT3D3 d3d); + void SetZFormat(LPDDPIXELFORMAT lpPF) { memcpy(&ZFormat, lpPF, sizeof(ZFormat)); } + LPDDPIXELFORMAT GetZFormat() { return &ZFormat; } + + // caps methods + void CheckCaps(LPDIRECT3DDEVICE3 the_device); +#ifdef TARGET_DC + bool ModulateAlphaSupported() { return TRUE; } + bool DestInvSourceColourSupported() { return TRUE; } + bool AdamiLightingSupported() { return FALSE; } +#else + bool ModulateAlphaSupported() { return CanDoModulateAlpha; } + bool DestInvSourceColourSupported() { return CanDoDestInvSourceColour; } + bool AdamiLightingSupported() { return CanDoAdamiLighting; } +#endif + +/* + LPDDModeInfo FindFormat (LPDDPIXELFORMAT lpddsd, + LPDDModeInfo * lpNextBest, + LPDDModeInfo lpStartFormat = NULL); + + DWORD EnumFormats (const D3DDEV_ENUMINFO & eiInfo); +*/ +}; + +//--------------------------------------------------------------- + +class DDDriverInfo +{ + private: + protected: + public: + ULONG DriverFlags; // D3D Driver flags + + // Driver info. + GUID guid, // guid, if any + hardware_guid; + LPTSTR szName; // name + LPTSTR szDesc; // description + DDCAPS ddHalCaps; // Hardware caps + DDCAPS ddHelCaps; // Emulation caps + + // Mode Info + ULONG ModeCount; // Count of Modes. + DDModeInfo *ModeList, // List of Modes. + *ModeListEnd; + + // D3D Info + ULONG DeviceCount; // Count of D3D devices. + D3DDeviceInfo *DeviceList, // List of D3D Devices. + *DeviceListEnd; + + DDDriverInfo *Next, + *Prev; + + DDDriverInfo(); + ~DDDriverInfo(); + + // Driver methods. + HRESULT Create(GUID *lpGuid,LPTSTR lpDriverName,LPTSTR lpDriverDesc); + void Destroy(void); + + BOOL Match(GUID *the_guid); + + GUID *GetGuid(void); + + inline BOOL IsValid(void) { return DriverFlags&DD_DRIVER_VALID; } + inline void ValidOn(void) { DriverFlags |= DD_DRIVER_VALID; } + inline void ValidOff(void) { DriverFlags &= ~DD_DRIVER_VALID; } + + inline BOOL IsPrimary(void) { return DriverFlags&DD_DRIVER_PRIMARY; } + inline void PrimaryOn(void) { DriverFlags |= DD_DRIVER_PRIMARY; } + inline void PrimaryOff(void) { DriverFlags &= ~DD_DRIVER_PRIMARY; } + + inline BOOL IsD3D(void) { return DriverFlags&DD_DRIVER_D3D; } + inline void D3DOn(void) { DriverFlags |= DD_DRIVER_D3D; } + inline void D3DOff(void) { DriverFlags &= ~DD_DRIVER_D3D; } + + + // Mode methods. + HRESULT LoadModes(LPDIRECTDRAW4 lpDD4); + HRESULT DestroyModes(void); + + HRESULT AddMode(DDModeInfo *the_mode); + HRESULT DeleteMode(DDModeInfo *the_mode); + DDModeInfo *FindMode(SLONG w,SLONG h,SLONG bpp,SLONG refresh,DDModeInfo **next_best=NULL,DDModeInfo *start_mode=NULL); + + inline SLONG CountModes(void) { return ModeCount; } + inline BOOL ModesLoaded(void) { return ((DriverFlags&DD_DRIVER_M_LOADED) ? TRUE : FALSE); } + inline void TurnModesLoadedOn(void) { DriverFlags |= DD_DRIVER_M_LOADED; } + inline void TurnModesLoadedOff(void) { DriverFlags &= ~DD_DRIVER_M_LOADED;} + + + + // Device methods. + HRESULT LoadDevices(LPDIRECT3D3 lpD3D3); + HRESULT DestroyDevices(void); + + HRESULT AddDevice(D3DDeviceInfo *the_device); + HRESULT DeleteDevice(D3DDeviceInfo *the_device); + D3DDeviceInfo *FindDevice(GUID *the_guid, D3DDeviceInfo **next_best,D3DDeviceInfo *start_device=NULL); + D3DDeviceInfo *FindDeviceSupportsMode(GUID *the_guid,DDModeInfo *the_mode,D3DDeviceInfo **next_best_device,D3DDeviceInfo *start_device=NULL); + DDModeInfo *FindModeSupportsDevice(SLONG w, SLONG h, SLONG bpp,SLONG refresh,D3DDeviceInfo *the_device,DDModeInfo **next_best,DDModeInfo *start_device=NULL); + + inline SLONG CountDevices(void) { return DeviceCount; } + inline BOOL DevicesLoaded(void) { return ((DriverFlags&DD_DRIVER_D_LOADED) ? TRUE : FALSE); } + inline void TurnDevicesLoadedOn(void) { DriverFlags |= DD_DRIVER_D_LOADED; } + inline void TurnDevicesLoadedOff(void) { DriverFlags &= ~DD_DRIVER_D_LOADED;} + +}; + +//--------------------------------------------------------------- + +class DDDriverManager +{ + private: + protected: + public: + ULONG ManagerFlags, // Global flags + DriverCount; // Count of DD Drivers + DDDriverInfo *DriverList, // List of DD Device Drivers. + *DriverListEnd; + + DDDriverInfo *CurrDriver; // Pointer to current DD Device driver + DDModeInfo *CurrMode; // Pointer to current mode in DD driver + D3DDeviceInfo *CurrDevice; // Pointer to current D3D device + DDModeInfo *CurrTextureFormat; // Pointer to current Texture Format + + + DDDriverManager(); + ~DDDriverManager(); + + // Methods. + HRESULT Init(void); + HRESULT Fini(void); + + HRESULT LoadDrivers(void); + HRESULT DestroyDrivers(void); + + HRESULT AddDriver(DDDriverInfo *the_driver); + DDDriverInfo *FindDriver(GUID *guid,DDDriverInfo **next_best,DDDriverInfo *start_driver=NULL); + DDDriverInfo *FindDriver(DDCAPS *hal,DDCAPS *hel,DDDriverInfo **next_best,DDDriverInfo *start_driver=NULL); + + inline BOOL IsInitialised(void) { return ManagerFlags&DD_DRIVER_INIT; } + inline void InitOn(void) { ManagerFlags |= DD_DRIVER_INIT; } + inline void InitOff(void) { ManagerFlags &= ~DD_DRIVER_INIT; } +}; + +extern DDDriverManager the_manager; + +//--------------------------------------------------------------- + +#define InitStruct(s) { ZeroMemory(&(s), sizeof(s)); (s).dwSize = sizeof(s); } + +#endif diff --git a/fallen/DDLibrary/Headers/DDlib.h b/fallen/DDLibrary/Headers/DDlib.h new file mode 100644 index 0000000..7854eed --- /dev/null +++ b/fallen/DDLibrary/Headers/DDlib.h @@ -0,0 +1,128 @@ +// DDLib.h +// Guy Simmons, 20th November 1997 + +#ifndef DDLIB_H +#define DDLIB_H + +#include + +// Link in the MF standard library. +#ifdef _DEBUG +#pragma comment(lib, "MFStdLib_D.lib") +#else +#pragma comment(lib, "MFStdLib_R.lib") +#endif + +// Link in the DX libraries. +#pragma comment(lib, "ddraw.lib") +#pragma comment(lib, "dinput.lib") +#ifdef TARGET_DC +#pragma comment(lib, "dplayx.lib") +#else +#pragma comment(lib, "dplay.lib") +// What kind of pervert needs to link with RM???? +#pragma comment(lib, "d3drm.lib") +#endif +#pragma comment(lib, "dsound.lib") + +#include "D3DTexture.h" +#include "DDManager.h" +#include "Debug.h" +#include "DIManager.h" +#include "DSManager.h" +#include "GDisplay.h" +#include "GWorkScreen.h" +#include "QSManager.h" +#include "SampleManager.h" +#include "Net.h" + +#include "WindProcs.h" + +#include "resource.h" + +#ifdef TARGET_DC +#include "target.h" +#endif + + +//--------------------------------------------------------------- +// mikes mouse stuff + +extern volatile SLONG MouseDX,MouseDY; +extern void RecenterMouse(void); + +//--------------------------------------------------------------- + +#define SET_BLACK_BACKGROUND the_display.SetBlackBackground() +#define SET_WHITE_BACKGROUND the_display.SetWhiteBackground() +#define SET_BLUE_BACKGROUND the_display.SetBlueBackground() +#define SET_USER_BACKGROUND the_display.SetUserBackground() + +#define BEGIN_SCENE the_display.BeginScene() +#define END_SCENE the_display.EndScene() +#define CLEAR_VIEWPORT the_display.ClearViewport() +#define FLIP(a,f) the_display.Flip(a,f) +#define DRAW_PRIMITIVE(pt,vt,v,vc,f) the_display.DrawPrimitive(pt,vt,v,vc,f) +#define DRAW_INDEXED_PRIMITIVE(pt,vt,v,vc,i,ic,f) the_display.DrawIndexedPrimitive(pt,vt,v,vc,i,ic,f) + +// macros to set render state in the card +#define REALLY_SET_RENDER_STATE(t,s) the_display.SetRenderState(t,s) +#define REALLY_SET_TEXTURE(tex) the_display.SetTexture(tex) +#define REALLY_SET_NO_TEXTURE the_display.SetTexture(NULL) +#define REALLY_SET_TEXTURE_STATE(n,t,s) the_display.SetTextureState(n,t,s) + +/* +// macros used in code - *usually* just call REALLY_* +#define SET_RENDER_STATE(t,s) REALLY_SET_RENDER_STATE(t,s) +#define SET_TEXTURE(tex) REALLY_SET_TEXTURE(tex) +#define SET_NO_TEXTURE REALLY_SET_NO_TEXTURE +#define SET_TEXTURE_STATE(n,t,s) REALLY_SET_TEXTURE_STATE(n,t,s) +*/ + +//--------------------------------------------------------------- + +#ifndef NDEBUG + +#ifdef TARGET_DC + + +#undef FAILED +#undef SUCCEEDED +//#define FAILED(f) (ASSERT((signed)(f)>=0),(signed)(f)<0) +#define FAILED(f) ((signed)(f)<0) +#define SUCCEEDED(f) ((signed)(f)>=0) + + + +#else //#ifdef TARGET_DC + + +inline SLONG check_result(HRESULT f, SLONG line, CBYTE *file) +{ +// if (f == DD_OK) // this is an *INCORRECT* error test; see e.g. Petzold "Programming Windows 95" + if ( f >= 0 ) + { + return FALSE; + } + else + { + TRACE("%s(%d):\n\t", file, line); + LogText("Error in %s line %d\n\t", file, line); + dd_error(f); + + return TRUE; + } +} + +#undef FAILED +#undef SUCCEEDED +#define FAILED(f) (check_result(f, __LINE__, __FILE__)) +#define SUCCEEDED(f) (!FAILED(f)) + +#endif //#else //#ifdef TARGET_DC + + +#endif // else use Micro$oft macros + +#endif + diff --git a/fallen/DDLibrary/Headers/DIManager.h b/fallen/DDLibrary/Headers/DIManager.h new file mode 100644 index 0000000..2de523b --- /dev/null +++ b/fallen/DDLibrary/Headers/DIManager.h @@ -0,0 +1,364 @@ +// DIManager.h +// Guy Simmons, 19th February 1998. + +#ifndef DIMANAGER_H +#define DIMANAGER_H + +#ifdef TARGET_DC +#include "mapledev.h" +#include "lcd.h" +#include "vib.h" +#include "perstore.h" +#include "maptimer.h" +#endif + +//--------------------------------------------------------------- + +#define MOUSE DIDEVTYPE_MOUSE +#define KEYBOARD DIDEVTYPE_KEYBOARD +#define JOYSTICK DIDEVTYPE_JOYSTICK + +//--------------------------------------------------------------- + +#define DI_DRIVER_INIT (1<<0) + +#define DI_DEVICE_VALID (1<<0) +#define DI_DEVICE_NEEDS_POLL (1<<1) + + +#ifdef TARGET_DC +// DC needs to cope with different controllers +#define ENABLE_REMAPPING 1 +#else +// PC doesn't +#define ENABLE_REMAPPING 0 +#endif + +//--------------------------------------------------------------- + +// If bActuallyGetOne is FALSE, then just the current types are set up, no device is actually grabbed. +void ClearPrimaryDevice ( void ); +BOOL GetInputDevice ( UBYTE type, UBYTE sub_type, bool bActuallyGetOne = TRUE ); +BOOL ReadInputDevice(void); + + + +#ifdef TARGET_DC + + + + + + + + +#ifdef TARGET_DC +struct VMU_Screen +{ + bool bRotated; // TRUE if this has been rotated. + BYTE bData[32*6]; // The bitmap data itself. +}; + +// Roattes a VMU screen. bRotated is the state you want the screen to be in. +// The rout will then rotate if necessary. +void RotateVMUScreen ( bool bRotated, VMU_Screen *pvmuScreen ); + +// A routine for converting a TGA to a VMU screen bitmap. +bool CreateVMUScreenFromTGA ( char *pchName, VMU_Screen **ppvmuScreen ); + +// Displays the given screen on all the screen devices on the current controller. +// If there is no primary, it displays it on all of the controllers. +// This is what you generally call to display an image. +bool WriteLCDScreenToCurrentController ( VMU_Screen *pvmuScreen ); + +#endif + + + + + +// A VMU device. +class MapleVMU +{ +public: + MapleVMU *pNextVMU; // The next VMU on this device. + + MAPLEDEVTYPE type; // What sort of device is this? + GUID guid; // The device's GUID. + int iEnumNumber; // What number device is this on this controller (0/1)? + bool bUpsideDown; // TRUE if a VMU screen is upside down or not. + union + { + IUnknown *pUnknown; // Generic pointer + //PLGUN pLgun; // Light gun interface. + PLCD pLcd; // LCD interface. + LPFLASHDEVICE pFlash; // Flash memory device + PTMR pTimer; // Timer device + PVIB pVib; // Vibration device + }; + + DWORD dwLcdBufferId; // ID for the LCD buffer. + BYTE *pLcdBuffer; // The LCD buffer; + + bool Vib_bGotDevInfo; // Have we got the device's data yet? + float Vib_fMinFreq; // Minimum vibration freq. + float Vib_fMaxFreq; // Maximum vibration freq. + + MapleVMU ( void ) + { + pNextVMU = NULL; + type = 0; + iEnumNumber = -1; + pUnknown = NULL; + bUpsideDown = TRUE; + dwLcdBufferId = 0; + pLcdBuffer = NULL; + Vib_bGotDevInfo = FALSE; + Vib_fMinFreq = 0.5f; + Vib_fMaxFreq = 20.0f; + } + + ~MapleVMU ( void ) + { + if ( pLcdBuffer != NULL ) + { + ASSERT ( type == MDT_LCD ); + ASSERT ( pLcd != NULL ); + ASSERT ( dwLcdBufferId != 0 ); + pLcd->FreeLcdBuffer ( dwLcdBufferId ); + dwLcdBufferId = 0; + pLcdBuffer = NULL; + } + if ( pUnknown != NULL ) + { + // Whatever it was, release it. + pUnknown->Release(); + } + } + + // Call these to make sure you've grabbed the interface pointer. + void EnsureDevicePtr ( void ); + + // Write this standard 48x32 bitmap to the LCD. + // Data format is 3x32 bytes, like you'd expect. + // If bQueue is TRUE, this (almost) always works. + // If bQueue is FALSE, if there is a problem, like it's busy, + // then it can fail, and the return is FALSE; + // If the LCD screen is not a standard type, then it does its best, + // or fails and returns FALSE. + bool Lcd_WriteScreen ( void *pvData, bool bQueue ); + + + // Write this screen to the LCD device. + // The screen will be rotated as needed. + // If bQueue is TRUE, this (almost) always works. + // If bQueue is FALSE, if there is a problem, like it's busy, + // then it can fail, and the return is FALSE; + // If the LCD screen is not a standard type, then it does its best, + // or fails and returns FALSE. + bool Lcd_WriteScreen ( VMU_Screen *pvmuScreen, bool bQueue ); + + + + // Get a directory of the flash device. Return is an array of strings. + // YOU DO NOT OWN THIS ARRAY. If you want to use it or store it, + // copy it. The array may change/move next time you do any Maple call. + char **Flash_GetDirectory ( void ); + + // Get the size of the given file. If it doesn't exist, the result is -1. + DWORD Flash_GetFileSize ( char *pcFilename ); + + // Reads the given file into pvData, which is of size dwSizeOfData. + // Return is TRUE on success, FALSE on failure. + bool Flash_ReadFile ( char *pcFilename, void *pvData, DWORD dwSizeOfData ); + + // Creates the given file & writes the given data to it. + // pcGameName is the game name you wish to be tagged onto the file. Must be less than 16 chars. + // pcComment is any comment you wish to be tagged onto the file. Must be less than 16 chars. + // If the file already exists, it is deleted. + // If there is not enough space on the device, the call will fail. + // Return is TRUE on success, FALSE on failure. + bool Flash_WriteFile ( char *pcFilename, char *pcGameName, char *pcComment, void *pvData, DWORD dwSizeOfData, + char *pcIconPalette, char *pcIconData ); + + // Returns the number of free blocks in this VMU. + // If there is an error, -1 is returned. + int Flash_GetFreeBlocks ( void ); + + +}; + + + + +//--------------------------------------------------------------- + +class DIDeviceInfo +{ + private: + protected: + public: + CBYTE Instance[MAX_PATH], // Device instance name. + Product[MAX_PATH]; // Device product name. + UBYTE DeviceType, // Device type, e.g. Joystick + DeviceSubType; // Device sub type. e.g. Traditional, Gamepad etc. + UBYTE NumButtons; // Number of buttons on this device. + UBYTE NumAxis; // Number of axis on this device. + + UBYTE PortNumber; // Port number, if known. + +#if ENABLE_REMAPPING + UBYTE AxisMappings[2]; // Mapping from DI stuff to my standardised ones. + UBYTE ButtonMappings[32]; // A mapping from DI stuff to my standardised input mapping. +#endif + + ULONG DeviceFlags; // DI Device flags + + GUID guidInstance; + + DIDeviceInfo *Next, + *Prev; + LPDIRECTINPUTDEVICE2 lpdiInputDevice; // DI Device. + +#ifdef TARGET_DC + // The VMUs connected to this device. + MapleVMU *pFirstVMU; // The first VMU on this system. + DWORD dwDirection; // The slot direction field. +#endif + + DIDeviceInfo(); + ~DIDeviceInfo(); + + // DeviceInfo methods. + HRESULT Create(LPCDIDEVICEINSTANCE lpDIDevice); + void Destroy(void); + + inline BOOL IsValid(void) { return DeviceFlags&DI_DEVICE_VALID; } + inline void ValidOn(void) { DeviceFlags |= DI_DEVICE_VALID; } + inline void ValidOff(void) { DeviceFlags &= ~DI_DEVICE_VALID; } + + inline BOOL NeedsPoll(void) { return DeviceFlags&DI_DEVICE_NEEDS_POLL; } + inline void NeedsPollOn(void) { DeviceFlags |= DI_DEVICE_NEEDS_POLL; } + inline void NeedsPollOff(void) { DeviceFlags &= ~DI_DEVICE_NEEDS_POLL; } + + BOOL GetThisDevice ( UBYTE type ); + BOOL DIEnumDeviceObjectsProc ( LPCDIDEVICEOBJECTINSTANCE pDIDOI ); + + +}; + +//--------------------------------------------------------------- + +class DIDriverManager +{ + private: + protected: + public: + ULONG ManagerFlags, // Global flags + DeviceCount; // Count of DI Devices. + + bool bVMUScreenUpdatesEnabled; + + DIDeviceInfo *DeviceList, // List of DI Device. + *DeviceListEnd; + LPDIRECTINPUT lp_DI; // The DirectInput object. + + DIDriverManager(); + ~DIDriverManager(); + + // Methods. + HRESULT Init(void); + HRESULT Fini(void); + + HRESULT LoadDevices ( bool *pbChanged=NULL ); + HRESULT DestroyAllDevices(void); + HRESULT DestroyDevice(DIDeviceInfo *the_device); + + HRESULT AddDevice(DIDeviceInfo *the_driver); + DIDeviceInfo *FindDevice(UBYTE type,UBYTE sub_type,DIDeviceInfo **next_best,DIDeviceInfo *start_device=NULL); + + DIDeviceInfo *FindFirstWithButtonPressed ( UBYTE type, UBYTE sub_type ); + + int ScanForVMUs ( void ); + + inline BOOL IsInitialised(void) { return ManagerFlags&DI_DRIVER_INIT; } + inline void InitOn(void) { ManagerFlags |= DI_DRIVER_INIT; } + inline void InitOff(void) { ManagerFlags &= ~DI_DRIVER_INIT; } +}; + +extern DIDriverManager the_input_manager; + + + + +// Allows or disallows the automatic update of VMU screens. +// This can be quite slow, and for time-critical things (e.g. +// video playbacl), you'll want to turn it off. Do turn it back on +// afterwards though. +void SetVMUScreenUpdateEnable ( bool bEnable ); + + +// Gets the first VMU on the primary controller. If it can't find it, +// it takes the first VMU on the first controller it finds. +MapleVMU *FindFirstVMUOnCurrentController ( void ); + + +// Tries to find a memory VMU at slot iVMUNum on controller iCtrlNum. +// If not, returns NULL. Controllers are numbered 0-3, VMU numbers 0-1. +MapleVMU *FindMemoryVMUAt ( int iCtrlNum, int iVMUNum ); + + +// Forces a rescan of devices. Any new devices will be added to the available list. +// This does not reassign the primary - if you want to do that, +// call ClearPrimaryDevice(). +// If anything new was found, or anything existing was removed, returns TRUE. +bool RescanDevices ( void ); + +// Often called after a RescanDevices - deletes any missing devices. +void DeleteInvalidDevice ( void ); + +// Returns the current VMU. If it can't be found any more, and +// bFindNextBest is TRUE, it tries to find the first one on the +// primary, and then tries to find the first one on anything. +// If bFindNextBest is FALSE, it just returns NULL. +MapleVMU *FindCurrentStorageVMU ( bool bFindNextBest ); + +// Sets the current storage VMU. If NULL, there will be no current VMU. +void SetCurrentStorageVMU ( MapleVMU *pVMU ); + + + +// Tries to find a vibration VMU on the primary. If there are two (unlikely), +// it retruns the first one. If there are none, it returns NULL. +// Yes, I know they're not actually VMUs that vibrate. +MapleVMU *FindFirstVibratorOnCurrentController ( void ); + + +// Turn vibrations on or off. +void SetVibrationEnable ( bool bEnabled ); + + +// Make the vibrator in the primary device vibrate with the given +// characteristics. Returns TRUE if it works, or FALSE if not. +// The most common cause of FALSE is that another vibration +// is already happening, or was set off very recently. +// +// fFrequency is in Hz. +// fStartPower is from 1.0 (max) to 0.0 +// fShrinkTime is the time in seconds for the power to shrink to 0. +// If this is 0, the effect will be a one-shot one - a single jolt, basically. +// bEnsureThisHappens - set this to TRUE to wait for up to a tenth of a second +// for this to be activated. This is for important thing. +bool Vibrate ( float fFrequency, float fStartPower, float fShrinkTime, bool bEnsureThisHappens=FALSE ); + + + +#endif + +//--------------------------------------------------------------- + + + + + +#endif diff --git a/fallen/DDLibrary/Headers/DSManager.h b/fallen/DDLibrary/Headers/DSManager.h new file mode 100644 index 0000000..d0a4e04 --- /dev/null +++ b/fallen/DDLibrary/Headers/DSManager.h @@ -0,0 +1,48 @@ +// DSManager.h +// Guy Simmons, 22nd February 1998. + +#ifndef DSMANAGER_H +#define DSMANAGER_H + +//--------------------------------------------------------------- + +#define DS_DRIVER_INIT (1<<0) + +#define DS_DRIVER_VALID (1<<0) + +//--------------------------------------------------------------- + +class DSDriverManager +{ + private: + protected: + public: + ULONG ManagerFlags; // Global flags + LPDIRECTSOUND lp_DS; // The DirectSound object. + + + DSDriverManager(); + ~DSDriverManager(); + + // Methods. + HRESULT Init(void); + HRESULT Fini(void); + + + inline BOOL IsInitialised(void) { return ManagerFlags&DS_DRIVER_INIT; } + inline void InitOn(void) { ManagerFlags |= DS_DRIVER_INIT; } + inline void InitOff(void) { ManagerFlags &= ~DS_DRIVER_INIT; } + + inline HRESULT CreateSoundBuffer(LPCDSBUFFERDESC desc,LPLPDIRECTSOUNDBUFFER buff,IUnknown FAR * u) + { + return lp_DS->CreateSoundBuffer(desc,buff,u); + } + +}; + +extern DSDriverManager the_sound_manager; + +//--------------------------------------------------------------- + +#endif + diff --git a/fallen/DDLibrary/Headers/Debug.h b/fallen/DDLibrary/Headers/Debug.h new file mode 100644 index 0000000..ae0bb56 --- /dev/null +++ b/fallen/DDLibrary/Headers/Debug.h @@ -0,0 +1,28 @@ +// Debug.h +// Guy Simmons, 15th November 1997. + +#ifndef DEBUG_H +#define DEBUG_H + +//--------------------------------------------------------------- + +#ifndef NDEBUG + +HANDLE InitDebugLog(void); +void FiniDebugLog(void); +void DebugText(CBYTE *error, ...); +void dd_error(HRESULT dd_err); +void d3d_error(HRESULT dd_err); +void di_error(HRESULT di_err); + +#else + +#define dd_error +#define d3d_error +#define di_error + +#endif + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/DDLibrary/Headers/Drive.h b/fallen/DDLibrary/Headers/Drive.h new file mode 100644 index 0000000..fbde845 --- /dev/null +++ b/fallen/DDLibrary/Headers/Drive.h @@ -0,0 +1,12 @@ +// drive.h +// +// handles CD-ROM drives + +void LocateCDROM(void); + +char* GetCDPath(void); +char* GetTexturePath(void); +char* GetSFXPath(void); +char* GetMoviesPath(void); +char* GetSpeechPath(void); + diff --git a/fallen/DDLibrary/Headers/FFManager.h b/fallen/DDLibrary/Headers/FFManager.h new file mode 100644 index 0000000..7bc159a --- /dev/null +++ b/fallen/DDLibrary/Headers/FFManager.h @@ -0,0 +1,35 @@ +// FFManager.h +// 18th Sept 98 +// +// Limitations: Currently assumes first joystick + +#include "MFStdLib.h" +#include "DIManager.h" + + +#ifdef TARGET_DC +#error Silly person! DC has no force feedback. +#endif + +#if 0 + +PC doesn't have DIDeviceInfo's any more + +class FFManager { + private: + SLONG ForceFeedback; + LPDIRECTINPUTEFFECT testeffect; + DIDeviceInfo* DeviceInfo; + LPDIRECTINPUTDEVICE2 lpdiInputDevice; // DI Device. + public: + FFManager(); + ~FFManager(); + + BOOL FFSupported(LPDIRECTINPUTDEVICE2 device); + void ReleaseFX(); + BOOL Test(); +}; + +extern FFManager* the_ff_manager; + +#endif \ No newline at end of file diff --git a/fallen/DDLibrary/Headers/FileClump.h b/fallen/DDLibrary/Headers/FileClump.h new file mode 100644 index 0000000..9d4396b --- /dev/null +++ b/fallen/DDLibrary/Headers/FileClump.h @@ -0,0 +1,32 @@ +// FileClump.h +// +// File clump class - contains multiple files + +#ifndef FILECLUMP_H +#define FILECLUMP_H + +// FileClump +// +// a bunch of files stored in a metafile + +class FileClump +{ +public: + FileClump(const char* clumpfn, ULONG max_id, bool readonly); + ~FileClump(); + + bool Exists(ULONG id); // sees if a file exists + + UBYTE* Read(ULONG id); // read a whole file + bool Write(void* buffer, size_t nbytes, ULONG id); // write a whole file + +private: + FILE* ClumpFD; // FILE* for the clump, may be NULL if the open failed + ULONG MaxID; // maximum ID + size_t* Offsets; // MaxID offsets + size_t* Lengths; // MaxID lengths + size_t NextOffset; // next offset for writing + bool ReadOnly; // read-only flag +}; + +#endif // FILECLUMP_H diff --git a/fallen/DDLibrary/Headers/GDisplay.h b/fallen/DDLibrary/Headers/GDisplay.h new file mode 100644 index 0000000..a8392c9 --- /dev/null +++ b/fallen/DDLibrary/Headers/GDisplay.h @@ -0,0 +1,467 @@ +// Display.h +// Guy Simmons, 13th November 1997. + +#ifndef DISPLAY_H +#define DISPLAY_H + +#include "DDManager.h" + + +#ifdef TARGET_DC +#define USE_COMPRESSED_BACKGROUNDS 1 +#else +#define USE_COMPRESSED_BACKGROUNDS 0 +#endif + +//--------------------------------------------------------------- + +#define SHELL_ACTIVE (LibShellActive()) +#define SHELL_CHANGED (LibShellChanged()) +#define FLAGS_USE_3D (1<<1) +#define FLAGS_USE_WORKSCREEN (1<<2) + +//--------------------------------------------------------------- + +#define DEFAULT_WIDTH (640) +#define DEFAULT_HEIGHT (480) +#define DEFAULT_DEPTH (16) + + +enum enumDisplayType +{ + DT_PAL, + DT_NTSC, + DT_VGA, +}; + +extern enumDisplayType eDisplayType; + + +//--------------------------------------------------------------- + +#if USE_COMPRESSED_BACKGROUNDS +typedef void *CompressedBackground; +#endif + + +extern void InitBackImage(CBYTE *name); +#if USE_COMPRESSED_BACKGROUNDS +extern void UseBackSurface(CompressedBackground use); +#else +extern void UseBackSurface(LPDIRECTDRAWSURFACE4 use); +#endif +extern void ResetBackImage(void); +// Set b3DInFrame to FALSE if there is no 3D going on, i.e. blits will work on the DC. +// Ignored for the PC. +extern void ShowBackImage(bool b3DInFrame = TRUE); + +SLONG OpenDisplay(ULONG width, ULONG height, ULONG depth, ULONG flags); +SLONG CloseDisplay(void); +SLONG SetDisplay(ULONG width,ULONG height,ULONG depth); +SLONG ClearDisplay(UBYTE r,UBYTE g,UBYTE b); +void ShellPaused(void); +void ShellPauseOn(void); +void ShellPauseOff(void); +void DumpBackToTGA(CBYTE *tga_name); +void DumpBackToRaw(void); // To shot\ + +//--------------------------------------------------------------- + +#define DISPLAY_INIT (1<<0) +#define DISPLAY_PAUSE (1<<1) +#define DISPLAY_PAUSE_ACK (1<<2) +#define DISPLAY_LOCKED (1<<3) + +#define BK_COL_NONE 0 +#define BK_COL_BLACK 1 +#define BK_COL_WHITE 2 +#define BK_COL_USER 3 + + + +class Display +{ + private: + protected: + enum + { + DWF_FULLSCREEN = (1<<0), + DWF_VISIBLE = (1<<1), + DWF_ZBUFFER = (1<<2), + DWF_ACTIVE = (1<<3), + DWF_USE_3D = (1<<4), + DWF_USE_WORK = (1<<5), + DWF_DISPLAY_CHANGED = (1<<6), + DWF_TEXTURES_INVALID = (1<<7) + }Attributes; + + enum + { + DWF_VALID_INTERFACE = (1<<0), + DWF_VALID_FULLSCREEN = (1<<1), + DWF_VALID_FRONT = (1<<2), + DWF_VALID_BACK = (1<<3), + DWF_VALID_WORK = (1<<4), + DWF_VALID_CLIPPER = (1<<5), + DWF_VALID_VIEWPORT = (1<<6), + + DWF_VALID = DWF_VALID_INTERFACE | + DWF_VALID_FULLSCREEN | + DWF_VALID_FRONT | + DWF_VALID_BACK + }Validates; + + volatile SLONG AttribFlags, // Attribute flags. + ValidFlags, // Validation flags. + PauseCount; + + + + inline void TurnValidInterfaceOn(void) { ValidFlags |= DWF_VALID_INTERFACE; } + inline void TurnValidInterfaceOff(void) { ValidFlags &= ~DWF_VALID_INTERFACE; } + + inline void TurnValidFullscreenOn(void) { ValidFlags |= DWF_VALID_FULLSCREEN; } + inline void TurnValidFullscreenOff(void) { ValidFlags &= ~DWF_VALID_FULLSCREEN; } + + inline void TurnValidFrontOn(void) { ValidFlags |= DWF_VALID_FRONT; } + inline void TurnValidFrontOff(void) { ValidFlags &= ~DWF_VALID_FRONT; } + + inline void TurnValidBackOn(void) { ValidFlags |= DWF_VALID_BACK; } + inline void TurnValidBackOff(void) { ValidFlags &= ~DWF_VALID_BACK; } + + inline void TurnValidWorkOn(void) { ValidFlags |= DWF_VALID_WORK; } + inline void TurnValidWorkOff(void) { ValidFlags &= ~DWF_VALID_WORK; } + + inline void TurnValidClipperOn(void) { ValidFlags |= DWF_VALID_CLIPPER; } + inline void TurnValidClipperOff(void) { ValidFlags &= ~DWF_VALID_CLIPPER; } + + inline void TurnValidViewportOn(void) { ValidFlags |= DWF_VALID_VIEWPORT; } + inline void TurnValidViewportOff(void) { ValidFlags &= ~DWF_VALID_VIEWPORT; } + + inline BOOL IsValidDefaults(void) { return ((CurrDriver && CurrMode && CurrDevice) ? TRUE : FALSE); } + inline BOOL IsValidInterface(void) { return ((ValidFlags&DWF_VALID_INTERFACE) ? TRUE : FALSE); } + inline BOOL IsValidFullscreen(void) { return ((ValidFlags&DWF_VALID_FULLSCREEN) ? TRUE : FALSE); } + inline BOOL IsValidFront(void) { return ((ValidFlags&DWF_VALID_FRONT) ? TRUE : FALSE); } + inline BOOL IsValidBack(void) { return ((ValidFlags&DWF_VALID_BACK) ? TRUE : FALSE); } + inline BOOL IsValidWork(void) { return ((ValidFlags&DWF_VALID_WORK) ? TRUE : FALSE); } + inline BOOL IsValidClipper(void) { return ((ValidFlags&DWF_VALID_CLIPPER) ? TRUE : FALSE); } + inline BOOL IsValidViewport(void) { return ((ValidFlags&DWF_VALID_VIEWPORT) ? TRUE : FALSE); } + + UBYTE *background_image_mem; + +#ifdef TARGET_DC + bool bInScene; + LPDIRECTDRAWSURFACE4 psurfBackHandle; +#endif + + public: + ULONG BackColour, + PaletteSize; + D3DDeviceInfo *CurrDevice; // Current Device + D3DMATERIALHANDLE black_handle, + white_handle, + user_handle; + D3DRECT ViewportRect; + D3DTexture *TextureList; + DDDriverInfo *CurrDriver; // Current Driver + DDModeInfo *CurrMode; // Current Mode + GUID *DDGuid; + LPDIRECT3D3 lp_D3D; + LPDIRECT3DDEVICE3 lp_D3D_Device; + LPDIRECT3DMATERIAL3 lp_D3D_Black, + lp_D3D_White, + lp_D3D_User; + LPDIRECT3DVIEWPORT3 lp_D3D_Viewport; + LPDIRECTDRAW lp_DD; + LPDIRECTDRAW4 lp_DD4; + LPDIRECTDRAWCLIPPER lp_DD_Clipper; + LPDIRECTDRAWPALETTE lp_DD_Palette; + LPDIRECTDRAWSURFACE4 lp_DD_FrontSurface, + lp_DD_BackSurface, +#ifndef TARGET_DC + lp_DD_WorkSurface, +#endif + lp_DD_ZBuffer; +#if USE_COMPRESSED_BACKGROUNDS + CompressedBackground lp_DD_Background, + lp_DD_Background_use_instead; +#else + LPDIRECTDRAWSURFACE4 lp_DD_Background, + lp_DD_Background_use_instead; +#endif +#ifdef TARGET_DC + LPDIRECT3DTEXTURE2 lp_DD_Background_use_instead_texture; + LPDIRECT3DTEXTURE2 lp_DD_Background_use_instead_texture2; +#endif + IDirectDrawGammaControl* lp_DD_GammaControl; + PALETTEENTRY *lp_SysPalette, + *lp_CurrPalette; + RECT DisplayRect; // Current surface rectangle. + + // + // Pixel format variables. + // + + SLONG mask_red; + SLONG mask_green; + SLONG mask_blue; + SLONG shift_red; + SLONG shift_green; + SLONG shift_blue; + + // + // For writing directly to the back-buffer. These + // are only valid when the screen is locked. + // + + SLONG screen_width; + SLONG screen_height; + SLONG screen_pitch; + SLONG screen_bbp; + UBYTE *screen; + + volatile ULONG DisplayFlags; + + Display(); + ~Display(); + + // Methods. + HRESULT Init(void); + HRESULT Fini(void); + + HRESULT GenerateDefaults(void); + + HRESULT InitInterfaces(void); + HRESULT FiniInterfaces(void); + + HRESULT InitWindow(void); + HRESULT FiniWindow(void); + + HRESULT InitFullscreenMode(void); + HRESULT FiniFullscreenMode(void); + + HRESULT InitFront(void); + HRESULT FiniFront(void); + + HRESULT InitPalette(void); + HRESULT FiniPalette(void); + + HRESULT InitBack(void); + HRESULT FiniBack(void); + +#ifdef TARGET_DC + HRESULT InitBackCache(void); + HRESULT FiniBackCache(void); +#endif + + HRESULT InitViewport(void); + HRESULT FiniViewport(void); + HRESULT UpdateViewport(void); + + HRESULT InitWork(void); + HRESULT FiniWork(void); + + HRESULT InitClipper(void); + HRESULT FiniClipper(void); + + void RunFMV(); + void RunCutscene(int which, int language=0, bool bAllowButtonsToExit=TRUE ); + + HRESULT ChangeDriver(GUID *DD_guid,D3DDeviceInfo *device_hint,DDModeInfo *mode_hint); + HRESULT ChangeDevice(GUID *D3D_guid,DDModeInfo *mode_hint); + HRESULT ChangeMode(SLONG w,SLONG h,SLONG bpp,SLONG refresh); + + bool IsGammaAvailable(); + void SetGamma(int black = 0, int white = 256); + void GetGamma(int* black, int* white); + + HRESULT Restore(void); + + HRESULT AddLoadedTexture(D3DTexture *the_texture); // Remember this texture + void RemoveAllLoadedTextures(void); // Forget all textures + HRESULT FreeLoadedTextures(void); // Destroy each texture you know + HRESULT ReloadTextures(void); + + HRESULT toGDI(void); + HRESULT fromGDI(void); + + void *screen_lock (void); + void screen_unlock(void); + + void MenuOn(void); + void MenuOff(void); +#ifndef TARGET_DC + HRESULT ShowWorkScreen(void); +#endif + + void blit_back_buffer(void); + +#ifdef TARGET_DC + // Sod the user colour background stuff - it's junk. + // Something always gets blitted over it anyway. + void SetUserColour(UBYTE red, UBYTE green, UBYTE blue) {} + + inline HRESULT SetBlackBackground(void) { return DD_OK; } + inline HRESULT SetWhiteBackground(void) { return DD_OK; } + inline HRESULT SetUserBackground(void) { return DD_OK; } + inline HRESULT BeginScene(void) { + //TRACE("BeginScene "); + if ( bInScene ) + { + return ( DD_OK ); + } + else + { + bInScene = TRUE; + return lp_D3D_Device->BeginScene(); + } + } + inline HRESULT EndScene(void) { /*TRACE("EndScene ");*/ bInScene = FALSE; return lp_D3D_Device->EndScene(); } + inline HRESULT ClearViewport(void) { + HRESULT hres = lp_D3D_Viewport->Clear ( + 1, + &ViewportRect, + D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER + ); + return hres; + } +#else //#ifdef TARGET_DC + + void SetUserColour(UBYTE red, UBYTE green, UBYTE blue); + + inline HRESULT SetBlackBackground(void) { BackColour=BK_COL_BLACK; return lp_D3D_Viewport->SetBackground(black_handle); } + inline HRESULT SetWhiteBackground(void) { BackColour=BK_COL_WHITE; return lp_D3D_Viewport->SetBackground(white_handle); } + inline HRESULT SetUserBackground(void) { BackColour=BK_COL_USER; return lp_D3D_Viewport->SetBackground(user_handle); } + inline HRESULT BeginScene(void) { return lp_D3D_Device->BeginScene(); } + inline HRESULT EndScene(void) { return lp_D3D_Device->EndScene(); } + inline HRESULT ClearViewport(void) { + return lp_D3D_Viewport->Clear ( + 1, + &ViewportRect, + D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER + ); + } +#endif //#else //#ifdef TARGET_DC + + inline HRESULT SetRenderState(D3DRENDERSTATETYPE type,SLONG state) + { + return lp_D3D_Device->SetRenderState(type,state); + } + inline HRESULT SetTexture(LPDIRECT3DTEXTURE2 tex) + { + ASSERT ( lp_D3D_Device != NULL ); + return lp_D3D_Device->SetTexture(0, tex); + } + inline HRESULT SetTextureState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD dw) + { + return lp_D3D_Device->SetTextureStageState(stage, type, dw); + } + + HRESULT Flip(LPDIRECTDRAWSURFACE4 alt,SLONG flags); + + inline HRESULT DrawPrimitive(D3DPRIMITIVETYPE p_type,DWORD dwVertexDesc,LPVOID v,DWORD v_count,DWORD flags) + { + return lp_D3D_Device->DrawPrimitive(p_type,dwVertexDesc,v,v_count,flags); + } + inline HRESULT DrawIndexedPrimitive(D3DPRIMITIVETYPE p_type,DWORD dwVertexDesc,LPVOID v,DWORD v_count,LPWORD i,DWORD i_count,DWORD flags) + { + return lp_D3D_Device->DrawIndexedPrimitive(p_type,dwVertexDesc,v,v_count,i,i_count,flags); + } + + + inline BOOL IsValid(void) { return (((ValidFlags&DWF_VALID)==DWF_VALID) ? TRUE : FALSE); } + + inline BOOL IsDisplayChanged(void) { return (((AttribFlags&DWF_DISPLAY_CHANGED)==DWF_DISPLAY_CHANGED) ? TRUE : FALSE); } + inline void DisplayChangedOn(void) { AttribFlags |= DWF_DISPLAY_CHANGED; } + inline void DisplayChangedOff(void) { AttribFlags &= ~DWF_DISPLAY_CHANGED; } + + inline BOOL IsTexturesInvalid(void) { return (((AttribFlags&DWF_TEXTURES_INVALID)==DWF_TEXTURES_INVALID) ? TRUE : FALSE);} + inline void TexturesInvalidOn(void) { AttribFlags |= DWF_TEXTURES_INVALID; } + inline void TexturesInvalidOff(void) { AttribFlags &= ~DWF_TEXTURES_INVALID; } + + inline BOOL IsFullScreen(void) { return (AttribFlags&DWF_FULLSCREEN); } + inline void FullScreenOn(void) { AttribFlags |= DWF_FULLSCREEN; } + inline void FullScreenOff(void) { AttribFlags &= ~DWF_FULLSCREEN; } + + inline BOOL IsCreateZBuffer(void) { return (AttribFlags&DWF_ZBUFFER); } + inline void CreateZBufferOn(void) { AttribFlags |= DWF_ZBUFFER; } + inline void CreateZBufferOff(void) { AttribFlags &= ~DWF_ZBUFFER; } + + inline BOOL IsUse3D(void) { return (AttribFlags&DWF_USE_3D); } + inline void Use3DOn(void) { AttribFlags |= DWF_USE_3D; } + inline void Use3DOff(void) { AttribFlags &= ~DWF_USE_3D; } + +#ifndef TARGET_DC + inline BOOL IsUseWork(void) { return (AttribFlags&DWF_USE_WORK); } + inline void UseWorkOn(void) { AttribFlags |= DWF_USE_WORK; } + inline void UseWorkOff(void) { AttribFlags &= ~DWF_USE_WORK; } +#endif + + inline BOOL IsInitialised(void) { return DisplayFlags&DISPLAY_INIT; } + inline void InitOn(void) { DisplayFlags |= DISPLAY_INIT; } + inline void InitOff(void) { DisplayFlags &= ~DISPLAY_INIT; } + + inline DDDriverInfo *GetDriverInfo(void) { return CurrDriver; } + inline DDModeInfo *GetModeInfo(void) { return CurrMode; } + inline D3DDeviceInfo *GetDeviceInfo(void) { return CurrDevice; } + + inline ULONG GetFormattedPixel(UBYTE r, UBYTE g, UBYTE b) {return ((r >> mask_red) << shift_red) | ((g >> mask_green) << shift_green) | ((b >> mask_blue) << shift_blue);} + + // + // The screen must be locked for these functions to work! + // + + void PlotPixel (SLONG x, SLONG y, UBYTE red, UBYTE green, UBYTE blue); + void PlotFormattedPixel(SLONG x, SLONG y, ULONG colour); + void GetPixel (SLONG x, SLONG y, UBYTE *red, UBYTE *green, UBYTE *blue); + + // + // A background picture... The image must be the same dimensions as the + // back buffer and the image data must remain valid while the surface + // is alive. + // + + void create_background_surface(UBYTE *image_data); // Must be same dimensions as back buffer! +#if USE_COMPRESSED_BACKGROUNDS + void use_this_background_surface(CompressedBackground this_one); +#else + void use_this_background_surface(LPDIRECTDRAWSURFACE4 this_one); +#endif + void blit_background_surface(bool b3DInFrame = TRUE); + void destroy_background_surface(void); +}; + + +#if USE_COMPRESSED_BACKGROUNDS +// This uses my funky pixel format. +// This only works to a 640x480,565 format image. +// Unpacks image_data into surface +extern void UnpackBackground ( UBYTE* image_data, IDirectDrawSurface4* surface ); +// This uses my funky pixel format. +// This only works to a 640x480,565 format image. +// Packs surface (640x480,565 pixels - raw data) into image_data. +// Returns the size of the packed version. You can pass in NULL for image_data, +// and it will just return the size, and not try to copy anything. +extern int PackBackground ( UBYTE* image_data, WORD *surface ); +#endif + + +//--------------------------------------------------------------- + +// they're macros now! +#define DisplayWidth 640 +#define DisplayHeight 480 + +extern SLONG RealDisplayWidth; +extern SLONG RealDisplayHeight; +extern SLONG DisplayBPP; +extern Display the_display; +extern volatile SLONG hDDLibStyle, + hDDLibStyleEx; +extern volatile HMENU hDDLibMenu; +extern volatile HWND hDDLibWindow; + +//--------------------------------------------------------------- + +#endif + diff --git a/fallen/DDLibrary/Headers/GWorkScreen.h b/fallen/DDLibrary/Headers/GWorkScreen.h new file mode 100644 index 0000000..9e29767 --- /dev/null +++ b/fallen/DDLibrary/Headers/GWorkScreen.h @@ -0,0 +1,48 @@ +// WorkScreen.h +// Guy Simmons, 10th December 1997 + +#ifndef WORK_SCREEN_H +#define WORK_SCREEN_H + + + +// Never used on DC. +#ifndef TARGET_DC + + +//--------------------------------------------------------------- + +extern UBYTE *WorkScreen, + WorkScreenDepth; +extern SLONG WorkScreenHeight, + WorkScreenWidth, + WorkScreenPixelWidth; + +extern UBYTE *WorkWindow; +extern SLONG WorkWindowHeight, + WorkWindowWidth; +extern MFRect WorkWindowRect; + +//--------------------------------------------------------------- + +void ShowWorkScreen(ULONG flags); +void *LockWorkScreen(void); +void UnlockWorkScreen(void); + +void SetWorkWindowBounds(SLONG left, SLONG top, SLONG width, SLONG height); + +inline void SetWorkWindow(void) { WorkWindow=(WorkScreen+WorkWindowRect.Left*WorkScreenDepth+(WorkWindowRect.Top*WorkScreenWidth)); } + +MFPoint *GlobalToLocal(MFPoint *the_point); +void GlobalXYToLocal(SLONG *x,SLONG *y); +inline BOOL XYInRect(SLONG x,SLONG y,MFRect *the_rect) { if(x>=the_rect->Left&&y>=the_rect->Top&&x<=the_rect->Right&&y<=the_rect->Bottom)return TRUE;else return FALSE; } +inline BOOL PointInRect(MFPoint *the_point,MFRect *the_rect) { if(the_point->X>=the_rect->Left&&the_point->Y>=the_rect->Top&&the_point->X<=the_rect->Right&&the_point->Y<=the_rect->Bottom)return TRUE;else return FALSE; } + +//--------------------------------------------------------------- + + + +#endif //#ifndef TARGET_DC + + +#endif diff --git a/fallen/DDLibrary/Headers/MFX_Miles.h b/fallen/DDLibrary/Headers/MFX_Miles.h new file mode 100644 index 0000000..35b5c87 --- /dev/null +++ b/fallen/DDLibrary/Headers/MFX_Miles.h @@ -0,0 +1,121 @@ +// MFX_Miles.h +// +// Miles Sound System + + +#ifndef TARGET_DC + +#ifndef _MFX_MILES_H_ +#define _MFX_MILES_H_ + +#include "c:\fallen\miles\mss.h" // i tried changing the project settings but it didn't care + +// MFX_Sample +// +// sample control block + +enum SampleType +{ + SMP_Ambient = 0, + SMP_Music, + SMP_Effect +}; + +struct MFX_Sample +{ + MFX_Sample* prev_lru; // prev LRU entry (i.e. sample used before this one) + MFX_Sample* next_lru; // next LRU entry (i.e. sample used after this one) + char* fname; // sample filename + void* dptr; // data pointer for sample, else NULL + bool is3D; // is 3D? + bool stream; // sample is to be streamed? + int rate; // sample rate (initialized when sample is loaded) + int size; // size of sample, in bytes + int usecount; // sample is in use (count) + int type; // SampleType of sample - used to get volume + float linscale; // linear scaling for sample volume - used to set 3D distances + bool loading; // sample is loading +}; + +#define MAX_SAMPLE 552 // max. number of samples +#define MIN_STREAM_SIZE 1024*1024 // samples bigger than this are streamed +#define MAX_SAMPLE_MEM 16*1024*1024 // max. amount of sample mem + +// MFX_QWave +// +// control block for a queued wave + +struct MFX_QWave +{ + MFX_QWave* next; // next voice to be queued, or NULL + ULONG wave; // sound sample to be played + ULONG flags; // flags for the sample + SLONG x,y,z; // coordinates of the voice + float gain; // gain of voice +}; + +#define MAX_QWAVE 32 // number of queued wave slots +#define MAX_QVOICE 5 // maximum waves queued per voice + +// MFX_Voice +// +// voice control block + +struct Thing; + +struct MFX_Voice +{ + UWORD id; // channel_id for this voice + ULONG wave; // sound sample playing on this voice + ULONG flags; // flags for this voice (see mfx.h) + SLONG x,y,z; // coordinates of this voice + Thing* thing; // thing this voice belongs to + MFX_QWave* queue; // queue of samples to play + SLONG queuesz; // number of queued samples + MFX_Sample* smp; // sample being played + HSAMPLE h2D; // 2D sound handle + H3DSAMPLE h3D; // 3D sound handle + HSTREAM hStream; // stream handle + bool playing; // sample is playing? + float ratemult; // rate multiplier + float gain; // gain +}; + +#define MAX_VOICE 64 // number of voices +#define VOICE_MSK 63 // mask for voice indices + +// MFX_3D +// +// a 3D provider + +struct MFX_3D +{ + HPROVIDER hnd; + char* name; +}; + +#define MAX_PROVIDER 16 // max. number of providers + +// Miles-specific exports + +HDIGDRIVER GetMilesDriver(); + +int Get3DProviderList(MFX_3D** prov); +void Set3DProvider(int ix); +int Get3DProvider(); + +void SetLinScale(SLONG wave, float linscale); // set volume scaling for sample (1.0 = normal) +void SetPower(SLONG wave, float dB); // set power for sample in dB (0 = normal) + + + +void init_my_dialog (HWND hWnd); +void my_dialogs_over(HWND hWnd); + + + + +#endif + + +#endif //#ifndef TARGET_DC diff --git a/fallen/DDLibrary/Headers/MFx.h b/fallen/DDLibrary/Headers/MFx.h new file mode 100644 index 0000000..5ac7f9d --- /dev/null +++ b/fallen/DDLibrary/Headers/MFx.h @@ -0,0 +1,106 @@ +// +// MFx.h +// +// Muckyfoot sound fx api for A3D / PSX +// +// (same header, different cpp) +// +#ifndef _mfx_h_ +#define _mfx_h_ + + +#include "MFStdLib.h" +#include "c:\fallen\headers\structs.h" +#include "c:\fallen\headers\thing.h" + +// set this to enable forcing the PC to only play FX available on the PSX +#define DODGYPSXIFY 1 +// with this clear, the code to do it is taken out completely, for speed +// with this set, the code will look in the config.ini to see whether or not to PSXify sound. + + +#define MFX_LOOPED (1) // loop the wave infinitely +#define MFX_MOVING (2) // update the source's coords automatically +#define MFX_REPLACE (4) // play, replacing whatever's there and blatting the queue +#define MFX_OVERLAP (8) // allocate a new channel if current is occupied +#define MFX_QUEUED (16) // queue this up for later +#define MFX_CAMERA (32) // attach to camera +#define MFX_HI_PRIORITY (64) // these are for A3d not for us as they... +#define MFX_LO_PRIORITY (128) // ...determine priority for funky HW channels +#define MFX_LOCKY (256) // don't adjust Y coord when cam-ing or move-ing +#define MFX_SHORT_QUEUE (512) // for sync-ing music -- queue for later, but replace the top of the queue +#define MFX_PAIRED_TRK1 (1024) // when this chan starts playing, trigger the next chan in sync +#define MFX_PAIRED_TRK2 (2048) // don't start this wave until the previous chan triggers it +#define MFX_EARLY_OUT (4096) // mostly for music, 'breaks out' early from the wave, also works on loops +#define MFX_NEVER_OVERLAP (8192) // if anything at all playing on the channel, leave it + +#define MFX_ENV_NONE (0) +#define MFX_ENV_ALLEY (1) +#define MFX_ENV_SEWER (2) +#define MFX_ENV_STADIUM (3) + +#define MFX_CHANNEL_ALL (0x010000) +#define MFX_WAVE_ALL (0x010000) +// Excludes the memstream sounds. +#define MFX_WAVE_ALMOST_ALL (0x010001) + +//----- volume functions + +void MFX_get_volumes(SLONG* fx, SLONG* amb, SLONG* mus); // all 0 to 127 +void MFX_set_volumes(SLONG fx, SLONG amb, SLONG mus); + +//----- transport functions ----- + +void MFX_play_xyz(UWORD channel_id, ULONG wave, ULONG flags, SLONG x, SLONG y, SLONG z); +//void MFX_play_pos(UWORD channel_id, ULONG wave, ULONG flags, GameCoord* position); +void MFX_play_thing(UWORD channel_id, ULONG wave, ULONG flags, Thing* p); +void MFX_play_ambient(UWORD channel_id, ULONG wave, ULONG flags); +UBYTE MFX_play_stereo(UWORD channel_id, ULONG wave, ULONG flags); + +void MFX_stop(SLONG channel_id, ULONG wave); +void MFX_stop_attached(Thing *p); + +//----- audio processing functions ----- + +void MFX_set_pitch(UWORD channel_id, ULONG wave, SLONG pitchbend); +void MFX_set_gain(UWORD channel_id, ULONG wave, UBYTE gain); +void MFX_set_queue_gain(UWORD channel_id, ULONG wave, UBYTE gain); +//void MFX_set_wave(UWORD channel_id, ULONG wave, ULONG new_wave); +//void MFX_set_xyz(UWORD channel_id, ULONG wave, SLONG x, SLONG y, SLONG z); +//void MFX_set_pos(UWORD channel_id, ULONG wave, GameCoord* position); +//void MFX_set_channel_gain(UWORD channel_id, UBYTE gain); + +//----- listener & environment ----- + +void MFX_set_listener(SLONG x, SLONG y, SLONG z, SLONG heading, SLONG roll, SLONG pitch); +//void MFX_set_environment(SLONG env_type); + +//----- sound library functions ----- + +//void MFX_load_wave_list(CBYTE *path,CBYTE *script_file); // load list from a text file +void MFX_load_wave_list(CBYTE *names[]=0); // load list from array +//void MFX_load_wave_file(CBYTE *wave_file); // load file +void MFX_free_wave_list(); // free list + +//----- querying information back ----- + +UWORD MFX_get_wave(UWORD channel_id, UBYTE index=0); + +//----- general system stuff ----- + +void MFX_render ( void ); + +//----- init stuff (why the fuck there isn't MFX_init() and MFX_term() I'll never understand. Someone, somewhere in this company should take a dictionary out and look up the word "design". It's under D.) + +void MilesInit(HINSTANCE hInstance, HWND hWnd); +void MilesTerm(); + + +// Mikes bodge stuff to get conversation in + +SLONG MFX_QUICK_play(CBYTE *str, SLONG loop, SLONG x=0, SLONG y=0, SLONG z=0); // should be low-res (24.8) coordinates +void MFX_QUICK_wait(void); +void MFX_QUICK_stop ( bool bAllowMemstream = FALSE ); +SLONG MFX_QUICK_still_playing(void); + +#endif diff --git a/fallen/DDLibrary/Headers/QSManager.h b/fallen/DDLibrary/Headers/QSManager.h new file mode 100644 index 0000000..59d8c0e --- /dev/null +++ b/fallen/DDLibrary/Headers/QSManager.h @@ -0,0 +1,154 @@ +// QSManager.h +// Guy Simmons, 6th May 1998. + +#ifndef QSMANAGER_H +#define QSMANAGER_H + +//--------------------------------------------------------------- + +// #include "qmixer.h" +#include "qmdx.h" + +#if defined(QMDX_H) + #define QS(name) QMDX_ ## name +#ifndef TARGET_DC + #pragma comment(lib, "qmdx.lib") +#endif +#else + #define QS(name) QSWaveMix ## name +#ifndef TARGET_DC + #pragma comment(lib, "Qmixer.lib") +#endif +#endif + +//--------------------------------------------------------------- + +#define QS_WAVE_VALID (1<<0) +#define QS_WAVE_LOADED (1<<1) +#define QS_WAVE_STREAMED (1<<2) + +//--------------------------------------------------------------- + +class Wave +{ + private: + ULONG WaveFlags; + LPMIXWAVE MixWave; + + public: + Wave *Next, + *Prev; + + Wave(); + ~Wave(); + + // Methods. + HRESULT Init(CBYTE *file_name,HQMIXER the_mixer); + HRESULT Fini(HQMIXER the_mixer); + HRESULT Load(void); + HRESULT Free(void); + + inline BOOL IsValid(void) { return WaveFlags&QS_WAVE_VALID; } + inline void ValidOn(void) { WaveFlags |= QS_WAVE_VALID; } + inline void ValidOff(void) { WaveFlags &= ~QS_WAVE_VALID; } + + inline BOOL IsLoaded(void) { return WaveFlags&QS_WAVE_LOADED; } + inline void LoadedOn(void) { WaveFlags |= QS_WAVE_LOADED; } + inline void LoadedOff(void) { WaveFlags &= ~QS_WAVE_LOADED; } + + inline BOOL IsStreamed(void) { return WaveFlags&QS_WAVE_STREAMED; } + inline void StreamedOn(void) { WaveFlags |= QS_WAVE_STREAMED; } + inline void StreamedOff(void) { WaveFlags &= ~QS_WAVE_STREAMED; } + + inline LPMIXWAVE GetMixWave(void) { return MixWave; } +}; + +//--------------------------------------------------------------- + +#define QS_CHANNEL_OPEN (1<<0) + +//--------------------------------------------------------------- + +class Channel +{ + private: + int IChannel; + ULONG ChannelFlags, + ChannelPriority; + SLONG ChannelUserRef, + ChannelWaveID; + + public: + Channel(); + ~Channel(); + + // Methods. + void Open(void); + void Close(void); + + inline SLONG GetUserRef(void) { return ChannelUserRef; } + inline void SetUserRef(SLONG ref) { ChannelUserRef = ref; } + inline SLONG GetPriority(void) { return ChannelPriority; } + inline void SetPriority(SLONG pri) { ChannelPriority = pri; } + inline SLONG GetWaveID(void) { return ChannelWaveID; } + inline void SetWaveID(SLONG id) { ChannelWaveID = id; } +}; + +//--------------------------------------------------------------- + +#define QS_MANAGER_INIT (1<<0) +#define QS_MANAGER_ACTIVE (1<<1) + +#define MAX_CHANNELS 16 + +//--------------------------------------------------------------- + +class QSManager +{ + private: + ULONG ManagerFlags, + WaveCount; + Channel Channels[MAX_CHANNELS]; + HQMIXER HQMixer; + QMIXCONFIG Config; + Wave *WaveList, + *WaveListEnd; + + + public: + QSManager(); + ~QSManager(); + + // Methods. + HRESULT Init(void); + HRESULT Fini(void); + void ActivateSound(void); + void DeactivateSound(void); + + HRESULT LoadWaves(CBYTE *wave_path,CBYTE *script_name); + HRESULT LoadWave(CBYTE *wave_name); + HRESULT FreeWaves(void); + HRESULT AddWave(Wave *the_wave); + HRESULT DeleteWave(Wave *the_wave); + + HRESULT PlayWave(SLONG wave_ref,SLONG wave_id,SLONG play_type,WaveParams *the_params); + HRESULT StopWave(SLONG wave_ref,SLONG wave_id); + + inline BOOL IsInitialised(void) { return ManagerFlags&QS_MANAGER_INIT; } + inline void InitOn(void) { ManagerFlags |= QS_MANAGER_INIT; } + inline void InitOff(void) { ManagerFlags &= ~QS_MANAGER_INIT; } + + inline BOOL IsActive(void) { return ManagerFlags&QS_MANAGER_ACTIVE; } + inline void ActiveOn(void) { ManagerFlags |= QS_MANAGER_ACTIVE; } + inline void ActiveOff(void) { ManagerFlags &= ~QS_MANAGER_ACTIVE; } + + inline HQMIXER GetHQMixer(void) { return HQMixer; } +}; + +//--------------------------------------------------------------- + +extern QSManager the_qs_sound_manager; + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/DDLibrary/Headers/SampleManager.h b/fallen/DDLibrary/Headers/SampleManager.h new file mode 100644 index 0000000..77fc606 --- /dev/null +++ b/fallen/DDLibrary/Headers/SampleManager.h @@ -0,0 +1,109 @@ +// SampleManager.h +// Guy Simmons, 24th February 1998. + +#ifndef SAMPLEMANAGER_H +#define SAMPLEMANAGER_H + +//--------------------------------------------------------------- + +#define SM_MANAGER_INIT (1<<0) + +#define SM_SAMPLE_VALID (1<<0) +#define SM_SAMPLE_LOADED (1<<1) +#define SM_SAMPLE_LOOPED (1<<2) +#define SM_SAMPLE_STREAMED (1<<3) +#define SM_SAMPLE_3D (1<<4) + +#define MAX_DUP_BUFFERS 10 + +//--------------------------------------------------------------- + +class SampleInfo +{ + private: + protected: + public: + ULONG BufferCount, + SampleFlags, + SampleSize; + SLONG BaseFrequency, + Priority[MAX_DUP_BUFFERS], + UserRef[MAX_DUP_BUFFERS]; + HANDLE hNotifyEvent[2]; + HMMIO hmmFile; + LPDIRECTSOUNDBUFFER lp_DS_Buffer[MAX_DUP_BUFFERS]; + LPDIRECTSOUNDNOTIFY lp_DS_Notify; + MMCKINFO RIFFChunk; + WAVEFORMATEX WaveFormat; + + SampleInfo *Next, + *Prev; + + SampleInfo(); + ~SampleInfo(); + + // Methods. + HRESULT Create(CBYTE *file_name,UBYTE buffer_count); + HRESULT LoadSampleData(void); + HRESULT FreeSampleData(void); + void *Play(SLONG user_ref,SLONG vol,SLONG pan,SLONG freq,SLONG priority); + HRESULT Control(LPDIRECTSOUNDBUFFER the_buf,SLONG vol,SLONG pan,SLONG freq); + HRESULT Restore(LPDIRECTSOUNDBUFFER the_buf); + + + HRESULT SetUpNotifications(void); + + inline BOOL IsValid(void) { return SampleFlags&SM_SAMPLE_VALID; } + inline void ValidOn(void) { SampleFlags |= SM_SAMPLE_VALID; } + inline void ValidOff(void) { SampleFlags &= ~SM_SAMPLE_VALID; } + + inline BOOL IsLoaded(void) { return SampleFlags&SM_SAMPLE_LOADED; } + inline void LoadedOn(void) { SampleFlags |= SM_SAMPLE_LOADED; } + inline void LoadedOff(void) { SampleFlags &= ~SM_SAMPLE_LOADED; } + + inline BOOL IsLooped(void) { return SampleFlags&SM_SAMPLE_LOOPED; } + inline void LoopedOn(void) { SampleFlags |= SM_SAMPLE_LOOPED; } + inline void LoopedOff(void) { SampleFlags &= ~SM_SAMPLE_LOOPED; } + + inline BOOL IsStreamed(void) { return SampleFlags&SM_SAMPLE_STREAMED; } + inline void StreamedOn(void) { SampleFlags |= SM_SAMPLE_STREAMED; } + inline void StreamedOff(void) { SampleFlags &= ~SM_SAMPLE_STREAMED; } + + inline BOOL IsSample3D(void) { return SampleFlags&SM_SAMPLE_3D; } + inline void Sample3DOn(void) { SampleFlags |= SM_SAMPLE_3D; } + inline void Sample3DOff(void) { SampleFlags &= ~SM_SAMPLE_3D; } +}; + +//--------------------------------------------------------------- + +class SampleManager +{ + private: + protected: + public: + ULONG ManagerFlags; + + // Samples Info + ULONG SampleCount; // Count of Modes. + SampleInfo *SampleList, // List of Modes. + *SampleListEnd; + + + SampleManager(); + ~SampleManager(); + + // Methods. + HRESULT LoadSamples(CBYTE *script_name); + HRESULT DestroySamples(void); + + HRESULT AddSample(SampleInfo *the_sample); + HRESULT DeleteSample(SampleInfo *the_sample); +}; + +//--------------------------------------------------------------- + +extern SampleManager samples; + +//--------------------------------------------------------------- +#endif + diff --git a/fallen/DDLibrary/Headers/Tga.h b/fallen/DDLibrary/Headers/Tga.h new file mode 100644 index 0000000..a2df84d --- /dev/null +++ b/fallen/DDLibrary/Headers/Tga.h @@ -0,0 +1,67 @@ +// +// Loads in 32-bit RGBA uncompressed TGAs. +// + +#ifndef _TGA_ +#define _TGA_ + +#include "FileClump.h" + +// +// The format of a TGA pixel. +// + +typedef struct +{ + UBYTE blue; + UBYTE green; + UBYTE red; + UBYTE alpha; + +} TGA_Pixel; + +// +// Info describing the tga. +// + +typedef struct +{ + SLONG valid; + SLONG width; + SLONG height; + SLONG contains_alpha; + +} TGA_Info; + +// +// If the width and height of the tga exceed the maximums, then the tga is not loaded. +// + +TGA_Info TGA_load( + const CBYTE *file, + SLONG max_width, + SLONG max_height, + TGA_Pixel *data, + ULONG id, + BOOL bCanShrink = TRUE); + +// +// Saves out a tga. +// + +void TGA_save( + const CBYTE *file, + SLONG width, + SLONG height, + TGA_Pixel *data, + SLONG contains_alpha); // FALSE => Save without the alpha data. + + +// Clump management + +void OpenTGAClump(const char* clumpfn, size_t maxid, bool readonly); +bool DoesTGAExist(const char* filename, ULONG id); +void CloseTGAClump(); +FileClump* GetTGAClump(); + +#endif diff --git a/fallen/DDLibrary/Headers/WindProcs.h b/fallen/DDLibrary/Headers/WindProcs.h new file mode 100644 index 0000000..591ef2c --- /dev/null +++ b/fallen/DDLibrary/Headers/WindProcs.h @@ -0,0 +1,32 @@ +// WindProcs.h +// Guy Simmons, 14th November 1997. + +#ifndef WINDPROCS_H +#define WINDPROCS_H + +#include "DDManager.h" + + +//--------------------------------------------------------------- + +typedef struct +{ + DDDriverInfo *DriverCurrent, + *DriverNew; + + D3DDeviceInfo *DeviceCurrent, + *DeviceNew; + + DDModeInfo *ModeCurrent, + *ModeNew; +}ChangeDDInfo; + +//--------------------------------------------------------------- + +BOOL FAR PASCAL AboutBoxProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK ChangeDriverProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK DDLibShellProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/DDLibrary/Headers/net.h b/fallen/DDLibrary/Headers/net.h new file mode 100644 index 0000000..b5d4ff4 --- /dev/null +++ b/fallen/DDLibrary/Headers/net.h @@ -0,0 +1,190 @@ +// +// Network stuff... +// + +#ifndef NET_H +#define NET_H + + + +// ======================================================== +// +// Initialising and releasing all the DirectPlay stuff... +// Call once each at the start and end of the program. +// +// ======================================================== + +void NET_init(void); +void NET_kill(void); + + +// +// The NULL player ID. +// Use this player ID to send a message to everyone. +// If the system sends a message, then it comes from NET_PLAYER_SYSTEM +// + +#define NET_PLAYER_NONE 255 +#define NET_PLAYER_ALL 254 +#define NET_PLAYER_SYSTEM 253 + + +// ======================================================== +// +// CONNECTION STUFF +// +// ======================================================== + +// +// Returns the number of connections available. +// Returns the name of the given connection. +// + +SLONG NET_get_connection_number(void); +CBYTE *NET_get_connection_name (SLONG connection); + +// +// Establishes a connection. Returns TRUE on success. +// + +SLONG NET_connection_make(SLONG connection); + + +// ======================================================== +// +// SESSION STUFF +// +// ======================================================== + +// +// Creates a session. Makes this machine the host. Returns FALSE +// on failure. +// + +SLONG NET_create_session(CBYTE *name, SLONG max_players, CBYTE *my_player_name); + +// +// Returns the number of sessions available. +// Gets info about the given session. +// Joins the given session. +// + +#define NET_NAME_LENGTH 64 + +typedef struct +{ + CBYTE name[NET_NAME_LENGTH]; + +} NET_Sinfo; + +SLONG NET_get_session_number(void); +NET_Sinfo NET_get_session_info (SLONG session); + +// +// Joins the given session. Returns FALSE on failure. +// + +SLONG NET_join_session(SLONG session, CBYTE *my_player_name); + +// +// Leaves the session. +// + +void NET_leave_session(void); + +// +// Starts the game. It sends out a START_GAME system message +// and assigns player_ids to all the other players. Only the host +// should call this function. Other players should wait for +// a START_GAME system message. +// +// This function returns your player_id. Do not wait for a START_GAME +// message because you won't get one. Returns NET_PLAYER_NONE on failure. +// + +UBYTE NET_start_game(void); + +// ======================================================== +// +// PLAYER STUFF +// +// ======================================================== + +// +// To find the player in the current session. To update this list you +// have to process the message loop. The player argument to NET_get_player_name +// is not a player_id, just the n'th player in the session. +// + +SLONG NET_get_num_players(void); +CBYTE *NET_get_player_name(SLONG player); + + +// ======================================================== +// +// MESSAGE STUFF +// +// ======================================================== + +// +// Maximum length of a message in bytes. +// + +#define NET_MESSAGE_LENGTH (16 * 1024) + +// +// Sends a message to the given player. Pass NET_PLAYER_ALL to send +// a broadcast message to everyone. +// + +void NET_message_send( + UBYTE player_id, + void *data, + UWORD num_bytes); + +// +// Returns TRUE if there is a message in the queue. +// + +SLONG NET_message_waiting(void); + +// +// Gets the next message in the queue. +// + +#define NET_SYSMESS_NOP 0 // Do nothing! +#define NET_SYSMESS_START_GAME 1 +#define NET_SYSMESS_LOST_CONNECTION 2 +#define NET_SYSMESS_HOST_QUIT_OUT 3 + +typedef struct +{ + UBYTE player_id; + UBYTE shit1; + UWORD shit2; + + union + { + struct // For system messages, when player == NET_PLAYER_SYSTEM + { + UBYTE sysmess; + UBYTE player_id; // For the START_GAME system message. + UBYTE shite; + + } system; + + struct // For all other messages. + { + UWORD num_bytes; + UWORD more_shit; + void *data; + + } player; + }; + +} NET_Message; + +void NET_message_get(NET_Message *answer); + + +#endif diff --git a/fallen/DDLibrary/Headers/resource.h b/fallen/DDLibrary/Headers/resource.h new file mode 100644 index 0000000..af4b7b0 --- /dev/null +++ b/fallen/DDLibrary/Headers/resource.h @@ -0,0 +1,331 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by C:\fallen\DDLibrary\DDlib.rc +// +#define IDR_MAIN_MENU 101 +#define IDD_ABOUT 102 +#define IDB_MUCKY_LOGO 103 +#define IDD_DRIVERS 104 +#define IDC_POINTER_DRAGDROP 105 +#define IDR_MAIN_ACCELERATOR 115 +#define IDR_LEDIT_MENU 120 +#define IDR_LEDIT_POPUPS 121 +#define IDR_LEDIT_ACCELERATOR 122 +#define IDI_MFLOGO 127 +#define IDD_NEWMISSION 135 +#define IDR_GEDIT_MENU 138 +#define IDR_SEDIT_MENU 143 +#define IDR_SEDIT_ACCELERATOR 144 +#define IDD_CHOOSE_PRIM 150 +#define IDD_PLAYER_SETUP 151 +#define IDD_ENEMY_SETUP 152 +#define IDD_ITEM_SETUP 153 +#define IDD_TRIGGER_SETUP 155 +#define IDD_MESSAGE_SETUP 156 +#define IDD_VEHICLE_SETUP 157 +#define IDD_VEFFECT_SETUP 158 +#define IDR_GEDIT_ACCELERATOR 160 +#define IDD_CAMERA_TARGET_SETUP 164 +#define IDD_EVENTTAB_CONDITION 165 +#define IDD_INPUT_BOX 170 +#define IDB_TOOLBAR 174 +#define IDB_BITMAP1 176 +#define IDD_MKTDRIVERS 178 +#define IDB_SCENE_ICONS 179 +#define IDR_CEDIT_ACCELERATORS 180 +#define IDD_TRANSFER_SETUP 181 +#define IDD_LOCK_SETUP 182 +#define IDD_RESET_SETUP 183 +#define IDD_MILESDLG 184 +#define IDD_STALL_SETUP 185 +#define IDD_EXTEND_SETUP 186 +#define IDD_MOVE_SETUP 187 +#define IDD_PEE_SETUP 188 +#define IDD_SIGN_SETUP 190 +#define IDB_AHEAD 193 +#define IDB_STOP 195 +#define IDB_RIGHTTURN 196 +#define IDB_BITMAP4 197 +#define IDD_GRAPHICSDLG 198 +#define IDI_ICON1 199 +#define IDD_MISSION_EDITOR 200 +#define IDI_ICON2 200 +#define IDB_WORKSPACE 201 +#define IDD_CREATURE_SETUP 201 +#define IDR_GEDIT_POPUPS 202 +#define IDD_CAMERA_SETUP 202 +#define IDB_SCENE_ICONS1 202 +#define IDD_MISSION_EDITOR2 203 +#define IDD_EVENTTAB_ACTION 204 +#define IDD_EVENTTAB_INFO 205 +#define IDD_MAPEXIT_SETUP 206 +#define IDD_ACTIVATE_SETUP 207 +#define IDD_TRAP_SETUP 208 +#define IDD_PLATFORM_SETUP 209 +#define IDD_WAYPOINT_SETUP 210 +#define IDD_BOMB_SETUP 211 +#define IDD_BURN_SETUP 212 +#define IDD_SEFFECT_SETUP 213 +#define IDD_SPOTFX_SETUP 214 +#define IDD_SET_SKILLS 215 +#define IDD_BARREL_SETUP 216 +#define IDD_WAYPOINT_PICKER 217 +#define IDD_TREASURE_SETUP 218 +#define IDD_BONUS_SETUP 219 +#define IDD_CONVERSATION_SETUP 220 +#define IDD_COUNTER_SETUP 221 +#define IDD_DLIGHT_SETUP 222 +#define IDD_SCENE_EDITOR 223 +#define IDD_NAVBEACON_SETUP 224 +#define IDD_ANIMATION_SETUP 225 +#define IDD_ENEMYFLAGS_SETUP 226 +#define IDD_WAREFX_SETUP 227 +#define IDC_DEVICES 1000 +#define IDC_EDIT_MNAME 1000 +#define IDC_DRIVERS 1001 +#define IDC_MODES 1002 +#define IDC_PRIM_LIST 1036 +#define IDC_RADIO1 1037 +#define IDC_LOCKED 1037 +#define IDC_RADIO2 1038 +#define IDC_UNLOCKED 1038 +#define IDC_LIST1 1039 +#define IDC_LIST2 1040 +#define IDC_SPIN1 1041 +#define IDC_SPIN2 1042 +#define IDC_SPIN3 1043 +#define IDC_SPIN4 1044 +#define IDC_SPIN5 1045 +#define IDC_EDIT1 1050 +#define IDC_EDIT2 1051 +#define IDC_EDIT3 1052 +#define IDC_EDIT4 1053 +#define IDC_EDIT5 1054 +#define IDC_COMBO1 1055 +#define IDC_COMBO2 1056 +#define IDC_COMBO3 1057 +#define IDC_CHECK1 1057 +#define IDC_COMBO4 1058 +#define IDC_CHECK2 1058 +#define IDC_WAYPOINT_GROUP 1059 +#define IDC_TAB1 1070 +#define IDC_BUTTON1 1071 +#define IDC_BUTTON2 1072 +#define IDC_STATIC_DEPEND1 1073 +#define IDC_STATIC_DEPEND2 1074 +#define IDC_STATIC_TIME 1075 +#define IDC_STATIC_RADIUS 1076 +#define IDC_STATIC_LABEL 1077 +#define IDC_STATIC_LISTEN 1077 +#define IDC_STATIC_INFO 1078 +#define IDC_STATIC_DELAY 1083 +#define IDC_STATIC_PROMPT 1084 +#define IDC_LIST3 1085 +#define IDC_STATIC_TRAY 1087 +#define IDC_STATIC_ADJUST 1088 +#define IDC_STATIC_ADJUST2 1089 +#define IDC_STATIC_ADJUST3 1090 +#define IDC_STATIC_ANIM 1091 +#define IDC_STATIC_ADJUST4 1092 +#define IDC_MKTCOMBO_MODE 1095 +#define IDC_MKTCOMBO_CARD 1096 +#define IDC_LABEL1 1098 +#define IDC_MAP_VIEW 1100 +#define IDC_WORKSPACE_TREE 1101 +#define IDC_WORKSPACE_TREE2 1102 +#define IDC_TREE1 1103 +#define IDC_SCROLLBAR1 1109 +#define IDC_HAS_PISTOL 1114 +#define IDC_HAS_SHOTGUN 1115 +#define IDC_HAS_AK47 1116 +#define IDC_HAS_GRENADE 1117 +#define IDC_HAS_BALLOON 1118 +#define IDC_SOUNDDRV 1121 +#define IDC_NOSHOW 1122 +#define IDC_KNIFE 1123 +#define IDC_BAT 1124 +#define IDC_NOPSX_BUTTON 1126 +#define IDC_CUSTOM_1 1130 +#define IDC_CUSTOM_2 1131 +#define IDC_CUSTOM_3 1132 +#define IDC_CUSTOM_4 1133 +#define IDC_CUSTOM_5 1134 +#define IDC_CUSTOM_6 1135 +#define IDC_CUSTOM_7 1136 +#define IDC_CUSTOM_8 1137 +#define IDC_CHECK_1 1140 +#define IDC_CHECK_2 1141 +#define IDC_CHECK_3 1142 +#define IDC_CHECK_4 1143 +#define IDC_CHECK_5 1144 +#define IDC_CHECK_6 1145 +#define IDC_CHECK_7 1146 +#define IDC_CHECK_8 1147 +#define IDC_WITH_SLIDE 1149 +#define IDC_WITH_COMBO_PPP 1150 +#define IDC_WITH_COMBO_KKK 1151 +#define IDC_WITH_COMBO_ANY 1152 +#define IDC_WITH_GRAPPLE_ATTACK 1153 +#define IDC_WITH_SIDE_KICK 1154 +#define IDC_WITH_BACK_KICK 1155 +#define IDC_AHEAD 1156 +#define IDC_STOP 1157 +#define IDC_TURN_RIGHT 1158 +#define IDC_UTURN 1159 +#define IDC_RIGHT_TURN 1163 +#define IDC_FLIP_LEFT_RIGHT 1165 +#define IDC_FLIP_TOP_BOTTOM 1166 +#define IDC_LOCK_DIRECTION 1167 +#define IDC_CANT_INTERRUPT 1168 +#define IDC_PRIMARY_3D 1170 +#define IDC_SECONDARY_3D 1171 +#define IDC_SOFTWARE_3D 1172 +#define IDC_RESOLUTION 1173 +#define IDC_COLOURS_16 1174 +#define IDC_COLOURS_32 1175 +#define IDC_SOUND_DROPDOWN 1176 +#define IDC_DATETIMEPICKER1 1177 +#define IDC_GRAB_CAMERA 1181 +#define IDC_STATIC_3DCARD 1182 +#define IDC_STATIC_BITDEPTH 1183 +#define IDC_STATIC_RES 1184 +#define IDC_STATIC_SELECT 1185 +#define IDC_GRAPHICS_OPTIONS 1187 +#define IDC_SOUND_OPTIONS 1188 +#define IDC_TOOLBAR1 1200 +#define ID_DISPLAY_DEVICES 40001 +#define ID_DISPLAY_MODES 40002 +#define ID_DISPLAY_EXIT 40004 +#define ID_DISPLAY_DRIVERS 40005 +#define ID_ABOUT 40006 +#define ID_MODES_640X480 40007 +#define ID_MODES_800X600 40008 +#define ID_MODES_1024X768 40009 +#define ID_MODES_320X200 40010 +#define ID_DISPLAY_FULLSCREEN 40011 +#define ID_FILE_EXIT 40019 +#define ID_FILE_OPEN_ARSE 40020 +#define ID_FRAME_PLACEANEWLIGHT 40021 +#define ID_FRAME_EDITLIGHT 40022 +#define ID_FRAME_SETAMBIENT 40023 +#define ID_EDIT_CLEARALL 40024 +#define ID_EDIT_SETLAMPOSTCOLOUR 40028 +#define ID_EDIT_PLACELIGHT 40029 +#define ID_MAP_NIGHTSKY 40030 +#define ID_MAP_DAYTIME 40031 +#define ID_MAP_LIGHTSUNDERLAMPOSTS 40032 +#define ID_EDIT_EDITLIGHTS 40034 +#define ID_EDIT_SETAMBIENT 40035 +#define ID_EDIT_UNDO_ARSE 40036 +#define ID_EDIT_SETSKYCOLOUR 40037 +#define ID_EDIT_REDO_ARSE 40038 +#define ID_MAP_DARKENBOTTOMSOFBUILDINGS 40039 +#define ID_FILE_SAVE_ARSE 40045 +#define ID_FILE_LOAD_ARSE 40046 +#define ID_MAP_INFO 40048 +#define ID_HELP_ABOUT 40050 +#define ID_EDIT_DELETE_ARSE 40052 +#define ID_FILE_OPENMAP 40053 +#define ID_FILE_OPEN_WS 40053 +#define ID_FILE_MODELESS 40056 +#define ID_FILE_SAVE_SEWERS 40056 +#define ID_FILE_LOAD_SEWERS 40057 +#define ID_FILE_REDO_ARSE 40058 +#define ID_EDIT_PLACE_SEWERS 40059 +#define ID_EDIT_PLACE_GROUND 40060 +#define ID_EDIT_PLACE_ROCK 40061 +#define ID_EDIT_PLACE_WATER 40062 +#define ID_VIEW_SEWER_ENGINE 40063 +#define ID_VIEW_SEWER_EDITOR 40064 +#define ID_VIEW_CITY_ENGINE 40065 +#define ID_VIEW_SHOW_BUILDINGS 40066 +#define ID_EDIT_PLACE_PRIM 40067 +#define ID_EDIT_PLACE_LADDER 40068 +#define ID_EDIT_PLACE_HOLE 40071 +#define ID_EDIT_PLACE_GRATING 40072 +#define ID_EDIT_PLACE_ENTRANCE 40073 +#define ID_EDIT_EDIT_LIGHT 40087 +#define ID_MISSIONROOT_EXPORTMISSION 40089 +#define ID_FILE_SAVE_WS 40090 +#define ID_MISSIONROOT_DELETEMISSION 40091 +#define ID_EVENTPOINTROOT_DELETEWAYPOINT 40092 +#define ID_MISSIONROOT_ADDSEWERMAP 40093 +#define ID_EVENTPOINTROOT_PROPERTIES 40095 +#define ID_EVENTPOINTROOT_DEPENDENCY_LINK 40099 +#define ID_EVENTPOINTROOT_DEPENDENCY_CANCEL 40100 +#define ID_FILE_EXITALL 40101 +#define ID_BUTTON40102 40102 +#define ID_BUTTON40103 40103 +#define ID_MAPROOT_IMPORTMISSION 40104 +#define ID_BUTTON40105 40105 +#define ID_BUTTON40106 40106 +#define ID_BUTTON40107 40107 +#define ID_BUTTON40108 40108 +#define ID_BUTTON40109 40109 +#define ID_BUTTON40110 40110 +#define ID_BUTTON40111 40111 +#define ID_BUTTON40112 40112 +#define ID_BUTTON40113 40113 +#define ID_BUTTON40114 40114 +#define ID_BUTTON40115 40115 +#define ID_BUTTON40116 40116 +#define ID_BUTTON40117 40117 +#define ID_EVENTPOINTROOT_COPYWAYPOINT 40118 +#define ID_MISSIONROOT_VALIDATEMISSION 40119 +#define ID_TOOLBAR_PRIM 40120 +#define ID_MAPROOT_RESETPRIMS 40121 +#define ID_MAPROOT_SAVEPRIMS 40122 +#define ID_EVENTPOINTROOT_INSIDE 40123 +#define ID_EDIT_INSIDES 40124 +#define ID_MISSIONROOT_SETDEFAULTSKILLS 40125 +#define ID_EVENTPOINTROOT_WARE 40126 +#define ID_EVENTPOINTROOT_NORMAL 40128 +#define ID_EVENTPOINTROOT_RENUMBERWAYPOINTLOWER 40129 +#define ID_CEDIT_MOUSELOOK 40130 +#define IDS_NODIRECTX 40130 +#define ID_MISSIONROOT_SETCRIMERATE 40131 +#define ID_CEDIT_CAMERA_PUNCHIN 40132 +#define ID_CEDIT_PLAYBACK 40133 +#define ID_CEDIT_ERASE 40134 +#define ID_MISSIONROOT_SETCIVVYCOUNT 40135 +#define ID_CEDIT_REWIND 40136 +#define ID_CEDIT_FFWD 40137 +#define ID_MISSIONROOT_DELETECIVS 40138 +#define ID_MISSIONROOT_SETCARSCOUNT 40139 +#define ID_GEDIT_DEL_PRIMS 40140 +#define ID_MISSIONROOT_SETMUSICWORLD 40141 +#define ID_MISSIONROOT_CRIMERATE_VISIBILITY 40142 +#define ID_MISSIONROOT_DELETECARS 40143 +#define ID_MAPROOT_COUNTPRIMS 40145 +#define ID_MISSIONROOT_BOREDOM 40146 +#define ID_MISSIONROOT_REFRESHMISSION 40147 +#define ID_MODES_512X384 40147 +#define ID_MISSIONROOT_SHOWMISSIONINFO 40148 +#define ID_MISSIONROOT_SETCARCOLLISIONWITHROADPRIMS 40149 +#define ID_WORKSPACEROOT_REFRESH 40150 +#define ID_MAPROOT_DELETEMAP 40152 +#define ID_EVENTPOINTROOT_MAGICNUMBER 40153 +#define ID_WORKSPACEROOT_ADD 40155 +#define ID_MAPROOT_NEWMISSION 40156 +#define ID_MISSIONROOT_ADDMISSIONBRIEF 40157 +#define ID_MISSIONROOT_ADDLIGHTMAP 40158 +#define ID_FILE_SAVEWORKSPACE 40160 +#define ID_FILE_CLOSE_WS 40160 +#define ID_FILE_NEWTCTRLN 40161 +#define ID_FILE_NEW_WS 40161 +#define ID_FILE_SAVEAS 40163 +#define ID_FILE_SAVE_WS_AS 40163 +#define ID_EDITOR_MISSIONEDITOR 40164 +#define ID_TOOLBAR_WAYPOINT 40200 +#define ID_TOOLBAR_ZONE 40201 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 40156 +#define _APS_NEXT_CONTROL_VALUE 1189 +#define _APS_NEXT_SYMED_VALUE 104 +#endif +#endif diff --git a/fallen/DDLibrary/Headers/snd_type.h b/fallen/DDLibrary/Headers/snd_type.h new file mode 100644 index 0000000..38f6376 --- /dev/null +++ b/fallen/DDLibrary/Headers/snd_type.h @@ -0,0 +1,19 @@ +// snd_type.h + +#undef NO_SOUND +#undef A3D_SOUND +#undef Q_SOUND +#undef M_SOUND +#undef DS_SOUND + +#ifdef TARGET_DC +// No sound for the moment +//#define NO_SOUND 1 +#define DC_SOUND 1 +#else +// My sound doesn't seem to be working. Must be linking with the wron libs or something. +#define NO_SOUND 1 +//#define A3D_SOUND 1 +//#define Q_SOUND 1 +//#define M_SOUND 1 +#endif diff --git a/fallen/DDLibrary/Source/A3DManager.cpp b/fallen/DDLibrary/Source/A3DManager.cpp new file mode 100644 index 0000000..9f82d52 --- /dev/null +++ b/fallen/DDLibrary/Source/A3DManager.cpp @@ -0,0 +1,783 @@ +// A3DManager.cpp +// 2nd October 1998 +// +// (experimental) Aureal 3D Manager library +// +// requires either Aureal 3D sound card + drivers, OR normal sound card with A2D installed +// +// NOTE! RTTI (run-time type information) MUST BE ENABLED IN PROJECT SETTINGS! +// + +#ifndef TARGET_DC + + +#include "A3DManager.h" +#include "snd_type.h" +//#include "A3DPlay.h" + +extern volatile HWND hDDLibWindow; + + +/************************************************************************************** + * + * Globals + * + */ + +// Why is this global? Because sound sources need access to it too. +IA3d4 *a3droot; +IA3dGeom *a3dgeom = NULL; +A3DManager the_a3d_manager(A3D_1ST_REFLECTIONS | A3D_OCCLUSIONS | A3D_DIRECT_PATH_A3D); + + +void Decode(SLONG hr) { + TRACE("A3D Error: "); + switch(hr) { + case A3DERROR_FAILED_FILE_OPEN: + TRACE("Failed File Open"); break; + + case A3DERROR_FAILED_LOCK_BUFFER: + TRACE("Failed Lock"); break; + + case A3DERROR_FAILED_UNLOCK_BUFFER: + TRACE("Failed Unlock"); break; + + case A3DERROR_UNRECOGNIZED_FORMAT: + TRACE("Unrecongized Format"); break; + + case A3DERROR_FAILED_ALLOCATE_WAVEDATA: + TRACE("Failed Allocate Wavedata"); break; + + case E_INVALIDARG: + TRACE("Invalid Argument"); break; + + case A3DERROR_MEMORY_ALLOCATION: + TRACE("Memory Allocation Error"); break; + + case A3DERROR_FAILED_CREATE_PRIMARY_BUFFER: + TRACE("Primary Buffer Create Failed"); break; + + case A3DERROR_NO_WAVE_DATA: + TRACE("No Wave Data"); break; + + case A3DERROR_UNKNOWN_PLAYMODE: + TRACE("Unknown Play Mode"); break; + + case A3DERROR_FAILED_PLAY: + TRACE("Failed Play"); break; + } + + TRACE("\n"); +} + +void ErrChk(SLONG hr) { + if (hr==S_OK) return; + Decode(hr); +} + +BOOL Failed(SLONG hr) { + if (hr==S_OK) FALSE; + Decode(hr); + return TRUE; +} + +void A3D_Check_Init(void) { + the_a3d_manager.Init(A3D_1ST_REFLECTIONS | A3D_OCCLUSIONS | A3D_DIRECT_PATH_A3D); +} + + +/* ============================================================= +// RegDBSetKeyValue() Set the registry database key value +// +// =============================================================*/ + +static void RegDBSetKeyValue( + char *szKey, /* in, key string */ + char *szName, /* in, name string NULL == Default */ + char *szValue) /* in, value string */ +{ + DWORD dwOptions = REG_OPTION_NON_VOLATILE; + REGSAM samDesired = KEY_ALL_ACCESS; + HKEY hKey; + DWORD dwDisposition; + + /* Create the key, even if it already existed. */ + + RegCreateKeyExA( + HKEY_CLASSES_ROOT, /* handle of an open key */ + szKey, /* lpSubKey address of subkey name */ + 0, /* reserved word */ + "REG_SZ", /* address of class string */ + dwOptions, /* special options flag */ + samDesired, /* desired security access */ + NULL, /* address of key security structure */ + &hKey, /* address of buffer for opened handle */ + &dwDisposition); /* address of disposition value buffer */ + + /* Just write to it. */ + RegSetValueExA( + hKey, /* handle of key to set value for */ + szName, /* address of value to set */ + 0, /* reserved */ + REG_SZ, /* flag for value type */ + (CONST BYTE *)szValue, /* address of value data */ + strlen(szValue) /* length of value buffer */ + ); + + /* close the key. */ + RegCloseKey(hKey); +} + + +/* ============================================================= +// A3dRegister() Registers the COM objects for A3D. +// +// Returns: +// +// S_OK +// +// =============================================================*/ + +HRESULT A3dRegister(void) +{ + // A3d COM Keys + RegDBSetKeyValue("A3d", "", "A3d Object"); + RegDBSetKeyValue("A3d\\CLSID", "", "{d8f1eee0-f634-11cf-8700-00a0245d918b}"); + RegDBSetKeyValue("CLSID\\{d8f1eee0-f634-11cf-8700-00a0245d918b}", "", "A3d Object"); + RegDBSetKeyValue("CLSID\\{d8f1eee0-f634-11cf-8700-00a0245d918b}\\InprocServer32", "", "a3d.dll"); + RegDBSetKeyValue("CLSID\\{d8f1eee0-f634-11cf-8700-00a0245d918b}\\InprocServer32", "ThreadingModel", "Apartment"); + + RegDBSetKeyValue("A3dApi", "", "A3dApi Object"); + RegDBSetKeyValue("A3dApi\\CLSID", "", "{92FA2C24-253C-11d2-90FB-006008A1F441}"); + RegDBSetKeyValue("CLSID\\{92FA2C24-253C-11d2-90FB-006008A1F441}", "", "A3dApi Object"); + RegDBSetKeyValue("CLSID\\{92FA2C24-253C-11d2-90FB-006008A1F441}","AppID","{92FA2C24-253C-11D2-90FB-006008A1F441}"); + RegDBSetKeyValue("CLSID\\{92FA2C24-253C-11d2-90FB-006008A1F441}\\InprocServer32", "", "a3dapi.dll"); + RegDBSetKeyValue("CLSID\\{92FA2C24-253C-11d2-90FB-006008A1F441}\\InprocServer32", "ThreadingModel", "Apartment"); + + + RegDBSetKeyValue("A3dDAL", "", "A3dDAL Object"); + RegDBSetKeyValue("A3dDAL\\CLSID", "", "{442D12A1-2641-11d2-90FB-006008A1F441}"); + RegDBSetKeyValue("CLSID\\{442D12A1-2641-11d2-90FB-006008A1F441}", "", "A3dDAL Object"); + RegDBSetKeyValue("CLSID\\{442D12A1-2641-11d2-90FB-006008A1F441}","AppID","{442D12A1-2641-11D2-90FB-006008A1F441}"); + RegDBSetKeyValue("CLSID\\{442D12A1-2641-11d2-90FB-006008A1F441}\\InprocServer32", "", "a3d.dll"); + RegDBSetKeyValue("CLSID\\{442D12A1-2641-11d2-90FB-006008A1F441}\\InprocServer32", "ThreadingModel", "Apartment"); + + + return S_OK; +} + + +/************************************************************************************** + * + * Construct, Destruct + * + */ + +void A3DManager::Init(SLONG features) { + SLONG hr; + +#ifndef A3D_SOUND + return; +#endif + + if (a3droot) return; + + if (!hDDLibWindow) return; + + // Get the api root + + A3dRegister(); + + CoInitialize(NULL); + hr = CoCreateInstance(CLSID_A3dApi, NULL, CLSCTX_INPROC_SERVER, + IID_IA3d4, (void **)&a3droot); + if (FAILED(hr)) return; + + //--- + hr = a3droot->QueryInterface(IID_IA3dGeom, (void **)&a3dgeom); + if (FAILED(hr)) return; + //--- + + // debug override +// features=A3D_OCCLUSIONS|A3D_DIRECT_PATH|A3D_DISTANCE_MODEL|A3D_AUTO_DOPPLER; +// features=A3D_OCCLUSIONS|A3D_DIRECT_PATH|A3D_DISTANCE_MODEL|A3D_AUTO_DOPPLER|A3D_1ST_REFLECTIONS|A3D_LATE_REFLECTIONS; +// features=A3D_1ST_REFLECTIONS | A3D_OCCLUSIONS | A3D_DIRECT_PATH_A3D; + features=A3D_1ST_REFLECTIONS | A3D_OCCLUSIONS; // dirpath seems to be not req'd any more + + a3droot->Init(NULL, features,A3DRENDERPREFS_DEFAULT); + + // set the coop level + + a3droot->SetCooperativeLevel(hDDLibWindow,A3D_CL_NORMAL); +// a3droot->SetCooperativeLevel(GetDesktopWindow(),A3D_CL_NORMAL); + + + // Use it to acquire a listener + + hr = a3droot->QueryInterface(IID_IA3dListener, (void **)&a3dlis); + if (FAILED(hr)) return; + + // Enable the resource manager + +// a3droot->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC); + // disabled -- seems to be obsoleted in latest version + + // Initialise our ill-gotten gains + + a3dgeom->Enable(A3D_OCCLUSIONS); +// a3dgeom->Disable(A3D_OCCLUSIONS); + + //a3dgeom->Enable(A3D_DIRECT_PATH_A3D);// not req'd any more? + +// a3dgeom->Enable(A3D_DISTANCE_MODEL); +// a3dgeom->Disable(A3D_DISTANCE_MODEL); +// a3dgeom->Enable(A3D_AUTO_DOPPLER); +// a3dgeom->Disable(A3D_AUTO_DOPPLER); + + a3dgeom->Enable(A3D_1ST_REFLECTIONS); +// a3dgeom->Enable(A3D_LATE_REFLECTIONS); + + +// a3droot->SetCoordinateSystem(A3D_LEFT_HANDED_CS); + + ListenPos(0,0,0); + ListenRot(0,0,0); + + a3dgeom->LoadIdentity(); + + //--- build material library + + a3dgeom->NewMaterial(&mat_lib[A3D_MAT_CARPET]); + a3dgeom->NewMaterial(&mat_lib[A3D_MAT_STEEL]); + a3dgeom->NewMaterial(&mat_lib[A3D_MAT_SNDPROOF]); + + mat_lib[A3D_MAT_CARPET] ->SetReflectance(0.8,0.3); + mat_lib[A3D_MAT_CARPET] ->SetTransmittance(0.8, 0.3); + + mat_lib[A3D_MAT_STEEL] ->SetReflectance(0.9, 1.0); + mat_lib[A3D_MAT_STEEL] ->SetTransmittance(0.5, 0.5); + + mat_lib[A3D_MAT_SNDPROOF] ->SetReflectance(0.0, 0.0); + mat_lib[A3D_MAT_SNDPROOF] ->SetTransmittance(1.0, 0.0); + + //--- + + a3droot->Clear(); // off we go... +} + +A3DManager::A3DManager(SLONG features) { + a3droot=NULL; + a3dlis=NULL; + a3dgeom=NULL; + memset(mat_lib,0,A3D_MAT_COUNT*sizeof(IA3dMaterial*)); + //Init(features); +} + +void A3DCleanUp(void) { +#ifdef A3D_SOUND + the_a3d_manager.Fini(); +#endif +} + +void A3DManager::Fini(void) { + + SLONG i; + + //--- free material library + + for (i=0;iRelease(); + mat_lib[i]=0; + } + } + + + //--- + + if (a3droot) a3droot->Flush(); // to restore balance and harmony. or something. + srclist.Clear(); + datalist.Clear(); + if (a3dlis) + a3dlis->Release(); + if (a3dgeom) a3dgeom->Release(); + if (a3droot) + a3droot->Release(); + a3dgeom=0; + a3droot=0; + a3dlis=0; + CoUninitialize(); +} + +A3DManager::~A3DManager() { + Fini(); +} + +// +// Channel Play +// + +A3DSource* A3DManager::Play(A3DData *Original, A3DSource* Channel, UBYTE flags) { + if (!Channel) { +// TRACE("Creating\n"); + Channel = new A3DSource(Original); + } else { + Channel->Pause(); + if (flags & 2) Channel->Rewind(); + if (Original!=Channel->cloned_from) { + Channel->Change(Original); + Channel->Rewind(); + } + } +// TRACE("playing %p (a3dsrc=%p)\n",Channel,Channel->GetSource()); + Channel->Flags=flags; + Channel->Play(flags & 1); + return Channel; +} + +// +// Channel Check +// + +BOOL A3DManager::Valid(A3DBase* item) { + A3DBase *temp; + + try { + temp = dynamic_cast(item); + return TRUE; // always returns TRUE coz a failed dynamic_cast<> returns NULL, not an exception + } + catch (...) { + return FALSE; + } +} + +A3DSource* A3DManager::ValidChannel(A3DBase* item) { + A3DSource *temp; + + try { + temp = dynamic_cast(item); + return temp; + } + catch (...) { + return NULL; // redundant + } +} + +A3DBase* A3DManager::ValidWave(A3DBase* item) { + A3DBase *temp; + + try { + temp = dynamic_cast(item); + return temp; + } + catch (...) { + return NULL; // redundant + } +} + + +void A3DManager::BindMaterial(SLONG material) { + a3dgeom->BindMaterial(mat_lib[material]); +} + +/************************************************************************************** + * + * Source Construct/Destruct + * + */ + +A3DSource::A3DSource(CBYTE *fn) { + A3DBase *data=NULL; + + if (fn) { + data=the_a3d_manager.datalist.Find(fn); + if (!data) { + data = new A3DData(fn); + } + } + DupeConstruct(data); + +} + +A3DSource::A3DSource(A3DBase *original) { + DupeConstruct(original); +} + +void A3DSource::SetupParams() { + a3dsrc->SetGain(1.0); + a3dsrc->SetMinMaxDistance(1,6144,A3D_MUTE); +// a3dsrc->SetMinMaxDistance(1,6144,A3D_AUDIBLE); +// a3dsrc->SetDistanceModelScale(0.001); + a3dsrc->SetDistanceModelScale(0.002); +} + +void A3DSource::DupeConstruct(A3DBase *original) { + SLONG hr; + the_a3d_manager.srclist += this; + rendermode=0; + autofree=0; + queuepos=0; + User=0; + cloned_from=original; + a3dsrc=0; + if (!original) return; +// if (original) { + strcpy(title,original->GetTitle()); + type=original->type; + owner=original->owner; + hr = a3droot->DuplicateSource(original->GetSource(),&a3dsrc); +// } + if (FAILED(hr)) return; + if (type&A3DSOURCE_INITIAL_RENDERMODE_NATIVE) { + a3dsrc->SetRenderMode(A3DSOURCE_RENDERMODE_NATIVE); + } else { + SetPositionl(0,0,0); + a3dsrc->SetRenderMode(A3DSOURCE_RENDERMODE_DEFAULT); + } + SetupParams(); +} + + +A3DSource::~A3DSource() { + Stop(); + FreeWave(); + the_a3d_manager.srclist -= this; +} + + +/************************************************************************************** + * + * Source Configuration + * + */ + +void A3DSource::SetMute(UBYTE mute) { +/* if (mute) + rendermode|=A3D_MUTE; + else + rendermode&=!A3D_MUTE; + if (a3dsrc) a3dsrc->SetRenderMode(rendermode); + */ +} + +void A3DSource::Set3D(UBYTE is3d) { + // despite what the API docs say, this doesn't seem to actually exist yet. hm. + /* + if (is3d) + rendermode&=!A3D_DISABLE_3D; + else + rendermode|=A3D_DISABLE_3D; + if (a3dsrc) a3dsrc->SetRenderMode(rendermode); + */ +} + +void A3DSource::DoChange(A3DBase *original) { + SLONG hr; + + FreeWave(); + cloned_from=original; + if (original) { + strcpy(title,original->GetTitle()); + hr = a3droot->DuplicateSource(original->GetSource(),&a3dsrc); + if (FAILED(hr)) { + TRACE("change failed\n"); + return; + } + SetupParams(); + } +} + +void A3DSource::Change(A3DBase *original) { + QueueFlush(); + DoChange(original); +} + +void A3DSource::Queue(A3DBase *original, SLONG x, SLONG y, SLONG z, SLONG flags) { + if (queuepos==MAX_QUEUE_LENGTH) return; + queue[queuepos].original=original; + queue[queuepos].x=x; + queue[queuepos].y=y; + queue[queuepos].z=z; + queue[queuepos].flags=flags; + queuepos++; +} + +UBYTE A3DSource::CBEnded() { +/* UBYTE i; + + if (queuepos) { + DoChange(queue[0].original); + SetPositionl(queue[0].x,queue[0].y,queue[0].z); + Flags=queue[0].flags; + if (queue[0].flags&A3D_LOOP) + Play(1); + else + Play(0); + for (i=1;iPlay(A3D_LOOPED)); + else + ErrChk(a3dsrc->Play(A3D_SINGLE)); + } +} + +void A3DSource::Stop() { + if (a3dsrc) { + a3dsrc->Stop(); + Rewind(); + } +} + +void A3DSource::Rewind() { + if (a3dsrc) { + a3dsrc->SetWavePosition(0); + last_time=0; + } +} + + +/************************************************************************************** + * + * A3DData -- a source that simply holds data. no transport, location, etc + * + */ + +A3DData::A3DData(CBYTE *fn, UBYTE ntype) { + HRESULT hr; + + the_a3d_manager.datalist += this; + next=NULL; + a3dsrc=NULL; + + owner=0; + + type=ntype; + hr = a3droot->NewSource(type,&a3dsrc); + if (FAILED(hr)) { + strcpy(title,"[failed]"); + Decode(hr); + return; + } + if (fn) { + strcpy(title,fn); + hr = a3dsrc->LoadWaveFile(fn); + if (FAILED(hr)) { + Decode(hr); + return; + } + if (type & A3DSOURCE_INITIAL_RENDERMODE_NATIVE) + a3dsrc->SetRenderMode(A3DSOURCE_RENDERMODE_NATIVE); + } else { + strcpy(title,"[null]"); + } +} + + +A3DData::~A3DData() { + FreeWave(); + the_a3d_manager.datalist -= this; +} + +/************************************************************************************** + * + * A3DList -- just a linked list. yawn. + * + */ + + +A3DList::~A3DList() { + Clear(); +} + +void A3DList::Clear() { + // this may require some explanation. + // the action of deleting list calls list's destructor -- which actually adjusts list + // itself to point to the next item, ready for the next turn. + while (list) delete list; +} + +void A3DList::Add(A3DBase *item) { + item->last=tail; + if (tail) tail->next=item; + tail=item; + if (!list) list=item; + count++; +}; + +void A3DList::Del(A3DBase *item) { + if (tail==item) tail=item->last; + if (item->last) + item->last->next=item->next; + else + list=item->next; + if (item->next) item->next->last=item->last; + count--; +}; + +A3DBase *A3DList::Index(SLONG index) { + A3DBase *walk=list; + + while ((--index)&&walk) walk=walk->next; + return walk; +}; + +A3DBase *A3DList::Find(CBYTE *want) { + A3DBase *walk=list; + + while (walk&&stricmp(want,walk->GetTitle())) walk=walk->next; + return walk; +} + + +/************************************************************************************** + * + * A3DBase -- the root of all evil + * + */ + +void A3DBase::FreeWave() { + if (a3dsrc) a3dsrc->Release(); + a3dsrc=NULL; + length_samples=0; + length_seconds=0; +} + + +ULONG A3DBase::GetLengthSamples() { + WAVEFORMATEX format; + ULONG size; + + if (a3dsrc) { + if (!length_samples) { + a3dsrc->GetWaveFormat(&format); + size=a3dsrc->GetWaveSize(); // sigh, not implemented yet + length_samples=size/(format.wBitsPerSample>>3); + } + } + return length_samples; +} + +float A3DBase::GetLengthSeconds() { + WAVEFORMATEX format; + SLONG size; + + if (a3dsrc) { + if (length_seconds==0) { + a3dsrc->GetWaveFormat(&format); + //size=a3dsrc->GetWaveSize(); // ditto - DONT WORRY ABOUT THE WARNING THIS ISN'T USED + length_seconds=((float)size)/format.nAvgBytesPerSec; + } + } + return length_seconds; +} + + +BOOL A3DBase::HasEnded(UBYTE early_out) { + ULONG t,c; + + if (a3dsrc) { + + if (early_out) { + a3dsrc->GetWavePosition(&t); + c=a3dsrc->GetWaveSize(); + if (t>=c-4000) { /*TRACE("caught early? %d/%d\n",t,c);*/ return 1; } + } + +/* a3dsrc->GetWavePosition(&t); +// TRACE("%d : ( %d )\n",t,last_time); + if ((!t)&&(!last_time)) + t=1; + else + last_time=t; + return (!t); + */ + a3dsrc->GetStatus(&t); + return !(t&A3DSTATUS_PLAYING); + } + return 1; +/* TRACE("%d : %d\n",t,GetLengthSamples()); + return (t>GetLengthSamples());*/ +}; + + + +#else //#ifndef TARGET_DC + +// Spoof it all... + +#include "A3DManager.h" +#include "snd_type.h" +//#include "A3DPlay.h" + + +IA3d4 *a3droot; +IA3dGeom *a3dgeom = NULL; +A3DManager the_a3d_manager(A3D_1ST_REFLECTIONS | A3D_OCCLUSIONS | A3D_DIRECT_PATH_A3D); + +void Decode(SLONG hr) {} +void ErrChk(SLONG hr) {} +BOOL Failed(SLONG hr) { return TRUE; } +void A3D_Check_Init(void) {} +static void RegDBSetKeyValue( + char *szKey, /* in, key string */ + char *szName, /* in, name string NULL == Default */ + char *szValue) /* in, value string */ +{} + +HRESULT A3dRegister(void) { return 0; } +void A3DManager::Init(SLONG features) {} +A3DManager::A3DManager(SLONG features) {} +void A3DCleanUp(void) {} +void A3DManager::Fini(void) {} +A3DManager::~A3DManager() {} +A3DSource* A3DManager::Play(A3DData *Original, A3DSource* Channel, UBYTE flags) { return NULL; } +BOOL A3DManager::Valid(A3DBase* item) { return TRUE; } +A3DSource* A3DManager::ValidChannel(A3DBase* item) { return NULL; } +A3DBase* A3DManager::ValidWave(A3DBase* item) { return NULL; } +void A3DManager::BindMaterial(SLONG material) {} +A3DSource::A3DSource(CBYTE *fn) {} +A3DSource::A3DSource(A3DBase *original) {} +void A3DSource::SetupParams() {} +void A3DSource::DupeConstruct(A3DBase *original) {} +A3DSource::~A3DSource() {} +void A3DSource::SetMute(UBYTE mute) {} +void A3DSource::Set3D(UBYTE is3d) {} +void A3DSource::DoChange(A3DBase *original) {} +void A3DSource::Change(A3DBase *original) {} +void A3DSource::Queue(A3DBase *original, SLONG x, SLONG y, SLONG z, SLONG flags) {} +UBYTE A3DSource::CBEnded() { return 0; } +void A3DSource::Play(UBYTE looped) {} +void A3DSource::Stop() {} +void A3DSource::Rewind() {} +A3DData::A3DData(CBYTE *fn, UBYTE ntype) {} +A3DData::~A3DData() {} +A3DList::~A3DList() {} +void A3DList::Clear() {} +void A3DList::Add(A3DBase *item) {} +void A3DList::Del(A3DBase *item) {} +A3DBase *A3DList::Index(SLONG index) { return NULL; } +A3DBase *A3DList::Find(CBYTE *want) { return NULL; } +void A3DBase::FreeWave() {} +ULONG A3DBase::GetLengthSamples() { return 0; } +float A3DBase::GetLengthSeconds() { return 0.0f; } +BOOL A3DBase::HasEnded(UBYTE early_out) { return TRUE; } + + +#endif //#else //#ifndef TARGET_DC + + diff --git a/fallen/DDLibrary/Source/AsyncFile.cpp b/fallen/DDLibrary/Source/AsyncFile.cpp new file mode 100644 index 0000000..327e061 --- /dev/null +++ b/fallen/DDLibrary/Source/AsyncFile.cpp @@ -0,0 +1,155 @@ +// AsyncFile +// +// asynchronous file loading +// +// ha ha the funny thing about this code is that it will only work under Windows NT ... oops! + +#include +#include "asyncfile.h" + +static AsyncFile File[MAX_ASYNC_FILES]; + +static AsyncFile FreeList; +static AsyncFile ActiveList; + +static void Unlink(AsyncFile* file); +static void FreeLink(AsyncFile* file); +static void ActiveLink(AsyncFile* file); + +// InitAsyncFile +// +// initialize + +void InitAsyncFile(void) +{ + memset(File, 0, sizeof(File)); + memset(&FreeList, 0, sizeof(FreeList)); + memset(&ActiveList, 0, sizeof(ActiveList)); + + FreeList.next = FreeList.prev = &FreeList; + ActiveList.next = ActiveList.prev = &ActiveList; + + for (int ii = 0; ii < MAX_ASYNC_FILES; ii++) + { + FreeLink(&File[ii]); + } +} + +// TermAsyncFile +// +// terminate + +void TermAsyncFile(void) +{ + CancelAsyncFile(NULL); +} + +// LoadAsyncFile +// +// load an async file +// returns false on error + +bool LoadAsyncFile(char* filename, void* buffer, DWORD blen, void* key) +{ + // get free AsyncFile + if (FreeList.next == &FreeList) return false; + + AsyncFile* file = FreeList.next; + + // open the file + file->hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (!file->hFile) return false; + + // set the key + file->hKey = key; + + // begin the read operation + file->Control.Offset = 0; + file->Control.OffsetHigh = 0; + file->Control.hEvent = 0; + + if (!ReadFileEx(file->hFile, buffer, blen, &file->Control, NULL)) + { + // failure + CloseHandle(file->hFile); + return false; + } + + // success + Unlink(file); + ActiveLink(file); + return true; +} + +// GetNextCompletedAsyncFile +// +// return key for completed file + +void* GetNextCompletedAsyncFile(void) +{ + for (AsyncFile* file = ActiveList.next; file != &ActiveList; file = file->next) + { + if (HasOverlappedIoCompleted(&file->Control)) + { + // this has finished + Unlink(file); + FreeLink(file); + + CloseHandle(file->hFile); + + return file->hKey; + } + } + + return NULL; +} + +// CancelAsyncFile +// +// cancel loading an async file + +void CancelAsyncFile(void* key) +{ + AsyncFile* file = ActiveList.next; + + while (file != &ActiveList) + { + AsyncFile* next = file->next; + + if (!key || (file->hKey == key)) + { + CancelIo(file->hFile); + CloseHandle(file->hFile); + Unlink(file); + FreeLink(file); + } + + file = next; + } +} + +// List utilities + +static void Unlink(AsyncFile* file) +{ + file->next->prev = file->prev; + file->prev->next = file->next; +} + +static void FreeLink(AsyncFile* file) +{ + file->prev = &FreeList; + file->next = FreeList.next; + + file->next->prev = file; + file->prev->next = file; +} + +static void ActiveLink(AsyncFile* file) +{ + file->prev = &ActiveList; + file->next = ActiveList.next; + + file->next->prev = file; + file->prev->next = file; +} diff --git a/fallen/DDLibrary/Source/AsyncFile2.cpp b/fallen/DDLibrary/Source/AsyncFile2.cpp new file mode 100644 index 0000000..8ad82e3 --- /dev/null +++ b/fallen/DDLibrary/Source/AsyncFile2.cpp @@ -0,0 +1,319 @@ +// AsyncFile2 +// +// asynchronous file loading +// +// the API opens files and moves blocks from the Free to the Active list; it also moves blocks from +// the Complete to the Free list. a critical section is used to serialize access to the Active and +// Complete lists (only the API accesses the Free list) and an event is used to wake the worker thread +// when required. To avoid using the MT C RTL the worker thread only makes WIN32 calls. +// +// If you don't understand what this means, DON'T FUCK WITH THIS CODE + +#include +//#include +#ifndef TARGET_DC +#include +#endif + +#ifdef TARGET_DC +#include "target.h" +#endif + +#include "asyncfile2.h" + +static AsyncFile File[MAX_ASYNC_FILES]; + +static AsyncFile FreeList; +static AsyncFile ActiveList; +static AsyncFile CompleteList; + +static void Unlink(AsyncFile* file); +static void FreeLink(AsyncFile* file); +static void ActiveLink(AsyncFile* file); +static void CompleteLink(AsyncFile* file); + +// thread stuff + +static int KillThread; +static void* CancelKey; + +static CRITICAL_SECTION csLock; +static HANDLE hEvent; +static HANDLE hThread; +static DWORD WINAPI ThreadRun(LPVOID arg); + +// amount to read per ms +static const int BytesPerMillisecond = 128 * 1024; + +// InitAsyncFile +// +// initialize + +void InitAsyncFile(void) +{ + // set up structures + memset(File, 0, sizeof(File)); + memset(&FreeList, 0, sizeof(FreeList)); + memset(&ActiveList, 0, sizeof(ActiveList)); + memset(&CompleteList, 0, sizeof(CompleteList)); + + FreeList.next = FreeList.prev = &FreeList; + ActiveList.next = ActiveList.prev = &ActiveList; + CompleteList.next = CompleteList.prev = &CompleteList; + + for (int ii = 0; ii < MAX_ASYNC_FILES; ii++) + { + FreeLink(&File[ii]); + } + + // init sync objects + InitializeCriticalSection(&csLock); + + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + KillThread = 0; + CancelKey = 0; + + // begin background thread + DWORD tid; + + hThread = CreateThread(NULL, 0, ThreadRun, NULL, 0, &tid); +} + +// TermAsyncFile +// +// terminate + +void TermAsyncFile(void) +{ + // tell thread to die + TRACE("MAIN: Telling worker thread to die\n"); + EnterCriticalSection(&csLock); + KillThread = 1; + LeaveCriticalSection(&csLock); + + SetEvent(hEvent); + + // wait for thread to die + TRACE("MAIN: Waiting for worker thread to die\n"); + EnterCriticalSection(&csLock); + while (KillThread != 2) + { + LeaveCriticalSection(&csLock); + Sleep(0); + EnterCriticalSection(&csLock); + } + LeaveCriticalSection(&csLock); + + TRACE("MAIN: Closing down\n"); + CloseHandle(hThread); + CloseHandle(hEvent); +} + +// ThreadRun +// +// the main thread + +DWORD WINAPI ThreadRun(LPVOID arg) +{ + for (;;) + { + // wait to be signalled + WaitForSingleObject(hEvent, INFINITE); + + TRACE("Worker: Signalled\n"); + + // get command + EnterCriticalSection(&csLock); + + if (KillThread == 1) + { + TRACE("Worker: Received kill instruction\n"); + KillThread = 2; + LeaveCriticalSection(&csLock); + return 0; + } + + if (CancelKey) + { + TRACE("Worker: Received cancel instruction\n"); + AsyncFile* file = ActiveList.next; + while (file != &ActiveList) + { + AsyncFile* next = file->next; + if (file->hKey == CancelKey) + { + Unlink(file); + CompleteLink(file); + } + file = next; + } + CancelKey = NULL; + } + + AsyncFile* file = NULL; + + if (ActiveList.next != &ActiveList) + { + TRACE("Worker: Received file load instruction\n"); + file = ActiveList.next; + Unlink(file); + } + + LeaveCriticalSection(&csLock); + + if (file) + { + DWORD amount; + + // read file + TRACE("Worker: Commence reading file\n"); + + while (file->blen > BytesPerMillisecond) + { + TRACE("Worker: Reading block\n"); + ReadFile(file->hFile, file->buffer, BytesPerMillisecond, &amount, NULL); + file->buffer += BytesPerMillisecond; + file->blen -= BytesPerMillisecond; + Sleep(0); + } + + if (file->blen) + { + TRACE("Worker: Reading final block\n"); + ReadFile(file->hFile, file->buffer, file->blen, &amount, NULL); + } + TRACE("Worker: Complete\n"); + + EnterCriticalSection(&csLock); + CompleteLink(file); + LeaveCriticalSection(&csLock); + } + } + + return 0; +} + +// LoadAsyncFile +// +// load an async file +// returns false on error + +bool LoadAsyncFile(char* filename, void* buffer, DWORD blen, void* key) +{ + // get free AsyncFile + if (FreeList.next == &FreeList) return false; + + AsyncFile* file = FreeList.next; + + // open the file + file->hFile = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (!file->hFile) return false; + + // set the key + file->hKey = key; + + // set up the read + file->buffer = (UBYTE*)buffer; + file->blen = blen; + + // success + Unlink(file); + + // send to worker thread & signal it + TRACE("MAIN: Adding block to active list\n"); + EnterCriticalSection(&csLock); + ActiveLink(file); + LeaveCriticalSection(&csLock); + + TRACE("MAIN: Signalling worker thread\n"); + SetEvent(hEvent); + + return true; +} + +// GetNextCompletedAsyncFile +// +// return key for completed file + +void* GetNextCompletedAsyncFile(void) +{ + EnterCriticalSection(&csLock); + for (AsyncFile* file = CompleteList.next; file != &CompleteList; file = file->next) + { + Unlink(file); + LeaveCriticalSection(&csLock); + + CloseHandle(file->hFile); + FreeLink(file); + + return file->hKey; + } + LeaveCriticalSection(&csLock); + + return NULL; +} + +// CancelAsyncFile +// +// cancel loading an async file + +void CancelAsyncFile(void* key) +{ + if (!key) return; + + // signal worker thread to cancel the file + TRACE("MAIN: Instructing worker thread to cancel\n"); + EnterCriticalSection(&csLock); + CancelKey = key; + LeaveCriticalSection(&csLock); + + SetEvent(hEvent); + + // wait for thread + EnterCriticalSection(&csLock); + while (CancelKey) + { + LeaveCriticalSection(&csLock); + Sleep(0); + EnterCriticalSection(&csLock); + } + LeaveCriticalSection(&csLock); + + TRACE("MAIN: Continuing after cancel\n"); +} + +// List utilities + +static void Unlink(AsyncFile* file) +{ + file->next->prev = file->prev; + file->prev->next = file->next; +} + +static void FreeLink(AsyncFile* file) +{ + file->prev = &FreeList; + file->next = FreeList.next; + + file->next->prev = file; + file->prev->next = file; +} + +static void ActiveLink(AsyncFile* file) +{ + file->prev = &ActiveList; + file->next = ActiveList.next; + + file->next->prev = file; + file->prev->next = file; +} + +static void CompleteLink(AsyncFile* file) +{ + file->prev = &CompleteList; + file->next = CompleteList.next; + + file->next->prev = file; + file->prev->next = file; +} diff --git a/fallen/DDLibrary/Source/BinkClient.cpp b/fallen/DDLibrary/Source/BinkClient.cpp new file mode 100644 index 0000000..62cf64b --- /dev/null +++ b/fallen/DDLibrary/Source/BinkClient.cpp @@ -0,0 +1,246 @@ +// BinkClient.cpp +// +// simple client for BINK file playback +// +// DO NOT PUT ANY OF YOUR USUAL CRAP INTO THIS FILE +// If you want to change anything, do it in do_bink_intro() or bink_flipper() in GDisplay.cpp + +#ifndef TARGET_DC + +#include "DDLib.h" +#include "bink.h" +#include "MFX_Miles.h" +#include "snd_type.h" +#include "drive.h" + +static s32 focus = 1; // we have focus +static HBINK bink = NULL; // a bink file is loaded + +// BinkMessage +// +// handle bink windows messages + +void BinkMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (!bink) return; + + switch (message) + { + case WM_SETFOCUS: + BinkPause(bink, 0); + focus = 1; + break; + + case WM_KILLFOCUS: + BinkPause(bink, 1); + focus = 0; + break; + } +} + +// ClearScreen +// +// clear the screen + +static void ClearScreen(IDirectDrawSurface* lpdds, DDSURFACEDESC* lpddsd) +{ + u8* ptr = (u8*)lpddsd->lpSurface; + u32 llen = lpddsd->dwWidth * lpddsd->ddpfPixelFormat.dwRGBBitCount / 8; + + for (u32 ii = 0; ii < lpddsd->dwHeight; ii++) + { + memset(ptr, 0, llen); + ptr += lpddsd->lPitch; + } +} + +// NextBinkFrame +// +// show the next frame + +static bool NextBinkFrame(IDirectDrawSurface* lpdds, DDSURFACEDESC* lpddsd, s32 stype, u32 xoff, u32 yoff, bool (*flip)()) +{ + HRESULT res; + bool rc = true; + + if (!bink) return false; + + BinkDoFrame(bink); + + res = lpdds->Lock(0, lpddsd, DDLOCK_WAIT, 0); + + if (res == DDERR_SURFACELOST) + { + res = lpdds->Restore(); + if (SUCCEEDED(res)) + { + res = lpdds->Lock(0, lpddsd, DDLOCK_WAIT, 0); + } + } + + if (SUCCEEDED(res)) + { + // clear the buffer for the first screen + if (bink->FrameNum == 1) + { + ClearScreen(lpdds, lpddsd); + } + BinkCopyToBuffer(bink, lpddsd->lpSurface, lpddsd->lPitch, bink->Height, xoff, yoff, stype); + lpdds->Unlock(NULL); + if (flip) rc = flip(); + } + + if (bink->FrameNum == bink->Frames) return false; + + BinkNextFrame(bink); + + return rc; +} + +// EndMovie +// +// clears the screen + +static void EndMovie(IDirectDrawSurface* lpdds, DDSURFACEDESC* lpddsd, bool (*flip)()) +{ + HRESULT res; + + res = lpdds->Lock(0, lpddsd, DDLOCK_WAIT, 0); + + if (res == DDERR_SURFACELOST) + { + res = lpdds->Restore(); + if (SUCCEEDED(res)) + { + res = lpdds->Lock(0, lpddsd, DDLOCK_WAIT, 0); + } + } + + if (SUCCEEDED(res)) + { + ClearScreen(lpdds, lpddsd); + lpdds->Unlock(NULL); + if (flip) flip(); + } +} + +// BinkPlay +// +// play a bink video using the back surface and the flip function specified + +void BinkPlay(const char* filename, IDirectDrawSurface* lpdds, bool (*flip)()) +{ + // obtain surface info + DDSURFACEDESC DDSD; + + memset(&DDSD, 0, sizeof(DDSD)); + DDSD.dwSize = sizeof(DDSD); + + if (FAILED(lpdds->GetSurfaceDesc(&DDSD))) + { + MessageBox(0, "Can't playback the movie ... bad surface", "Error", MB_OK); + return; + } + + s32 stype = BinkDDSurfaceType(lpdds); + + if ((stype == -1) || (stype == BINKSURFACE8P)) + { + MessageBox(0, "Can't playback the movie ... bad video colour depth", "Error", MB_OK); + return; + } + + // set sound driver +#ifdef M_SOUND + if (GetMilesDriver()) + { + BinkSoundUseMiles(GetMilesDriver()); + } +#endif + + // open the bink file & check it's size + char fullname[MAX_PATH]; + strcpy(fullname, GetMoviesPath()); + strcat(fullname, filename); + bink = BinkOpen(fullname, 0); + if (!bink) return; + + if ((bink->StretchWidth > DDSD.dwWidth) || (bink->StretchHeight > DDSD.dwHeight)) + { + MessageBox(0, "Can't playback the movie ... bad video resolution", "Error", MB_OK); + BinkClose(bink); + bink = NULL; + return; + } + + u32 xoff = (DDSD.dwWidth - bink->StretchWidth) / 2; + u32 yoff = (DDSD.dwHeight - bink->StretchHeight) / 2; + + Keys[KB_SPACE] = 0; + Keys[KB_ENTER] = 0; + Keys[KB_ESC] = 0; + + + // play each frame +// for (;;) + while(SHELL_ACTIVE) + { + MSG msg; + + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) break; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + if (!BinkWait(bink)) + { + if (!NextBinkFrame(lpdds, &DDSD, stype, xoff, yoff, flip)) break; + } + + if (!focus) Sleep(1); // lost focus + } + + if (Keys[KB_SPACE] || + Keys[KB_ENTER] || + Keys[KB_ESC]) + { + Keys[KB_SPACE] = 0; + Keys[KB_ENTER] = 0; + Keys[KB_ESC] = 0; + + break; + } + } + + // clear the buffer + // (this is done to avoid coloured crap on the mode change) + EndMovie(lpdds, &DDSD, flip); + + BinkClose(bink); + bink = NULL; +} + + + +#else //#ifndef TARGET_DC + +#include "DDLib.h" + + +// Sod it - spoof the lot of them. +void BinkMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + ASSERT(FALSE); +} + +void BinkPlay(const char* filename, IDirectDrawSurface* lpdds, bool (*flip)()) +{ + ASSERT(FALSE); +} + + + +#endif //#else //#ifndef TARGET_DC diff --git a/fallen/DDLibrary/Source/D3DTexture.cpp b/fallen/DDLibrary/Source/D3DTexture.cpp new file mode 100644 index 0000000..b8f5ae4 --- /dev/null +++ b/fallen/DDLibrary/Source/D3DTexture.cpp @@ -0,0 +1,4486 @@ +// D3DTexture.cpp +// Guy Simmons, 29th November 1997. + +#include "DDLib.h" +#include "tga.h" + +#ifdef TARGET_DC +#include "target.h" +#endif + +#ifndef VERIFY +#ifdef NDEBUG +#define VERIFY(x) x +#else +#define VERIFY(x) {ASSERT(x);} +#endif +#endif + +#ifdef TEX_EMBED +static D3DTexture* EmbedSource = NULL; +static LPDIRECTDRAWSURFACE4 EmbedSurface = NULL; +static LPDIRECT3DTEXTURE2 EmbedTexture = NULL; +static UBYTE EmbedOffset = 0; +#endif + + +extern void POLY_reset_render_states ( void ); + + +// Do VQ compression if the size is over this value. +// +// Note: 32x32x2 = 2048, but 32x32/4+2048 = 2304 +// But: 64x64x2 = 8192, but 64x64/4+2048 = 3072, +// +// So under 32x32, the VQ size is actually greater. +// However, if mipmapped, they would normally take: +// 32x32x2*(4/3) = 2730, but 32x32*(4/3)/4+2048 = 2389 +// 64x64x2*(4/3) = 10922, but 64x64*(4/3)/4+2048 = 3413, +// +// So when mipmapping, VQ is a win even at 32x32. At 16x16 however: +// 16x16x2*(4/3) = 682, but 16x16*(4/3)/4+2048 = 2389 +// ... as expected. + +#define VQ_MINIMUM_SIZE 32 + +// Now that mipmapped VQs are on disk, they load even faster than normal stuff. +// So there's no reason not to. +//#ifdef DEBUG +//#define DONT_VQ_MY_TEXTURES_PLEASE_BOB +//#else +//#define DONT_VQ_MY_TEXTURES_PLEASE_BOB +//#endif + + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +// The structure that holds the mapping from page to texture. +#define MAX_TEXTURES_PER_PAGE 16 +struct PageToTextureMap +{ + int iType; // One of the D3DPAGE_xxx types. + D3DTexture *d3dTexture[MAX_TEXTURES_PER_PAGE]; + LPDIRECT3DTEXTURE2 lp_Texture; + LPDIRECTDRAWSURFACE4 lp_Surface; +}; + +// The structure that defines where each texture goes in which page. +struct TextureToPageMap +{ + char *name; // Texture file name. + int iPageNum; // The page this is in. + int iPagePos; // Position in page. +}; + +// And now the list of textures in pages. +// Pages are separated by strings starting with "***" and then a page type, which is one of: +// "64_3", "64_4", "32_3", "32_4", etc, then a colon followed by the directory of the page. +// Each page can only be composed of textures in a single directory. This is not a big +// restriction. Then comes the actual filename of the page image. If this file doesn't exist +// then (theoretically), one is created automagically. You must _have_ a filename, because +// it gets saved out. +// Then the list of texture names, without leading directory. There doesn't have to +// be the full number of textures in a page - the list can end early. Can't have more of course. +// Textures are listed going across the texture first for 4x4s, then down a line, e.g.: +// +// 1234 +// 5678 +// 9abc +// def0 +// +// For historical reasons, 3x3 chunks are listed the other way round: +// +// 147 +// 258 +// 369 +// +// Confusing eh? :-) +// +// If a filename is NULL or "", then that position is skipped. +// The end comes at "***END" + + +char *TexturePageList[] = { + +#if 0 + "***64_4:server\\textures\\shared\\people3\\", "server\\textures\\shared\\people3\\person_purple.tga", + "femchest1.tga", + "", + "", + "femarse1.tga", + "seam1.tga", + "", + "front1.tga", + "fembak1.tga", + "femshoo1.tga", + "", + "crotch1.tga", + "hattop1.tga", + "leg1.tga", + "", + "", + "hatside1.tga", + + "***64_4:server\\textures\\shared\\people3\\", "server\\textures\\shared\\people3\\person_red.tga", + "femchest2.tga", + "", + "", + "femarse2.tga", + "seam2.tga", + "", + "front5.tga", + "fembak2.tga", + "femshoo2.tga", + "", + "crotch5.tga", + "hattop5.tga", + "leg5.tga", + "", + "", + "hatside5.tga", + + + + // NOTE! Not the correct page texture! + "***64_4:server\\textures\\shared\\people3\\", "server\\textures\\shared\\people3\\person_page3.tga", + "femchest3.tga", + "", + "", + "femarse3.tga", + "seam3.tga", + "", + "front4.tga", + "fembak3.tga", + "femshoo3.tga", + "", + "crotch4.tga", + "hattop4.tga", + "leg4.tga", + "", + "", + "hatside4.tga", + + // NOTE! Not the correct page texture! + "***64_4:server\\textures\\shared\\people3\\", "server\\textures\\shared\\people3\\person_page4.tga", + "", + "", + "", + "", + "", + "", + "front2.tga", + "", + "", + "", + "crotch2.tga", + "hattop2.tga", + "leg2.tga", + "", + "", + "hatside2.tga", + + // NOTE! Not the correct page texture! + "***64_4:server\\textures\\shared\\people3\\", "server\\textures\\shared\\people3\\person_page5.tga", + "", + "", + "", + "", + "", + "", + "front3.tga", + "", + "", + "", + "crotch3.tga", + "hattop3.tga", + "leg3.tga", + "", + "", + "hatside3.tga", +#endif + + "***64_4:server\\textures\\shared\\people\\", "server\\textures\\shared\\people\\page_darci1.tga", + "tex064.tga", + "tex077.tga", + "tex081.tga", + "tex080.tga", + "tex065.tga", + "tex069.tga", + "tex082.tga", + "tex078.tga", + "tex067.tga", + "tex068.tga", + "tex070.tga", + "tex066.tga", + "tex062.tga", + "tex061.tga", + "tex079.tga", + "tex063.tga", + + "***64_4:server\\textures\\extras\\", "server\\textures\\extras\\page_misc_alpha.tga", + "bludsplt.tga", + "bigleaf.tga", + "tinybutt.tga", + "footprint.tga", + "leaf.tga", + "rubbish.tga", + "", + "", + "", + "", + "", + "", + "raindrop.tga", + +#if 1 + "***64_4:server\\textures\\extras\\DC\\", "server\\textures\\extras\\DC\\page_joybutts.tga", + "button_A.tga", + "button_B.tga", + "button_C.tga", + "button_X.tga", + "button_Y.tga", + "button_Z.tga", + "button_LEFT.tga", + "button_RIGHT.tga", + "button_PADLEFT.tga", + "button_PADRIGHT.tga", + "button_PADDOWN.tga", + "button_PADUP.tga", +#endif + + "***END" +}; + +// +// The texture page lists for each mission... +// + +#ifdef TARGET_DC + +CBYTE *fname_for_packed_array[] = +{ + "PackedTextures\\testdrive1a\\array_testdrive1a.dat", + "PackedTextures\\FTutor1\\array_FTutor1.dat", + "PackedTextures\\Assault1\\array_Assault1.dat", + "PackedTextures\\police1\\array_police1.dat", + "PackedTextures\\police2\\array_police2.dat", + "PackedTextures\\Bankbomb1\\array_Bankbomb1.dat", + "PackedTextures\\police3\\array_police3.dat", + "PackedTextures\\Gangorder2\\array_Gangorder2.dat", + "PackedTextures\\police4\\array_police4.dat", + "PackedTextures\\bball2\\array_bball2.dat", + "PackedTextures\\wstores1\\array_wstores1.dat", + "PackedTextures\\e3\\array_e3.dat", + "PackedTextures\\westcrime1\\array_westcrime1.dat", + "PackedTextures\\carbomb1\\array_carbomb1.dat", + "PackedTextures\\botanicc\\array_botanicc.dat", + "PackedTextures\\Semtex\\array_Semtex.dat", + "PackedTextures\\AWOL1\\array_AWOL1.dat", + "PackedTextures\\mission2\\array_mission2.dat", + "PackedTextures\\park2\\array_park2.dat", + "PackedTextures\\MIB\\array_MIB.dat", + "PackedTextures\\skymiss2\\array_skymiss2.dat", + "PackedTextures\\factory1\\array_factory1.dat", + "PackedTextures\\estate2\\array_estate2.dat", + "PackedTextures\\Stealtst1\\array_Stealtst1.dat", + "PackedTextures\\snow2\\array_snow2.dat", + "PackedTextures\\Gordout1\\array_Gordout1.dat", + "PackedTextures\\Baalrog3\\array_Baalrog3.dat", + "PackedTextures\\Finale1\\array_Finale1.dat", + "PackedTextures\\Gangorder1\\array_Gangorder1.dat", + "PackedTextures\\FreeCD1\\array_FreeCD1.dat", + "PackedTextures\\jung3\\array_jung3.dat", + "PackedTextures\\fight1\\array_fight1.dat", + "PackedTextures\\fight2\\array_fight2.dat", + "PackedTextures\\testdrive2\\array_testdrive2.dat", + "PackedTextures\\testdrive3\\array_testdrive3.dat", + "PackedTextures\\Album1\\array_Album1.dat", +}; + + +#endif + + + +#define MAX_NUM_D3DPAGES 200 + +int iNumD3DPages = 0; +D3DPage pageD3D[MAX_NUM_D3DPAGES]; + + +#endif + + + + + +static DWORD dwSizeOfFastLoadBuffer = 0; +void *pvFastLoadBuffer = NULL; + +inline void *GetMeAFastLoadBufferAtLeastThisBigPlease ( DWORD dwSize ) +{ + if ( dwSizeOfFastLoadBuffer < dwSize ) + { + if ( pvFastLoadBuffer != NULL ) + { + VirtualFree ( pvFastLoadBuffer, NULL, MEM_RELEASE ); + } + // Grow slightly more than needed to prevent hammering. + dwSizeOfFastLoadBuffer = ( dwSize * 5 / 4 + 1024 ); + // Ensure it's 4k-aligned. + dwSizeOfFastLoadBuffer = ( ( dwSizeOfFastLoadBuffer + 4095 ) & ~4095 ); + + TRACE ( "Growing FastLoad buffer to 0x%x bytes\n", dwSizeOfFastLoadBuffer ); + + pvFastLoadBuffer = VirtualAlloc ( NULL, dwSizeOfFastLoadBuffer, MEM_COMMIT, PAGE_READWRITE ); + ASSERT ( pvFastLoadBuffer != NULL ); + } + return ( pvFastLoadBuffer ); +} + + +void NotGoingToLoadTexturesForAWhileNowSoYouCanCleanUpABit ( void ) +{ + if ( pvFastLoadBuffer != NULL ) + { + TRACE ( "Freeing FastLoad buffer\n" ); + VirtualFree ( pvFastLoadBuffer, NULL, MEM_RELEASE ); + pvFastLoadBuffer = NULL; + dwSizeOfFastLoadBuffer = 0; + } +} + +inline void *FastLoadFileSomewhere ( MFFileHandle handle, DWORD dwSize ) +{ + void *pvData = GetMeAFastLoadBufferAtLeastThisBigPlease ( dwSize ); + ASSERT ( pvData != NULL ); + + DWORD dwAlignedFileSize = dwSize & ( ~4095 ); + // DMA read + DWORD dwRead = 0; + if ( dwAlignedFileSize > 0 ) + { + dwRead = FileRead ( handle, pvData, dwAlignedFileSize ); + } + // Finish off with PIO or whatever. + if ( dwSize - dwAlignedFileSize > 0 ) + { + dwRead += FileRead ( handle, (void *)( (char *)pvData + dwAlignedFileSize ), dwSize - dwAlignedFileSize ); + } + + ASSERT ( dwRead == dwSize ); + + return ( pvData ); +} + + + + + +// +// Loads a 'cpp' file of disk that's been converted to +// a 'dat' file with the Martin utility! +// + +CBYTE **D3DTEXTURE_cpp_array; +CBYTE *D3DTEXTURE_cpp_buffer; + +void D3DTEXTURE_load_cpp_array(CBYTE *fname) +{ + CBYTE **ans; + SLONG ans_max; + SLONG ans_upto; + + CBYTE *buffer; + SLONG buffer_max; + SLONG buffer_upto; + + // + // Initialise answer. + // + + D3DTEXTURE_cpp_array = NULL; + D3DTEXTURE_cpp_buffer = NULL; + + // + // Open file. + // + + FILE *handle = MF_Fopen(fname, "rb"); + + if (handle == NULL) + { + ASSERT(0); + + return; + } + + // + // Read in our memory requirements. + // + + if (fread(&ans_max, sizeof(SLONG), 1, handle) != 1) goto file_error; + if (fread(&buffer_max, sizeof(SLONG), 1, handle) != 1) goto file_error; + + // + // Allocate memory. + // + + ans_upto = 0; + ans = (CBYTE **) MemAlloc(sizeof(CBYTE *) * ans_max); + + buffer_upto = 0; + buffer = (CBYTE *) MemAlloc(sizeof(CBYTE) * buffer_max); + + ASSERT(ans ); + ASSERT(buffer); + + memset(ans, 0, sizeof(CBYTE *) * ans_max ); + memset(buffer, 0, sizeof(CBYTE ) * buffer_max); + + // + // Load in the indices and the buffer. + // + + if (fread(ans, sizeof(SLONG), ans_max, handle) != ans_max ) goto file_error; + if (fread(buffer, sizeof(CBYTE), buffer_max, handle) != buffer_max) goto file_error; + + // + // Convert indices to pointers... + // + + SLONG i; + + for (i = 0; i < ans_max; i++) + { + ans[i] = buffer + SLONG(ans[i]); + } + + // + // Return the result. + // + + D3DTEXTURE_cpp_array = ans; + D3DTEXTURE_cpp_buffer = buffer; + + MF_Fclose(handle); + + return; + + file_error: + + ASSERT(0); + + MF_Fclose(handle); + + return; + +} + + + + + + + + + + + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +static bool m_bTexturePagesInitialised = FALSE; + + +void FreeAllD3DPages ( void ) +{ + for ( int i = 0; i < iNumD3DPages; i++ ) + { + pageD3D[i].Unload(); + } + iNumD3DPages = 0; + + // And free the array memory. + if ( D3DTEXTURE_cpp_array != NULL ) + { + MemFree(D3DTEXTURE_cpp_array ); + D3DTEXTURE_cpp_array = NULL; + } + + if ( D3DTEXTURE_cpp_buffer != NULL ) + { + MemFree(D3DTEXTURE_cpp_buffer); + D3DTEXTURE_cpp_buffer = NULL; + } + + // And redo all the render states and sorting. + POLY_reset_render_states(); + +} + + +#endif + + + + + + + + + + + + + + + + + +void D3DTexture::BeginLoading() +{ + SLONG first_time = TRUE; + +#ifdef TEX_EMBED + EmbedSource = NULL; + EmbedSurface = NULL; + EmbedTexture = NULL; + EmbedOffset = 0; + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + //if ( !m_bTexturePagesInitialised ) + + + // Unload everything first. + FreeAllD3DPages(); + + ASSERT ( iNumD3DPages == 0 ); + + while(1) + { + // Done once only. + //m_bTexturePagesInitialised = TRUE; + + // Scan my text list, initialising the D3DPages as we go. + char **ppcList = TexturePageList; + int iPageType = 0; + int iPagePos = 0; + int iSafetyTimeout = 1000; + + if (first_time) + { + // + // Don't use TexturePageList, use the right one for the current mission. + // + + int i = 0; + bool bFound = FALSE; + + while(1) + { + extern CBYTE ELEV_fname_level[]; + extern CBYTE *suggest_order[]; + + if (suggest_order[i][0] == '!') + { + break; + } + + if (strcmp(ELEV_fname_level + 7, suggest_order[i]) == 0) + { + // + // Found our mission... + // + + D3DTEXTURE_load_cpp_array(fname_for_packed_array[i]); + + //ppcList = texture_page_lists_for_each_mission[i]; + + ppcList = D3DTEXTURE_cpp_array; + + //goto found_mission; + bFound = TRUE; + break; + } + + i++; + } + + if ( !bFound ) + { + // Not found - this happens on the frontend screen for example. + // Carry on. + first_time = FALSE; + continue; + } + + //found_mission:; + } + + while ( TRUE ) + { + + iSafetyTimeout--; + if ( iSafetyTimeout <= 0 ) + { + // Oops. + ASSERT ( FALSE ); + break; + } + + // This should be a command. + char *pcCurString = *ppcList; + ppcList++; + ASSERT ( ( pcCurString[0] == '*' ) && ( pcCurString[1] == '*' ) && ( pcCurString[2] == '*' ) ); + if ( 0 == stricmp ( pcCurString+3, "END" ) ) + { + // End of list. + break; + } + + // Find the page type + if ( 0 == strncmp ( pcCurString, "***64_4:", 8 ) ) + { + iPageType = D3DPAGE_64_4X4; + } + else if ( 0 == strncmp ( pcCurString, "***32_4:", 8 ) ) + { + iPageType = D3DPAGE_32_4X4; + } + else if ( 0 == strncmp ( pcCurString, "***64_3:", 8 ) ) + { + iPageType = D3DPAGE_64_3X3; + } + else if ( 0 == strncmp ( pcCurString, "***32_3:", 8 ) ) + { + iPageType = D3DPAGE_32_3X3; + } + else + { + ASSERT ( FALSE ); + } + + + // Set up the texture page. + pageD3D[iNumD3DPages].bPageType = (UBYTE)iPageType; + pageD3D[iNumD3DPages].bNumTextures = 0; + pageD3D[iNumD3DPages].pcDirectory = pcCurString + 8; + // Next string is the filename of the page. + pageD3D[iNumD3DPages].pcFilename = *ppcList++; + pageD3D[iNumD3DPages].ppcTextureList = ppcList; + pageD3D[iNumD3DPages].pTex = NULL; + + // See how many textures there are. + while ( (*ppcList)[0] != '*' ) + { + //pageD3D[iNumD3DPages].pTextures[pageD3D[iNumD3DPages].bNumTextures] = NULL; + pageD3D[iNumD3DPages].bNumTextures++; + ppcList++; + } + + switch ( iPageType ) + { + case D3DPAGE_64_4X4: + case D3DPAGE_32_4X4: + ASSERT ( pageD3D[iNumD3DPages].bNumTextures <= 16 ); + break; + case D3DPAGE_64_3X3: + case D3DPAGE_32_3X3: + ASSERT ( pageD3D[iNumD3DPages].bNumTextures <= 9 ); + break; + default: + ASSERT ( FALSE ); + break; + } + + ASSERT ( iNumD3DPages < MAX_NUM_D3DPAGES ); + iNumD3DPages++; + } + + // Texture pages are not actually loaded until a texture on them + // is loaded - it's all demand-loaded. Hooray! + + if (first_time) + { + first_time = FALSE; + } + else + { + break; + } + } +#endif + + +#endif + + // And redo all the render states and sorting. + POLY_reset_render_states(); + +} + + + + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + +void D3DPage::EnsureLoaded ( void ) +{ + if ( this->pTex != NULL ) + { + // Cool - already done. + return; + } + + // OK, we need to load this up. + this->pTex = MFnew(); + ASSERT ( this->pTex != NULL ); + +// Set to 1 to allow null or missing filenames +#define JUST_TESTING 0 + + HRESULT hres = this->pTex->LoadTextureTGA ( this->pcFilename, -1, TRUE ); + if ( FAILED(hres) ) + { +#ifdef TARGET_DC + // File missing. +#if !JUST_TESTING + ASSERT ( FALSE ); +#else + // Just testing, so don't die, just don't page. +#endif + this->pTex = NULL; +#else + // File probably not there - autogenerate it on the PC and save it out. + // For now, do nothing. + this->pTex = NULL; +#endif + } +} + + +void D3DPage::Unload ( void ) +{ + if ( this->pTex != NULL ) + { + ASSERT ( pTex != NULL ); + pTex->Destroy(); + MFdelete(pTex); + pTex = NULL; + } +} + + +#endif //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + + +#undef JUST_TESTING + + + + +#ifdef TEX_EMBED +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +void D3DTexture::GetTexOffsetAndScale ( float *pfUScale, float *pfUOffset, float *pfVScale, float *pfVOffset ) +{ + switch ( bPageType ) + { + case D3DPAGE_NONE: + *pfUScale = 1.0f; + *pfVScale = 1.0f; + *pfUOffset = 0.0f; + *pfVOffset = 0.0f; + break; + case D3DPAGE_64_3X3: + case D3DPAGE_32_3X3: + // Arranged with 32-pixel gaps between textures, and + // the textures are right up against the edge. + // So along the edge, you have 64 texels, 32 pagging, 64 texels, 32 padding, 64 texels. + // So the offsets are 0.0, 0.375, 0.75 + *pfUScale = 0.25f; + *pfVScale = 0.25f; + *pfUOffset = 0.375f * (float)( bPagePos % 3 ); + *pfVOffset = 0.375f * (float)( bPagePos / 3 ); + break; + case D3DPAGE_64_4X4: + case D3DPAGE_32_4X4: + // Edge-to-edge packing. + *pfUScale = 0.25f; + *pfVScale = 0.25f; + *pfUOffset = 0.25f * (float)( bPagePos & 0x3 ); + *pfVOffset = 0.25f * (float)( bPagePos >> 2 ); + break; + default: + ASSERT ( FALSE ); + break; + } + +} + +#endif //#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB +#endif //#ifdef TEX_EMBED + + +#ifndef TARGET_DC + +//--------------------------------------------------------------- + +HRESULT D3DTexture::LoadTexture8(CBYTE *tex_file,CBYTE *pal_file) +{ + HRESULT result; + + ASSERT(Type == D3DTEXTURE_TYPE_UNUSED); + + ASSERT(0); // the TGA clumper doesn't deal with 8bpp textures + + lp_Texture = NULL; +#ifndef TARGET_DC + lp_Palette = NULL; +#endif + lp_Surface = NULL; + + + // Check parameters. + if((!tex_file) || (!pal_file)) + { + // Invalid parameters. + return DDERR_GENERIC; + } + + strcpy(texture_name,tex_file); +#ifdef TARGET_DC + // We don't support 8-bit sources. + ASSERT(FALSE); +#else + strcpy(palette_name,pal_file); +#endif + + Type = D3DTEXTURE_TYPE_8; + + result = Reload(); + + if(FAILED(result)) + { + DebugText("LoadTexture8: unable to load texture\n"); + } + + // + // Finally let the display driver know about this texture page. + // + + the_display.AddLoadedTexture(this); + + return DD_OK; +} + +#endif //#ifndef TARGET_DC + + +HRESULT D3DTexture::ChangeTextureTGA(CBYTE *tga_file) { + + if (Type != D3DTEXTURE_TYPE_UNUSED) + { + // + // There must be one already loaded. + // + Destroy(); + strcpy(texture_name, tga_file); + Reload(); + + return DD_OK; + } + return DDERR_GENERIC; +} + +HRESULT D3DTexture::LoadTextureTGA(CBYTE *tga_file, ULONG id,BOOL bCanShrink) +{ + HRESULT result; + + if (Type != D3DTEXTURE_TYPE_UNUSED) + { + // + // Already loaded. + // + + return DD_OK; + } + + lp_Texture = NULL; +#ifndef TARGET_DC + lp_Palette = NULL; +#endif + lp_Surface = NULL; + + this->bCanShrink = bCanShrink; + + // Check parameters. + if(!tga_file) + { + // Invalid parameters. + return DDERR_GENERIC; + } + + strcpy(texture_name, tga_file); + ID = id; + + Type = D3DTEXTURE_TYPE_TGA; + + result = Reload(); + + if(FAILED(result)) + { + DebugText("LoadTextureTGA: unable to load texture\n"); + return ( result ); + } + + // + // Finally let the display driver know about this texture page. + // + + the_display.AddLoadedTexture(this); + + return DD_OK; +} + + +HRESULT D3DTexture::CreateUserPage(SLONG texture_size, BOOL i_want_an_alpha_channel) +{ + HRESULT result; + + ASSERT(Type == D3DTEXTURE_TYPE_UNUSED); + + lp_Texture = NULL; +#ifndef TARGET_DC + lp_Palette = NULL; +#endif + lp_Surface = NULL; + UserWantsAlpha = i_want_an_alpha_channel; + + // + // A user page. + // + + size = texture_size; + + // + // Reload it... or rather, re-create it, or even create it in the first place! + // + + Type = D3DTEXTURE_TYPE_USER; + + result = Reload(); + + if (FAILED(result)) + { + DebugText("Could not create user page.\n"); + } + + // + // Let the display driver know about this texture page. + // + + the_display.AddLoadedTexture(this); + + return DD_OK; +} + + + +//--------------------------------------------------------------- + + +// +// Given the bitmask for a colour in a pixel format, it calculates the mask and +// shift so that you can construct a pixel in pixel format given its RGB values. +// The formula is... +// +// PIXEL(r,g,b) = ((r >> mask) << shift) | ((g >> mask) << shift) | ((b >> mask) << shift); +// +// THIS ASSUMES that r,g,b are 8-bit values. +// + +void OS_calculate_mask_and_shift( + ULONG bitmask, + SLONG *mask, + SLONG *shift) +{ + SLONG i; + SLONG b; + SLONG num_bits = 0; + SLONG first_bit = -1; + + for (i = 0, b = 1; i < 32; i++, b <<= 1) + { + if (bitmask & b) + { + num_bits += 1; + + if (first_bit == -1) + { + // + // We have found the first bit. + // + + first_bit = i; + } + } + } + + ASSERT(first_bit != -1 && num_bits != 0); + + *mask = 8 - num_bits; + *shift = first_bit; + + if (*mask < 0) + { + // + // More than 8 bits per colour component? May + // as well support it! + // + + *shift -= *mask; + *mask = 0; + } +} + + +HRESULT D3DTexture::Reload_TGA(void) +{ + //SLONG i; + + D3DDeviceInfo *current_device; + + DDModeInfo *mi; + + //SLONG bpp; + + DDSURFACEDESC2 dd_sd; + + int iMipmapLevel; + + TRACE ("Tex<%s>\n", texture_name); + + +#ifdef TARGET_DC + + + +#if USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + + + + // Extract the directory and file name. +#define MAX_DIRECTORY_LENGTH 63 + char pcDirectory[MAX_DIRECTORY_LENGTH+1]; + char *pcFilename; + // Find the last backslash. + char *pcTemp = texture_name; + while ( *pcTemp != '\0' ) + { + if ( *pcTemp == '\\' ) + { + pcFilename = pcTemp + 1; + } + pcTemp++; + } + ASSERT ( pcFilename - texture_name < MAX_DIRECTORY_LENGTH ); + strncpy ( pcDirectory, texture_name, ( pcFilename - texture_name ) ); + pcDirectory[pcFilename - texture_name] = '\0'; + + + // Shouldn't start with a slash, but should end with one. + ASSERT ( pcDirectory[0] != '\\' ); + ASSERT ( pcDirectory[strlen(pcDirectory)-1] == '\\' ); + + + // Spot the special texture that _shouldn't_ be paged at the moment. + // These are thug jackets and civillian clothes. + bool bOKToPage = TRUE; + +#define DONT_PAGE_IF_ITS(dont_directory, dont_name) if ( ( 0 == strcmp ( pcDirectory, dont_directory ) ) && ( 0 == strcmp ( pcFilename, dont_name ) ) ) { bOKToPage = FALSE; } + + // Jacket 1 (brown). + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people\\", "tex021.tga" ); // 64+21 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people\\", "tex022.tga" ); // 64+22 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people\\", "tex024.tga" ); // 64+24 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people\\", "tex025.tga" ); // 64+25 + + // Jacket 2 (green) + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex002.tga" ); // 10*64+2 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex003.tga" ); // 10*64+3 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex004.tga" ); // 10*64+4 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex005.tga" ); // 10*64+5 + + // Jacket 3 (purple) + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex032.tga" ); // 10*64+32 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex033.tga" ); // 10*64+33 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex036.tga" ); // 10*64+36 + DONT_PAGE_IF_ITS ( "server\\textures\\shared\\people2\\", "tex037.tga" ); // 10*64+37 + +#undef DONT_PAGE_IF_ITS + + // Civillians (that's all that is in this directory). + if ( ( 0 == strcmp ( pcDirectory, "server\\textures\\shared\\people3\\" ) ) ) { bOKToPage = FALSE; } + + + if ( !bOKToPage ) + { + // Load as normal. + TRACE ( "Didn't page <%s>", texture_name ); + wPageNum = -1; + bPagePos = 0; + bPageType = D3DPAGE_NONE; + } + else + { + // Look for this texture's name in the texture page list. + for ( int i = 0; i < iNumD3DPages; i++ ) + { + if ( 0 == stricmp ( pcDirectory, pageD3D[i].pcDirectory ) ) + { + // Got a match. Look for the texture name. + char **ppList = pageD3D[i].ppcTextureList; + for ( int j = 0; j < (int)pageD3D[i].bNumTextures; j++ ) + { + if ( 0 == stricmp ( *ppList, pcFilename ) ) + { + // Found a match. + + // Make sure the page is loaded. + pageD3D[i].EnsureLoaded(); + + wPageNum = i; + bPagePos = j; + bPageType = pageD3D[i].bPageType; + + if ( pageD3D[i].pTex != NULL ) + { + lp_Texture = pageD3D[i].pTex->lp_Texture; + lp_Surface = pageD3D[i].pTex->lp_Surface; + if ( lp_Texture != NULL ) + { + lp_Texture->AddRef(); + } + else + { + ASSERT ( FALSE ); + } + if ( lp_Surface != NULL ) + { + lp_Surface->AddRef(); + } + else + { + ASSERT ( FALSE ); + } + ContainsAlpha = pageD3D[i].pTex->ContainsAlpha; + mask_red = pageD3D[i].pTex->mask_red ; + mask_green = pageD3D[i].pTex->mask_green ; + mask_blue = pageD3D[i].pTex->mask_blue ; + mask_alpha = pageD3D[i].pTex->mask_alpha ; + shift_red = pageD3D[i].pTex->shift_red ; + shift_green = pageD3D[i].pTex->shift_green ; + shift_blue = pageD3D[i].pTex->shift_blue ; + shift_alpha = pageD3D[i].pTex->shift_alpha ; + } + else + { + // Nads. Well, just continue for now. + goto found_and_continue; + ASSERT ( FALSE ); + } + return DD_OK; + } + ppList++; + } + } + } + // Didn't find it - load as normal. + wPageNum = -1; + bPagePos = 0; + bPageType = D3DPAGE_NONE; + +found_and_continue:; + } + +#endif + + + if ( bCanShrink ) + { + +// Mipmaps chew too much memory for now, and shrunk down they look ugly. +//#define MIPMAP_PLEASE_BOB +//#define MIPMAP_SHRINK_PLEASE_BOB 1 + + // See if the "mvq" file is there, and load it if it is, + // rather than calculating it, which takes forever. + char new_filename[100]; + strcpy ( new_filename, texture_name ); + // Change the ".tga" extension to a ".mvq" (Mipmapped VQ). + char *pch = new_filename; + while ( *pch != '\0' ) + { + if ( ( pch[0] == 't' ) && + ( pch[1] == 'g' ) && + ( pch[2] == 'a' ) ) + { + pch[0] = 'm'; + pch[1] = 'v'; + pch[2] = 'q'; + break; + } + pch++; + } + + + // This is bodge! + char *new_new_filename = new_filename; + if ( 0 == strnicmp ( new_filename, "c:\\fallen\\", strlen ( "c:\\fallen\\" ) ) ) + { + // Strip this off. + new_new_filename = new_filename + strlen ( "c:\\fallen\\" ); + } + + + MFFileHandle handle = FileOpen ( new_new_filename ); + if ( handle != FILE_OPEN_ERROR ) + { + // Yep - load it. + + // Header is: + // byte: version number - currently always 1 + // byte: size as a power of two, e.g. 5 = 32x32. + // byte: pixel format. 0 = 565, 1 = 4444. + // byte: padding - ignored + // Then comes 2k of codebook, then the mipmap levels, smallest level first. + // The smallest level is only a single byte and is padded with another byte before it. + + + // Bin old texture stuff (whatever that means). + Destroy(); + + + // Load it all at once. + int iFileSize = FileSize ( handle ); + ASSERT ( iFileSize > 0 ); + ASSERT ( iFileSize < 1000000 ); + + +#if 0 + char *pcFile = (char *)MemAlloc ( iFileSize ); + ASSERT ( pcFile != NULL ); + char *pcCurFilePos = pcFile; + + int iRead = FileRead ( handle, (void *)pcFile, iFileSize ); + ASSERT ( iRead == iFileSize ); +#else + + char *pcFile = (char *)FastLoadFileSomewhere ( handle, iFileSize ); + char *pcCurFilePos = pcFile; + +#endif + + FileClose ( handle ); + + + // OK, check the header. + + // Version. + ASSERT ( pcFile[0] == 1 ); + + // Log2 size. + size = 1 << pcFile[1]; +#ifdef MIPMAP_SHRINK_PLEASE_BOB + // Shrink it. + size >>= MIPMAP_SHRINK_PLEASE_BOB; +#endif + + // Format + // the mask and shift values are not actually used, but might as well fill them in. + switch ( pcFile[2] ) + { + case 0: + // 565. + ContainsAlpha = 0; + mask_red = 5; + mask_green = 6; + mask_blue = 5; + mask_alpha = 0; + shift_red = 11; + shift_green = 5; + shift_blue = 0; + shift_alpha = 0; + mi = the_display.GetDeviceInfo()->OpaqueTexFmt; + break; + case 1: + // 4444. + ContainsAlpha = 1; + mask_red = 4; + mask_green = 4; + mask_blue = 4; + mask_alpha = 4; + shift_red = 8; + shift_green = 4; + shift_blue = 0; + shift_alpha = 12; + mi = the_display.GetDeviceInfo()->AlphaTexFmt; + break; + default: + // Unknown + ASSERT ( FALSE ); + break; + } + + + // pcFile[3] is padding. + + pcCurFilePos += 4; + + + + + // OK, now create a VQ'd mipmapped surface and fill it. + + int iNumMipmapLevels = 0; + DWORD dwSize = size; + // Only mipmap down to 2x2 for VQs. + while ( dwSize > 1 ) + { + dwSize >>= 1; + iNumMipmapLevels++; + } +#ifdef MIPMAP_SHRINK_PLEASE_BOB + // There are actually more than this in the file. + iNumMipmapLevels += MIPMAP_SHRINK_PLEASE_BOB; +#endif + + + + + // The VQ format is something I've basically guessed at! + // But it seems to work. + DDSURFACEDESC2 dd_sd2; + + dd_sd2 = mi->ddSurfDesc; + + dd_sd2.dwSize = sizeof(dd_sd2); + #ifdef MIPMAP_PLEASE_BOB + dd_sd2.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT | + DDSD_MIPMAPCOUNT; + #else + dd_sd2.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; + #endif + dd_sd2.dwWidth = size; + dd_sd2.dwHeight = size; + #ifdef MIPMAP_PLEASE_BOB + dd_sd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE| DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; + #else + dd_sd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + #endif + dd_sd2.ddsCaps.dwCaps2 = 0; + dd_sd2.ddsCaps.dwCaps3 = 0; + dd_sd2.ddsCaps.dwCaps4 = 0; + dd_sd2.dwTextureStage = 0; + #ifdef MIPMAP_PLEASE_BOB + dd_sd2.dwMipMapCount = iNumMipmapLevels; +#ifdef MIPMAP_SHRINK_PLEASE_BOB + dd_sd2.dwMipMapCount -= MIPMAP_SHRINK_PLEASE_BOB; +#endif + + #else + dd_sd2.dwMipMapCount = 0; + #endif + + dd_sd2.ddpfPixelFormat.dwFlags |= DDPF_COMPRESSED; + + VERIFY(SUCCEEDED(the_display.lp_DD4->CreateSurface(&dd_sd2, &lp_Surface, NULL))); + VERIFY(SUCCEEDED(lp_Surface->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lp_Texture))); + + + + // Now lock the surface. + dd_sd2.dwSize = sizeof(dd_sd); + dd_sd2.dwFlags = DDSD_LPSURFACE | DDSD_PITCH; + HRESULT res = lp_Surface->Lock(NULL, &dd_sd2, 0, NULL); + ASSERT(SUCCEEDED(res)); + + + // Fill the codebook. + WORD *pwDst = (WORD *)dd_sd2.lpSurface; + for ( int i = 0; i < 256; i++ ) + { + pwDst[0] = *((WORD*)pcCurFilePos ); + pcCurFilePos += 2; + pwDst[1] = *((WORD*)pcCurFilePos ); + pcCurFilePos += 2; + pwDst[2] = *((WORD*)pcCurFilePos ); + pcCurFilePos += 2; + pwDst[3] = *((WORD*)pcCurFilePos ); + pcCurFilePos += 2; + pwDst += 4; + } + + + // OK, the mipmaps are stored in the top level surface (no GetAttachedSurface or any of that + // rubbish), and stored smallest-first. + + // Now fill in the mipmaps - they use the same codebook. + UCHAR *pPtr = (UCHAR *) dd_sd2.lpSurface + 2048; +#ifdef MIPMAP_PLEASE_BOB + // Special-case the first level. It's only a single byte, but writes to + // vidmem must be WORD-aligned. + *(WORD *)pPtr = (WORD)*pcCurFilePos; + pPtr += 2; +#endif + pcCurFilePos += 2; + + + // Now do the rest. + dwSize = 4; + for ( iMipmapLevel = iNumMipmapLevels - 2; iMipmapLevel >= 0; iMipmapLevel-- ) + { +#ifndef MIPMAP_PLEASE_BOB + if ( iMipmapLevel != 0 ) + { + // No mipmapping - skip all but the last level. + pcCurFilePos += ( (dwSize * dwSize) / 4 ); + } + else +#endif +#ifdef MIPMAP_SHRINK_PLEASE_BOB + if ( iMipmapLevel < MIPMAP_SHRINK_PLEASE_BOB ) + { + // Skip the larger levels. + pcCurFilePos += ( (dwSize * dwSize) / 4 ); + } + else +#endif + { + WORD *pwTemp = (WORD *)pcCurFilePos; + for ( int i = (dwSize * dwSize) / 4; i > 0; i -= 2 ) + { + *(WORD*)pPtr = *pwTemp; + pwTemp++; + pPtr+=2; + } + + pcCurFilePos = (char *)pwTemp; + } + dwSize <<= 1; + } + + ASSERT ( ( pcCurFilePos - pcFile ) == iFileSize ); +#if 0 + MemFree ( pcFile ); +#endif + + VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + + + + static int iTexLoadCount = 0; + TRACE(":"); + iTexLoadCount++; + if ( ( iTexLoadCount & 0x3f ) == 0 ) + { + TRACE("\n"); + } + + return DD_OK; + + } + + } + +#endif + + TGA_Info ti; + TGA_Pixel *tga; + + //HRESULT result; + + // + // Allocate memory for the texture. + // + + tga = (TGA_Pixel *) MemAlloc (256 * 256 * sizeof(TGA_Pixel)); + + if (tga == NULL) + { + TRACE("Not enough MAIN memory to load tga %s\n", texture_name); + + return DDERR_GENERIC; + } + + // + // Load the texture. + // + ti = TGA_load( + texture_name, + 256, + 256, + tga, + ID, + bCanShrink); + + if (!ti.valid) + { + // + // Invalid tga. + // + + TRACE("TGA %s is invalid\n", texture_name); + //ASSERT ( FALSE ); + MemFree(tga); + return DDERR_GENERIC; + } + + if (ti.width != ti.height) + { + TRACE("TGA %s is not square\n", texture_name); + MemFree(tga); + return DDERR_GENERIC; + } + +#if 0 + if (ti.width != 32 && + ti.width != 64 && + ti.width != 128 && + ti.width != 256) +#else + // Tsk tsk - how do we test for powers of two? :-) + if ( ( ti.width & ( ti.width - 1 ) ) != 0 ) +#endif + { + TRACE("TGA %s is not a valid size", texture_name); + MemFree(tga); + return DDERR_GENERIC; + } + + #if WE_WANT_ALL_TEXTURES_TO_BE_256_x_256 + + if (ti.width != 256) + { + TRACE("Texture \"%s\" (%d x %d) is an invalid size", texture_name, ti.width, ti.height); + MemFree(tga); + return DDERR_GENERIC; + } + + #endif + + if (the_manager.CurrDriver && (the_manager.CurrDriver->DriverFlags & DD_DRIVER_LOW_MEMORY)) + { + if (strstr(texture_name, "multifont") || + strstr(texture_name, "PCdisplay") || + strstr(texture_name, "olyfont")) + { + // + // Don't halve these textures... + // + } + else + { + // + // Shall we halve the size of this texture? YEAH! + // + +#ifndef TARGET_DC + extern void SW_halfsize(TGA_Pixel *tga, SLONG size); + + SW_halfsize(tga, ti.width); + + ti.width >>= 1; + ti.height >>= 1; + + tga = (TGA_Pixel *) realloc(tga, ti.width * ti.height * sizeof(TGA_Pixel)); +#endif + } + } + + size = ti.width; + + // + // Get the current device. + // + + current_device = the_display.GetDeviceInfo(); + + if (!current_device) + { + TRACE("No device!\n"); + + return DDERR_GENERIC; + } + +#ifdef TARGET_DC + static int iTexLoadCount = 0; + TRACE("."); + iTexLoadCount++; + if ( ( iTexLoadCount & 0x3f ) == 0 ) + { + TRACE("\n"); + } +#else + TRACE("texture = %s\n", this->texture_name); +#endif + + // + // Does this texture page contain alpha? + // + + ContainsAlpha = ti.contains_alpha; + + // + // Find the best texture format. + // + + if (ContainsAlpha) + { + mi = current_device->AlphaTexFmt; + } + else + { + mi = current_device->OpaqueTexFmt; + } + + // + // Use the best texture format. + // + + SLONG dwMaskR, dwMaskG, dwMaskB, dwMaskA; + SLONG dwShiftR, dwShiftG, dwShiftB, dwShiftA; + + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRBitMask, &dwMaskR, &dwShiftR ); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwGBitMask, &dwMaskG, &dwShiftG ); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwBBitMask, &dwMaskB, &dwShiftB ); + + if (ContainsAlpha) + { + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRGBAlphaBitMask, &dwMaskA, &dwShiftA); + } + mask_red = (UBYTE)dwMaskR; + mask_green = (UBYTE)dwMaskG; + mask_blue = (UBYTE)dwMaskB; + mask_alpha = (UBYTE)dwMaskA; + shift_red = (UBYTE)dwShiftR; + shift_green = (UBYTE)dwShiftG; + shift_blue = (UBYTE)dwShiftB; + shift_alpha = (UBYTE)dwShiftA; + +#ifndef TARGET_DC +#ifdef SAVE_MY_VQ_TEXTURES_PLEASE_BOB + // Saving textures, so force the format to be the DC's one! + if (ContainsAlpha) + { + mask_red = 4; + mask_green = 4; + mask_blue = 4; + mask_alpha = 4; + shift_red = 8; + shift_green = 4; + shift_blue = 0; + shift_alpha = 12; + } + else + { + mask_red = 3; + mask_green = 2; + mask_blue = 3; + mask_alpha = 8; + shift_red = 11; + shift_green = 5; + shift_blue = 0; + shift_alpha = 0; + } +#endif +#endif + + + + // + // Get rid of the old texture stuff. + // + + Destroy(); + + // Guy. Do all the font mapping stuff here. + if(IsFont()) + { + CreateFonts(&ti,tga); + + // Change the outline colour to black. + SLONG size = (ti.width*ti.height); + + while(size--) + { + if ( + (tga+size)->red==0xff && + (tga+size)->green==0 && + (tga+size)->blue==0xff + ) + { + (tga+size)->red = 0; + (tga+size)->green = 0; + (tga+size)->blue = 0; + } + } + } + + // replace red-only pixels with black + // + // WITHOUT AFFECTING BLACK'S ALPHA-CHANNELS. ATF. + if (IsFont2()) + { + SLONG size = (ti.width * ti.height); + + while (size--) + { + if ((tga[size].green == 0) && (tga[size].blue == 0) && (tga[size].red > 128 ) ) + { + tga[size].red = 0; + tga[size].alpha = 0; + } + } + } + + int interlace; + int xoff,yoff; + +#ifdef TARGET_DC + bool bVQPlease = FALSE; +#ifndef DONT_VQ_MY_TEXTURES_PLEASE_BOB + if ( bCanShrink && ( ti.width >= VQ_MINIMUM_SIZE ) && ( ti.height >= VQ_MINIMUM_SIZE ) ) + { + bVQPlease = TRUE; + dd_sd = mi->ddSurfDesc; + dd_sd.lpSurface = MemAlloc ( ti.width * ti.height * 2 ); + interlace = ti.width; + xoff = yoff = 0; +#ifdef TEX_EMBED +#if !USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + TexSource = this; + TexOffset = 0; +#endif +#endif + } + else +#endif +#endif + { +#ifdef TEX_EMBED +#if !USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + if ((ti.width == 64) && (ti.height == 64) && !ContainsAlpha) + { + if (EmbedSurface) + { + TexOffset = 128 + EmbedOffset++; + TexSource = EmbedSource; + lp_Surface = EmbedSurface; + lp_Texture = EmbedTexture; + lp_Surface->AddRef(); + lp_Texture->AddRef(); + + if (EmbedOffset == 16) + { + EmbedSource = NULL; + EmbedSurface = NULL; + EmbedTexture = NULL; + EmbedOffset = 0; + } + + xoff = (TexOffset & 3) * 64; + yoff = ((TexOffset >> 2) & 3) * 64; + } + else + { + dd_sd = mi->ddSurfDesc; + + dd_sd.dwSize = sizeof(dd_sd); + dd_sd.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; + dd_sd.dwWidth = 256; + dd_sd.dwHeight = 256; + dd_sd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; +#ifdef TARGET_DC + dd_sd.ddsCaps.dwCaps2 = 0; +#else + dd_sd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; +#endif + dd_sd.dwTextureStage = 0; + + VERIFY(SUCCEEDED(the_display.lp_DD4->CreateSurface(&dd_sd, &lp_Surface, NULL))); + VERIFY(SUCCEEDED(lp_Surface->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lp_Texture))); + + TexOffset = 128; + TexSource = this; + + EmbedSource = this; + EmbedSurface = lp_Surface; + EmbedTexture = lp_Texture; + EmbedOffset = 1; + + xoff = yoff = 0; + } + interlace = 256; + } + else +#endif +#endif + { + dd_sd = mi->ddSurfDesc; + + dd_sd.dwSize = sizeof(dd_sd); + dd_sd.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; + dd_sd.dwWidth = ti.width; + dd_sd.dwHeight = ti.height; + dd_sd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; +#ifdef TARGET_DC + dd_sd.ddsCaps.dwCaps2 = 0; +#else + dd_sd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; +#endif + dd_sd.dwTextureStage = 0; + + VERIFY(SUCCEEDED(the_display.lp_DD4->CreateSurface(&dd_sd, &lp_Surface, NULL))); + VERIFY(SUCCEEDED(lp_Surface->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lp_Texture))); + + interlace = ti.width; + xoff = yoff = 0; + +#ifdef TEX_EMBED +#if !USE_FANCY_TEXTURE_PAGES_PLEASE_BOB + TexSource = this; + TexOffset = 0; +#endif +#endif + } + } + + // + // Lock the surface. + // + + +#ifdef TARGET_DC + if ( !bVQPlease ) +#endif + { + dd_sd.dwSize = sizeof(dd_sd); + HRESULT res = lp_Surface->Lock(NULL, &dd_sd, 0, NULL); + ASSERT(SUCCEEDED(res)); + } + + // + // Copy the texture in + // + // ASSUMES 16 or 32-bits PER PIXEL! + // + + { + UWORD *wscreenw = (UWORD *) dd_sd.lpSurface; + ULONG *wscreenl = (ULONG *) dd_sd.lpSurface; + + SLONG i; + SLONG j; + ULONG pixel; + + SLONG red; + SLONG green; + SLONG blue; + + SLONG bright; + + for (j = 0; j < ti.height; j++) + for (i = 0; i < ti.width; i++) + { + pixel = 0; + + red = tga[i + j * ti.width].red; + green = tga[i + j * ti.width].green; + blue = tga[i + j * ti.width].blue; + + /* + + // + // Add some gamma! + // + + red = 256 - ((256 - red) * (256 - red) >> 8); + green = 256 - ((256 - green) * (256 - green) >> 8); + blue = 256 - ((256 - blue) * (256 - blue) >> 8); + + if (red > 255) {red = 255;} + if (green > 255) {green = 255;} + if (blue > 255) {blue = 255;} + + */ + + if (GreyScale) + { + bright = (red + green + blue) * 85 >> 8; + + red = bright; + green = bright; + blue = bright; + } + + pixel |= (red >> mask_red ) << shift_red; + pixel |= (green >> mask_green) << shift_green; + pixel |= (blue >> mask_blue ) << shift_blue; + +#define ISPIXEL(x,y) (tga[(x) + (y) * ti.width].red | tga[(x) + (y) * ti.width].green | tga[(x) + (y) * ti.width].blue) + + if (ContainsAlpha) + { + pixel |= (tga[i + j * ti.width].alpha >> mask_alpha) << shift_alpha; + + if (!pixel && !ISPIXEL(i,j)) + { + // this is a bit bad ... we want to copy the nearest texel across + int i2,j2; + + if ((i - 1 >= 0) && ISPIXEL(i - 1, j)) + { + i2 = i - 1; + j2 = j; + } + else if ((i + 1 < ti.width) && ISPIXEL(i + 1, j)) + { + i2 = i + 1; + j2 = j; + } + else if ((j - 1 >= 0) && ISPIXEL(i, j - 1)) + { + i2 = i; + j2 = j - 1; + } + else if ((j + 1 < ti.height) && ISPIXEL(i, j + 1)) + { + i2 = i; + j2 = j + 1; + } + else if ((i - 1 >= 0) && (j - 1 >= 0) && ISPIXEL(i - 1, j - 1)) + { + i2 = i - 1; + j2 = j - 1; + } + else if ((i - 1 >= 0) && (j + 1 < ti.height) && ISPIXEL(i - 1, j + 1)) + { + i2 = i - 1; + j2 = j + 1; + } + else if ((i + 1 < ti.width) && (j - 1 >= 0) && ISPIXEL(i + 1, j - 1)) + { + i2 = i + 1; + j2 = j - 1; + } + else if ((i + 1 < ti.width) && (j + 1 < ti.height) && ISPIXEL(i + 1, j + 1)) + { + i2 = i + 1; + j2 = j + 1; + } + else + { + i2 = i; + j2 = j; + } + + red = tga[i2 + j2 * ti.width].red; + green = tga[i2 + j2 * ti.width].green; + blue = tga[i2 + j2 * ti.width].blue; + + pixel |= (red >> mask_red ) << shift_red; + pixel |= (green >> mask_green) << shift_green; + pixel |= (blue >> mask_blue ) << shift_blue; + } + } + + if (dd_sd.ddpfPixelFormat.dwRGBBitCount == 32) + { + wscreenl[i + xoff + (j + yoff) * interlace] = pixel; + } + else + { + wscreenw[i + xoff + (j + yoff) * interlace] = (WORD)pixel; + } + } + } + + // + // Unlock the surface. + // + + +#ifndef TARGET_DC + + + +#ifdef SAVE_MY_VQ_TEXTURES_PLEASE_BOB +extern UBYTE save_out_the_vqs; + + //if (save_out_the_vqs) + { + + // VQ and mipmap this texture and save the data format out. + + // Try to create the file first for an early-out. + char new_filename[100]; + strcpy ( new_filename, texture_name ); + // Change the ".tga" extension to a ".mvq" (Mipmapped VQ). + char *pch = new_filename; + while ( *pch != '\0' ) + { + if ( ( pch[0] == 't' ) && + ( pch[1] == 'g' ) && + ( pch[2] == 'a' ) ) + { + pch[0] = 'm'; + pch[1] = 'v'; + pch[2] = 'q'; + break; + } + pch++; + } + + MFFileHandle handle = FileCreate ( new_filename, FALSE ); + if ( handle == FILE_CREATION_ERROR ) + { + // Probably already exists - don't update it. + goto dont_save_mvq; + } + + + { + + // OK, now create a VQ'd mipmapped surface and fill it. + int iNumMipmapLevels = 0; + DWORD dwSize = ti.height; + ASSERT ( ti.height == ti.width ); + ASSERT ( ti.height < 512 ); + // Only mipmap down to 2x2 for VQs. + while ( dwSize > 1 ) + { + dwSize >>= 1; + iNumMipmapLevels++; + } + + + + // USe the DC's pixel format, not whatever the PC uses. + DDPIXELFORMAT ddpf_DC; + if (ContainsAlpha) + { + ddpf_DC.dwRBitMask = 0x0f00; + ddpf_DC.dwGBitMask = 0x00f0; + ddpf_DC.dwBBitMask = 0x000f; + ddpf_DC.dwRGBAlphaBitMask = 0xf000; + } + else + { + ddpf_DC.dwRBitMask = 0xf800; + ddpf_DC.dwGBitMask = 0x07e0; + ddpf_DC.dwBBitMask = 0x001f; + ddpf_DC.dwRGBAlphaBitMask = 0x0000; + } + + + + UWORD *(pwdst[10]); + UCHAR *(pcTexels[10]); + // This should be big enough... + UCHAR *pcRealTexelBlock = (UCHAR *)MemAlloc ( ( ti.height * ti.height / 4 ) * 2 + 10*4 ); + ASSERT ( pcRealTexelBlock != NULL ); + //UCHAR pcRealTexelBlock[(512*512/4) * 2 + 10*4]; + // DWORD align it. + UCHAR *pcTexelBlock = (UCHAR *)( ( (DWORD)pcRealTexelBlock + 3 ) & ~3 ); + + dwSize = ti.height; + //UCHAR pcpwdstBlock[512*512*2*2]; + UCHAR *pcpwdstBlock = (UCHAR *)MemAlloc ( 512*512*2*2 ); + ASSERT ( pcpwdstBlock != NULL ); + UCHAR *pcTemp = pcpwdstBlock; + for ( int i = 0; i < iNumMipmapLevels; i++ ) + { + //pwdst[i] = (UWORD *)MemAlloc ( 2 * dwSize * dwSize ); + pwdst[i] = (UWORD *)pcTemp; + pcTemp += 2 * dwSize * dwSize; + ASSERT ( pwdst[i] != NULL ); + pcTexels[i] = pcTexelBlock; + pcTexelBlock += dwSize * dwSize / 4; + pcTexelBlock = (UCHAR *)( ( (DWORD)pcTexelBlock + 3 ) & ~3 ); + if ( i > 0 ) + { + // Create the mipmap by a cheesy box filter of the previous level. + // FIXME - do a better filter. + UWORD *pwsrc1 = pwdst[i-1]; + UWORD *pwsrc2 = pwdst[i-1] + dwSize * 2; + UWORD *pwdst1 = pwdst[i]; + for ( int iY = 0; iY < (signed)dwSize; iY++ ) + { + for ( int iX = 0; iX < (signed)dwSize; iX++ ) + { + UWORD wR, wG, wB, wA; + UWORD wSrc1 = *pwsrc1++; + UWORD wSrc2 = *pwsrc1++; + UWORD wSrc3 = *pwsrc2++; + UWORD wSrc4 = *pwsrc2++; + // Assume the blue channel is the bottom one. + ASSERT ( ( ddpf_DC.dwRGBAlphaBitMask & 3 ) == 0 ); + ASSERT ( ( ddpf_DC.dwRBitMask & 3 ) == 0 ); + ASSERT ( ( ddpf_DC.dwGBitMask & 3 ) == 0 ); + ASSERT ( ( ddpf_DC.dwBBitMask & 0xc000 ) == 0 ); + wR = (wSrc1 & (UWORD)ddpf_DC.dwRBitMask) >> 2; + wR += (wSrc2 & (UWORD)ddpf_DC.dwRBitMask) >> 2; + wR += (wSrc3 & (UWORD)ddpf_DC.dwRBitMask) >> 2; + wR += (wSrc4 & (UWORD)ddpf_DC.dwRBitMask) >> 2; + // Add half an LSB. + wR += ( (UWORD)ddpf_DC.dwRBitMask >> 1) & ~(UWORD)ddpf_DC.dwRBitMask; + wR &= ddpf_DC.dwRBitMask; + wG = (wSrc1 & (UWORD)ddpf_DC.dwGBitMask) >> 2; + wG += (wSrc2 & (UWORD)ddpf_DC.dwGBitMask) >> 2; + wG += (wSrc3 & (UWORD)ddpf_DC.dwGBitMask) >> 2; + wG += (wSrc4 & (UWORD)ddpf_DC.dwGBitMask) >> 2; + wG += ( (UWORD)ddpf_DC.dwGBitMask >> 1) & ~(UWORD)ddpf_DC.dwGBitMask; + wG &= ddpf_DC.dwGBitMask; + wB = (wSrc1 & (UWORD)ddpf_DC.dwBBitMask); + wB += (wSrc2 & (UWORD)ddpf_DC.dwBBitMask); + wB += (wSrc3 & (UWORD)ddpf_DC.dwBBitMask); + wB += (wSrc4 & (UWORD)ddpf_DC.dwBBitMask); + wR += ( (UWORD)ddpf_DC.dwBBitMask << 1) & ~( (UWORD)ddpf_DC.dwBBitMask << 2 ); + wB >>= 2; + wB &= ddpf_DC.dwBBitMask; + wA = (wSrc1 & (UWORD)ddpf_DC.dwRGBAlphaBitMask) >> 2; + wA += (wSrc2 & (UWORD)ddpf_DC.dwRGBAlphaBitMask) >> 2; + wA += (wSrc3 & (UWORD)ddpf_DC.dwRGBAlphaBitMask) >> 2; + wA += (wSrc4 & (UWORD)ddpf_DC.dwRGBAlphaBitMask) >> 2; + wA += ( (UWORD)ddpf_DC.dwRGBAlphaBitMask >> 1) & ~(UWORD)ddpf_DC.dwRGBAlphaBitMask; + wA &= (UWORD)ddpf_DC.dwRGBAlphaBitMask; + *pwdst1++ = wR | wG | wB | wA; + } + // Skip a source line. + pwsrc1 += dwSize * 2; + pwsrc2 += dwSize * 2; + } + } + else + { + // Copy from the source. + memcpy ( pwdst[0], dd_sd.lpSurface, 2 * dwSize * dwSize ); + } + dwSize >>= 1; + } + ASSERT ( dwSize == 1 ); + + + dwSize = ti.height; + //UWORD pwTemp[512*512]; + UWORD *pwTemp = (UWORD *)MemAlloc ( 512 * 512 * 2); + ASSERT ( pwTemp != NULL ); + for ( i = 0; i < iNumMipmapLevels; i++ ) + { + // Swizzle and pack into 2x2 blocks. + UWORD *pwsrc = (UWORD *) pwdst[i]; + UWORD *pwdst1 = (UWORD *) pwTemp; + for ( int iY = 0; iY < (signed)dwSize; iY++ ) + { + for ( int iX = 0; iX < (signed)dwSize; iX++ ) + { + int iOffset = 0; + iOffset |= ( iY << 0 ) & 0x00001; + iOffset |= ( iX << 1 ) & 0x00002; + iOffset |= ( iY << 1 ) & 0x00004; + iOffset |= ( iX << 2 ) & 0x00008; + iOffset |= ( iY << 2 ) & 0x00010; + iOffset |= ( iX << 3 ) & 0x00020; + iOffset |= ( iY << 3 ) & 0x00040; + iOffset |= ( iX << 4 ) & 0x00080; + iOffset |= ( iY << 4 ) & 0x00100; + iOffset |= ( iX << 5 ) & 0x00200; + iOffset |= ( iY << 5 ) & 0x00400; + iOffset |= ( iX << 6 ) & 0x00800; + iOffset |= ( iY << 6 ) & 0x01000; + iOffset |= ( iX << 7 ) & 0x02000; + iOffset |= ( iY << 7 ) & 0x04000; + iOffset |= ( iX << 8 ) & 0x08000; + iOffset |= ( iY << 8 ) & 0x10000; + iOffset |= ( iX << 9 ) & 0x20000; + pwdst1[iOffset] = *pwsrc++; + } + } + // And copy it back in. + memcpy ( pwdst[i], pwTemp, 2 * dwSize * dwSize ); + dwSize >>= 1; + } + MemFree ( pwTemp ); + + //memset ( &(pwdst[ti.height * ti.width / 2]), 0, ti.width * ti.height ); + + + ULONG *pdwCodeBook1 = (ULONG *)MemAlloc ( 256 * 4 ); + ASSERT ( pdwCodeBook1 != NULL ); + ULONG *pdwCodeBook2 = (ULONG *)MemAlloc ( 256 * 4 ); + ASSERT ( pdwCodeBook2 != NULL ); + //ULONG pdwCodeBook1[256]; + //ULONG pdwCodeBook2[256]; + int iNumEntries = 0; + + + + // Let's do this another way. Scan multiple times, with smaller and smaller tolerance levels + // until we run out of codebook space. + for ( int iPrecision = 0; iPrecision < 10; iPrecision++ ) + { + ULONG dwMask1, dwMask2; + #define BINARY_DAMMIT(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)((a<<15)|(b<<14)|(c<<13)|(d<<12)|(e<<11)|(f<<10)|(g<<9)|(h<<8)|(i<<7)|(j<<6)|(k<<5)|(l<<4)|(m<<3)|(n<<2)|(o<<1)|(p<<0)) + if ( ContainsAlpha ) + { + // RRRRGGGGBBBBAAAA + switch ( iPrecision ) + { + case 0: dwMask1 = BINARY_DAMMIT(1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0); break; + case 1: dwMask1 = BINARY_DAMMIT(1,0,0,0,1,1,0,0,1,0,0,0,1,0,0,0); break; + case 2: dwMask1 = BINARY_DAMMIT(1,1,0,0,1,1,0,0,1,0,0,0,1,0,0,0); break; + case 3: dwMask1 = BINARY_DAMMIT(1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0); break; + case 4: dwMask1 = BINARY_DAMMIT(1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,0); break; + case 5: dwMask1 = BINARY_DAMMIT(1,1,1,0,1,1,1,0,1,1,0,0,1,1,0,0); break; + case 6: dwMask1 = BINARY_DAMMIT(1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0); break; + case 7: dwMask1 = BINARY_DAMMIT(1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0); break; + case 8: dwMask1 = BINARY_DAMMIT(1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0); break; + case 9: dwMask1 = BINARY_DAMMIT(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); break; + } + } + else + { + // RRRRRGGGGGGBBBBB + switch ( iPrecision ) + { + case 0: dwMask1 = BINARY_DAMMIT(1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0); break; + case 1: dwMask1 = BINARY_DAMMIT(1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0); break; + case 2: dwMask1 = BINARY_DAMMIT(1,1,0,0,0,1,1,0,0,0,0,1,1,0,0,0); break; + case 3: dwMask1 = BINARY_DAMMIT(1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0); break; + case 4: dwMask1 = BINARY_DAMMIT(1,1,1,0,0,1,1,1,0,0,0,1,1,1,0,0); break; + case 5: dwMask1 = BINARY_DAMMIT(1,1,1,0,0,1,1,1,1,0,0,1,1,1,0,0); break; + case 6: dwMask1 = BINARY_DAMMIT(1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0); break; + case 7: dwMask1 = BINARY_DAMMIT(1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0); break; + case 8: dwMask1 = BINARY_DAMMIT(1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0); break; + case 9: dwMask1 = BINARY_DAMMIT(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); break; + } + } + // Replicate this texel mask into the other four. + dwMask1 |= dwMask1 << 16; + dwMask2 = dwMask1; + #undef BINARY_DAMMIT + + + // Now scan the texture, making any codebook entries that don't exist. + // FIXME - at the moment, the mipmap levels are not scanned - maybe I should. + ULONG *pdwsrc = (ULONG *)pwdst[0]; + int iChunk; + for ( iChunk = 0; iChunk < (ti.width * ti.height) / 4; iChunk++ ) + { + ULONG dwSrc1 = pdwsrc[iChunk*2]; + ULONG dwSrc2 = pdwsrc[iChunk*2+1]; + ULONG dwSrc1Mask = dwSrc1 & dwMask1; + ULONG dwSrc2Mask = dwSrc2 & dwMask2; + // See if this chunk or something close is already in the codebook. + for ( int j = 0; j < iNumEntries; j++ ) + { + if ( ( ( pdwCodeBook1[j] & dwMask1 ) == dwSrc1Mask ) && ( ( pdwCodeBook2[j] & dwMask2 ) == dwSrc2Mask ) ) + { + // Joy. + break; + } + } + if ( j == iNumEntries ) + { + // Didn't find a match. + if ( iNumEntries < 256 ) + { + // Cool - just grow the table. + pdwCodeBook1[iNumEntries] = dwSrc1; + pdwCodeBook2[iNumEntries] = dwSrc2; + iNumEntries++; + } + else + { + // No more entries - exit. + goto no_more_entries_PC; + } + } + } + + } + no_more_entries_PC: + + // OK, filled the codebook, so rescan and find the closest matches for each texel, + // this time using a decent geometric error, not masks! + + // Actually, do a loop of (a) find the closest entries, then (b) make the entries the average of + // the things that use them. + // On the last time round, all the mipmap levels do (a), and (b) is not done. + + for ( int iNumTimesRoundTheLoop = 2; iNumTimesRoundTheLoop >= 0; iNumTimesRoundTheLoop-- ) + { + // Refind the closest match for each chunk. + // FIXME - this only does the top mipmap level. + dwSize = ti.height; + int iLevelsThisTime; + if ( iNumTimesRoundTheLoop == 0 ) + { + // Last time round the loop, do all mipmap levels. + iLevelsThisTime = iNumMipmapLevels; + } + else + { + // Just do the top one. + iLevelsThisTime = 1; + } + for ( iMipmapLevel = 0; iMipmapLevel < iLevelsThisTime; iMipmapLevel++ ) + { + ULONG *pdwsrc = (ULONG *)pwdst[iMipmapLevel]; + UCHAR *pcdst = pcTexels[iMipmapLevel]; + for ( int iChunk = 0; iChunk < (signed)(dwSize * dwSize) / 4; iChunk++ ) + { + ULONG dwSrc1 = pdwsrc[iChunk*2]; + ULONG dwSrc2 = pdwsrc[iChunk*2+1]; + + int iClosest = -1; + int iClosestVal = 100000000; + if ( ContainsAlpha ) + { + for ( i = 0; i < iNumEntries; i++ ) + { + if ( ( pdwCodeBook1[i] == dwSrc1 ) && ( pdwCodeBook2[i] == dwSrc2 ) ) + { + // Perfect match. + iClosest = i; + break; + } + + // RRRR GGGG BBBB AAAA + int iVal, iVal1, iVal2, iVal3, iVal4; + iVal1 = ( ( pdwCodeBook1[i] >> 24 ) & 0xf0 ) - ( ( dwSrc1 >> 24 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook1[i] >> 20 ) & 0xf0 ) - ( ( dwSrc1 >> 20 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook1[i] >> 16 ) & 0xf0 ) - ( ( dwSrc1 >> 16 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook1[i] >> 12 ) & 0xf0 ) - ( ( dwSrc1 >> 12 ) & 0xf0 ); + iVal = ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + iVal1 = ( ( pdwCodeBook1[i] >> 8 ) & 0xf0 ) - ( ( dwSrc1 >> 8 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook1[i] >> 4 ) & 0xf0 ) - ( ( dwSrc1 >> 4 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook1[i] >> 0 ) & 0xf0 ) - ( ( dwSrc1 >> 0 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook1[i] << 4 ) & 0xf0 ) - ( ( dwSrc1 << 4 ) & 0xf0 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + iVal1 = ( ( pdwCodeBook2[i] >> 24 ) & 0xf0 ) - ( ( dwSrc2 >> 24 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook2[i] >> 20 ) & 0xf0 ) - ( ( dwSrc2 >> 20 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook2[i] >> 16 ) & 0xf0 ) - ( ( dwSrc2 >> 16 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook2[i] >> 12 ) & 0xf0 ) - ( ( dwSrc2 >> 12 ) & 0xf0 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + iVal1 = ( ( pdwCodeBook2[i] >> 8 ) & 0xf0 ) - ( ( dwSrc2 >> 8 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook2[i] >> 4 ) & 0xf0 ) - ( ( dwSrc2 >> 4 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook2[i] >> 0 ) & 0xf0 ) - ( ( dwSrc2 >> 0 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook2[i] << 4 ) & 0xf0 ) - ( ( dwSrc2 << 4 ) & 0xf0 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + if ( iVal < iClosestVal ) + { + iClosestVal = iVal; + iClosest = i; + } + } + ASSERT ( iClosest != -1 ); + *pcdst++ = (UBYTE)iClosest; + } + else + { + for ( i = 0; i < iNumEntries; i++ ) + { + if ( ( pdwCodeBook1[i] == dwSrc1 ) && ( pdwCodeBook2[i] == dwSrc2 ) ) + { + // Perfect match. + iClosest = i; + break; + } + + // RRRR RGGG GGGB BBBB + int iVal, iVal1, iVal2, iVal3; + iVal1 = ( ( pdwCodeBook1[i] >> 24 ) & 0xf8 ) - ( ( dwSrc1 >> 24 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook1[i] >> 19 ) & 0xfc ) - ( ( dwSrc1 >> 19 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook1[i] >> 13 ) & 0xf8 ) - ( ( dwSrc1 >> 13 ) & 0xf8 ); + iVal = ( ( iVal1 * iVal1 ) << 2 ) + ( iVal2 * iVal2 ) + ( ( iVal3 * iVal3 ) << 2 ); + iVal1 = ( ( pdwCodeBook1[i] >> 8 ) & 0xf8 ) - ( ( dwSrc1 >> 8 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook1[i] >> 3 ) & 0xfc ) - ( ( dwSrc1 >> 3 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook1[i] << 3 ) & 0xf8 ) - ( ( dwSrc1 << 3 ) & 0xf8 ); + iVal += ( ( iVal1 * iVal1 ) << 2 ) + ( iVal2 * iVal2 ) + ( ( iVal3 * iVal3 ) << 2 ); + iVal1 = ( ( pdwCodeBook2[i] >> 24 ) & 0xf8 ) - ( ( dwSrc2 >> 24 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook2[i] >> 19 ) & 0xfc ) - ( ( dwSrc2 >> 19 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook2[i] >> 13 ) & 0xf8 ) - ( ( dwSrc2 >> 13 ) & 0xf8 ); + iVal += ( ( iVal1 * iVal1 ) << 2 ) + ( iVal2 * iVal2 ) + ( ( iVal3 * iVal3 ) << 2 ); + iVal1 = ( ( pdwCodeBook2[i] >> 8 ) & 0xf8 ) - ( ( dwSrc2 >> 8 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook2[i] >> 3 ) & 0xfc ) - ( ( dwSrc2 >> 3 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook2[i] << 3 ) & 0xf8 ) - ( ( dwSrc2 << 3 ) & 0xf8 ); + iVal += ( ( iVal1 * iVal1 ) << 2 ) + ( iVal2 * iVal2 ) + ( ( iVal3 * iVal3 ) << 2 ); + if ( iVal < iClosestVal ) + { + iClosestVal = iVal; + iClosest = i; + } + } + ASSERT ( iClosest != -1 ); + *pcdst++ = (UBYTE)iClosest; + } + } + dwSize >>= 1; + } + + //if ( iNumTimesRoundTheLoop > 0 ) + { + + // Now make the entries be the average of the texels that use them. + // FIXME - only looks at the top mipmap level. + dwSize = ti.height; + ULONG *pdwsrc = (ULONG *)pwdst[0]; + UCHAR *pcdst = pcTexels[0]; + + for ( i = 0; i < iNumEntries; i++ ) + { + float fA0 = 0.0f; + float fR0 = 0.0f; + float fG0 = 0.0f; + float fB0 = 0.0f; + float fA1 = 0.0f; + float fR1 = 0.0f; + float fG1 = 0.0f; + float fB1 = 0.0f; + float fA2 = 0.0f; + float fR2 = 0.0f; + float fG2 = 0.0f; + float fB2 = 0.0f; + float fA3 = 0.0f; + float fR3 = 0.0f; + float fG3 = 0.0f; + float fB3 = 0.0f; + int iNumTexels = 0; + + for ( int iChunk = 0; iChunk < (signed)(dwSize * dwSize) / 4; iChunk++ ) + { + if ( pcdst[iChunk] == i ) + { + ULONG dwSrc1 = pdwsrc[iChunk*2]; + ULONG dwSrc2 = pdwsrc[iChunk*2+1]; + iNumTexels++; + + if ( ContainsAlpha ) + { + fA0 += (float)( ( dwSrc1 >> 28 ) & 0xf ); + fR0 += (float)( ( dwSrc1 >> 24 ) & 0xf ); + fG0 += (float)( ( dwSrc1 >> 20 ) & 0xf ); + fB0 += (float)( ( dwSrc1 >> 16 ) & 0xf ); + fA1 += (float)( ( dwSrc1 >> 12 ) & 0xf ); + fR1 += (float)( ( dwSrc1 >> 8 ) & 0xf ); + fG1 += (float)( ( dwSrc1 >> 4 ) & 0xf ); + fB1 += (float)( ( dwSrc1 >> 0 ) & 0xf ); + fA2 += (float)( ( dwSrc2 >> 28 ) & 0xf ); + fR2 += (float)( ( dwSrc2 >> 24 ) & 0xf ); + fG2 += (float)( ( dwSrc2 >> 20 ) & 0xf ); + fB2 += (float)( ( dwSrc2 >> 16 ) & 0xf ); + fA3 += (float)( ( dwSrc2 >> 12 ) & 0xf ); + fR3 += (float)( ( dwSrc2 >> 8 ) & 0xf ); + fG3 += (float)( ( dwSrc2 >> 4 ) & 0xf ); + fB3 += (float)( ( dwSrc2 >> 0 ) & 0xf ); + } + else + { + fR0 += (float)( ( dwSrc1 >> 27 ) & 0x1f ); + fG0 += (float)( ( dwSrc1 >> 21 ) & 0x3f ); + fB0 += (float)( ( dwSrc1 >> 16 ) & 0x1f ); + fR1 += (float)( ( dwSrc1 >> 11 ) & 0x1f ); + fG1 += (float)( ( dwSrc1 >> 5 ) & 0x3f ); + fB1 += (float)( ( dwSrc1 >> 0 ) & 0x1f ); + fR2 += (float)( ( dwSrc2 >> 27 ) & 0x1f ); + fG2 += (float)( ( dwSrc2 >> 21 ) & 0x3f ); + fB2 += (float)( ( dwSrc2 >> 16 ) & 0x1f ); + fR3 += (float)( ( dwSrc2 >> 11 ) & 0x1f ); + fG3 += (float)( ( dwSrc2 >> 5 ) & 0x3f ); + fB3 += (float)( ( dwSrc2 >> 0 ) & 0x1f ); + } + } + } + + float fTemp = 1.0f / (float)iNumTexels; + fA0 *= fTemp; + fR0 *= fTemp; + fG0 *= fTemp; + fB0 *= fTemp; + fA1 *= fTemp; + fR1 *= fTemp; + fG1 *= fTemp; + fB1 *= fTemp; + fA2 *= fTemp; + fR2 *= fTemp; + fG2 *= fTemp; + fB2 *= fTemp; + fA3 *= fTemp; + fR3 *= fTemp; + fG3 *= fTemp; + fB3 *= fTemp; + + if ( ContainsAlpha ) + { + pdwCodeBook1[i] = ( (int)fA0 << 28 ) | ( (int)fR0 << 24 ) | ( (int)fG0 << 20 ) | ( (int)fB0 << 16 ); + pdwCodeBook1[i] |= ( (int)fA1 << 12 ) | ( (int)fR1 << 8 ) | ( (int)fG1 << 4 ) | ( (int)fB1 << 0 ); + pdwCodeBook2[i] = ( (int)fA2 << 28 ) | ( (int)fR2 << 24 ) | ( (int)fG2 << 20 ) | ( (int)fB2 << 16 ); + pdwCodeBook2[i] |= ( (int)fA3 << 12 ) | ( (int)fR3 << 8 ) | ( (int)fG3 << 4 ) | ( (int)fB3 << 0 ); + } + else + { + pdwCodeBook1[i] = ( (int)fR0 << 27 ) | ( (int)fG0 << 21 ) | ( (int)fB0 << 16 ); + pdwCodeBook1[i] |= ( (int)fR1 << 11 ) | ( (int)fG1 << 5 ) | ( (int)fB1 << 0 ); + pdwCodeBook2[i] = ( (int)fR2 << 27 ) | ( (int)fG2 << 21 ) | ( (int)fB2 << 16 ); + pdwCodeBook2[i] |= ( (int)fR3 << 11 ) | ( (int)fG3 << 5 ) | ( (int)fB3 << 0 ); + } + } + } + } + + + + // Now bung it all out to file, including a header. + // Remember to cope with endianness changes. + //#define CONVERT_WORD_ENDIANNESS(thing) ( (WORD)( ( ( (thing) & 0x00ff ) << 8 ) | ( ( (thing) & 0xff00 ) >> 8 ) ) ) + //#define CONVERT_DWORD_ENDIANNESS(thing) ( (DWORD)( ( ( (thing) & 0x000000ff ) << 24 ) | ( ( (thing) & 0x0000ff00 ) << 8 ) | ( ( (thing) & 0x00ff0000 ) >> 8 ) | ( ( (thing) & 0xff000000 ) >> 24 ) ) ) + //#define CONVERT_DWORD_ENDIANNESS(thing) ( (DWORD)( ( ( (thing) & 0x000000ff ) << 8 ) | ( ( (thing) & 0x0000ff00 ) >> 8 ) | ( ( (thing) & 0x00ff0000 ) << 8 ) | ( ( (thing) & 0xff000000 ) >> 8 ) ) ) + #define CONVERT_DWORD_ENDIANNESS(thing) (thing) + + #if 0 + char new_filename[100]; + strcpy ( new_filename, texture_name ); + // Change the ".tga" extension to a ".mvq" (Mipmapped VQ). + char *pch = new_filename; + while ( *pch != '\0' ) + { + if ( ( pch[0] == 't' ) && + ( pch[1] == 'g' ) && + ( pch[2] == 'a' ) ) + { + pch[0] = 'm'; + pch[1] = 'v'; + pch[2] = 'q'; + break; + } + pch++; + } + + MFFileHandle handle = FileCreate ( new_filename, TRUE ); + ASSERT ( handle != INVALID_HANDLE_VALUE ); + #endif + + // Header is: + // byte: version number - currently always 1 + // byte: size as a power of two, e.g. 5 = 32x32. + // byte: pixel format. 0 = 565, 1 = 4444. + // byte: padding - ignored + // Then comes 2k of codebook, then the mipmap levels, smallest level first. + // The smallest level is only a single byte and is padded with another byte before it. + + int written; + char cTemp = 1; + written = FileWrite ( handle, (void *)&cTemp, 1 ); + ASSERT ( written == 1 ); + + char cSize = 0; + while ( ( 1 << cSize ) < ti.height ) + { + cSize++; + } + ASSERT ( ( 1 << cSize ) == ti.height ); + ASSERT ( ( 1 << cSize ) == ti.width ); + written = FileWrite ( handle, (void *)&cSize, 1 ); + ASSERT ( written == 1 ); + + char cFormat; + if ( ContainsAlpha ) + { + cFormat = 1; + } + else + { + cFormat = 0; + } + written = FileWrite ( handle, (void *)&cFormat, 1 ); + ASSERT ( written == 1 ); + + // Junk padding. + written = FileWrite ( handle, (void *)&cFormat, 1 ); + ASSERT ( written == 1 ); + + + // Write the codebook into the file. + for ( i = 0; i < 256; i++ ) + { + DWORD dwTemp; + dwTemp = CONVERT_DWORD_ENDIANNESS ( pdwCodeBook1[i] ); + written = FileWrite ( handle, (void *)&dwTemp, 4 ); + ASSERT ( written == 4 ); + dwTemp = CONVERT_DWORD_ENDIANNESS ( pdwCodeBook2[i] ); + written = FileWrite ( handle, (void *)&dwTemp, 4 ); + ASSERT ( written == 4 ); + //*pdwdst++ = pdwCodeBook1[i]; + //*pdwdst++ = pdwCodeBook2[i]; + } + + + // OK, the mipmaps are stored in the top level surface (no GetAttachedSurface or any of that + // rubbish), and stored smallest-first. + + // Now fill in the mipmaps - they use the same codebook. + //UCHAR *pPtr = (UCHAR *) dd_sd2.lpSurface + 2048; + // Special-case the first level. It's only a single byte, but writes to + // vidmem must be WORD-aligned. + //*(WORD *)pPtr = (WORD)pcTexels[iNumMipmapLevels - 1][0]; + //pPtr += 2; + + // single byte of padding. + cTemp = 0; + written = FileWrite ( handle, (void *)&cTemp, 1 ); + ASSERT ( written == 1 ); + + cTemp = pcTexels[iNumMipmapLevels - 1][0]; + written = FileWrite ( handle, (void *)&cTemp, 1 ); + ASSERT ( written == 1 ); + + + // Now do the rest. + dwSize = 4; + for ( iMipmapLevel = iNumMipmapLevels - 2; iMipmapLevel >= 0; iMipmapLevel-- ) + { + unsigned char *pTemp = pcTexels[iMipmapLevel]; + + int iNumBytes = (dwSize * dwSize) / 4; + written = FileWrite ( handle, (void *)pTemp, iNumBytes ); + ASSERT ( written == iNumBytes ); + + //for ( int i = (dwSize * dwSize) / 4; i > 0; i-- ) + //{ + // *(WORD*)pPtr = *pTemp; + // pTemp++; + // pPtr+=2; + //} + + //memcpy ( pPtr, pcTexels[iMipmapLevel], (dwSize * dwSize) / 4 ); + //memset ( pPtr, iMipmapLevel + 2, dwSize * dwSize / 4 ); + //pPtr += dwSize * dwSize / 4; + + //VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + + dwSize <<= 1; + } + + OutputDebugString ( "Saved MVQ version\n" ); + + FileClose ( handle ); + + MemFree ( pdwCodeBook2 ); + MemFree ( pdwCodeBook1 ); + MemFree ( pcpwdstBlock ); + MemFree ( pcRealTexelBlock ); + } + + +dont_save_mvq:; + } + +#endif //#ifdef SAVE_MY_VQ_TEXTURES_PLEASE_BOB + + VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + + + + + + + + + + + + + + + + + + + + + + +#else + if ( !bVQPlease ) + { + VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + } + else + { + + + + + + + // OK, now create a VQ'd mipmapped surface and fill it. + + int iNumMipmapLevels = 0; + DWORD dwSize = ti.height; + ASSERT ( ti.height == ti.width ); + ASSERT ( ti.height < 512 ); + // Only mipmap down to 2x2 for VQs. + while ( dwSize > 1 ) + { + dwSize >>= 1; + iNumMipmapLevels++; + } + + + + // The VQ format is something I've basically guessed at! + // But it seems to work. + DDSURFACEDESC2 dd_sd2; + + dd_sd2 = mi->ddSurfDesc; + + dd_sd2.dwSize = sizeof(dd_sd2); +#ifdef MIPMAP_PLEASE_BOB + dd_sd2.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT | + DDSD_MIPMAPCOUNT; +#else + dd_sd2.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; +#endif + dd_sd2.dwWidth = ti.width; + dd_sd2.dwHeight = ti.height; +#ifdef MIPMAP_PLEASE_BOB + dd_sd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE| DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; +#else + dd_sd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE; +#endif + dd_sd2.ddsCaps.dwCaps2 = 0; + dd_sd2.ddsCaps.dwCaps3 = 0; + dd_sd2.ddsCaps.dwCaps4 = 0; + dd_sd2.dwTextureStage = 0; +#ifdef MIPMAP_PLEASE_BOB + dd_sd2.dwMipMapCount = iNumMipmapLevels; +#else + dd_sd2.dwMipMapCount = 0; +#endif + + dd_sd2.ddpfPixelFormat.dwFlags |= DDPF_COMPRESSED; + + VERIFY(SUCCEEDED(the_display.lp_DD4->CreateSurface(&dd_sd2, &lp_Surface, NULL))); + VERIFY(SUCCEEDED(lp_Surface->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lp_Texture))); + + + +#if 0 + // See if the "mvq" file is there, and load it if it is, + // rather than calculating it, which takes forever. + + char new_filename[100]; + strcpy ( new_filename, texture_name ); + // Change the ".tga" extension to a ".mvq" (Mipmapped VQ). + char *pch = new_filename; + while ( *pch != '\0' ) + { + if ( ( pch[0] == 't' ) && + ( pch[1] == 'g' ) && + ( pch[2] == 'a' ) ) + { + pch[0] = 'm'; + pch[1] = 'v'; + pch[2] = 'q'; + break; + } + pch++; + } + + MemFree ( dd_sd.lpSurface ); + + MFFileHandle handle = FileOpen ( new_filename ); + if ( handle != INVALID_HANDLE_VALUE ) + { + // Yep - load it. + + // Header is: + // byte: version number - currently always 1 + // byte: size as a power of two, e.g. 5 = 32x32. + // byte: pixel format. 0 = 565, 1 = 4444. + // byte: padding - ignored + // Then comes 2k of codebook, then the mipmap levels, smallest level first. + // The smallest level is only a single byte and is padded with another byte before it. + + + // Load it all at once. + int iFileSize = FileSize ( handle ); + ASSERT ( iFileSize > 0 ); + ASSERT ( iFileSize < 1000000 ); + char *pcFile = (char *)MemAlloc ( iFileSize ); + ASSERT ( pcFile != NULL ); + char *pcCurFilePos = pcFile; + + int iRead = FileRead ( handle, (void *)pcFile, iFileSize ); + ASSERT ( iRead == iFileSize ); + + FileClose ( handle ); + + + // OK, check the header. + + // Version. + ASSERT ( pcFile[0] == 1 ); + + // Log2 size. + ASSERT ( ( 1 << pcFile[1] ) == ti.height ); + ASSERT ( ( 1 << pcFile[1] ) == ti.width ); + + // Format + if ( ContainsAlpha ) + { + ASSERT ( pcFile[2] == 1 ); + } + else + { + ASSERT ( pcFile[2] == 0 ); + } + + // pcFile[3] is padding. + + pcCurFilePos += 4; + + + + // Now lock the surface. + dd_sd2.dwSize = sizeof(dd_sd); + dd_sd2.dwFlags = DDSD_LPSURFACE | DDSD_PITCH; + HRESULT res = lp_Surface->Lock(NULL, &dd_sd2, 0, NULL); + ASSERT(SUCCEEDED(res)); + + + // Write the codebook. + WORD *pwDst = (WORD *)dd_sd2.lpSurface; + for ( int i = 0; i < 256; i++ ) + { + pwDst[1] = *((WORD *)pcCurFilePos); + pcCurFilePos += 2; + pwDst[0] = *((WORD *)pcCurFilePos); + pcCurFilePos += 2; + pwDst[3] = *((WORD *)pcCurFilePos); + pcCurFilePos += 2; + pwDst[2] = *((WORD *)pcCurFilePos); + pcCurFilePos += 2; + pwDst += 4; + } + + + // OK, the mipmaps are stored in the top level surface (no GetAttachedSurface or any of that + // rubbish), and stored smallest-first. + + // Now fill in the mipmaps - they use the same codebook. + UCHAR *pPtr = (UCHAR *) dd_sd2.lpSurface + 2048; +#ifdef MIPMAP_PLEASE_BOB + // Special-case the first level. It's only a single byte, but writes to + // vidmem must be WORD-aligned. + *(WORD *)pPtr = (WORD)*pcCurFilePos; + pPtr += 2; +#endif + pcCurFilePos += 2; + + + // Now do the rest. + dwSize = 4; + for ( iMipmapLevel = iNumMipmapLevels - 2; iMipmapLevel >= 0; iMipmapLevel-- ) + { +#ifndef MIPMAP_PLEASE_BOB + if ( iMipmapLevel != 0 ) + { + // No mipmapping - skip all but the last level. + pcCurFilePos += ( (dwSize * dwSize) / 4 ); + } + else +#endif + { + WORD *pwTemp = (WORD *)pcCurFilePos; + for ( int i = (dwSize * dwSize) / 4; i > 0; i -= 2 ) + { + *(WORD*)pPtr = *pwTemp; + pwTemp++; + pPtr+=2; + } + + pcCurFilePos = (char *)pwTemp; + } + dwSize <<= 1; + } + + ASSERT ( ( pcCurFilePos - pcFile ) == iFileSize ); + MemFree ( pcFile ); + + VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + + } + else +#endif + { + +#ifdef DEBUG + // Oh dear - we'll have to actually do the work. + char cTemp[200]; + // Should have been an .mvq file present - fix it! + sprintf ( cTemp, "Had to mipmap/VQ \"%s\" manually\n", texture_name ); + TRACE ( cTemp ); +#endif + + + UWORD *(pwdst[10]); + UCHAR *(pcTexels[10]); + // This should be big enough... + UCHAR *pcRealTexelBlock = (UCHAR *)MemAlloc ( ( ti.height * ti.height / 4 ) * 2 + 10*4 ); + ASSERT ( pcRealTexelBlock != NULL ); + //UCHAR pcRealTexelBlock[(512*512/4) * 2 + 10*4]; + // DWORD align it. + UCHAR *pcTexelBlock = (UCHAR *)( ( (DWORD)pcRealTexelBlock + 3 ) & ~3 ); + + dwSize = ti.height; + //UCHAR pcpwdstBlock[512*512*2*2]; + UCHAR *pcpwdstBlock = (UCHAR *)MemAlloc ( 512*512*2*2 ); + ASSERT ( pcpwdstBlock != NULL ); + UCHAR *pcTemp = pcpwdstBlock; + for ( int i = 0; i < iNumMipmapLevels; i++ ) + { + //pwdst[i] = (UWORD *)MemAlloc ( 2 * dwSize * dwSize ); + pwdst[i] = (UWORD *)pcTemp; + pcTemp += 2 * dwSize * dwSize; + ASSERT ( pwdst[i] != NULL ); + pcTexels[i] = pcTexelBlock; + pcTexelBlock += dwSize * dwSize / 4; + pcTexelBlock = (UCHAR *)( ( (DWORD)pcTexelBlock + 3 ) & ~3 ); + if ( i > 0 ) + { + // Create the mipmap by a cheesy box filter of the previous level. + // FIXME - do a better filter. + UWORD *pwsrc1 = pwdst[i-1]; + UWORD *pwsrc2 = pwdst[i-1] + dwSize * 2; + UWORD *pwdst1 = pwdst[i]; + for ( int iY = 0; iY < (signed)dwSize; iY++ ) + { + for ( int iX = 0; iX < (signed)dwSize; iX++ ) + { + UWORD wR, wG, wB, wA; + UWORD wSrc1 = *pwsrc1++; + UWORD wSrc2 = *pwsrc1++; + UWORD wSrc3 = *pwsrc2++; + UWORD wSrc4 = *pwsrc2++; + // Assume the blue channel is the bottom one. + ASSERT ( ( dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask & 3 ) == 0 ); + ASSERT ( ( dd_sd2.ddpfPixelFormat.dwRBitMask & 3 ) == 0 ); + ASSERT ( ( dd_sd2.ddpfPixelFormat.dwGBitMask & 3 ) == 0 ); + ASSERT ( ( dd_sd2.ddpfPixelFormat.dwBBitMask & 0xc000 ) == 0 ); + wR = (wSrc1 & (UWORD)dd_sd2.ddpfPixelFormat.dwRBitMask) >> 2; + wR += (wSrc2 & (UWORD)dd_sd2.ddpfPixelFormat.dwRBitMask) >> 2; + wR += (wSrc3 & (UWORD)dd_sd2.ddpfPixelFormat.dwRBitMask) >> 2; + wR += (wSrc4 & (UWORD)dd_sd2.ddpfPixelFormat.dwRBitMask) >> 2; + // Add half an LSB. + wR += ( (UWORD)dd_sd2.ddpfPixelFormat.dwRBitMask >> 1) & ~(UWORD)dd_sd2.ddpfPixelFormat.dwRBitMask; + wR &= dd_sd2.ddpfPixelFormat.dwRBitMask; + wG = (wSrc1 & (UWORD)dd_sd2.ddpfPixelFormat.dwGBitMask) >> 2; + wG += (wSrc2 & (UWORD)dd_sd2.ddpfPixelFormat.dwGBitMask) >> 2; + wG += (wSrc3 & (UWORD)dd_sd2.ddpfPixelFormat.dwGBitMask) >> 2; + wG += (wSrc4 & (UWORD)dd_sd2.ddpfPixelFormat.dwGBitMask) >> 2; + wG += ( (UWORD)dd_sd2.ddpfPixelFormat.dwGBitMask >> 1) & ~(UWORD)dd_sd2.ddpfPixelFormat.dwGBitMask; + wG &= dd_sd2.ddpfPixelFormat.dwGBitMask; + wB = (wSrc1 & (UWORD)dd_sd2.ddpfPixelFormat.dwBBitMask); + wB += (wSrc2 & (UWORD)dd_sd2.ddpfPixelFormat.dwBBitMask); + wB += (wSrc3 & (UWORD)dd_sd2.ddpfPixelFormat.dwBBitMask); + wB += (wSrc4 & (UWORD)dd_sd2.ddpfPixelFormat.dwBBitMask); + wR += ( (UWORD)dd_sd2.ddpfPixelFormat.dwBBitMask << 1) & ~( (UWORD)dd_sd2.ddpfPixelFormat.dwBBitMask << 2 ); + wB >>= 2; + wB &= dd_sd2.ddpfPixelFormat.dwBBitMask; + wA = (wSrc1 & (UWORD)dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask) >> 2; + wA += (wSrc2 & (UWORD)dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask) >> 2; + wA += (wSrc3 & (UWORD)dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask) >> 2; + wA += (wSrc4 & (UWORD)dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask) >> 2; + wA += ( (UWORD)dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask >> 1) & ~(UWORD)dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask; + wA &= (UWORD)dd_sd2.ddpfPixelFormat.dwRGBAlphaBitMask; + *pwdst1++ = wR | wG | wB | wA; + } + // Skip a source line. + pwsrc1 += dwSize * 2; + pwsrc2 += dwSize * 2; + } + } + else + { + // Copy from the source. + memcpy ( pwdst[0], dd_sd.lpSurface, 2 * dwSize * dwSize ); + } + dwSize >>= 1; + } + #ifdef MIPMAP_PLEASE_BOB + ASSERT ( dwSize == 1 ); + #endif + + + dwSize = ti.height; + //UWORD pwTemp[512*512]; + UWORD *pwTemp = (UWORD *)MemAlloc ( 512 * 512 * 2); + ASSERT ( pwTemp != NULL ); + for ( i = 0; i < iNumMipmapLevels; i++ ) + { + // Swizzle and pack into 2x2 blocks. + UWORD *pwsrc = (UWORD *) pwdst[i]; + UWORD *pwdst1 = (UWORD *) pwTemp; + for ( int iY = 0; iY < (signed)dwSize; iY++ ) + { + for ( int iX = 0; iX < (signed)dwSize; iX++ ) + { + int iOffset = 0; + iOffset |= ( iY << 0 ) & 0x00001; + iOffset |= ( iX << 1 ) & 0x00002; + iOffset |= ( iY << 1 ) & 0x00004; + iOffset |= ( iX << 2 ) & 0x00008; + iOffset |= ( iY << 2 ) & 0x00010; + iOffset |= ( iX << 3 ) & 0x00020; + iOffset |= ( iY << 3 ) & 0x00040; + iOffset |= ( iX << 4 ) & 0x00080; + iOffset |= ( iY << 4 ) & 0x00100; + iOffset |= ( iX << 5 ) & 0x00200; + iOffset |= ( iY << 5 ) & 0x00400; + iOffset |= ( iX << 6 ) & 0x00800; + iOffset |= ( iY << 6 ) & 0x01000; + iOffset |= ( iX << 7 ) & 0x02000; + iOffset |= ( iY << 7 ) & 0x04000; + iOffset |= ( iX << 8 ) & 0x08000; + iOffset |= ( iY << 8 ) & 0x10000; + iOffset |= ( iX << 9 ) & 0x20000; + pwdst1[iOffset] = *pwsrc++; + } + } + // And copy it back in. + memcpy ( pwdst[i], pwTemp, 2 * dwSize * dwSize ); + dwSize >>= 1; + } + MemFree ( pwTemp ); + + //memset ( &(pwdst[ti.height * ti.width / 2]), 0, ti.width * ti.height ); + + + ULONG *pdwCodeBook1 = (ULONG *)MemAlloc ( 256 * 4 ); + ASSERT ( pdwCodeBook1 != NULL ); + ULONG *pdwCodeBook2 = (ULONG *)MemAlloc ( 256 * 4 ); + ASSERT ( pdwCodeBook2 != NULL ); + //ULONG pdwCodeBook1[256]; + //ULONG pdwCodeBook2[256]; + int iNumEntries = 0; + + + + // Let's do this another way. Scan multiple times, with smaller and smaller tolerance levels + // until we run out of codebook space. + for ( int iPrecision = 0; iPrecision < 10; iPrecision++ ) + { + ULONG dwMask1, dwMask2; + #define BINARY_DAMMIT(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)((a<<15)|(b<<14)|(c<<13)|(d<<12)|(e<<11)|(f<<10)|(g<<9)|(h<<8)|(i<<7)|(j<<6)|(k<<5)|(l<<4)|(m<<3)|(n<<2)|(o<<1)|(p<<0)) + if ( ContainsAlpha ) + { + // RRRRGGGGBBBBAAAA + switch ( iPrecision ) + { + case 0: dwMask1 = BINARY_DAMMIT(1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0); break; + case 1: dwMask1 = BINARY_DAMMIT(1,0,0,0,1,1,0,0,1,0,0,0,1,0,0,0); break; + case 2: dwMask1 = BINARY_DAMMIT(1,1,0,0,1,1,0,0,1,0,0,0,1,0,0,0); break; + case 3: dwMask1 = BINARY_DAMMIT(1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0); break; + case 4: dwMask1 = BINARY_DAMMIT(1,1,0,0,1,1,1,0,1,1,0,0,1,1,0,0); break; + case 5: dwMask1 = BINARY_DAMMIT(1,1,1,0,1,1,1,0,1,1,0,0,1,1,0,0); break; + case 6: dwMask1 = BINARY_DAMMIT(1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0); break; + case 7: dwMask1 = BINARY_DAMMIT(1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0); break; + case 8: dwMask1 = BINARY_DAMMIT(1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0); break; + case 9: dwMask1 = BINARY_DAMMIT(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); break; + } + } + else + { + // RRRRRGGGGGGBBBBB + switch ( iPrecision ) + { + case 0: dwMask1 = BINARY_DAMMIT(1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0); break; + case 1: dwMask1 = BINARY_DAMMIT(1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0); break; + case 2: dwMask1 = BINARY_DAMMIT(1,1,0,0,0,1,1,0,0,0,0,1,1,0,0,0); break; + case 3: dwMask1 = BINARY_DAMMIT(1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0); break; + case 4: dwMask1 = BINARY_DAMMIT(1,1,1,0,0,1,1,1,0,0,0,1,1,1,0,0); break; + case 5: dwMask1 = BINARY_DAMMIT(1,1,1,0,0,1,1,1,1,0,0,1,1,1,0,0); break; + case 6: dwMask1 = BINARY_DAMMIT(1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0); break; + case 7: dwMask1 = BINARY_DAMMIT(1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0); break; + case 8: dwMask1 = BINARY_DAMMIT(1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0); break; + case 9: dwMask1 = BINARY_DAMMIT(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); break; + } + } + // Replicate this texel mask into the other four. + dwMask1 |= dwMask1 << 16; + dwMask2 = dwMask1; + #undef BINARY_DAMMIT + + + // Now scan the texture, making any codebook entries that don't exist. + // FIXME - at the moment, the mipmap levels are not scanned - maybe I should. + ULONG *pdwsrc = (ULONG *)pwdst[0]; + int iChunk; + for ( iChunk = 0; iChunk < (ti.width * ti.height) / 4; iChunk++ ) + { + ULONG dwSrc1 = pdwsrc[iChunk*2]; + ULONG dwSrc2 = pdwsrc[iChunk*2+1]; + ULONG dwSrc1Mask = dwSrc1 & dwMask1; + ULONG dwSrc2Mask = dwSrc2 & dwMask2; + // See if this chunk or something close is already in the codebook. + for ( int j = 0; j < iNumEntries; j++ ) + { + if ( ( ( pdwCodeBook1[j] & dwMask1 ) == dwSrc1Mask ) && ( ( pdwCodeBook2[j] & dwMask2 ) == dwSrc2Mask ) ) + { + // Joy. + break; + } + } + if ( j == iNumEntries ) + { + // Didn't find a match. + if ( iNumEntries < 256 ) + { + // Cool - just grow the table. + pdwCodeBook1[iNumEntries] = dwSrc1; + pdwCodeBook2[iNumEntries] = dwSrc2; + iNumEntries++; + } + else + { + // No more entries - exit. + goto no_more_entries; + } + } + } + + } + no_more_entries: + + // OK, filled the codebook, so rescan and find the closest matches for each texel, + // this time using a decent geometric error, not masks! + + // Actually, do a loop of (a) find the closest entries, then (b) make the entries the average of + // the things that use them. + // On the last time round, all the mipmap levels do (a), and (b) is not done. + + for ( int iNumTimesRoundTheLoop = 1; iNumTimesRoundTheLoop >= 0; iNumTimesRoundTheLoop-- ) + { + // Refind the closest match for each chunk. + // FIXME - this only does the top mipmap level. + dwSize = ti.height; + int iLevelsThisTime; + if ( iNumTimesRoundTheLoop == 0 ) + { + // Last time round the loop, do all mipmap levels. + iLevelsThisTime = iNumMipmapLevels; + } + else + { + // Just do the top one. + iLevelsThisTime = 1; + } + for ( iMipmapLevel = 0; iMipmapLevel < iLevelsThisTime; iMipmapLevel++ ) + { + ULONG *pdwsrc = (ULONG *)pwdst[iMipmapLevel]; + UCHAR *pcdst = pcTexels[iMipmapLevel]; + for ( int iChunk = 0; iChunk < (signed)(dwSize * dwSize) / 4; iChunk++ ) + { + ULONG dwSrc1 = pdwsrc[iChunk*2]; + ULONG dwSrc2 = pdwsrc[iChunk*2+1]; + + int iClosest = -1; + int iClosestVal = 100000000; + if ( ContainsAlpha ) + { + for ( i = 0; i < iNumEntries; i++ ) + { + if ( ( pdwCodeBook1[i] == dwSrc1 ) && ( pdwCodeBook2[i] == dwSrc2 ) ) + { + // Perfect match. + iClosest = i; + break; + } + + // RRRR GGGG BBBB AAAA + int iVal, iVal1, iVal2, iVal3, iVal4; + iVal1 = ( ( pdwCodeBook1[i] >> 24 ) & 0xf0 ) - ( ( dwSrc1 >> 24 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook1[i] >> 20 ) & 0xf0 ) - ( ( dwSrc1 >> 20 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook1[i] >> 16 ) & 0xf0 ) - ( ( dwSrc1 >> 16 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook1[i] >> 12 ) & 0xf0 ) - ( ( dwSrc1 >> 12 ) & 0xf0 ); + iVal = ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + iVal1 = ( ( pdwCodeBook1[i] >> 8 ) & 0xf0 ) - ( ( dwSrc1 >> 8 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook1[i] >> 4 ) & 0xf0 ) - ( ( dwSrc1 >> 4 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook1[i] >> 0 ) & 0xf0 ) - ( ( dwSrc1 >> 0 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook1[i] << 4 ) & 0xf0 ) - ( ( dwSrc1 << 4 ) & 0xf0 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + iVal1 = ( ( pdwCodeBook2[i] >> 24 ) & 0xf0 ) - ( ( dwSrc2 >> 24 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook2[i] >> 20 ) & 0xf0 ) - ( ( dwSrc2 >> 20 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook2[i] >> 16 ) & 0xf0 ) - ( ( dwSrc2 >> 16 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook2[i] >> 12 ) & 0xf0 ) - ( ( dwSrc2 >> 12 ) & 0xf0 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + iVal1 = ( ( pdwCodeBook2[i] >> 8 ) & 0xf0 ) - ( ( dwSrc2 >> 8 ) & 0xf0 ); + iVal2 = ( ( pdwCodeBook2[i] >> 4 ) & 0xf0 ) - ( ( dwSrc2 >> 4 ) & 0xf0 ); + iVal3 = ( ( pdwCodeBook2[i] >> 0 ) & 0xf0 ) - ( ( dwSrc2 >> 0 ) & 0xf0 ); + iVal4 = ( ( pdwCodeBook2[i] << 4 ) & 0xf0 ) - ( ( dwSrc2 << 4 ) & 0xf0 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ) + ( iVal4 * iVal4 ); + if ( iVal < iClosestVal ) + { + iClosestVal = iVal; + iClosest = i; + } + } + ASSERT ( iClosest != -1 ); + *pcdst++ = (UBYTE)iClosest; + } + else + { + for ( i = 0; i < iNumEntries; i++ ) + { + if ( ( pdwCodeBook1[i] == dwSrc1 ) && ( pdwCodeBook2[i] == dwSrc2 ) ) + { + // Perfect match. + iClosest = i; + break; + } + + // RRRR RGGG GGGB BBBB + int iVal, iVal1, iVal2, iVal3; + iVal1 = ( ( pdwCodeBook1[i] >> 24 ) & 0xf8 ) - ( ( dwSrc1 >> 24 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook1[i] >> 19 ) & 0xfc ) - ( ( dwSrc1 >> 19 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook1[i] >> 13 ) & 0xf8 ) - ( ( dwSrc1 >> 13 ) & 0xf8 ); + iVal = ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ); + iVal1 = ( ( pdwCodeBook1[i] >> 8 ) & 0xf8 ) - ( ( dwSrc1 >> 8 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook1[i] >> 3 ) & 0xfc ) - ( ( dwSrc1 >> 3 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook1[i] << 3 ) & 0xf8 ) - ( ( dwSrc1 << 3 ) & 0xf8 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ); + iVal1 = ( ( pdwCodeBook2[i] >> 24 ) & 0xf8 ) - ( ( dwSrc2 >> 24 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook2[i] >> 19 ) & 0xfc ) - ( ( dwSrc2 >> 19 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook2[i] >> 13 ) & 0xf8 ) - ( ( dwSrc2 >> 13 ) & 0xf8 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ); + iVal1 = ( ( pdwCodeBook2[i] >> 8 ) & 0xf8 ) - ( ( dwSrc2 >> 8 ) & 0xf8 ); + iVal2 = ( ( pdwCodeBook2[i] >> 3 ) & 0xfc ) - ( ( dwSrc2 >> 3 ) & 0xfc ); + iVal3 = ( ( pdwCodeBook2[i] << 3 ) & 0xf8 ) - ( ( dwSrc2 << 3 ) & 0xf8 ); + iVal += ( iVal1 * iVal1 ) + ( iVal2 * iVal2 ) + ( iVal3 * iVal3 ); + if ( iVal < iClosestVal ) + { + iClosestVal = iVal; + iClosest = i; + } + } + ASSERT ( iClosest != -1 ); + *pcdst++ = (UBYTE)iClosest; + } + } + dwSize >>= 1; + } + + //if ( iNumTimesRoundTheLoop > 0 ) + { + + // Now make the entries be the average of the texels that use them. + // FIXME - only looks at the top mipmap level. + dwSize = ti.height; + ULONG *pdwsrc = (ULONG *)pwdst[0]; + UCHAR *pcdst = pcTexels[0]; + + for ( i = 0; i < iNumEntries; i++ ) + { + float fA0 = 0.0f; + float fR0 = 0.0f; + float fG0 = 0.0f; + float fB0 = 0.0f; + float fA1 = 0.0f; + float fR1 = 0.0f; + float fG1 = 0.0f; + float fB1 = 0.0f; + float fA2 = 0.0f; + float fR2 = 0.0f; + float fG2 = 0.0f; + float fB2 = 0.0f; + float fA3 = 0.0f; + float fR3 = 0.0f; + float fG3 = 0.0f; + float fB3 = 0.0f; + int iNumTexels = 0; + + for ( int iChunk = 0; iChunk < (signed)(dwSize * dwSize) / 4; iChunk++ ) + { + if ( pcdst[iChunk] == i ) + { + ULONG dwSrc1 = pdwsrc[iChunk*2]; + ULONG dwSrc2 = pdwsrc[iChunk*2+1]; + iNumTexels++; + + if ( ContainsAlpha ) + { + fA0 += (float)( ( dwSrc1 >> 28 ) & 0xf ); + fR0 += (float)( ( dwSrc1 >> 24 ) & 0xf ); + fG0 += (float)( ( dwSrc1 >> 20 ) & 0xf ); + fB0 += (float)( ( dwSrc1 >> 16 ) & 0xf ); + fA1 += (float)( ( dwSrc1 >> 12 ) & 0xf ); + fR1 += (float)( ( dwSrc1 >> 8 ) & 0xf ); + fG1 += (float)( ( dwSrc1 >> 4 ) & 0xf ); + fB1 += (float)( ( dwSrc1 >> 0 ) & 0xf ); + fA2 += (float)( ( dwSrc2 >> 28 ) & 0xf ); + fR2 += (float)( ( dwSrc2 >> 24 ) & 0xf ); + fG2 += (float)( ( dwSrc2 >> 20 ) & 0xf ); + fB2 += (float)( ( dwSrc2 >> 16 ) & 0xf ); + fA3 += (float)( ( dwSrc2 >> 12 ) & 0xf ); + fR3 += (float)( ( dwSrc2 >> 8 ) & 0xf ); + fG3 += (float)( ( dwSrc2 >> 4 ) & 0xf ); + fB3 += (float)( ( dwSrc2 >> 0 ) & 0xf ); + } + else + { + fR0 += (float)( ( dwSrc1 >> 27 ) & 0x1f ); + fG0 += (float)( ( dwSrc1 >> 21 ) & 0x3f ); + fB0 += (float)( ( dwSrc1 >> 16 ) & 0x1f ); + fR1 += (float)( ( dwSrc1 >> 11 ) & 0x1f ); + fG1 += (float)( ( dwSrc1 >> 5 ) & 0x3f ); + fB1 += (float)( ( dwSrc1 >> 0 ) & 0x1f ); + fR2 += (float)( ( dwSrc2 >> 27 ) & 0x1f ); + fG2 += (float)( ( dwSrc2 >> 21 ) & 0x3f ); + fB2 += (float)( ( dwSrc2 >> 16 ) & 0x1f ); + fR3 += (float)( ( dwSrc2 >> 11 ) & 0x1f ); + fG3 += (float)( ( dwSrc2 >> 5 ) & 0x3f ); + fB3 += (float)( ( dwSrc2 >> 0 ) & 0x1f ); + } + } + } + + float fTemp = 1.0f / (float)iNumTexels; + fA0 *= fTemp; + fR0 *= fTemp; + fG0 *= fTemp; + fB0 *= fTemp; + fA1 *= fTemp; + fR1 *= fTemp; + fG1 *= fTemp; + fB1 *= fTemp; + fA2 *= fTemp; + fR2 *= fTemp; + fG2 *= fTemp; + fB2 *= fTemp; + fA3 *= fTemp; + fR3 *= fTemp; + fG3 *= fTemp; + fB3 *= fTemp; + + if ( ContainsAlpha ) + { + pdwCodeBook1[i] = ( (int)fA0 << 28 ) | ( (int)fR0 << 24 ) | ( (int)fG0 << 20 ) | ( (int)fB0 << 16 ); + pdwCodeBook1[i] |= ( (int)fA1 << 12 ) | ( (int)fR1 << 8 ) | ( (int)fG1 << 4 ) | ( (int)fB1 << 0 ); + pdwCodeBook2[i] = ( (int)fA2 << 28 ) | ( (int)fR2 << 24 ) | ( (int)fG2 << 20 ) | ( (int)fB2 << 16 ); + pdwCodeBook2[i] |= ( (int)fA3 << 12 ) | ( (int)fR3 << 8 ) | ( (int)fG3 << 4 ) | ( (int)fB3 << 0 ); + } + else + { + pdwCodeBook1[i] = ( (int)fR0 << 27 ) | ( (int)fG0 << 21 ) | ( (int)fB0 << 16 ); + pdwCodeBook1[i] |= ( (int)fR1 << 11 ) | ( (int)fG1 << 5 ) | ( (int)fB1 << 0 ); + pdwCodeBook2[i] = ( (int)fR2 << 27 ) | ( (int)fG2 << 21 ) | ( (int)fB2 << 16 ); + pdwCodeBook2[i] |= ( (int)fR3 << 11 ) | ( (int)fG3 << 5 ) | ( (int)fB3 << 0 ); + } + } + } + } + + + dd_sd2.dwSize = sizeof(dd_sd); + dd_sd2.dwFlags = DDSD_LPSURFACE | DDSD_PITCH; + HRESULT res = lp_Surface->Lock(NULL, &dd_sd2, 0, NULL); + ASSERT(SUCCEEDED(res)); + + // Copy the codebook into the surface. + ULONG *pdwdst = (ULONG *)dd_sd2.lpSurface; + for ( i = 0; i < 256; i++ ) + { + *pdwdst++ = pdwCodeBook1[i]; + *pdwdst++ = pdwCodeBook2[i]; + } + + + #ifdef MIPMAP_PLEASE_BOB + + // OK, the mipmaps are stored in the top level surface (no GetAttachedSurface or any of that + // rubbish), and stored smallest-first. + + // Now fill in the mipmaps - they use the same codebook. + UCHAR *pPtr = (UCHAR *) dd_sd2.lpSurface + 2048; + // Special-case the first level. It's only a single byte, but writes to + // vidmem must be WORD-aligned. + *(WORD *)pPtr = (WORD)pcTexels[iNumMipmapLevels - 1][0]; + pPtr += 2; + // Now do the rest. + dwSize = 4; + for ( iMipmapLevel = iNumMipmapLevels - 2; iMipmapLevel >= 0; iMipmapLevel-- ) + { + + + + WORD *pTemp = (WORD *)pcTexels[iMipmapLevel]; + for ( int i = (dwSize * dwSize) / 4; i > 0; i -= 2 ) + { + *(WORD*)pPtr = *pTemp; + pTemp++; + pPtr+=2; + } + + //memcpy ( pPtr, pcTexels[iMipmapLevel], (dwSize * dwSize) / 4 ); + //memset ( pPtr, iMipmapLevel + 2, dwSize * dwSize / 4 ); + //pPtr += dwSize * dwSize / 4; + + //VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + + dwSize <<= 1; + } + + #else + + // And copy the data in. This MUST be done this way, because + // byte writes to videomemory do not work! They get interpreted + // as word writes, with random junk in the other byte! + UCHAR *pPtr = (UCHAR *) dd_sd2.lpSurface + 2048; + WORD *pTemp = (WORD *)pcTexels[0]; + for ( i = (ti.width * ti.height) / 4; i > 0; i -= 2 ) + { + *(WORD*)pPtr = *pTemp; + pTemp++; + pPtr+=2; + } + #endif + MemFree ( pdwCodeBook2 ); + MemFree ( pdwCodeBook1 ); + MemFree ( pcpwdstBlock ); + MemFree ( pcRealTexelBlock ); + MemFree ( dd_sd.lpSurface ); + + VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + } + + } + #endif + + MemFree(tga); + + + return DD_OK; +} + + + + +#ifndef TARGET_DC + +HRESULT D3DTexture::Reload_8(void) +{ + UBYTE temp_palette[768], + *surface_mem; + SLONG bytes_read, + c0, + pitch; + D3DDeviceInfo *current_device; + DDModeInfo *the_format,*next_best_format; + DDSURFACEDESC2 dd_sd; + HANDLE file_handle; + HANDLE t_handle; + HANDLE p_handle; + HRESULT result; + PALETTEENTRY the_palette[256]; + SLONG score; + SLONG best_score; + + + + + // Check parameters. + if(strlen(texture_name)<=0 || strlen(texture_name)<=0) + { + // Invalid parameters. + return DDERR_GENERIC; + } + + // Get the current device. + current_device = the_display.GetDeviceInfo(); + if(!current_device) + { + // No current device. + return DDERR_GENERIC; + } + + // + // There is never any alpha in an 8-bit palettized texture. + // + + ContainsAlpha = FALSE; + + // ==================================================== + // MARKS HACKED-IN CODE! + // ==================================================== + + + // + // Find an 8-bit palettized texture format. + // + + DDModeInfo *mi; + + the_format = NULL; + + for (mi = current_device->FormatList; mi; mi = mi->Next) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + the_format = mi; + + // + // Use the old code to load the 8-bit textures. + // + + goto load_8bit; + } + } + + // + // Look for a suitable 16-bit format. + // + + best_score = 0; + the_format = NULL; + + for (mi = current_device->FormatList; mi; mi = mi->Next) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_RGB) + { + // + // True colour... + // + + if (mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount == 16) + { + // + // And 16-bit. + // + + score = 5; + + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) + { + // + // Knock off a bit for alpha + // + + score -= 1; + } + + if (score > best_score) + { + best_score = score; + the_format = mi; + } + } + } + } + + if (the_format == NULL) + { + // + // We really are in the shit now! There aren't any texture + // formats for us to choose from. + // + + return DDERR_GENERIC; + } + + // + // Open the texture and palette files. + // + + t_handle = CreateFile( + texture_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (t_handle == NULL) + { + DebugText("Could not open texture file.\n"); + return DDERR_GENERIC; + } + + p_handle = CreateFile( + palette_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (p_handle == NULL) + { + DebugText("Could not open palette file.\n"); + return DDERR_GENERIC; + } + + // + // We have to convert the texture into the given format. + // + + OS_calculate_mask_and_shift(the_format->ddSurfDesc.ddpfPixelFormat.dwRBitMask ,&mask_red, &shift_red ); + OS_calculate_mask_and_shift(the_format->ddSurfDesc.ddpfPixelFormat.dwGBitMask ,&mask_green, &shift_green); + OS_calculate_mask_and_shift(the_format->ddSurfDesc.ddpfPixelFormat.dwBBitMask ,&mask_blue, &shift_blue ); + // + // Get rid of the old texture stuff. + // + + Destroy(); + + // + // Create + // + + dd_sd = the_format->ddSurfDesc; + + dd_sd.dwSize = sizeof(dd_sd); + dd_sd.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; + dd_sd.dwWidth = 256; + dd_sd.dwHeight = 256; + dd_sd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; +#ifdef TARGET_DC + dd_sd.ddsCaps.dwCaps2 = 0; +#else + dd_sd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; +#endif + + VERIFY(SUCCEEDED(the_display.lp_DD4->CreateSurface(&dd_sd, &lp_Surface, NULL))); + + // + // Lock + // + + VERIFY(SUCCEEDED(lp_Surface->Lock(NULL, &dd_sd, 0, NULL))); + + // + // Load in the palette. + // + + ReadFile(p_handle, temp_palette, 768, (LPDWORD) &bytes_read, NULL); + + // + // Copy the texture in + // + + { + UWORD pixel_our; + UBYTE colour; + UBYTE red; + UBYTE green; + UBYTE blue; + UWORD *wscreen = (UWORD *) dd_sd.lpSurface; + UBYTE line[256]; + SLONG i; + SLONG j; + + // + // 16 bits per pixel. + // + + for (i = 0; i < 256; i++) + { + ReadFile(t_handle, line, 256, (LPDWORD) &bytes_read, NULL); + + for (j = 0; j < 256; j++) + { + colour = line[j]; + + red = temp_palette[colour * 3 + 0]; + green = temp_palette[colour * 3 + 1]; + blue = temp_palette[colour * 3 + 2]; + + pixel_our = 0; + + pixel_our |= (red >> mask_red ) << shift_red; + pixel_our |= (green >> mask_green) << shift_green; + pixel_our |= (blue >> mask_blue ) << shift_blue; + + wscreen[i * 256 + j] = pixel_our; + } + } + } + + // + // Close the files. + // + + CloseHandle(t_handle); + CloseHandle(p_handle); + + // + // Unlock + // + + VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); + + // Get d3d texture interface. + result = lp_Surface->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lp_Texture); + + if(FAILED(result)) + { + DebugText("LoadTexture8: unable to create texture\n"); + dd_error(result); + goto cleanup; + } + + // + // Success. + // + + return DD_OK; + + + + + // ==================================================== + // END OF MARKS HACKED-IN CODE + // ==================================================== + + + // + // Found an 8-bit palettized texture format. + // + + load_8bit:; + + + // Get rid of the old texture stuff. + Destroy(); + + // + // Set up the texture. + // + + // Set up the surface description. + dd_sd = the_format->ddSurfDesc; + dd_sd.dwFlags = DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; + dd_sd.dwWidth = 256; + dd_sd.dwHeight = 256; + dd_sd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; +#ifdef TARGET_DC + dd_sd.ddsCaps.dwCaps2 = 0; +#else + dd_sd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; +#endif + + // Create the main texture surface. + result = the_display.lp_DD4->CreateSurface ( + &dd_sd, + &lp_Surface, + NULL + ); + if(FAILED(result)) + { + DebugText("LoadTexture8: unable to create main texture surface\n"); + dd_error(result); + goto cleanup; + } + + // Read in the bit map. + file_handle = CreateFile ( + texture_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if(file_handle == NULL) + { + DebugText("LoadTexture8: unable to open palette file\n"); + goto cleanup; + } + + // Read the bit map directly into the texture surface. + result = lp_Surface->Lock(NULL,&dd_sd,DDLOCK_WAIT|DDLOCK_NOSYSLOCK,NULL); + if(FAILED(result)) + { + DebugText("LoadTexture8: unable to lock temp texture surface\n"); + dd_error(result); + goto cleanup; + } + pitch = dd_sd.lPitch; + surface_mem = (UBYTE*)dd_sd.lpSurface; + for(c0=0;c0<256;c0++,surface_mem+=pitch) + { + if(ReadFile(file_handle,surface_mem,256,(LPDWORD)&bytes_read,NULL)==FALSE) + { + DebugText("LoadTexture8: unable to read texture file\n"); + goto cleanup; + } + } + lp_Surface->Unlock(NULL); + CloseHandle(file_handle); + + // + // Set up the palette. + // + + // Read the palette into temp storage. + file_handle = CreateFile ( + palette_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (file_handle == NULL) + { + DebugText("LoadTexture8: unable to open palette file\n"); + goto cleanup; + } + if(ReadFile(file_handle,temp_palette,768,(LPDWORD)&bytes_read,NULL)==FALSE) + { + DebugText("LoadTexture8: unable to read palette file\n"); + goto cleanup; + } + CloseHandle(file_handle); + + // Set up palette entries. + ZeroMemory(the_palette,sizeof(the_palette)); + for(c0=0;c0<256;c0++) + { + the_palette[c0].peRed = temp_palette[(c0*3)+0]; + the_palette[c0].peGreen = temp_palette[(c0*3)+1]; + the_palette[c0].peBlue = temp_palette[(c0*3)+2]; + } + + // Create the texture palette. + result = the_display.lp_DD4->CreatePalette ( + DDPCAPS_8BIT|DDPCAPS_ALLOW256, + the_palette, + &lp_Palette, + NULL + ); + if(FAILED(result)) + { + DebugText("LoadTexture8: unable to create texture palette\n"); + dd_error(result); + goto cleanup; + } + + // Attach palette to texture surface. + result = lp_Surface->SetPalette(lp_Palette); + if(FAILED(result)) + { + DebugText("LoadTexture8: unable to attach texture palette\n"); + dd_error(result); +// goto cleanup; + } + + + // Get d3d texture interface. + result = lp_Surface->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lp_Texture); + if(FAILED(result)) + { + DebugText("LoadTexture8: unable to create texture\n"); + dd_error(result); + goto cleanup; + } + + // Success. + return DD_OK; + +cleanup: + + // Cleanup. + Destroy(); + return result; +} + +#endif //#ifndef TARGET_DC + + + +HRESULT D3DTexture::Reload_user() +{ + D3DDeviceInfo *current_device; + + SLONG score; + DDModeInfo *mi; + SLONG best_score; + DDModeInfo *best_mi; + + //SLONG bpp; + + SLONG try_shift_alpha; + SLONG try_shift_red; + SLONG try_shift_green; + SLONG try_shift_blue; + + SLONG try_mask_alpha; + SLONG try_mask_red; + SLONG try_mask_green; + SLONG try_mask_blue; + + DDSURFACEDESC2 dd_sd; + HRESULT result; + + // + // Get the current device. + // + + current_device = the_display.GetDeviceInfo(); + + if (!current_device) + { + TRACE("No device!\n"); + + return DDERR_GENERIC; + } + + best_score = 0; + best_mi = NULL; + + if (UserWantsAlpha) + { + // + // Find the texture format with the most bits of alpha. + // + + for (mi = current_device->FormatList; mi; mi = mi->Next) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_RGB) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount == 16) + { + // + // Find out how many bits there are for each component. + // + + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRGBAlphaBitMask, &try_mask_alpha, &try_shift_alpha); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRBitMask , &try_mask_red, &try_shift_red ); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwGBitMask , &try_mask_green, &try_shift_green); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwBBitMask , &try_mask_blue, &try_shift_blue ); + + score = (32 - try_mask_alpha) << 8; + score /= mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount; + + if (score > best_score) + { + best_score = score; + best_mi = mi; + } + } + } + } + } + } + else + { + // + // Find a 5:6:5 or similar format. + // + + for (mi = current_device->FormatList; mi; mi = mi->Next) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_RGB) + { + // + // True colour... + // + + if (mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount >= 16) + { + score = 0x100; + score -= mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount; + + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) + { + // + // Knock off score for alpha + // + + score -= 1; + } + + if (score > best_score) + { + best_score = score; + best_mi = mi; + } + } + } + } + } + + if (best_mi == NULL) + { + // + // Couldn't find a suitable texture format. + // + + TRACE("Could not find texture format for the user texture page\n"); + return DDERR_GENERIC; + } + + mi = best_mi; + + SLONG dwMaskR, dwMaskG, dwMaskB, dwMaskA; + SLONG dwShiftR, dwShiftG, dwShiftB, dwShiftA; + + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRBitMask, &dwMaskR, &dwShiftR ); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwGBitMask, &dwMaskG, &dwShiftG ); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwBBitMask, &dwMaskB, &dwShiftB ); + + if (UserWantsAlpha) + { + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRGBAlphaBitMask, &dwMaskA, &dwShiftA); + } + else + { + dwMaskA = 0; + dwShiftA = 0; + } + mask_red = (UBYTE)dwMaskR; + mask_green = (UBYTE)dwMaskG; + mask_blue = (UBYTE)dwMaskB; + mask_alpha = (UBYTE)dwMaskA; + shift_red = (UBYTE)dwShiftR; + shift_green = (UBYTE)dwShiftG; + shift_blue = (UBYTE)dwShiftB; + shift_alpha = (UBYTE)dwShiftA; + + + // + // Get rid of the old texture stuff. + // + + Destroy(); + + // + // The surface + // + + dd_sd = mi->ddSurfDesc; + + dd_sd.dwSize = sizeof(dd_sd); + dd_sd.dwFlags = + DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; + dd_sd.dwWidth = size; + dd_sd.dwHeight = size; + dd_sd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; +#ifdef TARGET_DC + dd_sd.ddsCaps.dwCaps2 = 0; +#else + dd_sd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; +#endif + + VERIFY(SUCCEEDED(the_display.lp_DD4->CreateSurface(&dd_sd, &lp_Surface, NULL))); + + // + // Get d3d texture interface. + // + + result = lp_Surface->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lp_Texture); + + if(FAILED(result)) + { + TRACE("ReloadTextureUser: Could not get the texture interface.\n"); + Destroy(); + return DDERR_GENERIC; + } + + // + // Success. + // + + return DD_OK; + +} + +HRESULT D3DTexture::LockUser(UWORD **bitmap, SLONG *pitch) +{ + DDSURFACEDESC2 dd_sd; + +// ASSERT(Type == D3DTEXTURE_TYPE_USER); + + InitStruct(dd_sd); + + if (lp_Surface == NULL || FAILED(lp_Surface->Lock(NULL, &dd_sd, DDLOCK_WAIT, NULL))) + { + return DDERR_GENERIC; + } + else + { + *bitmap = (UWORD *) dd_sd.lpSurface; + *pitch = dd_sd.lPitch; + + return DD_OK; + } +} + +void D3DTexture::UnlockUser() +{ +// ASSERT(Type == D3DTEXTURE_TYPE_USER); + + VERIFY(SUCCEEDED(lp_Surface->Unlock(NULL))); +} + +HRESULT D3DTexture::Reload(void) +{ + Font *current_font, + *next_font; + HRESULT ans; + + + // + // erk ... we have to call the POLY engine from here + // this hook needs calling when the textures are reloaded + // en masse, but tracking down each point in the game where + // this happens is tricky ... + // so there's a cheeky little call here ... + // + POLY_reset_render_states(); + + if(IsFont()) + { + current_font = FontList; + while(current_font) + { + next_font = current_font->NextFont; + MFdelete(current_font); + current_font = next_font; + } + FontList = NULL; + } + + if (DontBotherLoadingInSoftwareMode) + { + // + // Hey- no use loading this texture if we ain't gonna use it! + // + + return D3D_OK; + } + + // + // Always fail in software mode! + // + +#if 0 + if (!the_display.CurrDevice->d3dHalDesc.dcmColorModel) + { + // + // We are in software. + // + + return DDERR_GENERIC; + } +#endif + + switch(Type) + { + case D3DTEXTURE_TYPE_8: +#ifdef TARGET_DC + // No support for paletted textures, thanks. + ASSERT ( FALSE ); +#else + ans = Reload_8(); +#endif + break; + + case D3DTEXTURE_TYPE_TGA: + ans = Reload_TGA(); + break; + + case D3DTEXTURE_TYPE_USER: + ans = Reload_user(); + break; + + default: + ASSERT(0); + break; + } + + return ans; +} + + + +//--------------------------------------------------------------- + +HRESULT D3DTexture::Destroy(void) +{ + int a = 0, b = 0, c = 0, d = 0; + + + Font *current_font, + *next_font; + + + // Get rid of fonts. + if(IsFont()) + { + current_font = FontList; + while(current_font) + { + next_font = current_font->NextFont; + MFdelete(current_font); + current_font = next_font; + } + FontList = NULL; + } + + // Release texture. + if(lp_Texture) + { + DebugText("Releasing texture\n"); + a = lp_Texture->Release(); + DebugText("Done\n"); + lp_Texture = NULL; + } + +#ifndef TARGET_DC + // Release palette. + if(lp_Palette) + { + DebugText("Releasing palette\n"); + b = lp_Palette->Release(); + DebugText("Done\n"); + lp_Palette = NULL; + } +#endif + + // Release surface. + if(lp_Surface) + { + DebugText("Releasing surface\n"); + c = lp_Surface->Release(); + DebugText("Done\n"); + lp_Surface = NULL; + } + +//#define I_LIKE_TO_ASSERT 1 + +#ifdef I_LIKE_TO_ASSERT + ASSERT(a == 0 && b == 0 && c == 0 && d == 0); +#endif + +// TextureHandle = NULL; + + return DD_OK; +} + +//--------------------------------------------------------------- + +#define MATCH_TGA_PIXELS(p1,p2) ((p1)->red==(p2)->red&&(p1)->green==(p2)->green&&(p1)->blue==(p2)->blue) + +BOOL scan_for_baseline(TGA_Pixel **line_ptr,TGA_Pixel *underline,TGA_Info *info,SLONG *y_ptr) +{ + while(*y_ptrheight) + { + if(MATCH_TGA_PIXELS(*line_ptr,underline)) + { + // Got the baseline so drop to the next line. + *y_ptr += 1; + *line_ptr += info->width; + return TRUE; + } + + *y_ptr += 1; + *line_ptr += info->width; + } + return FALSE; +} + +//--------------------------------------------------------------- + +HRESULT D3DTexture::CreateFonts(TGA_Info *tga_info,TGA_Pixel *tga_data) +{ + SLONG current_char, + char_x,char_y, + char_height,char_width, + tallest_char; + Font *the_font; + TGA_Pixel underline, + *current_line, + *current_pixel; + + + // Scan down the image looking for the underline. + underline.red = 0xff; + underline.green = 0x00; + underline.blue = 0xff; + current_line = tga_data; + char_y = 0; + if(scan_for_baseline(¤t_line,&underline,tga_info,&char_y)) + { +map_font: + // Found a font baseline so map it. + the_font = MFnew(); + if(FontList) + { + the_font->NextFont = FontList; + FontList = the_font; + } + else + { + the_font->NextFont = NULL; + FontList = the_font; + } + + current_char = 0; + char_x = 0; + tallest_char = 1; + + while(current_char<93) + { + // Scan across to find the width of char. + char_width = 0; + current_pixel = current_line+char_x; + while(!MATCH_TGA_PIXELS(current_pixel,&underline)) + { + current_pixel++; + char_width++; + + // Reached the end of the line. + if(char_x+char_width>=tga_info->width) + { + // Find the next baseline. + char_y += tallest_char+1; + if(char_y>=tga_info->height) + return DDERR_GENERIC; + current_line = tga_data+(char_y*tga_info->width); + + if(!scan_for_baseline(¤t_line,&underline,tga_info,&char_y)) + return DDERR_GENERIC; + + char_x = 0; + tallest_char = 1; + char_width = 0; + current_pixel = current_line; + } + } + + // Now scan down to find the height of the char + char_height = 0; + current_pixel = current_line+char_x; + while(!MATCH_TGA_PIXELS(current_pixel,&underline)) + { + current_pixel += tga_info->width; + char_height++; + + // Reached the bottom of the page. + if(char_height>=tga_info->height) + return DDERR_GENERIC; + } + + the_font->CharSet[current_char].X = char_x; + the_font->CharSet[current_char].Y = char_y; + the_font->CharSet[current_char].Width = char_width; + the_font->CharSet[current_char].Height = char_height; + + char_x += char_width+1; + if(tallest_char=tga_info->height) + return DDERR_GENERIC; + current_line = tga_data+(char_y*tga_info->width); + + if(scan_for_baseline(¤t_line,&underline,tga_info,&char_y)) + goto map_font; + } + + return DD_OK; +} + +//--------------------------------------------------------------- + +Font *D3DTexture::GetFont(SLONG id) +{ + Font *current_font; + + + current_font = FontList; + while(id && current_font) + { + current_font = current_font->NextFont; + id--; + } + return current_font; +} + +//--------------------------------------------------------------- + + +void D3DTexture::set_greyscale(BOOL is_greyscale) +{ + if (is_greyscale != GreyScale) + { + GreyScale = is_greyscale; + + if (Type != D3DTEXTURE_TYPE_UNUSED) + { + Reload(); + } + } +} + + + + + diff --git a/fallen/DDLibrary/Source/DCLowLevel.cpp b/fallen/DDLibrary/Source/DCLowLevel.cpp new file mode 100644 index 0000000..15436ab --- /dev/null +++ b/fallen/DDLibrary/Source/DCLowLevel.cpp @@ -0,0 +1,2710 @@ +// ======================================================== +// +// THIS IS RIPPED FROM THE DC EXAMPLE CODE +// +// ======================================================== + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Copyright (c) 1996, 1997 Microsoft Corporation + +Module Name: + + DSUtil.cpp + +Abstract: + + Contains routines for handling sounds from resources + +-------------------------------------------------------------------*/ + + +#include +#include +#include "MFStdLib.h" +#include +#include +#ifdef TARGET_DC +#include + +// On DC, it's called "pows" for some reason ("s" = "single"?) +#define powf pows + +#endif + +// ++++ Global Variables ++++++++++++++++++++++++++++++++++++++++++++ +LPDIRECTSOUND g_pds = NULL; // The DirectSound object +LPDIRECTSOUND3DLISTENER g_pds3dl = NULL; +LPDIRECTSOUNDBUFFER g_pdsbPrimary = NULL; + +HRESULT g_errLast; + +#define CheckError(anything) (FALSE) + + +#ifdef TARGET_DC +// Stream Yamaha ADPCM, not normal PCM. +#define STREAMING_BUFFER_IS_ADPCM defined + +// Pants hack for the ADPCM buffer. +//#define CRAPPY_STREAMING_ADPCM_HACK defined +#endif + + +//extern HWND g_hwndApp; + +extern volatile HWND hDDLibWindow; + + +bool m_bSoundHasActuallyStartedPlaying = FALSE; + +#define DCLL_OUTPUT_STEREO_WAVS + +#ifdef DCLL_OUTPUT_STEREO_WAVS +FILE *DCLL_handle; +#endif + + +#ifdef DEBUG +#define SHARON TRACE +//#define SHARON sizeof +#else +#define SHARON sizeof +#endif + + + +inline DWORD ReadNonalignedDword ( void *addr ) +{ + DWORD res; + unsigned char *myaddr = (unsigned char *)addr; + + res = ( ( *myaddr++ ) & 0xff ); + res |= ( ( *myaddr++ ) & 0xff ) << 8; + res |= ( ( *myaddr++ ) & 0xff ) << 16; + res |= ( ( *myaddr++ ) & 0xff ) << 24; + + return ( res ); +} + +inline WORD ReadNonalignedWord ( void *addr ) +{ + WORD res; + char *myaddr = (char *)addr; + + res = ( ( *myaddr++ ) & 0xff ); + res |= ( ( *myaddr++ ) & 0xff ) << 8; + + return ( res ); +} + + + +void *DwordMemcpy ( void *pvDst, const void *pvSrc, size_t dwSize ) +{ + + //TRACE ( "DwordMemcpy arrived with 0x%x, 0x%x, 0x%x\n", pvDst, pvSrc, dwSize ); + + if ( ( (DWORD)pvSrc & 0x3 ) == 0 ) + { + // Source is DWORD-aligned. + const DWORD *pdwSrc = (DWORD *)pvSrc; + DWORD *pdwDst = (DWORD *)pvDst; + ASSERT ( ( (DWORD)pdwSrc & 0x3 ) == 0 ); + ASSERT ( ( (DWORD)pdwDst & 0x3 ) == 0 ); + ASSERT ( ( dwSize & 0x3 ) == 0 ); + dwSize >>= 2; + while ( dwSize > 0 ) + { + *pdwDst++ = *pdwSrc++; + dwSize--; + } + } + else + { + +#ifdef DEBUG + // Check endianness + DWORD dwTest = 0x12345678; + ASSERT ( *(((char*)&dwTest)+0) == 0x78 ); + ASSERT ( *(((char*)&dwTest)+1) == 0x56 ); + ASSERT ( *(((char*)&dwTest)+2) == 0x34 ); + ASSERT ( *(((char*)&dwTest)+3) == 0x12 ); +#endif + + // Source is not dword aligned! + const unsigned char *pdwSrc = (unsigned char *)pvSrc; + DWORD *pdwDst = (DWORD *)pvDst; + //ASSERT ( ( (DWORD)pdwSrc & 0x3 ) == 0 ); + ASSERT ( ( (DWORD)pdwDst & 0x3 ) == 0 ); + ASSERT ( ( dwSize & 0x3 ) == 0 ); + dwSize >>= 2; + while ( dwSize > 0 ) + { + DWORD dwTemp = (DWORD)*pdwSrc++; + dwTemp |= ( (DWORD)(*pdwSrc++) ) << 8; + dwTemp |= ( (DWORD)(*pdwSrc++) ) << 16; + dwTemp |= ( (DWORD)(*pdwSrc++) ) << 24; + *pdwDst++ = dwTemp; + dwSize--; + } + } + return pvDst; +} + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Function: + + InitDirectSound + +Description: + + Initialize the DirectSound object + +Arguments: + + None + +Return Value: + + TRUE on success, FALSE on failure. + +-------------------------------------------------------------------*/ +BOOL +InitDirectSound() +{ + // Create the DirectSound object + g_errLast = DirectSoundCreate(NULL, &g_pds, NULL); + + if (CheckError(TEXT("DirectSoundCreate"))) + return FALSE; + + // Set the DirectSound cooperative level + if (g_pds->SetCooperativeLevel(hDDLibWindow, DSSCL_NORMAL) != DS_OK) + { + ASSERT(0); + } + + return TRUE; +} + + +BOOL +InitDirectSound3D() +{ + DSBUFFERDESC dsbd; + + // Create the primary sound buffer (needed for the listener interface) + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D; + g_errLast = g_pds->CreateSoundBuffer(&dsbd, &g_pdsbPrimary, NULL); + if (CheckError(TEXT("Create SoundBuffer"))) + return FALSE; + + // Get a pointer to the IDirectSound3DListener interface + g_errLast = g_pdsbPrimary->QueryInterface(IID_IDirectSound3DListener, (void **)&g_pds3dl); + if (CheckError(TEXT("QueryInterface for IDirectSound3DListener interface"))) + return FALSE; + + // + // How many metres in an UC block? 256 => 2 metres? + // + + g_pds3dl->SetDistanceFactor(0.25F / 256.0F, DS3D_IMMEDIATE); + + // We no longer need the primary buffer, just the Listener interface + // g_pdsbPrimary->Release(); + + // Set the doppler factor to the maximum, so we can more easily notice it + // g_errLast = g_pds3dl->SetDopplerFactor(DS3D_MAXDOPPLERFACTOR, DS3D_IMMEDIATE); + + // + // Set the primary buffer playing all the time to avoid nasty clicks... + // + + g_pdsbPrimary->Play(0,0,0); + + return TRUE; +} + + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Function: + + ParseWaveFile + +Description: + + Get the Wave File header, size, and data pointer... + +Arguments: + + void *pvWaveFile - Pointer to the wav file to parse + + WAVEFORMATEX **ppWaveHeader - Fill this with pointer to wave header + + BYTE **ppbWaveData - Fill this with pointer to wave data + + DWORD **pcbWaveSize - Fill this with wave data size. + +Return Value: + + TRUE on success, FALSE on failure. + +-------------------------------------------------------------------*/ +BOOL +ParseWaveFile(void *pvWaveFile, 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 *)pvWaveFile; + dwRiff = *pdw++; + dwLength = *pdw++; + dwType = *pdw++; + + // Check if it's a WAV format file + if (dwType != mmioFOURCC('W', 'A', 'V', 'E')) + { + ASSERT ( FALSE ); + return FALSE; + } + + // Check if it's a RIFF format file + if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F')) + { + ASSERT ( FALSE ); + return FALSE; + } + + pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4); + + while (pdw < pdwEnd) + { +#if 0 + dwType = *pdw++; + dwLength = *pdw++; +#else + dwType = ReadNonalignedDword ( pdw ); + pdw++; + dwLength = ReadNonalignedDword ( pdw ); + pdw++; +#endif + + switch (dwType) + { + case mmioFOURCC('f', 'm', 't', ' '): + if (ppWaveHeader && !*ppWaveHeader) + { + if (dwLength < sizeof(WAVEFORMAT)) + return FALSE; + + *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; + default: + ASSERT ( FALSE ); + return FALSE; + break; + } + + pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1)); + } + + return FALSE; +} + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Function: + + GetWaveResource + +Description: + + Load a WAV file from the executable's Resource file or the specified file. + +Arguments: + + LPCTSTR tszName - Name of the WAV file to load + + WAVEFORMATEX **ppWaveHeader - Fill this with pointer to wave header + + BYTE **ppbWaveData - Fill this with pointer to wave data + + DWORD **pcbWaveSize - Fill this with wave data size. + +Return Value: + + TRUE on success, FALSE on failure. + + NOTE! Return values of **ppWaveHeader, **ppbWaveData, **pcbWaveSize + are owned by this rout. Do not do anything permanent to them, coz + the memory blocks will be frazzed next time this is called. + +-------------------------------------------------------------------*/ + + +// For some bizarre reason, they keep failing every now and then. +#define USE_ALIGNED_LOADS 0 + +static DWORD dwSizeOfGWRBlock = 0; +static void *pvGWRBlock = NULL; + +BOOL +GetWaveResource(char *szName, WAVEFORMATEX **ppWaveHeader, + BYTE **ppbWaveData, DWORD *pcbWaveSize) +{ + //HRSRC hResInfo; + //HGLOBAL hResData; + //void *pvRes; + MFFileHandle hFile; + //static BYTE *rgbyFileTemp = NULL; + unsigned long cbRead; + DWORD dwSize; + + /* + + // Find the specifed WAV resource + hResInfo = FindResource(g_hinst, tszName, TEXT("WAV")); + if (hResInfo == NULL) + goto TryFile; + + // Load the Resource + hResData = LoadResource(g_hinst, hResInfo); + if (hResData == NULL) + goto TryFile; + + // Lock the Resource + pvRes = LockResource(hResData); + if (pvRes == NULL) + goto TryFile; + + // Read and parse the Resource + if (ParseWaveFile(pvRes, ppWaveHeader, ppbWaveData, pcbWaveSize) != NULL) + return TRUE; + + */ + +//TryFile: + +#ifdef TARGET_DC + // GDWorkshop converts any non-alphanumerics to "_" + char chTemp[128]; + char *pchSrc = szName; + char *pchDst = chTemp; + while ( TRUE ) + { + if ( ( ( *pchSrc >= 'a' ) && ( *pchSrc <= 'z' ) ) || + ( ( *pchSrc >= 'A' ) && ( *pchSrc <= 'Z' ) ) || + ( ( *pchSrc >= '0' ) && ( *pchSrc <= '9' ) ) || + ( *pchSrc == '.' ) || + ( *pchSrc == '\\' ) + ) + { + *pchDst++ = *pchSrc++; + } + else if ( *pchSrc == '\0' ) + { + *pchDst++ = '\0'; + break; + } + else + { + *pchDst++ = '_'; + pchSrc++; + } + } + + szName = chTemp; +#endif + + +#if 0 +#ifdef DEBUG + if ( 0 == stricmp ( szName, "data\\sfx\\1622dc\\heli.wav" ) ) + { + // Replace it for the mo. + szName = "data\\sfx\\1622dc\\helifucked64.wav"; + } + else if ( 0 == stricmp ( szName, "data\\sfx\\1622dc\\sfx080799_\\search2.wav" ) ) + { + // Replace it for the mo. + szName = "data\\sfx\\1622dc\\sfx080799_\\search2fucked32.wav"; + } +#endif +#endif + + + + + hFile = FileOpen ( szName ); + if ( hFile == FILE_OPEN_ERROR ) + { + TRACE ( "Failed to load sound %s\n", szName ); + return FALSE; + } + + dwSize = FileSize(hFile); + +#if !USE_ALIGNED_LOADS + // Free memory used in previous call. + if ( pvGWRBlock != NULL ) + { + MemFree ( pvGWRBlock ); + pvGWRBlock = NULL; + } + pvGWRBlock = (BYTE*) MemAlloc ( dwSize ); + if ( !pvGWRBlock ) + { + ASSERT ( FALSE ); + return FALSE; + } +#else + if ( dwSizeOfGWRBlock < dwSize ) + { + if ( pvGWRBlock != NULL ) + { + //MemFree ( pvGWRBlock ); + VirtualFree ( pvGWRBlock, NULL, MEM_RELEASE ); + } + // Grow slightly more than needed to prevent hammering. + dwSizeOfGWRBlock = ( dwSize * 5 / 4 + 10240 ); + // Ensure it's 4k-aligned. + dwSizeOfGWRBlock = ( ( dwSizeOfGWRBlock + 4095 ) & ~4095 ); + //pvGWRBlock = MemAlloc ( dwSizeOfGWRBlock ); + pvGWRBlock = VirtualAlloc ( NULL, dwSizeOfGWRBlock, MEM_COMMIT, PAGE_READWRITE ); + ASSERT ( pvGWRBlock != NULL ); + } + //rgbyFileTemp = (BYTE *)pvGWRBlock; + +#endif + +#if !USE_ALIGNED_LOADS + // Load in one go. + cbRead = FileRead ( hFile, pvGWRBlock, dwSize ); +#else + // Use DMA load, then finish the rest. + + int iAlignedFileSize = dwSize & ( ~4095 ); + // DMA read + if ( iAlignedFileSize > 0 ) + { + cbRead = FileRead ( hFile, pvGWRBlock, iAlignedFileSize ); + } + else + { + cbRead = 0; + } + // Finish off with PIO or whatever. + if ( dwSize - iAlignedFileSize > 0 ) + { + cbRead += FileRead ( hFile, (void *)( (char *)pvGWRBlock + iAlignedFileSize ), dwSize - iAlignedFileSize ); + } +#endif + FileClose ( hFile ); + +#if 0 + + hFile = CreateFile(tszName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + dwSize = GetFileSize(hFile, NULL); + + pvGWRBlock = (BYTE*) MemAlloc(dwSize); + if (!pvGWRBlock) + return FALSE; + + ReadFile (hFile, pvGWRBlock, dwSize, &cbRead, NULL); + CloseHandle(hFile); + +#endif + + if (cbRead != dwSize) + { + ASSERT ( FALSE ); +#if !USE_ALIGNED_LOADS + //MemFree ( pvGWRBlock ); +#endif + return FALSE; + } + + if (ParseWaveFile(pvGWRBlock, ppWaveHeader, ppbWaveData, pcbWaveSize) == NULL) + { +#if !USE_ALIGNED_LOADS + //MemFree ( pvGWRBlock ); +#endif + return FALSE; + } + + + // This is NOT freed until next call, since it holds all the data that the pointer all point into. +#if !USE_ALIGNED_LOADS + //MemFree ( pvGWRBlock ); +#endif + + return TRUE; +} + + + +// Call this when a bunch of sounds have finished loading. +// Can be called whenever you like really. +void DCLL_ProbablyDoneMostOfMySoundLoadingForAWhile ( void ) +{ +#if !USE_ALIGNED_LOADS + if ( pvGWRBlock != NULL ) + { + MemFree ( pvGWRBlock ); + pvGWRBlock = NULL; + } +#else + if ( pvGWRBlock != NULL ) + { + //MemFree ( pvGWRBlock ); + VirtualFree ( pvGWRBlock, NULL, MEM_RELEASE ); + pvGWRBlock = NULL; + } +#endif +} + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Function: + + FillSoundBuffer + +Description: + + Copies the Sound data to the specified DirecSoundBuffer's data file + +Arguments: + + LPCTSTR tszName - Name of the WAV file to load + + WAVEFORMATEX **ppWaveHeader - Fill this with pointer to wave header + + BYTE **ppbWaveData - Fill this with pointer to wave data + + DWORD **pcbWaveSize - Fill this with wave data size. + +Return Value: + + TRUE on success, FALSE on failure. + +-------------------------------------------------------------------*/ +BOOL +FillSoundBuffer(IDirectSoundBuffer *pdsb, BYTE *pbWaveData, DWORD dwWaveSize) +{ + LPVOID pMem1, pMem2; + DWORD dwSize1, dwSize2; + + if (!pdsb || !pbWaveData || !dwWaveSize) + return FALSE; + + g_errLast = pdsb->Lock(0, dwWaveSize, &pMem1, &dwSize1, &pMem2, &dwSize2, 0); + + switch(g_errLast) + { + case DS_OK: + break; + + case DSERR_BUFFERLOST: OutputDebugString("DSERR_BUFFERLOST: \n"); break; + case DSERR_INVALIDCALL: OutputDebugString("DSERR_INVALIDCALL: \n"); break; + case DSERR_INVALIDPARAM: OutputDebugString("DSERR_INVALIDPARAM: \n"); break; + case DSERR_PRIOLEVELNEEDED: OutputDebugString("DSERR_PRIOLEVELNEEDED: \n"); break; + + default: + ASSERT(0); + break; + } + + if (CheckError(TEXT("Lock SoundBuffer"))) + return FALSE; + + +// Have you learned nothing of what I have taught you, young Adami? +#if 0 + memcpy(pMem1, pbWaveData, dwSize1); + + if (dwSize2 != 0) + memcpy(pMem2, pbWaveData+dwSize1, dwSize2); +#else + //TRACE ( "DwordMemcpy called with 0x%x, 0x%x, 0x%x\n", pMem1, pbWaveData, dwSize1 ); + DwordMemcpy(pMem1, pbWaveData, dwSize1); + + if (dwSize2 != 0) + { + //TRACE ( "DwordMemcpy called with 0x%x, 0x%x, 0x%x\n", pMem2, pbWaveData+dwSize1, dwSize2 ); + DwordMemcpy(pMem2, pbWaveData+dwSize1, dwSize2); + } + +#endif + + pdsb->Unlock(pMem1, dwSize1, pMem2, dwSize2); + + return TRUE; +} + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Function: + + LoadSoundBuffer + +Description: + + Creates a DirectSoundBuffer and loads the specified file into it. + +Arguments: + + LPCTSTR tszName - Name of the WAV file to load + +Return Value: + + TRUE on success, FALSE on failure. + +-------------------------------------------------------------------*/ + +SLONG DCLL_bytes_of_sound_memory_used = 0; + +#ifdef DEBUG +DWORD dwTotalSampleSize = 0; +#endif + +IDirectSoundBuffer * +LoadSoundBuffer(char *szName, SLONG is_3d) +{ + IDirectSoundBuffer *pdsb = NULL; + DSBUFFERDESC dsbd = {0}; + BYTE *pbWaveData; + + DCLL_bytes_of_sound_memory_used = 0; + + + +#if 0 + // Just testing. + return NULL; +#else + + + + if (GetWaveResource(szName, &dsbd.lpwfxFormat, &pbWaveData, &dsbd.dwBufferBytes)) + { + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2; + + #ifdef DCLL_OUTPUT_STEREO_WAVS + + if (dsbd.lpwfxFormat->nChannels == 2) + { + // + // This is a stereo sample. + // + + fprintf(DCLL_handle, szName); + fprintf(DCLL_handle, "\r\n"); + + fflush(DCLL_handle); + } + + #endif + + if (is_3d) + { + //dsbd.dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE; + } + +#ifdef TARGET_DC + // Do a compact, just in case we got fragmentation, though it's unlikely. + HRESULT hres = g_pds->Compact(); + ASSERT ( SUCCEEDED ( hres ) ); +#endif + + pdsb = NULL; + +#ifdef DEBUG + // See if we're out of memory or not. + DSCAPS dscaps; + ZeroMemory ( &dscaps, sizeof(dscaps) ); + dscaps.dwSize = sizeof(dscaps); + g_pds->GetCaps ( &dscaps ); + if ( dscaps.dwMaxContigFreeHwMemBytes < 0x8000 ) + { + SHARON ( "Running very low on sound memory - 0x%x bytes left.\n", dscaps.dwMaxContigFreeHwMemBytes ); + // And don't bother to load it. + goto yuk_didnt_like_that_sound; + } + + if ( dsbd.dwBufferBytes > 0x8000 ) + { + SHARON ( "Tried to load <%s> more than 32k in length - bad person!\n", szName ); + goto yuk_didnt_like_that_sound; + } +#endif + + if (SUCCEEDED(g_pds->CreateSoundBuffer(&dsbd, &pdsb, NULL))) + { + if (!FillSoundBuffer(pdsb, pbWaveData, dsbd.dwBufferBytes)) + { + pdsb->Release(); + pdsb = NULL; + } + + DCLL_bytes_of_sound_memory_used = dsbd.dwBufferBytes; + + + #ifdef TARGET_DC + + DSBCAPS dsbcaps; + ZeroMemory ( (void *)&dsbcaps, sizeof ( dsbcaps ) ); + dsbcaps.dwSize = sizeof ( dsbcaps ); + pdsb->GetCaps ( &dsbcaps ); + + if ( dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE ) + { + //SHARON ( "Hardware buffer 0x%x bytes, %i CPU overhead\n", dsbcaps.dwBufferBytes, dsbcaps.dwPlayCpuOverhead ); + // Make sure this is the right length. + if ( ( dsbd.dwBufferBytes & 31 ) != 0 ) + { + TRACE ( "Hardware buffer wasn't a multiple of 32 bytes in length - don't loop it! %i \n", (dsbd.dwBufferBytes & 31) ); + } + if ( dsbd.dwBufferBytes > 16383 ) + { + TRACE ( "Hardware buffer more than 32k samples - don't loop it! %i \n", (dsbd.dwBufferBytes) ); + } + } + else + { + SHARON ( "Software buffer <%s>, 0x%x bytes, %iHz\n", szName, dsbcaps.dwBufferBytes, dsbd.lpwfxFormat->nSamplesPerSec ); + SHARON ( "Binning it for now.\n" ); + ASSERT ( FALSE ); + pdsb->Release(); + pdsb = NULL; + } + +#if 0 +#ifdef DEBUG + + CBYTE *words_for_11khz[] = + { + "Suspension", + "Scrape", + "Balrog", + "Footstep", + "PAIN", + "TAUNT", + "darci\\", + "roper\\" + "bthug1\\", + "wthug1\\", + "wthug2\\", + "cop\\COP", + "misc\\", + "Barrel", + "Ambience", + "CarX", + "!" + }; + + // Shall we chop these down even more? + bool bChopIt = FALSE; + for (int j = 0; words_for_11khz[j][0] != '!'; j++) + { + if (strstr(szName, words_for_11khz[j])) + { + bChopIt = TRUE; + break; + } + } + + + if ( bChopIt ) + { + // Chop it down to 8kHz. + dwTotalSampleSize += ( dsbcaps.dwBufferBytes * 8000 / dsbd.lpwfxFormat->nSamplesPerSec ); + } + else if ( dsbd.lpwfxFormat->nSamplesPerSec > 11100 ) + { + // Pretend you halved the sample rate. + dwTotalSampleSize += dsbcaps.dwBufferBytes / 2; + } + else + { + dwTotalSampleSize += dsbcaps.dwBufferBytes; + } + SHARON ( "Total desired sample memory 0x%x\n", dwTotalSampleSize ); +#endif +#endif + + #endif + + } + else + { + pdsb = NULL; + } +yuk_didnt_like_that_sound:; + } + +#endif + + return pdsb; +} + + +IDirectSoundBuffer *CreateStreamingSoundBuffer(int nSamplesPerSec, WORD wBitsPerSample, DWORD dwBufferSize) +{ + IDirectSoundBuffer *pdsb = NULL; + DSBUFFERDESC dsbd = {0}; + WAVEFORMATEX waveformatex = {0}; + +#ifdef STREAMING_BUFFER_IS_ADPCM + // Set up the Wave format description for Yamaha ADPCM + waveformatex.wFormatTag = 0x0020; + waveformatex.nChannels = 1; + waveformatex.nSamplesPerSec = 22050; + waveformatex.wBitsPerSample = 4; + waveformatex.nBlockAlign = (waveformatex.nChannels * waveformatex.wBitsPerSample) / 8; + waveformatex.nAvgBytesPerSec = waveformatex.nSamplesPerSec * waveformatex.nBlockAlign; + waveformatex.cbSize = 0; + dsbd.dwSize = sizeof(dsbd); + dsbd.dwBufferBytes = dwBufferSize; + dsbd.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY;// | DSBCAPS_LOCSOFTWARE; + dsbd.lpwfxFormat = &waveformatex; +#else + // Set up the Wave format description + waveformatex.wFormatTag = WAVE_FORMAT_PCM; + waveformatex.nChannels = 1; + waveformatex.nSamplesPerSec = nSamplesPerSec; + waveformatex.wBitsPerSample = wBitsPerSample; + waveformatex.nBlockAlign = (waveformatex.nChannels * waveformatex.wBitsPerSample) / 8; + waveformatex.nAvgBytesPerSec = waveformatex.nSamplesPerSec * waveformatex.nBlockAlign; + waveformatex.cbSize = 0; + dsbd.dwSize = sizeof(dsbd); + dsbd.dwBufferBytes = dwBufferSize; + dsbd.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY;// | DSBCAPS_LOCSOFTWARE; + dsbd.lpwfxFormat = &waveformatex; +#endif + + g_errLast = g_pds->CreateSoundBuffer(&dsbd, &pdsb, NULL); + if (CheckError(TEXT("Create DirectSound Buffer"))) + return NULL; + + return pdsb; +} + + + + + + + + + + + + + + + + + + + + +// ======================================================== +// +// FROM HERE ONWARDS IT'S MY CODE! +// +// ======================================================== + +#include "dclowlevel.h" + + +typedef struct dcll_sound +{ + SLONG used; + IDirectSoundBuffer *dsb; + IDirectSound3DBuffer *dsb_3d; + +} DCLL_Sound; + +#define DCLL_MAX_SOUNDS 1024 + +DCLL_Sound DCLL_sound[DCLL_MAX_SOUNDS]; + + + + + + +// +// Nasty streaming stuff... +// + +// How many bytes to do at a time. +#define DCLL_GRANULARITY 256 + +#ifdef STREAMING_BUFFER_IS_ADPCM + +// We need a much smaller buffer for 1 second's worth. +#define DCLL_STREAM_BUFFER_SIZE ( DCLL_GRANULARITY * 64 ) + +#else +//#define DCLL_STREAM_BUFFER_SIZE (22050 * sizeof(UWORD) * 1) // Number of bytes for 1 seconds of 22khz 16-bit mono sound +#define DCLL_STREAM_BUFFER_SIZE ( DCLL_GRANULARITY * 128 ) +#endif + + +#define DCLL_STREAM_COMMAND_NOTHING 0 +#define DCLL_STREAM_COMMAND_START_NEW_SOUND 1 + +SLONG DCLL_stream_loop; +SLONG DCLL_stream_command; +CBYTE DCLL_stream_new_fname[MAX_PATH]; +SLONG DCLL_stream_data_offset; +SLONG DCLL_stream_silence_count; + +IDirectSoundBuffer *DCLL_stream_dsb; +MFFileHandle DCLL_stream_file_handle; // The file handle of what we are streaming... +HANDLE DCLL_stream_event; +HANDLE DCLL_stream_thread; // Streaming sound thread +float DCLL_stream_volume_range = 1.0F; + + +// Used for buffering streaming reads. +char pcDCLL_stream_buffer[DCLL_GRANULARITY]; + + +void DCLL_stream_set_volume_range(float max_vol) +{ + SATURATE(max_vol, 0.0F, 1.0F); + + //DCLL_stream_volume_range = max_vol; + + DCLL_stream_volume(max_vol); + +} + + +#ifdef DEBUG + +#define NUM_TRACIES 16 +#define MAX_LENGTH_TRACIE 100 + + +char pcTracieString[NUM_TRACIES][MAX_LENGTH_TRACIE]; +int m_iDumpedTracieNum = 0; +int m_iTracieNum = 0; + + +void Tracie ( char *fmt, ... ) +{ + va_list va; + va_start ( va, fmt ); + vsprintf ( pcTracieString[m_iTracieNum++], fmt, va ); + if ( m_iTracieNum >= NUM_TRACIES ) + { + m_iTracieNum = 0; + } + va_end ( va ); +} + + +void DumpTracies ( void ) +{ + while ( m_iDumpedTracieNum != m_iTracieNum ) + { + TRACE ( pcTracieString[m_iDumpedTracieNum] ); + m_iDumpedTracieNum++; + if ( m_iDumpedTracieNum >= NUM_TRACIES ) + { + m_iDumpedTracieNum = 0; + } + } +} + + +// A sort of pseudo-trace thingie for threads. +// Use it like TRACIE(("thing %i\n", iThing )); +#define TRACIE(arg) Tracie arg; + + +#else + +#define TRACIE sizeof + +#endif + + + + +// Set this to 0 for new-fangled goodness on the DC. +#define OLD_STYLE_THING_THAT_DIDNT_WORK_VERY_WELL 0 + + + +// +// The thread that handles streaming. +// + +DWORD DCLL_stream_process(int nUnused) +{ + while(1) + { + WaitForSingleObject(DCLL_stream_event, INFINITE); + + // + // What's hapenned to our event? + // + +#if 0 + // Debugging - rip out this. + DCLL_stream_command = DCLL_STREAM_COMMAND_NOTHING; + if (DCLL_stream_file_handle != NULL) + { + // Close it. + FileClose ( DCLL_stream_file_handle ); + DCLL_stream_file_handle = NULL; + } +#else + + + switch(DCLL_stream_command) + { + case DCLL_STREAM_COMMAND_NOTHING: + + { + DWORD write_pos; + SLONG start; + + // + // Find out which bit of the buffer we should overwrite. + // + + DWORD dummy; +#ifdef TARGET_DC + // We need to find the write position. +#if OLD_STYLE_THING_THAT_DIDNT_WORK_VERY_WELL + DCLL_stream_dsb->GetCurrentPosition(&dummy, &write_pos); +#else + DCLL_stream_dsb->GetCurrentPosition(&write_pos, &dummy); +#endif +#else + // Different on the PC. + DCLL_stream_dsb->GetCurrentPosition(&write_pos, &dummy); +#endif + + + + // Very occasionally, the read position is just before the end of the buffer, which causes this to fall over. + // So add a little something to tweak it. +#if OLD_STYLE_THING_THAT_DIDNT_WORK_VERY_WELL + if ( write_pos >= ( DCLL_STREAM_BUFFER_SIZE / 2 ) ) +#else + +#define SOUND_POS_TWEAK_FACTOR 64 + if ( ( write_pos >= ( ( DCLL_STREAM_BUFFER_SIZE / 2 ) - SOUND_POS_TWEAK_FACTOR ) ) && + ( write_pos < ( ( DCLL_STREAM_BUFFER_SIZE ) - SOUND_POS_TWEAK_FACTOR ) ) ) +#endif + { + // + // Overwrite the first half. + // + + start = 0; + TRACIE (( "Write pos 0x%x - overwriting first half\n", write_pos )); + } + else + { + // + // Overwrite the second half. + // + + start = DCLL_STREAM_BUFFER_SIZE / 2; + TRACIE (( "Write pos 0x%x - overwriting second half\n", write_pos )); + } + + if (DCLL_stream_file_handle == NULL) + { + // + // No more sound data, so fill the sound buffer + // with silence. + // + + DCLL_stream_silence_count += 1; + + if (DCLL_stream_silence_count >= 2) + { + // + // We can safely stop the sound from playing. + // + + DCLL_stream_silence_count = 0; + + DCLL_stream_dsb->Stop(); + + break; + } + } + + UBYTE *block1_mem = NULL; + UBYTE *block2_mem = NULL; + DWORD block1_length; + DWORD block2_length; + +#ifdef TARGET_DC +#if OLD_STYLE_THING_THAT_DIDNT_WORK_VERY_WELL + DCLL_stream_dsb->Lock(start, DCLL_STREAM_BUFFER_SIZE / 2, (void **) &block1_mem, &block1_length, (void **) &block2_mem, &block2_length, DSBLOCK_FROMWRITECURSOR ); +#else + DCLL_stream_dsb->Lock(start, DCLL_STREAM_BUFFER_SIZE / 2, (void **) &block1_mem, &block1_length, (void **) &block2_mem, &block2_length, 0 ); +#endif +#else + DCLL_stream_dsb->Lock(start, DCLL_STREAM_BUFFER_SIZE / 2, (void **) &block1_mem, &block1_length, (void **) &block2_mem, &block2_length, 0 ); +#endif + + + + if ( block1_mem == NULL ) + { + // NADS! Has happened though. Which is pretty damn scary. + ASSERT ( FALSE ); + TRACE (( "Eek - the Lock just failed for the sound\n." )); + } + else + { + + if (DCLL_stream_file_handle == NULL) + { + // + // Silence... + // + + // Can't use memset - must use DWORD writes. + //memset(block1_mem, 0, block1_length); + DWORD *dst1 = (DWORD *)block1_mem; + DWORD count = block1_length; + + #ifdef TARGET_DC + + ASSERT ( ( (DWORD)dst1 & 3 ) == 0 ); + ASSERT ( ( count & 3 ) == 0 ); + + #endif + + count >>= 2; + while ( (count--) > 0 ) + { + *dst1++ = 0; + } + } + else + { + DWORD bytes_read; + + // + // Read sound data from the file. + // + + #ifdef TARGET_DC + // The version that streams in 256 byte chunks. + ASSERT ( ( block1_length & (DCLL_GRANULARITY-1) ) == 0 ); + DWORD dwBytesToWrite = block1_length; + UBYTE *pbBlockMem = block1_mem; + while ( dwBytesToWrite > 0 ) + { + if ( DCLL_stream_file_handle != NULL ) + { + bytes_read = FileRead ( DCLL_stream_file_handle, pcDCLL_stream_buffer, DCLL_GRANULARITY ); + if ( bytes_read < DCLL_GRANULARITY ) + { + if ( DCLL_stream_loop ) + { + // Start from the beginning again. + FileSeek(DCLL_stream_file_handle, SEEK_MODE_BEGINNING, DCLL_stream_data_offset); + DWORD new_bytes_read = FileRead ( DCLL_stream_file_handle, pcDCLL_stream_buffer + bytes_read, DCLL_GRANULARITY - bytes_read ); + ASSERT ( new_bytes_read == ( DCLL_GRANULARITY - bytes_read ) ); + } + else + { + // Need to pad with silence. + memset ( pcDCLL_stream_buffer + bytes_read, 0, DCLL_GRANULARITY - bytes_read ); + FileClose ( DCLL_stream_file_handle ); + DCLL_stream_file_handle = NULL; + } + } + } + else + { + bytes_read = 0; + memset ( pcDCLL_stream_buffer, 0, DCLL_GRANULARITY ); + } + + // And copy the buffer in. MUST BE IN DWORDS. + DWORD *pdwSrc = (DWORD*)pcDCLL_stream_buffer; + DWORD *pdwDst = (DWORD*)pbBlockMem; + for ( int i = 0; i < ( DCLL_GRANULARITY / 4 ); i++ ) + { + *pdwDst++ = *pdwSrc++; + } + dwBytesToWrite -= DCLL_GRANULARITY; + pbBlockMem += DCLL_GRANULARITY; + } + #else + + + + #if 0 + ReadFile( + DCLL_stream_file_handle, + block1_mem, + block1_length, + &bytes_read, + NULL); + #else + bytes_read = FileRead ( DCLL_stream_file_handle, block1_mem, block1_length ); + #endif + + if (bytes_read < block1_length) + { + if (DCLL_stream_loop) + { + // + // Go back to the beginning of the data section of the file and + // start looping again. + // + + FileSeek(DCLL_stream_file_handle, SEEK_MODE_BEGINNING, DCLL_stream_data_offset); + // SetFilePointer(DCLL_stream_file_handle, DCLL_stream_data_offset, NULL, FILE_BEGIN); + + FileRead(DCLL_stream_file_handle, block1_mem + bytes_read, block1_length - bytes_read); + } + else + { + // + // Fill the remainder of the buffer with silence and close the file. + // + + // Can't use memset - must be DWORD writes. + //memset(block1_mem + bytes_read, 0, block1_length - bytes_read); + DWORD *dst1 = (DWORD *)( block1_mem + bytes_read ); + DWORD count = block1_length - bytes_read; + + #ifdef TARGET_DC + + ASSERT ( ( (DWORD)dst1 & 3 ) == 0 ); + ASSERT ( ( count & 3 ) == 0 ); + + #endif + + count >>= 2; + while ( (count--) > 0 ) + { + *dst1++ = 0; + } + + #if 0 + CloseHandle(DCLL_stream_file_handle); + #else + FileClose ( DCLL_stream_file_handle ); + #endif + + DCLL_stream_file_handle = NULL; + } + } +#endif + } + + /* + + memset(block1_mem, 0, block1_length); + + if (start) + { + SLONG i; + + for (i = 0; i < block1_length; i++) + { + block1_mem[i] = rand(); + } + } + + */ + + #ifdef TARGET_DC + // This has started falling over on the PC. But I don't care. + ASSERT(block2_mem == NULL); + #endif + + DCLL_stream_dsb->Unlock(block1_mem, block1_length, block2_mem, block2_length); + } + } + + break; + + case DCLL_STREAM_COMMAND_START_NEW_SOUND: + + { + DWORD status = 0; + + DCLL_stream_dsb->GetStatus(&status); + + if (status & (DSBSTATUS_LOOPING|DSBSTATUS_PLAYING)) + { + // + // If the buffer is playing, then we close + // the current file handle and stop the sound playing. + // + + if (DCLL_stream_file_handle) + { + FileClose(DCLL_stream_file_handle); + + DCLL_stream_file_handle = NULL; + DCLL_stream_silence_count = 0; + } + + DCLL_stream_dsb->Stop(); + } + + { + BYTE temp[256]; + ULONG bytes_read; + DWORD size; + WAVEFORMATEX *pwfx; + BYTE *data_start; + + // + // Open the sound file. + // + +#ifdef CRAPPY_STREAMING_ADPCM_HACK + // Always load this + if ( strstr ( DCLL_stream_new_fname, "FrontLoop" ) ) + { + strcpy ( DCLL_stream_new_fname, "Data\\sfx\\1622DC\\GeneralMusic\\FrontLoopMONOAD.wav" ); + } + else + { + strcpy ( DCLL_stream_new_fname, "Data\\sfx\\1622DC\\whoryou.wav" ); + } +#endif + + +#if 0 + DCLL_stream_file_handle = CreateFile(DCLL_stream_new_fname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (DCLL_stream_file_handle == NULL) +#else + DCLL_stream_file_handle = FileOpen ( DCLL_stream_new_fname ); + if (DCLL_stream_file_handle == FILE_OPEN_ERROR ) +#endif + { + DCLL_stream_file_handle = NULL; + bytes_read = 0; + } + else + { + // + // Read the first 256 bytes to get file header + // + +#if 0 + ReadFile(DCLL_stream_file_handle, temp, 256, &bytes_read, NULL); +#else + bytes_read = FileRead ( DCLL_stream_file_handle, temp, 256 ); +#endif + } + + if (bytes_read != 256) + { + DCLL_stream_file_handle = NULL; + + DCLL_stream_dsb->Stop(); + } + else + { + // + // Parse the header information to get to the sound data. + // + + ParseWaveFile((void *) temp, &pwfx, &data_start, &size); + + // + // Set file pointer to point to start of data + // + + DCLL_stream_data_offset = (SLONG) (data_start - temp); +#if 0 + SetFilePointer(DCLL_stream_file_handle, DCLL_stream_data_offset, NULL, FILE_BEGIN); +#else + FileSeek ( DCLL_stream_file_handle, SEEK_MODE_BEGINNING, (int) (data_start - temp) ); +#endif + + // + // Fill up the sound buffer with the data. + // + + UBYTE *block1_mem = NULL; + UBYTE *block2_mem = NULL; + DWORD block1_length; + DWORD block2_length; + + DCLL_stream_dsb->Lock(0, 0, (void **) &block1_mem, &block1_length, (void **) &block2_mem, &block2_length, DSBLOCK_ENTIREBUFFER); + + if (block1_mem) + { + DWORD bytes_read; + + // + // Read sound data from the file. + // + +#ifndef TARGET_DC + +#if 0 + ReadFile( + DCLL_stream_file_handle, + block1_mem, + block1_length, + &bytes_read, + NULL); +#else + bytes_read = FileRead ( DCLL_stream_file_handle, block1_mem, block1_length ); +#endif + + if (bytes_read < block1_length) + { + // + // Fill the remainder of the buffer with silence and close the file. + // + + // Can't use memset - must use DWORD writes. + //memset(block1_mem + bytes_read, 0, block1_length - bytes_read); + DWORD *dst1 = (DWORD *)( block1_mem + bytes_read ); + DWORD count = block1_length - bytes_read; + ASSERT ( ( (DWORD)dst1 & 3 ) == 0 ); + ASSERT ( ( count & 3 ) == 0 ); + count >>= 2; + while ( (count--) > 0 ) + { + *dst1++ = 0; + } + +#if 0 + CloseHandle(DCLL_stream_file_handle); +#else + FileClose ( DCLL_stream_file_handle ); +#endif + DCLL_stream_file_handle = NULL; + } + +#else +// The version that streams in 256 byte chunks. + ASSERT ( ( block1_length & (DCLL_GRANULARITY-1) ) == 0 ); + DWORD dwBytesToWrite = block1_length; + UBYTE *pbBlockMem = block1_mem; + while ( dwBytesToWrite > 0 ) + { + if ( DCLL_stream_file_handle != NULL ) + { + bytes_read = FileRead ( DCLL_stream_file_handle, pcDCLL_stream_buffer, DCLL_GRANULARITY ); + if ( bytes_read < DCLL_GRANULARITY ) + { + // Need to pad with silence. + memset ( pcDCLL_stream_buffer + bytes_read, 0, DCLL_GRANULARITY - bytes_read ); + FileClose ( DCLL_stream_file_handle ); + DCLL_stream_file_handle = NULL; + } + } + else + { + bytes_read = 0; + memset ( pcDCLL_stream_buffer, 0, DCLL_GRANULARITY ); + } + + // And copy the buffer in. MUST BE IN DWORDS. + DWORD *pdwSrc = (DWORD*)pcDCLL_stream_buffer; + DWORD *pdwDst = (DWORD*)pbBlockMem; + for ( int i = 0; i < ( DCLL_GRANULARITY / 4 ); i++ ) + { + *pdwDst++ = *pdwSrc++; + } + dwBytesToWrite -= DCLL_GRANULARITY; + pbBlockMem += DCLL_GRANULARITY; + } +#endif + + } + + DCLL_stream_dsb->Unlock(block1_mem, block1_length, block2_mem, block2_length); + + ASSERT(block2_mem == NULL); + + // + // Start the buffer playing. + // + + DCLL_stream_dsb->SetCurrentPosition(0); + DCLL_stream_dsb->Play(0, 0, DSBPLAY_LOOPING); + } + } + } + + DCLL_stream_command = DCLL_STREAM_COMMAND_NOTHING; + + break; + + default: + ASSERT(0); + break; + } + + + +#endif + + } + + return 0; + +} + +void DCLL_stream_init(void) +{ + DWORD thread_id; + + // + // Create the event that we use to communicate with + // the streaming thread. + // + + DCLL_stream_event = CreateEvent(NULL, FALSE, FALSE, NULL); + + // + // Create the streaming buffer... + // + + DCLL_stream_dsb = CreateStreamingSoundBuffer(22050, 16, DCLL_STREAM_BUFFER_SIZE); + + // + // Spawn off the new thread. + // + + DCLL_stream_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DCLL_stream_process, NULL, 0, &thread_id); + ASSERT(DCLL_stream_thread); +#ifdef TARGET_DC + SetThreadPriority ( DCLL_stream_thread, THREAD_PRIORITY_HIGHEST ); +#endif + + // + // Setup notifications... + // + + IDirectSoundNotify *pdsn; + DSBPOSITIONNOTIFY rgdsbpn[2]; + + /* + + IDirectSoundBuffer_QueryInterface( + DCLL_stream_dsb, + IID_IDirectSoundNotify, + (void **)&pdsn); + + */ + + DCLL_stream_dsb->QueryInterface(IID_IDirectSoundNotify, (void **)&pdsn); + + rgdsbpn[0].hEventNotify = DCLL_stream_event; + rgdsbpn[1].hEventNotify = DCLL_stream_event; + rgdsbpn[0].dwOffset = DCLL_STREAM_BUFFER_SIZE / 2; + rgdsbpn[1].dwOffset = DCLL_STREAM_BUFFER_SIZE - 2; + + pdsn->SetNotificationPositions(2, rgdsbpn); + + // + // No longer need the DirectSoundNotify interface, so release it + // + + pdsn->Release(); +} + +SLONG DCLL_stream_play(CBYTE *fname, SLONG loop) +{ + if (DCLL_stream_command != DCLL_STREAM_COMMAND_NOTHING) + { + // + // Waiting to play another sample. + // + + if (loop && !DCLL_stream_loop) + { + return FALSE; + } + } + + // + // The command to the thread. + // + + DCLL_stream_loop = loop; + DCLL_stream_command = DCLL_STREAM_COMMAND_START_NEW_SOUND; + +#ifdef TARGET_DC + // Some filenames begin with ".\" which confuses the poor DC + if ( ( fname[0] == '.' ) && ( fname[1] == '\\' ) ) + { + fname += 2; + } +#endif + + // Some missions have empty briefing names. + if ( fname[0] == '\0' ) + { + return FALSE; + } + + +#ifndef TARGET_DC + strcpy(DCLL_stream_new_fname, fname); +#else + // Some filename have more than one '.', which GDWorkshop converts to an underline. + // They are all of the format blah.ucmfoobar.wav, which changes to + // blah.ucmfoobar_wav + char *pcSrc = fname; + char *pcDst = DCLL_stream_new_fname; + bool bFoundFullStop = FALSE; + while ( *pcSrc != '\0' ) + { + *pcDst = *pcSrc++; + if ( *pcDst == '.' ) + { + if ( bFoundFullStop ) + { + *pcDst = '_'; + } + else + { + bFoundFullStop = TRUE; + } + } + pcDst++; + } + *pcDst = '\0'; + + +#if 0 +// No longer needed - everything is ADPCM. +#ifdef STREAMING_BUFFER_IS_ADPCM + // If the file ends in MONO, add a further AD to it. + int iTemp = strlen ( DCLL_stream_new_fname ); + if ( ( DCLL_stream_new_fname[iTemp-8] == 'M' ) && + ( DCLL_stream_new_fname[iTemp-7] == 'O' ) && + ( DCLL_stream_new_fname[iTemp-6] == 'N' ) && + ( DCLL_stream_new_fname[iTemp-5] == 'O' ) ) + { + strcpy ( &(DCLL_stream_new_fname[iTemp-4]), "AD.wav" ); + } +#endif +#endif + + +#endif + + // + // Wake up the process. + // + + SetEvent(DCLL_stream_event); + + return TRUE; +} + + +void DCLL_stream_stop() +{ + +#ifndef TARGET_DC + // This rout is buggered on the PC. + return; +#endif + + // + // Make sure a sound doesn't sneakily start playing... + // + + DCLL_stream_command = DCLL_STREAM_COMMAND_NOTHING; + + DCLL_stream_dsb->Stop(); + + // + // Close the streaming file and stop the buffer from playing. + // + + if (DCLL_stream_file_handle) + { +#if 0 + CloseHandle(DCLL_stream_file_handle); +#else + FileClose ( DCLL_stream_file_handle ); +#endif + + DCLL_stream_file_handle = NULL; + DCLL_stream_silence_count = 0; + } + + while(1) + { + ULONG status; + HRESULT res; + + res = DCLL_stream_dsb->GetStatus(&status); + + ASSERT(res == DS_OK); + + if ((status & DSBSTATUS_PLAYING) || + (status & DSBSTATUS_LOOPING)) + { + Sleep(10); + + DCLL_stream_dsb->Stop(); + } + else + { + return; + } + } +} + +SLONG DCLL_stream_is_playing() +{ + ULONG status; + HRESULT res; + + if (DCLL_stream_command == DCLL_STREAM_COMMAND_START_NEW_SOUND) + { + return TRUE; + } + + res = DCLL_stream_dsb->GetStatus(&status); + + ASSERT(res == DS_OK); + + if ((status & DSBSTATUS_PLAYING) || + (status & DSBSTATUS_LOOPING)) + { + return TRUE; + } + else + { + return FALSE; + } +} + + +// Returns TRUE if the stream has actually started playing, +// i.e. the disk has seeked, etc. +bool DCLL_stream_has_started_streaming ( void ) +{ + ULONG status; + HRESULT res; + + res = DCLL_stream_dsb->GetStatus(&status); + + ASSERT(res == DS_OK); + + if ((status & DSBSTATUS_PLAYING) || + (status & DSBSTATUS_LOOPING)) + { + return TRUE; + } + else + { + return FALSE; + } +} + + + +void DCLL_stream_wait() +{ + while(1) + { + if (DCLL_stream_is_playing()) + { + Sleep(10); + } + else + { + return; + } + } +} + +void DCLL_stream_volume(float volume) +{ + if (DCLL_stream_dsb == NULL) + { + return; + } + + SATURATE(volume, 0.0F, 1.0F); + + // Done elsewhere. + //volume *= DCLL_stream_volume_range; + + volume = powf( volume, 0.1F); + + SLONG ivolume = SLONG(DSBVOLUME_MIN + (DSBVOLUME_MAX - DSBVOLUME_MIN) * volume); + + DCLL_stream_dsb->SetVolume(ivolume); +} + + + + + + + +void DCLL_memstream_init(); + + +void DCLL_init() +{ + InitDirectSound(); + InitDirectSound3D(); + + memset(DCLL_sound, 0, sizeof(DCLL_sound)); + + DCLL_stream_init(); + DCLL_memstream_init(); + + #ifdef DCLL_OUTPUT_STEREO_WAVS + + DCLL_handle = fopen("t:\\stereowavs.txt", "wb"); + + #endif +} + + + + + +DCLL_Sound *DCLL_load_sound(CBYTE *fname) +{ + SLONG i; + + DCLL_Sound *ds; + + for (i = 0; i < DCLL_MAX_SOUNDS; i++) + { + ds = &DCLL_sound[i]; + + if (!ds->used) + { + goto found_unused_sound; + } + } + + // + // No more sounds left! + // + + ASSERT(0); + + return NULL; + +found_unused_sound:; + + ds->used = TRUE; + + ds->dsb = LoadSoundBuffer(fname, TRUE); + + if (!ds->dsb) + { + ds->used = FALSE; + + return NULL; + } + + ASSERT(ds->dsb); + + (ds->dsb)->QueryInterface(IID_IDirectSound3DBuffer, (void **) &ds->dsb_3d); + + return ds; +} + + +void DCLL_set_volume(DCLL_Sound *ds, float volume) +{ + if (ds == NULL) + { + return; + } + + SATURATE(volume, 0.0F, 1.0F); + + volume = powf(volume, 0.1F); + + SLONG ivolume = SLONG(DSBVOLUME_MIN + (DSBVOLUME_MAX - DSBVOLUME_MIN) * volume); + + HRESULT hres = ds->dsb->SetVolume(ivolume); + + //TRACE ( "Vol %i\n", ivolume ); + +} + +SLONG DCLL_still_playing(DCLL_Sound *ds) +{ + ULONG status; + if(ds==NULL) + return(0); + if(ds->dsb==NULL) + return(0); + + ds->dsb->GetStatus(&status); + if ((status & DSBSTATUS_PLAYING) || (status & DSBSTATUS_LOOPING)) + { + return(1); + } + else + return(0); + + +} + + +void DCLL_2d_play_sound(DCLL_Sound *ds, SLONG flag) +{ + if (ds == NULL) + { + return; + } + + ULONG status; + + ASSERT ( ds->dsb != NULL ); + if ( ds->dsb_3d != NULL ) + { + ds->dsb_3d->SetMode(DS3DMODE_DISABLE, DS3D_IMMEDIATE); + } + + ds->dsb->GetStatus(&status); + + if ((status & DSBSTATUS_PLAYING) || + (status & DSBSTATUS_LOOPING)) + { + if (flag & DCLL_FLAG_INTERRUPT) + { + ds->dsb->SetCurrentPosition(0); + } + } + else + { + switch(ds->dsb->Play(0, 0, (flag & DCLL_FLAG_LOOP) ? DSBPLAY_LOOPING : 0)) + { + case DS_OK: + break; + + case DSERR_PRIOLEVELNEEDED: + ASSERT(0); + break; + + default: + ASSERT(0); + break; + } + } +} + +float DCLL_3d_listener_x; +float DCLL_3d_listener_y; +float DCLL_3d_listener_z; + + + +void DCLL_3d_play_sound(DCLL_Sound *ds, float x, float y, float z, SLONG flag) +{ + if (ds == NULL) + { + return; + } + + ASSERT(ds->dsb); + ASSERT(ds->dsb_3d); + + ds->dsb_3d->SetMode(DS3DMODE_NORMAL, DS3D_IMMEDIATE); + + // + // Start playing- or restart if it's already playing. + // + + ULONG status; + + ds->dsb->GetStatus(&status); + + if ((status & DSBSTATUS_PLAYING) || + (status & DSBSTATUS_LOOPING)) + { + if (flag & DCLL_FLAG_INTERRUPT) + { + ds->dsb->SetCurrentPosition(0); + } + } + else + { + ds->dsb->Play(0,0,(flag & DCLL_FLAG_LOOP) ? DSBPLAY_LOOPING : 0); + } + + // + // Set position. + // + + ds->dsb_3d->SetPosition(x,y,z, DS3D_IMMEDIATE); +} + + +void DCLL_3d_set_listener( + float x, + float y, + float z, + float matrix[9]) +{ + DCLL_3d_listener_x = x; + DCLL_3d_listener_y = y; + DCLL_3d_listener_z = z; + + if (!g_pds3dl) + { + return; + } + + g_pds3dl->SetPosition(x, y, z, DS3D_DEFERRED); + + g_pds3dl->SetOrientation( + matrix[6], + matrix[7], + matrix[8], + matrix[3], + matrix[4], + matrix[5], + DS3D_DEFERRED); + + g_pds3dl->CommitDeferredSettings(); +} + + +void DCLL_stop_sound(DCLL_Sound *ds) +{ + if (ds == NULL) + { + return; + } + + ds->dsb->Stop(); +} + + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(arg) if ( (arg) != NULL ) { (arg)->Release(); (arg) = NULL; } +#endif + + +void DCLL_free_sound(DCLL_Sound *ds) +{ + if (ds == NULL || !ds->used) + { + return; + } + + SAFE_RELEASE ( ds->dsb_3d ); + SAFE_RELEASE ( ds->dsb ); + ds->used = FALSE; +} + + +void DCLL_fini(void) +{ + SLONG i; + + DCLL_Sound *ds; + + for (i = 0; i < DCLL_MAX_SOUNDS; i++) + { + ds = &DCLL_sound[i]; + + if (ds->used) + { + DCLL_free_sound(ds); + } + } + + // + // Release objects... + // + + g_pds3dl->Release(); + g_pdsbPrimary->Release(); + g_pds->Release(); + +} + + + + + + + +void init_my_dialog(HWND h) +{ +} + +void my_dialogs_over(HWND h) +{ +} + +void MilesTerm(void) +{ +} + + + + + + + + + + + + +#ifndef TARGET_DC + +#include "sound_id.h" + +// +// Does the DC conversion of looping samples. +// + +void DCLL_looping_sample_conversion(void) +{ + SLONG i; + + SLONG looping_sample[] = + { + S_SLIDE_START, + S_SEARCH_END, + S_ZIPWIRE, + S_TROPICAL, + S_RAIN_START, + S_AMBIENCE_END, + S_AMB_POLICE1, + S_AMB_POSHEETA, + S_AMB_OFFICE1, + S_TUNE_CLUB_START, + S_RECKONING_LOOP, + S_HELI, + S_TUNE_CLUB, + S_ACIEEED, + S_FRONT_END_LOOP_EDIT, + S_FIRE_HYDRANT, + S_FIRE, + S_CAR_SIREN1, + S_CARX_CRUISE, + S_CARX_IDLE, + S_CAR_REVERSE_LOOP, + -12345 + }; + + CreateDirectory("t:\\SillyDCwavs", NULL); + + // + // Moves all these files to to the directory on t:\ + // + + FILE *handle = fopen("t:\\SillyDCwavs\\dcconv.bat", "wb"); + + if (!handle) + { + return; + } + + fprintf(handle, "mkdir converted\r\n\r\n"); + + CBYTE src[256]; + CBYTE dst[256]; + CBYTE jst[256]; + + CBYTE *ch; + + for (i = 0; looping_sample[i] >= 0; i++) + { + sprintf(src, "data\\sfx\\1622\\%s", sound_list[looping_sample[i]]); + + for (ch = src; *ch; ch++); + while(*ch != '\\') ch--; + ch++; + + strcpy(jst, ch); + + sprintf(dst, "t:\\sillyDCwavs\\%s", jst); + + CopyFile(src, dst, FALSE); + + // + // Mention this filename in the batch file. + // + + fprintf(handle, "wavcon %s converted\\%s\r\n", jst, jst); + fprintf(handle, "copy %s n:\\urbanchaos\\thegame\\data\\sfx\\1622DC\\%s /Y\r\n", jst, jst); + fprintf(handle, "copy converted\\%s n:\\urbanchaos\\thegame\\data\\sfx\\1622DC\\%s /Y\r\n", jst, jst); + fprintf(handle, "\r\n"); + } + + fclose(handle); +} + +#endif + + + + + +// ======================================================== +// +// STREAMING FILES FROM MEMORY +// +// ======================================================== + +// +// The sound to stream. +// + +UBYTE *DCLL_memstream_sound; +SLONG DCLL_memstream_sound_length; // length in bytes +UBYTE *DCLL_memstream_sound_upto; // Where we have played upto. + + +#define DCLL_MEMSTREAM_BUFFER_SIZE (32768) + +IDirectSoundBuffer *DCLL_memstream_dsb; +HANDLE DCLL_memstream_event; +HANDLE DCLL_memstream_thread; // Streaming sound thread + + +// +// The thread that handles memstreaming. +// + +DWORD DCLL_memstream_process(void) +{ + while(1) + { + WaitForSingleObject(DCLL_memstream_event, INFINITE); + + +// Debugging - disable it. +#if 1 + + + + { + DWORD write_pos; + SLONG start; + + // + // Find out which bit of the buffer we should overwrite. + // + + DWORD dummy; + + #ifdef TARGET_DC + // We need to find the write position. +#if OLD_STYLE_THING_THAT_DIDNT_WORK_VERY_WELL + DCLL_memstream_dsb->GetCurrentPosition(&dummy, &write_pos); +#else + DCLL_memstream_dsb->GetCurrentPosition(&write_pos, &dummy); +#endif + #else + // Different on the PC. + DCLL_memstream_dsb->GetCurrentPosition(&write_pos, &dummy); + #endif + + + +#if OLD_STYLE_THING_THAT_DIDNT_WORK_VERY_WELL + if ( write_pos >= ( DCLL_STREAM_BUFFER_SIZE / 2 ) ) +#else + if ( ( write_pos >= ( ( DCLL_STREAM_BUFFER_SIZE / 2 ) - SOUND_POS_TWEAK_FACTOR ) ) && + ( write_pos < ( ( DCLL_STREAM_BUFFER_SIZE ) - SOUND_POS_TWEAK_FACTOR ) ) ) +#endif + { + // + // Overwrite the first half. + // + + start = 0; + TRACIE (( "Memstream: writing first half\n" )); + } + else + { + // + // Overwrite the second half. + // + + start = DCLL_MEMSTREAM_BUFFER_SIZE / 2; + TRACIE (( "Memstream: writing second half\n" )); + } + + if (DCLL_memstream_sound == NULL) + { + // + // No more sound data so stop the buffer! Something + // bad must be happening. + // + + DCLL_memstream_dsb->Stop(); + } + + UBYTE *block1_mem = NULL; + UBYTE *block2_mem = NULL; + DWORD block1_length = 0; + DWORD block2_length = 0; + +#if OLD_STYLE_THING_THAT_DIDNT_WORK_VERY_WELL + DCLL_memstream_dsb->Lock(start, DCLL_MEMSTREAM_BUFFER_SIZE / 2, (void **) &block1_mem, &block1_length, (void **) &block2_mem, &block2_length, DSBLOCK_FROMWRITECURSOR); +#else + DCLL_memstream_dsb->Lock(start, DCLL_MEMSTREAM_BUFFER_SIZE / 2, (void **) &block1_mem, &block1_length, (void **) &block2_mem, &block2_length, 0); +#endif + + + // + // Fill the buffer with data. + // + + SLONG i; + SLONG count = block1_length >> 2; + SLONG *dst = (SLONG *) block1_mem; + SLONG *src = (SLONG *) DCLL_memstream_sound_upto; + SLONG *end = (SLONG *) (DCLL_memstream_sound + DCLL_memstream_sound_length); + + #ifdef TARGET_DC + + ASSERT((SLONG(dst) & 3) == 0); + ASSERT((count & 3) == 0); + + #endif + + for (i = count; i > 0; i--) + { + *dst++ = *src++; + + if (src >= end) + { + src = (SLONG *) DCLL_memstream_sound; + } + } + + DCLL_memstream_sound_upto = (UBYTE *) src; + + DCLL_memstream_dsb->Unlock(block1_mem, block1_length, block2_mem, block2_length); + } + + +#endif + + + } + + // Doesn't ever exit, but the DC compiler + // complains that it doesn't return a value. + return 0; +} + + + +void DCLL_memstream_init() +{ + DWORD thread_id; + + // + // Create the event that we use to communicate with the + // memstream thread. + // + + DCLL_memstream_event = CreateEvent(NULL, FALSE, FALSE, NULL); + + // + // Create the memstream buffer. + // + + DCLL_memstream_dsb = CreateStreamingSoundBuffer(22050, 16, DCLL_MEMSTREAM_BUFFER_SIZE); + + // + // Spawn off the new thread. + // + + DCLL_memstream_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DCLL_memstream_process, NULL, 0, &thread_id); + + ASSERT(DCLL_memstream_thread); + + #ifdef TARGET_DC + SetThreadPriority(DCLL_memstream_thread, THREAD_PRIORITY_HIGHEST); + #endif + + // + // Setup notifications... + // + + IDirectSoundNotify *pdsn; + DSBPOSITIONNOTIFY rgdsbpn[2]; + + DCLL_memstream_dsb->QueryInterface(IID_IDirectSoundNotify, (void **)&pdsn); + + rgdsbpn[0].hEventNotify = DCLL_memstream_event; + rgdsbpn[1].hEventNotify = DCLL_memstream_event; + rgdsbpn[0].dwOffset = DCLL_MEMSTREAM_BUFFER_SIZE / 2; + rgdsbpn[1].dwOffset = DCLL_MEMSTREAM_BUFFER_SIZE - 2; + + if (pdsn->SetNotificationPositions(2, rgdsbpn) != DS_OK) + { + // + // + // + + ASSERT(0); + } + + // + // No longer need the DirectSoundNotify interface, so release it + // + + pdsn->Release(); +} + +void DCLL_memstream_load(CBYTE *fname) +{ + BYTE temp[256]; + ULONG bytes_read; + DWORD size; + WAVEFORMATEX *pwfx; + BYTE *data_start; + MFFileHandle handle; + + // + // Stop the buffer. + // + + DCLL_memstream_dsb->Stop(); + + // + // Initialise the sound. + // + + DCLL_memstream_unload(); + + // + // Open the sound file. + // + + handle = FileOpen(fname); + + if (handle == FILE_OPEN_ERROR ) + { + ASSERT ( FALSE ); + return; + } + + // + // Read the first 256 bytes to get file header + // + + bytes_read = FileRead(handle, temp, 256); + + if (bytes_read != 256) + { + return; + } + + // + // Parse the header information to get to the sound data. + // + + ParseWaveFile((void *) temp, &pwfx, &data_start, &size); + + // + // Set file pointer to point to start of data + // + + FileSeek(handle, SEEK_MODE_BEGINNING, (int) (data_start - temp)); + + // + // Allocate the sound. + // + + DCLL_memstream_sound = (UBYTE *) MemAlloc(size); + DCLL_memstream_sound_length = size; + DCLL_memstream_sound_upto = DCLL_memstream_sound; + + ASSERT(DCLL_memstream_sound); + + // + // Load in the sound. + // + + bytes_read = FileRead(handle, DCLL_memstream_sound, DCLL_memstream_sound_length); + + ASSERT(bytes_read == (unsigned)DCLL_memstream_sound_length); + + // + // Lock the sound buffer. + // + + UBYTE *block1_mem = NULL; + UBYTE *block2_mem = NULL; + DWORD block1_length = 0; + DWORD block2_length = 0; + + DCLL_memstream_dsb->Lock(0, 0, (void **) &block1_mem, &block1_length, (void **) &block2_mem, &block2_length, DSBLOCK_ENTIREBUFFER); + + // + // Make sure what happens is what we expect. + // + + ASSERT(block2_mem == NULL); + ASSERT(block1_length == DCLL_MEMSTREAM_BUFFER_SIZE); + ASSERT(block2_length == 0); + + // + // Fill the buffer with data. + // + + SLONG i; + SLONG count = DCLL_MEMSTREAM_BUFFER_SIZE >> 2; + SLONG *dst = (SLONG *) block1_mem; + SLONG *src = (SLONG *) DCLL_memstream_sound; + SLONG *end = (SLONG *) (DCLL_memstream_sound + DCLL_memstream_sound_length); + + ASSERT((SLONG(dst) & 3) == 0); + ASSERT((count & 3) == 0); + + for (i = count; i > 0; i--) + { + *dst++ = *src++; + + if (src >= end) + { + src = (SLONG *) DCLL_memstream_sound; + } + } + + // + // Unlock the buffer. + // + + DCLL_memstream_dsb->Unlock(block1_mem, block1_length, block2_mem, block2_length); + + + FileClose(handle); + +} + +void DCLL_memstream_volume(float volume) +{ + if (DCLL_memstream_dsb == NULL) + { + return; + } + + SATURATE(volume, 0.0F, 1.0F); + + volume = powf( volume, 0.1F); + + SLONG ivolume = SLONG(DSBVOLUME_MIN + (DSBVOLUME_MAX - DSBVOLUME_MIN) * volume); + + DCLL_memstream_dsb->SetVolume(ivolume); +} + + +void DCLL_memstream_play() +{ + // + // Start the buffer playing. + // + + ASSERT(DCLL_memstream_sound); + +#if 0 + // Don't reset it! It's so short, and if you reset it, + // it sounds a bit crappy. Just start playing it again from the + // current position. + DCLL_memstream_dsb->SetCurrentPosition(0); +#endif + DCLL_memstream_dsb->Play(0, 0, DSBPLAY_LOOPING); + + DCLL_memstream_volume(DCLL_stream_volume_range * 0.5F); +} + +void DCLL_memstream_stop() +{ + // + // Stop the sound. + // + + DCLL_memstream_dsb->Stop(); +} + +void DCLL_memstream_unload() +{ + Sleep(100); // Give the streaming thread enough time to finish what it's doing! + + if (DCLL_memstream_sound) + { + MemFree(DCLL_memstream_sound); + } + + DCLL_memstream_sound = NULL; + DCLL_memstream_sound_length = 0; + DCLL_memstream_sound_upto = NULL; +} + diff --git a/fallen/DDLibrary/Source/DDManager.cpp b/fallen/DDLibrary/Source/DDManager.cpp new file mode 100644 index 0000000..8a70699 --- /dev/null +++ b/fallen/DDLibrary/Source/DDManager.cpp @@ -0,0 +1,2511 @@ +// DDManager.cpp +// Guy Simmons, 12th November 1997. + +#ifdef TARGET_DC +#define INITGUID +#endif + +#include "DDLib.h" +#include "c:\fallen\headers\env.h" +#include "c:\fallen\headers\game.h" +#include +#ifdef TARGET_DC +#include "target.h" +#endif + + +DDDriverManager the_manager; + +//--------------------------------------------------------------- +// +// Callback functions. +// +//--------------------------------------------------------------- + +BOOL WINAPI DriverEnumCallback ( + GUID FAR *lpGuid, + LPTSTR lpDesc, + LPTSTR lpName, + LPVOID lpExtra + ) +{ + CallbackInfo *the_info; + DDDriverInfo *new_driver; + HRESULT result; + + + if(!lpExtra) + { + // Programming error, invalid pointer + return DDENUMRET_OK; + } + + the_info = (CallbackInfo*)lpExtra; + + // Get Pointer to driver info + new_driver = MFnew(); + if(!new_driver) + { + // Error, Not enough memory to create driver + return DDENUMRET_OK; + } + + // Setup the driver. + result = new_driver->Create(lpGuid,lpName,lpDesc); + if(FAILED(result)) + { + // Error, Driver setup failed + return DDENUMRET_OK; + } + + // Add To Global Driver List + result = the_manager.AddDriver(new_driver); + if(FAILED(result)) + { + // Error, Driver Create Failed + return DDENUMRET_OK; + } + + // Increment driver count + the_info->Count++; + + // Success + return DDENUMRET_OK; +} + +//--------------------------------------------------------------- + +HRESULT WINAPI ModeEnumCallback ( + LPDDSURFACEDESC2 lpDDSurfDesc, + LPVOID lpExtra + ) +{ + CallbackInfo *the_info; + DDDriverInfo *the_driver; + DDModeInfo *new_mode; + HRESULT result; + + + if(!lpExtra) + { + return DDENUMRET_OK; + } + + the_info = (CallbackInfo*)lpExtra; + the_driver = (DDDriverInfo*)the_info->Extra; + + if(!the_driver) + { + return DDENUMRET_OK; + } + + if(!lpDDSurfDesc) + { + return DDENUMRET_CANCEL; + } + + // Double check structure size + ASSERT(lpDDSurfDesc->dwSize == sizeof(*lpDDSurfDesc)); + + // Create Mode node + new_mode = MFnew(); + if(!new_mode) + { + // Error, not enough memory to store mode info + return DDENUMRET_OK; + } + + // Copy surface description + new_mode->ddSurfDesc = *lpDDSurfDesc; + + // Add Mode to Driver Mode List + result = the_driver->AddMode(new_mode); + if(FAILED(result)) + { + return DDENUMRET_OK; + } + + // Update mode count + the_info->Count++; + + return DDENUMRET_OK; +} + +//--------------------------------------------------------------- + +HRESULT WINAPI DeviceEnumCallback ( + LPGUID lpGuid, + LPTSTR lpName, + LPTSTR lpDesc, + LPD3DDEVICEDESC lpHalDevice, + LPD3DDEVICEDESC lpHelDevice, + LPVOID lpExtra + ) +{ + CallbackInfo *the_info; + D3DDeviceInfo *new_device; + DDDriverInfo *the_driver; + HRESULT result; + + if(!lpExtra) + { + // Programming error, invalid pointer + return DDENUMRET_OK; + } + + the_info = (CallbackInfo*)lpExtra; + the_driver = (DDDriverInfo*)the_info->Extra; + + if(!the_driver) + { + // Programming Error, invalid pointer + return DDENUMRET_OK; + } + + // Create D3D Device node + new_device = MFnew(); + if(!new_device) + { + // Not Enough memory to create D3D device node + return DDENUMRET_OK; + } + + // Initialize D3D Device info + result = new_device->Create(lpGuid,lpName,lpDesc,lpHalDevice,lpHelDevice); + if(FAILED(result)) + { + // Error + return DDENUMRET_OK; + } + + // If this is a hardware device then set the drivers hardware pointer. + if(new_device->IsHardware()) + { + the_driver->hardware_guid = *lpGuid; + + if (lpHalDevice->dwDeviceRenderBitDepth & DDBD_16) {the_driver->DriverFlags |= DD_DRIVER_RENDERS_TO_16BIT;} + if (lpHalDevice->dwDeviceRenderBitDepth & DDBD_32) {the_driver->DriverFlags |= DD_DRIVER_RENDERS_TO_32BIT;} + } + + // Add to Driver D3D Device list + result = the_driver->AddDevice(new_device); + if(FAILED(result)) + { + // Error + return DDENUMRET_OK; + } + + // Update D3D device Driver count + the_info->Count++; + + return DDENUMRET_OK; +} + +//--------------------------------------------------------------- + +HRESULT WINAPI TextureFormatEnumCallback ( + LPDDPIXELFORMAT lpTextureFormat, + LPVOID lpExtra + ) +{ + CallbackInfo *the_info; + D3DDeviceInfo *the_device; + DDModeInfo *new_format; + HRESULT result; + + + if(!lpExtra) + { + // Programming error, invalid pointer + return DDENUMRET_OK; + } + + the_info = (CallbackInfo*)lpExtra; + the_device = (D3DDeviceInfo*)the_info->Extra; + + if(!the_device) + { + // Programming error, invalid pointer + return DDENUMRET_OK; + } + + if(!lpTextureFormat) + { + // Error, invalid pointer + return DDENUMRET_CANCEL; + } + + // Double check structure size + ASSERT(lpTextureFormat->dwSize == sizeof(*lpTextureFormat)); + + // Create format node + new_format = MFnew(); + if(!new_format) + { + // Error, not enough memory to store format info + return DDENUMRET_OK; + } + + // Copy texture format description + InitStruct(new_format->ddSurfDesc); + + new_format->ddSurfDesc.dwFlags = DDSD_PIXELFORMAT; + new_format->ddSurfDesc.ddpfPixelFormat = *lpTextureFormat; + + // Add format to D3D device format list + result = the_device->AddFormat(new_format); + if(FAILED(result)) + { + // Error, not enough memory to store mode info + MFdelete(new_format); + return DDENUMRET_OK; + } + + // Update format count + the_info->Count++; + + return DDENUMRET_OK; +} + +//--------------------------------------------------------------- + +#ifndef TARGET_DC +HRESULT WINAPI ZFormatEnumCallback(LPDDPIXELFORMAT lpZFormat, LPVOID lpExtra) +{ + CallbackInfo *the_info; + D3DDeviceInfo *the_device; + DDModeInfo *new_format; + HRESULT result; + + if(!lpExtra) + { + // Programming error, invalid pointer + return DDENUMRET_OK; + } + + the_info = (CallbackInfo*)lpExtra; + the_device = (D3DDeviceInfo*)the_info->Extra; + + if(!the_device) + { + // Programming error, invalid pointer + return DDENUMRET_OK; + } + + if(!lpZFormat) + { + // Error, invalid pointer + return DDENUMRET_CANCEL; + } + + if (!the_info->Count) + { + // + // Just in case there is no 16-bit zbuffer... + // + + the_device->SetZFormat(lpZFormat); + } + + + // + // Every card has a 16-bit zbuffer! That is what we want... and no stencil buffer! + // + + if (lpZFormat->dwZBufferBitDepth == 16 && + lpZFormat->dwStencilBitDepth == 0) + { + the_device->SetZFormat(lpZFormat); + } + + /* + + if (!the_device->IsHardware() && (lpZFormat->dwZBufferBitDepth != 16)) + { + return DDENUMRET_OK; + } + + // Double check structure size + ASSERT(lpZFormat->dwSize == sizeof(*lpZFormat)); + + // tell device + if (!the_info->Count || (lpZFormat->dwZBufferBitDepth > the_device->GetZFormat()->dwZBufferBitDepth)) + { + the_device->SetZFormat(lpZFormat); + } + + */ + + // Update format count + the_info->Count++; + + return DDENUMRET_OK; +} +#endif + +//--------------------------------------------------------------- + +SLONG FlagsToBitDepth(SLONG flags) +{ + if(flags&DDBD_1) + return 1; + else if(flags&DDBD_2) + return 2L; + else if(flags&DDBD_4) + return 4L; + else if(flags&DDBD_8) + return 8L; + else if(flags&DDBD_16) + return 16L; + else if(flags&DDBD_24) + return 24L; + else if(flags&DDBD_32) + return 32L; + else + return 0L; +} + +ULONG FlagsToMask(SLONG flags) +{ + if (flags & DDBD_1) return 0x01; + if (flags & DDBD_2) return 0x03; + if (flags & DDBD_4) return 0x07; + if (flags & DDBD_8) return 0xFF; + if (flags & DDBD_16) return 0xFFFF; + if (flags & DDBD_24) return 0xFFFFFF; + if (flags & DDBD_32) return 0xFFFFFFFF; + + return 0; +} + +//--------------------------------------------------------------- + +SLONG BitDepthToFlags(SLONG 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 0; //ERROR. + } +} + +//--------------------------------------------------------------- + +BOOL IsPalettized(LPDDPIXELFORMAT lp_dd_pf) +{ + if(!lp_dd_pf) + { + // Error, + return FALSE; + } + + if(lp_dd_pf->dwFlags&DDPF_PALETTEINDEXED1) + return TRUE; + + if(lp_dd_pf->dwFlags&DDPF_PALETTEINDEXED2) + return TRUE; + + if(lp_dd_pf->dwFlags&DDPF_PALETTEINDEXED4) + return TRUE; + + if(lp_dd_pf->dwFlags&DDPF_PALETTEINDEXED8) + return TRUE; + + // Not palettized + return FALSE; +} + +//--------------------------------------------------------------- + +BOOL GetDesktopMode ( + DDDriverInfo *the_driver, + LPGUID D3D_guid, + DDModeInfo **the_mode, + D3DDeviceInfo **the_device + ) +{ + SLONG w,h,bpp; + HDC hdc; + HWND hDesktop; + DDModeInfo *new_mode; + D3DDeviceInfo *new_device, + *next_best_device; + + + // Check Parameters + if((!the_driver) || (!the_mode) || (!the_device)) + return FALSE; + + // Get Desktop Mode info + hDesktop = GetDesktopWindow(); + hdc = GetDC(hDesktop); + + w = GetDeviceCaps(hdc,HORZRES); + h = GetDeviceCaps(hdc,VERTRES); + bpp = GetDeviceCaps(hdc,PLANES) * GetDeviceCaps(hdc,BITSPIXEL); + + ReleaseDC(hDesktop,hdc); + + // Get Mode + new_mode = the_driver->FindMode(w,h,bpp,0,NULL); + if(!new_mode) + return FALSE; + + // Get Compatible Device + new_device = the_driver->FindDeviceSupportsMode(D3D_guid,new_mode,&next_best_device); + if(!new_device) + { + if(!next_best_device) + return FALSE; + new_device = next_best_device; + } + + // Save results + *the_mode = new_mode; + *the_device = new_device; + + // Success + return TRUE; +} + +//--------------------------------------------------------------- + +BOOL GetFullscreenMode ( + DDDriverInfo *the_driver, + GUID *D3D_guid, + SLONG w, + SLONG h, + SLONG bpp, + SLONG refresh, + DDModeInfo **the_mode, + D3DDeviceInfo **the_device + ) +{ + D3DDeviceInfo *new_device, + *next_best_device; + DDModeInfo *new_mode, + *next_best_mode; + + + // Check Parameters + if((!the_driver) || (!the_mode) || (!the_device)) + return FALSE; + + // Get D3D Device + new_device = the_driver->FindDevice(D3D_guid,&next_best_device); + if(!new_device) + { + if(!next_best_device) + return FALSE; + new_device = next_best_device; + } + + // Double check requested mode parameters + if((w==0) || (h==0) || (bpp==0)) + { + // Pick a reasonable full screen default + // Most Hardware devices support 16 bpp, + // many don't support 8 bpp, so pick 16 + w = DEFAULT_WIDTH; + h = DEFAULT_HEIGHT; + bpp = DEFAULT_DEPTH; + } + + // Get Compatible Mode + new_mode = the_driver->FindModeSupportsDevice(w,h,bpp,refresh,new_device,&next_best_mode); + if(!new_mode) + { + if(!next_best_mode) + return FALSE; + new_mode = next_best_mode; + } + + // Save results + *the_mode = new_mode; + *the_device = new_device; + + // Success + return TRUE; +} + +//--------------------------------------------------------------- +// +// Validate functions. +// +//--------------------------------------------------------------- + +DDDriverInfo *ValidateDriver(GUID *DD_guid) +{ + DDDriverInfo *new_driver, + *next_best_driver; + + + // Find Driver matching specified GUID + new_driver = the_manager.FindDriver(DD_guid, &next_best_driver); + if(new_driver) + { + // Exact match + return new_driver; + } + + // Return next best match (or failure) + return next_best_driver; +} + +//--------------------------------------------------------------- + +D3DDeviceInfo *ValidateDevice ( + DDDriverInfo *the_driver, + GUID *D3D_guid, + DDModeInfo *the_filter + ) +{ + D3DDeviceInfo *new_device, + *next_best_device; + + + // Check Parameters + if(!the_driver) + return FALSE; + + if(!the_filter) + { + new_device = the_driver->FindDevice(D3D_guid, &next_best_device); + } + else + { + // Filter device against mode + new_device = NULL; //the_driver->FindDeviceSupportsMode(D3D_guid, the_filter, &next_best_device); + } + + if(new_device) + { + // Exact match + return new_device; + } + + // Return next best match (or failure) + return next_best_device; +} + +//--------------------------------------------------------------- + +DDModeInfo *ValidateMode ( + DDDriverInfo *the_driver, + DWORD w, + DWORD h, + DWORD bpp, + DWORD refresh, + D3DDeviceInfo *the_filter + ) +{ + DDModeInfo *new_mode, + *next_best_mode; + + // Check Parameters + if(!the_driver) + return FALSE; + + if(!the_filter) + new_mode = the_driver->FindMode(w, h, bpp, refresh, &next_best_mode); + else + { + // Filter mode against D3D device compatiblity + new_mode = the_driver->FindModeSupportsDevice(w, h, bpp, refresh, the_filter, &next_best_mode); + } + + if(new_mode) + { + // Exact match + return new_mode; + } + + // Return next best match (or failure) + return next_best_mode; +} + +//--------------------------------------------------------------- +// +// CLASS : DDModeInfo +// +//--------------------------------------------------------------- + +DDModeInfo::DDModeInfo() +{ + InitStruct(ddSurfDesc); + Prev = NULL; + Next = NULL; +} + +DDModeInfo::DDModeInfo(const DDSURFACEDESC & ddDesc) +{ + CopyMemory(&ddSurfDesc,(const void *)&ddDesc,sizeof (ddSurfDesc)); + ASSERT(ddSurfDesc.dwSize == sizeof(ddSurfDesc)); + Prev = NULL; + Next = NULL; +} + +//--------------------------------------------------------------- + +DDModeInfo::~DDModeInfo() +{ + Prev = NULL; + Next = NULL; +} + +//--------------------------------------------------------------- + +SLONG DDModeInfo::GetWidth(void) +{ + ASSERT(ddSurfDesc.dwSize == sizeof(ddSurfDesc)); + + // Check that Pixel format is valid + if(!(ddSurfDesc.dwFlags & DDSD_WIDTH)) + return 0; + + // Get Bits Per Pixel + return ddSurfDesc.dwWidth; +} + +//--------------------------------------------------------------- + +SLONG DDModeInfo::GetHeight(void) +{ + ASSERT(ddSurfDesc.dwSize == sizeof(ddSurfDesc)); + + // Check that Pixel format is valid + if(!(ddSurfDesc.dwFlags & DDSD_HEIGHT)) + return 0L; + + // Get Bits Per Pixel + return ddSurfDesc.dwHeight; +} + +//--------------------------------------------------------------- + +SLONG DDModeInfo::GetBPP(void) +{ + ASSERT(ddSurfDesc.dwSize == sizeof(ddSurfDesc)); + ASSERT(ddSurfDesc.ddpfPixelFormat.dwSize == sizeof(ddSurfDesc.ddpfPixelFormat)); + + // Check that Pixel format is valid + if(!(ddSurfDesc.dwFlags & DDSD_PIXELFORMAT)) + return 0; + + // Assume it is RGB + return ddSurfDesc.ddpfPixelFormat.dwRGBBitCount; +} + +//--------------------------------------------------------------- + +HRESULT DDModeInfo::GetMode(SLONG *w,SLONG *h,SLONG *bpp,SLONG *refresh) +{ + ASSERT(ddSurfDesc.dwSize == sizeof(ddSurfDesc)); + ASSERT(ddSurfDesc.ddpfPixelFormat.dwSize == sizeof(ddSurfDesc.ddpfPixelFormat)); + + // Check that width is valid + if(!(ddSurfDesc.dwFlags & DDSD_WIDTH)) + return DDERR_GENERIC; + + // Check that height is valid + if(!(ddSurfDesc.dwFlags & DDSD_HEIGHT)) + return DDERR_GENERIC; + + // Check that Pixel format is valid + if(!(ddSurfDesc.dwFlags & DDSD_PIXELFORMAT)) + return DDERR_GENERIC; + + // Get Width, height, BPP + *w = (SLONG)ddSurfDesc.dwWidth; + *h = (SLONG)ddSurfDesc.dwHeight; + *bpp = (SLONG)ddSurfDesc.ddpfPixelFormat.dwRGBBitCount; + *refresh = 0L; + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +BOOL DDModeInfo::ModeSupported(D3DDeviceInfo *the_device) +{ + SLONG bpp, + depths, + depth_flags; + + + // Check Parameters + if(!the_device) + return FALSE; + + // Make sure D3D device supports this mode + bpp = GetBPP(); + depth_flags = BitDepthToFlags(bpp); + depths = 0; + + // Get Supported Bit Depths for this D3D device + if(the_device->IsHardware()) + depths = the_device->d3dHalDesc.dwDeviceRenderBitDepth; + else + depths = the_device->d3dHelDesc.dwDeviceRenderBitDepth; + + if(depths & depth_flags) + { + // Supported !!! + return TRUE; + } + + // Not Supported !!! + return FALSE; +} + +//--------------------------------------------------------------- + +BOOL DDModeInfo::Match(SLONG w,SLONG h,SLONG bpp) +{ + ASSERT(ddSurfDesc.dwSize == sizeof(ddSurfDesc)); + + // Check for width & height match. + if((ddSurfDesc.dwWidth==(DWORD)w) && (ddSurfDesc.dwHeight==(DWORD)h)) + { + // Check for bpp match. + if(ddSurfDesc.ddpfPixelFormat.dwRGBBitCount==(DWORD)bpp) + { + // Check for palettized mode. + if(bpp<=8 && !IsPalettized(&ddSurfDesc.ddpfPixelFormat)) + { + return FALSE; + } + + return TRUE; + } + } + + return FALSE; +} + +//--------------------------------------------------------------- + +BOOL DDModeInfo::Match(SLONG bpp) +{ + ASSERT(ddSurfDesc.dwSize == sizeof(ddSurfDesc)); + + // Check for bpp match. + if(ddSurfDesc.ddpfPixelFormat.dwRGBBitCount==(DWORD)bpp) + { + // Check for palettized mode. + if(bpp<=8 && !IsPalettized(&ddSurfDesc.ddpfPixelFormat)) + { + return FALSE; + } + + return TRUE; + } + + + return FALSE; +} + +//--------------------------------------------------------------- +// +// CLASS : D3DDeviceInfo +// +//--------------------------------------------------------------- + +D3DDeviceInfo::D3DDeviceInfo() +{ + D3DFlags = 0; + + szName = NULL; + szDesc = NULL; + + InitStruct(d3dHalDesc); + InitStruct(d3dHelDesc); + + FormatCount = 0; + FormatList = NULL; + FormatListEnd = NULL; + OpaqueTexFmt = NULL; + AlphaTexFmt = NULL; +#ifndef TARGET_DC + CanDoModulateAlpha = false; + CanDoDestInvSourceColour = false; +#endif + + Prev = NULL; + Next = NULL; + + memset(&ZFormat, 0, sizeof(ZFormat)); +} + +//--------------------------------------------------------------- + +D3DDeviceInfo::~D3DDeviceInfo() +{ + Destroy(); +} + +//--------------------------------------------------------------- + +HRESULT D3DDeviceInfo::Create ( + LPGUID lpD3DGuid, + LPTSTR lpD3DName, + LPTSTR lpD3DDesc, + LPD3DDEVICEDESC lpD3DHal, + LPD3DDEVICEDESC lpD3DHel + ) +{ + ULONG str_len, + str_size; + LPTSTR szTemp; + + + // Copy GUID + if(!lpD3DGuid) + return DDERR_INVALIDPARAMS; + guid = *lpD3DGuid; + + // Copy Name + if(!lpD3DName) + szTemp = TEXT("UNKNOWN"); + else + szTemp = lpD3DName; + + str_len = _tcslen(szTemp); + str_size= (str_len+1)*sizeof(TCHAR); + szName = (LPTSTR)MemAlloc(str_size); + if(szName) + _tcscpy(szName,szTemp); + + // Copy Description + if(!lpD3DDesc) + szTemp = TEXT("UNKNOWN"); + else + szTemp = lpD3DDesc; + + str_len = _tcslen(szTemp); + str_size= (str_len+1)*sizeof(TCHAR); + szDesc = (LPTSTR)MemAlloc(str_size); + if(szDesc) + _tcscpy(szDesc,szTemp); + + // Copy D3D info + if(lpD3DHal) + d3dHalDesc = *lpD3DHal; + + if (lpD3DHel) + d3dHelDesc = *lpD3DHel; + + // Mark Texture format list as not loaded + FormatCount = 0; + + // Mark as valid + ValidOn(); + + return DD_OK; +} + +//--------------------------------------------------------------- + +void D3DDeviceInfo::Destroy (void) +{ + // Destroy Texture Formats +// DestroyFormats(); + + // Clean up strings + if(szDesc) + { + MemFree(szDesc); + szDesc = NULL; + } + + if(szName) + { + MemFree(szName); + szName = NULL; + } + + Prev = NULL; + Next = NULL; +} + +//--------------------------------------------------------------- + +void D3DDeviceInfo::CheckCaps(LPDIRECT3DDEVICE3 the_device) +{ + D3DDEVICEDESC hw; + D3DDEVICEDESC sw; + HRESULT rc; + + InitStruct(hw); + InitStruct(sw); + + rc = the_device->GetCaps(&hw, &sw); + if (FAILED(rc)) return; + +#ifndef TARGET_DC + if (hw.dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATEALPHA) + { + CanDoModulateAlpha = true; + TRACE("Card can do MODULATEALPHA\n"); + } + else + { + CanDoModulateAlpha = false; + TRACE("Card *cannot* do MODULATEALPHA\n"); + } + + if (hw.dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_INVSRCCOLOR) + { + CanDoDestInvSourceColour = true; + TRACE("Card can do INVSRCCOLOR\n"); + } + else + { + CanDoDestInvSourceColour = false; + TRACE("Card *cannot* do INVSRCCOLOR\n"); + } + + + if ((hw.dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_SRCCOLOR) && + (hw.dpcTriCaps.dwSrcBlendCaps & D3DPBLENDCAPS_DESTCOLOR)) + { + CanDoAdamiLighting = true; + TRACE("Card can do ADAMI LIGHTING\n"); + } + else + { + CanDoAdamiLighting = false; + TRACE("Card *cannot* do ADAMI LIGHTING\n"); + } + + SLONG adami_lighting = ENV_get_value_number("Adami_lighting", -1, "Render"); + + if (adami_lighting == -1) + { + ENV_set_value_number("Adami_lighting", 1, "Render"); + + adami_lighting = 1; + } + + if (adami_lighting == 0) + { + CanDoAdamiLighting = false; + + TRACE("Overriding ADAMI LIGHTING\n"); + } +#endif + + +} + +// Notes: +// +// RagePro *cannot* do MODULATEALPHA but *can* do INVSRCCOLOR + +//--------------------------------------------------------------- + +HRESULT D3DDeviceInfo::LoadFormats(LPDIRECT3DDEVICE3 the_d3d_device) +{ + CallbackInfo callback_info; + HRESULT result; + + + // Have we already loaded the texture formats + if(!FormatsLoaded()) + { + // Check Parameters + if(!the_d3d_device) + { + result = DDERR_GENERIC; + // Output error. + return result; + } + + // Enumerate all Texture Formats for this device + callback_info.Result = TRUE; + callback_info.Count = 0L; + callback_info.Extra = (void*)this; + + result = the_d3d_device->EnumTextureFormats(TextureFormatEnumCallback,(void *)&callback_info); + if(FAILED(result)) + { + // Error + // Output error. + return result; + } + + // Double check count + if((!callback_info.Result) || (callback_info.Count==0) || (FormatCount!=callback_info.Count)) + { + result = DDERR_GENERIC; + // Output error. + return result; + } + + // discover our preferred texture formats + FindOpaqueTexFmt(); + FindAlphaTexFmt(); + + // Mark texture formats as loaded + TurnFormatsLoadedOn(); + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +void D3DDeviceInfo::FindOpaqueTexFmt() +{ + OpaqueTexFmt = NULL; + + SLONG best_score = 0; + + for (DDModeInfo* mi = FormatList; mi; mi = mi->Next) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_RGB) + { + // + // True colour... + // + + if (mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount >= 16) + { + SLONG score = 0x100; + score -= mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount; + + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) + { + // + // Knock off score for alpha + // + + score -= 1; + } + + if (score > best_score) + { + best_score = score; + OpaqueTexFmt = mi; + } + } + } + } + + ASSERT(OpaqueTexFmt); +} + +//--------------------------------------------------------------- + +extern void OS_calculate_mask_and_shift(ULONG bitmask, SLONG* mask, SLONG* shift); + +void D3DDeviceInfo::FindAlphaTexFmt() +{ + SLONG try_shift_alpha; + SLONG try_shift_red; + SLONG try_shift_green; + SLONG try_shift_blue; + + SLONG try_mask_alpha; + SLONG try_mask_red; + SLONG try_mask_green; + SLONG try_mask_blue; + + AlphaTexFmt = NULL; + + SLONG best_score = 0; + + for (DDModeInfo* mi = FormatList; mi; mi = mi->Next) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_RGB) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) + { + if (mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount >= 16) + { + SLONG score; + + // + // Find out how many bits there are for each component. + // + + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRGBAlphaBitMask, &try_mask_alpha, &try_shift_alpha); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwRBitMask , &try_mask_red, &try_shift_red ); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwGBitMask , &try_mask_green, &try_shift_green); + OS_calculate_mask_and_shift(mi->ddSurfDesc.ddpfPixelFormat.dwBBitMask , &try_mask_blue, &try_shift_blue ); + + // + // Rate this texture. We prefer the same number of bits per element + // and then go for the format with the least bits per pixel to save + // memory. + // + + if (try_mask_alpha == try_mask_red && + try_mask_alpha == try_mask_green && + try_mask_alpha == try_mask_blue) + { + score = 0x400; + } + else if (try_mask_red == try_mask_green && + try_mask_red == try_mask_blue) + { + score = 0x300; + } + else + { + score = 0x200; + } + + if (try_mask_alpha == 7) // i.e. only 1 bit of alpha + { + score = 0x100; + } + + score -= mi->ddSurfDesc.ddpfPixelFormat.dwRGBBitCount; + + if (score > best_score) + { + best_score = score; + AlphaTexFmt = mi; + } + } + } + } + } + + ASSERT(AlphaTexFmt); +} + +//--------------------------------------------------------------- + +HRESULT D3DDeviceInfo::LoadZFormats(LPDIRECT3D3 d3d) +{ +#ifdef TARGET_DC + // The DC pretends to have a 32-bit Z-buffer, which is fine. + DDPIXELFORMAT ZFormat; + ZeroMemory ( &ZFormat, sizeof ( ZFormat ) ); + ZFormat.dwSize = sizeof ( ZFormat ); + ZFormat.dwFlags = DDPF_ZBUFFER; + ZFormat.dwZBufferBitDepth = 32; + SetZFormat(&ZFormat); +#else + CallbackInfo callback_info; + HRESULT result; + + // Enumerate all Z formats for this device + callback_info.Result = TRUE; + callback_info.Count = 0; + callback_info.Extra = (void*)this; + + result = d3d->EnumZBufferFormats(guid, ZFormatEnumCallback,(void*)&callback_info); + if (FAILED(result)) + { + return result; + } + + if (!callback_info.Result || !callback_info.Count) + { + result = DDERR_GENERIC; + return result; + } +#endif + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT D3DDeviceInfo::DestroyFormats(void) +{ + DDModeInfo *current_format, + *next_format; + + + if(FormatsLoaded()) + { + current_format = FormatList; + + while(current_format) + { + next_format = current_format->Next; + + MFdelete(current_format); + + current_format = next_format; + } + + FormatCount = 0; + FormatList = NULL; + FormatListEnd = NULL; + + // Mark as unloaded + TurnFormatsLoadedOff(); + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT D3DDeviceInfo::AddFormat(DDModeInfo *the_format) +{ + // Check Parameters + if(!the_format) + { + // Error, Invalid parameters + return DDERR_INVALIDPARAMS; + } + + // Add Format to end of list. + the_format->Prev = FormatListEnd; + the_format->Next = NULL; + + // Update list end. + if(FormatListEnd) + FormatListEnd->Next = the_format; + FormatListEnd = the_format; + + // Update List. + if(!FormatList) + FormatList = the_format; + + FormatCount++; + + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT D3DDeviceInfo::DelFormat(DDModeInfo *the_format) +{ + return DD_OK; +} + +//--------------------------------------------------------------- + +BOOL D3DDeviceInfo::IsHardware(void) +{ + SLONG colour_model; + + + colour_model = d3dHalDesc.dcmColorModel; + if(colour_model) + return TRUE; + return FALSE; +} + +//--------------------------------------------------------------- + +BOOL D3DDeviceInfo::Match(GUID *the_guid) +{ + if(the_guid==NULL) + return FALSE; + + if(!IsValid()) + return FALSE; + + if(*the_guid!=guid) + return FALSE; + + // Success + return TRUE; +} + +//--------------------------------------------------------------- + +DDModeInfo *D3DDeviceInfo::FindFormat ( + SLONG bpp, + DDModeInfo **next_best_format, + DDModeInfo *start + ) +{ + DDModeInfo *current_format; + + + // Get Starting node + if(!start) + current_format = FormatList; + else + current_format = start; + + if(next_best_format) + *next_best_format = current_format; + + // Search format list for best match + while(current_format) + { + if(current_format->Match(bpp)) + { + return current_format; + } + current_format = current_format->Next; + } + + // Failure, user may use lpNextBest instead + return NULL; +} + +//--------------------------------------------------------------- +// +// CLASS : DDDriverInfo +// +//--------------------------------------------------------------- + +DDDriverInfo::DDDriverInfo() +{ + DriverFlags = 0; + + InitStruct(ddHalCaps); + InitStruct(ddHelCaps); + + ModeCount = 0; + ModeList = NULL; + ModeListEnd = NULL; + + DeviceCount = 0; + DeviceList = NULL; + DeviceListEnd = NULL; + + Next = NULL; + Prev = NULL; +} + +//--------------------------------------------------------------- + +DDDriverInfo::~DDDriverInfo() +{ + Destroy(); +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::Create( + GUID *lpGuid, + LPTSTR lpDriverName, + LPTSTR lpDriverDesc + ) +{ + ULONG str_len, + str_size; + HRESULT result; + LPDIRECTDRAW lpDD = NULL; + LPDIRECTDRAW4 lpDD4 = NULL; + LPDIRECT3D3 lpD3D = NULL; + LPTSTR szTemp; + + + if(IsValid()) + { + // Programmer Error, already valid, call Fini to cleanup + return FALSE; + } + + // Copy GUID + if(!lpGuid) + PrimaryOn(); + else + guid = *lpGuid; + + // Copy Name + if(!lpDriverName) + szTemp = TEXT("UNKNOWN"); + else + szTemp = lpDriverName; + + str_len = _tcslen(szTemp); + str_size= (str_len+1)*sizeof(TCHAR); + szName = (LPTSTR)MemAlloc(str_size); + if(szName) + _tcscpy(szName,szTemp); + + // Copy Desc + if(!lpDriverDesc) + szTemp = TEXT("UNKNOWN"); + else + szTemp = lpDriverDesc; + + str_len = _tcslen(szTemp); + str_size= (str_len+1)*sizeof(TCHAR); + szDesc = (LPTSTR)MemAlloc(str_size); + if(szDesc) + _tcscpy(szDesc,szTemp); + + // Create DirectDraw Object + result = DirectDrawCreate(lpGuid,&lpDD,NULL); //BCleak + if(FAILED(result)) + { + // Error + goto cleanup; + } + + // Get The DirectDraw4 Interface + result = lpDD->QueryInterface(IID_IDirectDraw4,(void **)&lpDD4); + if(FAILED(result)) + { + // Error + goto cleanup; + } + + // Get The Direct3D Interface + result = lpDD->QueryInterface(IID_IDirect3D3,(void **)&lpD3D); + if(FAILED(result)) + { + // Error + goto cleanup; + } + + // Get The Driver Caps + result = lpDD4->GetCaps(&ddHalCaps,&ddHelCaps); + if(FAILED(result)) + { + // Error + goto cleanup; + } + + // Enumerate all D3D Devices for this driver + DeviceCount = 0; + result = LoadDevices(lpD3D); + if(FAILED(result)) + goto cleanup; + + + // Enumerate all Modes for this DD Driver + ModeCount = 0; + result = LoadModes(lpDD4); + if(FAILED(result)) + goto cleanup; + + // + // Does this driver have less than 4 meg of video memory? + // + + { + DDCAPS ddcaps; + + memset(&ddcaps, 0, sizeof(ddcaps)); + + ddcaps.dwSize = sizeof(ddcaps); + + lpDD4->GetCaps(&ddcaps, NULL); + + SLONG total = ddcaps.dwVidMemTotal; + + if (total < 5 * 1024 * 1024) + { + DriverFlags |= DD_DRIVER_LOW_MEMORY; + } + } + + // Mark as Valid Driver. + ValidOn(); + + // Success. + result = DD_OK; + +cleanup: + // Cleanup the Interfaces before leaving + if(lpD3D) + { + lpD3D->Release(); + lpD3D = NULL; + } + + if(lpDD4) + { + lpDD4->Release(); + lpDD4 = NULL; + } + + if(lpDD) + { + lpDD->Release(); + lpDD = NULL; + } + + return result; +} + +//--------------------------------------------------------------- + +void DDDriverInfo::Destroy(void) +{ + // Destroy all Modes and Devices. + DestroyDevices(); + DestroyModes(); + + // Clean up strings + if(szDesc) + { + MemFree(szDesc); + szDesc = NULL; + } + + if(szName) + { + MemFree(szName); + szName = NULL; + } + + Prev = NULL; + Next = NULL; + + ValidOff(); +} + +//--------------------------------------------------------------- + +BOOL DDDriverInfo::Match(GUID *the_guid) +{ + if(!IsValid()) + return FALSE; + + if(!the_guid) + { + /* + if (the_display.IsFullScreen()) + { + if(!IsPrimary()) + return TRUE; + } + else + */ + { + if(IsPrimary()) + return TRUE; + } + } + else + { + if(*the_guid==guid) + return TRUE; + } + + return FALSE; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::LoadModes(LPDIRECTDRAW4 lpDD4) +{ + CallbackInfo callback_info; + HRESULT result; + + + // Have we already loaded the modes + if(!ModesLoaded()) + { + // Check Parameters + if(!lpDD4) + { + result = DDERR_GENERIC; + return result; + } + + // Enumerate all modes for this driver. + callback_info.Result = TRUE; + callback_info.Count = 0L; + callback_info.Extra = (void*)this; + + result = lpDD4->EnumDisplayModes(0L,NULL,&callback_info,ModeEnumCallback); + if(FAILED(result)) + { + return result; + } + + // Double check count. + if((!callback_info.Result) || (callback_info.Count == 0) || (ModeCount != callback_info.Count)) + { + result = DDERR_GENERIC; + return result; + } + + // Mark Modes as loaded + TurnModesLoadedOn(); + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::DestroyModes(void) +{ + DDModeInfo *current_mode, + *next_mode; + + + current_mode = ModeList; + while(current_mode) + { + next_mode = current_mode->Next; + + MFdelete(current_mode); + + current_mode = next_mode; + } + + ModeCount = 0; + ModeList = NULL; + ModeListEnd = NULL; + + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::AddMode(DDModeInfo *the_mode) +{ + if(!the_mode) + { + // Error, Invalid parameters + return DDERR_INVALIDPARAMS; + } + + { + // Add Mode to end of List. + the_mode->Prev = ModeListEnd; + the_mode->Next = NULL; + + // Update list end. + if(ModeListEnd) + ModeListEnd->Next= the_mode; + ModeListEnd = the_mode; + + // Update list. + if(!ModeList) + ModeList = the_mode; + + // + // Is this a 16-bit, a 24-bit or a 32-bit mode? + // + + if (the_mode->GetBPP() == 16) + { + if (DriverFlags & DD_DRIVER_RENDERS_TO_16BIT) + { + DriverFlags |= DD_DRIVER_SUPPORTS_16BIT; + } + } + else + if (the_mode->GetBPP() == 32) + { + if (DriverFlags & DD_DRIVER_RENDERS_TO_32BIT) + { + DriverFlags |= DD_DRIVER_SUPPORTS_32BIT; + } + } + + // + // What about the resolution? + // + + if (the_mode->GetWidth() == 320 && the_mode->GetHeight() == 240) {DriverFlags |= DD_DRIVER_MODE_320;} + if (the_mode->GetWidth() == 512 && the_mode->GetHeight() == 384) {DriverFlags |= DD_DRIVER_MODE_512;} + if (the_mode->GetWidth() == 640 && the_mode->GetHeight() == 480) {DriverFlags |= DD_DRIVER_MODE_640;} + if (the_mode->GetWidth() == 800 && the_mode->GetHeight() == 600) {DriverFlags |= DD_DRIVER_MODE_800;} + if (the_mode->GetWidth() == 1024 && the_mode->GetHeight() == 768) {DriverFlags |= DD_DRIVER_MODE_1024;} + + + ModeCount++; + } + + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::DeleteMode(DDModeInfo *the_mode) +{ + return DD_OK; +} + + +//--------------------------------------------------------------- + +DDModeInfo *DDDriverInfo::FindMode ( + SLONG w, + SLONG h, + SLONG bpp, + SLONG refresh, + DDModeInfo **next_best, + DDModeInfo *start_mode + ) +{ + DDModeInfo *current_mode; + + + // Get Starting node + if(!start_mode) + current_mode = ModeList; + else + current_mode = start_mode; + + if(next_best) + *next_best = current_mode; + + // Search mode list for best match + while(current_mode) + { + if(current_mode->Match(w,h,bpp)) + { + return current_mode; + } + else if ( + current_mode->Match ( + DEFAULT_WIDTH, + DEFAULT_HEIGHT, + 8 + ) + ) + { + if(next_best) + *next_best = current_mode; + } + current_mode = current_mode->Next; + } + + // Failure, user may use lpNextBest instead + return NULL; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::LoadDevices(LPDIRECT3D3 lpD3D3) +{ + CallbackInfo callback_info; + HRESULT result; + + + // Have we already loaded the D3D Devices for this driver. + if(!DevicesLoaded()) + { + // Check Parameters + if (! lpD3D3) + { + result = DDERR_GENERIC; + return result; + } + + // Enumerate all D3D Devices for this driver. + callback_info.Result = TRUE; + callback_info.Count = 0L; + callback_info.Extra = (void*)this; + + result = lpD3D3->EnumDevices(DeviceEnumCallback, &callback_info); + if(FAILED(result)) + { + return result; + } + + // Double check count. + if((!callback_info.Result) || (callback_info.Count==0) || (DeviceCount!=callback_info.Count)) + { + result = DDERR_GENERIC; + return result; + } + + // Mark Devices as loaded + TurnDevicesLoadedOn(); + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::DestroyDevices(void) +{ + D3DDeviceInfo *current_device, + *next_device; + + + current_device = DeviceList; + while(current_device) + { + next_device = current_device->Next; + + MFdelete(current_device); + + current_device = next_device; + } + + DeviceCount = 0; + DeviceList = NULL; + DeviceListEnd = NULL; + + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::AddDevice(D3DDeviceInfo *the_device) +{ + if(!the_device) + { + // Error, Invalid parameters + return DDERR_INVALIDPARAMS; + } + + // Add Device to end of List. + the_device->Prev = DeviceListEnd; + the_device->Next = NULL; + + // Update list end. + if(DeviceListEnd) + DeviceListEnd->Next = the_device; + DeviceListEnd = the_device; + + // Update list. + if(!DeviceList) + DeviceList = the_device; + + DeviceCount++; + + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverInfo::DeleteDevice(D3DDeviceInfo *the_device) +{ + return DD_OK; +} + +//--------------------------------------------------------------- + +D3DDeviceInfo *DDDriverInfo::FindDevice ( + GUID *the_guid, + D3DDeviceInfo **next_best, + D3DDeviceInfo *start_device + ) +{ + D3DDeviceInfo *current_device, + *first_device = NULL, + *hardware_device = NULL, + *mmx_device = NULL, + *rgb_device = NULL; + + + if(next_best) + *next_best = NULL; + + // Get Root + if(!start_device) + current_device = DeviceList; + else + current_device = start_device; + + first_device = current_device; + + // Search mode list for best match + while(current_device) + { + if(!SOFTWARE) + { + if(current_device->Match(the_guid)) + return current_device; + + + + if(current_device->IsHardware()) + if(!hardware_device) + hardware_device = current_device; + + } + + if(current_device->guid==IID_IDirect3DRGBDevice) + if(!rgb_device) + { + rgb_device = current_device; + if(SOFTWARE) + return current_device; //added by MD to force software + } + + if(current_device->guid==IID_IDirect3DMMXDevice) + if(!mmx_device) + { + mmx_device = current_device; + if(SOFTWARE) + return current_device; //added by MD to force software + } + + current_device = current_device->Next; + } + + if(next_best) + { + if(hardware_device) + *next_best = hardware_device; + else if(rgb_device) + *next_best = rgb_device; + else if(mmx_device) + *next_best = mmx_device; + else if(first_device) + *next_best = first_device; + } + + // Failure, user may use lpNextBest instead + return NULL; +} + +//--------------------------------------------------------------- + +D3DDeviceInfo *DDDriverInfo::FindDeviceSupportsMode ( + GUID *the_guid, + DDModeInfo *the_mode, + D3DDeviceInfo **next_best_device, + D3DDeviceInfo *start_device + ) +{ + D3DDeviceInfo *current_device; + + + // Check parameters + if(!the_mode) + { + // Error, Invalid parameters + if(next_best_device) + *next_best_device = NULL; + return NULL; + } + + // Get Root + if(!start_device) + current_device = DeviceList; + else + current_device = start_device; + + if(next_best_device) + { + if(the_mode->ModeSupported(current_device)) + *next_best_device = current_device; + } + + // Search the device list for correct device. + while(current_device) + { + if(current_device->Match(the_guid)) + { + +// if(SOFTWARE==0 || !current_device->IsHardware()) //accept this mode if software not required or if it is software_required and not hardware + if(the_mode->ModeSupported(current_device)) + return current_device; + } + else if(current_device->IsHardware()) + { +// if(SOFTWARE==0) // if asking for software dont let any hardware drivers through the net + if(next_best_device) + { + if(the_mode->ModeSupported(current_device)) + *next_best_device = current_device; + } + + } + + else if(the_mode->ModeSupported(current_device)) + { + if(next_best_device) + *next_best_device= current_device; + } + current_device = current_device->Next; + } + + // Failure, user may use lpNextBest instead + return NULL; +} + +//--------------------------------------------------------------- + +DDModeInfo *DDDriverInfo::FindModeSupportsDevice ( + SLONG w, + SLONG h, + SLONG bpp, + SLONG refresh, + D3DDeviceInfo *the_device, + DDModeInfo **next_best, + DDModeInfo *start_mode + ) +{ + DDModeInfo *current_mode; + + + // Check parameters + if(!the_device) + { + // Error, Invalid parameters + if(next_best) + *next_best = NULL; + return NULL; + } + + // Get Root + if(!start_mode) + current_mode = ModeList; + else + current_mode = start_mode; + + if(next_best) + { + if(current_mode->ModeSupported(the_device)) + *next_best = current_mode; + } + + // Search mode list for best match + while(current_mode) + { + if(current_mode->Match(w,h,bpp)) + { + if(current_mode->ModeSupported(the_device)) + return current_mode; + } + else if ( + current_mode->Match ( + DEFAULT_WIDTH, + DEFAULT_HEIGHT, + DEFAULT_DEPTH + ) + ) + { + if(next_best) + { + if(current_mode->ModeSupported(the_device)) + *next_best = current_mode; + } + } + else if(current_mode->ModeSupported(the_device)) + { + if(next_best) + *next_best = current_mode; + } + current_mode = current_mode->Next; + } + + // Failure, user may use lpNextBest instead + return NULL; +} + +//--------------------------------------------------------------- + +GUID *DDDriverInfo::GetGuid(void) +{ + if(IsPrimary()) + return NULL; + else + return &guid; +} + +//--------------------------------------------------------------- +// +// CLASS : DDDriverManager +// +//--------------------------------------------------------------- + +DDDriverManager::DDDriverManager() +{ + ManagerFlags = 0; + DriverCount = 0; + DriverList = NULL; + DriverListEnd = NULL; + + CurrDriver = NULL; + CurrMode = NULL; + CurrDevice = NULL; + CurrTextureFormat = NULL; +} + +//--------------------------------------------------------------- + +DDDriverManager::~DDDriverManager() +{ + Fini(); +} + +//--------------------------------------------------------------- + +HRESULT DDDriverManager::Init(void) +{ + HRESULT result; + + + if(!IsInitialised()) + { + result = LoadDrivers(); + if(FAILED(result)) + return result; + + InitOn(); + } + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverManager::Fini(void) +{ + if(IsInitialised()) + { + DestroyDrivers(); + + InitOff(); + } + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverManager::LoadDrivers(void) +{ + CallbackInfo callback_info; + HRESULT result; + + + // Initialize all valid drivers in system + callback_info.Result = TRUE; + callback_info.Count = 0L; + callback_info.Extra = (void*)NULL; + + result = DirectDrawEnumerate(DriverEnumCallback,&callback_info); + if(FAILED(result)) + { + return result; + } + + // Double check count. + if((!callback_info.Result) || (callback_info.Count == 0) || (DriverCount != callback_info.Count)) + { + result = DDERR_GENERIC; + return result; + } + + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverManager::DestroyDrivers(void) +{ + DDDriverInfo *current_driver, + *next_driver; + + + current_driver = DriverList; + while(current_driver) + { + next_driver = current_driver->Next; + + MFdelete(current_driver); + + current_driver = next_driver; + } + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT DDDriverManager::AddDriver(DDDriverInfo *the_driver) +{ + if(!the_driver) + { + // Error, Invalid parameters + return DDERR_INVALIDPARAMS; + } + + // Add driver to list. + the_driver->Prev = DriverListEnd; + the_driver->Next = NULL; + + // Update list end. + if(DriverListEnd) + DriverListEnd->Next = the_driver; + DriverListEnd = the_driver; + + // Update list. + if(!DriverList) + DriverList = the_driver; + + DriverCount++; + + return DD_OK; +} + +//--------------------------------------------------------------- + +DDDriverInfo *DDDriverManager::FindDriver(GUID *the_guid, DDDriverInfo **next_best, DDDriverInfo *start_driver) +{ + DDDriverInfo *current_driver; + +/* +#ifdef DEBUG + if(!IsInitialized()) + { + // Error, not initialized + return NULL; + } +#endif +*/ + // Get Start node + if(!start_driver) + current_driver = the_manager.DriverList; + else + current_driver = start_driver; + + if(next_best) + *next_best = current_driver; + + + // + // Find all the drivers. + // + + SLONG i; + + DDDriverInfo *driver[10]; + SLONG driver_upto = 0; + + while(current_driver) + { + ASSERT(driver_upto < 10); + + driver[driver_upto++] = current_driver; + + current_driver = current_driver->Next; + } + + DDDriverInfo *choice1 = NULL; + DDDriverInfo *choice2 = NULL; + +extern int Video3DMode; + + if (Video3DMode == 1) // select voodoo first + { + for (i = 0; i < driver_upto; i++) + { + if (the_guid) + { + if (driver[i]->Match(the_guid)) + { + choice1 = driver[i]; + } + else + { + choice2 = driver[i]; + } + } + else + { + if (driver[i]->IsPrimary()) + { + choice2 = driver[i]; // Primary device 2nd choice for debug mode + } + else + { + choice1 = driver[i]; + } + } + } + + if (!choice1) {choice1 = choice2;} + if (!choice2) {choice2 = choice1;} + + current_driver = choice1; + + if (next_best) + { + *next_best = choice2; + } + + return current_driver; + } + else + { + for (i = 0; i < driver_upto; i++) + { + if (the_guid) + { + if (driver[i]->Match(the_guid)) + { + choice1 = driver[i]; + } + else + { + choice2 = driver[i]; + } + } + else + { + if (driver[i]->IsPrimary()) + { + choice1 = driver[i]; // Primary device 1st choice for debug mode + } + else + { + choice2 = driver[i]; + } + } + } + + if (!choice1) {choice1 = choice2;} + if (!choice2) {choice2 = choice1;} + + current_driver = choice1; + + if (next_best) + { + *next_best = choice2; + } + + return current_driver; + } + + + + + /* + + while(current_driver) + { + if(current_driver->Match(the_guid)) + { + // Success + return current_driver; + } + else if(current_driver->IsPrimary()) + { + if(next_best) + *next_best = current_driver; + } + current_driver = current_driver->Next; + } + + */ + + // Failure, user could use next best instead + return NULL; +} + +//--------------------------------------------------------------- +/* +DDDriverInfo *DDDriverManager::FindDriver(DDCAPS *hal,DDCAPS *hel,DDDriverInfo **next_best,DDDriverInfo *start_driver) +{ + DDDriverInfo *current_driver, lpNextDrv; + + + // Get Start node + if(!start_driver) + current_driver = the_manager.DriverList; + else + current_driver = start_driver; + + if(next_best) + *next_best = current_driver; + + // + // Find all the drivers. + // + + SLONG i; + + DDDriverInfo *driver[10]; + SLONG driver_upto = 0; + + while(current_driver) + { + ASSERT(driver_upto < 10); + + driver[driver_upto++] = current_driver; + + current_driver = current_driver->Next; + } + + DDDriverInfo *choice1 = NULL; + DDDriverInfo *choice2 = NULL; + + #ifdef NDEBUG + + for (i = 0; i < driver_upto; i++) + { + if (driver[i]->IsPrimary()) + { + choice2 = driver[i]; // Primary device 2nd choice for debug mode + } + else + { + choice1 = driver[i]; + } + } + + if (!choice1) {choice1 = choice2;} + if (!choice2) {choice2 = choice1;} + + current_driver = choice1; + + if (next_best) + { + *next_best = choice2; + } + + return current_driver; + + #else + + for (i = 0; i < driver_upto; i++) + { + if (driver[i]->IsPrimary()) + { + choice1 = driver[i]; // Primary device 1st choice for debug mode + } + else + { + choice2 = driver[i]; + } + } + + if (!choice1) {choice1 = choice2;} + if (!choice2) {choice2 = choice1;} + + current_driver = choice1; + + if (next_best) + { + *next_best = choice2; + } + + return current_driver; + + #endif + +// while(current_driver) +// { +// if(current_driver->Match(hal,hel)) +// { +// // Success +// return current_driver; +// } +// else if(current_driver->IsPrimary()) +// { +// if(next_best) +// *next_best = current_driver; +// } +// +// current_driver = current_driver->Next; +// } + + // Failure, user could use next best instead + return NULL; +} + +*/ + +//--------------------------------------------------------------- diff --git a/fallen/DDLibrary/Source/DIManager.cpp b/fallen/DDLibrary/Source/DIManager.cpp new file mode 100644 index 0000000..f22eafd --- /dev/null +++ b/fallen/DDLibrary/Source/DIManager.cpp @@ -0,0 +1,2754 @@ +// DIManager.cpp +// Guy Simmons, 19th February 1998 + +#include "DDLib.h" +#ifndef TARGET_DC +#include "FFManager.h" +#else +#include "maplusag.h" +#endif + +#ifdef TARGET_DC +#include "target.h" +#endif + +// TEMP +DIJOYSTATE the_state; + + +#ifdef TARGET_DC // This whole file is just for Dreamcast now... + +DIDeviceInfo *primary_device = NULL; +DIDriverManager the_input_manager; + +UBYTE last_type; +UBYTE last_sub_type; + + + +#ifdef DEBUG +// Enable some tracing. +#define SHARON TRACE + +#else + +// Don't dump info. +#define SHARON sizeof + +#endif + + + + + +#if ENABLE_REMAPPING +#ifdef TARGET_DC + +enum eAxisMapping +{ + MY_DC_X_AXIS = 0, + MY_DC_Y_AXIS = 1 +}; + +// These had better agree with the ones in interfac.h, or you're toast. +enum eButtonMapping +{ + MY_DC_BUTTON_A = 1, + MY_DC_BUTTON_B = 0, + MY_DC_BUTTON_C = 11, + MY_DC_BUTTON_D = 13, + MY_DC_BUTTON_X = 8, + MY_DC_BUTTON_Y = 7, + MY_DC_BUTTON_Z = 12, + MY_DC_BUTTON_START = 2, + MY_DC_BUTTON_UP = 3, + MY_DC_BUTTON_DOWN = 4, + MY_DC_BUTTON_LEFT = 5, + MY_DC_BUTTON_RIGHT = 6, + MY_DC_BUTTON_RTRIGGER = 9, + MY_DC_BUTTON_LTRIGGER = 10, + // General analogue buttons. + MY_DC_BUTTON_AN3 = 14, + MY_DC_BUTTON_AN4 = 15, + MY_DC_BUTTON_AN5 = 16, + MY_DC_BUTTON_AN6 = 17, + // Another direction pad. I think. + MY_DC_BUTTON_2_UP = 18, + MY_DC_BUTTON_2_DOWN = 19, + MY_DC_BUTTON_2_LEFT = 20, + MY_DC_BUTTON_2_RIGHT = 21, + + // Special one - any unmapped buttons are remapped here. Don't read it! + MY_DC_BUTTON_BOGUS = 31, +}; + +#endif +#endif + + +//--------------------------------------------------------------- + +extern HINSTANCE hGlobalThisInst; + +//--------------------------------------------------------------- +// +// User functions. +// +//--------------------------------------------------------------- + + +// Clears the current primary device, and does everything +// needed to start searching for thenext one to press a button again. +void ClearPrimaryDevice ( void ) +{ + SHARON ( "ClearPrimaryDevice\n" ); + primary_device = NULL; +} + + +// Used for a simple count. +int m_iNumMapleDevices; + + + +// Forces a rescan of devices. Any new devices will be added to the available list. +// This does not reassign the primary - if you want to do that, +// call ClearPrimaryDevice(). +// If anything new was found, or anything existing was removed, returns TRUE. +bool RescanDevices ( void ) +{ + bool bChanged = FALSE; + HRESULT result = the_input_manager.LoadDevices ( &bChanged ); + return bChanged; +} + + +// Often called after a RescanDevices - deletes any missing devices. +void DeleteInvalidDevice ( void ) +{ + DIDeviceInfo *current_device, + *next_device; + + current_device = the_input_manager.DeviceList; + while(current_device) + { + next_device = current_device->Next; + + if ( !(current_device->IsValid()) ) + { + // Destroy it then + the_input_manager.DestroyDevice ( current_device ); + } + current_device = next_device; + } +} + + +BOOL GetInputDevice ( UBYTE type, UBYTE sub_type, bool bActuallyGetOne ) +{ + + SHARON ( "GetInputDevice\n" ); + + last_type = type; + last_sub_type = sub_type; + + if ( bActuallyGetOne ) + { +#ifdef TARGET_DC + // Tsk tsk. + ASSERT ( FALSE ); +#endif + + DIDeviceInfo *the_device; + ZeroMemory(&the_state,sizeof(the_state)); + the_device = the_input_manager.FindDevice(type,sub_type,NULL); + if ( the_device != NULL ) + { + return ( the_device->GetThisDevice ( type ) ); + } + } + else + { + return TRUE; + } +} + + +//--------------------------------------------------------------- + +// Returns TRUE if there are any devices connected, +// whether or not any of them is the primary. +BOOL AreAnyDevicesConnected ( void ) +{ + if ( the_input_manager.DeviceList != NULL ) + { + ASSERT ( the_input_manager.DeviceCount != 0 ); + return TRUE; + } + else + { + //ASSERT ( the_input_manager.DeviceCount == 0 ); + return FALSE; + } +} + + + +//--------------------------------------------------------------- + +BOOL ReadInputDevice(void) +{ + BOOL read_it = FALSE; + HRESULT result; + + if ( primary_device == NULL ) + { +#ifdef TARGET_DC + // No current primary, so keep scanning existing controllers + // for a one to press a button, then make that the primary. + primary_device = the_input_manager.FindFirstWithButtonPressed ( last_type, last_sub_type ); + if ( primary_device != NULL ) + { + // Go on to read it. + } + else + { + // None has pressed a button yet, which is fine. + return FALSE; + } +#else //#ifdef TARGET_DC + primary_device = the_input_manager.FindDevice(JOYSTICK,0,NULL); + if (primary_device == NULL) + { + return FALSE; + } + else + { + return primary_device->GetThisDevice(JOYSTICK); + } +#endif //#else //#ifdef TARGET_DC + } + + + if ( primary_device != NULL ) + { +#ifdef TARGET_DC + ASSERT ( !primary_device->NeedsPoll() ); +#else + //if(primary_device->NeedsPoll()) + { + result = primary_device->lpdiInputDevice->Poll(); + switch(result) + { + case DIERR_INPUTLOST: + case DIERR_NOTACQUIRED: + result = primary_device->lpdiInputDevice->Acquire(); + + if (result != DI_OK) + { + return read_it; + } + + //if(FAILED(result)) + // return read_it; + break; + case DIERR_NOTINITIALIZED: + break; + } + } +#endif + +#if ENABLE_REMAPPING + DIJOYSTATE temp_state; + result = primary_device->lpdiInputDevice->GetDeviceState(sizeof(temp_state),&temp_state); +#else + result = primary_device->lpdiInputDevice->GetDeviceState(sizeof(the_state),&the_state); +#endif + switch(result) + { + default: + SHARON ( "Primary Device fell over in some way\n" ); + result = primary_device->lpdiInputDevice->Acquire(); + + if (result != DI_OK) + { +#ifdef TARGET_DC + // Start searching for primary devices again. + ClearPrimaryDevice(); +#endif + return read_it; + } + + //if(FAILED(result)) + // return read_it; + + break; + case DI_OK: + +#if ENABLE_REMAPPING + // Remap from DI internals to my standard mappings. + + // Can't be arsed to remap the axis. + // But, if there aren't enough (e.g. lightgun, which has no axis), + // set them to mid-way to stop them interfereing. + + if ( primary_device->NumAxis >= 1 ) + { + the_state.lX = temp_state.lX; + } + else + { + the_state.lX = 128; + } + if ( primary_device->NumAxis >= 2 ) + { + the_state.lY = temp_state.lY; + } + else + { + the_state.lY = 128; + } + + for ( int i = 0; i < primary_device->NumButtons; i++ ) + { + ASSERT ( primary_device->ButtonMappings[i] != (UBYTE) -1 ); + the_state.rgbButtons[primary_device->ButtonMappings[i]] = temp_state.rgbButtons[i]; + } +#endif + + read_it = TRUE; + break; + } + } + return read_it; +} + + + + +//--------------------------------------------------------------- +// +// Callback functions. +// +//--------------------------------------------------------------- + +BOOL CALLBACK DIDeviceEnumCallback ( + LPCDIDEVICEINSTANCE lpDIDevice, + LPVOID lpExtra + ) +{ + CallbackInfo *the_info; + DIDeviceInfo *new_device; + HRESULT result; + + //SHARON ( "DIDeviceEnumCallback\n" ); + + if(!lpExtra) + { + // Programming error, invalid pointer + return DIENUM_STOP; + } + + the_info = (CallbackInfo*)lpExtra; + + + // See if we already have this device. + DIDeviceInfo *pCurDev = the_input_manager.DeviceList; + while ( pCurDev != NULL ) + { + if ( IsEqualGUID ( pCurDev->guidInstance, lpDIDevice->guidInstance ) ) + { + // Already got this one - skip it. + pCurDev->ValidOn(); + return DIENUM_CONTINUE; + } + + pCurDev = pCurDev->Next; + } + +#ifdef DEBUG + SHARON ( "DIDeviceEnumCallback: found something new.\n" ); + char pcTemp[200]; + textConvertUniToChar ( pcTemp, lpDIDevice->tszProductName ); + SHARON ( "FFWBP:Device says it's a <%s>\n", pcTemp ); +#endif + + // create DeviceInfo instance. + new_device = MFnew(); + if(!new_device) + { + // Error, Not enough memory to create DeviceInfo. + return DIENUM_STOP; + } + + // Setup the device info. + result = new_device->Create(lpDIDevice); + if(FAILED(result)) + { + // Error, DeviceInfo setup failed. + return DIENUM_STOP; + } + + // Add To Global DeviceInfo List + result = the_input_manager.AddDevice(new_device); + if(FAILED(result)) + { + // Error, DeviceInfo setup failed. + return DIENUM_STOP; + } + + new_device->ValidOn(); + + // Increment device count. + the_info->Count++; + + // Success. + return DIENUM_CONTINUE; +} + +//--------------------------------------------------------------- +// +// CLASS : DIDeviceInfo +// +//--------------------------------------------------------------- + +DIDeviceInfo::DIDeviceInfo() +{ + SHARON ( "DIDeviceInfo creator\n" ); + DeviceFlags = 0; + NumButtons = 0; + NumAxis = 0; + PortNumber = -1; + pFirstVMU = NULL; + +#if ENABLE_REMAPPING + AxisMappings[0] = -1; + AxisMappings[1] = -1; + for ( int i = 0; i < 32; i++ ) + { + ButtonMappings[i] = -1; + } +#endif + + Next = NULL; + Prev = NULL; + +} + +//--------------------------------------------------------------- + +DIDeviceInfo::~DIDeviceInfo() +{ + SHARON ( "DIDeviceInfo destructor\n" ); + Destroy(); +} + +//--------------------------------------------------------------- + +HRESULT DIDeviceInfo::Create(LPCDIDEVICEINSTANCE lpDIDevice) +{ + HRESULT result; + LPDIRECTINPUTDEVICE lp_di_device; + + SHARON ( "DIDeviceInfo::Create\n" ); + + + // Copy the device type. + DeviceType = LOBYTE(lpDIDevice->dwDevType); + DeviceSubType = HIBYTE(lpDIDevice->dwDevType); + +#ifndef TARGET_DC + // Copy the instance name. + strcpy(Instance,lpDIDevice->tszInstanceName); + + // Copy the product name. + strcpy(Product,lpDIDevice->tszProductName); +#else + + // Copy the instance name. + textConvertUniToChar(Instance,lpDIDevice->tszInstanceName); + + // Copy the product name. + textConvertUniToChar(Product,lpDIDevice->tszProductName); + +#endif + + // Copy the GUID. + guidInstance = lpDIDevice->guidInstance; + + // Now create the device. + result = the_input_manager.lp_DI->CreateDevice ( + lpDIDevice->guidInstance, + &lp_di_device, + NULL + ); + if(FAILED(result)) + return result; + + result = lp_di_device->QueryInterface(IID_IDirectInputDevice2,(LPVOID*)&lpdiInputDevice); + di_error(result); + if(SUCCEEDED(result)) + ValidOn(); + + + // Get the port number of the device + DIPROPDWORD dipropdword; + dipropdword.diph.dwSize = sizeof(DIPROPDWORD); + dipropdword.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipropdword.diph.dwObj = 0; + dipropdword.diph.dwHow = DIPH_DEVICE; + result = lpdiInputDevice->GetProperty(DIPROP_PORTNUMBER, &dipropdword.diph); + ASSERT (SUCCEEDED(result)); + PortNumber = (UBYTE)dipropdword.dwData; + +#ifdef TARGET_DC + // Get the device's direction. + result = lpdiInputDevice->GetProperty(DIPROP_EXPDIRECTION, &dipropdword.diph); + ASSERT (SUCCEEDED(result)); + dwDirection = dipropdword.dwData; +#endif + + lp_di_device->Release(); + + return result; +} + +//--------------------------------------------------------------- + +void DIDeviceInfo::Destroy(void) +{ + SHARON ( "DIDeviceInfo::Destroy\n" ); + if(IsValid()) + lpdiInputDevice->Release(); + + Prev = NULL; + Next = NULL; + + ValidOff(); +} + + + + +//--------------------------------------------------------------- + + + + +// The EnumDeviceObjects callback. +BOOL DIDeviceInfo::DIEnumDeviceObjectsProc(LPCDIDEVICEOBJECTINSTANCE pDIDOI) +{ + if ((LOBYTE(LOWORD(pDIDOI->dwType)) & DIDFT_AXIS) != 0) + { +#if ENABLE_REMAPPING + if ( NumAxis < 2 ) + { + if (IsEqualGUID(pDIDOI->guidType, GUID_XAxis)) + { + AxisMappings[NumAxis] = MY_DC_X_AXIS; + } + else + { + AxisMappings[NumAxis] = MY_DC_Y_AXIS; + } + } +#endif + NumAxis++; + } + else if ((LOBYTE(LOWORD(pDIDOI->dwType)) & DIDFT_BUTTON) != 0) + { +#if ENABLE_REMAPPING + if ( NumButtons < 32 ) + { + int iMapping = -1; + switch ( pDIDOI->wUsage ) + { + case USAGE_A_BUTTON : iMapping = MY_DC_BUTTON_A; break; + case USAGE_B_BUTTON : iMapping = MY_DC_BUTTON_B; break; + case USAGE_C_BUTTON : iMapping = MY_DC_BUTTON_C; break; + case USAGE_D_BUTTON : iMapping = MY_DC_BUTTON_D; break; + case USAGE_START_BUTTON : iMapping = MY_DC_BUTTON_START; break; + case USAGE_LA_BUTTON : iMapping = MY_DC_BUTTON_LEFT; break; + case USAGE_RA_BUTTON : iMapping = MY_DC_BUTTON_RIGHT; break; + case USAGE_DA_BUTTON : iMapping = MY_DC_BUTTON_DOWN; break; + case USAGE_UA_BUTTON : iMapping = MY_DC_BUTTON_UP; break; + case USAGE_X_BUTTON : iMapping = MY_DC_BUTTON_X; break; + case USAGE_Y_BUTTON : iMapping = MY_DC_BUTTON_Y; break; + case USAGE_Z_BUTTON : iMapping = MY_DC_BUTTON_Z; break; + case USAGE_LB_BUTTON : iMapping = MY_DC_BUTTON_2_LEFT; break; + case USAGE_RB_BUTTON : iMapping = MY_DC_BUTTON_2_RIGHT; break; + case USAGE_DB_BUTTON : iMapping = MY_DC_BUTTON_2_DOWN; break; + case USAGE_UB_BUTTON : iMapping = MY_DC_BUTTON_2_UP; break; + case USAGE_RTRIG_BUTTON : iMapping = MY_DC_BUTTON_RTRIGGER; break; + case USAGE_LTRIG_BUTTON : iMapping = MY_DC_BUTTON_LTRIGGER; break; + case USAGE_AN3_BUTTON : iMapping = MY_DC_BUTTON_AN3; break; + case USAGE_AN4_BUTTON : iMapping = MY_DC_BUTTON_AN4; break; + case USAGE_AN5_BUTTON : iMapping = MY_DC_BUTTON_AN5; break; + case USAGE_AN6_BUTTON : iMapping = MY_DC_BUTTON_AN6; break; + default: + SHARON ( "Eh? Unknown button number\n" ); + break; + } + ButtonMappings[NumButtons] = (UBYTE)iMapping; + } +#endif + NumButtons++; + } + else + { + SHARON ( "Ooh - it's a wacky joypad object!\n" ); + } + + return(TRUE); +} + + + + +// Useful stub to convert from a callback to something more sane. +BOOL CALLBACK +DIEnumDeviceObjectsProcStub(LPCDIDEVICEOBJECTINSTANCE pDIDOI, LPVOID pvContext) +{ + DIDeviceInfo *pDevice = (DIDeviceInfo *)pvContext; + return(pDevice->DIEnumDeviceObjectsProc(pDIDOI)); +} + + + + +BOOL DIDeviceInfo::GetThisDevice ( UBYTE type ) +{ + SHARON ( "DIDeviceInfo::GetThisDevice\n" ); + + DIDEVCAPS di_dcaps; + HRESULT result; + + + DWORD coopflags; + // Set up the coop level. +/* result = this->lpdiInputDevice->SetCooperativeLevel( + hDDLibWindow, + DISCL_NONEXCLUSIVE | + DISCL_FOREGROUND + ); */ + if (type==JOYSTICK) { + // Force Feedback *requires* exclusive mode + coopflags = DISCL_EXCLUSIVE | DISCL_FOREGROUND; + } else { + // Probably keyboard or mouse -- use nonexclusively + coopflags = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND; + } + + + result = lpdiInputDevice->SetCooperativeLevel( + hDDLibWindow, + coopflags + ); + if(FAILED(result)) + return FALSE; + + // Set the data format. Fudged for Joysticks for now. + result = lpdiInputDevice->SetDataFormat(&c_dfDIJoystick); + if(FAILED(result)) + return FALSE; + + // Get the device capabilities, mainly to find out if we need to poll. + InitStruct(di_dcaps); + + result = lpdiInputDevice->GetCapabilities(&di_dcaps); + if(FAILED(result)) + return FALSE; + + if(di_dcaps.dwFlags&DIDC_POLLEDDATAFORMAT) + { +#ifdef TARGET_DC + ASSERT ( FALSE ); +#endif + this->NeedsPollOn(); + } + + + + //ASSERT ( di_dcaps.dwButtons < 256 ); + //NumButtons = (UBYTE)di_dcaps.dwButtons; + + + + + // EnumObjects is how we determine how many buttons and axes this controller + // has. By interpreting this data correctly we can automatically work with + // new controllers that have a different number of buttons, etc. + // DirectInput will call our DIEnumDeviceObjectsProcStub (which will then + // call our DIEnumDeviceObjectsProc) once for each object (button or axis) + // on the device. + NumButtons = 0; + NumAxis = 0; +#if ENABLE_REMAPPING + AxisMappings[0] = -1; + AxisMappings[1] = -1; + for ( int i = 0; i < 32; i++ ) + { + ButtonMappings[i] = -1; + } +#endif + + result = lpdiInputDevice->EnumObjects(DIEnumDeviceObjectsProcStub, this, 0); + if ( FAILED ( result ) ) + { + return FALSE; + } + + result = lpdiInputDevice->SetDataFormat(&c_dfDIJoystick); + if ( FAILED ( result ) ) + { + return FALSE; + } + + + // Anything that has the word "fishing" in its title is reporting crappy things - + // ignore all slightly odd buttons and both triggers for this device. + + if ( ( strstr ( Product, "fishing" ) != NULL ) || + ( strstr ( Product, "FISHING" ) != NULL ) || + ( strstr ( Product, "Fishing" ) != NULL ) ) + { + for ( int j = 0; j < 32; j++ ) + { + switch ( ButtonMappings[j] ) + { + case MY_DC_BUTTON_C : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_Z : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_2_LEFT : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_2_RIGHT : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_2_DOWN : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_2_UP : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_RTRIGGER : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_LTRIGGER : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_AN3 : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_AN4 : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_AN5 : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + case MY_DC_BUTTON_AN6 : ButtonMappings[j] = MY_DC_BUTTON_BOGUS; break; + default: + // Fine. + break; + } + } + } + + + // Initially acquire the device. + result = lpdiInputDevice->Acquire(); + if(FAILED(result)) + return FALSE; + + return TRUE; +} + + + + + +//--------------------------------------------------------------- +// +// CLASS : DIDriverManager +// +//--------------------------------------------------------------- + +DIDriverManager::DIDriverManager() +{ + ManagerFlags = 0; + DeviceCount = 0; + DeviceList = NULL; + DeviceListEnd = NULL; + bVMUScreenUpdatesEnabled = TRUE; +} + +//--------------------------------------------------------------- + +DIDriverManager::~DIDriverManager() +{ + Fini(); +} + +//--------------------------------------------------------------- + +HRESULT DIDriverManager::Init(void) +{ + SHARON ( "DIDriverManager::Init\n"); + HRESULT result; + + + if(!IsInitialised()) + { +#if 1 + result = DirectInputCreate ( + hGlobalThisInst, + DIRECTINPUT_VERSION, + &lp_DI, + NULL + ); +#else + + CoInitialize(NULL); + + CoCreateInstance( + CLSID_DirectInput8, + NULL, + CLSCTX_INPROC_SERVER, + IID_IDirectInput8W, + (void **) &lp_DI); + + result = lp_DI->Initialize(hGlobalThisInst, DIRECTINPUT_VERSION); + + /* + + + result = DirectInputCreateEx ( + hGlobalThisInst, + DIRECTINPUT_VERSION, + IID_IDirectInput2, + &lp_DI, + NULL + ); + */ +#endif + if(FAILED(result)) + { + switch(result) + { + case DIERR_BETADIRECTINPUTVERSION: + return result; + break; + + case DIERR_OLDDIRECTINPUTVERSION: + return result; + break; + + default: + break; + } + + return result; + } + + result = LoadDevices(); + if(FAILED(result)) + return result; + +#ifndef TARGET_DC + the_ff_manager = new FFManager(); +#endif + + InitOn(); + } + return DI_OK; +} + +//--------------------------------------------------------------- + +HRESULT DIDriverManager::Fini(void) +{ + SHARON ( "DIDriverManager::Fini\n" ); + if(IsInitialised()) + { +#ifndef TARGET_DC + MFdelete(the_ff_manager); + the_ff_manager=NULL; +#endif + + DestroyAllDevices(); + + InitOff(); + } + return DI_OK; +} + +//--------------------------------------------------------------- + +// Can be called multiple times - will find any new devices and add them, but retain any existing ones. +// If pbChanged is non-NULL, it will be set to TRUE if there are any new devices. +// Note - DC - it WILL bin any VMU devices and remake them. +HRESULT DIDriverManager::LoadDevices ( bool *pbChanged ) +{ + //SHARON ( "DIDriverManager::LoadDevices\n" ); + + CallbackInfo callback_info; + HRESULT result; + + // Initialize all valid drivers in system + callback_info.Result = TRUE; + callback_info.Count = 0L; + callback_info.Extra = (void*)NULL; + + int iOldDeviceCount = DeviceCount; + + // First set all the devices to invalid - the enum rout will set them to valid. + DIDeviceInfo *pCurDev = the_input_manager.DeviceList; + while ( pCurDev != NULL ) + { + pCurDev->ValidOff(); + pCurDev = pCurDev->Next; + } + + + ASSERT ( lp_DI != NULL ); + result = lp_DI->EnumDevices(NULL, DIDeviceEnumCallback, &callback_info, DIEDFL_ALLDEVICES/* DIEDFL_ATTACHEDONLY */); + if(FAILED(result)) + { + return result; + } + + // Double check count. + if((!callback_info.Result) || (DeviceCount != callback_info.Count)) + { + result = DDERR_GENERIC; + } + + + // Clean up if the primary got removed. + if ( ( primary_device != NULL ) && ( !(primary_device->IsValid()) ) ) + { + primary_device = NULL; + } + + + if ( pbChanged != NULL ) + { + if ( DeviceCount > (unsigned)iOldDeviceCount ) + { + // Yes, something new. + *pbChanged = TRUE; + } + // See if any got removed. + pCurDev = the_input_manager.DeviceList; + while ( pCurDev != NULL ) + { + if ( !(pCurDev->IsValid()) ) + { + *pbChanged = TRUE; + } + pCurDev = pCurDev->Next; + } + } + + +#ifdef TARGET_DC + // And scan for the Maple devices that hang off them. + // Note that there is no need to change *pbChanged, + // coz removing and adding VMUs causes controller disconnect/reconnect anyway, + // which should be spotted. + // Oh - removing a VMU doesn't cause a disconnect - so we do have to count them. + int iPrevNumVMUs = m_iNumMapleDevices; + int iNewNumVMUs = ScanForVMUs(); + ASSERT ( iNewNumVMUs == m_iNumMapleDevices ); + if ( iPrevNumVMUs != iNewNumVMUs ) + { + if ( pbChanged != NULL ) + { + *pbChanged = TRUE; + } + } +#endif + + return result; +} + +//--------------------------------------------------------------- + +HRESULT DIDriverManager::DestroyAllDevices(void) +{ + SHARON ( "DIDriverManager::DestroyDevices\n" ); + + DIDeviceInfo *current_device, + *next_device; + + current_device = DeviceList; + while(current_device) + { + next_device = current_device->Next; + DestroyDevice ( current_device ); + current_device = next_device; + } + + ASSERT ( DeviceList == NULL ); + ASSERT ( DeviceListEnd == NULL ); + + return DI_OK; +} + +//--------------------------------------------------------------- + +HRESULT DIDriverManager::DestroyDevice ( DIDeviceInfo *the_device ) +{ + SHARON ( "DIDriverManager::DestroyDevices\n" ); + + DIDeviceInfo *current_device; + + current_device = DeviceList; + while(current_device) + { + if ( current_device == the_device ) + { + if ( current_device->Prev == NULL ) + { + ASSERT ( DeviceList == current_device ); + DeviceList = current_device->Next; + } + else + { + ASSERT ( DeviceList != current_device ); + current_device->Prev->Next = current_device->Next; + } + + if ( current_device->Next == NULL ) + { + ASSERT ( DeviceListEnd == current_device ); + DeviceListEnd = current_device->Prev; + } + else + { + ASSERT ( DeviceListEnd != current_device ); + current_device->Next->Prev = current_device->Prev; + } + + MFdelete(current_device); + + break; + } + + current_device = current_device->Next; + } + + return DI_OK; +} + +//--------------------------------------------------------------- + +HRESULT DIDriverManager::AddDevice(DIDeviceInfo *the_device) +{ + SHARON ( "DIDriverManager::AddDevice\n" ); + + if(!the_device) + { + // Error, Invalid parameters + return DIERR_INVALIDPARAM; + } + + // Add device to list. + the_device->Prev = DeviceListEnd; + the_device->Next = NULL; + + // Update list end. + if(DeviceListEnd) + DeviceListEnd->Next = the_device; + DeviceListEnd = the_device; + + // Update list. + if(!DeviceList) + DeviceList = the_device; + + DeviceCount++; + + return DI_OK; +} + +//--------------------------------------------------------------- + +DIDeviceInfo *DIDriverManager::FindDevice(UBYTE type,UBYTE sub_type,DIDeviceInfo **next_best,DIDeviceInfo *start_device) +{ + SHARON ( "DIDriverManager::FindDevice\n" ); + + DIDeviceInfo *current_device; + + + // Get Start node + if(!start_device) + current_device = DeviceList; + else + current_device = start_device; + + if(next_best) + *next_best = current_device; + + while(current_device) + { + if(current_device->DeviceType==type) + { + if(sub_type) + { + if(current_device->DeviceSubType==sub_type) + { + // Success. + return current_device; + } + else + { + if(next_best) + *next_best = current_device; + } + } + else + { + // Success. + return current_device; + } + + } + current_device = current_device->Next; + } + + // Failure, user could use next best instead + return NULL; +} + + + + + + + +static DWORD dwLastTimeWeSentPicciesToVMUs = 0; +// In milliseconds. +#define SEND_VMU_PICCIE_EVERY 2000 + +// Sega says I have to. +#define LOOK_FOR_START_NOT_JUST_ANY_BUTTON 1 + +DIDeviceInfo *DIDriverManager::FindFirstWithButtonPressed ( UBYTE type, UBYTE sub_type ) +{ + DIDeviceInfo *current_device; + + + // Scan for new devices. + LoadDevices(); + + + if ( ( timeGetTime() - dwLastTimeWeSentPicciesToVMUs ) > SEND_VMU_PICCIE_EVERY ) + { + if ( bVMUScreenUpdatesEnabled ) + { + // Send the "press any button" bitmap to the screens of all the devices. + DIDeviceInfo *current_device = the_input_manager.DeviceList; + while ( current_device != NULL ) + { + MapleVMU *pVMU = current_device->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_LCD ) + { +extern VMU_Screen *pvmuscreenPressStart; + pVMU->Lcd_WriteScreen ( pvmuscreenPressStart, TRUE ); + } + pVMU = pVMU->pNextVMU; + } + current_device = current_device->Next; + } + } + dwLastTimeWeSentPicciesToVMUs = timeGetTime(); + } + + + + + current_device = DeviceList; + + while(current_device) + { + bool bGoodDevice = FALSE; + + if(current_device->DeviceType==type) + { + if(sub_type) + { + if(current_device->DeviceSubType==sub_type) + { + bGoodDevice = TRUE; + } + } + else + { + // Success. + bGoodDevice = TRUE; + } + } + + if ( bGoodDevice ) + { +#ifdef TARGET_DC + ASSERT ( !current_device->NeedsPoll() ); +#else + // Yep, scan this device for a pressed button. + if(current_device->NeedsPoll()) + { + HRESULT result = current_device->lpdiInputDevice->Poll(); + switch(result) + { + case DIERR_INPUTLOST: + case DIERR_NOTACQUIRED: + result = current_device->lpdiInputDevice->Acquire(); + if (result != DI_OK) + { + // Don't care. + } + result = current_device->lpdiInputDevice->Poll(); + if (result != DI_OK) + { + // Don't care. + } + break; + case DIERR_NOTINITIALIZED: + // Don't care. + break; + } + } +#endif + + DIJOYSTATE dijoyState; + + HRESULT result = current_device->lpdiInputDevice->GetDeviceState(sizeof(dijoyState),&dijoyState); + switch(result) + { + default: + result = current_device->lpdiInputDevice->Acquire(); + if (result != DI_OK) + { + // OK, maybe it hasn't been set up. + if ( !current_device->GetThisDevice ( last_type ) ) + { + // Nope - really stuffed. Right - bin this device - probably doesn't exist any more. + DIDeviceInfo *next_device = current_device->Next; + SHARON ( "FFWBP:Device 0x%x is toast - destroying it\n", current_device ); + SHARON ( "FFWBP:Device said it was a <%s>\n", current_device->Product ); + DestroyDevice ( current_device ); + + current_device = next_device; + continue; + } + } + break; + case DI_OK: + + // See if any of the buttons were pressed. + for ( int i = 0; i < current_device->NumButtons ; i++ ) + { + if ( ( dijoyState.rgbButtons[i] & 0x80 ) != 0 ) + { +#if LOOK_FOR_START_NOT_JUST_ANY_BUTTON + // Ignore non-Start buttons. + if ( current_device->ButtonMappings[i] == MY_DC_BUTTON_START ) + { +#else + // Ignore ones remapped to BOGUS. + if ( current_device->ButtonMappings[i] != MY_DC_BUTTON_BOGUS ) + { +#endif + + // Got one. + SHARON ( "FFWBP:Found down button %i on 0x%x\n", i, current_device ); + SHARON ( "FFWBP:Device says it's a <%s>\n", current_device->Product ); + + #ifdef DEBUG + { + // Dump out the full controller/VMU info. + SHARON ( "Controller/VMU dump.\n" ); + DIDeviceInfo *curdev = DeviceList; + while(curdev) + { + SHARON ( "Port %i: device <%s>, %i axis, %i buttons.\n", curdev->PortNumber, curdev->Product, curdev->NumAxis, curdev->NumButtons ); + MapleVMU *pVMU = curdev->pFirstVMU; + while ( pVMU != NULL ) + { + SHARON ( " Maple device number %i, type <", pVMU->iEnumNumber ); + + if ( ( pVMU->type & MDT_CONTROLLER ) != 0 ) SHARON ( "controller " ); + if ( ( pVMU->type & MDT_STORAGE ) != 0 ) SHARON ( "storage " ); + if ( ( pVMU->type & MDT_LCD ) != 0 ) SHARON ( "lcd " ); + if ( ( pVMU->type & MDT_TIMER ) != 0 ) SHARON ( "timer " ); + if ( ( pVMU->type & MDT_AUDIO_IN ) != 0 ) SHARON ( "audio-in " ); + if ( ( pVMU->type & MDT_LIGHTGUN ) != 0 ) SHARON ( "lightgun " ); + if ( ( pVMU->type & MDT_VIBRATION ) != 0 ) SHARON ( "vibration " ); + + // In theory, no device should have more than one bit set. + ASSERT ( ( pVMU->type & ( pVMU->type - 1 ) ) == 0 ); + + SHARON ( ">\n" ); + + pVMU = pVMU->pNextVMU; + } + curdev = curdev->Next; + } + SHARON ( "Dump end.\n" ); + } + #endif + + + // Clear all VMU screens, apart from the ones on the device we are using. + // On that, put the standard logo. + DIDeviceInfo *curdev = DeviceList; + while ( curdev != NULL ) + { + MapleVMU *pVMU = curdev->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_LCD ) + { + BYTE bTest[192]; + if ( curdev == current_device ) + { + // Display the UC logo. + extern VMU_Screen *pvmuscreenUCLogo; + pVMU->Lcd_WriteScreen ( pvmuscreenUCLogo, TRUE ); + } + else + { + // Blank all the other screens. + memset ( bTest, 0, 192 ); + pVMU->Lcd_WriteScreen ( bTest, TRUE ); + } + + } + pVMU = pVMU->pNextVMU; + } + curdev = curdev->Next; + } + return ( current_device ); + } + } + } + break; + } + + } + + current_device = current_device->Next; + } + + // None found. + return ( NULL ); +} + + + + + +#ifdef TARGET_DC + + +// VMU file handling library. + + + + +BOOL CALLBACK FlashEnumProc(LPCMAPLEDEVICEINSTANCE pmdi, LPVOID pvContext) +{ + DWORD dwPort = pmdi->dwPort; + DIDriverManager *pthis = (DIDriverManager *)pvContext; + + + bool bAdded = FALSE; + DIDeviceInfo *current_device = pthis->DeviceList; + while(current_device) + { + if ( current_device->PortNumber == dwPort ) + { + // Add this device to the controller. + MapleVMU *pVMU = MFnew(); + ASSERT ( pVMU != NULL ); + + pVMU->type = pmdi->devType; + pVMU->iEnumNumber = pmdi->dwDevNum - 1; + pVMU->guid = pmdi->guidDevice; + pVMU->pNextVMU = current_device->pFirstVMU; + + DWORD dwControllerDirection = DIPROP_EXTRACT_EXPDIRECTION ( current_device->dwDirection, pmdi->dwDevNum ); + if ( ( ( pmdi->dwDirection == MAPLEDEV_EXPDIR_TOP ) && ( dwControllerDirection == DIPROP_EXPDIR_TOP ) ) || + ( ( pmdi->dwDirection == MAPLEDEV_EXPDIR_BOTTOM ) && ( dwControllerDirection == DIPROP_EXPDIR_BOTTOM ) ) ) + { + // Directions match, so the VMU is upside down. + pVMU->bUpsideDown = TRUE; + } + else + { + // Directions don't match, so they're not. + pVMU->bUpsideDown = TRUE; + } + + current_device->pFirstVMU = pVMU; + + m_iNumMapleDevices++; + + bAdded = TRUE; + break; + } + current_device = current_device->Next; + } + + ASSERT ( bAdded ); + + return(TRUE); +} + + + + + +// Scan for VMUs, and attach any you find to the respective controllers. +// Returns the number of VMUs found. +int DIDriverManager::ScanForVMUs() +{ + // Clean out the Maple devices. + m_iNumMapleDevices = 0; + DIDeviceInfo *current_device = DeviceList; + while(current_device) + { + while ( current_device->pFirstVMU != NULL ) + { + MapleVMU *pVMU = current_device->pFirstVMU; + current_device->pFirstVMU = pVMU->pNextVMU; + + MFdelete(pVMU); + } + current_device = current_device->Next; + } + + MapleEnumerateDevices ( MDT_ALLDEVICES, FlashEnumProc, (void *)this, 0 ); + + return ( m_iNumMapleDevices ); + +} + + + + + + +// Call these to make sure you've grabbed the interface pointer. +void MapleVMU::EnsureDevicePtr ( void ) +{ + if ( pUnknown != NULL ) + { + // Already done. + return; + } + + HRESULT hres; + switch ( type ) + { + case MDT_STORAGE : + hres = MapleCreateDevice ( &guid, (IUnknown **)&pFlash ); + break; + case MDT_LCD : + hres = MapleCreateDevice ( &guid, (IUnknown **)&pLcd ); + break; + case MDT_TIMER : + hres = MapleCreateDevice ( &guid, (IUnknown **)&pTimer ); + break; + case MDT_VIBRATION : + hres = MapleCreateDevice ( &guid, (IUnknown **)&pVib ); + break; + case MDT_CONTROLLER : + case MDT_AUDIO_IN : + case MDT_LIGHTGUN : + default: + ASSERT ( FALSE ); + pUnknown = NULL; + return; + break; + } + + if ( FAILED ( hres ) ) + { + // Nads. + ASSERT ( FALSE ); + pUnknown = NULL; + } + +} + +// Write this standard 48x32 bitmap to the LCD. +// Data format is 6x32 bytes, like you'd expect, except that the +// VMU is upside down & back to front of course! +// If bQueue is TRUE, this always works. +// If bQueue is FALSE, if there is a problem, like it's busy, +// then it can fail, and the return is FALSE; +// If the LCD screen is not a standard type, then it does its best, +// or fails and returns FALSE. + +bool MapleVMU::Lcd_WriteScreen ( void *pvData, bool bQueue ) +{ + ASSERT ( type == MDT_LCD ); + EnsureDevicePtr(); + + if ( !pLcd->IsStandardLcd() ) + { + // Bleuch. No. + return FALSE; + } + + HRESULT hres; + if ( pLcdBuffer == NULL ) + { + ASSERT ( dwLcdBufferId == 0 ); + hres = pLcd->GetLcdBuffer ( &pLcdBuffer, &dwLcdBufferId, 192 ); + if ( FAILED ( hres ) ) + { + return FALSE; + } + } + else + { + ASSERT ( dwLcdBufferId != 0 ); + } + + memcpy ( pLcdBuffer, pvData, 192 ); + + hres = pLcd->SendLcdBuffer ( dwLcdBufferId, 0, 0, 0, NULL ); + if ( FAILED ( hres ) ) + { + return FALSE; + } + + return TRUE; +} + + +// Same, but with a VMU_Screen argument. +bool MapleVMU::Lcd_WriteScreen ( VMU_Screen *pvmuScreen, bool bQueue ) +{ + ASSERT ( type == MDT_LCD ); + EnsureDevicePtr(); + + ASSERT ( pvmuScreen != NULL ); + RotateVMUScreen ( bUpsideDown, pvmuScreen); + + return Lcd_WriteScreen ( (void *)(pvmuScreen->bData), bQueue ); +} + + +// Checks to see if the VMU has been formatted. +bool Flash_CheckVMUOK ( MapleVMU *pthis ) +{ + ASSERT ( pthis->type == MDT_STORAGE ); + if ( ( pthis == NULL ) || ( pthis->pFlash == NULL ) ) + { + return FALSE; + } + HRESULT hres = pthis->pFlash->CheckFormat(); + if ( FAILED ( hres ) ) + { + return FALSE; + } + else + { + return TRUE; + } +} + + +// Max number of entries. +#define MAX_DIRECTORY_ENTRIES 50 +// Lenght of longest name +#define MAX_DIRECTORY_LENGTH MAX_FLASH_FILE_NAME + +int m_iNumDirectoryFiles; +char m_szDir[MAX_DIRECTORY_ENTRIES+1][MAX_DIRECTORY_LENGTH+1]; +char *m_pszDirectory[MAX_DIRECTORY_ENTRIES+1]; + + +// The directory callback. +BOOL Flash_GetDirectoryCallback ( LPFLASHDEVICE pIFlashDevice, FSFILEID fsfileid, LPCFSFILEDESC lpcfsfiledesc, void *pvContext ) +{ + // When called by FastEnumFlashFiles, only the filename is valid in lpcfsfiledesc. + if ( m_iNumDirectoryFiles < MAX_DIRECTORY_ENTRIES ) + { + if ( strlen ( lpcfsfiledesc->szFileName ) < MAX_DIRECTORY_LENGTH - 1 ) + { + // Add this filename to the list. + strncpy ( m_szDir[m_iNumDirectoryFiles], lpcfsfiledesc->szFileName, MAX_DIRECTORY_LENGTH ); + m_pszDirectory[m_iNumDirectoryFiles] = m_szDir[m_iNumDirectoryFiles]; + m_iNumDirectoryFiles++; + } + else + { + // Long filename - sod it, coz we're only interested in ours anyway, which are all 8.3 format. + ASSERT ( FALSE ); + } + + // Always terminate with an empty string. + m_szDir[m_iNumDirectoryFiles][0] = '\0'; + m_pszDirectory[m_iNumDirectoryFiles] = NULL; + } + + return TRUE; +} + + + +// Get a directory of the flash device. Return is an array of strings. +// YOU DO NOT OWN THIS ARRAY. If you want to use it or store it, +// copy it. The array may change/move next time you do any Maple call. +// A return value of NULL indicates an error. +char **MapleVMU::Flash_GetDirectory ( void ) +{ + ASSERT ( type == MDT_STORAGE ); + EnsureDevicePtr(); + if ( !Flash_CheckVMUOK ( this ) ) + { + // Don't auto-format. + return NULL; + } + + m_iNumDirectoryFiles = 0; + + HRESULT hres = pFlash->FastEnumFlashFiles ( Flash_GetDirectoryCallback, NULL ); + if ( FAILED ( hres ) ) + { + return NULL; + } + + return m_pszDirectory; +} + + +// Returns the number of free blocks in this VMU. +// If there is an error, -1 is returned. +int MapleVMU::Flash_GetFreeBlocks ( void ) +{ + ASSERT ( type == MDT_STORAGE ); + EnsureDevicePtr(); + if ( !Flash_CheckVMUOK ( this ) ) + { + // Don't auto-format. + return -1; + } + + FSDEVICEDESC fsdevdesc; + fsdevdesc.dwSize = sizeof ( fsdevdesc ); + fsdevdesc.dwFlags = FSDD_FREE_BLOCKS; + HRESULT hres = pFlash->GetDeviceDesc ( &fsdevdesc ); + if ( FAILED ( hres ) ) + { + return -1; + } + + return (signed int)( fsdevdesc.dwFreeBlocks ); + +} + + +// Opens the given flash file. +// NULL if it failed. +LPFLASHFILE OpenVMUFile ( MapleVMU *pthis, char *pName ) +{ + LPFLASHFILE pFile; + + if ( ( pthis == NULL ) || ( pthis->pFlash == NULL ) ) + { + return NULL; + } + HRESULT hres = pthis->pFlash->OpenFlashFileByName ( &pFile, pName ); + if ( FAILED ( hres ) ) + { + return NULL; + } + else + { + return pFile; + } +} + + + +// Get the size of the given file. If it doesn't exist, the result is -1. +DWORD MapleVMU::Flash_GetFileSize ( char *pcFilename ) +{ + ASSERT ( type == MDT_STORAGE ); + EnsureDevicePtr(); + if ( !Flash_CheckVMUOK ( this ) ) + { + // Don't auto-format. + return -1; + } + + LPFLASHFILE pFile = OpenVMUFile ( this, pcFilename ); + if ( pFile == NULL ) + { + return -1; + } + else + { + DWORD dwSize; + FSFILEDESC desc; + + ZeroMemory ( &desc, sizeof ( desc ) ); + desc.dwSize = sizeof ( desc ); + desc.dwFlags = FSFD_TOTAL_BYTES; + + HRESULT hres = pFile->GetFileDesc ( &desc ); + if ( FAILED ( hres ) ) + { + dwSize = -1; + } + else + { + dwSize = desc.dwTotalBytes; + } + + pFile->Release(); + + return dwSize; + } +} + +// Reads the given file into pvData, which is of size dwSizeOfData. +// Return is TRUE on success, FALSE on failure. +bool MapleVMU::Flash_ReadFile ( char *pcFilename, void *pvData, DWORD dwSizeOfData ) +{ + ASSERT ( type == MDT_STORAGE ); + EnsureDevicePtr(); + if ( !Flash_CheckVMUOK ( this ) ) + { + // Don't auto-format. + return FALSE; + } + + // Reading past the end of the file is an error, so first + // we need to find the size of the file. + DWORD dwFileSize = Flash_GetFileSize ( pcFilename ); + if ( dwFileSize == -1 ) + { + // File doesn't exist or something. + return FALSE; + } + + // Don't read past the end. + if ( dwSizeOfData > dwFileSize ) + { + dwSizeOfData = dwFileSize; + } + + LPFLASHFILE pFile = OpenVMUFile ( this, pcFilename ); + if ( pFile == NULL ) + { + // This should never happen if we checked the size with GetFileSize. + //ASSERT ( FALSE ); + return FALSE; + } + else + { + HRESULT hres = pFile->Read ( 0, dwSizeOfData, (BYTE *)pvData ); + if ( FAILED ( hres ) ) + { + pFile->Release(); + return FALSE; + } + else + { + pFile->Release(); + return TRUE; + } + } +} + +// Creates the given file & writes the given data to it. +// pcGameName is the game name you wish to be tagged onto the file. Must be less than 16 chars. +// pcComment is any comment you wish to be tagged onto the file. Must be less than 16 chars. +// If the file already exists, it is deleted. +// If there is not enough space on the device, the call will fail. +// Return is TRUE on success, FALSE on failure. +bool MapleVMU::Flash_WriteFile ( char *pcFilename, char *pcGameName, char *pcComment, void *pvData, DWORD dwSizeOfData, + char *pcIconPalette, char *pcIconData ) +{ + ASSERT ( type == MDT_STORAGE ); + EnsureDevicePtr(); + if ( !Flash_CheckVMUOK ( this ) ) + { + // Don't auto-format. + return FALSE; + } + + if ( strlen ( pcFilename ) > ( MAX_FLASH_FILE_NAME - 1 ) ) + { + // Too long. + ASSERT ( FALSE ); + return FALSE; + } + + FSFILEDESC desc; + ZeroMemory ( &desc, sizeof ( desc ) ); + desc.dwSize = sizeof ( desc ); + desc.dwFlags = FSFD_CREATE_FILE; + + //FSFD_CREATE_FILE equals these flags: + //FSFD_BYTES_REQUIRED + //FSFD_FILE_NAME + //FSFD_VMS_COMMENT + //FSFD_BOOT_ROM_COMMENT + //FSFD_GAME_NAME + //FSFD_STATUS + //FSFD_COPY + //FSFD_FILEICON + + desc.dwBytesRequired = dwSizeOfData; + strncpy ( desc.szFileName, pcFilename, MAX_FLASH_FILE_NAME-1 ); + desc.szFileName[MAX_FLASH_FILE_NAME-1] = '\0'; + + if ( pcGameName != NULL ) + { + char pcTemp[MAX_VMS_COMMENT]; + DWORD dwMaxLength = MIN ( MAX_VMS_COMMENT, MIN ( MAX_BOOT_ROM_COMMENT, MAX_GAME_NAME ) ); + dwMaxLength--; + strncpy ( pcTemp, pcGameName, dwMaxLength ); + pcTemp[dwMaxLength] = '\0'; + + // If pcComment is NULL, we use the game name anyway. + strcpy ( desc.szVMSComment, pcTemp ); + strcpy ( desc.szBootROMComment, pcTemp ); + strcpy ( desc.szGameName, pcTemp ); + } + else + { + desc.szVMSComment[0] = '\0'; + desc.szBootROMComment[0] = '\0'; + desc.szGameName[0] = '\0'; + } + + if ( pcComment != NULL ) + { + char pcTemp[MAX_VMS_COMMENT]; + DWORD dwMaxLength = MIN ( MAX_VMS_COMMENT, MIN ( MAX_BOOT_ROM_COMMENT, MAX_GAME_NAME ) ); + dwMaxLength--; + strncpy ( pcTemp, pcComment, dwMaxLength ); + pcTemp[dwMaxLength] = '\0'; + + strcpy ( desc.szVMSComment, pcTemp ); + } + + desc.bStatus = FS_STATUS_DATA_FILE; + desc.bCopy = FS_COPY_ENABLED; + + desc.fsfileicon.bAnimationFrames = 1; + desc.fsfileicon.bAnimationDelay = 1; + if ( pcIconPalette != NULL ) + { + ASSERT ( pcIconData != NULL ); + memcpy ( desc.fsfileicon.palette, pcIconPalette, 16*2 ); + memcpy ( desc.fsfileicon.pixelsFrame1, pcIconData, 32*16 ); + } + else + { + ASSERT ( pcIconData == NULL ); + memset ( desc.fsfileicon.palette, 0, 16*2 ); + memset ( desc.fsfileicon.pixelsFrame1, 0, 32*16 ); + } + + + LPFLASHFILE pFile = NULL; + + HRESULT hres = pFlash->CreateFlashFile ( &pFile, &desc ); + if ( FAILED ( hres ) ) + { + // May already exist - try deleting it. + pFile = OpenVMUFile ( this, pcFilename ); + if ( pFile == NULL ) + { + // No, doesn't exist - just a general failure. + return FALSE; + } + else + { + // Does exist - bin it. + hres = pFile->Delete(); + pFile->Release(); + if ( FAILED ( hres ) ) + { + // Double nads - file exists but can't be deleted???? + return FALSE; + } + else + { + // Good. Now create it again. + HRESULT hres = pFlash->CreateFlashFile ( &pFile, &desc ); + if ( FAILED ( hres ) ) + { + // Nope - maybe we're out of space or something. + return FALSE; + } + } + } + } + + // If we got here, the file was crated successfully. + ASSERT ( pFile != NULL ); + hres = pFile->Write ( 0, dwSizeOfData, (BYTE *)pvData ); + if ( FAILED ( hres ) ) + { + pFile->Release(); + return FALSE; + } + + // And flush the controller. + hres = pFile->Flush(); + if ( FAILED ( hres ) ) + { + pFile->Release(); + return FALSE; + } + + pFile->Release(); + return TRUE; + +} + + + +// Allows or disallows the automatic update of VMU screens. +// This can be quite slow, and for time-critical things (e.g. +// video playbacl), you'll want to turn it off. Do turn it back on +// afterwards though. +void SetVMUScreenUpdateEnable ( bool bEnable ) +{ + the_input_manager.bVMUScreenUpdatesEnabled = bEnable; +} + + + +// Gets the first VMU on the primary controller. If it can't find it, +// it takes the first VMU on the first controller it finds. +MapleVMU *FindFirstVMUOnCurrentController ( void ) +{ + if ( primary_device != NULL ) + { + MapleVMU *pVMU = primary_device->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_STORAGE ) + { + return pVMU; + } + pVMU = pVMU->pNextVMU; + } + } + + // Not found on primary, or no primary. + DIDeviceInfo *curdev = the_input_manager.DeviceList; + while ( curdev != NULL ) + { + MapleVMU *pVMU = curdev->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_STORAGE ) + { + return pVMU; + } + pVMU = pVMU->pNextVMU; + } + curdev = curdev->Next; + } + + // No VMUs at all. + return NULL; + +} + + +// Tries to find a memory VMU at slot iVMUNum on controller iCtrlNum. +// If not, returns NULL. Controllers are numbered 0-3, VMU numbers 0-1. +MapleVMU *FindMemoryVMUAt ( int iCtrlNum, int iVMUNum ) +{ + // Not found on primary, or no primary. + DIDeviceInfo *curdev = the_input_manager.DeviceList; + while ( curdev != NULL ) + { + if ( curdev->PortNumber == iCtrlNum ) + { + MapleVMU *pVMU = curdev->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_STORAGE ) + { + if ( pVMU->iEnumNumber == iVMUNum ) + { + return pVMU; + } + } + pVMU = pVMU->pNextVMU; + } + } + curdev = curdev->Next; + } + + // Not found. + return ( NULL ); +} + + + +// A routine to rotate a VMU screen. +// This not just a vertical flip, it needs to do a horizontal flip as well. +// This converts the VMU screen to the desired orientation, +// so it may not actually do anything! + +static BYTE bFlipNibble[16] = +{ + 0x0, // 0000 -> 0000 + 0x8, // 0001 -> 1000 + 0x4, // 0010 -> 0100 + 0xc, // 0011 -> 1100 + 0x2, // 0100 -> 0010 + 0xa, // 0101 -> 1010 + 0x6, // 0110 -> 0110 + 0xe, // 0111 -> 1110 + 0x1, // 1000 -> 0001 + 0x9, // 1001 -> 1001 + 0x5, // 1010 -> 0101 + 0xd, // 1011 -> 1101 + 0x3, // 1100 -> 0011 + 0xb, // 1101 -> 1011 + 0x7, // 1110 -> 0111 + 0xf, // 1111 -> 1111 +}; + +void RotateVMUScreen ( bool bRotated, VMU_Screen *pvmuScreen ) +{ + if ( bRotated != pvmuScreen->bRotated ) + { + pvmuScreen->bRotated = bRotated; + + // OK, they're really both sources and both dests. Sue me. + BYTE *pbSrc = &(pvmuScreen->bData[0]); + BYTE *pbDst = &(pvmuScreen->bData[32*6-1]); + for ( int i = 0; i < 32*3; i++ ) + { + // Reverse the bits + BYTE bData1 = *pbSrc; + BYTE bData2 = *pbDst; + + bData1 = ( bFlipNibble[bData1&0xf] << 4 ) | bFlipNibble[bData1>>4]; + bData2 = ( bFlipNibble[bData2&0xf] << 4 ) | bFlipNibble[bData2>>4]; + + // And swap them over. + *pbSrc = bData2; + *pbDst = bData1; + + pbSrc++; + pbDst--; + } + } +} + + +// A routine for converting a TGA to a VMU screen bitmap. +bool CreateVMUScreenFromTGA ( char *pchName, VMU_Screen **ppvmuScreen ) +{ + TGA_Pixel pPixelData[32*48]; + + ASSERT ( *ppvmuScreen == NULL ); + + // Load the savegame icon from disk. +extern TGA_Info TGA_load_from_file(const CBYTE *file, SLONG max_width, SLONG max_height, TGA_Pixel* data, BOOL bCanShrink); + TGA_Info tga_info = TGA_load_from_file ( pchName, 48, 32, pPixelData, FALSE ); + if ( tga_info.valid ) + { + // Create the screen. + *ppvmuScreen = MFnew(); + ASSERT ( *ppvmuScreen != NULL ); + + // Convert to black and while. + UBYTE *pbDst = (**ppvmuScreen).bData; + TGA_Pixel *pcSrc = pPixelData; + for ( int iY = 0; iY < 32; iY++ ) + { + for ( int iX1 = 0; iX1 < 6; iX1++ ) + { + UBYTE bThisByte = 0; + for ( int iX2 = 0; iX2 < 8; iX2++ ) + { + bThisByte <<= 1; + // Just take the red channel! + if ( pcSrc->red < 128 ) + { + bThisByte |= 1; + } + pcSrc++; + } + *pbDst++ = bThisByte; + } + } + + (*ppvmuScreen)->bRotated = FALSE; + + return TRUE; + } + else + { + ASSERT ( FALSE ); + return FALSE; + } +} + + + +// Displays the given screen on all the screen devices on the current controller. +// This is what you call to display an image. +// If there is no primary, it doesn't do anything - the "press any key" screen should be up. +bool WriteLCDScreenToCurrentController ( VMU_Screen *pvmuScreen ) +{ + if ( primary_device == NULL ) + { + return FALSE; + } + + MapleVMU *pVMU = primary_device->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_LCD ) + { + pVMU->Lcd_WriteScreen ( pvmuScreen, TRUE ); + } + pVMU = pVMU->pNextVMU; + } + + return TRUE; +} + + + +GUID m_guidCurrentVMU = GUID_NULL; + +// Returns the current VMU. If it can't be found any more, and +// bFindNextBest is TRUE, it tries to find the first one on the +// primary, and then tries to find the first one on anything. +// If bFindNextBest is FALSE, it just returns NULL. +MapleVMU *FindCurrentStorageVMU ( bool bFindNextBest ) +{ + if ( !IsEqualGUID ( m_guidCurrentVMU, GUID_NULL ) ) + { + // Look for the current one. + DIDeviceInfo *curdev = the_input_manager.DeviceList; + while ( curdev != NULL ) + { + MapleVMU *pVMU = curdev->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_STORAGE ) + { + if ( pVMU->guid == m_guidCurrentVMU ) + { + return pVMU; + } + } + pVMU = pVMU->pNextVMU; + } + curdev = curdev->Next; + } + } + + // Not found, or no current. + if ( bFindNextBest ) + { + // Find the first on the primary. + if ( primary_device != NULL ) + { + MapleVMU *pVMU = primary_device->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_STORAGE ) + { + return pVMU; + } + pVMU = pVMU->pNextVMU; + } + } + + // OK, well try all the other devices. + DIDeviceInfo *curdev = the_input_manager.DeviceList; + while ( curdev != NULL ) + { + MapleVMU *pVMU = curdev->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_STORAGE ) + { + return pVMU; + } + pVMU = pVMU->pNextVMU; + } + curdev = curdev->Next; + } + } + + return NULL; +} + + +// Sets the current storage VMU. If NULL, there will be no current VMU. +void SetCurrentStorageVMU ( MapleVMU *pVMU ) +{ + if ( pVMU == NULL ) + { + m_guidCurrentVMU = GUID_NULL; + } + else + { + ASSERT ( pVMU->type == MDT_STORAGE ); + m_guidCurrentVMU = pVMU->guid; + } +} + + + + + +// Tries to find a vibration VMU on the primary. If there are two (unlikely), +// it retruns the first one. If there are none, it returns NULL. +// Yes, I know they're not actually VMUs that vibrate. +MapleVMU *FindFirstVibratorOnCurrentController ( void ) +{ + if ( primary_device != NULL ) + { + MapleVMU *pVMU = primary_device->pFirstVMU; + while ( pVMU != NULL ) + { + if ( pVMU->type == MDT_VIBRATION ) + { + // Found one! + return pVMU; + } + pVMU = pVMU->pNextVMU; + } + } + + return NULL; +} + + + +bool m_bVibrationsEnabled = TRUE; + +void SetVibrationEnable ( bool bEnabled ) +{ + m_bVibrationsEnabled = bEnabled; +} + + +// Make the vibrator in the primary device vibrate with the given +// characteristics. Returns TRUE if it works, or FALSE if not. +// The most common cause of FALSE is that another vibration +// is already happening, or was set off very recently. + +static HANDLE m_hVibrationEvent = NULL; + +bool Vibrate ( float fFrequency, float fStartPower, float fShrinkTime, bool bEnsureThisHappens ) +{ + if ( !m_bVibrationsEnabled ) + { + // Shan't. + return FALSE; + } + + MapleVMU *pVib = FindFirstVibratorOnCurrentController(); + if ( pVib != NULL ) + { + ASSERT ( pVib->type == MDT_VIBRATION ); + pVib->EnsureDevicePtr(); + + // The Fishing rod doesn't like me creating a vibration device, so at least make sure it doesn't crash. + // Can alos happen if you rip the pack out at just the wrong time. + if ( pVib->pVib == NULL ) + { + return FALSE; + } + + if ( !pVib->Vib_bGotDevInfo ) + { + // Get the device info. + UINT iTemp1 = 1; + UINT iTemp2; + VIB_INFO vibInfo; + HRESULT hres = pVib->pVib->GetVibInfo ( &iTemp1, &iTemp2, &vibInfo ); + ASSERT ( SUCCEEDED ( hres ) ); + + pVib->Vib_fMinFreq = ( vibInfo.minFrequency + 1 ) * (float)VIB_FREQ_INCREMENT_HZ; + pVib->Vib_fMaxFreq = ( vibInfo.maxFrequency + 1 ) * (float)VIB_FREQ_INCREMENT_HZ; + + pVib->Vib_bGotDevInfo = TRUE; + } + + if ( m_hVibrationEvent == NULL ) + { + // Set up the event. + m_hVibrationEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + } + + VIB_SETTINGS vibset; + + if ( fStartPower > 1.0f ) + { + fStartPower = 1.0f; + } + else if ( fStartPower < 0.0f ) + { + // Ok then, I won't. + return FALSE; + } + + if ( fFrequency > pVib->Vib_fMaxFreq ) + { + fFrequency = pVib->Vib_fMaxFreq; + } + else if ( fFrequency < pVib->Vib_fMinFreq ) + { + if ( fFrequency < 0.0f ) + { + // Ok then, I won't. + return FALSE; + } + else + { + fFrequency = pVib->Vib_fMinFreq; + } + } + + + vibset.sourceId = 1; + vibset.bContinuousVib = FALSE; + vibset.initialPower = (BYTE)( fStartPower * (float)VIB_POWER_MAX ); + vibset.direction = VIB_DIRECTION_FORWARD; + vibset.frequency = (BYTE)( fFrequency * ( 1.0f / (float)VIB_FREQ_INCREMENT_HZ ) - 1.0f + 0.4999f ); + + if ( fShrinkTime > 0.0f ) + { + // Shrinking with time, e.g. explosion. + vibset.vibType = VIB_TYPE_CONVERGENT; + // This says how many waves go before the power goes down by one. + vibset.wavesPerStep = (BYTE)( ( ( fShrinkTime * fFrequency ) / ( fStartPower * (float)VIB_POWER_MAX ) ) + 0.5f ); + if ( vibset.wavesPerStep == 0 ) + { + // 0 makes it not work. + vibset.wavesPerStep = 1; + } + + TRACE ( "Vibrated with freq %f, power %f, shrinktime %f\n", fFrequency, fStartPower, fShrinkTime ); + } + else + { + // One-shot, e.g. gunshots. + vibset.vibType = VIB_TYPE_CONSTANT; + vibset.wavesPerStep = 0; + + TRACE ( "Vibrated with freq %f, power %f, one-shot.\n", fFrequency, fStartPower, fShrinkTime ); + } + + + // We have a manual reset event that was created in the signaled state. + // So, the first time through here, the Wait will return immediately. + // We pass that event to Vibrate. Because the parameter is not NULL, + // Vibrate will return quickly with VIBERR_PENDING. We then go off + // and do other things. When the command to the device finishes, + // the Api will signal our event. So, the next time we get here + // that Wait will return immediately again. If, however, we tried to + // call the api again very quickly (before it finished the last call) + // we'd wait here until the previous call was finished. The calls + // shouldn't take more than 2 frames to complete, and it's unlikely + // that we'll tell the device to vibrate twice in that time frame (a + // human won't be able to feel changes that quick), so this is okay. + + // Waiting two frames sounds pretty bad though, and may happen if, + // for example, two people fire guns at the same time. Well, if it happens, + // I'll bin the waiting one. + + + // First make sure the previous send is finished. + DWORD dwWaitReturn; + if ( bEnsureThisHappens ) + { + // Use quite a long timeout - this is an important vibration + // (e.g. a large, long-lasting one, such as an explosion). + dwWaitReturn = WaitForSingleObject ( m_hVibrationEvent, 100 ); + } + else + { + dwWaitReturn = WaitForSingleObject ( m_hVibrationEvent, 0 ); + } + + if ( dwWaitReturn == WAIT_TIMEOUT ) + { + // Nads - not going to hang around any longer. + // There was already a vibro command being sent, so tough - + // this one gets ditched. + return FALSE; + } + + ResetEvent ( m_hVibrationEvent ); + + // Start the vibration. + HRESULT hres = pVib->pVib->Vibrate ( 1, &vibset, m_hVibrationEvent ); + if ( hres == VIBERR_DEVICEUNPLUGGED ) + { + // Since there was an error, our event was never signaled. + SetEvent ( m_hVibrationEvent ); + return FALSE; + } + else if ( ( hres != VIB_OK ) && ( hres != VIBERR_PENDING ) ) + { + // Since there was an error, our event was never signaled. + SetEvent ( m_hVibrationEvent ); + return FALSE; + } + + return TRUE; + + } + + return FALSE; +} + + + + +#endif //#ifdef TARGET_DC + + + +//--------------------------------------------------------------- + + +#else // The new PC implementation.... + + + + +// ======================================================== +// +// JOYSTICK STUFF +// +// ======================================================== + +IDirectInput *OS_joy_direct_input; +IDirectInputDevice *OS_joy_input_device; +IDirectInputDevice2 *OS_joy_input_device2; // We need this newer interface to poll the joystick. + +SLONG OS_joy_x_range_min; +SLONG OS_joy_x_range_max; +SLONG OS_joy_y_range_min; +SLONG OS_joy_y_range_max; + +// +// The callback function for enumerating joysticks. +// + +BOOL CALLBACK OS_joy_enum( + LPCDIDEVICEINSTANCE instance, + LPVOID context ) +{ + HRESULT hr; + LPDIRECTINPUTDEVICE pDevice; + + // + // Get an interface to the joystick. + // + + hr = OS_joy_direct_input->CreateDevice( + instance->guidInstance, + &OS_joy_input_device, + NULL); + + if (FAILED(hr)) + { + // + // Cant use this joystick for some reason! + // + + OS_joy_input_device = NULL; + OS_joy_input_device2 = NULL; + + return DIENUM_CONTINUE; + } + + // + // Query for the IDirectInputDevice2 interface. + // We need this to poll the joystick. + // + + OS_joy_input_device->QueryInterface( + IID_IDirectInputDevice2, + (LPVOID *) &OS_joy_input_device2); + + // + // No need to find another joystick! + // + + return DIENUM_STOP; +} + +// +// Initialises the joystick. +// + +void OS_joy_init(void) +{ + HRESULT hr; + + // + // Initialise everything. + // + + OS_joy_direct_input = NULL; + OS_joy_input_device = NULL; + OS_joy_input_device2 = NULL; + + // + // Create the direct input object. + // + + CoInitialize(NULL); + +#ifdef MAD_AM_I + + CoCreateInstance( + CLSID_DirectInput8, + NULL, + CLSCTX_INPROC_SERVER, + IID_IDirectInput8W, + (void **) &OS_joy_direct_input); + + extern HINSTANCE hGlobalThisInst; + + hr = OS_joy_direct_input->Initialize(hGlobalThisInst, DIRECTINPUT_VERSION); +#else + return; +#endif + + if (hr != DI_OK) + { + if (hr == DIERR_BETADIRECTINPUTVERSION) + { + return; + } + + if (hr == DIERR_OLDDIRECTINPUTVERSION) + { + return; + } + + return; + } + + /* + + hr = DirectInputCreateEx( + OS_this_instance, + DIRECTINPUT_VERSION, + &OS_joy_direct_input, + NULL); + + if (FAILED(hr)) + { + // + // No direct input! + // + + return; + } + + */ + + // + // Find a joystick. + // + + hr = OS_joy_direct_input->EnumDevices( + DIDEVTYPE_JOYSTICK, + OS_joy_enum, + NULL, + DIEDFL_ATTACHEDONLY); + + if (OS_joy_input_device == NULL || + OS_joy_input_device2 == NULL) + { + // + // The joystick wasn't properly found. + // + + OS_joy_input_device = NULL; + OS_joy_input_device2 = NULL; + + return; + } + + // + // So we can get the nice 'n' simple joystick data format. + // + + OS_joy_input_device->SetDataFormat(&c_dfDIJoystick); + + // + // Grab the joystick exclusively when our window in the foreground. + // + + OS_joy_input_device->SetCooperativeLevel( + hDDLibWindow, + DISCL_EXCLUSIVE | DISCL_FOREGROUND); + + // + // What is the range of the joystick? + // + + DIPROPRANGE diprg; + + // + // In x... + // + + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.diph.dwObj = DIJOFS_X; + diprg.lMin = 0; + diprg.lMax = 0; + + OS_joy_input_device->GetProperty( + DIPROP_RANGE, + &diprg.diph); + + OS_joy_x_range_min = diprg.lMin; + OS_joy_x_range_max = diprg.lMax; + + // + // In y... + // + + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.diph.dwObj = DIJOFS_Y; + diprg.lMin = 0; + diprg.lMax = 0; + + OS_joy_input_device->GetProperty( + DIPROP_RANGE, + &diprg.diph); + + OS_joy_y_range_min = diprg.lMin; + OS_joy_y_range_max = diprg.lMax; + +} + +// +// Polls the joystick. +// + +SLONG OS_joy_poll(void) +{ + HRESULT hr; + + if (OS_joy_direct_input == NULL || + OS_joy_input_device == NULL || + OS_joy_input_device2 == NULL) + { + // + // No joystick detected. + // + + memset(&the_state, 0, sizeof(the_state)); + + return FALSE; + } + + SLONG acquired_already = FALSE; + + try_again_after_acquiring:; + + { + // + // We acquired the joystick okay. Poll the joystick to + // update its state. + // + + OS_joy_input_device2->Poll(); + + // + // Finally get the state of the joystick. + // + + hr = OS_joy_input_device->GetDeviceState(sizeof(the_state), &the_state); + + if (hr == DIERR_NOTACQUIRED || + hr == DIERR_INPUTLOST) + { + if (acquired_already) + { + // + // Oh dear! + // + + memset(&the_state, 0, sizeof(the_state)); + + return FALSE; + } + else + { + hr = OS_joy_input_device->Acquire(); + + if (hr == DI_OK) + { + acquired_already = TRUE; + + goto try_again_after_acquiring; + } + else + { + memset(&the_state, 0, sizeof(the_state)); + + return FALSE; + } + } + } + } + + return TRUE; +} + + + +BOOL GetInputDevice(UBYTE type, UBYTE sub_type, bool bActuallyGetOne) +{ + if (type == JOYSTICK && bActuallyGetOne) + { + if (!OS_joy_direct_input) + { + OS_joy_init(); + } + } + + if (OS_joy_input_device && + OS_joy_input_device2) + { + return TRUE; + } + else + { + return FALSE; + } +} + +BOOL ReadInputDevice() +{ + return OS_joy_poll(); +} + + + +#endif + + + + + + + + + + + diff --git a/fallen/DDLibrary/Source/DSManager.cpp b/fallen/DDLibrary/Source/DSManager.cpp new file mode 100644 index 0000000..d688330 --- /dev/null +++ b/fallen/DDLibrary/Source/DSManager.cpp @@ -0,0 +1,80 @@ +// DSManager.cpp +// Guy Simmons, 22nd February 1998 + +#include "DDLib.h" + + +DSDriverManager the_sound_manager; + +//--------------------------------------------------------------- +// +// Callback functions. +// +//--------------------------------------------------------------- + + +//--------------------------------------------------------------- +// +// CLASS : DSDriverManager +// +//--------------------------------------------------------------- + +DSDriverManager::DSDriverManager() +{ + ManagerFlags = 0; +} + +//--------------------------------------------------------------- + +DSDriverManager::~DSDriverManager() +{ + Fini(); +} + +//--------------------------------------------------------------- + +HRESULT DSDriverManager::Init(void) +{ + HRESULT result; + + + if(!IsInitialised()) + { + // Create the DirectSound object. + result = DirectSoundCreate ( + NULL, + &lp_DS, + NULL + ); + if(FAILED(result)) + return result; + + // Set the cooperative level. + lp_DS->SetCooperativeLevel ( + hDDLibWindow, +// DSSCL_NORMAL + DSSCL_EXCLUSIVE + ); + if(FAILED(result)) + return result; + + InitOn(); + } + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT DSDriverManager::Fini(void) +{ + if(IsInitialised()) + { + // Release DirectSound. + lp_DS->Release(); + + InitOff(); + } + return DS_OK; +} + +//--------------------------------------------------------------- diff --git a/fallen/DDLibrary/Source/Drive.cpp b/fallen/DDLibrary/Source/Drive.cpp new file mode 100644 index 0000000..e748308 --- /dev/null +++ b/fallen/DDLibrary/Source/Drive.cpp @@ -0,0 +1,124 @@ +// drive.cpp +// +// CD-ROM drives + +#include "ddlib.h" +#include "drive.h" +#include "c:\fallen\headers\env.h" + +static char Path[MAX_PATH]; // CD-ROM path +static bool TexturesCD; // textures on CD? +static bool SFX_CD; // sound effects on CD? +static bool MoviesCD; // movies on CD? +static bool SpeechCD; // speech on CD? + +// Exit +// +// exit on failure + +static void Exit(void) +{ +#ifndef TARGET_DC + MessageBox(NULL, "Cannot locate Urban Chaos CD-ROM", NULL, MB_ICONERROR); +#else + ASSERT(FALSE); +#endif + exit(1); +} + +// LocateCDROM +// +// locate the CD drive containing the Urban Chaos CD + + +#ifdef TARGET_DC + + +void LocateCDROM(void) +{ + // Er... I know where it is on the DreamCast :-) +#ifdef FILE_PC +#error SPONG! + // It's on the PC. + strcpy ( Path, "\\PC\\" ); +#else + // It's on the DC itself. + strcpy ( Path, "\\CD-ROM\\" ); +#endif + +} + + +#else //#ifdef TARGET_DC + + +void LocateCDROM(void) +{ +#ifdef FINAL + TexturesCD = ENV_get_value_number("textures", 0, "LocalInstall") ? false : true; + SFX_CD = ENV_get_value_number("sfx", 0, "LocalInstall") ? false : true; + MoviesCD = ENV_get_value_number("movies", 0, "LocalInstall") ? false : true; + SpeechCD = ENV_get_value_number("speech", 0, "LocalInstall") ? false : true; +#else + TexturesCD = ENV_get_value_number("textures", 1, "LocalInstall") ? false : true; + SFX_CD = ENV_get_value_number("sfx", 1, "LocalInstall") ? false : true; + MoviesCD = ENV_get_value_number("movies", 1, "LocalInstall") ? false : true; + SpeechCD = ENV_get_value_number("speech", 1, "LocalInstall") ? false : true; +#endif + + if (!TexturesCD && !SFX_CD && !MoviesCD && !SpeechCD) return; // don't need CD-ROM + + char strings[256]; + + if (!GetLogicalDriveStrings(255, strings)) + { + MessageBox(NULL, "Cannot locate system devices - serious internal error", NULL, MB_ICONERROR); + exit(0); + } + + for (;;) + { + char* sptr = strings; + + while (*sptr) + { + if (GetDriveType(sptr) == DRIVE_CDROM) + { + char filename[MAX_PATH]; + + sprintf(filename, "%sclumps\\mib.txc", sptr); // fallen.ex_ doesnt exist on eidos funny fanny builds + + FILE* fd = MF_Fopen(filename, "rb"); + + if (fd) + { + // found it! + MF_Fclose(fd); + strcpy(Path, sptr); + return; + } + } + + sptr += strlen(sptr) + 1; + } + + if (MessageBox(NULL, "Cannot locate Urban Chaos CD-ROM", NULL, MB_ICONERROR | MB_RETRYCANCEL) == IDCANCEL) + { + break; + } + } + exit(0); +} + + +#endif //#else //#ifdef TARGET_DC + +// Get*Path + +static inline char* GetPath(bool on_cd) { return on_cd ? Path : ".\\"; } + +char* GetCDPath(void) { return Path; } +char* GetTexturePath(void) { return GetPath(TexturesCD); } +char* GetSFXPath(void) { return GetPath(SFX_CD); } +char* GetMoviesPath(void) { return GetPath(MoviesCD); } +char* GetSpeechPath(void) { return GetPath(SpeechCD); } diff --git a/fallen/DDLibrary/Source/FFManager.cpp b/fallen/DDLibrary/Source/FFManager.cpp new file mode 100644 index 0000000..618746f --- /dev/null +++ b/fallen/DDLibrary/Source/FFManager.cpp @@ -0,0 +1,90 @@ +// FFManager.cpp +// Force Feedback handler +// 18th Sept 98 +// +// Limitations: Currently assumes first joystick + + +#ifndef TARGET_DC + +#if 0 + +#include "FFManager.h" + + +FFManager* the_ff_manager; + +FFManager::FFManager() { + testeffect=0; + ForceFeedback=0; + DeviceInfo=the_input_manager.FindDevice(JOYSTICK,0,NULL,NULL); + if (!DeviceInfo) return; + lpdiInputDevice=DeviceInfo->lpdiInputDevice; + + ForceFeedback=FFSupported(lpdiInputDevice); + if (ForceFeedback) TRACE("*** Force Feedback Detected ***\n"); + +} + +FFManager::~FFManager() { + ReleaseFX(); +} + +void FFManager::ReleaseFX() { + if (testeffect) testeffect->Release(); +} + + +BOOL FFManager::FFSupported(LPDIRECTINPUTDEVICE2 device) { + DIDEVCAPS caps; + + if (!device) { + return ForceFeedback; + } else { + caps.dwSize=sizeof(caps); + device->GetCapabilities(&caps); + if (caps.dwFlags&DIDC_FORCEFEEDBACK) return 1; + return 0; + } +} + +BOOL FFManager::Test() { + DIEFFECT effect; + DICONSTANTFORCE diConstantForce; + DWORD dwAxes[2] = { DIJOFS_X, DIJOFS_Y }; + LONG lDirection[2] = { 18000, 0 }; + HRESULT res; + + if ((!ForceFeedback)||(!lpdiInputDevice)) return FALSE; + if (testeffect) testeffect->Release(); + + effect.dwSize=sizeof(effect); + effect.dwFlags = DIEFF_POLAR | DIEFF_OBJECTOFFSETS; + effect.dwDuration = (DWORD)( 0.5f * DI_SECONDS ); + effect.dwSamplePeriod = 0; // = default + effect.dwGain = DI_FFNOMINALMAX; // no scaling + effect.dwTriggerButton = DIEB_NOTRIGGER; // not a button response + effect.dwTriggerRepeatInterval = 0; // not applicable + effect.cAxes = 2; + effect.rgdwAxes = dwAxes; + effect.rglDirection = lDirection; + effect.lpEnvelope = NULL; + effect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + effect.lpvTypeSpecificParams = &diConstantForce; + + diConstantForce.lMagnitude = DI_FFNOMINALMAX; // full force + + res=lpdiInputDevice->CreateEffect(GUID_ConstantForce,&effect,&testeffect,NULL); + if (res==DI_OK) { + res=testeffect->Start(1,0); + return TRUE; + } + return FALSE; + +} + +#endif // #if 0 + +#endif //#ifndef TARGET_DC + + diff --git a/fallen/DDLibrary/Source/FileClump.cpp b/fallen/DDLibrary/Source/FileClump.cpp new file mode 100644 index 0000000..adce023 --- /dev/null +++ b/fallen/DDLibrary/Source/FileClump.cpp @@ -0,0 +1,144 @@ +// FileClump.cpp +// +// metafile class + +#include "DDLib.h" +#include "FileClump.h" + +// FileClump +// +// create a file clump + +FileClump::FileClump(const char* clumpfn, ULONG max_id, bool readonly) +{ + // basic init + ClumpFD = NULL; + MaxID = max_id; + Offsets = NULL; + Lengths = NULL; + NextOffset = 0; + ReadOnly = readonly; + + if (ReadOnly) + { + if (ClumpFD = MF_Fopen(clumpfn, "rb")) + { + // read header + fread(&MaxID, sizeof(ULONG), 1, ClumpFD); + ASSERT(MaxID == max_id); + Offsets = new size_t[MaxID]; + Lengths = new size_t[MaxID]; + fread(Offsets, sizeof(size_t), MaxID, ClumpFD); + fread(Lengths, sizeof(size_t), MaxID, ClumpFD); + } + else + { + MaxID = 0; + } + } + else + { + if (ClumpFD = MF_Fopen(clumpfn, "wb")) + { + // write dummy header + fwrite(&MaxID, sizeof(ULONG), 1, ClumpFD); + Offsets = new size_t[MaxID]; + Lengths = new size_t[MaxID]; + for (ULONG ii = 0; ii < MaxID; ii++) + { + Offsets[ii] = Lengths[ii] = 0; + } + fwrite(Offsets, sizeof(size_t), MaxID, ClumpFD); + fwrite(Lengths, sizeof(size_t), MaxID, ClumpFD); + NextOffset = sizeof(ULONG) + 2 * MaxID * sizeof(size_t); + } + else + { + MaxID = 0; + } + } +} + +// ~FileClump +// +// destroy a file clump + +FileClump::~FileClump() +{ + if (ClumpFD) + { + if (!ReadOnly) + { + // write the real header + fseek(ClumpFD, 0, SEEK_SET); + fwrite(&MaxID, sizeof(ULONG), 1, ClumpFD); + fwrite(Offsets, sizeof(size_t), MaxID, ClumpFD); + fwrite(Lengths, sizeof(size_t), MaxID, ClumpFD); + + TRACE("MaxID = %8.8X\n", MaxID); + for (ULONG ii = 0; ii < MaxID; ii++) + { + if (Offsets[ii]) TRACE("%8.8X Off %8.8X Len %8.8X\n", ii, Offsets[ii], Lengths[ii]); + } + } + MF_Fclose(ClumpFD); + } + delete[] Offsets; + delete[] Lengths; +} + +// Exists +// +// does a file exist in the clump file? + +bool FileClump::Exists(ULONG id) +{ + if (id >= MaxID) return false; + if (!Offsets[id]) return false; + + return true; +} + +// Read +// +// read a file from the clump + +UBYTE* FileClump::Read(ULONG id) +{ + if (id >= MaxID) return NULL; + if (!Offsets[id]) return NULL; + + UBYTE* buffer = new UBYTE[Lengths[id]]; + + if (buffer) + { + fseek(ClumpFD, Offsets[id], SEEK_SET); + if (fread(buffer, 1, Lengths[id], ClumpFD) != Lengths[id]) + { + delete[] buffer; + buffer = NULL; + } + } + + return buffer; +} + +// Write +// +// write a file to the clump + +bool FileClump::Write(void* buffer, size_t nbytes, ULONG id) +{ + if (id >= MaxID) return false; + if (ReadOnly) return false; + if (Offsets[id]) return false; + + fseek(ClumpFD, NextOffset, SEEK_SET); + if (fwrite(buffer, 1, nbytes, ClumpFD) != nbytes) return false; + + Offsets[id] = NextOffset; + Lengths[id] = nbytes; + NextOffset += nbytes; + + return true; +} diff --git a/fallen/DDLibrary/Source/GDebug.cpp b/fallen/DDLibrary/Source/GDebug.cpp new file mode 100644 index 0000000..d491689 --- /dev/null +++ b/fallen/DDLibrary/Source/GDebug.cpp @@ -0,0 +1,281 @@ +// Debug.cpp +// Guy Simmons, 15th November 1997. + +#include "DDLib.h" + +#ifndef NDEBUG + +HANDLE LogFile; + +//--------------------------------------------------------------- + +HANDLE InitDebugLog(void) +{ + LogFile = CreateFile ( + "DebugLog.txt", + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + CREATE_ALWAYS, + 0, + NULL + ); + if(LogFile==INVALID_HANDLE_VALUE) + { + LogFile = NULL; + } + return LogFile; +} + +//--------------------------------------------------------------- + +void FiniDebugLog(void) +{ + if(LogFile) + CloseHandle(LogFile); +} + +//--------------------------------------------------------------- + +void DebugText(CBYTE *error, ...) +{ + CBYTE buf[512]; + SLONG bytes_written; + va_list argptr; + + if(LogFile) + { + va_start(argptr,error); + vsprintf(buf, error,argptr); + va_end(argptr); + + WriteFile(LogFile,buf,strlen(buf),(LPDWORD)&bytes_written,NULL); + } +} + +//--------------------------------------------------------------- + +#define OutputDXError TRACE + +void dd_error(HRESULT dd_err) +{ + if(dd_err) + { + OutputDXError("DirectDraw Error: "); + switch(dd_err) + { + case DDERR_ALREADYINITIALIZED: OutputDXError("DDERR_ALREADYINITIALIZED");break; + case DDERR_CANNOTATTACHSURFACE: OutputDXError("DDERR_CANNOTATTACHSURFACE");break; + case DDERR_CANNOTDETACHSURFACE: OutputDXError("DDERR_CANNOTDETACHSURFACE");break; + case DDERR_CURRENTLYNOTAVAIL: OutputDXError("DDERR_CURRENTLYNOTAVAIL");break; + case DDERR_EXCEPTION: OutputDXError("DDERR_EXCEPTION");break; + case DDERR_GENERIC: OutputDXError("DDERR_GENERIC");break; + case DDERR_HEIGHTALIGN: OutputDXError("DDERR_HEIGHTALIGN");break; + case DDERR_INCOMPATIBLEPRIMARY: OutputDXError("DDERR_INCOMPATIBLEPRIMARY");break; + case DDERR_INVALIDCAPS: OutputDXError("DDERR_INVALIDCAPS");break; + case DDERR_INVALIDCLIPLIST: OutputDXError("DDERR_INVALIDCLIPLIST");break; + case DDERR_INVALIDMODE: OutputDXError("DDERR_INVALIDMODE");break; + case DDERR_INVALIDOBJECT: OutputDXError("DDERR_INVALIDOBJECT");break; + case DDERR_INVALIDPARAMS: OutputDXError("DDERR_INVALIDPARAMS");break; + case DDERR_INVALIDPIXELFORMAT: OutputDXError("DDERR_INVALIDPIXELFORMAT");break; + case DDERR_INVALIDRECT: OutputDXError("DDERR_INVALIDRECT");break; + case DDERR_LOCKEDSURFACES: OutputDXError("DDERR_LOCKEDSURFACES");break; + case DDERR_NO3D: OutputDXError("DDERR_NO3D");break; + case DDERR_NOALPHAHW: OutputDXError("DDERR_NOALPHAHW");break; + case DDERR_NOCLIPLIST: OutputDXError("DDERR_NOCLIPLIST");break; + case DDERR_NOCOLORCONVHW: OutputDXError("DDERR_NOCOLORCONVHW");break; + case DDERR_NOCOOPERATIVELEVELSET: OutputDXError("DDERR_NOCOOPERATIVELEVELSET");break; + case DDERR_NOCOLORKEY: OutputDXError("DDERR_NOCOLORKEY");break; + case DDERR_NOCOLORKEYHW: OutputDXError("DDERR_NOCOLORKEYHW");break; + case DDERR_NODIRECTDRAWSUPPORT: OutputDXError("DDERR_NODIRECTDRAWSUPPORT");break; + case DDERR_NOEXCLUSIVEMODE: OutputDXError("DDERR_NOEXCLUSIVEMODE");break; + case DDERR_NOFLIPHW: OutputDXError("DDERR_NOFLIPHW");break; + case DDERR_NOGDI: OutputDXError("DDERR_NOGDI");break; + case DDERR_NOMIRRORHW: OutputDXError("DDERR_NOMIRRORHW");break; + case DDERR_NOTFOUND: OutputDXError("DDERR_NOTFOUND");break; + case DDERR_NOOVERLAYHW: OutputDXError("DDERR_NOOVERLAYHW");break; + case DDERR_NORASTEROPHW: OutputDXError("DDERR_NORASTEROPHW");break; + case DDERR_NOROTATIONHW: OutputDXError("DDERR_NOROTATIONHW");break; + case DDERR_NOSTRETCHHW: OutputDXError("DDERR_NOSTRETCHHW");break; + case DDERR_NOT4BITCOLOR: OutputDXError("DDERR_NOT4BITCOLOR");break; + case DDERR_NOT4BITCOLORINDEX: OutputDXError("DDERR_NOT4BITCOLORINDEX");break; + case DDERR_NOT8BITCOLOR: OutputDXError("DDERR_NOT8BITCOLOR");break; + case DDERR_NOTEXTUREHW: OutputDXError("DDERR_NOTEXTUREHW");break; + case DDERR_NOVSYNCHW: OutputDXError("DDERR_NOVSYNCHW");break; + case DDERR_NOZBUFFERHW: OutputDXError("DDERR_NOZBUFFERHW");break; + case DDERR_NOZOVERLAYHW: OutputDXError("DDERR_NOZOVERLAYHW");break; + case DDERR_OUTOFCAPS: OutputDXError("DDERR_OUTOFCAPS");break; + case DDERR_OUTOFMEMORY: OutputDXError("DDERR_OUTOFMEMORY");break; + case DDERR_OUTOFVIDEOMEMORY: OutputDXError("DDERR_OUTOFVIDEOMEMORY");break; + case DDERR_OVERLAYCANTCLIP: OutputDXError("DDERR_OVERLAYCANTCLIP");break; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: OutputDXError("DDERR_OVERLAYCOLORKEYONLYONEACTIVE");break; + case DDERR_PALETTEBUSY: OutputDXError("DDERR_PALETTEBUSY");break; + case DDERR_COLORKEYNOTSET: OutputDXError("DDERR_COLORKEYNOTSET");break; + case DDERR_SURFACEALREADYATTACHED: OutputDXError("DDERR_SURFACEALREADYATTACHED");break; + case DDERR_SURFACEALREADYDEPENDENT: OutputDXError("DDERR_SURFACEALREADYDEPENDENT");break; + case DDERR_SURFACEBUSY: OutputDXError("DDERR_SURFACEBUSY");break; + case DDERR_CANTLOCKSURFACE: OutputDXError("DDERR_CANTLOCKSURFACE");break; + case DDERR_SURFACEISOBSCURED: OutputDXError("DDERR_SURFACEISOBSCURED");break; + case DDERR_SURFACELOST: OutputDXError("DDERR_SURFACELOST");break; + case DDERR_SURFACENOTATTACHED: OutputDXError("DDERR_SURFACENOTATTACHED");break; + case DDERR_TOOBIGHEIGHT: OutputDXError("DDERR_TOOBIGHEIGHT");break; + case DDERR_TOOBIGSIZE: OutputDXError("DDERR_TOOBIGSIZE");break; + case DDERR_TOOBIGWIDTH: OutputDXError("DDERR_TOOBIGWIDTH");break; + case DDERR_UNSUPPORTED: OutputDXError("DDERR_UNSUPPORTED");break; + case DDERR_UNSUPPORTEDFORMAT: OutputDXError("DDERR_UNSUPPORTEDFORMAT");break; + case DDERR_UNSUPPORTEDMASK: OutputDXError("DDERR_UNSUPPORTEDMASK");break; + case DDERR_VERTICALBLANKINPROGRESS: OutputDXError("DDERR_VERTICALBLANKINPROGRESS");break; + case DDERR_WASSTILLDRAWING: OutputDXError("DDERR_WASSTILLDRAWING");break; + case DDERR_XALIGN: OutputDXError("DDERR_XALIGN");break; + case DDERR_INVALIDDIRECTDRAWGUID: OutputDXError("DDERR_INVALIDDIRECTDRAWGUID");break; + case DDERR_DIRECTDRAWALREADYCREATED: OutputDXError("DDERR_DIRECTDRAWALREADYCREATED");break; + case DDERR_NODIRECTDRAWHW: OutputDXError("DDERR_NODIRECTDRAWHW");break; + case DDERR_PRIMARYSURFACEALREADYEXISTS: OutputDXError("DDERR_PRIMARYSURFACEALREADYEXISTS");break; + case DDERR_NOEMULATION: OutputDXError("DDERR_NOEMULATION");break; + case DDERR_REGIONTOOSMALL: OutputDXError("DDERR_REGIONTOOSMALL");break; + case DDERR_CLIPPERISUSINGHWND: OutputDXError("DDERR_CLIPPERISUSINGHWND");break; + case DDERR_NOCLIPPERATTACHED: OutputDXError("DDERR_NOCLIPPERATTACHED");break; + case DDERR_NOHWND: OutputDXError("DDERR_NOHWND");break; + case DDERR_HWNDSUBCLASSED: OutputDXError("DDERR_HWNDSUBCLASSED");break; + case DDERR_HWNDALREADYSET: OutputDXError("DDERR_HWNDALREADYSET");break; + case DDERR_NOPALETTEATTACHED: OutputDXError("DDERR_NOPALETTEATTACHED");break; + case DDERR_NOPALETTEHW: OutputDXError("DDERR_NOPALETTEHW");break; + case DDERR_BLTFASTCANTCLIP: OutputDXError("DDERR_BLTFASTCANTCLIP");break; + case DDERR_NOBLTHW: OutputDXError("DDERR_NOBLTHW");break; + case DDERR_NODDROPSHW: OutputDXError("DDERR_NODDROPSHW");break; + case DDERR_OVERLAYNOTVISIBLE: OutputDXError("DDERR_OVERLAYNOTVISIBLE");break; + case DDERR_NOOVERLAYDEST: OutputDXError("DDERR_NOOVERLAYDEST");break; + case DDERR_INVALIDPOSITION: OutputDXError("DDERR_INVALIDPOSITION");break; + case DDERR_NOTAOVERLAYSURFACE: OutputDXError("DDERR_NOTAOVERLAYSURFACE");break; + case DDERR_EXCLUSIVEMODEALREADYSET: OutputDXError("DDERR_EXCLUSIVEMODEALREADYSET");break; + case DDERR_NOTFLIPPABLE: OutputDXError("DDERR_NOTFLIPPABLE");break; + case DDERR_CANTDUPLICATE: OutputDXError("DDERR_CANTDUPLICATE");break; + case DDERR_NOTLOCKED: OutputDXError("DDERR_NOTLOCKED");break; + case DDERR_CANTCREATEDC: OutputDXError("DDERR_CANTCREATEDC");break; + case DDERR_NODC: OutputDXError("DDERR_NODC");break; + case DDERR_WRONGMODE: OutputDXError("DDERR_WRONGMODE");break; + case DDERR_IMPLICITLYCREATED: OutputDXError("DDERR_IMPLICITLYCREATED");break; + case DDERR_NOTPALETTIZED: OutputDXError("DDERR_NOTPALETTIZED");break; + case DDERR_UNSUPPORTEDMODE: OutputDXError("DDERR_UNSUPPORTEDMODE");break; + case DDERR_NOMIPMAPHW: OutputDXError("DDERR_NOMIPMAPHW");break; + case DDERR_INVALIDSURFACETYPE: OutputDXError("DDERR_INVALIDSURFACETYPE");break; + case DDERR_NOOPTIMIZEHW: OutputDXError("DDERR_NOOPTIMIZEHW");break; + case DDERR_NOTLOADED: OutputDXError("DDERR_NOTLOADED");break; + case DDERR_DCALREADYCREATED: OutputDXError("DDERR_DCALREADYCREATED");break; + case DDERR_NONONLOCALVIDMEM: OutputDXError("DDERR_NONONLOCALVIDMEM");break; + case DDERR_CANTPAGELOCK: OutputDXError("DDERR_CANTPAGELOCK");break; + case DDERR_CANTPAGEUNLOCK: OutputDXError("DDERR_CANTPAGEUNLOCK");break; + case DDERR_NOTPAGELOCKED: OutputDXError("DDERR_NOTPAGELOCKED");break; + case DDERR_MOREDATA: OutputDXError("DDERR_MOREDATA");break; + case DDERR_VIDEONOTACTIVE: OutputDXError("DDERR_VIDEONOTACTIVE");break; + case DDERR_DEVICEDOESNTOWNSURFACE: OutputDXError("DDERR_DEVICEDOESNTOWNSURFACE");break; + case DDERR_NOTINITIALIZED: OutputDXError("DDERR_NOTINITIALIZED");break; + default: OutputDXError("Unknown - %ld",dd_err&0xffff); + } + OutputDXError("\n"); + } +} + +//--------------------------------------------------------------- + +void d3d_error(HRESULT dd_err) +{ + if(dd_err) + { + OutputDXError("Direct3D Error: "); + switch(dd_err) + { + case D3DERR_BADMAJORVERSION: OutputDXError("D3DERR_BADMAJORVERSION");break; + case D3DERR_BADMINORVERSION: OutputDXError("D3DERR_BADMINORVERSION");break; + case D3DERR_INVALID_DEVICE: OutputDXError("D3DERR_INVALID_DEVICE");break; + case D3DERR_EXECUTE_CREATE_FAILED: OutputDXError("D3DERR_EXECUTE_CREATE_FAILED");break; + case D3DERR_EXECUTE_DESTROY_FAILED: OutputDXError("D3DERR_EXECUTE_DESTROY_FAILED");break; + case D3DERR_EXECUTE_LOCK_FAILED: OutputDXError("D3DERR_EXECUTE_LOCK_FAILED");break; + case D3DERR_EXECUTE_UNLOCK_FAILED: OutputDXError("D3DERR_EXECUTE_UNLOCK_FAILED");break; + case D3DERR_EXECUTE_LOCKED: OutputDXError("D3DERR_EXECUTE_LOCKED");break; + case D3DERR_EXECUTE_NOT_LOCKED: OutputDXError("D3DERR_EXECUTE_NOT_LOCKED");break; + case D3DERR_EXECUTE_FAILED: OutputDXError("D3DERR_EXECUTE_FAILED");break; + case D3DERR_EXECUTE_CLIPPED_FAILED: OutputDXError("D3DERR_EXECUTE_CLIPPED_FAILED");break; + case D3DERR_TEXTURE_NO_SUPPORT: OutputDXError("D3DERR_TEXTURE_NO_SUPPORT");break; + case D3DERR_TEXTURE_CREATE_FAILED: OutputDXError("D3DERR_TEXTURE_CREATE_FAILED");break; + case D3DERR_TEXTURE_DESTROY_FAILED: OutputDXError("D3DERR_TEXTURE_DESTROY_FAILED");break; + case D3DERR_TEXTURE_LOCK_FAILED: OutputDXError("D3DERR_TEXTURE_LOCK_FAILED");break; + case D3DERR_TEXTURE_UNLOCK_FAILED: OutputDXError("D3DERR_TEXTURE_UNLOCK_FAILED");break; + case D3DERR_TEXTURE_LOAD_FAILED: OutputDXError("D3DERR_TEXTURE_LOAD_FAILED");break; + case D3DERR_TEXTURE_SWAP_FAILED: OutputDXError("D3DERR_TEXTURE_SWAP_FAILED");break; + case D3DERR_TEXTURE_LOCKED: OutputDXError("D3DERR_TEXTURE_LOCKED");break; + case D3DERR_TEXTURE_NOT_LOCKED: OutputDXError("D3DERR_TEXTURE_NOT_LOCKED");break; + case D3DERR_TEXTURE_GETSURF_FAILED: OutputDXError("D3DERR_TEXTURE_GETSURF_FAILED");break; + case D3DERR_MATRIX_CREATE_FAILED: OutputDXError("D3DERR_MATRIX_CREATE_FAILED");break; + case D3DERR_MATRIX_DESTROY_FAILED: OutputDXError("D3DERR_MATRIX_DESTROY_FAILED");break; + case D3DERR_MATRIX_SETDATA_FAILED: OutputDXError("D3DERR_MATRIX_SETDATA_FAILED");break; + case D3DERR_MATRIX_GETDATA_FAILED: OutputDXError("D3DERR_MATRIX_GETDATA_FAILED");break; + case D3DERR_SETVIEWPORTDATA_FAILED: OutputDXError("D3DERR_SETVIEWPORTDATA_FAILED");break; + case D3DERR_MATERIAL_CREATE_FAILED: OutputDXError("D3DERR_MATERIAL_CREATE_FAILED");break; + case D3DERR_MATERIAL_DESTROY_FAILED: OutputDXError("D3DERR_MATERIAL_DESTROY_FAILED");break; + case D3DERR_MATERIAL_SETDATA_FAILED: OutputDXError("D3DERR_MATERIAL_SETDATA_FAILED");break; + case D3DERR_MATERIAL_GETDATA_FAILED: OutputDXError("D3DERR_MATERIAL_GETDATA_FAILED");break; + case D3DERR_LIGHT_SET_FAILED: OutputDXError("D3DERR_LIGHT_SET_FAILED");break; + case D3DERR_SCENE_IN_SCENE: OutputDXError("D3DERR_SCENE_IN_SCENE");break; + case D3DERR_SCENE_NOT_IN_SCENE: OutputDXError("D3DERR_SCENE_NOT_IN_SCENE");break; + case D3DERR_SCENE_BEGIN_FAILED: OutputDXError("D3DERR_SCENE_BEGIN_FAILED");break; + case D3DERR_SCENE_END_FAILED: OutputDXError("D3DERR_SCENE_END_FAILED");break; + case D3DERR_INBEGIN: OutputDXError("D3DERR_INBEGIN");break; + case D3DERR_NOTINBEGIN: OutputDXError("D3DERR_NOTINBEGIN");break; + case D3DERR_NOVIEWPORTS: OutputDXError("D3DERR_NOVIEWPORTS");break; + case D3DERR_VIEWPORTDATANOTSET: OutputDXError("D3DERR_VIEWPORTDATANOTSET");break; + case D3DERR_INVALIDCURRENTVIEWPORT: OutputDXError("D3DERR_INVALIDCURRENTVIEWPORT");break; + case D3DERR_INVALIDPRIMITIVETYPE: OutputDXError("D3DERR_INVALIDPRIMITIVETYPE");break; + case D3DERR_INVALIDVERTEXTYPE: OutputDXError("D3DERR_INVALIDVERTEXTYPE");break; + case D3DERR_TEXTURE_BADSIZE: OutputDXError("D3DERR_TEXTURE_BADSIZE");break; + default: dd_error(dd_err); + } + OutputDXError("\n"); + } +} + +//--------------------------------------------------------------- + +void di_error(HRESULT di_err) +{ + if(di_err) + { + OutputDXError("DirectInput Error: "); + switch(di_err) + { + case DIERR_OLDDIRECTINPUTVERSION: OutputDXError("DIERR_OLDDIRECTINPUTVERSION");break; + case DIERR_BETADIRECTINPUTVERSION: OutputDXError("DIERR_BETADIRECTINPUTVERSION");break; + case DIERR_BADDRIVERVER: OutputDXError("DIERR_BADDRIVERVER");break; + case DIERR_DEVICENOTREG: OutputDXError("DIERR_DEVICENOTREG");break; + case DIERR_NOTFOUND: OutputDXError("DIERR_NOTFOUND\nDIERR_OBJECTNOTFOUND\nDIERR_READONLY\nDIERR_HANDLEEXISTS");break; + case DIERR_INVALIDPARAM: OutputDXError("DIERR_INVALIDPARAM");break; + case DIERR_NOINTERFACE: OutputDXError("DIERR_NOINTERFACE");break; + case DIERR_GENERIC: OutputDXError("DIERR_GENERIC");break; + case DIERR_OUTOFMEMORY: OutputDXError("DIERR_OUTOFMEMORY");break; + case DIERR_UNSUPPORTED: OutputDXError("DIERR_UNSUPPORTED");break; + case DIERR_NOTINITIALIZED: OutputDXError("DIERR_NOTINITIALIZED");break; + case DIERR_ALREADYINITIALIZED: OutputDXError("DIERR_ALREADYINITIALIZED");break; + case DIERR_NOAGGREGATION: OutputDXError("DIERR_NOAGGREGATION");break; + case DIERR_OTHERAPPHASPRIO: OutputDXError("DIERR_OTHERAPPHASPRIO");break; + case DIERR_INPUTLOST: OutputDXError("DIERR_INPUTLOST");break; + case DIERR_ACQUIRED: OutputDXError("DIERR_ACQUIRED");break; + case DIERR_NOTACQUIRED: OutputDXError("DIERR_NOTACQUIRED");break; + case E_PENDING: OutputDXError("E_PENDING");break; + case DIERR_INSUFFICIENTPRIVS: OutputDXError("DIERR_INSUFFICIENTPRIVS");break; + case DIERR_DEVICEFULL: OutputDXError("DIERR_DEVICEFULL");break; + case DIERR_MOREDATA: OutputDXError("DIERR_MOREDATA");break; + case DIERR_NOTDOWNLOADED: OutputDXError("DIERR_NOTDOWNLOADED");break; + case DIERR_HASEFFECTS: OutputDXError("DIERR_HASEFFECTS");break; + case DIERR_NOTEXCLUSIVEACQUIRED: OutputDXError("DIERR_NOTEXCLUSIVEACQUIRED");break; + case DIERR_INCOMPLETEEFFECT: OutputDXError("DIERR_INCOMPLETEEFFECT");break; + case DIERR_NOTBUFFERED: OutputDXError("DIERR_NOTBUFFERED");break; + case DIERR_EFFECTPLAYING: OutputDXError("DIERR_EFFECTPLAYING");break; + default: OutputDXError("Unknown - %ld",di_err&0xffff); + } + OutputDXError("\n"); + } +} + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/DDLibrary/Source/GDisplay.cpp b/fallen/DDLibrary/Source/GDisplay.cpp new file mode 100644 index 0000000..079645e --- /dev/null +++ b/fallen/DDLibrary/Source/GDisplay.cpp @@ -0,0 +1,6608 @@ +// Display.cpp +// Guy Simmons, 13th November 1997. + +#include "DDLib.h" +#include "c:\fallen\headers\demo.h" +#include "c:\fallen\headers\interfac.h" +#include "BinkClient.h" +#include "c:\fallen\headers\env.h" +#include "c:\fallen\headers\xlat_str.h" + +#include "poly.h" +#include "vertexbuffer.h" +#include "polypoint.h" +#include "renderstate.h" +#include "polypage.h" +#include "gdisplay.h" +#include "panel.h" +#include "c:\fallen\headers\game.h" + +#ifdef TARGET_DC +#include "target.h" +#include "platutil.h" +#include "DCLowLevel.h" +#include "sg_mww.h" +#endif + + +// +// From mfx_miles.h... +// + +extern void init_my_dialog (HWND hWnd); +extern void my_dialogs_over(HWND hWnd); + + +SLONG RealDisplayWidth; +SLONG RealDisplayHeight; +SLONG DisplayBPP; +Display the_display; +volatile SLONG hDDLibStyle = NULL, + hDDLibStyleEx = NULL; +volatile HWND hDDLibWindow = NULL; +volatile HMENU hDDLibMenu = NULL; + +int Video3DMode = -1; // 0 = primary, 1 = secondary, 2 = software, -1 = unknown +bool VideoTrueColour = false; // true = 24-bit, false = 16-bit +int VideoRes = -1; // 0 = 320x240, 1 = 512x384, 2= 640x480, 3 = 800x600, 4 = 1024x768, -1 = unknown + +enumDisplayType eDisplayType; + + + +#ifdef TARGET_DC +// Texture to hold the background, coz blits don't seem to work. +LPDIRECTDRAWSURFACE4 lpBackgroundCache = NULL; +LPDIRECTDRAWSURFACE4 lpBackgroundCache2 = NULL; +//static LPDIRECT3DTEXTURE2 lpBackgroundCacheTexture = NULL; +#endif + + +//--------------------------------------------------------------- + UBYTE *image_mem = NULL,*image = NULL; + + +#ifdef DEBUG +HRESULT WINAPI EnumSurfacesCallbackFunc( + LPDIRECTDRAWSURFACE4 lpDDSurface, + LPDDSURFACEDESC2 lpDDSurfaceDesc, + LPVOID lpContext ) +{ + TRACE ( "Surf: width %i height %i bpp %i", lpDDSurfaceDesc->dwWidth, lpDDSurfaceDesc->dwHeight, lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount ); + if ( lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_COMPRESSED ) + { + TRACE ( " compressed" ); + } + else + { + TRACE ( " uncompressed" ); + } + TRACE ( "\n" ); + return DDENUMRET_OK; +} + + +#endif + + + + + +// ======================================================== +// +// MOVIE STUFF! +// +// ======================================================== + + +#include "mmstream.h" // Multimedia stream interfaces +#include "amstream.h" // DirectShow multimedia stream interfaces +#include "ddstream.h" // DirectDraw multimedia stream interfaces + +//extern ULONG get_hardware_input(UWORD type); + +#ifndef TARGET_DC + +void RenderStreamToSurface(IDirectDrawSurface *pSurface, IMultiMediaStream *pMMStream, IDirectDrawSurface *back_surface) +{ + IMediaStream *pPrimaryVidStream; + IDirectDrawMediaStream *pDDStream; + IDirectDrawStreamSample *pSample; + RECT rect; + RECT midrect; + DDSURFACEDESC ddsd; + + pMMStream->GetMediaStream(MSPID_PrimaryVideo, &pPrimaryVidStream); + ASSERT ( pPrimaryVidStream != NULL ); + pPrimaryVidStream->QueryInterface(IID_IDirectDrawMediaStream, (void **)&pDDStream); + ASSERT ( pDDStream != NULL ); + + /* + + InitStruct(ddsd); + + pSurface->GetSurfaceDesc(&ddsd); + + if (pDDStream->SetFormat(&ddsd, NULL) == S_OK) + { + } + else + { + return; + } + + */ + + InitStruct(ddsd); + + pDDStream->GetFormat(&ddsd, NULL, NULL, NULL); + + /* + + ddsd.dwWidth = 640; + ddsd.dwHeight = 480; + + if (pDDStream->SetFormat(&ddsd, NULL) == S_OK) + { + } + else + { + return; + } + + */ + + midrect.top = 420 - (ddsd.dwWidth >> 1); + midrect.left = 240 - (ddsd.dwHeight >> 1); + midrect.bottom = midrect.top + ddsd.dwHeight; + midrect.right = midrect.left + ddsd.dwWidth; + + rect.top = 0; + rect.left = 0; + rect.bottom = ddsd.dwHeight; + rect.right = ddsd.dwWidth; + +// pDDStream->CreateSample(pSurface, NULL, 0, &pSample); + pDDStream->CreateSample(back_surface, &rect, 0, &pSample); + ASSERT ( pSample != NULL ); + pMMStream->SetState(STREAMSTATE_RUN); + + + while (pSample->Update(0, NULL, NULL, NULL) == S_OK) + { + if (FAILED(pSurface->Blt( + NULL, + back_surface, + &rect, + DDBLT_WAIT, + NULL))) + { + pSurface->Blt( + &midrect, + back_surface, + &rect, + DDBLT_WAIT, + NULL); + } + + MSG msg; + + if (PeekMessage( + &msg, + hDDLibWindow, + WM_KEYDOWN, + WM_KEYDOWN, + PM_REMOVE)) + { + // + // User has pressed a key. + // + + break; + } + + ULONG input = get_hardware_input(INPUT_TYPE_JOY); // 1 << 1 ==> INPUT_TYPE_JOY + + if (input & (INPUT_MASK_JUMP|INPUT_MASK_START|INPUT_MASK_SELECT|INPUT_MASK_KICK|INPUT_MASK_PUNCH|INPUT_MASK_ACTION)) + { + break; + } + } + + pMMStream->SetState(STREAMSTATE_STOP); + + int i; + i = pSample->Release(); + ASSERT ( i == 0 ); + i = pDDStream->Release(); + ASSERT ( i == 0 ); + i = pPrimaryVidStream->Release(); + ASSERT ( i == 0 ); +} + +#else //#ifndef TARGET_DC + +void RenderStreamToSurface(IDirectDrawSurface *pSurface, IMultiMediaStream *pMMStream, IDirectDrawSurface *back_surface, IDirectDrawSurface *pddsTexture=NULL ) +{ + IMediaStream *pPrimaryVidStream; + IDirectDrawMediaStream *pDDStream; + IDirectDrawStreamSample *pSample; + RECT rect; + RECT scrrect; + RECT texrect; + DDSURFACEDESC ddsd; + + HRESULT hres; + + hres = pMMStream->GetMediaStream(MSPID_PrimaryVideo, &pPrimaryVidStream); + hres = pPrimaryVidStream->QueryInterface(IID_IDirectDrawMediaStream, (void **)&pDDStream); + + /* + + InitStruct(ddsd); + + pSurface->GetSurfaceDesc(&ddsd); + + if (pDDStream->SetFormat(&ddsd, NULL) == S_OK) + { + } + else + { + return; + } + + */ + + InitStruct(ddsd); + + hres = pDDStream->GetFormat(&ddsd, NULL, NULL, NULL); + + scrrect.top = ( 480 - 640 * ddsd.dwHeight / ddsd.dwWidth ) >> 1; + scrrect.left = 0; + scrrect.bottom = 480 - scrrect.top; + scrrect.right = 640; + + texrect.left = 0; + texrect.right = 1024; + texrect.top = 0; + texrect.bottom = 512; + + rect.top = 0; + rect.left = 0; + rect.bottom = ddsd.dwHeight; + rect.right = ddsd.dwWidth; + + if ( pddsTexture != NULL ) + { + // We stream to a texture and draw that on the screen each frame. + // This does the dithering for us, which looks a lot prettier. + + D3DTLVERTEX tlvVertex[4]; + tlvVertex[0].dvSX = (float)(scrrect.left); + tlvVertex[0].dvSY = (float)(scrrect.top); + tlvVertex[0].dvTU = (float)(rect.left) / (float)(texrect.right); + tlvVertex[0].dvTV = (float)(rect.top) / (float)(texrect.bottom); + tlvVertex[0].dvSZ = 0.5f; + tlvVertex[0].dvRHW = 0.5f; + tlvVertex[0].dcColor = 0xffffffff; + tlvVertex[0].dcSpecular = 0x00000000; + + tlvVertex[1].dvSX = (float)(scrrect.right); + tlvVertex[1].dvSY = (float)(scrrect.top); + tlvVertex[1].dvTU = (float)(rect.right) / (float)(texrect.right); + tlvVertex[1].dvTV = (float)(rect.top) / (float)(texrect.bottom); + tlvVertex[1].dvSZ = 0.5f; + tlvVertex[1].dvRHW = 0.5f; + tlvVertex[1].dcColor = 0xffffffff; + tlvVertex[1].dcSpecular = 0x00000000; + + tlvVertex[2].dvSX = (float)(scrrect.right); + tlvVertex[2].dvSY = (float)(scrrect.bottom); + tlvVertex[2].dvTU = (float)(rect.right) / (float)(texrect.right); + tlvVertex[2].dvTV = (float)(rect.bottom) / (float)(texrect.bottom); + tlvVertex[2].dvSZ = 0.5f; + tlvVertex[2].dvRHW = 0.5f; + tlvVertex[2].dcColor = 0xffffffff; + tlvVertex[2].dcSpecular = 0x00000000; + + tlvVertex[3].dvSX = (float)(scrrect.left); + tlvVertex[3].dvSY = (float)(scrrect.bottom); + tlvVertex[3].dvTU = (float)(rect.left) / (float)(texrect.right); + tlvVertex[3].dvTV = (float)(rect.bottom) / (float)(texrect.bottom); + tlvVertex[3].dvSZ = 0.5f; + tlvVertex[3].dvRHW = 0.5f; + tlvVertex[3].dcColor = 0xffffffff; + tlvVertex[3].dcSpecular = 0x00000000; + + + IDirect3DTexture2 *pd3dtTexture = NULL; + + hres = pddsTexture->QueryInterface ( IID_IDirect3DTexture2, (void **)&pd3dtTexture ); + ASSERT ( SUCCEEDED ( hres ) ); + + // Set up the D3D engine. + the_display.lp_D3D_Device->SetTexture ( 0, pd3dtTexture ); + //the_display.lp_D3D_Device->SetTexture ( 0, NULL ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + //the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + //the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_TEXCOORDINDEX, 0 ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_MINFILTER, D3DTFN_LINEAR ); + the_display.lp_D3D_Device->SetTextureStageState ( 0, D3DTSS_MIPFILTER, D3DTFP_NONE ); + + the_display.lp_D3D_Device->SetTextureStageState ( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + the_display.lp_D3D_Device->SetTextureStageState ( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + + the_display.lp_D3D_Device->SetRenderState ( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); + the_display.lp_D3D_Device->SetRenderState ( D3DRENDERSTATE_ALPHATESTENABLE, FALSE ); + the_display.lp_D3D_Device->SetRenderState ( D3DRENDERSTATE_FOGENABLE, FALSE ); + the_display.lp_D3D_Device->SetRenderState ( D3DRENDERSTATE_CULLMODE, D3DCULL_NONE ); + + // End any previous scene (coz it's picky). + hres = the_display.lp_D3D_Device->EndScene(); + ASSERT ( SUCCEEDED ( hres ) ); + + hres = pDDStream->CreateSample(pddsTexture, &rect, DDSFF_PROGRESSIVERENDER, &pSample); + hres = pMMStream->SetState(STREAMSTATE_RUN); + + while ((hres = pSample->Update(0, NULL, NULL, NULL)) == S_OK) + { + + // Draw the texture. + + hres = the_display.lp_D3D_Device->BeginScene(); + ASSERT ( SUCCEEDED ( hres ) ); + + hres = the_display.lp_D3D_Viewport->Clear ( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER ); + ASSERT ( SUCCEEDED ( hres ) ); + + hres = the_display.lp_D3D_Device->DrawPrimitive ( D3DPT_TRIANGLEFAN, + D3DVT_TLVERTEX, + tlvVertex, + 4, + D3DDP_DONOTCLIP | D3DDP_DONOTUPDATEEXTENTS ); + ASSERT ( SUCCEEDED ( hres ) ); + + hres = the_display.lp_D3D_Device->EndScene(); + ASSERT ( SUCCEEDED ( hres ) ); + + hres = pSurface->Flip ( NULL, 0 ); + + ULONG input = get_hardware_input ( INPUT_TYPE_JOY | INPUT_TYPE_REMAP_DPAD | INPUT_TYPE_REMAP_BUTTONS | INPUT_TYPE_REMAP_START_BUTTON | INPUT_TYPE_GONEDOWN ); + if (input & (INPUT_MASK_JUMP|INPUT_MASK_START|INPUT_MASK_SELECT|INPUT_MASK_KICK|INPUT_MASK_PUNCH|INPUT_MASK_ACTION)) + { + break; + } + } + + // Let the texture go. + the_display.lp_D3D_Device->SetTexture ( 0, NULL ); + int i = pd3dtTexture->Release(); + + // And start a new scene, or you'll confuse the rest of the game. + hres = the_display.lp_D3D_Device->BeginScene(); + + } + else + { + + hres = pDDStream->CreateSample(back_surface, &rect, 0, &pSample); + hres = pMMStream->SetState(STREAMSTATE_RUN); + + while (pSample->Update(0, NULL, NULL, NULL) == S_OK) + { + + #if 0 + if (FAILED(pSurface->Blt( + NULL, + back_surface, + &rect, + DDBLT_WAIT, + NULL))) + { + hres = pSurface->Blt( + &midrect, + back_surface, + &rect, + DDBLT_WAIT, + NULL); + } + #else + hres = pSurface->Flip ( NULL, 0 ); + #endif + + ULONG input = get_hardware_input ( INPUT_TYPE_JOY | INPUT_TYPE_REMAP_DPAD | INPUT_TYPE_REMAP_BUTTONS | INPUT_TYPE_REMAP_START_BUTTON | INPUT_TYPE_GONEDOWN ); + if (input & (INPUT_MASK_JUMP|INPUT_MASK_START|INPUT_MASK_SELECT|INPUT_MASK_KICK|INPUT_MASK_PUNCH|INPUT_MASK_ACTION)) + { + break; + } + } + } + + hres = pMMStream->SetState(STREAMSTATE_STOP); + hres = pSample->Release(); + hres = pDDStream->Release(); + hres = pPrimaryVidStream->Release(); + +} + +#endif //#else //#ifndef TARGET_DC + + +#include "ddraw.h" // DirectDraw interfaces +#include "mmstream.h" // Multimedia stream interfaces +#include "amstream.h" // DirectShow multimedia stream interfaces +#include "ddstream.h" // DirectDraw multimedia stream interfaces + + +void RenderFileToMMStream(const char * szFileName, IMultiMediaStream **ppMMStream, IDirectDraw *pDD) +{ + IAMMultiMediaStream *pAMStream = NULL; + + HRESULT hres; +#ifdef TARGET_DC + hres = CoCreateInstance( + CLSID_AMMultiMediaStream, + NULL, + CLSCTX_INPROC_SERVER, + IID_IAMMultiMediaStream, + (void **)&pAMStream); + if ( FAILED ( hres ) ) + { + switch ( hres ) + { + case REGDB_E_CLASSNOTREG: + hres++; + break; + case CLASS_E_NOAGGREGATION: + hres++; + break; + } + + ASSERT ( FALSE ); + // Not good. + return; + } +#else + CoCreateInstance( + CLSID_AMMultiMediaStream, + NULL, + CLSCTX_INPROC_SERVER, + IID_IAMMultiMediaStream, + (void **)&pAMStream); +#endif + + WCHAR wPath[MAX_PATH]; // Wide (32-bit) string name + + +#ifdef DEBUG + // HACK. We don't have any movies apart from this one at the moment. + //szFileName = "\\CD-ROM\\fallen\\dshow\\pcintro_withsound.avi"; +#endif + + + MultiByteToWideChar( + CP_ACP, + 0, + szFileName, + -1, + wPath, + sizeof(wPath) / sizeof(wPath[0])); + + //hres = pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL); + hres = pAMStream->Initialize(STREAMTYPE_READ, 0, NULL); + if ( FAILED ( hres ) ) + { + switch ( hres ) + { + case E_ABORT: + hres++; + break; + case E_INVALIDARG: + hres++; + break; + case E_NOINTERFACE: + hres++; + break; + case E_OUTOFMEMORY: + hres++; + break; + case E_POINTER: + hres++; + break; + } + } + hres = pAMStream->AddMediaStream(pDD, &MSPID_PrimaryVideo, 0, NULL); + hres = pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, AMMSF_ADDDEFAULTRENDERER, NULL); + hres = pAMStream->OpenFile(wPath, 0); + + *ppMMStream = pAMStream; +} + + + +#ifdef TARGET_DC + + + +#if 0 +// Never used - always use PlayQuickMovie +int _CRTAPI1 do_intro(void) +{ + +#if 0 + DDSURFACEDESC ddsd; + IDirectDraw *pDD; + IDirectDrawSurface *pSurface; + IMultiMediaStream *pMMStream; + + IDirectDrawSurface *back_surface; + + HRESULT hres = CoInitializeEx(NULL,COINIT_MULTITHREADED); + + if (SUCCEEDED(the_display.lp_DD_FrontSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&pSurface)) && + SUCCEEDED(the_display.lp_DD_BackSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&back_surface))) + { + + +#if 1 + // Do it forever for the moment. + while ( TRUE ) + { + RenderFileToMMStream("\\CD-ROM\\fallen\\PCcutscene_300.avi", &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface); + pMMStream->Release(); + + ULONG input = get_hardware_input ( INPUT_TYPE_JOY | INPUT_TYPE_REMAP_DPAD | INPUT_TYPE_REMAP_BUTTONS | INPUT_TYPE_REMAP_START_BUTTON ); + if (input & (INPUT_MASK_JUMP|INPUT_MASK_START|INPUT_MASK_SELECT|INPUT_MASK_KICK|INPUT_MASK_PUNCH|INPUT_MASK_ACTION)) + { + break; + } + } +#else + RenderFileToMMStream("data\\eidos.avi", &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface); + pMMStream->Release(); + + RenderFileToMMStream("data\\urban_final.mpeg", &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface); + pMMStream->Release(); +#endif + + pSurface->Release(); + } + + CoUninitialize(); + + // On DC, we need to free DLLs explicitely. + CoFreeUnusedLibraries(); +#endif + + return 0; +} +#endif + + +#else + +int _CRTAPI1 do_intro(void) +{ +#if 0 + DDSURFACEDESC ddsd; + IDirectDraw *pDD; + IDirectDrawSurface *pSurface; + IMultiMediaStream *pMMStream; + + IDirectDrawSurface *back_surface; + +#ifdef TARGET_DC + CoInitializeEx(NULL,COINIT_MULTITHREADED); +#else + CoInitialize(NULL); +#endif + + /* + + DirectDrawCreate(NULL, &pDD, NULL); + pDD->SetCooperativeLevel(GetDesktopWindow(), DDSCL_NORMAL); + InitStruct(ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + pDD->CreateSurface(&ddsd, &pPrimarySurface, NULL); + + */ + + + //RenderStreamToSurface(pPrimarySurface, pMMStream); + + // get a IDirectDrawSurface from the IDirectDrawSurface4 since M$ don't seem to have + // bothered updating the DX Media SDK ... + + if (SUCCEEDED(the_display.lp_DD_FrontSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&pSurface)) && + SUCCEEDED(the_display.lp_DD_BackSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&back_surface))) + { + RenderFileToMMStream("data\\eidos.avi", &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface); + pMMStream->Release(); + + RenderFileToMMStream("data\\urban_final.mpeg", &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface); + pMMStream->Release(); + + pSurface->Release(); + } + + /* + + pPrimarySurface->Release(); + pDD->Release(); + + */ + + CoUninitialize(); + + return 0; +#else + return 0; +#endif +} + + +#endif + + + +#ifndef TARGET_DC +// Use PlayQuickMovie instead please. +int _CRTAPI1 do_only_game_intro(void) +{ +#if 0 + DDSURFACEDESC ddsd; + IDirectDraw *pDD; + IDirectDrawSurface *pSurface; + IMultiMediaStream *pMMStream; + + IDirectDrawSurface *back_surface; + +#ifdef TARGET_DC + CoInitializeEx(NULL,COINIT_MULTITHREADED); +#else + CoInitialize(NULL); +#endif + + // get a IDirectDrawSurface from the IDirectDrawSurface4 since M$ don't seem to have + // bothered updating the DX Media SDK ... + + if (SUCCEEDED(the_display.lp_DD_FrontSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&pSurface)) && + SUCCEEDED(the_display.lp_DD_BackSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&back_surface))) + { + RenderFileToMMStream("data\\urban_final.mpeg", &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface); + pMMStream->Release(); + + pSurface->Release(); + } + + CoUninitialize(); + + return 0; +#else + return 0; +#endif +} +#endif + + +extern CBYTE DATA_DIR[]; + +void InitBackImage(CBYTE *name) +{ + MFFileHandle image_file; + SLONG height; + CBYTE fname[200]; + + sprintf(fname,"%sdata\\%s",DATA_DIR,name); + + +#ifdef TARGET_DC + +#if !USE_COMPRESSED_BACKGROUNDS +#error Must use compressed backgrounds on DC. +#endif + + + // Horrible cheat - use ".BGS" version instead. +void FRONTEND_scr_img_load_into_screenfull(CBYTE *name, CompressedBackground *screen); + FRONTEND_scr_img_load_into_screenfull ( name, &(the_display.lp_DD_Background) ); + + +#else + + + + if(image_mem==0) + { + image_mem = (UBYTE*)MemAlloc(640*480*3); + } + + if(image_mem) + { + image_file = FileOpen(fname); + if(image_file>0) + { + FileSeek(image_file,SEEK_MODE_BEGINNING,18); + image = image_mem+(640*479*3); + for(height=480;height;height--,image-=(640*3)) + { + FileRead(image_file,image,640*3); + } + FileClose(image_file); + } + the_display.create_background_surface(image_mem); + } + + + + + // Save out the DC .BGS version by cheating horribly. + LPDIRECTDRAWSURFACE4 lpJunk = NULL; +extern void FRONTEND_scr_img_load_into_screenfull(CBYTE *name, LPDIRECTDRAWSURFACE4 *screen); + FRONTEND_scr_img_load_into_screenfull ( name, &lpJunk ); + + lpJunk->Release(); + +#endif + + + +} + +#if USE_COMPRESSED_BACKGROUNDS +void UseBackSurface(CompressedBackground use) +#else +void UseBackSurface(LPDIRECTDRAWSURFACE4 use) +#endif +{ + the_display.use_this_background_surface(use); +} + + + + +#if USE_COMPRESSED_BACKGROUNDS +CompressedBackground m_lpLastBackground = NULL; +#else +LPDIRECTDRAWSURFACE4 m_lpLastBackground = NULL; +#endif + + + + +void ResetBackImage(void) +{ + the_display.destroy_background_surface(); +#ifdef TARGET_DC + ASSERT ( image_mem == NULL ); +#endif + if(image_mem) + { + MemFree(image_mem); + image_mem=0; + } + +#ifdef TARGET_DC + // And flush the background cache(s). + the_display.lp_DD_Background_use_instead = NULL; + m_lpLastBackground = NULL; +#endif + +} + + +void ShowBackImage(bool b3DInFrame) +{ + the_display.blit_background_surface(b3DInFrame); +} + + + + + +//--------------------------------------------------------------- + +SLONG OpenDisplay(ULONG width, ULONG height, ULONG depth, ULONG flags) +{ + HRESULT result; + + result = the_manager.Init(); + if(FAILED(result)) + { + return -1; + } + +extern HINSTANCE hGlobalThisInst; +extern void GraphicsDialog(HINSTANCE hInst, HWND hWnd); + + GraphicsDialog(hGlobalThisInst, hDDLibWindow); + +extern int Video3DMode; +extern bool VideoTrueColour; +extern int VideoRes; + + depth = VideoTrueColour ? 32 : 16; + switch (VideoRes) + { + case 0: width = 320; height = 240; break; + case 1: width = 512; height = 384; break; + case 2: width = 640; height = 480; break; + case 3: width = 800; height = 600; break; + case 4: width = 1024; height = 768; break; + } + + if(flags&FLAGS_USE_3D) + the_display.Use3DOn(); + +#ifndef TARGET_DC + if(flags&FLAGS_USE_WORKSCREEN) + the_display.UseWorkOn(); +#endif + + // Voodoo must be fullscreen + if (Video3DMode == 1) + the_display.FullScreenOn(); + + // 32-bit colour must also be fullscreen + if (VideoTrueColour) + the_display.FullScreenOn(); + + result = SetDisplay(width,height,depth); + +// The DC picks specific times to show movies. +#ifndef TARGET_DC + if (SUCCEEDED(result)) + { + // + // Show a movie! + // + + do_intro(); + } +#endif + + return result; +} + +//--------------------------------------------------------------- + +SLONG CloseDisplay(void) +{ + the_display.Fini(); + the_manager.Fini(); + + return 1; +} + +//--------------------------------------------------------------- + +SLONG SetDisplay(ULONG width,ULONG height,ULONG depth) +{ + HRESULT result; + + RealDisplayWidth = width; + RealDisplayHeight = height; + DisplayBPP = depth; + result = the_display.ChangeMode(width,height,depth,0); + if(FAILED(result)) + return -1; + + // Attempt to change the device to hardware. + if(!the_display.IsFullScreen()|| SOFTWARE) + { + result = the_display.ChangeDevice(&the_display.CurrDriver->hardware_guid,NULL); + if(FAILED(result)) + return -1; + } + + // tell the polygon engine + PolyPage::SetScaling(float(width)/float(DisplayWidth), float(height)/float(DisplayHeight)); + + return 0; +} + +//--------------------------------------------------------------- + +SLONG ClearDisplay(UBYTE r,UBYTE g,UBYTE b) +{ + DDBLTFX dd_bltfx; + + dd_bltfx.dwSize = sizeof(dd_bltfx); + dd_bltfx.dwFillColor = 0; + + the_display.lp_DD_FrontSurface->Blt(NULL,NULL,NULL,DDBLT_COLORFILL,&dd_bltfx); + + return 0; +} + +struct RGB_565 +{ + UWORD R : 5, + G : 6, + B : 5; +}; + +struct RGB_555 +{ + UWORD R : 5, + G : 5, + B : 5; +}; + + +void LoadBackImage(UBYTE *image_data) +{ + ASSERT(0); + + UWORD pixel, + *surface_mem; + SLONG try_count, + height, + pitch, + width; + DDSURFACEDESC2 dd_sd; + HRESULT result; + RGB_565 rgb; + + +// if(the_display.lp_DD_BackSurface) + { + InitStruct(dd_sd); + try_count = 0; +do_the_lock: + result = the_display.lp_DD_BackSurface->Lock(NULL,&dd_sd,DDLOCK_WAIT|DDLOCK_NOSYSLOCK,NULL); + switch(result) + { + case DD_OK: + pitch = dd_sd.lPitch>>1; + surface_mem = (UWORD*)dd_sd.lpSurface; + for(height=0;(unsigned)heightUnlock(NULL); + switch(result) + { + case DDERR_SURFACELOST: + try_count++; + if(try_count<10) + { + the_display.Restore(); + goto do_the_unlock; + } + break; + } + break; + case DDERR_SURFACELOST: + try_count++; + if(try_count<10) + { + the_display.Restore(); + goto do_the_lock; + } + break; + default: + try_count++; + if(try_count<10) + goto do_the_lock; + } + } +} + +//--------------------------------------------------------------- + +UBYTE tga_header[] = { + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0xe0, 0x01, + 0x10, 0x01 + + }; +void DumpBackToTGA(CBYTE *tga_name) +{ + UWORD *rgb_fudge, + *surface_mem; + SLONG height, + pitch, + width; + DDSURFACEDESC2 dd_sd; + HRESULT result; + MFFileHandle tga_handle; + RGB_565 rgb565; + RGB_555 rgb555[640]; + + + if(the_display.lp_DD_BackSurface) + { + InitStruct(dd_sd); + result = the_display.lp_DD_BackSurface->Lock(NULL,&dd_sd,DDLOCK_WAIT|DDLOCK_NOSYSLOCK,NULL); + switch(result) + { + case DD_OK: + pitch = dd_sd.lPitch>>1; + surface_mem = (UWORD*)dd_sd.lpSurface+(479*pitch); + tga_handle = FileCreate(tga_name,TRUE); + if(tga_handle) + { + rgb_fudge = (UWORD*)&rgb565; + FileWrite(tga_handle,&tga_header,sizeof(tga_header)); + for(height=0;height<480;height++,surface_mem-=pitch) + { + for(width=0;width<640;width++) + { + *rgb_fudge = *(surface_mem+width); + rgb555[width].R = rgb565.R; + rgb555[width].G = rgb565.G>>1; + rgb555[width].B = rgb565.B; + } + FileWrite(tga_handle,&rgb555,sizeof(rgb555)); + } + FileClose(tga_handle); + } + result = the_display.lp_DD_BackSurface->Unlock(NULL); + break; + case DDERR_SURFACELOST: + the_display.Restore(); + break; + } + } +} + +void DumpBackToRaw() +{ + SLONG i; + SLONG x; + SLONG y; + + UBYTE red; + UBYTE green; + UBYTE blue; + + CBYTE fname[32]; + + FILE *handle; + + + // + // Find the first available file. + // + + for (i = 0; i < 100; i++) + { + sprintf(fname, "c:\\tmp\\shot%03d.raw", i); + + handle = MF_Fopen(fname, "rb"); + + if (handle) + { + // + // This file already exists... + // + + MF_Fclose(handle); + } + else + { + handle = MF_Fopen(fname, "wb"); + + if (handle) + { + goto found_file; + } + else + { + return; + } + } + } + + // + // All thousand filenames are used up! + // + + return; + + found_file:; + + // + // Save out the raw. + // + + for (y = 0; y < the_display.screen_height; y++) + { + for (x = 0; x < the_display.screen_width; x++) + { + the_display.GetPixel( + x, + y, + &red, + &green, + &blue); + + fputc(red, handle); + fputc(green, handle); + fputc(blue, handle); + } + } + + // + // Close the file. + // + + MF_Fclose(handle); +} + + +//--------------------------------------------------------------- + +Display::Display() +{ + DisplayFlags = 0; + CurrDevice = NULL; + CurrDriver = NULL; + CurrMode = NULL; + + CreateZBufferOn(); +#if defined(NDEBUG) || defined (TARGET_DC) + FullScreenOn(); +#endif + + lp_DD_Clipper = NULL; + lp_DD_FrontSurface = NULL; + lp_DD_BackSurface = NULL; +#ifndef TARGET_DC + lp_DD_WorkSurface = NULL; +#endif + lp_DD_ZBuffer = NULL; + lp_CurrPalette = NULL; + lp_SysPalette = NULL; + lp_D3D_Black = NULL; + lp_D3D_White = NULL; + lp_D3D_User = NULL; + lp_DD_GammaControl = NULL; + + + BackColour = BK_COL_BLACK; + TextureList = NULL; +} + +//--------------------------------------------------------------- + +Display::~Display() +{ + Fini(); +} + +//--------------------------------------------------------------- + +HRESULT Display::Init(void) +{ + HRESULT result; + static bool run_fmv = false; + +#ifndef TARGET_DC + SOFTWARE = (Video3DMode == 2) ? 1 : 0; +#endif + + if(!IsInitialised()) + { + if((!hDDLibWindow) || (!IsWindow(hDDLibWindow))) + { + result = DDERR_GENERIC; + // Output error. + return result; + } +#define HIDE_MOUSE 1 +#ifdef HIDE_MOUSE +#ifndef TARGET_DC + if (IsFullScreen()) + { + // hide the cursor + ShowCursor(FALSE); + } +#endif +#endif + + // Create DD/D3D Interface objects. + result = InitInterfaces(); + if(FAILED(result)) + goto cleanup; + + // Attach the window to the DD interface. + result = InitWindow(); + if(FAILED(result)) + goto cleanup; + + // Set the Mode. + result = InitFullscreenMode(); + if(FAILED(result)) + goto cleanup; + + // Create Front Surface & Palette. + result = InitFront(); + if(FAILED(result)) + goto cleanup; + + // Create Back surface & D3D device. + result = InitBack(); + if(FAILED(result)) + goto cleanup; + + if (background_image_mem) + { + create_background_surface(background_image_mem); + } + else + { + } + + InitOn(); + +#ifndef TARGET_DC +#ifndef VERSION_DEMO + // run the FMV + if (!run_fmv) + { + RunFMV(); + run_fmv = true; + } +#endif +#endif + + return DD_OK; + +cleanup: + Fini(); + return DDERR_GENERIC; + + } + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::Fini(void) +{ + // Cleanup + toGDI(); + + if (lp_DD_Background) + { +#if USE_COMPRESSED_BACKGROUNDS + MemFree ( lp_DD_Background ); +#else //#if USE_COMPRESSED_BACKGROUNDS + lp_DD_Background->Release(); +#endif //#else //#if USE_COMPRESSED_BACKGROUNDS + lp_DD_Background = NULL; + } + FiniBack(); + FiniFront(); + FiniFullscreenMode (); + FiniWindow (); + FiniInterfaces(); + + InitOff(); + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::GenerateDefaults(void) +{ + D3DDeviceInfo *new_device; + DDDriverInfo *new_driver; + DDModeInfo *new_mode; + HRESULT result; + + + new_driver = ValidateDriver(NULL); + if(!new_driver) + { + // Error, invalid DD Guid + result = DDERR_GENERIC;; + DebugText("GenerateDefaults: unable to get default driver\n"); + // Output error. + return result; + } + + if(IsFullScreen()) + { + // Get D3D device and compatible mode + if ( + !GetFullscreenMode ( + new_driver, + NULL, + DEFAULT_WIDTH, + DEFAULT_HEIGHT, + DEFAULT_DEPTH, + 0, + &new_mode, + &new_device + ) + ) + { + result = DDERR_GENERIC; + DebugText("GenerateDefaults: unable to get default screen mode\n"); + return result; + } + } + else + { + // Get Desktop mode and compatible D3D device + if ( + !GetDesktopMode ( + new_driver, + NULL, + &new_mode, + &new_device + ) + ) + { + result = DDERR_GENERIC; + DebugText("GenrateDefaults: unable to get default screen mode\n"); + return result; + } + } + + // Return results + CurrDriver = new_driver; + CurrMode = new_mode; + CurrDevice = new_device; + + // Success. + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::InitInterfaces(void) +{ + GUID *the_guid; + HRESULT result; + + + // Do we have a current DD Driver + if(!CurrDriver) + { + // So, Grab the Primary DD driver. + CurrDriver = ValidateDriver(NULL); + if(!CurrDriver) + { + // Error, No current Driver + result = DDERR_GENERIC; + // Output error. + return result; + } + } + + // Get DD Guid. + the_guid = CurrDriver->GetGuid(); + + // Create DD interface + result = DirectDrawCreate(the_guid,&lp_DD,NULL); + if(FAILED(result)) + { + // Error + // Output error. + goto cleanup; + } + + // Get DD4 interface + result = lp_DD->QueryInterface((REFIID)IID_IDirectDraw4,(void **)&lp_DD4); + if(FAILED(result)) + { + // Error + // Output error. + +#ifdef TARGET_DC + ASSERT(FALSE); +#else + // Inform User that they Need DX 6.0 installed + MessageBox(hDDLibWindow,TEXT("Need DirectX 6.0 or greater to run"), TEXT("Error"),MB_OK); +#endif + goto cleanup; + } + + // Get D3D interface + result = lp_DD4->QueryInterface((REFIID)IID_IDirect3D3,(void **)&lp_D3D); + if(FAILED(result)) + { + // Error + // Output error. + goto cleanup; + } + + // Mark this stage as done + TurnValidInterfaceOn(); + + // Success + return DD_OK; + +cleanup: + // Failure + FiniInterfaces (); + + return result; +} + +//--------------------------------------------------------------- + +HRESULT Display::FiniInterfaces(void) +{ + // Mark this stage as invalid + TurnValidInterfaceOff (); + + // Release Direct3D Interface + if(lp_D3D) + { + lp_D3D->Release(); + lp_D3D = NULL; + } + + // Release DirectDraw4 Interface + if(lp_DD4) + { + lp_DD4->Release(); + lp_DD4 = NULL; + } + + // Release DirectDraw Interface + if(lp_DD) + { + lp_DD->Release(); + lp_DD = NULL; + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::InitWindow(void) +{ + HRESULT result; + SLONG flags; + + + // Check Initialization + if((!hDDLibWindow) || (!IsWindow(hDDLibWindow))) + { + // Error, we need a valid window to continue + result = DDERR_GENERIC; + // Output error. + return result; + } + +#ifdef TARGET_DC + // Must be this on DC. + flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN; +#else //#ifdef TARGET_DC + // Get Cooperative Flags + if(IsFullScreen()) + { + flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_FPUSETUP; + } + else + { + flags = DDSCL_NORMAL | DDSCL_FPUSETUP; + } +#endif //#else //#ifdef TARGET_DC + + // Set Cooperative Level + result = lp_DD4->SetCooperativeLevel(hDDLibWindow,flags); + if(FAILED(result)) + { + // Error + // Output error. + return result; + } + + // init VB + VB_Init(); + TheVPool->Create(lp_D3D, !CurrDevice->IsHardware()); + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::FiniWindow(void) +{ + HRESULT result; + + VB_Term(); + +#ifndef TARGET_DC + if(lp_DD4) + { + result = lp_DD4->SetCooperativeLevel(hDDLibWindow,DDSCL_NORMAL|DDSCL_FPUSETUP); + if(FAILED(result)) + { + // Error + // Output error. + return result; + } + } +#endif + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + + + +#define FMV1a "eidos" +#define FMV1b "logo24" +#define FMV2 "pcintro_withsound" +#define FMV3 "new_pccutscene%d_300" + + +#ifndef TARGET_DC +// this function returns true to continue or false to end the movie + +static LPDIRECTDRAWSURFACE4 fmv_primary; +static LPDIRECTDRAWSURFACE4 fmv_secondary; + +static bool bink_flipper() +{ + fmv_primary->Blt(NULL, fmv_secondary, NULL, DDBLT_WAIT, NULL); + + ULONG input = get_hardware_input(INPUT_TYPE_JOY) | get_hardware_input(INPUT_TYPE_KEY); + + if (input & (INPUT_MASK_JUMP|INPUT_MASK_START|INPUT_MASK_SELECT|INPUT_MASK_KICK|INPUT_MASK_PUNCH|INPUT_MASK_ACTION)) + { + return false; + } + + return true; +} + + + +static void PlayMovie(int type) +{ + LPDIRECTDRAW lpDD; + LPDIRECTDRAW4 lpDD4; + HRESULT res; + + // init DirectDraw + if (FAILED(DirectDrawCreate(NULL, &lpDD, NULL))) return; + if (FAILED(lpDD->QueryInterface((REFIID)IID_IDirectDraw4, (void**)&lpDD4))) + { + lpDD->Release(); + return; + } + + if (FAILED(lpDD4->SetCooperativeLevel(hDDLibWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_FPUSETUP))) + { + lpDD4->Release(); + lpDD->Release(); + return; + } + + // clear the current screen + DDSURFACEDESC2 dd_sd; + InitStruct(dd_sd); + + dd_sd.dwFlags = DDSD_CAPS; + dd_sd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + if (SUCCEEDED(lpDD4->CreateSurface(&dd_sd, &fmv_primary, NULL))) + { + DDBLTFX bfx; + InitStruct(bfx); + + bfx.dwFillColor = 0; + + fmv_primary->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &bfx); + + fmv_primary->Release(); + } + + // go to 640x480xlots of colours + TRACE("Trying 640x480x24\n"); + if (FAILED(lpDD4->SetDisplayMode(640,480,24,0,0))) + { + TRACE("Trying 640x480x32\n"); + if (FAILED(lpDD4->SetDisplayMode(640,480,32,0,0))) + { + TRACE("Trying 640x480x16\n"); + if (FAILED(lpDD4->SetDisplayMode(640,480,16,0,0))) + { + goto error; + } + } + } + +#ifndef NDEBUG + ShowCursor(FALSE); +#endif + + // create a primary surface + InitStruct(dd_sd); + + dd_sd.dwFlags = DDSD_CAPS; + dd_sd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + if (SUCCEEDED(lpDD4->CreateSurface(&dd_sd, &fmv_primary, NULL))) + { + DDBLTFX bfx; + InitStruct(bfx); + + bfx.dwFillColor = 0; + + fmv_primary->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &bfx); + + // create a back buffer + InitStruct(dd_sd); + fmv_primary->GetSurfaceDesc(&dd_sd); + dd_sd.ddsCaps.dwCaps = 0; + + if (SUCCEEDED(lpDD4->CreateSurface(&dd_sd, &fmv_secondary, NULL))) + { + DDBLTFX bfx; + InitStruct(bfx); + + bfx.dwFillColor = 0; + + fmv_secondary->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &bfx); + + IDirectDrawSurface* lpdds; + + if (SUCCEEDED(fmv_secondary->QueryInterface(IID_IDirectDrawSurface, (void**)&lpdds))) + { + if (!type) + { + BinkPlay("bink\\" FMV1a ".bik", lpdds, bink_flipper); + BinkPlay("bink\\" FMV1b ".bik", lpdds, bink_flipper); + BinkPlay("bink\\" FMV2 ".bik", lpdds, bink_flipper); + } + else + { + char filename[MAX_PATH]; + sprintf(filename, "bink\\" FMV3, type); + TRACE("Playing %s\n", filename); + BinkPlay(filename, lpdds, bink_flipper); + } + lpdds->Release(); + } + + fmv_secondary->Release(); + } + + fmv_primary->Release(); + } + +#ifndef NDEBUG + ShowCursor(TRUE); +#endif + +error: + lpDD4->Release(); + lpDD->Release(); +} + + +LPDIRECTDRAWSURFACE4 mirror; + +static bool quick_flipper() +{ + the_display.lp_DD_FrontSurface->Blt(&the_display.DisplayRect,mirror,NULL,DDBLT_WAIT,NULL); + + return true; +} + +#endif //#ifndef TARGET_DC + + + +#ifdef TARGET_DC + + +#if 0 +// DirectArseShow version. + +void PlayQuickMovie(SLONG type, SLONG language) +{ + +//#ifdef DEBUG + // Not just now thanks. + //return; +//#endif + + // Use DirectShow on DC. + DDSURFACEDESC ddsd; + IDirectDraw *pDD; + IDirectDrawSurface *pSurface; + IMultiMediaStream *pMMStream; + + IDirectDrawSurface *back_surface; + + HRESULT hres = CoInitializeEx(NULL,COINIT_MULTITHREADED); + + if (SUCCEEDED(the_display.lp_DD_FrontSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&pSurface)) && + SUCCEEDED(the_display.lp_DD_BackSurface->QueryInterface(IID_IDirectDrawSurface, (void**)&back_surface))) + { + + pSurface->AddRef(); + int i = pSurface->Release(); + ASSERT ( i == 1 ); + back_surface->AddRef(); + i = back_surface->Release(); + ASSERT ( i == 1 ); + + +#if 0 + // Create a texture to render to. + DDSURFACEDESC ddsd; + InitStruct(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + ddsd.dwWidth = 1024; + ddsd.dwHeight = 512; + //ddsd.dwWidth = 512; + //ddsd.dwHeight = 256; + + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY; + //ddsd.ddsCaps.dwCaps2 = 0; + InitStruct(ddsd.ddpfPixelFormat); + ddsd.ddpfPixelFormat.dwFourCC = 0; +#if 0 + // Can't get 32bpp to work + ddsd.ddpfPixelFormat.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; + ddsd.ddpfPixelFormat.dwRGBBitCount = 32; + ddsd.ddpfPixelFormat.dwRBitMask = 0x00ff0000; + ddsd.ddpfPixelFormat.dwGBitMask = 0x0000ff00; + ddsd.ddpfPixelFormat.dwBBitMask = 0x000000ff; + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; +#else + // Can't get 32bpp to work + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwRGBBitCount = 16; + ddsd.ddpfPixelFormat.dwRBitMask = 0xf800; + ddsd.ddpfPixelFormat.dwGBitMask = 0x07e0; + ddsd.ddpfPixelFormat.dwBBitMask = 0x001f; + ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0x0000; +#endif + + + IDirectDrawSurface *pddsTexture; + hres = the_display.lp_DD->CreateSurface(&ddsd, &pddsTexture, NULL); + ASSERT ( SUCCEEDED ( hres ) ); +#else + // No texturing gubbins. + IDirectDrawSurface *pddsTexture = NULL; +#endif + + + char filename[MAX_PATH]; + char *pcDirectory; + + switch ( language ) + { + case 1: + pcDirectory = "\\CD-ROM\\fallen\\dshow_french\\"; + break; + default: + ASSERT ( FALSE ); + /* FALLTHROUGH */ + case 0: + pcDirectory = "\\CD-ROM\\fallen\\dshow\\"; + break; + } + + + if ( type == -1 ) + { + // These two don't have language-specific versions. + // Eidos & MF logo FMVs + ASSERT ( language == 0 ); + + // Play this one (Eidos). +#if 0 + RenderFileToMMStream("\\CD-ROM\\fallen\\dshow\\" FMV1a ".avi", &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface, pddsTexture); + i = pMMStream->Release(); + ASSERT ( i == 0 ); +#endif + + // Then play this one (Muckyfoot). + sprintf(filename, "\\CD-ROM\\fallen\\dshow\\" FMV1b ".avi" ); + } + else if ( type == 0 ) + { + // The intro movie. + sprintf(filename, "%s" FMV2 ".avi", pcDirectory ); + } + else + { + sprintf(filename, "%s" FMV3 ".avi", pcDirectory, type ); + } + + + +#if 1 +#ifdef DEBUG + // Show lots of them. +#if 1 + RenderFileToMMStream("\\CD-ROM\\fallen\\dshow\\pccutscene1_300_25_100.avi", &pMMStream, the_display.lp_DD); + // This seems to be needed, sadly. + Sleep ( 500 ); + RenderStreamToSurface(pSurface, pMMStream, back_surface, pddsTexture); + i = pMMStream->Release(); + ASSERT ( i == 0 ); +#endif + +#if 1 + RenderFileToMMStream("\\CD-ROM\\fallen\\dshow_french\\PCcutscene1_TEST_320_15C.avi", &pMMStream, the_display.lp_DD); + // This seems to be needed, sadly. + Sleep ( 500 ); + RenderStreamToSurface(pSurface, pMMStream, back_surface, pddsTexture); + i = pMMStream->Release(); + ASSERT ( i == 0 ); +#endif +#endif +#endif + + +#if 0 +// Not just yet. + TRACE("Playing %s\n", filename); + RenderFileToMMStream(filename, &pMMStream, the_display.lp_DD); + RenderStreamToSurface(pSurface, pMMStream, back_surface, pddsTexture); + i = pMMStream->Release(); + ASSERT ( i == 0 ); + +#endif + + if ( pddsTexture != NULL ) + { + i = pddsTexture->Release(); + ASSERT ( i == 0 ); + } + i = pSurface->Release(); + ASSERT ( i == 0 ); + i = back_surface->Release(); + ASSERT ( i == 0 ); + } + else + { + ASSERT ( FALSE ); + } + + + hres = the_display.lp_D3D_Device->EndScene(); + ASSERT ( SUCCEEDED ( hres ) ); + + + CoUninitialize(); + + + // Incant this spell to get the DC to GIVE ME BACK MY MEMORY YOU BASTARD + // It is important to _believe_ this will work. If you question it, it will fail. + // You have been warned. Ask not for whom the memory vanishes... + + Sleep(4); + CoFreeUnusedLibraries(); + Sleep(4); + CoFreeUnusedLibraries(); + +} + +#else + + +static bool bMWInitialised = FALSE; + + + +static bool bThereWasAnErrorInMW = FALSE; + +static void errMWErrFunc(void *errobj, Sint32 errcode) +{ + bThereWasAnErrorInMW = TRUE; + + return; +} + + + +void PlayQuickMovie(SLONG type, SLONG language, bool bAllowButtonsToExit ) +{ + +#if 0 +#ifdef DEBUG + // Not just now thanks. + return; +#endif +#endif + + + + + // CRI had better rule. + char filename[MAX_PATH]; + char *pcDirectory; + char *pcSubDir; + + switch ( language ) + { + case 1: + pcDirectory = "\\CD-ROM\\fallen\\dshowfr\\"; + break; + default: + ASSERT ( FALSE ); + /* FALLTHROUGH */ + case 0: + pcDirectory = "\\CD-ROM\\fallen\\dshow\\"; + break; + } + + + + bool bSixtyHertz; + + // 50 or 60Hz? + BYTE bFormat = GetVideoOutputFormat(); + switch ( bFormat ) + { + case VIDFMT_NTSC_RGB: + case VIDFMT_NTSC: + case VIDFMT_VGA: + // NTSC 60Hz or VGA 60Hz. + bSixtyHertz = TRUE; + break; + + case VIDFMT_PAL_RGB: + case VIDFMT_PAL: + case VIDFMT_PAL_M_RGB: + case VIDFMT_PAL_M: + case VIDFMT_PAL_N_RGB: + case VIDFMT_PAL_N: + // PAL 50Hz. + bSixtyHertz = FALSE; + break; + + default: + ASSERT ( FALSE ); + break; + } + + if ( bSixtyHertz ) + { + // Don't have any 60Hz ones yet. + //pcSubDir = "Sixty\\"; + pcSubDir = "Fifty\\"; + } + else + { + pcSubDir = "Fifty\\"; + } + + + switch ( type ) + { + case -3: + ASSERT ( language == 0 ); + // CRI logo. + sprintf ( filename, "%s%ssfdlogoq.sfd", pcDirectory, pcSubDir ); + break; + case -2: + ASSERT ( language == 0 ); + // Eidos logo. + sprintf ( filename, "%s%seidos.sfd", pcDirectory, pcSubDir ); + break; + case -1: + ASSERT ( language == 0 ); + // MF logo. + sprintf ( filename, "%s%slogo24.sfd", pcDirectory, pcSubDir ); + break; + case 0: + // Intro movie. + sprintf ( filename, "%s%spcintro_withsound.sfd", pcDirectory, pcSubDir ); + break; + case 1: + // Cutscene 1 (Bane's office). + sprintf ( filename, "%s%spccutscene1_300.sfd", pcDirectory, pcSubDir ); + break; + case 2: + // Cutscene 2 (before Day of Reckoning). + // No speech - use the English. + sprintf ( filename, "\\CD-ROM\\fallen\\dshow\\%spccutscene2_300.sfd", pcSubDir ); + break; + case 3: + // Cutscene 3 (Day of Reckoning won). + // No speech - use the English. + sprintf ( filename, "\\CD-ROM\\fallen\\dshow\\%spccutscene3_300.sfd", pcSubDir ); + break; + default: + ASSERT ( FALSE ); + break; + } + + + // Test this one instead. + //strcpy ( filename, "\\CD-ROM\\fallen\\dshow\\pcintro_withsound.sfd" ); + + +#if 0 + // Sample movie settings. +#define MOVIE_FTYPE MWE_PLY_FTYPE_SFD +#define MOVIE_BPS (1024 * 1024 * 4) +#define MOVIE_WIDTH (352) +#define MOVIE_HEIGHT (240) +#define MOVIE_NFRM (3) +#else +#define MOVIE_FTYPE MWE_PLY_FTYPE_SFD +// Yes, the movies are actually only 3800 bits/sec, but any lower than +// this and it starts to break up. Bloody thing. +#define MOVIE_BPS (1024 * 1024 * 5) +//#define MOVIE_WIDTH (640) +//#define MOVIE_HEIGHT (480) +#define MOVIE_WIDTH (320) +#define MOVIE_HEIGHT (240) +//#define MOVIE_WIDTH (512) +//#define MOVIE_HEIGHT (256) +#define MOVIE_NFRM (3) +#endif + + +// Doesn't work - don't set it. +#define HALVE_FRAME_RATE 0 + + + + // Init CRI stuff. + + // Imported from DCLowLevel. +extern LPDIRECTSOUND g_pds; + + + ASSERT ( the_display.lp_DD4 != NULL ); + ASSERT ( the_display.lp_DD_FrontSurface != NULL ); + ASSERT ( the_display.lp_DD_BackSurface != NULL ); + ASSERT ( g_pds != NULL ); + + + MWS_PLY_IPRM_SFW iprm; + + memset(&iprm, 0, sizeof(MWS_PLY_IPRM_SFW)); + iprm.winhn = NULL; + iprm.ddraw = the_display.lp_DD4; + iprm.dds_prim = the_display.lp_DD_FrontSurface; + iprm.dds_back = the_display.lp_DD_BackSurface; + iprm.dsnd = g_pds; + + + // 50 or 60Hz? + if ( bSixtyHertz ) + { +#if HALVE_FRAME_RATE + iprm.vfreq = MWE_PLY_VFREQ_NTSC / 2; +#else + iprm.vfreq = MWE_PLY_VFREQ_NTSC; +#endif + } + else + { +#if HALVE_FRAME_RATE + iprm.vfreq = MWE_PLY_VFREQ_PAL / 2; +#else + iprm.vfreq = MWE_PLY_VFREQ_PAL; +#endif + } + + + mwPlyInitSfw(&iprm); + + mwPlyEntryErrFunc(errMWErrFunc, NULL); + + //bMWInitialised = TRUE; + + + + // Do this and discard to stop held-down buttons skipping past (all too easy to do). + get_hardware_input(INPUT_TYPE_JOY | INPUT_TYPE_GONEDOWN); + + + // Allocate the work memory. + DWORD dwWorkSpaceSize = mwPlyCalcWorkSfw(MOVIE_FTYPE, MOVIE_BPS, + MOVIE_WIDTH, MOVIE_HEIGHT, MOVIE_NFRM); + + + Sint8 *pcMWWorkSpace = (Sint8*)VirtualAlloc(NULL, dwWorkSpaceSize, MEM_COMMIT, PAGE_READWRITE); + if ( pcMWWorkSpace == NULL ) + { + // Out of space for FMV. + ASSERT ( FALSE ); + } + else + { + + // Turn off VMU screen updates - they are waaaay too slow. + SetVMUScreenUpdateEnable ( FALSE ); + + + // Draw black screens. + DDBLTFX ddbf; + ddbf.dwSize = sizeof(DDBLTFX); + ddbf.dwFillColor = 0; + the_display.lp_DD_BackSurface->Blt(NULL, NULL, NULL, + DDBLT_WAIT | DDBLT_COLORFILL, &ddbf); + the_display.lp_DD_FrontSurface->Flip(NULL, DDFLIP_WAIT); + the_display.lp_DD4->WaitForVerticalBlank(DDWAITVB_BLOCKEND, NULL); + the_display.lp_DD_BackSurface->Blt(NULL, NULL, NULL, + DDBLT_WAIT | DDBLT_COLORFILL, &ddbf); + + + +// Tries to "catch" dropped video frames. +// Actually, at the moment, it just spots them. +#define CATCH_DROPPED_FRAMES 1 + + + + MWPLY ply; + + // Start video. + MWS_PLY_CPRM_SFW cprm; + + memset(&cprm, 0, sizeof(cprm)); + cprm.ftype = MOVIE_FTYPE; + cprm.max_bps = MOVIE_BPS; + cprm.max_width = MOVIE_WIDTH; + cprm.max_height = MOVIE_HEIGHT; + cprm.nfrm_pool_wk = MOVIE_NFRM; + cprm.wksize = dwWorkSpaceSize; + cprm.work = pcMWWorkSpace; + + ply = mwPlyCreateSfw(&cprm); + ASSERT ( ply != NULL ); + + // Filename is in ASCII, not unicode. + mwPlyStartFname ( ply, (signed char *)filename ); + + +#if CATCH_DROPPED_FRAMES + // Wait for a VBLANK. + the_display.lp_DD4->WaitForVerticalBlank(DDWAITVB_BLOCKEND, NULL); + DWORD dwNumFramesIDrew = 0; + DWORD dwNumFramesIActuallyDrew = 0; + DWORD dwStartTime = timeGetTime(); + DWORD dwLastFrameError = 0; +#endif + + + + + + // Play video. + MSG msg; + bool bStopIt = FALSE; + + while ( !bStopIt ) + { + mwExecMainServer(); + + // Flush messages (but ignore them). + if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) + { + if (!GetMessage(&msg, NULL, 0, 0)) + { + // Panic. + ASSERT ( FALSE ); + break; + } + //TranslateMessage(&msg); + //DispatchMessage(&msg); + } + + + // Only scan input every now and then. + static iInputCountdown = 0; + if ( ( ( iInputCountdown++ ) & 3 ) == 0 ) + { + ULONG input = get_hardware_input(INPUT_TYPE_JOY | INPUT_TYPE_GONEDOWN); + if ( bAllowButtonsToExit ) + { + if (input & (INPUT_MASK_JUMP|INPUT_MASK_START|INPUT_MASK_SELECT|INPUT_MASK_KICK|INPUT_MASK_PUNCH|INPUT_MASK_ACTION)) + { + bStopIt = TRUE; + } + } + else + { + // Not allowed to exit this one, but read the input anyway + // (there's stuff that needs doing, e.g. soft reset handling). + } + } + + if (mwPlyGetStat(ply) == MWE_PLY_STAT_PLAYEND) + { + // End of movie. + bStopIt = TRUE; + } + + if ( bThereWasAnErrorInMW ) + { + ASSERT ( FALSE ); + bStopIt = TRUE; + } + + // Flip the screen. + the_display.lp_DD_FrontSurface->Flip(NULL, 0); + + // V sync. + the_display.lp_DD4->WaitForVerticalBlank(DDWAITVB_BLOCKEND, NULL); +#if HALVE_FRAME_RATE + // Double wait. + the_display.lp_DD4->WaitForVerticalBlank(DDWAITVB_BLOCKEND, NULL); +#endif + + +#if CATCH_DROPPED_FRAMES + dwNumFramesIDrew++; + dwNumFramesIActuallyDrew++; + + // The >>4 is to stop the calculations ovberflowing. + DWORD dwTimeDifference = ( timeGetTime() - dwStartTime ) >> 4; + DWORD dwNumberOfFramesThatShouldHaveBeenShown = ( dwTimeDifference * iprm.vfreq ) / ( ( 1000 * 1000 ) >> 4 ); + int iThisError = (int)dwNumberOfFramesThatShouldHaveBeenShown - (int)dwNumFramesIDrew; + + if ( iThisError > 1 ) + { + if ( dwNumFramesIActuallyDrew < 200 ) + { + // Bedding in period - for the first chunk of frames, + // there is a big delay, which should not be corrected for. + TRACE ( "Bedding in error %i\n", iThisError ); + dwNumFramesIDrew += iThisError - 1; + } + else + { + // Try to correct the error by doing another frame. + TRACE ( "Correcting error %i\n", iThisError ); + mwExecMainServer(); + + // This is a massive tweak thing. For some reason, this over-corrects + // a fair bit. So pretend we drew more than we did. + dwNumFramesIDrew += iThisError >> 1; + dwNumFramesIActuallyDrew++; + } + } + +#endif + + + } + + TRACE ( "Done\n" ); + + + + // Stop video. + + // Draw black screens again. + ddbf.dwSize = sizeof(DDBLTFX); + ddbf.dwFillColor = 0; + the_display.lp_DD_BackSurface->Blt(NULL, NULL, NULL, + DDBLT_WAIT | DDBLT_COLORFILL, &ddbf); + the_display.lp_DD_FrontSurface->Flip(NULL, DDFLIP_WAIT); + the_display.lp_DD4->WaitForVerticalBlank(DDWAITVB_BLOCKEND, NULL); + the_display.lp_DD_BackSurface->Blt(NULL, NULL, NULL, + DDBLT_WAIT | DDBLT_COLORFILL, &ddbf); + + mwPlyStop(ply); + + mwPlyDestroy(ply); + } + + // End-of-day cleanup. + mwPlyFinishSfw(); + + + // Turn VMU screen updates back on. + SetVMUScreenUpdateEnable ( TRUE ); + + + if ( pcMWWorkSpace != NULL ) + { + VirtualFree ( pcMWWorkSpace , 0, MEM_RELEASE ); + } + + +#if 0 + // Incant this spell to get the DC to GIVE ME BACK MY MEMORY YOU BASTARD + // It is important to _believe_ this will work. If you question it, it will fail. + // You have been warned. Ask not for whom the memory vanishes... + + Sleep(4); + CoFreeUnusedLibraries(); + Sleep(4); + CoFreeUnusedLibraries(); +#endif + +} + +#endif + + + +#else //#ifdef TARGET_DC +void PlayQuickMovie(SLONG type, SLONG language_ignored, bool bIgnored ) +{ + DDSURFACEDESC2 back; + DDSURFACEDESC2 mine; + + // + // Must create a 640x480 surface with the same pixel format as the + // primary surface. + // + + InitStruct(back); + + the_display.lp_DD_BackSurface->GetSurfaceDesc(&back); + + // + // Create the mirror surface in system memory. + // + + InitStruct(mine); + + mine.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + mine.dwWidth = 640; + mine.dwHeight = 480; + mine.ddpfPixelFormat = back.ddpfPixelFormat; + mine.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + + HRESULT result = the_display.lp_DD4->CreateSurface(&mine, &mirror, NULL); + + IDirectDrawSurface *lpdds; + + if (SUCCEEDED(mirror->QueryInterface(IID_IDirectDrawSurface, (void**)&lpdds))) + { + if (!type) + { + BinkPlay("bink\\" FMV1a ".bik", lpdds, quick_flipper); + BinkPlay("bink\\" FMV1b ".bik", lpdds, quick_flipper); + BinkPlay("bink\\" FMV2 ".bik", lpdds, quick_flipper); + } + else + { + char filename[MAX_PATH]; + sprintf(filename, "bink\\" FMV3 ".bik", type); + TRACE("Playing %s\n", filename); + BinkPlay(filename, lpdds, quick_flipper); + } + } + + mirror->Release(); +} +#endif //#else //#ifdef TARGET_DC + + +#ifndef TARGET_DC +void Display::RunFMV() +{ + if (!hDDLibWindow) return; + + // should we run it? + if (!ENV_get_value_number("play_movie", 1, "Movie")) return; + + PlayQuickMovie(0,0,TRUE); +} +#endif + + +void Display::RunCutscene(int which, int language, bool bAllowButtonsToExit) +{ + //extern void FRONTEND_scr_unload_theme(void); + //FRONTEND_scr_unload_theme(); + + //Fini(); + + PlayQuickMovie(which, language, bAllowButtonsToExit); + + //Init(); +} + + +//--------------------------------------------------------------- + +HRESULT Display::InitFullscreenMode(void) +{ + SLONG flags = 0, + style, + w,h,bpp,refresh; + HRESULT result; + + + // Check Initialization + if((!CurrMode) || (!lp_DD4)) + { + // Error, we need a valid mode and DirectDraw 2 interface to proceed + result = DDERR_GENERIC; + DebugText("InitFullScreenMode: invalid initialization\n"); + return result; + } + + // DC is always fullscreen +#ifndef TARGET_DC + // Do window mode setup. + if(!IsFullScreen()) + { + // Set window style. + style = GetWindowStyle(hDDLibWindow); + style &= ~WS_POPUP; + style |= WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME|WS_MINIMIZEBOX; + SetWindowLong(hDDLibWindow,GWL_STYLE,style); + + // Save Surface Rectangle. + DisplayRect.left = 0; + DisplayRect.top = 0; + DisplayRect.right = RealDisplayWidth; + DisplayRect.bottom = RealDisplayHeight; + + AdjustWindowRectEx ( + &DisplayRect, + GetWindowStyle(hDDLibWindow), + GetMenu(hDDLibWindow) != NULL, + GetWindowExStyle(hDDLibWindow) + ); + SetWindowPos( + hDDLibWindow, + NULL, + 0,0, + DisplayRect.right-DisplayRect.left, + DisplayRect.bottom-DisplayRect.top, + SWP_NOMOVE|SWP_NOZORDER|SWP_SHOWWINDOW + ); + + GetClientRect(hDDLibWindow,&the_display.DisplayRect); + ClientToScreen(hDDLibWindow,(LPPOINT)&the_display.DisplayRect); + ClientToScreen(hDDLibWindow,(LPPOINT)&the_display.DisplayRect+1); + + // Success + TurnValidFullscreenOn(); + return DD_OK; + } + + + // Get the shell menu & window style. + hDDLibMenu = GetMenu(hDDLibWindow); + hDDLibStyle = GetWindowLong(hDDLibWindow,GWL_STYLE); + hDDLibStyleEx = GetWindowLong(hDDLibWindow,GWL_EXSTYLE); + +#else //#ifndef TARGET_DC + hDDLibMenu = 0; + hDDLibStyle = 0; + hDDLibStyleEx = 0; +#endif //#else //#ifndef TARGET_DC + + +#ifdef TARGET_DC + // We know which mode we want, and what to try. + + DisplayRect.left = 0; + DisplayRect.top = 0; + DisplayRect.right = 640; + DisplayRect.bottom = 480; + + + // Find out which modes we are allowed to support. + // This si from the command-line +extern LPSTR lpszGlobalArgs; + + + + + // Er.. just do some non-display-related regional checking here as well. + BYTE bCountry = FirmwareGetCountryCode(); + + + if ( NULL != strstr ( lpszGlobalArgs, "EUROPE_ONLY" ) ) + { + // This is a European build, and should only work there. + if ( bCountry != COUNTRY_EUROPE ) + { + TRACE ( "EUROPE_ONLY - rebooting\n" ); + ASSERT ( FALSE ); + // Reset to Boot ROM. + ResetToFirmware(); + } + } + if ( NULL != strstr ( lpszGlobalArgs, "AMERICA_ONLY" ) ) + { + // This is an American build, and should only work there. + if ( bCountry != COUNTRY_AMERICA ) + { + TRACE ( "AMERICA_ONLY - rebooting\n" ); + ASSERT ( FALSE ); + // Reset to Boot ROM. + ResetToFirmware(); + } + } + + + + + BYTE bFormat = GetVideoOutputFormat(); + switch ( bFormat ) + { + case VIDFMT_NTSC_RGB: + case VIDFMT_NTSC: + // NTSC 60Hz. + +#if 0 + if ( NULL != strstr ( lpszGlobalArgs, "NO_NTSC" ) ) + { + TRACE ( "NO_NTSC set, and this is an NTSC mode - rebooting\n" ); + ASSERT ( FALSE ); + // Reset to Boot ROM. + ResetToFirmware(); + } +#endif + + + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 30, 0 ); + if(SUCCEEDED(result)) + { + eDisplayType = DT_NTSC; + TurnValidFullscreenOn(); + return result; + } + break; + + case VIDFMT_PAL_RGB: + case VIDFMT_PAL: + case VIDFMT_PAL_M_RGB: + case VIDFMT_PAL_M: + case VIDFMT_PAL_N_RGB: + case VIDFMT_PAL_N: + // PAL 50Hz. + // Try a stretched one. + +#if 0 + if ( NULL != strstr ( lpszGlobalArgs, "NO_PAL" ) ) + { + TRACE ( "NO_PAL set, and this is a PAL mode - rebooting\n" ); + ASSERT ( FALSE ); + // Reset to Boot ROM. + ResetToFirmware(); + } +#endif + + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 25, DDSDM_PALHEIGHTRATIO_1_100 ); + if(SUCCEEDED(result)) + { + eDisplayType = DT_PAL; + TurnValidFullscreenOn(); + return result; + } + + // Wacky. Try normal then. + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 25, 0 ); + if(SUCCEEDED(result)) + { + eDisplayType = DT_PAL; + TurnValidFullscreenOn(); + return result; + } + break; + + case VIDFMT_VGA: + // VGA 60Hz. + +#if 0 + if ( NULL != strstr ( lpszGlobalArgs, "NO_VGA" ) ) + { + TRACE ( "NO_VGA set, and this is a VGA mode - rebooting\n" ); + ASSERT ( FALSE ); + // Reset to Boot ROM. + ResetToFirmware(); + } +#endif + + + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 60, 0 ); + if(SUCCEEDED(result)) + { +#ifdef DEBUG + // For testing US settings. + eDisplayType = DT_NTSC; +#else + eDisplayType = DT_VGA; +#endif + TurnValidFullscreenOn(); + return result; + } + break; + + default: + ASSERT ( FALSE ); + break; + } + + + ASSERT ( FALSE ); + +#if 0 +#if 0 + // Bloody thing doesn't work - corrupts my textures and puts fuzz on the screen. + + // Try stretched PAL 50Hz.interlaced + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 25, DDSDM_PALHEIGHTRATIO_1_066 ); + if(SUCCEEDED(result)) + { + TurnValidFullscreenOn(); + return result; + } +#endif + + // NTSC 60Hz interlaced + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 30, 0 ); + if(SUCCEEDED(result)) + { + TurnValidFullscreenOn(); + return result; + } + + // Non-stretched PAL 50Hz interlaced + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 25, 0 ); + if(SUCCEEDED(result)) + { + TurnValidFullscreenOn(); + return result; + } + + // VGA 60Hz + result = lp_DD4->SetDisplayMode ( 640, 480, 16, 60, 0 ); + if(SUCCEEDED(result)) + { + TurnValidFullscreenOn(); + return result; + } +#endif + + ASSERT ( FALSE ); + +#else + + + // Calculate Mode info + CurrMode->GetMode(&w,&h,&bpp,&refresh); + + // Special check for mode 320 x 200 x 8 + if((w==320) && (h==200) && (bpp==8)) + { + // Make sure we use Mode 13 instead of Mode X + flags = DDSDM_STANDARDVGAMODE; + } + + // Set Requested Fullscreen mode + result = lp_DD4->SetDisplayMode(w,h,bpp,refresh,flags); + if(SUCCEEDED(result)) + { + // Save Surface Rectangle + DisplayRect.left = 0; + DisplayRect.top = 0; + DisplayRect.right = w; + DisplayRect.bottom = h; + + // Success + TurnValidFullscreenOn(); + return result; + } + + DebugText("SetDisplayMode failed (%d x %d x %d), trying (640 x 480 x %d)\n", w, h, bpp, bpp); + + // Don't give up! + // Try 640 x 480 x bpp mode instead + if((w!=DEFAULT_WIDTH || h!=DEFAULT_HEIGHT)) + { + w = DEFAULT_WIDTH; + h = DEFAULT_HEIGHT; + + CurrMode = ValidateMode(CurrDriver,w,h,bpp,0,CurrDevice); + if(CurrMode) + { + result = lp_DD4->SetDisplayMode(w,h,bpp,0,0); + if(SUCCEEDED(result)) + { + // Save Surface Rectangle + DisplayRect.left = 0; + DisplayRect.top = 0; + DisplayRect.right = w; + DisplayRect.bottom = h; + + // Success + TurnValidFullscreenOn(); + return result; + } + } + } + + // Keep trying + // Try 640 x 480 x 16 mode instead + if(bpp!=DEFAULT_DEPTH) + { + DebugText("SetDisplayMode failed (640 x 480 x %d), trying (640 x 480 x 16)\n", bpp); + bpp = DEFAULT_DEPTH; + + CurrMode = ValidateMode(CurrDriver,w,h,bpp,0,CurrDevice); + if(CurrMode) + { + result = lp_DD4->SetDisplayMode(w,h,bpp,0,0); + if(SUCCEEDED(result)) + { + // Save Surface Rectangle + DisplayRect.left = 0; + DisplayRect.top = 0; + DisplayRect.right = w; + DisplayRect.bottom = h; + + // Success + TurnValidFullscreenOn(); + return result; + } + } + } + // Failure + // Output error. + return result; + +#endif + +} + +//--------------------------------------------------------------- + +HRESULT Display::FiniFullscreenMode(void) +{ + TurnValidFullscreenOff (); + + // Restore original desktop mode + if(lp_DD4) + lp_DD4->RestoreDisplayMode(); + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +// +// Given the bitmask for a colour in a pixel format, it calculates the mask and +// shift so that you can construct a pixel in pixel format given its RGB values. +// The formula is... +// +// PIXEL(r,g,b) = ((r >> mask) << shift) | ((g >> mask) << shift) | ((b >> mask) << shift); +// +// THIS ASSUMES that r,g,b are 8-bit values. +// + +void calculate_mask_and_shift( + ULONG bitmask, + SLONG *mask, + SLONG *shift) +{ + SLONG i; + SLONG b; + SLONG num_bits = 0; + SLONG first_bit = -1; + + LogText(" bitmask %x \n",bitmask); + + for (i = 0, b = 1; i < 32; i++, b <<= 1) + { + if (bitmask & b) + { + num_bits += 1; + + if (first_bit == -1) + { + // + // We have found the first bit. + // + + first_bit = i; + } + } + } + + if (first_bit == -1 || + num_bits == 0) + { + // + // This is bad! + // + + LogText(" poo mask shift first bit %d num_bits %d \n",first_bit,num_bits); + TRACE("No valid masks and shifts.\n"); + LogText("No valid masks and shifts.\n"); + + *mask = 0; + *shift = 0; + + return; + } + + *mask = 8 - num_bits; + *shift = first_bit; + + if (*mask < 0) + { + // + // More than 8 bits per colour component? May + // as well support it! + // + + *shift -= *mask; + *mask = 0; + } +} + + + + + +//--------------------------------------------------------------- + +HRESULT Display::InitFront(void) +{ + DDSURFACEDESC2 dd_sd; + HRESULT result; + + + // Check Initialization + if((!CurrMode) || (!lp_DD4)) + { + // Error, Need a valid mode and DD interface to proceed + result = DDERR_GENERIC; + // Output error. + return result; + } + + // Note: There is no need to fill in width, height, bpp, etc. + // This was taken care of in the SetDisplayMode call. + + // Setup Surfaces caps for a front buffer and back buffer + InitStruct(dd_sd); + +#ifndef TARGET_DC + if(IsFullScreen() && CurrDevice->IsHardware()) +#endif + { + // + // Fullscreen harware. + // + + dd_sd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + dd_sd.ddsCaps.dwCaps = DDSCAPS_COMPLEX|DDSCAPS_FLIP|DDSCAPS_PRIMARYSURFACE|DDSCAPS_3DDEVICE; + dd_sd.dwBackBufferCount = 1; + } +#ifndef TARGET_DC + else + { + // + // In a window or software mode. + // + + dd_sd.dwFlags = DDSD_CAPS; + dd_sd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + } +#endif + + // Create Primary surface + result = lp_DD4->CreateSurface(&dd_sd,&lp_DD_FrontSurface,NULL); + if(FAILED(result)) + { + // Error + DebugText("InitFront: unable to create front surface result %d\n",result); + return result; + } + +#ifndef TARGET_DC + // Create and attach palette, if necessary. + result = InitPalette(); + if(FAILED(result)) + return result; +#endif + +#ifndef TARGET_DC + if (!the_display.IsFullScreen()) + { + // Create and attach clipper, if necessary. + result = InitClipper(); + if(FAILED(result)) + return result; + } +#endif + + // No gamma control on DC. +#ifndef TARGET_DC + // create gamma control + result = lp_DD_FrontSurface->QueryInterface(IID_IDirectDrawGammaControl, (void**)&lp_DD_GammaControl); + if (FAILED(result)) + { + lp_DD_GammaControl = NULL; + TRACE("No gamma\n"); + } + else + { + TRACE("Gamma control OK\n"); + + int black, white; + + GetGamma(&black, &white); + SetGamma(black, white); + } +#endif + + // Mark as Valid + TurnValidFrontOn(); + + // + // We need to work out the pixel format of the front buffer. + // + + InitStruct(dd_sd); + + lp_DD_FrontSurface->GetSurfaceDesc(&dd_sd); + + // + // It must be an RGB mode! + // + + ASSERT(dd_sd.ddpfPixelFormat.dwFlags & DDPF_RGB); + + // + // Work out the masks and shifts for each colour component. + // + + calculate_mask_and_shift(dd_sd.ddpfPixelFormat.dwRBitMask, &mask_red, &shift_red); + calculate_mask_and_shift(dd_sd.ddpfPixelFormat.dwGBitMask, &mask_green, &shift_green); + calculate_mask_and_shift(dd_sd.ddpfPixelFormat.dwBBitMask, &mask_blue, &shift_blue); + + LogText(" mask red %x shift red %d \n",mask_red,shift_red); + LogText(" mask green %x shift green %d \n",mask_green,shift_green); + LogText(" mask blue %x shift blue %d \n",mask_blue,shift_blue); + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::FiniFront(void) +{ + // Mark as Invalid + TurnValidFrontOff(); + + // Cleanup clipper. + FiniClipper(); + + // Cleanup palette. + FiniPalette(); + + // release gamma control + if (lp_DD_GammaControl) + { + lp_DD_GammaControl->Release(); + lp_DD_GammaControl = NULL; + } + + // Release Front Surface Object + if(lp_DD_FrontSurface) + { + lp_DD_FrontSurface->Release(); + lp_DD_FrontSurface = NULL; + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::InitPalette(void) +{ + SLONG c0, + flags, + pal_mem_size; + DDSURFACEDESC2 dd_sd; + HDC hdc; + HRESULT result; + + + // Destroy old palette + FiniPalette(); + + // Make sure we are properly intialized + // for this to work + if((!lp_DD4) || (!lp_DD_FrontSurface)) + { + // Error, need a valid DD interfac and a primary surface to continue + result = DDERR_GENERIC; + // Output error. + return result; + } + + // Get primary surface caps + InitStruct(dd_sd); + + result = lp_DD_FrontSurface->GetSurfaceDesc(&dd_sd); + if(FAILED(result)) + { + // Error + DebugText("InitPalette: unable to get FrontSurface description"); + return result; + } + + // Make sure it is a palettized surface + if(!IsPalettized(&(dd_sd.ddpfPixelFormat))) + { + return DD_OK; + } + + // Create and save System palette + hdc = GetDC(NULL); + PaletteSize = GetDeviceCaps(hdc,SIZEPALETTE); + if(PaletteSize) + { + if(PaletteSize>256) + PaletteSize = 256; + + // Get memory for system palette + lp_SysPalette = new PALETTEENTRY[PaletteSize]; + if(!lp_SysPalette) + { + ReleaseDC (NULL, hdc); + + // Error, not enough memory + result = DDERR_GENERIC; + DebugText("InitPalette: not enough memory for storing palette\n"); + goto cleanup; + } + + // Get Memory for current palette + lp_CurrPalette = new PALETTEENTRY[PaletteSize]; + if(!lp_CurrPalette) + { + ReleaseDC(NULL,hdc); + + // Error, not enough memory + result = DDERR_GENERIC; + DebugText("InitPalette: not enough memory for storing palette\n"); + goto cleanup; + } + + // Save system palette + GetSystemPaletteEntries(hdc,0,PaletteSize,lp_SysPalette); + + // Copy system palette to temporary values + pal_mem_size = PaletteSize*sizeof (PALETTEENTRY); + CopyMemory(lp_CurrPalette,lp_SysPalette,pal_mem_size); + } + ReleaseDC(NULL,hdc); + + if(dd_sd.ddpfPixelFormat.dwFlags&DDPF_PALETTEINDEXED1) + { + flags = DDPCAPS_1BIT; + + // Bagsy the whole palette. + for(c0= 0;c0<2;c0++) + lp_CurrPalette[c0].peFlags = D3DPAL_FREE|PC_RESERVED; + } + else if(dd_sd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2) + { + flags = DDPCAPS_2BIT; + + // Bagsy the whole palette. + for(c0=0;c0<4;c0++) + lp_CurrPalette[c0].peFlags = D3DPAL_FREE|PC_RESERVED; + } + else if(dd_sd.ddpfPixelFormat.dwFlags&DDPF_PALETTEINDEXED4) + { + flags = DDPCAPS_4BIT; + + // Bagsy the whole palette except first & last colours. + lp_CurrPalette[0].peFlags = D3DPAL_READONLY; + lp_CurrPalette[15].peFlags = D3DPAL_READONLY; + + for(c0=1;c0<15;c0++) + lp_CurrPalette[c0].peFlags = D3DPAL_FREE|PC_RESERVED; + } + else if(dd_sd.ddpfPixelFormat.dwFlags&DDPF_PALETTEINDEXED8) + { + flags = DDPCAPS_8BIT; + + // Bagsy the whole palette. + lp_CurrPalette[0].peFlags = D3DPAL_READONLY; + lp_CurrPalette[255].peFlags = D3DPAL_READONLY; + + for(c0=1;c0<254;c0++) + lp_CurrPalette[c0].peFlags = D3DPAL_FREE|PC_RESERVED; + } + else + { + result = DDERR_GENERIC; + DebugText("InitPalette: unknown palette type\n"); + goto cleanup; + } + + // Create Primary Palette + result = lp_DD4->CreatePalette ( + flags, + lp_CurrPalette, + &lp_DD_Palette, + NULL + ); + if(FAILED(result)) + { + DebugText("InitPalette: unable to create palette\n"); + goto cleanup; + } + + // Attach palette to primary surface + result = lp_DD_FrontSurface->SetPalette(lp_DD_Palette); + if(FAILED(result)) + { + // Error + DebugText("InitPalette: unable to attach palette to FrontSurface\n"); + goto cleanup; + } + + // Success + return DD_OK; + +cleanup: + + // Cleanup + FiniPalette(); + return result; +} + +//--------------------------------------------------------------- + +HRESULT Display::FiniPalette(void) +{ + // Clean up DD Palette object. + if(lp_DD_Palette) + { + lp_DD_Palette->Release(); + lp_DD_Palette = NULL; + } + + // Cleanup Current Palette + if(lp_CurrPalette) + { + delete []lp_CurrPalette; + lp_CurrPalette = NULL; + } + + // Cleanup System Palette + if(lp_SysPalette) + { + // Note: Should we try and restore system palette here ?!? + + // Destroy system palette + delete []lp_SysPalette; + lp_SysPalette = NULL; + } + + PaletteSize = 0; + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::InitBack(void) +{ + SLONG mem_type, + w,h; + DDSCAPS2 dd_scaps; + DDSURFACEDESC2 dd_sd; + HRESULT result; + LPD3DDEVICEDESC device_desc; + + + // Check Initialization + if ( + (!hDDLibWindow) || (!IsWindow(hDDLibWindow)) || + (!CurrDevice) || (!CurrMode) || + (!lp_DD4) || (!lp_D3D) || (!lp_DD_FrontSurface) + ) + { + // Error, Not initialized properly before calling this method + result = DDERR_GENERIC; + DebugText("InitBack: invalid initialisation\n"); + return result; + } + + // Calculate the width & height. This is useful for windowed mode & the z buffer. + w = abs(DisplayRect.right-DisplayRect.left); + h = abs(DisplayRect.bottom-DisplayRect.top); + + if(IsFullScreen() && CurrDevice->IsHardware()) + { + // Get the back surface from the front surface. + memset(&dd_scaps, 0, sizeof(dd_scaps)); + dd_scaps.dwCaps = DDSCAPS_BACKBUFFER; + result = lp_DD_FrontSurface->GetAttachedSurface(&dd_scaps,&lp_DD_BackSurface); + if(FAILED(result)) + { + DebugText("InitBack: no attached surface\n"); + return result; + } + } + else + { + // Create the back surface. + InitStruct(dd_sd); + dd_sd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH; + dd_sd.dwWidth = w; + dd_sd.dwHeight = h; + dd_sd.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN|DDSCAPS_3DDEVICE; + + if (!CurrDevice->IsHardware()) + { + dd_sd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + } + + result = lp_DD4->CreateSurface(&dd_sd,&lp_DD_BackSurface,NULL); + if(FAILED(result)) + { + DebugText("InitBack: unable to create back surface\n"); + return result; + } + } + + if(IsUse3D()) + { + // Create and attach Z-buffer (optional) + + // Get D3D Device description + if(CurrDevice->IsHardware()) + { + // Hardware device - Z buffer on video ram. + device_desc = &(CurrDevice->d3dHalDesc); + mem_type = DDSCAPS_VIDEOMEMORY; + } + else + { + // Software device - Z buffer in system ram. + device_desc = &(CurrDevice->d3dHelDesc); + mem_type = DDSCAPS_SYSTEMMEMORY; + } + + // Enumerate all Z formats associated with this D3D device + result = CurrDevice->LoadZFormats(lp_D3D); + if(FAILED(result)) + { + // Error, no texture formats + // Hope we can run OK without textures + DebugText("InitBack: unable to load Z formats\n"); + } + +#ifdef TARGET_DC + // No real Z buffer - don't bother +#else + // Can we create a Z buffer? + if(IsCreateZBuffer() && device_desc && device_desc->dwDeviceZBufferBitDepth) + { + // Create the z-buffer. + InitStruct(dd_sd); +#if 0 + dd_sd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_ZBUFFERBITDEPTH; + dd_sd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | mem_type; + dd_sd.dwWidth = w; + dd_sd.dwHeight = h; + dd_sd.dwZBufferBitDepth = FlagsToBitDepth(device_desc->dwDeviceZBufferBitDepth); +#else + dd_sd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + dd_sd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | mem_type; + dd_sd.dwWidth = w; + dd_sd.dwHeight = h; + memcpy(&dd_sd.ddpfPixelFormat, CurrDevice->GetZFormat(), sizeof(DDPIXELFORMAT)); +#endif + result = lp_DD4->CreateSurface(&dd_sd,&lp_DD_ZBuffer,NULL); + if(FAILED(result)) + { + DebugText("InitBack: unable to create ZBuffer\n"); + dd_error(result); + + // Note: we may be able to continue without a z buffer + // So don't exit + } + else + { + // Attach Z buffer to back surface. + result = lp_DD_BackSurface->AddAttachedSurface(lp_DD_ZBuffer); + if(FAILED(result)) + { + DebugText("InitBack: unable to attach ZBuffer 1\n"); + + if(lp_DD_ZBuffer) + { + lp_DD_ZBuffer->Release(); + lp_DD_ZBuffer = NULL; + } + + // Note: we may be able to continue without a z buffer + // So don't exit + } + } + } +#endif + + // Create the D3D device interface + result = lp_D3D->CreateDevice(CurrDevice->guid,lp_DD_BackSurface,&lp_D3D_Device,NULL); + if(FAILED(result)) + { + DebugText("InitBack: unable to create D3D device\n"); + d3d_error(result); + return result; + } + + // Enumerate all Texture formats associated with this D3D device + result = CurrDevice->LoadFormats(lp_D3D_Device); + if(FAILED(result)) + { + // Error, no texture formats + // Hope we can run OK without textures + DebugText("InitBack: unable to load texture formats\n"); + } + + // Create the viewport + result = InitViewport(); + if(FAILED(result)) + { + DebugText("InitBack: unable to init viewport\n"); + return result; + } + + // check the device caps + CurrDevice->CheckCaps(lp_D3D_Device); + + + } + +#ifndef TARGET_DC + if(IsUseWork()) + { + // Create a work screen for user access. + + // Get D3D Device description. We want a system ram surface regardless of the device type. + if(CurrDevice->IsHardware()) + { + // Hardware device - Z buffer on video ram. + device_desc = &(CurrDevice->d3dHalDesc); + } + else + { + // Software device - Z buffer in system ram. + device_desc = &(CurrDevice->d3dHelDesc); + } + + // Can we create the surface? + if(device_desc) + { + // Create the z-buffer. + InitStruct(dd_sd); + dd_sd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH; + dd_sd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY; + dd_sd.dwWidth = w; + dd_sd.dwHeight = h; + result = lp_DD4->CreateSurface(&dd_sd,&lp_DD_WorkSurface,NULL); + if(FAILED(result)) + { + DebugText("InitBack: unable to create work surface\n"); + dd_error(result); + return result; + } + WorkScreenPixelWidth = w; + WorkScreenWidth = w; + WorkScreenHeight = h; + } + + } +#endif + + // Mark as valid + TurnValidBackOn(); + + +#ifdef TARGET_DC + InitBackCache(); +#endif + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +#ifdef TARGET_DC + +static bool bBackCacheInit = FALSE; + +// Creates the background texture caches, which are only used in the frontend. +HRESULT Display::InitBackCache(void) +{ + if ( bBackCacheInit ) + { + // Already done. + return DD_OK; + } + + // Reset the cache. + CompressedBackground m_lpLastBackground = NULL; + + + ASSERT ( lpBackgroundCache == NULL ); + ASSERT ( the_display.lp_DD_Background_use_instead_texture == NULL ); + DDSURFACEDESC2 ddsd; + DDSURFACEDESC2 back; + HRESULT result; + InitStruct(back); + InitStruct(ddsd); + + lp_DD_BackSurface->GetSurfaceDesc(&back); + + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + ddsd.dwWidth = 1; + while ( ddsd.dwWidth < back.dwWidth ) + { + ddsd.dwWidth <<= 1; + } + ddsd.dwHeight = 1; + while ( ddsd.dwHeight < back.dwHeight ) + { + ddsd.dwHeight <<= 1; + } + ddsd.ddpfPixelFormat = back.ddpfPixelFormat; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps2 = 0; + + +#ifdef DEBUG + DDSCAPS2 ddsc; + ddsc.dwCaps = DDSCAPS_TEXTURE; + ddsc.dwCaps2 = 0; + ddsc.dwCaps3 = 0; + ddsc.dwCaps4 = 0; + DWORD dwFree, dwTotal; + HRESULT hres = the_display.lp_DD4->GetAvailableVidMem ( &ddsc, &dwTotal, &dwFree ); + TRACE ( "Memory before TEXTURE_free_unneeded: %ikb\n", dwFree / 1024 ); +#endif + + result = lp_DD4->CreateSurface(&ddsd, &lpBackgroundCache, NULL); + if (FAILED(result)) + { + ASSERT ( FALSE ); + lpBackgroundCache = NULL; + return DDERR_OUTOFMEMORY; + } + //VERIFY(SUCCEEDED(lpBackgroundCache->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lpBackgroundCacheTexture))); + VERIFY(SUCCEEDED(lpBackgroundCache->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&the_display.lp_DD_Background_use_instead_texture))); + + + // ...and another one. + ASSERT ( lpBackgroundCache2 == NULL ); + ASSERT ( the_display.lp_DD_Background_use_instead_texture2 == NULL ); + InitStruct(back); + InitStruct(ddsd); + + lp_DD_BackSurface->GetSurfaceDesc(&back); + + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + ddsd.dwWidth = 1; + while ( ddsd.dwWidth < back.dwWidth ) + { + ddsd.dwWidth <<= 1; + } + ddsd.dwHeight = 1; + while ( ddsd.dwHeight < back.dwHeight ) + { + ddsd.dwHeight <<= 1; + } + ddsd.ddpfPixelFormat = back.ddpfPixelFormat; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps2 = 0; + + +#ifdef DEBUG + ddsc.dwCaps = DDSCAPS_TEXTURE; + ddsc.dwCaps2 = 0; + ddsc.dwCaps3 = 0; + ddsc.dwCaps4 = 0; + dwFree, dwTotal; + hres = the_display.lp_DD4->GetAvailableVidMem ( &ddsc, &dwTotal, &dwFree ); + ASSERT ( SUCCEEDED ( hres ) ); + TRACE ( "After freeing: %ikb\n", dwFree / 1024 ); +#endif + + + result = lp_DD4->CreateSurface(&ddsd, &lpBackgroundCache2, NULL); +#ifdef DEBUG + if ( result == DDERR_OUTOFMEMORY ) + { + HRESULT hres = lp_DD4->EnumSurfaces ( DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL, NULL, NULL, &EnumSurfacesCallbackFunc ); + + ASSERT ( FALSE ); + } +#endif + if (FAILED(result)) + { + ASSERT ( FALSE ); + lpBackgroundCache2 = NULL; + return DDERR_OUTOFMEMORY; + } + //VERIFY(SUCCEEDED(lpBackgroundCache->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&lpBackgroundCacheTexture))); + VERIFY(SUCCEEDED(lpBackgroundCache2->QueryInterface(IID_IDirect3DTexture2,(LPVOID *)&the_display.lp_DD_Background_use_instead_texture2))); + + +#ifdef DEBUG + ddsc.dwCaps = DDSCAPS_TEXTURE; + ddsc.dwCaps2 = 0; + ddsc.dwCaps3 = 0; + ddsc.dwCaps4 = 0; + dwFree, dwTotal; + hres = the_display.lp_DD4->GetAvailableVidMem ( &ddsc, &dwTotal, &dwFree ); + ASSERT ( SUCCEEDED ( hres ) ); + TRACE ( "After freeing: %ikb\n", dwFree / 1024 ); +#endif + + + bBackCacheInit = TRUE; + + return ( DD_OK ); +} + + +// Bins the background textures, which are only used in the frontend. +HRESULT Display::FiniBackCache(void) +{ + if ( !bBackCacheInit ) + { + // Already done. + return DD_OK; + } + + // Remember to release the textures. + if ( the_display.lp_D3D_Device != NULL ) + { + the_display.lp_D3D_Device->SetTexture ( 0, NULL ); + the_display.lp_D3D_Device->SetTexture ( 1, NULL ); + the_display.lp_D3D_Device->SetTexture ( 2, NULL ); + the_display.lp_D3D_Device->SetTexture ( 3, NULL ); + } + + if ( the_display.lp_DD_Background_use_instead_texture != NULL ) + { + int res = the_display.lp_DD_Background_use_instead_texture->Release(); + ASSERT ( res == 1 ); + the_display.lp_DD_Background_use_instead_texture = NULL; + } + if ( lpBackgroundCache != NULL ) + { + int res = lpBackgroundCache->Release(); + ASSERT ( res == 0 ); + lpBackgroundCache = NULL; + } + if ( the_display.lp_DD_Background_use_instead_texture2 != NULL ) + { + int res = the_display.lp_DD_Background_use_instead_texture2->Release(); + ASSERT ( res == 1 ); + the_display.lp_DD_Background_use_instead_texture2 = NULL; + } + if ( lpBackgroundCache2 != NULL ) + { + int res = lpBackgroundCache2->Release(); + ASSERT ( res == 0 ); + lpBackgroundCache2 = NULL; + } + + bBackCacheInit = FALSE; + + return ( DD_OK ); +} +#endif + + + +HRESULT Display::FiniBack(void) +{ +#ifdef TARGET_DC + // Clean up the background texture. + FiniBackCache(); +#endif + + // Mark as invalid + TurnValidBackOff(); + +#ifndef TARGET_DC + // Clean up the work screen stuff. + if(IsUseWork()) + { + // Release the work surface. + if(lp_DD_WorkSurface) + { + lp_DD_WorkSurface->Release(); + lp_DD_WorkSurface = NULL; + } + } +#endif + + // Clean up the D3D stuff. + if(IsUse3D()) + { + // Cleanup viewport + FiniViewport(); + + // Release D3D Device + if(lp_D3D_Device) + { + lp_D3D_Device->Release(); + lp_D3D_Device = NULL; + } + + // Release Z Buffer + if(lp_DD_ZBuffer) + { + // Detach Z-Buffer from back buffer + if(lp_DD_BackSurface) + lp_DD_BackSurface->DeleteAttachedSurface(0L,lp_DD_ZBuffer); + + // Release Z-Buffer + lp_DD_ZBuffer->Release(); + lp_DD_ZBuffer = NULL; + } + } + + // Release back surface. + if(lp_DD_BackSurface) + { + lp_DD_BackSurface->Release(); + lp_DD_BackSurface = NULL; + } + + // Success + return DD_OK; +} + + +//--------------------------------------------------------------- + +HRESULT Display::InitClipper(void) +{ + HRESULT result; + + + // Check Initialization + if((!CurrMode) || (!lp_DD4)) + { + result = DDERR_GENERIC; + DebugText("InitClipper: invalid initialisation\n"); + return result; + } + +#ifndef TARGET_DC + + result = lp_DD4->CreateClipper(0,&lp_DD_Clipper,NULL); + if(FAILED(result)) + { + DebugText("InitClipper: unable to create clipper\n"); + dd_error(result); + DebugText("\n"); + return result; + } + + // Set clipper window handle. + result = lp_DD_Clipper->SetHWnd(0,hDDLibWindow); + if(FAILED(result)) + { + DebugText("InitClipper: unable to set window handle\n"); + dd_error(result); + DebugText("\n"); + return result; + } + + // Attach clipper to front surface. + result = lp_DD_FrontSurface->SetClipper(lp_DD_Clipper); + if(FAILED(result)) + { + DebugText("InitClipper: unable to attach clipper\n"); + dd_error(result); + DebugText("\n"); + return result; + } +#else + lp_DD_Clipper = 0; +#endif + + // Mark as Valid + TurnValidClipperOn(); + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::FiniClipper(void) +{ + // Mark as Invalid + TurnValidClipperOff(); + +#ifndef TARGET_DC + // Release Primary Surface Object + if(lp_DD_Clipper) + { + lp_DD_Clipper->Release(); + lp_DD_Clipper = NULL; + } +#endif + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::InitViewport(void) +{ + D3DMATERIAL material; + HRESULT result; + + // Check Initialization + if((!lp_D3D) || (!lp_D3D_Device)) + { + // Error, Not properly initialized before calling this method + result = DDERR_GENERIC; + // Output error. + return result; + } + + // Create Viewport + result = lp_D3D->CreateViewport(&lp_D3D_Viewport,NULL); + if(FAILED(result)) + { + // Output error. + return result; + } + + // Attach viewport to D3D device + result = lp_D3D_Device->AddViewport(lp_D3D_Viewport); + if(FAILED(result)) + { + lp_D3D_Viewport->Release(); + lp_D3D_Viewport = NULL; + + // Output error. + return result; + } + + // Black material. + result = lp_D3D->CreateMaterial(&lp_D3D_Black,NULL); + if(FAILED(result)) + { + DebugText("InitViewport: Error creating black material\n"); + return result; + } + + InitStruct(material); + material.diffuse.r = D3DVAL(0.0); + material.diffuse.g = D3DVAL(0.0); + material.diffuse.b = D3DVAL(0.0); + material.diffuse.a = D3DVAL(1.0); + material.ambient.r = D3DVAL(0.0); + material.ambient.g = D3DVAL(0.0); + material.ambient.b = D3DVAL(0.0); + material.dwRampSize = 0; + + result = lp_D3D_Black->SetMaterial(&material); + if(FAILED(result)) + { + DebugText("InitViewport: Error setting black material\n"); + lp_D3D_Black->Release(); + lp_D3D_Black = NULL; + return result; + } + result = lp_D3D_Black->GetHandle(lp_D3D_Device,&black_handle); + if(FAILED(result)) + { + DebugText("InitViewport: Error getting black handle\n"); + lp_D3D_Black->Release(); + lp_D3D_Black = NULL; + return result; + } + + // White material. + result = lp_D3D->CreateMaterial(&lp_D3D_White,NULL); + if(FAILED(result)) + { + DebugText("InitViewport: Error creating white material\n"); + return result; + } + material.diffuse.r = D3DVAL(1.0); + material.diffuse.g = D3DVAL(1.0); + material.diffuse.b = D3DVAL(1.0); + material.diffuse.a = D3DVAL(1.0); + material.ambient.r = D3DVAL(1.0); + material.ambient.g = D3DVAL(1.0); + material.ambient.b = D3DVAL(1.0); + material.dwRampSize = 0; + + result = lp_D3D_White->SetMaterial(&material); + if(FAILED(result)) + { + DebugText("InitViewport: Error setting white material\n"); + lp_D3D_White->Release(); + lp_D3D_White = NULL; + return result; + } + result = lp_D3D_White->GetHandle(lp_D3D_Device,&white_handle); + if(FAILED(result)) + { + DebugText("InitViewport: Error getting white handle\n"); + lp_D3D_White->Release(); + lp_D3D_White = NULL; + return result; + } + + // + // User material. + // + + SetUserColour(255, 150, 255); + + // Set up Initial Viewport parameters + result = UpdateViewport(); + if(FAILED(result)) + { + lp_D3D_Device->DeleteViewport(lp_D3D_Viewport); + lp_D3D_Viewport->Release(); + lp_D3D_Viewport = NULL; + + return result; + } + + // Mark as valid + TurnValidViewportOn(); + + /// Success + return DD_OK; +} + + +//--------------------------------------------------------------- + +#ifndef TARGET_DC + +void Display::SetUserColour(UBYTE red, UBYTE green, UBYTE blue) +{ + D3DMATERIAL material; + HRESULT result; + + float r = (1.0F / 255.0F) * float(red); + float g = (1.0F / 255.0F) * float(green); + float b = (1.0F / 255.0F) * float(blue); + + if (lp_D3D_User) + { + lp_D3D_User->Release(); + lp_D3D_User = NULL; + user_handle = NULL; + } + + result = lp_D3D->CreateMaterial(&lp_D3D_User,NULL); + + ASSERT(!FAILED(result)); + + InitStruct(material); + material.diffuse.r = D3DVAL(r); + material.diffuse.g = D3DVAL(g); + material.diffuse.b = D3DVAL(b); + material.diffuse.a = D3DVAL(1.0); + material.ambient.r = D3DVAL(r); + material.ambient.g = D3DVAL(g); + material.ambient.b = D3DVAL(b); + material.dwRampSize = 0; + + result = lp_D3D_User->SetMaterial(&material); + + ASSERT(!FAILED(result)); + + result = lp_D3D_User->GetHandle(lp_D3D_Device,&user_handle); + + ASSERT(!FAILED(result)); +} + +#endif //#ifndef TARGET_DC + + +//--------------------------------------------------------------- + +HRESULT Display::FiniViewport(void) +{ + // Mark as invalid + TurnValidViewportOff(); + + // Get rid of any loaded texture maps. + FreeLoadedTextures(); + + // Release materials. + if(lp_D3D_Black) + { + lp_D3D_Black->Release(); + lp_D3D_Black = NULL; + black_handle = NULL; + } + + if(lp_D3D_White) + { + lp_D3D_White->Release(); + lp_D3D_White = NULL; + white_handle = NULL; + } + + if (lp_D3D_User) + { + lp_D3D_User->Release(); + lp_D3D_User = NULL; + user_handle = NULL; + } + + // Release D3D viewport + if(lp_D3D_Viewport) + { + lp_D3D_Device->DeleteViewport(lp_D3D_Viewport); + lp_D3D_Viewport->Release(); + lp_D3D_Viewport = NULL; + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::UpdateViewport(void) +{ + SLONG s_w,s_h; + HRESULT result; + D3DVIEWPORT2 d3d_viewport; + + + // Check Parameters + if((!lp_D3D_Device) || (!lp_D3D_Viewport)) + { + // Not properly initialized before calling this method + result = DDERR_GENERIC; + // Output error. + return result; + } + + // Get Surface Width and Height + s_w = abs(DisplayRect.right - DisplayRect.left); + s_h = abs(DisplayRect.bottom - DisplayRect.top); + + // Update Viewport + InitStruct(d3d_viewport); + d3d_viewport.dwX = 0; + d3d_viewport.dwY = 0; + d3d_viewport.dwWidth = s_w; + d3d_viewport.dwHeight = s_h; + d3d_viewport.dvClipX = 0.0f; + d3d_viewport.dvClipY = 0.0f; + d3d_viewport.dvClipWidth = (float)s_w; + d3d_viewport.dvClipHeight = (float)s_h; + d3d_viewport.dvMinZ = 1.0f; + d3d_viewport.dvMaxZ = 0.0f; + + // Update Viewport + result = lp_D3D_Viewport->SetViewport2(&d3d_viewport); + if(FAILED(result)) + { + // Output error. + return result; + } + + // Update D3D device to use this viewport + result = lp_D3D_Device->SetCurrentViewport(lp_D3D_Viewport); + if(FAILED(result)) + { + // Output error. + return result; + } + + // Reload any pre-loaded textures. + ReloadTextures(); + + // Set the view port rect. + ViewportRect.x1 = 0; + ViewportRect.y1 = 0; + ViewportRect.x2 = s_w; + ViewportRect.y2 = s_h; + + // Set the background colour. + switch(the_display.BackColour) + { + case BK_COL_NONE: + break; + case BK_COL_BLACK: return the_display.SetBlackBackground(); + case BK_COL_WHITE: return the_display.SetWhiteBackground(); + case BK_COL_USER: return the_display.SetUserBackground(); + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::ChangeDriver ( + GUID *DD_guid, + D3DDeviceInfo *device_hint, + DDModeInfo *mode_hint + ) +{ + SLONG w,h,bpp,refresh; + D3DDeviceInfo *new_device, + *old_device; + DDDriverInfo *new_driver, + *old_driver; + DDModeInfo *new_mode, + *old_mode; + GUID *D3D_guid; + HRESULT result; + + DebugText("\nInto change driver\n"); + + // Get New Driver + new_driver = ValidateDriver(DD_guid); + if(!new_driver) + { + // Error, invalid DD Guid + result = DDERR_GENERIC; + DebugText("ChangeDriver: invalid DD GUID\n"); + return result; + } + + // Get requested D3D device + if(device_hint) + D3D_guid = &(device_hint->guid); + else if(CurrDevice) + D3D_guid = &(CurrDevice->guid); + else + D3D_guid = NULL; + + // Get requested mode + if(mode_hint) + mode_hint->GetMode(&w,&h,&bpp,&refresh); + else + { + // Default to 640 x 480 x 16 + w = DEFAULT_WIDTH; + h = DEFAULT_HEIGHT; + bpp = DEFAULT_DEPTH; + refresh = 0; + } + + // Get new device and mode compatible with this driver + if(!GetFullscreenMode(new_driver,D3D_guid,w,h,bpp,refresh,&new_mode,&new_device)) + { + result = DDERR_GENERIC; + DebugText("ChangeDriver: unable to find a valid D3D device & mode for this driver"); + return result; + } + + // Save old defaults + old_driver = CurrDriver; + old_mode = CurrMode; + old_device = CurrDevice; + + // Destroy almost everything + DebugText("Into Fini\n"); + Fini (); + DebugText("Out of Fini\n"); + + // Set new defaults + CurrDriver = new_driver; + CurrMode = new_mode; + CurrDevice = new_device; + + // Re-create almost everything based on new driver, device, and mode + DebugText("Into Init\n"); + result = Init(); + DebugText("Out of Init\n"); + if(FAILED(result)) + { + // Try to restore old defaults + Fini (); + + CurrDriver = old_driver; + CurrMode = old_mode; + CurrDevice = old_device; + + Init (); + return result; + } + +// // Notify the window of a successful change in Driver +// SendMessage(hWindow, D3DWIN_CHANGED_DRIVER, 0, 0); + + // Notify a display change. + DisplayChangedOn(); + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::ChangeDevice ( + GUID *D3D_guid, + DDModeInfo *mode_hint + ) +{ + SLONG w,h,bpp,refresh; + D3DDeviceInfo *new_device, + *old_device; + DDDriverInfo *old_driver; + DDModeInfo *new_mode, + *old_mode, + *next_best_mode; + HRESULT result; + + // Check Parameters + if(!D3D_guid) + { + result = DDERR_GENERIC; + DebugText("Changedevice: invalid parameters\n"); + return result; + } + + // Check Initialization + if(!IsValid() || (!lp_DD_BackSurface)) + { + result = DDERR_GENERIC; + DebugText("Changedevice: invalid initialization\n"); + return result; + } + + // Save Original State + old_driver = CurrDriver; + old_mode = CurrMode; + old_device = CurrDevice; + + // Verify new D3D device belongs to current DD driver + new_device = old_driver->FindDevice(D3D_guid, NULL); + if(!new_device) + { + result = DDERR_GENERIC; + // Output error. + return result; + } + + // + // Step 1. Verify new D3D device is supported with current mode + // + if(mode_hint) + new_mode = mode_hint; + else + new_mode = old_mode; + if(!new_mode->ModeSupported(new_device)) + { + // We are a full screen app, so we can do what we want + // Pick a new mode that is compatible with this device + new_mode->GetMode(&w,&h,&bpp,&refresh); + + new_mode = old_driver->FindModeSupportsDevice(w,h,bpp,0,new_device,&next_best_mode); + if(!new_mode) + { + if(!next_best_mode) + { + // Error , no compatible mode found!!! + result = DDERR_GENERIC; + // Output error. + return result; + } + new_mode = next_best_mode; + } + } + if(new_mode==old_mode) + new_mode = NULL; + + + // + // Step 2. Destroy Old D3D Device (and mode) + // + FiniBack(); + if(new_mode) + { + FiniFront(); + } + VB_Term(); + + // + // Step 3. Create new D3D Device (new mode optional) + // + + // Set new D3D device (and mode) + if(new_mode) + CurrMode = new_mode; + CurrDevice = new_device; + + // Create new mode, if necessary + if(new_mode) + { + // Change Mode + result = InitFullscreenMode(); + if(FAILED(result)) + { + // Try to restore original mode and device + CurrDevice = old_device; + CurrMode = old_mode; + + InitFullscreenMode(); + InitFront(); + InitBack(); + VB_Init(); + TheVPool->Create(lp_D3D, !CurrDevice->IsHardware()); + + return result; + } + + // Create Primary + result = InitFront(); + if(FAILED(result)) + { + // Try to restore original mode and device + CurrDevice = old_device; + CurrMode = old_mode; + + InitFullscreenMode(); + InitFront(); + InitBack(); + VB_Init(); + TheVPool->Create(lp_D3D, !CurrDevice->IsHardware()); + + return result; + } + } + + // Create new D3D Device + result = InitBack(); + if(FAILED(result)) + { + // Try to restore original mode and device + if(new_mode) + CurrMode = old_mode; + CurrDevice = old_device; + + if(new_mode) + { + FiniFront(); + InitFullscreenMode(); + InitFront(); + VB_Init(); + TheVPool->Create(lp_D3D, !CurrDevice->IsHardware()); + } + + result = InitBack(); + if(FAILED(result)) + { + // Return Error + // Output result. + return result; + } + } + + VB_Init(); + TheVPool->Create(lp_D3D, !CurrDevice->IsHardware()); + + // Notify a display change. + DisplayChangedOn(); + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::ChangeMode ( + SLONG w, + SLONG h, + SLONG bpp, + SLONG refresh + ) +{ + HRESULT result; + DDDriverInfo *old_driver; + DDModeInfo *new_mode, + *old_mode; + D3DDeviceInfo *new_device, + *next_best_device, + *old_device; + + + // Check Initialization + if((!hDDLibWindow) || (!IsWindow(hDDLibWindow))) + { + result = DDERR_GENERIC; + DebugText("ChangeMode: main window not initialised\n"); + return result; + } + + if(!IsInitialised()) + { + result = GenerateDefaults(); + if(FAILED(result)) + { + result = DDERR_GENERIC; + // Output error. + return result; + } + + result = Init(); + if(FAILED(result)) + { + result = DDERR_GENERIC; + // Output error. + return result; + } + + + } + + old_driver = CurrDriver; + old_mode = CurrMode; + old_device = CurrDevice; + + + // + // Step 1. Get New Mode + // + // Find new mode corresponding to w, h, bpp + new_mode = old_driver->FindMode(w, h, bpp, 0, NULL); + if(!new_mode) + { + result = DDERR_GENERIC; + DebugText("ChangeMode: mode not available with this driver\n"); + return result; + } + + // + // Step 2. Check if Device needs to be changed as well + // + if(new_mode->ModeSupported(old_device)) + { + new_device = NULL; + } + else + { + new_device = old_driver->FindDeviceSupportsMode(&old_device->guid,new_mode,&next_best_device); + if(!new_device) + { + if(!next_best_device) + { + // No D3D device is compatible with this new mode + result = DDERR_GENERIC; + DebugText("ChangeMode: No device is compatible with this mode\n"); + return result; + } + new_device = next_best_device; + } + } + + // + // Step 3. Destroy current Mode + // + FiniBack(); + FiniFront(); +// FiniFullscreenMode (); // Don't do this => unnecessary mode switch + + // + // Step 4. Create new mode + // + CurrMode = new_mode; + if(new_device) + CurrDevice = new_device; + + // Change Mode + result = InitFullscreenMode(); + if(FAILED(result)) + return result; + + // Create Primary Surface + result = InitFront(); + if(FAILED(result)) + { + DebugText("ChangeMode: Error in InitFront\n"); + + // Try to restore old mode + CurrMode = old_mode; + CurrDevice = old_device; + + InitFullscreenMode(); + InitFront(); + InitBack(); + + return result; + } + + // Create Render surface + result = InitBack(); + if(FAILED(result)) + { + DebugText("ChangeMode: Error in InitBack\n"); + + FiniFront(); + // FiniFullscreenMode (); // Unnecessary mode switch + + // Try to restore old mode + CurrMode = old_mode; + CurrDevice = old_device; + + InitFullscreenMode(); + InitFront(); + InitBack(); + + return result; + } + + // + // Reload the background image. + // + + if (background_image_mem) + { + create_background_surface(background_image_mem); + } + + // Notify a display change. + DisplayChangedOn(); + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::Restore(void) +{ + HRESULT result; + + + // Check Initialization + if(!IsValid()) + { + result = DDERR_GENERIC; + DebugText("Restore: invalid initialisation\n"); + return result; + } + + // Restore Primary Surface + if(lp_DD_FrontSurface) + { + result = lp_DD_FrontSurface->IsLost(); + if (FAILED(result)) + { + result = lp_DD_FrontSurface->Restore(); + if(FAILED(result)) + return result; + } + } + + // Restore Z Buffer + if(lp_DD_ZBuffer) + { + result = lp_DD_ZBuffer->IsLost(); + if (FAILED(result)) + { + result = lp_DD_ZBuffer->Restore(); + if(FAILED(result)) + return result; + } + } + + // Restore Rendering surface + if(lp_DD_BackSurface) + { + result = lp_DD_BackSurface->IsLost(); + if (FAILED(result)) + { + result = lp_DD_BackSurface->Restore(); + if(FAILED(result)) + return result; + } + } + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::AddLoadedTexture(D3DTexture *the_texture) +{ +#ifdef DEBUG + // Check that this isn't a circular list and that this texture isn't already loaded. + D3DTexture *t = TextureList; + int iCountdown = 10000; + while ( t != NULL ) + { + ASSERT ( t != the_texture ); + t = t->NextTexture; + iCountdown--; + ASSERT ( iCountdown > 0 ); + } + +#endif + + the_texture->NextTexture = TextureList; + TextureList = the_texture; + + + return DD_OK; +} + +//--------------------------------------------------------------- + +void Display::RemoveAllLoadedTextures(void) +{ + TextureList = NULL; +} + + +//--------------------------------------------------------------- + +HRESULT Display::FreeLoadedTextures(void) +{ + D3DTexture *current_texture; + + + int iCountdown = 10000; + + current_texture = TextureList; + while(current_texture) + { + D3DTexture *next_texture = current_texture->NextTexture; + current_texture->Destroy(); + current_texture = next_texture; + iCountdown--; + if ( iCountdown == 0 ) + { + // Oh dear - not good. + ASSERT ( FALSE ); + break; + } + } + + return DD_OK; +} + +//--------------------------------------------------------------- + +static char clumpfile[MAX_PATH] = ""; +static size_t clumpsize = 0; + +void SetLastClumpfile(char* file, size_t size) +{ + strcpy(clumpfile, file); + clumpsize = size; +} + +HRESULT Display::ReloadTextures(void) +{ + D3DTexture *current_texture; + +#ifdef TARGET_DC + ASSERT ( clumpfile[0] == '\0' ); +#else + if (clumpfile[0]) + { + OpenTGAClump(clumpfile, clumpsize, true); + } +#endif + + current_texture = TextureList; + while(current_texture) + { + D3DTexture *next_texture = current_texture->NextTexture; + current_texture->Reload(); + current_texture = next_texture; + } + +#ifdef TARGET_DC + ASSERT ( clumpfile[0] == '\0' ); +#else + if (clumpfile[0]) + { + CloseTGAClump(); + } +#endif + + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::toGDI(void) +{ + HRESULT result; + +/* + // Restore system palette. + if(lpddpPalette) + { + // Save the current palette + hResult = lpddpPalette->GetEntries (0, 0, cPalette, lppeCurr); + if (FAILED (hResult)) + { + REPORTERR (hResult); + return hResult; + } + + // Restore the system palette into our device + hResult = lpddpPalette->SetEntries (0, 0, cPalette, lppeSystem); + if (FAILED (hResult)) + { + REPORTERR (hResult); + return hResult; + } + } +*/ + + // Flip to GDI Surface + if(lp_DD4) + { + result = lp_DD4->FlipToGDISurface(); + if(FAILED(result)) + { + // Output error. + return result; + } + } + +#ifndef TARGET_DC + // Force window to redraw itself (on GDI surface). + if((hDDLibWindow) && (IsWindow(hDDLibWindow))) + { + DrawMenuBar(hDDLibWindow); + RedrawWindow(hDDLibWindow, NULL, NULL, RDW_FRAME); + } +#endif + + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +HRESULT Display::fromGDI(void) +{ +// HRESULT result; + +/* + // Restore current palette + if (lpddpPalette) + { + hResult = lpddpPalette->SetEntries (0, 0, cPalette, lppeCurr); + if (FAILED (hResult)) + return hResult; + } +*/ + // Success + return DD_OK; +} + +//--------------------------------------------------------------- + +void Display::MenuOn(void) +{ +#ifndef TARGET_DC + if(IsFullScreen()) + { + // Set the window style + SetMenu(hDDLibWindow,hDDLibMenu); + SetWindowLong(hDDLibWindow,GWL_STYLE,hDDLibStyle); + SetWindowLong(hDDLibWindow,GWL_EXSTYLE,hDDLibStyleEx); + } +#endif +} + +//--------------------------------------------------------------- + +void Display::MenuOff(void) +{ +#ifndef TARGET_DC + if(IsFullScreen()) + { + SetWindowLong(hDDLibWindow,GWL_STYLE,0); + SetWindowLong(hDDLibWindow,GWL_EXSTYLE,0); + SetMenu(hDDLibWindow,NULL); + } +#endif +} + +//--------------------------------------------------------------- + +#ifndef TARGET_DC +HRESULT Display::ShowWorkScreen(void) +{ + return lp_DD_FrontSurface->Blt(&DisplayRect,lp_DD_WorkSurface,NULL,DDBLT_WAIT,NULL); +} +#endif + +//--------------------------------------------------------------- +void *Display::screen_lock(void) +{ + if (DisplayFlags & DISPLAY_LOCKED) + { + // + // Don't do anything if you try to lock the screen twice in a row. + // + + TRACE("Locking the screen when it is already locked!\n"); + } + else + { + DDSURFACEDESC2 ddsdesc; + HRESULT ret; + + InitStruct(ddsdesc); + + ret = lp_DD_BackSurface->Lock(NULL, &ddsdesc, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL); + + if (SUCCEEDED(ret)) + { + screen_width = ddsdesc.dwWidth; + screen_height = ddsdesc.dwHeight; + screen_pitch = ddsdesc.lPitch; + screen_bbp = ddsdesc.ddpfPixelFormat.dwRGBBitCount; + screen = (UBYTE *) ddsdesc.lpSurface; + + DisplayFlags |= DISPLAY_LOCKED; + } + else + { + d3d_error(ret); + + screen = NULL; + } + } + + return screen; +} + +void Display::screen_unlock(void) +{ + if (DisplayFlags & DISPLAY_LOCKED) + { + lp_DD_BackSurface->Unlock(NULL); + } + + screen = NULL; + DisplayFlags &= ~DISPLAY_LOCKED; +} + + + +void Display::PlotPixel(SLONG x, SLONG y, UBYTE red, UBYTE green, UBYTE blue) +{ + if (DisplayFlags & DISPLAY_LOCKED) + { + if (WITHIN(x, 0, screen_width - 1) && + WITHIN(y, 0, screen_height - 1)) + { + if (CurrMode->GetBPP() == 16) + { + UWORD *dest; + + UWORD pixel = GetFormattedPixel(red, green, blue); + SLONG index = x + x + y * screen_pitch; + + dest = (UWORD *) (&(screen[index])); + dest[0] = pixel; + } + else + { + ULONG* dest; + ULONG pixel = GetFormattedPixel(red, green, blue); + SLONG index = x*4 + y * screen_pitch; + + dest = (ULONG*)(screen + index); + dest[0] = pixel; + } + } + } + else + { + // + // Do nothing if the screen is not locked. + // + + TRACE("PlotPixel while screen is not locked.\n"); + } +} + +void Display::PlotFormattedPixel(SLONG x, SLONG y, ULONG colour) +{ + if (DisplayFlags & DISPLAY_LOCKED) + { + if (WITHIN(x, 0, screen_width - 1) && + WITHIN(y, 0, screen_height - 1)) + { + if (CurrMode->GetBPP() == 16) + { + UWORD *dest; + SLONG index = x + x + y * screen_pitch; + + dest = (UWORD *) (&(screen[index])); + dest[0] = colour; + } + else + { + ULONG* dest; + SLONG index = x*4 + y*screen_pitch; + dest = (ULONG*)(screen + index); + dest[0] = colour; + } + } + } + else + { + // + // Do nothing if the screen is not locked. + // + + TRACE("PlotFormattedPixel while screen is not locked.\n"); + } +} + +void Display::GetPixel(SLONG x, SLONG y, UBYTE *red, UBYTE *green, UBYTE *blue) +{ + SLONG index; + + ULONG colour; + + *red = 0; + *green = 0; + *blue = 0; + + if (DisplayFlags & DISPLAY_LOCKED) + { + if (WITHIN(x, 0, screen_width - 1) && + WITHIN(y, 0, screen_height - 1)) + { + if (CurrMode->GetBPP() == 16) + { + UWORD *dest; + SLONG index = x + x + y * screen_pitch; + + dest = (UWORD *) (&(screen[index])); + colour = dest[0]; + } + else + { + ULONG *dest; + SLONG index = 4*x + y*screen_pitch; + dest = (ULONG*)(screen + index); + colour = dest[0]; + + } + + *red = ((colour >> shift_red) << mask_red) & 0xff; + *green = ((colour >> shift_green) << mask_green) & 0xff; + *blue = ((colour >> shift_blue) << mask_blue) & 0xff; + } + } +} + + + +void Display::blit_back_buffer() +{ + POINT clientpos; + RECT dest; + + HRESULT res; + + if (the_display.IsFullScreen()) + { + res = lp_DD_FrontSurface->Blt(NULL,lp_DD_BackSurface,NULL,DDBLT_WAIT,0); + } + else + { + clientpos.x = 0; + clientpos.y = 0; + + ClientToScreen( + hDDLibWindow, + &clientpos); + + GetClientRect( + hDDLibWindow, + &dest); + + dest.top += clientpos.y; + dest.left += clientpos.x; + dest.right += clientpos.x; + dest.bottom += clientpos.y; + + res = lp_DD_FrontSurface->Blt(&dest,lp_DD_BackSurface,NULL,DDBLT_WAIT,0); + } + + if (FAILED(res)) + { + dd_error(res); + } +} + + +// create a background surface from a 640x480x24 image + +void CopyBackground16(UBYTE* image_data, IDirectDrawSurface4* surface) +{ + DDSURFACEDESC2 mine; + HRESULT res; + + InitStruct(mine); + res = surface->Lock(NULL, &mine, DDLOCK_WAIT, NULL); + if (FAILED(res)) return; + + SLONG pitch = mine.lPitch >> 1; + UWORD *mem = (UWORD *) mine.lpSurface; + SLONG width; + SLONG height; + + // stretch the image + + SLONG sdx = 65536 * 640 / mine.dwWidth; + SLONG sdy = 65536 * 480 / mine.dwHeight; + + SLONG lsy = -1; + SLONG sy = 0; + UWORD* lmem = NULL; + + for (height = 0; (unsigned)height < mine.dwHeight; height++) + { + UBYTE* src = image_data + 640 * 3 * (sy >> 16); + + if ((sy >> 16) == lsy) + { + // repeat line + memcpy(mem, lmem, mine.dwWidth * 2); + } + else + { + SLONG sx = 0; + + for (width = 0; (unsigned)width < mine.dwWidth; width++) + { + UBYTE* pp = src + 3 * (sx >> 16); + + mem[width] = the_display.GetFormattedPixel(pp[2], pp[1], pp[0]); + + sx += sdx; + } + } + + lmem = mem; + lsy = sy >> 16; + + mem += pitch; + sy += sdy; + } + + surface->Unlock(NULL); +} + + + +void CopyBackground32(UBYTE* image_data, IDirectDrawSurface4* surface) +{ + DDSURFACEDESC2 mine; + HRESULT res; + + InitStruct(mine); + res = surface->Lock(NULL, &mine, DDLOCK_WAIT, NULL); + if (FAILED(res)) return; + + SLONG pitch = mine.lPitch >> 2; + ULONG *mem = (ULONG *)mine.lpSurface; + SLONG width; + SLONG height; + + // stretch the image + + SLONG sdx = 65536 * 640 / mine.dwWidth; + SLONG sdy = 65536 * 480 / mine.dwHeight; + + SLONG lsy = -1; + SLONG sy = 0; + ULONG* lmem = NULL; + + for (height = 0; (unsigned)height < mine.dwHeight; height++) + { + UBYTE* src = image_data + 640 * 3 * (sy >> 16); + + if ((sy >> 16) == lsy) + { + // repeat line + memcpy(mem, lmem, mine.dwWidth * 4); + } + else + { + SLONG sx = 0; + + for (width = 0; (unsigned)width < mine.dwWidth; width++) + { + UBYTE* pp = src + 3 * (sx >> 16); + + mem[width] = the_display.GetFormattedPixel(pp[2], pp[1], pp[0]); + + sx += sdx; + } + } + + lmem = mem; + lsy = sy >> 16; + + mem += pitch; + sy += sdy; + } + + surface->Unlock(NULL); +} + + + + +#ifdef TARGET_DC +// This uses my funky pixel format. +// This only works to a 640x480,565 format image. +// Unpacks image_data into surface +#define UNPACKING_DEBUG_INFO 0 +void UnpackBackground ( UBYTE* image_data, IDirectDrawSurface4* surface ) +{ + DDSURFACEDESC2 mine; + HRESULT res; + + InitStruct(mine); + mine.dwFlags = DDSD_PITCH; + res = surface->Lock(NULL, &mine, DDLOCK_WAIT, NULL); + if (FAILED(res)) return; + + SLONG pitch = mine.lPitch >> 1; + WORD *mem = (WORD *)mine.lpSurface; + SLONG width; + SLONG height; + + // The two line buffers. + WORD wLine[2][640]; + int iCurLineBuffer = 0; + int iPrevLineBuffer = 1; + + // Fill both lines with zeroes. + + for ( int iY = 0; iY < 480; iY++ ) + { + // Fill one line buffer. + for ( int iX = 0; iX < 640; iX++ ) + { + UBYTE bData = *image_data++; + +#if UNPACKING_DEBUG_INFO + if ( bData & 0x80 ) + { + image_data++; + + // White = raw data. + wLine[iCurLineBuffer][iX] = 0xffff; + } + else + { + if ( bData & 0x40 ) + { + // Red = horizontal lerp. + wLine[iCurLineBuffer][iX] = 0xf800; + } + else + { + // Green = vertical lerp. + wLine[iCurLineBuffer][iX] = 0x07e0; + } + } + +#else //#if UNPACKING_DEBUG_INFO + if ( bData & 0x80 ) + { + // Top bit set - this and the next byte are raw 555 pixel data. + WORD wPixel = ( bData << 8 ) | ( *image_data++ ); + // And convert to 565, not 555. + wLine[iCurLineBuffer][iX] = ( ( wPixel & 0x7fe0 ) << 1 ) | ( wPixel &0x1f ); + } + else + { + // Top bit clear. + // Format is now: + // 0 d rr gg bb + WORD wPixel; + if ( bData & 0x40 ) + { + // d bit is set - use pixel above. + if ( iY > 0 ) + { + wPixel = wLine[iPrevLineBuffer][iX]; + } + else + { + // This is valid. + wPixel = 0; + } + } + else + { + // d bit is clear - use pixel to left. + if ( iX > 0 ) + { + wPixel = wLine[iCurLineBuffer][iX-1]; + } + else + { + // This is valid. + wPixel = 0; + } + } + // Now modify by the two-bit-fields for each colour. + + + WORD wMask; + WORD wBottomBit; + WORD wComponent; + + // Red. + wMask = 0xf800; + wBottomBit = 0x0800; + switch ( ( bData & 0x30 ) >> 4 ) + { + case 0: + // No change. + break; + case 1: + // Plus 1 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 2: + // Plus 2 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 3: + // Minus 2 (with wraparound) + wComponent = ( wPixel & wMask ) - wBottomBit - wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + } + + // Green. + wMask = 0x07e0; + wBottomBit = 0x0020; + switch ( ( bData & 0x0c ) >> 2 ) + { + case 0: + // No change. + break; + case 1: + // Plus 1 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 2: + // Plus 2 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 3: + // Minus 2 (with wraparound) + wComponent = ( wPixel & wMask ) - wBottomBit - wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + } + + // Blue. + wMask = 0x001f; + wBottomBit = 0x0001; + switch ( ( bData & 0x03 ) >> 0 ) + { + case 0: + // No change. + break; + case 1: + // Plus 1 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 2: + // Plus 2 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 3: + // Minus 2 (with wraparound) + wComponent = ( wPixel & wMask ) - wBottomBit - wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + } + + wLine[iCurLineBuffer][iX] = wPixel; + + } +#endif //#else //#if UNPACKING_DEBUG_INFO + + + } + // Dump that line into the surface. +#if 0 + memcpy ( mem, wLine[iCurLineBuffer], 640 * 2 ); +#else + for ( iX = 0; iX < 640; iX++ ) + { + mem[iX] = wLine[iCurLineBuffer][iX]; + } +#endif + mem += pitch; + + iPrevLineBuffer = iCurLineBuffer; + iCurLineBuffer = 1 - iCurLineBuffer; + } + + surface->Unlock(NULL); +} + +#endif //#ifdef TARGET_DC + + +// This uses my funky pixel format. +// This only works to a 640x480,565 format image. +// Packs surface (640x480,565 pixels - raw data) into image_data. +// Returns the size of the packed version. You can pass in NULL for image_data, +// and it will just return the size, and not try to copy anything. +int PackBackground ( UBYTE* image_data, WORD *surface ) +{ + // The two line buffers. + WORD wLine[2][640]; + int iCurLineBuffer = 0; + int iPrevLineBuffer = 1; + + int iTotalSize = 0; + + for ( int iY = 0; iY < 480; iY++ ) + { + for ( int iX = 0; iX < 640; iX++ ) + { + + WORD wPixel = surface[iX + 640 * iY]; + + WORD wNeighbourPixel[2]; + // Find left pixel. + if ( iX > 0 ) + { + wNeighbourPixel[0] = wLine[iCurLineBuffer][iX - 1]; + } + else + { + wNeighbourPixel[0] = 0; + } + + // Find above pixel. + if ( iY > 0 ) + { + wNeighbourPixel[1] = wLine[iPrevLineBuffer][iX]; + } + else + { + wNeighbourPixel[1] = 0; + } + + + // Now try both to see if they will work. + BYTE bData; + for ( int iNeighbour = 0; iNeighbour < 2; iNeighbour++ ) + { + bData = iNeighbour << 6; + + WORD wMask; + WORD wShift; + WORD wPrev; + WORD wCur; + + // Try the red channel. + wMask = 0xf800; + wShift = 11; + wPrev = ( wNeighbourPixel[iNeighbour] & wMask ) >> wShift; + wCur = ( wPixel & wMask ) >> wShift; + switch ( wCur - wPrev ) + { + case 0: + case -1: + // Cool. (the -1 is a fudge, but only loses a tiny bit of accuracy). + bData |= ( 0 << 4 ); + break; + case 1: + // Yep. + bData |= ( 1 << 4 ); + break; + case 2: + // Yep. + bData |= ( 2 << 4 ); + break; + case -2: + // Yep. + bData |= ( 3 << 4 ); + break; + default: + // No - out of range - try the next neighbour. + continue; + } + + // Try the green channel. + wMask = 0x07e0; + wShift = 5; + wPrev = ( wNeighbourPixel[iNeighbour] & wMask ) >> wShift; + wCur = ( wPixel & wMask ) >> wShift; + switch ( wCur - wPrev ) + { + case 0: + case -1: + // Cool. (the -1 is a fudge, but only loses a tiny bit of accuracy). + bData |= ( 0 << 2 ); + break; + case 1: + // Yep. + bData |= ( 1 << 2 ); + break; + case 2: + // Yep. + bData |= ( 2 << 2 ); + break; + case -2: + // Yep. + bData |= ( 3 << 2 ); + break; + default: + // No - out of range - try the next neighbour. + continue; + } + + // Try the blue channel. + wMask = 0x001f; + wShift = 0; + wPrev = ( wNeighbourPixel[iNeighbour] & wMask ) >> wShift; + wCur = ( wPixel & wMask ) >> wShift; + switch ( wCur - wPrev ) + { + case 0: + case -1: + // Cool. (the -1 is a fudge, but only loses a tiny bit of accuracy). + bData |= ( 0 << 0 ); + break; + case 1: + // Yep. + bData |= ( 1 << 0 ); + break; + case 2: + // Yep. + bData |= ( 2 << 0 ); + break; + case -2: + // Yep. + bData |= ( 3 << 0 ); + break; + default: + // No - out of range - try the next neighbour. + continue; + } + + // OK, that worked - stop looking. + break; + + } + + if ( iNeighbour == 2 ) + { + // Nope - have to store the pixel raw. + // But convert to 555 first. + if ( image_data != NULL ) + { + // Format 565: rrrr rggg gggb bbbb + // Convert to: 0rrr rrgg gggb bbbb + // And set top bit to say it's raw data. + image_data[0] = ( wPixel >> 9 ) | 0x80; + image_data[1] = ( ( wPixel & 0x01c0 ) >> 1 ) | ( wPixel & 0x001f ); + image_data += 2; + + } + iTotalSize += 2; + + // And remember to put this into the line buffer, remembering to chop off the bottom + // bit of green, but we don't actually convert to 555. + wLine[iCurLineBuffer][iX] = wPixel & 0xffdf; + } + else + { + // Cool - we could do it. + if ( image_data != NULL ) + { + *image_data++ = bData; + } + iTotalSize += 1; + + // And write back this version into the line buffer. + + WORD wPixel; + if ( bData & 0x40 ) + { + // d bit is set - use pixel above. + wPixel = wNeighbourPixel[1]; + } + else + { + // d bit is clear - use pixel to left. + wPixel = wNeighbourPixel[0]; + } + // Now modify by the two-bit-fields for each colour. + + WORD wMask; + WORD wBottomBit; + WORD wComponent; + + // Red. + wMask = 0xf800; + wBottomBit = 0x0800; + switch ( ( bData & 0x30 ) >> 4 ) + { + case 0: + // No change. + break; + case 1: + // Plus 1 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 2: + // Plus 2 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 3: + // Minus 2 (with wraparound) + wComponent = ( wPixel & wMask ) - wBottomBit - wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + } + + // Green. + wMask = 0x07e0; + wBottomBit = 0x0020; + switch ( ( bData & 0x0c ) >> 2 ) + { + case 0: + // No change. + break; + case 1: + // Plus 1 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 2: + // Plus 2 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 3: + // Minus 2 (with wraparound) + wComponent = ( wPixel & wMask ) - wBottomBit - wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + } + + // Blue. + wMask = 0x001f; + wBottomBit = 0x0001; + switch ( ( bData & 0x03 ) >> 0 ) + { + case 0: + // No change. + break; + case 1: + // Plus 1 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 2: + // Plus 2 (with wraparound) + wComponent = ( wPixel & wMask ) + wBottomBit + wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + case 3: + // Minus 2 (with wraparound) + wComponent = ( wPixel & wMask ) - wBottomBit - wBottomBit; + wPixel = ( wPixel & ~wMask ) | ( wComponent & wMask ); + break; + } + + wLine[iCurLineBuffer][iX] = wPixel; + } + + + } + iPrevLineBuffer = iCurLineBuffer; + iCurLineBuffer = 1 - iCurLineBuffer; + } + + return ( iTotalSize ); + +} + + + + +void CopyBackground(UBYTE* image_data, IDirectDrawSurface4* surface) +{ +//#ifdef TARGET_DC +// // Always use my wacky compressed format. ATF +// UnpackBackground ( image_data, surface ); +//#else + +#if USE_COMPRESSED_BACKGROUNDS + // This just won't work. + ASSERT ( FALSE ); +#endif + + if (the_display.CurrMode->GetBPP() == 16) CopyBackground16(image_data, surface); + else CopyBackground32(image_data, surface); +//#endif +} + + + + +void PANEL_ResetDepthBodge ( void ); + +HRESULT Display::Flip(LPDIRECTDRAWSURFACE4 alt,SLONG flags) +{ + extern void PreFlipTT(); + PreFlipTT(); + + // Make sure panels and text work. + PANEL_ResetDepthBodge(); + + // Draw the screensaver (if any). + PANEL_screensaver_draw(); + + if(IsFullScreen() && CurrDevice->IsHardware()) + { +#ifdef TARGET_DC + + +#if 1 +#ifdef TARGET_DC + // Reset the viewport so that text, etc gets drawn even when in letterbox mode. + + { + D3DVIEWPORT2 viewData; + memset(&viewData, 0, sizeof(D3DVIEWPORT2)); + viewData.dwSize = sizeof(D3DVIEWPORT2); + + // A horrible hack for letterbox mode. + viewData.dwWidth = 640; + viewData.dwHeight = 480; + viewData.dwX = 0; + viewData.dwY = 0; + viewData.dvClipX = -1.0f; + viewData.dvClipY = 1.0f; + viewData.dvClipWidth = 2.0f; + viewData.dvClipHeight = 2.0f; + viewData.dvMinZ = 0.0f; + viewData.dvMaxZ = 1.0f; + HRESULT hres = (the_display.lp_D3D_Viewport)->SetViewport2 ( &viewData ); + } + +#endif +#endif + + + // Draw the frame. + POLY_frame_draw(TRUE, TRUE); + + // Flip. + HRESULT hres = lp_DD_FrontSurface->Flip(alt,flags); + + // And start the next one. + POLY_frame_init(FALSE, FALSE); + + return hres; + + //return DD_OK; +#else + return lp_DD_FrontSurface->Flip(alt,flags); +#endif + } + else + { +#ifdef TARGET_DC + // Bad dog! + ASSERT ( FALSE ); +#endif + // LogText("left - %ld, right - %ld, top - %ld. bottom - %ld\n",DisplayRect.left,DisplayRect.right,DisplayRect.top,DisplayRect.bottom); + return lp_DD_FrontSurface->Blt(&DisplayRect,lp_DD_BackSurface,NULL,DDBLT_WAIT,NULL); + } +} + + + +#if USE_COMPRESSED_BACKGROUNDS +void Display::use_this_background_surface(CompressedBackground this_one) +#else +void Display::use_this_background_surface(LPDIRECTDRAWSURFACE4 this_one) +#endif +{ + lp_DD_Background_use_instead = this_one; +} + + + +void Display::create_background_surface(UBYTE *image_data) +{ + +#if USE_COMPRESSED_BACKGROUNDS + + // Don't call this. + ASSERT ( FALSE ); + + + // First convert to 565 format. + WORD *pwTemp = (WORD *)MemAlloc ( 640 * 480 * 2 ); + ASSERT ( pwTemp != NULL ); + UBYTE *pbSrc = image_data; + + for ( int i = 0; i < 640*480; i++ ) + { + // From 24-bit RGB to 565. + *pwTemp = ( ( *pbSrc++ ) & 0xf8 ) << 8; + *pwTemp |= ( ( *pbSrc++ ) & 0xfc ) << 3; + *pwTemp |= ( ( *pbSrc++ ) & 0xf8 ) >> 3; + pwTemp++; + } + + // See how big it is, compressed. + int iSize = PackBackground ( NULL, pwTemp ); + + TRACE ( "create_background_surface: Original 565 0x%x, now 0x%x, saving of %i percent\n", 640*480*2, iSize, (100*iSize)/(640*480*2) ); + + if (lp_DD_Background) + { + MemFree ( lp_DD_Background ); + lp_DD_Background = NULL; + } + + lp_DD_Background = MemAlloc ( iSize ); + + PackBackground ( (UBYTE *)lp_DD_Background, pwTemp ); + + // And free the 565 version. + MemFree ( (void *)pwTemp ); + + +#else //#if USE_COMPRESSED_BACKGROUNDS + + DDSURFACEDESC2 back; + DDSURFACEDESC2 mine; + + // + // Remember this if we have to reload. + // + + background_image_mem = image_data; + + // + // Incase we already have one! + // + + if (lp_DD_Background) + { + lp_DD_Background->Release(); + lp_DD_Background = NULL; + } + + lp_DD_Background_use_instead = NULL; + + // + // Create a mirror surface to the back buffer. + // + + InitStruct(back); + + lp_DD_BackSurface->GetSurfaceDesc(&back); + + // + // Create the mirror surface in system memory. + // + + InitStruct(mine); + + mine.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + mine.dwWidth = back.dwWidth; + mine.dwHeight = back.dwHeight; + mine.ddpfPixelFormat = back.ddpfPixelFormat; + mine.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + + HRESULT result = lp_DD4->CreateSurface(&mine, &lp_DD_Background, NULL); + + if (FAILED(result)) + { + lp_DD_Background = NULL; + background_image_mem = NULL; + return; + } + + // + // Copy the image into the surface... + // + + CopyBackground(image_data, lp_DD_Background); + +#endif //#else //#if USE_COMPRESSED_BACKGROUNDS + + + return; +} + + + + +void Display::blit_background_surface(bool b3DInFrame) +{ +#if USE_COMPRESSED_BACKGROUNDS + CompressedBackground lpBG = NULL; +#else + LPDIRECTDRAWSURFACE4 lpBG = NULL; +#endif + + if ( lp_DD_Background_use_instead != NULL ) + { + lpBG = lp_DD_Background_use_instead; + } + else if ( lp_DD_Background != NULL ) + { + lpBG = lp_DD_Background; + } + else + { + return; + } + + + HRESULT result; + +#ifdef TARGET_DC + { + + if ( !b3DInFrame ) + { + // Won't have been done yet. + //POLY_frame_init(FALSE,FALSE); + } + + + // Use a poly draw. + ASSERT ( lpBackgroundCache != NULL ); + + if ( lpBG != m_lpLastBackground ) + { + // Get the texture handle. + m_lpLastBackground = lpBG; + + + static iCount = 0; + + +#if USE_COMPRESSED_BACKGROUNDS + + if ( lpBG != NULL ) + { + UnpackBackground ( (UCHAR *)lpBG, lpBackgroundCache ); + } + else + { + // Bum - black screen time :-( + ASSERT ( FALSE ); + } +#else + { + // Copy the data to the texture cache thingie. + RECT rect; + rect.top = 0; + rect.left = 0; + rect.right = 640; + rect.bottom = 480; + HRESULT hres = lpBackgroundCache->Blt ( &rect, lpBG, &rect, DDBLT_WAIT, NULL ); + VERIFY(SUCCEEDED(hres)); + } +#endif + } + + // ARGH! Got to use a poly draw instead. Useless machine. + + POLY_Point pp[4]; + POLY_Point *quad[4] = { &pp[0], &pp[1], &pp[2], &pp[3] }; + + pp[0].colour=0xffffffff; pp[0].specular=0; + pp[1].colour=0xffffffff; pp[1].specular=0; + pp[2].colour=0xffffffff; pp[2].specular=0; + pp[3].colour=0xffffffff; pp[3].specular=0; + + pp[0].X=0.0f; pp[0].Y=0.0f; pp[0].Z=0.0001f; + pp[0].u=0.0f; pp[0].v=0.0f; + + pp[1].X=0.0f; pp[1].Y=480.0f; pp[1].Z=0.0001f; + pp[1].u=0.0f; pp[1].v=480.0f / 512.0f; + + pp[2].X=640.0f; pp[2].Y=0.0f; pp[2].Z=0.0001f; + pp[2].u=640.0f / 1024.0f; pp[2].v=0.0f; + + pp[3].X=640.0f; pp[3].Y=480.0f; pp[3].Z=0.0001f; + pp[3].u=640.0f / 1024.0f; pp[3].v=480.0f / 512.0f; + + POLY_add_quad ( quad, POLY_PAGE_BACKGROUND_IMAGE, FALSE, TRUE ); + + + if ( !b3DInFrame ) + { + // Draw the stuff now. + //POLY_frame_draw(TRUE,TRUE); + } + + } + + + +#else + { + result = lp_DD_BackSurface->Blt(NULL,lpBG,NULL,DDBLT_WAIT,0); + + if (FAILED(result)) + { + dd_error(result); + } + } +#endif +} + +void Display::destroy_background_surface() +{ + if (lp_DD_Background) + { +#if USE_COMPRESSED_BACKGROUNDS + MemFree ( lp_DD_Background ); +#else //#if USE_COMPRESSED_BACKGROUNDS + lp_DD_Background->Release(); +#endif //#else //#if USE_COMPRESSED_BACKGROUNDS + lp_DD_Background = NULL; + } + + + background_image_mem = NULL; +} + +bool Display::IsGammaAvailable() +{ + return (lp_DD_GammaControl != NULL); +} + +// note: 0,256 is normal - white is *exclusive* + +void Display::SetGamma(int black, int white) +{ + if (!lp_DD_GammaControl) return; + + if (black < 0) black = 0; + if (white > 256) white = 256; + if (black > white - 1) black = white - 1; + + ENV_set_value_number("BlackPoint", black, "Gamma"); + ENV_set_value_number("WhitePoint", white, "Gamma"); + + DDGAMMARAMP ramp; + int diff = white - black; + + black <<= 8; + + for (int ii = 0; ii < 256; ii++) + { + ramp.red[ii] = black; + ramp.green[ii] = black; + ramp.blue[ii] = black; + + black += diff; + } + + lp_DD_GammaControl->SetGammaRamp(0, &ramp); +} + +void Display::GetGamma(int* black, int* white) +{ + *black = ENV_get_value_number("BlackPoint", 0, "Gamma"); + *white = ENV_get_value_number("WhitePoint", 256, "Gamma"); +} + + +// +// DIALOG BOX +// + +static bool is_primary = false; +static bool is_secondary = false; +static DDDriverInfo *primary_driver; +static DDDriverInfo *secondary_driver; + + + +// +// Returns TRUE if the current Video3DMode support 16 or 32-bit colour. +// + +#define SUPPORTS_16 (1 << 0) +#define SUPPORTS_32 (1 << 2) + +SLONG CurrentVideo3DModeSupports(void) +{ + SLONG ans = 0; + + switch(Video3DMode) + { + case 0: + + ASSERT(primary_driver); + + if (primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_16BIT) {ans |= SUPPORTS_16;} + if (primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT) {ans |= SUPPORTS_32;} + + break; + + case 1: + + ASSERT(secondary_driver); + + if (secondary_driver->DriverFlags & DD_DRIVER_SUPPORTS_16BIT) {ans |= SUPPORTS_16;} + if (secondary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT) {ans |= SUPPORTS_32;} + + break; + + case 2: + + if (primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT) + { + ans = SUPPORTS_32; + } + else + { + ans = SUPPORTS_16; + } + + break; + + default: + ASSERT(0); + break; + } + + return ans; +} + + + +#ifndef TARGET_DC + + +static void InitDialog(HWND hWnd) +{ + // centre window + RECT winsize; + RECT scrsize; + + GetWindowRect(hWnd, &winsize); + GetClientRect(GetDesktopWindow(), &scrsize); + + int xoff = ((scrsize.right - scrsize.left) - (winsize.right - winsize.left)) / 2; + int yoff = ((scrsize.bottom - scrsize.top) - (winsize.bottom - winsize.top)) / 2; + + SetWindowPos(hWnd, NULL, xoff, yoff, 0,0, SWP_NOZORDER | SWP_NOSIZE); + + // localise this bastard + CBYTE *lang=ENV_get_value_string("language"); + + if (!lang) lang="text\\lang_english.txt"; + XLAT_load(lang); + XLAT_init(); + //SetWindowText(hWnd,XLAT_str(X_GRAPHICS)); + SetDlgItemTextA(hWnd,IDC_GRAPHICS_OPTIONS,XLAT_str(X_GRAPHICS)); + SetDlgItemTextA(hWnd,IDC_STATIC_3DCARD,XLAT_str(X_3DCARD)); + SetDlgItemTextA(hWnd,IDC_STATIC_BITDEPTH,XLAT_str(X_NUM_COLOURS)); + SetDlgItemTextA(hWnd,IDC_STATIC_RES,XLAT_str(X_RESOLUTION)); + SetDlgItemTextA(hWnd,IDC_PRIMARY_3D,XLAT_str(X_USE_PRIMARY)); + SetDlgItemTextA(hWnd,IDC_SECONDARY_3D,XLAT_str(X_USE_SECONDARY)); + SetDlgItemTextA(hWnd,IDC_SOFTWARE_3D,XLAT_str(X_USE_SOFTWARE)); + SetDlgItemTextA(hWnd,IDC_COLOURS_16,XLAT_str(X_16BIT)); + SetDlgItemTextA(hWnd,IDC_COLOURS_32,XLAT_str(X_24BIT)); + SetDlgItemTextA(hWnd,IDC_NOSHOW,XLAT_str(X_DO_NOT_SHOW)); + SetDlgItemTextA(hWnd,IDOK,XLAT_str(X_OKAY)); + SetDlgItemTextA(hWnd,IDCANCEL,XLAT_str(X_EXIT)); + + // get windows + HWND primary3D = GetDlgItem(hWnd, IDC_PRIMARY_3D); + HWND secondary3D = GetDlgItem(hWnd, IDC_SECONDARY_3D); + HWND software3D = GetDlgItem(hWnd, IDC_SOFTWARE_3D); + + HWND colour16 = GetDlgItem(hWnd, IDC_COLOURS_16); + HWND colour32 = GetDlgItem(hWnd, IDC_COLOURS_32); + + HWND res = GetDlgItem(hWnd, IDC_RESOLUTION); + + HWND noshow = GetDlgItem(hWnd, IDC_NOSHOW); + + // set 3D card buttons + EnableWindow(primary3D, is_primary); + EnableWindow(secondary3D, is_secondary); + +#ifdef VERSION_DEMO + EnableWindow(software3D, FALSE); +#else + if (is_primary || is_secondary) EnableWindow(software3D, FALSE); +#endif + + // + // Always have software available- just for now. + // + +#ifndef VERSION_DEMO + EnableWindow(software3D, TRUE); +#endif + + if (Video3DMode == 1 && !is_secondary) + { + // + // Argh! Use primary! + // + + Video3DMode = 0; + } + + // + // Does the card support our bit depth? + // + + SLONG supports = CurrentVideo3DModeSupports(); + + if (VideoTrueColour == 1 && !(supports & SUPPORTS_32)) + { + VideoTrueColour = 0; + } + + if (VideoTrueColour == 0 && !(supports & SUPPORTS_16)) + { + VideoTrueColour = 1; + } + + EnableWindow(colour16, !!(supports & SUPPORTS_16)); + EnableWindow(colour32, !!(supports & SUPPORTS_32)); + + SendMessage(primary3D, BM_SETCHECK, (Video3DMode == 0) ? BST_CHECKED : BST_UNCHECKED, 0); + SendMessage(secondary3D, BM_SETCHECK, (Video3DMode == 1) ? BST_CHECKED : BST_UNCHECKED, 0); + SendMessage(software3D, BM_SETCHECK, (Video3DMode == 2) ? BST_CHECKED : BST_UNCHECKED, 0); + + // set colour buttons + SendMessage(colour16, BM_SETCHECK, !VideoTrueColour ? BST_CHECKED : BST_UNCHECKED, 0); + SendMessage(colour32, BM_SETCHECK, VideoTrueColour ? BST_CHECKED : BST_UNCHECKED, 0); + + // set resolutions + + switch(Video3DMode) + { + case 0: + + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"320 x 240"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"512 x 384"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"640 x 480"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"800 x 600"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"1024 x 768"); + + break; + + case 1: + + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"512 x 384"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"640 x 480"); + + if (secondary_driver->DriverFlags & DD_DRIVER_MODE_1024) + { + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"800 x 600"); + + SATURATE(VideoRes, 0, 2); + } + else + { + SATURATE(VideoRes, 0, 1); + } + + break; + + case 2: + + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"320 x 240"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"512 x 384"); + + SATURATE(VideoRes, 0, 1); + + break; + } + + SendMessage(res, CB_SETCURSEL, VideoRes, 0); + + // set no show + //SendMessage(noshow, BM_SETCHECK, BST_UNCHECKED, 0); + + // + // Get MFX_MILES.cpp to initialise the sound part of our dialog box. + // + + init_my_dialog(hWnd); +} + +static void FinishDialog(HWND hWnd) +{ + // get windows + HWND primary3D = GetDlgItem(hWnd, IDC_PRIMARY_3D); + HWND secondary3D = GetDlgItem(hWnd, IDC_SECONDARY_3D); + HWND software3D = GetDlgItem(hWnd, IDC_SOFTWARE_3D); + + HWND colour16 = GetDlgItem(hWnd, IDC_COLOURS_16); + HWND colour32 = GetDlgItem(hWnd, IDC_COLOURS_32); + + HWND res = GetDlgItem(hWnd, IDC_RESOLUTION); + + //HWND noshow = GetDlgItem(hWnd, IDC_NOSHOW); + + if (SendMessage(primary3D, BM_GETCHECK, 0, 0)) Video3DMode = 0; + else if (SendMessage(secondary3D, BM_GETCHECK, 0, 0)) Video3DMode = 1; + else Video3DMode = 2; + + if (SendMessage(colour16, BM_GETCHECK, 0, 0)) VideoTrueColour = false; + else VideoTrueColour = true; + + VideoRes = SendMessage(res, CB_GETCURSEL, 0, 0); + + if (Video3DMode == 1) + { + VideoRes += 1; + } + + /* + + if (SendMessage(noshow, BM_GETCHECK, 0, 0)) + { + ENV_set_value_number("run_video_dialog", 0, "Render"); + } + + */ + + my_dialogs_over(hWnd); +} + +static BOOL CALLBACK dlgproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + InitDialog(hWnd); + return TRUE; + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDOK: + FinishDialog(hWnd); + EndDialog(hWnd, 0); + return TRUE; + + case IDCANCEL: + // + // End everything! + // + + extern void MilesTerm(void); + + MilesTerm(); + the_manager.Fini(); + + exit(1); + + case IDC_PRIMARY_3D: + + { + HWND colour16 = GetDlgItem(hWnd, IDC_COLOURS_16); + HWND colour32 = GetDlgItem(hWnd, IDC_COLOURS_32); + HWND res = GetDlgItem(hWnd, IDC_RESOLUTION); + + // + // Enable diable the colour buttons. + // + + EnableWindow(colour16, !!(primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_16BIT)); + EnableWindow(colour32, !!(primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT)); + + if (SendMessage(colour16, BM_GETCHECK, 0, 0)) + { + if (!(primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_16BIT)) + { + SendMessage(colour16, BM_SETCHECK, FALSE, 0); + SendMessage(colour32, BM_SETCHECK, TRUE, 0); + } + } + else + { + if (!(primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT)) + { + SendMessage(colour16, BM_SETCHECK, TRUE, 0); + SendMessage(colour32, BM_SETCHECK, FALSE, 0); + } + } + + // set resolutions + + SendMessage(res, CB_RESETCONTENT, 0,0); + + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"320 x 240"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"512 x 384"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"640 x 480"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"800 x 600"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"1024 x 768"); + + SendMessage(res, CB_SETCURSEL, VideoRes, 0); + + } + + break; + + case IDC_SECONDARY_3D: + + { + HWND colour16 = GetDlgItem(hWnd, IDC_COLOURS_16); + HWND colour32 = GetDlgItem(hWnd, IDC_COLOURS_32); + HWND res = GetDlgItem(hWnd, IDC_RESOLUTION); + + // + // Enable diable the colour buttons. + // + + EnableWindow(colour16, !!(secondary_driver->DriverFlags & DD_DRIVER_SUPPORTS_16BIT)); + EnableWindow(colour32, !!(secondary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT)); + + if (SendMessage(colour16, BM_GETCHECK, 0, 0)) + { + if (!(secondary_driver->DriverFlags & DD_DRIVER_SUPPORTS_16BIT)) + { + SendMessage(colour16, BM_SETCHECK, FALSE, 0); + SendMessage(colour32, BM_SETCHECK, TRUE, 0); + } + } + else + { + if (!(secondary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT)) + { + SendMessage(colour16, BM_SETCHECK, TRUE, 0); + SendMessage(colour32, BM_SETCHECK, FALSE, 0); + } + } + + // set resolutions + + SendMessage(res, CB_RESETCONTENT, 0,0); + + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"512 x 384"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"640 x 480"); + + if (secondary_driver->DriverFlags & DD_DRIVER_MODE_1024) + { + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"800 x 600"); + + SATURATE(VideoRes, 0, 2); + } + else + { + SATURATE(VideoRes, 0, 1); + } + + SendMessage(res, CB_SETCURSEL, VideoRes, 0); + + break; + } + + case IDC_SOFTWARE_3D: + + { + HWND colour16 = GetDlgItem(hWnd, IDC_COLOURS_16); + HWND colour32 = GetDlgItem(hWnd, IDC_COLOURS_32); + HWND res = GetDlgItem(hWnd, IDC_RESOLUTION); + + if (primary_driver->DriverFlags & DD_DRIVER_SUPPORTS_32BIT) + { + #ifdef NDEBUG + + // + // Enable and diable the colour buttons. + // + + EnableWindow(colour16, FALSE); + EnableWindow(colour32, TRUE); + + if (SendMessage(colour16, BM_GETCHECK, 0, 0)) + { + SendMessage(colour16, BM_SETCHECK, FALSE, 0); + SendMessage(colour32, BM_SETCHECK, TRUE, 0); + } + + #else + + // + // Enable all the colour buttons. + // + + EnableWindow(colour16, TRUE); + EnableWindow(colour32, TRUE); + + #endif + } + else + { + // + // We have to use 16-bit software :( + // + + EnableWindow(colour16, TRUE); + EnableWindow(colour32, FALSE); + + SendMessage(colour16, BM_SETCHECK, TRUE, 0); + SendMessage(colour32, BM_SETCHECK, FALSE, 0); + + } + + // set resolutions + + SendMessage(res, CB_RESETCONTENT, 0,0); + + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"320 x 240"); + SendMessage(res, CB_INSERTSTRING, -1, (LPARAM)"512 x 384"); + + SATURATE(VideoRes, 0, 1); + + SendMessage(res, CB_SETCURSEL, VideoRes, 0); + } + + break; + } + + break; + } + + return FALSE; +} + + +#endif //#ifndef TARGET_DC + + + +// +// Returns TRUE if the driver has a harware mode that allowed alpha textures... +// + +SLONG valid_driver(DDDriverInfo *drv) +{ +#ifndef TARGET_DC + D3DDeviceInfo *d3d; + + if (drv == NULL) + { + return FALSE; + } + + for (d3d = drv->DeviceList; d3d; d3d = d3d->Next) + { + if (d3d->IsHardware()) + { + if (d3d->d3dHalDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHA) + { + return TRUE; + } + } + } + + return FALSE; +#else + return TRUE; +#endif +} + + +// GraphicsDialog +// +// do the dialog box + +void GraphicsDialog(HINSTANCE hInst, HWND hWnd) +{ +#ifdef TARGET_DC + Video3DMode = -1; + VideoTrueColour = false; + VideoRes = -1; +#else + // read existing config (if any) + Video3DMode = ENV_get_value_number("video_card", -1, "Render"); + VideoTrueColour = ENV_get_value_number("video_truecolour", 0, "Render") ? true : false; + VideoRes = ENV_get_value_number("video_res", -1, "Render"); +#endif + + is_primary = false; + is_secondary = false; + primary_driver = NULL; + secondary_driver = NULL; + + // check for 1ry and 2ry cards + DDDriverInfo* drv = the_manager.DriverList; + + while (drv) + { + if (drv->IsPrimary()) + { + is_primary = true; + primary_driver = drv; + } + else + { + is_secondary = true; + secondary_driver = drv; + } + + drv = drv->Next; + } + + // + // Ban incompatible drivers? + // + + if (!valid_driver(primary_driver )) {is_primary = FALSE; primary_driver = NULL;} + if (!valid_driver(secondary_driver)) {is_secondary = FALSE; secondary_driver = NULL;} + + // ban illegal settings + if ((Video3DMode == 0) && !is_primary) Video3DMode = -1; + if ((Video3DMode == 1) && !is_secondary) Video3DMode = -1; + + // set default card + if (Video3DMode == -1) + { + if (is_primary) Video3DMode = 0; + else if (is_secondary) Video3DMode = 1; + else Video3DMode = 2; + } + +#ifndef TARGET_DC +#ifdef VERSION_DEMO + if (Video3DMode == 2) + { + MessageBox(NULL, "This demo requires a 3D accelerator (the release version works without one)", NULL, MB_ICONEXCLAMATION | MB_OK); + exit(1); + } +#endif +#endif + + // set default res + if (VideoRes == -1) + { + if (Video3DMode < 2) VideoRes = 2; + else VideoRes = 0; + } + +#ifndef TARGET_DC + // run dialog +// if (ENV_get_value_number("run_video_dialog", 1, "Render")) + { + DialogBox(hInst, MAKEINTRESOURCE(IDD_GRAPHICSDLG), hWnd, (DLGPROC)dlgproc); + } +#else + // I know what I want, thanks. + Video3DMode = 0; // Primary. + VideoTrueColour = FALSE; + VideoRes = 2; // 640x480. +#endif + +#ifndef TARGET_DC + // store config + ENV_set_value_number("video_card", Video3DMode, "Render"); + ENV_set_value_number("video_truecolour", VideoTrueColour ? 1 : 0, "Render"); + ENV_set_value_number("video_res", VideoRes, "Render"); +#endif + + // look for illegal shit + char* err = NULL; + + /* + + if (Video3DMode == 1) + { + if (VideoTrueColour) err = "Card does not support 24-bit colour"; + } + else if (Video3DMode == 2) + { +// if (VideoTrueColour) err = "Renderer does not support 24-bit colour"; + } + + */ + +#ifndef TARGET_DC + if (err) + { + MessageBox(NULL, err, NULL, MB_ICONEXCLAMATION); + exit(1); + } +#endif + + if (Video3DMode == 0) + { + the_manager.CurrDriver = primary_driver; + } + else + if (Video3DMode == 1) + { + the_manager.CurrDriver = secondary_driver; + } +} + + + + + + + diff --git a/fallen/DDLibrary/Source/GFile.cpp b/fallen/DDLibrary/Source/GFile.cpp new file mode 100644 index 0000000..219f58c --- /dev/null +++ b/fallen/DDLibrary/Source/GFile.cpp @@ -0,0 +1,209 @@ +// File.cpp +// Guy Simmons, 10th February 1997. + +#include "DDLib.h" + + +#define MAX_LENGTH_OF_BASE_PATH 64 +CBYTE cBasePath[MAX_LENGTH_OF_BASE_PATH+1]; + +//--------------------------------------------------------------- + +#define MAX_LENGTH_OF_FULL_NAME (MAX_LENGTH_OF_BASE_PATH+16) +CBYTE cTempFilename[MAX_LENGTH_OF_FULL_NAME+1]; + +CBYTE *MakeFullPathName ( CBYTE *cFilename ) +{ + strcpy ( cTempFilename, cBasePath ); + ASSERT ( strlen ( filename ) < ( MAX_LENGTH_OF_FULL_NAME - MAX_LENGTH_OF_BASE_PATH ) ); + strcat ( cTempFilename, cFilename ); + return ( cTempFilename ); +} + + +//--------------------------------------------------------------- + +BOOL FileExists(CBYTE *file_name) +{ + file_name = MakeFullPathName ( file_name ); + + if(GetFileAttributes(file_name)==0xffffffff) + return FALSE; + else + return TRUE; +} + +//--------------------------------------------------------------- + +MFFileHandle FileOpen(CBYTE *file_name) +{ + MFFileHandle result = FILE_OPEN_ERROR; + + file_name = MakeFullPathName ( file_name ); + + if(FileExists(file_name)) + { + result = CreateFile ( + file_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if(result==INVALID_HANDLE_VALUE) + result = FILE_OPEN_ERROR; + } + return result; +} + +//--------------------------------------------------------------- + +void FileClose(MFFileHandle file_handle) +{ + CloseHandle(file_handle); +} + +//--------------------------------------------------------------- + +MFFileHandle FileCreate(CBYTE *file_name,BOOL overwrite) +{ + DWORD creation_mode; + MFFileHandle result; + + file_name = MakeFullPathName ( file_name ); + + if(overwrite) + { + creation_mode = CREATE_ALWAYS; + } + else + { + creation_mode = CREATE_NEW; + } + result = CreateFile ( + file_name, + (GENERIC_READ|GENERIC_WRITE), + (FILE_SHARE_READ|FILE_SHARE_WRITE), + NULL, + creation_mode, + 0, + NULL + ); + if(result==INVALID_HANDLE_VALUE) + result = FILE_CREATION_ERROR; + + return result; +} + +//--------------------------------------------------------------- + +void FileDelete(CBYTE *file_name) +{ + file_name = MakeFullPathName ( file_name ); + DeleteFile(file_name); +} + +//--------------------------------------------------------------- + +SLONG FileSize(MFFileHandle file_handle) +{ + DWORD result; + + + result = GetFileSize(file_handle,NULL); + if(result==0xffffffff) + return FILE_SIZE_ERROR; + else + return (SLONG)result; +} + +//--------------------------------------------------------------- + +SLONG FileRead(MFFileHandle file_handle,void *buffer,ULONG size) +{ + SLONG bytes_read; + + + if(ReadFile(file_handle,buffer,size,(LPDWORD)&bytes_read,NULL)==FALSE) + return FILE_READ_ERROR; + else + return bytes_read; +} + +//--------------------------------------------------------------- + +SLONG FileWrite(MFFileHandle file_handle,void *buffer,ULONG size) +{ + SLONG bytes_written; + + + if(WriteFile(file_handle,buffer,size,(LPDWORD)&bytes_written,NULL)==FALSE) + return FILE_WRITE_ERROR; + else + return bytes_written; +} + +//--------------------------------------------------------------- + +SLONG FileSeek(MFFileHandle file_handle,const int mode,SLONG offset) +{ + DWORD method; + + + switch(mode) + { + case SEEK_MODE_BEGINNING: + method = FILE_BEGIN; + break; + case SEEK_MODE_CURRENT: + method = FILE_CURRENT; + break; + case SEEK_MODE_END: + method = FILE_END; + break; + } + if(SetFilePointer(file_handle,offset,NULL,method)==0xffffffff) + return FILE_SEEK_ERROR; + else + return 0; +} + +//--------------------------------------------------------------- + +SLONG FileLoadAt(CBYTE *file_name,void *buffer) +{ + SLONG size; + MFFileHandle handle; + + file_name = MakeFullPathName ( file_name ); + + handle = FileOpen(file_name); + if(handle!=FILE_OPEN_ERROR) + { + size = FileSize(handle); + if(size>0) + { + if(FileRead(handle,buffer,size)==size) + { + FileClose(handle); + return size; + } + } + FileClose(handle); + } + return FILE_LOAD_AT_ERROR; +} + +//--------------------------------------------------------------- + +void FileSetBasePath(CBYTE *path_name) +{ + ASSERT ( strlen ( path_name ) < MAX_LENGTH_OF_BASE_PATH ); + strncpy ( cBasePath, path_name, MAX_LENGTH_OF_BASE_PATH ); +} + +//--------------------------------------------------------------- + + diff --git a/fallen/DDLibrary/Source/GHost.cpp b/fallen/DDLibrary/Source/GHost.cpp new file mode 100644 index 0000000..5c10c41 --- /dev/null +++ b/fallen/DDLibrary/Source/GHost.cpp @@ -0,0 +1,584 @@ +// GHost.cpp +// Guy Simmons, 20th November 1997. + +#include "DDLib.h" +#include "c:\fallen\headers\Sound.h" +#include "a3dmanager.h" +#include "snd_type.h" +#include "mfx.h" +#include "mfx_miles.h" + +#define PAUSE_TIMEOUT 500 +#define PAUSE (1<<0) +#define PAUSE_ACK (1<<1) + +int iGlobalWinMode; +DWORD ShellID; +HACCEL hDDLibAccel; +HANDLE hDDLibThread; +HINSTANCE hGlobalPrevInst, + hGlobalThisInst; +LPSTR lpszGlobalArgs; +WNDCLASS DDLibClass; + +volatile BOOL ShellActive; +volatile ULONG PauseFlags = 0, + PauseCount = 0; + + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +//--------------------------------------------------------------- + +DWORD DDLibThread(LPVOID param) +{ + MSG msg; + +#ifdef TARGET_DC + // Create a basic window - only used for message passing. + hDDLibWindow = CreateWindowEx ( + 0, + TEXT("Urban Chaos"), + TEXT("Urban Chaos"), + WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_DESKTOP, + NULL, + hGlobalThisInst, + NULL + ); + +#else + hDDLibWindow = CreateWindowEx ( + 0, + "Urban Chaos", + "Urban Chaos", + #ifndef NDEBUG + WS_OVERLAPPEDWINDOW, + #else + WS_POPUP, + #endif + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_DESKTOP, + NULL, + hGlobalThisInst, + NULL + ); +#endif + + ShowWindow(hDDLibWindow,iGlobalWinMode); + UpdateWindow(hDDLibWindow); + + ShellActive = TRUE; + while(GetMessage(&msg,NULL,0,0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + ShellActive = FALSE; + + return 0; +} + +//--------------------------------------------------------------- + +BOOL SetupKeyboard(void); +void ResetKeyboard(void); + +BOOL SetupHost(ULONG flags) +{ + DWORD id; + + + ShellActive = FALSE; + +#ifndef NDEBUG + InitDebugLog(); +#endif + + if(!SetupMemory()) + return FALSE; + if(!SetupKeyboard()) + return FALSE; + +#ifdef TARGET_DC + if(the_input_manager.Init()!=DI_OK) + { + ASSERT ( FALSE ); + return FALSE; + } +#endif + + // Create the shell window. +#ifdef TARGET_DC + // Create & register the window class. + DDLibClass.hInstance = hGlobalThisInst; + DDLibClass.lpszClassName = TEXT("Urban Chaos"); + DDLibClass.lpfnWndProc = DDLibShellProc; + DDLibClass.style = 0; + DDLibClass.hIcon = NULL; + DDLibClass.hCursor = NULL; + #ifndef NDEBUG + DDLibClass.lpszMenuName = NULL; + #else + DDLibClass.lpszMenuName = NULL; + #endif + DDLibClass.cbClsExtra = 0; + DDLibClass.cbWndExtra = 0; + DDLibClass.hbrBackground = NULL; + + RegisterClass(&DDLibClass); + + hDDLibWindow = CreateWindowEx ( + 0, + TEXT("Urban Chaos"), + TEXT("Urban Chaos"), + WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_DESKTOP, + NULL, + hGlobalThisInst, + NULL + ); +#else + // Create & register the window class. + DDLibClass.hInstance = hGlobalThisInst; + DDLibClass.lpszClassName = TEXT("Urban Chaos"); + DDLibClass.lpfnWndProc = DDLibShellProc; + DDLibClass.style = 0; + DDLibClass.hIcon = LoadIcon(hGlobalThisInst, MAKEINTRESOURCE(IDI_ICON2)); + DDLibClass.hCursor = LoadCursor(NULL, IDC_ARROW); + #ifndef NDEBUG + DDLibClass.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN_MENU); + #else + DDLibClass.lpszMenuName = NULL; + #endif + DDLibClass.cbClsExtra = 0; + DDLibClass.cbWndExtra = 0; + DDLibClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + + RegisterClass(&DDLibClass); + + hDDLibWindow = CreateWindowEx ( + 0, + "Urban Chaos", + "Urban Chaos", + #ifndef NDEBUG + WS_OVERLAPPEDWINDOW, + #else + WS_POPUP, + #endif + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_DESKTOP, + NULL, + hGlobalThisInst, + NULL + ); +#endif + + if(hDDLibWindow) + { + // Init the sound manager. We're not too fussed about the result. + +#ifdef A3D_SOUND + A3D_Check_Init(); +#endif + +#ifdef Q_SOUND + the_qs_sound_manager.Init(); +#endif + +#ifdef M_SOUND + MilesInit(hGlobalThisInst, hDDLibWindow); +#endif + + + + // This does shed-loads of work, so it's been moved to much later in the boot process. +//#ifdef TARGET_DC +//extern void MFX_DC_init ( void ); +// MFX_DC_init(); +//#endif + + + +#ifndef TARGET_DC + // Load the keyboard accelerators. + hDDLibAccel = LoadAccelerators(hGlobalThisInst,MAKEINTRESOURCE(IDR_MAIN_ACCELERATOR)); +#endif + + // Display the window. +// ShowWindow(hDDLibWindow,iGlobalWinMode); +// UpdateWindow(hDDLibWindow); + + ShellActive = TRUE; + } + + the_game.DarciStrength=0; + the_game.DarciStamina=0; + the_game.DarciSkill=0; + the_game.DarciConstitution=0; + + return ShellActive; +} + +//--------------------------------------------------------------- + +void ResetHost(void) +{ +#ifdef M_SOUND + MilesTerm(); +#endif + + ResetKeyboard(); + ResetMemory(); + +#ifndef NDEBUG + FiniDebugLog(); +#endif + + UnregisterClass(TEXT("Urban Chaos"),GetModuleHandle(NULL)); +} + +//--------------------------------------------------------------- + +void ShellPaused(void) +{ + return; + + SLONG timeout; + + + if(PauseFlags&PAUSE) + { + PauseFlags |= PAUSE_ACK; // Send acknowledgement, +// do_pause_check: + timeout = GetTickCount(); + while(PauseFlags&PAUSE) // Wait while paused + { + if(Keys[KB_L]) + { + LibShellMessage("ShellPauseOff: Timeout",__FILE__,__LINE__); + } +/* + if((GetTickCount()-timeout)>PAUSE_TIMEOUT) + { + g_ShellMessage("ShellPaused: Timeout",__FILE__,__LINE__); + goto do_pause_check; + } +*/ + } + PauseFlags |= PAUSE_ACK; // Send acknowledgement, + } +} + +//--------------------------------------------------------------- + +void ShellPauseOn(void) +{ + the_display.toGDI(); + return; + + SLONG timeout; + + + PauseCount++; + if(PauseCount==1) + { + PauseFlags |= PAUSE; // Set pause flag. +// do_ack_check: + timeout = GetTickCount(); + while(!(PauseFlags&PAUSE_ACK)) // Wait for acknowledgement. + { + if(Keys[KB_L]) + { + LibShellMessage("ShellPauseOff: Timeout",__FILE__,__LINE__); + } +/* + if((GetTickCount()-timeout)>PAUSE_TIMEOUT) + { + g_ShellMessage("ShellPauseOn: Timeout",__FILE__,__LINE__); + goto do_ack_check; + } +*/ + } + PauseFlags &= ~PAUSE_ACK; // Clear ack flag. + + the_display.toGDI(); + } +} + +//--------------------------------------------------------------- + +void ShellPauseOff(void) +{ + return; + + SLONG timeout; + + + if(PauseCount==0) + return; + + if(PauseCount==1) + { + the_display.fromGDI(); + + PauseFlags &= ~PAUSE; // Clear pause flag. +// do_ack_check: + timeout = GetTickCount(); + while(!(PauseFlags&PAUSE_ACK)) // Wait for acknowledgement. + { + if(Keys[KB_L]) + { + LibShellMessage("ShellPauseOff: Timeout",__FILE__,__LINE__); + } +/* + if((GetTickCount()-timeout)>PAUSE_TIMEOUT) + { + g_ShellMessage("ShellPauseOff: Timeout",__FILE__,__LINE__); + goto do_ack_check; + } +*/ + } + PauseFlags &= ~PAUSE_ACK; // Clear ack flag. + } + PauseCount--; +} + +//--------------------------------------------------------------- +extern void ClearLatchedKeys(); + +extern SLONG app_inactive; +extern SLONG restore_surfaces; + + +BOOL LibShellActive(void) +{ + SLONG result; + MSG msg; + + // + // release any remembered keys + // + ClearLatchedKeys(); + + while(1) + { + while(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) + { + result = (SLONG)GetMessage(&msg,NULL,0,0); +#ifndef TARGET_DC + if(result) + { + if(!TranslateAccelerator(hDDLibWindow,hDDLibAccel,&msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + else + { + ShellActive = FALSE; + } +#endif + } + + + if (app_inactive && the_display.lp_DD4 && the_display.IsFullScreen()) + { + Sleep(100); + } + else + { + break; + } + } + + if (restore_surfaces) + { + if (the_display.lp_DD4) + { + the_display.lp_DD4->RestoreAllSurfaces(); + + extern void FRONTEND_restore_screenfull_surfaces(void); + + FRONTEND_restore_screenfull_surfaces(); + } + + restore_surfaces = FALSE; + } + + return ShellActive; +} + +//--------------------------------------------------------------- + +BOOL LibShellChanged(void) +{ + if(the_display.IsDisplayChanged()) + { + the_display.DisplayChangedOff(); + return TRUE; + } + return FALSE; +} + +//--------------------------------------------------------------- + +BOOL LibShellMessage(const char *pMessage, const char *pFile, ULONG dwLine) +{ + BOOL result; + CBYTE buff1[512], + buff2[512]; + ULONG flag; + + if (pMessage == NULL) + { + pMessage = "Looks like a coder has caught a bug."; + } + + TRACE("LbShellMessage: %s\n", pMessage); + +#ifndef TARGET_DC + wsprintf( buff1, "Uh oh, something bad's happened!"); + wsprintf( buff2, "%s\n\n%s\n\nIn : %s\nline : %u", buff1, pMessage, pFile, dwLine); + strcat(buff2, "\n\nAbort=Kill Application, Retry=Debug, Ignore=Continue"); + flag = MB_ABORTRETRYIGNORE|MB_ICONSTOP|MB_DEFBUTTON3; + + result = FALSE; + the_display.toGDI(); + switch(MessageBox(hDDLibWindow,buff2,"Mucky Foot Message",flag)) + { + case IDABORT: + exit(1); + break; + case IDCANCEL: + case IDIGNORE: + break; + case IDRETRY: + _asm int 3; + break; + } + + the_display.fromGDI(); +#else + result = TRUE; +#endif + + return result; +} + +//--------------------------------------------------------------- + +void Time(MFTime *the_time) +{ + SYSTEMTIME new_time; + + + GetLocalTime(&new_time); + the_time->Hours = new_time.wHour; + the_time->Minutes = new_time.wMinute; + the_time->Seconds = new_time.wSecond; + the_time->MSeconds = new_time.wMilliseconds; + the_time->DayOfWeek = new_time.wDayOfWeek; + the_time->Day = new_time.wDay; + the_time->Month = new_time.wMonth; + the_time->Year = new_time.wYear; + the_time->Ticks = GetTickCount(); +} + +//--------------------------------------------------------------- +// +// WinMain - Entry point for windows application. +// +//--------------------------------------------------------------- + +static UWORD argc; +static LPTSTR argv[MAX_PATH]; + +#ifdef TARGET_DC +// Include this again in just one file - this one. +#include "dtags.h" +#endif + +int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPTSTR lpszArgs, int iWinMode) +{ + // Store WinMain parameters. +#ifdef TARGET_DC + // This malloc has to be a malloc, not a MemAlloc - the heap has not yet been set up. + lpszGlobalArgs = (char *)malloc ( ( _tcslen (lpszArgs) + 1 ) * sizeof(*lpszGlobalArgs) ); + ASSERT ( lpszGlobalArgs != NULL ); + textConvertUniToChar ( lpszGlobalArgs, lpszArgs ); +#else + lpszGlobalArgs = lpszArgs; +#endif + iGlobalWinMode = iWinMode; + hGlobalThisInst = hThisInst; + hGlobalPrevInst = hPrevInst; + +void init_best_found(void); + init_best_found(); + + +#ifdef TARGET_DC + // Init the DTrace logging. + LOG_INIT +#endif + + + #if 0 // Someone already done it! :) + #ifdef NDEBUG + + // + // So you can't have multiple release builds of fallen running at once! + // + + CreateMutex(NULL, TRUE, "This is your friendly Urban Chaos mutex!"); + + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + // + // Fallen is already running! + // + + return 0; + } + + #endif + #endif + +#ifndef FINAL +// extern void CONSOLE_TCP(); +// CONSOLE_TCP(); +#endif + + // try and create an event + // this always succeeds + // if event existed before (still succeeds) and ERROR_ALREADY_EXISTS is returned, so die + // note the event is automatically deleted by the system when the app exits (even if it crashes) + + #ifdef FINAL + HANDLE hEvent = CreateEventA(NULL, FALSE, FALSE, "UrbanChaosExclusionZone"); + if (GetLastError() != ERROR_ALREADY_EXISTS) + #endif + { + return MF_main(argc,argv); + } + + return ERROR_ALREADY_EXISTS; +} + +//--------------------------------------------------------------- diff --git a/fallen/DDLibrary/Source/GKeyboard.cpp b/fallen/DDLibrary/Source/GKeyboard.cpp new file mode 100644 index 0000000..b981ab8 --- /dev/null +++ b/fallen/DDLibrary/Source/GKeyboard.cpp @@ -0,0 +1,183 @@ +// Keyboard.cpp +// Guy Simmons, 11th February 1997. + +#include "DDLib.h" + +#ifdef TARGET_DC +volatile UBYTE Keys[256], + LastKey; +#else +volatile UBYTE AltFlag, + ControlFlag, + ShiftFlag; +volatile UBYTE Keys[256], + LastKey; +#endif + +UBYTE key_turn[256]; + +#define MAX_RELEASE 10 +UBYTE Released[MAX_RELEASE]; +SWORD release_count=0; +UBYTE game_turn=0; + +HHOOK KeyboardHook; + +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam); + +//--------------------------------------------------------------- + +BOOL SetupKeyboard(void) +{ +#ifndef TARGET_DC + AltFlag = 0; + ControlFlag = 0; + ShiftFlag = 0; +#endif + LastKey = 0; + memset((char*)&Keys[0],0,256); + memset((char*)&key_turn[0],0,256); + +#ifdef _RELEASE + KeyboardHook = NULL; +/* + KeyboardHook = SetWindowsHookEx( + WH_KEYBOARD, + (HOOKPROC)KeyboardProc, + NULL, + 0 + ); + ERROR_MSG(KeyboardHook,"Can't setup the keyboard.") + if(KeyboardHook==NULL) + { + // Unable to set up keyboard. + return FALSE; + } +*/ +#endif + return TRUE; +} + +//--------------------------------------------------------------- + +void ResetKeyboard(void) +{ +#if defined(_RELEASE) && !defined(TARGET_DC) + if(KeyboardHook) + UnhookWindowsHookEx(KeyboardHook); +#endif +} + +//--------------------------------------------------------------- + +#define KEYMASK_REPEAT (0x0000ffff) +#define KEYMASK_SCAN (0x00ff0000) +#define KEYMASK_EXTENDED (0x01000000) +#define KEYMASK_RESERVED (0x1e000000) +#define KEYMASK_CONTEXT (0x20000000) +#define KEYMASK_PSTATE (0x40000000) +#define KEYMASK_TSTATE (0x80000000) + +// +// set game flags from keyboard state array +// + +inline void SetFlagsFromKeyArray() +{ +#ifndef TARGET_DC + AltFlag = Keys[KB_LALT] || Keys[KB_RALT]; + ControlFlag = Keys[KB_LCONTROL];// || Keys[KB_RCONTROL]; + ShiftFlag = Keys[KB_LSHIFT] || Keys[KB_RSHIFT]; +#endif +} + +// +// KeyboardProc for WM_KEYUP & WM_KEYDOWN +// + +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) +{ + UBYTE key_code; + ULONG virtual_keycode = wParam; + + +#ifndef TARGET_DC + if(code<0) + { + return CallNextHookEx(KeyboardHook,code,wParam,lParam); + } +#endif + + // Get key scan code. + key_code = (UBYTE)((lParam&KEYMASK_SCAN)>>16); + + // Extended key press? + if(lParam&KEYMASK_EXTENDED) + { + key_code += 0x80; + } + + // Key up? + if(lParam&KEYMASK_TSTATE) + { + + if(key_turn[key_code]==game_turn && release_count>1,(client_rect.top+client_rect.bottom)>>1); + p.x=(client_rect.left+client_rect.right)>>1; + p.y=(client_rect.top+client_rect.bottom)>>1; + + ScreenToClient(hDDLibWindow,&p); + + + OldMouseX=p.x; + OldMouseY=p.y; + +} + + +//--------------------------------------------------------------- diff --git a/fallen/DDLibrary/Source/GWorkScreen.cpp b/fallen/DDLibrary/Source/GWorkScreen.cpp new file mode 100644 index 0000000..96e24bd --- /dev/null +++ b/fallen/DDLibrary/Source/GWorkScreen.cpp @@ -0,0 +1,300 @@ +// WorkScreen.cpp +// Guy Simmons, 10th December 1997 + + +// The work screen is never used on the DC +#ifndef TARGET_DC + + + +#include "DDLib.h" + + +UBYTE CurrentPalette[256*3], + WorkScreenDepth, + *WorkScreen, + *WorkWindow; +SLONG WorkScreenHeight, + WorkScreenWidth, + WorkScreenPixelWidth, + WorkWindowHeight, + WorkWindowWidth; + +MFRect WorkWindowRect; + + + + +//--------------------------------------------------------------- + +void ShowWorkScreen(ULONG flags) +{ + flags = flags; + + the_display.ShowWorkScreen(); +} + +//--------------------------------------------------------------- + +void *LockWorkScreen(void) +{ + DDSURFACEDESC2 dd_sd; + HRESULT result; + + + if(the_display.lp_DD_WorkSurface) + { + InitStruct(dd_sd); + result = the_display.lp_DD_WorkSurface->Lock ( + NULL, + &dd_sd, + DDLOCK_WAIT, + NULL + ); + switch(result) + { + case DD_OK: + WorkScreenPixelWidth = dd_sd.dwWidth; + WorkScreenWidth = dd_sd.lPitch; + WorkScreenHeight = dd_sd.dwHeight; + WorkScreen = (UBYTE*)dd_sd.lpSurface; + SetWorkWindow(); + return dd_sd.lpSurface; + case DDERR_SURFACELOST: + the_display.Restore(); + return LockWorkScreen(); + } + } + return 0; +} + +//--------------------------------------------------------------- + +void UnlockWorkScreen(void) +{ + HRESULT result; + + + if(the_display.lp_DD_WorkSurface) + { + result = the_display.lp_DD_WorkSurface->Unlock(NULL); + if(result==DDERR_SURFACELOST) + { + the_display.Restore(); + UnlockWorkScreen(); + } + } +} + +//--------------------------------------------------------------- + +void ClearWorkScreen(UBYTE colour) +{ + DDBLTFX dd_bltfx; + HRESULT result; + + + if(the_display.lp_DD_WorkSurface) + { + InitStruct(dd_bltfx); + dd_bltfx.dwFillColor = colour; + result = the_display.lp_DD_WorkSurface->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT,&dd_bltfx); + switch(result) + { + case DD_OK: + break; + case DDERR_SURFACELOST: + the_display.Restore(); + ClearWorkScreen(colour); + break; + } + } +} + +//--------------------------------------------------------------- + + +void ShowWorkWindow(ULONG flags) +{ + SLONG x_scale, + y_scale; + HRESULT result; + RECT ww_dest_rect, + ww_source_rect; + + + if(the_display.lp_DD_WorkSurface==NULL) + return; + + ww_source_rect.left = WorkWindowRect.Left; + ww_source_rect.top = WorkWindowRect.Top; + ww_source_rect.right = WorkWindowRect.Right; + ww_source_rect.bottom = WorkWindowRect.Bottom; + + if(the_display.IsFullScreen()) + { +// result = the_display.ShowWorkScreen(); + result = the_display.lp_DD_FrontSurface->Blt ( + &ww_source_rect, + the_display.lp_DD_WorkSurface, + &ww_source_rect, + DDBLT_WAIT, + NULL + ); + } + else + { + x_scale = ((the_display.DisplayRect.right-the_display.DisplayRect.left)<<16)/WorkScreenPixelWidth; + y_scale = ((the_display.DisplayRect.bottom-the_display.DisplayRect.top)<<16)/WorkScreenHeight; + ww_dest_rect.left = the_display.DisplayRect.left+ww_source_rect.left; + ww_dest_rect.top = the_display.DisplayRect.top+ww_source_rect.top; + ww_dest_rect.right = ww_dest_rect.left+((WorkWindowWidth*x_scale)>>16); + ww_dest_rect.bottom = ww_dest_rect.top+((WorkWindowHeight*y_scale)>>16); + + result = the_display.lp_DD_FrontSurface->Blt ( + &ww_dest_rect, + the_display.lp_DD_WorkSurface, + &ww_source_rect, + DDBLT_WAIT, + NULL + ); + } + if(result==DDERR_SURFACELOST) + { + if(SUCCEEDED(the_display.Restore())) + ShowWorkWindow(flags); + } +} + +//--------------------------------------------------------------- + +void SetWorkWindowBounds(SLONG left, SLONG top, SLONG width, SLONG height) +{ + if((left+width)>=WorkScreenPixelWidth) + { + width -= (left+width)-WorkScreenPixelWidth; + if(width<1) + { + left = 0; + width = 1; + } + } + if((top+height)>=WorkScreenHeight) + { + height -= (top+height)-WorkScreenHeight; + if(height<1) + { + top = 0; + height = 1; + } + } + WorkWindowRect.Left = left; + WorkWindowRect.Top = top; + WorkWindowRect.Right = (left+width)-1; + WorkWindowRect.Bottom = (top+height)-1; + WorkWindowRect.Width = width; + WorkWindowRect.Height = height; + + WorkWindowHeight = height; + WorkWindowWidth = width; + + SetWorkWindow(); +} + +//--------------------------------------------------------------- + +MFPoint *GlobalToLocal(MFPoint *the_point) +{ + the_point->X -= WorkWindowRect.Left; + the_point->Y -= WorkWindowRect.Top; + + return the_point; +} + +//--------------------------------------------------------------- + +void GlobalXYToLocal(SLONG *x,SLONG *y) +{ + *x -= WorkWindowRect.Left; + *y -= WorkWindowRect.Top; +} + +//--------------------------------------------------------------- + +void SetPalette(UBYTE *the_palette) +{ + ULONG c0; + + + for(c0=0;c0<256;c0++) + { + CurrentPalette[c0*3+0] = the_palette[(c0*3)+0]; + CurrentPalette[c0*3+1] = the_palette[(c0*3)+1]; + CurrentPalette[c0*3+2] = the_palette[(c0*3)+2]; + } +} + +//--------------------------------------------------------------- + +SLONG FindColour(UBYTE *the_palette,SLONG r,SLONG g,SLONG b) +{ + SLONG found = -1; + + if(r>255) + r=255; + if(g>255) + g=255; + if(b>255) + b=255; + + switch(WorkScreenDepth) + { + case 1: + { + + SLONG dist = 0x7fffffff, + c0, + dist2, + tr, + tg, + tb; + + + for(c0=0;c0<256;c0++) + { + tr = *the_palette++; + tg = *the_palette++; + tb = *the_palette++; + + tr -= r; + tg -= g; + tb -= b; + + dist2= abs(tr*tr)+abs(tg*tg)+abs(tb*tb); + if(dist2>3)<<11)|((g>>2)<<5)|(b>>3)); + break; + case 4: + found=((r<<16)|(g<<8)|(b)); + break; + + } + return(found); +} + +//--------------------------------------------------------------- + +#endif //#ifndef TARGET_DC + + + diff --git a/fallen/DDLibrary/Source/MFX_DC.cpp b/fallen/DDLibrary/Source/MFX_DC.cpp new file mode 100644 index 0000000..c23b1e2 --- /dev/null +++ b/fallen/DDLibrary/Source/MFX_DC.cpp @@ -0,0 +1,845 @@ +#include "game.h" +#include "dclowlevel.h" +#include "sound_id.h" +#include "matrix.h" +#include "mfx.h" + + + + +#ifdef DEBUG +#define SHARON TRACE +#else +#define SHARON sizeof +#endif + + +// So that we can disable sounds during pause. +extern SLONG GAMEMENU_menu_type; +#define GAMEMENU_MENU_TYPE_PAUSE 1 + + +// +// All our sounds. 'copy_of' is the index of the MFX_DC_Sound that +// 'own's' the DCLL_Sound *ds (the one that allocated it first) +// + +typedef struct +{ + Thing *thing; + UWORD channel_id; + UWORD copy_of; // copy_of == the index of this sound if it's not a copy of another sound. + DCLL_Sound *ds; + +} MFX_DC_Sound; + +#define MFX_DC_MAX_SOUNDS 1024 + +MFX_DC_Sound MFX_DC_sound[MFX_DC_MAX_SOUNDS]; + + +// +// The amount of sound memory needed. +// + +SLONG MFX_DC_sound_memory; +SLONG MFX_DC_11khz_saving; +SLONG MFX_DC_num_duplicates; +SLONG MFX_DC_duplicate_saving; +SLONG MFX_DC_large_file_saving; + + +extern SLONG DCLL_bytes_of_sound_memory_used; + + +void MFX_DC_init(void) +{ + SLONG i; + + SLONG biggest_sample_index = 0; + SLONG biggest_sample_size = 0; + + CBYTE fname[256]; + + SHARON ( "Entered MFX_DC_init\n" ); + + + // + // Initialise the DC sound system. + // + + DCLL_init(); + + // + // Load all the sound fx. + // + + +#define GUESS_HOW_MANY_SOUNDS_TO_LOAD 548 +#define HOW_MUCH_COMPLETION_BAR_WE_GET 160 +#define HOW_MANY_UPDATES 20 + int iNumWavsLoaded = 0; + int iNumWavsToDoNextChunk = GUESS_HOW_MANY_SOUNDS_TO_LOAD / HOW_MANY_UPDATES; + int iCurChunkVal = 0; + + + MFX_DC_sound_memory = 0; + + for (i = 0; sound_list[i][0] != '!'; i++) + { + ASSERT(WITHIN(i, 0, MFX_DC_MAX_SOUNDS - 1)); + + iNumWavsLoaded++; + if ( iNumWavsLoaded > iNumWavsToDoNextChunk ) + { + // Do an update of the status bar. + iNumWavsToDoNextChunk += GUESS_HOW_MANY_SOUNDS_TO_LOAD / HOW_MANY_UPDATES; + iCurChunkVal += HOW_MUCH_COMPLETION_BAR_WE_GET / HOW_MANY_UPDATES; +extern void ATTRACT_loadscreen_draw(SLONG completion); + ATTRACT_loadscreen_draw ( iCurChunkVal ); + } + + + if (i > 0) + { + // + // If this name is too similar to the previous filename, assume + // the sounds are similar enough so that we can just use the + // previous sound... + // + + CBYTE *ch1 = sound_list[i - 0]; + CBYTE *ch2 = sound_list[i - 1]; + + SLONG differences = 0; + + while(1) + { + if (*ch1 == '.' && *ch2 == '.') + { + break; + } + + if (*ch1 != *ch2) + { + differences += 1; + + if (differences > 2) + { + break; + } + } + + if (*ch1 != '.') ch1++; + if (*ch2 != '.') ch2++; + } + + if (differences <= 2) + { + // + // Similar enough... + // + + MFX_DC_sound[i].ds = MFX_DC_sound[i - 1].ds; + MFX_DC_sound[i].copy_of = MFX_DC_sound[i - 1].copy_of; + + MFX_DC_num_duplicates += 1; + MFX_DC_duplicate_saving += DCLL_bytes_of_sound_memory_used; + + continue; + } + } + + #ifdef TARGET_DC + sprintf(fname, "Data\\Sfx\\1622DC\\%s", sound_list[i]); + #else + sprintf(fname, "Data\\Sfx\\1622\\%s", sound_list[i]); + #endif + + SHARON ( "Loading sound <%s>\n", fname ); + + MFX_DC_sound[i].ds = DCLL_load_sound(fname); + MFX_DC_sound[i].copy_of = i; + + if (DCLL_bytes_of_sound_memory_used > 128 * 1024) + { + // + // This sound won't work on the DC! + // + + SHARON("WONT WORK ON DC! - \"%s\"\n", fname); + } + + if (DCLL_bytes_of_sound_memory_used > 300 * 1024) + { + ASSERT(0); + + // + // Dont load any samples that are too big... + // + + DCLL_free_sound(MFX_DC_sound[i].ds); + + MFX_DC_sound[i].ds = NULL; + + { + CBYTE str[500]; + + sprintf(str, "Not loading huge sound file (%4d k) \"%s\"\n", DCLL_bytes_of_sound_memory_used >> 10, sound_list[i]); + ASSERT ( FALSE ); + SHARON ( str ); + } + + MFX_DC_large_file_saving += DCLL_bytes_of_sound_memory_used; + DCLL_bytes_of_sound_memory_used = 0; + } + else + { + SLONG j; + + CBYTE *words_for_11khz[] = + { + "Suspension", + "Scrape", + "Balrog", + "Footstep", + "PAIN", + "TAUNT", + "darci\\", + "roper\\" + "bthug1\\", + "wthug1\\", + "wthug2\\", + "cop\\COP", + "misc\\", + "Barrel", + "Ambience", + "CarX", + "!" + }; + + // + // Shall we pretend this file is 11025 khz? + // + + for (j = 0; words_for_11khz[j][0] != '!'; j++) + { + if (strstr(sound_list[i], words_for_11khz[j])) + { + DCLL_bytes_of_sound_memory_used >>= 1; + MFX_DC_11khz_saving += DCLL_bytes_of_sound_memory_used; + + break; + } + } + + MFX_DC_sound_memory += DCLL_bytes_of_sound_memory_used; + } + + if (DCLL_bytes_of_sound_memory_used > biggest_sample_size) + { + biggest_sample_size = DCLL_bytes_of_sound_memory_used; + biggest_sample_index = i; + } + } + + SHARON ( "Done MFX_DC_init\n" ); + +} + +// +// Stops all sounds with the given channel_id (apart from the given wave) +// + +void MFX_stop_channel_id(UWORD channel_id, ULONG wave) +{ + SLONG i; + + MFX_DC_Sound *ms; + + if (channel_id == 0) + { + return; + } + + for (i = 0; i < MFX_DC_MAX_SOUNDS; i++) + { + ms = &MFX_DC_sound[i]; + + if (ms->channel_id == channel_id && (ULONG)i != wave) + { + ms->thing = NULL; + ms->channel_id = 0; + + DCLL_stop_sound(ms->ds); + } + } +} + +void MFX_free_sound(SLONG wave) +{ + MFX_DC_Sound *ms; + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + if (ms->ds) + { + DCLL_free_sound(ms->ds); + + ms->ds = NULL; + ms->channel_id = 0; + ms->thing = 0; + + // + // If any sounds are copies of this sound, we must free them too. + // + + SLONG i; + + for (i = 0; sound_list[i][0] != '!'; i++) + { + ASSERT(WITHIN(i, 0, MFX_DC_MAX_SOUNDS - 1)); + + if (i == wave) + { + continue; + } + + if (MFX_DC_sound[i].copy_of == wave) + { + MFX_DC_sound[i].ds = NULL; + } + } + } +} + +void MFX_load_sound(SLONG wave) +{ + MFX_DC_Sound *ms; + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + if (ms->ds) + { + // + // Already loaded! + // + + return; + } + else + { + // + // If this sound is a copy of another one, just use the copy... + // + + if (ms->copy_of && ms->copy_of != wave) + { + ASSERT(WITHIN(ms->copy_of, 0, MFX_DC_MAX_SOUNDS - 1)); + + MFX_DC_Sound *ms_copy = &MFX_DC_sound[ms->copy_of]; + + if (ms_copy->ds) + { + ms->ds = ms_copy->ds; + + return; + } + } + + CBYTE fname[256]; + + #ifdef TARGET_DC + sprintf(fname, "Data\\Sfx\\1622DC\\%s", sound_list[wave]); + #else + sprintf(fname, "Data\\Sfx\\1622\\%s", sound_list[wave]); + #endif + + ms->ds = DCLL_load_sound(fname); + + if (ms->copy_of && ms->copy_of != wave) + { + // + // Make sure the 'owner' of this sound has a copy of the sound too... + // + + ASSERT(WITHIN(ms->copy_of, 0, MFX_DC_MAX_SOUNDS - 1)); + + MFX_DC_Sound *ms_copy = &MFX_DC_sound[ms->copy_of]; + + ASSERT(ms_copy->ds == NULL); + + ms_copy->ds = ms->ds; + } + } +} + + + +// ======================================================== +// +// IMPLEMENT THE MUCKYFOOT SOUND SYSTEM +// +// ======================================================== + +SLONG MFX_DC_vol_fx = 127; // From 0 to 127 +SLONG MFX_DC_vol_amb = 127; // From 0 to 127 +SLONG MFX_DC_vol_mus = 127; // From 0 to 127 + +SLONG MFX_DC_listener_x; +SLONG MFX_DC_listener_y; +SLONG MFX_DC_listener_z; + +void MFX_get_volumes(SLONG *fx, SLONG *amb, SLONG *mus) +{ + *fx = MFX_DC_vol_fx; + *amb = MFX_DC_vol_amb; + *mus = MFX_DC_vol_mus; +} + +void MFX_set_volumes(SLONG fx, SLONG amb, SLONG mus) +{ + SATURATE(fx, 0, 127); + SATURATE(amb, 0, 127); + SATURATE(mus, 0, 127); + + MFX_DC_vol_fx = fx; + MFX_DC_vol_amb = amb; + MFX_DC_vol_mus = mus; + + DCLL_stream_set_volume_range(float(mus) * (1.0F / 127.0F)); + + // + // Set the volumes of the various DCLL_sounds...? + // + + // ... +} + +extern SLONG DCLL_still_playing(DCLL_Sound *ds); + +void MFX_play_xyz(UWORD channel_id, ULONG wave, ULONG flags, SLONG x, SLONG y, SLONG z) +{ + MFX_DC_Sound *ms; + + if ( GAMEMENU_menu_type == GAMEMENU_MENU_TYPE_PAUSE ) + { + // Don't play sounds during pause. + return; + } + + SLONG dx = abs(x - MFX_DC_listener_x); + SLONG dy = abs(y - MFX_DC_listener_y); + SLONG dz = abs(z - MFX_DC_listener_z); + + SLONG dist = dx + dy + dz >> 8; + SLONG vol = 256 - (256 * dist >> 13); + + if (vol <= 0) + { +// if(flags & MFX_LOOPED) +// vol=1; //play it quiet because we might be going to fade it in etc +// else + return; + } + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + if(ms->channel_id==channel_id) //MikeD + { + if (!(flags & MFX_REPLACE)) + { + // + // not replace so dont allow this sound + // + if(DCLL_still_playing(ms->ds)) + return; + } + } + + ms->thing = NULL; + ms->channel_id = channel_id; + + + DCLL_set_volume(ms->ds, float(MFX_DC_vol_fx * vol >> 8) * (1.0F / 127.0F)); + DCLL_2d_play_sound(ms->ds, ((flags & MFX_QUEUED) ? 0 : DCLL_FLAG_INTERRUPT) | ((flags & MFX_LOOPED) ? DCLL_FLAG_LOOP : 0)); + + /* + + DCLL_3d_play_sound( + ms->ds, + float(x >> 8), + float(y >> 8), + float(z >> 8), + ((flags & MFX_QUEUED) ? 0 : DCLL_FLAG_INTERRUPT) | ((flags & MFX_LOOPED) ? DCLL_FLAG_LOOP : 0)); + + */ +} + + + + +void MFX_play_thing(UWORD channel_id, ULONG wave, ULONG flags, Thing* p) +{ + MFX_DC_Sound *ms; + + if ( GAMEMENU_menu_type == GAMEMENU_MENU_TYPE_PAUSE ) + { + // Don't play sounds during pause. + return; + } + + SLONG dx = abs(p->WorldPos.X - MFX_DC_listener_x); + SLONG dy = abs(p->WorldPos.Y - MFX_DC_listener_y); + SLONG dz = abs(p->WorldPos.Z - MFX_DC_listener_z); + + SLONG dist = dx + dy + dz >> 8; + SLONG vol = 256 - (256 * dist >> 13); + + if (vol <= 0 ) + { +// if(flags & MFX_LOOPED) +// vol=1; //play it quiet because we might be going to fade it in etc +// else + return; + } + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + DCLL_set_volume(ms->ds, float(MFX_DC_vol_fx * vol >> 8) * (1.0F / 127.0F)); + if(ms->channel_id==channel_id && ms->thing==p) //MikeD + { + if (!(flags & MFX_REPLACE)) + { + // + // not replace so dont allow this sound + // + if(DCLL_still_playing(ms->ds)) + return; + } + } + + + ms->thing = p; + ms->channel_id = channel_id; + + + DCLL_2d_play_sound(ms->ds, ((flags & MFX_QUEUED) ? 0 : DCLL_FLAG_INTERRUPT) | ((flags & MFX_LOOPED) ? DCLL_FLAG_LOOP : 0)); + + /* + + DCLL_3d_play_sound( + ms->ds, + float(p->WorldPos.X >> 8), + float(p->WorldPos.Y >> 8), + float(p->WorldPos.Z >> 8), + ((flags & MFX_QUEUED) ? 0 : DCLL_FLAG_INTERRUPT) | ((flags & MFX_LOOPED) ? DCLL_FLAG_LOOP : 0)); + + */ +} + +void MFX_play_at_stream_volume(UWORD channel_id, ULONG wave, ULONG flags) +{ + MFX_DC_Sound *ms; + + if ( GAMEMENU_menu_type == GAMEMENU_MENU_TYPE_PAUSE ) + { + // Don't play sounds during pause. + return; + } + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + ms->thing = NULL; + ms->channel_id = channel_id; + + // + // Ambient => 2D... + // + + DCLL_set_volume(ms->ds, float(MFX_DC_vol_mus) * (1.0F / 127.0F)); + + DCLL_2d_play_sound(ms->ds, ((flags & MFX_QUEUED) ? 0 : DCLL_FLAG_INTERRUPT) | ((flags & MFX_LOOPED) ? DCLL_FLAG_LOOP : 0)); +} + + + +void MFX_play_ambient(UWORD channel_id, ULONG wave, ULONG flags) +{ + MFX_DC_Sound *ms; + + if ( GAMEMENU_menu_type == GAMEMENU_MENU_TYPE_PAUSE ) + { + // Don't play sounds during pause. + return; + } + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + ms->thing = NULL; + ms->channel_id = channel_id; + + // + // Ambient => 2D... + // + + DCLL_set_volume(ms->ds, float(MFX_DC_vol_amb) * (1.0F / 127.0F)); + + DCLL_2d_play_sound(ms->ds, ((flags & MFX_QUEUED) ? 0 : DCLL_FLAG_INTERRUPT) | ((flags & MFX_LOOPED) ? DCLL_FLAG_LOOP : 0)); +} + +UBYTE MFX_play_stereo(UWORD channel_id, ULONG wave, ULONG flags) +{ + // + // Stereo => Same as ambient but at FX volume???? + // + + MFX_DC_Sound *ms; + + if ( GAMEMENU_menu_type == GAMEMENU_MENU_TYPE_PAUSE ) + { + // Don't play sounds during pause. + return 0; + } + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + ms->thing = NULL; + ms->channel_id = channel_id; + + // + // Ambient => 2D... + // + + DCLL_set_volume(ms->ds, float(MFX_DC_vol_fx) * (1.0F / 127.0F)); + + DCLL_2d_play_sound(ms->ds, ((flags & MFX_QUEUED) ? 0 : DCLL_FLAG_INTERRUPT) | ((flags & MFX_LOOPED) ? DCLL_FLAG_LOOP : 0)); + + return 0; +} + +void MFX_stop(SLONG channel_id, ULONG wave) +{ + SLONG i; + + MFX_DC_Sound *ms; + + if ( ( wave == MFX_WAVE_ALL ) || ( wave == MFX_WAVE_ALMOST_ALL ) ) + { + for (i = 0; i < MFX_DC_MAX_SOUNDS - 1; i++) + { + ms = &MFX_DC_sound[i]; + + ms->thing = NULL; + ms->channel_id = 0; + + DCLL_stop_sound(ms->ds); + } + + // And stop the streaming sound. + DCLL_stream_stop(); + + if ( wave != MFX_WAVE_ALMOST_ALL ) + { + DCLL_memstream_stop(); + } + + return; + } + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + ms->thing = NULL; + + DCLL_stop_sound(ms->ds); +} + +void MFX_stop_attached(Thing *p) +{ + SLONG i; + + MFX_DC_Sound *ms; + + // + // Look for the sound attached to this thing. + // + + for (i = 0; i < MFX_DC_MAX_SOUNDS; i++) + { + ms = &MFX_DC_sound[i]; + + if (ms->thing == p) + { + ms->thing = NULL; + ms->channel_id = 0; + + DCLL_stop_sound(ms->ds); + + return; + } + } +} + + +// +// Ignore these for now! +// + +void MFX_set_pitch(UWORD channel_id, ULONG wave, SLONG pitchbend) +{ +} + +void MFX_set_gain(UWORD channel_id, ULONG wave, UBYTE gain) +{ + MFX_DC_Sound *ms; + + ASSERT(WITHIN(wave, 0, MFX_DC_MAX_SOUNDS - 1)); + + ms = &MFX_DC_sound[wave]; + + DCLL_set_volume(ms->ds, float(gain) * (1.0F / 255.0F)); +} + +void MFX_set_queue_gain(UWORD channel_id, ULONG wave, UBYTE gain) +{ +} + + +void MFX_set_listener(SLONG x, SLONG y, SLONG z, SLONG heading, SLONG roll, SLONG pitch) +{ + float matrix[9]; + float rad_yaw; + float rad_pitch; + float rad_roll; + + MFX_DC_listener_x = x; + MFX_DC_listener_y = y; + MFX_DC_listener_z = z; + + rad_yaw = float(heading) * 2.0F * PI / 2048.0F; + rad_pitch = float(roll ) * 2.0F * PI / 2048.0F; + rad_roll = float(pitch ) * 2.0F * PI / 2048.0F; + + MATRIX_calc( + matrix, + rad_yaw, + rad_pitch, + rad_roll); + + DCLL_3d_set_listener( + float(x >> 8), + float(y >> 8), + float(z >> 8), + matrix); +} + + +void MFX_load_wave_list(CBYTE *names[]) +{ +} + +void MFX_free_wave_list() +{ +} + + +UWORD MFX_get_wave(UWORD channel_id, UBYTE index) +{ + return 0; +} + +void MFX_render() +{ +} + + +// +// Streaming sound stuff... +// + +SLONG MFX_QUICK_play_id = 1; +SLONG last_started=0; + +SLONG MFX_QUICK_play(CBYTE *str, SLONG loop, SLONG x, SLONG y, SLONG z) +{ + + if ( GAMEMENU_menu_type == GAMEMENU_MENU_TYPE_PAUSE ) + { + // Don't play sounds during pause. + return NULL; + } + + if (DCLL_stream_play(str, loop)) + { + last_started=timeGetTime(); + + if (!loop) + { + // Assume it's speech. + DCLL_stream_volume( (float)MFX_DC_vol_fx * ( 1.0f / 127.0f ) ); + } + else + { + // Assume it's music. + DCLL_stream_volume( (float)MFX_DC_vol_mus * ( 1.0f / 127.0f ) ); + } + + return ++MFX_QUICK_play_id; + } + else + { + return NULL; + } +} + +void MFX_QUICK_wait() +{ + DCLL_stream_wait(); +} + +void MFX_QUICK_stop ( bool bAllowMemstream ) +{ + DCLL_stream_stop(); + if ( !bAllowMemstream ) + { + DCLL_memstream_stop(); + } +// ASSERT(!DCLL_stream_is_playing()); +} + +SLONG MFX_QUICK_still_playing() +{ + SLONG ret; + + ret=DCLL_stream_is_playing(); + if(ret==0) + { + // + // It's stopped or maybe it never started + // + if((timeGetTime()-last_started)<8000) //8 seconds + { + ret=1; + } + } + else + last_started=0; //it has definatly started so dont let the 8 second delay thing happen + return(ret); +} + diff --git a/fallen/DDLibrary/Source/MFX_Miles.cpp b/fallen/DDLibrary/Source/MFX_Miles.cpp new file mode 100644 index 0000000..8213c26 --- /dev/null +++ b/fallen/DDLibrary/Source/MFX_Miles.cpp @@ -0,0 +1,2090 @@ + + +#if 0 + +// MFX_Miles.cpp +// +// Miles Sound System + +// Making it asynchronous: +// +// 1. Keep everything the same. vptr->smp points to sample, sptr->dptr points to data, only "pending" is marked for sample +// 2. When IO completes, go through voices and trigger/modify according to data in vptr + +#define ASYNC_FILE_IO 1 +#define TALK_3D 0 + +#include "snd_type.h" +#include "c:\fallen\headers\demo.h" + +#include "MFX.h" +#include "MFX_Miles.h" + +#include "c:\fallen\headers\fc.h" +#include "c:\fallen\headers\env.h" +#include "c:\fallen\headers\xlat_str.h" +#include "c:\fallen\headers\demo.h" +#include "c:\fallen\ddengine\headers\poly.h" +#include "resource.h" +#ifndef TARGET_DC +#include +#endif + +#include "drive.h" + +#if ASYNC_FILE_IO +#include "asyncfile2.h" +#endif + +#ifdef DODGYPSXIFY +BOOL dodgy_psx_mode=0; +#endif + + + + + +#ifdef NO_SOUND +// +// GET NO_SOUND COMPILING! +// + +SLONG MFX_QUICK_play(char *c, SLONG a, SLONG b, SLONG d) +{ + return 0; +} + +void MilesTerm(void) +{ + return; +} + + +#endif + + + + +#ifdef M_SOUND + +#define COORDINATE_UNITS float(1.0 / 256.0) // 1 tile ~= 1 meter + +HDIGDRIVER drv = NULL; + +static MFX_Voice Voices[MAX_VOICE]; +static MFX_QWave QWaves[MAX_QWAVE]; +static MFX_QWave* QFree; // first free queue elt. (NEVER NULL - we waste one element) +static MFX_QWave* QFreeLast; // last free queue elt. + +static MFX_Sample Samples[MAX_SAMPLE]; +static MFX_Sample TalkSample; // for talk +static int NumSamples; +static MFX_Sample LRU; // sentinel for LRU dllist + +static MFX_3D Providers[MAX_PROVIDER]; +static MFX_3D FallbackProvider; +static int CurProvider; +static int IsEAX; +static int NumProviders; +static HPROVIDER Provider = NULL; +static H3DPOBJECT Listener = NULL; +static H3DPOBJECT FallbackListener = NULL; +static UBYTE DoMilesDialog = 1; +static const float MinDist = 512; // min distance for 3D provider +static const float MaxDist = (64 << 8); // max distance for 3D provider +static float Gain2D = 1.0; // gain for 2D voices +static float LX,LY,LZ; // listener coords + +static float Volumes[3]; // volumes for each SampleType + +static int Num3DVoices = 0; +static int Max3DVoices = 0; +static int AllocatedRAM = 0; + +static char* PathName(char *fname); +static void DumpInfo(); +static void InitVoices(); +static void LoadWaveFile(MFX_Sample* sptr); +static void LoadTalkFile(char* filename); +#if ASYNC_FILE_IO +static void LoadWaveFileAsync(MFX_Sample* sptr); +#endif +static void LoadWaveFileFinished(MFX_Sample* sptr); +static void UnloadWaveFile(MFX_Sample* sptr); +static void UnloadTalkFile(); +static void MilesDialog(HINSTANCE hInst, HWND hWnd); +static void FinishLoading(MFX_Voice* vptr); + +static void PlayVoice(MFX_Voice* vptr); +static void MoveVoice(MFX_Voice* vptr); +static void SetVoiceRate(MFX_Voice* vptr, float mult); +static void SetVoiceGain(MFX_Voice* vptr, float gain); + +extern CBYTE* sound_list[]; + + +//---------------------------------------------------------------------------- +// DODGY PSXIFIER (sorry eddie :} ) +// +// Yeah, sorry is right - why does this mess have to be in my lovely file? +// Check out File/New on the VC menu +// + +#ifdef DODGYPSXIFY + +BOOL dodgy_psx_info_loaded=0; +BOOL dodgy_psx_info[1024]; + +void LoadDodgyPSXInfo() { + SLONG i=0; + dodgy_psx_info_loaded=1; + dodgy_psx_mode=ENV_get_value_number("dodgy_psx_sound",0,"Audio"); + if (!dodgy_psx_mode) return; + ZeroMemory(dodgy_psx_info,sizeof(dodgy_psx_info)); + while (strcmp(sound_list[i],"!")) { + dodgy_psx_info[i]=GetPrivateProfileInt("PSXSound",sound_list[i],0,"c:\\fallen\\psxsound.ini"); + i++; + } +} + +inline BOOL AvailableOnPSX(SLONG i) { + if (!dodgy_psx_info_loaded) LoadDodgyPSXInfo(); + if (!dodgy_psx_mode) return 1; + return dodgy_psx_info[i]; +} + +#define PSXCheck(i) { if (!AvailableOnPSX(i)) return; } +#define PSXCheck2(i) { if (!AvailableOnPSX(i)) return 0; } + +#else + +#define PSXCheck(i) ; +#define PSXCheck2(i) ; + +#endif + +//---------------------------------------------------------------------------- + + +// MilesInit +// +// init the Miles crap + +void MilesInit(HINSTANCE hInst, HWND hWnd) +{ + if (drv) return; + + AIL_set_preference(DIG_MIXER_CHANNELS, MAX_VOICE); + AIL_set_preference(DIG_DEFAULT_VOLUME, 127); + if (!AIL_quick_startup(1,0,44100,16,2)) return; + AIL_quick_handles(&drv, NULL, NULL); + +#if ASYNC_FILE_IO + InitAsyncFile(); +#endif + + InitVoices(); + + // initialize Samples[] + LRU.prev_lru = LRU.next_lru = &LRU; + AllocatedRAM = 0; + + NumSamples = 0; + CBYTE buf[_MAX_PATH]; + CBYTE** names = sound_list; + MFX_Sample* sptr = Samples; + + while (strcmp(names[0], "!")) + { + sptr->prev_lru = NULL; + sptr->next_lru = NULL; + sptr->fname = NULL; + sptr->dptr = NULL; + sptr->is3D = true; + sptr->rate = 0; + sptr->stream = false; + sptr->size = 0; + sptr->type = SMP_Effect; + sptr->linscale = 1.0; + sptr->loading = false; + + if (stricmp("null.wav", names[0])) + { + FILE* fd = MF_Fopen(PathName(names[0]), "rb"); + if (fd) + { + sptr->fname = names[0]; + sptr->dptr = NULL; + if (((!strnicmp(names[0], "music",5))||(!strnicmp(names[0], "generalmusic",12)))&&(!strstr(names[0],"Club1"))&&(!strstr(names[0],"Acid"))) + { + sptr->is3D = false; + sptr->type = SMP_Music; + } + sptr->rate = 0; + sptr->stream = false; + + fseek(fd, 0, SEEK_END); + sptr->size = ftell(fd); + MF_Fclose(fd); + + if (sptr->size > MIN_STREAM_SIZE) + { + sptr->stream = true; + sptr->is3D = false; + } + +// TRACE("FOUND: %s (%s)\n", sptr->fname, PathName(sptr->fname)); + } + else + { + TRACE("NOT FOUND: %s (%s)\n", names[0], PathName(names[0])); + } + } + + NumSamples++; + + if (sptr->fname) + { + int gain = GetPrivateProfileInt("PowerLevels", sptr->fname, 0, "data\\sfx\\powerlvl.ini"); + if (gain) + { + gain *= 4; + SetPower(sptr-Samples, float(gain)); + TRACE("Setting %s gain to %d dB\n",sptr->fname,gain); + } + } + + sptr++; + names++; + } + + ASSERT(NumSamples <= MAX_SAMPLE); + + sptr = &TalkSample; + + sptr->prev_lru = NULL; + sptr->next_lru = NULL; + sptr->fname = NULL; + sptr->dptr = NULL; + sptr->is3D = TALK_3D ? true : false; + sptr->rate = 0; + sptr->stream = false; + sptr->size = 0; + sptr->type = SMP_Effect; + sptr->linscale = 1.0; + sptr->loading = false; + + // get 3D providers list + HPROENUM next = HPROENUM_FIRST; + MFX_3D* prov = &Providers[0]; + int best = -1; + int sbest = 0; + + FallbackProvider.hnd = NULL; + + while ((NumProviders < MAX_PROVIDER) && AIL_enumerate_3D_providers(&next, &prov->hnd, &prov->name)) + { + // try and open this + M3DRESULT res = AIL_open_3D_provider(prov->hnd); + if (res == M3D_NOERR) + { + TRACE("Found provider: %s\n", prov->name); + AIL_close_3D_provider(prov->hnd); + + int score; + if (!strcmp(prov->name, "Aureal A3D Interactive(TM)")) score = 30; + else if (!strcmp(prov->name, "Microsoft DirectSound3D with Creative Labs EAX(TM)")) score = 100; + else if (!strcmp(prov->name, "Microsoft DirectSound3D hardware support")) score = 50; + else if (!strcmp(prov->name, "Microsoft DirectSound3D software emulation")) score = 20; + else if (!strcmp(prov->name, "RSX 3D Audio from RAD Game Tools")) score = 10; + else score = 5; + + if (score > sbest) + { + best = NumProviders; + sbest = score; + } + + if (!strcmp(prov->name, "Miles Fast 2D Positional Audio")) + { + // store fallback 2D provider + FallbackProvider = *prov; + } + + prov++; + NumProviders++; + } + else + { + TRACE("Can't use provider: %s\n", prov->name); + } + } + + CurProvider = best; + + // create fallback 3D provider + if (FallbackProvider.hnd) + { + if (AIL_open_3D_provider(FallbackProvider.hnd) == M3D_NOERR) + { + TRACE("Opened fallback provider %s\n", FallbackProvider.name); + FallbackListener = AIL_open_3D_listener(FallbackProvider.hnd); + } + else + { + TRACE("Couldn't open fallback provider\n"); + FallbackProvider.hnd = NULL; + } + } + else + { + TRACE("No fallback provider\n"); + } + + // read config file + DoMilesDialog = ENV_get_value_number("run_sound_dialog", 1, "Audio"); + char* str = ENV_get_value_string("3D_sound_driver", "Audio"); + + if (str) + { + for (int ii = 0; ii < NumProviders; ii++) + { + if (!stricmp(Providers[ii].name, str)) CurProvider = ii; + } + } + + Volumes[SMP_Ambient] = float(ENV_get_value_number("ambient_volume", 127, "Audio")) / 127; + Volumes[SMP_Music] = float(ENV_get_value_number("music_volume", 127, "Audio")) / 127; + Volumes[SMP_Effect] = float(ENV_get_value_number("fx_volume", 127, "Audio")) / 127; + + /* + + // + // WAIT FOR THE GRAPHICS DIALOG BOX TO FINISH OFF INITIALISING US! + // + // It calls init_my_dialog() and my_dialog_over()... + // + // + + // do dialog + if (DoMilesDialog) + { + MilesDialog(hInst, hWnd); + ENV_set_value_number("run_sound_dialog", DoMilesDialog, "Audio"); + } + + // set 3D provider + Set3DProvider(CurProvider); + + */ +} + +// MilesTerm +// +// term the Miles crap + +void MilesTerm() +{ + if (!drv) return; + + DumpInfo(); + + MFX_free_wave_list(); + + // free waves + for (int ii = 0; ii < NumSamples; ii++) + { + UnloadWaveFile(&Samples[ii]); + } + NumSamples = 0; + + UnloadTalkFile(); + + // free providers & listener + Set3DProvider(-1); + if (FallbackListener) + { + AIL_close_3D_listener(FallbackListener); + FallbackListener = NULL; + } + if (FallbackProvider.hnd) + { + AIL_close_3D_provider(FallbackProvider.hnd); + FallbackProvider.hnd = NULL; + } + + AIL_quick_shutdown(); + drv = NULL; + +#if ASYNC_FILE_IO + TermAsyncFile(); +#endif +} + +// GetMilesDriver +// +// BinkClient calls this to find the Miles driver for BINK + +HDIGDRIVER GetMilesDriver() +{ + return drv; +} + +// PathName +// +// get a sample's full pathname + +static char* PathName(char* fname) +{ + CBYTE buf[MAX_PATH]; + static CBYTE pathname[MAX_PATH]; + + if (strchr(fname,'-')) // usefully, all the taunts etc have a - in them, and none of the other sounds do... bonus! + { + CHAR *ptr = strrchr(fname,'\\')+1; + sprintf(buf,"talk2\\misc\\%s",ptr); + strcpy(pathname, GetSFXPath()); + strcat(pathname, buf); + return pathname; + } + else + { + sprintf(buf, "data\\sfx\\1622\\%s", fname); + if (!strnicmp(fname, "music", 5)) + { + if (!MUSIC_WORLD) MUSIC_WORLD = 1; +#ifdef VERSION_DEMO + MUSIC_WORLD = 1; +#endif + buf[19] = '0' + (MUSIC_WORLD / 10); + buf[20] = '0' + (MUSIC_WORLD % 10); + } + } + + strcpy(pathname, GetSFXPath()); + strcat(pathname, buf); + + return pathname; +} + +// SetLinScale +// +// set a sample's linear scale + +void SetLinScale(SLONG wave, float linscale) +{ + if ((wave >= 0) && (wave < NumSamples)) + { + Samples[wave].linscale = linscale; + } +} + +// SetPower +// +// set a sample's power in dB + +void SetPower(SLONG wave, float dB) +{ + SetLinScale(wave, float(exp(log(10) * dB / 20))); +} + +// DumpInfo +// +// dump info about loaded sounds + +static void DumpInfo() +{ +#ifdef _DEBUG + FILE* fd = MF_Fopen("c:\\soundinfo.txt", "w"); + if (fd) + { + int loaded = 0; + for (int ii = 0; ii < NumSamples; ii++) + { + fprintf(fd, "%d : %s : %d K : %s\n", ii, Samples[ii].fname, Samples[ii].size >> 10, Samples[ii].dptr ? "LOADED" : "unloaded"); + if (Samples[ii].dptr) loaded++; + } + fprintf(fd, "-------\nTotal %d samples, (%d loaded = %d K)\n\n", NumSamples, loaded, AllocatedRAM >> 10); + fprintf(fd, "LRU queue:\n\n"); + for (MFX_Sample* sptr = LRU.next_lru; sptr != &LRU; sptr = sptr->next_lru) + { + fprintf(fd, "%s (%d)\n", sptr->fname, sptr->usecount); + } + MF_Fclose(fd); + } +#endif +} + +// Get3DProviderList +// +// get the list of providers + +int Get3DProviderList(MFX_3D** prov) +{ + *prov = &Providers[0]; + return NumProviders; +} + +// Get3DProvider +// +// get the 3D provider + +int Get3DProvider() +{ + return CurProvider; +} + +// Set3DProvider +// +// set a provider + +void Set3DProvider(int ix) +{ + if (!drv) return; + + if (Listener) + { + AIL_close_3D_listener(Listener); + } + Listener = NULL; + + if (Provider) + { + MFX_stop(MFX_CHANNEL_ALL, MFX_WAVE_ALL); + AIL_close_3D_provider(Provider); + } + Provider = NULL; + + if ((ix >= 0) && (ix < NumProviders)) + { + CurProvider = ix; + + if (Providers[ix].hnd == FallbackProvider.hnd) + { + // only use fallback provider + IsEAX = false; + } + else if (AIL_open_3D_provider(Providers[ix].hnd) == M3D_NOERR) + { + Provider = Providers[ix].hnd; + TRACE("Selected 3D provider: %s\n", Providers[ix].name); + Listener = AIL_open_3D_listener(Provider); + + IsEAX = !strcmp(Providers[ix].name, "Microsoft DirectSound3D with Creative Labs EAX(TM)"); + } + + if (IsEAX) + { + float level = 0.0; + AIL_set_3D_provider_preference(Provider, "EAX effect volume", &level); + Gain2D = 0.7f; + } + else + { + Gain2D = 1.0; + } + + // write to config + ENV_set_value_string("3D_sound_driver", Providers[ix].name, "Audio"); + } +} + +// InitVoices +// +// initialize the voices and queue + +static void InitVoices() +{ + int ii; + + for (ii = 0; ii < MAX_VOICE; ii++) + { + Voices[ii].id = 0; + Voices[ii].wave = 0; + Voices[ii].flags = 0; + Voices[ii].x = 0; + Voices[ii].y = 0; + Voices[ii].z = 0; + Voices[ii].thing = NULL; + Voices[ii].queue = NULL; + Voices[ii].queuesz = 0; + Voices[ii].smp = NULL; + Voices[ii].h2D = NULL; + Voices[ii].h3D = NULL; + } + + for (ii = 0; ii < MAX_QWAVE; ii++) + { + QWaves[ii].next = &QWaves[ii+1]; + } + QWaves[ii-1].next = NULL; + QFree = &QWaves[0]; + QFreeLast = &QWaves[ii-1]; + + LX = LY = LZ = 0; +} + +// Hash +// +// hash a channel ID to a voice ID + +static inline int Hash(UWORD channel_id) +{ + return (channel_id * 37) & VOICE_MSK; +} + +// FindVoice +// +// find an active voice with the given channel ID and wave # + +static MFX_Voice* FindVoice(UWORD channel_id, ULONG wave) +{ + int offset = Hash(channel_id); + + for (int ii = 0; ii < MAX_VOICE; ii++) + { + int vn = (ii + offset) & VOICE_MSK; + if ((Voices[vn].id == channel_id) && (Voices[vn].wave == wave)) return &Voices[vn]; + } + + return NULL; +} + +// FindFirst +// +// find the first active voice with the given channel ID + +static MFX_Voice* FindFirst(UWORD channel_id) +{ + int offset = Hash(channel_id); + + for (int ii = 0; ii < MAX_VOICE; ii++) + { + int vn = (ii + offset) & VOICE_MSK; + if (Voices[vn].id == channel_id) return &Voices[vn]; + } + + return NULL; +} + +// FindNext +// +// find the next active voice with the same channel ID + +static MFX_Voice* FindNext(MFX_Voice* vptr) +{ + int offset = Hash(vptr->id); + + int ii = ((vptr - Voices) - offset) & VOICE_MSK; + + for (ii++; ii < MAX_VOICE; ii++) + { + int vn = (ii + offset) & VOICE_MSK; + if (Voices[vn].id == vptr->id) return &Voices[vn]; + } + + return NULL; +} + +// FindFree +// +// find a free voice + +static MFX_Voice* FindFree(UWORD channel_id) +{ + int offset = Hash(channel_id); + + for (int ii = 0; ii < MAX_VOICE; ii++) + { + int vn = (ii + offset) & VOICE_MSK; + if (!Voices[vn].smp) return &Voices[vn]; + } + + return NULL; +} + +// FreeVoiceSource +// +// remove a voice's source + +static void FreeVoiceSource(MFX_Voice* vptr) +{ + if (vptr->h2D) + { + vptr->smp->usecount--; + AIL_release_sample_handle(vptr->h2D); + vptr->h2D = NULL; + } + if (vptr->h3D) + { + vptr->smp->usecount--; + AIL_release_3D_sample_handle(vptr->h3D); + vptr->h3D = NULL; + Num3DVoices--; + } + if (vptr->hStream) + { + AIL_close_stream(vptr->hStream); + vptr->hStream = NULL; + } +} + +// FreeVoice +// +// free a voice up + +static void FreeVoice(MFX_Voice* vptr) +{ + if (!vptr) return; + + // remove queue + QFreeLast->next = vptr->queue; + while (QFreeLast->next) QFreeLast = QFreeLast->next; + vptr->queue = NULL; + vptr->queuesz = 0; + + // reset data + FreeVoiceSource(vptr); + + if (vptr->thing) + { + vptr->thing->Flags &= ~FLAGS_HAS_ATTACHED_SOUND; + } + vptr->thing = NULL; + vptr->flags = 0; + vptr->id = 0; + vptr->wave = 0; + vptr->smp = NULL; +} + +// GetVoiceForWave +// +// find a voice slot for the wave + +static MFX_Voice* GetVoiceForWave(UWORD channel_id, ULONG wave, ULONG flags) +{ + // just return a new voice if overlapped + if (flags & MFX_OVERLAP) return FindFree(channel_id); + + MFX_Voice* vptr; + + if (flags & (MFX_QUEUED | MFX_NEVER_OVERLAP)) + { + // find first voice on this channel, if any + vptr = FindFirst(channel_id); + } + else + { + // find voice playing this sample, if any + vptr = FindVoice(channel_id, wave); + } + + if (!vptr) + { + vptr = FindFree(channel_id); + } + else + { + // found a voice - return NULL if not queued but never overlapped (else queue) + if ((flags & (MFX_NEVER_OVERLAP | MFX_QUEUED)) == MFX_NEVER_OVERLAP) return NULL; + } + + return vptr; +} + +// SetupVoiceTalk +// +// setup a talking voice + +static SLONG SetupVoiceTalk(MFX_Voice* vptr, char* filename) +{ + vptr->id = 0; + vptr->wave = NumSamples; + vptr->flags = 0; + vptr->thing = NULL; + vptr->queue = NULL; + vptr->queuesz = 0; + vptr->smp = NULL; + vptr->queuesz = 0; + vptr->smp = NULL; + vptr->playing = false; + vptr->ratemult = 1.0; + vptr->gain = 1.0; + + if (!Volumes[SMP_Effect]) return FALSE; + + LoadTalkFile(filename); + if (!TalkSample.dptr) return FALSE; + + vptr->smp = &TalkSample; + FinishLoading(vptr); + + return TRUE; +} + +// SetupVoice +// +// setup a voice for playback + +static void SetupVoice(MFX_Voice* vptr, UWORD channel_id, ULONG wave, ULONG flags) +{ + vptr->id = channel_id; + vptr->wave = wave; + vptr->flags = flags; + vptr->thing = NULL; + vptr->queue = NULL; + vptr->queuesz = 0; + vptr->smp = NULL; + vptr->playing = false; + vptr->ratemult = 1.0; + vptr->gain = 1.0; + + if (wave >= NumSamples) return; + + MFX_Sample* sptr = &Samples[wave]; + + if ((sptr->type!=SMP_Music)&&(GAME_STATE & (GS_LEVEL_LOST|GS_LEVEL_WON))) return ; // once the level's won or lost, no more sounds + + + float level = Volumes[sptr->type]; + + if (!level) return; + + if (sptr->stream) + { + if (!sptr->fname) return; + vptr->hStream = AIL_open_stream(drv, PathName(sptr->fname), 0); + AIL_set_stream_volume(vptr->hStream, S32(Gain2D * level * 127)); + TRACE("Opened stream %s\n", sptr->fname); + vptr->smp = sptr; + } + else + { + // load the sample + if (!sptr->dptr) + { +#if ASYNC_FILE_IO + LoadWaveFileAsync(sptr); +#else + LoadWaveFile(sptr); +#endif + if (!sptr->dptr) return; + } + + // unlink from LRU queue + if (sptr->prev_lru) + { + sptr->prev_lru->next_lru = sptr->next_lru; + sptr->next_lru->prev_lru = sptr->prev_lru; + } + + // free some stuff if we've got too many loaded + if (AllocatedRAM > MAX_SAMPLE_MEM) + { + MFX_Sample* sptr = LRU.next_lru; + while (sptr != &LRU) + { + MFX_Sample* next = sptr->next_lru; + if (!sptr->usecount) + { + UnloadWaveFile(sptr); + if (AllocatedRAM <= MAX_SAMPLE_MEM) break; + } + sptr = next; + } + } + + // link in at front + sptr->next_lru = &LRU; + sptr->prev_lru = LRU.prev_lru; + sptr->next_lru->prev_lru = sptr; + sptr->prev_lru->next_lru = sptr; + + vptr->smp = sptr; + + if (!sptr->loading) + { + FinishLoading(vptr); + } + } +} + +// FinishLoading +// +// set up voice after sample has loaded + +static void FinishLoading(MFX_Voice* vptr) +{ + MFX_Sample* sptr = vptr->smp; + + if (sptr->is3D) + { + if (Provider) + { + vptr->h3D = AIL_allocate_3D_sample_handle(Provider); + } + + if (!vptr->h3D && FallbackProvider.hnd) + { + vptr->h3D = AIL_allocate_3D_sample_handle(FallbackProvider.hnd); + } + + if (vptr->h3D) + { + sptr->usecount++; + AIL_set_3D_sample_file(vptr->h3D, sptr->dptr); + AIL_set_3D_sample_distances(vptr->h3D, MaxDist * COORDINATE_UNITS * sptr->linscale, MinDist * COORDINATE_UNITS * sptr->linscale, + MaxDist * COORDINATE_UNITS * sptr->linscale, MinDist * COORDINATE_UNITS * sptr->linscale); + AIL_set_3D_sample_volume(vptr->h3D, S32(Volumes[sptr->type] * 127)); + if (IsEAX) + { + float level = 0.0; + AIL_set_3D_sample_preference(vptr->h3D, "EAX sample reverb mix", &level); + } + Num3DVoices++; + if (Num3DVoices > Max3DVoices) Max3DVoices = Num3DVoices; +// TRACE("Setup 3D voice %d for %s - %d in use, max %d\n", vptr - Voices, sptr->fname, Num3DVoices, Max3DVoices); + } + } + + if (!vptr->h3D) + { + // get 2D handle + vptr->h2D = AIL_allocate_file_sample(drv, sptr->dptr, 0); +// TRACE("Setup 2D voice %d for %s\n", vptr - Voices, sptr->fname); + if (vptr->h2D) + { + sptr->usecount++; + AIL_set_sample_volume(vptr->h2D, S32(Gain2D * Volumes[sptr->type] * 127)); + } + } + + MoveVoice(vptr); + if (vptr->ratemult != 1.0) SetVoiceRate(vptr, vptr->ratemult); + if (vptr->gain != 1.0) SetVoiceGain(vptr, vptr->gain); + if (vptr->playing) PlayVoice(vptr); +} + +// PlayVoice +// +// play the voice + +static void PlayVoice(MFX_Voice* vptr) +{ + if (vptr->h2D) + { + if (vptr->flags & MFX_LOOPED) + { + AIL_set_sample_loop_count(vptr->h2D, 0); + } + AIL_start_sample(vptr->h2D); + } + if (vptr->h3D) + { + if (vptr->flags & MFX_LOOPED) + { + AIL_set_3D_sample_loop_count(vptr->h3D, 0); + } + AIL_start_3D_sample(vptr->h3D); + } + if (vptr->hStream) + { + if (vptr->flags & MFX_LOOPED) + { + AIL_set_stream_loop_count(vptr->hStream, 0); + } + AIL_start_stream(vptr->hStream); + } + vptr->playing = true; +} + +// MoveVoice +// +// set position of voice source from voice x,y,z + +static void MoveVoice(MFX_Voice* vptr) +{ + if (vptr->h3D) + { + float x = vptr->x * COORDINATE_UNITS; + float y = vptr->y * COORDINATE_UNITS; + float z = vptr->z * COORDINATE_UNITS; +/* +#ifndef FINAL +void AENG_draw_rectr(SLONG x,SLONG y,SLONG w,SLONG h,SLONG col,SLONG layer,SLONG page); + AENG_draw_rectr(vptr->x>>6,vptr->z>>7,2,2,0xffff,1,POLY_PAGE_COLOUR); +#endif +*/ + + + + if ((fabs(x - LX) < 0.5) && (fabs(y - LY) < 0.5) && (fabs(z - LZ) < 0.5)) + { + // set exactly at the listener if within epsilon + AIL_set_3D_position(vptr->h3D, LX, LY, LZ); + } + else + { + AIL_set_3D_position(vptr->h3D, x, y, z); + } + } +} + +// SetVoiceRate +// +// set rate for voice + +static void SetVoiceRate(MFX_Voice* vptr, float mult) +{ + if (vptr->h2D) + { + AIL_set_sample_playback_rate(vptr->h2D, S32(mult * vptr->smp->rate)); + } + if (vptr->h3D) + { + AIL_set_3D_sample_playback_rate(vptr->h3D, S32(mult * vptr->smp->rate)); + } + if (vptr->hStream) + { + AIL_set_stream_playback_rate(vptr->hStream, S32(mult * vptr->smp->rate)); + } + vptr->ratemult = mult; +} + +// SetVoiceGain +// +// set gain for voice + +static void SetVoiceGain(MFX_Voice* vptr, float gain) +{ + if (vptr->smp == NULL) + { + return; + } + + gain *= Volumes[vptr->smp->type]; + + if (vptr->h2D) + { + AIL_set_sample_volume(vptr->h2D, S32(Gain2D * gain * 127)); + } + if (vptr->h3D) + { + AIL_set_3D_sample_volume(vptr->h3D, S32(gain * 127)); + } + if (vptr->hStream) + { + AIL_set_stream_volume(vptr->hStream, S32(Gain2D * gain * 127)); + } + if (vptr->queue) + vptr->queue->gain=gain; + vptr->gain = gain; +} + +// IsVoiceDone +// +// check if voice is done + +static bool IsVoiceDone(MFX_Voice* vptr) +{ + if (vptr->flags & MFX_LOOPED) return false; + + U32 status; + U32 posn; + + if (vptr->h2D) + { + status = AIL_sample_status(vptr->h2D); + posn = AIL_sample_position(vptr->h2D); + } + else if (vptr->h3D) + { + status = AIL_3D_sample_status(vptr->h3D); + posn = AIL_3D_sample_offset(vptr->h3D); + } + else if (vptr->hStream) + { + status = AIL_stream_status(vptr->hStream); + posn = AIL_stream_position(vptr->hStream); + } + else if (vptr->smp && vptr->smp->loading) + { + return false; + } + else + { + return true; + } + + if (vptr->flags & MFX_EARLY_OUT) + { + return (vptr->smp->size - (signed)posn < 440*2); + } + + return (status != SMP_PLAYING); +} + +// QueueWave +// +// queue a wave + +static void QueueWave(MFX_Voice* vptr, UWORD wave, ULONG flags, SLONG x, SLONG y, SLONG z) +{ + if ((flags & MFX_SHORT_QUEUE) && vptr->queue) + { + // short queue - just blat it over the queued one + vptr->queue->flags = flags; + vptr->queue->wave = wave; + vptr->queue->x = x; + vptr->queue->y = y; + vptr->queue->z = z; + return; + } + + if (vptr->queuesz > MAX_QVOICE) return; // too many queued voices + if (QFree == QFreeLast) return; // no free slots + + // allocate a queue element + MFX_QWave* qptr = vptr->queue; + + if (qptr) + { + while (qptr->next) qptr = qptr->next; + qptr->next = QFree; + QFree = QFree->next; + qptr = qptr->next; + } + else + { + vptr->queue = QFree; + QFree = QFree->next; + qptr = vptr->queue; + } + + qptr->next = NULL; + qptr->flags = flags; + qptr->wave = wave; + qptr->x = x; + qptr->y = y; + qptr->z = z; + qptr->gain = 1.0; +} + +// TriggerPairedVoice +// +// trigger a paired voice + +static void TriggerPairedVoice(UWORD channel_id) +{ + MFX_Voice* vptr = FindFirst(channel_id); + + if (!vptr || !vptr->smp) return; + + vptr->flags &= ~MFX_PAIRED_TRK2; + PlayVoice(vptr); +} + +// PlayWave +// +// play a sound + +static UBYTE PlayWave(UWORD channel_id, ULONG wave, ULONG flags, SLONG x, SLONG y, SLONG z, Thing* thing) +{ + MFX_Voice* vptr = GetVoiceForWave(channel_id, wave, flags); + + if (!vptr) return 0; + + if (thing) + { + vptr->x = (thing->WorldPos.X >> 8); + vptr->y = (thing->WorldPos.Y >> 8); + vptr->z = (thing->WorldPos.Z >> 8); + } + else + { + vptr->x = x; + vptr->y = y; + vptr->z = z; + } + + if (vptr->smp) + { + if ((vptr->smp->type!=SMP_Music)&&(GAME_STATE & (GS_LEVEL_LOST|GS_LEVEL_WON))) return 0; // once the level's won or lost, no more sounds + if (flags & MFX_QUEUED) + { + QueueWave(vptr, wave, flags, vptr->x, vptr->y, vptr->z); + return 2; + } + if ((vptr->wave == wave) && !(flags & MFX_REPLACE)) + { + MoveVoice(vptr); + return 0; + } + FreeVoice(vptr); + } + + SetupVoice(vptr, channel_id, wave, flags); + MoveVoice(vptr); + if (!(flags & MFX_PAIRED_TRK2)) + { + PlayVoice(vptr); + } + if (thing) + { + vptr->thing = thing; + thing->Flags |= FLAGS_HAS_ATTACHED_SOUND; + } + if (flags & MFX_PAIRED_TRK1) + { + TriggerPairedVoice(channel_id + 1); + } + + return 1; +} + +// PlayTalk +// +// play a speech + +static UBYTE PlayTalk(char* filename, SLONG x, SLONG y, SLONG z) +{ + MFX_Voice* vptr = GetVoiceForWave(0, NumSamples, 0); + if (!vptr) return 0; + + if (vptr->smp) + { + FreeVoice(vptr); + } + + if (x | y | z) TalkSample.is3D = TALK_3D ? true : false; + else TalkSample.is3D = false; + + vptr->x = x; + vptr->y = y; + vptr->z = z; + + if (!SetupVoiceTalk(vptr, filename)) + { + return FALSE; + } + + MoveVoice(vptr); + PlayVoice(vptr); + + return 1; +} + +//----- volume functions + +// MFX_get_volumes +// +// get the current volumes, all 0 to 127 + +void MFX_get_volumes(SLONG* fx, SLONG* amb, SLONG* mus) +{ + *fx = SLONG(127 * Volumes[SMP_Effect]); + *amb = SLONG(127 * Volumes[SMP_Ambient]); + *mus = SLONG(127 * Volumes[SMP_Music]); +} + +// MFX_set_volumes +// +// set the current volumes, all 0 to 127 + +void MFX_set_volumes(SLONG fx, SLONG amb, SLONG mus) +{ + if (fx < 0) fx = 0; + else if (fx > 127) fx = 127; + if (amb < 0) amb = 0; + else if (amb > 127) amb = 127; + if (mus < 0) mus = 0; + else if (mus > 127) mus = 127; + + Volumes[SMP_Effect] = float(fx) / 127; + Volumes[SMP_Ambient] = float(amb) / 127; + Volumes[SMP_Music] = float(mus) / 127; + + ENV_set_value_number("ambient_volume", amb, "Audio"); + ENV_set_value_number("music_volume", mus, "Audio"); + ENV_set_value_number("fx_volume", fx, "Audio"); +} + +//----- transport functions ----- + +// MFX_play_xyz +// +// play a sound at the given location + +void MFX_play_xyz(UWORD channel_id, ULONG wave, ULONG flags, SLONG x, SLONG y, SLONG z) +{ + if (!drv) return; + PSXCheck(wave); + PlayWave(channel_id, wave, flags, x >> 8, y >> 8, z >> 8, NULL); +} + +// MFX_play_thing +// +// play a sound from a thing + +void MFX_play_thing(UWORD channel_id, ULONG wave, ULONG flags, Thing* p) +{ + if (!drv) return; + PSXCheck(wave); + PlayWave(channel_id, wave, flags, 0,0,0, p); +} + +// MFX_play_ambient +// +// play an ambient sound + +void MFX_play_ambient(UWORD channel_id, ULONG wave, ULONG flags) +{ + if (!drv) return; + + PSXCheck(wave); + if (wave < NumSamples) + { + Samples[wave].is3D = false; // save 3D channels for non-ambient sounds + if (Samples[wave].type == SMP_Effect) + { + Samples[wave].type = SMP_Ambient; // use this volume setting + } + } + PlayWave(channel_id, wave, flags, FC_cam[0].x, FC_cam[0].y, FC_cam[0].z, NULL); +} + +// MFX_play_stereo +// +// play a stereo sound + +UBYTE MFX_play_stereo(UWORD channel_id, ULONG wave, ULONG flags) +{ + if (!drv) return 0; + + PSXCheck2(wave); + return PlayWave(channel_id, wave, flags, 0, 0, 0, NULL); +} + +// MFX_stop +// +// stop a sound + +void MFX_stop(SLONG channel_id, ULONG wave) +{ + if (!drv) return; + + if (channel_id == MFX_CHANNEL_ALL) + { + for (int ii = 0; ii < MAX_VOICE; ii++) + { + FreeVoice(&Voices[ii]); + } + } + else + { + if (wave == MFX_WAVE_ALL) + { + MFX_Voice* vptr = FindFirst(channel_id); + while (vptr) + { + FreeVoice(vptr); + vptr = FindNext(vptr); + } + } + else + { + FreeVoice(FindVoice(channel_id, wave)); + } + } +} + +// MFX_stop_attached +// +// stop all sounds attached to a thing + +void MFX_stop_attached(Thing *p) +{ + if (!drv) return; + + for (int ii = 0; ii < MAX_VOICE; ii++) + { + if (Voices[ii].thing == p) FreeVoice(&Voices[ii]); + } +} + +//----- audio processing functions ----- + +void MFX_set_pitch(UWORD channel_id, ULONG wave, SLONG pitchbend) +{ + if (!drv) return; + + MFX_Voice* vptr = FindVoice(channel_id, wave); + if (!vptr || !vptr->smp) return; + + float pitch = float(pitchbend + 256) / 256; + SetVoiceRate(vptr, pitch); +} + +void MFX_set_gain(UWORD channel_id, ULONG wave, UBYTE gain) +{ + if (!drv) return; + + MFX_Voice* vptr = FindVoice(channel_id, wave); + if (!vptr || !vptr->smp) return; + + float fgain = float(gain) / 255; + SetVoiceGain(vptr, fgain); +} +/* +void MFX_set_loop_count(UWORD channel_id, ULONG wave, UBYTE count) +{ + if (!drv) return; + + MFX_Voice* vptr = FindVoice(channel_id, wave); + if (!vptr || !vptr->smp) return; + + float fgain = float(gain) / 255; + SetVoiceGain(vptr, fgain); + + AIL_set_sample_loop_count(); +} +*/ +void MFX_set_queue_gain(UWORD channel_id, ULONG wave, UBYTE gain) +{ + if (!drv) return; + + float fgain = float(gain) / 256; + + MFX_Voice* vptr = FindFirst(channel_id); + while (vptr) + { + if (!vptr->queue && (vptr->wave == wave)) + { + SetVoiceGain(vptr, fgain); + } + + for (MFX_QWave* qptr = vptr->queue; qptr; qptr = qptr->next) + { + if (qptr->wave == wave) qptr->gain = fgain; + } + + vptr = FindNext(vptr); + } +} + +//----- sound library functions ----- + +static void LoadWaveFile(MFX_Sample* sptr) +{ + if (!sptr->fname) return; // no file + if (sptr->dptr) return; // already loaded + + sptr->size = AIL_file_size(PathName(sptr->fname)); + + sptr->dptr = AIL_file_read(PathName(sptr->fname), NULL); + if (!sptr->dptr) return; + + AllocatedRAM += sptr->size; + + LoadWaveFileFinished(sptr); +} + +static void LoadTalkFile(char* filename) +{ + if (TalkSample.dptr) + { + AIL_mem_free_lock(TalkSample.dptr); + AllocatedRAM -= TalkSample.size; + } + + TalkSample.dptr = AIL_file_read(filename, NULL); + if (!TalkSample.dptr) return; + + TalkSample.size = AIL_file_size(filename); + AllocatedRAM += TalkSample.size; + + LoadWaveFileFinished(&TalkSample); +} + +#if ASYNC_FILE_IO + +static void LoadWaveFileAsync(MFX_Sample* sptr) +{ + if (!sptr->fname) return; // no file + if (sptr->dptr) return; // loaded + + sptr->size = AIL_file_size(PathName(sptr->fname)); + + sptr->dptr = AIL_mem_alloc_lock(sptr->size); + if (!sptr->dptr) return; + + AllocatedRAM += sptr->size; + + if (!LoadAsyncFile(PathName(sptr->fname), sptr->dptr, sptr->size, sptr)) + { + AIL_mem_free_lock(sptr->dptr); + AllocatedRAM -= sptr->size; + sptr->dptr = NULL; + + // fall back to synchronous loading + LoadWaveFile(sptr); + return; + } + + sptr->loading = true; +} + +#endif + +static void LoadWaveFileFinished(MFX_Sample* sptr) +{ + AILSOUNDINFO info; + + sptr->loading = false; + + if (!AIL_WAV_info(sptr->dptr, &info)) + { + TRACE("sample = %s - INVALID\n", sptr->fname); + AIL_mem_free_lock(sptr->dptr); + AllocatedRAM -= sptr->size; + sptr->dptr = NULL; + return; + } + else + { + sptr->rate = info.rate; + + if (sptr->is3D) + { + if (info.channels > 1) + { + sptr->is3D = false; + } + if (info.format != WAVE_FORMAT_PCM) + { + if (sptr->is3D) + { + // decompress + void* wav; + U32 size; + if (!AIL_decompress_ADPCM(&info, &wav, &size)) + { + sptr->is3D = false; + } + else + { + AIL_mem_free_lock(sptr->dptr); + AllocatedRAM -= sptr->size; + sptr->dptr = wav; + sptr->size = size; + AllocatedRAM += sptr->size; + } + } + } + } + } +} + +static void UnloadWaveFile(MFX_Sample* sptr) +{ + if (!sptr->dptr) return; + if (sptr->usecount) return; + + // unlink + if (sptr->prev_lru) + { + sptr->prev_lru->next_lru = sptr->next_lru; + sptr->next_lru->prev_lru = sptr->prev_lru; + sptr->next_lru = sptr->prev_lru = NULL; + } + + // cancel pending IO +#if ASYNC_FILE_IO + if (sptr->loading) + { + CancelAsyncFile(sptr); + sptr->loading = false; + } +#endif + + // free + AIL_mem_free_lock(sptr->dptr); + sptr->dptr = NULL; + + AllocatedRAM -= sptr->size; +} + +static void UnloadTalkFile() +{ + if (!TalkSample.dptr) return; + AIL_mem_free_lock(TalkSample.dptr); + TalkSample.dptr = NULL; + + AllocatedRAM -= TalkSample.size; +} + +void MFX_load_wave_list(CBYTE *names[]) +{ + if (!drv) return; + + MFX_free_wave_list(); + + // free waves + for (int ii = 0; ii < NumSamples; ii++) + { + if (Samples[ii].type==SMP_Music) UnloadWaveFile(&Samples[ii]); + } + UnloadWaveFile(&TalkSample); +} + +void MFX_free_wave_list() +{ + + // reset the music system +extern void MUSIC_reset(); // yeah yeah i know ugly + MUSIC_reset(); + + if (!drv) return; + + MFX_stop(MFX_CHANNEL_ALL, MFX_WAVE_ALL); + + InitVoices(); + +} + +//----- listener & environment ----- + +void MFX_set_listener(SLONG x, SLONG y, SLONG z, SLONG heading, SLONG roll, SLONG pitch) +{ + if (!drv) return; + + if (Listener || FallbackListener) + { + x >>= 8; + y >>= 8; + z >>= 8; + + LX = x * COORDINATE_UNITS; + LY = y * COORDINATE_UNITS; + LZ = z * COORDINATE_UNITS; + + heading += 0x200; + heading &= 0x7FF; + + float xorient = float(COS(heading)) / 65536; + float zorient = float(SIN(heading)) / 65536; + + if (Listener) + { + AIL_set_3D_position(Listener, LX, LY, LZ); + AIL_set_3D_orientation(Listener, xorient, 0, zorient, 0, 1, 0); + } + + if (FallbackListener) + { + AIL_set_3D_position(FallbackListener, LX, LY, LZ); + AIL_set_3D_orientation(FallbackListener, xorient, 0, zorient, 0, 1, 0); + } + + // move voices so the epsilon checks + // get made + for (int ii = 0; ii < MAX_VOICE; ii++) + { + if (Voices[ii].h3D) MoveVoice(&Voices[ii]); + } + } +} + +//----- general system stuff ----- + +// MFX_render +// +// update the parameters of the sounds + +void MFX_render() +{ + if (!drv) return; + +#if ASYNC_FILE_IO + // check for async completions + MFX_Sample* sptr; + + while (sptr = (MFX_Sample*)GetNextCompletedAsyncFile()) + { + // set up sample now it's in RAM + LoadWaveFileFinished(sptr); + + // and trigger any voices that were waiting for it + for (int ii = 0; ii < MAX_VOICE; ii++) + { + if (Voices[ii].smp == sptr) + { + FinishLoading(&Voices[ii]); + } + } + } +#endif + + for (int ii = 0; ii < MAX_VOICE; ii++) + { + MFX_Voice* vptr = &Voices[ii]; + + if (vptr->flags & MFX_PAIRED_TRK2) continue; + if (!vptr->smp) continue; + + if (IsVoiceDone(vptr)) + { + if (!vptr->queue) + { + FreeVoice(vptr); + } + else + { + // get next wave from queue + MFX_QWave* qptr = vptr->queue; + vptr->queue = qptr->next; + + if (qptr->flags & MFX_PAIRED_TRK1) TriggerPairedVoice(Voices[ii].id + 1); + + // free the old sample and set up the new one + Thing* thing = vptr->thing; + FreeVoiceSource(vptr); + SetupVoice(vptr, vptr->id, qptr->wave, qptr->flags & ~MFX_PAIRED_TRK2); + vptr->thing = thing; + + // set the position + if ((vptr->flags & MFX_MOVING) && vptr->thing) + { + vptr->x = vptr->thing->WorldPos.X >> 8; + vptr->y = vptr->thing->WorldPos.Y >> 8; + vptr->z = vptr->thing->WorldPos.Z >> 8; + } + else + { + vptr->x = qptr->x; + vptr->y = qptr->y; + vptr->z = qptr->z; + } + + // relocate and play + MoveVoice(vptr); + PlayVoice(vptr); + SetVoiceGain(vptr, qptr->gain); + + // release queue element + qptr->next = QFree; + QFree = qptr; + } + } + else + { + if (vptr->flags & MFX_CAMERA) + { + vptr->x = FC_cam[0].x >> 8; + vptr->z = FC_cam[0].z >> 8; + if (!(vptr->flags & MFX_LOCKY)) vptr->y = FC_cam[0].y >> 8; + MoveVoice(vptr); + } + if ((vptr->flags & MFX_MOVING) && vptr->thing) + { + vptr->x = vptr->thing->WorldPos.X >> 8; + vptr->y = vptr->thing->WorldPos.Y >> 8; + vptr->z = vptr->thing->WorldPos.Z >> 8; + MoveVoice(vptr); + } + } + } +} + +//----- querying information back ----- + +UWORD MFX_get_wave(UWORD channel_id, UBYTE index) +{ + if (!drv) return 0; + + MFX_Voice* vptr = FindFirst(channel_id); + + while (index--) + { + vptr = FindNext(vptr); + } + + return vptr ? vptr->wave : 0; +} + +// dlgproc +// +// dialog box procedure + +static BOOL CALLBACK dlgproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND ctrl; + int ii; + + ctrl = GetDlgItem(hWnd, IDC_SOUND_DROPDOWN); + + switch (message) + { + case WM_INITDIALOG: + { + RECT winsize; + RECT scrsize; + + GetWindowRect(hWnd, &winsize); + GetClientRect(GetDesktopWindow(), &scrsize); + + // localise this bastard + CBYTE *lang=ENV_get_value_string("language"); + + if (!lang) lang="text\\lang_english.txt"; + XLAT_load(lang); + XLAT_init(); + SetWindowText(hWnd,XLAT_str(X_MILES_SETUP)); + SetDlgItemText(hWnd,IDC_STATIC_SELECT,XLAT_str(X_SELECT_SOUND)); + SetDlgItemText(hWnd,IDC_NOSHOW,XLAT_str(X_DO_NOT_SHOW)); + SetDlgItemText(hWnd,IDOK,XLAT_str(X_OKAY)); + + int xoff = ((scrsize.right - scrsize.left) - (winsize.right - winsize.left)) / 2; + int yoff = ((scrsize.bottom - scrsize.top) - (winsize.bottom - winsize.top)) / 2; + + // SetWindowPos(hWnd, NULL, xoff, yoff, 0,0, SWP_NOZORDER | SWP_NOSIZE); + + for (ii = 0; ii < NumProviders; ii++) + { + SendMessage(ctrl, CB_INSERTSTRING, -1, (LPARAM)Providers[ii].name); + } + + SendMessage(ctrl, CB_SETCURSEL, CurProvider, 0); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + CurProvider = SendMessage(ctrl, CB_GETCURSEL, 0, 0); + DoMilesDialog = SendMessage(GetDlgItem(hWnd, IDC_NOSHOW), BM_GETCHECK, 0, 0) ? 0 : 1; + + case IDCANCEL: + EndDialog(hWnd, 0); + return TRUE; + } + break; + } + + return FALSE; +} + +// MilesDialog +// +// do the dialog box + +static void MilesDialog(HINSTANCE hInst, HWND hWnd) +{ + DialogBox(hInst, MAKEINTRESOURCE(IDD_MILESDLG), hWnd, (DLGPROC)dlgproc); +} + +// MFX_QUICK_play +// +// play a speech + +SLONG MFX_QUICK_play(CBYTE* str, SLONG x, SLONG y, SLONG z) +{ + return PlayTalk(str, x,y,z); +} + +SLONG MFX_QUICK_still_playing() +{ + MFX_Voice* vptr = GetVoiceForWave(0, NumSamples, 0); + if (!vptr) return 0; + + return IsVoiceDone(vptr) ? 0 : 1; +} + +void MFX_QUICK_stop() +{ + MFX_stop(0, NumSamples); +} + +void MFX_QUICK_wait() +{ + while (MFX_QUICK_still_playing()); + MFX_QUICK_stop(); +} + +#if 0 + +static HAUDIO quick_wav=NULL; + +SLONG MFX_QUICK_play(CBYTE *str) +{ + char filename[256]; + strcpy(filename, GetSpeechPath()); + strcat(filename, str); + + quick_wav=AIL_quick_load(filename); + if(quick_wav) + { + AIL_quick_play(quick_wav,1); + return(1); + } + else + { + return(0); + } +} + +void MFX_QUICK_wait(void) +{ + if(quick_wav) + { + while(AIL_quick_status(quick_wav)==QSTAT_PLAYING) + { + } + + AIL_quick_unload(quick_wav); + quick_wav=0; + + + } +} +SLONG MFX_QUICK_still_playing(void) +{ + if(quick_wav) + { + if(AIL_quick_status(quick_wav)==QSTAT_PLAYING) + { + return(1); + } + + } + + return(0); +} + +void MFX_QUICK_stop(void) +{ + if(quick_wav) + { + + // + // The big white manual says unloading a playing sample will stop it, so there! + // + AIL_quick_unload(quick_wav); + quick_wav=0; + + + } +} + +#endif + +#endif // M_SOUND + + +#ifndef M_SOUND + +#ifndef TARGET_DC +SLONG MFX_QUICK_play(CBYTE* fname) +{ + return 1; +} + +void MFX_QUICK_wait(void) +{ +} + +SLONG MFX_QUICK_still_playing(void) +{ + return 0; +} + +void MFX_QUICK_stop() +{ +} +#endif + +#endif + + + + + + + + + + + +#ifndef TARGET_DC + +void init_my_dialog (HWND hWnd) +{ + HWND ctrl; + int ii; + + + #ifdef NO_SOUND + return; + #else + + ctrl = GetDlgItem(hWnd, IDC_SOUND_DROPDOWN); + + { + RECT winsize; + RECT scrsize; + + GetWindowRect(hWnd, &winsize); + GetClientRect(GetDesktopWindow(), &scrsize); + + // localise this bastard + CBYTE *lang=ENV_get_value_string("language"); + + if (!lang) lang="text\\lang_english.txt"; + XLAT_load(lang); + XLAT_init(); + SetDlgItemText(hWnd,IDC_SOUND_OPTIONS,XLAT_str(X_MILES_SETUP)); + SetDlgItemText(hWnd,IDC_STATIC_SELECT,XLAT_str(X_SELECT_SOUND)); + SetDlgItemText(hWnd,IDC_NOSHOW,XLAT_str(X_DO_NOT_SHOW)); + SetDlgItemText(hWnd,IDOK,XLAT_str(X_OKAY)); + + int xoff = ((scrsize.right - scrsize.left) - (winsize.right - winsize.left)) / 2; + int yoff = ((scrsize.bottom - scrsize.top) - (winsize.bottom - winsize.top)) / 2; + + SetWindowPos(hWnd, NULL, xoff, yoff, 0,0, SWP_NOZORDER | SWP_NOSIZE); + + SendMessage(ctrl, CB_RESETCONTENT, 0,0); + + for (ii = 0; ii < NumProviders; ii++) + { + SendMessage(ctrl, CB_INSERTSTRING, -1, (LPARAM)Providers[ii].name); + } + + SendMessage(ctrl, CB_SETCURSEL, CurProvider, 0); + + } + #endif +} + +void my_dialogs_over(HWND hWnd) +{ + HWND ctrl; + + #ifdef NO_SOUND + return; + #else + + + ctrl = GetDlgItem(hWnd, IDC_SOUND_DROPDOWN); + + CurProvider = SendMessage(ctrl, CB_GETCURSEL, 0, 0); + + Set3DProvider(CurProvider); + + #endif +} + + +#endif //#ifndef TARGET_DC + +#endif diff --git a/fallen/DDLibrary/Source/MFx.cpp b/fallen/DDLibrary/Source/MFx.cpp new file mode 100644 index 0000000..71b3d9e --- /dev/null +++ b/fallen/DDLibrary/Source/MFx.cpp @@ -0,0 +1,758 @@ +#if 0 +#include "snd_type.h" +#if defined(Q_SOUND) || defined(NO_SOUND) + +// since if NO_SOUND is defined, we still need MFx.cpp but with the short-circuited functions +// but if Q_SOUND is defined, MFx_QMDX will handle it, so this one needs taking out + +// +// MFx.cpp +// +// Muckyfoot sound fx api for A3D / PSX +// +// A3D Version +// + +#include "MFx.h" +#include "A3DManager.h" +#include "c:\fallen\headers\fc.h" + +#ifdef TARGET_DC +#include "target.h" +#endif + +#define MFX_MAX_CHANS 64 +#define MFX_MAX_MASK 0x3f; +#define MFX_MAX_QUEUED 32 +#define MFX_MAX_QUEUED_CHAN 5 + + +extern IA3dGeom *a3dgeom; + +static BOOL MFX_initialised=0; + +//----- structs -------------------------------------------------------------------- + +struct MFX_Queue { + UWORD wave; + SWORD next; + ULONG flags; + SLONG x,y,z; + float gain; +}; + +struct MFX_Channel { + UWORD id; // thing-id of sound on this channel + UWORD wave; // sound sample playing on this channel + ULONG flags; + SLONG x,y,z; // coordinates to play it, if it's positional + A3DSource* source; // a3d source that handles this channel + Thing* thing; // thing pointer + SWORD queue; // index of queue structure + UWORD queuectr; // number of queued items +// float gain; // channel gain +}; + + +//----- globals stuff -------------------------------------------------------------- + +MFX_Channel MFX_channels[MFX_MAX_CHANS]; +MFX_Queue MFX_queue[MFX_MAX_QUEUED]; + + +//----- internal stuff ------------------------------------------------------------- + +void MFX_trigger_paired_channel(UWORD channel_id); +void MFX_load_wave_file (CBYTE *wave_file); + + +inline SLONG MFX_hash(SLONG chan) { return (chan*3)&MFX_MAX_MASK; } // really crap hash + +MFX_Channel* MFX_get_channel(UWORD channel_id, UWORD wave_id) { + SLONG i, first = MFX_hash(channel_id); + MFX_Channel *chan = &MFX_channels[first]; + + i=first; + while (1) { + if ((chan->id==channel_id)&&(chan->wave==wave_id)) return chan; + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } + if (i==first) return NULL; + } +} + + + + +MFX_Channel* MFX_get_first_channel(UWORD channel_id) { + SLONG i, first = MFX_hash(channel_id); + MFX_Channel *chan = &MFX_channels[first]; + + i=first; + while (1) { + if (chan->id==channel_id) return chan; + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } + if (i==first) return NULL; + } +} + +MFX_Channel* MFX_get_next_channel(MFX_Channel* chan) { + SLONG i=chan-MFX_channels, id = chan->id, first = MFX_hash(chan->id); + while (1) { + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } + if (i==first) return NULL; + if (chan->id==id) return chan; + } +} + + +MFX_Channel* MFX_get_free_channel(SLONG channel_id) { + SLONG i, first=MFX_hash(channel_id); + MFX_Channel* chan = &MFX_channels[first]; + + i=first; + while (1) { + if (!chan->source) return chan; + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } +// if (i==first) ASSERT(0); + if (i==first) return 0; + } +} + + +void MFX_kill(MFX_Channel* chan) { + if (!chan) return; + chan->thing=0; + if (!chan->source) return; + delete chan->source; + chan->source=0; + chan->flags=chan->id=chan->wave=0; +} + +inline MFX_Channel* MFX_locate_for_play(UWORD channel_id, ULONG wave, ULONG flags) { + if (flags&MFX_OVERLAP) { + return MFX_get_free_channel(channel_id); + } else { + MFX_Channel *chan; + if (flags&(MFX_QUEUED|MFX_NEVER_OVERLAP)) + chan=MFX_get_first_channel(channel_id); + else + chan=MFX_get_channel(channel_id, wave); + if (!chan) + chan=MFX_get_free_channel(channel_id); + else + if ((flags&(MFX_NEVER_OVERLAP|MFX_QUEUED))==MFX_NEVER_OVERLAP) return 0; // existing sound is fine... + return chan; + } +} + +inline void MFX_std_chan_setup(MFX_Channel* chan, UWORD id, ULONG wave, ULONG flags) { + chan->id=id; + chan->wave=wave; + chan->flags=flags; + chan->source=new A3DSource(the_a3d_manager.datalist[wave]); + chan->source->User=(SLONG)chan; + chan->source->autofree=1; + chan->queue=-1; + chan->queuectr=0; + chan->thing=0; + if (flags&MFX_LO_PRIORITY) chan->source->SetPriority(0.25); + if (flags&MFX_HI_PRIORITY) chan->source->SetPriority(0.75); +} + +inline UWORD MFX_queue_free(SLONG base) { + SLONG i=base; + while (1) { + if (MFX_queue[i].wave==0) return i; + i++; if (i==MFX_MAX_QUEUED) i=0; + if (i==base) return -1; + } +} + +inline void MFX_queue_wave(MFX_Channel* chan, UWORD wave, ULONG flags, SLONG x, SLONG y, SLONG z) { + SLONG ndx; + MFX_Queue* q; + + if ((flags&&MFX_SHORT_QUEUE)&&chan->queuectr) { + // short queue -- queued wave will always be the next wave played + q=&MFX_queue[chan->queue]; + q->flags=flags; + q->wave=wave; + q->x=x; q->y=y; q->z=z; + return; + } + + if (chan->queuectr>MFX_MAX_QUEUED_CHAN) return; + + if (chan->queue>=0) { + ndx=chan->queue; + while (MFX_queue[ndx].next>=0) ndx=MFX_queue[ndx].next; + MFX_queue[ndx].next=MFX_queue_free(ndx); + ndx=MFX_queue[ndx].next; + } else { + chan->queue=ndx=MFX_queue_free(0); + } + if (ndx==-1) return; + chan->queuectr++; + MFX_queue[ndx].flags=flags; + MFX_queue[ndx].wave=wave; + MFX_queue[ndx].x=x; + MFX_queue[ndx].y=y; + MFX_queue[ndx].z=z; + MFX_queue[ndx].gain=1; + MFX_queue[ndx].next=-1; +} + +//----- external stuff ------------------------------------------------------------- + +void MFX_play_xyz(UWORD channel_id, ULONG wave, ULONG flags, SLONG x, SLONG y, SLONG z) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + ASSERT(chan); + + if (!chan) return; // erk, no free channels + + x>>=8; y>>=8; z>>=8; + chan->x=x; chan->y=y; chan->z=z; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,x,y,z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) { + chan->source->SetPositionl(chan->x,chan->y,chan->z); + return; + } + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(x,y,z); + if (!(flags&MFX_PAIRED_TRK2)) chan->source->Play(flags&MFX_LOOPED); + if (flags&MFX_PAIRED_TRK1) MFX_trigger_paired_channel(channel_id+1); + +} + +void MFX_play_pos(UWORD channel_id, ULONG wave, ULONG flags, GameCoord* position) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + chan->x=position->X>>8; chan->y=position->Y>>8; chan->z=position->Z>>8; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,chan->x,chan->y,chan->z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) { + chan->source->SetPositionl(chan->x,chan->y,chan->z); + return; + } + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(chan->x,chan->y,chan->z); + if (!(flags&MFX_PAIRED_TRK2)) chan->source->Play(flags&MFX_LOOPED); + if (flags&MFX_PAIRED_TRK1) MFX_trigger_paired_channel(channel_id+1); +} + +void MFX_play_thing(UWORD channel_id, ULONG wave, ULONG flags, Thing* p) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + chan->x=p->WorldPos.X>>8; chan->y=p->WorldPos.Y>>8; chan->z=p->WorldPos.Z>>8; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,chan->x,chan->y,chan->z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) return; + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(chan->x,chan->y,chan->z); + if (!(flags&MFX_PAIRED_TRK2)) chan->source->Play(flags&MFX_LOOPED); + chan->thing=p; + p->Flags|=FLAGS_HAS_ATTACHED_SOUND; + if (flags&MFX_PAIRED_TRK1) MFX_trigger_paired_channel(channel_id+1); + +} + +void MFX_play_ambient(UWORD channel_id, ULONG wave, ULONG flags) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + chan->x=FC_cam[0].x; + chan->y=FC_cam[0].y; // add some fancier stuff later + chan->z=FC_cam[0].z; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,chan->x,chan->y,chan->z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) { + chan->source->SetPositionl(chan->x,chan->y,chan->z); + return; + } + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(chan->x,chan->y,chan->z); + if (!(flags&MFX_PAIRED_TRK2)) chan->source->Play(flags&MFX_LOOPED); + if (flags&MFX_PAIRED_TRK1) MFX_trigger_paired_channel(channel_id+1); +} + +UBYTE MFX_play_stereo(UWORD channel_id, ULONG wave, ULONG flags) { +#ifdef NO_SOUND + return(0); +#endif + MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return 0; // erk, no free channels + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,0,0,0); + return 2; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) return 0; + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + if (!(flags&MFX_PAIRED_TRK2)) { + //TRACE("play stereo: live\n"); + chan->source->Play(flags&MFX_LOOPED); + } + if (flags&MFX_PAIRED_TRK1) MFX_trigger_paired_channel(channel_id+1); + return 1; +} + +void MFX_stop(SLONG channel_id, ULONG wave) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan; + + if (channel_id==MFX_CHANNEL_ALL) { + + UWORD i; + for (i=0,chan=MFX_channels;ithing==p) MFX_kill(chan); + } +} + +//----- audio processing functions ----- + + +void MFX_set_pitch(UWORD channel_id, ULONG wave, SLONG pitchbend) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan = MFX_get_channel(channel_id, wave); + float pitch; + + if(!chan) + return; + + pitch=(float)(pitchbend+256)/256.0f; + if (chan->source) chan->source->SetPitchf(pitch); +} + +void MFX_set_gain(UWORD channel_id, ULONG wave, UBYTE gain) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan = MFX_get_channel(channel_id, wave); + float fgain; + + if(!chan) + return; + + fgain=(float)(gain)/256.0f; + //TRACE("gain set: %f\n",fgain); + if (chan->source) chan->source->SetGainf(fgain); +} + +void MFX_set_queue_gain(UWORD channel_id, ULONG wave, UBYTE gain) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan = MFX_get_channel(channel_id, wave); + MFX_Queue* q; + float fgain; + + if(!chan) return; + + fgain=(float)(gain)/256.0f; + if (chan->queue>=0) + q=&MFX_queue[chan->queue]; + else { // assume we really want to set the current one? +// TRACE("queuef (short circuit) gain set: %f\n",fgain); + if (chan->source) chan->source->SetGainf(fgain); + return; + } +// TRACE("queuef gain set: %f\n",fgain); + while (q) { + q->gain=fgain; + q=(q->next)?&MFX_queue[q->next]:0; + } + +} + +/* +void MFX_set_channel_gain(UWORD channel_id, UBYTE gain) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan = MFX_get_channel(channel_id,0); + + if (!chan) return; + chan->gain=(float)(gain)/256.0; + if (chan->source) chan->source->SetGainf(chan->gain); +} +*/ + +void MFX_set_wave(UWORD channel_id, ULONG wave, ULONG new_wave) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan = MFX_get_channel(channel_id, wave); +} + + +void MFX_set_xyz(UWORD channel_id, UWORD wave, SLONG x, SLONG y, SLONG z) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan = MFX_get_channel(channel_id, wave); + if(!chan) + return; + if (chan->source) chan->source->SetPositionl(x>>8,y>>8,z>>8); +} + + +void MFX_set_pos(UWORD channel_id, UWORD wave, GameCoord* position) { +#ifdef NO_SOUND + return; +#endif + MFX_Channel* chan = MFX_get_channel(channel_id, wave); + if(!chan) + return; + if (chan->source) chan->source->SetPositionl(position->X>>8,position->Y>>8,position->Z>>8); +} + +//----- listener & environment ----- + +void MFX_set_listener(SLONG x, SLONG y, SLONG z, SLONG heading, SLONG roll, SLONG pitch) { +#ifdef NO_SOUND + return; +#endif + float h,p,r; + + heading*=360; h=(float)heading; h/=2048; + pitch*=360; p=(float)pitch; p/=2048; + a3dgeom->LoadIdentity(); + a3dgeom->PushMatrix(); + a3dgeom->Translate3f((float)x/256.0f,(float)y/256.0f,(float)z/256.0f); + a3dgeom->Rotate3f(-h,0,1,0); + a3dgeom->Rotate3f(p,1,0,0); + a3dgeom->Scale3f(1,1,-1); + a3dgeom->BindListener(); + a3dgeom->PopMatrix(); + +} + +void MFX_set_environment(SLONG env_type) { + // do nothing for the moment. + // later, probably set up some funkatronic a3d stuff +} + +//----- sound library functions ----- + +extern CBYTE *sound_list[]; + +void MFX_load_wave_list(CBYTE *names[]) { +#ifdef NO_SOUND + return; +#endif + + SLONG i; + CBYTE buff[_MAX_PATH]; + void *oldnames=NULL; + + if (names==0) names=sound_list; + + if (MFX_initialised) + MFX_stop(MFX_CHANNEL_ALL,MFX_WAVE_ALL); + + if (oldnames==names) return; + + oldnames=names; + + MFX_free_wave_list(); + + memset(MFX_channels,0,sizeof(MFX_Channel)*MFX_MAX_CHANS); + + i=0; + while (strcmp(names[i],"!")) { + + if (stricmp("NULL.wav",names[i])) { + strcpy(buff,"Data\\sfx\\1622\\"); + strcat(buff,names[i]); + MFX_load_wave_file(buff); + } + i++; + } +} + +void MFX_load_wave_list(CBYTE *path,CBYTE *script_file) { +#ifdef NO_SOUND + return; +#endif + + FILE *script_handle; + CBYTE wave_name[MAX_PATH], + wave_file[MAX_PATH]; + ULONG streamed; // currently ignored... +// static CBYTE previous_list[_MAX_PATH]={0}; + +// if (!stricmp(previous_list,script_file)) return; + + MFX_free_wave_list(); + +// strcpy(previous_list,script_file); + + memset(MFX_channels,0,sizeof(MFX_Channel)*MFX_MAX_CHANS); + + script_handle = MF_Fopen(script_file,"r"); + if(script_handle) + { + while(fscanf(script_handle,"%s %d",wave_name,&streamed)>0) + { + strcpy(wave_file,path); + strcat(wave_file,wave_name); + // cunning correction thingy + if (stricmp("NULL.wav",wave_name)) + MFX_load_wave_file(wave_file); + } + + // Finished with the script. + MF_Fclose(script_handle); + } + +} + + +void MFX_load_wave_file(CBYTE *wave_file) { +#ifdef NO_SOUND + return; +#endif + + A3DData *wave; + + if (strstr(wave_file,"music\\")) { + wave = new A3DData(wave_file,A3DSOURCE_INITIAL_RENDERMODE_NATIVE); + } else { + wave = new A3DData(wave_file); + } + wave->owner=1; +} + +void MFX_free_wave_list(void) { +#ifdef NO_SOUND + return; +#endif + A3DData *item, *next; + + if (MFX_initialised) + MFX_stop(MFX_CHANNEL_ALL,MFX_WAVE_ALL); + else + memset(MFX_channels,0,sizeof(MFX_Channel)*MFX_MAX_CHANS); + + MFX_initialised=1; + + item=static_cast(the_a3d_manager.datalist.Head()); + while (item) { + next=static_cast(item->next); + if (item->owner==1) delete item; + item=next; + } +} + +//----- querying information back ----- + +UWORD MFX_get_wave(UWORD channel_id, UBYTE index) { + MFX_Channel *chan=MFX_get_first_channel(channel_id); + while (index) { + chan=MFX_get_next_channel(chan); + index--; + } + return chan?chan->wave:0; + +} + +//----- general system stuff ----- + +void MFX_render ( void ) { +#ifdef NO_SOUND + return; +#endif + A3DSource *item, *next; + MFX_Channel* targ; + MFX_Queue* q; + + the_a3d_manager.Render(); + item=static_cast(the_a3d_manager.srclist.Head()); + while (item) { + next=static_cast(item->next); + targ=(MFX_Channel*)item->User; + if (targ->flags&MFX_PAIRED_TRK2) { item=next; continue; } + if (item->autofree&&item->HasEnded((targ->flags&MFX_EARLY_OUT)?1:0)) { + if (targ) { + if (!targ->queuectr) { +// TRACE("[MFX] deleted\n"); + targ->source=0; + delete item; + if (targ->thing) targ->thing->Flags&=~FLAGS_HAS_ATTACHED_SOUND; + } else { + float gain; +// if (targ->thing&&(targ->thing->Class==CLASS_VEHICLE)) TRACE("[MFX] queue-play\n"); + q=&MFX_queue[targ->queue]; + gain=q->gain; + + if (q->flags&MFX_PAIRED_TRK1) MFX_trigger_paired_channel(targ->id+1); + + // update targ + targ->flags=q->flags&~MFX_PAIRED_TRK2; // no longer relevant + if ((targ->flags&MFX_MOVING)&&(targ->thing)) { + targ->x=targ->thing->WorldPos.X>>8; + targ->y=targ->thing->WorldPos.Y>>8; + targ->z=targ->thing->WorldPos.Z>>8; + } else { + targ->x=q->x; targ->y=q->y; targ->z=q->z; + } + //if (q->wave>100) TRACE("MFX play from queue -- w%d gain%f\n",q->wave,gain); + targ->wave=q->wave; + targ->queuectr--; + targ->queue=q->next; + // free q + q->wave=0; + // update source + item->Change(the_a3d_manager.datalist[targ->wave]); + item->SetPositionl(targ->x,targ->y,targ->z); + item->SetGainf(gain); + item->Play(q->flags&MFX_LOOPED); + the_a3d_manager.Render(); + + } + } else { +// TRACE("[MFX] deleted (no User)\n"); + delete item; + } + } else { + // it continues playing... we may need to do some processing + if (targ) { + if (targ->flags&MFX_CAMERA) { +// TRACE("[MFX] repositioned by camera\n"); + targ->x=FC_cam[0].x>>8; + targ->z=FC_cam[0].z>>8; + if (!(targ->flags&MFX_LOCKY)) targ->y=FC_cam[0].y>>8; + item->SetPositionl(targ->x,targ->y,targ->z); + } + if ((targ->flags&MFX_MOVING)&&(targ->thing)) { + targ->x=targ->thing->WorldPos.X>>8; + targ->y=targ->thing->WorldPos.Y>>8; + targ->z=targ->thing->WorldPos.Z>>8; + item->SetPositionl(targ->x,targ->y,targ->z); + } + } + } + item=next; + } +} + + +void MFX_trigger_paired_channel(UWORD channel_id) { + MFX_Channel* chan; + + chan = MFX_get_first_channel(channel_id); + + if (!chan||!chan->source) return; + + chan->flags&=~MFX_PAIRED_TRK2; + chan->source->Play(chan->flags&MFX_LOOPED); +} + + + +#endif //#if defined(Q_SOUND) || defined(NO_SOUND) +#endif diff --git a/fallen/DDLibrary/Source/MFx_QMDX.cpp b/fallen/DDLibrary/Source/MFx_QMDX.cpp new file mode 100644 index 0000000..02a5f60 --- /dev/null +++ b/fallen/DDLibrary/Source/MFx_QMDX.cpp @@ -0,0 +1,670 @@ +#include "snd_type.h" +#if defined(Q_SOUND) +// +// MFx.cpp +// +// Muckyfoot sound fx api for A3D / PSX +// +// QMDX Version +// + +#include "MFx.h" +#include "QSManager.h" +#include "c:\fallen\headers\fc.h" + + +//#define DISABLE_MFX + + +#define MFX_MAX_CHANS 64 +#define MFX_MAX_MASK 0x3f; +#define MFX_MAX_QUEUED 32 +#define MFX_MAX_QUEUED_CHAN 5 + + +static BOOL MFX_initialised=0; + +//----- structs -------------------------------------------------------------------- + +struct MFX_Queue { + UWORD wave; + SWORD next; + ULONG flags; + SLONG x,y,z; +}; + +/* +struct MFX_Channel { + UWORD id; // thing-id of sound on this channel + UWORD wave; // sound sample playing on this channel + ULONG flags; + SLONG x,y,z; // coordinates to play it, if it's positional + A3DSource* source; // a3d source that handles this channel + Thing* thing; // thing pointer + SWORD queue; // index of queue structure + UWORD queuectr; // number of queued items +}; +*/ + +//----- globals stuff -------------------------------------------------------------- +/* +MFX_Channel MFX_channels[MFX_MAX_CHANS]; +MFX_Queue MFX_queue[MFX_MAX_QUEUED]; +*/ + +//----- internal stuff ------------------------------------------------------------- +/* +inline SLONG MFX_hash(SLONG chan) { return (chan*3)&MFX_MAX_MASK; } // really crap hash + +MFX_Channel* MFX_get_channel(UWORD channel_id, UWORD wave_id) { + SLONG i, first = MFX_hash(channel_id); + MFX_Channel *chan = &MFX_channels[first]; + + i=first; + while (1) { + if ((chan->id==channel_id)&&(chan->wave==wave_id)) return chan; + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } + if (i==first) return NULL; + } +} + +MFX_Channel* MFX_get_first_channel(UWORD channel_id) { + SLONG i, first = MFX_hash(channel_id); + MFX_Channel *chan = &MFX_channels[first]; + + i=first; + while (1) { + if (chan->id==channel_id) return chan; + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } + if (i==first) return NULL; + } +} + +MFX_Channel* MFX_get_next_channel(MFX_Channel* chan) { + SLONG i, id = chan->id, first = MFX_hash(chan->id); + while (1) { + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } + if (i==first) return NULL; + if (chan->id==id) return chan; + } +} + + +MFX_Channel* MFX_get_free_channel(SLONG channel_id) { + SLONG i, first=MFX_hash(channel_id); + MFX_Channel* chan = &MFX_channels[first]; + + i=first; + while (1) { + if (!chan->source) return chan; + i++; chan++; + if (i>=MFX_MAX_CHANS) { + i=0; chan=MFX_channels; + } + if (i==first) ASSERT(0); + } +} + + +void MFX_kill(MFX_Channel* chan) { + chan->thing=0; + if (!chan->source) return; + delete chan->source; + chan->source=0; + chan->flags=chan->id=chan->wave=0; +} + +inline MFX_Channel* MFX_locate_for_play(UWORD channel_id, ULONG wave, ULONG flags) { + if (flags&MFX_OVERLAP) { + return MFX_get_free_channel(channel_id); + } else { + MFX_Channel *chan; + if (flags&MFX_QUEUED) + chan=MFX_get_first_channel(channel_id); + else + chan=MFX_get_channel(channel_id, wave); + if (!chan) chan=MFX_get_free_channel(channel_id); + return chan; + } +} + +inline void MFX_std_chan_setup(MFX_Channel* chan, UWORD id, ULONG wave, ULONG flags) { + chan->id=id; + chan->wave=wave; + chan->flags=flags; + chan->source=new A3DSource(the_a3d_manager.datalist[wave]); + chan->source->User=(SLONG)chan; + chan->source->autofree=1; + chan->queue=-1; + chan->queuectr=0; + chan->thing=0; + if (flags&MFX_LO_PRIORITY) chan->source->SetPriority(0.25); + if (flags&MFX_HI_PRIORITY) chan->source->SetPriority(0.75); +} + +inline UWORD MFX_queue_free(SLONG base) { + SLONG i=base; + while (1) { + if (MFX_queue[i].wave==0) return i; + i++; if (i==MFX_MAX_QUEUED) i=0; + if (i==base) return -1; + } +} + +inline void MFX_queue_wave(MFX_Channel* chan, UWORD wave, ULONG flags, SLONG x, SLONG y, SLONG z) { + SLONG ndx; + + if (chan->queuectr>MFX_MAX_QUEUED_CHAN) return; + + if (chan->queue>=0) { + ndx=chan->queue; + while (MFX_queue[ndx].next>=0) ndx=MFX_queue[ndx].next; + MFX_queue[ndx].next=MFX_queue_free(ndx); + ndx=MFX_queue[ndx].next; + } else { + chan->queue=ndx=MFX_queue_free(0); + } + if (ndx==-1) return; + chan->queuectr++; + MFX_queue[ndx].flags=flags; + MFX_queue[ndx].wave=wave; + MFX_queue[ndx].x=x; + MFX_queue[ndx].y=y; + MFX_queue[ndx].z=z; + MFX_queue[ndx].next=-1; +} +*/ + +inline SLONG PlayType(ULONG flags) { + SLONG type=0; + if (flags&MFX_LOOPED) type=WAVE_LOOP; + if (flags&MFX_REPLACE) type|=WAVE_PLAY_INTERUPT; + if (flags&MFX_OVERLAP) type|=WAVE_PLAY_OVERLAP; + if (flags&MFX_QUEUED) type|=WAVE_PLAY_QUEUE; + if (!(flags&(MFX_REPLACE|MFX_OVERLAP|MFX_QUEUED))) type|=WAVE_PLAY_NO_INTERUPT; + return type; +} + +//----- external stuff ------------------------------------------------------------- + +void MFX_play_xyz(UWORD channel_id, ULONG wave, ULONG flags, SLONG x, SLONG y, SLONG z) { +#ifdef DISABLE_MFX + return; +#endif + + WaveParams params; + + params.Priority = 1; + params.Flags = WAVE_CARTESIAN; + params.Mode.Cartesian.Scale = (128<<8); + params.Mode.Cartesian.X = x>>8; + params.Mode.Cartesian.Y = y>>8; + params.Mode.Cartesian.Z = z>>8; + + PlayWave(channel_id,wave,PlayType(flags),¶ms); +/* MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + x>>=8; y>>=8; z>>=8; + chan->x=x; chan->y=y; chan->z=z; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,x,y,z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) { + chan->source->SetPositionl(chan->x,chan->y,chan->z); + return; + } + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(x,y,z); + chan->source->Play(flags&MFX_LOOPED); +*/ +} + +void MFX_play_pos(UWORD channel_id, ULONG wave, ULONG flags, GameCoord* position) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + chan->x=position->X>>8; chan->y=position->Y>>8; chan->z=position->Z>>8; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,chan->x,chan->y,chan->z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) { + chan->source->SetPositionl(chan->x,chan->y,chan->z); + return; + } + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(chan->x,chan->y,chan->z); + chan->source->Play(flags&MFX_LOOPED);*/ + WaveParams params; + + params.Priority = 1; + params.Flags = WAVE_CARTESIAN; + params.Mode.Cartesian.Scale = (128<<8); + params.Mode.Cartesian.X = position->X>>8; + params.Mode.Cartesian.Y = position->Y>>8; + params.Mode.Cartesian.Z = position->Z>>8; + + PlayWave(channel_id,wave,PlayType(flags),¶ms); + +} + +void MFX_play_thing(UWORD channel_id, ULONG wave, ULONG flags, Thing* p) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + chan->x=p->WorldPos.X>>8; chan->y=p->WorldPos.Y>>8; chan->z=p->WorldPos.Z>>8; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,chan->x,chan->y,chan->z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) return; + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(chan->x,chan->y,chan->z); + chan->source->Play(flags&MFX_LOOPED); + chan->thing=p; + p->Flags|=FLAGS_HAS_ATTACHED_SOUND;*/ + WaveParams params; + + params.Priority = 1; + params.Flags = WAVE_CARTESIAN; + params.Mode.Cartesian.Scale = (128<<8); + params.Mode.Cartesian.X = p->WorldPos.X>>8; + params.Mode.Cartesian.Y = p->WorldPos.Y>>8; + params.Mode.Cartesian.Z = p->WorldPos.Z>>8; + + PlayWave(channel_id,wave,PlayType(flags),¶ms); + + +} + +void MFX_play_ambient(UWORD channel_id, ULONG wave, ULONG flags) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + chan->x=FC_cam[0].x; + chan->y=FC_cam[0].y; // add some fancier stuff later + chan->z=FC_cam[0].z; + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if (flags&MFX_QUEUED) { + MFX_queue_wave(chan,wave,flags,chan->x,chan->y,chan->z); + return; + } + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) { + chan->source->SetPositionl(chan->x,chan->y,chan->z); + return; + } + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->SetPositionl(chan->x,chan->y,chan->z); + chan->source->Play(flags&MFX_LOOPED);*/ + WaveParams params; + + params.Priority = 1; + params.Flags = WAVE_CARTESIAN; + params.Mode.Cartesian.Scale = (128<<8); + params.Mode.Cartesian.X = FC_cam[0].x; + params.Mode.Cartesian.Y = FC_cam[0].y; + params.Mode.Cartesian.Z = FC_cam[0].z; + + PlayWave(channel_id,wave,PlayType(flags),¶ms); + +} + +void MFX_play_stereo(UWORD channel_id, ULONG wave, ULONG flags) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan=MFX_locate_for_play(channel_id, wave, flags); + + if (!chan) return; // erk, no free channels + + // we now have a channel which is either blank or can be stomped + if (chan->source) { + if ((chan->wave==wave)&!(flags&MFX_REPLACE)) return; + MFX_kill(chan); + } + + MFX_std_chan_setup(chan,channel_id,wave,flags); + chan->source->Play(flags&MFX_LOOPED);*/ + MFX_play_ambient(channel_id,wave,flags); // heh +} + +void MFX_stop(SLONG channel_id, ULONG wave) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan; + + if (channel_id==MFX_CHANNEL_ALL) { + + UWORD i; + for (i=0,chan=MFX_channels;ithing==p) MFX_kill(chan); + }*/ +} + +//----- audio processing functions ----- + +void MFX_set_pitch(UWORD channel_id, ULONG wave, SLONG pitchbend) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan = MFX_get_channel(channel_id, wave); + float pitch; + + pitch=(float)(pitchbend+256)/256.0; + if (chan->source) chan->source->SetPitchf(pitch);*/ +} + +void MFX_set_wave(UWORD channel_id, ULONG wave, ULONG new_wave) { +#ifdef DISABLE_MFX + return; +#endif +// MFX_Channel* chan = MFX_get_channel(channel_id, wave); + +} + +void MFX_set_xyz(UWORD channel_id, UWORD wave, SLONG x, SLONG y, SLONG z) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan = MFX_get_channel(channel_id, wave); + if (chan->source) chan->source->SetPositionl(x>>8,y>>8,z>>8);*/ +} + + +void MFX_set_pos(UWORD channel_id, UWORD wave, GameCoord* position) { +#ifdef DISABLE_MFX + return; +#endif +/* MFX_Channel* chan = MFX_get_channel(channel_id, wave); + if (chan->source) chan->source->SetPositionl(position->X>>8,position->Y>>8,position->Z>>8);*/ +} + +//----- listener & environment ----- + +extern void SetListenerOrientation(SLONG angle,SLONG roll,SLONG tilt); + + +void MFX_set_listener(SLONG x, SLONG y, SLONG z, SLONG heading, SLONG roll, SLONG pitch) { +#ifdef DISABLE_MFX + return; +#endif + + SetListenerPosition(x>>8,y>>8,z>>8,128<<8); + SetListenerOrientation(heading,roll,pitch); + +/* float h,p,r; + + heading*=360; h=(float)heading; h/=2048; + pitch*=360; p=(float)pitch; p/=2048; + a3dgeom->LoadIdentity(); + a3dgeom->PushMatrix(); + a3dgeom->Translate3f((float)x/256.0,(float)y/256.0,(float)z/256.0); + a3dgeom->Rotate3f(-h,0,1,0); + a3dgeom->Rotate3f(p,1,0,0); + a3dgeom->Scale3f(1,1,-1); + a3dgeom->BindListener(); + a3dgeom->PopMatrix();*/ + +} + +void MFX_set_environment(SLONG env_type) { + // do nothing for the moment. + // later, probably set up some funkatronic a3d stuff +} + +//----- sound library functions ----- + +extern CBYTE *sound_list[]; +extern void LoadWave(CBYTE *wave_name); + +void MFX_load_wave_list(CBYTE *names[]) { +#ifdef DISABLE_MFX + return; +#endif + + SLONG i; + CBYTE buff[_MAX_PATH]; + void *oldnames=NULL; + + if (names==0) names=sound_list; + + if (oldnames==names) return; + + oldnames=names; + +// MFX_free_wave_list(); + FreeWaveList(); + +// memset(MFX_channels,0,sizeof(MFX_Channel)*MFX_MAX_CHANS); + + i=0; + while (strcmp(names[i],"!")) { + + if (stricmp("NULL.wav",names[i])) { + strcpy(buff,"Data\\sfx\\1622\\"); + strcat(buff,names[i]); +// MFX_load_wave_file(buff); + LoadWave(buff); + } + i++; + } +} + +void MFX_load_wave_list(CBYTE *path,CBYTE *script_file) { +#ifdef DISABLE_MFX + return; +#endif + + FILE *script_handle; + CBYTE wave_name[MAX_PATH], + wave_file[MAX_PATH]; + ULONG streamed; // currently ignored... + +// MFX_free_wave_list(); + FreeWaveList(); + +// memset(MFX_channels,0,sizeof(MFX_Channel)*MFX_MAX_CHANS); + + script_handle = MF_Fopen(script_file,"r"); + if(script_handle) + { + while(fscanf(script_handle,"%s %d",wave_name,&streamed)>0) + { + strcpy(wave_file,path); + strcat(wave_file,wave_name); + // cunning correction thingy + if (stricmp("NULL.wav",wave_name)) +// MFX_load_wave_file(wave_file); + LoadWave(wave_file); + } + + // Finished with the script. + MF_Fclose(script_handle); + } + +} + + +void MFX_load_wave_file(CBYTE *wave_file) { +#ifdef DISABLE_MFX + return; +#endif +/* + A3DData *wave; + + if (strstr(wave_file,"music\\")) { + wave = new A3DData(wave_file,A3DSOURCE_INITIAL_RENDERMODE_NATIVE); + } else { + wave = new A3DData(wave_file); + } + wave->owner=1;*/ +} + +void MFX_free_wave_list(void) { +#ifdef DISABLE_MFX + return; +#endif + /*A3DData *item, *next; + + if (MFX_initialised) + MFX_stop(MFX_CHANNEL_ALL,MFX_WAVE_ALL); + else + memset(MFX_channels,0,sizeof(MFX_Channel)*MFX_MAX_CHANS); + + MFX_initialised=1; + + item=static_cast(the_a3d_manager.datalist.Head()); + while (item) { + next=static_cast(item->next); + if (item->owner==1) delete item; + item=next; + }*/ +} + + +//----- general system stuff ----- + +void MFX_render() { +#ifdef DISABLE_MFX + return; +#endif +/* A3DSource *item, *next; + MFX_Channel* targ; + MFX_Queue* q; + + the_a3d_manager.Render(); + item=static_cast(the_a3d_manager.srclist.Head()); + while (item) { + next=static_cast(item->next); + targ=(MFX_Channel*)item->User; + if (item->autofree&&item->HasEnded()) { + if (targ) { + if (!targ->queuectr) { +// TRACE("[MFX] deleted\n"); + targ->source=0; + delete item; + if (targ->thing) targ->thing->Flags&=~FLAGS_HAS_ATTACHED_SOUND; + } else { +// TRACE("[MFX] queue-play\n"); + q=&MFX_queue[targ->queue]; + // update targ + targ->x=q->x; targ->y=q->y; targ->z=q->z; + targ->flags=q->flags; + targ->wave=q->wave; + targ->queuectr--; + targ->queue=q->next; + // free q + q->wave=0; + // update source + item->Change(the_a3d_manager.datalist[targ->wave]); + item->SetPositionl(targ->x,targ->y,targ->z); + item->Play(q->flags&MFX_LOOPED); + } + } else { +// TRACE("[MFX] deleted (no User)\n"); + delete item; + } + } else { + // it continues playing... we may need to do some processing + if (targ) { + if (targ->flags&MFX_CAMERA) { +// TRACE("[MFX] repositioned by camera\n"); + targ->x=FC_cam[0].x>>8; + targ->z=FC_cam[0].z>>8; + if (!(targ->flags&MFX_LOCKY)) targ->y=FC_cam[0].y>>8; + item->SetPositionl(targ->x,targ->y,targ->z); + } + if ((targ->flags&MFX_MOVING)&&(targ->thing)) { + targ->x=targ->thing->WorldPos.X>>8; + targ->y=targ->thing->WorldPos.Y>>8; + targ->z=targ->thing->WorldPos.Z>>8; + item->SetPositionl(targ->x,targ->y,targ->z); + } + } + } + item=next; + }*/ +} + +#endif \ No newline at end of file diff --git a/fallen/DDLibrary/Source/QSManager.cpp b/fallen/DDLibrary/Source/QSManager.cpp new file mode 100644 index 0000000..49dd419 --- /dev/null +++ b/fallen/DDLibrary/Source/QSManager.cpp @@ -0,0 +1,670 @@ +// QSManager.cpp +// Guy Simmons, 6th May 1998. + + +#ifndef TARGET_DC + +#include "DDLib.h" +#include "C:\fallen\DDEngine\Headers\Matrix.h" + +//--------------------------------------------------------------- +// +// User Functions. +// +//--------------------------------------------------------------- + +void LoadWaveList(CBYTE *wave_path,CBYTE *wave_list) +{ + the_qs_sound_manager.LoadWaves(wave_path,wave_list); +} + +//--------------------------------------------------------------- + +void LoadWave(CBYTE *wave_name) +{ + the_qs_sound_manager.LoadWave(wave_name); +} + +//--------------------------------------------------------------- + +void FreeWaveList(void) +{ + the_qs_sound_manager.FreeWaves(); +} + +//--------------------------------------------------------------- + +void PlayWave(SLONG ref,SLONG wave_id,SLONG play_type,WaveParams *the_params) +{ + the_qs_sound_manager.PlayWave(ref,wave_id-1,play_type,the_params); +} + +//--------------------------------------------------------------- + +void StopWave(SLONG ref,SLONG wave_id) +{ + the_qs_sound_manager.StopWave(ref,wave_id-1); +} + +//--------------------------------------------------------------- + +void SetListenerPosition(SLONG x,SLONG y,SLONG z,SLONG scale) +{ + float f_scale; + QMIX_RESULT r; + QSVECTOR position; + TCHAR error_text[256]; + + + f_scale = 1.0f/(float)scale; + position.x = (float)x*f_scale; + position.y = (float)y*f_scale; + position.z = (float)z*f_scale; + + r = QS(SetListenerPosition(the_qs_sound_manager.GetHQMixer(),&position,0)); + if(r) + { + QS(GetErrorText(r,error_text,256)); +// DebugText("%s\n",error_text); + } +} + +//--------------------------------------------------------------- + +void SetListenerOrientation(SLONG angle,SLONG roll,SLONG tilt) +{ + QMIX_RESULT r; + QSVECTOR direction, + up; + TCHAR error_text[256]; +/* float dirvec[3]; + + MATRIX_vector(dirvec,angle,tilt); + direction.x=dirvec[0]; + direction.y=dirvec[1]; + direction.z=dirvec[2]; + */ + + direction.x = 0.0f; + direction.y = 0.0f; + direction.z = 1.0f; + up.x = 0.0f; + up.y = 1.0f; + up.z = 0.0f; + r = QS(SetListenerOrientation(the_qs_sound_manager.GetHQMixer(),&direction,&up,0)); + if(r) + { + QS(GetErrorText(r,error_text,256)); +// DebugText("%s\n",error_text); + } + + // Fudge the velocity. + up.x = 0.0f; + up.y = 0.0f; + up.z = 0.0f; + r = QS(SetListenerVelocity(the_qs_sound_manager.GetHQMixer(),&up,0)); + if(r) + { + QS(GetErrorText(r,error_text,256)); +// DebugText("%s\n",error_text); + } +} + +//--------------------------------------------------------------- +// +// class QSManager +// +//--------------------------------------------------------------- + +QSManager the_qs_sound_manager; + +//--------------------------------------------------------------- + +QSManager::QSManager() +{ + ManagerFlags = 0; + WaveList = WaveListEnd = NULL; + WaveCount = 0; +} + +//--------------------------------------------------------------- + +QSManager::~QSManager() +{ + Fini(); +} + +//--------------------------------------------------------------- + +HRESULT QSManager::Init(void) +{ + if(!IsInitialised()) + { + // Set up the config struct & initialise QSound. + InitStruct(Config); + Config.dwFlags = QMIX_CONFIG_LEFTCOORDS; + Config.dwSamplingRate = 22050; + Config.iChannels = MAX_CHANNELS; + Config.hwnd = hDDLibWindow; + HQMixer = QS(InitEx(&Config)); + + // If all is well active QSound. + if(HQMixer) + { + SLONG r; + CBYTE error_text[200]; + ActivateSound(); + + // Open all the channels. + r=QS(OpenChannel(HQMixer,0,QMIX_OPENALL)); + if(r) + { + QS(GetErrorText(r,error_text,256)); +// DebugText("PlayWave: %s\n",error_text); + } + + InitOn(); + } + + } + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT QSManager::Fini(void) +{ + if(IsInitialised()) + { + QS(CloseSession(HQMixer)); + + InitOff(); + } + return DS_OK; +} + +//--------------------------------------------------------------- + +void QSManager::ActivateSound(void) +{ + // Activate QSound. + if(!IsActive()) + { + if(!QS(Activate(HQMixer,TRUE))) + ActiveOn(); + } +} + +//--------------------------------------------------------------- + +void QSManager::DeactivateSound(void) +{ + // Deactivate QSound. + if(IsActive()) + { + if(!QS(Activate(HQMixer,FALSE))) + ActiveOff(); + } +} + +//--------------------------------------------------------------- + +HRESULT QSManager::LoadWaves(CBYTE *wave_path,CBYTE *script_name) +{ + CBYTE wave_name[MAX_PATH], + wave_file[MAX_PATH]; + ULONG streamed; + FILE *script_handle; + HRESULT result = DSERR_GENERIC; + Wave *new_wave; + + + // Get rid of any existing samples. + FreeWaves(); +// LogText + // Open the script file. + script_handle = MF_Fopen(script_name,"r"); + if(script_handle) + { + while(fscanf(script_handle,"%s %d",wave_name,&streamed)>0) + { +// LogText(" wave name %s streamed %d \n",wave_name,streamed); + new_wave = new Wave; + if(new_wave) + { + // Set up attributes. + if(streamed) + new_wave->StreamedOn(); + + // Initialise the wave. + strcpy(wave_file,wave_path); + strcat(wave_file,wave_name); + result = new_wave->Init(wave_file,HQMixer); + if(FAILED(result)) + { + delete new_wave; + return result; + } + + AddWave(new_wave); + + } + } + + // Finished with the script. + MF_Fclose(script_handle); + } + + return result; +} + +//--------------------------------------------------------------- + +HRESULT QSManager::LoadWave(CBYTE *wave_name) +{ + ULONG streamed=0; //temp? + HRESULT result = DSERR_GENERIC; + Wave *new_wave; + + + new_wave = new Wave; + if(new_wave) + { + // Set up attributes. + if(streamed) + new_wave->StreamedOn(); + + // Initialise the wave. + result = new_wave->Init(wave_name,HQMixer); + if(FAILED(result)) + { + delete new_wave; + return result; + } + + AddWave(new_wave); + + } + return result; +} + +//--------------------------------------------------------------- + +HRESULT QSManager::FreeWaves(void) +{ + Wave *current_wave, + *next_wave; + + + current_wave = WaveList; + while(current_wave) + { + next_wave = current_wave->Next; + current_wave->Fini(HQMixer); + delete current_wave; + + current_wave = next_wave; + } + + // Initialise wave list. + WaveList = WaveListEnd = NULL; + WaveCount = 0; + + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT QSManager::AddWave(Wave *the_wave) +{ + if(!the_wave) + { + // Error, Invalid parameters + return DSERR_GENERIC; + } + + // Add sample to list. + the_wave->Prev = WaveListEnd; + the_wave->Next = NULL; + + // Update list end. + if(WaveListEnd) + WaveListEnd->Next = the_wave; + WaveListEnd = the_wave; + + // Update list. + if(!WaveList) + WaveList = the_wave; + + WaveCount++; + + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT QSManager::DeleteWave(Wave *the_wave) +{ + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT QSManager::PlayWave(SLONG wave_ref,SLONG wave_id,SLONG play_type,WaveParams *the_params) +{ + float f_scale; + int channel; + BOOL channel_done = FALSE, + has_channel = FALSE; + SLONG c0, + play_flags = QMIX_QUEUEWAVE, + play_loop = 0; + LPMIXWAVE the_wave; + Wave *current_wave; + QMIX_DISTANCES distances; + QMIXPLAYPARAMS play_params; + QMIX_RESULT r; + QSVECTOR wave_position; + TCHAR error_text[256]; + + + // Get a pointer to the requested wave. + current_wave = WaveList; + for(c0=0;c0Next; + if(!current_wave) + return DSERR_GENERIC; + } + the_wave = current_wave->GetMixWave(); + + // Check the wave. + if(!the_wave) + return DSERR_GENERIC; + + // Try & match the wave ref & channel. + for(c0=0;c0=0) + { + if(the_params) + { + // Set the channel parameters according to the user params. + switch(the_params->Flags&WAVE_TYPE_MASK) + { + case WAVE_STEREO: + QS(SetVolume(HQMixer,channel,QMIX_USEONCE,32767)); + break; + case WAVE_POLAR: + + break; + case WAVE_CARTESIAN: + f_scale = 1.0f/(float)the_params->Mode.Cartesian.Scale; + wave_position.x = (float)the_params->Mode.Cartesian.X*f_scale; + wave_position.y = (float)the_params->Mode.Cartesian.Y*f_scale; + wave_position.z = (float)the_params->Mode.Cartesian.Z*f_scale; + r = QS(SetSourcePosition(HQMixer,channel,0,&wave_position)); + + // Report any errors. + if(r) + { + QS(GetErrorText(r,error_text,256)); +// DebugText("PlayWave: %s\n",error_text); + } + + if(the_params->Flags&WAVE_DISTANCE_MAPPING) + { + distances.cbSize = sizeof(QMIX_DISTANCES); + distances.minDistance = 40.0f; + distances.maxDistance = 56.0f; + distances.scale = 8.0f; + QS(SetDistanceMapping(HQMixer,channel,QMIX_USEONCE,&distances)); + } + else + { + distances.cbSize = sizeof(QMIX_DISTANCES); + distances.minDistance = 20.0f; + distances.maxDistance = 100.0; + distances.scale = 1.0f; + QS(SetDistanceMapping(HQMixer,channel,QMIX_USEONCE,&distances)); + } + break; + } + } + + // Loop status. + if(the_params->Flags&WAVE_PAN_RATE) + QS(SetPanRate(HQMixer,channel,QMIX_USEONCE,1000)); + + // Pan rate status. + if(the_params->Flags&WAVE_LOOP) + play_loop = -1; + + // Set the play mode. + if(play_type==WAVE_PLAY_QUEUE) + { + play_flags = QMIX_QUEUEWAVE; + } + else + { + play_flags = QMIX_CLEARQUEUE; + + // Get channel status. + channel_done = QS(IsChannelDone(HQMixer,channel)); + + // If we don't want to interupt the current wave then exit. + if(!channel_done && play_type==WAVE_PLAY_NO_INTERUPT) + return DS_OK; + // If we want to play the wave lots then get any old channel. + else if(!channel_done && play_type==WAVE_PLAY_OVERLAP) + { + channel = QS(FindChannel(HQMixer,QMIX_FINDCHANNEL_LRU,0)); + if(channel<0) + return DSERR_GENERIC; + } + } + + // Play the wave. + if(the_params->Flags&WAVE_SET_LOOP_POINTS) + { + InitStruct(play_params); + play_params.lStartLoop = the_params->LoopStart; + play_params.lEndLoop = the_params->LoopEnd; +// play_params.lEnd = the_params->LoopEnd; + + r = QS(PlayEx(HQMixer,channel,play_flags,the_wave,play_loop,&play_params)); + } + else + { + r = QS(PlayEx(HQMixer,channel,play_flags,the_wave,play_loop,0)); + } + + // Report any errors. + if(r) + { + QS(GetErrorText(r,error_text,256)); +// DebugText("PlayWave: %s\n",error_text); + } + + // Free up the channel if the wave is not playing. + if(QS(IsChannelDone(HQMixer,channel))) + Channels[channel].SetUserRef(-1); + } + + // return success. + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT QSManager::StopWave(SLONG wave_ref,SLONG wave_id) +{ + BOOL has_channel = FALSE; + SLONG c0; + TCHAR error_text[256]; + QMIX_RESULT r; + + + // Try & match the wave ref & channel. + for(c0=0;c0 +#pragma comment(lib, "winmm.lib") + +#ifndef VERIFY +#ifdef NDEBUG +#define VERIFY(x) x +#else +#define VERIFY(x) {ASSERT(x);} +#endif +#endif + +SampleManager samples; + +//--------------------------------------------------------------- +// +// User functions. +// +//--------------------------------------------------------------- + +void LoadSampleList(CBYTE *sample_file) +{ + samples.LoadSamples(sample_file); +} + +//--------------------------------------------------------------- + +void PlaySample(SLONG ref,SWORD sample_no,SLONG vol,SLONG pan,SLONG freq,SLONG pri) +{ + // Fudged for now. + SLONG c0; + SampleInfo *current_sample; + + + if(sample_no) + { + current_sample = samples.SampleList; + for(c0=1;c0<=sample_no;c0++) + { + if(c0==sample_no) + { + if(current_sample) + current_sample->Play(ref,vol,pan,freq,pri); + } + if(current_sample) + current_sample = current_sample->Next; + else + break; + } + } +} + +//--------------------------------------------------------------- + +void StopSample(SLONG user_ref) +{ + +} + +//--------------------------------------------------------------- +// +// CLASS : SampleInfo +// +//--------------------------------------------------------------- + +SampleInfo::SampleInfo() +{ + SampleFlags = 0; + hmmFile = NULL; + + Next = NULL; + Prev = NULL; +} + +//--------------------------------------------------------------- + +SampleInfo::~SampleInfo() +{ + if(hmmFile) + { + mmioClose(hmmFile,0); + hmmFile = NULL; + } +// Destroy(); +} + +//--------------------------------------------------------------- + +HRESULT SampleInfo::Create(CBYTE *file_name,UBYTE buffer_count) +{ + int mm_error; + SWORD extra_bytes = 0; + MMCKINFO mm_temp_chunk; + PCMWAVEFORMAT temp_wave_format; + + + if(IsValid()) + { + // Programmer error. + return FALSE; + } + + // open the file. + hmmFile = mmioOpenA(file_name,NULL,MMIO_READ); + if(!hmmFile) + { + // It's not a valid file so exit. + goto error; + } + + // Read the RIFF chunk. + mm_error = mmioDescend(hmmFile,&RIFFChunk,NULL,0); + if(mm_error!=0) + { + // Error reading file. + goto error; + } + + // Check the chunk to see if it's a WAV. + if((RIFFChunk.ckid != FOURCC_RIFF) || (RIFFChunk.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) + { + // It's not a WAV. + goto error; + } + + // Search for the 'fmt' chunk. + mm_temp_chunk.ckid = mmioFOURCC('f', 'm', 't', ' '); + mm_error = mmioDescend(hmmFile,&mm_temp_chunk,&RIFFChunk,MMIO_FINDCHUNK); + if(mm_error!=0) + { + // Error reading file. + goto error; + } + + // The 'fmt' chunk should be >= sizeof(PCMWAVEFORMAT) + if(mm_temp_chunk.cksizeMAX_DUP_BUFFERS) + BufferCount = MAX_DUP_BUFFERS; + else + BufferCount = buffer_count; + + ZeroMemory(&Priority,sizeof(Priority)); + ZeroMemory(&UserRef,sizeof(UserRef)); + + + // All is well. + ValidOn(); + + // Success. + return DS_OK; + +error: + // Failed. + if(hmmFile) + { + mmioClose(hmmFile,0); + hmmFile = NULL; + } + return DSERR_GENERIC; +} + +//--------------------------------------------------------------- + +HRESULT SampleInfo::LoadSampleData(void) +{ + int mm_error; + UBYTE *data_ptr1, + *data_ptr2; + ULONG c0, + data_count1, + data_count2; + DSBUFFERDESC ds_bd; + HRESULT result; + MMCKINFO mm_temp_chunk; + + + // Seek to the end of the RIFF chunk. + mm_error = mmioSeek(hmmFile,RIFFChunk.dwDataOffset+sizeof(FOURCC),SEEK_SET); + if(mm_error<0) + { + // Seek error. + return DSERR_GENERIC; + } + + // Now find the 'data' chunk. + mm_temp_chunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); + mm_error = mmioDescend(hmmFile,&mm_temp_chunk,&RIFFChunk,MMIO_FINDCHUNK); + if(mm_error!=0) + { + // Can't find data chunk. + return DSERR_GENERIC; + } + + // Now extract the size of the sample. + SampleSize = mm_temp_chunk.cksize; + + // Extract the base frequency. + BaseFrequency = WaveFormat.nSamplesPerSec; + + // If the loaded flag is set then the buffer has already been created, we just need to reload the data. + if(!IsLoaded()) + { + // Set up the buffer description + InitStruct(ds_bd); + + + // Please decide what DSBCAPS_flags you want to use - CTRLDEFAULT is legacy. + ASSERT ( FALSE ); + //ds_bd.dwFlags = DSBCAPS_CTRLDEFAULT; + ds_bd.dwFlags =0; + + + + + ds_bd.lpwfxFormat = &WaveFormat; + + if(IsStreamed()) + { + ds_bd.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY; + ds_bd.dwBufferBytes = 3*WaveFormat.nAvgBytesPerSec; + } + else + { + ds_bd.dwFlags |= DSBCAPS_STATIC; + ds_bd.dwBufferBytes = SampleSize; + } + + // Create the buffer. + result = the_sound_manager.CreateSoundBuffer(&ds_bd,&lp_DS_Buffer[0],NULL); + if(FAILED(result)) + { + // Unable to create sound buffer. + return result; + } + } + + // Now lock the buffer & copy the sample in. + result = lp_DS_Buffer[0]->Lock ( + 0,SampleSize, + (LPVOID*)&data_ptr1,&data_count1, + (LPVOID*)&data_ptr2,&data_count2, + DSBLOCK_ENTIREBUFFER + ); + if(result==DSERR_BUFFERLOST) + { + // Restore the lost buffer. + } + else if(FAILED(result)) + { + // Unable to lock buffer. + return result; + } + + if(IsStreamed()) + { + // Set up the streaming events. + SetUpNotifications(); + } + else + { + // Read the sample data in. + mm_error = mmioRead(hmmFile,(HPSTR)data_ptr1,data_count1); + if(mm_error!=(int)data_count1) + { + // Unable to read data, so unlock the buffer & exit. + lp_DS_Buffer[0]->Unlock(data_ptr1,data_count1,data_ptr2,data_count2); + return DSERR_GENERIC; + } + if(data_count2) + { + mm_error = mmioRead(hmmFile,(HPSTR)data_ptr2,data_count2); + if(mm_error!=(int)data_count2) + { + // Unable to read data, so unlock the buffer & exit. + lp_DS_Buffer[0]->Unlock(data_ptr1,data_count1,data_ptr2,data_count2); + return DSERR_GENERIC; + } + } + + // Now unlock the buffer. + result = lp_DS_Buffer[0]->Unlock(data_ptr1,data_count1,data_ptr2,data_count2); + } + + // Again we only need to do this if the LOADED flag is not set. + if(!IsLoaded()) + { + // Create the duplicate buffers. + for(c0=1;c0DuplicateSoundBuffer(lp_DS_Buffer[0],&lp_DS_Buffer[c0]); + } + } + + // We now have the main sample data loaded in. + LoadedOn(); + + // Success. + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT SampleInfo::FreeSampleData(void) +{ + return DS_OK; +} + +//--------------------------------------------------------------- + +void *SampleInfo::Play(SLONG user_ref,SLONG vol,SLONG pan,SLONG freq,SLONG priority) +{ + ULONG c0, + status; + SLONG buffer_index = 0, + flags=0, + lowest_pri = 0x7fffffff; + HRESULT result; + LPDIRECTSOUNDBUFFER buffer_ref = NULL; + + + if(IsValid()) + { + if(!IsLoaded()) + { + LoadSampleData(); + } + + if(IsLoaded()) + { + // Scan for the user reference to see if we're already playing this sample. + for(c0=0;c0GetStatus(&status)==DS_OK); + if(status&DSBSTATUS_PLAYING) + { + // Yes we are, so just set the control stuff & return. + VERIFY(Control(lp_DS_Buffer[c0],vol,pan,freq)==DS_OK); + return lp_DS_Buffer[c0]; + } + } + } + + // Find a buffer that isn't currently playing. + for(c0=0;c0GetStatus(&status)==DS_OK); + if(!status&DSBSTATUS_PLAYING) + { + // Got one. + buffer_ref = lp_DS_Buffer[c0]; + buffer_index = c0; + break; + } + else if(Priority[c0]=lowest_pri) + { + buffer_ref = lp_DS_Buffer[buffer_index]; + } + } + } + + if(buffer_ref) + { + // Ensure that the play position is at the start of the data. + VERIFY(buffer_ref->SetCurrentPosition(0)==DS_OK); + + // Set the sound buffer controls. + VERIFY(Control(buffer_ref,vol,pan,freq)==DS_OK); + + // Set the priority & the user reference. + Priority[buffer_index] = priority; + UserRef[buffer_index] = user_ref; + + // Set up the play flags. + if(IsLooped()) + flags = DSBPLAY_LOOPING; + + // Start the sample. + result = buffer_ref->Play(0,0,flags); + if(result==DSERR_BUFFERLOST) + { + Restore(buffer_ref); + result = buffer_ref->Play(0,0,flags); + } + if(FAILED(result)) + buffer_ref = NULL; + } + + return buffer_ref; +} + +//--------------------------------------------------------------- + +HRESULT SampleInfo::Control(LPDIRECTSOUNDBUFFER the_buf,SLONG vol,SLONG pan,SLONG freq) +{ + SLONG new_freq; + + + new_freq = BaseFrequency+freq; + in_range(new_freq,DSBFREQUENCY_MIN,DSBFREQUENCY_MAX); + VERIFY(the_buf->SetFrequency(new_freq)==DS_OK); + + in_range(pan,DSBPAN_LEFT,DSBPAN_RIGHT); + VERIFY(the_buf->SetPan(pan)==DS_OK); + + in_range(vol,DSBVOLUME_MIN,DSBVOLUME_MAX); + VERIFY(the_buf->SetVolume(vol)==DS_OK); + + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT SampleInfo::Restore(LPDIRECTSOUNDBUFFER the_buf) +{ + HRESULT result; + + + result = the_buf->Restore(); + if(SUCCEEDED(result)) + { + // If the buffer was lost then the sample data will have been too, + // so force a reload of the data. + if(IsLoaded()) + result = LoadSampleData(); + } + else + { + // If an error occured at this stage then the sample is probably lost for good. + // We probably need to do a tidy up of the DS buffer here. + } + + return result; +} + +//--------------------------------------------------------------- + +#define NUM_PLAY_NOTIFICATIONS 4 + +HRESULT SampleInfo::SetUpNotifications(void) +{ + //DSBPOSITIONNOTIFY dsbPosNotify[NUM_PLAY_NOTIFICATIONS +1 ]; + + + // Create the 2 events. One for Play one for Stop. + hNotifyEvent[0] = CreateEvent(NULL, FALSE, FALSE, NULL); + hNotifyEvent[1] = CreateEvent(NULL, FALSE, FALSE, NULL); + + // setup the first one. +// dsbPosNotify[0].dwOffset = dwSize; +// dsbPosNotify[0].hEventNotify = hNotifyEvent[0]; + + return DS_OK; +} + +//--------------------------------------------------------------- +// +// CLASS : SampleManager +// +//--------------------------------------------------------------- + +SampleManager::SampleManager() +{ + ManagerFlags = 0; + + SampleCount = 0; + SampleList = NULL; + SampleListEnd = NULL; +} + +//--------------------------------------------------------------- + +SampleManager::~SampleManager() +{ + DestroySamples(); +} + +//--------------------------------------------------------------- + +HRESULT SampleManager::LoadSamples(CBYTE *script_name) +{ + CBYTE sample_name[MAX_PATH]; + UBYTE looped, + rep_count, + sample_3d, + streamed; + FILE *script_handle; + HRESULT result = DSERR_GENERIC; + SampleInfo *new_sample; + + + // Get rid of any existing samples. + DestroySamples(); + + // Open the script file. + script_handle = MF_Fopen(script_name,"r"); + if(script_handle) + { + while(fscanf(script_handle,"%s %d %d %d %d",sample_name,&rep_count,&looped,&streamed,&sample_3d)>0) + { + new_sample = MFnew(); + if(new_sample) + { + // Initialise the sample. + result = new_sample->Create(sample_name,rep_count); + if(FAILED(result)) + { + MFdelete(new_sample); + return result; + } + + // Set up attributes. + if(looped) + new_sample->LoopedOn(); + if(streamed) + new_sample->StreamedOn(); + if(sample_3d) + new_sample->Sample3DOn(); + + // Add the sample to the list. + result = AddSample(new_sample); + if(FAILED(result)) + { + MFdelete(new_sample); + return result; + } + } + } + + // Finished with the script. + MF_Fclose(script_handle); + } + + return DSERR_GENERIC; +} + +//--------------------------------------------------------------- + +HRESULT SampleManager::DestroySamples(void) +{ + SampleInfo *current_sample, + *next_sample; + + + current_sample = SampleList; + while(current_sample) + { + next_sample = current_sample->Next; + + MFdelete(current_sample); + + current_sample = next_sample; + } + + SampleCount = 0; + SampleList = NULL; + SampleListEnd = NULL; + + // Success. + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT SampleManager::AddSample(SampleInfo *the_sample) +{ + if(!the_sample) + { + // Error, Invalid parameters + return DSERR_GENERIC; + } + + // Add sample to list. + the_sample->Prev = SampleListEnd; + the_sample->Next = NULL; + + // Update list end. + if(SampleListEnd) + SampleListEnd->Next = the_sample; + SampleListEnd = the_sample; + + // Update list. + if(!SampleList) + SampleList = the_sample; + + SampleCount++; + + return DS_OK; +} + +//--------------------------------------------------------------- + +HRESULT SampleManager::DeleteSample(SampleInfo *the_sample) +{ + return DS_OK; +} + +//--------------------------------------------------------------- diff --git a/fallen/DDLibrary/Source/Tga.cpp b/fallen/DDLibrary/Source/Tga.cpp new file mode 100644 index 0000000..851bfd4 --- /dev/null +++ b/fallen/DDLibrary/Source/Tga.cpp @@ -0,0 +1,1384 @@ +// +// Loads in 32-bit RGBA uncompressed TGAs. +// + +#include +#include "Tga.h" +#include "FileClump.h" + + + + + +#ifdef TARGET_DC + + +#ifdef DEBUG +// For quick loading +//#define BOGUS_TGAS_PLEASE_BOB I have been defined +// Do a downsample of textures to minimise memory use for now. +// This is a two-to-the-power one, so "2" means quarter the size. +//#define DOWNSAMPLE_PLEASE_BOB_AMOUNT 2 +#else +// For quick loading +//#define BOGUS_TGAS_PLEASE_BOB I have been defined +// Do a downsample of textures to minimise memory use for now. +// This is a two-to-the-power one, so "2" means quarter the size. +//#define DOWNSAMPLE_PLEASE_BOB_AMOUNT 2 +#endif + +// Don't downsample any smaller than this. +#define DOWNSAMPLE_MINIMUM_SIZE 16 + + +#endif + + +static FileClump* tclump = NULL; +static bool writing; +static bool init_convert = false; + +TGA_Info TGA_load_from_file(const CBYTE *file, SLONG max_width, SLONG max_height, TGA_Pixel* data, BOOL bCanShrink = TRUE); + +#ifndef TARGET_DC +static void TGA_make_conversion_tables(void); +static void TGA_write_compressed(const TGA_Info& ti, TGA_Pixel* data, ULONG id); +static TGA_Info TGA_read_compressed(TGA_Pixel* data, ULONG id, SLONG max_width, SLONG max_height); +#endif + + + +#ifndef TARGET_DC +// OpenTGAClump +// +// create a texture clump + +void OpenTGAClump(const char* clumpfn, size_t maxid, bool readonly) +{ + if (!init_convert) + { + TGA_make_conversion_tables(); + init_convert = true; + } + + delete tclump; + tclump = NULL; + + writing = !readonly; + + tclump = new FileClump(clumpfn, maxid, readonly); +} + +// CloseTGAClump +// +// close a texture clump + +void CloseTGAClump() +{ + delete tclump; + tclump = NULL; +} + +// GetTGAClump +// +// return tclump + +FileClump* GetTGAClump() +{ + ASSERT(tclump); + return tclump; +} + +#endif //#ifndef TARGET_DC + + +// DoesTGAExist +// +// look for a TGA + +bool DoesTGAExist(const char* filename, ULONG id) +{ + if (writing) + { + FILE* fd = MF_Fopen(filename, "rb"); + if (fd) + { + MF_Fclose(fd); + return true; + } + return false; + } + else + { + return tclump->Exists(id); + } +} + + +// TGA_load +// +// loads a TGA + +SLONG tga_width; +SLONG tga_height; + +TGA_Info TGA_load(const CBYTE* file, SLONG max_width, SLONG max_height, TGA_Pixel* data, ULONG id, BOOL bCanShrink ) +{ +#ifdef TARGET_DC + ASSERT (!tclump || (id == -1)); +#else + if (!tclump || (id == -1)) +#endif + { + // read directly from file + return TGA_load_from_file(file, max_width, max_height, data, bCanShrink); + } + +#ifndef TARGET_DC + if (writing) + { + // read from file, then write compressed + TGA_Info ti = TGA_load_from_file(file, max_width, max_height, data); + TGA_write_compressed(ti, data, id); + return ti; + } + + // read compressed + return TGA_read_compressed(data, id, max_width, max_height); +#endif + +} + +// TGA_load_from_file +// +// load a TGA from file + +TGA_Info TGA_load_from_file(const CBYTE *file, SLONG max_width, SLONG max_height, TGA_Pixel* data, BOOL bCanShrink) +{ + + + + SLONG i; + SLONG x; + SLONG y; + SLONG y1; + SLONG y2; + + //UBYTE red; + //UBYTE green; + //UBYTE blue; + + SLONG tga_pixel_depth; + SLONG tga_image_type; + SLONG tga_id_length; + + SLONG tga_pal; + + UBYTE header[18]; + UBYTE definitely_no_alpha; + + FILE* fd; + + TGA_Info ans; + UBYTE pal[256*3]; + + + + +#ifdef BOGUS_TGAS_PLEASE_BOB + if ( bCanShrink ) + { + // Fast dodgy textures that don't need loading. + ans.valid = 1; + ans.width = 16; + ans.height = 16; + ans.contains_alpha = 1; + ASSERT ( max_width >= ans.width ); + ASSERT ( max_height >= ans.height ); + + TGA_Pixel *pdest = data; + DWORD junk; + while ( *file != '\0' ) + { + junk ^= *file++; + junk ^= ( junk >> 2 ) ^ ( junk << 1 ); + } + junk ^= ( junk << 3 ) ^ ( junk >> 2 ) ^ ( junk >> 13 ) ^ ( junk >> 21 ) ^ ( junk >> 16 ); + for ( int i = 0; i < ans.height; i++ ) + { + for ( int j = 0; j < ans.width; j++ ) + { + int num = ( i & 1 ) | ( ( j & 1 ) << 1 ); + pdest->alpha = (UBYTE)( junk >> ( num ) ); + pdest->red = (UBYTE)( junk >> ( num + 1 ) ); + pdest->green = (UBYTE)( junk >> ( num + 2 ) ); + pdest->blue = (UBYTE)( junk >> ( num + 3 ) ); + pdest++; + } + } + + return ( ans ); + } + +#endif + + + // + // Open the file. + // + + fd = MF_Fopen(file, "rb"); + if (!fd) + { + ans.valid = 0; + return ans; + } + + // + // Read the header. + // + + if (fread(header, 1, 18, fd) != 18) goto file_error; + + // + // Extract info from the header. + // + + tga_id_length = header[0x0]; + tga_pal = header[1]; + tga_image_type = header[0x2]; + tga_width = header[0xc] + header[0xd] * 256; + tga_height = header[0xe] + header[0xf] * 256; + tga_pixel_depth = header[0x10]; + + // + // Is this a valid tga file? + // + + ans.valid = 0; + ans.width = tga_width; + ans.height = tga_height; + ans.contains_alpha = 0; + + if (tga_image_type != 2 && tga_pal!=1) + { + TRACE("Tga must be true colour and uncompressed.\n"); + MF_Fclose(fd); + return ans; + } + + if (tga_pixel_depth != 32 && tga_pixel_depth != 24 && tga_pal!=1) + { + TRACE("Tga must be 32-bit or 24-bit (24-bit + 8-bit alpha channel)\n"); + MF_Fclose(fd); + return ans; + } + + if (tga_width > max_width || + tga_height > max_height) + { + TRACE("Invalid dimensions:\n\tWanted <= %d x %d\n\tGot %d x %d\n", max_width, max_height, tga_width, tga_height); + MF_Fclose(fd); + return ans; + } + + // + // The tga file is valid... + // + + ans.valid = 1; + + // + // Skip past the image identification field. + // + + fseek(fd, tga_id_length, SEEK_CUR); + + if (header[0x1]) + { + UBYTE col; + // + // The file has colour map data- but how much? + // + + SLONG entries = header[5] + header[6] * 256; + SLONG bitsperentry = header[7]; + ULONG length; + + length = ( entries * bitsperentry + 7 ) >> 3; + ASSERT(length<=256*3); + + if (fread(&pal[0], 1, length, fd) != length) goto file_error; + + UBYTE* buffer = new UBYTE[tga_width * tga_height]; + if (fread(buffer, 1, tga_width * tga_height, fd) != tga_width * tga_height) goto file_error; + UBYTE* bp = buffer; + + for (i = 0; i < tga_width * tga_height; i++) + { + col = *bp++; + + data[i].red=pal[col*3+2]; + data[i].green=pal[col*3+1]; + data[i].blue=pal[col*3+0]; + data[i].alpha = 255; + + definitely_no_alpha = 1; + } + + delete[] buffer; + } + else + { + + // + // Load in the data. + // + + if (tga_pixel_depth == 32) + { + if (fread(data, 1, sizeof(TGA_Pixel) * tga_width * tga_height, fd) != sizeof(TGA_Pixel) * tga_width * tga_height) goto file_error; + + // + // Might be alpha channel data... + // + + definitely_no_alpha = 0; + } + else + { + // + // We have to load a pixel in at a time to add the NULL alpha channel. + // + + UBYTE* buffer = new UBYTE[3 * tga_width * tga_height]; + if (fread(buffer, 1, 3 * tga_width * tga_height,fd) != 3 * tga_width * tga_height) goto file_error; + UBYTE* bp = buffer; + + for (i = 0; i < tga_width * tga_height; i++) + { + data[i].blue = *bp++; + data[i].green = *bp++; + data[i].red = *bp++; + data[i].alpha = 255; + } + + delete[] buffer; + + // + // There is no alpha channel data. + // + + definitely_no_alpha = 1; + } + } + + MF_Fclose(fd); + + // + // All ok. Does this tga contain any alpha? + // + + if (definitely_no_alpha == 0) + { + for (i = 0; i < tga_width * tga_height; i++) + { + if (data[i].alpha != 255) + { + // + // Found alpha channel data. + // + + ans.contains_alpha = 1; + + break; + } + } + } + else + { + ans.contains_alpha = 0; + } + + // + // TGAs are stored upside down to what we expect. + // + + TGA_Pixel spare; + + for (y = 0; y < tga_height / 2; y++) + { + y1 = y; + y2 = tga_height - 1 - y; + + for (x = 0; x < tga_width; x++) + { + spare = data[x + y1 * tga_width]; + data[x + y1 * tga_width] = data[x + y2 * tga_width]; + data[x + y2 * tga_width] = spare; + } + } + +#ifdef DOWNSAMPLE_PLEASE_BOB_AMOUNT + // OK, now downsample the image + if ( bCanShrink ) + { + int iPasses = DOWNSAMPLE_PLEASE_BOB_AMOUNT; + while ( iPasses-- > 0 ) + { + if ( ( tga_width <= DOWNSAMPLE_MINIMUM_SIZE ) || ( tga_height <= DOWNSAMPLE_MINIMUM_SIZE ) ) + { + // Stop! + break; + } + tga_width >>= 1; + tga_height >>= 1; + ans.width = tga_width; + ans.height = tga_height; + + // Just a cheesy in-place box filter. + TGA_Pixel *psrc1 = data; + TGA_Pixel *psrc2 = data + ( tga_width << 1 ); + TGA_Pixel *pdest = data; + + for ( int j = tga_height; j > 0; j-- ) + { + for ( int k = tga_width; k > 0; k-- ) + { + pdest->alpha = (UBYTE)( ( (DWORD)psrc1[0].alpha + (DWORD)psrc1[1].alpha + (DWORD)psrc2[0].alpha + (DWORD)psrc2[1].alpha ) >> 2 ); + pdest->red = (UBYTE)( ( (DWORD)psrc1[0].red + (DWORD)psrc1[1].red + (DWORD)psrc2[0].red + (DWORD)psrc2[1].red ) >> 2 ); + pdest->green = (UBYTE)( ( (DWORD)psrc1[0].green + (DWORD)psrc1[1].green + (DWORD)psrc2[0].green + (DWORD)psrc2[1].green ) >> 2 ); + pdest->blue = (UBYTE)( ( (DWORD)psrc1[0].blue + (DWORD)psrc1[1].blue + (DWORD)psrc2[0].blue + (DWORD)psrc2[1].blue ) >> 2 ); + pdest++; + psrc1 += 2; + psrc2 += 2; + } + psrc1 += tga_width<<1; + psrc2 += tga_width<<1; + } + } + } +#endif + + return ans; + + file_error:; + + // + // Error! + // + + TRACE("File error loading TGA file %s\n", file); + MF_Fclose(fd); + ans.valid = 0; + + return ans; +} + +#ifndef TARGET_DC + +// WriteSquished +// +// write out a file, squished + +static void WriteSquished(UWORD* buffer, size_t nwords, ULONG id) +{ + UWORD used[65536]; + UWORD mapping[65536]; + + memset(used, 0, 65536*2); + + UWORD total = 0; + + for (size_t ii = 3; ii < nwords; ii++) + { + if (!used[buffer[ii]]) + { + used[buffer[ii]] = total + 1; + mapping[total] = buffer[ii]; + total++; + } + } + + int bits = 1; + + while (total > (1 << bits)) bits++; + + int bits_required = bits * (nwords - 3) + (5 + total) * 16; + int bits_normal = 16 * nwords; + + if (bits_required < bits_normal) + { + UWORD* squished = new UWORD[(bits_required + 15) / 16]; + UWORD* sptr = squished; + + *sptr++ = 0xFFFF; // marker for compressed file + *sptr++ = buffer[0]; + *sptr++ = buffer[1]; + *sptr++ = buffer[2]; + *sptr++ = total; + + for (ii = 0; ii < total; ii++) + { + *sptr++ = mapping[ii]; + } + + // write out bit-encoded data + // 10-bit A,B,C,D into 16 bits goes: + // 0xAAAAAAAAAABBBBBB 0xBBBBCCCCCCCCCCDD 0xDDDDDDDD00000000 + + UWORD cword = 0; // current word + UWORD cbits = 0; // # bits in current word + + for (ii = 3; ii < nwords; ii++) + { + UWORD encoded = used[buffer[ii]] - 1; + + ASSERT(encoded < total); + + if (cbits + bits > 16) + { + // add (16 - cbits) bits and write out + cword <<= (16 - cbits); + cword |= encoded >> (bits - (16 - cbits)); + *sptr++ = cword; + // store low bits and remember how many + cword = encoded; + cbits = bits - (16 - cbits); + } + else + { + // add (bits) bits + cword <<= bits; + cword |= encoded; + cbits += bits; + } + } + + if (cbits) *sptr++ = (cword << (16 - cbits)); + + ASSERT((sptr - squished) == ((bits_required + 15) / 16)); + + tclump->Write(squished, 2 * (sptr - squished), id); + delete[] squished; + } + else + { + tclump->Write(buffer, 2 * nwords, id); + } +} + +// ReadSquished +// +// read in a squished file + +static UBYTE* ReadSquished(ULONG id) +{ + // read squished file + UBYTE* buffer = tclump->Read(id); + if (!buffer) return NULL; + + UWORD* bptr = (UWORD*)buffer; + + if (*bptr != 0xFFFF) return buffer; // unsquished + + bptr++; + + // allocate output buffer + size_t nwords = bptr[1] * bptr[2]; + + UBYTE* output = new UBYTE[2 * (nwords + 3)]; + UWORD* optr = (UWORD*)output; + + // copy header + *optr++ = *bptr++; + *optr++ = *bptr++; + *optr++ = *bptr++; + + // read mapping + UWORD total = *bptr++; + UWORD mapping[65536]; + + for (size_t ii = 0; ii < total; ii++) + { + mapping[ii] = *bptr++; + } + + int bits = 1; + + while (total > (1 << bits)) bits++; + + // read bit-encoded data + int cbits = 16; + UWORD cword = *bptr++; + + for (ii = 0; ii < nwords; ii++) + { + UWORD encoded; + + if (cbits > bits) + { + // read (bits) bits + encoded = cword >> (16 - bits); + cword <<= bits; + cbits -= bits; + } + else + { + // read (16 - cbits) bits + int xbits = bits - cbits; + encoded = cword >> (16 - bits); + cword = *bptr++; + cbits = 16; + encoded |= (cword >> (16 - xbits)); + cword <<= xbits; + cbits -= xbits; + } + + ASSERT(encoded < total); + + *optr++ = mapping[encoded]; + } + + delete[] buffer; + + return output; +} + +// TGA_make_conversion_tables +// +// make conversion tables + +static UBYTE C8to4[256]; +static UBYTE C8to5[256]; +static UBYTE C8to6[256]; +static UBYTE C4to8[16]; +static UBYTE C5to8[32]; +static UBYTE C6to8[64]; + +static void TGA_make_conversion_tables(void) +{ + int ii; + + for (ii = 0; ii < 256; ii++) + { + C8to4[ii] = (((ii * 30) / 256) + 1) / 2; + C8to5[ii] = (((ii * 62) / 256) + 1) / 2; + C8to6[ii] = (((ii * 126) / 256) + 1) / 2; + } + + for (ii = 0; ii < 16; ii++) C4to8[ii] = (ii << 4) | ii; + for (ii = 0; ii < 32; ii++) C5to8[ii] = (ii << 3) | (ii >> 2); + for (ii = 0; ii < 64; ii++) C6to8[ii] = (ii << 2) | (ii >> 4); +} + + +// TGA_write_compressed +// +// write a TGA out compressed + +static void TGA_write_compressed(const TGA_Info& ti, TGA_Pixel* data, ULONG id) +{ + if (!ti.valid) return; + if (tclump->Exists(id)) return; + + UWORD* buffer = new UWORD[ti.width * ti.height + 3]; + UWORD* bptr = buffer; + + *bptr++ = (UWORD)ti.contains_alpha; + *bptr++ = (UWORD)ti.width; + *bptr++ = (UWORD)ti.height; + + if (ti.contains_alpha) + { + // compress to 4:4:4:4 + for (int ii = 0; ii < ti.width * ti.height; ii++) + { + UWORD pix; + + pix = C8to4[data->blue]; + pix |= C8to4[data->green] << 4; + pix |= C8to4[data->red] << 8; + pix |= C8to4[data->alpha] << 12; + + *bptr++ = pix; + data++; + } + } + else + { + // compress to 5:6:5 + for (int ii = 0; ii < ti.width * ti.height; ii++) + { + UWORD pix; + + pix = C8to5[data->blue]; + pix |= C8to6[data->green] << 5; + pix |= C8to5[data->red] << 11; + + *bptr++ = pix; + data++; + } + } + + WriteSquished(buffer, ti.width * ti.height + 3, id); + delete[] buffer; +} + +// TGA_read_compressed +// +// read a TGA in compressed + +static TGA_Info TGA_read_compressed(TGA_Pixel* data, ULONG id, SLONG max_width, SLONG max_height) +{ + TGA_Info ti; + + ti.valid = 0; + + if (!tclump->Exists(id)) return ti; + + UBYTE* buffer = ReadSquished(id); + if (!buffer) return ti; + UWORD* bptr = (UWORD*)buffer; + + ti.valid = 1; + ti.contains_alpha = *bptr++; + ti.width = *bptr++; + ti.height = *bptr++; + + ASSERT(ti.width <= max_width); + ASSERT(ti.height <= max_height); + + if (ti.contains_alpha) + { + // compress to 4:4:4:4 + for (int ii = 0; ii < ti.width * ti.height; ii++) + { + UWORD pix = *bptr++; + + data->blue = C4to8[pix & 0xF]; + data->green = C4to8[(pix >> 4) & 0xF]; + data->red = C4to8[(pix >> 8) & 0xF]; + data->alpha = C4to8[(pix >> 12) & 0xF]; + data++; + } + } + else + { + // compress to 5:6:5 + for (int ii = 0; ii < ti.width * ti.height; ii++) + { + UWORD pix = *bptr++; + + data->blue = C5to8[pix & 0x1F]; + data->green = C6to8[(pix >> 5) & 0x3F]; + data->red = C5to8[(pix >> 11) & 0x1F]; + data->alpha = 0; + data++; + } + } + + delete[] buffer; + return ti; +} + +TGA_Info TGA_load_remap(const CBYTE *file,const CBYTE *pname,SLONG max_width,SLONG max_height,TGA_Pixel *data) +{ + SLONG i; + SLONG x; + SLONG y; + SLONG y1; + SLONG y2; + + SLONG tga_pixel_depth; + SLONG tga_image_type; + SLONG tga_id_length; + + SLONG tga_pal; + + UBYTE header[18]; + UBYTE junk; + UBYTE definitely_no_alpha; + + FILE *handle,*phandle; + + TGA_Info ans; + UBYTE pal[256*3]; + UBYTE remap_pal[256*4]; + + // + // Open the file. + // + + phandle = MF_Fopen(pname, "rb"); + if (phandle == NULL) + { + ans.valid = 0; + return ans; + } + + if (fread(&pal[0], 1, 24, phandle) != 24) + goto file_error; + + if (fread(&remap_pal[0], 1, 256*4, phandle) != 256*4) + goto file_error; + + MF_Fclose(phandle); + + { + SLONG pal1=0,pal2=0,c0; + for(c0=0;c0<16*4;c0++) + pal1+=remap_pal[c0]; + + for(c0=240*4;c0<256*4;c0++) + pal2+=remap_pal[c0]; + + if(pal2>pal1) + { + + // + // shunt the pallette down + // + for(c0=0;c0<16*4;c0++) + { + remap_pal[c0]=remap_pal[240*4+c0]; + } + } + + } + + + + handle = MF_Fopen(file, "rb"); + + if (handle == NULL) + { + ans.valid = 0; + return ans; + } + + + // + // Read the header. + // + + if (fread(header, sizeof(UBYTE), 18, handle) != 18) goto file_error; + + // + // Extract info from the header. + // + + tga_id_length = header[0x0]; + tga_pal = header[1]; + tga_image_type = header[0x2]; + tga_width = header[0xc] + header[0xd] * 256; + tga_height = header[0xe] + header[0xf] * 256; + tga_pixel_depth = header[0x10]; + + // + // Is this a valid tga file? + // + + ans.valid = 0; + ans.width = tga_width; + ans.height = tga_height; + ans.contains_alpha = 0; + + if (tga_pal!=1) + { + TRACE("Tga must be true colour and uncompressed.\n"); + MF_Fclose(handle); + return ans; + } + + + if (tga_width > max_width || + tga_height > max_height) + { + TRACE("Invalid dimensions:\n\tWanted <= %d x %d\n\tGot %d x %d\n", max_width, max_height, tga_width, tga_height); + MF_Fclose(handle); + return ans; + } + + // + // The tga file is valid... + // + + ans.valid = 1; + + // + // Skip past the image identification field. + // + + for (i = 0; i < tga_id_length; i++) + { + if (fread(&junk, sizeof(UBYTE), 1, handle) != 1) goto file_error; + } + + if (header[0x1]) + { + UBYTE col; + // + // The file has colour map data- but how much? + // + + SLONG entries = header[5] + header[6] * 256; + SLONG bitsperentry = header[7]; + SLONG length; + + length = ( entries * bitsperentry + 7 ) >> 3; + ASSERT(length<=256*3); + + { + if (fread(&pal[0], sizeof(UBYTE), length, handle) != length) + goto file_error; + + } + for (i = 0; i < tga_width * tga_height; i++) + { + if (fread(&col, sizeof(UBYTE), 1, handle) != 1) + goto file_error; + col=255-col; + + col&=15; + + data[i].red=remap_pal[col*4+0]; + data[i].green=remap_pal[col*4+1]; + data[i].blue=remap_pal[col*4+2]; + data[i].alpha = 255; + + } + definitely_no_alpha = 1; + } + + MF_Fclose(handle); + + // + // All ok. Does this tga contain any alpha? + // + + { + ans.contains_alpha = 0; + } + + // + // TGAs are stored upside down to what we expect. + // + + TGA_Pixel spare; + + for (y = 0; y < tga_height / 2; y++) + { + y1 = y; + y2 = tga_height - 1 - y; + + for (x = 0; x < tga_width; x++) + { + spare = data[x + y1 * tga_width]; + data[x + y1 * tga_width] = data[x + y2 * tga_width]; + data[x + y2 * tga_width] = spare; + } + } + + return ans; + + file_error:; + + // + // Error! + // + + TRACE("File error loading TGA file %s\n", file); + MF_Fclose(handle); + ans.valid = 0; + + return ans; +} + +#endif //#ifndef TARGET_DC + + + +#ifndef TARGET_DC + +// +// expects to load a 16 colour indexed palletised tga +// +extern volatile HWND hDDLibWindow; + +void psx_load_error(CBYTE *err,const CBYTE *fname) +{ +#ifndef TARGET_DC + CBYTE title[256]; + + // + // Tell the user about not loading the waypoint. + // + + sprintf(title, "err >%s< fname >%s<",err,fname); + + MessageBox( + hDDLibWindow, + title, + "psx texture error", + MB_OK | MB_ICONERROR | MB_APPLMODAL); +#endif +} + + +TGA_Info TGA_load_psx(const CBYTE *file,SLONG max_width,SLONG max_height,UBYTE *data,UBYTE *pal) +{ + SLONG i; + SLONG x; + SLONG y; + SLONG y1; + SLONG y2; + + UBYTE red; + UBYTE green; + UBYTE blue; + + SLONG tga_pixel_depth; + SLONG tga_image_type; + SLONG tga_id_length; + + SLONG tga_pal; + + UBYTE header[18]; + UBYTE junk; + UBYTE definitely_no_alpha; + + FILE *handle; + + TGA_Info ans; + + // + // Open the file. + // + + handle = MF_Fopen(file, "rb"); + + if (handle == NULL) + { + psx_load_error("dont exist",file); + DebugText(" %s dont exist \n",file); + ans.valid = 0; + return ans; + } + else + DebugText(" file %s exists \n",file); + + // + // Read the header. + // + + if (fread(header, sizeof(UBYTE), 18, handle) != 18) goto file_error; + + // + // Extract info from the header. + // + + tga_id_length = header[0x0]; + tga_pal = header[1]; + tga_image_type = header[0x2]; + tga_width = header[0xc] + header[0xd] * 256; + tga_height = header[0xe] + header[0xf] * 256; + tga_pixel_depth = header[0x10]; + + // + // Is this a valid tga file? + // + + ans.valid = 0; + ans.width = tga_width; + ans.height = tga_height; + ans.contains_alpha = 0; + + if(tga_pal!=1 && tga_image_type!=3) + { + psx_load_error("no pal/greyscale",file); + TRACE("missing pal\n"); + MF_Fclose(handle); + return ans; + } + + + if (tga_width > max_width || + tga_height > max_height) + { + psx_load_error("funny size",file); + + TRACE("Invalid dimensions:\n\tWanted <= %d x %d\n\tGot %d x %d\n", max_width, max_height, tga_width, tga_height); + MF_Fclose(handle); + return ans; + } + + // + // The tga file is valid... + // + + ans.valid = 1; + + // + // Skip past the image identification field. + // + + for (i = 0; i < tga_id_length; i++) + { + if (fread(&junk, sizeof(UBYTE), 1, handle) != 1) goto file_error; + } + + if (tga_pal) + { + UBYTE col,palpos=0; + // + // The file has colour map data- but how much? + // + + SLONG entries = header[5] + header[6] * 256; + SLONG bitsperentry = header[7]; + SLONG length; + + length = entries * bitsperentry + 7 >> 3; + ASSERT(length<=256*3); + + if (fread(&pal[i], sizeof(UBYTE), length, handle) != length) + goto file_error; + + if (fread(data, sizeof(UBYTE),tga_width * tga_height, handle) != tga_width * tga_height) + goto file_error; + + // + // make data compatable with alternative palettes + // + if(tga_width==64) + { + SLONG temp; + + for (i = 0; i < tga_width * tga_height; i++) + { + data[i]=255-data[i]; + data[i]&=15; + } + + for(i=0;i>1;i++) + { + + temp=pal[i]; + pal[i]=pal[length-i-1]; + pal[length-i-1]=temp; + + } + } + else + { + for(i=0;i<(length/3);i++) + { + SLONG t; + + t=pal[i*3+0]; + pal[i*3+0]=pal[i*3+2]; + pal[i*3+2]=t; + } + } + + + { + SLONG pal1=0,pal2=0,c0; + if(length>=255*3) + { + for(c0=0;c0<16*3;c0++) + pal1+=pal[c0]; + for(c0=240*3;c0<256*3;c0++) + pal2+=pal[c0]; + if(pal2>pal1) + { + + // + // shunt the pallette down + // + for(c0=0;c0<16*3;c0++) + { + pal[c0]=pal[240*3+c0]; + } + } + } + } + + // + // read the pal indexes straight in, no conversion to RGB + // + + } + else + { + if(tga_image_type!=3) + { + psx_load_error("not gray scale",file); + + TRACE(" not gray scale!\n"); + return ans; + } + SLONG c0; + UBYTE remap[256]; + SLONG next_pal=0; + memset(remap,0,255); + if (fread(data, sizeof(UBYTE),tga_width * tga_height, handle) != tga_width * tga_height) + goto file_error; + + for(c0=0;c0> 8; + header[0xe] = height & 0xff; + header[0xf] = height >> 8; + + header[0x10] = (contains_alpha) ? 32 : 24; + + // + // Write out the header. + // + + fwrite(&header, sizeof(UBYTE), 18, handle); + + // + // Write out the pixel data. + // + + for (y = height - 1; y >= 0; y--) + for (x = 0; x < width; x++) + { + if (contains_alpha) + { + fwrite(&data[x + y * width].alpha, sizeof(UBYTE), 1, handle); + } + + fwrite(&data[x + y * width].blue, sizeof(UBYTE), 1, handle); + fwrite(&data[x + y * width].green, sizeof(UBYTE), 1, handle); + fwrite(&data[x + y * width].red, sizeof(UBYTE), 1, handle); + } + + MF_Fclose(handle); +} + + +#endif //#ifndef TARGET_DC + + + + diff --git a/fallen/DDLibrary/Source/WindProcs.cpp b/fallen/DDLibrary/Source/WindProcs.cpp new file mode 100644 index 0000000..07ffbb6 --- /dev/null +++ b/fallen/DDLibrary/Source/WindProcs.cpp @@ -0,0 +1,733 @@ +// WindProcs.cpp +// Guy Simmons, 14th November 1997. + +#include "DDLib.h" +//#include "finaleng.h" +#include "BinkClient.h" +#include "c:\fallen\headers\music.h" +#include "c:\fallen\headers\game.h" + +extern void MFX_QUICK_stop(void); + +#ifndef TARGET_DC + + +//--------------------------------------------------------------- + +BOOL FAR PASCAL AboutBoxProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_COMMAND: + if(LOWORD(wParam)==IDOK || LOWORD(wParam)==IDCANCEL) + EndDialog(hDlg,TRUE); + break; + case WM_INITDIALOG: + return TRUE; + } + return FALSE; +} + +//--------------------------------------------------------------- + +BOOL DlgDriversInit(HWND hDlg) +{ + SLONG result; + ChangeDDInfo *change_info; + DDDriverInfo *current_driver, + *driver_list; + GUID *DD_guid; + TCHAR szBuff[80]; + + + // Check Parameters + change_info = (ChangeDDInfo*)(void *)GetWindowLong (hDlg, DWL_USER); + if(!change_info) + return FALSE; + + current_driver = change_info->DriverNew; + + // Validate Driver + if(!current_driver) + DD_guid = NULL; + else + DD_guid = current_driver->GetGuid(); + current_driver = ValidateDriver(DD_guid); + if(!current_driver) + return FALSE; + + // Dump Driver list to Combo Box + driver_list = the_manager.DriverList; + while(driver_list) + { + if(driver_list->IsPrimary()) + wsprintf(szBuff,TEXT("%s (Primary)"),driver_list->szName); + else + wsprintf(szBuff,TEXT("%s"),driver_list->szName); + + // Add String to Combo Box + result = SendDlgItemMessage(hDlg, IDC_DRIVERS, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuff); + + // Set up pointer to driver for this item + SendDlgItemMessage(hDlg, IDC_DRIVERS, CB_SETITEMDATA, (WPARAM)result, (LPARAM)(void *)driver_list); + + // Is it the current Driver + if(current_driver==driver_list) + { + // Set as our current selection + SendDlgItemMessage (hDlg, IDC_DRIVERS, CB_SETCURSEL, (WPARAM)result, 0L); + } + driver_list = driver_list->Next; + } + + // Success + return TRUE; +} + + +BOOL DlgDevicesInit(HWND hDlg) +{ + SLONG result; + ChangeDDInfo *change_info; + D3DDeviceInfo *current_device, + *device_list; + DDDriverInfo *current_driver; + GUID *D3D_guid; + TCHAR szBuff[80]; + + + // Check Parameters + change_info = (ChangeDDInfo*)(void *)GetWindowLong(hDlg, DWL_USER); + if(!change_info) + return FALSE; + + current_driver = change_info->DriverNew; + if(!current_driver) + return FALSE; + + current_device = change_info->DeviceNew; + + // Validate Device + if(!current_device) + D3D_guid = NULL; + else + D3D_guid = &(current_device->guid); + current_device = ValidateDevice(current_driver, D3D_guid, NULL); + if(!current_device) + return FALSE; + + // Dump Device list to Combo Box + device_list = current_driver->DeviceList; + while(device_list) + { + // Get Device String + wsprintf(szBuff,TEXT("%s"),device_list->szName); + + // Add String to Combo Box + result = SendDlgItemMessage(hDlg, IDC_DEVICES, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuff); + + // Set up pointer to device for this item + SendDlgItemMessage(hDlg, IDC_DEVICES, CB_SETITEMDATA, (WPARAM)result, (LPARAM)(void *)device_list); + + // Is it the current device + if(current_device==device_list) + { + // Set as our current selection + SendDlgItemMessage(hDlg, IDC_DEVICES, CB_SETCURSEL, (WPARAM)result, 0L); + } + device_list = device_list->Next; + } + + // Success + return TRUE; +} + + +int _cdecl CompareModes(const void *element1, const void *element2) +{ + int compare = 0; + SLONG w1,w2, + h1,h2, + bpp1,bpp2, + refresh1,refresh2; + DDModeInfo *mode1, + *mode2; + + + mode1 = *((DDModeInfo**)element1); + mode2 = *((DDModeInfo**)element2); + + // Handle Null pointers + if((!mode1) && (!mode2)) + return 0; + if((mode1) && (!mode2)) + return -1; + if((!mode1) && (mode2)) + return 1; + + // Get Mode Data + mode1->GetMode(&w1,&h1,&bpp1,&refresh1); + mode2->GetMode(&w2,&h2,&bpp2,&refresh2); + + // Sort first on BPP then width then height + if(bpp1 < bpp2) + compare = -1; + else if(bpp1 > bpp2) + compare = 1; + else if(w1 < w2) + compare = -1; + else if(w1 > w2) + compare = 1; + else if(h1 < h2) + compare = -1; + else if(h1 > h2) + compare = 1; + + // Equality + return compare; +} + + +BOOL DlgModesInit (HWND hDlg) +{ + SLONG buffer_size, + index, + mode_count, + result, + w,h,bpp,refresh; + ChangeDDInfo *change_info; + D3DDeviceInfo *current_device; + DDDriverInfo *current_driver; + DDModeInfo *current_mode, + *mode_list, + **mode_buffer; + TCHAR szBuff[80]; + + + // Check Parameters + change_info = (ChangeDDInfo*)(void *)GetWindowLong(hDlg, DWL_USER); + if(!change_info) + return FALSE; + + current_driver = change_info->DriverNew; + current_device = change_info->DeviceNew; + current_mode = change_info->ModeNew; + + if(!current_driver) + return FALSE; + + if(!current_device) + { + current_device = ValidateDevice(current_driver, NULL, NULL); + if(!current_device) + return FALSE; + } + + mode_count = current_driver->CountModes(); + if(!mode_count) + return FALSE; + + if(!current_mode) + { + current_mode = ValidateMode( + current_driver, + DEFAULT_WIDTH, + DEFAULT_HEIGHT, + DEFAULT_DEPTH, + 0, + current_device + ); + } + + // Get memory for Mode list + buffer_size = mode_count * sizeof(DDModeInfo*); + mode_buffer = (DDModeInfo**)MemAlloc(buffer_size); + if(!mode_buffer) + return FALSE; + + // Create Mode List + index = 0; + mode_list = current_driver->ModeList; + while(mode_list) + { + mode_buffer[index] = mode_list; + + index++; + + mode_list = mode_list->Next; + } + + // Sort Mode list + qsort((void*)mode_buffer,(size_t)mode_count,sizeof(DDModeInfo*),CompareModes); + + // Dump Mode list to Combo Box + for(index=0;indexModeSupported(current_device))) + { + mode_buffer[index]->GetMode(&w,&h,&bpp,&refresh); + + // Set up Mode String + if(refresh) + wsprintf(szBuff, TEXT("%4d x %4d x %4d (%4d Hz)"), w, h, bpp, refresh); + else + wsprintf (szBuff, TEXT("%4d x %4d x %4d"), w, h, bpp); + + // Add String to Combo Box + result = SendDlgItemMessage(hDlg, IDC_MODES, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szBuff); + + // Set up pointer to Mode Info for this item + SendDlgItemMessage(hDlg, IDC_MODES, CB_SETITEMDATA, (WPARAM)result, (LPARAM)(void *)mode_buffer[index]); + + // Is it the current Mode + if(current_mode==mode_buffer[index]) + { + // Set as our current selection + SendDlgItemMessage (hDlg, IDC_MODES, CB_SETCURSEL, (WPARAM)result, 0L); + } + } + } + + // Cleanup Memory + MemFree(mode_buffer); + + // Success + return TRUE; +} + +//--------------------------------------------------------------- + +DDDriverInfo *DlgGetDriver(HWND hDlg) +{ + SLONG index; + + + index = SendDlgItemMessage(hDlg, IDC_DRIVERS, CB_GETCURSEL, 0, 0); + if(index!=CB_ERR) + { + // Return pointer to driver + return (DDDriverInfo*)SendDlgItemMessage(hDlg, IDC_DRIVERS, CB_GETITEMDATA, (WPARAM)index, (LPARAM)0); + } + + // Failure + return NULL; +} + +//--------------------------------------------------------------- + +D3DDeviceInfo *DlgGetDevice(HWND hDlg) +{ + SLONG index; + + + index = SendDlgItemMessage(hDlg, IDC_DEVICES, CB_GETCURSEL, 0, 0); + if(index!=CB_ERR) + { + // Get pointer to device + return (D3DDeviceInfo*)SendDlgItemMessage(hDlg, IDC_DEVICES, CB_GETITEMDATA, (WPARAM)index, (LPARAM)0); + } + + // Failure + return NULL; +} + +//--------------------------------------------------------------- + +DDModeInfo *DlgGetMode(HWND hDlg) +{ + SLONG index; + + + index = SendDlgItemMessage(hDlg, IDC_MODES, CB_GETCURSEL, 0, 0); + if(index!=CB_ERR) + { + // Get pointer to device + return (DDModeInfo*)SendDlgItemMessage(hDlg, IDC_MODES, CB_GETITEMDATA, (WPARAM)index, (LPARAM)0); + } + + // Failure + return NULL; +} + +//--------------------------------------------------------------- + +BOOL CALLBACK ChangeDriverProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + BOOL changed; + D3DDeviceInfo *the_device; + DDDriverInfo *the_driver; + DDModeInfo *the_mode; + ChangeDDInfo *change_info; + + + switch (message) + { + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + change_info = (ChangeDDInfo*)GetWindowLong(hDlg, DWL_USER); + if(!change_info) + EndDialog (hDlg, FALSE); + + changed = FALSE; + + // Get new driver. + the_driver = DlgGetDriver(hDlg); + if((the_driver) && (the_driver!=change_info->DriverCurrent)) + { + changed = TRUE; + change_info->DriverNew = the_driver; + } + else + change_info->DriverNew = change_info->DriverCurrent; + + // Get new device. + the_device = DlgGetDevice(hDlg); + if((the_device) && (the_device!=change_info->DeviceCurrent)) + { + changed = TRUE; + change_info->DeviceNew = the_device; + } + else + change_info->DeviceNew = change_info->DeviceCurrent; + + // Get new mode. + the_mode = DlgGetMode(hDlg); + if ((the_mode) && (the_mode!=change_info->ModeCurrent)) + { + changed = TRUE; + change_info->ModeNew = the_mode; + } + else + change_info->ModeNew = change_info->ModeCurrent; + + // Return success/failure + EndDialog(hDlg, changed); + break; + case IDCANCEL: + EndDialog (hDlg, FALSE); + break; + case IDC_DRIVERS: + if(HIWORD(wParam)==CBN_SELENDOK) + { + // User has changed the current driver + change_info = (ChangeDDInfo*)GetWindowLong(hDlg, DWL_USER); + + // Check if user has changed the Driver + the_driver = DlgGetDriver(hDlg); + if((the_driver) && (the_driver!=change_info->DriverNew)) + { + change_info->DriverNew = the_driver; + change_info->DeviceNew = NULL; // Pick a new device + change_info->ModeNew = NULL; // Pick a new mode + + // Update the Device list + SendDlgItemMessage(hDlg, IDC_DEVICES, CB_RESETCONTENT, 0, 0); + DlgDevicesInit(hDlg); + + // Update the Mode list + SendDlgItemMessage(hDlg, IDC_MODES, CB_RESETCONTENT, 0, 0); + DlgModesInit(hDlg); + } + } + break; + case IDC_DEVICES: + if(HIWORD(wParam)==CBN_SELENDOK) + { + // User has changed the current device + change_info = (ChangeDDInfo*)GetWindowLong(hDlg,DWL_USER); + + // Check if user has changed the device + the_device = DlgGetDevice(hDlg); + if((the_device) && (the_device!=change_info->DeviceNew)) + { + change_info->DeviceNew = the_device; + + // Update the Mode list + SendDlgItemMessage(hDlg,IDC_MODES,CB_RESETCONTENT,0,0); + DlgModesInit(hDlg); + } + } + break; + case IDC_MODES: + if(HIWORD(wParam)==CBN_SELENDOK) + { + // User has changed the current mode + change_info = (ChangeDDInfo*)GetWindowLong(hDlg, DWL_USER); + + // Check if user has changed the Mode + the_mode = DlgGetMode(hDlg); + if((the_mode) && (the_mode!=change_info->ModeNew)) + { + change_info->ModeNew = the_mode; + } + } + break; + } + break; + case WM_INITDIALOG: + // Save pointer to ChangeInfo + SetWindowLong(hDlg, DWL_USER, (long)lParam); + + // Set up the current driver, device, and mode lists + if(GetDlgItem(hDlg, IDC_DRIVERS)) + if(!DlgDriversInit(hDlg)) + return FALSE; + + if(GetDlgItem (hDlg, IDC_DEVICES)) + if(!DlgDevicesInit(hDlg)) + return FALSE; + + if(GetDlgItem (hDlg, IDC_MODES)) + if(!DlgModesInit(hDlg)) + return FALSE; + + // Successful init + return TRUE; + } + return FALSE; +} + + +#endif //#ifndef TARGET_DC + + +//--------------------------------------------------------------- + +SLONG app_inactive; +SLONG restore_surfaces; + +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam); + +LRESULT CALLBACK DDLibShellProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int result; + SLONG w,h,bpp,refresh; + ChangeDDInfo change_info; + GUID *D3D_guid, + *DD_guid; + HMENU hMenu; + HINSTANCE hInstance; + +#ifndef TARGET_DC + BinkMessage(hWnd, message, wParam, lParam); +#endif + + switch(message) + { +#ifndef TARGET_DC + case WM_ACTIVATEAPP: + + if (!wParam) + { + // + // Lost focus... + // + + app_inactive = TRUE; + } + else + { + app_inactive = FALSE; + restore_surfaces = TRUE; + } + + break; + + case WM_SIZE: + case WM_MOVE: + + // + // Tell the new engine the that window has moved. + // + +// FINALENG_window_moved(LOWORD(lParam),HIWORD(lParam)); + + if(the_display.IsFullScreen()) + { + SetRect(&the_display.DisplayRect,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN)); + } + else + { + GetClientRect(hWnd,&the_display.DisplayRect); + ClientToScreen(hWnd,(LPPOINT)&the_display.DisplayRect); + ClientToScreen(hWnd,(LPPOINT)&the_display.DisplayRect+1); + } + break; + case WM_MOUSEMOVE: + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONUP: + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + MouseProc(message,wParam,lParam); + break; +#endif //#ifndef TARGET_DC + + case WM_KEYDOWN: + case WM_KEYUP: + KeyboardProc(message,wParam,lParam); + break; + case WM_CLOSE: + // normally, we should call DestroyWindow(). + // instead, let's set flags so the normal quit process goes thru. + GAME_STATE=0; + break; +#ifndef TARGET_DC + case WM_COMMAND: + hMenu = GetMenu(hWnd); + switch(LOWORD(wParam)) + { + case ID_DISPLAY_EXIT: + PostMessage(hWnd,WM_CLOSE,0,0); + break; +#ifndef NDEBUG + case ID_DISPLAY_FULLSCREEN: +#if defined(_DEBUG) || defined(ALLOW_WINDOWED) + ShellPauseOn(); + if(the_display.IsFullScreen()) + { + the_display.FullScreenOff(); + CheckMenuItem(hMenu,ID_DISPLAY_FULLSCREEN,MF_UNCHECKED); + ShowCursor(TRUE); + } + else + { + the_display.FullScreenOn(); + CheckMenuItem(hMenu,ID_DISPLAY_FULLSCREEN,MF_CHECKED); + ShowCursor(FALSE); + } + the_display.Fini(); + the_display.ChangeMode(RealDisplayWidth,RealDisplayHeight,DisplayBPP,0); + + ShellPauseOff(); +#endif + break; + case ID_DISPLAY_DRIVERS: + hInstance = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); + if(hInstance) + { + ShellPauseOn(); + // Setup Change info + change_info.DriverCurrent = the_display.GetDriverInfo(); + change_info.DriverNew = change_info.DriverCurrent; + + change_info.DeviceCurrent = the_display.GetDeviceInfo(); + change_info.DeviceNew = change_info.DeviceCurrent; + + change_info.ModeCurrent = the_display.GetModeInfo(); + change_info.ModeNew = change_info.ModeCurrent; + + result = DialogBoxParam( + hInstance, + MAKEINTRESOURCE(IDD_DRIVERS), + hWnd, + (DLGPROC)ChangeDriverProc, + (LPARAM)(void *)&change_info + ); + + if(result==TRUE) + { + if(change_info.DriverCurrent!=change_info.DriverNew) + { + if (change_info.DriverNew) + DD_guid = change_info.DriverNew->GetGuid(); + else + DD_guid = NULL; + the_display.ChangeDriver(DD_guid,change_info.DeviceNew,change_info.ModeNew); + } + else if(change_info.DeviceCurrent!=change_info.DeviceNew) + { + if (change_info.DeviceNew) + D3D_guid = &(change_info.DeviceNew->guid); + else + D3D_guid = NULL; + the_display.ChangeDevice(D3D_guid,change_info.ModeNew); + + } + else if(change_info.ModeCurrent!=change_info.ModeNew) + { + change_info.ModeNew->GetMode(&w,&h,&bpp,&refresh); + the_display.ChangeMode(w,h,bpp,refresh); + } + } + ShellPauseOff(); + } + break; + case ID_MODES_512X384: + ShellPauseOn(); + SetDisplay(512,384,16); + ShellPauseOff(); + break; + case ID_MODES_320X200: + ShellPauseOn(); + SetDisplay(320,200,16); + ShellPauseOff(); + break; + case ID_MODES_640X480: + ShellPauseOn(); + SetDisplay(640,480,16); + ShellPauseOff(); + break; + case ID_MODES_800X600: + ShellPauseOn(); + SetDisplay(800,600,16); + ShellPauseOff(); + break; + case ID_MODES_1024X768: + ShellPauseOn(); + SetDisplay(1024,768,16); + ShellPauseOff(); + break; + case ID_EDITOR_MISSIONEDITOR: +#ifdef EDITOR +int gedit(void); + MFX_QUICK_stop(); + MUSIC_reset(); + ShellPauseOn(); + result=gedit(); + if (result==-1) { + PostMessage(hWnd,WM_CLOSE,0,0); + break; + } + ShellPauseOff(); + SetDisplay(640,480,16); +#endif + break; + case ID_ABOUT: + hInstance = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); + if(hInstance) + { + ShellPauseOn(); + DialogBox(hInstance,MAKEINTRESOURCE(IDD_ABOUT),hWnd,(DLGPROC)AboutBoxProc); + ShellPauseOff(); + } + break; +#endif + } + break; + case WM_ENTERMENULOOP: + ShellPauseOn(); + break; + case WM_EXITMENULOOP: + ShellPauseOff(); + break; +#endif //#ifndef TARGET_DC + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd,message,wParam,lParam); + } + return 0; +} + +//--------------------------------------------------------------- + diff --git a/fallen/DDLibrary/Source/net.cpp b/fallen/DDLibrary/Source/net.cpp new file mode 100644 index 0000000..9f6f396 --- /dev/null +++ b/fallen/DDLibrary/Source/net.cpp @@ -0,0 +1,1179 @@ +// +// Direct play stuff. +// + +#include "DDLib.h" +#include "net.h" + + +// +// Our private cunning messages... +// + +#define NET_CUNNING_TYPE_DPID (177773.055F) +#define NET_CUNNING_TYPE_START_GAME (559225.123F) + +typedef struct +{ + float type; + CBYTE filling[16]; + DPID dpid; + SLONG player_id; + CBYTE padding[20]; + SLONG must_be_12345; + CBYTE crap[16]; + SLONG must_be_314159; + CBYTE shit[8]; + +} NET_Cunning; + + +// +// Error checking... +// + +#ifndef VERIFY +#ifdef NDEBUG +#define VERIFY(x) {x;} +#else +#define VERIFY(x) {ASSERT(x);} +#endif +#endif + + +// +// The main interface to DirectPlay3 +// + +LPDIRECTPLAY3A NET_dp; + +// +// TRUE if this machine is the host. +// The local player number. +// + +UBYTE NET_i_am_host; +UBYTE NET_local_player; + +// +// All the players. +// + +typedef struct +{ + UBYTE used; + UBYTE player_id; + UWORD shit; + DPID dpid; + CBYTE name[NET_NAME_LENGTH]; + +} NET_Player; + +#define NET_MAX_PLAYERS 32 + +NET_Player NET_player[NET_MAX_PLAYERS]; + +// +// The buffer into which messages are recieved. +// + +CBYTE NET_buffer[NET_MESSAGE_LENGTH]; + +SLONG net_init_done=0; + +void NET_init(void) +{ + HRESULT res; + ASSERT(0); + + if(net_init_done==0) + { + net_init_done=1; + } + else + { + return; + } + // + // Initialise the COM module. + // + +#ifdef TARGET_DC + CoInitializeEx(NULL,COINIT_MULTITHREADED); +#else + CoInitialize(NULL); +#endif + + // + // Create the DirectPlay3 interface. + // + + res = CoCreateInstance(CLSID_DirectPlay, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay3A, (LPVOID*)&NET_dp); + + if (res != S_OK) + { + NET_dp = NULL; + } +} + + +void NET_kill(void) +{ + if(net_init_done) + { + ASSERT(0); + if (NET_dp) + { + NET_dp->Release(); + } + + // + // Get rid of the tossy COM module. + // + + CoUninitialize(); + } +} + + +// +// All the avaliable connections. +// + +typedef struct +{ + LPCGUID guid; + void *connection; + SLONG connection_size; + CBYTE name[NET_NAME_LENGTH]; + +} NET_Connection; + +#define NET_MAX_CONNECTIONS 8 + +NET_Connection NET_connection[NET_MAX_CONNECTIONS]; +SLONG NET_connection_upto; + +// +// The enumeration function for connections. +// + +BOOL FAR PASCAL NET_enum_connections( + LPCGUID lpguidSP, + LPVOID lpConnection, + DWORD dwConnectionSize, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext) +{ + if (!WITHIN(NET_connection_upto, 0, NET_MAX_CONNECTIONS - 1)) + { + // + // No more connections please! + // + + return FALSE; + } + + NET_Connection *nc = &NET_connection[NET_connection_upto++]; + + nc->connection = MemAlloc(dwConnectionSize); + + if (nc->connection) + { + nc->guid = lpguidSP; + nc->connection_size = dwConnectionSize; + + memcpy(nc->connection, lpConnection, dwConnectionSize); + strncpy(nc->name, (CBYTE *) lpName->lpszShortNameA, NET_NAME_LENGTH - 1); + } + else + { + // + // No more memory???!!! + // + + return FALSE; + } + + // + // Continue the enumeration please. + // + + return TRUE; +} + + +SLONG NET_get_connection_number() +{ + SLONG i; + + // + // Free up all the memory the connection have used up so far. + // + + for (i = 0; i < NET_connection_upto; i++) + { + if (NET_connection[i].connection) + { + MemFree(NET_connection[i].connection); + } + } + + // + // Enumerate all the connections. + // + + NET_connection_upto = 0; + + VERIFY(NET_dp->EnumConnections(NULL, NET_enum_connections, NULL, DPCONNECTION_DIRECTPLAY) == DP_OK); + + return NET_connection_upto; +} + +CBYTE *NET_get_connection_name(SLONG connection) +{ + ASSERT(WITHIN(connection, 0, NET_connection_upto - 1)); + + return NET_connection[connection].name; +} + + +SLONG NET_connection_make(SLONG connection) +{ + HRESULT res; + + ASSERT(WITHIN(connection, 0, NET_connection_upto - 1)); + + res = NET_dp->InitializeConnection(NET_connection[connection].connection, 0); + + if (res == DP_OK) + { + return TRUE; + } + else + { + return FALSE; + } +} + +SLONG NET_create_session(CBYTE *session_name, SLONG max_players, CBYTE *my_player_name) +{ + SLONG i; + + HRESULT res; + + DPNAME dpname; + DPSESSIONDESC2 session; + + InitStruct(session); + + session.dwFlags = DPSESSION_KEEPALIVE; + session.guidApplication = GUID_NULL; + session.dwMaxPlayers = max_players; + session.lpszSessionNameA = session_name; + + res = NET_dp->Open(&session, DPOPEN_CREATE); + + if (res == DP_OK) + { + // + // Clear out old player info. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + NET_player[i].used = FALSE; + } + + // + // Create a local player. + // + + InitStruct(dpname); + + dpname.lpszShortNameA = my_player_name; + + res = NET_dp->CreatePlayer( + &NET_player[0].dpid, + &dpname, + NULL, // No event, + NULL, // No data, + NULL, // No data, + 0); + + if (res == DP_OK) + { + NET_player[0].used = TRUE; + NET_player[0].player_id = NET_PLAYER_NONE; + + NET_i_am_host = TRUE; + NET_local_player = 0; + + return TRUE; + } + else + { + // + // Close the session. + // + + NET_dp->Close(); + + return FALSE; + } + } + else + { + return FALSE; + } +} + +// +// All the available sessions +// + +typedef struct +{ + CBYTE name[NET_NAME_LENGTH]; + SLONG num_players; + SLONG max_players; + GUID guidInstance; + GUID guidApplication; + +} NET_Session; + +#define NET_MAX_SESSIONS 16 + +NET_Session NET_session[NET_MAX_SESSIONS]; +SLONG NET_session_upto; + + +// +// The session enumeration function. +// + +BOOL FAR PASCAL NET_enum_sessions( + LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext) +{ + NET_Session *ns; + + if (dwFlags & DPESC_TIMEDOUT) + { + return FALSE; + } + + if (!WITHIN(NET_session_upto, 0, NET_MAX_SESSIONS - 1)) + { + return FALSE; + } + + ns = &NET_session[NET_session_upto]; + + ns->num_players = lpThisSD->dwCurrentPlayers; + ns->max_players = lpThisSD->dwMaxPlayers; + ns->guidInstance = lpThisSD->guidInstance; + ns->guidApplication = lpThisSD->guidApplication; + + strncpy(ns->name, lpThisSD->lpszSessionNameA, NET_NAME_LENGTH - 1); + + NET_session_upto += 1; + + return TRUE; +} + +SLONG NET_get_session_number() +{ + DPSESSIONDESC2 desc; + + InitStruct(desc); + + desc.guidApplication = GUID_NULL; + + NET_session_upto = 0; + + NET_dp->EnumSessions(&desc, 0, NET_enum_sessions, NULL, 0); + + return NET_session_upto; +} + +NET_Sinfo NET_get_session_info(SLONG session) +{ + NET_Sinfo ans; + + ASSERT(WITHIN(session, 0, NET_MAX_SESSIONS - 1)); + + strncpy(ans.name, NET_session[session].name, NET_NAME_LENGTH - 1); + + return ans; +} + +// +// The player enumeration function. +// + +BOOL FAR PASCAL NET_enum_players( + DPID dpId, + DWORD dwPlayerType, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext) +{ + SLONG i; + + if (dwPlayerType == DPPLAYERTYPE_PLAYER) + { + // + // Look for a spare player structure. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (!NET_player[i].used) + { + NET_player[i].used = TRUE; + NET_player[i].dpid = dpId; + NET_player[i].player_id = NET_PLAYER_NONE; // Dont know this yet. + + return TRUE; + } + } + + // + // No more room for any more players. + // + + return FALSE; + } + + return TRUE; +} + +SLONG NET_join_session(SLONG session, CBYTE *my_player_name) +{ + SLONG i; + + HRESULT res; + + DPNAME dpname; + DPSESSIONDESC2 desc; + + ASSERT(WITHIN(session, 0, NET_MAX_SESSIONS - 1)); + + // + // Describe the session we want to join. + // + + InitStruct(desc); + + desc.guidInstance = NET_session[session].guidInstance; + + res = NET_dp->Open(&desc, DPOPEN_JOIN); + + if (res == DP_OK) + { + // + // Find all other players in the session. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + NET_player[i].used = FALSE; + } + + res = NET_dp->EnumPlayers( + NULL, + NET_enum_players, + NULL, + 0); + + if (res != DP_OK) + { + NET_dp->Close(); + + return FALSE; + } + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (!NET_player[i].used) + { + NET_local_player = i; + + goto found_local_player; + } + } + + // + // No space for a new player. + // + + NET_dp->Close(); + + return FALSE; + + found_local_player:; + + // + // Create a player. + // + + InitStruct(dpname); + + dpname.lpszShortNameA = my_player_name; + + res = NET_dp->CreatePlayer( + &NET_player[NET_local_player].dpid, + &dpname, + NULL, // No event, + NULL, // No data, + NULL, // No data, + 0); // No special flags. + + if (res == DP_OK) + { + NET_player[NET_local_player].used = TRUE; + NET_player[NET_local_player].player_id = NET_PLAYER_NONE; + + NET_i_am_host = FALSE; + + return TRUE; + } + else + { + // + // Get rid of all players and leave the session. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + NET_player[i].used = FALSE; + } + + NET_dp->Close(); + + return FALSE; + } + } + else + { + return FALSE; + } +} + + +UBYTE NET_start_game() +{ + SLONG i; + SLONG player_upto; + + NET_Cunning *nc; + + HRESULT res; + + ASSERT(NET_i_am_host); + ASSERT(WITHIN(NET_local_player, 0, NET_MAX_PLAYERS - 1)); + + // + // Assign the player ids. + // + + player_upto = 0; + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (NET_player[i].used) + { + NET_player[i].player_id = player_upto++; + } + } + + // + // Send a special chat message to the all the other players that + // tells them their player_id. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (NET_player[i].used) + { + nc = (NET_Cunning *) NET_buffer; + + nc->type = NET_CUNNING_TYPE_DPID; + nc->dpid = NET_player[i].dpid; + nc->player_id = NET_player[i].player_id; + + nc->must_be_12345 = 12345; + nc->must_be_314159 = 314159; + + res = NET_dp->Send( + NET_player[NET_local_player].dpid, + DPID_ALLPLAYERS, + DPSEND_GUARANTEED, + nc, + sizeof(NET_Cunning)); + + if (res != DP_OK) + { + TRACE("Couldn't synchronisation message.\n"); + } + else + { + TRACE("Send synchro message ok\n"); + } + } + } + + // + // Send the start game message. + // + + nc = (NET_Cunning *) NET_buffer; + + nc->type = NET_CUNNING_TYPE_START_GAME; + + nc->must_be_12345 = 12345; + nc->must_be_314159 = 314159; + + res = NET_dp->Send( + NET_player[NET_local_player].dpid, + DPID_ALLPLAYERS, + DPSEND_GUARANTEED, + nc, + sizeof(NET_Cunning)); + + if (res != DP_OK) + { + TRACE("Couldn't start synchronisation message.\n"); + } + else + { + TRACE("Send start synchro message ok\n"); + } + + return NET_player[NET_local_player].player_id; +} + + +void NET_leave_session() +{ + NET_dp->Close(); +} + + +SLONG NET_get_num_players() +{ + SLONG i; + SLONG ans = 0; + + #define NAME_BUFFER_SIZE 1024 + + ULONG name_buffer_size; + UBYTE name_buffer[NAME_BUFFER_SIZE]; + + DPNAME *dpname; + + HRESULT res; + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (NET_player[i].used) + { + name_buffer_size = NAME_BUFFER_SIZE; + + res = NET_dp->GetPlayerName(NET_player[i].dpid, name_buffer, &name_buffer_size); + + if (res == DP_OK) + { + dpname = (DPNAME *) name_buffer; + + strncpy(NET_player[i].name, dpname->lpszShortNameA, NET_NAME_LENGTH - 1); + } + else + { + TRACE("Could not get player name. %d", i); + + strncpy(NET_player[i].name, "Unknown", NET_NAME_LENGTH - 1); + } + + ans += 1; + } + } + + return ans; +} + +CBYTE *NET_get_player_name(SLONG player) +{ + SLONG i; + + SLONG player_number = 0; + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (NET_player[i].used) + { + if (player == player_number) + { + return NET_player[i].name; + } + + player_number += 1; + } + } + + return "Unknown"; +} + +void NET_message_send( + UBYTE player_id, + void *data, + UWORD num_bytes) +{ + SLONG i; + DPID to; + + ASSERT(WITHIN(NET_local_player, 0, NET_MAX_PLAYERS - 1)); + + if (player_id == NET_PLAYER_ALL) + { + to = DPID_ALLPLAYERS; + } + else + { + // + // Find the DPID for this player. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (NET_player[i].used) + { + if (NET_player[i].player_id == player_id) + { + to = NET_player[i].dpid; + + goto found_dpid; + } + } + } + + // + // Could not find anyone with this dpid. + // + + ASSERT(0); + } + + found_dpid:; + + NET_dp->Send( + NET_player[NET_local_player].dpid, + to, + 0, + data, + num_bytes); +} + + +SLONG NET_message_waiting() +{ + ULONG ans; + + HRESULT res; + + ASSERT(WITHIN(NET_local_player, 0, NET_MAX_PLAYERS - 1)); + + res = NET_dp->GetMessageCount( + NET_player[NET_local_player].dpid, + &ans); + + if (res == DP_OK) + { + if (ans) + { + TRACE("Message waiting\n"); + } + + return ans; + } + else + { + TRACE("Error getting message count\n"); + + return 0; + } +} + +void NET_message_get(NET_Message *ans) +{ + SLONG i; + + DPID from; + DPID to; + ULONG num_bytes; + + SLONG match; + DPID dpid; + SLONG player_id; + + NET_Player *np; + NET_Cunning *nc; + + DPMSG_GENERIC *sm = (DPMSG_GENERIC *) NET_buffer; + DPMSG_CREATEPLAYERORGROUP *sp; + DPMSG_DESTROYPLAYERORGROUP *sd; + DPMSG_CHAT *sc; + + HRESULT res; + + ASSERT(WITHIN(NET_local_player, 0, NET_MAX_PLAYERS - 1)); + + to = NET_player[NET_local_player].dpid; + num_bytes = NET_MESSAGE_LENGTH; + + res = NET_dp->Receive( + &from, + &to, + DPRECEIVE_TOPLAYER, + NET_buffer, + &num_bytes); + + TRACE("Received %d bytes\n", num_bytes); + TRACE(" DPMSG_GENERIC = %d bytes\n", sizeof(DPMSG_GENERIC)); + + if (res == DP_OK) + { + TRACE("E\n"); + + if (from == DPID_SYSMSG) + { + TRACE("System message.\n"); + + // + // Handle a system message. + // + + switch(sm->dwType) + { + case DPSYS_CHAT: + + TRACE("Got chat message\n"); + + sc = (DPMSG_CHAT *) NET_buffer; + + // + // This could be one of our syschat messages. + // + + match = sscanf(sc->lpChat->lpszMessageA, "SYSCHAT: DPID %d => player id %d", &dpid, &player_id); + + if (match == 2) + { + TRACE("Chat DPID message %d player_id %d\n", dpid, player_id); + + // + // Find the player with the given dpid and set his + // player id. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (NET_player[i].used) + { + if (NET_player[i].dpid == dpid) + { + NET_player[i].player_id = player_id; + + goto found_player; + } + } + } + + // + // No such player! + // + + ASSERT(0); + + found_player:; + + // + // Create a NOP message. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_NOP; + } + + if (strncmp(sc->lpChat->lpszMessageA, "SYSCHAT: Start the game!", 24) == 0) + { + TRACE("Start game message\n"); + + // + // Create a START_GAME message. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_START_GAME; + } + + return; + + case DPSYS_CREATEPLAYERORGROUP: + + TRACE("C\n"); + + sp = (DPMSG_CREATEPLAYERORGROUP *) NET_buffer; + + // + // Find a spare player structure. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + np = &NET_player[i]; + + if (!np->used) + { + // + // Create the new player. + // + + ASSERT(sp->dwPlayerType == DPPLAYERTYPE_PLAYER); + + np->used = TRUE; + np->dpid = sp->dpId; + + goto found_spare_player;; + } + } + + ASSERT(0); + + found_spare_player:; + + // + // Create a NOP message. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_NOP; + + return; + + case DPSYS_DESTROYPLAYERORGROUP: + + TRACE("B\n"); + + + sd = (DPMSG_DESTROYPLAYERORGROUP *) NET_buffer; + + // + // Find this player. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + np = &NET_player[i]; + + if (np->used && np->dpid == sd->dpId) + { + np->used = FALSE; + + goto destroyed_player; + } + } + + ASSERT(0); + + destroyed_player:; + + if (i == NET_local_player) + { + // + // I have been ejected from the game... create a + // LOST CONNECTION system message. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_LOST_CONNECTION; + } + else + { + // + // Create a NOP message. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_NOP; + } + + return; + + case DPSYS_SESSIONLOST: + + TRACE("A\n"); + + // + // Lost our connection... + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_LOST_CONNECTION; + + return; + + default: + + TRACE("Unknown system message %d\n", sm->dwType); + + // + // Create a NULL message. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_NOP; + + return; + } + } + else + { + TRACE("User message.\n"); + + if (num_bytes == sizeof(NET_Cunning)) + { + TRACE("Size ok\n"); + + nc = (NET_Cunning *) NET_buffer; + + if (nc->must_be_12345 == 12345 && + nc->must_be_314159 == 314159) + { + TRACE("Magic numbers ok\n"); + + if (nc->type == NET_CUNNING_TYPE_DPID) + { + TRACE("NET CUNNING DPID\n"); + + // + // Set this players player_id... + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + if (NET_player[i].used) + { + if (NET_player[i].dpid == nc->dpid) + { + NET_player[i].player_id = nc->player_id; + + if (i != NET_local_player) + { + + // + // Tell the user to ignore this message... + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_NOP; + } + else + { + // + // Start the game once we know our player id. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_START_GAME; + ans->system.player_id = nc->player_id; + } + + TRACE("Nop\n"); + + return; + } + } + } + + // + // Oh dear!!! Maybe this wasn't a cunning message after all... + // + + ASSERT(0); + } + else + if (nc->type == NET_CUNNING_TYPE_START_GAME) + { + TRACE("Ignored start game message\n"); + + // + // Start the game! + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_NOP; + + return; + } + } + } + + + // + // A message from another player. + // + + for (i = 0; i < NET_MAX_PLAYERS; i++) + { + np = &NET_player[i]; + + if (np->used) + { + if (np->dpid == from) + { + ans->player_id = np->player_id; + + goto found_player_id; + } + } + } + + ASSERT(0); + + found_player_id:; + + ans->player.num_bytes = num_bytes; + ans->player.data = NET_buffer; + + return; + } + } + else + { + TRACE("Didn't receive messages properly\n"); + + // + // Create a NOP message. + // + + ans->player_id = NET_PLAYER_SYSTEM; + ans->system.sysmess = NET_SYSMESS_NOP; + + return; + } +} + + + + + + + + + + diff --git a/fallen/DDLibrary/ahead.bmp b/fallen/DDLibrary/ahead.bmp new file mode 100644 index 0000000000000000000000000000000000000000..94ab1e2e18589ef0449728841f7dd3b5ede7a501 GIT binary patch literal 4324 zcmbuCy^9k;6u{rx?AP7iCArOA67O>HlDpg`D+ppCf`urSR+e^(3N~UPidb2SV0#K8 zSlCz#hbSC=fN0@gV4;YGAT|~@5@&YyV|I6DcXl%{$!unRzuEU@Gs&Df`@IQ%`9@yH zq@D~af=ybixDEiVhsY(Z)9DoK&;P*w^cU<8f53kC8|rU=fwlh=tXDt4+WQLDi!We3 z`v~UK_h3GG1Los>Fdw}JYxgCz9`1p0|2Y_UcEPyu0QBqkK)-qy^ozGazi z{57bZyG-gO(2k!0?bvD1j+_8(aujfM7;xy3IsxpD09Q8vJ3TLCgP9;HzR}{o}B>|6D z5G3)^f;3)Iki|<0IK1Zq#TN@wc$zN~r11=& zFUa6oK2MOv1-x7!z(u@FAi@KlY$ALSK8Zp+;OQ>J7lA;Ghw~Q-BzPFVQy`GxAy0Ca z7lIUz_*{V;kNF%y4$kp%K^IrXspz7`V*3Z{&E{adf?dxuaC zaDrd@C~Z+A=7SJg1Dkbnc#eSMeSsL43wR!#L2Fc;2!Cp1gw|FX$=Z z34u9^1tYdYc2C3)Vbutu)RFYOY%=6FW;7C!mw7r!K^k0_DudI4`J#$AXGD6U=b_^98e< WKZ#(r^Dhz5j8;4S@@tXT2KW!#pv)}* literal 0 HcmV?d00001 diff --git a/fallen/DDLibrary/arrowcop.cur b/fallen/DDLibrary/arrowcop.cur new file mode 100644 index 0000000000000000000000000000000000000000..98febab06c525a01d7e06a6bf56e318060f97452 GIT binary patch literal 326 zcmajZF$%&k7>405bRc$lZ=|3i z=wIGEG(!?8kW-RKLxoD6G?FwXwv?0O^HV(6@5RjCH&cFm>#j-~P*_Nj?=H8f6`U$8 zkPGHgaKsswxWxTS{U6@o=S~M+)Tz$%+ GzvcmjqJBmI literal 0 HcmV?d00001 diff --git a/fallen/DDLibrary/bitmap1.bmp b/fallen/DDLibrary/bitmap1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..91cb70a79d8a10f4a117dfc84a8275adecd75999 GIT binary patch literal 5162 zcmbW4J&Rpc6o$_jtrCaDY{T(EcEvqx*NS9rgUh`DCZQ1V1qG*D@R5` zd!uJKBPnfR#tE8?$VX@+r_r(x2ElD({&<^#M~l!{xoylyXAyIyt-&^?xe5z)E@Gkt ztaZw#VSc|I`E$}R^-SACef;t~Q)rGeZJE*cG<1Zi!8Ng+|H}tP3q~xJX{vjA5dN49 z&J?xQ;Ih~84|x@g8LLqCdi_~mIaAyiLT=!A-bCt5c!W?`Fj-&AtD#_poT`mND}Jh} zKX{lH{lLZGZv!sW{jgykKH!eG!pV?iczD18_5v5aNp zpxju$r_E9Nb{!F%3!VS!<`kuy@|c*P{riLKnO!DxFn+Gb`?kA;vEV* zU~HK0|D@Yih9U7bduXz_caj-Nh`G^-rmlb*=E*JYxek4a7~~Pv&_w6{dc+KZDCAFH zIjl8!bV??E<4eq749^jBaAgZqQWCC*k>2-zYZwa*!#pEzgb$VREGmO?q{sVIn78y@ zHOE9c4p?Y?_pQVhsaK&|f-$4#<#n*x`S@y8dl_cqwaz+A~<49cCZL#nkIMxNspw&2#Swa zFkvMw|8>FP(%Y1x2?6;OrZsIxK!Slk6MqSQP(fmFw|hEkd}LbY`{h6(&Ps)0J61~eE5176dp$g=?=u6Ns|-@MoAGw3?ga_i-`zZ9r!QgH@M0O4x>$_fgt2dr@|N< zSBr~-Elk+L#$07|pgSLEMLeiYsZM(lX7YV+Wm(dN5b~s*nces1&9~qCX7-2uAD<|( zpU{4TtG1z(hkiqC%JV-<()~jdDuura!@NU_p}M-dLQjX2zjBTvT=?-38vBVMKrKB^ z4UJI)RhHm|dnxLZEdTOgFrO!RLRI=%J(JAKt71A~AW}LEMm^Y3j)2Kipm!MtL)YZJ z-3)?;WFAjea1O)^^t8wM0}KTT=g7Q5NxYkic|v7OZHw`k_&5u(o}1uFPKycc32}Tx z#BE&`THvy+13vf=oBwA?Q@Reo8kT2lk@TTB%Z%#Xl?bh{5}GGbNy@lVNDq7!m-rg7j>o{2B$Wt+rKBs@m&WpUH|PBzI%^QP zUjrO{@M_CzmTlTapeoyXlAx01R5zU=uJ_StbP8BwcMrmv^6Cz=sqT{rW1XUuWeZ>;Ia>>$8m|sqxH9ba0J`zB=R~ zWoS5+=CIg$SmUVyJJqUi&4A;LYs4aD)vE#ck+t}Q91*7=IoBs1v?OE!?qb$_!@{wp z^*}trd9>}ub071ta!N(|p?HY_5r!kGh)&qKlo2bV1!zX^GfE<{LE|~euGju-;UBzq zYxZ9YE_RKFbaBAhC=UL~w!*{~wda1hO%eFt-e0bemi$Px7&)IsPN#b7SL6-&1(OMW z>c&I)_}Qhe>+a&O3~WZl=XW=n(2YbD0W)G4ML2aPn6`guZ-LRo-9&T{gQxe0R{{A4 DX@>JW literal 0 HcmV?d00001 diff --git a/fallen/DDLibrary/icon1.ico b/fallen/DDLibrary/icon1.ico new file mode 100644 index 0000000000000000000000000000000000000000..fcfab3cdfa9193a5d0d5e5461b611843e7d4c238 GIT binary patch literal 7078 zcmeI0y=xpt6u{p_2d5k&k{VS8DX#1$2&PiypdzUZZk*PEz_cmd1iWtCCJ+#8=OPJ7 zkw$;PfkO&=YP*R*;DCb&L?X>Xj3&SLX7~2v_M{V*^8s3Ec4pq^Z{Dm{b0;#8p=@of ziC(|GBk~db+FF|57>InZBNCqt3#?Q;H}$mxp64W?VP4`~|DE@JgxnFzm< zWvS!NP$rWJy(*&pN{l+9@uMQWEqHZJ@jY(3GH(UbdDB4WO#_=Z3~b&oNb}lYv3VUJ z+5gk?i}KbLG~U`>_hzPE4YlcOZ`;eJ+V;1ppEtHVdOKc?F&k*kcq;PXwaBePWRsw) zha#h@O+=Q?YL%V#>Z>s{md4cBmP2!ump%3gTcYzU~mx` z91aer9Q@@#WfY#fhsDFAEXz4s09tICXus3^1B_vP!VQ%Hs>Oe*A96KvDxpSCulIA4HVamy!qs+;jlRGE3 zZHMJXPX3(yIr(*qa`NZYCWj%1A*T+yZB)fpkA$APZX-1aYn6i<1UQ0n zurS+hoB}KXmH-aSd3KH zOxc_&R^?k|Rolv5*Vd;m*Jw+hS+5340g|4&PymzCr8*`j({p2eMycCarcU-uwRB2R z)wkS+hCW4^?vEx)HNweiuR*A=DaxCrLv4{QOIxoi(70F>+|<1^U{vT%17PI3Bnw2B z9zS~!bb$t@8(>Q?J;U^%8Na4ifhH)|S5cZiMNnObf4V2OzpBNkUSDHNlr5zxDg%2W zrp5}O3CjGo*s0P67Mzf*%Rt)NG_!5PuunHnrg7twCow*JXs-m$U3Q++^Ov3L2HAtx zOOsp0$G>hKe}1}o_~3MvHkxSr?5Cy4Ae)}=c+>Dng<}~ld$=^n2I=f~*g4z90k57v zzqHhPPT8h?N*hRdPI;F}@0DGhQ~00cuFffTO1L_waCW#lr_6h`{VQ^Nsa+tm*>hXe zrLtetqqbknqiMegRLgz=hqnFs4jub*9lG}CIn3Cfx}wo;x-Bx!V7ZBCX55vtiim5Bc1x^Rnre z=Q`Fe)3rb3!&~tX9GMvg8X-V} z0WNsK?RG`b&lli3<@I{v_Y3gt6?muZM*cy*;Ei7reV>y8e4%;@eyQSqzf;D7uNUs2 zk@Tp;eQ+SP757nUH}cB=MlBMxvxO@X>vu%C4{! znAVJx{6Hd*a9?-=xvR{LQBYBdjW{!HGlvKxCgSRoi5XvMQ&GCF{MaEHcsveT<5q+P zfFW3)=U5k3bH+Qd5(8a)XBlh1F*55b`yT$eY8z2M(iGmp(GO`_QBbq6p1JXQxPS1l zwypCN!6sfy>|N*GHTEM}oPY9~M%0hI1&#|@=V@RF;)Bd})5f*Xl{Xy?c&O1Hv9mL} z`sIbPa=GxBU)pIJY5pKO`3Fn61Fyu53}75<$wK2Z=dQ@O&``%D!cLvRLyNU literal 0 HcmV?d00001 diff --git a/fallen/DDLibrary/mucky_lo.bmp b/fallen/DDLibrary/mucky_lo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..91cb70a79d8a10f4a117dfc84a8275adecd75999 GIT binary patch literal 5162 zcmbW4J&Rpc6o$_jtrCaDY{T(EcEvqx*NS9rgUh`DCZQ1V1qG*D@R5` zd!uJKBPnfR#tE8?$VX@+r_r(x2ElD({&<^#M~l!{xoylyXAyIyt-&^?xe5z)E@Gkt ztaZw#VSc|I`E$}R^-SACef;t~Q)rGeZJE*cG<1Zi!8Ng+|H}tP3q~xJX{vjA5dN49 z&J?xQ;Ih~84|x@g8LLqCdi_~mIaAyiLT=!A-bCt5c!W?`Fj-&AtD#_poT`mND}Jh} zKX{lH{lLZGZv!sW{jgykKH!eG!pV?iczD18_5v5aNp zpxju$r_E9Nb{!F%3!VS!<`kuy@|c*P{riLKnO!DxFn+Gb`?kA;vEV* zU~HK0|D@Yih9U7bduXz_caj-Nh`G^-rmlb*=E*JYxek4a7~~Pv&_w6{dc+KZDCAFH zIjl8!bV??E<4eq749^jBaAgZqQWCC*k>2-zYZwa*!#pEzgb$VREGmO?q{sVIn78y@ zHOE9c4p?Y?_pQVhsaK&|f-$4#t@%)?yj|VyJ-sUMGy}nco4;-C*Of0f;Uf!c=EXT0#-o; z4_-VAA_$9rKvuz5;2RLciw7@KCzG_9OlFeFbRgZf$>-ZiHrZ~jT>rKKK91Pq8Ma)` z7J|o~r6cG8$ueaxlVvuW!TbIX-q*kIzWjmr={Nk3ztB1SiO!oJ=)5|D`|>l~7a!n0 zKZN`2Jvs;P5I%j2_LJ9WKRSSOZy(Ox$8c^vgmd!&MtAOG<;HEaE?z_H!d0}+T|#T` zJZO3r6zzdVQ_x@x+8Tm_P0)G>@&mwW^GU{4W0I`o4^>-f*G>99k>9rsOnmaz);#j< z0*tRl!(p^)7fASSm#DjI6_|6&K+dfKBDV+>dEU$YeF@|^Pl;6=a{%vHwvg9 z$88$-#J7d#vX4)nXbG!(V`|4S(RN{8`37O?L;g$ClrkH6rvIm?+1?&rrpmI8v;>_K|`3S0`zk6!U-;rAzTlK}VG`BUNsfy8I$uY%VHn9r^sC9e%Eu3rtW z4LIrX)biQ@_Z8eEP|529H9QLxPaNS@Ew7$|0j~-eaecs$>jK7H9caK+fkwO>XvpP2 rV_pnca4}%T^MEB!154ch@xU_opDeK4{Vxk7UmSLKzrt5e_DeV~}J+_{KlAmAdV0`IV-f#4>o@|w0L zT`$74wX=8f+*onsa|m{NE?GsM_qaz_pR+|~!E=L!;!w}`Rj-$PpN#5B-5Tn}`kYPo zGw=pqN5yk=!DsVMZ}NFcbG=~QUcM)I1@*=sN5z%5@AaOhtDr}nE4?Bm?|!=I^@e?Y z+sP@`SGQO79jqm9Gd}k9p$uNvv#@P^mvepW1K*Qb~#HuB6ENw4sC!$Sdva^Umz*BgID;&5lSjzxIA!XvNUZYNJq zJK1jk$o>6qxx4!%x3@p#=H`c7Uw@aYt8a37`Bg41zR3CcXE{52l+)7(aqbi7Ev}Ea z7;%bAWb?9Yy-FKxwQkIJy=(0bd&r-{YtAp9UqCnGtHs8zPlQ>?~W?SnE`Ok;^E*;E* z0=~apxL=Iv8^-pG+u%U!`FX@4u&MVI_>vEU_W2Wq`Qhh~^GT2v(G041{Jcmsah$`% z#B-j>!^a3G^r790Kfw?N##kMbrWv1*OU$PURPhL`tF_3S8IK<+l}=L(8rQ@JHrJ%~ zd89-N2BiU-Y>0N+`X{k%7S)bPe64of{O@qj{E4Kz!1(1sQ<)DO}d zX}>RkZ2sspMO^^wppN2)PAl+ph|~P?=lP?rhSypP^`|iKkZWUn=Nyw|EYGuY&=IP) zu>a`h?$c00mOmf(@`1+qIUb^kZ6Tcn9?JgU_?x(>IQ1Tt)Q7 zFqSRbH04T zP9yh5Tyf8*%m*2jB3SKtpI=#yqYZSs1D_^S=lntAyn`VGYzAMbBJc5qn(;QU_vin> zAN%{gIr9BsbL{)efdYj$`9m@&;F|+7c!u{EDB*nt_V9iJ6?h+kO1!&34c=9t7Vjp| WfOipS#39gf8e9Iq^84uDn#f<6W&!~K literal 0 HcmV?d00001 diff --git a/fallen/DDLibrary/toolbar.bmp b/fallen/DDLibrary/toolbar.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9388f76a9fb90020e42a2356f17dba53b1e593b4 GIT binary patch literal 478 zcma)1yA{GP3{>8uXAMebpl1&zpib!&>8--McnqrutAsn*PE3bl{qFS3Z)>>v5@TkO+ZqnX<;+z7#4)$lqv@REcM`WW;yfq?;#EAdHR2!; e2j2fz3y)Y*E#^^GHWDX%>_tTx;eHSLl|#OMODmNC literal 0 HcmV?d00001 diff --git a/fallen/DDLibrary/uturn.BMP b/fallen/DDLibrary/uturn.BMP new file mode 100644 index 0000000000000000000000000000000000000000..855fa5cf2665c03752b9561c16dd49f15a8125c4 GIT binary patch literal 4364 zcmcJSON-M`6oAi3(8hGcgf_L^J zcn9YIXJ-H>2Y|yFV1EqQ8vwStfQ>d_y#?Tx*(Brt8B;1}ol}-+r;b?fxC*9qj5aqT zth)&azA+gLCL3-7itkqtEBj7@6n7M4xRXG{9RxC7SfJts1v*|xV8ROs%y@2r4bLgC zDBftAO~q=lV0F5|eG!Q`x$W~axV zoyY1J%W;gjLz66`DdKV5w9Owe*rC^y{QgkphjyOlSL<*0NpJ@}Yg_rGetrE(DV$Gg zk_L-97rVeDkPvB*@(Y~&!AXAU(@W$iA<`gulYpB95+V&aFX0A(gh&I%E4VJ;2w8g) zZH?D(O~4VUXD-$ma8)3YN`51*2$Bzwpy{XiEx0U5Y8H6D7TLBHE~Tg9=Rg(Yz?B(@ zCD2`9U%E8EEJ*7WkJj2#1uH=$r1O>d@)_j7mkDy=c0o?uCdiGO1qE=Epb)ML3gW7u rFfI!ma8cldX97o@3)Xo4V}f;_KZ#(y=U*bA``Yd4H~mIfbp-eajrE$% literal 0 HcmV?d00001 diff --git a/fallen/Debug/Fallen.tlog/CL.command.1.tlog b/fallen/Debug/Fallen.tlog/CL.command.1.tlog new file mode 100644 index 0000000000000000000000000000000000000000..55a3e752c00c92c9c2a91d3237cfe5b73e5fad5a GIT binary patch literal 104568 zcmeI5TW=dx6h_Z868{19ou(}ap-MbBz7CD;;7i?95mB17P>GhRMJnaT1K%D`P-f;# z*oK$c(o*Ck9((NZjMw@0?d`?+58x_tb3dY2wn&)i?* zX}UT7S9_g+y2?p>T_+h)n5Bj z?{=wo{gnRDyV{kqt#)pYbXAt+I~qY-eTz2LH|cSClrQuN-sqEE>mBTvMmCJu z!9)FpfB1+0Sp0YK>!JTx+*=%Ash?gt>C&F*c*SYo4UZf|w(s=i1JiN!!_%^vd;lt00*|KlDR?Q2N^hdq#kvd<3iD8^J#8!+t3C^X&SlpDBlD z^}1Ghi>HsLkEb8W(;q4ho9EX@zty7GBZJiJ-^_0ygHHy(uNnNIZ1pC&KH`^U<&N3; zME1$#k;#iSS7#`-x5~RVzh3(1n!nV{2BP_BKJ)bYK2Ois&(Z58e^FNK+xW4@($9`dSaDX?>EY3%^=N%8t?wq-I|3B+*~7|LCt1jkMt+lA5AoJFXrgOPcfGFe;Z)~R zo!i&y+%9^3m%M)y0jJViu4SXCpV|jpV{+qX3tN`m1=YR`siQM z6PxNgs_%lWY(G)GeZ7~xkM@=JvtAn(>!%+!Rz6mKG%LTGV9y9Jm90O=zen*={9uZo zBli&EjrxVw(IJjc93KxqQXKz={2al)5x~0YZc3}4+4b1`*!;0<{%P42JIAk&e#;6h zWcSk-pBZ=7EeiFIrT$&~`sm+^eY#?!`fwjj_1olnh@WYEAJ9>Q2p>uxEW(!~*GGII z=B*FUO4TbfD)V6<_QSD%7sI|$U`}kG>OH*sP@Oeq%EsT$$oWXOZktbP`_T)ZUikFF z?|UzNThY2nu7~)djN$E9#;niRg?qS%`@VDE&99e!tJpOUpRSqY@W|nP3g+D#|6K$h zHUdn_G2phxfCYdBfCUi20@#lLZGwFxz!HC-=pNC%P|>|Y-u`W^_K)d*2->6E5np|pfsmYC1le_Pf)nwO8eZ99f8jr@K z@ewq>&aIDjTRFp4#HC9%Dv!!XQ~5l-KJp7$_8X#i#OjIFhlm%ND{!|`4 z5qmo8FtK7t@Dy7H1$E(MykLA_p**%Q< zQ)xbHWWYY`M`gcFux|t)TMzY6AC3AtwI0%!=@^fm*gdiPP_g?awLa3HmUC)PRBum~ z9(70EW2yTxb@A(=|5Vi1Yj>%~qaKfXyuR1twYl}uZZUt>wMOUB`B*w{#JAb?Q9o1- zZoR)ADv!#e^8Hu&Hn~3HtxMKg)H8n`rAO(bDSe(^ANk+Qy0`9lg;vYL&WC>Jk4Aqt z!M+i|BKcJ2K|bV1Bfm|qpZGJW{#M-AbN%@F`1$zx{rB_t+4mg5hl~K`H!u%}c{t3& zi8K%ARGzxk-Zbg;k-tnkn5R-t-=10ekgk$x9g5$7#cy)!qkW~g9+^CRdwlz7zI~fq zAMtBh2G)uQ4ELzx)#eSY%ANgmB<<(csAeK)o zAJ4x3o_(8K5Ai=}bRWsPCv%T?kJ88T?(^*WsJCAF%)om~kF*P5z4?0f9{SoXa!-)7fC{aRy% z_2eO2PqvNzaIK` zvJ_5a=MU6d*K$|rKDv+YN7DVf2=8c&AtG1EfB-cy)3a!W1C!QZHo^QlA z$@LL$v+<{5o^`VD@bU0tdH7bZlcU#1{#+e8>8p)>k9{A{zR$7iq5hd-c~;$jq5Qq& S1&Hbq)g!7GDXMoD!G8lAOa(pw literal 0 HcmV?d00001 diff --git a/fallen/Debug/Fallen.tlog/CL.read.1.tlog b/fallen/Debug/Fallen.tlog/CL.read.1.tlog new file mode 100644 index 0000000000000000000000000000000000000000..2fa76798e16fb9c6965e3b315a6be4032422065b GIT binary patch literal 191174 zcmeI5+in~;5{7xbz`lbn?VG^fYz!lJ(r9#8OB!Kj6paEQdjFT$-TIrV?N)bBH(5i@ zlovmYIF=$Sr6O4;*2ntKzyAu0@OyX-SK&O|$**O2kdHQD6`sOc{@YSMI+xGghWqe~ zeEcZC{vQ7J{ce~2tN8&@KgO`;lS z@Z)}eYfiWKQ~B1MpLlxSWSz0{uv^zXy?(TaH=_Hv0&DsEukzKfc>S|<->eTba3|mK zLcXs5_xfL9Tg%dC5tan@6nh^(SH6WWFOe^K{OJc0oqnBmveQ>`iXOyvde}FJBH-m> zd~tgHyogtZ7qMFH(&uU?vDZ?3+oG{d3;D>01&R^VVIHouuAXGomf=m-??L`_>qJxC z{q1G#?nOsiH&M7s<3l?;(ag12q^Kc3GOZ{m)y({qV2;d}f@8CN)Z9zRm`R~U7Z_H5YXEbSllydrzZKdq&u zfqpc9xsYh|%7IKfi5d{6U&y}4?mxYjG+u|j@E}jzLu=8~gLuh&{nW6oaVJHIY$vUT zRDFwp>H|FYTB3RHQlf7BB9XK;3#y^drD$#~yUtoaE^WVtb=p{|(zD@rjiYZmOwQ8U zjNWo7cM!P4cog4|Z(B;s)RhK)!9&cwm2>$h8hUHI=ee7@$?iSgiE-KK*G^*{FY>@U zp~iLFMEm;p|xl^)EniWgVL+GlPIl?)V>%_W@(AkmSN>AmZG#g(N{-leC(lajrH_9=tXvr zr|RKCa%AvfWua-rJgLqn}RHVxHSwZ2DzjEIU68~c`0qh`-i zqQfEfB5hr3)Awp`-cPYLx;f6diG6s;bT_VQEW;CiSPxnaZEhq3Mn?~#5O_2{XIdpw zYh$gRm5$dQWS>17{90)_#&WqRn{5qC%eRwT2<&%6lUT$2NT9St-sFk5BUiGUE)CkL zVGXnoFl^0%fV6n9=FXLe}~#>_HS1bj$@ zyTEPum+0xyjgHU<;!ji0B9%wE9-PXxaVpo=sa%gvXYgFUBjVK4pTt-R!5!nh+;PXw9dtgOUNUG%`-t+Tsj1EO{;{G^PPK%TJuU!$39LT zIbXc8zRx$4^PSt#hF6La=y^ouz$p+OLD%5kq^6bMg|^feR94fwD~L^{*YM{ zHSW!nrbQG&&NrnGiJWh0a=!bc?XikQJb~nV)6OA07w!h}Zy)(3 zIp5U&A9B8kOVX!$k@L;d7dhWNeUbCcIgR9e(=C_Mm+;c$d~;7_Bt`w`PWy~hB3s;5 zBi~<$KaFo&`;m#9@APdqIbZZ5r_R6aS1fZlU%bb1-n>54pXp21m#l9)iJ7eLzP_bs z%gOqV>xZmwTFr{AZ+hlH);A|7{TU{P+amMQ{dZ)2Q*D*fwfQ~PH8MPv#>Xxq>zi8Z zS9XxBFS_r3kvY6yq3D}U;DPLcJscTS3R=m`p(5k z$e_sjPFH&N?{c!fX&E@;0KH@KVHwE!ruP4k^+k0gr|;G06j9Ff&09y#^v%vV@_{PIn{UCKEyiG>DNiU9!cMQH`yQ!@1*8u^Sz}byj}Pqy@)Sj z?QZ1X3;D>0TqJ$d^9GW>IrSluzNwW*lD=ux^+oeK%vLODzW=R}-}&m5BI%oY-bnhU zzUI{LsvzlW@0*Ifr=04W-$}3M6<)%J<&SF#d2CU94R6#xtIBNqma^3(N#C?6h@|ga zuTQiWBz^IUNA61=oa!6jxg4@1@ceW7Tnb;lmL4FhUnpI58oO77#nrRn-FqD-XK8Il zU)5!6^P`c{GIgba{~+m0(sv_WT&R7YN%cFYVn@=~rnfOGJ3N;*TU*{XM`{ zN#C3~6vsI`Bz<#wHc9%TiuW4Eq5#=T7R+UdL4@uwj8;Vs^dyG|pH>p69^d;##=iiU# zy_Bu8dD+r-E_(eg!*_aH*Odl-fu!&LE?&;`ovxXqAA&P|^EuG5zS-fq^kKu6@=l&j zl4DqX&h$;Igp%}~>-X0TouuzL(efg({<-AGR%=i?wj${}x1&k=lJq^33e>H<;j)y< z&sq2scHw*Y7CsBNb`0wEdf*_9-Hb9y#O`jYfTy%#*}O8m*8cO*~p9pIBtIe2k!8xe0uuEZl=8l0*`z9+b?hYD#C+GKL?5T`oFM6&Q#I;W zEdP>q#G8Lu(YvN1{U9HqqVOcO1+4L_7}d zaiZ_Odu&ehUCCYG{Oxh9K`zB&TW@np#{ng-oNrEbh@5X~-I1JcT5X*ZeWz|H z$@!+9H{}M&`I7TJUe^@zm`nMENXr(_)VYKHNO~z98qbDJ&eHLqo>zE@{LHI{*5X=1 z9-D@0$TaMB`x&HcW#mNPv?z!Zedlvp>?&mh{a6f@$gj;H=ev>mwEZm)PV_}37dL|o zsqN!F)=HemIOMPsQ#uZbzN$;`<=d9hGIgba{~+hP|1N=?FF9W@F{RJouwMNpc5m0* zc0NiZ63?a0>z9_5oUdipH7EL}#oVaCfvi2fU(~#kobSH-QF6Xtq@>Pe98He^Bp^>!^)@c$}BnGLuxF;)h6egUT2Bjt*_$MUWDYv zdjUSYTciw6A2*KWa-8Tp)ptP7cm5WgoUi?@-CYxduimRRh|?|aiw3Ij51FZ@T5uEXNP4I+kDbrSuU`C}HGBcYTR$ zdaBcVr)%g(CUU;hx83A?bE-yG&KI{Q3#l|ccJ2f}vcWe}g*tCKh1ODydX=}Z;Nh0N zJnz2Y)6hX3JCk1}3;g)^`d?u?iRJS|e*`O{Ge47s{pp8HP9cOC2-H-aJUUQP~d{+D1R5Vf9%#S;3SnpOIn{TTjQ{SUNMnuKFt6-4Q zUytBWm$+f!B;P|{uOi_~!gnQAjZ@TFNcc|o{f^~wBz#Hu9%ivf_>%D5NJagVy!-Y& zdeXl-ensSnF-a2xUZ=Sw6S}tDt;){vHYShrLCG) zx}x9bY4dB2wI#CYsZP~V*U*nlBz&hceGc}@UMi@A{#lMf!hkt82HMVXKfoTyCRs0!Q zU)w3@@3&TyWPQ^zHnP5H{$0shAF(3#xk}{OzvDg_y_7GGeH2;W)XZ}1X7T6Pi7^g2 z?8KC=jYnVArTFq~OKF+9(!hUk7BFW4a~AM%dHXRdJ3N;*uV3C?a29a>v}dxuX)!lh z-~HZ)tnU;tLe_WwgtcsKe%x83cG${e^KCU`>erVbBU#@vwK}rCW%Nkam#l9}Z(j}j z$XUSC{e5G(99iF~$c?P;+-;%u*j+UJ&NqgRgVI%i{k!~4`XZLn74hUo)}8bmY$b+^ zI>5cG2MwZoU2k-JNW@vdskb6zeQ}eK)A#C=dL-+cw~l0e^YrC&*OT>4w_HkK`r%c_ zBCo!bKH`Z!S({&TEFHD>C9>(MMpnHLfBGWK-qIMI){u#;?{ub5*0(n6yO7KcuWVk* zsUYR+X@V{(-)Y-G$`^6U@U{c5oZdE-n5_#6nv`!^&$w0~!Jb%Wo+~XE zDc_vh5Gmi(sv{@*rrIjyYV$MB8hMmT$BCqqg3=J!~0qHoIn8um9vDha;T=Aml%%)XSZjHGxeFOc$0^9DnjFyG#lu9NAFCnx$&-z8{V8*_rwuN!(HkTc#k zZ#mtDKjqeXEi=nvy1ZQOP`lV&%L|;zy z{VWxX()&tnS?qq!w-lx2(YzA9*gj64xBF3F)oW6|^I2_6)#jhC8lJe7$9BSM$TZ9& z@EK0@g$5-llTTjjsMCrSC1ypwuvB5YKy{8%AnX%U5hQS&F6=ICB}ej-Vm@7GGl zjbphSDPK~)hgmF6^tHe3Ps%r~5=_cBwcn1EFXEDPR&FEJBKTQvTstY>ymchyo2M_I zyPlM9y5-U=2eyk7ee-sIpQ$~4Zq}E`PgYIJH>K}-Cui`yxfQkCC6~_hN%_{Nd~c-o z{@Bp(YpH>e^d;%L{}p7+0`#RH&hsVdn@=n3guGeGn;#2#jczHw|1ehnOZz*LzUg@b zN#C6M5J}(E$|FhNv|2Xj`A*%qk@QVHZ`zfJ-aF3ootj(P?@>9t%la7IUAXf)mmYP* zT7IfQ$YU;>*OEEUH?QWX=M`Qezus75$HldTJbw09|E%g{X5Uh_nk4C)76p;?o$rap zt|I9>KbO33Gf4U#_A&}dUy{DZoh3RX3iBhR(ltfBUnl8H(ic4zml7wJdwuHg9JKU) zAL|Yuo=aP%P+C@!z9fA~`ld|ND}C}v`c74^N&3!bwJlkjALG@ig0=G4d|M5f`WY=` zBPIz|Xx&W`VbKNcu*d&dnB823d1-lD;2bKp4yANcv7i zZk*>kcjmOmj`MtNxi{zerf?J_eN+2?Nc!gWUy$_8)7PU@GMc1s-a3->&FS}swtkhn zo`>eP$5s(4U31kehorBCScwy1{pgOQFIbi3`|O^%tb_A>r*Gd$`lj!tVa4(0IovX70mU zlh@73-^lBx)(^?+rjaV-b*Jvl$m^z_H|77x>(1r;{qCp3d!>)jqeWgfJrnP*uu`7! zZ1{+~^t{4L#!43y5<^vRhPuek48$%)RhMQO3S3TaCDc44D~T?w8-w4eu@C!E1pXhsYo0e^d!a|qI(!rfS54>LMxr0jl9Ja=zwaTh zJDrn{<#Ob8r}_@a>(1Yzb22X{^KQaf_!M^Gd-xV=yqHB^H?{wVye@7s())4A>*nc; zyl$Spc2bLqHD7&Y+m>yVu1Wcnij#TMEtlRzqAJbFyt${6ylyHR%gMYcFUoK-Z(4^R zXxFv;!pjFfD*aYoch#`Gw+)9oq;@~DzL;a#C3dgnqv0!jeU6u;??xhd%R5*keWxpd zIIA1O`70fTlJuQkrK}Z7D5NR~q;alD^;?#_6WW>uC&r`nA)z_Gcn}{|ned BT(tlI literal 0 HcmV?d00001 diff --git a/fallen/Debug/Fallen.tlog/CL.write.1.tlog b/fallen/Debug/Fallen.tlog/CL.write.1.tlog new file mode 100644 index 0000000000000000000000000000000000000000..b51c0f1a9f108965860933e016ae173262639fe3 GIT binary patch literal 17282 zcmchdL37hE5QTMShQGo9!-<;{JC13SxN*`pGYtJB{C42IxE))vdUzS0rl$hSr(La9 zYwi2{=T}&V@8M_Igeu(QrwM!fHiSbsha>*3!EY7*tP8vF3BULF`7PM+f4#--1YQM} zW_t=Jth&PbPLk#7)%yed-piIpFdNZN64fy36D;?YXBYk0k6>)>yP%8=RKocINxU=Rq$f}EMrE?y| zO3)zYmAJAEqNeQ6=9)v=Iow?D2UhzoJd3o0SkX41jHj17rPZ|-(c6hN=FNt7dsJ{G zmhH8w@g7v`XbUgNtK^#4VvT#TrftDe@AobCnqG~yZ7XKw7W<$?lK0U8H?CsC+j77v zd8=qQE-lAB)4P|+mR+27_B!~ec*w4dJk>_4zNDPOR?I0{X%&$tY=;OO#a!AU1_M^8 zMS+|iUTIe6Yes3i%KobbNn7D$)q|;3RrUNI&_gM4IACXa_V2OB+CACBLd!l{FzVWk z)Z^r_H&nbDyIp>5X(y@=Kd?IXChYFjbuxxpX7sOdUn4FjL`L&*+%xq)>JgPEk;HC5 z-GKr5#Iwvwp!s!1ov&|*{{?xhRow@yj-9r)YY*^9&3#62g&#E|=@B~zC4#ikzxM`k zSPK-=fLh4asTnnhIWgcI^Gicr9ba42&T@RCp%uF}?cSSgU$9R{Sy@K)uD56+z3f^J_Nir*1%{TCT19R=r1NR;Xa=y+~X24AO>QO-i0{r)xxCeY1K(EgHKZh4zd% z@V0-s-f`18_!vGQzRQ2u^pP9a?`-xL;nP`W<2R|({eKsKQo=K z_=&l>jGsF7L|)c%7UbrYtZ(W3$?aP_xpLF;GcP}NJ}vXoa&tB}F`m%5Y3Xdw&zs%? zO0cFmhnp5pBE7Wv4AV{G+s5<_>86ddm3VIIX3i(BZdQI)>!rR;Y~Q}j%h1yKu$xM~ zOgdS1GjlU(H#44Qduiz$+)aCLg6`%{vlTZfp4xk9{K8$%`~A$EQlJzy))=^{)11sp z;;lH>HTY?zzW>Jiey*kP`&Oz0&FMGX-o?rfH!anSxOu7C#LJr$CuKUPi5Dwe++I$K z2`_1`s&SKYdK@n^R`U2+u?EP^i`7GJ8r3+l?#NBdE0)~USnE`RcEQv%R!Nni&h=Gp z;#^1LX2qH=H!Y_Ib2FDZGB+_+pm}La?V6hx>uCMatrix; +} + +inline void SetCMatrix(GameKeyFrameElement *e, CMatrix33 *c) +{ + e->CMatrix = *c; +}; + +//************************************************************************************************ +#else + +// JCL - wow - 4 bytes for the matrix instead of 36 (well, 12..) + +struct GameKeyFrameElement +{ + SBYTE m00, m01, m10, m11; +// SBYTE dm02, dm12, dm20, dm21, dm22; +// UBYTE pad1,pad2,pad3; + SBYTE OffsetX; + SBYTE OffsetY; + SBYTE OffsetZ; + UBYTE Pad; +}; + +void GetCMatrix(GameKeyFrameElement *e, CMatrix33 *c); +void SetCMatrix(GameKeyFrameElement *e, CMatrix33 *c); + +#endif +//************************************************************************************************ +//************************************************************************************************ + + +struct GameFightCol +{ + UWORD Dist1; + UWORD Dist2; + + UBYTE Angle; + UBYTE Priority; + UBYTE Damage; + UBYTE Tween; + + UBYTE AngleHitFrom; + UBYTE Height; + UBYTE Width; + UBYTE Dummy; + + struct GameFightCol *Next; + +}; + + +// +// This Contains +// +struct GameKeyFrame +{ + UBYTE XYZIndex; + UBYTE TweenStep; + SWORD Flags; + GameKeyFrameElement *FirstElement; + GameKeyFrame *PrevFrame,*NextFrame; + GameFightCol *Fight; +}; + +/* +struct GameKeyFrameChunk +{ + UWORD MultiObject[10]; + SLONG ElementCount; + struct BodyDef PeopleTypes[MAX_PEOPLE_TYPES]; + struct GameKeyFrame AnimKeyFrames[20000]; + struct GameKeyFrame *AnimList[200]; + struct GameKeyFrameElement TheElements[MAX_NUMBER_OF_ELEMENTS]; + SLONG MaxKeyFrames; + SLONG MaxElements; +}; +*/ + + +struct FightCol +{ + UWORD Dist1; + UWORD Dist2; + + UBYTE Angle; + UBYTE Priority; + UBYTE Damage; + UBYTE Tween; + + UBYTE AngleHitFrom; + UBYTE Height; + UBYTE Width; + UBYTE Dummy; + + ULONG Dummy2; + + struct FightCol *Next; + +}; + + +struct GameKeyFrameChunk +{ + UWORD MultiObject[10]; + SLONG ElementCount; + struct BodyDef *PeopleTypes; //[MAX_PEOPLE_TYPES]; + struct GameKeyFrame *AnimKeyFrames; //[MAX_NUMBER_OF_FRAMES]; + struct GameKeyFrame **AnimList; //[200]; + struct GameKeyFrameElement *TheElements; //[MAX_NUMBER_OF_ELEMENTS]; + struct GameFightCol *FightCols; //[200]; + + SWORD MaxPeopleTypes; + SWORD MaxKeyFrames; + SWORD MaxAnimFrames; + SWORD MaxFightCols; + SLONG MaxElements; +}; + + + + +struct KeyFrame +{ + SWORD ChunkID; + SWORD Flags; + SLONG FrameID, + TweenStep, + ElementCount; + KeyFrameElement *FirstElement; + KeyFrame *PrevFrame, + *NextFrame; + SWORD Dx,Dy,Dz; + SWORD Fixed; + struct FightCol *Fight; +}; + + + +struct KeyFrameChunk +{ + CBYTE ANMName[64], + ASCName[64], + VUEName[64]; + UWORD MultiObject; + UWORD MultiObjectStart; + UWORD MultiObjectEnd; + SLONG ElementCount; + struct BodyDef PeopleTypes[MAX_PEOPLE_TYPES]; + CBYTE PeopleNames[MAX_PEOPLE_TYPES][PEOPLE_NAME_SIZE]; +// UBYTE BodyBits[MAX_BODY_PARTS][MAX_BODY_VARIETY]; //10 types of each body part +#ifdef PSX + KeyFrame KeyFrames[1]; +#else + KeyFrame KeyFrames[MAX_NUMBER_OF_FRAMES]; +#endif + KeyFrameElement *FirstElement; + KeyFrameElement *LastElement; + SLONG KeyFrameCount; +}; + +struct KeyFrameEdDefaults +{ + SLONG Left, + Top; + SLONG Height, + Width; +// KeyFrameChunk KeyFrameChunks[MAX_NUMBER_OF_CHUNKS]; +}; + +#define ANIM_NAME_SIZE 64 +#define ANIM_LOOP 1 + +class Anim +{ + private: + CBYTE AnimName[ANIM_NAME_SIZE]; + ULONG AnimFlags; + SLONG FrameCount; + Anim *LastAnim, + *NextAnim; + KeyFrame *CurrentFrame, + *FrameListEnd, + *FrameListStart; + UBYTE TweakSpeed; + + public: + Anim(); + ~Anim(); + void AddKeyFrame(KeyFrame *the_frame); + void RemoveKeyFrame(KeyFrame *the_frame); + inline void SetAnimName(CBYTE *string) { strcpy(AnimName,string); } + inline CBYTE *GetAnimName(void) { return AnimName; } + inline void SetCurrentFrame(KeyFrame *the_frame) { CurrentFrame=the_frame; } + inline KeyFrame *GetFrameList(void) { return FrameListStart; } + inline void SetFrameList(KeyFrame *frame_list) { FrameListStart=frame_list; } + inline KeyFrame *GetFrameListEnd(void) { return FrameListEnd; } + inline KeyFrame *GetFrameListStart(void) { return FrameListStart; } + inline void SetFrameListEnd(KeyFrame *frame_list_end) { FrameListEnd=frame_list_end;} + inline SLONG GetFrameCount(void) { return FrameCount; } + inline void SetFrameCount(SLONG count) { FrameCount=count; } + inline ULONG GetAnimFlags(void) { return AnimFlags; } + inline void SetAnimFlags(ULONG flags) { AnimFlags=flags; } + void SetAllTweens(SLONG tween); + void StartLooping(void); + void StopLooping(void); + inline void SetNextAnim(Anim *next) { NextAnim=next; } + inline Anim *GetNextAnim(void) { return NextAnim; } + inline void SetLastAnim(Anim *last) { LastAnim=last; } + inline Anim *GetLastAnim(void) { return LastAnim; } + inline UBYTE GetTweakSpeed(void) { return TweakSpeed; } + inline void SetTweakSpeed(UBYTE speed) { TweakSpeed=speed; } +}; + +class Character +{ + private: + CBYTE CharName[32]; + UWORD MultiObject; +#ifdef TARGET_DC + // OI! This needs to be aligned on the DC, but it's probably a + // Good Thing to align it on the PC as well. + UWORD wJunk; +#endif + Anim AnimList[50]; + + public: + + + void AddAnim(Anim *the_anim); + void RemoveAnim(Anim *the_anim); + inline CBYTE *GetCharName(void) { return CharName; } + inline void SetCharName(CBYTE *string) { strcpy(CharName,string); } + inline UWORD GetMultiObject(void) { return MultiObject; } + inline void SetMultiObject(UWORD multi) { MultiObject=multi; } +}; + + +// +// Anim initailisation stuff. +// + +void ANIM_init(void); +void ANIM_fini(void); + + +#endif + + diff --git a/fallen/Editor/Headers/BuildTab.hpp b/fallen/Editor/Headers/BuildTab.hpp new file mode 100644 index 0000000..74d1e51 --- /dev/null +++ b/fallen/Editor/Headers/BuildTab.hpp @@ -0,0 +1,155 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _BUILDTAB_HPP_ +#define _BUILDTAB_HPP_ + +#include "ModeTab.hpp" +#include "Stealth.h" +#include "EditMod.hpp" +#include "undo.hpp" + + +#define FLAG_WINDOW_USED (1<<0) +#define FLAG_WINDOW_LEDGE (1<<1) +#define FLAG_WINDOW_FAT_LEDGE (1<<2) +#define FLAG_WINDOW_WIDE_LEDGE (1<<3) +#define FLAG_WINDOW_SUNK_IN (1<<4) +#define FLAG_WINDOW_FLAT (1<<5) +#define FLAG_WINDOW_EDGED (1<<6) +#define FLAG_WINDOW_EDGED_DEEP (1<<7) +#define FLAG_WINDOW_EDGED_FAT (1<<8) + + +/* +#define FLAG_WINDOW_ (1<<) +*/ + +/* +#define FLAG_WALL_ (1<<) +*/ + +/* +#define FLAG_STOREY_ (1<<) +*/ + +#define FLAG_BUILDING_ +/* +#define FLAG_BUILDING_ +*/ + + + + +#define PASTE_TEXTURE (1<<0) +#define PASTE_ALTITUDE (1<<1) + + +class MapBlock +{ + SLONG X; + SLONG Z; + SLONG Width; + SLONG Depth; + struct DepthStrip *Ptr; + + + public: + MapBlock(void); + ~MapBlock(); + void Cut(SLONG x,SLONG y,SLONG w,SLONG h,SLONG rooftop); + void Paste(SLONG x,SLONG z,SLONG flags,SLONG rooftop); + void Allocate(SLONG w,SLONG h); + void Rotate(SLONG dir); + void Free(void); + inline SLONG GetWidth(void) {return(Width);} + inline SLONG GetDepth(void) {return(Depth);} + inline SLONG GetX(void) {return(X);} + inline SLONG GetZ(void) {return(Z);} +}; + + + + + + + +class BuildTab : public ModeTab +{ + private: + SLONG Axis; + SLONG GridFlag; + UBYTE AxisMode; + EdRect View1; + EdRect View2; + EdRect View3; + UBYTE RedrawTabContent; + UWORD CurrentCol; + SLONG X1,Y1,Z1,X2,Y2,Z2; + SLONG FloorHead; + SLONG EditWindow; + SLONG EditY; + SLONG CurrentY; + SLONG ViewX,ViewY,ViewZ; + SLONG ViewSize; + + public: + BuildTab(EditorModule *parent); + ~BuildTab(); + void DrawTabContent(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG SetWorldMouse(ULONG flag); + SLONG KeyboardInterface(void); + SLONG DragEngine(UBYTE flags,MFPoint *clicked_point); + SLONG CalcMapCoord(SLONG *mapx,SLONG *mapy,SLONG *mapz,SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *clicked_point); + SLONG DragPaint(UBYTE flags); + SLONG DragMark(UBYTE flags); + SLONG DragVertex(UBYTE flags); + SLONG DragBuilding(UBYTE flags,UBYTE type); + SLONG MouseInContent(void); + SLONG DoKeys(void); + SLONG DoZoom(void); + void HighlightVertexes(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG ClickInVertexStoreyList(SLONG building,SLONG storey_index,SLONG w,SLONG h,MFPoint *mouse_point,SLONG flags); + SLONG ClickInVertex(SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *mouse_point,SLONG flags); + SLONG ClickNearWall(SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *mouse_point); + SLONG WallOptions(void); + SLONG RoofOptions(void); + SLONG FenceOptions(void); + void DeleteVertex(void); + void AddHeightOffset(SLONG *x,SLONG *y); + SLONG GetHeightColour(SLONG storey); + void DrawContentLine(SLONG x1,SLONG y1,SLONG x2,SLONG y2,SLONG col); + void DrawContentLineY(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col); + + SLONG DrawWall(SLONG px,SLONG pz,SLONG x1,SLONG z1,SLONG index,SLONG storey); + SLONG DrawWindow(SLONG px,SLONG pz,SLONG x1,SLONG z1,SLONG dx,SLONG dz); + void DrawRoofFaces(SLONG roof,SLONG storey); + void DrawFloorFaces(SLONG wall); + void CheckStoreyIntegrity(UWORD storey); + void ResetBuildTab(void); + void DrawFloorTextures(SLONG x,SLONG y,SLONG w,SLONG h); + void DrawFloorLabels(SLONG x,SLONG y,SLONG w,SLONG h); + inline void SetViewToEngine(void) {ViewX=(engine.X>>8)&ELE_AND;ViewY=(engine.Y>>8)&ELE_AND;ViewZ=(engine.Z>>8)&ELE_AND;} + inline void SetEngineToView(void) {engine.X=ViewX<<8;engine.Y=ViewY<<8;engine.Z=ViewZ<<8;} + void DrawContentRect(SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG col); +// Undo MyUndo; + UBYTE RedrawModuleContent; + void Clear(void); + UWORD Mode; + SLONG EditStorey; + SLONG EditWall; + SLONG EditBuilding; + UWORD Texture; + UWORD RoofTop; + EditorModule *Parent; +}; + + + +#endif + diff --git a/fallen/Editor/Headers/ColTab.hpp b/fallen/Editor/Headers/ColTab.hpp new file mode 100644 index 0000000..80dac27 --- /dev/null +++ b/fallen/Editor/Headers/ColTab.hpp @@ -0,0 +1,80 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _COLTAB_HPP_ +#define _COLTAB_HPP_ + +#include "ModeTab.hpp" +#include "Stealth.h" +#include "EditMod.hpp" +#include "undo.hpp" + +#define COL_TYPE_PLANE 1 +#define COL_TYPE_BEZIER 2 + +struct ColInfo +{ + UWORD Type; + UWORD Next; + union + { + struct + { + SLONG Left; + SLONG Right; + SLONG Top; + SLONG Bottom; + SLONG Depth; + }Plane; + struct + { + SLONG Top; + SLONG Bottom; + SLONG X[4]; + SLONG Z[4]; + }Bezier; + }; +}; + +class ColTab : public ModeTab +{ + private: + SLONG Axis; + SLONG GridFlag; + UBYTE AxisMode; + EdRect View1; + EdRect View2; + EdRect View3; + UBYTE RedrawTabContent; + UWORD CurrentCol; + UWORD ClipView; + public: + ColTab(EditorModule *parent); + ~ColTab(); + void DrawTabContent(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG SetWorldMouse(ULONG flag); + SLONG KeyboardInterface(void); + SLONG DragACol(UBYTE flags,MFPoint *clicked_point,UWORD copy); + SLONG DragEngine(UBYTE flags,MFPoint *clicked_point); +// Undo MyUndo; + UBYTE RedrawModuleContent; + void Recalc(void); + void Clear(void); + UWORD PlaceBezier(void); + UWORD Mode; + EditorModule *Parent; +}; + + +#define MAX_COL_INFO 1000 + +extern struct ColInfo col_info[MAX_COL_INFO]; +extern UWORD next_col_info; + +#endif + diff --git a/fallen/Editor/Headers/ComTab.h b/fallen/Editor/Headers/ComTab.h new file mode 100644 index 0000000..0733e23 --- /dev/null +++ b/fallen/Editor/Headers/ComTab.h @@ -0,0 +1,54 @@ +// ComTab.h +// Guy Simmons, 9th March 1998. + +#ifndef COMTAB_H +#define COMTAB_H + +#include "EdCom.h" + +#define COM_MODE_NONE 0 +#define COM_MODE_SELECT_THING 1 +#define COM_MODE_SELECT_WAYPOINT 2 +#define COM_MODE_SELECT_SWITCH 3 + +//--------------------------------------------------------------- + +class CommandTab : public ModeTab +{ + private: + UWORD DataField, + TabMode; + SLONG TabData; + EditCommand *DataCommand; + EditComList *CurrentComList; + + public: + CommandTab(); + ~CommandTab(); + + void DrawTabContent(void); + void UpdateTab(UBYTE update_level); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleTab(MFPoint *current_point); + void HandleControl(UWORD control_id); + void DoComListPopup(MFPoint *clicked_point,EditComList *the_comlist); + void DoCommandPopup(MFPoint *clicked_point,UWORD select_pos); + void CommonCommandOptions(ULONG id,EditCommand *the_command); + EditCondList *CommandTab::SelectConditionList(void); + + void DrawListsBox(void); + void DrawCurrentList(void); + + UWORD ListsHilitePos(MFPoint *current_point); + EditComList *HilitetedList(UWORD select_pos); + UWORD CurrentListHilitePos(MFPoint *current_point); + EditCommand *HilitetedCommand(UWORD select_pos); + + inline UWORD GetTabMode(void) { return TabMode; } + inline void SetTabMode(UWORD mode) { TabMode=mode; } + inline void SetTabData(SLONG data) { TabData=data; } +}; + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Headers/CondTab.h b/fallen/Editor/Headers/CondTab.h new file mode 100644 index 0000000..a12313e --- /dev/null +++ b/fallen/Editor/Headers/CondTab.h @@ -0,0 +1,54 @@ +// CondTab.h +// Guy Simmons, 16th March 1998. + +#ifndef CONDTAB_H +#define CONDTAB_H + +#include "EdCom.h" + +#define COND_MODE_NONE 0 +#define COND_MODE_SELECT_THING 1 +#define COND_MODE_SELECT_SWITCH 2 + +//--------------------------------------------------------------- + +class ConditionTab : public ModeTab +{ + private: + UWORD DataField, + TabMode; + SLONG TabData; + EditCondition *DataCondition; + EditCondList *CurrentCList; + + + public: + ConditionTab(); + ~ConditionTab(); + + void DrawTabContent(void); + void UpdateTab(UBYTE update_level); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleTab(MFPoint *current_point); + void HandleControl(UWORD control_id); + void DoCListPopup(MFPoint *clicked_point,EditCondList *the_clist); + void DoConditionPopup(MFPoint *clicked_point,UWORD select_pos); + void CommonConditionOptions(ULONG id,EditCondition *the_condition); + EditCondList *SelectConditionList(void); + + void DrawListsBox(void); + void DrawCurrentList(void); + + UWORD ListsHilitePos(MFPoint *current_point); + EditCondList *HilitetedList(UWORD select_pos); + UWORD CurrentListHilitePos(MFPoint *current_point); + EditCondition *HilitetedCondition(UWORD select_pos); + + inline UWORD GetTabMode(void) { return TabMode; } + inline void SetTabMode(UWORD mode) { TabMode=mode; } + inline void SetTabData(SLONG data) { TabData=data; } +}; + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Headers/Controls.hpp b/fallen/Editor/Headers/Controls.hpp new file mode 100644 index 0000000..6786fe4 --- /dev/null +++ b/fallen/Editor/Headers/Controls.hpp @@ -0,0 +1,283 @@ +// Controls.hpp +// Guy Simmons, 18th February 1997 + +#ifndef _CONTROLS_HPP_ +#define _CONTROLS_HPP_ + +#include "Primativ.hpp" + +#define BUTTON 1 +#define RADIO_BUTTON 2 +#define CHECK_BOX 3 +#define STATIC_TEXT 4 +#define EDIT_TEXT 5 +#define PULLDOWN_MENU 6 +#define POPUP_MENU 7 +#define H_SLIDER 8 +#define V_SLIDER 9 + +#define CONTROL_NONE 0 +#define CONTROL_INACTIVE (1<<0) +#define CONTROL_HILITED (1<<1) +#define CONTROL_SELECTED (1<<2) +#define CONTROL_CLICKED (1<<3) +#define CONTROL_SHOW_EXTRA (1<<4) + +#define EDIT_TEXT_LENGTH 64 + +// ^ - Seperator line. +// ~ - Check line. +// @ - Inactive. +// ! - End of list. + +#define MENU_NORMAL (1<<0) +#define MENU_SEPERATOR (1<<1) +#define MENU_END (1<<2) +#define MENU_HILITED (1<<3) +#define MENU_INACTIVE (1<<4) +#define MENU_CHECK (1<<5) +#define MENU_CHECK_MASK (1<<7) + +#define CTRL_SELECTED 0 +#define CTRL_DESELECTED 1 +#define CTRL_ACTIVE 2 +#define CTRL_INACTIVE 3 + +class MenuDef2 +{ +public: + CBYTE *ItemText; + UBYTE HotKey, + ItemFlags, + ItemID, + MutualExclusiveID; + EdRect ItemRect; +/* +#ifdef _MSC_VER + MenuDef2(CBYTE *s) { ItemText=s; } + MenuDef2(CBYTE *s,UBYTE k) { ItemText=s;HotKey=k; } +#endif +*/ +}; + +struct ControlDef +{ + UBYTE ControlType, + HotKey; + CBYTE *Title; + SWORD ControlLeft, + ControlTop, + ControlWidth, + ControlHeight; + MenuDef2 *TheMenuDef; +}; + + +class Control : public EdRect +{ + private: + UBYTE Flags, + ControlID, + ControlType, + HotKey; + CBYTE *ControlTitle; + Control *LastControl, + *NextControl; + ControlDef *TheDef; + + public: + Control(void) { ControlTitle=NULL;LastControl=NULL;NextControl=NULL; } + virtual void DrawControl(void); + virtual UWORD TrackControl(MFPoint *down_point); + virtual void TrackKey(void); + virtual void HiliteControl(MFPoint *current_point); + virtual void UnHiliteControl(void); + + virtual inline BOOL PointInControl(MFPoint *the_point) { return PointInRect(the_point); } + + inline void SetFlags(UBYTE flags) { Flags=flags; } + inline UBYTE GetFlags(void) { return Flags; } + inline void SetID(UBYTE id) { ControlID=id; } + inline UBYTE GetID(void) { return ControlID; } + inline void SetType(UBYTE type) { ControlType=type; } + inline UBYTE GetType(void) { return ControlType; } + inline void SetTitle(CBYTE *title) { ControlTitle=title; } + inline CBYTE *GetTitle(void) { return ControlTitle; } + inline void SetHotKey(UBYTE key) { HotKey=key; } + inline UBYTE GetHotKey(void) { return HotKey; } + + inline void SetLastControl(Control *last_control) { LastControl=last_control; } + inline void SetNextControl(Control *next_control) { NextControl=next_control; } + inline Control *GetLastControl(void) { return LastControl; } + inline Control *GetNextControl(void) { return NextControl; } +}; + + +class CButton : public Control +{ + public: + CButton(ControlDef *the_def); + void DrawControl(void); +}; + +class CRadioButton : public Control +{ + public: + CRadioButton(ControlDef *the_def); + void DrawControl(void); +}; + +class CCheckBox : public Control +{ + public: + CCheckBox(ControlDef *the_def); + void DrawControl(void); +}; + +class CStaticText : public Control +{ + private: + CBYTE String1[EDIT_TEXT_LENGTH], + String2[EDIT_TEXT_LENGTH]; + public: + CStaticText(ControlDef *the_def); + void DrawControl(void); + inline CBYTE *SetString1(CBYTE *the_string) { strncpy(String1,the_string,EDIT_TEXT_LENGTH);String1[EDIT_TEXT_LENGTH-1]=0;return String1; } + inline CBYTE *SetString2(CBYTE *the_string) { strncpy(String2,the_string,EDIT_TEXT_LENGTH);String2[EDIT_TEXT_LENGTH-1]=0;return String2; } +}; + +class CEditText : public Control +{ + private: + CBYTE EditText[EDIT_TEXT_LENGTH]; + ULONG SelectEnd, + SelectStart; + SLONG CursorPos, + TextX; + + public: + CEditText(ControlDef *the_def); + void DrawControl(void); + UWORD TrackControl(MFPoint *down_point); + inline CBYTE *GetEditString(void) { return EditText; } + inline CBYTE *SetEditString(CBYTE *the_string) { strcpy(EditText,the_string); return EditText; } +}; + +class CPullDown : public Control +{ + private: + MenuDef2 *TheMenu; + EdRect ItemsRect; + + public: + CPullDown(ControlDef *the_def); + void DrawControl(void); + UWORD TrackControl(MFPoint *down_point); + inline void SetItemFlags(UWORD item,UBYTE flags){ TheMenu[item-1].ItemFlags=flags; } + inline UBYTE GetItemFlags(UWORD item) { return TheMenu[item-1].ItemFlags; } +}; + +class CPopUp : public Control +{ + private: + MenuDef2 *TheMenu; + EdRect ItemsRect; + + public: + CPopUp(ControlDef *the_def); + void DrawControl(void); + UWORD TrackControl(MFPoint *down_point); + void SetItemState(UWORD item,UBYTE state); + inline void SetItemFlags(UWORD item,UBYTE flags){ TheMenu[item-1].ItemFlags=flags; } + inline UBYTE GetItemFlags(UWORD item) { return TheMenu[item-1].ItemFlags; } +}; + +#define SLIDER_SIZE 13 + +class CHSlider : public Control +{ + private: + UBYTE DragFlags, + LeftButtonFlags, + RightButtonFlags; + SLONG CurrentValue, + MinValue, + MaxValue, + ValueStep; + SLONG CurrentDrag, + MinDrag, + MaxDrag, + DragStep; + EdRect DragRect, + LeftButtonRect, + RightButtonRect; + void (*update_function)(void); + + void SetupDrag(void); + + public: + CHSlider(ControlDef *the_def); + void DrawControl(); + void HiliteControl(MFPoint *current_point); + void UnHiliteControl(void); + UWORD TrackControl(MFPoint *down_point); + BOOL PointInControl(MFPoint *the_point); + + void SetCurrentValue(SLONG value); + inline void SetUpdateFunction(void (*the_fn)(void)) { update_function=the_fn; } + inline SLONG GetCurrentValue(void) { return CurrentValue; } + inline void SetValueRange(SLONG min,SLONG max) { MinValue=min;MaxValue=max;SetupDrag(); } + inline void SetValueStep(SLONG value_step) { ValueStep=value_step; } + + inline void SetDragFlags(UBYTE flags) { DragFlags=flags; } + inline UBYTE GetDragFlags(void) { return DragFlags; } + inline void SetLeftButtonFlags(UBYTE flags) { LeftButtonFlags=flags; } + inline UBYTE GetLeftButtonFlags(void) { return LeftButtonFlags; } + inline void SetRightButtonFlags(UBYTE flags) { RightButtonFlags=flags; } + inline UBYTE GetRightButtonFlags(void) { return RightButtonFlags; } +}; + +class CVSlider : public Control +{ + private: + UBYTE DragFlags, + TopButtonFlags, + BottomButtonFlags; + SLONG CurrentValue, + MinValue, + MaxValue, + ValueStep; + SLONG CurrentDrag, + MinDrag, + MaxDrag, + DragStep; + EdRect DragRect, + TopButtonRect, + BottomButtonRect; + void (*update_function)(void); + + void SetupDrag(void); + + public: + CVSlider(ControlDef *the_def); + void DrawControl(); + void HiliteControl(MFPoint *current_point); + void UnHiliteControl(void); + UWORD TrackControl(MFPoint *down_point); + BOOL PointInControl(MFPoint *the_point); + + void SetCurrentValue(SLONG value); + inline void SetUpdateFunction(void (*the_fn)(void)) { update_function=the_fn; } + inline SLONG GetCurrentValue(void) { return CurrentValue; } + inline void SetValueRange(SLONG min,SLONG max) { MinValue=min;MaxValue=max;SetupDrag(); } + inline void SetValueStep(SLONG value_step) { ValueStep=value_step; } + + inline void SetDragFlags(UBYTE flags) { DragFlags=flags; } + inline UBYTE GetDragFlags(void) { return DragFlags; } + inline void SetTopButtonFlags(UBYTE flags) { TopButtonFlags=flags; } + inline UBYTE GetTopButtonFlags(void) { return TopButtonFlags; } + inline void SetBottomButtonFlags(UBYTE flags) { BottomButtonFlags=flags; } + inline UBYTE GetBottomButtonFlags(void) { return BottomButtonFlags; } +}; + +#endif diff --git a/fallen/Editor/Headers/CtrlSet.hpp b/fallen/Editor/Headers/CtrlSet.hpp new file mode 100644 index 0000000..b95c916 --- /dev/null +++ b/fallen/Editor/Headers/CtrlSet.hpp @@ -0,0 +1,66 @@ +// CtrlSet.hpp +// Guy Simmons, 25th November 1996. + +#ifndef _CTRLSET_HPP_ +#define _CTRLSET_HPP_ + +#include "Controls.hpp" +#include "Primativ.hpp" + +#define CS_ACTIVE (1<<0) +#define CS_CLEANUP (1<<1) + + +class ControlSet +{ + private: + UBYTE ControlCount, + StateFlags; + Control *ControlList, + *CurrentControl; + EdRect SetRect; + + void AddControl(Control *the_control); + + protected: + + + public: + ControlSet(ControlDef *defs); + ControlSet(); + virtual ~ControlSet(); + void InitControlSet(ControlDef *defs); + void FiniControlSet(void); + + void DrawControlSet(void); + UBYTE HandleControlSet(MFPoint *current_point); + UWORD HandleControlSetClick(UBYTE flags,MFPoint *clicked_point); + UWORD HandleControlSetKey(UBYTE the_key); + + inline Control *GetControlList(void) { return ControlList; } + Control *GetControlPtr(UWORD id); + void SetControlState(UWORD id,UBYTE state); + UBYTE GetControlState(UWORD id); + void ToggleControlSelectedState(UWORD id); + void ToggleControlActiveState(UWORD id); + void SetMenuItemState(UWORD id,UWORD item,UBYTE state); + void SetPopUpItemState(CPopUp *the_popup,UWORD item,UBYTE state); + + inline UBYTE GetStateFlags(void) { return StateFlags; } + inline void SetStateFlags(UBYTE flags) { StateFlags=flags; } + + void SetControlDrawArea(void); + void FillControlDrawArea(ULONG colour); + void HiliteControlDrawArea(ULONG hilite,ULONG lolite); + inline void ControlSetBounds(EdRect *bounds_rect) { SetRect=*bounds_rect; } + inline EdRect *ControlGetBounds(void) { return &SetRect; } + inline BOOL PointInControlSet(MFPoint *the_point) { return SetRect.PointInRect(the_point); } + + inline MFPoint *GlobalToLocal(MFPoint *the_point) { the_point->X-=SetRect.GetLeft();the_point->Y-=SetRect.GetTop();return the_point; } + inline MFPoint *LocalToGlobal(MFPoint *the_point) { the_point->X+=SetRect.GetLeft();the_point->Y+=SetRect.GetTop();return the_point; } + + inline UBYTE GetControlCount(void) { return ControlCount; } +}; + + +#endif diff --git a/fallen/Editor/Headers/DarkCity.h b/fallen/Editor/Headers/DarkCity.h new file mode 100644 index 0000000..2a50d99 --- /dev/null +++ b/fallen/Editor/Headers/DarkCity.h @@ -0,0 +1,8 @@ +// DarkCity.h +// Guy Simmons, 14th October 197. + + +#ifndef DARKCITY_H +#define DARKCITY_H + +#endif diff --git a/fallen/Editor/Headers/EdCom.h b/fallen/Editor/Headers/EdCom.h new file mode 100644 index 0000000..1dc8908 --- /dev/null +++ b/fallen/Editor/Headers/EdCom.h @@ -0,0 +1,137 @@ +// EdCom.h +// Guy Simmons, 16th March 1998. + +#ifndef ED_COM_H +#define ED_COM_H + +//--------------------------------------------------------------- +// Editor condition stuff. + +#define MAX_EDIT_CONDITIONS 1000 + +struct EditCondition +{ + BOOL Used; + + UWORD Flags, + ConditionType, + Data1, + Data2, + Data3, + GroupRef; + + EditCondition *Next, + *Prev; +}; + +extern ULONG ed_condition_count; +extern EditCondition edit_conditions[MAX_EDIT_CONDITIONS]; + +//--------------------------------------------------------------- + +void init_ed_conditions(void); +EditCondition *alloc_ed_condition(void); +void free_ed_condition(EditCondition *the_condition); + +//--------------------------------------------------------------- +// Editor condition list stuff. + +#define MAX_EDIT_CLISTS 100 + +struct EditCondList +{ + BOOL Used; + CBYTE CListName[32]; + + EditCondition *ConditionList, + *ConditionListEnd; + + ULONG ConditionCount; + EditCondList *Next, + *Prev; +}; + +extern ULONG ed_clist_count; +extern EditCondList edit_clists[MAX_EDIT_CLISTS], + *clists, + *clists_end, + *win_conditions, + *lose_conditions; + +#define ED_CONLIST_NUMBER(c) (UWORD)(c-edit_clists) + +//--------------------------------------------------------------- + +void init_ed_clists(void); +EditCondList *alloc_ed_clist(void); +void free_ed_clist(EditCondList *the_clist); +void add_condition(EditCondList *the_clist,EditCondition *the_condition); +void remove_condition(EditCondList *the_clist,EditCondition *the_condition); +void move_condition(EditCondList *the_clist,EditCondition *insert_point,EditCondition *the_condition); + +//--------------------------------------------------------------- +// Editor command stuff. + +#define MAX_EDIT_COMMANDS 2000 + +struct EditCommand +{ + BOOL Used; + + UWORD Flags, + CommandType, + Data1, + Data2, + Data3, + GroupRef; + + EditCommand *Next, + *Prev; +}; + +extern ULONG ed_command_count; +extern EditCommand edit_commands[MAX_EDIT_COMMANDS]; + +//--------------------------------------------------------------- + +void init_ed_commands(void); +EditCommand *alloc_ed_command(void); +void free_ed_command(EditCommand *the_command); + +//--------------------------------------------------------------- +// Editor command list stuff. + +#define MAX_EDIT_COMLISTS 200 + +struct EditComList +{ + BOOL Used; + CBYTE ComListName[32]; + + EditCommand *CommandList, + *CommandListEnd; + + ULONG CommandCount; + EditComList *Next, + *Prev; +}; + +extern ULONG ed_comlist_count; +extern EditComList edit_comlists[MAX_EDIT_COMLISTS], + *comlists, + *comlists_end; + +#define ED_COMLIST_NUMBER(c) (UWORD)(c-edit_comlists) + +//--------------------------------------------------------------- + +void init_ed_comlists(void); +EditComList *alloc_ed_comlist(void); +void free_ed_comlist(EditComList *the_clist); +void add_command(EditComList *the_clist,EditCommand *the_command); +void remove_command(EditComList *the_comlist,EditCommand *the_command); +void move_command(EditComList *the_comlist,EditCommand *insert_point,EditCommand *the_command); + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Headers/EdUtils.h b/fallen/Editor/Headers/EdUtils.h new file mode 100644 index 0000000..24a7f16 --- /dev/null +++ b/fallen/Editor/Headers/EdUtils.h @@ -0,0 +1,60 @@ +// EdUtils.h +// Guy Simmons, 5th April 1997. + +#include "c:\fallen\headers\structs.h" +//#define GAME_SCALE 2560.0 + +extern SLONG current_element; +extern struct KeyFrameElement *the_elements; + + +void read_object_name(FILE *file_handle,CBYTE *dest_string); +void load_multi_vue(struct KeyFrameChunk *the_chunk,float scale); +//void load_key_frame_chunks(KeyFrameChunk *the_chunk,CBYTE *vue_name); +void sort_multi_object(struct KeyFrameChunk *the_chunk); +void setup_anim_stuff(void); +void reset_anim_stuff(void); +void load_chunk_texture_info(KeyFrameChunk *the_chunk); +void do_single_shot(UBYTE *screen,UBYTE *palette); +void do_record_frame(UBYTE *screen,UBYTE *palette); +SLONG write_pcx(CBYTE *fname,UBYTE *src,UBYTE *pal); +void editor_show_work_screen(ULONG flags); +void editor_show_work_window(ULONG flags); + + +//--------------------------------------------------------------- + +inline UWORD calc_lights(SLONG x,SLONG y,SLONG z,struct SVector *p_vect) +{ +#ifdef EDITOR + SLONG dx,dy,dz,dist; + SLONG lx,ly,lz; + ULONG c0; + SLONG total=0; + lx=p_vect->X+x; + ly=p_vect->Y+y; + lz=p_vect->Z+z; + + for(c0=1;c0 +#include "c:\fallen\ddlibrary\headers\DDLib.h" + +void Time(struct MFTime *the_time); + +//--------------------------------------------------------------- +// Draw2D + +extern UBYTE *CharTable[]; +extern UBYTE *WorkWindow; +extern SLONG WorkWindowHeight, + WorkWindowWidth; +extern MFRect WorkWindowRect; + +void SetWorkWindowBounds(SLONG left, SLONG top, SLONG width, SLONG height); +MFPoint *GlobalToLocal(MFPoint *the_point); +void GlobalXYToLocal(SLONG *x,SLONG *y); + +extern void (*DrawBox)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void (*DrawBoxC)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); + +extern void DrawCircle(SLONG x,SLONG y,SLONG radius,ULONG colour); +extern void DrawCircleC(SLONG x,SLONG y,SLONG radius,ULONG colour); + +extern void (*DrawLine)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void (*DrawLineC)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void (*DrawHLine)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void (*DrawHLineC)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void (*DrawVLine)(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void (*DrawVLineC)(SLONG x,SLONG y1,SLONG y2,ULONG colour); + +extern void (*DrawPoint)(MFPoint *the_point,ULONG colour); +extern void (*DrawPointC)(MFPoint *the_point,ULONG colour); + +extern void (*DrawPixel)(SLONG x,SLONG y,ULONG colour); +extern void (*DrawPixelC)(SLONG x,SLONG y,ULONG colour); + +extern void DrawRect(MFRect *the_rect,ULONG colour); +extern void DrawRectC(MFRect *the_rect,ULONG colour); + +extern void (*QuickText)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void (*QuickTextC)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void (*QuickChar)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void (*QuickCharC)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); + +SLONG QTStringWidth(CBYTE *the_string); +inline SLONG QTStringHeight(void) { return 8; } +inline SLONG QTCharWidth(CBYTE the_char) { return (CharTable[the_char])[0]; } +inline SLONG QTCharHeight(CBYTE the_char) { return (CharTable[the_char])[1]; } + +void SetDrawFunctions(ULONG depth); +void ShowWorkWindow(ULONG flags); + +//--------------------------------------------------------------- +// Palette + +#define FADE_IN 1<<0 +#define FADE_OUT 1<<1 + +extern UBYTE CurrentPalette[256*3]; + +void InitPalettes(void); +SLONG CreatePalettes(void); +void DestroyPalettes(void); +void RestorePalettes(void); +void SetPalette(UBYTE *the_palette); +SLONG FindColour(UBYTE *pal,SLONG r,SLONG g,SLONG b); + +//--------------------------------------------------------------- +// Sprites + +#define END_LINE 0x00 +#define COPY_PIXELS 0x01 +#define SKIP_PIXELS 0x02 +#define DUPLICATE_PIXELS 0x03 +#define FINISHED 0x04 + +typedef struct +{ + UBYTE *SpriteData; + UWORD SpriteHeight; + UWORD SpriteWidth; +}BSprite; + + +extern void (*DrawBSprite)(SLONG x,SLONG y,BSprite *the_sprite); +extern void (*DrawBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite); +extern void (*DrawMonoBSprite)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void (*DrawMonoBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + +void DrawBSpritePal16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +void DrawBSpritePal32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +void DrawBSpritePalC16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +void DrawBSpritePalC32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +void SetupBSprites(BSprite *sprite_ref,UBYTE *sprite_data); + +//--------------------------------------------------------------- + +#endif + diff --git a/fallen/Editor/Headers/FileReq.hpp b/fallen/Editor/Headers/FileReq.hpp new file mode 100644 index 0000000..fade057 --- /dev/null +++ b/fallen/Editor/Headers/FileReq.hpp @@ -0,0 +1,28 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _FILEREQ_HPP_ +#define _FILEREQ_HPP_ + +#include "ModeTab.hpp" + + +class FileRequester : public EdRect +{ + private: CBYTE *WildCard; + CBYTE *Title; + EdRect OK; + EdRect Cancel; + EdRect TextEdit; + EdRect TextList[30]; + public: + FileRequester(CBYTE *Path,CBYTE *Extension,CBYTE *Title,CBYTE *FileName); + CBYTE *Path; + CBYTE FileName[200]; + SLONG Draw(); + ControlSet Controls; + +}; + +#endif + diff --git a/fallen/Editor/Headers/GameEd.h b/fallen/Editor/Headers/GameEd.h new file mode 100644 index 0000000..4a546cf --- /dev/null +++ b/fallen/Editor/Headers/GameEd.h @@ -0,0 +1,110 @@ +// GameEd.h +// Guy Simmons, 12th January 1998. + +#ifndef GAMEED_H +#define GAMEED_H + +#include "engine.h" +#include "ComTab.h" +#include "CondTab.h" +#include "SaveTab.h" +#include "ThingTab.h" + +//--------------------------------------------------------------- + +#define CLASS_NONE 0 +#define CLASS_PLAYER 1 +#define CLASS_CAMERA 2 +#define CLASS_PROJECTILE 3 +#define CLASS_BUILDING 4 +#define CLASS_PERSON 5 + +#define TAB_NONE 0 +#define TAB_THINGS 1 +#define TAB_LEVELS 2 +#define TAB_COMMANDS 3 +#define TAB_CONDITIONS 4 + +#define SELECT_NONE 0 +#define SELECT_WAYPOINT 1 +#define SELECT_NEXT_WAYPOINT 2 +#define SELECT_PREV_WAYPOINT 3 +#define SELECT_COND_TAB_THING 4 +#define SELECT_COND_TAB_SWITCH 5 +#define SELECT_THING_TAB_THING 6 +#define SELECT_THING_TAB_SWITCH 7 +#define SELECT_COM_TAB_WAYPOINT 8 +#define SELECT_COM_TAB_THING 9 +#define SELECT_COM_TAB_SWITCH 10 + +//--------------------------------------------------------------- + +class GameEditor : public EditorModule +{ + private: + + BOOL FlashState; + UBYTE SelectMode; + SLONG CurrentThing, + FlashCount; + EdItem BackupItem, + HilitedItem, + LastItem, + SelectedItem; + EngineStuff EdEngine; + MFPoint DownPoint; + + CommandTab *CommandMode; + ConditionTab *ConditionMode; + SaveTab *SaveMode; + ThingTab *ThingMode; + + + public: + + ~GameEditor(); + + void SetupModule(void); + void CreateTabs(void); + void DestroyTabs(void); + + void DrawContent(void); + void HandleContentClick(UBYTE flags,MFPoint *clicked_point); + void HandleControlClick(UBYTE flags,MFPoint *clicked_point); + void HandleModule(void); + void HandleThingDrag(void); + UWORD EngineKeys(void); + void DoThingPopup(MFPoint *clicked_point); + void DoBlockPopup(MFPoint *clicked_point); + void HandleWaypointDrag(void); + void DoWaypointPopup(MFPoint *clicked_point); + void HandleSizeDrag(void); + + void GameEdEngine(void); + SLONG DrawFacet(UWORD facet_index,SLONG x,SLONG y,SLONG z); + void ScanEngine(void); + void RenderEngine(void); + void MapText(SLONG x,SLONG y,CBYTE *the_str,ULONG col); + void MapThingInfo(SLONG x,SLONG y,BucketMapThing *the_map_thing); + void MapWaypointInfo(SLONG x,SLONG y,BucketWaypoint *the_waypoint); + void MapSphereInfo(SLONG x,SLONG y,BucketSphereArea *the_sphere); + + void ClearTabMode(void); + + inline void SetSelectMode(UBYTE mode) { SetLocalEscape();SelectMode=mode;BackupItem=SelectedItem;SelectedItem=HilitedItem; } + inline void ClearSelectMode(void) { ClearTabMode();ClearLocalEscape();SelectMode=0;SelectedItem=BackupItem; } +}; + +//--------------------------------------------------------------- + +struct GameEdDefaults +{ + SLONG Left, + Top; + SLONG Height, + Width; +}; + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Headers/HmTab.hpp b/fallen/Editor/Headers/HmTab.hpp new file mode 100644 index 0000000..c48b8c7 --- /dev/null +++ b/fallen/Editor/Headers/HmTab.hpp @@ -0,0 +1,33 @@ +// +// A simple editor for putting HM stuff around prims. +// + +class HmTab : public ModeTab +{ + private: + + void draw_prim(UWORD prim); + void draw_grid(UWORD prim); + void draw_cog (UWORD prim); + + public: + + // + // The bare minimum... + // + + HmTab(EditorModule *parent); + ~HmTab(); + + void DrawTabContent (void); + void HandleTab (MFPoint *current_point); + UWORD HandleTabClick (UBYTE flags, MFPoint *clicked_point); + void HandleControl (UWORD control_id); + void DrawModuleContent (SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + UBYTE RedrawModuleContent; + + // + // Extra stuff... + // +}; diff --git a/fallen/Editor/Headers/Icon.hpp b/fallen/Editor/Headers/Icon.hpp new file mode 100644 index 0000000..edd0af1 --- /dev/null +++ b/fallen/Editor/Headers/Icon.hpp @@ -0,0 +1,29 @@ +// Window.hpp +// Guy Simmons, 18th February 1997. + +#ifndef _ICON_HPP_ +#define _ICON_HPP_ + +#include "Primativ.hpp" + + +struct AWindowIcon +{ + void (*Function)(UWORD id); + UBYTE Flag; + UWORD ImageOn; + SWORD ImageOff; +}; + +class WinBarIcon : public EdRect +{ + private: + struct AWindowIcon *WindowIcons; + public: + inline WinBarIcon() {} + void DrawIcons(void); + void HandleIconClick(UBYTE flags,MFPoint *clicked_point); + void InitIcons(struct AWindowIcon *p_icons); +}; + +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/Intrface.hpp b/fallen/Editor/Headers/Intrface.hpp new file mode 100644 index 0000000..b6ffb65 --- /dev/null +++ b/fallen/Editor/Headers/Intrface.hpp @@ -0,0 +1,96 @@ +// Intrface.hpp +// Guy Simmons, 18th February 1997. + +#ifndef _INTRFACE_HPP_ +#define _INTRFACE_HPP_ + +class Interface +{ + private: + ULONG ContentColour, + ContentColourBr, + HiliteColour, + LoliteColour, + ActiveColour, + InactiveColour, + WhiteColour, + GreyColour, + YellowColour, + RedColour, + GreenColour, + BlueColour, + TextColour, + SelectColour; + UBYTE InterfacePalette[768]; + UBYTE *interface_sprite_data; + BSprite *interface_sprites; + + public: + Interface(); + ~Interface(); + void SetupInterfaceDefaults(void); + inline ULONG GetContentColour(void) { return ContentColour; }; + inline ULONG GetContentColourBr(void) { return ContentColourBr; }; + inline ULONG GetHiliteColour(void) { return HiliteColour; }; + inline ULONG GetWhiteColour(void) { return WhiteColour; }; + inline ULONG GetGreyColour(void) { return GreyColour; }; + inline ULONG GetYellowColour(void) { return YellowColour; }; + inline ULONG GetRedColour(void) { return RedColour; }; + inline ULONG GetGreenColour(void) { return GreenColour; }; + inline ULONG GetBlueColour(void) { return BlueColour; }; + inline ULONG GetLoliteColour(void) { return LoliteColour; }; + inline ULONG GetActiveColour(void) { return ActiveColour; }; + inline ULONG GetInactiveColour(void) { return InactiveColour; }; + inline ULONG GetTextColour(void) { return TextColour; }; + inline ULONG GetSelectColour(void) { return SelectColour; }; + inline UBYTE *GetPalette(void) { return InterfacePalette; }; + inline BSprite* GetInterfaceSprite(UWORD id) { return &interface_sprites[id]; }; +// inline BSprite* GetInterfacePointer(UWORD id) { return &interface_pointers[id];}; +}; + + + + +extern Interface *InterfaceDefaults; +#define CONTENT_COL_BR InterfaceDefaults->GetContentColourBr() +#define CONTENT_COL InterfaceDefaults->GetContentColour() +#define HILITE_COL InterfaceDefaults->GetHiliteColour() +#define LOLITE_COL InterfaceDefaults->GetLoliteColour() +#define ACTIVE_COL InterfaceDefaults->GetActiveColour() +#define INACTIVE_COL InterfaceDefaults->GetInactiveColour() +#define TEXT_COL InterfaceDefaults->GetTextColour() +#define SELECT_COL InterfaceDefaults->GetSelectColour() +#define WHITE_COL InterfaceDefaults->GetWhiteColour() +#define GREY_COL InterfaceDefaults->GetGreyColour() +#define YELLOW_COL InterfaceDefaults->GetYellowColour() +#define RED_COL InterfaceDefaults->GetRedColour() +#define GREEN_COL InterfaceDefaults->GetGreenColour() +#define BLUE_COL InterfaceDefaults->GetBlueColour() + +#define INTERFACE_SPRITE(ID) InterfaceDefaults->GetInterfaceSprite(ID) +#define INTERFACE_POINTER(ID) InterfaceDefaults->GetInterfacePointer(ID) + +#define PALETTE InterfaceDefaults->GetPalette() + +#define DEFAULTS_DIRECTORY "EditDefs" + +#define GROW_ICON 1 + +#define UP_ICON 6 +#define DOWN_ICON 7 +#define LEFT_ICON 8 +#define RIGHT_ICON 9 +#define CHECK_ICON 10 +#define RADIO_ICON1 11 +#define RADIO_ICON2 12 +#define RADIO_ICON3 13 +#define RADIO_ICON4 14 +#define MENU_ICON 15 + +#define NO_CLICK 0 +#define LEFT_CLICK 1 +#define RIGHT_CLICK 2 +#define MIDDLE_CLICK 3 + + +#endif diff --git a/fallen/Editor/Headers/KFrameEd.hpp b/fallen/Editor/Headers/KFrameEd.hpp new file mode 100644 index 0000000..39058b7 --- /dev/null +++ b/fallen/Editor/Headers/KFrameEd.hpp @@ -0,0 +1,135 @@ +// KFrameEd.hpp +// Guy Simmons, 12th March 1997. + +#ifndef _KFRAMEED_HPP_ +#define _KFRAMEED_HPP_ + +#include "EditMod.hpp" +#include "Anim.h" +#include "Prim.h" +#include "LevelEd.hpp" + + +#define GOT_ANIM_COPY (1<<0) + +extern void test_draw(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween, + struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next, + struct Matrix33 *rot_mat, + struct Matrix31 *parent_pos, struct Matrix33 *parent_mat, + KeyFrameElement *parent_element, + struct Matrix31 *end_pos, struct Matrix33 *end_mat + ); + +class KeyFrameEditor : public EditorModule +{ + private: + SLONG AnimAngleX[2], + AnimAngleY[2], + AnimAngleZ[2], + AnimOffsetX[2], + AnimOffsetY[2], + AnimOffsetZ[2], + AnimScale, + AnimCount[2], + AnimTween[2], + AnimGlobalAngleX, + AnimGlobalAngleY, + AnimGlobalOffsetX, + AnimGlobalOffsetY, +// CurrentElement, + Flags; + UBYTE SpeedFlag; + SLONG QuaternionFlag; + SLONG Flip1, Flip2; + Anim *AnimList[2], + *CurrentAnim[2], + *PlayingAnim[2]; + Character *CurrentCharacter, + TestCharacter; + ControlSet AnimControls; + EdRect AllAnimsRect, + AnimFrameRect, + CharactersRect, + BodyPartRect, + KeyFrameRect; + KeyFrame *CurrentFrame[2], + *SelectedFrame; + struct FightCol FightingCol; + struct FightCol *FightingColPtr; + ULONG FightColBank; + UBYTE VideoMode; + UBYTE PersonID,Bank; + UBYTE PersonBits[MAX_BODY_BITS]; + SLONG DontDrawBoth; + SLONG MoveSeparately; + +// KeyFrameChunk *TestChunk; +// KeyFrameElement *TheElements; + + public: + + ~KeyFrameEditor(); + void SetupModule(void); + void CreateKeyFrameTabs(void); + void DestroyKeyFrameTabs(void); + void DrawContent(void); + void DrawControls(void); + void HandleContentClick(UBYTE flags,MFPoint *clicked_point); + void HandleControlClick(UBYTE flags,MFPoint *clicked_point); + SLONG HandleModuleKeys(void); + void HandleModule(void); + void AddKeyFrameChunk(void); + void HandleControl(ULONG control_id); + void HandleAnimControl(ULONG control_id); + void DrawCombatEditor(void); + void DrawPeopleTypes(void); + void DoCurrentAnim(void); + // JCL - recursive anim stuff + void DoAnimRecurse(SLONG part_number, struct Matrix33 *mat, SLONG start_object, + struct Matrix31 *parent_pos, struct Matrix33 *parent_mat, + KeyFrameElement *parent_element); + void DoHierarchicalAnim(); + + void DrawKeyFrame(UWORD multi_object,EdRect *bounds_rect,struct KeyFrame *the_frame,struct Matrix33 *r_matrix); +// void LoadMultiVUE(struct KeyFrameChunk *the_chunk); +// void SortMultiObject(struct KeyFrameChunk *the_chunk); +// void test_draw(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next,struct Matrix33 *rot_mat); + void DrawKeyFrames(void); + void SetPersonBits(void); + void SetBodyType(SLONG part); + SLONG GetPartID(UWORD current); + void DrawAnimFrames(Anim *the_anim,BOOL hilite); + Anim *DrawAllAnimsBox(void); + void ClearAll(void); + void AppendAnim(void); + void InsertAnim(Anim *insert_here); + void DestroyAnim(Anim *the_anim); + void LoadAllAnims(KeyFrameChunk *the_chunk); + void SaveAllAnims(KeyFrameChunk *the_chunk,SLONG save_all); + void LoadAnim(MFFileHandle file_handle,Anim *the_anim); + void SaveAnim(MFFileHandle file_handle,Anim *the_anim); + void SaveBodyPartInfo(MFFileHandle file_handle,SLONG version,KeyFrameChunk *the_chunk); + void LoadBodyPartInfo(MFFileHandle file_handle,SLONG version,KeyFrameChunk *the_chunk); + + void LoadKeyFrameChunks(void); + void SaveChunkTextureInfo(KeyFrameChunk *the_chunk); + void LoadChunkTextureInfo(KeyFrameChunk *the_chunk); + void SetAnimBank(SLONG bank); + + SLONG DragAndDropFrame(KeyFrame *selected_frame,SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *clicked_point,ULONG del_flag); + + LevelEditor *LinkLevelEditor; + inline SLONG GetAnimAngleX(void) { return AnimAngleX[Bank]; } + inline SLONG GetAnimAngleY(void) { return AnimAngleY[Bank]; } + inline SLONG GetAnimAngleZ(void) { return AnimAngleZ[Bank]; } + + inline Anim *GetCurrentAnim(void) { return CurrentAnim[Bank]; } + inline UBYTE GetPersonID(void) { return PersonID; } + inline void SetSelectedFrame(KeyFrame *kframe) { SelectedFrame=kframe; } + + SLONG GetQuaternionFlag() {return (!(QuaternionFlag));}; +}; + + +#endif + diff --git a/fallen/Editor/Headers/KFramer.hpp b/fallen/Editor/Headers/KFramer.hpp new file mode 100644 index 0000000..aed38b6 --- /dev/null +++ b/fallen/Editor/Headers/KFramer.hpp @@ -0,0 +1,43 @@ +// KFramer.hpp +// Guy Simmons, 19th September 1997. + + +#ifndef _KFRAMER_HPP_ +#define _KFRAMER_HPP_ + +#include "EditMod.hpp" + + +#define CTRL_KF_LOAD_BUTTON 1 +#define CTRL_KF_FRAME_SLIDER 2 + + +class KeyFrameEditor2 : public EditorModule +{ + private: + SLONG AnimAngleX, + AnimAngleY, + AnimAngleZ, + AnimOffsetX, + AnimOffsetY, + AnimOffsetZ, + AnimScale, + AnimCount, + AnimTween; + ControlSet KeyFramesControls; + EdRect KeyFramesRect; + + public: + ~KeyFrameEditor2(); + void SetupModule(void); + void DrawContent(void); + void HandleContentClick(UBYTE flags,MFPoint *clicked_point); + void HandleControlClick(UBYTE flags,MFPoint *clicked_point); + void HandleModule(void); + void HandleKeyFramesControl(ULONG control_id); + void DrawKeyFrames(void); + void DrawKeyFrame(UWORD multi_object,EdRect *bounds_rect,struct KeyFrame *the_frame,struct Matrix33 *r_matrix); +}; + +#endif + diff --git a/fallen/Editor/Headers/LevelEd.hpp b/fallen/Editor/Headers/LevelEd.hpp new file mode 100644 index 0000000..0a58520 --- /dev/null +++ b/fallen/Editor/Headers/LevelEd.hpp @@ -0,0 +1,97 @@ +// LevelEdit.cpp +// Guy Simmons, 19th February 1997. + +#ifndef _LEVELED_HPP_ +#define _LEVELED_HPP_ + +#include "Edit.h" +#include "EditMod.hpp" +#include "PaintTab.hpp" +#include "PrPiTab.hpp" +#include "LightTab.hpp" +#include "ColTab.hpp" +#include "MapTab.hpp" +#include "MapEdTab.hpp" +#include "BuildTab.hpp" +#include "HmTab.hpp" +#include "SewerTab.hpp" + +#define TAB_NONE 0 +#define TAB_PAINT 1 +#define TAB_PRIMPICK 2 +#define TAB_LIGHT 3 +#define TAB_MAP 4 +#define TAB_MAPED 5 +#define TAB_BUILD 6 +#define TAB_HM 7 +#define TAB_SEWER 8 + +#define UNDO_NONE 0 +#define UNDO_TEXTURE 1 + + +class LevelEditor : public EditorModule +{ + private: + UBYTE UndoType, + LastU[4], + LastV[4]; + ControlSet PrimSet; + UWORD CurrentAnimTmap; + + public: + ~LevelEditor(void); + void SetupModule(void); + void CreateLevelTabs(void); + void DestroyLevelTabs(void); + void DrawContent(void); + void DrawAnimTmapContent(SLONG current_anim_tmap); + void DrawTexStyleContent(void); + void DrawPSXTexContent(void); + SLONG HandlePSXTexClick(UBYTE flags,MFPoint *clicked_point); + SLONG HandleTexStyleClick(UBYTE flags,MFPoint *clicked_point); + void HandleAnimTmapClick(UBYTE flags,MFPoint *clicked_point); + void HandleContentClick(UBYTE flags,MFPoint *clicked_point); + void HandleControlClick(UBYTE flags,MFPoint *clicked_point); + void DragEngine(UBYTE flags,MFPoint *clicked_point); + void HandleStyleControl(ULONG control_id); + void HandlePSXControl(ULONG control_id); + UBYTE DoStylePopup(MFPoint *clicked_point,UBYTE flags); + void SetWallTextureInfo(SLONG wall,UBYTE page,EdTexture *current_texture); + void TextureFace(SWORD face,PaintTab *texture_mode); + + UBYTE DoInStylePopup(MFPoint *clicked_point,UBYTE flags); + void DrawInTexStyleContent(void); + void HandleInStyleControl(ULONG control_id); + void DrawTexInStyleContent(void); + SLONG HandleTexInStyleClick(UBYTE flags,MFPoint *clicked_point); + + + void HandleModule(void); + void DoFacePopup(MFPoint *clicked_point); + BOOL ApplyTexture(struct EditFace *edit_face); + inline void SetAnimTexture(SLONG tmap) { CurrentAnimTmap=(UWORD)tmap; } + ModeTab *TestMode; + PaintTab *PaintMode; + PrimPickTab *PrimMode; + LightTab *LightMode; + ColTab *ColMode; + MapTab *MapMode; + MapEdTab *MapEdMode; + BuildTab *BuildMode; + HmTab *HmMode; + SewerTab *SewerMode; + ControlSet PSXControls; + ControlSet StyleControls; + ControlSet InStyleControls; +}; + +struct LevelEdDefaults +{ + SLONG Left, + Top; + SLONG Height, + Width; +}; + +#endif diff --git a/fallen/Editor/Headers/LightTab.hpp b/fallen/Editor/Headers/LightTab.hpp new file mode 100644 index 0000000..1471e59 --- /dev/null +++ b/fallen/Editor/Headers/LightTab.hpp @@ -0,0 +1,63 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _LIGHTTAB_HPP_ +#define _LIGHTTAB_HPP_ + +#include "ModeTab.hpp" +#include "Stealth.h" +#include "EditMod.hpp" +#include "undo.hpp" + + +#define LIGHT_TAB_MODE_WAIT 0 +#define LIGHT_TAB_MODE_PLACE_LIGHT 1 +#define LIGHT_TAB_MODE_EDIT_LIGHT 2 +#define LIGHT_TAB_MODE_DRAG_LIGHT 3 +#define LIGHT_TAB_MODE_PLACE_AMBIENT 4 +#define LIGHT_TAB_MODE_REPEAT_PLACE_LIGHT 5 + + +class LightTab : public ModeTab +{ + private: + SLONG Axis; + SLONG GridFlag; + UBYTE AxisMode; + EdRect View1; + EdRect View2; + EdRect View3; + UBYTE RedrawTabContent; + UBYTE Shadow; + UWORD CurrentLight; + public: + LightTab(EditorModule *parent); + ~LightTab(); + void DrawTabContent(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG SetWorldMouse(ULONG flag); + SLONG KeyboardInterface(void); + SWORD CreateLightThing(SLONG x,SLONG y,SLONG z,SLONG bright); + void DeleteLightThing(SWORD thing); + SLONG DragALight(UBYTE flags,MFPoint *clicked_point,UWORD copy); + SLONG DragEngine(UBYTE flags,MFPoint *clicked_point); + void SetAmbientAngle(void); + void RecalcAllLights(void); + void SmoothGroup(void); + Undo MyUndo; + UBYTE RedrawModuleContent; + UWORD Mode; + SLONG ClickOnLight(MFPoint *clicked_point); + EditorModule *Parent; +}; + + +extern void add_a_background_thing(UWORD prim,SLONG x,SLONG y,SLONG z); +extern void apply_light_to_map(SLONG x,SLONG y,SLONG z,SLONG bright); + +#endif + diff --git a/fallen/Editor/Headers/MapEdTab.hpp b/fallen/Editor/Headers/MapEdTab.hpp new file mode 100644 index 0000000..97cc963 --- /dev/null +++ b/fallen/Editor/Headers/MapEdTab.hpp @@ -0,0 +1,67 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _MAPEDTAB_HPP_ +#define _MAPEDTAB_HPP_ + +#include "ModeTab.hpp" +#include "Stealth.h" +#include "EditMod.hpp" +#include "undo.hpp" + +#define FLOOR_CUT_BRUSH 1 +#define FLOOR_PASTE_BRUSH 2 +#define FLOOR_HOLD_BRUSH 3 +#define FLOOR_CUT_BRUSH_DEF 4 + + +class MapEdTab : public ModeTab +{ + private: + SLONG Axis; + SLONG GridFlag; + UBYTE AxisMode; + EdRect View1; + EdRect View2; + EdRect View3; + UBYTE RedrawTabContent; + UWORD CurrentCol; + SLONG X1,Y1,Z1,X2,Y2,Z2; + public: + MapEdTab(EditorModule *parent); + ~MapEdTab(); + void DrawTabContent(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG SetWorldMouse(ULONG flag); + SLONG KeyboardInterface(void); + SLONG DragEngine(UBYTE flags,MFPoint *clicked_point); + SLONG CalcMapCoord(SLONG *mapx,SLONG *mapy,SLONG *mapz,SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *clicked_point); + SLONG DragPaint(UBYTE flags); + SLONG DragMark(UBYTE flags); + void CutFloorBrush(MFPoint *current_point,SLONG button); + SLONG MouseInContent(void); + void DragAltitude(SLONG mx,SLONG mz); + SLONG FlattenArea(void); + SLONG SmoothArea(void); + SLONG SlopeArea(void); + void ChangeMapAltitude(SLONG mx,SLONG mz,SLONG step,UBYTE offset_flag); +// Undo MyUndo; + UBYTE RedrawModuleContent; + void Clear(void); + UWORD Mode; + UWORD SubMode; + EditorModule *Parent; + BuildTab *BuildMode; + MapBlock CutMapBlock; + SLONG RoofTop; + SLONG Texture; +}; + + + +#endif + diff --git a/fallen/Editor/Headers/MapTab.hpp b/fallen/Editor/Headers/MapTab.hpp new file mode 100644 index 0000000..7f24a1a --- /dev/null +++ b/fallen/Editor/Headers/MapTab.hpp @@ -0,0 +1,80 @@ +// TexTab.hpp +// MCD, 20th February 1997 + +#ifndef _MAPTAB_HPP_ +#define _MAPTAB_HPP_ + +#include "ModeTab.hpp" +#include "Stealth.h" +#include "EditMod.hpp" +#include "undo.hpp" + +#define MAP_TYPE_PLANE 1 +#define MAP_TYPE_BEZIER 2 + +struct MapInfo +{ + SLONG Left; + SLONG Right; + SLONG Top; + SLONG Bottom; + + SLONG X; + SLONG Y; + SLONG Z; + SWORD AngleY; + SWORD Background; + void *PtrMap; + SWORD MapWidth; + SWORD MapHeight; + CBYTE Name[20]; + SLONG Dummy[4]; + + +}; + +class MapTab : public ModeTab +{ + private: + SLONG Axis; + SLONG GridFlag; + UBYTE AxisMode; + EdRect View1; + EdRect View2; + EdRect View3; + UBYTE RedrawTabContent; + UWORD CurrentMap; + UWORD DefMode; + public: + MapTab(EditorModule *parent); + ~MapTab(); + void DrawTabContent(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG SetWorldMouse(ULONG flag); + SLONG KeyboardInterface(void); + SLONG DragAMap(UBYTE flags,MFPoint *clicked_point,UWORD copy); + SLONG DragAMapDef(UBYTE flags,MFPoint *clicked_point,UWORD copy); + SLONG DragAMapDefXYZ(UBYTE flags,MFPoint *clicked_point,UWORD copy); + SLONG DragEngine(UBYTE flags,MFPoint *clicked_point); + void SetMapPos(SLONG x,SLONG y,SLONG z); +// Undo MyUndo; + UBYTE RedrawModuleContent; + void Recalc(void); + void Clear(void); + UWORD PlaceBezier(void); + UWORD Mode; + EditorModule *Parent; +}; + + +#define MAX_MAP_INFO 1000 + +extern struct MapInfo map_info[MAX_MAP_INFO]; +extern UWORD next_map_info; + +#endif + diff --git a/fallen/Editor/Headers/ModeTab.hpp b/fallen/Editor/Headers/ModeTab.hpp new file mode 100644 index 0000000..2399bc7 --- /dev/null +++ b/fallen/Editor/Headers/ModeTab.hpp @@ -0,0 +1,75 @@ +// ModeTab.hpp +// Guy Simmons, 18th February 1997. + +#ifndef _MODETAB_HPP_ +#define _MODETAB_HPP_ + +#include "Controls.hpp" +#include "CtrlSet.hpp" +#include "Primativ.hpp" + +#define TAB_ACTIVE (1<<0) +#define TAB_CLEANUP (1<<1) + + +class ModeTab : public ControlSet +{ + private: + CBYTE *Title; + UWORD TabID; + ULONG *ExternalUpdate; + ModeTab *LastModeTab, + *NextModeTab; + EdRect TitleRect; + + protected: + EdRect ContentRect; + + + + public: + ModeTab(); + inline void RequestUpdate(void) { if(ExternalUpdate)*ExternalUpdate=1; } + + void SetupModeTab(CBYTE *the_title,UWORD id,EdRect *bounding_rect,ULONG *update_ptr); + void SetTabArea(EdRect *bounding_rect); + void MoveTabArea(EdRect *bounding_rect); + void SetTabDrawArea(void); + void ClearTab(void); + + void DrawTab(void); + virtual void DrawTabContent(void); + virtual void HandleTab(MFPoint *current_point); + virtual UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + + inline UWORD GetTabID(void) { return TabID; } + inline void SetTabID(UWORD id) { TabID=id; } + + inline void SetLastTabLink(ModeTab *last_tab) { LastModeTab=last_tab; } + inline void SetNextTabLink(ModeTab *next_tab) { NextModeTab=next_tab; } + inline ModeTab *GetLastTabLink(void) { return LastModeTab; } + inline ModeTab *GetNextTabLink(void) { return NextModeTab; } + + inline BOOL PointInTabContent(MFPoint *the_point){ return ContentRect.PointInRect(the_point); } + inline SLONG ContentLeft(void) { return ContentRect.GetLeft(); } + inline SLONG ContentTop(void) { return ContentRect.GetTop(); } + inline SLONG ContentRight(void) { return ContentRect.GetRight(); } + inline SLONG ContentBottom(void) { return ContentRect.GetBottom(); } + inline SLONG ContentWidth(void) { return ContentRect.GetWidth(); } + inline SLONG ContentHeight(void) { return ContentRect.GetHeight(); } + + inline BOOL PointInTitle(MFPoint *the_point) { return TitleRect.PointInRect(the_point); } + inline SLONG TitleLeft(void) { return TitleRect.GetLeft(); } + inline SLONG TitleRight(void) { return TitleRect.GetRight(); } + inline SLONG TitleTop(void) { return TitleRect.GetTop(); } + inline SLONG TitleWidth(void) { return TitleRect.GetWidth(); } + inline SLONG TitleHeight(void) { return TitleRect.GetHeight(); } + + inline MFPoint *GlobalToLocal(MFPoint *the_point) { the_point->X-=ContentRect.GetLeft();the_point->Y-=ContentRect.GetTop();return the_point; } + inline MFPoint *LocalToGlobal(MFPoint *the_point) { the_point->X+=ContentRect.GetLeft();the_point->Y+=ContentRect.GetTop();return the_point; } + + inline void SetExternalUpdatePtr(ULONG *ptr) { ExternalUpdate=ptr; } +}; + +#endif + diff --git a/fallen/Editor/Headers/ObjectEd.hpp b/fallen/Editor/Headers/ObjectEd.hpp new file mode 100644 index 0000000..8a21e23 --- /dev/null +++ b/fallen/Editor/Headers/ObjectEd.hpp @@ -0,0 +1,36 @@ +// ObjectEd.hpp +// Guy Simmons, 26th February 1997. + +#ifndef _OBJECTED_HPP_ +#define _OBJECTED_HPP_ + +#include "EditMod.hpp" +#include "TexTab.hpp" + +#define TAB_NONE 0 +#define TAB_TEXTURE 1 + + +class ObjectEditor : public EditorModule +{ + private: + TextureTab *TextureMode; + + public: + void SetupModule(void); + void CreateObjectTabs(void); + void DestroyObjectTabs(void); + void HandleControlClick(UBYTE flags,MFPoint *clicked_point); + void HandleModule(void); +}; + +struct ObjectEdDefaults +{ + SLONG Left, + Top; + SLONG Height, + Width; +}; + +#endif + diff --git a/fallen/Editor/Headers/PaintTab.hpp b/fallen/Editor/Headers/PaintTab.hpp new file mode 100644 index 0000000..9b3c614 --- /dev/null +++ b/fallen/Editor/Headers/PaintTab.hpp @@ -0,0 +1,122 @@ +// PaintTab.hpp +// Guy Simmons, 7th April 1997 + +#ifndef _PAINTTAB_HPP_ +#define _PAINTTAB_HPP_ + +#include "undo.hpp" +#include "ModeTab.hpp" +#include "BuildTab.hpp" +#include "Stealth.h" + + +#define PALETTE_PAINT 0 +#define TEXTURE_PAINT 1 +#define PLANAR_PAINT 2 +#define ANIM_TMAP_PAINT 3 +#define FLOOR_PAINT 4 +#define STYLE_PAINT 5 +#define STYLE_DEFINE 6 +#define INSTYLE_DEFINE 7 +#define PSX_TEX_DEFINE 8 + + +#define FLOOR_CUT_BRUSH 1 +#define FLOOR_PASTE_BRUSH 2 + + +#define FLAGS_SHOW_TEXTURE (1<<0) +#define FLAGS_QUADS (1<<1) +#define FLAGS_FIXED (1<<2) +extern CBYTE texture_style_names[200][21]; + +extern UWORD floor_texture_sizes[]; + +class PaintTab : public ModeTab +{ + private: + UBYTE CurrentColour; + SLONG CurrentTexturePage; + ULONG PaintMode, + TextureFlags; + SLONG TextureWidth, + TextureHeight, + TextureX, + TextureY, + TextureZoom; + EdRect ClickRect[4], + AnimRect, + PaintRect; + EdTexture CurrentTexture; + SLONG CurrentAnimTmap; + SLONG ShowAnimTmap; + + + void do_undo_me_bloody_self_then(SLONG index); + + public: + PaintTab(EditorModule *parent); + ~PaintTab(); + void UpdateTabInfo(void); + void DrawTabContent(void); + void DrawTexture(void); + void DrawStyleTexture(void); + void UpdateTexture(void); + void UpdateTextureInfo(void); + void DrawPalette(void); + void DrawAnimTmapSelector(void); + void UpdatePalette(void); + void UpdatePaletteInfo(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void HandlePaletteControl(UWORD control_id); + void HandleTextureControl(UWORD control_id); + void HandleStyleControl(UWORD control_id); + void SelectColour(MFPoint *clicked_point); + void SelectTexture(MFPoint *clicked_point); + void SelectStyle(MFPoint *clicked_point); + void SelectAnimTexture(MFPoint *clicked_point); + void PlanarMapping(MFPoint *clicked_point); + void DoPlanarMap(void); + void DoPlanarMapF(void); + void SetEditAnimTexture(MFPoint *clicked_point); +// UWORD ConvertFreeToFixedEle(struct TextureBits *t); + UWORD ConvertFreeToFixedEle(struct TextureBits *t,SLONG *x,SLONG *y,SLONG *width,SLONG *height,SLONG *page); + void ConvertFixedToFree(struct TextureBits *t); + void ConvertMiniTex(struct MiniTextureBits *tex); + UWORD ConvertTexToMiniTex(void); + void CutFloorBrush(BuildTab *BuildMode,MFPoint *current_point); + + inline SLONG GetTexturePage(void) { return CurrentTexturePage; } + inline void SetTexturePage(SLONG page) { CurrentTexturePage=page; } + inline EdTexture *GetTexture(void) { return &CurrentTexture; } + inline ULONG GetTextureFlags(void) { return TextureFlags; } + inline void SetTextureFlags(ULONG flags) { TextureFlags=flags; } + inline ULONG GetPaintMode(void) { return PaintMode; } + inline void SetPaintMode(ULONG mode) { PaintMode=mode; } + inline UWORD GetCurrentColour(void) { return CurrentColour; } + inline void SetCurrentColour(UWORD col) { CurrentColour=col; } + inline ULONG GetAnimTmap(void) { return CurrentAnimTmap; } + inline void SetAnimTmap(ULONG v) { CurrentAnimTmap=v; } + + Undo MyUndo; + BOOL ApplyTexture(struct EditFace *edit_face); + EditorModule *Parent; + ControlSet PaletteSet, + StyleSet, + inStyleSet, + TextureSet; + SLONG CurrentTextureRot; + SLONG CurrentStyleEdit; + SLONG CurrentStylePos; + SLONG CurrentInStyleEdit; + SLONG CurrentInStylePos; + SLONG SubMode,SubStatus; + MapBlock CutMapBlock; + +}; + + +#endif + diff --git a/fallen/Editor/Headers/Poly.h b/fallen/Editor/Headers/Poly.h new file mode 100644 index 0000000..0770818 --- /dev/null +++ b/fallen/Editor/Headers/Poly.h @@ -0,0 +1,104 @@ +#ifndef POLY_H +#define POLY_H 1 + +#include +//DEFINES + +#define POLY_FLAG_GOURAD (1<<0) +#define POLY_FLAG_TEXTURED (1<<1) +#define POLY_FLAG_MASKED (1<<2) +#define POLY_FLAG_SEMI_TRANS (1<<3) +#define POLY_FLAG_ALPHA (1<<4) +#define POLY_FLAG_TILED (1<<5) +#define POLY_FLAG_DOUBLESIDED (1<<6) +#define POLY_FLAG_WALKABLE (1<<7) +//#define POLY_FLAG_ (1<<) +#define VM_GT 1 +#define POLY_MODES 0x3f + +// STRUCTS + +struct EnginePoint //redesign this +{ + SLONG X; // these + SLONG Y; // elements + SLONG TMapX; // fixed + SLONG TMapY; // by + SLONG Shade; // trig function + SLONG X3d; + SLONG Y3d; + SLONG Z3d; + SLONG DistSqr; + UWORD padw; + UBYTE Flags; + UBYTE padb; +}; + +struct MfEnginePoint //redesign this +{ + SLONG X; // these + SLONG Y; // elements + SLONG Z3d; + UBYTE TX; // fixed + UBYTE TY; // by + UBYTE Shade; // trig function + UBYTE padw; +}; + +struct MFDXEnginePoint +{ + float ScrX, + ScrY, + ScrZ, + U, + V; + D3DCOLOR Colour; +}; + +struct PolyInfo +{ + UWORD *PTexture; + UWORD Col; + UWORD DrawFlags; + UBYTE Page; +}; + + +//DATA + +extern SLONG div_table[65536]; +extern UWORD *tmaps[]; +extern UBYTE *pals[]; +extern UBYTE tmap[]; +extern UBYTE tmap2[]; +extern UBYTE fade_tables[256*65]; +extern UBYTE mix_map[256*256]; +extern UWORD pal_to_16[256]; +extern struct PolyInfo poly_info; + +// FUNCTIONS + +extern UWORD is_it_clockwise(const struct EnginePoint *point1,const struct EnginePoint *point2,const struct EnginePoint *point3); +extern void my_trig(struct MfEnginePoint *p3,struct MfEnginePoint *p2,struct MfEnginePoint *p1); +extern void my_trigp(struct MfEnginePoint *p3,struct MfEnginePoint *p2,struct MfEnginePoint *p1); +//extern void my_trig(struct EnginePoint *p3,struct EnginePoint *p2,struct EnginePoint *p1); +extern void init_tmap(void); +extern void make_fade_table(UBYTE *pal); +extern void make_mix_map(UBYTE *pal); +extern void double_work_window(void); +extern void init_poly_system(void); +extern void my_quad(struct MfEnginePoint *p4,struct MfEnginePoint *p3,struct MfEnginePoint *p2,struct MfEnginePoint *p1); + +extern void render_span8(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags); +extern void render_span16(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags); +extern void render_span32(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags); + +extern void (*render_span)(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags); + + +extern void draw_all_spans(void); +extern void my_quad_noz(struct MfEnginePoint *p4,struct MfEnginePoint *p3,struct MfEnginePoint *p2,struct MfEnginePoint *p1); +extern void my_trig_noz(struct MfEnginePoint *p4,struct MfEnginePoint *p3,struct MfEnginePoint *p2); + + +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/PrPiTab.hpp b/fallen/Editor/Headers/PrPiTab.hpp new file mode 100644 index 0000000..a4322b0 --- /dev/null +++ b/fallen/Editor/Headers/PrPiTab.hpp @@ -0,0 +1,93 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _PRIMPICKTAB_HPP_ +#define _PRIMPICKTAB_HPP_ + +#include "ModeTab.hpp" +#include "Stealth.h" +#include "EditMod.hpp" +#include "undo.hpp" + +/* +#define CTRL_PRIM_LOAD_BACKGROUND 1 +#define CTRL_PRIM_APPEND_NEW 2 +#define CTRL_PRIM_LOAD_MAP 3 +#define CTRL_PRIM_SAVE_MAP 4 +#define CTRL_PRIM_LORES_TEST 5 +#define CTRL_PRIM_X_AXIS_FREE 6 +#define CTRL_PRIM_Y_AXIS_FREE 7 +#define CTRL_PRIM_Z_AXIS_FREE 8 +#define CTRL_PRIM_GRID_ON 9 +*/ + +#define X_AXIS (1<<0) +#define Y_AXIS (1<<1) +#define Z_AXIS (1<<2) + +#define PRIM_MODE_SINGLE 0 +#define PRIM_MODE_MULTI 1 +#define PRIM_MODE_BACK 2 +#define PRIM_MODE_ANIM_KEY 3 +#define PRIM_MODE_ANIM_MORPH 4 + +extern void record_prim_status(void); + +extern void apply_user_rotates(struct PrimPoint *point); + +class PrimPickTab : public ModeTab +{ + private: + SLONG ListPos; + SLONG CurrentPrim; + SLONG DragThingView1; + SLONG DragThingView2; + SLONG DragThingView3; + SLONG Axis; + SLONG GridFlag; + SLONG GridMax; + SLONG GridCorner; + UBYTE AxisMode, + PrimTabMode; + EdRect PrimRect, + View1, + View2, + View3; + EditorModule *Parent; + UBYTE RedrawTabContent; + void DrawABuildingInRect(ULONG prim,SLONG x,SLONG y,SLONG w,SLONG h); + void DrawAPrimInRect(ULONG prim,SLONG x,SLONG y,SLONG w,SLONG h); + void DrawAMultiPrimInRect(ULONG prim,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG PrimScale,BackScale; + public: + PrimPickTab(EditorModule *parent); + ~PrimPickTab(); + void UpdatePrimInfo(void); + void DrawPrims(void); + void UpdatePrimPickWindow(void); + void DrawTabContent(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HiLightObjects(SLONG x,SLONG y,SLONG w,SLONG h); + inline SLONG GetCurrentPrim(void) {return CurrentPrim;} + inline void SetCurrentPrim(SLONG prim) {CurrentPrim=prim;} + SLONG SetWorldMouse(ULONG flag); + SLONG DragAPrim(UBYTE flags,MFPoint *clicked_point,SLONG button); + SLONG DragEngine(UBYTE flags,MFPoint *clicked_point); + SLONG KeyboardInterface(void); + Undo MyUndo; + UBYTE RedrawModuleContent; + UBYTE View2Mode; + + inline UBYTE GetPrimTabMode(void) { return PrimTabMode; } + inline void SetPrimTabMode(UBYTE mode) { PrimTabMode=mode; } +}; + + +extern void add_a_background_thing(UWORD prim,SLONG x,SLONG y,SLONG z); + +#endif + diff --git a/fallen/Editor/Headers/Prim.h b/fallen/Editor/Headers/Prim.h new file mode 100644 index 0000000..50821b8 --- /dev/null +++ b/fallen/Editor/Headers/Prim.h @@ -0,0 +1,723 @@ +#ifndef PRIM_H +#define PRIM_H 1 + +//DEFINES + + +// Set this to 1 to enable TomF's new D3D-friendly engine. +// 0 enables the old engine again. +// NOTE! There are other versions of this define dotted around in other header +// files! Make sure they all agree or you'll have grief. +#ifdef TARGET_DC +#define USE_TOMS_ENGINE_PLEASE_BOB 1 +#else +#define USE_TOMS_ENGINE_PLEASE_BOB 1 +#endif + + +// +// face savetype for primpoint size change +// +#define PRIM_START_SAVE_TYPE 5793 +#define PRIM_END_SAVE_TYPE 5800 + +// +// roof face flags +// + +#define RFACE_FLAG_SHADOW_1 (1<<0) // Form a number from 0-7 +#define RFACE_FLAG_SHADOW_2 (1<<1) +#define RFACE_FLAG_SHADOW_3 (1<<2) +#define RFACE_FLAG_SLIDE_EDGE (1 << 3) +#define RFACE_FLAG_SLIDE_EDGE_0 (1 << 3) +#define RFACE_FLAG_SLIDE_EDGE_1 (1 << 4) +#define RFACE_FLAG_SLIDE_EDGE_2 (1 << 5) +#define RFACE_FLAG_SLIDE_EDGE_3 (1 << 6) + +#define RFACE_FLAG_SPLIT (1 << 7) // Seeing as we aren't using this... +#define RFACE_FLAG_NODRAW (1 << 7) // ...I'll sneak in this flag! Its temporary. + + + +#define GAME_SCALE (256.0f) //(1660.0+200) //3660 +#define GAME_SCALE_DIV (100.0f) //170.0 //100.0 + +#define FACE_FLAG_WMOVE (1<<0) // A moving walkable face- ThingIndex in an index into the WMOVE_face array. +#define FACE_FLAG_SMOOTH (1<<0) +#define FACE_FLAG_OUTLINE (1<<1) +#define FACE_FLAG_SHADOW_1 (1<<2) // Form a number from 0-7 +#define FACE_FLAG_SHADOW_2 (1<<3) +#define FACE_FLAG_SHADOW_3 (1<<4) +#define FACE_FLAG_ROOF (1<<5) +#define FACE_FLAG_WALKABLE (1<<6) +#define FACE_FLAG_ENVMAP (1<<7) +#define FACE_FLAG_VERTICAL (1<<7) + +#define FACE_FLAG_TINT (1<<8) +#define FACE_FLAG_ANIMATE (1<<9) +#define FACE_FLAG_OTHER_SPLIT (1<<10) +#define FACE_FLAG_METAL (1<<10) +#define FACE_FLAG_NON_PLANAR (1<<11) +#define FACE_FLAG_TEX2 (1<<12) + +#define FACE_FLAG_FIRE_ESCAPE (1<<13) +#define FACE_FLAG_PRIM (1<<14) +#define FACE_FLAG_THUG_JACKET (1<<15) + +// +// The face has been fixed- the page changed by TEXTURE_fix_prim_textures() +// + +#define FACE_FLAG_FIXED (1 << 5) + +// +// An edge of a walkable quad that does not lead onto a +// connecting one. +// + +#define FACE_FLAG_SLIDE_EDGE (1 << 1) +#define FACE_FLAG_SLIDE_EDGE_0 (1 << 1) +#define FACE_FLAG_SLIDE_EDGE_1 (1 << 2) +#define FACE_FLAG_SLIDE_EDGE_2 (1 << 3) +#define FACE_FLAG_SLIDE_EDGE_3 (1 << 4) + +#define FACE_FLAG_SLIDE_EDGE_ALL (0xf << 1) +// +// Used only while loading in a SEX object... +// + +#define FACE_FLAG_EDGE_VISIBLE (1 << 13) +#define FACE_FLAG_EDGE_VISIBLE_A (FACE_FLAG_EDGE_VISIBLE << 0) +#define FACE_FLAG_EDGE_VISIBLE_B (FACE_FLAG_EDGE_VISIBLE << 1) +#define FACE_FLAG_EDGE_VISIBLE_C (FACE_FLAG_EDGE_VISIBLE << 2) + + + +//#define FACE_TYPE_FIRE_ESCAPE (1<<0) +#define FACE_TYPE_FENCE (1<<1) +#define FACE_TYPE_CABLE (1<<2) +#define FACE_TYPE_SKYLIGHT (1<<3) +#define FACE_TYPE_PRIM (1<<4) + +#define GET_SORT_LEVEL(f) (((f)>>2)&7) +#define OR_SORT_LEVEL(u,f) u|=((f)<<2) +#define SET_SORT_LEVEL(u,f) u&=~(7<<2);u|=((f)<<2) + + +// +// What each prim object is. +// + +#define PRIM_OBJ_LAMPPOST 1 +#define PRIM_OBJ_TRAFFIC_LIGHT 2 +#define PRIM_OBJ_WALK_DONT_WALK 3 +#define PRIM_OBJ_PETROL_PUMP 4 +#define PRIM_OBJ_DOUBLE_PETROL_PUMP 5 +#define PRIM_OBJ_GAS_STATION_SIGN 6 +#define PRIM_OBJ_BILLBOARD 7 +#define PRIM_OBJ_GAS_STATION_BBOARD 8 +#define PRIM_OBJ_HOTEL_SIGN 9 +#define PRIM_OBJ_GAS_SIGN 10 +#define PRIM_OBJ_GAS_STATION_LIGHT 11 +#define PRIM_OBJ_FIRE_ESCAPE1 12 +#define PRIM_OBJ_FIRE_ESCAPE2 13 +#define PRIM_OBJ_FIRE_ESCAPE3 14 +#define PRIM_OBJ_FIRE_ESCAPE4 15 +#define PRIM_OBJ_FIRE_ESCAPE5 16 +#define PRIM_OBJ_FIRE_ESCAPE6 17 +#define PRIM_OBJ_TYRE_SIGN 18 +#define PRIM_OBJ_CANOPY1 19 +#define PRIM_OBJ_CANOPY2 20 +#define PRIM_OBJ_CANOPY3 21 +#define PRIM_OBJ_CANOPY4 22 +#define PRIM_OBJ_DINER_SIGN 23 +#define PRIM_OBJ_MOTEL_SIGN1 25 +#define PRIM_OBJ_MOTEL_SIGN2 26 +#define PRIM_OBJ_WILDCATVAN_BODY 27 +#define PRIM_OBJ_INTERIOR_STAIRS2 28 +#define PRIM_OBJ_INTERIOR_STAIRS3 29 + +// +// Im giving up typing in the right names now.... +// + +#define PRIM_OBJ_RADIATOR 30 +#define PRIM_OBJ_MOTORBIKE 31 +#define PRIM_OBJ_BIN 33 +#define PRIM_OBJ_ITEM_KEY 36 +#define PRIM_OBJ_LION2 46 +#define PRIM_OBJ_BIKE 47 +#define PRIM_OBJ_VAN 48 +#define PRIM_OBJ_BOAT 49 +#define PRIM_OBJ_CAR 50 +#define PRIM_OBJ_STROBE 51 +#define PRIM_OBJ_DOOR 52 +#define PRIM_OBJ_LAMP 54 +#define PRIM_OBJ_SIGN 60 +#define PRIM_OBJ_TRAFFIC_CONE 67 +#define PRIM_OBJ_CHOPPER 74 +#define PRIM_OBJ_CHOPPER_BLADES 75 +#define PRIM_OBJ_CAN 76 +#define PRIM_OBJ_CANOPY 81 +#define PRIM_OBJ_ITEM_TREASURE 84 +#define PRIM_OBJ_HOOK 86 +#define PRIM_OBJ_VAN_WHEEL 87 +#define PRIM_OBJ_VAN_BODY 88 +#define PRIM_OBJ_PARK_BENCH 89 +#define PRIM_OBJ_JEEP_BODY 90 +#define PRIM_OBJ_MEATWAGON_BODY 91 +#define PRIM_OBJ_ARMCHAIR 101 +#define PRIM_OBJ_COFFEE_TABLE 102 +#define PRIM_OBJ_SOFA 105 +#define PRIM_OBJ_CAR_BODY 108 +#define PRIM_OBJ_WOODEN_TABLE 110 +#define PRIM_OBJ_ITEM_AK47 120 +#define PRIM_OBJ_ITEM_MAGNUM 121 +#define PRIM_OBJ_CHAIR 126 +#define PRIM_OBJ_ITEM_SHOTGUN 127 +#define PRIM_OBJ_SEDAN_BODY 131 +#define PRIM_OBJ_BALLOON 132 +#define PRIM_OBJ_BIKE_STEER 137 // The steering column of the bike. +#define PRIM_OBJ_BIKE_BWHEEL 138 +#define PRIM_OBJ_BIKE_FWHEEL 139 +#define PRIM_OBJ_BIKE_FRAME 140 +#define PRIM_OBJ_BARREL 141 +#define PRIM_OBJ_ITEM_HEALTH 142 +#define PRIM_OBJ_ITEM_GUN 143 +#define PRIM_OBJ_ITEM_KEYCARD 144 +#define PRIM_OBJ_ITEM_BOMB 145 +#define PRIM_OBJ_POLICE_BODY 150 +#define PRIM_OBJ_TAXI_BODY 155 +#define PRIM_OBJ_AMBULANCE_BODY 159 +#define PRIM_OBJ_ITEM_KNIFE 166 +#define PRIM_OBJ_ITEM_EXPLOSIVES 167 +#define PRIM_OBJ_ITEM_GRENADE 168 +#define PRIM_OBJ_TRIPWIRE 178 +#define PRIM_OBJ_MINE 188 +#define PRIM_OBJ_SPIKE 189 +#define PRIM_OBJ_VALVE 196 +#define PRIM_OBJ_THERMODROID 201 +#define PRIM_OBJ_ITEM_BASEBALLBAT 205 +#define PRIM_OBJ_CAR_WHEEL 220 +#define PRIM_OBJ_POLICE_TARGET 147 +#define PRIM_OBJ_SWITCH_OFF 216 +#define PRIM_OBJ_SWITCH_ON 157 +#define PRIM_OBJ_HYDRANT 228 +#define PRIM_OBJ_ITEM_FILE 232 +#define PRIM_OBJ_ITEM_FLOPPY_DISK 233 +#define PRIM_OBJ_ITEM_CROWBAR 234 +#define PRIM_OBJ_ITEM_GASMASK 235 +#define PRIM_OBJ_ITEM_WRENCH 236 +#define PRIM_OBJ_ITEM_VIDEO 237 +#define PRIM_OBJ_ITEM_GLOVES 238 +#define PRIM_OBJ_ITEM_WEEDKILLER 239 +#define PRIM_OBJ_ITEM_AMMO_SHOTGUN 253 +#define PRIM_OBJ_ITEM_AMMO_AK47 254 +#define PRIM_OBJ_ITEM_AMMO_PISTOL 255 +#define PRIM_OBJ_NUMBER 256 +#define PRIM_OBJ_WEAPON_GUN 256 +#define PRIM_OBJ_WEAPON_KNIFE 257 +#define PRIM_OBJ_WEAPON_SHOTGUN 258 +#define PRIM_OBJ_WEAPON_BAT 259 +#define PRIM_OBJ_WEAPON_AK47 260 +#define PRIM_OBJ_WEAPON_GUN_FLASH 261 +#define PRIM_OBJ_WEAPON_SHOTGUN_FLASH 262 +#define PRIM_OBJ_WEAPON_AK47_FLASH 263 + + + +// +// The "Fun Stuff" day (14th Jan 1999) +// + + + +// +// Returns the collision model to use for each prim. +// + +#define PRIM_COLLIDE_BOX 0 // As a rotated bounding box +#define PRIM_COLLIDE_NONE 1 // Just walk through the prim +#define PRIM_COLLIDE_CYLINDER 2 // As a cylinder +#define PRIM_COLLIDE_SMALLBOX 3 // A bounding box smaller than the prim + +UBYTE prim_get_collision_model(SLONG prim); + +// +// The type of shadow to draw under the prim. +// + +#define PRIM_SHADOW_NONE 0 +#define PRIM_SHADOW_BOXEDGE 1 +#define PRIM_SHADOW_CYLINDER 2 +#define PRIM_SHADOW_FOURLEGS 3 +#define PRIM_SHADOW_FULLBOX 4 + +UBYTE prim_get_shadow_type(SLONG prim); + +// +// Prim flags. +// + +#define PRIM_FLAG_LAMPOST (1 << 0) +#define PRIM_FLAG_CONTAINS_WALKABLE_FACES (1 << 1) +#define PRIM_FLAG_GLARE (1 << 2) +#define PRIM_FLAG_ITEM (1 << 3) +#define PRIM_FLAG_TREE (1 << 4) +#define PRIM_FLAG_ENVMAPPED (1 << 5) +#define PRIM_FLAG_JUST_FLOOR (1 << 6) +#define PRIM_FLAG_ON_FLOOR (1 << 7) + +#define PRIM_DAMAGE_DAMAGABLE (1 << 0) +#define PRIM_DAMAGE_EXPLODES (1 << 1) +#define PRIM_DAMAGE_CRUMPLE (1 << 2) +#define PRIM_DAMAGE_LEAN (1 << 3) +#define PRIM_DAMAGE_NOLOS (1 << 4) // You can't see through this prim (included in LOS calculation) + +#define SMAT_SHIFT0 (2) +#define SMAT_SHIFT1 (12) +#define SMAT_SHIFT2 (22) +#define SMAT_SHIFTD (22) +#define CMAT0_MASK (0x3ff00000) +#define CMAT1_MASK (0x000ffc00) +#define CMAT2_MASK (0x000003ff) + + +// STRUCTS +struct CMatrix33 +{ + SLONG M[3]; +}; + +struct Matrix33 +{ + SLONG M[3][3]; +}; + +struct Matrix31 +{ + SLONG M[3]; +}; + +struct SMatrix31 +{ + SWORD M[3]; +}; + +struct OldPrimPoint +{ + SLONG X,Y,Z; +}; + +struct PrimPoint +{ + SWORD X,Y,Z; +}; + + + +#define ROOF_SHIFT 3 +struct RoofFace4 +{ +// UWORD TexturePage; //could use the texture on the floor + SWORD Y; + SBYTE DY[3]; + UBYTE DrawFlags; + UBYTE RX; + UBYTE RZ; + SWORD Next; //link list of walkables off floor + +}; + +#ifdef PSX +#define WALKABLE TexturePage + +struct PrimFace4 +{ + SWORD TexturePage; + UBYTE AltPal; + UBYTE DrawFlags; + UWORD Points[4]; + UBYTE UV[4][2]; + SWORD ThingIndex; + UWORD FaceFlags; +}; + +struct PrimFace3 +{ + SWORD TexturePage; + UBYTE AltPal; + UBYTE DrawFlags; + UWORD Points[3]; + UBYTE UV[3][2]; + SWORD ThingIndex; + UWORD FaceFlags; +}; + +#else +#define WALKABLE Col2 +struct PrimFace3 +{ + UBYTE TexturePage; + UBYTE DrawFlags; + UWORD Points[3]; + UBYTE UV[3][2]; + SWORD Bright[3]; //make into byte + SWORD ThingIndex; + UWORD Col2; + UWORD FaceFlags; + UBYTE Type; // move after bright + SBYTE ID; // delete +}; + +struct PrimFace4 +{ + UBYTE TexturePage; + UBYTE DrawFlags; + UWORD Points[4]; + UBYTE UV[4][2]; + + union + { + SWORD Bright[4]; // Used for people. + + struct // We cant use a LIGHT_Col because of circluar #include problems :-( + { + UBYTE red; + UBYTE green; + UBYTE blue; + + } col; // Used for building faces... + }; + + + SWORD ThingIndex; + SWORD Col2; + UWORD FaceFlags; + UBYTE Type; // move after bright + SBYTE ID; +}; +#endif + +struct PrimFace4PSX +{ + SWORD TexturePage; + UBYTE AltPal; + UBYTE DrawFlags; + UWORD Points[4]; + UBYTE UV[4][2]; + SWORD ThingIndex; + UWORD FaceFlags; +}; + +struct PrimFace3PSX +{ + SWORD TexturePage; + UBYTE AltPal; + UBYTE DrawFlags; + UWORD Points[3]; + UBYTE UV[3][2]; + SWORD ThingIndex; + UWORD FaceFlags; +}; + + + + +struct PrimObject +{ + UWORD StartPoint; + UWORD EndPoint; + UWORD StartFace4; + UWORD EndFace4; + SWORD StartFace3; + SWORD EndFace3; + + UBYTE coltype; + UBYTE damage; // How this prim gets damaged + UBYTE shadowtype; + UBYTE flag; +}; + + +#if USE_TOMS_ENGINE_PLEASE_BOB + +// A flag that lives in the top bit of wTexturePage. +#define TEXTURE_PAGE_FLAG_JACKET (1<<15) +#define TEXTURE_PAGE_FLAG_OFFSET (1<<14) +#define TEXTURE_PAGE_FLAG_TINT (1<<13) +#define TEXTURE_PAGE_FLAG_NOT_TEXTURED (1<<12) +#define TEXTURE_PAGE_MASK (0x0fff) + +// A prim's material. +// Note that the indices are listed by first the low-quality ones, then the high-quality ones. +// Also, the material uses the number of vertices specified by wNumHiVertices, of which the +// first wNumVertices are used. There are no vertices used by the low-quality mesh that are +// not also used by the high-quality one. +struct PrimObjectMaterial +{ + UWORD wTexturePage; // The texture page, maybe with some flags in the top few bits. + UWORD wNumListIndices; // How many list indices there are. + UWORD wNumStripIndices; // How many interrupted strip indices there are. + UWORD wNumVertices; // Number of vertices used. + // For the low-quality models. + UWORD wNumLoListIndices; // How many list indices there are. + UWORD wNumLoStripIndices; // How many interrupted strip indices there are. + UWORD wNumLoVertices; // Number of vertices used. +}; + +// My version of an object - an addition to the one above. +// (can't change the size of PrimObject or the loader gets kersplat. + +// Object has no alpha polys in it - don't bother checking. +//#define D3DOBJECT_FLAG_NOALPHA (1<<0) + +struct TomsPrimObject +{ + UWORD wFlags; // D3DOBJECT_FLAG_*** flags. + UWORD wNumMaterials; // Number of materials. + UWORD wTotalSizeOfObj; // Number of vertices used by object. + UBYTE bLRUQueueNumber; // Position in the LRU queue. + UBYTE bPadding; + PrimObjectMaterial *pMaterials; // Pointer to the materials. Can MemFree this. + void *pD3DVertices; // Pointer to the D3DVERTEX list. DONT MEMFREE THIS + UWORD *pwListIndices; // Pointer to the indices in list form. Can MemFree this. + UWORD *pwStripIndices; // Pointer to the indices in interrupted strip form. DONT MEMFREE THIS + float fBoundingSphereRadius; // Guess! +}; +#endif + + + +struct PrimObjectOld +{ + CBYTE ObjectName[32]; + UWORD StartPoint; + UWORD EndPoint; + UWORD StartFace4; + UWORD EndFace4; + SWORD StartFace3; + SWORD EndFace3; + + UBYTE coltype; + UBYTE damage; // How this prim gets damaged + UBYTE shadowtype; + UBYTE flag; + + UWORD Dummy[4]; +}; + +struct PrimMultiObject +{ + UWORD StartObject; + UWORD EndObject; + SWORD Tween; + SWORD Frame; +}; + + +//data +extern CBYTE prim_names[2000][32]; +extern struct SVector global_res[]; //max points per object? +extern SLONG global_flags[]; +extern UWORD global_bright[]; + +extern UWORD background_prim; + +// FUNCTIONS + +//extern void draw_a_rot_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct PrimMultiAnim *anim_info); +extern void test_poly(void); + +extern SLONG load_all_prims(CBYTE *name); +extern SLONG save_all_prims(CBYTE *name); + +extern SLONG copy_prim_to_end(UWORD prim,UWORD direct,SWORD thing); +extern void delete_a_prim(UWORD prim); +extern void delete_last_prim(void); +extern void calc_normal(SWORD face,struct SVector *p_normal); +extern UWORD apply_ambient_light_to_object(UWORD object,SLONG lnx,SLONG lny,SLONG lnz,UWORD intense); + + +// +// Initialises all the prim data. +// + +void clear_prims(void); + +// +// Calculates the FACE_FLAG_SLIDE_EDGE flags in the walkable faces. +// + +void calc_slide_edges(void); + +// +// Calculates the normals for each prim. These aren't saved +// or loaded in. The length of each normal is 256. +// + +void calc_prim_normals(void); + +// +// Calculates the PRIM_Infos for all the prims and sets the +// PRIM_FLAG_ENVMAP_OR_TINTED flag for prims that contain environment +// mapped or tinted faces. +// + +void calc_prim_info(void); + + +// +// Puts all the array indices back to what they were at +// some point. +// + +void record_prim_status (void); +void revert_to_prim_status(void); + + + +// +// Returns the info for each prim. +// + +typedef struct +{ + SLONG minx; // The bounding rectangle of the prim. + SLONG miny; + SLONG minz; + + SLONG maxx; + SLONG maxy; + SLONG maxz; + + SLONG cogx; // The centre of gravity of the prim. + SLONG cogy; + SLONG cogz; + + SLONG radius; // The bounding sphere about the origin. + +} PrimInfo; + +PrimInfo *get_prim_info(SLONG prim); + + +// +// ... +// + +void compress_prims(void); + +// +// Returns the position of the given point of the prim. +// If the point is -1 then a random point is returned. +// + +void get_rotated_point_world_pos( + SLONG point, // -1 => A random point. + SLONG prim, + SLONG prim_x, + SLONG prim_y, + SLONG prim_z, + SLONG prim_yaw, + SLONG prim_pitch, + SLONG prim_roll, + SLONG *px, + SLONG *py, + SLONG *pz); + +// +// Collides the a movement vector with the bounding-box of the given prim. +// Returns TRUE if a collision occured. +// + +SLONG slide_along_prim( + SLONG prim, + SLONG prim_x, + SLONG prim_y, + SLONG prim_z, + SLONG prim_yaw, + SLONG x1, SLONG y1, SLONG z1, + SLONG *x2, SLONG *y2, SLONG *z2, + SLONG radius, + SLONG shrink, // Makes the bounding box of the prim much shorter and smaller. + SLONG dont_slide); // TRUE => Don't move if the vector collides with the prim. + +// +// Sets the animation used by the given anim_prim. Anims start +// from 1... anim 0 is not used. +// + +void set_anim_prim_anim(SLONG anim_prim_thing_index, SLONG anim); + + +// +// Returns the type of the given anim prim. +// + +#define ANIM_PRIM_TYPE_NORMAL 0 +#define ANIM_PRIM_TYPE_DOOR 1 +#define ANIM_PRIM_TYPE_SWITCH 2 + +SLONG get_anim_prim_type(SLONG anim_prim); + + +// +// Returns the THING_INDEX of the nearest anim prim to the given point of +// one of the given types within the maximum range. +// + +SLONG find_anim_prim( + SLONG x, + SLONG y, + SLONG z, + SLONG range, + ULONG type_bit_field); // i.e (1 << ANIM_PRIM_TYPE_DOOR) | (1 << ANIM_PRIM_TYPE_NORMAL) + +// +// Toggles the state of the given switch prim. +// + +void toggle_anim_prim_switch_state(SLONG anim_prim_thing_index); + +// +// Find the bounding box of each anim-prim. The positions and rotations +// are taken from the initial position of the first frame. +// + +void find_anim_prim_bboxes(void); + + +// +// Does nothing to the prim_points and prim_faces, but marks +// each of the prim_objects as not loaded. You won't be able +// to draw them, but next time you call load_prim_object() +// it will load in the prim. +// + +void mark_prim_objects_as_unloaded(void); + + +// +// Goes through all the prim faces and makes sure that none of them have +// their WMOVE flag set. +// + +void clear_all_wmove_flags(void); + + +// +// Returns TRUE if a face lies along this line. Coordinates are in world coordinates (8-bits per mapsquare) +// The line must lie completely within the fence. +// + +SLONG does_fence_lie_along_line(SLONG x1, SLONG z1, SLONG x2, SLONG z2); + + + +#endif + + + + + diff --git a/fallen/Editor/Headers/Primativ.hpp b/fallen/Editor/Headers/Primativ.hpp new file mode 100644 index 0000000..7de8656 --- /dev/null +++ b/fallen/Editor/Headers/Primativ.hpp @@ -0,0 +1,47 @@ +// Primativ.hpp +// Guy Simmons, 26th October 1996. + + +#ifndef _PRIMATIV_HPP_ +#define _PRIMATIV_HPP_ + + +class EdRect +{ + private: + + public: + SLONG Top, + Left, + Bottom, + Right, + Width, + Height; + MFPoint TopLeft, + BottomRight; + + void SetRect(SLONG left,SLONG top,SLONG width,SLONG height); + void MoveRect(SLONG left,SLONG top); + void NormalRect(void); + void OffsetRect(SLONG dx,SLONG dy); + void ShrinkRect(SLONG dx,SLONG dy); + void OutlineRect(ULONG colour); + void OutlineInvertedRect(void); + void HiliteRect(ULONG hilite,ULONG lolite); + void FillRect(ULONG colour); + void IndentRect(ULONG hilite,ULONG lolite); + + BOOL PointInRect(MFPoint *the_point); + BOOL IntersectRect(EdRect *the_rect); + + inline SLONG GetTop(void) { return Top; } + inline SLONG GetLeft(void) { return Left; } + inline SLONG GetBottom(void) { return Bottom; } + inline SLONG GetRight(void) { return Right; } + inline SLONG GetWidth(void) { return Width; } + inline SLONG GetHeight(void) { return Height; } + inline MFPoint GetTopLeft(void) { return TopLeft; } + inline MFPoint GetBottomRight(void) { return BottomRight; } +}; + +#endif diff --git a/fallen/Editor/Headers/SaveTab.h b/fallen/Editor/Headers/SaveTab.h new file mode 100644 index 0000000..5e9ad56 --- /dev/null +++ b/fallen/Editor/Headers/SaveTab.h @@ -0,0 +1,44 @@ +// SaveTab.h +// Guy Simmons, 26th January 1998. + +#ifndef SAVETAB_H +#define SAVETAB_H + +//--------------------------------------------------------------- + +class SaveTab : public ModeTab +{ + private: + BOOL SaveState; + ULONG LevelsMap[32]; + SLONG CurrentLevel, + HilitedLevel; + + public: + + SaveTab(); + ~SaveTab(); + + void DrawTabContent(void); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleTab(MFPoint *current_point); + void HandleControl(UWORD control_id); + + void DrawLevelBox(void); + UWORD LevelHilitePos(MFPoint *current_point); + void MapLevels(void); + + void LoadLevel(void); + void SaveLevel(void); + + inline void SetSaveState(BOOL state) { SaveState=state; } + inline BOOL GetSaveState(void) { return SaveState; } + + inline void SetMapBit(UBYTE bit) { LevelsMap[bit>>5] |= (1<<(bit&0x1f)); } + inline BOOL GetMapBit(UBYTE bit) { if(LevelsMap[bit>>5]&(1<<(bit&0x1f)))return TRUE;else return FALSE; } +}; + +//--------------------------------------------------------------- + + +#endif diff --git a/fallen/Editor/Headers/Stealth.h b/fallen/Editor/Headers/Stealth.h new file mode 100644 index 0000000..0bb1cee --- /dev/null +++ b/fallen/Editor/Headers/Stealth.h @@ -0,0 +1,40 @@ +// Stealth.h +// Guy Simmons, 21st February 1997. + +#ifndef _STEALTH_H_ +#define _STEALTH_H_ + +#define TEXTURE_WIDTH 256 +#define TEXTURE_HEIGHT 256 +#define TEXTURE_PAGE_SIZE (TEXTURE_WIDTH*TEXTURE_HEIGHT*2) + + +typedef struct +{ + UWORD *TexturePtr; + UBYTE *PalPtr; + +}GameTexture; + +#define NUM_GAME_TEXTURES 50 + +extern GameTexture game_textures[NUM_GAME_TEXTURES]; + +typedef struct +{ + +}EdTriangle; + +typedef struct +{ + +}EdQuad; + +typedef struct +{ + SLONG U[4], + V[4]; +}EdTexture; + + +#endif diff --git a/fallen/Editor/Headers/Structs.h b/fallen/Editor/Headers/Structs.h new file mode 100644 index 0000000..c39aaeb --- /dev/null +++ b/fallen/Editor/Headers/Structs.h @@ -0,0 +1,78 @@ +// Structs.h +// Guy Simmons, 27th March 1997. + + +#ifndef STRUCTS_H +#define STRUCTS_H + +#include "DarkCity.h" + + +//--------------------------------------------------------------- + +typedef struct +{ + SLONG X, + Y, + Z; +}Coord; + +//--------------------------------------------------------------- + +/* +typedef struct +{ + Matrix33 *TheMatrix; +}Object3D; + +typedef struct +{ + +}Object2D; + + +typedef struct +{ + UBYTE DrawType; + KeyFrameElement *AnimElements, + *NextAnimElements; + union + { + Object3D + Object + }DrawType; +}Draw; +*/ + +typedef struct +{ + ULONG DrawType; +}Draw; + +//--------------------------------------------------------------- + +typedef struct +{ + SBYTE Class, + State; + ULONG Flags; + SLONG Child, + Parent; + SLONG LinkChild, + LinkParent; + + Draw Draw; +}Thing; + +//--------------------------------------------------------------- + +typedef struct +{ + float Altitude; + void *MapWho; + +}MapElement; + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Headers/TexTab.hpp b/fallen/Editor/Headers/TexTab.hpp new file mode 100644 index 0000000..b247911 --- /dev/null +++ b/fallen/Editor/Headers/TexTab.hpp @@ -0,0 +1,58 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _TEXTAB_HPP_ +#define _TEXTAB_HPP_ + +#include "undo.hpp" +#include "ModeTab.hpp" +#include "Stealth.h" + + + +#define FLAGS_SHOW_TEXTURE (1<<0) +#define FLAGS_QUADS (1<<1) +#define FLAGS_FIXED (1<<2) + + +class TextureTab : public ModeTab +{ + private: + ULONG CurrentTexturePage, + TextureFlags; + + SLONG TextureWidth, + TextureHeight, + TextureX, + TextureY, + TextureZoom; + EditorModule *Parent; + EdRect ClickRect[4], + TextureRect; + EdTexture CurrentTexture; + + void do_undo_me_bloody_self_then(SLONG index); + public: + TextureTab(EditorModule *parent); + void DrawTabContent(void); + void DrawTexture(void); + void UpdateTexture(void); + void UpdateTextureInfo(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + UWORD ConvertFreeToFixedEle(struct TextureBits *t); + void ConvertFixedToFree(struct TextureBits *t); + + inline ULONG GetTexturePage(void) { return CurrentTexturePage; } + inline void SetTexturePage(ULONG page) { CurrentTexturePage=page; } + inline EdTexture *GetTexture(void) { return &CurrentTexture; } + inline ULONG GetTextureFlags(void) { return TextureFlags; } + inline void SetTextureFlags(ULONG flags) { TextureFlags=flags; } + Undo MyUndo; + BOOL ApplyTexture(struct EditFace *edit_face); +}; + + +#endif + diff --git a/fallen/Editor/Headers/Thing.h b/fallen/Editor/Headers/Thing.h new file mode 100644 index 0000000..3c20676 --- /dev/null +++ b/fallen/Editor/Headers/Thing.h @@ -0,0 +1,136 @@ +// Thing.h +// Guy Simmons, 15th October 1997. + +#ifndef ETHING_H +#define ETHING_H + +#include "anim.h" +#include "DarkCity.h" + + +//--------------------------------------------------------------- +// old style + +//defs +#define MAX_MAP_THINGS 2000 + + +#define MAP_THING_TYPE_PRIM 1 +#define MAP_THING_TYPE_MULTI_PRIM 2 +#define MAP_THING_TYPE_ROT_MULTI 3 +#define MAP_THING_TYPE_SPRITE 4 +#define MAP_THING_TYPE_AGENT 5 +#define MAP_THING_TYPE_LIGHT 6 +#define MAP_THING_TYPE_BUILDING 7 +#define MAP_THING_TYPE_ANIM_PRIM 8 + +// Game editor stuff. +#define MAP_THING_TYPE_ED_THING 8 + +#define TO_MTHING(m) &map_things[(m)] + +//structs +struct MapThing +{ + SLONG X; + SLONG Y; + SLONG Z; + UWORD MapChild; //mapwho 2 way linked list + UWORD MapParent; + UBYTE Type; + UBYTE SubType; // Type for lights... + ULONG Flags; + + union + { + struct + { + SWORD IndexOther; // Brightness for lights... + UWORD Width; + UWORD Height; + UWORD IndexOrig; // param for lights... + UWORD AngleX; // (R,G,B) for lights... + UWORD AngleY; + UWORD AngleZ; + UWORD IndexNext; + SWORD LinkSame; + SWORD OnFace; + SWORD State; + SWORD SubState; + SLONG BuildingList; + ULONG EditorFlags, + EditorData; + ULONG DummyArea[3]; + SLONG TweenStage; + //struct KeyFrameElement *AnimElements, + // *NextAnimElements; + KeyFrame *CurrentFrame; + KeyFrame *NextFrame; + }; + + struct + { + UWORD CommandRef; + SLONG Class, + Genus; + SLONG Data[6]; + }; + }; +}; + +struct MapThingPSX +{ + SLONG X; + SLONG Y; + SLONG Z; + UWORD MapChild; //mapwho 2 way linked list + UWORD MapParent; + UBYTE Type; + UBYTE SubType; // Type for lights... + ULONG Flags; + + SWORD IndexOther; // Brightness for lights... + UWORD Width; + UWORD Height; + UWORD IndexOrig; // param for lights... + UWORD AngleX; // (R,G,B) for lights... + UWORD AngleY; + UWORD AngleZ; + UWORD IndexNext; + SWORD LinkSame; + SWORD OnFace; + SWORD State; + SWORD SubState; + SLONG BuildingList; + ULONG EditorFlags, + EditorData; + ULONG DummyArea[3]; + SLONG TweenStage; + //struct KeyFrameElement *AnimElements, + // *NextAnimElements; + KeyFrame *CurrentFrame; + KeyFrame *NextFrame; + +}; + + +//data +extern struct MapThing map_things[MAX_MAP_THINGS]; + +//code +extern UWORD find_empty_map_thing(void); +extern void delete_thing_from_edit_map(SLONG x,SLONG y,UWORD thing); +extern void add_thing_to_edit_map(SLONG x,SLONG y,UWORD thing); +extern SLONG move_thing_on_cells(UWORD thing,SLONG x,SLONG y,SLONG z); +extern void delete_thing(SWORD index); +//--------------------------------------------------------------- +/* +void init_things(void); +THING_INDEX alloc_primary_thing(void); +void free_primary_thing(THING_INDEX thing); +THING_INDEX alloc_secondary_thing(void); +void free_secondary_thing(THING_INDEX thing); +*/ +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Headers/ThingTab.h b/fallen/Editor/Headers/ThingTab.h new file mode 100644 index 0000000..a35ca10 --- /dev/null +++ b/fallen/Editor/Headers/ThingTab.h @@ -0,0 +1,62 @@ +// ThingTab.h +// Guy Simmons, 15th January 1998. + +#ifndef THINGTAB_H +#define THINGTAB_H + + +#define THING_MODE_NONE 0 +#define THING_MODE_SELECT_THING 1 +#define THING_MODE_SELECT_SWITCH 2 + +//--------------------------------------------------------------- + +class ThingTab : public ModeTab +{ + private: + + BOOL Update; + UBYTE CurrentClass, + CurrentGenus; + UWORD CurrentThing, + TabMode; + SLONG TabData, + ThingFlags, + *DataPtr; + ControlSet CurrentSet; + EdRect CurrentSetRect; + + public: + + ThingTab(); + ~ThingTab(); + + void DrawTabContent(void); + void UpdateTab(UBYTE update_level); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleTab(MFPoint *current_point); + void HandleControl(UWORD control_id); + void HandleClassControl(UWORD control_id); + void HandleBuildingControl(UWORD control_id); + EditComList *SelectCommandList(void); + + void DrawClassSet(void); + void UpdateTabInfo(void); + void UpdateClassInfo(void); + void UpdateCheckBoxes(void); + + inline UBYTE GetCurrentClass(void) { return CurrentClass; } + inline UBYTE GetCurrentGenus(void) { return CurrentGenus; } + inline UBYTE GetThingFlags(void) { return ThingFlags; } + inline void SetCurrentClass(UBYTE clss) { CurrentClass=clss;UpdateTabInfo(); } + inline void SetCurrentGenus(UBYTE genus) { CurrentGenus=genus;UpdateClassInfo(); } + + inline UWORD GetTabMode(void) { return TabMode; } + inline void SetTabMode(UWORD mode) { TabMode=mode; } + inline void SetTabData(SLONG data) { TabData=data; } + inline void SetCurrentThing(UWORD thing) { CurrentThing=thing;UpdateClassInfo(); } +}; + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Headers/Window.hpp b/fallen/Editor/Headers/Window.hpp new file mode 100644 index 0000000..25f21cd --- /dev/null +++ b/fallen/Editor/Headers/Window.hpp @@ -0,0 +1,121 @@ +// Window.hpp +// Guy Simmons, 18th February 1997. + +#ifndef _WINDOW_HPP_ +#define _WINDOW_HPP_ + +#include "ModeTab.hpp" +#include "Primativ.hpp" +#include "Icon.hpp" + +#define ACTIVE (1<<0) + +#define HAS_TITLE (1<<0) +#define HAS_GROW (1<<1) +#define HAS_CLOSE (1<<2) +#define HAS_MAXIMIZE (1<<3) +#define HAS_MINIMIZE (1<<4) +#define HAS_VSCROLL (1<<5) +#define HAS_HSCROLL (1<<6) +#define HAS_CONTROLS (1<<7) + +#define HAS_ICONS (1<<8) + +#define OUTSIDE_WINDOW 0 +#define IN_WINDOW 1 +#define IN_TITLE 2 +#define IN_GROW 3 +#define IN_HSCROLL 4 +#define IN_VSCROLL 5 +#define IN_CONTENT 6 +#define IN_CONTROLS 7 +#define IN_ICONS 8 + + +class Window : public EdRect +{ + private: + UWORD ContentColour; + + UBYTE StateFlags, + Update, + *TopLeftPtr; + ULONG Flags; + CBYTE *Title; + UWORD ControlAreaHeight, + ControlAreaWidth; + EdRect ContentRect, + ControlRect, + GrowRect, + HScrollRect, + TitleRect, + IconRect, + VScrollRect; + ModeTab *CurrentTab, + *TabList; + + + void SetAreaSizes(void); + + protected: + ControlSet WindowControls; + + + public: + virtual inline ~Window() {} + + void SetupWindow(CBYTE *title,ULONG flags,SLONG x,SLONG y,SLONG width,SLONG height); + void SetContentDrawArea(void); + + inline UBYTE GetStateFlags(void) { return StateFlags; } + inline void SetStateFlags(UBYTE flags) { StateFlags=flags; } + + inline void SetContentColour(ULONG the_colour) { ContentColour=(UWORD)the_colour; } + inline EdRect *GetContentRect(void) { return &ContentRect; } + inline SLONG ContentLeft(void) { return ContentRect.GetLeft(); } + inline SLONG ContentTop(void) { return ContentRect.GetTop(); } + inline SLONG ContentRight(void) { return ContentRect.GetRight(); } + inline SLONG ContentBottom(void) { return ContentRect.GetBottom(); } + inline SLONG ContentWidth(void) { return ContentRect.GetWidth(); } + inline SLONG ContentHeight(void) { return ContentRect.GetHeight(); } + inline BOOL PointInContent(MFPoint *the_point) { return ContentRect.PointInRect(the_point); } + void FillContent(ULONG the_colour); + void ClearContent(void); + + inline SLONG ControlsLeft(void) { return ControlRect.GetLeft(); } + inline SLONG ControlsTop(void) { return ControlRect.GetTop(); } + inline SLONG ControlsWidth(void) { return ControlRect.GetWidth(); } + inline SLONG ControlsHeight(void) { return ControlRect.GetHeight(); } + inline BOOL PointInControls(MFPoint *the_point) { return ControlRect.PointInRect(the_point); } + inline void SetControlsWidth(UWORD width) { ControlAreaWidth=width;SetAreaSizes(); } + inline void SetControlsHeight(UWORD height) { ControlAreaHeight=height;SetAreaSizes(); } + + void ConstrainHeight(SLONG *new_height); + void MoveWindow(SLONG x,SLONG y); + void SizeWindow(SLONG dx,SLONG dy); + + inline MFPoint *GlobalToLocal(MFPoint *the_point) { the_point->X-=ContentRect.GetLeft();the_point->Y-=ContentRect.GetTop();return the_point; } + inline MFPoint *LocalToGlobal(MFPoint *the_point) { the_point->X+=ContentRect.GetLeft();the_point->Y+=ContentRect.GetTop();return the_point; } + + void DrawWindowFrame(void); + void DrawWindowContent(void); + void DrawWindow(void); + void DrawGrowBox(void); + + virtual void DrawContent(void); + virtual void DrawControls(void); + + ULONG WhereInWindow(MFPoint *the_point); + + void BringTabToFront(ModeTab *the_tab); + void BringTabIDToFront(UWORD id); + void ActivateNextTab(void); + void ActivateLastTab(void); + void AddTab(ModeTab *the_tab); + void HandleTab(MFPoint *current_point); + inline ModeTab *CurrentModeTab(void) { return CurrentTab; } + + WinBarIcon TopIcons; +}; + +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/building.hpp b/fallen/Editor/Headers/building.hpp new file mode 100644 index 0000000..a2a8e84 --- /dev/null +++ b/fallen/Editor/Headers/building.hpp @@ -0,0 +1,241 @@ +#ifndef BUILDING_H +#define BUILDING_H 1 + +//DEFINES +#define MAX_BUILDINGS (500) +#define MAX_STOREYS (MAX_BUILDINGS*5) +#define MAX_WALLS (MAX_STOREYS*6) +#define MAX_WINDOWS (MAX_WALLS*4) + + +#define MAX_BUILDING_FACETS 2000 +#define MAX_BUILDING_OBJECTS 200 + + +#define FACET_FLAG_NEAR_SORT (1<<0) +#define FACET_FLAG_ROOF (1<<1) +#define FACET_FLAG_CABLE (1<<2) + +#define FLAG_ROOF_FLAT (1<<1) +#define FLAG_ROOF_OVERLAP_SMALL (1<<2) +#define FLAG_ROOF_OVERLAP_MEDIUM (1<<3) +#define FLAG_ROOF_WALLED (1<<4) +#define FLAG_ROOF_RECESSED (1<<5) + + +#define FLAG_WALL_USED (1<<0) +#define FLAG_WALL_AUTO_WINDOWS (1<<1) +#define FLAG_WALL_FACET_LINKED (1<<2) +#define FLAG_WALL_FENCE_POST1 (1<<3) +#define FLAG_WALL_FENCE_POST2 (1<<4) +#define FLAG_WALL_ROOF_RIM (1<<5) +#define FLAG_WALL_ARCH_SIDE (1<<6) +#define FLAG_WALL_ARCH_TOP (1<<7) + +#define FLAG_STOREY_USED (1<<0) +#define FLAG_STOREY_NORMAL (1<<1) +#define FLAG_STOREY_LEDGE (1<<2) +#define FLAG_STOREY_ROOF (1<<3) + +#define FLAG_STOREY_FACET_LINKED (1<<4) +#define FLAG_STOREY_TILED_ROOF (1<<5) +#define FLAG_STOREY_ROOF_RIM (1<<6) + + +#define BROWN_BRICK1 1 +#define BROWN_BRICK2 2 +#define GREY_RIM1 3 +#define GREY_RIM2 4 +#define RED_WINDOW 5 +#define GREY_CORIGATED 6 +#define CRATES_SMALL_BROWN 7 +#define GREY_POSH 8 +#define HOTEL_SIGN1 9 +#define HOTEL_SIGN2 10 + +#define STOREY_TYPE_NORMAL (1) +#define STOREY_TYPE_ROOF (2) +#define STOREY_TYPE_WALL (3) +#define STOREY_TYPE_ROOF_QUAD (4) +#define STOREY_TYPE_FLOOR_POINTS (5) +#define STOREY_TYPE_FIRE_ESCAPE (6) +#define STOREY_TYPE_STAIRCASE (7) +#define STOREY_TYPE_DRAINPIPE (8) +#define STOREY_TYPE_CABLE (9) +#define STOREY_TYPE_FENCE (10) + +#define FACE_TYPE_FIRE_ESCAPE 1 + +// STRUCTS + +struct BuildingObject +{ + SWORD FacetHead; + SWORD StartFace4; + SWORD EndFace4; + SWORD StartFace3; + SWORD EndFace3; + SWORD StartPoint; + SWORD EndPoint; +}; + + +struct BuildingFacet +{ + SWORD StartFace4; + SWORD MidFace4; + SWORD EndFace4; + SWORD StartFace3; + SWORD EndFace3; + SWORD StartPoint; + SWORD MidPoint; + SWORD EndPoint; + SWORD NextFacet; + UWORD FacetFlags; +}; + + +struct TempBuilding +{ + UWORD FacetHead; + UWORD FacetCount; + +}; +//4 bytes + +struct TempFacet +{ + SLONG x1; + SLONG z1; + SLONG x2; + SLONG z2; + + SWORD Y; + UWORD PrevFacet; + + UWORD NextFacet; + UWORD RoofType; + + UWORD StoreyHead; + UWORD StoreyCount; + +}; +//28 bytes + +struct TempStorey +{ + UWORD StoreyFlags; + UBYTE WallStyle; + UBYTE WindowStyle; + SWORD Height; + SWORD Next; + SWORD Count; +}; +//10 bytes + +struct TXTY +{ + UBYTE Page,Tx,Ty,Flip; + +}; + +struct TextureInfo +{ + UBYTE Type; + UBYTE SubType; +}; + + +struct FWindow +{ + UWORD Dist; + UWORD Height; + UWORD WindowFlags; + UWORD WindowWidth; + UWORD WindowHeight; + SWORD Next; + UWORD Dummy[6]; +}; + +struct FWall +{ + SWORD DX,DZ; + UWORD WallFlags; + SWORD WindowHead; + UWORD TextureStyle; + UWORD WindowCount; + SWORD Next; + UWORD DY; + UWORD StoreyHead; + UWORD Dummy[6]; +}; + +struct FStorey +{ + SWORD DX,DY,DZ; + UBYTE StoreyType; + UBYTE StoreyFlags; + + UWORD Height; + SWORD WallHead; + + UWORD WallCount; + UWORD Roof; + + SWORD Next; + SWORD Prev; + SWORD Info1; + SWORD Info2; + UWORD BuildingHead; + + UWORD Dummy[1]; +}; + +struct FBuilding +{ + SLONG X,Y,Z; + UWORD BuildingFlags; + SWORD StoreyHead; + SWORD Angle; + UWORD StoreyCount; + CBYTE str[20]; + UWORD Dummy[6]; +}; + + + +//data + +extern UWORD next_building_object; +extern UWORD end_building_object; + +extern UWORD next_building_facet; +extern UWORD end_building_facet; + + + +extern struct BuildingObject building_objects[]; +extern struct BuildingFacet building_facets[]; + +extern struct FWindow window_list[MAX_WINDOWS]; +extern struct FWall wall_list[MAX_WALLS]; +extern struct FStorey storey_list[MAX_STOREYS]; +extern struct FBuilding building_list[MAX_BUILDINGS]; +extern struct TXTY textures_xy[200][8]; +extern UBYTE textures_flags[200][8]; +extern struct TextureInfo texture_info[]; + + +// functions + +extern SLONG place_building_at(UWORD prim,SLONG x,SLONG y,SLONG z); +extern void offset_buildings(SLONG x,SLONG y,SLONG z); +//extern void calc_buildings_world_box(UWORD prim,SLONG x,SLONG y,SLONG z,EdRect *rect); +//extern void calc_buildings_screen_box(UWORD prim,SLONG x,SLONG y,SLONG z,EdRect *rect); +extern void draw_a_building_at(UWORD building,SLONG x,SLONG y,SLONG z); +extern void create_city(void); +extern SLONG create_building_prim(UWORD building,SLONG *small_y); +extern SLONG next_connected_face(SLONG type,SLONG id,SLONG count); +extern SLONG is_storey_circular(SLONG storey); + +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/collide.hpp b/fallen/Editor/Headers/collide.hpp new file mode 100644 index 0000000..aa69f10 --- /dev/null +++ b/fallen/Editor/Headers/collide.hpp @@ -0,0 +1,43 @@ +#ifndef COLLISION_H +#define COLLISION_H 1 + +//#include "c:\fallen\headers\collide.h" +//DEFINES + +// STRUCTS + + +//data +//collision info + + +// FUNCTIONS + +extern void calc_collision_info(struct ColInfo *p_col); +//extern void calc_collision_info(SLONG left,SLONG right,SLONG top,SLONG bottom,SLONG depth,SLONG flag); + +extern void clear_all_col_info(void); + +extern void interface_thing(void); +extern void init_thing(void); +extern SLONG calc_height_at(SLONG x,SLONG z); +extern calc_things_height(struct MapThing *p_thing); + + +// +// Line intersection. Line segments that share a point count as +// intersecting. +// + +#define DONT_INTERSECT 0 +#define DO_INTERSECT 1 +#define COLLINEAR 2 + +SLONG lines_intersect( + SLONG x1, SLONG y1, SLONG x2, SLONG y2, + SLONG x3, SLONG y3, SLONG x4, SLONG y4, + SLONG *x, + SLONG *y); + + +#endif diff --git a/fallen/Editor/Headers/convert.h b/fallen/Editor/Headers/convert.h new file mode 100644 index 0000000..f3da2fe --- /dev/null +++ b/fallen/Editor/Headers/convert.h @@ -0,0 +1,7 @@ +// convert.h +// Mike Diskett, 3rd March 1997. + +#ifndef _CONVERT_H_ +#define _CONVERT_H_ + +#endif diff --git a/fallen/Editor/Headers/engine.h b/fallen/Editor/Headers/engine.h new file mode 100644 index 0000000..1a45b4b --- /dev/null +++ b/fallen/Editor/Headers/engine.h @@ -0,0 +1,400 @@ +#ifndef ED_ENGINE_H +#define ED_ENGINE_H 1 +#include "poly.h" + +//********************************************************* +// DEFINES +//********************************************************* +/* +//#define FLOAT_ENGINE 1 + +#ifdef FLOAT_ENGINE +typedef float FSLONG; +#else +typedef long FSLONG; +#endif +*/ +#define MAX_BLOCKS 15000 +#define MAX_BUCKETS 40960 +#define MAX_BUCKET_POOL 3000000 /* In BytES */ +#define MAX_BUCKET_POINTS MAX_BUCKET_POOL + +#define BT_QUAD 1 +#define BT_TRI 2 +#define BT_VECT 3 +#define BT_RECT 4 +#define BT_DX_QUAD 5 +#define BT_DX_TRI 6 + +// Game Editor bits. +#define BT_MAP_THING 7 +#define BT_WAYPOINT 8 +#define BT_LINE 9 +#define BT_SPHERE_AREA 10 +#define BT_RECT_AREA 11 + +#define EF_OFF_LEFT (1<<0) +#define EF_OFF_RIGHT (1<<1) +#define EF_OFF_TOP (1<<2) +#define EF_OFF_BOTTOM (1<<3) +#define EF_FAR_OUT (1<<4) +#define EF_BEHIND_YOU (1<<5) +#define EF_TRANSLATED (1<<6) +#define EF_TOO_BIG (1<<7) + +#define EF_CLIPFLAGS (EF_OFF_LEFT+EF_OFF_RIGHT+EF_OFF_TOP+EF_OFF_BOTTOM) + + +#define ENGINE_CLIPZ_FLAG (1<<0) +#define ENGINE_CLIPX_FLAG (1<<1) +#define ENGINE_CLIPY_FLAG (1<<2) + +/****************************************************************************/ +/* STRUCTS - Just for the engine. */ +/****************************************************************************/ + + +struct EngineStuff +{ + SLONG CosY,SinY,CosX,SinX,CosZ,SinZ; + SLONG CosDY,SinDY; + SLONG X,Y,Z; + SLONG Scale; + SLONG VW; + SLONG VH; + SLONG VW2; + SLONG VH2; + SLONG AngleX; + SLONG AngleY; + SLONG AngleZ; + SLONG AngleDY; + ULONG ShowDebug; + ULONG ExtraInfo; + ULONG BucketSize; + SLONG MousePosX; + SLONG MousePosY; + SLONG MousePosZ; + SLONG DX; + SLONG DY; + SLONG DZ; + SLONG ClipZ; + SLONG ClipMaxY; + SLONG ClipMinY; + SLONG ClipMaxX; + SLONG ClipMinX; + SLONG ClipFlag; + SLONG TrueY; +}; + + + +//--------------------------------------------------------------- +// A funny fanny thing for the game editor. + +#define ED_ITEM_NONE 0 +#define ED_ITEM_THING 1 +#define ED_ITEM_MAP_BLOCK 2 +#define ED_ITEM_BUILDING 3 +#define ED_ITEM_WAYPOINT 4 +#define ED_ITEM_SIZE_HOOK 5 + +struct EdItem +{ + UBYTE ItemType; + SLONG ItemRef; +}; + +//--------------------------------------------------------------- + +struct BucketHead +{ + void *BucketPtr; +}; + +struct BucketGeneric +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; +}; + + +struct BucketQuad +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + UBYTE TextPage; + UBYTE Col; + struct MfEnginePoint P[4]; + SLONG DebugInfo; + SLONG DebugFlags; + EdItem EditRef; +}; + +struct BucketTri +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + UBYTE TextPage; + UBYTE Col; + struct MfEnginePoint P[3]; + SLONG DebugInfo; + SLONG DebugFlags; + EdItem EditRef; +}; + +struct BucketVect +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + struct MfEnginePoint P[2]; + UWORD Col; + SLONG DebugInfo; +}; + +struct BucketRect +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + struct MfEnginePoint P[1]; + SLONG Width; + SLONG Height; + UBYTE Col; +}; + +// Game Editor stuff. +struct BucketMapThing +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + SLONG BaseX,BaseY, + X,Y; + EdItem EditRef; +}; + +struct BucketWaypoint +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + SLONG BaseX,BaseY, + X,Y; + EdItem EditRef; +}; + +struct BucketLine +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + SLONG X1,Y1, + X2,Y2; +}; + +struct BucketSphereArea +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + SLONG X,Y,Radius; + BOOL ShowSizeHook; + EdItem EditRef; +}; + +struct BucketRectArea +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + SLONG X,Y,Z; + BOOL ShowSizeHook; + EdItem EditRef; +}; + +// Added Direct3D bucket types, Guy - 2/10/97 + +struct BucketDXQuad +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + MFDXEnginePoint P[4]; + UBYTE TexturePage; +}; +typedef BucketDXQuad BucketDXQuad; + +struct BucketDXTri +{ + void *BucketPtr; + UWORD DrawFlags; + UBYTE BucketType; + MFDXEnginePoint P[3]; + UBYTE TexturePage; +}; +typedef BucketDXTri BucketDXTri; + + +//********************************************************* +// EXTERNS +//********************************************************* + +//DATA +extern SLONG poly_count; + +extern UBYTE bucket_pool[MAX_BUCKET_POOL]; +extern UWORD select_colour; +extern struct BucketHead bucket_heads[MAX_BUCKETS]; +extern UBYTE *current_bucket_pool; +extern UBYTE *end_bucket_pool; + +//FUNCTIONS +extern struct EngineStuff engine; + +extern void set_camera_to_base(void); +extern void set_camera_to_mid(void); +extern void set_camera(void); +extern void set_camera_plan(void); +extern void set_camera_front(void); +extern void set_camera_side(void); +extern void set_camera_angledy(SWORD angle); +extern void clear_camera_angledy(void); + +extern void init_camera(void); +extern void render_view(UBYTE highlight); +extern void init_engine(void); +extern void add_bucket(void *p_bucket,SLONG z); +extern ULONG (*rotate_point_gte)(struct SVector *v,struct SVector *r); +extern ULONG rotate_point_gte_perspective(struct SVector *v,struct SVector *r); +extern ULONG rotate_point_gte_normal(struct SVector *v,struct SVector *r); +extern void calc_world_pos_plan(SLONG x,SLONG y); +extern void calc_world_pos_front(SLONG x,SLONG y); + +extern void animate_texture_maps(void); + + +//********************************************************* +// MACROS +//********************************************************* + +#define setZ4(p,z1,z2,z3,z4) (p)->P[0].Z3d =(SWORD)(z1);(p)->P[1].Z3d =(SWORD)(z2);(p)->P[2].Z3d =(SWORD)(z3);(p)->P[3].Z3d =(SWORD)(z4) +#define setXY4(p,x1,y1,x2,y2,x3,y3,x4,y4) (p)->P[0].X =(SWORD)(x1);(p)->P[1].X =(SWORD)(x2);(p)->P[2].X =(SWORD)(x3);(p)->P[3].X =(SWORD)(x4);(p)->P[0].Y =(SWORD)(y1);(p)->P[1].Y =(SWORD)(y2);(p)->P[2].Y =(SWORD)(y3);(p)->P[3].Y =(SWORD)(y4) +#define setUV4NA(p,x1,y1,x2,y2,x3,y3,x4,y4,page) \ + (p)->P[0].TX =(SWORD)(x1);\ + (p)->P[1].TX =(SWORD)(x2);\ + (p)->P[2].TX =(SWORD)(x3);\ + (p)->P[3].TX =(SWORD)(x4);\ + (p)->P[0].TY=(SWORD)(y1);\ + (p)->P[1].TY=(SWORD)(y2);\ + (p)->P[2].TY=(SWORD)(y3);\ + (p)->P[3].TY=(SWORD)(y4);\ + (p)->TextPage=(SWORD)(page); + +#define setUV4(p,x1,y1,x2,y2,x3,y3,x4,y4,page) if(page>=0)\ + {\ + (p)->P[0].TX =(SWORD)(x1);\ + (p)->P[1].TX =(SWORD)(x2);\ + (p)->P[2].TX =(SWORD)(x3);\ + (p)->P[3].TX =(SWORD)(x4);\ + (p)->P[0].TY=(SWORD)(y1);\ + (p)->P[1].TY=(SWORD)(y2);\ + (p)->P[2].TY=(SWORD)(y3);\ + (p)->P[3].TY=(SWORD)(y4);\ + (p)->TextPage=(SWORD)(page);\ + }\ + else\ + {\ + SLONG temp_unique;\ + temp_unique=anim_tmaps[-(page)].Current;\ + (p)->P[0].TX =anim_tmaps[-(page)].UV[temp_unique][0][0];\ + (p)->P[1].TX =anim_tmaps[-(page)].UV[temp_unique][1][0];\ + (p)->P[2].TX =anim_tmaps[-(page)].UV[temp_unique][2][0];\ + (p)->P[3].TX =anim_tmaps[-(page)].UV[temp_unique][3][0];\ + (p)->P[0].TY =anim_tmaps[-(page)].UV[temp_unique][0][1];\ + (p)->P[1].TY =anim_tmaps[-(page)].UV[temp_unique][1][1];\ + (p)->P[2].TY =anim_tmaps[-(page)].UV[temp_unique][2][1];\ + (p)->P[3].TY =anim_tmaps[-(page)].UV[temp_unique][3][1];\ + (p)->TextPage =anim_tmaps[-(page)].Page[temp_unique];\ + }\ + +#define setShade4(p,s1,s2,s3,s4) (p)->P[0].Shade=(SWORD)(s1);(p)->P[1].Shade=(SWORD)(s2);(p)->P[2].Shade=(SWORD)(s3);(p)->P[3].Shade=(SWORD)(s4) + +#define setZ3(p,z1,z2,z3) (p)->P[0].Z3d =(SWORD)(z1);(p)->P[1].Z3d =(SWORD)(z2);(p)->P[2].Z3d =(SWORD)(z3) +#define setXY3(p,x1,y1,x2,y2,x3,y3) (p)->P[0].X =(SWORD)(x1);(p)->P[1].X =(SWORD)(x2);(p)->P[2].X =(SWORD)(x3);(p)->P[0].Y =(SWORD)(y1);(p)->P[1].Y =(SWORD)(y2);(p)->P[2].Y =(SWORD)(y3) +#define setUV3(p,x1,y1,x2,y2,x3,y3,page) (p)->P[0].TX =(SWORD)(x1);(p)->P[1].TX =(SWORD)(x2);(p)->P[2].TX =(SWORD)(x3);(p)->P[0].TY=(SWORD)(y1);(p)->P[1].TY=(SWORD)(y2);(p)->P[2].TY=(SWORD)(y3);(p)->TextPage=(SWORD)(page) +#define setShade3(p,s1,s2,s3) (p)->P[0].Shade=(SWORD)(s1);(p)->P[1].Shade=(SWORD)(s2);(p)->P[2].Shade=(SWORD)(s3) + +#define setXY2(p,x1,y1,x2,y2) (p)->P[0].X =(SWORD)(x1);(p)->P[1].X =(SWORD)(x2);(p)->P[0].Y =(SWORD)(y1);(p)->P[1].Y =(SWORD)(y2) +#define setUV2(p,x1,y1,x2,y2) (p)->P[0].TX =(SWORD)(x1);(p)->P[1].TX =(SWORD)(x2);(p)->P[0].TY=(SWORD)(y1);(p)->P[1].TY=(SWORD)(y2) +#define setShade2(p,s1,s2) (p)->P[0].Shade=(SWORD)(s1);(p)->P[1].Shade=(SWORD)(s2) + +#define setXY1(p,x1,y1) (p)->P[0].X =(SWORD)(x1);(p)->P[0].Y =(SWORD)(y1) + +#define setCol4(p,col) (p)->Col=(SWORD)(col) +#define setCol3(p,col) (p)->Col=(SWORD)(col) +#define setCol2(p,col) (p)->Col=(SWORD)(col) + +#define setPoly50MGT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_MASKED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPoly50MGT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_MASKED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPoly50GT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPoly50GT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPoly50T4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_TEXTURED) +#define setPoly50T3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_TEXTURED) +#define setPoly50G4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_GOURAD) +#define setPoly50G3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_SEMI_TRANS|POLY_FLAG_GOURAD) +#define setPoly50F4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_SEMI_TRANS) +#define setPoly50F3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_SEMI_TRANS) + +#define setPolyAMT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_ALPHA|POLY_FLAG_MASKED|POLY_FLAG_TEXTURED) +#define setPolyAMT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_ALPHA|POLY_FLAG_MASKED|POLY_FLAG_TEXTURED) +#define setPolyAG4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_ALPHA|POLY_FLAG_GOURAD) +#define setPolyAG3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_ALPHA|POLY_FLAG_GOURAD) +#define setPolyAT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_ALPHA|POLY_FLAG_TEXTURED) +#define setPolyAT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_ALPHA|POLY_FLAG_TEXTURED) + +#define setPolyTGT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_TILED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPolyTGT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_TILED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) + + +#define setPolyMGT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_MASKED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPolyMGT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_MASKED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPolyGT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPolyGT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define setPolyMT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_MASKED|POLY_FLAG_TEXTURED) +#define setPolyMT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_MASKED|POLY_FLAG_TEXTURED) +#define setPolyT4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_TEXTURED) +#define setPolyT3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_TEXTURED) +#define setPolyG4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(POLY_FLAG_GOURAD) +#define setPolyG3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(POLY_FLAG_GOURAD) +#define setPolyF4(p) ((struct BucketQuad*)p)->BucketType=BT_QUAD;((struct BucketQuad*)p)->DrawFlags=(0) +#define setPolyF3(p) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(0) +#define setPolyGVect(p) ((struct BucketVect*)p)->BucketType=BT_VECT;((struct BucketVect*)p)->DrawFlags=0 + +#define setPolyType3(p,type) ((struct BucketTri*) p)->BucketType=BT_TRI ;((struct BucketTri*) p)->DrawFlags=(type) +#define setPolyType4(p,type) ((struct BucketQuad*) p)->BucketType=BT_QUAD ;((struct BucketQuad*) p)->DrawFlags=(type) + +#define setRect(p) ((struct BucketQuad*)p)->BucketType=BT_RECT;((struct BucketQuad*)p)->DrawFlags=0 + + +#define POLY_50MGT (POLY_FLAG_SEMI_TRANS|POLY_FLAG_MASKED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define POLY_50MT (POLY_FLAG_SEMI_TRANS|POLY_FLAG_MASKED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define POLY_MGT (POLY_FLAG_GOURAD|POLY_FLAG_MASKED|POLY_FLAG_TEXTURED) +#define POLY_MT (POLY_FLAG_MASKED|POLY_FLAG_TEXTURED) +#define POLY_NULL (POLY_FLAG_SEMI_TRANS|POLY_FLAG_MASKED) + +#define POLY_50F (POLY_FLAG_SEMI_TRANS) +#define POLY_50GT (POLY_FLAG_SEMI_TRANS|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define POLY_50T (POLY_FLAG_SEMI_TRANS|POLY_FLAG_TEXTURED) +#define POLY_50G (POLY_FLAG_SEMI_TRANS|POLY_FLAG_GOURAD) +#define POLY_TGT (POLY_FLAG_TILED|POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define POLY_GT (POLY_FLAG_GOURAD|POLY_FLAG_TEXTURED) +#define POLY_TT (POLY_FLAG_TILED|POLY_FLAG_TEXTURED) +#define POLY_T (POLY_FLAG_TEXTURED) +#define POLY_G (POLY_FLAG_GOURAD) +#define POLY_F (0) +#endif + diff --git a/fallen/Editor/Headers/extra.h b/fallen/Editor/Headers/extra.h new file mode 100644 index 0000000..98a71d1 --- /dev/null +++ b/fallen/Editor/Headers/extra.h @@ -0,0 +1,44 @@ +#ifndef _EXTRA_ +#define _EXTRA_ + +// +// Extra stuff like puddles and mist. +// + +#define EXTRA_TYPE_NONE 0 +#define EXTRA_TYPE_PUDDLE 1 +#define EXTRA_TYPE_MIST 2 + +typedef struct +{ + UBYTE type; + UBYTE height; + UBYTE detail; + UBYTE shit1; + UWORD x; + UWORD z; + UWORD angle; + UWORD radius; + SLONG shit2; + SLONG shit3; + +} EXTRA_Thing; + +#define EXTRA_MAX_THINGS 256 + +extern EXTRA_Thing EXTRA_thing[EXTRA_MAX_THINGS]; + + +// +// Creates something of the given type with the default +// settings at (x,z). If something of that type already +// exists there, then it is deleted. +// + +#define EXTRA_SELECT_DIST 256 // How close two things of the same type can be from eachother. + +void EXTRA_create_or_delete(SLONG type, SLONG x, SLONG z); + + + +#endif diff --git a/fallen/Editor/Headers/game.h b/fallen/Editor/Headers/game.h new file mode 100644 index 0000000..fe30185 --- /dev/null +++ b/fallen/Editor/Headers/game.h @@ -0,0 +1,10 @@ +#ifndef GAME_H +#define GAME_H 1 +#include "macros.h" +#include "c:\fallen\headers\inline.h" +// turn off "integral value may be truncated" C++ warnings +#ifndef _MSC_VER +#pragma warning 389 9 +#pragma warning 14 9 +#endif +#endif diff --git a/fallen/Editor/Headers/macros.h b/fallen/Editor/Headers/macros.h new file mode 100644 index 0000000..d6709bb --- /dev/null +++ b/fallen/Editor/Headers/macros.h @@ -0,0 +1,50 @@ +#ifndef MACROS_H +#define MACROS_H 1 +#include "math.h" +//#define GetTickCount() 0 +#ifdef __MSC_VER +#define sqrl(x) (Root((SLONG)x)) +#else +#define sqrl(x) (SLONG)(sqrt((float)x)) +#endif + +#define COL_TO_RGB565(col) (((PALETTE[(col)*3]>>3)<<11)|((PALETTE[(col)*3+1]>>2)<<5)|(PALETTE[(col)*3+2]>>3)) +#define COL_TO_RGB888(col) ((PALETTE[(col)*3]<<16)|(PALETTE[(col)*3+1]<<8)|PALETTE[(col)*3+2]) + +#define RGB_TO_RGB565(r,g,b) (((r>>3)<<11)|((g>>2)<<5)|(b>>3)) +#define RGB_TO_565(r,g,b) (((r>>3)<<11)|((g>>2)<<5)|(b>>3)) +#define RGB_TO_RGB888(r,g,b) ((r<<16)|(g<<8)|(b)) + +#define CLIP_256(x) ((x)>=256?255:(x)) +#define CLIPV_0(x) if(x<0)x=0 + + + +#define TO_CELL(x,z) &game_map->Cells[((x)>>8)+(((z)>>8)*MAX_GAME_MAP_WIDTH)] +#define POLY_DATA_MAP(x,z) game_map->Cells[((x)>>8)+(((z)>>8)*MAX_GAME_MAP_WIDTH)].PolyIndex +#define THING_DATA_MAP(x,z) game_map->Cells[((x)>>8)+(((z)>>8)*MAX_GAME_MAP_WIDTH)].ThingIndex + +#define TO_MAP(x,z) &game_map->PolyIndex[((x)>>8)+(((z)>>8)*MAX_GAME_MAP_WIDTH)] +#define TO_BMAP(x,z) &game_map->PolyBackIndex[((x)>>10)+(((z)>>10)*BACK_MAP_WIDTH)] +#define ON_MAP(x,z) ( ((x)>0) && ((x)0) && ((z)PolyIndex[((x)>>8)+(((z)>>8)*MAX_GAME_MAP_WIDTH)] +#define DATA_BMAP(x,z) game_map->PolyBackIndex[((x)>>10)+(((z)>>10)*BACK_MAP_WIDTH)] +#define CLIP256(x) (x>255?255:x) +inline SLONG QLEN(SLONG x1,SLONG z1,SLONG x2,SLONG z2) +{ + SLONG temp_dx; + SLONG temp_dz; + temp_dx=abs(x2-x1); + temp_dz=abs(z2-z1); + return(QDIST2(temp_dx,temp_dz)); +} +inline SLONG TLEN(SLONG x1,SLONG z1,SLONG x2,SLONG z2) +{ + SLONG temp_dx; + SLONG temp_dz; + temp_dx=abs(x2-x1); + temp_dz=abs(z2-z1); + return(sqrl(SDIST2(temp_dx,temp_dz))); +} +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/map.h b/fallen/Editor/Headers/map.h new file mode 100644 index 0000000..b09d7e4 --- /dev/null +++ b/fallen/Editor/Headers/map.h @@ -0,0 +1,42 @@ +#ifndef EMAP_H +#define EMAP_H 1 + +#undef ELE_SIZE + +//defs +#define ELE_SHIFT (8) +#define ELE_SIZE (1<>1) +#define ELE_AND (0xffffff00) + +#define EDIT_MAP_WIDTH 128 +//1024 +#define EDIT_MAP_HEIGHT 1 +#define EDIT_MAP_DEPTH 128 +//4 + +//structs + + +struct DepthStrip +{ + UWORD MapThingIndex; +// UWORD Depth[EDIT_MAP_DEPTH]; + UWORD ColVectHead; +// UWORD Dummy1; + UWORD Texture; + SWORD Bright; + UBYTE Flags; + SBYTE Y; + SWORD Walkable; +}; + +//data +extern struct DepthStrip edit_map[EDIT_MAP_WIDTH][EDIT_MAP_DEPTH]; //2meg +extern SBYTE edit_map_roof_height[EDIT_MAP_WIDTH][EDIT_MAP_DEPTH]; +extern UWORD tex_map[EDIT_MAP_WIDTH][EDIT_MAP_DEPTH]; + + +//code + +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/outline.h b/fallen/Editor/Headers/outline.h new file mode 100644 index 0000000..a4ca9dc --- /dev/null +++ b/fallen/Editor/Headers/outline.h @@ -0,0 +1,57 @@ +// +// Functions for helping with the outline of shapes on grids. +// + +#ifndef _OUTLINE_ +#define _OUTLINE_ + + +typedef struct outline_outline OUTLINE_Outline; + + +// +// Creates a new outline. +// + +OUTLINE_Outline *OUTLINE_create(SLONG num_z_squares); + +// +// Adds the given line to the outline. Must be orthogonal. The shape +// can be concave or convex. It must link up completely before it is used +// by OUTLINE_overlap(). +// + +void OUTLINE_add_line( + OUTLINE_Outline *oo, + SLONG x1, SLONG z1, + SLONG x2, SLONG z2); + +// +// Frees up all the memory used in the given outline. +// + +void OUTLINE_free(OUTLINE_Outline *oo); + + +// +// Returns TRUE if the two outlines overlap. +// + +SLONG OUTLINE_overlap( + OUTLINE_Outline *oo1, + OUTLINE_Outline *oo2); + + +// +// Returns TRUE if the given line goes through an outline. +// + +SLONG OUTLINE_intersects( + OUTLINE_Outline *oo, + SLONG x1, SLONG z1, + SLONG x2, SLONG z2); + + + + +#endif diff --git a/fallen/Editor/Headers/perstex.h b/fallen/Editor/Headers/perstex.h new file mode 100644 index 0000000..1dc83aa --- /dev/null +++ b/fallen/Editor/Headers/perstex.h @@ -0,0 +1,35 @@ +// +// Handles the allocation of people textures on n:\ +// + +#ifndef _PERSTEX_ +#define _PERSTEX_ + + + +// ======================================================== + +// +// Returns the page number of the given texture file. The texture file should +// be found in n:\urbanchaos\textures\shared\PersTex. If the texture file has not yet +// been allocated a page number, it gives that file the next spare page number and +// puts a copy of the texture in n:\urbanchaos\textures\shared\people +// + +// +// Returned if it couldn't find the .tga in the n:\urbanchaos\textures\prims\MaxTex +// directory. +// + +#define PERSTEX_PAGENUMBER_QMARK 0 + +SLONG PERSTEX_get_number(CBYTE *fname); + +// ======================================================== + + + + + + +#endif diff --git a/fallen/Editor/Headers/prim_draw.h b/fallen/Editor/Headers/prim_draw.h new file mode 100644 index 0000000..20f8740 --- /dev/null +++ b/fallen/Editor/Headers/prim_draw.h @@ -0,0 +1,24 @@ +#ifndef PRIM_DRAW_H +#define PRIM_DRAW_H 1 + +//********** +//* DATA * +//********** + + + +//*************** +//* FUNCTIONS * +//*************** + +extern void draw_a_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z,UBYTE shade); +extern void draw_a_multi_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z); +extern void draw_a_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z,UBYTE shade); +extern void draw_a_rot_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct PrimMultiAnim *anim_info,struct Matrix33 *rot_mat); + +extern void init_matrix33(struct Matrix33 *mat); +extern void matrix_mult33(struct Matrix33* result,struct Matrix33* mat1,struct Matrix33* mat2); +extern void rotate_obj(SWORD xangle,SWORD yangle,SWORD zangle, Matrix33 *r3); + + +#endif diff --git a/fallen/Editor/Headers/prim_edit.h b/fallen/Editor/Headers/prim_edit.h new file mode 100644 index 0000000..684d3cb --- /dev/null +++ b/fallen/Editor/Headers/prim_edit.h @@ -0,0 +1,35 @@ +#ifndef PRIM_EDIT_H +#define PRIM_EDIT_H 1 + +extern void calc_prims_screen_box(UWORD prim,SLONG x,SLONG y,SLONG z,EdRect *rect); +extern void calc_prims_world_box(UWORD prim,SLONG x,SLONG y,SLONG z,EdRect *rect); + + +extern void save_asc(UWORD building,UWORD version); +extern void import_tex(CBYTE *fname); +extern void export_tex(CBYTE *fname); + +extern SBYTE read_asc(CBYTE *fname,SLONG scale,ULONG offset); +extern SLONG read_multi_asc(CBYTE *asc_name,UBYTE flag,float scale=1.0); +extern SBYTE read_multi_dxf(void); +extern SBYTE read_multi_vue(SLONG m_object); +extern void load_textures_for_prim(CBYTE *str,UWORD prim); +extern void save_textures_for_prim(CBYTE *str,UWORD prim); +extern SWORD SelectFlag; +extern SWORD SelectDrawn; +extern void calc_prims_screen_box(UWORD prim,SLONG x,SLONG y,SLONG z,EdRect *rect); + +// +// Saves out the given prim object. Returns FALSE on failure. +// + +SLONG save_prim_object(SLONG prim); + +// +// Saves out all the loaded prims as individual objects. +// + +void save_all_individual_prims(void); + + +#endif diff --git a/fallen/Editor/Headers/primtex.h b/fallen/Editor/Headers/primtex.h new file mode 100644 index 0000000..4ac590a --- /dev/null +++ b/fallen/Editor/Headers/primtex.h @@ -0,0 +1,31 @@ +// +// Handles the allocation of prims and prim textures on n:\ +// + +#ifndef _PRIMTEX_ +#define _PRIMTEX_ + + +// ======================================================== + +// +// Returns the page number of the given texture file. The texture file should +// be found in n:\urbanchaos\textures\shared\MaxTex. If the texture file has not yet +// been allocated a page number, it gives that file the next spare page number and +// puts a copy of the texture in n:\urbanchaos\textures\shared\prims +// + +// +// Returned if it couldn't find the .tga in the n:\urbanchaos\textures\prims\MaxTex +// directory. +// + +#define PRIMTEX_PAGENUMBER_QMARK 0 + +SLONG PRIMTEX_get_number(CBYTE *fname); + +// ======================================================== + + + +#endif diff --git a/fallen/Editor/Headers/scan.h b/fallen/Editor/Headers/scan.h new file mode 100644 index 0000000..9772f02 --- /dev/null +++ b/fallen/Editor/Headers/scan.h @@ -0,0 +1,9 @@ +#ifndef SCAN_H +#define SCAN_H 1 + +extern void (*scan_function)(SLONG face,SLONG x,SLONG y,SLONG z,SLONG extra); +extern void scan_map(void); +extern void scan_map_thing(SLONG map_thing); +extern void scan_a_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z); + +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/scrflc.h b/fallen/Editor/Headers/scrflc.h new file mode 100644 index 0000000..c339560 --- /dev/null +++ b/fallen/Editor/Headers/scrflc.h @@ -0,0 +1,152 @@ +#ifndef _SCRFLC_H_ +#define _SCRFLC_H_ + +//**************************************|************************************ + +struct FLCFileHeader +{ + ULONG Size; + UWORD Magic; + UWORD NumberOfFrames; + UWORD Width; + UWORD Height; + UWORD Depth; + UWORD Flags; + ULONG Speed; + UWORD Reserved_0; + ULONG Created; + ULONG Creator; + ULONG Updated; + ULONG Updater; + UWORD AspectX; + UWORD AspectY; + UBYTE Reserved_1[38]; + ULONG OFrame1; + ULONG OFrame2; + UBYTE Reserved_2[40]; +}; + +//**************************************|************************************ + +struct FLCPrefixChunk +{ + ULONG Size; + UWORD Type; +}; + +//**************************************|************************************ + +struct FLCFrameChunk +{ + ULONG Size; + UWORD Type; + UWORD Chunks; + UBYTE Reserved_0[8]; +}; + +//**************************************|************************************ + +struct FLCFrameDataChunk +{ + ULONG Size; + UWORD Type; +}; + +//**************************************|************************************ + +struct FLCPostageStamp +{ + ULONG Size; + UWORD Type; + UWORD Height; + UWORD Width; + UWORD XLate; +}; + +//**************************************|************************************ + +union MultiPointer +{ + UBYTE *UByte; + UWORD *UWord; + ULONG *ULong; + SBYTE *SByte; + SWORD *SWord; + SLONG *SLong; + struct FLCFileHeader *FLCFileHeader; + struct FLCPrefixChunk *FLCPrefixChunk; + struct FLCFrameChunk *FLCFrameChunk; + struct FLCFrameDataChunk *FLCFrameDataChunk; + struct FLCPostageStamp *FLCPostageStamp; +}; + +//**************************************|************************************ + +struct Animation +{ + SLONG PlaybackMode; + UBYTE *LastFrame; + UBYTE *NextFrameBuffer; + union MultiPointer NextFrameBufferPointer; + MFFileHandle PlayFileHandle; + MFFileHandle RecordFileHandle; + SWORD Xpos; + SWORD Ypos; + UBYTE Palette[256 * 3]; + SLONG FrameNumber; + SLONG FrameSizeMaximum; + SLONG Active; + struct FLCFileHeader FLCFileHeader; + struct FLCPrefixChunk FLCPrefixChunk; + struct FLCFrameChunk FLCFrameChunk; + struct FLCFrameDataChunk FLCFrameDataChunk; + struct FLCPostageStamp FLCPostageStamp; +}; + +//**************************************|************************************ + +#define FLI_COLOUR256 4 +#define FLI_SS2 7 +#define FLI_COLOUR 11 +#define FLI_LC 12 +#define FLI_BLACK 13 +#define FLI_BRUN 15 +#define FLI_COPY 16 +#define FLI_PSTAMP 18 + +//**************************************|************************************ + +#define PLAYBACK_MODE_STOPPED 0 +#define PLAYBACK_MODE_RECORD (1 << 0) +#define PLAYBACK_MODE_PLAY (1 << 1) + +//**************************************|************************************ +extern SLONG anim_stop(void); +extern SLONG anim_record(); + +extern SLONG anim_open(SBYTE *file_name, SWORD xpos, SWORD ypos, SWORD width, SWORD height, SBYTE *postage_stamp, SLONG playback ); +extern SLONG anim_close(SLONG playback); +extern SLONG anim_make_next_frame(UBYTE *WScreen, UBYTE *palette ); +extern SLONG anim_make_FLI_PSTAMP(); +extern SLONG anim_make_FLI_COLOUR256(UBYTE *palette); +extern SLONG anim_make_FLI_COLOUR(UBYTE *palette); +extern SLONG anim_make_FLI_SS2(UBYTE *wscreen, UBYTE *last_screen); +extern SLONG anim_make_FLI_LC(UBYTE *wscreen, UBYTE *last_screen); +extern SLONG anim_make_FLI_BLACK(UBYTE *wscreen ); +extern SLONG anim_make_FLI_BRUN(UBYTE *wscreen ); +extern SLONG anim_make_FLI_COPY(UBYTE *wscreen ); +extern SLONG anim_write_data(UBYTE *data, SLONG size); +extern SLONG anim_store_data(UBYTE *data, SLONG size); +extern SLONG anim_show_next_frame(); +extern SLONG anim_show_FLI_PSTAMP(); +extern SLONG anim_show_FLI_COLOUR256(); +extern SLONG anim_show_FLI_COLOUR(); +extern SLONG anim_show_FLI_SS2(); +extern SLONG anim_show_FLI_LC(); +extern SLONG anim_show_FLI_BLACK(); +extern SLONG anim_show_FLI_BRUN(); +extern SLONG anim_show_FLI_COPY(); +extern SLONG anim_read_data(UBYTE *data, SLONG size); + +//**************************************|************************************ +#endif diff --git a/fallen/Editor/Headers/sewertab.hpp b/fallen/Editor/Headers/sewertab.hpp new file mode 100644 index 0000000..403a646 --- /dev/null +++ b/fallen/Editor/Headers/sewertab.hpp @@ -0,0 +1,144 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _SewerTab_HPP_ +#define _SewerTab_HPP_ + +#include "ModeTab.hpp" +#include "Stealth.h" +#include "EditMod.hpp" +#include "undo.hpp" + + +#define FLAG_WINDOW_USED (1<<0) +#define FLAG_WINDOW_LEDGE (1<<1) +#define FLAG_WINDOW_FAT_LEDGE (1<<2) +#define FLAG_WINDOW_WIDE_LEDGE (1<<3) +#define FLAG_WINDOW_SUNK_IN (1<<4) +#define FLAG_WINDOW_FLAT (1<<5) +#define FLAG_WINDOW_EDGED (1<<6) +#define FLAG_WINDOW_EDGED_DEEP (1<<7) +#define FLAG_WINDOW_EDGED_FAT (1<<8) + + +/* +#define FLAG_WINDOW_ (1<<) +*/ + +/* +#define FLAG_WALL_ (1<<) +*/ + +/* +#define FLAG_STOREY_ (1<<) +*/ + +#define FLAG_BUILDING_ +/* +#define FLAG_BUILDING_ +*/ + + + + +#define PASTE_TEXTURE (1<<0) +#define PASTE_ALTITUDE (1<<1) + + +extern SWORD get_new_storey(void); +extern void free_wall(SWORD wall); +extern SWORD get_new_building(void); +extern SWORD get_new_wall(void); + + + + + + + +class SewerTab : public ModeTab +{ + private: + SLONG Axis; + SLONG GridFlag; + UBYTE AxisMode; + EdRect View1; + EdRect View2; + EdRect View3; + UBYTE RedrawTabContent; + SLONG X1,Y1,Z1,X2,Y2,Z2; + SLONG FloorHead; + SLONG EditWindow; + SLONG EditY; + SLONG CurrentY; + SLONG ViewX,ViewY,ViewZ; + SLONG ViewSize; + SLONG RoomID; + + public: + SewerTab(EditorModule *parent); + ~SewerTab(); + void DrawTabContent(void); + void HandleTab(MFPoint *current_point); + UWORD HandleTabClick(UBYTE flags,MFPoint *clicked_point); + void HandleControl(UWORD control_id); + void DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h); + SLONG SetWorldMouse(ULONG flag); + SLONG KeyboardInterface(void); + SLONG DragEngine(UBYTE flags,MFPoint *clicked_point); + SLONG CalcMapCoord(SLONG *mapx,SLONG *mapy,SLONG *mapz,SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *clicked_point); + SLONG DragPaint(UBYTE flags); + SLONG DragMark(UBYTE flags); + SLONG DragVertex(UBYTE flags); + SLONG DragBuilding(UBYTE flags,UBYTE type); + SLONG DragStairs(UWORD stairs,UBYTE flags); + + SLONG MouseInContent(void); + SLONG DoKeys(void); + SLONG DoZoom(void); + void HighlightVertexes(SLONG x,SLONG y,SLONG w,SLONG h); + SLONG ClickInVertexStoreyList(SLONG building,SLONG storey_index,SLONG w,SLONG h,MFPoint *mouse_point); + SLONG ClickInVertex(SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *mouse_point); + SLONG ClickNearWall(SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *mouse_point); + SLONG WallOptions(void); + SLONG RoofOptions(void); + SLONG FenceOptions(void); + void DeleteVertex(void); + void AddHeightOffset(SLONG *x,SLONG *y); + SLONG GetHeightColour(SLONG storey); + void DrawContentLine(SLONG x1,SLONG y1,SLONG x2,SLONG y2,SLONG col); + void DrawContentLineY(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col); + + SLONG DrawWall(SLONG px,SLONG pz,SLONG x1,SLONG z1,SLONG index,SLONG storey); + SLONG DrawWindow(SLONG px,SLONG pz,SLONG x1,SLONG z1,SLONG dx,SLONG dz); + void DrawRoofFaces(SLONG roof,SLONG storey); + void DrawFloorFaces(SLONG wall); + void CheckStoreyIntegrity(UWORD storey); + void ResetSewerTab(void); + void DrawFloorTextures(SLONG x,SLONG y,SLONG w,SLONG h); + void DrawFloorLabels(SLONG x,SLONG y,SLONG w,SLONG h); + inline void SetViewToEngine(void) {ViewX=(engine.X>>8)&ELE_AND;ViewY=(engine.Y>>8)&ELE_AND;ViewZ=(engine.Z>>8)&ELE_AND;} + inline void SetEngineToView(void) {engine.X=ViewX<<8;engine.Y=ViewY<<8;engine.Z=ViewZ<<8;} + inline void SetView(SLONG x,SLONG z) {ViewX=x;ViewZ=z;} + void DrawContentRect(SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG col); + void DoStairPopUp(SLONG stair,MFPoint *clicked_point); +// Undo MyUndo; + UBYTE RedrawModuleContent; + void Clear(void); + UWORD Mode; + SLONG EditBuilding; + SLONG EditStorey; + SLONG EditWall; + SLONG OutsideEditStorey; + SLONG OutsideEditWall; + UWORD Texture; + UWORD RoofTop; + UWORD CurrentFloorType; + EditorModule *Parent; +}; + + + +#endif + diff --git a/fallen/Editor/Headers/spare.h b/fallen/Editor/Headers/spare.h new file mode 100644 index 0000000..3e3007a --- /dev/null +++ b/fallen/Editor/Headers/spare.h @@ -0,0 +1,26 @@ +#ifndef _H +#define _H 1 + +//************************************************** +//DEFINES +//************************************************** + + + +//************************************************** +// STRUCTS +//************************************************** + + + + +//************************************************** +// FUNCTIONS +//************************************************** + + + + + + +#endif \ No newline at end of file diff --git a/fallen/Editor/Headers/undo.hpp b/fallen/Editor/Headers/undo.hpp new file mode 100644 index 0000000..36d33fe --- /dev/null +++ b/fallen/Editor/Headers/undo.hpp @@ -0,0 +1,90 @@ +// TexTab.hpp +// Guy Simmons, 20th February 1997 + +#ifndef _UNDO_HPP_ +#define _UNDO_HPP_ + +#include "Prim.h" +#define MAX_UNDO 100 + + +#define UNDO_APPLY_TEXTURE_PRIM4 1 +#define UNDO_APPLY_TEXTURE_PRIM3 2 +#define UNDO_APPLY_TEXTURE_CUBE 3 +#define UNDO_PLACE_OBJECT 4 +#define UNDO_DEL_OBJECT 5 +#define UNDO_MOVE_OBJECT 6 +#define UNDO_PLACE_CUBE 7 +#define UNDO_MOVE_TEXTURE 8 +#define UNDO_APPLY_PRIM4 9 +#define UNDO_APPLY_PRIM3 10 + + +struct GenericUndo +{ + UBYTE Type; + union + { + struct + { + UBYTE DrawFlags; + UBYTE Colour; + UWORD Face; + UWORD Page; + UBYTE U[4]; + UBYTE V[4]; + }Texture; + struct + { + UWORD Thing; + UWORD Prim; + SLONG X; + SLONG Y; + SLONG Z; + }Object; + struct + { + UWORD PCube; + UWORD CCube; + SLONG X; + SLONG Y; + SLONG Z; + }Cube; + struct + { + UWORD Ele; + UWORD Face; + UWORD Text1; + UWORD Text2; + }Ele; + }; +}; + + +class Undo +{ + private: + void advance_current_undo(UBYTE undo_mode); + void retreat_current_undo(UBYTE undo_mode); + SWORD index; + SWORD index_undo; + public: + Undo(void); + void ApplyPrim4(UBYTE undo_mode,UWORD face,PrimFace4 *the_prim4); + void ApplyPrim3(UBYTE undo_mode,UWORD face,PrimFace3 *the_prim3); + void ApplyTexturePrim4(UBYTE undo_mode,UWORD page,UWORD face,UBYTE u1,UBYTE v1,UBYTE u2,UBYTE v2,UBYTE u3,UBYTE v3,UBYTE u4,UBYTE v4); + void ApplyTexturePrim3(UBYTE undo_mode,UWORD page,UWORD face,UBYTE u1,UBYTE v1,UBYTE u2,UBYTE v2,UBYTE u3,UBYTE v3); + void ApplyTextureCube(UBYTE undo_mode,UWORD ele,UWORD face,UWORD text1,UWORD text2); + void MoveTexture(UBYTE undo_mode,UWORD page,UWORD face,UBYTE u1,UBYTE v1,UBYTE u2,UBYTE v2,UBYTE u3,UBYTE v3,UBYTE u4,UBYTE v4); + void PlaceObject(UBYTE undo_mode,UWORD prim,UWORD thing,SLONG x,SLONG y,SLONG z); + void MoveObject(UBYTE undo_mode,UWORD thing,SLONG dx,SLONG dy,SLONG dz); + void DelObject(UBYTE undo_mode,UWORD prim,UWORD thing,SLONG x,SLONG y,SLONG z); + void PlaceCube(UBYTE undo_mode,UWORD prev_cube,UWORD cur_cube,SLONG x,SLONG y,SLONG z); + SLONG DoUndo(UBYTE undo_mode); + + GenericUndo undo_info[MAX_UNDO]; + GenericUndo undo_undo_info[MAX_UNDO]; +}; + +#endif + diff --git a/fallen/Editor/Library/Draw2d.cpp b/fallen/Editor/Library/Draw2d.cpp new file mode 100644 index 0000000..682692f --- /dev/null +++ b/fallen/Editor/Library/Draw2d.cpp @@ -0,0 +1,210 @@ +// Draw2D.c +// Guy Simmons, 7th October 1996. + +#include "Editor.hpp" + +//--------------------------------------------------------------- +// Function pointers for draw routines. + +void (*DrawBox)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +void (*DrawBoxC)(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); + +void (*DrawLine)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +void (*DrawLineC)(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +void (*DrawHLine)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +void (*DrawHLineC)(SLONG x1,SLONG x2,SLONG y,ULONG colour); +void (*DrawVLine)(SLONG x,SLONG y1,SLONG y2,ULONG colour); +void (*DrawVLineC)(SLONG x,SLONG y1,SLONG y2,ULONG colour); + +void (*DrawPoint)(MFPoint *the_point,ULONG colour); +void (*DrawPointC)(MFPoint *the_point,ULONG colour); + + +void (*DrawPixel)(SLONG x,SLONG y,ULONG colour); +void (*DrawPixelC)(SLONG x,SLONG y,ULONG colour); + +void (*QuickText)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +void (*QuickTextC)(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +void (*QuickChar)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +void (*QuickCharC)(SLONG x,SLONG y,CBYTE the_char,ULONG colour); + +void (*DrawBSprite)(SLONG x,SLONG y,BSprite *the_sprite); +void (*DrawBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite); + +void (*DrawMonoBSprite)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +void (*DrawMonoBSpriteC)(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + +//--------------------------------------------------------------- + +extern void DrawBox8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBoxC8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBox16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBoxC16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBox32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); +extern void DrawBoxC32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour); + +extern void DrawLine8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLineC8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLine16(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLineC16(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLine32(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); +extern void DrawLineC32(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour); + +extern void DrawHLine8(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLineC8(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLine16(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLineC16(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLine32(SLONG x1,SLONG x2,SLONG y,ULONG colour); +extern void DrawHLineC32(SLONG x1,SLONG x2,SLONG y,ULONG colour); + +extern void DrawVLine8(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLineC8(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLine16(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLineC16(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLine32(SLONG x,SLONG y1,SLONG y2,ULONG colour); +extern void DrawVLineC32(SLONG x,SLONG y1,SLONG y2,ULONG colour); + +extern void DrawPoint8(MFPoint *the_point,ULONG colour); +extern void DrawPointC8(MFPoint *the_point,ULONG colour); +extern void DrawPoint16(MFPoint *the_point,ULONG colour); +extern void DrawPointC16(MFPoint *the_point,ULONG colour); +extern void DrawPoint32(MFPoint *the_point,ULONG colour); +extern void DrawPointC32(MFPoint *the_point,ULONG colour); + +extern void DrawPixel8(SLONG x,SLONG y,ULONG colour); +extern void DrawPixelC8(SLONG x,SLONG y,ULONG colour); +extern void DrawPixel16(SLONG x,SLONG y,ULONG colour); +extern void DrawPixelC16(SLONG x,SLONG y,ULONG colour); +extern void DrawPixel32(SLONG x,SLONG y,ULONG colour); +extern void DrawPixelC32(SLONG x,SLONG y,ULONG colour); + +extern void QuickText8(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickTextC8(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickChar8(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void QuickCharC8_16_32(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void QuickText16(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickTextC16(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickChar16(SLONG x,SLONG y,CBYTE the_char,ULONG colour); +extern void QuickText32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickTextC32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour); +extern void QuickChar32(SLONG x,SLONG y,CBYTE the_char,ULONG colour); + +extern void DrawBSprite8(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSprite16(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSprite32(SLONG x,SLONG y,BSprite *the_sprite); + +extern void DrawBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite); +extern void DrawBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite); + +extern void DrawMonoBSprite8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSprite16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSprite32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + +extern void DrawMonoBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); +extern void DrawMonoBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour); + +//--------------------------------------------------------------- +// Set Function pointers for this display depth + +void SetDrawFunctions(ULONG depth) +{ + switch (depth) + { + case 8: + DrawBox=DrawBox8; + DrawBoxC=DrawBoxC8; + + DrawLine=DrawLine8; + DrawLineC=DrawLineC8; + DrawHLine=DrawHLine8; + DrawHLineC=DrawHLineC8; + DrawVLine=DrawVLine8; + DrawVLineC=DrawVLineC8; + + DrawPoint=DrawPoint8; + DrawPointC=DrawPointC8; + + DrawPixel=DrawPixel8; + DrawPixelC=DrawPixelC8; + + QuickText =QuickText8; + QuickTextC=QuickTextC8; + QuickChar =QuickChar8; + QuickCharC=QuickCharC8_16_32; + + DrawBSprite=DrawBSprite8; + DrawBSpriteC=DrawBSpriteC8; + + DrawMonoBSprite=DrawMonoBSprite8; + DrawMonoBSpriteC=DrawMonoBSpriteC8; + + WorkScreenDepth=1; + break; + case 15: + case 16: + DrawBox=DrawBox16; + DrawBoxC=DrawBoxC16; + + DrawLine=DrawLine16; + DrawLineC=DrawLineC8; + DrawHLine=DrawHLine16; + DrawHLineC=DrawHLineC16; + DrawVLine=DrawVLine16; + DrawVLineC=DrawVLineC16; + + DrawPoint=DrawPoint16; + DrawPointC=DrawPointC16; + + DrawPixel=DrawPixel16; + DrawPixelC=DrawPixelC16; + + QuickText =QuickText16; + QuickTextC=QuickTextC16; + QuickChar =QuickChar16; + QuickCharC=QuickCharC8_16_32; + + DrawBSprite=DrawBSprite16; + DrawBSpriteC=DrawBSpriteC16; + + DrawMonoBSprite=DrawMonoBSprite16; + DrawMonoBSpriteC=DrawMonoBSpriteC16; + + WorkScreenDepth=2; + break; + case 24: + case 32: + DrawBox=DrawBox32; + DrawBoxC=DrawBoxC32; + + DrawLine=DrawLine32; + DrawLineC=DrawLineC8; + DrawHLine=DrawHLine32; + DrawHLineC=DrawHLineC32; + DrawVLine=DrawVLine32; + DrawVLineC=DrawVLineC32; + + DrawPoint=DrawPoint32; + DrawPointC=DrawPointC32; + + DrawPixel=DrawPixel32; + DrawPixelC=DrawPixelC32; + + QuickText =QuickText32; + QuickTextC=QuickTextC32; + QuickChar =QuickChar32; + QuickCharC=QuickCharC8_16_32; + + DrawBSprite=DrawBSprite32; + DrawBSpriteC=DrawBSpriteC32; + + DrawMonoBSprite=DrawMonoBSprite32; + DrawMonoBSpriteC=DrawMonoBSpriteC32; + + WorkScreenDepth=4; + break; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/DrawBox.cpp b/fallen/Editor/Library/DrawBox.cpp new file mode 100644 index 0000000..d50c5f0 --- /dev/null +++ b/fallen/Editor/Library/DrawBox.cpp @@ -0,0 +1,329 @@ +// DrawBox.cpp +// Guy Simmons, 9th February 1997. + + +#include "Editor.hpp" + +#define COLOUR_TO_LONG(c) (0x01010101*c) +#define COLOURW_TO_LONG(c) (0x00010001*c) + + +//--------------------------------------------------------------- + +void DrawBox8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UBYTE *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + + ptr = WorkWindow+x+(y*WorkScreenWidth); //have to use window + temp_width = width; + if(width<=4) + { + // Thin rectangles. + for(;height>=0;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOUR_TO_LONG(colour); + + for(;height>=0;height--) + { + for(width=x&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + w2 = temp_width-(x&3); + ptr_big = (ULONG*)ptr; + for(width=w2>>2;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UBYTE*)ptr_big; + for(width=w2&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } +} + +void DrawBox16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UWORD *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + ptr = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); //have to use window + temp_width = width; + if(width<=2) + { + // Thin rectangles. + for(;height>=0;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOURW_TO_LONG(colour); + + for(;height>=0;height--) + { + for(width=x&1;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + w2 = temp_width-(x&1); + ptr_big = (ULONG*)ptr; + for(width=w2>>1;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UWORD*)ptr_big; + for(width=w2&1;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += (WorkScreenWidth>>1)-temp_width; + } + } +} + +void DrawBox32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + ULONG *ptr; + SLONG temp_width; + + + ptr = (ULONG*)WorkWindow+x+(y*WorkScreenWidth>>2); //have to use window + temp_width = width; + { + // Thin rectangles. + for(;height>=0;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = colour; + } + ptr += ((WorkScreenWidth>>2)-temp_width); + } + } +} + +//--------------------------------------------------------------- + +void DrawBoxC8(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UBYTE *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0) + { + width += x; + x = 0; + } + if(y<0) + { + height += y; + y = 0; + } + if((x+width)>=WorkWindowWidth) + { + width -= (x+width)-WorkWindowWidth; + } + if((y+height)>=WorkWindowHeight) + { + height -= (y+height)-WorkWindowHeight; + } + + if(width<=0 || height<=0) + return; + + ptr = WorkWindow+x+(y*WorkScreenWidth); //have to use window + temp_width = width; + if(width<=4) + { + // Thin rectangles. + for(;height;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOUR_TO_LONG(colour); + + for(;height;height--) + { + for(width=x&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + w2 = temp_width-(x&3); + ptr_big = (ULONG*)ptr; + for(width=w2>>2;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UBYTE*)ptr_big; + for(width=w2&3;width>0;width--) + { + *ptr++ = (UBYTE)colour; + } + ptr += WorkScreenWidth-temp_width; + } + } +} + +void DrawBoxC16(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + UWORD *ptr; + ULONG big_col, + *ptr_big, + w2; + SLONG temp_width; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0) + { + width += x; + x = 0; + } + if(y<0) + { + height += y; + y = 0; + } + if((x+width)>=WorkWindowWidth) + { + width -= (x+width)-WorkWindowWidth; + } + if((y+height)>=WorkWindowHeight) + { + height -= (y+height)-WorkWindowHeight; + } + + if(width<=0 || height<=0) + return; + + ptr = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); //have to use window + temp_width = width; + if(width<=2) + { + // Thin rectangles. + for(;height;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + ptr += (WorkScreenWidth>>1)-temp_width; + } + } + else + { + // Fat rectangles. + big_col = COLOURW_TO_LONG(colour); + + for(;height;height--) + { + for(width=x&1;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + w2 = temp_width-(x&1); + ptr_big = (ULONG*)ptr; + for(width=w2>>1;width>0;width--) + { + *ptr_big++ = big_col; + } + ptr = (UWORD*)ptr_big; + for(width=w2&1;width>0;width--) + { + *ptr++ = (UWORD)colour; + } + ptr += (WorkScreenWidth>>1)-temp_width; + } + } +} + +void DrawBoxC32(SLONG x,SLONG y,SLONG width,SLONG height,ULONG colour) +{ + ULONG *ptr; + SLONG temp_width; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0) + { + width += x; + x = 0; + } + if(y<0) + { + height += y; + y = 0; + } + if((x+width)>=WorkWindowWidth) + { + width -= (x+width)-WorkWindowWidth; + } + if((y+height)>=WorkWindowHeight) + { + height -= (y+height)-WorkWindowHeight; + } + + if(width<=0 || height<=0) + return; + + ptr = (ULONG*)WorkWindow+(x)+(y*WorkScreenWidth>>2); //have to use window + temp_width = width; + + for(;height;height--) + { + for(width=temp_width;width>0;width--) + { + *ptr++ = colour; + } + ptr += ((WorkScreenWidth>>2)-temp_width); + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/DrawCirc.cpp b/fallen/Editor/Library/DrawCirc.cpp new file mode 100644 index 0000000..4620322 --- /dev/null +++ b/fallen/Editor/Library/DrawCirc.cpp @@ -0,0 +1,58 @@ +// DrawCirc.cpp +// Guy Simmons, 9th February 1998. + + +#include "Editor.hpp" + + +#define DRAW_STEPS 32 + +//--------------------------------------------------------------- + +void DrawCircle(SLONG x,SLONG y,SLONG radius,ULONG colour) +{ + SLONG angle = 0, + angle_step = (2048/DRAW_STEPS), + c0, + x1,y1, + x2,y2; + + + for(c0=0;c0>16); + y1 = y+((COS(angle)*radius)>>16); + x2 = x+((SIN((angle+angle_step)&2047)*radius)>>16); + y2 = y+((COS((angle+angle_step)&2047)*radius)>>16); + + DrawLine(x1,y1,x2,y2,colour); + + angle += angle_step; + } +} + +//--------------------------------------------------------------- + +void DrawCircleC(SLONG x,SLONG y,SLONG radius,ULONG colour) +{ + SLONG angle = 0, + angle_step = (2048/DRAW_STEPS), + c0, + x1,y1, + x2,y2; + + + for(c0=0;c0>16); + y1 = y+((COS(angle)*radius)>>16); + x2 = x+((SIN((angle+angle_step)&2047)*radius)>>16); + y2 = y+((COS((angle+angle_step)&2047)*radius)>>16); + + DrawLineC(x1,y1,x2,y2,colour); + + angle += angle_step; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/DrawLine.cpp b/fallen/Editor/Library/DrawLine.cpp new file mode 100644 index 0000000..fd3ba3c --- /dev/null +++ b/fallen/Editor/Library/DrawLine.cpp @@ -0,0 +1,562 @@ +// DrawLine.c +// Guy Simmons, 7th October 1996 + + +#include "Editor.hpp" + + +//--------------------------------------------------------------- +// Standard Bresenham algorithm. + +void DrawLine8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + UBYTE *line_dest; + SLONG ax,ay, + d, + dx,dy, + modulo, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + modulo = WorkScreenWidth*sy; + + x = x1; + y = y1; + line_dest = WorkWindow+x+(y*WorkScreenWidth); + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + *line_dest = (UBYTE)colour; + if(x==x2) + return; + if(d>=0) + { + d -= ax; + line_dest += modulo; + } + x += sx; + d += ay; + line_dest += sx; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + *line_dest = (UBYTE)colour; + if(y==y2) + return; + if(d>=0) + { + d -= ay; + line_dest += sx; + } + y += sy; + d += ax; + line_dest += modulo; + } + } +} + +void DrawLine16(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + UWORD *line_dest; + SLONG ax,ay, + d, + dx,dy, + modulo, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + modulo = (WorkScreenWidth>>1)*sy; + + x = x1; + y = y1; + line_dest = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + *line_dest = (UWORD)colour; + if(x==x2) + return; + if(d>=0) + { + d -= ax; + line_dest += modulo; + } + x += sx; + d += ay; + line_dest += sx; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + *line_dest = (UWORD)colour; + if(y==y2) + return; + if(d>=0) + { + d -= ay; + line_dest += sx; + } + y += sy; + d += ax; + line_dest += modulo; + } + } +} + +void DrawLine32(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + ULONG *line_dest; + SLONG ax,ay, + d, + dx,dy, + modulo, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + modulo = (WorkScreenWidth>>2)*sy; + + x = x1; + y = y1; + line_dest = (ULONG*)WorkWindow+x+(y*WorkScreenWidth>>2); + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + *line_dest = (ULONG)colour; + if(x==x2) + return; + if(d>=0) + { + d -= ax; + line_dest += modulo; + } + x += sx; + d += ay; + line_dest += sx; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + *line_dest = (ULONG)colour; + if(y==y2) + return; + if(d>=0) + { + d -= ay; + line_dest += sx; + } + y += sy; + d += ax; + line_dest += modulo; + } + } +} + +//--------------------------------------------------------------- +// Standard Bresenham algorithm. +// Bloody slow at clipping tho' + +void DrawLineC8(SLONG x1,SLONG y1,SLONG x2,SLONG y2,ULONG colour) +{ + SLONG ax,ay, + d, + dx,dy, + sx,sy, + x,y; + + + dx = x2-x1; + dy = y2-y1; + + if(abs(dx)+abs(dy)>10000) + return; + + ax = abs(dx)<<1; + ay = abs(dy)<<1; + sx = sgn(dx); + sy = sgn(dy); + + x = x1; + y = y1; + if(ax>ay) + { + d = ay-(ax>>1); + while(1) + { + DrawPixelC(x,y,colour); + if(x==x2) + return; + if(d>=0) + { + y += sy; + d -= ax; + } + x += sx; + d += ay; + } + } + else + { + d = ax-(ay>>1); + while(1) + { + DrawPixelC(x,y,colour); + if(y==y2) + return; + if(d>=0) + { + x += sx; + d -= ay; + } + y += sy; + d += ax; + } + } +} + +//--------------------------------------------------------------- + +void DrawHLine8(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UBYTE *line_dest; + ULONG count; + + + if(x1>x2) + { + swap(x1,x2); + } + line_dest = WorkWindow+x1+(y*WorkScreenWidth); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UBYTE)colour; + } +} + +void DrawHLine16(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UWORD *line_dest; + ULONG count; + + + if(x1>x2) + { + swap(x1,x2); + } + line_dest = (UWORD*)WorkWindow+x1+(y*WorkScreenWidth>>1); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UWORD)colour; + } +} + +void DrawHLine32(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + ULONG *line_dest; + ULONG count; + + + if(x1>x2) + { + swap(x1,x2); + } + line_dest = (ULONG*)WorkWindow+x1+(y*WorkScreenWidth>>2); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (ULONG)colour; + } +} + +//--------------------------------------------------------------- + +void DrawHLineC8(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UBYTE *line_dest; + ULONG count; + + + if(y>=0 && yx2) + { + swap(x1,x2); + } + if(x1=0) + { + if(x1<0) + x1 = 0; + if(x2>=WorkWindowWidth) + x2 = WorkWindowWidth-1; + line_dest = WorkWindow+x1+(y*WorkScreenWidth); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UBYTE)colour; + } + } + } +} + +void DrawHLineC16(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + UWORD *line_dest; + ULONG count; + + + if(y>=0 && yx2) + { + swap(x1,x2); + } + if(x1=0) + { + if(x1<0) + x1 = 0; + if(x2>=WorkWindowWidth) + x2 = WorkWindowWidth-1; + line_dest = (UWORD*)WorkWindow+x1+(y*WorkScreenWidth>>1); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (UWORD)colour; + } + } + } +} + +void DrawHLineC32(SLONG x1,SLONG x2,SLONG y,ULONG colour) +{ + ULONG *line_dest; + ULONG count; + + + if(y>=0 && yx2) + { + swap(x1,x2); + } + if(x1=0) + { + if(x1<0) + x1 = 0; + if(x2>=WorkWindowWidth) + x2 = WorkWindowWidth-1; + line_dest = (ULONG*)WorkWindow+x1+(y*WorkScreenWidth>>2); + count = (x2-x1)+1; + while(count--) + { + *(line_dest++) = (ULONG)colour; + } + } + } +} + +//--------------------------------------------------------------- + +void DrawVLine8(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UBYTE *line_dest; + ULONG count, + modulo; + + + if(y1>y2) + { + swap(y1,y2); + } + line_dest = WorkWindow+x+(y1*WorkScreenWidth); + count = (y2-y1)+1; + modulo = WorkScreenWidth; + while(count--) + { + *line_dest = (UBYTE)colour; + line_dest += modulo; + } +} + +void DrawVLine16(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UWORD *line_dest; + ULONG count, + modulo; + + + if(y1>y2) + { + swap(y1,y2); + } + line_dest = (UWORD*)WorkWindow+x+(y1*WorkScreenWidth>>1); + count = (y2-y1)+1; + modulo = WorkScreenWidth>>1; + while(count--) + { + *line_dest = (UWORD)colour; + line_dest += modulo; + } +} + +void DrawVLine32(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + ULONG *line_dest; + ULONG count, + modulo; + + + if(y1>y2) + { + swap(y1,y2); + } + line_dest = (ULONG*)WorkWindow+x+(y1*WorkScreenWidth>>2); + count = (y2-y1)+1; + modulo = WorkScreenWidth>>2; + while(count--) + { + *line_dest = (ULONG)colour; + line_dest += modulo; + } +} + + +//--------------------------------------------------------------- + +void DrawVLineC8(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UBYTE *line_dest; + ULONG count; + + + if(x>=0 && xy2) + { + swap(y1,y2); + } + if(y1=0) + { + if(y1<0) + y1 = 0; + if(y2>=WorkWindowHeight) + y2 = WorkWindowHeight-1; + line_dest = WorkWindow+x+(y1*WorkScreenWidth); + count = (y2-y1)+1; + while(count--) + { + *line_dest = (UBYTE)colour; + line_dest += WorkScreenWidth; + } + } + } +} + +void DrawVLineC16(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + UWORD *line_dest; + ULONG count; + + + if(x>=0 && xy2) + { + swap(y1,y2); + } + if(y1=0) + { + if(y1<0) + y1 = 0; + if(y2>=WorkWindowHeight) + y2 = WorkWindowHeight-1; + line_dest = (UWORD*)WorkWindow+x+(y1*WorkScreenWidth>>1); + count = (y2-y1)+1; + while(count--) + { + *line_dest = (UWORD)colour; + line_dest += WorkScreenWidth>>1; + } + } + } +} + +void DrawVLineC32(SLONG x,SLONG y1,SLONG y2,ULONG colour) +{ + ULONG *line_dest; + ULONG count; + + + if(x>=0 && xy2) + { + swap(y1,y2); + } + if(y1=0) + { + if(y1<0) + y1 = 0; + if(y2>=WorkWindowHeight) + y2 = WorkWindowHeight-1; + line_dest = (ULONG*)WorkWindow+x+(y1*WorkScreenWidth>>2); + count = (y2-y1)+1; + while(count--) + { + *line_dest = (ULONG)colour; + line_dest += WorkScreenWidth>>2; + } + } + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/DrawPnt.cpp b/fallen/Editor/Library/DrawPnt.cpp new file mode 100644 index 0000000..08ffa05 --- /dev/null +++ b/fallen/Editor/Library/DrawPnt.cpp @@ -0,0 +1,75 @@ +// DrawPoint.c +// Guy Simmons, 7th October 1996. + + +#include "Editor.hpp" + + +//--------------------------------------------------------------- + +void DrawPoint8(MFPoint *the_point,ULONG colour) +{ + *(WorkWindow+the_point->X+(the_point->Y*WorkScreenWidth)) = (UBYTE)colour; +} + +void DrawPoint16(MFPoint *the_point,ULONG colour) +{ + UWORD *ptr; + ptr = (UWORD*)WorkWindow+the_point->X+(the_point->Y*WorkScreenWidth>>1); + *ptr = (UWORD)colour; + +} + +void DrawPoint32(MFPoint *the_point,ULONG colour) +{ + ULONG *ptr; + ptr = (ULONG*)WorkWindow+the_point->X+(the_point->Y*WorkScreenWidth>>2); + *ptr = (ULONG)colour; +} + +//--------------------------------------------------------------- + +void DrawPointC8(MFPoint *the_point,ULONG colour) +{ + if ( + the_point->X>=0 && + the_point->XY>=0 && + the_point->YX+(the_point->Y*WorkScreenWidth)) = (UBYTE)colour; + } +} + +void DrawPointC16(MFPoint *the_point,ULONG colour) +{ + UWORD *ptr; + if ( + the_point->X>=0 && + the_point->XY>=0 && + the_point->YX+(the_point->Y*WorkScreenWidth>>1); + *ptr = (UWORD)colour; + } +} + +void DrawPointC32(MFPoint *the_point,ULONG colour) +{ + ULONG *ptr; + if ( + the_point->X>=0 && + the_point->XY>=0 && + the_point->YX+(the_point->Y*WorkScreenWidth>>2); + *ptr = (ULONG)colour; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/DrawPxl.cpp b/fallen/Editor/Library/DrawPxl.cpp new file mode 100644 index 0000000..f42d9c2 --- /dev/null +++ b/fallen/Editor/Library/DrawPxl.cpp @@ -0,0 +1,59 @@ +// DrawPixel.c +// Guy Simmons, 7th October 1996. + + +#include "Editor.hpp" + + +//--------------------------------------------------------------- + +void DrawPixel8(SLONG x,SLONG y,ULONG colour) +{ + *(WorkWindow+x+(y*WorkScreenWidth)) = (UBYTE)colour; +} + +void DrawPixel16(SLONG x,SLONG y,ULONG colour) +{ + UWORD *ptr; + ptr = (UWORD*)WorkWindow+x+(y*WorkScreenWidth>>1); + *ptr = (UWORD)colour; +} + +void DrawPixel32(SLONG x,SLONG y,ULONG colour) +{ + ULONG *ptr; + ptr = (ULONG*)WorkWindow+x+(y*WorkScreenWidth>>2); + *ptr = (ULONG)colour; +} + +//--------------------------------------------------------------- + +void DrawPixelC8(SLONG x,SLONG y,ULONG colour) +{ + if(x>=0 && x=0 && y=0 && x=0 && y>1); + *ptr = (UWORD)colour; + } +} + +void DrawPixelC32(SLONG x,SLONG y,ULONG colour) +{ + if(x>=0 && x=0 && y>2); + *ptr = (ULONG)colour; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/DrawRect.cpp b/fallen/Editor/Library/DrawRect.cpp new file mode 100644 index 0000000..667835d --- /dev/null +++ b/fallen/Editor/Library/DrawRect.cpp @@ -0,0 +1,24 @@ +// DrawRect.cpp +// Guy Simmons, 11th February 1997. + + +#include "Editor.hpp" + + +//--------------------------------------------------------------- + +void DrawRect(MFRect *the_rect,ULONG colour) +{ + the_rect = the_rect; + colour = colour; +} + +//--------------------------------------------------------------- + +void DrawRectC(MFRect *the_rect,ULONG colour) +{ + the_rect = the_rect; + colour = colour; +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/QuickTxt.cpp b/fallen/Editor/Library/QuickTxt.cpp new file mode 100644 index 0000000..66f7eaa --- /dev/null +++ b/fallen/Editor/Library/QuickTxt.cpp @@ -0,0 +1,487 @@ +// QuickText.c +// Guy Simmons, 7th October 1996. + +#include "Editor.hpp" + +extern UBYTE *CharTable[]; + +#define DRAW_CHAR for(c0=char_height;c0;c0--,string_dest+=WorkScreenWidth) \ + { \ + for(c1=0;c1>1) \ + { \ + for(c1=0;c1>2) \ + { \ + for(c1=0;c1>1); + + DRAW_CHAR16 + x += char_width+1; + } +} + +void QuickText32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + UBYTE *the_char_def; + ULONG *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + if(the_string) + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = (ULONG*)WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth>>2); + + DRAW_CHAR32 + x += char_width+1; + } +} + +//--------------------------------------------------------------- + +void QuickTextC8(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + UBYTE *string_dest, + *the_char_def, + *the_pixel; + SLONG c0,c1, + char_draw_height, + char_draw_width, + char_height, + char_width, + char_v_offset, + char_x_offset, + char_y, + char_y_offset, + clip; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(the_string) + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + char_v_offset = *(the_char_def++); + char_draw_width = char_width; + char_draw_height= char_height; + char_x_offset = 0; + char_y_offset = 0; + char_y = y; + + clip = 0; + if(x<0) + { + if((x+char_width)<0) + goto done_char; + char_x_offset = -x; + char_draw_width += x; + x = 0; + clip = 1; + } + if(y<0) + { + if((y+char_v_offset+char_height)<0) + goto done_char; + if((y+char_v_offset)<0) + { + char_y_offset = -(y+char_v_offset); + char_draw_height+= y+char_v_offset; + char_v_offset = 0; + } + else + { + char_v_offset += y; + } + char_y = 0; + clip = 1; + } + if((x+char_draw_width)>=WorkWindowWidth) + { + char_draw_width -= (x+char_draw_width)-WorkWindowWidth; + clip = 1; + } + if((y+char_v_offset+char_draw_height)>=WorkWindowHeight) + { + char_draw_height-= (char_y+char_v_offset+char_draw_height)-WorkWindowHeight; + if(char_draw_height<=0) + goto done_char; + clip = 1; + } + + string_dest = WorkWindow+x+((char_y+char_v_offset)*WorkScreenWidth); + + if(clip) + { + for(c0=0;c0=WorkWindowWidth) + return; + } +} + +void QuickTextC16(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + UWORD *string_dest; + UBYTE *the_char_def, + *the_pixel; + SLONG c0,c1, + char_draw_height, + char_draw_width, + char_height, + char_width, + char_v_offset, + char_x_offset, + char_y, + char_y_offset, + clip; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(the_string) + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + char_v_offset = *(the_char_def++); + char_draw_width = char_width; + char_draw_height= char_height; + char_x_offset = 0; + char_y_offset = 0; + char_y = y; + + clip = 0; + if(x<0) + { + if((x+char_width)<0) + goto done_char; + char_x_offset = -x; + char_draw_width += x; + x = 0; + clip = 1; + } + if(y<0) + { + if((y+char_v_offset+char_height)<0) + goto done_char; + if((y+char_v_offset)<0) + { + char_y_offset = -(y+char_v_offset); + char_draw_height+= y+char_v_offset; + char_v_offset = 0; + } + else + { + char_v_offset += y; + } + char_y = 0; + clip = 1; + } + if((x+char_draw_width)>=WorkWindowWidth) + { + char_draw_width -= (x+char_draw_width)-WorkWindowWidth; + clip = 1; + } + if((y+char_v_offset+char_draw_height)>=WorkWindowHeight) + { + char_draw_height-= (char_y+char_v_offset+char_draw_height)-WorkWindowHeight; + if(char_draw_height<=0) + goto done_char; + clip = 1; + } + + string_dest = (UWORD*)WorkWindow+x+((char_y+char_v_offset)*WorkScreenWidth>>1); + + if(clip) + { + for(c0=0;c0=WorkWindowWidth) + return; + } +} + +void QuickTextC32(SLONG x,SLONG y,CBYTE *the_string,ULONG colour) +{ + ULONG *string_dest; + UBYTE *the_char_def, + *the_pixel; + SLONG c0,c1, + char_draw_height, + char_draw_width, + char_height, + char_width, + char_v_offset, + char_x_offset, + char_y, + char_y_offset, + clip; + + + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(the_string) + while(*the_string) + { + the_char_def = CharTable[*(the_string++)]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + char_v_offset = *(the_char_def++); + char_draw_width = char_width; + char_draw_height= char_height; + char_x_offset = 0; + char_y_offset = 0; + char_y = y; + + clip = 0; + if(x<0) + { + if((x+char_width)<0) + goto done_char; + char_x_offset = -x; + char_draw_width += x; + x = 0; + clip = 1; + } + if(y<0) + { + if((y+char_v_offset+char_height)<0) + goto done_char; + if((y+char_v_offset)<0) + { + char_y_offset = -(y+char_v_offset); + char_draw_height+= y+char_v_offset; + char_v_offset = 0; + } + else + { + char_v_offset += y; + } + char_y = 0; + clip = 1; + } + if((x+char_draw_width)>=WorkWindowWidth) + { + char_draw_width -= (x+char_draw_width)-WorkWindowWidth; + clip = 1; + } + if((y+char_v_offset+char_draw_height)>=WorkWindowHeight) + { + char_draw_height-= (char_y+char_v_offset+char_draw_height)-WorkWindowHeight; + if(char_draw_height<=0) + goto done_char; + clip = 1; + } + + string_dest = (ULONG*)WorkWindow+x+((char_y+char_v_offset)*WorkScreenWidth>>2); + + if(clip) + { + for(c0=0;c0=WorkWindowWidth) + return; + } +} + +//--------------------------------------------------------------- + +void QuickChar8(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + UBYTE *the_char_def, + *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + the_char_def = CharTable[the_char]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth); + DRAW_CHAR +} + +void QuickChar16(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + UBYTE *the_char_def; + UWORD *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + the_char_def = CharTable[the_char]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = (UWORD*)WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth>>1); + DRAW_CHAR16 +} + +void QuickChar32(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + UBYTE *the_char_def; + ULONG *string_dest; + ULONG char_height, + char_width; + ULONG c0,c1; + + + the_char_def = CharTable[the_char]; + char_width = *(the_char_def++); + char_height = *(the_char_def++); + string_dest = (ULONG*)WorkWindow+x+((y+*(the_char_def++))*WorkScreenWidth>>2); + DRAW_CHAR32 +} +//--------------------------------------------------------------- + +void QuickCharC8_16_32(SLONG x,SLONG y,CBYTE the_char,ULONG colour) +{ + if(x>=WorkWindowWidth || y>=WorkWindowHeight) + return; + + if(x<0 || y<0) + return; + + QuickChar(x,y,the_char,colour); +} + +//--------------------------------------------------------------- + +SLONG QTStringWidth(CBYTE *the_string) +{ + SLONG width = 0; + + if(the_string) + while(*the_string) + { + width += (*CharTable[*(the_string++)])+1; + } + return width; +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/Sprites.cpp b/fallen/Editor/Library/Sprites.cpp new file mode 100644 index 0000000..051e908 --- /dev/null +++ b/fallen/Editor/Library/Sprites.cpp @@ -0,0 +1,815 @@ +// Sprites.cpp +// Guy Simmons, 13th February 1997. + +#include "Editor.hpp" +extern UBYTE CurrentPalette[256*3]; +/* +#define RGB_TO_RGB565(r,g,b) (UWORD)(((r>>4)<<11)|((g>>3)<<5)|(b>>4)) +#define RGB_TO_RGB888(r,g,b) ((r<<16)|(g<<8)|(b)) +#define COL_TO_RGB565(col,PALETTE) (UWORD)(((PALETTE[(col)*3]>>3)<<11)|((PALETTE[(col)*3+1]>>2)<<5)|(PALETTE[(col)*3+2]>>3)) +#define COL_TO_RGB888(col,PALETTE) ((PALETTE[(col)*3]<<16)|(PALETTE[(col)*3+1]<<8)|PALETTE[(col)*3+2]) +*/ +#define RGB_TO_RGB565(r,g,b) ((UWORD)the_display.GetFormattedPixel(r,g,b)) +#define RGB_TO_RGB888(r,g,b) ((r<<16)|(g<<8)|(b)) +#define COL_TO_RGB565(col,PALETTE) ((UWORD)the_display.GetFormattedPixel(PALETTE[(col)*3],PALETTE[(col)*3+1],PALETTE[(col)*3+2])) +#define COL_TO_RGB888(col,PALETTE) ((PALETTE[(col)*3]<<16)|(PALETTE[(col)*3+1]<<8)|PALETTE[(col)*3+2]) + + +#define DRAW_SPRITE while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + while(c0--) \ + *line_ptr++ = *src_ptr++; \ + break; \ + case SKIP_PIXELS: \ + line_ptr += (*src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + dup_pixel = *src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define DRAW_SPRITE16(pal) while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + while(c0--) \ + { \ + *line_ptr++ =COL_TO_RGB565(*src_ptr,pal); \ + src_ptr++; \ + } \ + break; \ + case SKIP_PIXELS: \ + line_ptr += *(src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + dup_pixel =COL_TO_RGB565(*src_ptr,pal); \ + src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define DRAW_SPRITE32(pal) while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + while(c0--) \ + { \ + *line_ptr++ =COL_TO_RGB888(*src_ptr,pal); \ + src_ptr++; \ + } \ + break; \ + case SKIP_PIXELS: \ + line_ptr += *(src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + dup_pixel =COL_TO_RGB888(*src_ptr,pal); \ + src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define DRAW_M_SPRITE while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + src_ptr += c0; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case SKIP_PIXELS: \ + line_ptr += (*src_ptr++)+1; \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + src_ptr++; \ + while(c0--) \ + *line_ptr++ = dup_pixel; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + + +#define V_SCAN while(v_scan) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + v_scan--; \ + break; \ + case COPY_PIXELS: \ + src_ptr += 1+*(src_ptr++); \ + break; \ + case SKIP_PIXELS: \ + src_ptr++; \ + break; \ + case DUPLICATE_PIXELS: \ + src_ptr += 2; \ + break; \ + } \ + } + +#define L_SCAN while(l_scan&&sprite_height) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + dst_ptr += WorkScreenPixelWidth; \ + line_ptr = dst_ptr; \ + sprite_height--; \ + pixel_count = 0; \ + break; \ + case COPY_PIXELS: \ + c0 = (*src_ptr++)+1; \ + if((pixel_count+c0)>=l_scan) \ + { \ + src_ptr += l_scan-pixel_count; \ + c0 -= l_scan-pixel_count; \ + pixel_count = l_scan; \ + goto copy_pixels; \ + } \ + else \ + { \ + pixel_count += c0; \ + src_ptr += c0; \ + } \ + break; \ + case SKIP_PIXELS: \ + c0 = (*src_ptr++)+1; \ + if((pixel_count+c0)>=l_scan) \ + { \ + c0 -= l_scan-pixel_count; \ + pixel_count = l_scan; \ + goto skip_pixels; \ + } \ + else \ + { \ + pixel_count += c0; \ + } \ + break; \ + case DUPLICATE_PIXELS: \ + c0 = (*src_ptr++)+1; \ + if((pixel_count+c0)>=l_scan) \ + { \ + c0 -= l_scan-pixel_count; \ + pixel_count = l_scan; \ + goto duplicate_pixels; \ + } \ + else \ + { \ + pixel_count += c0; \ + src_ptr++; \ + } \ + break; \ + case FINISHED: \ + return; \ + } \ + } + +#define R_SCAN while(1) \ + { \ + packet = *src_ptr++; \ + switch(packet) \ + { \ + case END_LINE: \ + goto end_line; \ + case COPY_PIXELS: \ + src_ptr += 1+*(src_ptr++); \ + break; \ + case SKIP_PIXELS: \ + src_ptr++; \ + break; \ + case DUPLICATE_PIXELS: \ + src_ptr += 2; \ + break; \ + case FINISHED: \ + return; \ + } \ + } + + +//--------------------------------------------------------------- + + +void DrawBSpritePal16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + UWORD dup_pixel, + *dst_ptr, + *line_ptr; + + + dst_ptr = (UWORD*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + DRAW_SPRITE16(pal) +} + +void DrawBSpritePal32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + ULONG dup_pixel, + *dst_ptr, + *line_ptr; + + + dst_ptr = (ULONG*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + DRAW_SPRITE32(pal) +} + +void DrawBSprite8(SLONG x,SLONG y,BSprite *the_sprite) +{ + UBYTE dup_pixel, + packet, + *dst_ptr, + *line_ptr, + *src_ptr; + ULONG c0; + + + dst_ptr = WorkWindow+x+(y*WorkScreenWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + DRAW_SPRITE +} + +void DrawBSprite16(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePal16(x,y,the_sprite,CurrentPalette); +} + +void DrawBSprite32(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePal32(x,y,the_sprite,CurrentPalette); +} + +//--------------------------------------------------------------- + +void DrawMonoBSprite8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + UBYTE dup_pixel, + packet, + *dst_ptr, + *line_ptr, + *src_ptr; + ULONG c0; + + dst_ptr = WorkWindow+x+(y*WorkScreenWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + dup_pixel = (UBYTE)colour; + DRAW_M_SPRITE +} + +void DrawMonoBSprite16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + + UWORD dup_pixel, + *dst_ptr, + *line_ptr; + + dst_ptr = (UWORD*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + dup_pixel = (UWORD)colour; + DRAW_M_SPRITE +} + +void DrawMonoBSprite32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + UBYTE packet, + *src_ptr; + ULONG c0; + + ULONG dup_pixel, + *dst_ptr, + *line_ptr; + + dst_ptr = (ULONG*)WorkWindow+x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + src_ptr = the_sprite->SpriteData; + dup_pixel = (ULONG)colour; + DRAW_M_SPRITE +} + +void DrawMonoBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + if(x<0 || (x+the_sprite->SpriteWidth)>=WorkWindowWidth || y<0 || (y+the_sprite->SpriteHeight)>=WorkWindowHeight) + return; + + DrawMonoBSprite8(x,y,the_sprite,colour); +} + +void DrawMonoBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + if(x<0 || (x+the_sprite->SpriteWidth)>=WorkWindowWidth || y<0 || (y+the_sprite->SpriteHeight)>=WorkWindowHeight) + return; + + DrawMonoBSprite16(x,y,the_sprite,colour); +} + +void DrawMonoBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite,ULONG colour) +{ + if(x<0 || (x+the_sprite->SpriteWidth)>=WorkWindowWidth || y<0 || (y+the_sprite->SpriteHeight)>=WorkWindowHeight) + return; + + DrawMonoBSprite32(x,y,the_sprite,colour); +} + +//--------------------------------------------------------------- + +void DrawBSpriteC8(SLONG x,SLONG y,BSprite *the_sprite) +{ + UBYTE dup_pixel, + packet, + *dst_ptr, + *line_ptr, + *src_ptr; + ULONG c0, + clip, + count_diff, + pixel_count, + sprite_height; + ULONG l_scan, + v_scan; + SLONG sprite_x; + + + if(x>=WorkWindowWidth || (x+the_sprite->SpriteWidth)<0 || y>=WorkWindowHeight || (y+the_sprite->SpriteHeight)<0) + return; + + sprite_height = the_sprite->SpriteHeight; + sprite_x = x; + src_ptr = the_sprite->SpriteData; + clip = 0; + l_scan = 0; + + + if(x<0) + { + l_scan = -x; + sprite_x= 0; + clip = 1; + } + if(y<0) + { + v_scan = -y; + sprite_height += y; + V_SCAN + y = 0; + clip = 1; + } + if((SLONG)(x+the_sprite->SpriteWidth)>=WorkWindowWidth) + { + clip = 1; + } + if((SLONG)(y+sprite_height)>=WorkWindowHeight) + { + sprite_height -= (y+sprite_height)-WorkWindowHeight; + clip = 1; + } + + dst_ptr = WorkWindow+sprite_x+(y*WorkScreenWidth); + line_ptr = dst_ptr; + + if(clip) + { + pixel_count = 0; + L_SCAN + while(sprite_height) + { + packet = *src_ptr++; + switch(packet) + { + case END_LINE: +end_line: + dst_ptr += WorkScreenWidth; + line_ptr = dst_ptr; + sprite_height--; + pixel_count = 0; + L_SCAN + break; + case COPY_PIXELS: + c0 = (*src_ptr++)+1; +copy_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + count_diff = (x+pixel_count)-WorkWindowWidth; + c0 -= count_diff; + while(c0--) + *line_ptr++ = *src_ptr++; + src_ptr += count_diff; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = *src_ptr++; + } + break; + case SKIP_PIXELS: + c0 = (*src_ptr++)+1; +skip_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + R_SCAN + } + else + line_ptr += c0; + break; + case DUPLICATE_PIXELS: + c0 = (*src_ptr++)+1; +duplicate_pixels: + pixel_count += c0; + dup_pixel = *src_ptr++; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + c0 -= (x+pixel_count)-WorkWindowWidth; + while(c0--) + *line_ptr++ = dup_pixel; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = dup_pixel; + } + break; + case FINISHED: + return; + } + } + } + else + { + DRAW_SPRITE + } +} + +extern void DrawBSpritePalC16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); +extern void DrawBSpritePalC32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal); + +void DrawBSpriteC16(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePalC16(x,y,the_sprite,CurrentPalette); +} + +void DrawBSpriteC32(SLONG x,SLONG y,BSprite *the_sprite) +{ + DrawBSpritePalC32(x,y,the_sprite,CurrentPalette); +} + +void DrawBSpritePalC16(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0, + clip, + count_diff, + pixel_count, + sprite_height; + ULONG l_scan, + v_scan; + SLONG sprite_x; + + UWORD dup_pixel, + *dst_ptr, + *line_ptr; + + + if(x>=WorkWindowWidth || (x+the_sprite->SpriteWidth)<0 || y>=WorkWindowHeight || (y+the_sprite->SpriteHeight)<0) + return; + + sprite_height = the_sprite->SpriteHeight; + sprite_x = x; + src_ptr = the_sprite->SpriteData; + clip = 0; + l_scan = 0; + + + if(x<0) + { + l_scan = -x; + sprite_x= 0; + clip = 1; + } + if(y<0) + { + v_scan = -y; + sprite_height += y; + V_SCAN + y = 0; + clip = 1; + } + if((SLONG)(x+the_sprite->SpriteWidth)>=WorkWindowWidth) + { + clip = 1; + } + if((SLONG)(y+sprite_height)>=WorkWindowHeight) + { + sprite_height -= (y+sprite_height)-WorkWindowHeight; + clip = 1; + } + + dst_ptr = (UWORD*)WorkWindow+sprite_x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + + if(clip) + { + pixel_count = 0; + L_SCAN + while(sprite_height) + { + packet = *src_ptr++; + switch(packet) + { + case END_LINE: +end_line: + dst_ptr += WorkScreenPixelWidth; + line_ptr = dst_ptr; + sprite_height--; + pixel_count = 0; + L_SCAN + break; + case COPY_PIXELS: + c0 = (*src_ptr++)+1; +copy_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + count_diff = (x+pixel_count)-WorkWindowWidth; + c0 -= count_diff; + while(c0--) + { + *line_ptr++ =COL_TO_RGB565(*src_ptr,pal); + src_ptr++; + } + src_ptr += count_diff; + R_SCAN + } + else + { + while(c0--) + { + *line_ptr++ =COL_TO_RGB565(*src_ptr,pal); + src_ptr++; + } + } + break; + case SKIP_PIXELS: + c0 = (*src_ptr++)+1; +skip_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + R_SCAN + } + else + line_ptr += c0; + break; + case DUPLICATE_PIXELS: + c0 = (*src_ptr++)+1; +duplicate_pixels: + pixel_count += c0; + dup_pixel = COL_TO_RGB565(*src_ptr,pal); + src_ptr++; + + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + c0 -= (x+pixel_count)-WorkWindowWidth; + while(c0--) + *line_ptr++ = dup_pixel; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = dup_pixel; + } + break; + case FINISHED: + return; + } + } + } + else + { + DRAW_SPRITE16(pal) + } +} + +void DrawBSpritePalC32(SLONG x,SLONG y,BSprite *the_sprite,UBYTE *pal) +{ + UBYTE packet, + *src_ptr; + ULONG c0, + clip, + count_diff, + pixel_count, + sprite_height; + ULONG l_scan, + v_scan; + SLONG sprite_x; + + ULONG dup_pixel, + *dst_ptr, + *line_ptr; + + + if(x>=WorkWindowWidth || (x+the_sprite->SpriteWidth)<0 || y>=WorkWindowHeight || (y+the_sprite->SpriteHeight)<0) + return; + + sprite_height = the_sprite->SpriteHeight; + sprite_x = x; + src_ptr = the_sprite->SpriteData; + clip = 0; + l_scan = 0; + + + if(x<0) + { + l_scan = -x; + sprite_x= 0; + clip = 1; + } + if(y<0) + { + v_scan = -y; + sprite_height += y; + V_SCAN + y = 0; + clip = 1; + } + if((SLONG)(x+the_sprite->SpriteWidth)>=WorkWindowWidth) + { + clip = 1; + } + if((SLONG)(y+sprite_height)>=WorkWindowHeight) + { + sprite_height -= (y+sprite_height)-WorkWindowHeight; + clip = 1; + } + + dst_ptr = (ULONG*)WorkWindow+sprite_x+(y*WorkScreenPixelWidth); + line_ptr = dst_ptr; + + if(clip) + { + pixel_count = 0; + L_SCAN + while(sprite_height) + { + packet = *src_ptr++; + switch(packet) + { + case END_LINE: +end_line: + dst_ptr += WorkScreenPixelWidth; + line_ptr = dst_ptr; + sprite_height--; + pixel_count = 0; + L_SCAN + break; + case COPY_PIXELS: + c0 = (*src_ptr++)+1; +copy_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + count_diff = (x+pixel_count)-WorkWindowWidth; + c0 -= count_diff; + while(c0--) + { + *line_ptr++ =COL_TO_RGB888(*src_ptr,pal); + src_ptr++; + } + src_ptr += count_diff; + R_SCAN + } + else + { + while(c0--) + { + *line_ptr++ =COL_TO_RGB888(*src_ptr,pal); + src_ptr++; + } + } + break; + case SKIP_PIXELS: + c0 = (*src_ptr++)+1; +skip_pixels: + pixel_count += c0; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + R_SCAN + } + else + line_ptr += c0; + break; + case DUPLICATE_PIXELS: + c0 = (*src_ptr++)+1; +duplicate_pixels: + pixel_count += c0; + dup_pixel = COL_TO_RGB888(*src_ptr,pal); + src_ptr++; + if((SLONG)(x+pixel_count)>=WorkWindowWidth) + { + c0 -= (x+pixel_count)-WorkWindowWidth; + while(c0--) + *line_ptr++ = dup_pixel; + R_SCAN + } + else + { + while(c0--) + *line_ptr++ = dup_pixel; + } + break; + case FINISHED: + return; + } + } + } + else + { + DRAW_SPRITE32(pal) + } +} + +//--------------------------------------------------------------- + +void SetupBSprites(BSprite *sprite_ref,UBYTE *sprite_data) +{ + ULONG spr_count; + + + spr_count = *(ULONG*)(&sprite_ref->SpriteHeight); + sprite_ref++; + while(spr_count--) + { + sprite_ref->SpriteData += (ULONG)sprite_data; + sprite_ref++; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Library/TextDef.cpp b/fallen/Editor/Library/TextDef.cpp new file mode 100644 index 0000000..7928298 --- /dev/null +++ b/fallen/Editor/Library/TextDef.cpp @@ -0,0 +1,937 @@ +// TextDef.c +// Guy Simmons, 7th October 1996. + +// Hard coded font definition for quick text functions. + +#include "Editor.hpp" + +//--------------------------------------------------------------- +// Byte1 - Width +// Byte2 - Height +// Byte3 - Vertical offset. + + +//--------------------------------------------------------------- + +static UBYTE Null[]= +{ + 0,0,0, +}; + +static UBYTE Space[] = +{ + 4,0,0, +}; + +static UBYTE Excl[] = +{ + 1,7,1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, +}; + +static UBYTE Dollar[] = +{ + 5,9,0, + 0,0,1,0,0, + 0,1,1,1,0, + 1,0,1,0,1, + 1,0,1,0,0, + 0,1,1,1,0, + 0,0,1,0,1, + 1,0,1,0,1, + 0,1,1,1,0, + 0,0,1,0,0, +}; + +static UBYTE Percent[] = +{ + 8,7,1, + 0,1,1,1,1,1,1,1, + 1,0,0,1,0,0,1,0, + 1,0,0,1,0,1,0,0, + 0,1,1,0,1,1,1,0, + 0,0,0,1,1,0,0,1, + 0,0,1,0,1,0,0,1, + 0,1,0,0,0,1,1,0, +}; + +static UBYTE And[] = +{ + 7,8,0, + 0,0,1,1,0,0,0, + 0,1,0,0,1,0,0, + 0,1,0,1,0,0,0, + 0,0,1,0,0,0,0, + 0,1,0,1,0,1,0, + 1,0,0,0,1,0,0, + 1,0,0,1,0,1,0, + 0,1,1,0,0,0,1, +}; + +static UBYTE Quotes[] = +{ + 3,2,1, + 1,0,1, + 1,0,1, +}; + +static UBYTE Astrisk[] = +{ + 5,5,1, + 0,1,0,1,0, + 0,0,1,0,0, + 1,1,1,1,1, + 0,0,1,0,0, + 0,1,0,1,0, +}; + +static UBYTE BrackO[] = +{ + 3,9,0, + 0,0,1, + 0,1,0, + 1,0,0, + 1,0,0, + 1,0,0, + 1,0,0, + 1,0,0, + 0,1,0, + 0,0,1, +}; + +static UBYTE BrackC[] = +{ + 3,9,0, + 1,0,0, + 0,1,0, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,1,0, + 1,0,0, +}; + +static UBYTE Plus[] = +{ + 5,5,2, + 0,0,1,0,0, + 0,0,1,0,0, + 1,1,1,1,1, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE Comma[] = +{ + 2,4,6, + 1,1, + 1,1, + 0,1, + 1,0, +}; + +static UBYTE Minus[] = +{ + 5,1,4, + 1,1,1,1,1 +}; + +static UBYTE Stop[] = +{ + 2,2,6, + 1,1, + 1,1, +}; + +static UBYTE Zero[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE One[] = +{ + 2,7,1, + 0,1, + 1,1, + 0,1, + 0,1, + 0,1, + 0,1, + 0,1, +}; + +static UBYTE Two[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,0,1,0,0, + 0,1,0,0,0, + 1,1,1,1,1, +}; + +static UBYTE Three[] = +{ + 5,7,1, + 1,1,1,1,1, + 0,0,0,1,0, + 0,0,1,0,0, + 0,1,1,1,0, + 0,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Four[] = +{ + 5,7,1, + 0,0,0,1,0, + 0,0,1,1,0, + 0,1,0,1,0, + 1,0,0,1,0, + 1,1,1,1,1, + 0,0,0,1,0, + 0,0,0,1,0, +}; + +static UBYTE Five[] = +{ + 5,7,1, + 1,1,1,1,1, + 1,0,0,0,0, + 1,1,1,1,0, + 0,0,0,0,1, + 0,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Six[] = +{ + 5,7,1, + 0,0,1,1,0, + 0,1,0,0,0, + 1,0,0,0,0, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Seven[] = +{ + 5,7,1, + 1,1,1,1,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,0,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE Eight[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE Nine[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,1,1,0,0, +}; + +static UBYTE Colon[] = +{ + 2,3,4, + 0,1, + 0,0, + 0,1, +}; + +static UBYTE QMark[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 0,0,0,0,1, + 0,0,0,1,0, + 0,0,1,0,0, + 0,0,0,0,0, + 0,0,1,0,0, +}; + +static UBYTE At[] = +{ + 7,8,1, + 0,0,1,1,1,0,0, + 0,1,0,0,0,1,0, + 1,0,0,1,1,0,1, + 1,0,1,0,1,0,1, + 1,0,1,0,1,0,1, + 1,0,0,1,1,1,0, + 0,1,0,0,0,0,0, + 0,0,1,1,1,0,0, +}; + +static UBYTE A[] = +{ + 5,7,1, + 0,0,1,0,0, + 0,0,1,0,0, + 0,1,0,1,0, + 0,1,0,1,0, + 1,1,1,1,1, + 1,0,0,0,1, + 1,0,0,0,1 +}; + +static UBYTE B[] = +{ + 5,7,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, +}; + +static UBYTE C[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,1, + 0,1,1,1,0 +}; + +static UBYTE D[] = +{ + 5,7,1, + 1,1,1,0,0, + 1,0,0,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,1,0, + 1,1,1,0,0, +}; + +static UBYTE E[] = +{ + 4,7,1, + 1,1,1,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +static UBYTE F[] = +{ + 4,7,1, + 1,1,1,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, +}; + +static UBYTE G[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,0, + 1,0,0,1,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE H[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, +}; + +static UBYTE I[] = +{ + 1,7,1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, +}; + +static UBYTE J[] = +{ + 5,7,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE K[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,1,0, + 1,0,1,0,0, + 1,1,0,0,0, + 1,0,1,0,0, + 1,0,0,1,0, + 1,0,0,0,1, +}; + +static UBYTE L[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +static UBYTE M[] = +{ + 7,7,1, + 1,0,0,0,0,0,1, + 1,1,0,0,0,1,1, + 1,0,1,0,1,0,1, + 1,0,0,1,0,0,1, + 1,0,0,0,0,0,1, + 1,0,0,0,0,0,1, + 1,0,0,0,0,0,1, +}; + +static UBYTE N[] = +{ + 5,7,1, + 1,1,0,0,1, + 1,1,0,0,1, + 1,0,1,0,1, + 1,0,1,0,1, + 1,0,0,1,1, + 1,0,0,1,1, + 1,0,0,0,1, +}; + +static UBYTE O[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE P[] = +{ + 5,7,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, +}; + +static UBYTE Q[] = +{ + 5,8,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,1,0,1, + 0,1,1,1,0, + 0,0,0,1,0, +}; + +static UBYTE R[] = +{ + 5,7,1, + 1,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,0, + 1,0,1,0,0, + 1,0,0,1,0, + 1,0,0,0,1, +}; + +static UBYTE S[] = +{ + 5,7,1, + 0,1,1,1,0, + 1,0,0,0,1, + 1,0,0,0,0, + 0,1,1,1,0, + 0,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE T[] = +{ + 5,7,1, + 1,1,1,1,1, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE U[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,1,1,0, +}; + +static UBYTE V[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,0,1,0, + 0,1,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE W[] = +{ + 7,7,1, + 1,0,0,0,0,0,1, + 1,0,0,0,0,0,1, + 0,1,0,1,0,1,0, + 0,1,0,1,0,1,0, + 0,0,1,0,1,0,0, + 0,0,1,0,1,0,0, + 0,0,1,0,1,0,0, +}; + +static UBYTE X[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0, + 0,1,0,1,0, + 1,0,0,0,1, + 1,0,0,0,1, +}; + +static UBYTE Y[] = +{ + 5,7,1, + 1,0,0,0,1, + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE Z[] = +{ + 4,7,1, + 1,1,1,1, + 0,0,0,1, + 0,0,1,0, + 0,1,0,0, + 1,0,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +static UBYTE Under[] = +{ + 6,1,7, + 1,1,1,1,1 +}; + +static UBYTE _a[] = +{ + 4,5,3, + 0,1,1,0, + 0,0,0,1, + 0,1,1,1, + 1,0,0,1, + 0,1,1,1, +}; + +static UBYTE _b[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,1,1,0, +}; + +static UBYTE _c[] = +{ + 4,5,3, + 0,1,1,0, + 1,0,0,1, + 1,0,0,0, + 1,0,0,1, + 0,1,1,0, +}; + +static UBYTE _d[] = +{ + 4,7,1, + 0,0,0,1, + 0,0,0,1, + 0,1,1,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, +}; + +static UBYTE _e[] = +{ + 4,5,3, + 0,1,1,0, + 1,0,0,1, + 1,1,1,1, + 1,0,0,0, + 0,1,1,0, +}; + +static UBYTE _f[] = +{ + 4,7,1, + 0,0,1,1, + 0,1,0,0, + 1,1,1,0, + 0,1,0,0, + 0,1,0,0, + 0,1,0,0, + 0,1,0,0, +}; + +static UBYTE _g[] = +{ + 4,7,3, + 0,1,1,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, + 0,0,0,1, + 0,1,1,0, +}; + +static UBYTE _h[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, +}; + +static UBYTE _i[] = +{ + 2,7,1, + 0,1, + 0,0, + 1,1, + 0,1, + 0,1, + 0,1, + 0,1, +}; + +static UBYTE _j[] = +{ + 3,9,1, + 0,0,1, + 0,0,0, + 0,1,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 0,0,1, + 1,1,0, +}; + +static UBYTE _k[] = +{ + 4,7,1, + 1,0,0,0, + 1,0,0,0, + 1,0,0,1, + 1,0,1,0, + 1,1,0,0, + 1,0,1,0, + 1,0,0,1, +}; + +static UBYTE _l[] = +{ + 2,7,1, + 1,1, + 0,1, + 0,1, + 0,1, + 0,1, + 0,1, + 0,1, +}; + +static UBYTE _m[] = +{ + 7,5,3, + 1,1,1,0,1,1,0, + 1,0,0,1,0,0,1, + 1,0,0,1,0,0,1, + 1,0,0,1,0,0,1, + 1,0,0,1,0,0,1, +}; + +static UBYTE _n[] = +{ + 4,5,3, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, +}; + +static UBYTE _o[] = +{ + 4,5,3, + 0,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,0, +}; + +static UBYTE _p[] = +{ + 4,7,3, + 1,1,1,0, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,1,1,0, + 1,0,0,0, + 1,0,0,0, +}; + +static UBYTE _q[] = +{ + 4,7,3, + 0,1,1,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, + 0,0,0,1, + 0,0,0,1, +}; + +static UBYTE _r[] = +{ + 4,5,3, + 1,0,1,1, + 1,1,0,0, + 1,0,0,0, + 1,0,0,0, + 1,0,0,0, +}; + +static UBYTE _s[] = +{ + 4,5,3, + 0,1,1,1, + 1,0,0,0, + 0,1,1,0, + 0,0,0,1, + 1,1,1,0, +}; + +static UBYTE _t[] = +{ + 3,7,1, + 0,1,0, + 0,1,0, + 1,1,1, + 0,1,0, + 0,1,0, + 0,1,0, + 0,0,1, +}; + +static UBYTE _u[] = +{ + 4,5,3, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, +}; + +static UBYTE _v[] = +{ + 5,5,3, + 1,0,0,0,1, + 0,1,0,1,0, + 0,1,0,1,0, + 0,0,1,0,0, + 0,0,1,0,0, +}; + +static UBYTE _w[] = +{ + 7,5,3, + 1,0,0,0,0,0,1, + 0,1,0,1,0,1,0, + 0,1,0,1,0,1,0, + 0,0,1,0,1,0,0, + 0,0,1,0,1,0,0, +}; + +static UBYTE _x[] = +{ + 5,5,3, + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0, + 0,1,0,1,0, + 1,0,0,0,1, +}; + +static UBYTE _y[] = +{ + 4,7,3, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 1,0,0,1, + 0,1,1,1, + 0,0,0,1, + 0,1,1,0, +}; + +static UBYTE _z[] = +{ + 4,5,3, + 1,1,1,1, + 0,0,1,0, + 0,1,0,0, + 1,0,0,0, + 1,1,1,1, +}; + +//--------------------------------------------------------------- + +UBYTE *CharTable[] = +{ + Null, Null, Null, Null, Null, Null, Null, Null, + Null, Null, Null, Null, Null, Null, Null, Null, + Null, Null, Null, Null, Null, Null, Null, Null, + Null, Null, Null, Null, NULL, Null, Null, Null, + Space, Excl, Quotes, Null, Dollar, Percent,And, Null, + BrackO, BrackC, Astrisk,Plus, Comma, Minus, Stop, Null, + Zero, One, Two, Three, Four, Five, Six, Seven, + Eight, Nine, Colon, Null, Null, Null, Null, QMark, + At, A, B, C, D, E, F, G, + H, I, J, K, L, M, N, O, + P, Q, R, S, T, U, V, W, + X, Y, Z, Null, Null, Null, Null, Under, + Null, _a, _b, _c, _d, _e, _f, _g, + _h, _i, _j, _k, _l, _m, _n, _o, + _p, _q, _r, _s, _t, _u, _v, _w, + _x, _y, _z, Null, Null, Null, Null, Null +}; + +//--------------------------------------------------------------- + diff --git a/fallen/Editor/Source/Alert.cpp b/fallen/Editor/Source/Alert.cpp new file mode 100644 index 0000000..e264e89 --- /dev/null +++ b/fallen/Editor/Source/Alert.cpp @@ -0,0 +1,141 @@ +// Alert.cpp +// Guy Simmons, 11th April 1997. + +#include "Editor.hpp" + + +#define BOX_WIDTH 250 +#define BOX_HEIGHT 100 + + +ControlDef buttons[] = +{ + { BUTTON, KB_ENTER, "Okay", 10, BOX_HEIGHT-26, 50, 0 }, + { BUTTON, KB_ESC, "Cancel", BOX_WIDTH-(70-10), BOX_HEIGHT-26, 50, 0 }, + + { 0 } +}; + +//--------------------------------------------------------------- + +Alert::Alert(CBYTE *text1,CBYTE *text2) +{ + SetRect ( + (WorkScreenPixelWidth-BOX_WIDTH)>>1, + (WorkScreenHeight-BOX_HEIGHT)>>1, + BOX_WIDTH, + BOX_HEIGHT + ); + AlertSet.InitControlSet(buttons); + AlertSet.ControlSetBounds(this); + HandleAlert(text1,text2); +} + +Alert::Alert() +{ + SetRect ( + (WorkScreenPixelWidth-BOX_WIDTH)>>1, + (WorkScreenHeight-BOX_HEIGHT)>>1, + BOX_WIDTH, + BOX_HEIGHT + ); + AlertSet.InitControlSet(buttons); + AlertSet.ControlSetBounds(this); +} + +//--------------------------------------------------------------- + +Alert::~Alert() +{ + +} + +//--------------------------------------------------------------- + +BOOL Alert::HandleAlert(CBYTE *text1,CBYTE *text2) +{ + UBYTE control_id, + update = 1; + SLONG temp_x, + temp_y, + temp_height, + temp_width, + text1_x, + text1_y, + text2_x, + text2_y; + MFPoint mouse_point; + + + + temp_x = WorkWindowRect.Left; + temp_y = WorkWindowRect.Top; + temp_height = WorkWindowRect.Height; + temp_width = WorkWindowRect.Width; + + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + + if(text1) + { + text1_x = GetLeft()+((BOX_WIDTH-QTStringWidth(text1))>>1); + text1_y = GetTop()+20; + } + + if(text2) + { + text2_x = GetLeft()+((BOX_WIDTH-QTStringWidth(text2))>>1); + text2_y = text1_y+20; + } + + if(LockWorkScreen()) + { + FillRect(CONTENT_COL); + HiliteRect(HILITE_COL,LOLITE_COL); + + if(text1) + QuickTextC(text1_x,text1_y,text1,TEXT_COL); + if(text2) + QuickTextC(text2_x,text2_y,text2,TEXT_COL); + + AlertSet.SetControlDrawArea(); + AlertSet.DrawControlSet(); + + UnlockWorkScreen(); + ShowWorkScreen(0); + } + + while(SHELL_ACTIVE) + { + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + AlertSet.HandleControlSet(&mouse_point); + + if(LeftMouse.ButtonState) + { + mouse_point.X = LeftMouse.MouseX; + mouse_point.Y = LeftMouse.MouseY; + LeftMouse.ButtonState = 0; + control_id = (UBYTE)AlertSet.HandleControlSetClick(LEFT_CLICK,&mouse_point); + if(control_id==1) + return TRUE; + else if(control_id==2) + return FALSE; + } + else if(LastKey) + { + control_id = (UBYTE)AlertSet.HandleControlSetKey(LastKey); + if(control_id) + { + LastKey = 0; + if(control_id==1) + return TRUE; + else if(control_id==2) + return FALSE; + } + } + } + SetWorkWindowBounds(temp_x,temp_y,temp_width,temp_height); + return FALSE; +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/BuildTab.cpp b/fallen/Editor/Source/BuildTab.cpp new file mode 100644 index 0000000..722890d --- /dev/null +++ b/fallen/Editor/Source/BuildTab.cpp @@ -0,0 +1,5976 @@ +#include "Editor.hpp" + +#include "BuildTab.hpp" +#include "engine.h" +#include "c:\fallen\headers\enter.h" +#include "c:\fallen\headers\id.h" +#include "extra.h" +#include "c:\fallen\headers\supermap.h" +#include "outline.h" + + + +//#pragma warning 14 9 + +//static counter; +//#define ShowWorkWindow(x) {DrawLineC(0+(counter-1)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,0);DrawLineC(0+(counter++)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,255);DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); ShowWorkWindow(x);} + +//--------------------------------------------------------------- +//debug stuff +/* +void cross_work_window(void) +{ + DrawLineC(0,0,WorkWindowWidth-1,WorkWindowHeight-1,255); + DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); + +} +*/ +//--------------------------------------------------------------- + + + + + +#define CTRL_BUILD_TEXTURE 1 +#define CTRL_BUILD_Y_AXIS_FREE 2 +#define CTRL_BUILD_Z_AXIS_FREE 3 +#define CTRL_BUILD_NEW_BUILDING 4 +#define CTRL_BUILD_NEXT_STOREY 5 +#define CTRL_BUILD_DUPLICATE_STOREY 6 +#define CTRL_TOGGLE_TILED_ROOF 7 +#define CTRL_ADD_FLAT_ROOF_QUAD 8 +#define CTRL_ADD_FIRE_ESCAPE 9 +#define CTRL_ADD_POKEY 10 +#define CTRL_DELETE_STOREY 11 +#define CTRL_ADD_STAIRCASE 12 +#define CTRL_ADD_SKYLIGHT 13 +#define CTRL_ADD_CABLE 14 +#define CTRL_BUILD_CREATE_BUILDING 15 +#define CTRL_ADD_LADDER 16 +#define CTRL_DELETE_BUILDING 17 +#define CTRL_NEW_FENCE 18 +#define CTRL_ANOTHER_INSIDE_SEED 19 +#define CTRL_PREV_INSIDE_SEED 20 +#define CTRL_ANOTHER_STAIRCASE_SEED 21 +#define CTRL_PREV_STAIRCASE_SEED 22 +#define CTRL_NEXT_STOREY 23 +#define CTRL_PREV_STOREY 24 +#define CTRL_BUILDING_TYPE_HOUSE 25 +#define CTRL_BUILDING_TYPE_WAREHOUSE 26 +#define CTRL_BUILDING_TYPE_OFFICE 27 +#define CTRL_BUILDING_TYPE_APARTEMENT 28 +#define CTRL_BUILDING_TYPE_CRATE_IN 29 +#define CTRL_BUILDING_TYPE_CRATE_OUT 30 +#define CTRL_ADD_TRENCH 31 +#define CTRL_SET_STOREY_HEIGHT_64 32 +#define CTRL_SET_STOREY_HEIGHT_128 33 +#define CTRL_SET_STOREY_HEIGHT_196 34 +#define CTRL_SET_STOREY_HEIGHT_256 35 +#define CTRL_TOGGLE_FLAT_TILED_ROOF 36 +#define CTRL_DEL_ALL 37 +#define CTRL_LOAD_TEXTURES 38 +#define CTRL_CUT_BUILDING 39 +#define CTRL_PASTE_BUILDING 40 +#define CTRL_SET_STOREY_TYPE_NORMAL 41 +#define CTRL_SET_STOREY_TYPE_FENCE 42 +#define CTRL_SCROLL_MAP_UP 43 +#define CTRL_SCROLL_MAP_DOWN 44 +#define CTRL_SCROLL_MAP_LEFT 45 +#define CTRL_SCROLL_MAP_RIGHT 46 + +#define BUILD_MODE_WAIT 1 +#define BUILD_MODE_PLACE_STOREY 2 + +#define BUILD_MODE_CONT_STOREY 3 +#define BUILD_MODE_EDIT_STOREY 4 + + +CBYTE *storey_name[]= +{ + "ZERO", + "NORMAL", + "ROOF", + "WALL", + "ROOF QUAD", + "FLOOR POINTS", + "FIRE ESCAPE", + "STAIRCASE", + "SKYLIGHT", + "CABLE", + "ANGLE FENCE", + "BRICKWALL", + "LADDER", + "FLAT FENCE", + "TRENCH", + "", + "", + "", + "", + "", + "", + "", +}; + + +ControlDef build_tab_def[] = +{ + { CHECK_BOX, 0, "Textures", 180, 200-50, 0, 10 }, + { CHECK_BOX, 0, "Y Free", 120, 213-10, 0, 10 }, + { CHECK_BOX, 0, "Z Free", 120, 226-10, 0, 10 }, + { BUTTON, 0, "New Building", 10, 40, 0, 0 }, + { BUTTON, 0, "Next Storey", 10, 80, 0, 0 }, + { BUTTON, 0, "Duplicate Storey", 10, 100, 0, 0 }, + { BUTTON, 0, "Toggle Tiled Roof", 10, 120, 0, 0 }, + { BUTTON, 0, "Add Flat Roof Quad", 10, 140, 0, 0 }, + { BUTTON, 0, "Add a FireEscape", 10, 160, 0, 0 }, + { BUTTON, 0, "Add a Ledge to Storey", 10, 180, 0, 0 }, + { BUTTON, 0, "Delete Storey", 180, 40, 0, 0 }, + { BUTTON, 0, "Add a StairCase", 10, 200, 0, 0 }, + { BUTTON, 0, "Add a SkyLight", 10, 220, 0, 0 }, + { BUTTON, 0, "Add cable", 10, 240, 0, 0 }, + { BUTTON, 0, "Create Building", 10, 260, 0, 0 }, + { BUTTON, 0, "Add Ladder", 10, 280, 0, 0 }, + { BUTTON, 0, "Delete Building", 180, 60, 0, 0 }, + { BUTTON, 0, "New Fence", 10, 60, 0, 0 }, + { BUTTON, 0, "Another inside seed", 180, 180, 0, 0 }, + { BUTTON, 0, "Previous inside seed", 180, 200, 0, 0 }, + { BUTTON, 0, "Another staircase seed", 180, 220, 0, 0 }, + { BUTTON, 0, "Previous staircase seed", 180, 240, 0, 0 }, + { BUTTON, 0, "Edit Next Storey", 180, 320, 0, 0 }, + { BUTTON, 0, "Edit Prev Storey", 180, 340, 0, 0 }, + { CHECK_BOX, 0, "House", 10, 320, 0, 10 }, + { CHECK_BOX, 0, "Warehouse", 10, 335, 0, 10 }, + { CHECK_BOX, 0, "Office", 10, 350, 0, 10 }, + { CHECK_BOX, 0, "Apartement", 10, 365, 0, 10 }, + { CHECK_BOX, 0, "Crate Inside", 10, 380, 0, 10 }, + { CHECK_BOX, 0, "Crate Outside", 10, 395, 0, 10 }, + { BUTTON, 0, "Add a Trench", 180, 160, 0, 0 }, + { BUTTON, 0, "Storey Height quart", 180, 360, 0, 0 }, + { BUTTON, 0, "Storey Height half", 180, 375, 0, 0 }, + { BUTTON, 0, "Storey Height 3quart", 180, 390, 0, 0 }, + { BUTTON, 0, "Storey Height normal", 180, 405, 0, 0 }, + { BUTTON, 0, "Toggle Flat Tiled Roof", 170, 120, 0, 0 }, + { BUTTON, 0, "Delete ALL BUILDS", 180, 80, 0, 0 }, + { BUTTON, 0, "Load Textures from map", 180, 100, 0, 0 }, + { BUTTON, 0, "Cut Building", 30, 450, 0, 0 }, + { BUTTON, 0, "Paste Building", 110, 450, 0, 0 }, + { BUTTON, 0, "Storey Type Normal", 180, 425, 0, 0 }, + { BUTTON, 0, "Storey Type Fence", 180, 440, 0, 0 }, + { BUTTON, 0, "Up", 170, 260, 0, 0 }, + { BUTTON, 0, "Down", 160, 300, 0, 0 }, + { BUTTON, 0, "Left", 140, 280, 0, 0 }, + { BUTTON, 0, "Right", 180, 280, 0, 0 }, + { 0 } +}; + +BuildTab *the_build; + +// +// The building the stairs have been calculated for. +// The storey the inside building stuff has been calculated for. +// TRUE => the inside stuff is valid. +// + +SLONG inside_building; +SLONG inside_storey; +SLONG inside_valid; +SLONG inside_failure; + + +#define MAX_SEED_BACKUPS 16 + +SLONG seed_inside[MAX_SEED_BACKUPS]; +SLONG seed_stairs[MAX_SEED_BACKUPS]; + +SLONG seed_inside_upto; +SLONG seed_stairs_upto; + + +class BuildingBlock +{ + SLONG WallCount; + SLONG StoreyCount; + SLONG X; + SLONG Z; + struct FWall *PWall; + struct FStorey *PStorey; + struct FBuilding PBuilding; + + + public: + BuildingBlock(void); + ~BuildingBlock(); + void Cut(SLONG building); + void Paste(SLONG x,SLONG z,SLONG flags); + void Allocate(SLONG building); + void Free(SLONG clear_textures); + inline SLONG GetX(void) {return(X);} + inline SLONG GetZ(void) {return(Z);} +}; + + +BuildingBlock building_block; + +BuildingBlock::BuildingBlock(void) +{ + PWall=0; + PStorey=0; +} + +BuildingBlock::~BuildingBlock(void) +{ + if(PWall) + Free(0); +} + +void BuildingBlock::Free(SLONG clear_textures) +{ + if(PWall) + { + SLONG c0; + if(clear_textures) + for(c0=1;c0Y=edit_map_roof_height[mx][mz]; + ptr++; + } + else + { + *ptr++=edit_map[mx][mz]; + } + + } + } +} + +void MapBlock::Paste(SLONG x,SLONG z,SLONG flags,SLONG mode) +{ + SLONG mx,mz; + struct DepthStrip *ptr; + if(Ptr==0) + return; + + ptr=Ptr; + + for(mz=z;mz=0&&mz>=0&&mxY; + } + else + { + if(flags&PASTE_TEXTURE) + edit_map[mx][mz].Texture=ptr->Texture; + if(flags&PASTE_ALTITUDE) + edit_map[mx][mz].Y=ptr->Y; + } + } + ptr++; + } +} + +void MapBlock::Rotate(SLONG dir) +{ + SLONG dx,dz; + SLONG temp; + struct DepthStrip *ptr,*ptr_new; + if(Ptr==0) + return; + + ptr_new=(struct DepthStrip*)MemAlloc(Width*Depth*sizeof(struct DepthStrip)); + + ptr=Ptr; + + for(dz=0;dzRot--; + ptr_new[new_dx+new_dz*Depth].Texture=*(UWORD*)tex; + + ptr++; + } + temp=Width; + Width=Depth; + Depth=temp; + Free(); + Ptr=ptr_new; + +} +//----------------------------------------------------------------------------- + + + +SWORD get_new_window(void) +{ + SLONG c0; + for(c0=1;c0SetUpdateFunction(redraw_all_prims); + + Axis=X_AXIS|Y_AXIS|Z_AXIS; + Mode=0; + ViewSize=16; + ViewX=0+(64<>ELE_SHIFT; + mz=ViewZ>>ELE_SHIFT; + + rect_size=ViewSize>>2; + +// if(0) + if(Mode==BUILD_MODE_WAIT) + { + for(building=1;building>ELE_SHIFT)-mx)*ViewSize+(w>>1); +// z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + if(x1>0&&x10&&z1>ELE_SHIFT)-mx)*ViewSize+(w>>1); +// z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + if(x1>0&&x10&&z1>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + if(x1>0&&x10&&z1>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + if(x1>0 && x10 && z1>6); + rect.SetRect(x1-ViewSize*2,z1+2,12,12); + rect.OutlineRect(0); //GetHeightColour(storey_index)); + QuickTextC(x1+2-ViewSize*2,z1+4,str,0); + } + + CurrentY=0; + for(c0=0;c0>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + if(x1>0 && x10 && z1>6); + rect.SetRect(x1-ViewSize*2,z1+2,12,12); + rect.OutlineRect(0); //GetHeightColour(storey_index)); + QuickTextC(x1+2-ViewSize*2,z1+4,str,0); + + sprintf(str,"%d",wall_list[wall].TextureStyle2); + rect.SetRect(x1-ViewSize*2+14,z1+2,12,12); + rect.OutlineRect(GetHeightColour(storey_index)); + QuickTextC(x1+2-ViewSize*2+14,z1+4,str,0); + } + + + + CurrentY=0; + for(c0=0;c0>1); + tz=((((z1+100)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + AddHeightOffset(&tx,&tz); + if(storey_list[storey_index].StoreyFlags&(FLAG_STOREY_FLAT_TILED_ROOF)) + QuickTextC(tx,tz,"FRoof",0); + else + QuickTextC(tx,tz,"TRoof",0); + + } + if(storey_list[storey_index].StoreyType==STOREY_TYPE_SKYLIGHT) + { + SLONG tx,tz; + + tx=((((x1+100)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + tz=((((z1+100)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + AddHeightOffset(&tx,&tz); + QuickTextC(tx,tz,"SKYLight",0); + + } + } + } + + + CurrentY=storey_list[storey_index].DY; + index=storey_list[storey_index].WallHead; + +// x1=((x1>>ELE_SHIFT)-mx)*ViewSize+(w>>1); +// z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + AddHeightOffset(&x1,&z1); +// if(0) + if(index) + { + rect.SetRect(x1-rect_size,z1-rect_size,rect_size<<1,rect_size<<1); + rect.OutlineRect(GetHeightColour(storey_index)); + + while(index) + { + x1=wall_list[index].DX; + z1=wall_list[index].DZ; + +// x1=((x1>>ELE_SHIFT)-mx)*ViewSize+(w>>1); +// z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + AddHeightOffset(&x1,&z1); + rect.SetRect(x1-rect_size,z1-rect_size,rect_size<<1,rect_size<<1); + rect.OutlineRect(GetHeightColour(storey_index)); + + index=wall_list[index].Next; + } + } +// if(roof_flag) +// { +// storey_index=storey_list[storey_list[storey_index].Prev].Next; +// roof_flag=0; +// } +// else + { + storey_index=storey_list[storey_index].Next; + + } + // storey_index=storey_list[storey_index].Next; + } + } + } +} + + + +SLONG BuildTab::ClickInVertexStoreyList(SLONG building,SLONG storey_index,SLONG w,SLONG h,MFPoint *mouse_point,SLONG flags) +{ + SLONG roof_flag=0; + EdRect rect; + SLONG mx,mz,rect_size; + SLONG x1,y1,z1,x2,y2,z2,index; + + SLONG ret_building=0,ret_storey,ret_wall,wall; + + mx=ViewX>>ELE_SHIFT; + mz=ViewZ>>ELE_SHIFT; + + rect_size=ViewSize>>2; + while(storey_index>0) + { + + x1=storey_list[storey_index].DX; + z1=storey_list[storey_index].DZ; + + switch(storey_list[storey_index].StoreyType) + { + case STOREY_TYPE_FIRE_ESCAPE: + { + CBYTE str[20]; + + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(w>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + if(x1>0&&x10&&z1>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + if(x1>0&&x10&&z1>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + + if(x1>0&&x10&&z1>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + + if(x1>0&&x10&&z1>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + if(x1>0&&x10&&z1>ELE_SHIFT)-mx)*ViewSize+(w>>1); +// z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(w>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + AddHeightOffset(&x1,&z1); + if(index) + { + rect.SetRect(x1-rect_size,z1-rect_size,rect_size<<1,rect_size<<1); + if(rect.PointInRect(mouse_point)) + { + if(storey_index==EditStorey) + { + + EditBuilding=building; + EditStorey=storey_index; + EditY=0;//storey_list[EditStorey].DY; + EditWall=0; + return(2); + } + else + { + ret_building=building; + ret_storey=storey_index; + ret_wall=0; + } + } + + + while(index) + { + x1=wall_list[index].DX; + z1=wall_list[index].DZ; + +// x1=((x1>>ELE_SHIFT)-mx)*ViewSize+(w>>1); +// z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(w>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + AddHeightOffset(&x1,&z1); + + rect.SetRect(x1-rect_size,z1-rect_size,rect_size<<1,rect_size<<1); + if(rect.PointInRect(mouse_point)) + { + if(storey_index==EditStorey) + { + EditBuilding=building; + EditStorey=storey_index; + EditY=0;//storey_list[EditStorey].DY; + EditWall=index; + return(2); + } + else + { + ret_building=building; + ret_storey=storey_index; + ret_wall=index; + } + } + + index=wall_list[index].Next; + } + } + if(roof_flag) + { + storey_index=storey_list[storey_list[storey_index].Prev].Next; + roof_flag=0; + } + else + { +/* + SLONG temp_index; + + temp_index=storey_list[storey_index].Roof; + if(temp_index) + { + storey_index=temp_index; + roof_flag=1; + + } + else +*/ + { + storey_index=storey_list[storey_index].Next; + roof_flag=0; + } + + } + } + + if(ret_building) + { + EditBuilding=ret_building; + EditStorey=ret_storey; + EditY=0;//storey_list[EditStorey].DY; + EditWall=ret_wall; + + DrawTabContent(); + + return(1); + + } + return(0); + +} + +SLONG BuildTab::ClickInVertex(SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *mouse_point,SLONG flags) +{ + SLONG storey_index,found; + SLONG building; + SLONG found_one=0; + + + //if(EditBuilding) + { + for(building=1;building>10; + pdz=(pdz*20)>>10; + + DrawContentLine(x1+(pdx>>1),z1+(pdz>>1),x1-(pdx>>1),z1-(pdz>>1),GetHeightColour(0)); + DrawContentLine(x2+(pdx>>1),z2+(pdz>>1),x2-(pdx>>1),z2-(pdz>>1),GetHeightColour(0)); + + DrawContentLine(x1+(pdx>>1),z1+(pdz>>1),x2+(pdx>>1),z2+(pdz>>1),GetHeightColour(0)); + DrawContentLine(x1-(pdx>>1),z1-(pdz>>1),x2-(pdx>>1),z2-(pdz>>1),GetHeightColour(0)); + return(0); +} + +SLONG BuildTab::DrawWall(SLONG px,SLONG pz,SLONG x1,SLONG z1,SLONG index,SLONG storey) +{ + SLONG wcount,wwidth,wwidth_perc,wallwidth,wallwidth_perc,dx,dz,dist; + SLONG prev_x,prev_z; + + dx=abs(px-x1); + dz=abs(pz-z1); + + dist=sqrl(SDIST2(dx,dz)); + if(dist==0) + return(0); + + if(wall_list[index].WallFlags&FLAG_WALL_AUTO_WINDOWS) + { + wcount=dist/(BLOCK_SIZE*3); + wwidth=dist/(wcount*2+1); + + } + else + { + wcount=0; //wall_list[index].WindowCount; + wwidth=BLOCK_SIZE; + } + + dx=(px-x1); + dz=(pz-z1); + + if(wcount<0) + return(0); + + wallwidth=(dist-(wcount*wwidth))/(wcount+1); + + dx=(dx<<10)/dist; + dz=(dz<<10)/dist; + + prev_x=x1; + prev_z=z1; + + while(wcount) + { + x1=prev_x+((dx*wallwidth)>>10); + z1=prev_z+((dz*wallwidth)>>10); + +// DrawLineC(prev_x,prev_z,x1,z1,1); //wall + DrawContentLine(prev_x,prev_z,x1,z1,GetHeightColour(storey)); + + prev_x=x1; + prev_z=z1; + + x1=prev_x+((dx*wwidth)>>10); + z1=prev_z+((dz*wwidth)>>10); + + DrawWindow(prev_x,prev_z,x1,z1,dx,dz); +// DrawContentLine(prev_x,prev_z,x1,z1,0); + + prev_x=x1; + prev_z=z1; + wcount--; + + } + x1=prev_x+((dx*wallwidth)>>10); + z1=prev_z+((dz*wallwidth)>>10); + +// DrawLineC(prev_x,prev_z,x1,z1,1); //wall + + if(storey_list[storey].StoreyType==STOREY_TYPE_FENCE) + { + DrawContentLine(prev_x,prev_z,x1,z1,YELLOW_COL); + + } + else + { + DrawContentLine(prev_x,prev_z,x1,z1,GetHeightColour(storey)); + } + return(0); + +} + + +void BuildTab::DrawContentLine(SLONG x1,SLONG y1,SLONG x2,SLONG y2,SLONG col) +{ +/* + x1=((x1>>ELE_SHIFT)-(ViewX>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Width>>1); + y1=((y1>>ELE_SHIFT)-(ViewZ>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Height>>1); + + x2=((x2>>ELE_SHIFT)-(ViewX>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Width>>1); + y2=((y2>>ELE_SHIFT)-(ViewZ>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Height>>1); +*/ + + + + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + y1=((((y1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + x2=((((x2)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + y2=((((y2)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + AddHeightOffset(&x1,&y1); + AddHeightOffset(&x2,&y2); + + DrawLineC(x1,y1,x2,y2,col); + +} + +void BuildTab::DrawContentLineY(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col) +{ + SLONG temp; +/* + x1=((x1>>ELE_SHIFT)-(ViewX>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Width>>1); + y1=((y1>>ELE_SHIFT)-(ViewZ>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Height>>1); + + x2=((x2>>ELE_SHIFT)-(ViewX>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Width>>1); + y2=((y2>>ELE_SHIFT)-(ViewZ>>ELE_SHIFT))*ViewSize+(WorkWindowRect.Height>>1); +*/ + + temp=CurrentY; + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + x2=((((x2)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + z2=((((z2)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + CurrentY=y1; + AddHeightOffset(&x1,&z1); + CurrentY=y2; + AddHeightOffset(&x2,&z2); + CurrentY=temp; + + DrawLineC(x1,z1,x2,z2,col); + +} +void BuildTab::DrawContentRect(SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG col) +{ + DrawContentLine(x1,z1,x2,z1,col); + DrawContentLine(x2,z1,x2,z2,col); + DrawContentLine(x2,z2,x1,z2,col); + DrawContentLine(x1,z2,x1,z1,col); +} + +SLONG find_nearest_point(SLONG x,SLONG z,SLONG index,SLONG *rx,SLONG *rz) +{ + SLONG best,best_dist=0x7fffffff,dx,dz,dist; + + dx=(storey_list[index].DX-x); + dz=(storey_list[index].DZ-z); + + dist=SDIST2(dx,dz); + best_dist=dist; + best=-index; + + index=storey_list[index].WallHead; + while(index) + { + dx=(wall_list[index].DX-x); + dz=(wall_list[index].DZ-z); + dist=SDIST2(dx,dz); + if(dist>ELE_SHIFT; + my=ViewY; + mz=ViewZ>>ELE_SHIFT; + + + width=ViewSize; + + count_across=((w/(width))>>1)+1; + count_high=(h/(width))>>1; + + for(dx=-count_across;dx<=count_across;dx++) + for(dz=-count_high;dz<=count_high;dz++) + { + SLONG x1,y1,x2,y2; + + x1=(w>>1)+(dx)*(width); + x2=(w>>1)+(dx)*(width)+width; + + y1=(h>>1)+dz*(width); + y2=(h>>1)+dz*(width)+width; + if(edit_info.RoofTex) + { + texture=tex_map[mx+dx][mz+dz]; + } + else + { + texture=edit_map[mx+dx][mz+dz].Texture; + } + if(mx+dx>=0&&mx+dx=0&&mz+dz=0&&mx+dx+ox=0&&mz+dz+oz>ELE_SHIFT; + my=ViewY; + mz=ViewZ>>ELE_SHIFT; + + width=ViewSize; + + count_across=((w/(width))>>1)+1; + count_high=((h/(width))>>1)-1; + + for(dx=-count_across;dx<=count_across;dx++) + for(dz=-count_high;dz<=count_high;dz++) + { + SLONG x1,y1,x2,y2,alt,salt; + CBYTE str[100]; + + x1=(w>>1)+(dx)*(width); + y1=(h>>1)+dz*(width); + if(RoofTop) + { + salt=edit_map_roof_height[mx+dx][mz+dz]; + } + else + { + salt=edit_map[mx+dx][mz+dz].Y; + } + alt=abs(salt); + + sprintf(str,"%d",alt); + QuickTextC(x1+1,y1+1,str,WHITE_COL); + QuickTextC(x1-1,y1-1,str,WHITE_COL); + if(salt<0) + QuickTextC(x1,y1,str,RED_COL); + else + QuickTextC(x1,y1,str,0); + +// x2=(w>>1)+(dx)*(width)+width; +// y2=(h>>1)+dz*(width)+width; +/* + if(add_floor_face_to_bucket(x1,y1,0,x2,y1,0,x1,y2,0,x2,y2,0,&edit_map[mx+dx][mz+dz],128,128,128,128)) + { + selected_prim_xyz.X = dx+mx; + selected_prim_xyz.Y = 0; + selected_prim_xyz.Z = dz+mz; + + hilited_face.MapX=dx+mx; + hilited_face.MapY=0; //dx+mx-1; + hilited_face.MapZ=dz+mz; + } +*/ + } + render_view(0); +} + +void draw_status_line(SLONG x,SLONG y,SLONG w,SLONG h,CBYTE *str) +{ + EdRect rect; + rect.SetRect(x,y,w,h); + rect.FillRect(CONTENT_COL); + rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC(x+4,y+2,str,0); +} + +// +// Returns TRUE if the given storey can have an inside generated for it. +// + +SLONG is_storey_habitable(SLONG storey) +{ + ASSERT(WITHIN(storey, 1, MAX_STOREYS - 1)); + + // + // It must be normal and circular. + // + + if ((storey_list[storey].StoreyType == STOREY_TYPE_NORMAL) && is_storey_circular(storey)) + { + return TRUE; + } + else + { + return FALSE; + } +} + + +SLONG identical_storey(SLONG px,SLONG pz,SLONG x1,SLONG z1,SLONG storey) +{ + storey=storey_list[storey].Next; + SLONG sx,sz,nx,nz,index; + + while(storey) + { + + sx=storey_list[storey].DX; + sz=storey_list[storey].DZ; + index=storey_list[storey].WallHead; + + while(index) + { + nx=wall_list[index].DX; + nz=wall_list[index].DZ; + + if(px==sx&&pz==sz&&x1==nx&&z1==nz) + return(1); + + + + sx=nx; + sz=nz; + index=wall_list[index].Next; + } + + + + storey=storey_list[storey].Next; + } + return(0); +} + +void BuildTab::DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG wwx,wwy,www,wwh; + EdRect drawrect; + + SLONG dx,dy,dz,width,height,count_across,count_high; + SLONG c0,c1; + SLONG mx,my,mz; + SLONG index; + struct EditMapElement *p_ele; + SLONG roof_flag=0; + SLONG building; + CBYTE str[100]; + SLONG storey_height; + + +// my=((CVSlider*)GetControlPtr(CTRL_BUILD_V_SLIDE_LEVEL))->GetCurrentValue(); +// my=((CVSlider*)GetControlPtr(CTRL_BUILD_V_SLIDE_LEVEL))->GetCurrentValue(); + + mx=ViewX>>ELE_SHIFT; + my=ViewY; + mz=ViewZ>>ELE_SHIFT; + + + RedrawModuleContent=0; + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + SetWorkWindowBounds(x,y,w-1,h-1); + drawrect.SetRect(0,0,w-1,h-1); + drawrect.FillRect(CONTENT_COL_BR); + + width=ViewSize; + + count_across=((w/(width))>>1)+1; + count_high=(h/(width))>>1; + + // + // Recalculate the insides all the time! + // + + inside_valid = FALSE; + inside_failure = FALSE; + + // + // Shall we recalculate the insides? + // + + if (EditBuilding && + EditStorey) + { + if (inside_building != EditBuilding || + inside_storey != EditStorey) + { + // + // The inside info is for the wrong place. + // + + inside_building = EditBuilding; + inside_storey = EditStorey; + inside_valid = FALSE; + } + + if (inside_valid) + { + // + // Everything okay. + // + } + else + { + inside_valid = FALSE; + + /* + + // + // Is this a valid storey and building? + // + + if (is_storey_habitable(inside_storey)) + { + // + // The inside stuff in the game work off the supermap structure, + // so convert this building into the supermap structure. + // + + create_super_dbuilding(inside_building); + + // + // Calculate the height of this storey. + // + + storey_height = storey_list[inside_storey].DY; + + // + // Calculate the insides for the storey. We use dbuilding 1 because + // create_super_dbuilding() always puts the building into dbuilding 1. + // + + inside_valid = ENTER_setup(1, storey_height, FALSE, TRUE); + + if (!inside_valid) + { + // + // We can't go inside this building. + // + + inside_failure = TRUE; + } + else + { + // + // Remember the seed used. + // + + building_list[EditBuilding].InsideSeed = dbuildings[1].SeedInside; + } + } + + */ + } + } + else + { + inside_valid = FALSE; + } + +/* + for(dx=-count_across;dxCubeType.Prim; + DrawBoxC(0+(w>>1)+dx*(width+1),0+(h>>1)+dz*(width+1),width,width,0); + } + else + DrawBoxC(0+(w>>1)+dx*(width+1),0+(h>>1)+dz*(width+1),width,width,1); + + if(my<127) + { + index=edit_map[(dx+mx)][(my+1)].Depth[(dz+mz)]; + if(index) + { + p_ele=&edit_map_eles[index]; + index=p_ele->CubeType.Prim; + DrawVLineC((w>>1)+dx*(width+1)-1,(h>>1)+dz*(width+1)-1,(h>>1)+(dz+1)*(width+1),2); + DrawVLineC((w>>1)+(dx+1)*(width+1),(h>>1)+dz*(width+1)-1,(h>>1)+(dz+1)*(width+1),2); + DrawHLineC((w>>1)+dx*(width+1)-1,(w>>1)+(dx+1)*(width+1),(h>>1)+dz*(width+1)-1,2); + DrawHLineC((w>>1)+dx*(width+1)-1,(w>>1)+(dx+1)*(width+1),(h>>1)+(dz+1)*(width+1),2); + } + } + + if(my>0) + { + index=edit_map[(dx+mx)][(my-1)].Depth[(dz+mz)]; + if(index) + { + p_ele=&edit_map_eles[index]; + index=p_ele->CubeType.Prim; + DrawPixelC(0+(w>>1)+dx*(width+1)+(width>>1),0+(h>>1)+dz*(width+1)+(width>>1),2); + } + } + } +*/ + + if (!Keys[KB_T]) + { + if(Texture&2) + DrawFloorTextures(x,y,w,h); + else + { + for(dx=-count_across;dx<=count_across;dx++) + { + DrawVLineC((w>>1)+(dx)*(width),0,h,RGB_TO_565(100,100,100)); + } + for(dz=-count_high;dz<=count_high;dz++) + { + DrawHLineC(0,w,(h>>1)+dz*(width),RGB_TO_565(100,100,100)); + } + } + if(Texture&4) + DrawFloorLabels(x,y,w,h); + + { + sprintf(str," engine (%d,%d,%d) view %d %d %d ",engine.X>>8,engine.Y>>8,engine.Z>>8,ViewX,ViewY,ViewZ); + QuickTextC(3,3,str,0); + QuickTextC(4,4,str,255); + } + } + + + + + // + // Draw all the extra things. + // + + if(0) + { + SLONG i; + SLONG j; + + SLONG x; + SLONG z; + + SLONG angle; + SLONG angle1; + SLONG angle2; + SLONG x1; + SLONG x2; + SLONG z1; + SLONG z2; + SLONG y1,y2; + + EXTRA_Thing *et; + + SLONG old_current_y; + + old_current_y = CurrentY; + CurrentY = 0; + + for (i = 0; i < EXTRA_MAX_THINGS; i++) + { + et = &EXTRA_thing[i]; + + switch(et->type) + { + case EXTRA_TYPE_NONE: + break; + + case EXTRA_TYPE_PUDDLE: + + #define NUM_EXTRA_PUDDLE_STEPS 16 + + for (angle = 0; angle < 2048; angle += 2048 / NUM_EXTRA_PUDDLE_STEPS) + { + angle1 = angle; + angle2 = angle + 1024; + + angle1 &= 2047; + angle2 &= 2047; + + x1 = et->x + (SIN(angle1) * et->radius >> 16); + z1 = et->z + (COS(angle1) * et->radius >> 16); + + x2 = et->x + (SIN(angle2) * et->radius >> 16); + z2 = et->z + (COS(angle2) * et->radius >> 16); + + DrawContentLine( + x1, z1, + x2, z2, + BLUE_COL); + } + + break; + + case EXTRA_TYPE_MIST: + + x1 = et->x - et->radius; + z1 = et->z - et->radius; + + x2 = et->x + et->radius; + z2 = et->z + et->radius; + + #define NUM_EXTRA_MIST_STEPS 25 + + for (j = 0; j < NUM_EXTRA_MIST_STEPS; j++) + { + x = x1 + ((x2 - x1) * j) / NUM_EXTRA_MIST_STEPS; + z = z1 + ((z2 - z1) * j) / NUM_EXTRA_MIST_STEPS; + + DrawContentLine( + x, z1, + x, z2, + GREY_COL); + + DrawContentLine( + x1, z, + x2, z, + GREY_COL); + } + break; + + default: + ASSERT(0); + break; + } + + if (et->type != EXTRA_TYPE_NONE) + { + // + // Always draw a little nodule that you can select. + // + + #define NUM_EXTRA_NODE_STEPS 8 + + for (angle = 0; angle < 2048; angle += 2048 / NUM_EXTRA_NODE_STEPS) + { + angle1 = angle; + angle2 = angle + 2048 / NUM_EXTRA_NODE_STEPS; + + angle1 &= 2047; + angle2 &= 2047; + + x1 = et->x + (SIN(angle1) * EXTRA_SELECT_DIST >> 17); + z1 = et->z + (COS(angle1) * EXTRA_SELECT_DIST >> 17); + + x2 = et->x + (SIN(angle2) * EXTRA_SELECT_DIST >> 17); + z2 = et->z + (COS(angle2) * EXTRA_SELECT_DIST >> 17); + + DrawContentLine( + x1, z1, + x2, z2, + YELLOW_COL); + } + } + } + + CurrentY = old_current_y; + } + + + + + + +// if(EditBuilding) +// if(0) + for(building=1;building[%d] ->[%d]",storey_index,storey_list[storey_index].Next,storey_list[storey_index].Prev,storey_list[storey_index].DY,storey_list[storey_index].Height,storey_list[storey_index].WallHead,wall_list[storey_list[storey_index].WallHead].Next,wall_list[wall_list[storey_list[storey_index].WallHead].Next].Next); + QuickText(20,ploty,str,0); + ploty+=20; + } + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + x1=storey_list[storey_index].DX; + y1=storey_list[storey_index].DY; + z1=storey_list[storey_index].DZ; + + CurrentY=storey_list[storey_index].DY; + index=storey_list[storey_index].WallHead; + switch(storey_list[storey_index].StoreyType) + { + case STOREY_TYPE_NORMAL: + drawn_normal=1; + break; + + } + + if(Mode==BUILD_MODE_CONT_STOREY) + { + + CurrentY=storey_list[EditStorey].DY; + mouse_point.X+= ((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + mouse_point.Y+=-((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + + CalcMapCoord(&fx,&fy,&fz,x,y,w,h,&mouse_point); + CurrentY=storey_list[storey_index].DY; + } + + if(roof_flag&&storey_list[storey_index].StoreyType==STOREY_TYPE_ROOF_QUAD&&index) + { + SLONG x[4],z[4]; + SLONG wall,c0; + + x[0]=x1; + z[0]=z1; + wall=index; + for(c0=1;c0<4&&wall;c0++) + { + x[c0]=wall_list[wall].DX; + z[c0]=wall_list[wall].DZ; + + wall=wall_list[wall].Next; + } + if(c0>3) + { + DrawContentLine(x[0],z[0],x[2],z[2],GetHeightColour(storey_index)); + DrawContentLine(x[1],z[1],x[3],z[3],GetHeightColour(storey_index)); + } + + } + + if(index==0) + { + + if(Mode==BUILD_MODE_CONT_STOREY&&storey_index==EditStorey) + DrawContentLine(x1,z1,fx,fz,GetHeightColour(storey_index)); + } + else + { + /* + if(Mode==BUILD_MODE_WAIT) + { + if(storey_list[storey_index].StoreyType==STOREY_TYPE_ROOF_QUAD) + { + CurrentY+=BLOCK_SIZE; + } + + } + */ + + px=x1; + py=y1; + pz=z1; + while(index) + { + x1=wall_list[index].DX; + y1=wall_list[index].DY; + z1=wall_list[index].DZ; + + + // if(!identical_storey(px,pz,x1,z1,storey_index)) + { + if(roof_flag) + DrawContentLine(px,pz,x1,z1,GetHeightColour(storey_index)); + else + { + if(storey_list[storey_index].StoreyType==STOREY_TYPE_CABLE) + { + DrawContentLineY(px,py,pz,x1,y1,z1,RED_COL); //otline tiled roofs + } + else + { + DrawWall(px,pz,x1,z1,index,storey_index); + + { + SLONG x1,y1,x2,y2; + x1=px; + y1=pz; + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Width>>1); + y1=((((y1)-(ViewZ))*ViewSize)/ELE_SIZE)+(WorkWindowRect.Height>>1); + + x2=x1; + y2=y1; + + AddHeightOffset(&x1,&y1); + CurrentY+=storey_list[storey_index].Height; + AddHeightOffset(&x2,&y2); + CurrentY-=storey_list[storey_index].Height; + + DrawLineC(x1,y1,x2,y2,0); + + } + } + } + + if(storey_list[storey_index].StoreyFlags&(FLAG_STOREY_TILED_ROOF|FLAG_STOREY_FLAT_TILED_ROOF)) + { + + CurrentY+=storey_list[storey_index].Height; + DrawContentLine(px,pz,x1,z1,0); //otline tiled roofs + CurrentY-=storey_list[storey_index].Height; + + } + + } + px=x1; + py=y1; + pz=z1; + index=wall_list[index].Next; + } + if(Mode==BUILD_MODE_CONT_STOREY&&storey_index==EditStorey) + DrawContentLine(px,pz,fx,fz,GetHeightColour(storey_index)); + } + + // + // If this is the current storey, then draw the insides of this building. + // + + if (storey_index == inside_storey && + building == inside_building) + { + // + // Have we got generated the insides for this storey? + // +#ifdef DOG_POO + if (inside_valid&&0) + { + ID_Roominfo ri; + ID_Wallinfo wi; + ID_Stairinfo si; + + // + // Draw the room layout. + // + + ID_editor_start_get_rooms(); + ID_editor_start_get_walls(); + ID_editor_start_get_stairs(); + + while(ID_editor_get_wall(&wi)) + { + // + // Draw the walls. + // + + x1 = wi.x1 << ELE_SHIFT; + z1 = wi.z1 << ELE_SHIFT; + x2 = wi.x2 << ELE_SHIFT; + z2 = wi.z2 << ELE_SHIFT; + + DrawContentLine( + x1, z1, + x2, z2, + RED_COL); + + // + // Draw the doors. + // + + for (i = 0; i < 4; i++) + { + dx = x2 - x1; + dz = z2 - z1; + + dx = SIGN(dx) << ELE_SHIFT; + dz = SIGN(dz) << ELE_SHIFT; + + if (wi.door[i] != 255) + { + doorx1 = x1 + dx * wi.door[i]; + doorz1 = z1 + dz * wi.door[i]; + + doorx2 = doorx1 + dx; + doorz2 = doorz1 + dz; + + DrawContentLine( + doorx1, doorz1, + doorx2, doorz2, + 0); + } + } + } + + // + // Draw the room names. + // + + while(ID_editor_get_room(&ri)) + { + tx=(((((ri.x<>1); + tz=(((((ri.z<>1); + AddHeightOffset(&tx,&tz); + + QuickTextC(tx, tz, ri.what, WHITE_COL); + } + + while(ID_editor_get_stair(&si)) + { + dx = si.x2 - si.x1; + dz = si.z2 - si.z1; + + #define NUM_DRAW_STEPS 8 + + for (i = 0; i < NUM_DRAW_STEPS; i++) + { + x1 = (si.x1 << ELE_SHIFT) + (1 << (ELE_SHIFT - 1)); + z1 = (si.z1 << ELE_SHIFT) + (1 << (ELE_SHIFT - 1)); + + x1 += i * dx * (256 / NUM_DRAW_STEPS); + z1 += i * dz * (256 / NUM_DRAW_STEPS); + + x2 = x1 + (dz * 128); + z2 = z1 - (dx * 128); + + DrawContentLine( + x1, z1, + x2, z2, + 0); + } + } + } +#endif + } + } + + if(roof_flag) + { + storey_index=storey_list[storey_list[storey_index].Prev].Next; + roof_flag=0; + } + else + { + /* + SLONG temp_index; + temp_index=storey_list[storey_index].Roof; + if(temp_index) + { + storey_index=temp_index; + roof_flag=1; + + } + else + */ + { + storey_index=storey_list[storey_index].Next; + roof_flag=0; + } + + } + if(Texture==2&&drawn_normal) + storey_index=0; + } + } + + + // + // Draw the edge of the map... + // + + CurrentY = 0; + + #define EDGE_COLOUR RED_COL + + for (SLONG i = 0; i < 128; i++) + { + DrawContentLine(i << 8, 0 << 8, i - 1 << 8, -1 << 8, EDGE_COLOUR); + DrawContentLine(i << 8, 128 << 8, i + 1 << 8, 129 << 8, EDGE_COLOUR); + + DrawContentLine( 0 << 8, i << 8, -1 << 8, i - 1 << 8, EDGE_COLOUR); + DrawContentLine(128 << 8, i << 8, 129 << 8, i + 1 << 8, EDGE_COLOUR); + } + + +/* + if(FloorHead) + { + index=FloorHead; + px=storey_list[index].DX; + pz=storey_list[index].DZ; + CurrentY=0; + index=storey_list[index].WallHead; + + while(index) + { + x1=wall_list[index].DX; + z1=wall_list[index].DZ; + + DrawContentLine(px,pz,x1,z1,GetHeightColour()); + px=x1; + pz=z1; + index=wall_list[index].Next; + } + if(Mode==BUILD_MODE_CONT_STOREY) + DrawContentLine(px,pz,fx,fz,GetHeightColour()); + + } +*/ + + + + if (!Keys[KB_T]) + { + HighlightVertexes(x,y,w,h); + } + +// if(0) + if(EditStorey&&storey_list[EditStorey].StoreyType==STOREY_TYPE_ROOF) + { + DrawRoofFaces(EditStorey,storey_list[EditStorey].Prev); + } + +// if(FloorHead) +// DrawFloorFaces(FloorHead); + +/* + { + + CBYTE str[100]; + sprintf(str," build %d storey %d wall %d edity %d",EditBuilding,EditStorey,EditWall,EditY); + QuickTextC(20,20,str,0); + } + switch(Mode) + { + break; + } +*/ + + + sprintf(str," Building: %d Storey %d (%s) wall %d xyz (%d,%d,%d) height %d sty1 %d sty2 %d",EditBuilding,EditStorey,storey_name[storey_list[EditStorey].StoreyType],EditWall,wall_list[EditWall].DX>>8,storey_list[EditStorey].DY,wall_list[EditWall].DZ>>8,storey_list[EditStorey].Height,wall_list[EditWall].TextureStyle,wall_list[EditWall].TextureStyle2); + + draw_status_line(0,h-14,w,14,str); + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + // + // Create a warning if the storey can't have an inside. + // + + if (inside_failure) + { + QuickTextC(3, 40, "CANNOT GENERATE AN INSIDE FOR THE STOREY: YOU WON'T BE ABLE TO GO INTO THE BUILDING.", RED_COL); + QuickTextC(4, 41, "CANNOT GENERATE AN INSIDE FOR THE STOREY: YOU WON'T BE ABLE TO GO INTO THE BUILDING.", WHITE_COL); + } +} + +//--------------------------------------------------------------- + + +void BuildTab::HandleTab(MFPoint *current_point) +{ + SLONG update = 0; + + + ModeTab::HandleTab(current_point); + KeyboardInterface(); + +} + +inline SLONG is_point_in_box(SLONG x,SLONG y,SLONG left,SLONG top,SLONG w,SLONG h) +{ + if(x>left&&xtop&&y3) + AxisMode=0; + switch(AxisMode) + { + case 0: +// SetControlState(CTRL_BUILD_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_BUILD_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_BUILD_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=X_AXIS; + break; + case 1: +// SetControlState(CTRL_BUILD_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_BUILD_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_BUILD_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=Y_AXIS; + break; + case 2: +// SetControlState(CTRL_BUILD_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_BUILD_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_BUILD_Z_AXIS_FREE,CTRL_SELECTED); + Axis=Z_AXIS; + break; + case 3: +// SetControlState(CTRL_BUILD_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_BUILD_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_BUILD_Z_AXIS_FREE,CTRL_SELECTED); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + break; + } + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); + } + + if (Keys[KB_U]) {Keys[KB_U] = 0; HandleControl(CTRL_NEXT_STOREY);} + if (Keys[KB_D]) {Keys[KB_D] = 0; HandleControl(CTRL_PREV_STOREY);} + + if (Keys[KB_M] || + Keys[KB_P]) + { + // + // Where is the mouse in the world? + // + + SLONG x; + SLONG y; + SLONG w; + SLONG h; + + SLONG mx; + SLONG my; + SLONG mz; + + MFPoint mouse_point; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + Parent->GlobalToLocal(&mouse_point); + + x = Parent->ContentLeft(); + y = Parent->ContentTop(); + w = Parent->ContentWidth(); + h = Parent->ContentHeight(); + + CalcMapCoord( + &mx, + &my, + &mz, + x,y,w,h, + &mouse_point); + + if (Keys[KB_M]) {Keys[KB_M] = 0; EXTRA_create_or_delete(EXTRA_TYPE_MIST, mx, mz);} + if (Keys[KB_P]) {Keys[KB_P] = 0; EXTRA_create_or_delete(EXTRA_TYPE_PUDDLE, mx, mz);} + + RequestUpdate(); + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); + } + + return(0); +} + +//#define QDIST3(x,y,z) (x>y ? (x>z ? x+(y>>2)+(z>>2) : z+(x>>2)+(y>>2)) : (y>z ? (y+(x>>2)+(z>>2) : z+(x>>2)+(y>>2) )) +//#define QDIST3(x,y,z) (x>y ? (x>z ? x+(y>>2)+(z>>2) : z+(x>>2)+(y>>2)) : (y>z ? (y+(x>>2)+(z>>2) : z+(x>>2)+(y>>2) )) + + + +SLONG BuildTab::DragEngine(UBYTE flags,MFPoint *clicked_point) +{ + SLONG wwx,wwy,www,wwh; + SLONG screen_change=0; + SLONG last_world_mouse; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + + { + SLONG start_x=0,start_y=0,start_z=0,flag=0; + SLONG old_x,old_y,old_z; + SLONG nx,ny,nz; + + old_x=nx=engine.X; + old_y=ny=engine.Y; + old_z=nz=engine.Z; + + while(SHELL_ACTIVE && MiddleButton) + { + last_world_mouse=SetWorldMouse(0); + if(last_world_mouse) + { + if(!flag) + { + flag=1; + start_x=engine.MousePosX<<8; + start_y=engine.MousePosY<<8; + start_z=engine.MousePosZ<<8; + } + + nx=engine.MousePosX<<8; + ny=engine.MousePosY<<8; + nz=engine.MousePosZ<<8; + + engine.X = (old_x+(-nx+start_x)); + engine.Y = (old_y+(-ny+start_y)); + engine.Z = (old_z+(-nz+start_z)); + +// engine.Z=nz<<8; + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + engine.X=old_x; + engine.Y=old_y; + engine.Z=old_z; + + } + } + if(flag) + { + engine.X= (old_x+(-nx+start_x)); + engine.Y= (old_y+(-ny+start_y)); + engine.Z= (old_z+(-nz+start_z)); + } + } + return(screen_change); + +} + +SLONG BuildTab::CalcMapCoord(SLONG *mapx,SLONG *mapy,SLONG *mapz,SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *clicked_point) +{ + SLONG width,count_across,count_high; + SLONG mx,my,mz; + SLONG dx,dy,dz; +/* + my=(engine.Y>>8)>>ELE_SHIFT; + mx=(engine.X>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + width=((16<<5)*engine.Scale)>>16; + LogText(" w %d h %d click xy %d,%d width %d res x %d res y %d \n",w,h,clicked_point->X,clicked_point->Y,width,(clicked_point->X-(w>>1))/(width+1),(clicked_point->Y-(h>>1))/(width+1)); + + dx=(clicked_point->X-(w>>1)); + dy=(clicked_point->Y-(h>>1)); + + if(dx>0) + *mapx=dx/(width+1)+mx; + else + *mapx=((dx)/(width+1))+mx-1; + + + if(dy>0) + *mapz=dy/(width+1)+mz; + else + *mapz=((dy)/(width+1))+mz-1; + + *mapy=my; +*/ + + mx=(ViewX>>(ELE_SHIFT)); + my=(ViewY>>(ELE_SHIFT)); + mz=(ViewZ>>(ELE_SHIFT)); + + + dx=(clicked_point->X-(w>>1)); + dz=(clicked_point->Y-(h>>1)); + if(dx<0) + dx=((dx-(ViewSize>>1))<>1))<>1))<>1))<ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + SetWorkWindowBounds(x,y,w-1,h-1); + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + + } + return(0); + +} + +SLONG BuildTab::DragPaint(UBYTE flags) +{ +/* + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + SLONG col; + SLONG screen_change=0; + MFPoint mouse_point; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + SetWorkWindowBounds(x,y,w-1,h-1); + + while(SHELL_ACTIVE && LeftButton) + { + SLONG mx,my,mz,index; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + + index=edit_map[(mx)][(my)].Depth[(mz)]; + if(!index) + insert_cube(mx,my,mz); + + + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; +// editor_user_interface(); +// KeyboardInterface(); + } + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(screen_change); +*/ + return(0); + +} + +SLONG BuildTab::DragMark(UBYTE flags) +{ + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + SLONG col = 0; + SLONG screen_change=0; + SLONG mx,my,mz,index; + + MFPoint mouse_point; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + SetWorkWindowBounds(x,y,w-1,h-1); + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + X1=mx; + Y1=my; + Z1=mz; + + while(SHELL_ACTIVE && LeftButton) + { + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + X2=mx; + Y2=my; + Z2=mz; + + + + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + } + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); + +} + +void move_insides(SLONG inside,SLONG dx,SLONG dy,SLONG dz) +{ + SLONG c0; + for(c0=0;c0EditStorey==storey) + the_build->EditStorey=new_storey; + + + if(first_storey==0) + first_storey=new_storey; + + wall=storey_list[storey].WallHead; + prev_wall=0; + while(wall) + { + new_wall=get_new_wall(); + wall_list[new_wall]=wall_list[wall]; + if(the_build->EditWall==wall) + the_build->EditWall=new_wall; + + if(prev_wall) + wall_list[prev_wall].Next=new_wall; + else + storey_list[new_storey].WallHead=new_wall; + + wall_list[new_wall].StoreyHead=new_storey; + + prev_wall=new_wall; + wall=wall_list[wall].Next; + } + storey_list[new_storey].Prev=prev_storey; + storey_list[prev_storey].Next=new_storey; + +/* + if(storey_list[storey].Roof) + { + SLONG new_roof; + new_roof=duplicate_storey_list(storey_list[storey].Roof,bh); + storey_list[new_storey].Roof=new_roof; + storey_list[new_roof].Prev=new_storey; + + } + */ + prev_storey=new_storey; + storey=storey_list[storey].Next; + } + return(first_storey); +} + +SLONG duplicate_building(SLONG building) +{ + SLONG storey,wall; + SLONG new_building,new_storey; + + new_building=get_new_building(); + building_list[new_building]=building_list[building]; + storey=building_list[building].StoreyHead; + + building_list[new_building].StoreyHead=duplicate_storey_list(storey,new_building); + return(new_building); + + +} + +SLONG BuildTab::DragBuilding(UBYTE flags,UBYTE type) +{ + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + SLONG col=0; + SLONG mx,my,mz,index; + + MFPoint mouse_point; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + SetWorkWindowBounds(x,y,w-1,h-1); + + LogText("before EditBuilding %d EditStorey %d EditWall %d \n",EditBuilding,EditStorey,EditWall); + + if(type==1) + EditBuilding=duplicate_building(EditBuilding); + + //LogText("after EditBuilding %d EditStorey %d EditWall %d \n",EditBuilding,EditStorey,EditWall); + + while(SHELL_ACTIVE && (flags==LEFT_CLICK&&LeftButton)||(flags==RIGHT_CLICK && RightButton)) + { + SLONG dx,dz; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + + + if(EditWall) + { +// LogText(" editwall %d pos (%d,%d) \n",EditWall,wall_list[EditWall].DX,wall_list[EditWall].DZ); + dx=mx-wall_list[EditWall].DX; + dz=mz-wall_list[EditWall].DZ; + } + else + { + dx=mx-storey_list[EditStorey].DX; + dz=mz-storey_list[EditStorey].DZ; + } + move_building(EditBuilding,dx,0,dz); + + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + } + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + if(mouse_point.Y>h) + return(0); + else + return(1); + +} + + +// +// moves all vertices above map co-ord map_x,map_z to mx,mz +// +void move_all_vertices(SLONG map_x,SLONG map_z,SLONG mx,SLONG mz) +{ + SLONG c0; + for(c0=1;c0ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + SetWorkWindowBounds(x,y,w-1,h-1); + +// LogText("before EditBuilding %d EditStorey %d EditWall %d \n",EditBuilding,EditStorey,EditWall); + + + //LogText("after EditBuilding %d EditStorey %d EditWall %d \n",EditBuilding,EditStorey,EditWall); + + while(SHELL_ACTIVE && (flags==LEFT_CLICK&&LeftButton)||(flags==RIGHT_CLICK && RightButton)) + { + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CurrentY=storey_list[EditStorey].DY; + + mouse_screen_y=mouse_point.Y; + + // + // This corrects the mouse offset problem + // + mouse_point.X+= ((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + mouse_point.Y+=-((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + + if(ShiftFlag) + { + SLONG dx,dz; + + if(EditWall) + { + // LogText(" editwall %d pos (%d,%d) \n",EditWall,wall_list[EditWall].DX,wall_list[EditWall].DZ); + dx=mx-wall_list[EditWall].DX; + dz=mz-wall_list[EditWall].DZ; + } + else + { + dx=mx-storey_list[EditStorey].DX; + dz=mz-storey_list[EditStorey].DZ; + } + move_building(EditBuilding,dx,0,dz); + + + } + else + if(Keys[KB_A]) + { + SLONG map_x,map_z; + + if(EditWall) + { + map_x=wall_list[EditWall].DX; + map_z=wall_list[EditWall].DZ; + } + else + { + map_x=storey_list[EditStorey].DX; + map_z=storey_list[EditStorey].DZ; + } + move_all_vertices(map_x,map_z,mx,mz); + + } + else + { + if(EditWall) + { + wall_list[EditWall].DX=mx; + wall_list[EditWall].DZ=mz; + } + else + { + storey_list[EditStorey].DX=mx; + storey_list[EditStorey].DZ=mz; + } + } + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + } + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + if(mouse_screen_y>h) + return(0); + else + return(1); + +} + +SLONG find_previous_wall(SLONG edit_storey,SLONG wall) +{ + SLONG index; + SLONG prev=0; + index=storey_list[edit_storey].WallHead; + while(index) + { + if(index==wall) + return(prev); + + prev=index; + index=wall_list[index].Next; + } + return(-1); +} + +void BuildTab::DeleteVertex(void) +{ + SLONG prev; + if(EditWall) + { + prev=find_previous_wall(EditStorey,EditWall); + if(prev>0) + { + wall_list[prev].Next=wall_list[EditWall].Next; + free_wall(EditWall); + EditWall=0; + } + else + { //prev is a storeyhead + storey_list[EditStorey].WallHead=wall_list[EditWall].Next; + free_wall(EditWall); + EditWall=0; + } + } + else + { + SLONG next; + next=storey_list[EditStorey].WallHead; + if(next) + { + storey_list[EditStorey].DX=wall_list[next].DX; + storey_list[EditStorey].DZ=wall_list[next].DZ; + storey_list[EditStorey].WallHead=wall_list[next].Next; + free_wall(next); + } + + } +} + + + +SLONG BuildTab::ClickNearWall(SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *mouse_point) +{ + SLONG mx,mz,rect_size; + EdRect rect; + SLONG best_building,best_storey=0,best_wall=0,best_dist=0x7fffffff,dist; + SLONG roof_flag=0,building; + + mx=ViewX>>ELE_SHIFT; + mz=ViewZ>>ELE_SHIFT; + + rect_size=ViewSize>>2; + + for(building=0;building>ELE_SHIFT)-mx)*ViewSize+(w>>1); + // z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(w>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + AddHeightOffset(&x1,&z1); + if(index) + { + px=x1; + pz=z1; + + + while(index) + { + x1=wall_list[index].DX; + z1=wall_list[index].DZ; + + // x1=((x1>>ELE_SHIFT)-mx)*ViewSize+(w>>1); + // z1=((z1>>ELE_SHIFT)-mz)*ViewSize+(h>>1); + x1=((((x1)-(ViewX))*ViewSize)/ELE_SIZE)+(w>>1); + z1=((((z1)-(ViewZ))*ViewSize)/ELE_SIZE)+(h>>1); + AddHeightOffset(&x1,&z1); + + // dist=dist_between_vertex_and_vector(px,pz,x1,z1,mouse_point->X,mouse_point->Y); + dist=dist_to_line(px,pz,x1,z1,mouse_point->X,mouse_point->Y); + if(distGlobalToLocal(&local_point); + + popup_def.ControlLeft = local_point.X+4; + popup_def.ControlTop = local_point.Y-4; + + flags=0; //wall_list[EditWall].WallFlags; + + old_flags=flags; + wall_popup[7].ItemFlags = 0; + for(c0=0;c0<7;c0++) + { + wall_popup[c0].ItemFlags = 0; + wall_popup[c0].MutualExclusiveID=0; + if(flags&(1<TrackControl(&local_point); +// while(RightButton&&SHELL_ACTIVE); + + + flags = 0; + +// wall_list[EditWall].WindowCount=0; + + if(wall_popup[0].ItemFlags&MENU_CHECK_MASK) + wall_list[EditWall].WallFlags|=FLAG_WALL_AUTO_WINDOWS; + else + wall_list[EditWall].WallFlags&=~FLAG_WALL_AUTO_WINDOWS; + + if(wall_popup[1].ItemFlags&MENU_CHECK_MASK) + wall_list[EditWall].WallFlags|=FLAG_WALL_FENCE_POST1; + else + wall_list[EditWall].WallFlags&=~FLAG_WALL_FENCE_POST1; + + if(wall_popup[3].ItemFlags&MENU_CHECK_MASK) + wall_list[EditWall].WallFlags|=FLAG_WALL_RECESSED; + else + wall_list[EditWall].WallFlags&=~FLAG_WALL_RECESSED; + +// if(wall_popup[2].ItemFlags&MENU_CHECK_MASK) +// wall_list[EditWall].WallFlags|=FLAG_WALL_FENCE_POST2; +// else +// wall_list[EditWall].WallFlags&=~FLAG_WALL_FENCE_POST2; + + if(wall_popup[2].ItemFlags&MENU_CHECK_MASK) + storey_list[wall_list[EditWall].StoreyHead].StoreyFlags|=FLAG_STOREY_ROOF_RIM2; + else + storey_list[wall_list[EditWall].StoreyHead].StoreyFlags&=~FLAG_STOREY_ROOF_RIM2; + + + if(wall_popup[4].ItemFlags&MENU_CHECK_MASK) + storey_list[wall_list[EditWall].StoreyHead].StoreyFlags|=FLAG_STOREY_ROOF_RIM; + else + storey_list[wall_list[EditWall].StoreyHead].StoreyFlags&=~FLAG_STOREY_ROOF_RIM; + + if(wall_popup[5].ItemFlags&MENU_CHECK_MASK) + wall_list[EditWall].WallFlags|=FLAG_WALL_CLIMBABLE; + else + wall_list[EditWall].WallFlags&=~FLAG_WALL_CLIMBABLE; + + if(wall_popup[6].ItemFlags&MENU_CHECK_MASK) + wall_list[EditWall].WallFlags|=FLAG_WALL_BARB_TOP; + else + wall_list[EditWall].WallFlags&=~FLAG_WALL_BARB_TOP; +/* + if(wall_popup[6].ItemFlags&MENU_CHECK_MASK) + wall_list[EditWall].WallFlags|=FLAG_WALL_ARCH_TOP; + else + wall_list[EditWall].WallFlags&=~FLAG_WALL_ARCH_TOP; +*/ + if(the_control) + { + delete the_control; + } + return(1); +} + +MenuDef2 roof_popup[] = +{ + { "~Flat Roof", 0 }, + { "~Overlap Small", 0 }, + { "~Overlap Medium", 0 }, + { "~Walled", 0 }, + { "~Reccesed", 0 }, + { "!", 0 } +}; + + + +SLONG BuildTab::RoofOptions(void) +{ + ULONG flags=0; + ULONG c0, + control_id; + CPopUp *the_control = 0; + MFPoint local_point; + + local_point.X = MouseX; + local_point.Y = MouseY; + + Parent->GlobalToLocal(&local_point); + + popup_def.ControlLeft = local_point.X+4; + popup_def.ControlTop = local_point.Y-4; + + + flags=storey_list[EditStorey].StoreyFlags; + roof_popup[5].ItemFlags = 0; + for(c0=0;c0<5;c0++) + { + roof_popup[c0].ItemFlags = 0; + roof_popup[c0].MutualExclusiveID=0; + if(flags&(1<<(c0+1))) + roof_popup[c0].ItemFlags |= MENU_CHECK_MASK; + else + roof_popup[c0].ItemFlags &= ~MENU_CHECK_MASK; + } + + + for(c0=1;c0<4;c0++) + { +// roof_popup[c0].MutualExclusiveID=1; + } + + popup_def.TheMenuDef = roof_popup; + the_control = new CPopUp(&popup_def); + control_id = the_control->TrackControl(&local_point); + flags = 0; + +// storey_list[EditStorey].StoreyFlags&=~0x1f; + for(c0=0;c0<5;c0++) + { + + if(roof_popup[c0].ItemFlags&MENU_CHECK_MASK) + storey_list[EditStorey].StoreyFlags|=1<<(c0+1); + else + storey_list[EditStorey].StoreyFlags&=~(1<<(c0+1)); + } + + + if(the_control) + { + delete the_control; + } + return(1); +} + + + +MenuDef2 fence_popup[] = +{ + {"~100% Angle topped fence"}, + {"~200% Barbed wire"}, + {"~100% Barbed wire"}, + {"~200% Chain fence"}, + {"~100% Chain fence"}, + {"~ 75% Chain fence"}, + {"~ 33% Chain fence"}, + + {"~100% Unclimbable fence"}, + {"~200% Unclimbable fence"}, + {"~300% Unclimbable fence"}, + + {"~200% Door 180 degree swivel"}, + {"~200% Door 90 degree swivel"}, + + {"!"} +}; + + + +SLONG BuildTab::FenceOptions(void) +{ + ULONG flags=0; + ULONG c0, + control_id; + CPopUp *the_control = 0; + MFPoint local_point; + CBYTE str[100]; + + local_point.X = MouseX; + local_point.Y = MouseY; + + Parent->GlobalToLocal(&local_point); + + popup_def.ControlLeft = local_point.X+4; + popup_def.ControlTop = local_point.Y-4; + + if (storey_list[EditStorey].ExtraFlags & FLAG_STOREY_EXTRA_UNCLIMBABLE) + { + // + // Might be a door because all doors are unclimbable. + // + + if (storey_list[EditStorey].StoreyType == STOREY_TYPE_OUTSIDE_DOOR) + { + if (storey_list[EditStorey].ExtraFlags & FLAG_STOREY_EXTRA_90DEGREE) + { + // + // 90 degree door. + // + + flags = 1 << 12; + } + else + { + // + // 180 degree door. + // + + flags = 1 << 11; + } + } + else + { + switch(storey_list[EditStorey].Height) + { + case 256: flags = 1 << 8; break; + case 512: flags = 1 << 9; break; + case 786: flags = 1 << 10; break; + } + } + } + else + { + switch(storey_list[EditStorey].StoreyType) + { + case STOREY_TYPE_FENCE: + flags=1<<1; + break; + case STOREY_TYPE_FENCE_BRICK: + + if (storey_list[EditStorey].Height == 256) + { + flags = 1 << 3; + } + else + { + flags = 1 << 2; + } + break; + case STOREY_TYPE_FENCE_FLAT: + sprintf(str,"HEIGHT %d \n",storey_list[EditStorey].Height); + QuickText(0,0,str,100); + QuickText(100,100,str,100); + QuickText(200,200,str,100); + + switch(storey_list[EditStorey].Height) + { + case(512): + flags=1<<4; + break; + case(256): + flags=1<<5; + break; + case(256-64): + flags=1<<6; + break; + case(256-128): + flags=1<<7; + break; + } + + break; + } + } + + fence_popup[6].ItemFlags = 0; + for(c0=0;c0<12;c0++) + { + fence_popup[c0].ItemFlags = 0; + fence_popup[c0].MutualExclusiveID=1; + if(flags&(1<<(c0+1))) + fence_popup[c0].ItemFlags |= MENU_CHECK_MASK; + else + fence_popup[c0].ItemFlags &= ~MENU_CHECK_MASK; + } + + popup_def.TheMenuDef = fence_popup; + the_control = new CPopUp(&popup_def); + control_id = the_control->TrackControl(&local_point); + flags = 0; + +// storey_list[EditStorey].StoreyFlags&=~0x1f; + + for(c0=0;c0<12;c0++) + { + + if(fence_popup[c0].ItemFlags&MENU_CHECK_MASK) + { + switch(c0) + { + case 0: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_UNCLIMBABLE; + storey_list[EditStorey].Height = 256; + break; + + case 1: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_BRICK; + storey_list[EditStorey].Height = 512; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + + case 2: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_BRICK; + storey_list[EditStorey].Height = 256; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + + case 3: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].Height = 512; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + case 4: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].Height = 256; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + case 5: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].Height = 256-64; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + case 6: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].Height = 128; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + + case 7: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].Height = 256; + storey_list[EditStorey].ExtraFlags |= FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + case 8: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].Height = 512; + storey_list[EditStorey].ExtraFlags |= FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + case 9: + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].Height = 768; + storey_list[EditStorey].ExtraFlags |= FLAG_STOREY_EXTRA_UNCLIMBABLE; + break; + + case 10: + storey_list[EditStorey].StoreyType = STOREY_TYPE_OUTSIDE_DOOR; + storey_list[EditStorey].Height = 512; + storey_list[EditStorey].ExtraFlags |= FLAG_STOREY_EXTRA_UNCLIMBABLE; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_90DEGREE; + break; + + case 11: + storey_list[EditStorey].StoreyType = STOREY_TYPE_OUTSIDE_DOOR; + storey_list[EditStorey].Height = 512; + storey_list[EditStorey].ExtraFlags |= FLAG_STOREY_EXTRA_UNCLIMBABLE; + storey_list[EditStorey].ExtraFlags |= FLAG_STOREY_EXTRA_90DEGREE; + break; + } + + break; + } +/* + storey_list[EditStorey].StoreyFlags|=1<<(c0+1); + else + storey_list[EditStorey].StoreyFlags&=~(1<<(c0+1)); +*/ + } + + + if(the_control) + { + delete the_control; + } + return(1); +} + + +SLONG count_wall_size(UWORD storey) +{ + SLONG count,index; + index=storey_list[storey].WallHead; + count=0; + + while(index&&count<1000) + { + count++; + index=wall_list[index].Next; +// if(count<10) +// LogText(" size count %d index %d \n",count,index); + } + return(count); + +} + +SLONG find_n_from_end(SLONG n,UWORD storey) +{ + SLONG count,index; + + count=count_wall_size(storey); +// LogText(" find n %d from end count %d \n",n,count); + + count=count-n; + if(count<0) + return(-1); + + index=storey_list[storey].WallHead; + count--; + if(count<0) + return(0); + while(index&&count) + { + count--; + index=wall_list[index].Next; +// LogText(" find count %d index %d \n",count,index); + } + return(index); + + +} + +void show_storey(UWORD index) +{ + SLONG count=0; + LogText("[%d,%d] ->",storey_list[index].DX,storey_list[index].DZ); + index=storey_list[index].WallHead; + while(index&&count++<10) + { + LogText("%d(%d,%d) ->",index,wall_list[index].DX,wall_list[index].DZ); + index=wall_list[index].Next; + } + LogText("\n"); + +} + + +void flip_storey(UWORD storey) +{ + SLONG c0,index,end_index,end_index_next; + SLONG size,prev=0; + SLONG end_x,end_z; + SLONG new_storey; + + index=find_n_from_end(0,storey); + + end_x=storey_list[storey].DX; + end_z=storey_list[storey].DZ; + + new_storey=get_new_storey(); +// storey_list[new_storey].StoreyFlags|=1; + storey_list[new_storey]=storey_list[storey]; + storey_list[new_storey].WallHead=0; + + storey_list[new_storey].DX=wall_list[index].DX; + storey_list[new_storey].DZ=wall_list[index].DZ; + + size=count_wall_size(storey); +// LogText(" count wall size = %d \n",size); + + for(c0=0;c00) + { + switch(storey_list[EditStorey].StoreyType) + { + case STOREY_TYPE_FIRE_ESCAPE: + { + if(EditWall<0) + { + + EditWall=0; + storey_list[EditStorey].Height++; + return(1); + } + } + break; + case STOREY_TYPE_LADDER: + if(EditWall<0) + { + SLONG size=4; + if(ShiftFlag) + size=1; + + EditWall=0; + storey_list[EditStorey].Height+=size; + return(1); + } + break; + case STOREY_TYPE_STAIRCASE: + if(EditWall<0) + { + EditWall=0; + storey_list[EditStorey].Info1++; + return(1); + } + + break; + case STOREY_TYPE_CABLE: + if(EditWall==99999) + { + EditWall=0; + storey_list[EditStorey].DY+=64; + return(1); + } + else + if(EditWall<0) + { + wall_list[-EditWall].DY+=64; + return(1); + + } + break; + + } + + LogText(" dragging editwall %d\n",EditWall); + if(ShiftFlag) + { + DragBuilding(flags,0); + } + else + if(ControlFlag) + { + DragBuilding(flags,1); + } + else + if(DragVertex(flags)==0) + { + DeleteVertex(); + return(1); + } + } + else + { + return(1); + } + + } + //drag vertex + break; + case RIGHT_CLICK: + if(ret=ClickInVertex(x,y,w,h,clicked_point,flags)) + { + if(ret>0) + { + switch(storey_list[EditStorey].StoreyType) + { + case STOREY_TYPE_FIRE_ESCAPE: + { + if(EditWall<0) + { + + EditWall=0; + storey_list[EditStorey].Height--; + return(1); + } + } + break; + case STOREY_TYPE_LADDER: + if(EditWall<0) + { + SLONG size=4; + if(ShiftFlag) + size=1; + + EditWall=0; + storey_list[EditStorey].Height-=size; + return(1); + } + break; + + case STOREY_TYPE_STAIRCASE: + if(EditWall<0) + { + EditWall=0; + storey_list[EditStorey].Info1--; + return(1); + } + break; + case STOREY_TYPE_CABLE: + if(EditWall==99999) + { + EditWall=0; + storey_list[EditStorey].DY-=64; + return(1); + } + else + if(EditWall<0) + { + wall_list[-EditWall].DY-=64; + return(1); + + } + break; + + } + if(EditWall>0) + { + SLONG temp_next; + temp_next=wall_list[EditWall].Next; + index=get_new_wall(); + wall_list[index].StoreyHead=EditStorey; + wall_list[index].WallFlags=1; //|FLAG_WALL_AUTO_WINDOWS; + + wall_list[EditWall].Next=index; + + wall_list[index].DX=wall_list[EditWall].DX; + wall_list[index].DZ=wall_list[EditWall].DZ; + wall_list[index].Next=temp_next; + // wall_list[index].WindowCount=0; + EditWall=index; + if(DragVertex(flags)==0) + { + DeleteVertex(); + return(1); + } + } + else + { + //trying to drag one of the root + + } + } + else + { + return(1); + } + + } + else + { + if(ClickNearWall(x,y,w,h,clicked_point)) + { + SetWorkWindowBounds(x,y,w-1,h-1); + switch(storey_list[EditStorey].StoreyType) + { + case STOREY_TYPE_ROOF: + RoofOptions(); + break; + case STOREY_TYPE_NORMAL: + WallOptions(); + break; + case STOREY_TYPE_FENCE: + case STOREY_TYPE_FENCE_BRICK: + case STOREY_TYPE_FENCE_FLAT: + case STOREY_TYPE_OUTSIDE_DOOR: + FenceOptions(); + break; + default: + WallOptions(); + break; + } + return(1); + + } + } + //delete vertex + break; + } + break; + + case BUILD_MODE_PLACE_STOREY: + switch(flags) + { + case LEFT_CLICK: + // + // This corrects the mouse offset problem + // + CurrentY=storey_list[EditStorey].DY; + clicked_point->X+= ((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + clicked_point->Y+=-((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + storey_list[EditStorey].DX=mx; + // storey_list[EditStorey].DY=my; + storey_list[EditStorey].DZ=mz; + Mode=BUILD_MODE_CONT_STOREY; + return(1); + case RIGHT_CLICK: + Mode=BUILD_MODE_WAIT; + break; + } + break; + + case BUILD_MODE_CONT_STOREY: + switch(flags) + { + case LEFT_CLICK: + // + // This corrects the mouse offset problem + // + CurrentY=storey_list[EditStorey].DY; + clicked_point->X+= ((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + clicked_point->Y+=-((-CurrentY)*(ViewSize+3))/(BLOCK_SIZE<<3); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + index=get_new_wall(); + wall_list[index].StoreyHead=EditStorey; + wall_list[index].WallFlags=1; //|FLAG_WALL_AUTO_WINDOWS; +// wall_list[index].WindowCount=0; + if(EditWall) + { + + wall_list[EditWall].Next=index; + } + else + { + storey_list[EditStorey].WallHead=index; + } + + EditWall=index; + + wall_list[EditWall].DX=mx; + if(EditStorey>0 && storey_list[EditStorey].StoreyType==STOREY_TYPE_CABLE) + { + wall_list[EditWall].DY=storey_list[EditStorey].DY; + wall_list[EditWall].TextureStyle2=4; + + } + + wall_list[EditWall].DZ=mz; + wall_list[EditWall].Next=0; + if(storey_list[EditStorey].StoreyType==STOREY_TYPE_LADDER) + { + Mode=BUILD_MODE_WAIT; + } + + break; + case RIGHT_CLICK: + Mode=BUILD_MODE_WAIT; + CheckStoreyIntegrity(EditStorey); + switch(storey_list[EditStorey].StoreyType) + { + case STOREY_TYPE_FIRE_ESCAPE: + + break; + } + + + return(1); + } + break; + } + return(0); + +} + +UWORD BuildTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + MFPoint local_point; + + + // This is a fudge to update the front screen buffer. + ShowWorkScreen(0); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + { + current_control = GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + control_id = current_control->TrackControl(&local_point); + HandleControl(control_id); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + return control_id; + } + current_control = current_control->GetNextControl(); + } + } + + break; + case RIGHT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + break; + } + return 0; +} + +//--------------------------------------------------------------- + +SLONG BuildTab::DoZoom(void) +{ + SLONG update=0; + if(Keys[KB_I]) + { + ViewSize++; + if(ViewSize>100) + ViewSize=100; + update=2; + } + + if(Keys[KB_O]) + { + ViewSize--; + if(ViewSize<3) + ViewSize=3; + update=2; + } + return(update); + +} + +SLONG BuildTab::DoKeys(void) +{ + SLONG update=0; + SLONG scroll_step; + + scroll_step=110/(ViewSize+39); + if(scroll_step<1) + scroll_step=1; + + scroll_step<<=ELE_SHIFT; + + + update=DoZoom(); + if(Keys[KB_LEFT]) + { + ViewX-=scroll_step; + update=2; + } + if(Keys[KB_RIGHT]) + { + ViewX+=scroll_step; + update=2; + } + if(!ShiftFlag) + { + + if(Keys[KB_UP]) + { + ViewZ-=scroll_step; + update=2; + } + if(Keys[KB_DOWN]) + { + ViewZ+=scroll_step; + update=2; + } + } + else + { + if(Keys[KB_UP]) + { + if(storey_list[EditStorey].Next) + { + Keys[KB_UP]=0; + EditStorey=storey_list[EditStorey].Next; + EditY=0;//storey_list[EditStorey].DY; + + } + update=2; + } + if(Keys[KB_DOWN]) + { + if(storey_list[EditStorey].Prev) + { + Keys[KB_DOWN]=0; + EditStorey=storey_list[EditStorey].Prev; + EditY=0;//storey_list[EditStorey].DY; + } + update=2; + } + } + + return(update); + +} + +SLONG BuildTab::SetWorldMouse(ULONG flag) +{ + MFPoint mouse_point; + MFPoint local_point; + SVector point,out; + SLONG wwx,wwy,www,wwh; + SLONG temp; + + temp=engine.ClipFlag; + engine.ClipFlag=0; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + + local_point = mouse_point; + Parent->GlobalToLocal(&local_point); + if(is_point_in_box(local_point.X,local_point.Y,0,0,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()/2-3); + set_camera_plan(); + calc_world_pos_plan(local_point.X,local_point.Y); + if(flag) + engine.MousePosY=engine.Y>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + engine.ClipFlag=temp; + return(1); + } + else + { + + engine.ClipFlag=temp; + return(0); + } + +} + +void free_walls(SLONG wall) +{ + SLONG next; + while(wall) + { + next=wall_list[wall].Next; + wall_list[wall].Next=0; + wall_list[wall].WallFlags=0; + wall=next; + } +} + +// +// Returns the bounding box of the storey- The coordinates returned +// are the mapsquares not the bottom left of them. +// + +void get_storey_bbox( + SLONG storey, + SLONG *x1, + SLONG *z1, + SLONG *x2, + SLONG *z2) +{ + SLONG next; + SLONG wall; + + *x1 = storey_list[storey].DX; + *z1 = storey_list[storey].DZ; + *x2 = storey_list[storey].DX; + *z2 = storey_list[storey].DZ; + + for (wall = storey_list[storey].WallHead; wall; wall = next) + { + next = wall_list[wall].Next; + + if ((wall_list[wall].DX >> 8) < *x1) {*x1 = wall_list[wall].DX;} + if ((wall_list[wall].DZ >> 8) < *z1) {*z1 = wall_list[wall].DZ;} + if ((wall_list[wall].DX >> 8) > *x2) {*x2 = wall_list[wall].DX;} + if ((wall_list[wall].DZ >> 8) > *z2) {*z2 = wall_list[wall].DZ;} + } + + *x2 -= 1; + *z2 -= 1; +} + + + + +// the thing that points to this storey needs to remove its own link +void delete_storey_list(SWORD storey) +{ + while(storey) + { + if(storey_list[storey].WallHead) + { + free_walls(storey_list[storey].WallHead); + storey_list[storey].WallHead=0; + } +/* + if(storey_list[storey].Roof) + { + delete_storey_list(storey_list[storey].Roof); + storey_list[storey].Roof=0; + } + */ + + storey_list[storey].StoreyFlags=0; + storey=storey_list[storey].Next; + } +} + +void delete_building(UWORD building) +{ + SLONG storey,wall; + + storey=building_list[building].StoreyHead; + if(storey) + delete_storey_list(storey); + + building_list[building].StoreyHead=0; + building_list[building].BuildingFlags=0; + +} + +// +// Returns the OUTLINE_Outline of the given storey. Returns NULL if +// the storey is not circular. Non-circular storeys are not defined. +// + +OUTLINE_Outline *get_storey_outline(SLONG storey) +{ + OUTLINE_Outline *oo; + + SLONG wall; + SLONG x1; + SLONG z1; + SLONG x2; + SLONG z2; + + if (!is_storey_circular(storey)) + { + // + // Not circular stories don't have outlines. + // + + return NULL; + } + + oo = OUTLINE_create(128); + + x1 = storey_list[storey].DX >> 8; + z1 = storey_list[storey].DZ >> 8; + + wall = storey_list[storey].WallHead; + + while(wall) + { + x2 = wall_list[wall].DX >> 8; + z2 = wall_list[wall].DZ >> 8; + + OUTLINE_add_line(oo, x1, z1, x2, z2); + + x1 = x2; + z1 = z2; + + wall = wall_list[wall].Next; + } + + return oo; +} + +SLONG do_storeys_overlap(SLONG s1,SLONG s2) +{ + OUTLINE_Outline *oos; + OUTLINE_Outline *ool; + oos=get_storey_outline(s1); + if(oos==NULL) + return(0); + ool=get_storey_outline(s2); + if(ool==NULL) + return(0); + + + if (OUTLINE_overlap(oos, ool)) + { + return(1); + } + else + { + return(0); + } +} + +SLONG set_storey_height(SLONG building,SLONG storey ,SLONG height) +{ + SLONG link; + SLONG y,offset_dy; + + OUTLINE_Outline *oos; + OUTLINE_Outline *ool; + + if (storey == 0 || building == 0) + { + return(0); + } + + // + // Find the outline of this storey. + // + + oos = get_storey_outline(storey); + + if (oos) + { + offset_dy=height-storey_list[storey].Height; + y=storey_list[storey].DY; + link=building_list[building].StoreyHead; + + while(link) + { + if(storey_list[link].DY>y) + { + switch(storey_list[link].StoreyType) + { + default: + case STOREY_TYPE_NORMAL: + + ool = get_storey_outline(link); + + if (ool == NULL) + { + } + else + { + // + // If this storey overlaps the one whose height we have changed, then + // update the height of this storey. + // + + if (OUTLINE_overlap(oos, ool)) + { + storey_list[link].DY+=offset_dy; + ASSERT(storey_list[link].DY>=0); + } + + OUTLINE_free(ool); + } + break; + + break; + + case STOREY_TYPE_FENCE: + + // + // Does this storey overlap the storey whose fence has changed. + // + + { + SLONG x1; + SLONG z1; + SLONG x2; + SLONG z2; + SLONG wall; + + wall = storey_list[link].WallHead; + + x1 = storey_list[link].DX >> 8; + z1 = storey_list[link].DZ >> 8; + + while(wall) + { + x2 = wall_list[wall].DX >> 8; + z2 = wall_list[wall].DZ >> 8; + + if (OUTLINE_intersects( + oos, + x1, z1, + x2, z2)) + { + // + // The fence overlaps the storey whose height has changed. + // + + storey_list[link].DY+=offset_dy; + ASSERT(storey_list[link].DY>=0); + + break; + } + + x1 = x2; + z1 = z2; + + wall = wall_list[wall].Next; + } + } + + break; + } + } + + link=storey_list[link].Next; + } + + storey_list[storey].Height=height; + + OUTLINE_free(oos); + return(1); + } + return(0); +} + + + +void load_textures_from_map(CBYTE *name) +{ + UWORD temp_end_prim_point; + UWORD temp_end_prim_face4; + UWORD temp_end_prim_face3; + UWORD temp_end_prim_object; + + UWORD no_prim_point; + UWORD no_prim_face4; + UWORD no_prim_face3; + UWORD no_prim_object; + SLONG save_type=1; + UWORD temp[4]; + SLONG c0; + SLONG size=0; + struct TinyStrip + { + UWORD MapThingIndex; + // UWORD Depth[EDIT_MAP_DEPTH]; + UWORD ColVectHead; + // UWORD Dummy1; + UWORD Texture; + SWORD Bright; + }tinyfloor; + + + + MFFileHandle handle = FILE_OPEN_ERROR; + handle=FileOpen(name); + if(handle!=FILE_OPEN_ERROR) + { + SLONG dx,dz; + + LogText(" load map %s \n",name); + FileRead(handle,(UBYTE*)&save_type,4); + + if(save_type<=8) + { + for(dx=0;dxHandleAlert("Can't add next storey to current floor (roof/firescape?) ",NULL); + delete quit_alert; +//` RequestUpdate(); + } + else + { + + + UWORD storey; + storey=get_new_storey(); + if(storey) + { + storey_list[storey].BuildingHead=EditBuilding; + storey_list[storey].StoreyFlags=1; + storey_list[storey].Prev=EditStorey; + switch(control_id&0xff) + { + case CTRL_BUILD_NEXT_STOREY: + + storey_list[storey].StoreyType=STOREY_TYPE_NORMAL; + storey_list[storey].DY=storey_list[EditStorey].DY+storey_list[EditStorey].Height; +// EditY=storey_list[storey].DY; + break; + + case CTRL_ADD_TRENCH: + storey_list[storey].StoreyType=STOREY_TYPE_TRENCH; + storey_list[storey].DY=0; //storey_list[EditStorey].DY+BLOCK_SIZE*4; //BLOCK_SIZE*5; +// EditY=storey_list[storey].DY; + break; + } + if(building_list[EditBuilding].StoreyHead) + { + if(storey_list[EditStorey].Next) + { + SLONG next; + next=storey_list[EditStorey].Next; + storey_list[storey].Next=next; + storey_list[next].Prev=storey; + } + storey_list[EditStorey].Next=storey; + building_list[EditBuilding].StoreyCount++; + } + else + { + building_list[EditBuilding].StoreyHead=storey; + building_list[EditBuilding].StoreyCount=1; + } + EditStorey=storey; + storey_list[EditStorey].WallHead=0; +// storey_list[EditStorey].Roof=0; + storey_list[EditStorey].Height=BLOCK_SIZE*4; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + } + } + RequestUpdate(); + } + break; + case CTRL_LOAD_TEXTURES: + { + + FileRequester *fr; + CBYTE fname[100]; + fr=new FileRequester("data\\","*.map","Load A MAP","temp.map"); + if(fr->Draw()) + { + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + strcpy(edit_info.MapName,fr->FileName); + load_textures_from_map(fname); +// the_leveleditor->BuildMode->ResetBuildTab(); + + } + + delete fr; + } + RequestUpdate(); + + break; + + case CTRL_CUT_BUILDING: + if(EditBuilding) + { + building_block.Cut(EditBuilding); + } + break; + case CTRL_SCROLL_MAP_UP: + offset_buildings(0,0,-256); + RequestUpdate(); + + break; + case CTRL_SCROLL_MAP_DOWN: + offset_buildings(0,0,256); + RequestUpdate(); + break; + case CTRL_SCROLL_MAP_LEFT: + offset_buildings(-256,0,0); + RequestUpdate(); + break; + case CTRL_SCROLL_MAP_RIGHT: + offset_buildings(256,0,0); + RequestUpdate(); + break; + case CTRL_PASTE_BUILDING: + building_block.Paste(ViewX,ViewZ,0); + RequestUpdate(); + + break; + case CTRL_DEL_ALL: + { + SLONG res; + Alert *quit_alert; + + quit_alert = new Alert; + res=quit_alert->HandleAlert("Delete ALL BUILDINGS you crazy fucker? ",NULL); + delete quit_alert; + + + if(res==1) + delete_all(); + } + RequestUpdate(); + break; + + case CTRL_TOGGLE_FLAT_TILED_ROOF: + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding&&building_list[EditBuilding].StoreyHead) + { + if(EditStorey) + { + storey_list[EditStorey].StoreyFlags&=~(FLAG_STOREY_TILED_ROOF); + + if(storey_list[EditStorey].StoreyFlags&FLAG_STOREY_FLAT_TILED_ROOF) + storey_list[EditStorey].StoreyFlags&=~(FLAG_STOREY_FLAT_TILED_ROOF); + else + storey_list[EditStorey].StoreyFlags|=(FLAG_STOREY_FLAT_TILED_ROOF); + RequestUpdate(); + + } + } + break; + case CTRL_TOGGLE_TILED_ROOF: + + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding&&building_list[EditBuilding].StoreyHead) + { + if(EditStorey) + { + storey_list[EditStorey].StoreyFlags&=~(FLAG_STOREY_FLAT_TILED_ROOF); + + if(storey_list[EditStorey].StoreyFlags&FLAG_STOREY_TILED_ROOF) + storey_list[EditStorey].StoreyFlags&=~(FLAG_STOREY_TILED_ROOF); + else + storey_list[EditStorey].StoreyFlags|=(FLAG_STOREY_TILED_ROOF); + RequestUpdate(); + + } + } + break; + case CTRL_BUILD_DUPLICATE_STOREY: + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding&&EditStorey) + { + if(storey_list[EditStorey].StoreyType!=STOREY_TYPE_NORMAL) + { + + Alert *quit_alert; + quit_alert = new Alert; + quit_alert->HandleAlert("Can't Duplicate current storey (roof/firescape?) ",NULL); + delete quit_alert; + RequestUpdate(); +// update_modules(); + } + else + { + + SWORD storey,wall,index,prev=0; + SLONG storey_height; + + storey_height=storey_list[EditStorey].Height; + storey=get_new_storey(); + + if(storey) + { + + // + // first make a gap for the storey with a bodge call to set storey height (pretend current storey is twice as high) + // + if(set_storey_height(EditBuilding,EditStorey,storey_list[EditStorey].Height<<1)) + storey_list[EditStorey].Height>>=1; //then correct the height change + + LogText(" duplicate storey %d to storey %d prev %d\n",EditStorey,storey,prev); + //storey_list[storey].BuildingHead=EditBuilding; + //storey_list[storey].StoreyFlags=1; + storey_list[storey]=storey_list[EditStorey]; + if(storey_list[storey].InsideStorey) + { + storey_list[storey].InsideStorey=duplicate_storey_list(storey_list[storey].InsideStorey,EditBuilding); + storey_list[storey_list[storey].InsideStorey].DY=storey_list[EditStorey].DY+storey_height; + } + if(storey_list[storey].InsideIDIndex) + { + storey_list[storey].InsideIDIndex=copy_insides(storey_list[storey].InsideIDIndex); + } + + storey_list[storey].Prev=EditStorey; + storey_list[storey].DY=storey_list[EditStorey].DY+storey_height; +// EditY=storey_list[storey].DY; + index=storey_list[EditStorey].WallHead; + while(index) + { + wall=get_new_wall(); + LogText(" copy index %d to wall %d prev %d \n",index,wall,prev); + wall_list[wall]=wall_list[index]; + wall_list[wall].StoreyHead=storey; + if(prev) + wall_list[prev].Next=wall; + else + { + + storey_list[storey].WallHead=wall; + LogText(" set storey %d wallhead to %d \n",storey,wall); + } + prev=wall; + index=wall_list[index].Next; + } + LogText(" original wallhead %d copy wallhead=%d \n",storey_list[EditStorey].WallHead,storey_list[storey].WallHead); + if(storey_list[EditStorey].Next) + { + SLONG next; + next=storey_list[EditStorey].Next; + storey_list[storey].Next=next; + storey_list[next].Prev=storey; + } + else + storey_list[storey].Next=0; + + + + + storey_list[EditStorey].Next=storey; + building_list[EditBuilding].StoreyCount++; +// storey_list[storey].Roof=0; + EditStorey=storey; + + + +/* + storey=building_list[EditBuilding].StoreyHead; + while(storey) + { + + switch(storey_list[storey].StoreyType) + { + case STOREY_TYPE_NORMAL: + case STOREY_TYPE_LADDER: + case STOREY_TYPE_FENCE: + if(storey_list[storey].DY>=storey_list[EditStorey].DY) + { + + storey_list[storey].DY+=storey_height; + } + break; + } + storey=storey_list[storey].Next; + } +*/ + + EditWall=0; + RequestUpdate(); + } + } + + } + break; + case CTRL_ADD_FIRE_ESCAPE: + + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding) + { + SLONG storey; + storey=get_new_storey(); + if(storey) + { + storey_list[storey].BuildingHead=EditBuilding; + storey_list[storey].StoreyFlags=1; + storey_list[storey].Prev=EditStorey; + storey_list[storey].StoreyType=STOREY_TYPE_FIRE_ESCAPE; + storey_list[storey].DY=0; //storey_list[EditStorey].DY-BLOCK_SIZE*5; +// EditY=storey_list[storey].DY; + if(building_list[EditBuilding].StoreyHead) + { + storey_list[storey].Next=building_list[EditBuilding].StoreyHead; + storey_list[storey_list[storey].Next].Prev=storey; +// storey_list[EditStorey].Next=storey; + building_list[EditBuilding].StoreyHead=storey; + } + else + { + building_list[EditBuilding].StoreyHead=storey; + } + EditStorey=storey; + storey_list[EditStorey].WallHead=0; +// storey_list[EditStorey].Roof=0; + storey_list[EditStorey].Height=4; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + RequestUpdate(); + } + } + break; + case CTRL_ADD_POKEY: + if(Mode==BUILD_MODE_WAIT) + if(EditStorey&&storey_list[EditStorey].StoreyType==STOREY_TYPE_NORMAL) + { + storey_list[EditStorey].StoreyFlags|=FLAG_STOREY_LEDGE; + } + + break; + case CTRL_ADD_LADDER: + + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding) + { + SLONG storey; + storey=get_new_storey(); + if(storey&&EditStorey&&EditBuilding) + { + storey_list[storey].BuildingHead=EditBuilding; + storey_list[storey].StoreyFlags=1; + storey_list[storey].Prev=EditStorey; + storey_list[storey].StoreyType=STOREY_TYPE_LADDER; + if(EditStorey) + storey_list[storey].DY=storey_list[EditStorey].DY; + else + storey_list[storey].DY=0; +// EditY=storey_list[storey].DY; + if(building_list[EditBuilding].StoreyHead) + { + if(storey_list[EditStorey].Next) + { + SLONG next; + next=storey_list[EditStorey].Next; + storey_list[storey].Next=next; + storey_list[next].Prev=storey; + } + storey_list[EditStorey].Next=storey; + building_list[EditBuilding].StoreyCount++; + +// storey_list[storey].Next=building_list[EditBuilding].StoreyHead; +// storey_list[storey_list[storey].Next].Prev=storey; +// storey_list[EditStorey].Next=storey; +// building_list[EditBuilding].StoreyHead=storey; + } + else + { + building_list[EditBuilding].StoreyHead=storey; + building_list[EditBuilding].StoreyCount=0; + } + EditStorey=storey; + storey_list[EditStorey].WallHead=0; +// storey_list[EditStorey].Roof=0; + storey_list[EditStorey].Height=4; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + RequestUpdate(); + } + } + break; + + case CTRL_ADD_STAIRCASE: + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding) + { + + + SLONG storey; + storey=get_new_storey(); + if(storey) + { + storey_list[storey].BuildingHead=EditBuilding; + storey_list[storey].StoreyFlags=1; + storey_list[storey].Prev=EditStorey; + storey_list[storey].StoreyType=STOREY_TYPE_STAIRCASE; + storey_list[storey].DY=0; //storey_list[EditStorey].DY-BLOCK_SIZE*5; +// EditY=storey_list[storey].DY; + if(building_list[EditBuilding].StoreyHead) + { + storey_list[storey].Next=building_list[EditBuilding].StoreyHead; + storey_list[storey_list[storey].Next].Prev=storey; +// storey_list[EditStorey].Next=storey; + building_list[EditBuilding].StoreyHead=storey; + } + else + { + building_list[EditBuilding].StoreyHead=storey; + } + EditStorey=storey; + storey_list[EditStorey].WallHead=0; +// storey_list[EditStorey].Roof=0; + storey_list[EditStorey].Height=4; + storey_list[EditStorey].Info1=0; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + RequestUpdate(); + } + } + break; + case CTRL_ADD_CABLE: + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding) + { + + + UWORD storey; + storey=get_new_storey(); + if(storey) + { + storey_list[storey].BuildingHead=EditBuilding; + storey_list[storey].StoreyFlags=1; +// storey_list[storey].Prev=EditStorey; + storey_list[storey].StoreyType=STOREY_TYPE_CABLE; + storey_list[storey].DY=storey_list[EditStorey].DY+BLOCK_SIZE*4; +// EditY=storey_list[storey].DY; + if(building_list[EditBuilding].StoreyHead) + { + storey_list[storey].Next=building_list[EditBuilding].StoreyHead; + storey_list[storey_list[storey].Next].Prev=storey; +// storey_list[EditStorey].Next=storey; + building_list[EditBuilding].StoreyHead=storey; + } + else + { + building_list[EditBuilding].StoreyHead=storey; + } + EditStorey=storey; + storey_list[EditStorey].WallHead=0; +// storey_list[EditStorey].Roof=0; + storey_list[EditStorey].Height=4; + storey_list[EditStorey].Info1=0; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + RequestUpdate(); + } + } + break; + case CTRL_ADD_SKYLIGHT: + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding) + { + if(storey_list[EditStorey].StoreyType!=STOREY_TYPE_NORMAL) + { + Alert *quit_alert; + + quit_alert = new Alert; + quit_alert->HandleAlert("Can't add SKYLIGHT storey to current floor (roof/firescape?) ",NULL); + delete quit_alert; +//` RequestUpdate(); + } + else + { + + + UWORD storey; + storey=get_new_storey(); + if(storey) + { + storey_list[storey].BuildingHead=EditBuilding; + storey_list[storey].StoreyFlags=1; + storey_list[storey].Prev=EditStorey; + storey_list[storey].StoreyType=STOREY_TYPE_SKYLIGHT; + storey_list[storey].DY=storey_list[EditStorey].DY+BLOCK_SIZE*4; //BLOCK_SIZE*5; +// EditY=storey_list[storey].DY; + if(building_list[EditBuilding].StoreyHead) + { + if(storey_list[EditStorey].Next) + { + SLONG next; + next=storey_list[EditStorey].Next; + storey_list[storey].Next=next; + storey_list[next].Prev=storey; + } + storey_list[EditStorey].Next=storey; + building_list[EditBuilding].StoreyCount++; + } + else + { + building_list[EditBuilding].StoreyHead=storey; + building_list[EditBuilding].StoreyCount=1; + } + EditStorey=storey; + storey_list[EditStorey].WallHead=0; +// storey_list[EditStorey].Roof=0; + storey_list[EditStorey].Height=BLOCK_SIZE*4; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + } + } + RequestUpdate(); + } + break; + + + case CTRL_ADD_FLAT_ROOF_QUAD: + if(Mode==BUILD_MODE_WAIT) + if(EditBuilding&&building_list[EditBuilding].StoreyHead) + { + + UWORD storey; + storey=get_new_storey(); + if(storey) + { + storey_list[storey].BuildingHead=EditBuilding; + storey_list[storey].StoreyFlags=1; + storey_list[storey].Prev=EditStorey; + storey_list[storey].StoreyType=STOREY_TYPE_ROOF_QUAD; + storey_list[storey].DY=storey_list[EditStorey].DY+4*BLOCK_SIZE+2; +// EditY=storey_list[storey].DY; + +// storey_list[EditStorey].Roof=storey; +// building_list[EditBuilding].StoreyCount++; + + EditStorey=storey; + storey_list[EditStorey].WallHead=0; + storey_list[EditStorey].Height=0; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + RequestUpdate(); + } + } + break; + case CTRL_DELETE_BUILDING: + if(Mode==BUILD_MODE_WAIT) + { + if(EditBuilding) + delete_building(EditBuilding); + EditBuilding=0; + EditStorey=0; + EditWall=0; + EditY=0; + RequestUpdate(); + } + break; + + case CTRL_ANOTHER_INSIDE_SEED: + + if (WITHIN(EditStorey, 1, MAX_STOREYS - 1)) + { + ASSERT(WITHIN(seed_inside_upto, 0, MAX_SEED_BACKUPS - 1)); + + seed_inside[seed_inside_upto] = building_list[EditBuilding].InsideSeed; + + seed_inside_upto += 1; + seed_inside_upto &= MAX_SEED_BACKUPS - 1; + + building_list[EditBuilding].InsideSeed = rand(); + + RequestUpdate(); + } + + break; + + case CTRL_PREV_INSIDE_SEED: + + if (WITHIN(EditStorey, 1, MAX_STOREYS - 1)) + { + seed_inside_upto -= 1; + seed_inside_upto &= MAX_SEED_BACKUPS - 1; + + ASSERT(WITHIN(seed_inside_upto, 0, MAX_SEED_BACKUPS - 1)); + + building_list[EditBuilding].InsideSeed = seed_inside[seed_inside_upto]; + + RequestUpdate(); + } + + break; + + case CTRL_ANOTHER_STAIRCASE_SEED: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + ASSERT(WITHIN(seed_stairs_upto, 0, MAX_SEED_BACKUPS - 1)); + + seed_stairs[seed_stairs_upto] = building_list[EditBuilding].StairSeed; + + seed_stairs_upto += 1; + seed_stairs_upto &= MAX_SEED_BACKUPS - 1; + + building_list[EditBuilding].StairSeed = rand(); + + RequestUpdate(); + } + + break; + + case CTRL_PREV_STAIRCASE_SEED: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + seed_stairs_upto -= 1; + seed_stairs_upto &= MAX_SEED_BACKUPS - 1; + + ASSERT(WITHIN(seed_stairs_upto, 0, MAX_SEED_BACKUPS - 1)); + + building_list[EditBuilding].StairSeed = seed_stairs[seed_stairs_upto]; + + RequestUpdate(); + } + + break; + + + case CTRL_NEXT_STOREY: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1) && + WITHIN(EditStorey, 1, MAX_STOREYS - 1)) + { + SLONG i_storey; + + i_storey = storey_list[EditStorey].Next; + + if (WITHIN(i_storey, 1, MAX_STOREYS - 1)) + { + EditStorey = i_storey; +// EditY = storey_list[i_storey].DY; + RequestUpdate(); + } + } + + break; + + + case CTRL_PREV_STOREY: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1) && + WITHIN(EditStorey, 1, MAX_STOREYS - 1)) + { + SLONG i_storey; + + i_storey = storey_list[EditStorey].Prev; + + if (WITHIN(i_storey, 1, MAX_STOREYS - 1)) + { + EditStorey = i_storey; +// EditY = storey_list[i_storey].DY; + RequestUpdate(); + } + } + + break; + + + case CTRL_BUILDING_TYPE_HOUSE: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + building_list[EditBuilding].BuildingType = BUILDING_TYPE_HOUSE; + RequestUpdate(); + } + + break; + + case CTRL_BUILDING_TYPE_WAREHOUSE: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + building_list[EditBuilding].BuildingType = BUILDING_TYPE_WAREHOUSE; + RequestUpdate(); + } + + break; + + case CTRL_BUILDING_TYPE_OFFICE: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + building_list[EditBuilding].BuildingType = BUILDING_TYPE_OFFICE; + RequestUpdate(); + } + + break; + + case CTRL_BUILDING_TYPE_APARTEMENT: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + building_list[EditBuilding].BuildingType = BUILDING_TYPE_APARTEMENT; + RequestUpdate(); + } + + break; + + case CTRL_BUILDING_TYPE_CRATE_IN: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + building_list[EditBuilding].BuildingType = BUILDING_TYPE_CRATE_IN; + RequestUpdate(); + } + + break; + + case CTRL_BUILDING_TYPE_CRATE_OUT: + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + building_list[EditBuilding].BuildingType = BUILDING_TYPE_CRATE_OUT; + RequestUpdate(); + } + + break; + + + case CTRL_SET_STOREY_TYPE_NORMAL: + + // + // Make the current storey a fence. + // + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + if (WITHIN(EditStorey, 1, MAX_STOREYS - 1)) + { + storey_list[EditStorey].StoreyType = STOREY_TYPE_NORMAL; + storey_list[EditStorey].ExtraFlags &= ~FLAG_STOREY_EXTRA_ONBUILDING; + } + } + + break; + + + case CTRL_SET_STOREY_TYPE_FENCE: + + // + // Make the current storey a fence. + // + + if (WITHIN(EditBuilding, 1, MAX_BUILDINGS - 1)) + { + if (WITHIN(EditStorey, 1, MAX_STOREYS - 1)) + { + storey_list[EditStorey].StoreyType = STOREY_TYPE_FENCE_FLAT; + storey_list[EditStorey].ExtraFlags |= FLAG_STOREY_EXTRA_ONBUILDING; + } + } + + break; + +/* + case CTRL_DEFINE_FLOOR_POINTS: + if(FloorHead) + { + SLONG index; + index=storey_list[FloorHead].WallHead; + while(index) + { + EditWall=index; + index=wall_list[index].Next; + } + EditStorey=FloorHead; + + Mode=BUILD_MODE_CONT_STOREY; + } + else + { + SLONG storey,wall; + storey=get_new_storey(); + if(storey) + { + FloorHead=storey; + storey_list[storey].StoreyFlags=1; + storey_list[storey].Prev=0; + storey_list[storey].StoreyType=STOREY_TYPE_FLOOR_POINTS; + storey_list[storey].DY=0; + EditY=0; + + EditStorey=storey; + storey_list[EditStorey].WallHead=0; + storey_list[EditStorey].Roof=0; + EditWall=0; + Mode=BUILD_MODE_PLACE_STOREY; + RequestUpdate(); + } + } + break; +*/ + } +} + diff --git a/fallen/Editor/Source/ColTab.cpp b/fallen/Editor/Source/ColTab.cpp new file mode 100644 index 0000000..a359101 --- /dev/null +++ b/fallen/Editor/Source/ColTab.cpp @@ -0,0 +1,1063 @@ +#include "Editor.hpp" + +#include "ColTab.hpp" +#include "engine.h" +//#include "collide.hpp" + +static counter; + +//#define ShowWorkWindow(x) {DrawLineC(0+(counter-1)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,0);DrawLineC(0+(counter++)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,255);DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); ShowWorkWindow(x);} + +//--------------------------------------------------------------- +//debug stuff +/* +void cross_work_window(void) +{ + DrawLineC(0,0,WorkWindowWidth-1,WorkWindowHeight-1,255); + DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); + +} +*/ +//--------------------------------------------------------------- + + +#define COL_MODE_WAIT 0 +#define COL_MODE_PLACE_PLANE 1 +#define COL_MODE_EDIT_PLANE 2 +#define COL_MODE_DRAG_PLANE 3 +#define COL_MODE_PLACE_BEZIER 4 + + +#define CTRL_COL_X_AXIS_FREE 1 +#define CTRL_COL_Y_AXIS_FREE 2 +#define CTRL_COL_Z_AXIS_FREE 3 +#define CTRL_COL_PLACE_PLANE 4 +#define CTRL_COL_PLACE_BEZIER 5 +#define CTRL_COL_RECALC 6 +#define CTRL_COL_CLEAR_COL 7 +#define CTRL_COL_CLIPPED_VIEW 8 + + +ControlDef col_tab_def[] = +{ + { CHECK_BOX, 0, "X Free", 120, 300-10, 0, 10 }, + { CHECK_BOX, 0, "Y Free", 120, 313-10, 0, 10 }, + { CHECK_BOX, 0, "Z Free", 120, 326-10, 0, 10 }, + { BUTTON, 0, "Place A Collision Z Plane" , 10, 10, 0, 0}, + { BUTTON, 0, "Place A Bezier Col Curve" , 10, 30, 0, 0}, + { BUTTON, 0, "Recalc Collision" , 10, 50, 0, 0}, + { BUTTON, 0, "CLEAR Collision" , 90, 200, 0, 0}, + { CHECK_BOX, 0, "Clipped View", 20, 300-10, 0, 10 }, + { 0 } +}; + + +ColTab *the_coltab; + +struct ColInfo col_info[MAX_COL_INFO]; +UWORD next_col_info=1; + +void redraw_col_tab(void); +//--------------------------------------------------------------- + +ColTab::ColTab(EditorModule *parent) +{ + Parent=parent; + + InitControlSet(col_tab_def); + AxisMode=3; + + SetControlState(CTRL_COL_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_COL_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_COL_Z_AXIS_FREE,CTRL_SELECTED); + + Axis=X_AXIS|Y_AXIS|Z_AXIS; + Mode=0; + col_info[0].Plane.Depth=320; + CurrentCol=0; + the_coltab=this; +} + +ColTab::~ColTab() +{ +} + +void ColTab::Clear(void) +{ +// clear_all_col_info(); +} + +void delete_col_info(SWORD index) +{ + SLONG c0; + for(c0=index;c0Plane.Depth,0); + } + else + for(c0=1;c0Type) + { + case COL_TYPE_BEZIER: + case COL_TYPE_PLANE: +// calc_collision_info(p_col); //->Plane.Left,p_col->Plane.Right,p_col->Plane.Top,p_col->Plane.Bottom,p_col->Plane.Depth,1); + break; + } + } +} + +void ColTab::DrawTabContent(void) +{ + EdRect content_rect; + + + content_rect = ContentRect; + content_rect.ShrinkRect(1,1); + content_rect.FillRect(CONTENT_COL); + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); +} + +void redraw_col_tab(void) +{ + + switch(the_coltab->Mode) + { + + + default: + + the_coltab->DrawTabContent(); + the_coltab->Parent->DrawContent(); + SetWorkWindowBounds(the_coltab->Parent->GetLeft(), + the_coltab->Parent->GetTop(), + the_coltab->Parent->GetWidth(), + the_coltab->Parent->GetHeight()); + break; + } + +} + +//--------------------------------------------------------------- +extern void hilight_col_info(void); + +void ColTab::DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG wwx,wwy,www,wwh; + EdRect drawrect; + + RedrawModuleContent=0; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + View1.SetRect(x,y,w-1,h/2-3); + View2.SetRect(x,y+h/2+4,w-1,h/2-4); + + SetWorkWindowBounds(x,y,w-1,h/2-3); + drawrect.SetRect(0,0,w-1,h/2-3); + + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + set_camera_plan(); + draw_editor_map(0); + render_view(1); +// hilight_map_things(MAP_THING_TYPE_COL); + hilight_col_info(); + + + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + drawrect.SetRect(0,0,w-1,h/2-4); + +// drawrect.FillRect(LOLITE_COL); + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + + set_camera_front(); + draw_editor_map(0); + render_view(1); +// hilight_map_things(MAP_THING_TYPE_COL); + hilight_col_info(); + + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT +} + +//--------------------------------------------------------------- + + +void ColTab::HandleTab(MFPoint *current_point) +{ + SLONG update = 0; + + + ModeTab::HandleTab(current_point); + KeyboardInterface(); + + if(CurrentCol&&(engine.ClipFlag&ENGINE_CLIPY_FLAG)) + { + struct ColInfo *p_col; + p_col=&col_info[CurrentCol]; + switch(p_col->Type) + { + case COL_TYPE_PLANE: + engine.ClipMinY=p_col->Plane.Top; + engine.ClipMaxY=p_col->Plane.Bottom; + break; + case COL_TYPE_BEZIER: + engine.ClipMinY=p_col->Bezier.Top; + engine.ClipMaxY=p_col->Bezier.Bottom; + break; + } + + engine.ClipFlag=ENGINE_CLIPY_FLAG; + } + +} + +inline SLONG is_point_in_box(SLONG x,SLONG y,SLONG left,SLONG top,SLONG w,SLONG h) +{ + if(x>left&&xtop&&y3) + AxisMode=0; + switch(AxisMode) + { + case 0: + SetControlState(CTRL_COL_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_COL_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_COL_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=X_AXIS; + break; + case 1: + SetControlState(CTRL_COL_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_COL_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_COL_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=Y_AXIS; + break; + case 2: + SetControlState(CTRL_COL_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_COL_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_COL_Z_AXIS_FREE,CTRL_SELECTED); + Axis=Z_AXIS; + break; + case 3: + SetControlState(CTRL_COL_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_COL_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_COL_Z_AXIS_FREE,CTRL_SELECTED); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + break; + } + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); + } + return(0); +} + + + +inline SLONG normalise_xyz(SLONG *x,SLONG *y,SLONG *z) +{ + SLONG dist; + + dist=(*x)*(*x)+(*y)*(*y)+(*z)*(*z); + dist=sqrl(dist); + + if(dist==0) + dist=1; + + *x=(*x<<8)/dist; + *y=(*y<<8)/dist; + *z=(*z<<8)/dist; + + return(dist); +} + +UWORD CreateColBezier(SLONG x,SLONG y,SLONG z) +{ + col_info[next_col_info].Type=COL_TYPE_BEZIER; + col_info[next_col_info].Bezier.X[0]=x; + col_info[next_col_info].Bezier.X[1]=x+100; + col_info[next_col_info].Bezier.X[2]=x+200; + col_info[next_col_info].Bezier.X[3]=x+300; + + col_info[next_col_info].Bezier.Z[0]=z; + col_info[next_col_info].Bezier.Z[1]=z; + col_info[next_col_info].Bezier.Z[2]=z; + col_info[next_col_info].Bezier.Z[3]=z; + + col_info[next_col_info].Bezier.Top=y-100; + col_info[next_col_info].Bezier.Bottom=y+100; + + next_col_info++; + return(next_col_info-1); +} + +UWORD CreateColPlane(SLONG x,SLONG y,SLONG z) +{ + col_info[next_col_info].Type=COL_TYPE_PLANE; + col_info[next_col_info].Plane.Left=x; + col_info[next_col_info].Plane.Right=x+300; + col_info[next_col_info].Plane.Top=y; + col_info[next_col_info].Plane.Bottom=y+300; + col_info[next_col_info].Plane.Depth=z; + next_col_info++; + return(next_col_info-1); +} + + +#define SHIFT_BEZ (10) +#define BEZ_ONE (1<>5;t>5) + { + + bx=(((((BEZ_ONE-t)*(BEZ_ONE-t))>>SHIFT_BEZ)*(BEZ_ONE-t))>>SHIFT_BEZ)*x0+ + (((((3*t)*(BEZ_ONE-t))>>SHIFT_BEZ)*(BEZ_ONE-t))>>SHIFT_BEZ)*x1+ + (((((3*t)*(1*t))>>SHIFT_BEZ)*(BEZ_ONE-t))>>SHIFT_BEZ)*x2+ + ((((t*t)>>SHIFT_BEZ)*t)>>SHIFT_BEZ)*x3; + + bz=(((((BEZ_ONE-t)*(BEZ_ONE-t))>>SHIFT_BEZ)*(BEZ_ONE-t))>>SHIFT_BEZ)*z0+ + (((((3*t)*(BEZ_ONE-t))>>SHIFT_BEZ)*(BEZ_ONE-t))>>SHIFT_BEZ)*z1+ + (((((3*t)*(1*t))>>SHIFT_BEZ)*(BEZ_ONE-t))>>SHIFT_BEZ)*z2+ + ((((t*t)>>SHIFT_BEZ)*t)>>SHIFT_BEZ)*z3; + + bx>>=SHIFT_BEZ; + bz>>=SHIFT_BEZ; + draw_3d_line(ox+bx,0,oz+bz,ox+px,0,oz+pz,WHITE_COL); + px=bx; + pz=bz; + } + draw_3d_line(ox+px,0,oz+pz,ox+x3,0,oz+z3,WHITE_COL); +} + +/* +void draw_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col) +{ + struct SVector point[2]; + struct SVector res[2]; + SLONG sx,sy,sz,c0; + ULONG f1,f2; + point[0].X=x1; + point[0].Y=y1; + point[0].Z=z1; + f1=rotate_point_gte(&point[0],&res[0]); + + point[1].X=x2; + point[1].Y=y2; + point[1].Z=z2; + f2=rotate_point_gte(&point[1],&res[1]); + f1=f1&f2; + if(!(f1 & EF_CLIPFLAGS)) + DrawLineC(res[0].X,res[0].Y,res[1].X,res[1].Y,col); +} +*/ +void draw_a_col_info(UWORD index) +{ + struct ColInfo *p_col; + SLONG col=WHITE_COL; + EdRect rect; + p_col=&col_info[index]; + switch(p_col->Type) + { + case COL_TYPE_PLANE: + draw_3d_line(p_col->Plane.Left,p_col->Plane.Top,p_col->Plane.Depth,p_col->Plane.Right,p_col->Plane.Top,p_col->Plane.Depth,col); + draw_3d_line(p_col->Plane.Right,p_col->Plane.Top,p_col->Plane.Depth,p_col->Plane.Right,p_col->Plane.Bottom,p_col->Plane.Depth,col); + draw_3d_line(p_col->Plane.Left,p_col->Plane.Bottom,p_col->Plane.Depth,p_col->Plane.Right,p_col->Plane.Bottom,p_col->Plane.Depth,col); + draw_3d_line(p_col->Plane.Left,p_col->Plane.Bottom,p_col->Plane.Depth,p_col->Plane.Left,p_col->Plane.Top,p_col->Plane.Depth,col); + break; + + case COL_TYPE_BEZIER: + SLONG mid_y,temp; + temp=engine.ClipFlag; + engine.ClipFlag=0; + + mid_y=p_col->Bezier.Top+p_col->Bezier.Bottom; + mid_y>>=1; + + set_screen_box(p_col->Bezier.X[0],mid_y,p_col->Bezier.Z[0],&rect,5,5); + rect.OutlineRect(WHITE_COL); + set_screen_box(p_col->Bezier.X[1],mid_y,p_col->Bezier.Z[1],&rect,5,5); + rect.OutlineRect(WHITE_COL); + set_screen_box(p_col->Bezier.X[2],mid_y,p_col->Bezier.Z[2],&rect,5,5); + rect.OutlineRect(WHITE_COL); + set_screen_box(p_col->Bezier.X[3],mid_y,p_col->Bezier.Z[3],&rect,5,5); + rect.OutlineRect(WHITE_COL); + draw_bezier(p_col->Bezier.X[0],p_col->Bezier.Z[0],p_col->Bezier.X[1],p_col->Bezier.Z[1],p_col->Bezier.X[2],p_col->Bezier.Z[2],p_col->Bezier.X[3],p_col->Bezier.Z[3]); + + draw_3d_line(p_col->Bezier.X[0],p_col->Bezier.Top,9999,p_col->Bezier.X[3],p_col->Bezier.Top,9999,col); + draw_3d_line(p_col->Bezier.X[0],p_col->Bezier.Bottom,9999,p_col->Bezier.X[3],p_col->Bezier.Bottom,9999,col); + engine.ClipFlag=temp; + break; + } +} + +void hilight_col_info(void) +{ + SLONG c0; + for(c0=1;c0SetRect(res[0].X,res[0].Y,res[1].X-res[0].X,res[1].Y-res[0].Y); + rect->NormalRect(); + rect->SetRect(rect->GetLeft()-3,rect->GetTop()-3,rect->GetWidth()+6,rect->GetHeight()+6); + rect->OutlineRect(WHITE_COL); + + engine.ClipFlag=temp; +} + +static void create_box_from_point(EdRect *rect,SLONG x1,SLONG y1,SLONG z1) +{ + struct SVector point[1]; + struct SVector res[1]; + SLONG sx,sy,sz,c0; + ULONG f1,f2; + SLONG temp; + temp=engine.ClipFlag; + engine.ClipFlag=0; + point[0].X=x1; + point[0].Y=y1; + point[0].Z=z1; + f1=rotate_point_gte(&point[0],&res[0]); + + rect->SetRect(res[0].X,res[0].Y,10,10); + rect->NormalRect(); + rect->SetRect(rect->GetLeft()-10,rect->GetTop()-10,rect->GetWidth()+10,rect->GetHeight()+10); + rect->OutlineRect(WHITE_COL); + engine.ClipFlag=temp; +} + + +SLONG select_this_col_info(SLONG index,MFPoint *mouse) +{ + struct ColInfo *p_col; + EdRect rect; + + p_col=&col_info[index]; + switch(p_col->Type) + { + case COL_TYPE_PLANE: + //corners + create_box_from_point(&rect,p_col->Plane.Left,p_col->Plane.Top,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(5); + create_box_from_point(&rect,p_col->Plane.Right,p_col->Plane.Top,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(6); + create_box_from_point(&rect,p_col->Plane.Right,p_col->Plane.Bottom,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(7); + create_box_from_point(&rect,p_col->Plane.Left,p_col->Plane.Bottom,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(8); + + + //edges + create_box_from_vect(&rect,p_col->Plane.Left,p_col->Plane.Top,p_col->Plane.Depth,p_col->Plane.Right,p_col->Plane.Top,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(1); + create_box_from_vect(&rect,p_col->Plane.Right,p_col->Plane.Top,p_col->Plane.Depth,p_col->Plane.Right,p_col->Plane.Bottom,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(2); + create_box_from_vect(&rect,p_col->Plane.Left,p_col->Plane.Bottom,p_col->Plane.Depth,p_col->Plane.Right,p_col->Plane.Bottom,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(3); + create_box_from_vect(&rect,p_col->Plane.Left,p_col->Plane.Top,p_col->Plane.Depth,p_col->Plane.Left,p_col->Plane.Bottom,p_col->Plane.Depth); + if(rect.PointInRect(mouse)) + return(4); + + break; + case COL_TYPE_BEZIER: + set_screen_box(p_col->Bezier.X[0],0,p_col->Bezier.Z[0],&rect,10,10); + if(rect.PointInRect(mouse)) + return(1); + set_screen_box(p_col->Bezier.X[1],0,p_col->Bezier.Z[1],&rect,10,10); + if(rect.PointInRect(mouse)) + return(2); + set_screen_box(p_col->Bezier.X[2],0,p_col->Bezier.Z[2],&rect,10,10); + if(rect.PointInRect(mouse)) + return(3); + set_screen_box(p_col->Bezier.X[3],0,p_col->Bezier.Z[3],&rect,10,10); + if(rect.PointInRect(mouse)) + return(4); + + create_box_from_vect(&rect,p_col->Bezier.X[0],p_col->Bezier.Top,9999,p_col->Bezier.X[3],p_col->Bezier.Top,9999); + if(rect.PointInRect(mouse)) + return(5); + + create_box_from_vect(&rect,p_col->Bezier.X[0],p_col->Bezier.Bottom,9999,p_col->Bezier.X[3],p_col->Bezier.Bottom,9999); + if(rect.PointInRect(mouse)) + return(6); + + break; + + + } + return(0); +} + +SLONG select_col_info(MFPoint *mouse,SLONG *ret) +{ + static UBYTE col=0; + SLONG c0; + col++; + + for(c0=1;c0ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; +// clicked_point->X-=x; +// clicked_point->Y-=y; + SetWorkWindowBounds(x,y,w-1,h/2-3); + set_camera_plan(); + drag=select_col_info(clicked_point,&side); +// DrawPixelC(clicked_point->X,clicked_point->Y,255); +// ShowWorkWindow(0); + + if(!drag) //if not selected one in that window try other + { + MFPoint local_point; + + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + set_camera_front(); + local_point =*clicked_point; + local_point.Y-=h/2+4; + drag=select_col_info(&local_point,&side); + window=1; +// ShowWorkWindow(0); + } + + if(drag) //drag in plan view + { + struct ColInfo *p_col; + drag_type=col_info[drag].Type; + p_col=&col_info[drag]; + + CurrentCol=drag; + + while(LeftButton) + { + SLONG nx,ny,nz; + last_world_mouse=SetWorldMouse(0); + + if(last_world_mouse) + { + switch(drag_type) + { + case COL_TYPE_PLANE: + if(window==0) + { + if(side) + col_info[CurrentCol].Plane.Depth=engine.MousePosZ; + } + switch(side) + { + case 1: //top + col_info[CurrentCol].Plane.Top=engine.MousePosY; + break; + case 3: //bot + col_info[CurrentCol].Plane.Bottom=engine.MousePosY; + break; + case 2: //right + col_info[CurrentCol].Plane.Right=engine.MousePosX; + break; + case 4: //left + col_info[CurrentCol].Plane.Left=engine.MousePosX; + break; + case 5: //topleft + col_info[CurrentCol].Plane.Top=engine.MousePosY; + col_info[CurrentCol].Plane.Left=engine.MousePosX; + break; + case 6: //topright + col_info[CurrentCol].Plane.Right=engine.MousePosX; + col_info[CurrentCol].Plane.Top=engine.MousePosY; + break; + case 7: //botright + col_info[CurrentCol].Plane.Right=engine.MousePosX; + col_info[CurrentCol].Plane.Bottom=engine.MousePosY; + break; + case 8: //botleft + col_info[CurrentCol].Plane.Left=engine.MousePosX; + col_info[CurrentCol].Plane.Bottom=engine.MousePosY; + break; + } + break; + case COL_TYPE_BEZIER: + switch(side) + { + case 5: + p_col->Bezier.Top=engine.MousePosY; + break; + case 6: + p_col->Bezier.Bottom=engine.MousePosY; + break; + default: + if(!ShiftFlag) + { + p_col->Bezier.X[side-1]=engine.MousePosX; + p_col->Bezier.Z[side-1]=engine.MousePosZ; + } + else + { + SLONG dx,dz; + dx=p_col->Bezier.X[side-1]-engine.MousePosX; + dz=p_col->Bezier.Z[side-1]-engine.MousePosZ; + p_col->Bezier.X[0]-=dx; + p_col->Bezier.Z[0]-=dz; + p_col->Bezier.X[1]-=dx; + p_col->Bezier.Z[1]-=dz; + p_col->Bezier.X[2]-=dx; + p_col->Bezier.Z[2]-=dz; + p_col->Bezier.X[3]-=dx; + p_col->Bezier.Z[3]-=dz; + + } + break; + } + break; + } + } + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + SetWorkWindowBounds(this->ContentLeft()+1,this->ContentTop()+1,this->ContentWidth(),this->ContentHeight()); + + DrawBox(0,0,this->ContentWidth(),this->ContentHeight(),CONTENT_COL); + set_camera(); + draw_editor_map(0); + render_view(1); + ShowWorkWindow(0); + editor_user_interface(0); + KeyboardInterface(); + } + if(!last_world_mouse) + { //delete col + delete_col_info(drag); + CurrentCol=0; + } + + RequestUpdate(); + } + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); + +} + +SLONG ColTab::DragEngine(UBYTE flags,MFPoint *clicked_point) +{ + SLONG wwx,wwy,www,wwh; + SLONG screen_change=0; + SLONG last_world_mouse; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + + { + SLONG start_x=0,start_y=0,start_z=0,flag=0; + SLONG old_x,old_y,old_z; + SLONG nx,ny,nz; + + old_x=nx=engine.X; + old_y=ny=engine.Y; + old_z=nz=engine.Z; + + while(MiddleButton) + { + last_world_mouse=SetWorldMouse(0); + if(last_world_mouse) + { + if(!flag) + { + flag=1; + start_x=engine.MousePosX<<8; + start_y=engine.MousePosY<<8; + start_z=engine.MousePosZ<<8; + } + + nx=engine.MousePosX<<8; + ny=engine.MousePosY<<8; + nz=engine.MousePosZ<<8; + + engine.X = (old_x+(-nx+start_x)); + engine.Y = (old_y+(-ny+start_y)); + engine.Z = (old_z+(-nz+start_z)); + +// engine.Z=nz<<8; + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + engine.X=old_x; + engine.Y=old_y; + engine.Z=old_z; + + } + } + if(flag) + { + engine.X= (old_x+(-nx+start_x)); + engine.Y= (old_y+(-ny+start_y)); + engine.Z= (old_z+(-nz+start_z)); + } + } + return(screen_change); + +} + +SLONG ColTab::HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h) +{ + SWORD thing; + SWORD bright; + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + + switch (Mode) + { + case COL_MODE_PLACE_PLANE: + if(SetWorldMouse(1)) + { + CurrentCol=CreateColPlane(engine.MousePosX,engine.MousePosY,engine.MousePosZ); + Mode=0; + } + return(1); + + break; + case COL_MODE_WAIT: + DragACol(flags,clicked_point,0); + break; + + case COL_MODE_PLACE_BEZIER: + if(SetWorldMouse(1)) + { + CurrentCol=CreateColBezier(engine.MousePosX,engine.MousePosY,engine.MousePosZ); + Mode=0; + } + return(1); + } + break; + case RIGHT_CLICK: + switch (Mode) + { + } + // Right click in content. + break; + case MIDDLE_CLICK: + DragEngine(flags,clicked_point); + break; + } + return(0); + +} + +UWORD ColTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + MFPoint local_point; + + + // This is a fudge to update the front screen buffer. + ShowWorkScreen(0); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + { + current_control = GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + control_id = current_control->TrackControl(&local_point); + HandleControl(control_id); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + return control_id; + } + current_control = current_control->GetNextControl(); + } + } + + break; + case RIGHT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + break; + } + return 0; +} + +//--------------------------------------------------------------- + +SLONG ColTab::SetWorldMouse(ULONG flag) +{ + MFPoint mouse_point; + MFPoint local_point; + SVector point,out; + SLONG wwx,wwy,www,wwh; + SLONG temp; + + temp=engine.ClipFlag; + engine.ClipFlag=0; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + + local_point = mouse_point; + Parent->GlobalToLocal(&local_point); + if(is_point_in_box(local_point.X,local_point.Y,0,0,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()/2-3); + set_camera_plan(); + calc_world_pos_plan(local_point.X,local_point.Y); + if(flag) + engine.MousePosY=engine.Y>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + engine.ClipFlag=temp; + return(1); + } + else + if(is_point_in_box(local_point.X,local_point.Y,0,Parent->ContentHeight()/2,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+Parent->ContentHeight()/2+3,Parent->ContentWidth()-1,Parent->ContentHeight()/2-4); + set_camera_front(); + calc_world_pos_front(local_point.X,local_point.Y-Parent->ContentHeight()/2); + if(flag) + engine.MousePosZ=engine.Z>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + engine.ClipFlag=temp; + return(1); + + } + else + { + + engine.ClipFlag=temp; + return(0); + } + +} + + +void ColTab::HandleControl(UWORD control_id) +{ + switch(control_id&0xff) + { + + case CTRL_COL_X_AXIS_FREE: + ToggleControlSelectedState(CTRL_COL_X_AXIS_FREE); + if(Axis&X_AXIS) + Axis&=~X_AXIS; + else + Axis|=X_AXIS; + break; + case CTRL_COL_Y_AXIS_FREE: + ToggleControlSelectedState(CTRL_COL_Y_AXIS_FREE); + if(Axis&Y_AXIS) + Axis&=~Y_AXIS; + else + Axis|=Y_AXIS; + break; + case CTRL_COL_Z_AXIS_FREE: + ToggleControlSelectedState(CTRL_COL_Z_AXIS_FREE); + if(Axis&Z_AXIS) + Axis&=~Z_AXIS; + else + Axis|=Z_AXIS; + break; + case CTRL_COL_PLACE_PLANE: + Mode=COL_MODE_PLACE_PLANE; + break; + case CTRL_COL_PLACE_BEZIER: + Mode=COL_MODE_PLACE_BEZIER; + break; + case CTRL_COL_RECALC: + Recalc(); + + break; + case CTRL_COL_CLEAR_COL: + Clear(); + + break; + case CTRL_COL_CLIPPED_VIEW: + ToggleControlSelectedState(CTRL_COL_CLIPPED_VIEW); + if(ClipView) + { + ClipView=0; + engine.ClipFlag=0; + } + else + { + struct ColInfo *p_col; + ClipView=1; + p_col=&col_info[CurrentCol]; + switch(p_col->Type) + { + case COL_TYPE_PLANE: + engine.ClipMinY=p_col->Plane.Top; + engine.ClipMaxY=p_col->Plane.Bottom; + break; + case COL_TYPE_BEZIER: + engine.ClipMinY=p_col->Bezier.Top; + engine.ClipMaxY=p_col->Bezier.Bottom; + break; + } + + engine.ClipFlag=ENGINE_CLIPY_FLAG; + } +// RequestRedraw(); + break; +/* + case CTRL_COL_DELETE: + delete_all_lights(); + RequestUpdate(); + Mode=0; + break; +*/ + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/ComTab.cpp b/fallen/Editor/Source/ComTab.cpp new file mode 100644 index 0000000..9657522 --- /dev/null +++ b/fallen/Editor/Source/ComTab.cpp @@ -0,0 +1,1148 @@ +// ComTab.cpp +// Guy Simmons, 9th March 1998. + +#include "Editor.hpp" +#include "EdCom.h" + +#include "..\..\Headers\Game.h" +#include "..\..\Headers\Command.h" + +//--------------------------------------------------------------- + +#define MAX_VIEW_LISTS 15 +#define MAX_VIEW_COMMANDS 24 + +#define LISTS_X 2 +#define LISTS_Y 32 +#define LISTS_WIDTH 150 +#define LISTS_HEIGHT ((MAX_VIEW_LISTS*8)+3) + +#define COM_LIST_X 2 +#define COM_LIST_Y 226 +#define COM_LIST_WIDTH (280) +#define COM_LIST_HEIGHT ((MAX_VIEW_COMMANDS*8)+3) + +#define COM_NAME_X 2 +#define COM_NAME_Y (COM_LIST_Y-14) +#define COM_NAME_WIDTH LISTS_WIDTH + +#define CTRL_NEW_COMLIST 1 +#define CTRL_LISTS_SLIDER 2 +#define CTRL_COMLIST_EDIT 3 +#define CTRL_COMLIST_SLIDER 4 +#define CTRL_NEW_COMMAND 5 + +#define UPDATE_NONE 0 +#define UPDATE_ALL 1 +#define UPDATE_LISTS_BOX 2 +#define UPDATE_CURRENT_LIST 3 + +#define MAX_FIELDS 4 +#define FIELD_1_WIDTH 94 +#define FIELD_2_WIDTH 62 +#define FIELD_3_WIDTH 62 +#define FIELD_4_WIDTH 62 + +#include "ComTab.def" + +extern CBYTE *class_text[], + *genus_text[][10], + *condition_text[], + *command_text[], + *s_command_text[]; + +//--------------------------------------------------------------- + + +UWORD command_field_widths[][MAX_FIELDS] = +{ + { COM_LIST_WIDTH-2, 0, 0, 0 }, // COM_NONE + { FIELD_1_WIDTH, 0, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_ATTACK_PLAYER + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_ATTACK_THING + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_ATTACK_GROUP + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_ATTACK_CLASS + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_DEFEND_PLAYER + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_DEFEND_THING + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_DEFEND_GROUP + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_DEFEND_CLASS + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_PATROL_WAYPOINT + { FIELD_1_WIDTH, 0, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_START_TIMER + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_WAIT_FOR_TRIGGER + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_WAIT_FOR_CLIST + { FIELD_1_WIDTH, 0, FIELD_3_WIDTH, FIELD_4_WIDTH }, // COM_FOLLOW_PLAYER + { 0, 0, 0, 0 } +}; + +CommandTab *the_com_tab; + +//--------------------------------------------------------------- +// Callback functions. +//--------------------------------------------------------------- + +void draw_comlists_box(void) +{ + the_com_tab->DrawListsBox(); +} + +void draw_comlist_box(void) +{ + the_com_tab->DrawCurrentList(); +} + +//--------------------------------------------------------------- +// CommandTab +//--------------------------------------------------------------- + +CommandTab::CommandTab() +{ + CurrentComList = NULL; + the_com_tab = this; + TabMode = COM_MODE_NONE; + + InitControlSet(com_tab_def); + + ((CHSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->SetUpdateFunction(draw_comlists_box); + ((CHSlider*)GetControlPtr(CTRL_COMLIST_SLIDER))->SetUpdateFunction(draw_comlist_box); +} + +//--------------------------------------------------------------- + +CommandTab::~CommandTab() +{ + +} + +//--------------------------------------------------------------- + +void CommandTab::DrawTabContent(void) +{ + SLONG message_height, + message_width; + EdRect message_rect; + + + SetTabDrawArea(); + ClearTab(); + + DrawControlSet(); + + DrawListsBox(); + DrawCurrentList(); + + switch(TabMode) + { + case COM_MODE_NONE: + break; + case COM_MODE_SELECT_THING: + message_height = QTStringHeight()+12; + message_width = QTStringWidth("Select A Thing")+12; + message_rect.SetRect( + 150-(message_width>>1), + 220-(message_height>>1), + message_width, + message_height + ); + message_rect.FillRect(RED_COL); + message_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + message_rect.GetLeft()+6, + message_rect.GetTop()+6, + "Select A Thing", + 0 + ); + break; + case COM_MODE_SELECT_WAYPOINT: + message_height = QTStringHeight()+12; + message_width = QTStringWidth("Select A Waypoint")+12; + message_rect.SetRect( + 150-(message_width>>1), + 220-(message_height>>1), + message_width, + message_height + ); + message_rect.FillRect(RED_COL); + message_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + message_rect.GetLeft()+6, + message_rect.GetTop()+6, + "Select A Waypoint", + 0 + ); + case COM_MODE_SELECT_SWITCH: + message_height = QTStringHeight()+12; + message_width = QTStringWidth("Select A Trigger")+12; + message_rect.SetRect( + 150-(message_width>>1), + 220-(message_height>>1), + message_width, + message_height + ); + message_rect.FillRect(RED_COL); + message_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + message_rect.GetLeft()+6, + message_rect.GetTop()+6, + "Select A Trigger", + 0 + ); + break; + } +} + +//--------------------------------------------------------------- + +void CommandTab::UpdateTab(UBYTE update_level) +{ + if(update_level) + { + if(LockWorkScreen()) + { + switch(update_level) + { + case UPDATE_ALL: + DrawTabContent(); + break; + case UPDATE_LISTS_BOX: + DrawListsBox(); + break; + case UPDATE_CURRENT_LIST: + DrawCurrentList(); + break; + } + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +} + +//--------------------------------------------------------------- + +UWORD CommandTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UBYTE update = UPDATE_NONE; + UWORD select_pos; + ULONG control_id = 0; + EditComList *the_comlist; + MFPoint local_point; + + + if(TabMode) + { + return 0; + } + if(TabData) + { + switch(DataField) + { + case 1: + DataCommand->Data1 = TabData; + break; + case 2: + DataCommand->Data2 = TabData; + break; + case 3: + DataCommand->Data3 = TabData; + break; + } + TabData = 0; + } + + SetTabDrawArea(); + + local_point = *clicked_point; + GlobalToLocal(&local_point); + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + select_pos = ListsHilitePos(&local_point); + if(select_pos) + { + CurrentComList = HilitetedList(select_pos); + if(CurrentComList) + { + ((CEditText*)GetControlPtr(CTRL_COMLIST_EDIT))->SetEditString(CurrentComList->ComListName); + if(CurrentComList->CommandCount>MAX_VIEW_COMMANDS) + { + ((CVSlider*)GetControlPtr(CTRL_COMLIST_SLIDER))->SetValueRange(0,CurrentComList->CommandCount-MAX_VIEW_COMMANDS); + } + else + { + ((CVSlider*)GetControlPtr(CTRL_COMLIST_SLIDER))->SetValueRange(0,0); + } + } + } + else + { + local_point = *clicked_point; + control_id = HandleControlSetClick(flags,&local_point); + HandleControl(control_id); + } + update = UPDATE_ALL; + break; + case RIGHT_CLICK: + select_pos = ListsHilitePos(&local_point); + if(select_pos) + { + the_comlist = HilitetedList(select_pos); + if(the_comlist) + { + DoComListPopup(&local_point,the_comlist); + update = UPDATE_ALL; + } + } + else + { + select_pos = CurrentListHilitePos(&local_point); + if(select_pos) + { + DoCommandPopup(&local_point,select_pos); + update = UPDATE_ALL; + } + } + break; + } + + UpdateTab(update); + + return 0; +} + +//--------------------------------------------------------------- + +void CommandTab::HandleTab(MFPoint *current_point) +{ + UBYTE update = UPDATE_NONE; + EdRect command_rect, + lists_rect; + MFPoint local_point; + static BOOL cleanup = FALSE; + + + if(TabMode) + { + cleanup = TRUE; + return; + } + if(TabData) + { + switch(DataField) + { + case 1: + DataCommand->Data1 = TabData; + break; + case 2: + DataCommand->Data2 = TabData; + break; + case 3: + DataCommand->Data3 = TabData; + break; + } + TabData = 0; + } + + ModeTab::HandleTab(current_point); + + local_point = *current_point; + GlobalToLocal(&local_point); + + command_rect.SetRect(COM_LIST_X,COM_LIST_Y,COM_LIST_WIDTH,COM_LIST_HEIGHT); + lists_rect.SetRect(LISTS_X,LISTS_Y,LISTS_WIDTH,LISTS_HEIGHT); + if(lists_rect.PointInRect(&local_point) && !cleanup) + { + update = UPDATE_LISTS_BOX; + cleanup = TRUE; + } + else if(command_rect.PointInRect(&local_point) && !cleanup) + { + update = UPDATE_CURRENT_LIST; + cleanup = TRUE; + } + + if(update==UPDATE_NONE && cleanup) + { + update = UPDATE_ALL; + cleanup = FALSE; + } + + UpdateTab(update); +} + +//--------------------------------------------------------------- + +void CommandTab::HandleControl(UWORD control_id) +{ + SLONG control = control_id&0xff; + + + switch(control) + { + case CTRL_NEW_COMLIST: + CurrentComList = alloc_ed_comlist(); + if(CurrentComList) + { + // set up the new command list. + if(ed_comlist_count>MAX_VIEW_LISTS) + { + ((CVSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->SetValueRange(0,ed_comlist_count-MAX_VIEW_LISTS); + } + ((CEditText*)GetControlPtr(CTRL_COMLIST_EDIT))->SetEditString(CurrentComList->ComListName); + + // Allocate the first command. + add_command(CurrentComList,alloc_ed_command()); + } + break; + case CTRL_LISTS_SLIDER: + break; + case CTRL_COMLIST_EDIT: + strcpy(CurrentComList->ComListName,((CEditText*)GetControlPtr(CTRL_COMLIST_EDIT))->GetEditString()); + break; + case CTRL_COMLIST_SLIDER: + break; + case CTRL_NEW_COMMAND: + if(CurrentComList) + { + // Create a new command. + add_command(CurrentComList,alloc_ed_command()); + if(CurrentComList->CommandCount>MAX_VIEW_COMMANDS) + { + ((CVSlider*)GetControlPtr(CTRL_COMLIST_SLIDER))->SetValueRange(0,CurrentComList->CommandCount-MAX_VIEW_COMMANDS); + } + } + break; + } +} + +//--------------------------------------------------------------- + +void CommandTab::DoComListPopup(MFPoint *clicked_point,EditComList *the_comlist) +{ + ULONG control_id = 0; + CPopUp *the_control = 0; + + + comlist_popup_def.ControlLeft = clicked_point->X+4; + comlist_popup_def.ControlTop = clicked_point->Y-4; + + comlist_popup_def.TheMenuDef = comlist_popup; + the_control = new CPopUp(&comlist_popup_def); + control_id = the_control->TrackControl(clicked_point); + + switch(control_id>>8) + { + case 0: + break; + case 1: + if(CurrentComList==the_comlist) + { + CurrentComList = NULL; + ((CEditText*)GetControlPtr(CTRL_COMLIST_EDIT))->SetEditString(""); + } + if(ed_comlist_count>MAX_VIEW_LISTS) + { + ((CVSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->SetValueRange(0,(ed_comlist_count-MAX_VIEW_LISTS)-1); + } + free_ed_comlist(the_comlist); + break; + } +} + +//--------------------------------------------------------------- + +void CommandTab::DoCommandPopup(MFPoint *clicked_point,UWORD select_pos) +{ + UBYTE field; + ULONG control_id = 0; + CPopUp *the_control = 0; + EditCommand *the_command; + EditCondList *the_cond_list; + + + the_command = HilitetedCommand(select_pos); + if(the_command) + { + command_popup_def.ControlLeft = clicked_point->X+4; + command_popup_def.ControlTop = clicked_point->Y-4; + + field = (select_pos&0x00ff)-1; + if(field==3) + { + switch(the_command->Data2) + { + case COM_S_NONE: + command_popup_def.TheMenuDef = generic_popup2; + break; + case COM_S_UNTIL_TRIGGER: + command_popup_def.TheMenuDef = select_switch_popup2; + break; + case COM_S_UNTIL_CLIST: + command_popup_def.TheMenuDef = select_clist_popup; + break; + case COM_S_WHILE_TRIGGER: + command_popup_def.TheMenuDef = select_switch_popup2; + break; + case COM_S_WHILE_CLIST: + command_popup_def.TheMenuDef = select_clist_popup; + break; + } + } + else + command_popup_def.TheMenuDef = command_defs[the_command->CommandType][field]; + + the_control = new CPopUp(&command_popup_def); + control_id = (the_control->TrackControl(clicked_point))>>8; + + if(control_id<=5) + CommonCommandOptions(control_id,the_command); + else + { + // Set the data fields. + if(field) + { + if(field==2) + { + the_command->Data2 = control_id-6; + the_command->Data3 = 0; + } + else if(field==3) + { + switch(the_command->Data2) + { + case COM_S_NONE: + break; + case COM_S_UNTIL_TRIGGER: + case COM_S_WHILE_TRIGGER: + TabMode = COM_MODE_SELECT_SWITCH; + DataCommand = the_command; + DataField = 3; + break; + case COM_S_UNTIL_CLIST: + case COM_S_WHILE_CLIST: + the_cond_list = SelectConditionList(); + if(the_cond_list) + { + the_command->Data3 = ED_CONLIST_NUMBER(the_cond_list); + } + break; + } + } + else + { + switch(the_command->CommandType) + { + case COM_NONE: + break; + case COM_ATTACK_PLAYER: + break; + case COM_ATTACK_THING: + TabMode = COM_MODE_SELECT_THING; + DataCommand = the_command; + DataField = 1; + break; + case COM_ATTACK_GROUP: + break; + case COM_ATTACK_CLASS: + break; + case COM_DEFEND_PLAYER: + break; + case COM_DEFEND_THING: + TabMode = COM_MODE_SELECT_THING; + DataCommand = the_command; + DataField = 1; + break; + case COM_DEFEND_GROUP: + break; + case COM_DEFEND_CLASS: + break; + case COM_PATROL_WAYPOINT: + TabMode = COM_MODE_SELECT_WAYPOINT; + DataCommand = the_command; + DataField = 1; + break; + case COM_START_TIMER: + break; + case COM_WAIT_FOR_TRIGGER: + TabMode = COM_MODE_SELECT_SWITCH; + DataCommand = the_command; + DataField = 1; + break; + case COM_WAIT_FOR_CLIST: + the_cond_list = SelectConditionList(); + if(the_cond_list) + { + the_command->Data1 = ED_CONLIST_NUMBER(the_cond_list); + } + break; + case COM_FOLLOW_PLAYER: + break; + } + } + } + else + { + the_command->CommandType = control_id-6; + } + } + } +} + +//--------------------------------------------------------------- + +void CommandTab::CommonCommandOptions(ULONG id,EditCommand *the_command) +{ + switch(id) + { + case 0: // NULL. + break; + case 1: // Delete Condition. + if(the_command) + { + if(CurrentComList->CommandCount>MAX_VIEW_COMMANDS) + { + ((CVSlider*)GetControlPtr(CTRL_COMLIST_SLIDER))->SetValueRange(0,(CurrentComList->CommandCount>MAX_VIEW_COMMANDS)-1); + } + } + remove_command(CurrentComList,the_command); + free_ed_command(the_command); + break; + case 2: // Blank. + break; + case 3: // Group Commands. + break; + case 4: // Ungroup Commands. + break; + case 5: // Blank. + break; + } +} + +//--------------------------------------------------------------- + +EditCondList *CommandTab::SelectConditionList(void) +{ + BOOL exit = FALSE; + UBYTE update = 2; + UWORD select_pos; + SLONG c0; + ControlSet select_set; + EditCondList *current_list, + *hilited_list, + *selected_list = NULL; + EdRect bounds_rect, + item_rect, + lists_rect; + MFPoint current_point; + + + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + bounds_rect.SetRect ( + (WorkScreenPixelWidth-(LISTS_WIDTH+20))>>1, + (WorkScreenHeight-(LISTS_HEIGHT+7))>>1, + LISTS_WIDTH+20, + LISTS_HEIGHT+7 + ); + select_set.ControlSetBounds(&bounds_rect); + select_set.InitControlSet(select_clist_def); + if(ed_clist_count>MAX_VIEW_LISTS) + { + ((CVSlider*)select_set.GetControlPtr(1))->SetValueRange(0,ed_clist_count-MAX_VIEW_LISTS); + } + ((CVSlider*)select_set.GetControlPtr(1))->SetCurrentValue(0); + + while(SHELL_ACTIVE && !exit) + { + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + current_point.X = MouseX; + current_point.Y = MouseY; + + if(select_set.HandleControlSet(¤t_point)) + update = 1; + + lists_rect.SetRect(LISTS_X,LISTS_Y-30,LISTS_WIDTH,LISTS_HEIGHT); + current_point.X -= bounds_rect.GetLeft(); + current_point.Y -= bounds_rect.GetTop(); + select_pos = 0; + if(lists_rect.PointInRect(¤t_point)) + { + for(c0=0;c0GetCurrentValue(); + while(current_list && c0) + { + c0--; + current_list = current_list->Next; + } + + c0 = 0; + hilited_list = NULL; + while(current_list && c0CListName,0); + + c0++; + current_list = current_list->Next; + } + + lists_rect.HiliteRect(LOLITE_COL,HILITE_COL); + } + + if(update<=2) + { + select_set.DrawControlSet(); + } + + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + select_set.FiniControlSet(); + + return selected_list; +} + +//--------------------------------------------------------------- + +void CommandTab::DrawListsBox(void) +{ + UWORD select_pos; + SLONG c0; + EditComList *current_list; + EdRect item_rect, + lists_rect; + MFPoint local_point; + + + SetTabDrawArea(); + + local_point.X = MouseX; + local_point.Y = MouseY; + GlobalToLocal(&local_point); + + select_pos = ListsHilitePos(&local_point); + + lists_rect.SetRect(LISTS_X,LISTS_Y,LISTS_WIDTH,LISTS_HEIGHT); + lists_rect.FillRect(ACTIVE_COL); + + // Skip the beginning of the list to match the slider bar position. + current_list = comlists; + c0 = ((CVSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->GetCurrentValue(); + while(current_list && c0) + { + c0--; + current_list = current_list->Next; + } + + c0 = 0; + while(current_list && c0ComListName,0); + + c0++; + current_list = current_list->Next; + } + lists_rect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +void CommandTab::DrawCurrentList(void) +{ + CBYTE field_text[MAX_FIELDS][64]; + UWORD select_pos; + SLONG c0,c1, + x_pos; + EditCommand *current_command; + EdRect field_rects[MAX_FIELDS], + list_rect; + MFPoint local_point; + + + SetTabDrawArea(); + + local_point.X = MouseX; + local_point.Y = MouseY; + GlobalToLocal(&local_point); + + select_pos = CurrentListHilitePos(&local_point); + + list_rect.SetRect(COM_LIST_X,COM_LIST_Y,COM_LIST_WIDTH,COM_LIST_HEIGHT); + list_rect.FillRect(ACTIVE_COL); + + if(CurrentComList) + { + // Skip the beginning of the list to match the slider bar position. + current_command = CurrentComList->CommandList; + if(current_command) + { + c0 = ((CVSlider*)GetControlPtr(CTRL_COMLIST_SLIDER))->GetCurrentValue(); + while(current_command && c0) + { + c0--; + current_command = current_command->Next; + } + + c0 = 0; + while(current_command && c0CommandType][c1], + QTStringHeight()+1 + ); + x_pos += command_field_widths[current_command->CommandType][c1]; + } + + // Hilite the field that the mouse is currently over. + if((select_pos>>8)==(c0+1)) + { + field_rects[(select_pos&0x00ff)-1].FillRect(HILITE_COL); + } + + + // Clear all the field text. + ZeroMemory(field_text,sizeof(field_text)); + + // Set the commands field text + sprintf(&field_text[0][0],"%s",command_text[current_command->CommandType]); + + // & it's data. + switch(current_command->CommandType) + { + case COM_NONE: + break; + case COM_ATTACK_PLAYER: + break; + case COM_ATTACK_THING: + sprintf(&field_text[1][0],"Thing %d",current_command->Data1); + break; + case COM_ATTACK_GROUP: + break; + case COM_ATTACK_CLASS: + break; + case COM_DEFEND_PLAYER: + break; + case COM_DEFEND_THING: + sprintf(&field_text[1][0],"Thing %d",current_command->Data1); + break; + case COM_DEFEND_GROUP: + break; + case COM_DEFEND_CLASS: + break; + case COM_PATROL_WAYPOINT: + sprintf(&field_text[1][0],"Waypoint %d",current_command->Data1); + break; + case COM_START_TIMER: + break; + case COM_WAIT_FOR_TRIGGER: + sprintf(&field_text[1][0],"%d",current_command->Data1); + break; + case COM_WAIT_FOR_CLIST: + if(current_command->Data1) + { + sprintf(&field_text[1][0],"%s",edit_clists[current_command->Data1].CListName); + } + else + { + sprintf(&field_text[1][0],"None"); + } + break; + case COM_FOLLOW_PLAYER: + break; + } + + if(current_command->CommandType) + { + // Now set the secondary commands field text + sprintf(&field_text[2][0],"%s",s_command_text[current_command->Data2]); + + // & it's data. + switch(current_command->Data2) + { + case COM_S_NONE: + break; + case COM_S_UNTIL_TRIGGER: + case COM_S_WHILE_TRIGGER: + sprintf(&field_text[3][0]," %d",current_command->Data3); + break; + case COM_S_UNTIL_CLIST: + case COM_S_WHILE_CLIST: + if(current_command->Data3) + { + sprintf(&field_text[3][0],"%s",edit_clists[current_command->Data3].CListName); + } + else + { + sprintf(&field_text[3][0],"None"); + } + break; + break; + } + } + + // Draw all field text. + for(c1=0;c1Next; + } + } + } + list_rect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +UWORD CommandTab::ListsHilitePos(MFPoint *current_point) +{ + UWORD c0; + EdRect item_rect, + lists_rect; + + + lists_rect.SetRect(LISTS_X,LISTS_Y,LISTS_WIDTH,LISTS_HEIGHT); + + if(lists_rect.PointInRect(current_point)) + { + for(c0=0;c0GetCurrentValue(); + while(current_list && c0) + { + c0--; + current_list = current_list->Next; + } + + // Now skip to the hilited item. + select_pos--; + while(current_list && select_pos) + { + select_pos--; + current_list = current_list->Next; + } + + return current_list; +} + +//--------------------------------------------------------------- + +UWORD CommandTab::CurrentListHilitePos(MFPoint *current_point) +{ + UWORD c0,c1; + SLONG x_pos; + EditCommand *current_command; + EdRect command_rect, + field_rects[MAX_FIELDS], + list_rect; + + + if(CurrentComList) + { + list_rect.SetRect(COM_LIST_X,COM_LIST_Y,COM_LIST_WIDTH,COM_LIST_HEIGHT); + + if(list_rect.PointInRect(current_point)) + { + for(c0=0;c0CommandType][c1], + QTStringHeight()+1 + ); + x_pos += command_field_widths[current_command->CommandType][c1]; + + if(field_rects[c1].PointInRect(current_point)) + { + return ((c0+1)<<8)|(c1+1); + } + } + } + } + } + } + } + return 0; +} + +//--------------------------------------------------------------- + +EditCommand *CommandTab::HilitetedCommand(UWORD select_pos) +{ + ULONG c0; + EditCommand *current_command = NULL; + + + if(CurrentComList) + { + current_command = CurrentComList->CommandList; + + // Skip the beginning of the list to match the slider bar position. + c0 = ((CVSlider*)GetControlPtr(CTRL_COMLIST_SLIDER))->GetCurrentValue(); + while(current_command && c0) + { + c0--; + current_command = current_command->Next; + } + + // Now skip to the hilited command. + select_pos = (select_pos>>8)-1; + while(current_command && select_pos) + { + select_pos--; + current_command = current_command->Next; + } + } + + return current_command; +} + +//--------------------------------------------------------------- + diff --git a/fallen/Editor/Source/ComTab.def b/fallen/Editor/Source/ComTab.def new file mode 100644 index 0000000..0526c0f --- /dev/null +++ b/fallen/Editor/Source/ComTab.def @@ -0,0 +1,160 @@ + +//--------------------------------------------------------------- + +ControlDef com_tab_def[] = +{ + { BUTTON, 0, "New Command List", LISTS_X, 10, 0, 0 }, + { V_SLIDER, 0, "", LISTS_X+LISTS_WIDTH, LISTS_Y, 0, LISTS_HEIGHT }, + { EDIT_TEXT, 0, "", COM_NAME_X, COM_NAME_Y, COM_NAME_WIDTH, 0 }, + { V_SLIDER, 0, "", COM_LIST_X+COM_LIST_WIDTH, COM_LIST_Y, 0, COM_LIST_HEIGHT }, + { BUTTON, 0, "New Command", COM_NAME_X+COM_NAME_WIDTH+2, COM_NAME_Y, 0, 0 }, + + { 0 } +}; + +//--------------------------------------------------------------- + +static ControlDef comlist_popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 comlist_popup[] = +{ + { "Delete Command List" }, + { "!" } +}; + +//--------------------------------------------------------------- + +static ControlDef command_popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 command_popup[] = +{ + { "Delete Command" }, + { "^" }, + { "Group Commands" }, + { "Ungroup Commands" }, + { "^" }, + { "NONE" }, + { "ATTACK_PLAYER" }, + { "ATTACK_THING" }, + { "ATTACK_GROUP" }, + { "ATTACK_CLASS" }, + { "DEFEND_PLAYER" }, + { "DEFEND_THING" }, + { "DEFEND_GROUP" }, + { "DEFEND_CLASS" }, + { "PATROL_WAYPOINT" }, + { "START_TIMER" }, + { "WAIT_FOR_TRIGGER" }, + { "WAIT_FOR_CLIST" }, + { "FOLLOW_PLAYER" }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_thing_popup2[] = +{ + { "Delete Command" }, + { "^" }, + { "Group Commands" }, + { "Ungroup Commands" }, + { "^" }, + { "Select Thing", }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_waypoint_popup[] = +{ + { "Delete Command" }, + { "^" }, + { "Group Commands" }, + { "Ungroup Commands" }, + { "^" }, + { "Select Waypoint", }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_switch_popup2[] = +{ + { "Delete Command" }, + { "^" }, + { "Group Commands" }, + { "Ungroup Commands" }, + { "^" }, + { "Select Switch", }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_clist_popup[] = +{ + { "Delete Command" }, + { "^" }, + { "Group Commands" }, + { "Ungroup Commands" }, + { "^" }, + { "Select Condition List" }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_secondary_popup[] = +{ + { "Delete Command" }, + { "^" }, + { "Group Commands" }, + { "Ungroup Commands" }, + { "^" }, + { "ALWAYS" }, + { "UNTIL_TRIGGER" }, + { "UNTIL_CLIST" }, + { "WHILE_TRIGGER" }, + { "WHILE_CLIST" }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 generic_popup2[] = +{ + { "Delete Command" }, + { "^" }, + { "Group Commands" }, + { "Ungroup Commands" }, + { "!" } +}; + + +//--------------------------------------------------------------- + +MenuDef2 *command_defs[][MAX_FIELDS] = +{ + { command_popup, NULL, NULL, NULL }, // COM_NONE + { command_popup, NULL, select_secondary_popup, NULL }, // COM_ATTACK_PLAYER + { command_popup, select_thing_popup2, select_secondary_popup, NULL }, // COM_ATTACK_THING + { command_popup, NULL, select_secondary_popup, NULL }, // COM_ATTACK_GROUP + { command_popup, NULL, select_secondary_popup, NULL }, // COM_ATTACK_CLASS + { command_popup, NULL, select_secondary_popup, NULL }, // COM_DEFEND_PLAYER + { command_popup, select_thing_popup2, select_secondary_popup, NULL }, // COM_DEFEND_THING + { command_popup, NULL, select_secondary_popup, NULL }, // COM_DEFEND_GROUP + { command_popup, NULL, select_secondary_popup, NULL }, // COM_DEFEND_CLASS + { command_popup, select_waypoint_popup, select_secondary_popup, NULL }, // COM_PATROL_WAYPOINT + { command_popup, NULL, select_secondary_popup, NULL }, // COM_START_TIMER + { command_popup, select_switch_popup2, select_secondary_popup, NULL }, // COM_WAIT_FOR_TRIGGER + { command_popup, select_clist_popup, select_secondary_popup, NULL }, // COM_WAIT_FOR_CLIST + { command_popup, NULL, select_secondary_popup, NULL } // COM_FOLLOW_PLAYER +}; + +//--------------------------------------------------------------- + +ControlDef select_clist_def[] = +{ + { V_SLIDER, 0, "", LISTS_X+LISTS_WIDTH, LISTS_Y-30, 0, LISTS_HEIGHT }, + { 0 } +}; + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/CondTab.cpp b/fallen/Editor/Source/CondTab.cpp new file mode 100644 index 0000000..d803efb --- /dev/null +++ b/fallen/Editor/Source/CondTab.cpp @@ -0,0 +1,1111 @@ +// CondTab.cpp +// Guy Simmons, 16th March 1998. + +#include "Editor.hpp" +#include "EdCom.h" + +#include "..\..\Headers\Game.h" +#include "..\..\Headers\Command.h" + + +//--------------------------------------------------------------- + +#define MAX_VIEW_LISTS 15 +#define MAX_VIEW_CONDS 24 + +#define LISTS_X 2 +#define LISTS_Y 32 +#define LISTS_WIDTH 150 +#define LISTS_HEIGHT ((MAX_VIEW_LISTS*8)+3) + +#define CON_LIST_X 2 +#define CON_LIST_Y 226 +#define CON_LIST_WIDTH (280) +#define CON_LIST_HEIGHT ((MAX_VIEW_CONDS*8)+3) + +#define CON_NAME_X 2 +#define CON_NAME_Y (CON_LIST_Y-14) +#define CON_NAME_WIDTH LISTS_WIDTH + +#define CTRL_NEW_CLIST 1 +#define CTRL_LISTS_SLIDER 2 +#define CTRL_CLIST_EDIT 3 +#define CTRL_CLIST_SLIDER 4 +#define CTRL_NEW_COND 5 + +#define UPDATE_NONE 0 +#define UPDATE_ALL 1 +#define UPDATE_LISTS_BOX 2 +#define UPDATE_CURRENT_LIST 3 + +#define MAX_FIELDS 4 +#define FIELD_1_WIDTH 112 +#define FIELD_2_WIDTH 56 +#define FIELD_3_WIDTH 56 +#define FIELD_4_WIDTH 56 + +#include "CondTab.def" + +extern CBYTE *class_text[]; +extern CBYTE *genus_text[][10]; +extern CBYTE *condition_text[]; + +//--------------------------------------------------------------- + +UWORD field_widths[][MAX_FIELDS] = +{ + { CON_LIST_WIDTH-2, 0, 0, 0 }, // CON_NONE + { FIELD_1_WIDTH, FIELD_2_WIDTH, 0, 0 }, // CON_THING_DEAD + { FIELD_1_WIDTH, FIELD_2_WIDTH, 0, 0 }, // CON_ALL_GROUP_DEAD + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // CON_PERCENT_GROUP_DEAD + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, 0 }, // CON_THING_NEAR_PLAYER + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, 0 }, // CON_GROUP_NEAR_PLAYER + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, 0 }, // CON_CLASS_NEAR_PLAYER + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // CON_THING_NEAR_THING + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // CON_GROUP_NEAR_THING + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, FIELD_4_WIDTH }, // CON_CLASS_NEAR_THING + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, 0 }, // CON_CLASS_COUNT + { FIELD_1_WIDTH, FIELD_2_WIDTH, FIELD_3_WIDTH, 0 }, // CON_GROUP_COUNT + { FIELD_1_WIDTH, FIELD_2_WIDTH, 0, 0 }, // CON_SWITCH_TRIGGERED + { FIELD_1_WIDTH, FIELD_2_WIDTH, 0, 0 }, // CON_TIME + { FIELD_1_WIDTH, FIELD_2_WIDTH, 0, 0 }, // CON_CLIST_FULFILLED + { 0, 0, 0, 0 } +}; +ConditionTab *the_con_tab; + +//--------------------------------------------------------------- +// Callback functions. +//--------------------------------------------------------------- + +void draw_lists_box(void) +{ + the_con_tab->DrawListsBox(); +} + +void draw_clist_box(void) +{ + the_con_tab->DrawCurrentList(); +} + +//--------------------------------------------------------------- +// ConditionTab +//--------------------------------------------------------------- + +ConditionTab::ConditionTab() +{ + CurrentCList = NULL; + the_con_tab = this; + TabMode = COND_MODE_NONE; + + InitControlSet(cond_tab_def); + + ((CHSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->SetUpdateFunction(draw_lists_box); + ((CHSlider*)GetControlPtr(CTRL_CLIST_SLIDER))->SetUpdateFunction(draw_clist_box); +} + +//--------------------------------------------------------------- + +ConditionTab::~ConditionTab() +{ +} + +//--------------------------------------------------------------- + +void ConditionTab::DrawTabContent(void) +{ + SLONG message_height, + message_width; + EdRect message_rect; + + + SetTabDrawArea(); + ClearTab(); + + DrawControlSet(); + + DrawListsBox(); + DrawCurrentList(); + + switch(TabMode) + { + case COND_MODE_NONE: + break; + case COND_MODE_SELECT_THING: + message_height = QTStringHeight()+12; + message_width = QTStringWidth("Select A Thing")+12; + message_rect.SetRect( + 150-(message_width>>1), + 220-(message_height>>1), + message_width, + message_height + ); + message_rect.FillRect(RED_COL); + message_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + message_rect.GetLeft()+6, + message_rect.GetTop()+6, + "Select A Thing", + 0 + ); + break; + case COND_MODE_SELECT_SWITCH: + message_height = QTStringHeight()+12; + message_width = QTStringWidth("Select A Trigger")+12; + message_rect.SetRect( + 150-(message_width>>1), + 220-(message_height>>1), + message_width, + message_height + ); + message_rect.FillRect(RED_COL); + message_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + message_rect.GetLeft()+6, + message_rect.GetTop()+6, + "Select A Trigger", + 0 + ); + break; + } +} + +//--------------------------------------------------------------- + +void ConditionTab::UpdateTab(UBYTE update_level) +{ + if(update_level) + { + if(LockWorkScreen()) + { + switch(update_level) + { + case UPDATE_ALL: + DrawTabContent(); + break; + case UPDATE_LISTS_BOX: + DrawListsBox(); + break; + case UPDATE_CURRENT_LIST: + DrawCurrentList(); + break; + } + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +} + +//--------------------------------------------------------------- + +UWORD ConditionTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UBYTE update = UPDATE_NONE; + UWORD select_pos; + ULONG control_id = 0; + EditCondList *the_clist; + MFPoint local_point; + + + if(TabMode) + { + return 0; + } + if(TabData) + { + switch(DataField) + { + case 1: + DataCondition->Data1 = TabData; + break; + case 2: + DataCondition->Data2 = TabData; + break; + case 3: + DataCondition->Data3 = TabData; + break; + } + TabData = 0; + } + + SetTabDrawArea(); + + local_point = *clicked_point; + GlobalToLocal(&local_point); + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + select_pos = ListsHilitePos(&local_point); + if(select_pos) + { + CurrentCList = HilitetedList(select_pos); + if(CurrentCList) + { + ((CEditText*)GetControlPtr(CTRL_CLIST_EDIT))->SetEditString(CurrentCList->CListName); + if(CurrentCList->ConditionCount>MAX_VIEW_CONDS) + { + ((CVSlider*)GetControlPtr(CTRL_CLIST_SLIDER))->SetValueRange(0,CurrentCList->ConditionCount-MAX_VIEW_CONDS); + } + else + { + ((CVSlider*)GetControlPtr(CTRL_CLIST_SLIDER))->SetValueRange(0,0); + } + } + } + else + { + local_point = *clicked_point; + control_id = HandleControlSetClick(flags,&local_point); + HandleControl(control_id); + } + update = UPDATE_ALL; + break; + case RIGHT_CLICK: + select_pos = ListsHilitePos(&local_point); + if(select_pos) + { + the_clist = HilitetedList(select_pos); + if(the_clist) + { + DoCListPopup(&local_point,the_clist); + update = UPDATE_ALL; + } + } + else + { + select_pos = CurrentListHilitePos(&local_point); + if(select_pos) + { + DoConditionPopup(&local_point,select_pos); + update = UPDATE_ALL; + } + } + break; + } + + UpdateTab(update); + + return 0; +} + +//--------------------------------------------------------------- + +void ConditionTab::HandleTab(MFPoint *current_point) +{ + UBYTE update = UPDATE_NONE; + EdRect condition_rect, + lists_rect; + MFPoint local_point; + static BOOL cleanup = FALSE; + + + if(TabMode) + { + cleanup = TRUE; + return; + } + if(TabData) + { + switch(DataField) + { + case 1: + DataCondition->Data1 = TabData; + break; + case 2: + DataCondition->Data2 = TabData; + break; + case 3: + DataCondition->Data3 = TabData; + break; + } + TabData = 0; + } + + ModeTab::HandleTab(current_point); + + local_point = *current_point; + GlobalToLocal(&local_point); + + condition_rect.SetRect(CON_LIST_X,CON_LIST_Y,CON_LIST_WIDTH,CON_LIST_HEIGHT); + lists_rect.SetRect(LISTS_X,LISTS_Y,LISTS_WIDTH,LISTS_HEIGHT); + if(lists_rect.PointInRect(&local_point) && !cleanup) + { + update = UPDATE_LISTS_BOX; + cleanup = TRUE; + } + else if(condition_rect.PointInRect(&local_point) && !cleanup) + { + update = UPDATE_CURRENT_LIST; + cleanup = TRUE; + } + + if(update==UPDATE_NONE && cleanup) + { + update = UPDATE_ALL; + cleanup = FALSE; + } + + UpdateTab(update); +} + +//--------------------------------------------------------------- + +void ConditionTab::HandleControl(UWORD control_id) +{ + SLONG control = control_id&0xff; + + + switch(control) + { + case CTRL_NEW_CLIST: + CurrentCList = alloc_ed_clist(); + if(CurrentCList) + { + // set up the new condition list. + if(ed_clist_count>MAX_VIEW_LISTS) + { + ((CVSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->SetValueRange(0,ed_clist_count-MAX_VIEW_LISTS); + } + ((CEditText*)GetControlPtr(CTRL_CLIST_EDIT))->SetEditString(CurrentCList->CListName); + + // Allocate the first condition. + add_condition(CurrentCList,alloc_ed_condition()); + } + break; + case CTRL_LISTS_SLIDER: + break; + case CTRL_CLIST_EDIT: + strcpy(CurrentCList->CListName,((CEditText*)GetControlPtr(CTRL_CLIST_EDIT))->GetEditString()); + break; + case CTRL_CLIST_SLIDER: + break; + case CTRL_NEW_COND: + if(CurrentCList) + { + // Create a new condition. + add_condition(CurrentCList,alloc_ed_condition()); + if(CurrentCList->ConditionCount>MAX_VIEW_CONDS) + { + ((CVSlider*)GetControlPtr(CTRL_CLIST_SLIDER))->SetValueRange(0,CurrentCList->ConditionCount-MAX_VIEW_CONDS); + } + } + break; + } +} + +//--------------------------------------------------------------- + +void ConditionTab::DoCListPopup(MFPoint *clicked_point,EditCondList *the_clist) +{ + ULONG control_id = 0; + CPopUp *the_control = 0; + + + clist_popup_def.ControlLeft = clicked_point->X+4; + clist_popup_def.ControlTop = clicked_point->Y-4; + + if(the_clist==win_conditions || the_clist==lose_conditions) + { + clist_popup[0].ItemFlags = MENU_INACTIVE; + } + else + { + clist_popup[0].ItemFlags = 0; + } + + clist_popup_def.TheMenuDef = clist_popup; + the_control = new CPopUp(&clist_popup_def); + control_id = the_control->TrackControl(clicked_point); + + switch(control_id>>8) + { + case 0: + break; + case 1: + if(CurrentCList==the_clist) + { + CurrentCList = NULL; + ((CEditText*)GetControlPtr(CTRL_CLIST_EDIT))->SetEditString(""); + } + if(ed_clist_count>MAX_VIEW_LISTS) + { + ((CVSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->SetValueRange(0,(ed_clist_count-MAX_VIEW_LISTS)-1); + } + free_ed_clist(the_clist); + break; + } +} + +//--------------------------------------------------------------- + +void ConditionTab::DoConditionPopup(MFPoint *clicked_point,UWORD select_pos) +{ + UBYTE field; + ULONG control_id = 0; + CPopUp *the_control = 0; + EditCondition *the_condition; + EditCondList *the_cond_list; + + + the_condition = HilitetedCondition(select_pos); + if(the_condition) + { + condition_popup_def.ControlLeft = clicked_point->X+4; + condition_popup_def.ControlTop = clicked_point->Y-4; + + field = (select_pos&0x00ff)-1; + condition_popup_def.TheMenuDef = condition_defs[the_condition->ConditionType][field]; + + the_control = new CPopUp(&condition_popup_def); + control_id = (the_control->TrackControl(clicked_point))>>8; + + if(control_id<=5) + CommonConditionOptions(control_id,the_condition); + else + { + // Set the data fields. + if(field) + { + switch(the_condition->ConditionType) + { + case CON_NONE: + break; + case CON_THING_DEAD: + TabMode = COND_MODE_SELECT_THING; + DataCondition = the_condition; + DataField = 1; + break; + case CON_ALL_GROUP_DEAD: + the_condition->Data1 = control_id-6; + break; + case CON_PERCENT_GROUP_DEAD: + the_condition->Data1 = control_id-6; + break; + case CON_THING_NEAR_PLAYER: + TabMode = COND_MODE_SELECT_THING; + DataCondition = the_condition; + DataField = 1; + break; + case CON_GROUP_NEAR_PLAYER: + the_condition->Data1 = (control_id-6)+1; + break; + case CON_CLASS_NEAR_PLAYER: + the_condition->Data1 = (control_id-6)+1; + break; + case CON_THING_NEAR_THING: + if(field<=2) + { + TabMode = COND_MODE_SELECT_THING; + DataCondition = the_condition; + DataField = field; + } + break; + case CON_GROUP_NEAR_THING: + if(field==1) + { + the_condition->Data1 = control_id-6; + } + else if(field==2) + { + TabMode = COND_MODE_SELECT_THING; + DataCondition = the_condition; + DataField = 2; + } + break; + case CON_CLASS_NEAR_THING: + if(field==1) + { + the_condition->Data1 = (control_id-6)+1; + } + else if(field==2) + { + TabMode = COND_MODE_SELECT_THING; + DataCondition = the_condition; + DataField = 2; + } + break; + case CON_CLASS_COUNT: + break; + case CON_GROUP_COUNT: + break; + case CON_SWITCH_TRIGGERED: + TabMode = COND_MODE_SELECT_SWITCH; + DataCondition = the_condition; + DataField = 1; + break; + case CON_TIME: + break; + case CON_CLIST_FULFILLED: + if(field==1) + { + the_cond_list = SelectConditionList(); + if(the_cond_list) + { + the_condition->Data1 = ED_CONLIST_NUMBER(the_cond_list); + } + } + break; + } + } + else + { + the_condition->ConditionType = control_id-6; + } + } + } +} + +//--------------------------------------------------------------- + +void ConditionTab::CommonConditionOptions(ULONG id,EditCondition *the_condition) +{ + switch(id) + { + case 0: // NULL. + break; + case 1: // Delete Condition. + if(the_condition) + { + if(CurrentCList->ConditionCount>MAX_VIEW_CONDS) + { + ((CVSlider*)GetControlPtr(CTRL_CLIST_SLIDER))->SetValueRange(0,(CurrentCList->ConditionCount>MAX_VIEW_CONDS)-1); + } + } + remove_condition(CurrentCList,the_condition); + free_ed_condition(the_condition); + break; + case 2: // Blank. + break; + case 3: // Group Conditions. + break; + case 4: // Ungroup Conditons. + break; + case 5: // Blank. + break; + } +} + +//--------------------------------------------------------------- + +EditCondList *ConditionTab::SelectConditionList(void) +{ + BOOL exit = FALSE; + UBYTE update = 2; + UWORD select_pos; + SLONG c0; + ControlSet select_set; + EditCondList *current_list, + *hilited_list, + *selected_list = NULL; + EdRect bounds_rect, + item_rect, + lists_rect; + MFPoint current_point; + + + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + bounds_rect.SetRect ( + (WorkScreenPixelWidth-(LISTS_WIDTH+20))>>1, + (WorkScreenHeight-(LISTS_HEIGHT+7))>>1, + LISTS_WIDTH+20, + LISTS_HEIGHT+7 + ); + select_set.ControlSetBounds(&bounds_rect); + select_set.InitControlSet(select_clist_def); + if(ed_clist_count>MAX_VIEW_LISTS) + { + ((CVSlider*)select_set.GetControlPtr(1))->SetValueRange(0,ed_clist_count-MAX_VIEW_LISTS); + } + ((CVSlider*)select_set.GetControlPtr(1))->SetCurrentValue(0); + + while(SHELL_ACTIVE && !exit) + { + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + current_point.X = MouseX; + current_point.Y = MouseY; + + if(select_set.HandleControlSet(¤t_point)) + update = 1; + + lists_rect.SetRect(LISTS_X,LISTS_Y-30,LISTS_WIDTH,LISTS_HEIGHT); + current_point.X -= bounds_rect.GetLeft(); + current_point.Y -= bounds_rect.GetTop(); + select_pos = 0; + if(lists_rect.PointInRect(¤t_point)) + { + for(c0=0;c0GetCurrentValue(); + while(current_list && c0) + { + c0--; + current_list = current_list->Next; + } + + c0 = 0; + hilited_list = NULL; + while(current_list && c0CListName,0); + + c0++; + current_list = current_list->Next; + } + + lists_rect.HiliteRect(LOLITE_COL,HILITE_COL); + } + + if(update<=2) + { + select_set.DrawControlSet(); + } + + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + select_set.FiniControlSet(); + + return selected_list; +} + +//--------------------------------------------------------------- + +void ConditionTab::DrawListsBox(void) +{ + UWORD select_pos; + SLONG c0; + EditCondList *current_list; + EdRect item_rect, + lists_rect; + MFPoint local_point; + + + SetTabDrawArea(); + + local_point.X = MouseX; + local_point.Y = MouseY; + GlobalToLocal(&local_point); + + select_pos = ListsHilitePos(&local_point); + + lists_rect.SetRect(LISTS_X,LISTS_Y,LISTS_WIDTH,LISTS_HEIGHT); + lists_rect.FillRect(ACTIVE_COL); + + // Skip the beginning of the list to match the slider bar position. + current_list = clists; + c0 = ((CVSlider*)GetControlPtr(CTRL_LISTS_SLIDER))->GetCurrentValue(); + while(current_list && c0) + { + c0--; + current_list = current_list->Next; + } + + c0 = 0; + while(current_list && c0CListName,0); + + c0++; + current_list = current_list->Next; + } + lists_rect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +void ConditionTab::DrawCurrentList(void) +{ + CBYTE field_text[MAX_FIELDS][64]; + UWORD select_pos; + SLONG c0,c1, + x_pos; + EditCondition *current_condition; + EdRect field_rects[MAX_FIELDS], + list_rect; + MFPoint local_point; + + + SetTabDrawArea(); + + local_point.X = MouseX; + local_point.Y = MouseY; + GlobalToLocal(&local_point); + + select_pos = CurrentListHilitePos(&local_point); + + list_rect.SetRect(CON_LIST_X,CON_LIST_Y,CON_LIST_WIDTH,CON_LIST_HEIGHT); + list_rect.FillRect(ACTIVE_COL); + + if(CurrentCList) + { + // Skip the beginning of the list to match the slider bar position. + current_condition = CurrentCList->ConditionList; + if(current_condition) + { + c0 = ((CVSlider*)GetControlPtr(CTRL_CLIST_SLIDER))->GetCurrentValue(); + while(current_condition && c0) + { + c0--; + current_condition = current_condition->Next; + } + + c0 = 0; + while(current_condition && c0ConditionType][c1], + QTStringHeight()+1 + ); + x_pos += field_widths[current_condition->ConditionType][c1]; + } + + // Hilite the field that the mouse is currently over. + if((select_pos>>8)==(c0+1)) + { + field_rects[(select_pos&0x00ff)-1].FillRect(HILITE_COL); + } + + + // Clear all the field text. + ZeroMemory(field_text,sizeof(field_text)); + + // Set the condition field text. + sprintf(&field_text[0][0],"%s",condition_text[current_condition->ConditionType]); + + // Now set the data fields text. + switch(current_condition->ConditionType) + { + case CON_NONE: + break; + case CON_THING_DEAD: + sprintf(&field_text[1][0],"Thing %d",current_condition->Data1); + break; + case CON_ALL_GROUP_DEAD: + sprintf(&field_text[1][0],"Group %d",current_condition->Data1); + break; + case CON_PERCENT_GROUP_DEAD: + sprintf(&field_text[1][0],"Group %d",current_condition->Data1); + sprintf(&field_text[2][0],"%d%%",current_condition->Data2); + break; + case CON_THING_NEAR_PLAYER: + sprintf(&field_text[1][0],"Thing %d",current_condition->Data1); + sprintf(&field_text[2][0],"%d",current_condition->Data3); + break; + case CON_GROUP_NEAR_PLAYER: + sprintf(&field_text[1][0],"Group %d",current_condition->Data1); + sprintf(&field_text[2][0],"%d",current_condition->Data3); + break; + case CON_CLASS_NEAR_PLAYER: + sprintf(&field_text[1][0],"%s",class_text[current_condition->Data1]); + sprintf(&field_text[2][0],"%d",current_condition->Data3); + break; + case CON_THING_NEAR_THING: + sprintf(&field_text[1][0],"Thing %d",current_condition->Data1); + sprintf(&field_text[2][0],"Thing %d",current_condition->Data2); + sprintf(&field_text[3][0],"%d",current_condition->Data3); + break; + case CON_GROUP_NEAR_THING: + sprintf(&field_text[1][0],"Group %d",current_condition->Data1); + sprintf(&field_text[2][0],"Thing %d",current_condition->Data2); + sprintf(&field_text[3][0],"%d",current_condition->Data3); + break; + case CON_CLASS_NEAR_THING: + sprintf(&field_text[1][0],"%s",class_text[current_condition->Data1]); + sprintf(&field_text[2][0],"Thing %d",current_condition->Data2); + sprintf(&field_text[3][0],"%d",current_condition->Data3); + break; + case CON_CLASS_COUNT: + sprintf(&field_text[1][0],"%s",class_text[current_condition->Data1]); + sprintf(&field_text[2][0],"%d",current_condition->Data2); + break; + case CON_GROUP_COUNT: + sprintf(&field_text[1][0],"Group %s",genus_text[current_condition->Data3][current_condition->Data1]); + sprintf(&field_text[2][0],"%d",current_condition->Data2); + break; + case CON_SWITCH_TRIGGERED: + sprintf(&field_text[1][0],"%d",current_condition->Data1); + break; + case CON_TIME: + sprintf(&field_text[1][0],"0"); + break; + case CON_CLIST_FULFILLED: + if(current_condition->Data1) + { + sprintf(&field_text[1][0],"%s",edit_clists[current_condition->Data1].CListName); + } + else + { + sprintf(&field_text[1][0],"None"); + } + break; + } + + // Draw all field text. + for(c1=0;c1Next; + } + } + } + list_rect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +UWORD ConditionTab::ListsHilitePos(MFPoint *current_point) +{ + UWORD c0; + EdRect item_rect, + lists_rect; + + + lists_rect.SetRect(LISTS_X,LISTS_Y,LISTS_WIDTH,LISTS_HEIGHT); + + if(lists_rect.PointInRect(current_point)) + { + for(c0=0;c0GetCurrentValue(); + while(current_list && c0) + { + c0--; + current_list = current_list->Next; + } + + // Now skip to the hilited item. + select_pos--; + while(current_list && select_pos) + { + select_pos--; + current_list = current_list->Next; + } + + return current_list; +} + +//--------------------------------------------------------------- + +UWORD ConditionTab::CurrentListHilitePos(MFPoint *current_point) +{ + UWORD c0,c1; + SLONG x_pos; + EditCondition *current_condition; + EdRect condition_rect, + field_rects[MAX_FIELDS], + list_rect; + + + if(CurrentCList) + { + list_rect.SetRect(CON_LIST_X,CON_LIST_Y,CON_LIST_WIDTH,CON_LIST_HEIGHT); + + if(list_rect.PointInRect(current_point)) + { + for(c0=0;c0ConditionType][c1], + QTStringHeight()+1 + ); + x_pos += field_widths[current_condition->ConditionType][c1]; + + if(field_rects[c1].PointInRect(current_point)) + { + return ((c0+1)<<8)|(c1+1); + } + } + } + } + } + } + } + return 0; +} + +//--------------------------------------------------------------- + +EditCondition *ConditionTab::HilitetedCondition(UWORD select_pos) +{ + ULONG c0; + EditCondition *current_condition = NULL; + + + if(CurrentCList) + { + current_condition = CurrentCList->ConditionList; + + // Skip the beginning of the list to match the slider bar position. + c0 = ((CVSlider*)GetControlPtr(CTRL_CLIST_SLIDER))->GetCurrentValue(); + while(current_condition && c0) + { + c0--; + current_condition = current_condition->Next; + } + + // Now skip to the hilited condition. + select_pos = (select_pos>>8)-1; + while(current_condition && select_pos) + { + select_pos--; + current_condition = current_condition->Next; + } + } + + return current_condition; +} + +//--------------------------------------------------------------- + diff --git a/fallen/Editor/Source/CondTab.def b/fallen/Editor/Source/CondTab.def new file mode 100644 index 0000000..33cbf21 --- /dev/null +++ b/fallen/Editor/Source/CondTab.def @@ -0,0 +1,154 @@ + +//--------------------------------------------------------------- + +ControlDef cond_tab_def[] = +{ + { BUTTON, 0, "New Condition List", LISTS_X, 10, 0, 0 }, + { V_SLIDER, 0, "", LISTS_X+LISTS_WIDTH, LISTS_Y, 0, LISTS_HEIGHT }, + { EDIT_TEXT, 0, "", CON_NAME_X, CON_NAME_Y, CON_NAME_WIDTH, 0 }, + { V_SLIDER, 0, "", CON_LIST_X+CON_LIST_WIDTH, CON_LIST_Y, 0, CON_LIST_HEIGHT }, + { BUTTON, 0, "New Condition", CON_NAME_X+CON_NAME_WIDTH+2, CON_NAME_Y, 0, 0 }, + + { 0 } +}; + +//--------------------------------------------------------------- + +static ControlDef clist_popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 clist_popup[] = +{ + { "Delete Condition List" }, + { "!" } +}; + +//--------------------------------------------------------------- + +static ControlDef condition_popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 condition_popup[] = +{ + { "Delete Condition" }, + { "^" }, + { "Group Conditions" }, + { "Ungroup Conditions" }, + { "^" }, + { "NONE" }, + { "THING_DEAD" }, + { "ALL_GROUP_DEAD" }, + { "PERCENT_GROUP_DEAD" }, + { "THING_NEAR_PLAYER" }, + { "GROUP_NEAR_PLAYER" }, + { "CLASS_NEAR_PLAYER" }, + { "THING_NEAR_THING" }, + { "GROUP_NEAR_THING" }, + { "CLASS_NEAR_THING" }, + { "CLASS_COUNT" }, + { "GROUP_COUNT" }, + { "SWITCH_TRIGGERED" }, + { "TIME" }, + { "CLIST_FULFILLED" }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_thing_popup[] = +{ + { "Delete Condition" }, + { "^" }, + { "Group Conditions" }, + { "Ungroup Conditions" }, + { "^" }, + { "Select Thing", }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_switch_popup[] = +{ + { "Delete Condition" }, + { "^" }, + { "Group Conditions" }, + { "Ungroup Conditions" }, + { "^" }, + { "Select Switch", }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_group_popup[] = +{ + { "Delete Condition" }, + { "^" }, + { "Group Conditions" }, + { "Ungroup Conditions" }, + { "^" }, + { "Group 0" }, + { "Group 1" }, + { "Group 2" }, + { "Group 3" }, + { "Group 4" }, + { "Group 5" }, + { "Group 6" }, + { "Group 7" }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 select_class_popup[] = +{ + { "Delete Condition" }, + { "^" }, + { "Group Conditions" }, + { "Ungroup Conditions" }, + { "^" }, + { "PLAYER" }, + { "CAMERA" }, + { "PROJECTILE" }, + { "BUILDING" }, + { "PERSON" }, + { "ANIMAL" }, + { "FURNITURE" }, + { "SWITCH" }, + { "VEHICLE" }, + { "!" } +}; + +//--------------------------------------------------------------- + +MenuDef2 generic_popup[] = +{ + { "Delete Condition" }, + { "^" }, + { "Group Conditions" }, + { "Ungroup Conditions" }, + { "!" } +}; + +//--------------------------------------------------------------- +extern MenuDef2 select_clist_popup[]; + +MenuDef2 *condition_defs[][MAX_FIELDS] = +{ + { condition_popup, generic_popup, generic_popup, NULL }, // CON_NONE + { condition_popup, select_thing_popup, generic_popup, NULL }, // CON_THING_DEAD + { condition_popup, select_group_popup, generic_popup, NULL }, // CON_ALL_GROUP_DEAD + { condition_popup, select_group_popup, generic_popup, NULL }, // CON_PERCENT_GROUP_DEAD + { condition_popup, select_thing_popup, generic_popup, NULL }, // CON_THING_NEAR_PLAYER + { condition_popup, select_group_popup, generic_popup, NULL }, // CON_GROUP_NEAR_PLAYER + { condition_popup, select_class_popup, generic_popup, NULL }, // CON_CLASS_NEAR_PLAYER + { condition_popup, select_thing_popup, select_thing_popup, NULL }, // CON_THING_NEAR_THING + { condition_popup, select_group_popup, select_thing_popup, NULL }, // CON_GROUP_NEAR_THING + { condition_popup, select_class_popup, select_thing_popup, NULL }, // CON_CLASS_NEAR_THING + { condition_popup, select_class_popup, generic_popup, NULL }, // CON_CLASS_COUNT + { condition_popup, select_group_popup, generic_popup, NULL }, // CON_GROUP_COUNT + { condition_popup, select_switch_popup, NULL, NULL }, // CON_SWITCH_TRIGGERED + { condition_popup, generic_popup, generic_popup, NULL }, // CON_TIME + { condition_popup, select_clist_popup, generic_popup, NULL } // CON_CLIST_FULFILLED +}; + +//--------------------------------------------------------------- + +extern ControlDef select_clist_def[]; \ No newline at end of file diff --git a/fallen/Editor/Source/Control.cpp b/fallen/Editor/Source/Control.cpp new file mode 100644 index 0000000..92df3cf --- /dev/null +++ b/fallen/Editor/Source/Control.cpp @@ -0,0 +1,15 @@ +// Control.cpp +// Guy Simmons, 26th March 1997. + +#include "Editor.hpp" + + +//--------------------------------------------------------------- + +void handle_character_controls(void) +{ + +} + +//--------------------------------------------------------------- + \ No newline at end of file diff --git a/fallen/Editor/Source/Controls.cpp b/fallen/Editor/Source/Controls.cpp new file mode 100644 index 0000000..3a52bb0 --- /dev/null +++ b/fallen/Editor/Source/Controls.cpp @@ -0,0 +1,1806 @@ +// Controls.cpp +// Guy Simmons, 12th November 1996 + +#include "Editor.hpp" + +#ifdef EDITOR + +//--------------------------------------------------------------- + +void Control::DrawControl(void) +{ +} + +//--------------------------------------------------------------- + +UWORD Control::TrackControl(MFPoint *down_point) +{ + UBYTE start_flags, + update; + MFPoint current_point, + start_point; + + + start_flags = Flags; + start_point.X = MouseX; + start_point.Y = MouseY; + Flags = (UBYTE)(start_flags|CONTROL_CLICKED); + update = 1; + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + + if(PointInControl(¤t_point)) + { + if(!(Flags&CONTROL_CLICKED)) + { + Flags = (UBYTE)(start_flags|CONTROL_CLICKED); + update = 1; + } + } + else + { + if(Flags&CONTROL_CLICKED) + { + Flags = (UBYTE)(start_flags&~(CONTROL_HILITED)); + update = 1; + } + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControl(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + update = 0; + } + + if(Flags&CONTROL_CLICKED) + { + Flags &= ~(CONTROL_CLICKED); + return GetID(); + } + else + return 0; +} + +//--------------------------------------------------------------- + +void Control::TrackKey(void) +{ + Flags |= CONTROL_HILITED; + if(LockWorkScreen()) + { + DrawControl(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + while(SHELL_ACTIVE && Keys[GetHotKey()]); + Flags &= ~CONTROL_HILITED; +} + +//--------------------------------------------------------------- + +void Control::HiliteControl(MFPoint *current_point) +{ + Flags |= CONTROL_HILITED; + current_point = current_point; +} + +//--------------------------------------------------------------- + +void Control::UnHiliteControl(void) +{ + Flags &= ~(CONTROL_HILITED); +} + +//--------------------------------------------------------------- +// Button. +//--------------------------------------------------------------- + +CButton::CButton(ControlDef *the_def) +{ + SLONG width; + + + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetType(BUTTON); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + width = the_def->ControlWidth; + if(width < (QTStringWidth(GetTitle())+6)) + width = QTStringWidth(GetTitle())+6; + + SetRect(the_def->ControlLeft,the_def->ControlTop,width,QTStringHeight()+5); +} + +//--------------------------------------------------------------- + +void CButton::DrawControl(void) +{ + ULONG text_colour; + SLONG text_x, + text_y; + CBYTE *ptr; + + text_x = GetLeft()+((GetWidth()>>1)-(QTStringWidth(GetTitle())>>1)); + text_y = GetTop()+((GetHeight()>>1)-(QTStringHeight()>>1)); + if(GetFlags()&CONTROL_INACTIVE) + { + text_colour = LOLITE_COL; + HiliteRect(HILITE_COL,LOLITE_COL); + } + else + { + text_colour = 0; + if(GetFlags()&CONTROL_HILITED) + FillRect(HILITE_COL); + else + FillRect(CONTENT_COL); + + if(GetFlags()&CONTROL_CLICKED) + { + HiliteRect(LOLITE_COL,HILITE_COL); + text_x++; + text_y++; + } + else + HiliteRect(HILITE_COL,LOLITE_COL); + } + + ptr=GetTitle(); + if(ptr[0]=='$') + { + SLONG sprite; + sprite=(ptr[1]-'0')*10+(ptr[2]-'0'); + DrawMonoBSprite(GetLeft()+7,GetTop()+3,INTERFACE_SPRITE(sprite),0); + } + else + QuickTextC(text_x,text_y,GetTitle(),text_colour); +} + +//--------------------------------------------------------------- +// Radio button. +//--------------------------------------------------------------- + +CRadioButton::CRadioButton(ControlDef *the_def) +{ + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetType(RADIO_BUTTON); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + SetRect(the_def->ControlLeft,the_def->ControlTop,10,10); +} + +//--------------------------------------------------------------- + +void CRadioButton::DrawControl(void) +{ + ULONG text_colour; + SLONG text_x, + text_y; + + + text_x = GetRight()+4; + text_y = GetTop()+((GetHeight()>>1)-(QTStringHeight()>>1)); + if(GetFlags()&CONTROL_INACTIVE) + { + text_colour = LOLITE_COL; +// LbSpriteDrawOneColour(GetLeft(),GetTop(),INTERFACE_SPRITE(RADIO_ICON4),CONTENT_COL); + } + else + { + text_colour = 0; +/* + if(GetFlags()&CONTROL_HILITED) + LbSpriteDrawOneColour(GetLeft(),GetTop(),INTERFACE_SPRITE(RADIO_ICON4),HILITE_COL); + else + LbSpriteDrawOneColour(GetLeft(),GetTop(),INTERFACE_SPRITE(RADIO_ICON4),ACTIVE_COL); +*/ +/* + if(GetFlags()&CONTROL_CLICKED) + LbSpriteDrawOneColour(GetLeft(),GetTop(),INTERFACE_SPRITE(RADIO_ICON3),ACTIVE_COL); + else if(GetFlags()&CONTROL_SELECTED) + LbSpriteDrawOneColour(GetLeft(),GetTop(),INTERFACE_SPRITE(RADIO_ICON3),0); +*/ + } +// LbSpriteDrawOneColour(GetLeft(),GetTop(),INTERFACE_SPRITE(RADIO_ICON1),LOLITE_COL); +// LbSpriteDrawOneColour(GetLeft(),GetTop(),INTERFACE_SPRITE(RADIO_ICON2),HILITE_COL); + QuickTextC(text_x,text_y,GetTitle(),text_colour); +} + +//--------------------------------------------------------------- +// Check box. +//--------------------------------------------------------------- + +CCheckBox::CCheckBox(ControlDef *the_def) +{ + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetType(CHECK_BOX); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + SetRect(the_def->ControlLeft,the_def->ControlTop,10,10); +} + +//--------------------------------------------------------------- + +void CCheckBox::DrawControl(void) +{ + ULONG text_colour; + SLONG text_x, + text_y; + + + text_x = GetRight()+4; + text_y = GetTop()+((GetHeight()>>1)-(QTStringHeight()>>1)); + + if(GetFlags()&CONTROL_INACTIVE) + { + text_colour = LOLITE_COL; + FillRect(CONTENT_COL); + } + else + { + text_colour = 0; + if(GetFlags()&CONTROL_HILITED) + FillRect(HILITE_COL); + else + FillRect(ACTIVE_COL); + + if(GetFlags()&CONTROL_CLICKED) + DrawMonoBSpriteC(GetLeft(),GetTop(),INTERFACE_SPRITE(CHECK_ICON),ACTIVE_COL); + else if(GetFlags()&CONTROL_SELECTED) + DrawMonoBSpriteC(GetLeft(),GetTop(),INTERFACE_SPRITE(CHECK_ICON),0); + + } + HiliteRect(LOLITE_COL,HILITE_COL); + QuickTextC(text_x,text_y,GetTitle(),text_colour); +} + +//--------------------------------------------------------------- +// Static Text. +//--------------------------------------------------------------- + +CStaticText::CStaticText(ControlDef *the_def) +{ + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetType(STATIC_TEXT); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + SetRect(the_def->ControlLeft,the_def->ControlTop,QTStringWidth(GetTitle()),10); + + SetString1(""); + SetString2(""); +} + +//--------------------------------------------------------------- + +void CStaticText::DrawControl(void) +{ + CBYTE text[256]; + + + sprintf(text,"%s%s%s",GetTitle(),String1,String2); + FillRect(CONTENT_COL); + QuickTextC(GetLeft(),GetTop()+((GetHeight()>>1)-(QTStringHeight()>>1)),text,0); +} + +//--------------------------------------------------------------- +// Edit Text. +//--------------------------------------------------------------- + +CEditText::CEditText(ControlDef *the_def) +{ + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetType(EDIT_TEXT); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + SetRect(the_def->ControlLeft,the_def->ControlTop,the_def->ControlWidth,QTStringHeight()+5); + + SetEditString(""); + CursorPos = 0; + TextX = GetLeft()+2; +} + +//--------------------------------------------------------------- + +void CEditText::DrawControl(void) +{ + ULONG text_colour; + CBYTE temp_string[EDIT_TEXT_LENGTH]; + SLONG c0, + cursor_x, + text_x, + text_y; + MFTime the_time; + + + text_x = GetRight()+4; + text_y = GetTop()+((GetHeight()>>1)-(QTStringHeight()>>1)); + + if(GetFlags()&CONTROL_INACTIVE) + { + text_colour = LOLITE_COL; + FillRect(CONTENT_COL); + } + else + { + text_colour = 0; + if(GetFlags()&CONTROL_HILITED) + FillRect(HILITE_COL); + else + FillRect(ACTIVE_COL); + } + + HiliteRect(LOLITE_COL,HILITE_COL); + QuickTextC(text_x,text_y,GetTitle(),text_colour); + + if(GetFlags()&CONTROL_CLICKED) + { + strncpy(temp_string,EditText,CursorPos); + temp_string[CursorPos] = 0; + cursor_x = TextX+QTStringWidth(temp_string); + if(cursor_x>(GetRight()-2)) + { + TextX -= cursor_x-(GetRight()-1); + cursor_x = (GetRight()-1); + } + else if(cursor_x<(GetLeft()+2)) + { + TextX += (GetLeft()+2)-cursor_x; + cursor_x = (GetLeft()+2); + } + } + + text_x = TextX; + for(c0=0;c0=(GetLeft()+2)) + { + if((text_x+QTCharWidth(EditText[c0])+1)<=(GetRight()-1)) + { + QuickCharC(text_x,text_y,EditText[c0],text_colour); + } + else + break; + } + text_x += QTCharWidth(EditText[c0])+1; + } + + if(GetFlags()&CONTROL_CLICKED) + { + Time(&the_time); + if(the_time.MSeconds>500) + { + DrawVLine(cursor_x,GetTop()+1,GetBottom()-1,LOLITE_COL); + SetFlags((UBYTE)(GetFlags()|CONTROL_SHOW_EXTRA)); + } + else + { + SetFlags((UBYTE)(GetFlags()&~(CONTROL_SHOW_EXTRA))); + } + } +} + +//--------------------------------------------------------------- + +extern UBYTE InkeyToAscii[]; +extern UBYTE InkeyToAsciiShift[]; + +UWORD CEditText::TrackControl(MFPoint *down_point) +{ + CBYTE temp_string[EDIT_TEXT_LENGTH], + the_char; + UBYTE last_state = 0; + ULONG count, + update = 0; + SLONG text_x; + MFPoint current_point, + start_point; + + +// ChangeMouseSprite(INTERFACE_POINTER(2)); +// LbMouseSetPointerHotspot(2,3); + + start_point.X = MouseX; + start_point.Y = MouseY; + SelectStart = 0; + SelectEnd = strlen(EditText); + SetFlags(CONTROL_CLICKED); + LeftButton = 1; // This is a fudge to force the CursorPos to be set. + while(SHELL_ACTIVE && (GetFlags()&CONTROL_CLICKED)) + { + if(LeftButton || RightButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + if(PointInControl(¤t_point)) + { + for(count=0,text_x=TextX;counttext_x && current_point.X<(text_x+QTCharWidth(EditText[count])+1)) + { + CursorPos = count; + break; + } + text_x += QTCharWidth(EditText[count])+1; + } +/* + while(MLeftButton || MRightButton) + { +// SET0(63,63,63); +// SET0(0,0,0); + } + LeftButton = 0; + RightButton = 0; +*/ + } + else + break; + } + + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + if(PointInControl(¤t_point)) + SetFlags((CONTROL_CLICKED|CONTROL_HILITED)); + else + SetFlags(CONTROL_CLICKED); + + if(LastKey) + { + if(LastKey==KB_ENTER) + { + LastKey = 0; + update = 1; + break; + } + else if(LastKey==KB_ESC) + { + Keys[KB_ESC] = 1; + update = 1; + break; + } + else if(LastKey==KB_TAB) + { + Keys[KB_TAB] = 1; + update = 1; + break; + } + else if(Keys[KB_RIGHT]) + { + CursorPos++; + if(CursorPos>=EDIT_TEXT_LENGTH) + CursorPos = EDIT_TEXT_LENGTH-1; + else if(CursorPos>strlen(EditText)) + CursorPos = strlen(EditText); + update = 1; + } + else if(Keys[KB_LEFT]) + { + CursorPos--; + if(CursorPos<0) + CursorPos = 0; + update = 1; + } + else if(Keys[KB_BS]) + { + count = CursorPos; + CursorPos--; + if(CursorPos<0) + CursorPos = 0; + else + { + TextX += QTCharWidth(EditText[CursorPos])+1; + if(TextX>(GetLeft()+2)) + TextX = (GetLeft()+2); + + do + { + EditText[count-1] = EditText[count]; + }while(EditText[count++]); + } + update = 1; + } + else if(Keys[KB_DEL]) + { + if(CursorPosTitle); + SetHotKey(the_def->HotKey); + + width = the_def->ControlWidth; + if(width < (QTStringWidth(GetTitle())+6+8)) + width = QTStringWidth(GetTitle())+6+8; + SetRect(the_def->ControlLeft,the_def->ControlTop,width,QTStringHeight()+5); + + TheMenu = 0; + if(the_def->TheMenuDef) + { + // Find widest menu item. + height = GetHeight(); + width = 0; + current_menu_def = the_def->TheMenuDef; + while(*(current_menu_def->ItemText) != '!') + { + if(width < QTStringWidth(current_menu_def->ItemText)) + width = QTStringWidth(current_menu_def->ItemText); + current_menu_def++; + } + width += 4; + + // Set up menu items. + item_rect.SetRect(GetRight()+1,GetTop(),width,0); + current_menu_def = the_def->TheMenuDef; + menu_height = 0; + while(*(current_menu_def->ItemText) != '!') + { + item_count++; + current_menu_def->ItemID = (UBYTE)item_count; + if(*(current_menu_def->ItemText) == '^') + { + current_menu_def->ItemFlags = MENU_SEPERATOR; + item_rect.SetRect(item_rect.GetLeft(),item_rect.GetBottom()+1,width,(height>>1)-1); + menu_height += (height>>1)-1; + } + else if(*(current_menu_def->ItemText) == '@') + { + current_menu_def->ItemFlags = MENU_INACTIVE; + item_rect.SetRect(item_rect.GetLeft(),item_rect.GetBottom()+1,width,height-1); + menu_height += height-1; + } + else + { + current_menu_def->ItemFlags = MENU_NORMAL; + item_rect.SetRect(item_rect.GetLeft(),item_rect.GetBottom()+1,width,height-1); + menu_height += height-1; + } + current_menu_def->ItemRect = item_rect; + current_menu_def++; + } + current_menu_def->ItemFlags = MENU_END; + TheMenu = the_def->TheMenuDef; + ItemsRect.SetRect(item_rect.GetLeft(),GetTop(),width,menu_height+1); + } +} + +//--------------------------------------------------------------- + +void CPullDown::DrawControl(void) +{ + ULONG text_colour; + SLONG draw_x, + draw_y; + MenuDef2 *current_menu_def; + + + draw_x = GetLeft()+(((GetWidth()-8)>>1)-(QTStringWidth(GetTitle())>>1)); + draw_y = GetTop()+((GetHeight()>>1)-(QTStringHeight()>>1)); + if(GetFlags()&CONTROL_INACTIVE) + { + QuickTextC(draw_x,draw_y,GetTitle(),LOLITE_COL); + HiliteRect(HILITE_COL,LOLITE_COL); + } + else + { + if(GetFlags()&CONTROL_HILITED) + FillRect(HILITE_COL); + else + FillRect(CONTENT_COL); + + QuickTextC(draw_x,draw_y,GetTitle(),0); + if(GetFlags()&CONTROL_CLICKED) + { + if(TheMenu) + { + ItemsRect.FillRect(CONTENT_COL); + current_menu_def = TheMenu; + do + { + if(current_menu_def->ItemFlags&MENU_HILITED) + { + current_menu_def->ItemRect.FillRect(HILITE_COL); + } + else + { + current_menu_def->ItemRect.FillRect(CONTENT_COL); + } + if(current_menu_def->ItemFlags&MENU_SEPERATOR) + { + draw_x = current_menu_def->ItemRect.GetLeft(); + draw_y = current_menu_def->ItemRect.GetTop()+(current_menu_def->ItemRect.GetHeight()>>1); + DrawHLineC(draw_x,current_menu_def->ItemRect.GetRight(),draw_y+1,LOLITE_COL); + DrawHLineC(draw_x,current_menu_def->ItemRect.GetRight(),draw_y+2,HILITE_COL); + } + else + { + draw_x = current_menu_def->ItemRect.GetLeft()+2; + draw_y = current_menu_def->ItemRect.GetTop()+((current_menu_def->ItemRect.GetHeight()>>1)-(QTStringHeight()>>1)); + + if(current_menu_def->ItemFlags&MENU_INACTIVE) + text_colour = LOLITE_COL; + else + text_colour = 0; + QuickTextC(draw_x,draw_y,current_menu_def->ItemText,text_colour); + } + current_menu_def++; + }while(current_menu_def->ItemFlags!=MENU_END); + ItemsRect.HiliteRect(HILITE_COL,LOLITE_COL); + } + } + HiliteRect(HILITE_COL,LOLITE_COL); + DrawMonoBSpriteC(GetLeft()+(GetWidth()-10),GetTop()+2,INTERFACE_SPRITE(MENU_ICON),0); + } +} + +//--------------------------------------------------------------- + +UWORD CPullDown::TrackControl(MFPoint *down_point) +{ + UBYTE menu_id = 0; + SLONG y_offset = 0; + MenuDef2 *current_menu_def; + MFPoint current_point, + last_point, + start_point; + + + // Do the menu stuff. + start_point.X = MouseX; + start_point.Y = MouseY; + SetFlags(CONTROL_CLICKED); + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + if(current_point.X!=last_point.X || current_point.Y!=last_point.Y) + { + if(PointInControl(¤t_point)) + SetFlags((CONTROL_CLICKED|CONTROL_HILITED)); + else + SetFlags(CONTROL_CLICKED); + + if(TheMenu) + { + menu_id = 0; + current_menu_def = TheMenu; + do + { + if(!(current_menu_def->ItemFlags&MENU_SEPERATOR)) + { + if ( + !(current_menu_def->ItemFlags&MENU_INACTIVE) && + current_menu_def->ItemRect.PointInRect(¤t_point) + ) + { + current_menu_def->ItemFlags |= MENU_HILITED; + menu_id = current_menu_def->ItemID; + } + else + current_menu_def->ItemFlags &= ~(MENU_HILITED); + } + current_menu_def++; + }while(current_menu_def->ItemFlags!=MENU_END); + } + + MFRect backup_rect; + + backup_rect = WorkWindowRect; + SetWorkWindowBounds ( + backup_rect.Left, + backup_rect.Top, + WorkScreenPixelWidth-backup_rect.Left, + WorkScreenHeight-backup_rect.Top + ); + if(LockWorkScreen()) + { + DrawControl(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + SetWorkWindowBounds(backup_rect.Left,backup_rect.Top,backup_rect.Width,backup_rect.Height); + last_point = current_point; +/* + if(LockWorkScreen()) + { + DrawControl(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + last_point = current_point; +*/ + } + } + SetFlags((UBYTE)(GetFlags()&~(CONTROL_CLICKED))); + + if(menu_id) + return (UWORD)((menu_id<<8)|GetID()); + else + return 0; +} + +//--------------------------------------------------------------- +// Popup Menu. +//--------------------------------------------------------------- + +CPopUp::CPopUp(ControlDef *the_def) +{ + SLONG item_count = 0, + height,menu_height,width; + MenuDef2 *current_menu_def; + EdRect item_rect; + + + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetType(POPUP_MENU); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + SetRect(the_def->ControlLeft,the_def->ControlTop,0,QTStringHeight()+6); + + TheMenu = 0; + if(the_def->TheMenuDef) + { + // Find dimensions of menu. + height = GetHeight(); + menu_height = 0; + width = 0; + current_menu_def = the_def->TheMenuDef; + while(*(current_menu_def->ItemText) != '!') + { + // Find widest item. + if(width < QTStringWidth(current_menu_def->ItemText)) + width = QTStringWidth(current_menu_def->ItemText); + + // Keep a tally of the total height. + if(*(current_menu_def->ItemText) == '^') + menu_height += (height>>1)-1; + else if(*(current_menu_def->ItemText) == '~') + menu_height += height-1; + else + menu_height += height-1; + + current_menu_def++; + } + width += 4+10; + + // If the menu is going to end up outside the WorkWindow we need to reposition it. + if((GetLeft()+width)>WorkWindowWidth) + { + MoveRect(GetLeft()-(width+4),GetTop()); + } + if((GetTop()+menu_height)>WorkWindowHeight) + { + MoveRect(GetLeft(),GetTop()-((GetTop()+menu_height)-WorkWindowHeight)); + } + + // Set up menu items. + item_rect.SetRect(GetRight()+1,GetTop(),width,0); + current_menu_def = the_def->TheMenuDef; + menu_height = 0; + while(*(current_menu_def->ItemText) != '!') + { + item_count++; + current_menu_def->ItemID = (UBYTE)item_count; + if(*(current_menu_def->ItemText) == '^') + { + current_menu_def->ItemFlags |= MENU_SEPERATOR; + item_rect.SetRect(item_rect.GetLeft(),item_rect.GetBottom()+1,width,(height>>1)-1); + menu_height += (height>>1)-1; + } + else if(*(current_menu_def->ItemText) == '~') + { + current_menu_def->ItemFlags |= MENU_CHECK; + item_rect.SetRect(item_rect.GetLeft(),item_rect.GetBottom()+1,width,height-1); + menu_height += height-1; + } + else + { + current_menu_def->ItemFlags |= MENU_NORMAL; + item_rect.SetRect(item_rect.GetLeft(),item_rect.GetBottom()+1,width,height-1); + menu_height += height-1; + } + current_menu_def->ItemRect = item_rect; + current_menu_def++; + } + current_menu_def->ItemFlags = MENU_END; + TheMenu = the_def->TheMenuDef; + ItemsRect.SetRect(item_rect.GetLeft(),GetTop(),width,menu_height+1); + } +} + +//--------------------------------------------------------------- + +void CPopUp::DrawControl(void) +{ + ULONG text_colour; + SLONG draw_x, + draw_y; + MenuDef2 *current_menu_def; + + + if(GetFlags()&CONTROL_CLICKED) + { + if(TheMenu) + { + ItemsRect.FillRect(CONTENT_COL); + current_menu_def = TheMenu; + do + { + if(current_menu_def->ItemFlags&MENU_HILITED) + { + current_menu_def->ItemRect.FillRect(HILITE_COL); + } + else + { + current_menu_def->ItemRect.FillRect(CONTENT_COL); + } + if(current_menu_def->ItemFlags&MENU_SEPERATOR) + { + draw_x = current_menu_def->ItemRect.GetLeft(); + draw_y = current_menu_def->ItemRect.GetTop()+(current_menu_def->ItemRect.GetHeight()>>1); + DrawHLineC(draw_x,current_menu_def->ItemRect.GetRight(),draw_y,LOLITE_COL); + DrawHLineC(draw_x,current_menu_def->ItemRect.GetRight(),draw_y+1,HILITE_COL); + } + else + { + draw_x = current_menu_def->ItemRect.GetLeft()+2; + draw_y = current_menu_def->ItemRect.GetTop()+((current_menu_def->ItemRect.GetHeight()>>1)-(QTStringHeight()>>1)); + + if(current_menu_def->ItemFlags&MENU_INACTIVE) + text_colour = LOLITE_COL; + else + text_colour = 0; + if(current_menu_def->ItemFlags&MENU_CHECK) + { + if(current_menu_def->ItemFlags&MENU_CHECK_MASK) + DrawMonoBSpriteC(draw_x,draw_y,INTERFACE_SPRITE(CHECK_ICON),text_colour); + QuickTextC(draw_x+10,draw_y,current_menu_def->ItemText+1,text_colour); + } + else + QuickTextC(draw_x+10,draw_y,current_menu_def->ItemText,text_colour); + } + current_menu_def++; + }while(current_menu_def->ItemFlags!=MENU_END); + ItemsRect.HiliteRect(HILITE_COL,LOLITE_COL); + } + } +} + +//--------------------------------------------------------------- + +UWORD CPopUp::TrackControl(MFPoint *down_point) +{ + UBYTE menu_id = 0; + MenuDef2 *current_menu_def; + MFPoint current_point, + last_point, + start_point; + + + start_point.X = MouseX; + start_point.Y = MouseY; + SetFlags(CONTROL_CLICKED); + while(SHELL_ACTIVE && (LeftButton || RightButton)) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + if(current_point.X!=last_point.X || current_point.Y!=last_point.Y || LeftMouse.ButtonState) + { + if(PointInControl(¤t_point)) + SetFlags((CONTROL_CLICKED|CONTROL_HILITED)); + else + SetFlags(CONTROL_CLICKED); + + if(TheMenu) + { + menu_id = 0; + current_menu_def = TheMenu; + do + { + if(!(current_menu_def->ItemFlags&MENU_SEPERATOR)) + { + if(!(current_menu_def->ItemFlags&MENU_INACTIVE) && current_menu_def->ItemRect.PointInRect(¤t_point)) + { + current_menu_def->ItemFlags |= MENU_HILITED; + menu_id = current_menu_def->ItemID; + if(LeftMouse.ButtonState && current_menu_def->ItemFlags&MENU_CHECK) + { + current_menu_def->ItemFlags ^= MENU_CHECK_MASK; + if(current_menu_def->ItemFlags&MENU_CHECK_MASK) + if(current_menu_def->MutualExclusiveID) + { + MenuDef2 *current_menu_def2; + current_menu_def2 = TheMenu; + do + { + if((current_menu_def2->MutualExclusiveID==current_menu_def->MutualExclusiveID)&& + (current_menu_def2!=current_menu_def)) + { + current_menu_def2->ItemFlags&=~MENU_CHECK_MASK; + + } + + current_menu_def2++; + }while(current_menu_def2->ItemFlags!=MENU_END); + + } + LeftMouse.ButtonState = 0; + } + } + else + current_menu_def->ItemFlags &= ~(MENU_HILITED); + } + current_menu_def++; + }while(SHELL_ACTIVE && (current_menu_def->ItemFlags!=MENU_END)); + } + + if(LockWorkScreen()) + { + DrawControl(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + last_point = current_point; + } + } + SetFlags((UBYTE)(GetFlags()&~(CONTROL_CLICKED))); + + if(menu_id && TheMenu[menu_id-1].ItemFlags&MENU_CHECK) + { +// TheMenu[menu_id-1].ItemFlags ^= MENU_CHECK_MASK; + } + + LeftMouse.ButtonState = 0; + + return (UWORD)((menu_id<<8)|GetID()); +} + +//--------------------------------------------------------------- + +void CPopUp::SetItemState(UWORD item,UBYTE state) +{ + switch(state) + { + case CTRL_ACTIVE: + SetItemFlags(item,(UBYTE)(GetItemFlags(item)&~(MENU_INACTIVE))); + break; + case CTRL_INACTIVE: + SetItemFlags(item,(UBYTE)(GetItemFlags(item)|MENU_INACTIVE)); + break; + } +} + +//--------------------------------------------------------------- +// HSlider Menu. +//--------------------------------------------------------------- + +CHSlider::CHSlider(ControlDef *the_def) +{ + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetDragFlags(0); + SetLeftButtonFlags(0); + SetRightButtonFlags(0); + SetType(H_SLIDER); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + SetRect(the_def->ControlLeft,the_def->ControlTop,the_def->ControlWidth,SLIDER_SIZE); + LeftButtonRect.SetRect(GetLeft(),GetTop(),GetHeight(),GetHeight()); + RightButtonRect.SetRect(GetRight()-9,GetTop(),GetHeight(),GetHeight()); + DragRect.SetRect(LeftButtonRect.GetRight()+1,GetTop()+1,40,GetHeight()-2); + + SetValueStep(1); + SetValueRange(0,0); + SetCurrentValue(0); + CurrentDrag = 0; + SetUpdateFunction(0); +} + +//--------------------------------------------------------------- + +void CHSlider::DrawControl(void) +{ + CBYTE text[16]; + UBYTE draw_colour; + SLONG sprite_x, + sprite_y, + text_x, + text_y; + + + // Draw drag rect. + if(DragStep) + { + FillRect(ACTIVE_COL); + if(DragFlags&CONTROL_HILITED) + DragRect.FillRect(HILITE_COL); + else + DragRect.FillRect(CONTENT_COL); + // if(DragFlags&CONTROL_SHOW_EXTRA) + { + sprintf(text,"%d",CurrentValue); + text_x = DragRect.GetLeft()+1+((DragRect.GetWidth()-QTStringWidth(text))>>1); + text_y = DragRect.GetTop()+((DragRect.GetHeight()-QTStringHeight())>>1); + QuickTextC(text_x,text_y,text,0); + } + DragRect.HiliteRect(HILITE_COL,LOLITE_COL); + draw_colour = 0; + } + else + { + FillRect(CONTENT_COL); + draw_colour = LOLITE_COL; + } + + HiliteRect(LOLITE_COL,HILITE_COL); + + // Draw left button. + if(LeftButtonFlags&CONTROL_HILITED) + LeftButtonRect.FillRect(HILITE_COL); + else + LeftButtonRect.FillRect(CONTENT_COL); + sprite_x = LeftButtonRect.GetLeft()+2; + sprite_y = LeftButtonRect.GetTop()+2; + if(LeftButtonFlags&CONTROL_CLICKED) + { + LeftButtonRect.HiliteRect(LOLITE_COL,HILITE_COL); + sprite_x++; + sprite_y++; + } + else + LeftButtonRect.HiliteRect(HILITE_COL,LOLITE_COL); + DrawMonoBSpriteC(sprite_x,sprite_y,INTERFACE_SPRITE(LEFT_ICON),draw_colour); + + // Draw right button. + if(RightButtonFlags&CONTROL_HILITED) + RightButtonRect.FillRect(HILITE_COL); + else + RightButtonRect.FillRect(CONTENT_COL); + sprite_x = RightButtonRect.GetLeft()+2; + sprite_y = RightButtonRect.GetTop()+2; + if(RightButtonFlags&CONTROL_CLICKED) + { + RightButtonRect.HiliteRect(LOLITE_COL,HILITE_COL); + sprite_x++; + sprite_y++; + } + else + RightButtonRect.HiliteRect(HILITE_COL,LOLITE_COL); + DrawMonoBSpriteC(sprite_x,sprite_y,INTERFACE_SPRITE(RIGHT_ICON),draw_colour); +} + +//--------------------------------------------------------------- + +void CHSlider::HiliteControl(MFPoint *current_point) +{ + UnHiliteControl(); + if(DragStep) + { + if(DragRect.PointInRect(current_point)) + DragFlags |= CONTROL_HILITED; + else if(LeftButtonRect.PointInRect(current_point)) + LeftButtonFlags |= CONTROL_HILITED; + else if(RightButtonRect.PointInRect(current_point)) + RightButtonFlags |= CONTROL_HILITED; + SetFlags((UBYTE)(GetFlags()|CONTROL_HILITED)); + } +} + +//--------------------------------------------------------------- + +void CHSlider::UnHiliteControl(void) +{ + DragFlags &= ~(CONTROL_HILITED); + LeftButtonFlags &= ~(CONTROL_HILITED); + RightButtonFlags &= ~(CONTROL_HILITED); + SetFlags((UBYTE)(GetFlags()&~(CONTROL_HILITED))); +} + +//--------------------------------------------------------------- + +UWORD CHSlider::TrackControl(MFPoint *down_point) +{ + UBYTE start_flags, + update; + SLONG drag_x, + new_drag_x, + start_time; + MFPoint current_point, + last_point, + start_point; + MFTime the_time; + + + if(DragStep) + { + update = 1; + start_point.X = MouseX; + start_point.Y = MouseY; + if(DragRect.PointInRect(down_point)) + { + drag_x = DragRect.GetLeft(); + last_point.X = down_point->X; + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + + if(current_point.X!=last_point.X) + { + drag_x += current_point.X-last_point.X; + new_drag_x = (drag_x-MinDrag)*ValueStep; + + SetCurrentValue((new_drag_x<<16)/DragStep); + + update = 1; + last_point = current_point; + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControl(); + if(update_function) + update_function(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + return GetID(); + } + else if(LeftButtonRect.PointInRect(down_point)) + { + start_time = GetTickCount()/251; + start_flags = LeftButtonFlags; + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + + if(LeftButtonRect.PointInRect(¤t_point)) + { + if(!(LeftButtonFlags&CONTROL_CLICKED)) + { + LeftButtonFlags = (UBYTE)(start_flags|CONTROL_CLICKED); + CurrentValue -= ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag -= DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(MinDrag+(CurrentDrag>>16),DragRect.GetTop()); + update = 1; + } + else + { + if((GetTickCount()/251)>(start_time+2)) + { + CurrentValue -= ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag -= DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(MinDrag+(CurrentDrag>>16),DragRect.GetTop()); + update = 2; + start_time = (GetTickCount()/251)-6; + } + } + } + else + { + if(LeftButtonFlags&CONTROL_CLICKED) + { + LeftButtonFlags = (UBYTE)(start_flags&~(CONTROL_HILITED)); + update = 1; + } + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControl(); + if(update==2) + if(update_function) + update_function(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + LeftButtonFlags &= ~(CONTROL_CLICKED); + return GetID(); + } + else if(RightButtonRect.PointInRect(down_point)) + { + start_time = GetTickCount()/251; + start_flags = RightButtonFlags; + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + + if(RightButtonRect.PointInRect(¤t_point)) + { + if(!(RightButtonFlags&CONTROL_CLICKED)) + { + RightButtonFlags = (UBYTE)(start_flags|CONTROL_CLICKED); + CurrentValue += ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag += DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(MinDrag+(CurrentDrag>>16),DragRect.GetTop()); + update = 1; + } + else + { + if((GetTickCount()/251)>(start_time+2)) + { + CurrentValue += ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag += DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(MinDrag+(CurrentDrag>>16),DragRect.GetTop()); + update = 2; + start_time = (GetTickCount()/251)-6; + } + } + } + else + { + if(RightButtonFlags&CONTROL_CLICKED) + { + RightButtonFlags = (UBYTE)(start_flags&~(CONTROL_HILITED)); + update = 1; + } + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControl(); + if(update==2) + if(update_function) + update_function(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + RightButtonFlags &= ~(CONTROL_CLICKED); + return GetID(); + } + } + return 0; +} + +//--------------------------------------------------------------- + +BOOL CHSlider::PointInControl(MFPoint *the_point) +{ + if(DragRect.PointInRect(the_point)) + { + if(LeftButtonFlags&CONTROL_HILITED || RightButtonFlags&CONTROL_HILITED) + UnHiliteControl(); + return TRUE; + } + else if(LeftButtonRect.PointInRect(the_point)) + { + if(DragFlags&CONTROL_HILITED) + UnHiliteControl(); + return TRUE; + } + else if(RightButtonRect.PointInRect(the_point)) + { + if(DragFlags&CONTROL_HILITED) + UnHiliteControl(); + return TRUE; + } + else + return FALSE; +} + +//--------------------------------------------------------------- + +void CHSlider::SetupDrag(void) +{ + MinDrag = LeftButtonRect.GetRight()+1; + MaxDrag = (RightButtonRect.GetLeft())-DragRect.GetWidth(); + if(MaxValue-MinValue) + DragStep = ((MaxDrag-MinDrag)<<16)/((MaxValue-MinValue)/ValueStep); + else + DragStep = 0; +} + +//--------------------------------------------------------------- + +void CHSlider::SetCurrentValue(SLONG value) +{ + CurrentValue = value; + if(ValueStep) + CurrentValue -= CurrentValue%ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + if(DragStep) + { + CurrentDrag = (CurrentValue/ValueStep)*DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(MinDrag+(CurrentDrag>>16),DragRect.GetTop()); + } +} + +//--------------------------------------------------------------- +// VSlider Menu. +//--------------------------------------------------------------- + +CVSlider::CVSlider(ControlDef *the_def) +{ + SetLastControl(NULL); + SetNextControl(NULL); + + SetFlags(0); + SetDragFlags(0); + SetTopButtonFlags(0); + SetBottomButtonFlags(0); + SetType(V_SLIDER); + SetTitle(the_def->Title); + SetHotKey(the_def->HotKey); + + SetRect(the_def->ControlLeft,the_def->ControlTop,SLIDER_SIZE,the_def->ControlHeight); + TopButtonRect.SetRect(GetLeft(),GetTop(),SLIDER_SIZE,SLIDER_SIZE); + BottomButtonRect.SetRect(GetLeft(),GetBottom()-(SLIDER_SIZE-1),SLIDER_SIZE,SLIDER_SIZE); + DragRect.SetRect(GetLeft()+1,TopButtonRect.GetBottom()+1,GetWidth()-2,40); + + SetValueStep(1); + SetValueRange(0,0); + SetCurrentValue(0); + CurrentDrag = 0; + SetUpdateFunction(0); +} + +//--------------------------------------------------------------- + +void CVSlider::DrawControl(void) +{ + UBYTE draw_colour; + SLONG sprite_x, + sprite_y, + text_x, + text_y; + + + // Draw drag rect. + if(DragStep) + { + FillRect(ACTIVE_COL); + + if(DragFlags&CONTROL_HILITED) + DragRect.FillRect(HILITE_COL); + else + DragRect.FillRect(CONTENT_COL); + DragRect.HiliteRect(HILITE_COL,LOLITE_COL); + draw_colour = 0; + } + else + { + FillRect(CONTENT_COL); + draw_colour = LOLITE_COL; + } + + HiliteRect(LOLITE_COL,HILITE_COL); + + // Draw top button. + if(TopButtonFlags&CONTROL_HILITED) + TopButtonRect.FillRect(HILITE_COL); + else + TopButtonRect.FillRect(CONTENT_COL); + sprite_x = TopButtonRect.GetLeft()+2; + sprite_y = TopButtonRect.GetTop()+2; + if(TopButtonFlags&CONTROL_CLICKED) + { + TopButtonRect.HiliteRect(LOLITE_COL,HILITE_COL); + sprite_x++; + sprite_y++; + } + else + TopButtonRect.HiliteRect(HILITE_COL,LOLITE_COL); + DrawMonoBSpriteC(sprite_x,sprite_y,INTERFACE_SPRITE(UP_ICON),draw_colour); + + // Draw bottom button. + if(BottomButtonFlags&CONTROL_HILITED) + BottomButtonRect.FillRect(HILITE_COL); + else + BottomButtonRect.FillRect(CONTENT_COL); + sprite_x = BottomButtonRect.GetLeft()+2; + sprite_y = BottomButtonRect.GetTop()+2; + if(BottomButtonFlags&CONTROL_CLICKED) + { + BottomButtonRect.HiliteRect(LOLITE_COL,HILITE_COL); + sprite_x++; + sprite_y++; + } + else + BottomButtonRect.HiliteRect(HILITE_COL,LOLITE_COL); + DrawMonoBSpriteC(sprite_x,sprite_y,INTERFACE_SPRITE(DOWN_ICON),draw_colour); +} + +//--------------------------------------------------------------- + +void CVSlider::HiliteControl(MFPoint *current_point) +{ + UnHiliteControl(); + if(DragStep) + { + if(DragRect.PointInRect(current_point)) + DragFlags |= CONTROL_HILITED; + else if(TopButtonRect.PointInRect(current_point)) + TopButtonFlags |= CONTROL_HILITED; + else if(BottomButtonRect.PointInRect(current_point)) + BottomButtonFlags |= CONTROL_HILITED; + SetFlags((UBYTE)(GetFlags()|CONTROL_HILITED)); + } +} + +//--------------------------------------------------------------- + +void CVSlider::UnHiliteControl(void) +{ + DragFlags &= ~(CONTROL_HILITED); + TopButtonFlags &= ~(CONTROL_HILITED); + BottomButtonFlags &= ~(CONTROL_HILITED); + SetFlags((UBYTE)(GetFlags()&~(CONTROL_HILITED))); +} + +//--------------------------------------------------------------- + +UWORD CVSlider::TrackControl(MFPoint *down_point) +{ + UBYTE start_flags, + update; + SLONG drag_y, + new_drag_y, + start_time; + MFPoint current_point, + last_point, + start_point; + MFTime the_time; + + + if(DragStep) + { + update = 1; + start_point.X = MouseX; + start_point.Y = MouseY; + if(DragRect.PointInRect(down_point)) + { + drag_y = DragRect.GetTop(); + last_point.Y = down_point->Y; + while(SHELL_ACTIVE && LeftButton) + { + current_point.Y = down_point->Y+(MouseY-start_point.Y); + + if(current_point.Y!=last_point.Y) + { + drag_y += current_point.Y-last_point.Y; + new_drag_y = (drag_y-MinDrag)*ValueStep; + + SetCurrentValue((new_drag_y<<16)/DragStep); + + update = 1; + last_point = current_point; + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControl(); + if(update_function) + update_function(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + return GetID(); + } + else if(TopButtonRect.PointInRect(down_point)) + { + start_time = GetTickCount()/251; + start_flags = TopButtonFlags; + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + + if(TopButtonRect.PointInRect(¤t_point)) + { + if(!(TopButtonFlags&CONTROL_CLICKED)) + { + TopButtonFlags = (UBYTE)(start_flags|CONTROL_CLICKED); + CurrentValue -= ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag -= DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(DragRect.GetLeft(),MinDrag+(CurrentDrag>>16)); + update = 2; + } + else + { + if((GetTickCount()/251)>(start_time+2)) + { + CurrentValue -= ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag -= DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(DragRect.GetLeft(),MinDrag+(CurrentDrag>>16)); + update = 2; + start_time = (GetTickCount()/251)-6; + } + } + } + else + { + if(TopButtonFlags&CONTROL_CLICKED) + { + TopButtonFlags = (UBYTE)(start_flags&~(CONTROL_HILITED)); + update = 1; + } + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControl(); + if(update==2) + if(update_function) + update_function(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + TopButtonFlags &= ~(CONTROL_CLICKED); + return GetID(); + } + else if(BottomButtonRect.PointInRect(down_point)) + { + start_time = GetTickCount()/251; + start_flags = BottomButtonFlags; + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = down_point->X+(MouseX-start_point.X); + current_point.Y = down_point->Y+(MouseY-start_point.Y); + + if(BottomButtonRect.PointInRect(¤t_point)) + { + if(!(BottomButtonFlags&CONTROL_CLICKED)) + { + BottomButtonFlags = (UBYTE)(start_flags|CONTROL_CLICKED); + CurrentValue += ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag += DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(DragRect.GetLeft(),MinDrag+(CurrentDrag>>16)); + update = 2; + } + else + { + if((GetTickCount()/251)>(start_time+2)) + { + CurrentValue += ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + CurrentDrag += DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(DragRect.GetLeft(),MinDrag+(CurrentDrag>>16)); + update = 2; + start_time = (GetTickCount()/251)-6; + } + } + } + else + { + if(BottomButtonFlags&CONTROL_CLICKED) + { + BottomButtonFlags = (UBYTE)(start_flags&~(CONTROL_HILITED)); + update = 1; + } + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControl(); + if(update==2) + if(update_function) + update_function(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + BottomButtonFlags &= ~(CONTROL_CLICKED); + return GetID(); + } + } + return 0; +} + +//--------------------------------------------------------------- + +BOOL CVSlider::PointInControl(MFPoint *the_point) +{ + if(DragRect.PointInRect(the_point)) + { + if(TopButtonFlags&CONTROL_HILITED || BottomButtonFlags&CONTROL_HILITED) + UnHiliteControl(); + return TRUE; + } + else if(TopButtonRect.PointInRect(the_point)) + { + if(DragFlags&CONTROL_HILITED) + UnHiliteControl(); + return TRUE; + } + else if(BottomButtonRect.PointInRect(the_point)) + { + if(DragFlags&CONTROL_HILITED) + UnHiliteControl(); + return TRUE; + } + else + return FALSE; +} + +//--------------------------------------------------------------- + +void CVSlider::SetupDrag(void) +{ + MinDrag = TopButtonRect.GetBottom()+1; + MaxDrag = (BottomButtonRect.GetTop())-DragRect.GetHeight(); + if(MaxValue-MinValue) + DragStep = ((MaxDrag-MinDrag)<<16)/((MaxValue-MinValue)/ValueStep); + else + DragStep = 0; + + SetCurrentValue(CurrentValue); +} + +//--------------------------------------------------------------- + +void CVSlider::SetCurrentValue(SLONG value) +{ + CurrentValue = value; + if(ValueStep) + CurrentValue -= CurrentValue%ValueStep; + in_range(CurrentValue,MinValue,MaxValue); + if(DragStep) + { + CurrentDrag = (CurrentValue/ValueStep)*DragStep; + in_range(CurrentDrag,0,(MaxDrag-MinDrag)<<16); + DragRect.MoveRect(DragRect.GetLeft(),MinDrag+(CurrentDrag>>16)); + } +} + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Source/CtrlSet.cpp b/fallen/Editor/Source/CtrlSet.cpp new file mode 100644 index 0000000..46fbee4 --- /dev/null +++ b/fallen/Editor/Source/CtrlSet.cpp @@ -0,0 +1,486 @@ +// CtrlSet.cpp +// Guy Simmons, 25th November 1996. + +#include "Editor.hpp" + + +//--------------------------------------------------------------- +// Private member functions +//--------------------------------------------------------------- + +void ControlSet::AddControl(Control *the_control) +{ + if(the_control) + { + if(CurrentControl == NULL) // Start of list? + { + CurrentControl = the_control; + ControlList = CurrentControl; + } + else + { + CurrentControl->SetNextControl(the_control); + the_control->SetLastControl(CurrentControl); + CurrentControl = the_control; + } + ControlCount++; + CurrentControl->SetID(ControlCount); + } +} + +//--------------------------------------------------------------- +// Public member functions +//--------------------------------------------------------------- + +ControlSet::ControlSet(ControlDef *defs) +{ + ControlList = NULL; + CurrentControl = NULL; + ControlCount = 0; + + InitControlSet(defs); +} + +//--------------------------------------------------------------- + +ControlSet::ControlSet() +{ + ControlList = NULL; + CurrentControl = NULL; + ControlCount = 0; +} + +//--------------------------------------------------------------- + +ControlSet::~ControlSet() +{ + FiniControlSet(); +} + +//--------------------------------------------------------------- + +void ControlSet::InitControlSet(ControlDef *defs) +{ + FiniControlSet(); + while(defs->ControlType) + { + switch(defs->ControlType) + { + case BUTTON: + AddControl(new CButton(defs)); + break; + case RADIO_BUTTON: + AddControl(new CRadioButton(defs)); + break; + case CHECK_BOX: + AddControl(new CCheckBox(defs)); + break; + case STATIC_TEXT: + AddControl(new CStaticText(defs)); + break; + case EDIT_TEXT: + AddControl(new CEditText(defs)); + break; + case PULLDOWN_MENU: + AddControl(new CPullDown(defs)); + break; + case POPUP_MENU: + break; + case H_SLIDER: + AddControl(new CHSlider(defs)); + break; + case V_SLIDER: + AddControl(new CVSlider(defs)); + break; + } + defs++; + } +} + +//--------------------------------------------------------------- + +void ControlSet::FiniControlSet(void) +{ + Control *current_control, + *next_control; + + + current_control = ControlList; + while(current_control) + { + next_control = current_control->GetNextControl(); + switch(current_control->GetType()) + { + case BUTTON: + delete (CButton*)current_control; + break; + case RADIO_BUTTON: + delete (CRadioButton*)current_control; + break; + case CHECK_BOX: + delete (CCheckBox*)current_control; + break; + case STATIC_TEXT: + delete (CStaticText*)current_control; + break; + case EDIT_TEXT: + delete (CEditText*)current_control; + break; + case PULLDOWN_MENU: + delete (CPullDown*)current_control; + break; + case POPUP_MENU: + break; + case H_SLIDER: + delete (CHSlider*)current_control; + break; + case V_SLIDER: + delete (CVSlider*)current_control; + break; + } + current_control = next_control; + } + ControlList = NULL; + CurrentControl = NULL; + ControlCount = 0; +} + +//--------------------------------------------------------------- + +void ControlSet::SetControlDrawArea(void) +{ + SetWorkWindowBounds ( + SetRect.GetLeft()+1, + SetRect.GetTop()+1, + SetRect.GetWidth()-2, + SetRect.GetHeight()-2 + ); +} + +//--------------------------------------------------------------- + +void ControlSet::FillControlDrawArea(ULONG colour) +{ + DrawBoxC(0,0,WorkWindowWidth-1,WorkWindowHeight-1,colour); +} + +//--------------------------------------------------------------- + +void ControlSet::HiliteControlDrawArea(ULONG hilite,ULONG lolite) +{ + DrawVLineC(WorkWindowWidth-1,0,WorkWindowHeight-1,lolite); + DrawHLineC(0,WorkWindowWidth-1,WorkWindowHeight-1,lolite); + DrawVLineC(0,0,WorkWindowHeight-1,hilite); + DrawHLineC(0,WorkWindowWidth-1,0,hilite); +} + +//--------------------------------------------------------------- + +void ControlSet::DrawControlSet(void) +{ + Control *current_control; + MFRect ww_rect; + + + // Backup current work window rect. + ww_rect = WorkWindowRect; + + // Do the draw. + SetControlDrawArea(); + current_control = ControlList; + while(current_control) + { + current_control->DrawControl(); + current_control = current_control->GetNextControl(); + } +/* + // Restore old work window rect. + SetWorkWindowBounds ( + ww_rect.Left, + ww_rect.Top, + ww_rect.Width, + ww_rect.Height + ); +*/ +} + +//--------------------------------------------------------------- + + +UBYTE ControlSet::HandleControlSet(MFPoint *current_point) +{ + UBYTE in_text = 0, + result = 0, + update = 0; + Control *current_control; + MFPoint local_point; + + + if(PointInControlSet(current_point)) + { + local_point = *current_point; + GlobalToLocal(&local_point); + current_control = ControlList; + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + if(!(current_control->GetFlags()&CONTROL_HILITED)) + { + current_control->HiliteControl(&local_point); + SetStateFlags((UBYTE)(GetStateFlags()|CS_CLEANUP)); + update = 1; + result = 1; + break; + } + if(current_control->GetType()==EDIT_TEXT) + in_text = 1; + } + else + { + if(current_control->GetFlags()&CONTROL_HILITED) + { + current_control->UnHiliteControl(); + SetStateFlags((UBYTE)(GetStateFlags()|CS_CLEANUP)); + update = 1; + } + } + current_control = current_control->GetNextControl(); + } + + if(in_text) + { +// LbMouseSetPointerHotspot(2,3); +// ChangeMouseSprite(INTERFACE_POINTER(2)); + } + else + { +// LbMouseSetPointerHotspot(0,0); +// ChangeMouseSprite(INTERFACE_POINTER(1)); + } + } + else if(GetStateFlags()&CS_CLEANUP) + { + current_control = ControlList; + while(current_control) + { + if(current_control->GetFlags()&CONTROL_HILITED) + { + current_control->UnHiliteControl(); + update = 1; + } + current_control = current_control->GetNextControl(); + } +// ChangeMouseSprite(INTERFACE_POINTER(1)); +// LbMouseSetPointerHotspot(0,0); + + SetStateFlags((UBYTE)(GetStateFlags()&~(CS_CLEANUP))); + } + + if(update) + { + if(LockWorkScreen()) + { + DrawControlSet(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + + return result; +} + +//--------------------------------------------------------------- + +UWORD ControlSet::HandleControlSetClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + + + if(PointInControlSet(clicked_point)) + { + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + GlobalToLocal(clicked_point); + current_control = ControlList; + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(clicked_point)) + { + SetControlDrawArea(); + control_id = current_control->TrackControl(clicked_point); + return control_id; + } + current_control = current_control->GetNextControl(); + } + break; + case RIGHT_CLICK: + break; + } + } + return 0; +} + +//--------------------------------------------------------------- + +UWORD ControlSet::HandleControlSetKey(UBYTE the_key) +{ + Control *current_control; + + + current_control = ControlList; + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE)) + { + if(current_control->GetType()==PULLDOWN_MENU || current_control->GetType()==POPUP_MENU) + { + // Loop through menu items. + + } + else + { + if(the_key==current_control->GetHotKey()) + { + SetControlDrawArea(); + current_control->TrackKey(); + return current_control->GetID(); + } + } + } + current_control = current_control->GetNextControl(); + } + return 0; +} + +//--------------------------------------------------------------- + +Control *ControlSet::GetControlPtr(UWORD id) +{ + UWORD c0; + Control *current_control; + + + current_control = ControlList; + for(c0=1;c0GetNextControl()); + return current_control; +} + +//--------------------------------------------------------------- + +void ControlSet::SetControlState(UWORD id,UBYTE state) +{ + UWORD c0; + Control *current_control; + + + current_control = GetControlList(); + for(c0=1;c0GetNextControl()); + + switch(state) + { + case CTRL_SELECTED: + current_control->SetFlags((UBYTE)(current_control->GetFlags()|CONTROL_SELECTED)); + break; + case CTRL_DESELECTED: + current_control->SetFlags((UBYTE)(current_control->GetFlags()&~(CONTROL_SELECTED))); + break; + case CTRL_ACTIVE: + current_control->SetFlags((UBYTE)(current_control->GetFlags()&~(CONTROL_INACTIVE))); + break; + case CTRL_INACTIVE: + current_control->SetFlags((UBYTE)(current_control->GetFlags()|CONTROL_INACTIVE)); + break; + } +} + +//--------------------------------------------------------------- + +UBYTE ControlSet::GetControlState(UWORD id) +{ + UWORD c0; + Control *current_control; + + + current_control = GetControlList(); + for(c0=1;c0GetNextControl()); + + if(current_control->GetFlags()&CONTROL_SELECTED) + return CTRL_SELECTED; + else + return CTRL_DESELECTED; +} + +//--------------------------------------------------------------- + +void ControlSet::ToggleControlSelectedState(UWORD id) +{ + UWORD c0; + Control *current_control; + + + current_control = GetControlList(); + for(c0=1;c0GetNextControl()); + + current_control->SetFlags((UBYTE)(current_control->GetFlags()^CONTROL_SELECTED)); +} + +//--------------------------------------------------------------- + +void ControlSet::ToggleControlActiveState(UWORD id) +{ + UWORD c0; + Control *current_control; + + + current_control = GetControlList(); + for(c0=1;c0GetNextControl()); + + current_control->SetFlags((UBYTE)(current_control->GetFlags()^CONTROL_INACTIVE)); +} + +//--------------------------------------------------------------- + +void ControlSet::SetMenuItemState(UWORD id,UWORD item,UBYTE state) +{ + UWORD c0; + Control *current_control; + CPullDown *the_menu; + + + current_control = GetControlList(); + for(c0=1;c0GetNextControl()); + + the_menu = (CPullDown*)current_control; + + switch(state) + { + case CTRL_ACTIVE: + the_menu->SetItemFlags(item,(UBYTE)(the_menu->GetItemFlags(item)&~(MENU_INACTIVE))); + break; + case CTRL_INACTIVE: + the_menu->SetItemFlags(item,(UBYTE)(the_menu->GetItemFlags(item)|MENU_INACTIVE)); + break; + } +} + +//--------------------------------------------------------------- + +void ControlSet::SetPopUpItemState(CPopUp *the_popup,UWORD item,UBYTE state) +{ + switch(state) + { + case CTRL_ACTIVE: + the_popup->SetItemFlags(item,(UBYTE)(the_popup->GetItemFlags(item)&~(MENU_INACTIVE))); + break; + case CTRL_INACTIVE: + the_popup->SetItemFlags(item,(UBYTE)(the_popup->GetItemFlags(item)|MENU_INACTIVE)); + break; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/EdCom.cpp b/fallen/Editor/Source/EdCom.cpp new file mode 100644 index 0000000..876860c --- /dev/null +++ b/fallen/Editor/Source/EdCom.cpp @@ -0,0 +1,465 @@ +// EdCom.cpp +// Guy Simmons, 16th March 1998 + +#include "Editor.hpp" +#include "EdCom.h" + + + +//--------------------------------------------------------------- +// Editor condition list stuff. +//--------------------------------------------------------------- + +ULONG ed_clist_count = 0; +EditCondList edit_clists[MAX_EDIT_CLISTS], + *clists, + *clists_end, + *win_conditions, + *lose_conditions; + +void add_clist(EditCondList *the_clist); +void remove_clist(EditCondList *the_clist); + +//--------------------------------------------------------------- + +void init_ed_clists(void) +{ + ed_clist_count = 0; + memset(edit_clists,0,sizeof(edit_clists)); + clists = NULL; + clists_end = NULL; + + init_ed_conditions(); +} + +//--------------------------------------------------------------- + +EditCondList *alloc_ed_clist(void) +{ + UWORD c0; + EditCondList *the_clist; + + + for(c0=1;c0Used = TRUE; + sprintf(the_clist->CListName,"Condition List %d",c0); + + the_clist->ConditionCount = 0; + the_clist->ConditionList = NULL; + the_clist->ConditionListEnd = NULL; + + add_clist(the_clist); + ed_clist_count++; + + return the_clist; + } + } + return NULL; +} + +//--------------------------------------------------------------- + +void free_ed_clist(EditCondList *the_clist) +{ + EditCondition *current_condition; + + + // Firstly remove all conditions. + current_condition = the_clist->ConditionList; + while(current_condition) + { + remove_condition(the_clist,current_condition); + free_ed_condition(current_condition); + + current_condition = current_condition->Next; + } + + // Now free the condition list. + remove_clist(the_clist); + + the_clist->Used = FALSE; + ed_clist_count--; +} + +//--------------------------------------------------------------- + +void add_clist(EditCondList *the_clist) +{ + // Add to list. + the_clist->Prev = clists_end; + the_clist->Next = NULL; + + // Update list end. + if(clists_end) + clists_end->Next = the_clist; + clists_end = the_clist; + + // Update list. + if(!clists) + clists = the_clist; +} + +//--------------------------------------------------------------- + +void remove_clist(EditCondList *the_clist) +{ + EditCondList *next_clist, + *prev_clist; + + + // Remove from list + prev_clist = the_clist->Prev; + next_clist = the_clist->Next; + + if(prev_clist) + prev_clist->Next = next_clist; + else + clists = next_clist; + + if(next_clist) + next_clist->Prev = prev_clist; + else + clists_end = prev_clist; +} + +//--------------------------------------------------------------- + +void add_condition(EditCondList *the_clist,EditCondition *the_condition) +{ + if(!the_clist || !the_condition) + { + // Error. + return; + } + + // Add to list. + the_condition->Prev = the_clist->ConditionListEnd; + the_condition->Next = NULL; + + // Update list end. + if(the_clist->ConditionListEnd) + the_clist->ConditionListEnd->Next = the_condition; + the_clist->ConditionListEnd = the_condition; + + // Update list. + if(!the_clist->ConditionList) + the_clist->ConditionList = the_condition; + + the_clist->ConditionCount++; +} + +//--------------------------------------------------------------- + +void remove_condition(EditCondList *the_clist,EditCondition *the_condition) +{ + EditCondition *next_condition, + *prev_condition; + + + // Remove from list + prev_condition = the_condition->Prev; + next_condition = the_condition->Next; + + if(prev_condition) + prev_condition->Next = next_condition; + else + the_clist->ConditionList = next_condition; + + if(next_condition) + next_condition->Prev = prev_condition; + else + the_clist->ConditionListEnd = prev_condition; + + the_clist->ConditionCount--; +} + +//--------------------------------------------------------------- + +void move_condition(EditCondList *the_clist,EditCondition *insert_point,EditCondition *the_condition) +{ +} + +//--------------------------------------------------------------- +// Editor condition stuff. +//--------------------------------------------------------------- + +ULONG ed_condition_count = 0; +EditCondition edit_conditions[MAX_EDIT_CONDITIONS]; + +//--------------------------------------------------------------- + +void init_ed_conditions(void) +{ + ed_condition_count = 0; + memset(edit_conditions,0,sizeof(edit_conditions)); +} + +//--------------------------------------------------------------- + +EditCondition *alloc_ed_condition(void) +{ + UWORD c0; + EditCondition *the_condition; + + + for(c0=1;c0Used = TRUE; + + the_condition->Flags = 0; + the_condition->ConditionType = 0; + the_condition->Data1 = 0; + the_condition->Data2 = 0; + the_condition->Data3 = 0; + + ed_condition_count++; + + return the_condition; + } + } + return NULL; +} + +//--------------------------------------------------------------- + +void free_ed_condition(EditCondition *the_condition) +{ + the_condition->Used = FALSE; + ed_condition_count--; +} + +//--------------------------------------------------------------- +// Editor command list stuff. +//--------------------------------------------------------------- + +ULONG ed_comlist_count = 0; +EditComList edit_comlists[MAX_EDIT_COMLISTS], + *comlists, + *comlists_end; + +void add_comlist(EditComList *the_comlist); +void remove_comlist(EditComList *the_comlist); + +//--------------------------------------------------------------- + +void init_ed_comlists(void) +{ + ed_comlist_count = 0; + comlists = NULL; + comlists_end = NULL; + memset(edit_comlists,0,sizeof(edit_comlists)); + + init_ed_commands(); +} + +//--------------------------------------------------------------- + +EditComList *alloc_ed_comlist(void) +{ + UWORD c0; + EditComList *the_comlist; + + + for(c0=1;c0Used = TRUE; + sprintf(the_comlist->ComListName,"Command List %d",c0); + + the_comlist->CommandCount = 0; + the_comlist->CommandList = NULL; + the_comlist->CommandListEnd = NULL; + + add_comlist(the_comlist); + ed_comlist_count++; + + return the_comlist; + } + } + return NULL; +} + +//--------------------------------------------------------------- + +void free_ed_comlist(EditComList *the_comlist) +{ + EditCommand *current_command; + + + // Firstly remove all commands. + current_command = the_comlist->CommandList; + while(current_command) + { + remove_command(the_comlist,current_command); + free_ed_command(current_command); + + current_command = current_command->Next; + } + + // Now free the command list. + remove_comlist(the_comlist); + + the_comlist->Used = FALSE; + ed_comlist_count--; +} + +//--------------------------------------------------------------- + +void add_comlist(EditComList *the_comlist) +{ + // Add to list. + the_comlist->Prev = comlists_end; + the_comlist->Next = NULL; + + // Update list end. + if(comlists_end) + comlists_end->Next = the_comlist; + comlists_end = the_comlist; + + // Update list. + if(!comlists) + comlists = the_comlist; +} + +//--------------------------------------------------------------- + +void remove_comlist(EditComList *the_comlist) +{ + EditComList *next_comlist, + *prev_comlist; + + + // Remove from list + prev_comlist = the_comlist->Prev; + next_comlist = the_comlist->Next; + + if(prev_comlist) + prev_comlist->Next = next_comlist; + else + comlists = next_comlist; + + if(next_comlist) + next_comlist->Prev = prev_comlist; + else + comlists_end = prev_comlist; +} + +//--------------------------------------------------------------- + +void add_command(EditComList *the_comlist,EditCommand *the_command) +{ + if(!the_comlist || !the_command) + { + // Error. + return; + } + + // Add to list. + the_command->Prev = the_comlist->CommandListEnd; + the_command->Next = NULL; + + // Update list end. + if(the_comlist->CommandListEnd) + the_comlist->CommandListEnd->Next = the_command; + the_comlist->CommandListEnd = the_command; + + // Update list. + if(!the_comlist->CommandList) + the_comlist->CommandList = the_command; + + the_comlist->CommandCount++; +} + +//--------------------------------------------------------------- + +void remove_command(EditComList *the_comlist,EditCommand *the_command) +{ + EditCommand *next_command, + *prev_command; + + + // Remove from list + prev_command = the_command->Prev; + next_command = the_command->Next; + + if(prev_command) + prev_command->Next = next_command; + else + the_comlist->CommandList = next_command; + + if(next_command) + next_command->Prev = prev_command; + else + the_comlist->CommandListEnd = prev_command; + + the_comlist->CommandCount--; +} + +//--------------------------------------------------------------- + +void move_command(EditComList *the_comlist,EditCommand *insert_point,EditCommand *the_command) +{ +} + +//--------------------------------------------------------------- +// Editor command stuff. +//--------------------------------------------------------------- + +ULONG ed_command_count = 0; +EditCommand edit_commands[MAX_EDIT_COMMANDS]; + +//--------------------------------------------------------------- + +void init_ed_commands(void) +{ + ed_command_count = 0; + memset(edit_commands,0,sizeof(edit_commands)); +} + +//--------------------------------------------------------------- + +EditCommand *alloc_ed_command(void) +{ + UWORD c0; + EditCommand *the_command; + + + for(c0=1;c0Used = TRUE; + + the_command->Flags = 0; + the_command->CommandType = 0; + the_command->Data1 = 0; + the_command->Data2 = 0; + the_command->Data3 = 0; + + ed_command_count++; + + return the_command; + } + } + return NULL; +} + +//--------------------------------------------------------------- + +void free_ed_command(EditCommand *the_command) +{ + the_command->Used = FALSE; + ed_command_count--; +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/EdText.cpp b/fallen/Editor/Source/EdText.cpp new file mode 100644 index 0000000..7449a4b --- /dev/null +++ b/fallen/Editor/Source/EdText.cpp @@ -0,0 +1,93 @@ +// EdText.cpp +// Guy Simmons, 19th January 1998. + +#include "Editor.hpp" + +//--------------------------------------------------------------- + +CBYTE *class_text[] = +{ + "None", + "Player", + "Camera", + "Projectile", + "Building", + "Person", + "Furniture", + "Trigger", + "Vehicle", + "Special" +}; + +//--------------------------------------------------------------- + +CBYTE *genus_text[][10] = +{ + { "None" }, + { "None", "Darci", "Roper" }, + { "None", "Tracker", "Fixed" }, + { "None" }, + { "None" }, + { "None", "BLANK", "BLANK", "Cop", "Thug", "Victim", "Mafiosa" }, + { "None" }, + { "None" }, + { "None", "Player Trigger", "Thing Trigger", "Group Trigger", "Class Trigger" }, + { "None", "Van", "Car" }, + { "None", "Key" }, + { "None" }, + { "None" } +}; + +//--------------------------------------------------------------- + +CBYTE *condition_text[] = +{ + "NONE", + "THING_DEAD", + "ALL_GROUP_DEAD", + "PERCENT_GROUP_DEAD", + "THING_NEAR_PLAYER", + "GROUP_NEAR_PLAYER", + "CLASS_NEAR_PLAYER", + "THING_NEAR_THING", + "GROUP_NEAR_THING", + "CLASS_NEAR_THING", + "CLASS_COUNT", + "GROUP_COUNT", + "SWITCH_TRIGGERED", + "TIME", + "CLIST_FULFILLED" +}; + +//--------------------------------------------------------------- + +CBYTE *command_text[] = +{ + "NONE", + "ATTACK_PLAYER", + "ATTACK_THING", + "ATTACK_GROUP", + "ATTACK_CLASS", + "DEFEND_PLAYER", + "DEFEND_THING", + "DEFEND_GROUP", + "DEFEND_CLASS", + "PATROL_WAYPOINT", + "START_TIMER", + "WAIT_FOR_TRIGGER", + "WAIT_FOR_CLIST", + "FOLLOW_PLAYER" +}; + +//--------------------------------------------------------------- + +CBYTE *s_command_text[] = +{ + "ALWAYS", + "UNTIL_TRIGGER", + "UNTIL_CLIST", + "WHILE_TRIGGER", + "WHILE_CLIST" +}; + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/EdUtils.cpp b/fallen/Editor/Source/EdUtils.cpp new file mode 100644 index 0000000..d5167a2 --- /dev/null +++ b/fallen/Editor/Source/EdUtils.cpp @@ -0,0 +1,1153 @@ +// EdUtils.cpp +// Guy Simmons, 5th April 1997 + +#include "Editor.hpp" +#include "c:\fallen\headers\animtmap.h" +#include "c:\fallen\headers\memory.h" + + +extern SLONG key_frame_count,current_element; + +extern SLONG x_centre, + y_centre, + z_centre; +extern struct KeyFrameChunk *test_chunk; + + +//--------------------------------------------------------------- + +//--------------------------------------------------------------- + + +//--------------------------------------------------------------- +/* +void invert_mult(struct Matrix33 *mat,struct PrimPoint *pp) +{ + Matrix33 temp_mat; + SLONG i,j; + SLONG x,y,z; + + for(i=0;i<3;i++) + for(j=0;j<3;j++) + { + temp_mat.M[i][j]=mat->M[j][i]; + } + +// LogText(" len before %d \n",SDIST3(pp->X,pp->Y,pp->Z)); + + x = (pp->X * temp_mat.M[0][0])+(pp->Y * temp_mat.M[0][1])+(pp->Z * temp_mat.M[0][2])>>15; + y = (pp->X * temp_mat.M[1][0])+(pp->Y * temp_mat.M[1][1])+(pp->Z * temp_mat.M[1][2])>>15; + z = (pp->X * temp_mat.M[2][0])+(pp->Y * temp_mat.M[2][1])+(pp->Z * temp_mat.M[2][2])>>15; +// LogText(" len after %d \n",SDIST3(x,y,z)); + + pp->X=x; + pp->Y=y; + pp->Z=z; +} +*/ +//--------------------------------------------------------------- + + +//--------------------------------------------------------------- + +extern void do_quad_clip_list(SWORD face,SLONG p0,SLONG p1,SLONG p2,SLONG p3); +extern void do_tri_clip_list(SWORD face,SLONG p0,SLONG p1,SLONG p2); +extern void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); +extern void matrix_transform(struct Matrix31* result, struct Matrix33* trans,struct Matrix31* mat2); +extern void matrix_transform_small(struct Matrix31* result, struct Matrix33* trans,struct SMatrix31* mat2); + +#define CLIP256(x) (x>255?255:x) +extern struct SVector global_res[]; //max points per object? +extern SLONG global_flags[]; + +extern UWORD is_it_clockwise(struct SVector *res,SLONG p1,SLONG p2,SLONG p3); + +void draw_element(UWORD prim,SLONG x,SLONG y,SLONG z,struct KeyFrameElement *anim_info) +{ + UWORD bright[1560]; + ULONG flag_and,flag_or; + SLONG az, + c0, + sp,ep; + struct Matrix31 offset; + struct Matrix33 local_matrix, + *mat, + mat_final; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + struct SVector temp; //max points per object? + struct PrimObject *p_obj; + + static SLONG scale=256; + + if(Keys[KB_LBRACE]) + scale+=5; + + if(Keys[KB_RBRACE]) + scale-=5; + + if(scale<256) + scale=256; + + + + p_obj = &prim_objects[prim]; + p_f4 = &prim_faces4[p_obj->StartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + + rotate_obj ( + 0, //engine.AngleX, + 0, //engine.AngleY, + 0, //engine.AngleZ, + &local_matrix + ); + + mat = &anim_info->Matrix; + + offset.M[0] = (anim_info->OffsetX*scale)>>(TWEEN_OFFSET_SHIFT+8); + offset.M[1] = (anim_info->OffsetY*scale)>>(TWEEN_OFFSET_SHIFT+8); + offset.M[2] = (anim_info->OffsetZ*scale)>>(TWEEN_OFFSET_SHIFT+8); + matrix_transformZMY((struct Matrix31*)&temp,&local_matrix,&offset); + x += temp.X; + y += temp.Y; + z += temp.Z; + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + + engine.X -= x<<8; + engine.Y -= y<<8; + engine.Z -= z<<8; + +//apply local rotation matrix + matrix_mult33(&mat_final,&local_matrix,mat); + + for(c0=sp;c0StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + if(current_bucket_pool>=end_bucket_pool) + goto exit; + + p0=p_f4->Points[0]-sp; + p1=p_f4->Points[1]-sp; + p2=p_f4->Points[2]-sp; + p3=p_f4->Points[3]-sp; + + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]&global_flags[p3]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]|global_flags[p3]; + + { + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + az = (global_res[p0].Z+global_res[p1].Z+global_res[p2].Z+global_res[p3].Z)>>2; + + setPolyType4( + current_bucket_pool, + p_f4->DrawFlags + ); + + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->Col2 + ); + + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + global_res[p0].X,global_res[p0].Y, + global_res[p1].X,global_res[p1].Y, + global_res[p2].X,global_res[p2].Y, + global_res[p3].X,global_res[p3].Y + ); + + if(SelectFlag) + if(SelectDrawn==0||is_it_clockwise(global_res,p0,p1,p2)) + do_quad_clip_list(c0,p0,p1,p2,p3); + + setUV4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->UV[0][0],p_f4->UV[0][1], + p_f4->UV[1][0],p_f4->UV[1][1], + p_f4->UV[2][0],p_f4->UV[2][1], + p_f4->UV[3][0],p_f4->UV[3][1], + p_f4->TexturePage + ); + + setZ4 ( + (struct BucketQuad*)current_bucket_pool, + -global_res[p0].Z, + -global_res[p1].Z, + -global_res[p2].Z, + -global_res[p3].Z + ); + + setShade4 ( + (struct BucketQuad*)current_bucket_pool, + CLIP256(p_f4->Bright[0]+bright[p0]), + CLIP256(p_f4->Bright[1]+bright[p1]), + CLIP256(p_f4->Bright[2]+bright[p2]), + CLIP256(p_f4->Bright[3]+bright[p3]) + ); + ((struct BucketQuad*)current_bucket_pool)->DebugInfo=c0; + ((struct BucketQuad*)current_bucket_pool)->DebugFlags=p_f4->FaceFlags; + + add_bucket((void *)current_bucket_pool,az); + + if(check_mouse_over_prim_quad(global_res,p0,p1,p2,p3,c0)) + { + selected_prim_xyz.X = x; + selected_prim_xyz.Y = y; + selected_prim_xyz.Z = z; + } + + current_bucket_pool += sizeof(struct BucketQuad); + } + } + p_f4++; + } + + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + if(current_bucket_pool>=end_bucket_pool) + goto exit; + + if(p_f3->Points[0]StartPoint|| + p_f3->Points[1]StartPoint|| + p_f3->Points[2]StartPoint) + { + ERROR_MSG(0," point before start point"); + goto exit; + } + if(p_f3->Points[0]>p_obj->EndPoint|| + p_f3->Points[1]>p_obj->EndPoint|| + p_f3->Points[2]>p_obj->EndPoint) + { + ERROR_MSG(0," point after end point"); + goto exit; + } + + + p0=p_f3->Points[0]-sp; + p1=p_f3->Points[1]-sp; + p2=p_f3->Points[2]-sp; + + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + az = (global_res[p0].Z+global_res[p1].Z+global_res[p2].Z)/3; + + setPolyType3( + current_bucket_pool, + p_f3->DrawFlags + ); + + setCol3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->Col2 + ); + + setXY3 ( + (struct BucketTri*)current_bucket_pool, + global_res[p0].X,global_res[p0].Y, + global_res[p1].X,global_res[p1].Y, + global_res[p2].X,global_res[p2].Y + ); + + if(SelectFlag) + if(SelectDrawn==0||is_it_clockwise(global_res,p0,p1,p2)) + do_tri_clip_list(-c0,p0,p1,p2); + + setUV3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->UV[0][0],p_f3->UV[0][1], + p_f3->UV[1][0],p_f3->UV[1][1], + p_f3->UV[2][0],p_f3->UV[2][1], + p_f3->TexturePage + ); + + setShade3 ( + (struct BucketTri*)current_bucket_pool, + CLIP256(p_f3->Bright[0]+bright[p0]), + CLIP256(p_f3->Bright[1]+bright[p1]), + CLIP256(p_f3->Bright[2]+bright[p2]) + ); + + ((struct BucketTri*)current_bucket_pool)->DebugInfo=c0; + ((struct BucketTri*)current_bucket_pool)->DebugFlags=p_f3->FaceFlags; + + add_bucket((void *)current_bucket_pool,az); + + if(check_mouse_over_prim_tri(global_res,p0,p1,p2,c0)) + { + selected_prim_xyz.X = x; + selected_prim_xyz.Y = y; + selected_prim_xyz.Z = z; + } + + current_bucket_pool += sizeof(struct BucketQuad); + } + p_f3++; + } +exit:; +} + +//--------------------------------------------------------------- + +//void draw_multi_prim(EdRect *bounds_rect,struct KeyFrame *the_frame,struct Matrix33 *r_matrix) +void draw_a_key_frame_at(UWORD prim,SLONG x,SLONG y,SLONG z) +{ + SLONG c0,c1; + KeyFrame *the_frame = &test_chunk->KeyFrames[0]; + + + for(c1=0,c0=prim_multi_objects[prim].StartObject;c0FirstElement[c1] + ); + } +} + +//--------------------------------------------------------------- + + +void clear_anim_stuff(void) +{ + test_chunk->MultiObject=0; + test_chunk->ElementCount=0; + +} + +//--------------------------------------------------------------- + + +void load_chunk_texture_info_old(KeyFrameChunk *the_chunk) +{ + CBYTE file_name[64]; + SLONG c0 = 0, + c1,c2; + MFFileHandle file_handle; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + struct PrimObject *p_obj; + + + strcpy(file_name,the_chunk->VUEName); + while(file_name[c0]!='.' && file_name[c0]!=0)c0++; + if(file_name[c0]=='.') + { + file_name[c0+1] = 'T'; + file_name[c0+2] = 'E'; + file_name[c0+3] = 'X'; + file_name[c0+4] = 0; + } + + file_handle = FileOpen(file_name); + if(file_handle!=FILE_OPEN_ERROR) + { + LogText(" read anims texture old %s \n",file_name); + for(c0=prim_multi_objects[the_chunk->MultiObject].StartObject;c0MultiObject].EndObject;c0++,c1++) + { + p_obj = &prim_objects[c0]; + p_f4 = &prim_faces4[p_obj->StartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + + +// LogText(" obj %d has f4 %d f3 %d \n",c0,-p_obj->StartFace4+p_obj->EndFace4,-p_obj->StartFace3+p_obj->EndFace3); + + for(c1=p_obj->StartFace4;c1EndFace4;c1++,p_f4++) + { + FileRead(file_handle,&p_f4->DrawFlags,sizeof(p_f4->DrawFlags)); + FileRead(file_handle,&p_f4->Col2,sizeof(p_f4->Col2)); + FileRead(file_handle,&p_f4->TexturePage,sizeof(p_f4->TexturePage)); +// if(p_f4->TexturePage>5) +// p_f4->TexturePage = 0; + + for(c2=0;c2<4;c2++) + { + FileRead(file_handle,&p_f4->UV[c2][0],sizeof(p_f4->UV[c2][0])); + FileRead(file_handle,&p_f4->UV[c2][1],sizeof(p_f4->UV[c2][1])); +// LogText("Q uv %d,%d \n",p_f4->UV[c2][0],p_f4->UV[c2][1]); + } + } + + for(c1=p_obj->StartFace3;c1EndFace3;c1++,p_f3++) + { + FileRead(file_handle,&p_f3->DrawFlags,sizeof(p_f3->DrawFlags)); + FileRead(file_handle,&p_f3->Col2,sizeof(p_f3->Col2)); + FileRead(file_handle,&p_f3->TexturePage,sizeof(p_f3->TexturePage)); +// if(p_f3->TexturePage>5) +// p_f3->TexturePage = 0; + + for(c2=0;c2<3;c2++) + { + FileRead(file_handle,&p_f3->UV[c2][0],sizeof(p_f3->UV[c2][0])); + FileRead(file_handle,&p_f3->UV[c2][1],sizeof(p_f3->UV[c2][1])); +// LogText("T uv %d,%d \n",p_f4->UV[c2][0],p_f4->UV[c2][1]); + } + } + } + FileClose(file_handle); + } +} + +void load_chunk_texture_info(KeyFrameChunk *the_chunk) +{ + CBYTE file_name[64]; + SLONG c0 = 0, + c1,c2; + MFFileHandle file_handle; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + struct PrimObject *p_obj; + SLONG save_type; + SLONG multi,count=0; + SLONG sizeof_face_data; + + + strcpy(file_name,the_chunk->VUEName); + while(file_name[c0]!='.' && file_name[c0]!=0)c0++; + if(file_name[c0]=='.') + { + file_name[c0+1] = 'T'; + file_name[c0+2] = 'E'; + file_name[c0+3] = 'X'; + file_name[c0+4] = 0; + } + + for(multi=the_chunk->MultiObjectStart;multi<=the_chunk->MultiObjectEnd;multi++) + { + if(count>0) + { + file_name[5]='1'+count-1; + } + count++; + file_handle = FileOpen(file_name); + if(file_handle!=FILE_OPEN_ERROR) + { + FileRead(file_handle,&save_type,sizeof(save_type)); + + { + for(c0=prim_multi_objects[multi].StartObject;c0StartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + + LogText("LCTI obj %d has f4 %d f3 %d \n",c0,-p_obj->StartFace4+p_obj->EndFace4,-p_obj->StartFace3+p_obj->EndFace3); + + FileRead(file_handle,&count,sizeof(count)); + + for(c1=p_obj->StartFace4;c1EndFace4&&count>0;c1++,p_f4++,count--) + { + FileRead(file_handle,&p_f4->DrawFlags,sizeof(p_f4->DrawFlags)); + FileRead(file_handle,&p_f4->Col2,sizeof(p_f4->Col2)); + FileRead(file_handle,&p_f4->TexturePage,sizeof(p_f4->TexturePage)); + + if (save_type > 0) + { + // + // After save type zero, we save the FaceFlags here. + // + + FileRead(file_handle, &p_f4->FaceFlags, sizeof(p_f4->FaceFlags)); + } + + for(c2=0;c2<4;c2++) + { + FileRead(file_handle,&p_f4->UV[c2][0],sizeof(p_f4->UV[c2][0])); + FileRead(file_handle,&p_f4->UV[c2][1],sizeof(p_f4->UV[c2][1])); + } + } + + // + // The size of each face's data. + // + + sizeof_face_data = sizeof(p_f4->DrawFlags); + sizeof_face_data += sizeof(p_f4->Col2); + sizeof_face_data += sizeof(p_f4->TexturePage); + sizeof_face_data += sizeof(p_f4->UV[0][0]) * 8; + + if (save_type > 0) + { + sizeof_face_data += sizeof(p_f4->FaceFlags); + } + + while(count) + { + ULONG poo[50]; + FileRead(file_handle,&poo[0],sizeof_face_data); + count--; + } + + FileRead(file_handle,&count,sizeof(count)); + for(c1=p_obj->StartFace3;c1EndFace3&&count>0;c1++,p_f3++,count--) + { + FileRead(file_handle,&p_f3->DrawFlags,sizeof(p_f3->DrawFlags)); + FileRead(file_handle,&p_f3->Col2,sizeof(p_f3->Col2)); + FileRead(file_handle,&p_f3->TexturePage,sizeof(p_f3->TexturePage)); + + if (save_type > 0) + { + // + // After save type zero, we save the FaceFlags here. + // + + FileRead(file_handle, &p_f3->FaceFlags, sizeof(p_f3->FaceFlags)); + } + + for(c2=0;c2<3;c2++) + { + FileRead(file_handle,&p_f3->UV[c2][0],sizeof(p_f3->UV[c2][0])); + FileRead(file_handle,&p_f3->UV[c2][1],sizeof(p_f3->UV[c2][1])); + } + } + + // + // The size of each face's data. + // + + sizeof_face_data = sizeof(p_f3->DrawFlags); + sizeof_face_data += sizeof(p_f3->Col2); + sizeof_face_data += sizeof(p_f3->TexturePage); + sizeof_face_data += sizeof(p_f3->UV[0][0]) * 6; + + if (save_type > 0) + { + sizeof_face_data += sizeof(p_f3->FaceFlags); + } + + while(count) + { + ULONG poo[50]; + FileRead(file_handle,&poo[0],sizeof_face_data); + count--; + } + + } + } + FileClose(file_handle); + + /* + if(save_type) + { + load_chunk_texture_info_old(the_chunk); + } + */ + } + } +} + + +//--------------------------------------------------------------- + +void do_single_shot(UBYTE *screen,UBYTE *palette) +{ + CBYTE f_name[128]; + SLONG c0 = 0; + + + do + { + sprintf(f_name,"SHOTS\\SCR%04d.PCX",c0); + c0++; + }while(FileExists(f_name)); + + write_pcx(f_name,screen,palette); +} + +//--------------------------------------------------------------- + +SLONG count = 0; + +void do_record_frame(UBYTE *screen,UBYTE *palette) +{ + CBYTE f_name[128]; +/* + SLONG c0 = 0; + + + do + { + sprintf(f_name,"FRAMES\\FRA%04d.PCX",c0); + c0++; + }while(FileExists(f_name)); +*/ + sprintf(f_name,"FRAMES\\FRA%04d.PCX",count++); + write_pcx(f_name,screen,palette); +} + +//--------------------------------------------------------------- + +struct PCXHeader +{ + UBYTE Manufacturer; + UBYTE Version; + UBYTE Encoding; + UBYTE BitsPerPixel; + UWORD X; + UWORD Y; + UWORD Width; + UWORD Height; + UWORD HorizRes; + UWORD VertRes; + UBYTE EGAPalette[48]; + UBYTE Reserved; + UBYTE NumColorPlanes; + UWORD BytesPerLine; + UWORD PaletteType; + UBYTE Padding[58]; +}; + +SLONG write_pcx(CBYTE *fname,UBYTE *src,UBYTE *pal) +{ + UBYTE pixel, + palette[769], + *ptr,buf[1024]; + SLONG c0, + count, + x,y; + MFFileHandle f_handle; + PCXHeader the_header; + + + f_handle = FileCreate(fname,TRUE); + if(f_handle!=FILE_CREATION_ERROR) + { + // Create & write out header. + memset((UBYTE*)&the_header,0,sizeof(the_header)); + the_header.Manufacturer = 10; + the_header.Version = 5; + the_header.Encoding = 1; + the_header.BitsPerPixel = 8; + the_header.X = 0; + the_header.Y = 0; + the_header.Width = WorkScreenPixelWidth-1; + the_header.Height = WorkScreenHeight-1; + the_header.HorizRes = WorkScreenPixelWidth; + the_header.VertRes = WorkScreenHeight; + the_header.NumColorPlanes = 1; + the_header.BytesPerLine = WorkScreenPixelWidth; + FileWrite(f_handle,(UBYTE*)&the_header,sizeof(the_header)); + + // Compress image & write the sucker out. + for(y=0;yStartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + + + mat = &anim_info->Matrix; + mat_next = &anim_info_next->Matrix; + + //move object "tweened quantity" , z&y flipped + offset.M[0] = (anim_info->OffsetX+(((anim_info_next->OffsetX-anim_info->OffsetX)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (anim_info->OffsetY+(((anim_info_next->OffsetY-anim_info->OffsetY)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (anim_info->OffsetZ+(((anim_info_next->OffsetZ-anim_info->OffsetZ)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x += temp.X; + y += temp.Y; + z += temp.Z; + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; + + + //create a temporary "tween" matrix between current and next + for(i=0;i<3;i++) + { + for(j=0;j<3;j++) + { + mat2.M[i][j]=mat->M[i][j]+(((mat_next->M[i][j]-mat->M[i][j])*tween)>>8); + } + } + + //apply local rotation matrix + matrix_mult33(&mat_final,rot_mat,&mat2); + + + for(c0=sp;c0StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + p0=p_f4->Points[0]-sp; + p1=p_f4->Points[1]-sp; + p2=p_f4->Points[2]-sp; + p3=p_f4->Points[3]-sp; + + flag_and = flags[p0]&flags[p1]&flags[p2]&flags[p3]; + flag_or = flags[p0]|flags[p1]|flags[p2]|flags[p3]; + if(!(flag_and & EF_CLIPFLAGS)) + { + + az=(res[p0].Z+res[p1].Z+res[p2].Z+res[p3].Z)>>2; + + setPolyType4( + current_bucket_pool, + p_f4->DrawFlags + ); + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->Col2 + ); + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y, + res[p3].X,res[p3].Y + ); + + setUV4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->UV[0][0],p_f4->UV[0][1], + p_f4->UV[1][0],p_f4->UV[1][1], + p_f4->UV[2][0],p_f4->UV[2][1], + p_f4->UV[3][0],p_f4->UV[3][1], + p_f4->TexturePage + ); + + setZ4((struct BucketQuad*)current_bucket_pool,-res[p0].Z,-res[p1].Z,-res[p2].Z,-res[p3].Z); + + setShade4 ( + (struct BucketQuad*)current_bucket_pool, + (p_f4->Bright[0]), + (p_f4->Bright[1]), + (p_f4->Bright[2]), + (p_f4->Bright[3]) + ); + ((struct BucketQuad*)current_bucket_pool)->DebugInfo=c0; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } + p_f4++; + } + + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + p0=p_f3->Points[0]-sp; + p1=p_f3->Points[1]-sp; + p2=p_f3->Points[2]-sp; + + flag_and = flags[p0]&flags[p1]&flags[p2]; + flag_or = flags[p0]|flags[p1]|flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + az=(res[p0].Z+res[p1].Z+res[p2].Z)/3; + + setPolyType3( + current_bucket_pool, + p_f3->DrawFlags + ); + + setCol3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->Col2 + ); + + setXY3 ( + (struct BucketTri*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y + ); + + setUV3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->UV[0][0],p_f3->UV[0][1], + p_f3->UV[1][0],p_f3->UV[1][1], + p_f3->UV[2][0],p_f3->UV[2][1], + p_f3->TexturePage + ); + + setShade3 ( + (struct BucketTri*)current_bucket_pool, + (p_f3->Bright[0]), + (p_f3->Bright[1]), + (p_f3->Bright[2]) + ); + + ((struct BucketTri*)current_bucket_pool)->DebugInfo=c0; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } + p_f3++; + } +} + +//--------------------------------------------------------------- + +void test_draw_all_get_sizes(SWORD multi_prim,struct KeyFrame *the_frame,SLONG x,SLONG y,SLONG z,SLONG tween,struct Matrix33 *rot_mat,SLONG *width,SLONG *height,SLONG *mid_x,SLONG *mid_y) +{ + UWORD prim; + ULONG flag_and,flag_or; + SLONG az, + c0,c1,c2, + count = 0, + ep, + flags[1560], + i,j, + max_x,max_y, + min_x,min_y, + mx = 0, + my = 0, + sp, + tx,ty,tz; + struct KeyFrameElement *the_element; + struct Matrix31 offset; + struct Matrix33 *mat, + *mat_next, + mat2, + mat_final; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + struct PrimObject *p_obj; + struct SVector res[1560],temp; //max points per object? + + + + min_x = min_y = 999999; + max_x = max_y = -999999; + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + + for(c2=0,c1=prim_multi_objects[multi_prim].StartObject;c1<=prim_multi_objects[multi_prim].EndObject;c1++) + { + the_element = &the_frame->FirstElement[c2++]; +// test_draw(c0,0,0,0,0,the_element,the_element,r_matrix); + prim=c1; + + p_obj =&prim_objects[prim]; + p_f4 =&prim_faces4[p_obj->StartFace4]; + p_f3 =&prim_faces3[p_obj->StartFace3]; + + + mat = &the_element->Matrix; + mat_next = &the_element->Matrix; + + //move object "tweened quantity" , z&y flipped + offset.M[0] = (the_element->OffsetX)>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (the_element->OffsetY)>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (the_element->OffsetZ)>>TWEEN_OFFSET_SHIFT; + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x = temp.X; + y = temp.Y; + z = temp.Z; + + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; + + for(i=0;i<3;i++) + { + for(j=0;j<3;j++) + { + mat2.M[i][j]=mat->M[i][j]+(((mat_next->M[i][j]-mat->M[i][j])*tween)>>8); + } + } + + //apply local rotation matrix + matrix_mult33(&mat_final,rot_mat,&mat2); + + + for(c0=sp;c0max_x) + max_x = res[c0-sp].X; + + if(res[c0-sp].Ymax_y) + max_y = res[c0-sp].Y; + } + } + + engine.X=tx; + engine.Y=ty; + engine.Z=tz; + *width = max_x-min_x; + *height = max_y-min_y; + + if(count) + { + *mid_x=mx/count; + *mid_y=my/count; + } + +} +*/ +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/EdWay.cpp b/fallen/Editor/Source/EdWay.cpp new file mode 100644 index 0000000..31206bb --- /dev/null +++ b/fallen/Editor/Source/EdWay.cpp @@ -0,0 +1,141 @@ +// EdWay.cpp +// Guy Simmons, 6th February 1998 + +#include "Editor.hpp" +#include "EdWay.h" + + +//--------------------------------------------------------------- + +ULONG ed_waypoint_count = 0; +EditWaypoint edit_waypoints[MAX_EDIT_WAYPOINTS]; + +//--------------------------------------------------------------- + +void init_ed_waypoints(void) +{ + ed_waypoint_count = 0; + memset(edit_waypoints,0,sizeof(edit_waypoints)); +} + +//--------------------------------------------------------------- + +UWORD alloc_ed_waypoint(void) +{ + UWORD c0; + + + for(c0=1;c00&&dx+mx0&&dz+mzedit_info.MinX && (x<<8)edit_info.MinZ && (z<<8)=0&&x=0&&z=MAX_EDIT_FACE_LIST) + return; + +// LogText(" face %d added to pos %d \n",face,next_face_selected); + + face_selected_list[next_face_selected]=face; + if(face<0) + prim_faces3[-face].FaceFlags|=FACE_FLAG_OUTLINE; + else + prim_faces4[face].FaceFlags|=FACE_FLAG_OUTLINE; + next_face_selected++; + edit_info.TileFlag=0; +} + + + +SLONG add_a_light(SWORD i,SLONG x,SLONG y,SLONG z) +{ + if(next_d_light>8)>>ELE_SHIFT,(engine.Y>>8)>>ELE_SHIFT,(engine.Z>>8)>>ELE_SHIFT); +extern UWORD apply_ambient_light_to_object(UWORD object,SLONG lnx,SLONG lny,SLONG lnz,UWORD intense); + +SLONG place_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z) +{ + UWORD map_thing; + struct MapThing *p_mthing; + + y=0; + + map_thing=find_empty_map_thing(); + if(!map_thing) + return(0); + add_thing_to_edit_map(x>>ELE_SHIFT,z>>ELE_SHIFT,map_thing); + p_mthing=TO_MTHING(map_thing); + p_mthing->X=x; + p_mthing->Y=y; + p_mthing->Z=z; + + p_mthing->Type=MAP_THING_TYPE_PRIM; +// p_mthing->IndexOther=copy_prim_to_end(prim,0,map_thing); + p_mthing->IndexOther=prim; //copy_prim_to_start(prim,0,map_thing); + p_mthing->IndexOrig=prim; + if(edit_info.Inside) + p_mthing->Flags|=FLAG_EDIT_PRIM_INSIDE; + else + p_mthing->Flags&=~FLAG_EDIT_PRIM_INSIDE; +// apply_ambient_light_to_object(prim,edit_info.amb_dx,edit_info.amb_dy,edit_info.amb_dz,edit_info.amb_bright); + + return(map_thing); +} + +SLONG place_anim_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z) +{ + UWORD map_thing; + struct MapThing *p_mthing; + + y=0; + + map_thing=find_empty_map_thing(); + if(!map_thing) + return(0); + add_thing_to_edit_map(x>>ELE_SHIFT,z>>ELE_SHIFT,map_thing); + p_mthing=TO_MTHING(map_thing); + p_mthing->X=x; + p_mthing->Y=y; + p_mthing->Z=z; + + p_mthing->Type=MAP_THING_TYPE_ANIM_PRIM; +// p_mthing->IndexOther=copy_prim_to_end(prim,0,map_thing); + p_mthing->IndexOther=prim; //copy_prim_to_start(prim,0,map_thing); + p_mthing->IndexOrig=prim; +// apply_ambient_light_to_object(prim,edit_info.amb_dx,edit_info.amb_dy,edit_info.amb_dz,edit_info.amb_bright); + + return(map_thing); +} + +SLONG is_thing_on_map(SLONG index) +{ + struct MapThing *p_thing; + SLONG map; + + p_thing=TO_MTHING(index); + map=edit_map[p_thing->X>>ELE_SHIFT][p_thing->Z>>ELE_SHIFT].MapThingIndex; + while(map) + { + if(map==index) + return(1); + map=map_things[map].MapChild; + } + return(0); +} + +void build_tims(UWORD next_texture); + +UWORD is_road[]= +{ + 323,324,325,326,327,328,331,332,333,334,340,341,342,343,348,349,350,351,352,353,354,355,356,0 +}; + +extern void move_texture(UWORD from,UWORD to); +extern UWORD get_split_bits(UWORD tex); + + +void save_game_map(CBYTE *name) +{ + UWORD temp1,temp2,temp3,temp; + SLONG save_type=26, ob_size; + SLONG x,y,z; + SLONG c0; + MapElement me; + Thing th; + struct MapThing *t_mthing; + SLONG next_texture=64*4; + UWORD *tex_map_psx; + + MFFileHandle handle = FILE_OPEN_ERROR; + MFFileHandle jandle = FILE_OPEN_ERROR; + + + + // + // Change the extension of 'name'... + // + + CBYTE gamename[256]; + CBYTE *ch; + + strcpy(gamename, name); + + for (ch = gamename; *ch; ch++); + while(*ch != '.') {ch--;} + ch++; + + if(save_psx) + *ch++ = 'p'; + else + *ch++ = 'i'; + *ch++ = 'a'; + *ch++ = 'm'; + *ch++ = '\000'; + + memset((CBYTE*)moved_from,0,16*64*2); + memset((CBYTE*)moved_to,0,16*64*2); + + + + jandle=FileCreate(gamename,1); + if(jandle!=FILE_CREATION_ERROR) { + // I'm evil. eeeeeeevilllle. +extern void save_ob_ob(MFFileHandle handle); + save_ob_ob(jandle); + FileClose(jandle); + } + + handle=FileCreate(gamename,1); + if(handle!=FILE_CREATION_ERROR) + { + PAP_Hi pap_hi; + PAP_Lo pap_lo; + SLONG c0; + + FileWrite(handle,(UBYTE*)&save_type,4); + +extern void add_flat_roof_to_pap(void); + add_flat_roof_to_pap(); + + ob_size = sizeof(OB_ob_upto) + (sizeof(OB_Ob)*OB_ob_upto) + (sizeof(OB_Mapwho)*OB_SIZE*OB_SIZE); + FileWrite(handle,(UBYTE*)&ob_size,4); + + memset(&me,0,sizeof(me)); + + c0=0; + while(is_road[c0]) + { +// ASSERT(is_road[c0]!=340); + moved_to[is_road[c0]]=next_texture; + moved_from[next_texture]=is_road[c0]; + + move_texture(is_road[c0],next_texture+25*64); + + next_texture++; + c0++; + } + tex_map_psx=(UWORD*)MemAlloc(128*128*2); + + for(x=0;xType) + { + + case MAP_THING_TYPE_ANIM_PRIM: + temp++; + break; + + } + } + + FileWrite(handle,(UBYTE*)&temp,sizeof(temp)); + for(c0=0;c0Type) + { + case MAP_THING_TYPE_ANIM_PRIM: + io_thing.Type=t_mthing->Type; + io_thing.X=t_mthing->X; + io_thing.Y=t_mthing->Y; + io_thing.Z=t_mthing->Z; + io_thing.AngleY=t_mthing->AngleY; + io_thing.IndexOther=t_mthing->IndexOther; + FileWrite(handle,(UBYTE*)&io_thing,sizeof(struct LoadGameThing)); + break; + } + } + + // + // save all the ob'sa we just made + // +/* //see supermap save_ob_ob + FileWrite(handle,(UBYTE*)&OB_ob_upto,sizeof(OB_ob_upto)); + FileWrite(handle,(UBYTE*)&OB_ob[0],sizeof(OB_Ob)*OB_ob_upto); + FileWrite(handle,(UBYTE*)&OB_mapwho[0][0],sizeof(OB_Mapwho)*OB_SIZE*OB_SIZE); +*/ + + + + extern void save_super_map(MFFileHandle handle); + save_super_map(handle); + FileWrite(handle,(UBYTE*)&editor_texture_set,sizeof(editor_texture_set)); + + + { + SLONG si,pi; + for(si=0;si<200;si++) + { + for(pi=0;pi<5;pi++) + { + SLONG flip; + SLONG page; + + page=textures_xy[si][pi].Page*64+(textures_xy[si][pi].Tx)+(textures_xy[si][pi].Ty)*8; + if(page>=8*64) + page=1; + page=page_remap[page]-1; +// ASSERT(((page)>>6)<4); + psx_textures_xy[si][pi]=(page&0xff); +// ASSERT(psx_textures_xy[si][pi]!=0x1b); + + flip=textures_xy[si][pi].Flip; + flip^=(page>>14)&3; + + psx_textures_xy[si][pi]|=flip<<14; + } + } + FileWrite(handle,(UBYTE*)psx_textures_xy,2*200*5); + } + FileClose(handle); + } + + { + // + // Save out a special extras file. + // + + FILE *handle = fopen("data\\game.ext", "wb"); + + if (handle) + { + fwrite(EXTRA_thing,1,sizeof(EXTRA_thing),handle); + fclose(handle); + } + } + + + if(save_psx) + { +void save_texture_styles_psx(UBYTE world); + save_texture_styles_psx(editor_texture_set); + build_tims(next_texture); + } + else + { +//extern void save_texture_styles(UBYTE world); +// save_texture_styles(editor_texture_set); + } + + + + // + // Create the game.map aswell... + // + +// CopyFile(gamename, "data\\game.map", FALSE); +} + + +void save_tex_remap(CBYTE *name) +{ + CBYTE name2[128]; + SLONG c0; + MFFileHandle handle = FILE_OPEN_ERROR; + UWORD type=1,count=64*8; + + strcpy(name2,name); + + for(c0=0;c0<128;c0++) + { + if(name2[c0]=='.') + { + name2[c0+1]='r'; + break; + } + } + + handle=FileCreate(name2,1); + if(handle!=FILE_OPEN_ERROR) + { + FileWrite(handle,(UBYTE*)&type,sizeof(type)); + FileWrite(handle,(UBYTE*)&count,sizeof(count)); + + FileWrite(handle,(UBYTE*)&page_remap,sizeof(UWORD)*count); + } + FileClose(handle); + +} + +void load_tex_remap(CBYTE *name) +{ + CBYTE name2[128]; + SLONG c0; + MFFileHandle handle = FILE_OPEN_ERROR; + UWORD type=0,count=64*8; + + strcpy(name2,name); + + for(c0=0;c0<128;c0++) + { + if(name2[c0]=='.') + { + name2[c0+1]='r'; + name2[c0+2]='a'; + name2[c0+3]='p'; + break; + } + } + + handle=FileOpen(name2); + if(handle!=FILE_OPEN_ERROR) + { + FileRead(handle,(UBYTE*)&type,sizeof(type)); + FileRead(handle,(UBYTE*)&count,sizeof(count)); + + FileRead(handle,(UBYTE*)&page_remap,sizeof(UWORD)*count); + if(type==0) + { + SLONG c0; + UWORD page; + for(c0=0;c0StartFace4;c0EndFace4;c0++) + { + prim_faces4[c0].ThingIndex=thing; + } + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + prim_faces3[c0].ThingIndex=thing; + } +} + +void clear_map(void) +{ + SLONG x,z; + background_prim=0; + + next_prim_point=1; + next_prim_face4=1; + next_prim_face3=1; + next_prim_object=1; + next_prim_multi_object=1; + + end_prim_point=MAX_PRIM_POINTS-1; + end_prim_face4=MAX_PRIM_FACES4-1; + end_prim_face3=MAX_PRIM_FACES3-1; + end_prim_object=MAX_PRIM_OBJECTS-1; + end_prim_multi_object=MAX_PRIM_MOBJECTS-1; + + next_face_selected=1; + next_d_light=1; + +// next_col_vect=1; +// next_col_vect_link=1; + + memset((UBYTE*)&edit_map[0][0],0,sizeof(struct DepthStrip)*EDIT_MAP_WIDTH*EDIT_MAP_HEIGHT); +// memset((UBYTE*)&edit_map_eles[0],0,sizeof(EditMapElement)*65000); + memset((UBYTE*)&map_things[0],0,sizeof(struct MapThing)*MAX_MAP_THINGS); + + memset((UBYTE*)wall_list,0,sizeof(struct FWall)*MAX_WALLS); + memset((UBYTE*)storey_list,0,sizeof(struct FStorey)*MAX_STOREYS); + memset((UBYTE*)building_list,0,sizeof(struct FBuilding)*MAX_BUILDINGS); + + + +} + + +SLONG fix_storey(SLONG storey,SLONG building,UBYTE magnify) +{ + SLONG roof,wall; + SLONG some_walls=0; + while(storey) + { + storey_list[storey].BuildingHead=building; + if(magnify&1) + { + storey_list[storey].DX<<=1; + storey_list[storey].DZ<<=1; + } + if(magnify&2) + { + storey_list[storey].DY=(storey_list[storey].DY*4)/5; + } + +// roof=storey_list[storey].Roof; +// if(roof) +// { +// fix_storey(roof,building,magnify); +// } + +/* + wall=storey_list[roof].WallHead; + LogText("Build %d storey %d roofhead %d \n",c0,roof,wall); + while(wall) + { + LogText("r wall %d set to storey %d\n",wall,storey); + wall_list[wall].StoreyHead=roof; + wall_list[wall].DX<<=1; + wall_list[wall].DZ<<=1; + wall=wall_list[wall].Next; + + + } +*/ + + wall=storey_list[storey].WallHead; + //LogText("building %d storey %d wallhead %d \n",c0,storey,wall); + while(wall) + { + some_walls=1; +// LogText("wall %d set to storey %d\n",wall,storey); + wall_list[wall].StoreyHead=storey; + if(magnify&1) + { + wall_list[wall].DX<<=1; + wall_list[wall].DZ<<=1; + } + if(magnify&1) + { + wall_list[wall].DY=(wall_list[wall].DY*4)/5; + } + wall=wall_list[wall].Next; + + } + storey=storey_list[storey].Next; + } + + return(some_walls); +} + + +void fix_buildings(UBYTE magnify) +{ + SLONG c0; + SLONG roof,storey,wall; + + for(c0=1;c02) + { + temp=200; + temp2=5; + FileWrite(handle,(UBYTE*)&temp,2); + FileWrite(handle,(UBYTE*)&temp2,2); + FileWrite(handle,(UBYTE*)&textures_flags[0][0],sizeof(UBYTE)*temp*temp2); + } + + FileClose(handle); + } + +} + +void save_texture_styles_psx(UBYTE world) +{ + UWORD temp,temp2; + SLONG save_type=5; + MFFileHandle handle = FILE_OPEN_ERROR; + + CBYTE fname[MAX_PATH]; + SLONG si,pi; + struct TXTY temp_t[200][5]; + + + for(si=0;si<200;si++) + { + for(pi=0;pi<5;pi++) + { + SLONG page; + + page=textures_xy[si][pi].Page*64+(textures_xy[si][pi].Tx)+(textures_xy[si][pi].Ty)*8; + if(page>=8*64) + page=1; + page=page_remap[page]-1; +// ASSERT((page>>6)<4); + temp_t[si][pi].Page=page&0xff;//(page>>6)&0xf; +// textures_xy[si][pi].Tx=(page&7);//<<5; +// textures_xy[si][pi].Ty=((page>>3)&7);//<<5; + temp_t[si][pi].Flip=textures_xy[si][pi].Flip; + temp_t[si][pi].Flip^=(page>>14)&3; + + + + } + } + + + + sprintf(fname, "%sstyle.pma", TEXTURE_WORLD_DIR); + + handle=FileCreate(fname,1); + + if(handle!=FILE_OPEN_ERROR) + { + FileWrite(handle,(UBYTE*)&save_type,4); + temp=9; //how many texture_pages + + temp=200; + temp2=5; + FileWrite(handle,(UBYTE*)&temp,2); + FileWrite(handle,(UBYTE*)&temp2,2); + FileWrite(handle,(UBYTE*)&temp_t[0][0],sizeof(struct TXTY)*temp*temp2); + temp=200; + temp2=21; + FileWrite(handle,(UBYTE*)&temp,2); + FileWrite(handle,(UBYTE*)&temp2,2); + FileWrite(handle,(UBYTE*)&texture_style_names[0][0],temp*temp2); + if(save_type>2) + { + temp=200; + temp2=5; + FileWrite(handle,(UBYTE*)&temp,2); + FileWrite(handle,(UBYTE*)&temp2,2); + FileWrite(handle,(UBYTE*)&temp_t[0][0],sizeof(UBYTE)*temp*temp2); + } + + FileClose(handle); + } +} + +void fix_style_names(void) +{ + SLONG c0,c1; + for(c0=0;c0<200;c0++) + { + for(c1=0;c1<21;c1++) + { + if(texture_style_names[c0][c1]<33&&texture_style_names[c0][c1+1]<33) + { + texture_style_names[c0][c1]=0; + break; + } + } + } +} + + + +//typical map data breakdown cumlative data used +/* + load map data\COLMAP.MAP + after map 131072 + after prim points 426636 + after prim face4 732908 + after prim face3 786696 + after prim objects 809208 + after prims 809208 + after things 973210 + after col_info 973276 + after windows 2413284 1.5 Mb (unused) + after walls 2863284 + after storeys 2933284 + after buildings 2959284 + total size read 2959284 +*/ + + +void reset_floor_flags() +{ + SLONG dx,dz; + for(dx=0;dxminsize && dxmaxcount) + maxcount=count; + tc[count]++; + } + } + + sprintf(str,"max8x8= %d",maxcount); + QuickTextC(70,70,str,0); +/* + sprintf(str," 0.%d 1.%d 2.%d 3.%d 4.%d 5.%d 6.%d 7.%d 8.%d 9.%d 10.%d",tc[0],tc[1],tc[2],tc[3],tc[4],tc[5],tc[6],tc[7],tc[8],tc[9],tc[10]); + QuickTextC(0,90,str,0); + + sprintf(str," 1.%d 2.%d 3.%d 4.%d 5.%d 6.%d 7.%d 8.%d 9.%d 10.%d",tc[11],tc[12],tc[13],tc[14],tc[15],tc[16],tc[17],tc[18],tc[19],tc[20]); + QuickTextC(0,110,str,0); +*/ + + memset(tc,0,2*129); + memset(tcz,0,2*129); + for(z=0;z>3)*20,str,0); + + } + x=128; + sprintf(str,"tx %d tz %d",tx,tz); + QuickTextC((x&7)*60,90+(x>>3)*20,str,0); + + + + + + +} + +SLONG load_map(CBYTE *name) +{ + UWORD temp_end_prim_point; + UWORD temp_end_prim_face4; + UWORD temp_end_prim_face3; + UWORD temp_end_prim_object; + + UWORD no_prim_point; + UWORD no_prim_face4; + UWORD no_prim_face3; + UWORD no_prim_object; + SLONG save_type=1; + UWORD temp[4]; + SLONG c0; + SLONG size=0; + SLONG x,z; + SLONG load_ok=0; + struct TinyStrip + { + UWORD MapThingIndex; + // UWORD Depth[EDIT_MAP_DEPTH]; + UWORD ColVectHead; + // UWORD Dummy1; + UWORD Texture; + SWORD Bright; + }tinyfloor; + + +// clear_map(); +//extern void load_game_map(void); +// load_game_map(); +// return; + + SLONG old_texture_set = editor_texture_set; + + MFFileHandle handle = FILE_OPEN_ERROR; + handle=FileOpen(name); + if(handle!=FILE_OPEN_ERROR) + { + SLONG dx,dz; + PAP_clear(); + + LogText(" load map %s \n",name); + FileRead(handle,(UBYTE*)&save_type,4); + + if(save_type<=8) + { + for(dx=0;dx19) + { + FileRead(handle,(UBYTE*)tex_map,sizeof(UWORD)*EDIT_MAP_WIDTH*EDIT_MAP_DEPTH); + } + else + { + memset((UBYTE*)tex_map,0,sizeof(UWORD)*EDIT_MAP_WIDTH*EDIT_MAP_DEPTH); + + } + + + // + // clean the muck out the mapwho + // + + for(x=0;x18) + { + FileRead(handle,(UBYTE*)edit_map_roof_height,sizeof(SBYTE)*EDIT_MAP_WIDTH*EDIT_MAP_DEPTH); + } + else + { + memset((UBYTE*)&edit_map_roof_height[0][0],0,sizeof(SBYTE)*EDIT_MAP_WIDTH*EDIT_MAP_DEPTH); + } + + + if (save_type < 13) + { + // + // This is where I changed FLOOR_HEIGHT_SHIFT; + // + + for(dx=0;dx>ELE_SHIFT,map_things[c0].Z>>ELE_SHIFT,c0); + + //map_things[c0].IndexOther+=-temp_end_prim_object+end_prim_object; + //set_things_faces(c0); + } + else + { + delete_thing(c0); + } + } + } + + + size+=FileRead(handle,(UBYTE*)&edit_info.amb_dx,4*5); + size+=FileRead(handle,(UBYTE*)&next_col_info,2); + size+=FileRead(handle,(UBYTE*)col_info,sizeof(struct ColInfo)*next_col_info); + LogText(" after col_info %d \n",size); + + size+=FileRead(handle,(UBYTE*)&temp[0],2); + size+=FileRead(handle,(UBYTE*)&temp[1],2); + size+=FileRead(handle,(UBYTE*)&temp[2],2); + size+=FileRead(handle,(UBYTE*)&temp[3],2); + + size+=FileRead(handle,(UBYTE*)window_list,sizeof(struct FWindow)*temp[0]); + LogText(" after windows %d \n",size); + + for(c0=0;c0=17) + { + for(c0=0;c021) + { + if(wall_list[c0].Tcount2&&wall_list[c0].Textures2) + { + + wall_list[c0].Textures2=(UBYTE*)MemAlloc(wall_list[c0].Tcount2); + ASSERT(wall_list[c0].Textures2); + + size+=FileRead(handle,(UBYTE*)wall_list[c0].Textures2,wall_list[c0].Tcount2); + } + } + else + { + wall_list[c0].Tcount2=0; + wall_list[c0].Textures2=0; + + } + } + size+=FileRead(handle,(UBYTE*)storey_list,sizeof(struct FStorey)*temp[2]); + LogText(" after storeys %d \n",size); + if(save_type<21) + { + for(c0=0;c022) + { + UWORD temp; + SLONG c0,stair; + + FileRead(handle,(UBYTE*)&temp,sizeof(temp)); + next_inside=temp; + FileRead(handle,(UBYTE*)&room_ids[0],sizeof(struct RoomID)*temp); + for(c0=1;c0127) + { + room_ids[c0].StairsX[stair]=127; + room_ids[c0].StairFlags[stair]=0; + } + if(room_ids[c0].StairsY[stair]>127) + { + room_ids[c0].StairsY[stair]=127; + room_ids[c0].StairFlags[stair]=0; + } + } + } + + } + + } + + // + // cables now have a dangle factor built in + // + if(save_type<25) + { + for(c0=0;c0= 14) + { + FileRead(handle,(UBYTE*)EXTRA_thing,sizeof(EXTRA_thing)); + } + + if (save_type >= 21) + { + FileRead(handle,(UBYTE*)&editor_texture_set,sizeof(editor_texture_set)); + } + else + { + editor_texture_set = 1; + } + + // + // check the storey link list of this building all actually belong to this building + // this is to fix bug of duplicate faces caused by screwy building link list + { + SLONG c0; + for(c0=1;c0= 26) { + size+=FileRead(handle,(UBYTE*)&map_things[0],sizeof(struct MapThing)*MAX_MAP_THINGS); + + for(c0=1;c0>ELE_SHIFT,map_things[c0].Z>>ELE_SHIFT,c0); + + //map_things[c0].IndexOther+=-temp_end_prim_object+end_prim_object; + //set_things_faces(c0); + } + else + { + delete_thing(c0); + } + } + } + + + FileClose(handle); + + load_tex_remap(name); + + { + SLONG index; + struct MapThing *p_thing; + index=background_prim; + while(index) + { + p_thing=TO_MTHING(index); + p_thing->Type=MAP_THING_TYPE_PRIM; + index=p_thing->IndexNext; + } + } + load_ok=1; + } + + // + // Load the correct set of textures for this map. + // + + void update_modules (void); + + if (editor_texture_set != old_texture_set) + { + free_game_textures(FREE_UNSHARED_TEXTURES); + load_game_textures(LOAD_UNSHARED_TEXTURES); + + update_modules(); + } + + { + SLONG index,count=0; + LogText(" *************************************\n"); + index=edit_map[48][45].MapThingIndex; + LogText(" on map cell [48][45] = index %d \n",index); + while(index&&count++<100) + { + LogText(" index %d type %d \n",index,map_things[index].Type); + index=map_things[index].MapChild; + } + LogText(" *************************************\n"); + } + + return(load_ok); + +} + +void setup_ambient(SLONG dx,SLONG dy,SLONG dz,SLONG bright,SLONG flags) +{ + edit_info.amb_dx=dx; + edit_info.amb_dz=dz; + edit_info.amb_dy=dy; + edit_info.amb_bright=bright; + edit_info.amb_flags=flags; +} + + + +UWORD is_it_clockwise(struct SVector *res,SLONG p1,SLONG p2,SLONG p3) +{ + SLONG z; + SLONG vx,vy,wx,wy; + + vx=res[p2].X-res[p1].X; + wx=res[p3].X-res[p2].X; + vy=res[p2].Y-res[p1].Y; + wy=res[p3].Y-res[p2].Y; + z=vx*wy-vy*wx; + + if(z>0) + return 1; + else + return 0; +} + + +void set_quad_buckets_texture(struct BucketQuad *p_bucket,struct TextureBits *texture) +{ + UBYTE sx,sy,w,h; + + sx=texture->X<<3; + sy=texture->Y<<3; + w=texture_sizes[texture->Width]; + h=texture_sizes[texture->Height]; + setUV4(p_bucket,sx,sy,sx+w-1,sy,sx,sy+h-1,sx+w-1,sy+h-1,(SWORD)texture->Page); +} + + +inline void insert_bucket_vect(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SWORD col) +{ + SLONG flag_and,flag_or; + SLONG az; + struct BucketVect *p_bucket; + + if(current_bucket_pool>=end_bucket_pool) + return; + + p_bucket =(struct BucketVect*)current_bucket_pool; + + az=(z1+z2)>>1; + + setPolyGVect(p_bucket); + setXY2(p_bucket,x1,y1,x2,y2); + p_bucket->Col=col; + add_bucket(p_bucket,az-150); + current_bucket_pool+=sizeof(struct BucketVect); + +} + +UWORD is_it_clockwise_xy(SLONG x1,SLONG y1,SLONG x2,SLONG y2,SLONG x3,SLONG y3) +{ + SLONG z; + SLONG vx,vy,wx,wy; + + vx=x2-x1; //point2->X-point1->X; + wx=x3-x2; //point3->X-point2->X; + vy=y2-y1; //point2->Y-point1->Y; + wy=y3-y2; //point3->Y-point2->Y; + z=vx*wy-vy*wx; + + if(z>0) + return 1; + else + return 0; +} + +inline struct BucketQuad *insert_quad(SLONG *flags,struct SVector *res,SLONG p1,SLONG p2,SLONG p3,SLONG p4,struct TextureBits t) +{ + SLONG flag_and,flag_or; + SLONG az; + struct BucketQuad *p_bucket; + + if(current_bucket_pool>=end_bucket_pool) + return(0); + + p_bucket=(struct BucketQuad*)current_bucket_pool; + + az=(res[p1].Z+res[p2].Z+res[p3].Z+res[p4].Z)>>2; + + flag_and=flags[p1]&flags[p2]&flags[p3]&flags[p4]; + flag_or=flags[p1]|flags[p2]|flags[p3]|flags[p4]; + if(!is_it_clockwise_xy(res[p1].X,res[p1].Y,res[p2].X,res[p2].Y,res[p3].X,res[p3].Y)) + { + if( ((flag_or&EF_BEHIND_YOU)==0) && !(flag_and & EF_CLIPFLAGS)) + { + // setPolyGT4(p_bucket); + setPolyType4(p_bucket,t.DrawFlags); +// setPolyType4(p_bucket,t.DrawFlags|POLY_FLAG_SEMI_TRANS); + setCol4(p_bucket,0xff); + setZ4(p_bucket,res[p4].Z,res[p3].Z,res[p1].Z,res[p2].Z); + setXY4(p_bucket,res[p4].X,res[p4].Y,res[p3].X,res[p3].Y,res[p1].X,res[p1].Y,res[p2].X,res[p2].Y); + set_quad_buckets_texture(p_bucket,&t); + setShade4(p_bucket,128,128,128,128); + p_bucket->DebugInfo=0; + p_bucket->DebugFlags=0; + add_bucket(p_bucket,az); + current_bucket_pool+=sizeof(struct BucketQuad); + return(p_bucket); + } + else + return(0); + } + else + return(0); +} + +inline struct BucketTri *insert_tri(SLONG *flags,struct SVector *res,SLONG p1,SLONG p2,SLONG p3) +{ + SLONG flag_and,flag_or; + struct BucketTri *p_bucket; + + if(current_bucket_pool>=end_bucket_pool) + return(0); + + p_bucket=(struct BucketTri*)current_bucket_pool; + + flag_and=flags[p1]&flags[p2]&flags[p3]; + flag_or=flags[p1]|flags[p2]|flags[p3]; + if( ((flag_or&EF_BEHIND_YOU)==0) && !(flag_and & EF_CLIPFLAGS)) + { + setPolyGT3(p_bucket); + setXY3(p_bucket,res[p1].X,res[p1].Y,res[p2].X,res[p2].Y,res[p3].X,res[p3].Y); + setUV3(p_bucket,64+32,32,64+64,32,64+64,64,1); + setShade3(p_bucket,64,128,128); + p_bucket->DebugInfo=0; + add_bucket(p_bucket,res[0].Z); + current_bucket_pool+=sizeof(struct BucketTri); + return(++p_bucket); + } + return(p_bucket); + return(0); +} + +#define TSHIFT 8 +UBYTE check_big_point_triangle(SLONG x,SLONG y,SLONG ux,SLONG uy,SLONG vx,SLONG vy,SLONG wx,SLONG wy) +{ + SLONG s,t,top,bot,res; + + GlobalXYToLocal(&x,&y); + top = (y-uy)*(wx-ux)+(ux-x)*(wy-uy); + bot = (vy-uy)*(wx-ux)-(vx-ux)*(wy-uy); + + +// if(next_col_column<5) +// printf(" top %d bot %d \n",top,bot); + + if(bot==0) + return 0; + + s=(top<>6,t>>6); + + return 1; // point inside triangle + } + else + return 0; // point outside triangle +} + + +// p1 p2 +// +// p2 p3 + +BOOL check_mouse_over_prim_quad(struct SVector *res,SLONG p1,SLONG p2,SLONG p3,SLONG p4,SLONG face) +{ + SLONG az; + + + az = (res[p1].Z+res[p2].Z+res[p3].Z+res[p4].Z)>>2; + if(!is_it_clockwise(res,p3,p2,p1)) + { + if ( + check_big_point_triangle(MouseX,MouseY,res[p1].X,res[p1].Y,res[p2].X,res[p2].Y,res[p3].X,res[p3].Y) || + check_big_point_triangle(MouseX,MouseY,res[p2].X,res[p2].Y,res[p4].X,res[p4].Y,res[p3].X,res[p3].Y) + ) + { + if(az < hilited_face.Z||hilited_face.EditTurn!=editor_turn) + { + hilited_face.Face = face; + hilited_face.EditTurn = editor_turn; + hilited_face.Z = az; + hilited_face.PEle = (struct EditMapElement*)-1; + hilited_face.Bucket = (struct BucketHead*)current_bucket_pool; + return TRUE; + } + } + } + return FALSE; +} + +BOOL check_mouse_over_floor_quad(SLONG x1,SLONG y1,SLONG x2,SLONG y2,SLONG x3,SLONG y3, SLONG x4,SLONG y4,SLONG face,SLONG az) +{ + if ( + check_big_point_triangle(MouseX,MouseY,x1,y1,x2,y2,x3,y3) || + check_big_point_triangle(MouseX,MouseY,x2,y2,x4,y4,x3,y3) + ) + { + if(az < hilited_face.Z||hilited_face.EditTurn!=editor_turn) + { + hilited_face.Face = face; + hilited_face.EditTurn = editor_turn; + hilited_face.Z = az; + hilited_face.PEle = (struct EditMapElement*)-2; + hilited_face.Bucket = (struct BucketHead*)current_bucket_pool; + return TRUE; + } + } + return FALSE; +} + + + + + + +BOOL check_mouse_over_prim_tri(struct SVector *res,SLONG p1,SLONG p2,SLONG p3,SLONG face) +{ + SLONG az; + + + az = (res[p1].Z+res[p2].Z+res[p3].Z)/3; + if(!is_it_clockwise(res,p3,p2,p1)) + { + if(check_big_point_triangle(MouseX,MouseY,res[p1].X,res[p1].Y,res[p2].X,res[p2].Y,res[p3].X,res[p3].Y)) + { + if(az < hilited_face.Z||hilited_face.EditTurn!=editor_turn) + { + hilited_face.Face = -face; + hilited_face.EditTurn = editor_turn; + hilited_face.Z = az; + hilited_face.PEle = (struct EditMapElement*)-1; + hilited_face.Bucket = (struct BucketHead*)current_bucket_pool; + return TRUE; + } + } + } + return FALSE; +} + +void check_mouse_quad(struct EditMapElement *p_ele,struct SVector *res,SLONG p1,SLONG p2,SLONG p3,SLONG p4,SLONG wx,SLONG wy,SLONG wz,SLONG face) +{ + SLONG az; + static count; + if(hilited_face.EditTurn!=editor_turn) + { + count=0; + } +/* + if(editor.TexturePriority) + { + if(MouseX<256&&MouseY<256) + return; + } +*/ + + az=(res[p1].Z+res[p2].Z+res[p3].Z+res[p4].Z)>>2; + if(!is_it_clockwise(res,p1,p2,p3)) + { + if(check_big_point_triangle(MouseX,MouseY,res[p3].X,res[p3].Y,res[p2].X,res[p2].Y,res[p1].X,res[p1].Y)|| + check_big_point_triangle(MouseX,MouseY,res[p1].X,res[p1].Y,res[p4].X,res[p4].Y,res[p3].X,res[p3].Y)) + { + if(az < hilited_face.Z||hilited_face.EditTurn!=editor_turn) + { + count++; + hilited_face.MapX=wx; + hilited_face.MapY=wy; + hilited_face.MapZ=wz; + hilited_face.Face=face; + hilited_face.EditTurn=editor_turn; + hilited_face.PEle=p_ele; + hilited_face.Z=az; + hilited_face.Bucket = 0; //(struct BucketHead*)current_bucket_pool; + } + } + } +} + + + +struct DisplayTypes +{ + SLONG Width,Height,Depth; + +}; + +struct DisplayTypes display_types[]= +{ + {320,200,8}, + {640,480,8}, + {800,600,8}, + {1024,768,8}, + {1280,1024,8}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, +}; + +void gamut_fiddle(void) +{ + + UBYTE temp_pal[768]; + SLONG c0,temp; + static SLONG gamut=0; + UBYTE *pal; + + if((pal=PALETTE)==0) + return; + + if(Keys[KB_F12]) + { + gamut+=ShiftFlag?-1:+1; + if(gamut<-256) + gamut=-256; + if(gamut>256) + gamut=256; + for(c0=0;c0<256*3;c0++) + { + temp=(pal[c0]+gamut); + if(temp>255) + temp=255; + if(temp<0) + temp=0; + + temp_pal[c0]=temp; + } + SetPalette(temp_pal); + } +} + +ULONG engine_keys_scroll_game(void) +{ + SLONG dx=0,dy=0,dz=0; + ULONG change=0; + SLONG scale; + + if(ShiftFlag) + { + if(Keys[KB_RIGHT]) + { +/* + dx=(SIN( ((engine.AngleY>>8)+2048+512)&2047)*80)>>16; + dz=(COS( ((engine.AngleY>>8)+2048+512)&2047)*80)>>16; + change=1; +*/ + dx=100; + change=1; + } + else if(Keys[KB_LEFT]) + { +/* + dx=-(SIN( ((engine.AngleY>>8)+2048+512)&2047)*80)>>16; + dz=-(COS( ((engine.AngleY>>8)+2048+512)&2047)*80)>>16; + change=1; +*/ + dx=-100; + change=1; + } + if(Keys[KB_UP]) + { + dy=100; + change=1; + } + + if(Keys[KB_DOWN]) + { + dy=-1000; + change=1; + } + } + else + { + if(Keys[KB_RIGHT]) + { +/* + engine.AngleY-=2048<<1; + engine.AngleY=((engine.AngleY+(2048<<8))&((2048<<8)-1)); + // if(engine.AngleY< (1536<<8) && (engine.AngleY>512<<8)) + // engine.AngleY=512<<8; + change=1; +*/ + dx=(SIN( ((engine.AngleY>>8)+2048+512)&2047)*200)>>16; + dz=(COS( ((engine.AngleY>>8)+2048+512)&2047)*200)>>16; + change=1; + } + else if(Keys[KB_LEFT]) + { +/* + engine.AngleY+=2048<<1; + engine.AngleY=((engine.AngleY+(2048<<8))&((2048<<8)-1)); + // if(engine.AngleY< (1536<<8) && (engine.AngleY>512<<8)) + // engine.AngleY=1536<<8; + change=1; +*/ + dx=-(SIN( ((engine.AngleY>>8)+2048+512)&2047)*200)>>16; + dz=-(COS( ((engine.AngleY>>8)+2048+512)&2047)*200)>>16; + + change=1; + } + + if(Keys[KB_UP]) + { + dx=-(SIN( ((engine.AngleY>>8)+2048)&2047)*150)>>16; + dz=-(COS( ((engine.AngleY>>8)+2048)&2047)*150)>>16; + change=1; + } + + if(Keys[KB_DOWN]) + { + dx=(SIN( ((engine.AngleY>>8)+2048)&2047)*150)>>16; + dz=(COS( ((engine.AngleY>>8)+2048)&2047)*150)>>16; + change=1; + } + } + if(change) + { + scale=3000-(engine.Scale+1000); + scale>>=8; + if(scale<=0) + scale=1; + + dx*=scale; + dz*=scale; + + dx>>=2; + dz>>=2; + + engine.X+=dx<<8; + engine.Y+=dy<<8; + engine.Z+=dz<<8; + } + return(change); + +} + +SLONG calc_step_size(void) +{ + SLONG scale; + scale=3000-(engine.Scale+1000); + + if(scale<1) + scale=1; + + scale<<=6; + return(scale); + +} + +ULONG engine_keys_scroll(void) +{ + SLONG update=0; + SLONG step_size; + + step_size=calc_step_size(); + + if(ControlFlag) + { + + if(Keys[KB_1]) + { + engine.Z=0; + update = 1; + } + if(Keys[KB_2]) + { + engine.Z=64<<8; + update = 1; + } + if(Keys[KB_3]) + { + engine.Z=128<<8; + update = 1; + } + if(Keys[KB_4]) + { + engine.Z=(128+64)<<8; + update = 1; + } + } + + if(Keys[KB_LEFT]) //&&!(ShiftFlag)) + { + Keys[KB_LEFT]=0; + engine.X-=step_size; + update = 1; + } + if(Keys[KB_RIGHT]) //&&!(ShiftFlag)) + { + Keys[KB_RIGHT]=0; + engine.X+=step_size; + update = 1; + } + if(Keys[KB_UP]&&!(ShiftFlag)) + { + Keys[KB_UP]=0; + engine.Y-=step_size; + update = 1; + } + if(Keys[KB_DOWN]&&!(ShiftFlag)) + { + Keys[KB_DOWN]=0; + engine.Y+=step_size; + update = 1; + } + if(Keys[KB_INS]||(Keys[KB_UP]&&ShiftFlag)) + { + Keys[KB_INS]=0; + engine.Z-=step_size; +// if( ((engine.Z>>ELE_SHIFT)>>8)<0) +// engine.Z=0; + update = 1; + } + if(Keys[KB_PGUP]||(Keys[KB_DOWN]&&ShiftFlag)) + { + Keys[KB_PGUP]=0; + engine.Z+=step_size; +// if( ((engine.Z>>ELE_SHIFT)>>8)>16) +// engine.Z=16<<(ELE_SHIFT+8); + update = 1; + } + + + return(update); +} + +ULONG engine_keys_scroll_plan(void) +{ + SLONG update=0; + SLONG step_size=256<<8; +// step_size=calc_step_size(); + + if(ShiftFlag) + step_size<<=2; + + if(Keys[KB_LEFT]) //&&!(ShiftFlag)) + { + Keys[KB_LEFT]=0; + engine.X-=step_size; + update = 1; + } + if(Keys[KB_RIGHT]) //&&!(ShiftFlag)) + { + Keys[KB_RIGHT]=0; + engine.X+=step_size; + update = 1; + } + if(Keys[KB_UP]&&!(ShiftFlag)) + { + Keys[KB_UP]=0; + engine.Z-=step_size; + update = 1; + } + if(Keys[KB_DOWN]&&!(ShiftFlag)) + { + Keys[KB_DOWN]=0; + engine.Z+=step_size; + update = 1; + } + if(Keys[KB_PGUP]||(Keys[KB_UP]&&ShiftFlag)) + { + Keys[KB_PGUP]=0; + Keys[KB_UP]=0; + engine.Y-=step_size; +// if( ((engine.Z>>ELE_SHIFT)>>8)<0) +// engine.Z=0; + update = 1; + } + if(Keys[KB_PGDN]||(Keys[KB_DOWN]&&ShiftFlag)) + { + Keys[KB_PGDN]=0; + Keys[KB_DOWN]=0; + engine.Y+=step_size; +// if( ((engine.Z>>ELE_SHIFT)>>8)>16) +// engine.Z=16<<(ELE_SHIFT+8); + update = 1; + } + return(update); +} + +ULONG engine_keys_spin(void) +{ + SLONG update=0; + gamut_fiddle(); + if(Keys[KB_DEL]) + { + engine.AngleY+=2048; + engine.AngleY+=2048; + engine.AngleY+=2048; + engine.AngleY+=2048; + engine.AngleY=((engine.AngleY+(2048<<8))&((2048<<8)-1)); +// if(engine.AngleY< (1536<<8) && (engine.AngleY>512<<8)) +// engine.AngleY=512<<8; + update = 1; + } + + if(Keys[(0x51 + 0x80)]) + { + engine.AngleY-=2048; + engine.AngleY-=2048; + engine.AngleY-=2048; + engine.AngleY-=2048; + engine.AngleY=((engine.AngleY+(2048<<8))&((2048<<8)-1)); +// if(engine.AngleY< (1536<<8) && (engine.AngleY>512<<8)) +// engine.AngleY=1536<<8; + update = 1; + } + + if(Keys[KB_HOME]) + { + engine.AngleX+=2048; + engine.AngleX+=2048; + engine.AngleX+=2048; + engine.AngleX+=2048; + engine.AngleX=((engine.AngleX+(2048<<8))&((2048<<8)-1)); +// if(engine.AngleX< (1536<<8) && (engine.AngleX>512<<8)) +// engine.AngleX=512<<8; + update = 1; + } + + if(Keys[KB_END]) + { + engine.AngleX-=2048; + engine.AngleX-=2048; + engine.AngleX-=2048; + engine.AngleX-=2048; + engine.AngleX=((engine.AngleX+(2048<<8))&((2048<<8)-1)); +// if(engine.AngleX< (1536<<8) && (engine.AngleX>512<<8)) +// engine.AngleX=1536<<8; + update = 1; + } + return(update); +} + +ULONG engine_keys_zoom(void) +{ + if(Keys[KB_I]) + { + engine.Scale+=ShiftFlag?4:64; + return(1); + } + if(Keys[KB_O]) + { + engine.Scale-=ShiftFlag?4:64; + if(engine.Scale<1) + engine.Scale=1; + return(1); + } + return(0); +} + +ULONG editor_user_interface(UBYTE type) +{ + ULONG update = 0; + static ULONG res=1; + static UWORD current_texture_l=0; + static UWORD current_texture_r=0; + CBYTE str[100]; +/* + if(Keys[KB_R]&&!ControlFlag) + { + Keys[KB_R]=0; +loop: + res++; + if(display_types[res].Width==0) + res=0; + if(SetDisplay(display_types[res].Width,display_types[res].Height,display_types[res].Depth)!=NoError) + goto loop; + return(1); + } +*/ + switch(type) + { + case 0: + update|=engine_keys_scroll(); + update|=engine_keys_spin(); + update|=engine_keys_zoom(); + break; + + case 1: + update|=engine_keys_scroll_game(); + update|=engine_keys_spin(); + update|=engine_keys_zoom(); + break; + case 2: + update|=engine_keys_scroll_plan(); + update|=engine_keys_spin(); +// update|=engine_keys_zoom(); + break; + + + } + return update; +} + +void draw_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col) +{ + struct SVector p1,p2; + struct SVector res1,res2; + SLONG temp; + SLONG f1,f2; + + + temp=engine.ClipFlag; + engine.ClipFlag=0; + + p1.X=x1; + p1.Y=y1; + p1.Z=z1; + + p2.X=x2; + p2.Y=y2; + p2.Z=z2; + + f1=rotate_point_gte(&p1,&res1); + f2=rotate_point_gte(&p2,&res2); + if(!( (f1&f2) & EF_CLIPFLAGS)) + DrawLineC(res1.X,res1.Y,res2.X,res2.Y,col); + engine.ClipFlag=temp; +} + +void draw_3d_text(SLONG x1,SLONG y1,SLONG z1,CBYTE *str,UBYTE col) +{ + struct SVector p1; + struct SVector res1,res2; + + p1.X=x1; + p1.Y=y1; + p1.Z=z1; + + rotate_point_gte(&p1,&res1); + QuickTextC(res1.X,res1.Y,str,col); +} + +void create_bucket_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col) +{ + struct SVector points; + struct SVector res; + SLONG sx,sy,sz; + SLONG c0; + SLONG prx,pry,prz; + sx=x2-x1; + sy=y2-y1; + sz=z2-z1; + + sx/=32; + sy/=32; + sz/=32; + + points.X=x1; + points.Y=y1; + points.Z=z1; + rotate_point_gte(&points,&res); + prx=res.X; + pry=res.Y; + prz=res.Z; + for(c0=0;c0<32;c0++) + { + points.X+=sx; + points.Y+=sy; + points.Z+=sz; + rotate_point_gte(&points,&res); + insert_bucket_vect(prx,pry,prz,res.X,res.Y,res.Z,col); + prx=res.X; + pry=res.Y; + prz=res.Z; + } +} + + +void create_bucket_3d_line_whole(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col) +{ + struct SVector point[2]; + struct SVector res[2]; + //SLONG sx,sy,sz,c0; + ULONG f1,f2; + point[0].X=x1; + point[0].Y=y1; + point[0].Z=z1; + f1=rotate_point_gte(&point[0],&res[0]); + + point[1].X=x2; + point[1].Y=y2; + point[1].Z=z2; + f2=rotate_point_gte(&point[1],&res[1]); + f1=f1&f2; + if(!(f1 & EF_CLIPFLAGS)) +// insert_bucket_vect(res[0].X,res[0].Y,res[0].Z,res[1].X,res[1].Y,res[1].Z,col); + insert_bucket_vect(res[0].X,res[0].Y,-5000,res[1].X,res[1].Y,-5000,col); +} + + +void draw_grid2(void) +{ + + SLONG x,y; + SLONG left,right,top,bottom; + SLONG col=LOLITE_COL; + SLONG z; + SLONG numb=32; +/* + z=(engine.Z>>8)+5000; + left=((engine.X>>8)-numb*HALF_ELE_SIZE)&(~(HALF_ELE_SIZE-1)); + right=((engine.X>>8)+numb*HALF_ELE_SIZE)&(~(HALF_ELE_SIZE-1)); + top=((engine.Y>>8)-numb*HALF_ELE_SIZE)&(~(HALF_ELE_SIZE-1)); + bottom=((engine.Y>>8)+numb*HALF_ELE_SIZE)&(~(HALF_ELE_SIZE-1)); + + for (x=left;x>8); + y=(engine.Y>>8); + z=(engine.Z>>8); + + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + create_bucket_3d_line(x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,WHITE_COL); + +} + +void draw_editor_grid(void) +{ + struct SVector points[8]; + struct SVector res[8]; + SLONG c0; + SLONG x,y,z; + if(edit_info.GridOn) + { + draw_grid2(); + return; + } + + + x=(engine.X>>8); + y=(engine.Y>>8); + z=(engine.Z>>8); + + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE*8,z-HALF_ELE_SIZE,x-HALF_ELE_SIZE,y+HALF_ELE_SIZE*8,z-HALF_ELE_SIZE,1); + create_bucket_3d_line(x+HALF_ELE_SIZE,y-HALF_ELE_SIZE*8,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE*8,z-HALF_ELE_SIZE,1); + create_bucket_3d_line(x+HALF_ELE_SIZE,y-HALF_ELE_SIZE*8,z+HALF_ELE_SIZE,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE*8,z+HALF_ELE_SIZE,1); + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE*8,z+HALF_ELE_SIZE,x-HALF_ELE_SIZE,y+HALF_ELE_SIZE*8,z+HALF_ELE_SIZE,1); + + create_bucket_3d_line(x-HALF_ELE_SIZE*8,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE*8,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE,1); + create_bucket_3d_line(x-HALF_ELE_SIZE*8,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,x+HALF_ELE_SIZE*8,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE,1); + create_bucket_3d_line(x-HALF_ELE_SIZE*8,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,x+HALF_ELE_SIZE*8,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE,1); + create_bucket_3d_line(x-HALF_ELE_SIZE*8,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,x+HALF_ELE_SIZE*8,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE,1); + + create_bucket_3d_line(x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE*8,x-HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE*8,1); + create_bucket_3d_line(x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z-HALF_ELE_SIZE*8,x+HALF_ELE_SIZE,y-HALF_ELE_SIZE,z+HALF_ELE_SIZE*8,1); + create_bucket_3d_line(x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE*8,x+HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE*8,1); + create_bucket_3d_line(x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z-HALF_ELE_SIZE*8,x-HALF_ELE_SIZE,y+HALF_ELE_SIZE,z+HALF_ELE_SIZE*8,1); + +#ifdef POO + points[0].X=x-HALF_ELE_SIZE; + points[0].Y=y-HALF_ELE_SIZE*8; + points[0].Z=z-HALF_ELE_SIZE; + + points[1].X=x+HALF_ELE_SIZE; + points[1].Y=y-HALF_ELE_SIZE*8; + points[1].Z=z-HALF_ELE_SIZE; + + points[2].X=x+HALF_ELE_SIZE; + points[2].Y=y+HALF_ELE_SIZE*8; + points[2].Z=z-HALF_ELE_SIZE; + + points[3].X=x-HALF_ELE_SIZE; + points[3].Y=y+HALF_ELE_SIZE*8; + points[3].Z=z-HALF_ELE_SIZE; + + points[4].X=x-HALF_ELE_SIZE; + points[4].Y=y-HALF_ELE_SIZE*8; + points[4].Z=z+HALF_ELE_SIZE; + + points[5].X=x+HALF_ELE_SIZE; + points[5].Y=y-HALF_ELE_SIZE*8; + points[5].Z=z+HALF_ELE_SIZE; + + points[6].X=x+HALF_ELE_SIZE; + points[6].Y=y+HALF_ELE_SIZE*8; + points[6].Z=z+HALF_ELE_SIZE; + + points[7].X=x-HALF_ELE_SIZE; + points[7].Y=y+HALF_ELE_SIZE*8; + points[7].Z=z+HALF_ELE_SIZE; + + for(c0=0;c0<8;c0++) + { + //transform all points for this Object + rotate_point_gte(&points[c0],&res[c0]); + } + DrawLineC(res[0].X,res[0].Y,res[3].X,res[3].Y,1); + DrawLineC(res[1].X,res[1].Y,res[2].X,res[2].Y,1); + DrawLineC(res[5].X,res[5].Y,res[6].X,res[6].Y,1); + DrawLineC(res[4].X,res[4].Y,res[7].X,res[7].Y,1); + + points[0].X=x-HALF_ELE_SIZE*8; + points[0].Y=y-HALF_ELE_SIZE; + points[0].Z=z-HALF_ELE_SIZE; + + points[1].X=x+HALF_ELE_SIZE*8; + points[1].Y=y-HALF_ELE_SIZE; + points[1].Z=z-HALF_ELE_SIZE; + + points[2].X=x+HALF_ELE_SIZE*8; + points[2].Y=y+HALF_ELE_SIZE; + points[2].Z=z-HALF_ELE_SIZE; + + points[3].X=x-HALF_ELE_SIZE*8; + points[3].Y=y+HALF_ELE_SIZE; + points[3].Z=z-HALF_ELE_SIZE; + + points[4].X=x-HALF_ELE_SIZE*8; + points[4].Y=y-HALF_ELE_SIZE; + points[4].Z=z+HALF_ELE_SIZE; + + points[5].X=x+HALF_ELE_SIZE*8; + points[5].Y=y-HALF_ELE_SIZE; + points[5].Z=z+HALF_ELE_SIZE; + + points[6].X=x+HALF_ELE_SIZE*8; + points[6].Y=y+HALF_ELE_SIZE; + points[6].Z=z+HALF_ELE_SIZE; + + points[7].X=x-HALF_ELE_SIZE*8; + points[7].Y=y+HALF_ELE_SIZE; + points[7].Z=z+HALF_ELE_SIZE; + + for(c0=0;c0<8;c0++) + { + //transform all points for this Object + rotate_point_gte(&points[c0],&res[c0]); + } + DrawLineC(res[0].X,res[0].Y,res[1].X,res[1].Y,1); + DrawLineC(res[3].X,res[3].Y,res[2].X,res[2].Y,1); + DrawLineC(res[4].X,res[4].Y,res[5].X,res[5].Y,1); + DrawLineC(res[7].X,res[7].Y,res[6].X,res[6].Y,1); + + points[0].X=x-HALF_ELE_SIZE; + points[0].Y=y-HALF_ELE_SIZE; + points[0].Z=z-HALF_ELE_SIZE*8; + + points[1].X=x+HALF_ELE_SIZE; + points[1].Y=y-HALF_ELE_SIZE; + points[1].Z=z-HALF_ELE_SIZE*8; + + points[2].X=x+HALF_ELE_SIZE; + points[2].Y=y+HALF_ELE_SIZE; + points[2].Z=z-HALF_ELE_SIZE*8; + + points[3].X=x-HALF_ELE_SIZE; + points[3].Y=y+HALF_ELE_SIZE; + points[3].Z=z-HALF_ELE_SIZE*8; + + points[4].X=x-HALF_ELE_SIZE; + points[4].Y=y-HALF_ELE_SIZE; + points[4].Z=z+HALF_ELE_SIZE*8; + + points[5].X=x+HALF_ELE_SIZE; + points[5].Y=y-HALF_ELE_SIZE; + points[5].Z=z+HALF_ELE_SIZE*8; + + points[6].X=x+HALF_ELE_SIZE; + points[6].Y=y+HALF_ELE_SIZE; + points[6].Z=z+HALF_ELE_SIZE*8; + + points[7].X=x-HALF_ELE_SIZE; + points[7].Y=y+HALF_ELE_SIZE; + points[7].Z=z+HALF_ELE_SIZE*8; + + for(c0=0;c0<8;c0++) + { + //transform all points for this Object + rotate_point_gte(&points[c0],&res[c0]); + } + DrawLineC(res[0].X,res[0].Y,res[4].X,res[4].Y,1); + DrawLineC(res[1].X,res[1].Y,res[5].X,res[5].Y,1); + DrawLineC(res[2].X,res[2].Y,res[6].X,res[6].Y,1); + DrawLineC(res[3].X,res[3].Y,res[7].X,res[7].Y,1); + +#endif +} + +void set_screen_box(SLONG x,SLONG y,SLONG z, EdRect *rect,SLONG w,SLONG h) +{ + + struct SVector p,res; + SLONG temp; + temp=engine.ClipFlag; + engine.ClipFlag=0; + p.X=x; + p.Y=y; + p.Z=z; + rotate_point_gte(&p,&res); + rect->SetRect(res.X-w,res.Y-h,w*2,h*2); + engine.ClipFlag=temp; +} + +void calc_things_screen_box(SLONG map_thing,EdRect *rect) +{ + struct MapThing *p_mthing; + + p_mthing=TO_MTHING(map_thing); + switch(p_mthing->Type) + { + case MAP_THING_TYPE_ANIM_PRIM: + set_screen_box(p_mthing->X,p_mthing->Y,p_mthing->Z,rect,20,20); + break; + case MAP_THING_TYPE_PRIM: + //3ds Prim Mesh + set_camera_angledy(p_mthing->AngleY); + calc_prims_screen_box(p_mthing->IndexOther,p_mthing->X,p_mthing->Y,p_mthing->Z,rect); + set_camera_angledy(0); + + break; + case MAP_THING_TYPE_LIGHT: + set_screen_box(p_mthing->X,p_mthing->Y,p_mthing->Z,rect,10,10); + break; + + case MAP_THING_TYPE_SPRITE: + case MAP_THING_TYPE_AGENT: + break; + + } +} + +SLONG hilight_map_things(UWORD type) +{ + SLONG dx,dy,dz; + SLONG mx,my,mz; + UWORD index; + EdRect prim_rect; + struct MapThing *p_mthing; + static UBYTE col=250; + SLONG screen_change=0; + col++; + if(col==0) + col=250; + + + mx=(engine.X>>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + for(dz=-28;dz<28;dz++) + for(dx=-28;dx<28;dx++) + { +// if(dx+mx>0&&dx+mx0&&dz+mzIndexNext; + screen_change=1; + } + return(screen_change); +} + +SLONG select_map_backgrounds(MFPoint *mouse,UWORD type) +{ + EdRect prim_rect; + SWORD index; + static UBYTE col=250; + struct MapThing *p_thing; + + col++; + if(col==0) + col=250; + + index=background_prim; + while(index) + { + p_thing=TO_MTHING(index); + calc_things_screen_box(index,&prim_rect); + if(prim_rect.PointInRect(mouse)) + return(index); + index=p_thing->IndexNext; + } + return(0); +} + + +SLONG select_map_things(MFPoint *mouse,UWORD type) +{ + SLONG dx,dy,dz; + SLONG mx,my,mz; + UWORD index; + EdRect prim_rect; + struct MapThing *p_mthing; + static UBYTE col=0; + SLONG screen_change=0; + col++; + + mx=(engine.X>>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + for(dz=-32;dz<32;dz++) + for(dx=-32;dx<32;dx++) + { +// if(dx+mx>0&&dx+mx0&&dz+mzType) + { + case MAP_THING_TYPE_ANIM_PRIM: +extern void draw_anim_prim_tween(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct GameKeyFrameElement *anim_info,struct GameKeyFrameElement *anim_info_next,struct Matrix33 *rot_mat); + // break; + rotate_obj ( + p_mthing->AngleX, + p_mthing->AngleY, + p_mthing->AngleZ, + &r_matrix + ); + { + the_chunk=&anim_chunk[p_mthing->IndexOther]; + for(c1=0,c0=prim_multi_objects[the_chunk->MultiObject[0]].StartObject;c0MultiObject[0]].EndObject;c0++,c1++) + { + draw_anim_prim_tween ( + c0, + p_mthing->X,p_mthing->Y,p_mthing->Z, + 0, + &the_chunk->AnimList[1]->FirstElement[c1], + &the_chunk->AnimList[1]->FirstElement[c1], + //&p_mthing->AnimElements[c1], + //&p_mthing->NextAnimElements[c1], + &r_matrix + ); + } + } + + break; + case MAP_THING_TYPE_PRIM: + //3ds Prim Mesh +// engine.AngleDY=p_mthing->AngleY; + set_camera_angledy(p_mthing->AngleY); + +// if(p_mthing->Flags&FLAG_EDIT_PRIM_ON_FLOOR || (prim_objects[p_mthing->IndexOther].flag & PRIM_FLAG_ON_FLOOR) ) + + /* + + if((prim_objects[p_mthing->IndexOther].flag & PRIM_FLAG_ON_FLOOR) ) + { + + SLONG px,py,pz,y; + +extern void find_things_min_point(SLONG drag,SLONG *px,SLONG *py,SLONG *pz); + + find_things_min_point(p_mthing->IndexOther,&px,&py,&pz); + +extern SLONG find_alt_for_this_pos(SLONG x,SLONG z); + y=find_alt_for_this_pos(p_mthing->X,p_mthing->Z); +// y=calc_edit_height_at(p_mthing->X,p_mthing->Z); + y-=py; + p_mthing->Y=y; + } + else + if(prim_objects[p_mthing->IndexOther].flag & PRIM_FLAG_JUST_FLOOR) + { + + SLONG px,py,pz,y; + +extern void find_things_min_point(SLONG drag,SLONG *px,SLONG *py,SLONG *pz); + + find_things_min_point(p_mthing->IndexOther,&px,&py,&pz); + + y=calc_edit_height_at(p_mthing->X,p_mthing->Z); + y-=py; + p_mthing->Y=y; + } + */ + + draw_a_prim_at(p_mthing->IndexOther,p_mthing->X,p_mthing->Y,p_mthing->Z,1); + set_camera_angledy(0); + //engine.AngleDY=0; + break; + case MAP_THING_TYPE_BUILDING: + draw_a_building_at(p_mthing->IndexOther,p_mthing->X,p_mthing->Y,p_mthing->Z); + break; + case MAP_THING_TYPE_MULTI_PRIM: + draw_a_multi_prim_at(p_mthing->IndexOther,p_mthing->X,p_mthing->Y,p_mthing->Z); + break; + + case MAP_THING_TYPE_ROT_MULTI: +#ifdef DOGPOO + // break; + rotate_obj ( + p_mthing->AngleX, + p_mthing->AngleY, + p_mthing->AngleZ, + &r_matrix + ); + //if(p_mthing->AnimElements&&p_mthing->NextAnimElements) + if(p_mthing->CurrentFrame&&p_mthing->NextFrame) + { + for(c1=0,c0=prim_multi_objects[test_chunk->MultiObject].StartObject;c0MultiObject].EndObject;c0++,c1++) + { +/* if(c1==1) + { +extern UBYTE store_pos; + store_pos = 1; + } +*/ + draw_prim_tween ( + c0, + p_mthing->X,p_mthing->Y,p_mthing->Z, + p_mthing->TweenStage, + &p_mthing->CurrentFrame->FirstElement[c1], + &p_mthing->NextFrame->FirstElement[c1], + //&p_mthing->AnimElements[c1], + //&p_mthing->NextAnimElements[c1], + &r_matrix + ); + } + } +#endif + break; + case MAP_THING_TYPE_SPRITE: + case MAP_THING_TYPE_AGENT: + break; + + } +} + +extern SLONG play_x,play_y,play_z; + + +void scan_a_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG *mid_x,SLONG *mid_y,SLONG *mid_z) +{ + SLONG c0; + struct PrimObject *p_obj; + SLONG sp,ep; + + + p_obj = &prim_objects[prim]; + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + *mid_x=0; + *mid_y=0; + *mid_z=0; + + for(c0=sp;c0StartPoint; + ep=p_obj->EndPoint; + + + for(c0=sp;c0*dist) + *dist=c_dist; + } + +} + + +void zoom_map_onto_screen(void) +{ + SWORD index; + struct MapThing *p_thing; + SLONG mid_x=0,mid_y=0,mid_z=0,mx,my,mz,count=0; + SLONG dist,b_dist=-999999; + + index=background_prim; + while(index) + { + p_thing=TO_MTHING(index); + scan_a_prim_at(p_thing->IndexOther,p_thing->X,p_thing->Y,p_thing->Z,&mx,&my,&mz); + mid_x+=mx; + mid_y+=my; + mid_z+=mz; + count++; + index=p_thing->IndexNext; + } + if(count) + { + mid_x/=count; + mid_y/=count; + mid_z/=count; + } + engine.X=mid_x<<8; + engine.Y=mid_y<<8; + engine.Z=mid_z<<8; + + index=background_prim; + while(index) + { + p_thing=TO_MTHING(index); + scan_a_prim_at_dist(p_thing->IndexOther,p_thing->X,p_thing->Y,p_thing->Z,mid_x,mid_y,mid_z,&dist); + if(dist>b_dist) + b_dist=dist; + index=p_thing->IndexNext; + } + // <<5*scale)>>16 + +// pos=((b_dist<<5)*scale)>>16; + + engine.Scale=(200<<11)/(b_dist); +// LogText(" zoom map dist= %d newscale %d = %d\n",b_dist,engine.Scale,((b_dist<<5)*engine.Scale)>>16); + +} + + +void draw_linked_background(void) +{ + SWORD index; + struct MapThing *p_thing; + index=background_prim; + while(index) + { + p_thing=TO_MTHING(index); + draw_a_prim_at(p_thing->IndexOther,p_thing->X,p_thing->Y,p_thing->Z,1); + index=p_thing->IndexNext; + } +} + +#define CLIPNEG(x) if(x<0)x=0 +#define SHADOW_SIZE 48 + + +// 1 2 +// +// 3 4 + +SLONG add_floor_tri_to_bucket(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG x3,SLONG y3,SLONG z3,struct DepthStrip *p_map,SLONG s1,SLONG s2,SLONG s3,SLONG shadow_flag,SLONG tx1,SLONG ty1,SLONG tx2,SLONG ty2,SLONG tx3,SLONG ty3,SLONG page) +{ + SLONG az; + if(current_bucket_pool > end_bucket_pool) + return(0); + az=z1; + setPolyType3( + current_bucket_pool, + POLY_GT + ); + + + + + setXY3 ( + (struct BucketTri*)current_bucket_pool, + x1,y1, + x2,y2, + x3,y3 + + ); + + setUV3( (struct BucketTri*)current_bucket_pool,tx1,ty1,tx2,ty2,tx3,ty3,page); + + setZ3((struct BucketTri*)current_bucket_pool,z1,z2,z3); + + + if(shadow_flag) + { + s1-=SHADOW_SIZE; + s2-=SHADOW_SIZE; + s3-=SHADOW_SIZE; + CLIPNEG(s1); + CLIPNEG(s2); + CLIPNEG(s3); + } + + setShade3((struct BucketTri*)current_bucket_pool,s1,s2,s3); + ((struct BucketTri*)current_bucket_pool)->DebugInfo=z1; + ((struct BucketTri*)current_bucket_pool)->DebugFlags=0; + add_bucket((void *)current_bucket_pool,az+300); + + + current_bucket_pool += sizeof(struct BucketTri); + return(0); + +} + +#define SET_TX_TY(x1,y1,x2,y2,x3,y3,x4,y4) tx1=x1;ty1=y1;tx2=x2;ty2=y2;tx3=x3;ty3=y3;tx4=x4;ty4=y4; + +SLONG add_floor_face_to_bucket(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG x3,SLONG y3,SLONG z3,SLONG x4,SLONG y4,SLONG z4,struct DepthStrip *p_map,SLONG s1,SLONG s2,SLONG s3,SLONG s4,UWORD tex) +{ + SLONG az; + UBYTE tx,ty,tsize,page; + SLONG shadow; + SLONG ret=0; + UBYTE tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4; + + az=z1; + + if(current_bucket_pool > end_bucket_pool) + return(0); + + if(check_mouse_over_floor_quad(x1,y1,x2,y2,x3,y3,x4,y4,0,az)) + { + ret=1; + } + + if(p_map->Walkable==-1) + { + struct AnimTmap *p_a; + SLONG cur; + + p_a=&anim_tmaps[p_map->Texture]; + cur=p_a->Current; + SET_TX_TY(p_a->UV[cur][0][0],p_a->UV[cur][0][1],p_a->UV[cur][1][0],p_a->UV[cur][1][1],p_a->UV[cur][2][0],p_a->UV[cur][2][1],p_a->UV[cur][3][0],p_a->UV[cur][3][1]); + page=p_a->Page[cur]; + tsize=32; + + } + else + { + + tx=((struct MiniTextureBits*)(&tex))->X<<5; + ty=((struct MiniTextureBits*)(&tex))->Y<<5; + page=((struct MiniTextureBits*)(&tex))->Page; + tsize=31; //floor_texture_sizes[((struct MiniTextureBits*)(&tex))->Size]-1; + switch(((struct MiniTextureBits*)(&tex))->Rot) + { + case 0: + SET_TX_TY(tx,ty,tx+tsize,ty,tx,ty+tsize,tx+tsize,ty+tsize); + break; + case 1: + SET_TX_TY( ,tx+tsize,ty,tx+tsize,ty+tsize,tx,ty,tx,ty+tsize); + break; + case 2: + SET_TX_TY( ,tx+tsize,ty+tsize,tx,ty+tsize,tx+tsize,ty,tx,ty); + break; + case 3: + SET_TX_TY( ,tx,ty+tsize,tx,ty,tx+tsize,ty+tsize,tx+tsize,ty); + break; + } + } + + + shadow=p_map->Flags&FLOOR_SHADOW_TYPE; + + if(shadow) + { + switch(shadow) + { + case 1: // all shadow + s1-=SHADOW_SIZE; + s2-=SHADOW_SIZE; + s3-=SHADOW_SIZE; + s4-=SHADOW_SIZE; + CLIPNEG(s1); + CLIPNEG(s2); + CLIPNEG(s3); + CLIPNEG(s4); + break; + case 2: + // . + // .. + // ... + add_floor_tri_to_bucket(x2,y2,z2,x4,y4,z4,x3,y3,z3,p_map,s2,s4,s3,1,tx2,ty2,tx4,ty4,tx3,ty3,page); + add_floor_tri_to_bucket(x2,y2,z2,x3,y3,z3,x1,y1,z1,p_map,s2,s3,s1,0,tx2,ty2,tx3,ty3,tx1,ty1,page); + return(ret); + case 3: + // . + // .. + // ... + add_floor_tri_to_bucket(x1,y1,z1,x4,y4,z4,x3,y3,z3,p_map,s1,s4,s3,1,tx1,ty1,tx4,ty4,tx3,ty3,page); + add_floor_tri_to_bucket(x1,y1,z1,x2,y2,z2,x4,y4,z4,p_map,s1,s2,s4,0,tx1,ty1,tx2,ty2,tx4,ty4,page); + return(ret); + case 4: + // ... + // .. + // . + add_floor_tri_to_bucket(x1,y1,z1,x2,y2,z2,x3,y3,z3,p_map,s1,s2,s3,1,tx1,ty1,tx2,ty2,tx3,ty3,page); + add_floor_tri_to_bucket(x2,y2,z2,x4,y4,z4,x3,y3,z3,p_map,s2,s4,s3,0,tx2,ty2,tx4,ty4,tx3,ty3,page); + return(ret); + case 5: + // ... + // .. + // . + add_floor_tri_to_bucket(x1,y1,z1,x2,y2,z2,x4,y4,z4,p_map,s1,s2,s4,1,tx1,ty1,tx2,ty2,tx4,ty4,page); + add_floor_tri_to_bucket(x1,y1,z1,x4,y4,z4,x3,y3,z3,p_map,s1,s4,s3,0,tx1,ty1,tx4,ty4,tx3,ty3,page); + return(ret); + } + } + + + setPolyType4( + current_bucket_pool, + POLY_GT + ); + + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + 1 + ); + + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + x1,y1, + x2,y2, + x3,y3, + x4,y4 + + ); + +// if(SelectFlag) +// do_quad_clip_list(c0,p0,p1,p2,p3); + setUV4( (struct BucketQuad*)current_bucket_pool,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4,page); + // tx,ty,tx+tsize,ty,tx,ty+tsize,tx+tsize,ty+tsize,page); + + setZ4((struct BucketQuad*)current_bucket_pool,z1,z2,z3,z4); + + + +// setShade4((struct BucketQuad*)current_bucket_pool,p_f4->Bright[0],p_f4->Bright[1],p_f4->Bright[2],p_f4->Bright[3]); + setShade4((struct BucketQuad*)current_bucket_pool,s1,s2,s3,s4); + ((struct BucketQuad*)current_bucket_pool)->DebugInfo=z1; + ((struct BucketQuad*)current_bucket_pool)->DebugFlags=0; + add_bucket((void *)current_bucket_pool,az+300); + + + + +/* + if(check_mouse_over_prim_quad(global_res,p0,p1,p2,p3,c0)) + { + selected_prim_xyz.X = x; + selected_prim_xyz.Y = y; + selected_prim_xyz.Z = z; + } +*/ + current_bucket_pool += sizeof(struct BucketQuad); + return(ret); +} + +#define SWAP_ROW() \ +{ \ + struct SVector *temp_ptr_sv; \ + ULONG *temp_ptr_flag; \ + temp_ptr_sv=prev_row_ptr; \ + prev_row_ptr=row_ptr; \ + row_ptr=temp_ptr_sv; \ + temp_ptr_flag=prev_row_flag_ptr; \ + prev_row_flag_ptr=row_flag_ptr; \ + row_flag_ptr=temp_ptr_flag; \ +} + + +#define DRAW_WIDTH 24 +void draw_map_floor(void) +{ + SLONG dx,dz; + SLONG mx,my,mz; + struct SVector point,row[2][66]; + ULONG row_flags[2][66]; + struct SVector *row_ptr; + ULONG *row_flag_ptr; + struct SVector *prev_row_ptr; + ULONG *prev_row_flag_ptr; + SLONG row_count; + UWORD texture; + +// LogText(" ddraw mmaap floorr \n"); + + + mx=(engine.X>>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + + row_ptr=&row[0][0]; + row_flag_ptr=&row_flags[0][0]; + + for(row_count=0,dx=-DRAW_WIDTH,dz=-DRAW_WIDTH;dx>8); + + row_flag_ptr[row_count]=rotate_point_gte(&point,&row_ptr[row_count]); + } + + prev_row_ptr=row_ptr; + prev_row_flag_ptr=row_flag_ptr; + + row_ptr=&row[1][0]; + row_flag_ptr=&row_flags[1][0]; + + for(dz=(-DRAW_WIDTH)+1;dz>8); + *row_flag_ptr=rotate_point_gte(&point,row_ptr); + } + else + // if(dx+mx-1>0&&dx+mx+10&&dz+mz+1>8); + row_flag_ptr[row_count]=rotate_point_gte(&point,&row_ptr[row_count]); + +// if(dx+mx-1>0&&dx+mx+10&&dz+mz+1>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + for(dx=-32;dx<=32;dx+=32) + for(dz=-32;dz<32;dz++) + { + struct SVector point,res; + SLONG x,z; + ULONG flags; + + x=dx*ELE_SIZE+(mx<max_z) + { + max_z=z; + } + if(zmax_x) + { + max_x=x; + } + if(x=EDIT_MAP_WIDTH<<8) + max_x=(EDIT_MAP_WIDTH<<8)-1; + + if(max_z>=EDIT_MAP_WIDTH<<8) + max_z=(EDIT_MAP_WIDTH<<8)-1; + + *minx=min_x; + *maxx=max_x; + + *minz=min_z; + *maxz=max_z; +} + +void draw_editor_map(ULONG flags) +{ + SLONG dx,dy,dz; + SLONG mx,my,mz; + struct EditMapElement *p_ele; + UWORD index; + + animate_texture_maps(); +// LogText(" draw editor \n"); + + engine.TrueY=engine.Y; + mx=(engine.X>>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; +//#ifdef POO + draw_map_floor(); + + + for(dz=-32;dz<32;dz++) + for(dx=-32;dx<32;dx++) + { +// if(dx+mx>0&&dx+mx0&&dz+mz=0 && dz+mzCubeType.Prim) + { + case 0: + //error + break; + case CUBE_TYPE_FULL: + draw_cube_ele_at((dx+mx)<>8)>>ELE_SHIFT; + y=(engine.Y>>8)>>ELE_SHIFT; + z=(engine.Z>>8)>>ELE_SHIFT; + + sprintf(str," x %d y %d z %d ",x,y,z); + QuickText(20,20,str,0); + + } +void process_map(); + process_map(); + + +//#endif +// test_poly(); +// editor_user_interface(); +/* + if(editor.TexturePriority) + render_view(1); + if(editor.TexturePriority) + show_texture(0,0,0,0); +*/ + if(SelectFlag<5) + SelectFlag=0; +} + + +/* --------------------------- 3DSRDR.C ------------------------------- + .3DS file format exerciser v1.2. + Written by Javier Arevalo, AKA Jare/Iguana. + I compile this with Watcom/32, but I guess it should work with + any compiler and OS combination for which the typedefs are + valid i.e. any that I know for PCs... Try it and see. + Oh, and also check the #pragma pack() thing. + + - DISCLAIMER - + + I hope I have not broken any patents or trade secrets by releasing + this info. This is purely a mind exercise to break into a file + format that is quite useful to know. As far as I have been told + a file format is not subject to anything such as copyright or + patent, so I have done this because I believe I'm allowed to. + + I PLACE THIS FILE IN THE PUBLIC DOMAIN, SO EVERYTHING CONTAINED HERE + IS TOTALLY FREE FOR YOU TO EXPLORE AND USE. I DISCLAIM ANY AND ALL + EVENTS COMING OUT OF ANY POSSIBLE USE (OR LACK OF USE) OR EXISTANCE + OF THIS FILE. I WON'T BE LIABLE FOR ANYTHING RELATED TO THIS FILE, + OR ANY PRIOR OR FUTURE VERSION OF IT. + + All trademarks mentioned are property of their respective holders. + + - Merits - + + Heavily based on info on the file 3DS_08.TXT by Jim Pitts + (jp5@ukc.ac.uk) + + Basic material-related stuff digged up by Jare. + Track info stuff too. + + Thanks to the Egerter brothers of WGT fame and to Walken/Impact studios + for extra info, Rex Deathstar for support. And definitely to + Xanthome/Darkzone for you know why. And of course, respect to + Avatar/Legend Design for being here before all of us. + + For a cool example of actual reading of 3DS files, look no + further than 3DSCO20.ZIP by Mats Byggmastar aka. MRI. I + personally prefer using a table-driven modification of this + code, but both approaches are quite ok and his is much faster + to write and follow. + + Now only lack is someone to explain how to make use of all this + stuff i.e. how exactly is data stored, how spline interpolations + are performed, what are those things called quaternions, etc. And + also, maybe, dig the rest of the chunks until we are actually able + to write 3DS files instead of just being bored reading. There's + lots to do. + + If you decide to work on this further, please make your findings + public like we have already done, ok? Upload it to + x2ftp.oulu.fi, THE place for programming info, and/or to + ftp.cdrom.com. But please PUBLISH it! + + - Change log - + + V 1.2: + - Added change log to have some idea what's going on. + - Added pivot point reading inside tracks stuff. + - Info about spline flags on keyframes. + - Added face edge visibility info. + - Finally!! Those flags that mark when the texture is wrapping + around inside a face. This happens when you apply spherical + or cylindrical coordinates, the faces along the 0§ axis don't + get proper mapping coords. Someone describe how to fix this? + - Added -quiet parm, only displays minimal chunk info. + - Object parent number is stored in CHUNK_TRACKOBJNAME. + This makes reference to the node number in CHUNK_OBJNUMBER. + - Object number changed to unsigned. Parent 65535 means none. + - Added CHUNK_PRJ and CHUNK_MLI to allow inspecting .PRJ and + .MLI files (they're basically the same chunks as .3DS). + - Added banner to identify myself, and disclaimer for "just in + case" possibilities. + - Corrected possible bug when chunklen == 0 (it was not a + chunk). + - Added several name descriptions of chunks. Use diff to find + all the new chunks. +*/ + +#include +#include +#include + +#ifndef PI +#define PI 3.141592687 +#endif + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long dword; + +typedef signed char sbyte; +typedef signed short sword; +typedef signed long sdword; + +#pragma pack(2) + +#define printf LogText + +typedef struct { + word id; + dword len; +} TChunkHeader, *PChunkHeader; + +#pragma pack() + +enum { + CHUNK_RGBF = 0x0010, + CHUNK_RGBB = 0x0011, +// CHUNK_RBGB2 = 0x0012, // ?? NOT HLS. + + CHUNK_PRJ = 0xC23D, + CHUNK_MLI = 0x3DAA, + + CHUNK_MAIN = 0x4D4D, + CHUNK_OBJMESH = 0x3D3D, + CHUNK_BKGCOLOR = 0x1200, + CHUNK_AMBCOLOR = 0x2100, + CHUNK_OBJBLOCK = 0x4000, + CHUNK_TRIMESH = 0x4100, + CHUNK_VERTLIST = 0x4110, + CHUNK_FACELIST = 0x4120, + CHUNK_FACEMAT = 0x4130, + CHUNK_MAPLIST = 0x4140, + CHUNK_SMOOLIST = 0x4150, + CHUNK_TRMATRIX = 0x4160, + CHUNK_LIGHT = 0x4600, + CHUNK_SPOTLIGHT = 0x4610, + CHUNK_CAMERA = 0x4700, + CHUNK_HIERARCHY = 0x4F00, + CHUNK_VIEWPORT = 0x7001, + CHUNK_MATERIAL = 0xAFFF, + CHUNK_MATNAME = 0xA000, + CHUNK_AMBIENT = 0xA010, + CHUNK_DIFFUSE = 0xA020, + CHUNK_SPECULAR = 0xA030, + CHUNK_TEXTURE = 0xA200, + CHUNK_BUMPMAP = 0xA230, + CHUNK_MAPFILE = 0xA300, + CHUNK_KEYFRAMER = 0xB000, + CHUNK_AMBIENTKEY = 0xB001, + CHUNK_TRACKINFO = 0xB002, + CHUNK_TRACKOBJNAME = 0xB010, + CHUNK_TRACKPIVOT = 0xB013, + CHUNK_TRACKPOS = 0xB020, + CHUNK_TRACKROTATE = 0xB021, + CHUNK_TRACKSCALE = 0xB022, + CHUNK_OBJNUMBER = 0xB030, + CHUNK_TRACKCAMERA = 0xB003, + CHUNK_TRACKFOV = 0xB023, + CHUNK_TRACKROLL = 0xB024, + CHUNK_TRACKCAMTGT = 0xB004, + CHUNK_TRACKLIGHT = 0xB005, + CHUNK_TRACKLIGTGT = 0xB006, + CHUNK_TRACKSPOTL = 0xB007, + CHUNK_FRAMES = 0xB008, + + +}; + +// ------------------------------------ + + // Forward declaration. +void ChunkReader(FILE *f, int ind, long p); + +void SkipReader(FILE *f, int ind, long p) +{ +} + +void RGBFReader (FILE *f, int ind, long p) { + float c[3]; + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s Red: %f, Green: %f, Blue: %f\n", ind, "", c[0], c[1], c[2]); +} + +void RGBBReader (FILE *f, int ind, long p) { + byte c[3]; + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s Red: %d, Green: %d, Blue: %d\n", ind, "", c[0], c[1], c[2]); +} + +void ASCIIZReader (FILE *f, int ind, long p) { + int c; + + // Read ASCIIZ name + while ( (c = fgetc(f)) != EOF && c != '\0') + putchar(c); + printf("\"\n"); +} + +void ObjBlockReader (FILE *f, int ind, long p) { + int c; + + // Read ASCIIZ object name + printf("%*sObject name \"", ind, ""); + ASCIIZReader(f, ind, p); + // Read rest of chunks inside this one. + ChunkReader(f, ind, p); +} + +void VertListReader (FILE *f, int ind, long p) { + word nv; + float c[3]; + + if (fread(&nv, sizeof(nv), 1, f) != 1) return; + printf("%*sVertices: %d\n", ind, "", nv); + while (nv-- > 0) { + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s X: %f, Y: %f, Z: %f\n", ind, "", c[0], c[1], c[2]); + } +} + +void FaceListReader (FILE *f, int ind, long p) { + word nv; + word c[3]; + word flags; + + if (fread(&nv, sizeof(nv), 1, f) != 1) return; + printf("%*sFaces: %d\n", ind, "", nv); + while (nv-- > 0) { + if (fread(&c, sizeof(c), 1, f) != 1) return; + if (fread(&flags, sizeof(flags), 1, f) != 1) return; + printf("%*s A %d, B %d, C %d, 0x%X:", + ind, "", c[0], c[1], c[2], flags); +// printf("%*s AB: %d, BC: %d, CA: %d, UWrap %d, VWrap %d\n", +// ind, "", + printf(" AB %d BC %d CA %d UWrap %d VWrap %d\n", + (flags & 0x04) != 0, (flags & 0x02) != 0, (flags & 0x01) != 0, + (flags & 0x08) != 0, (flags & 0x10) != 0); + } + // Read rest of chunks inside this one. + ChunkReader(f, ind, p); +} + +void FaceMatReader (FILE *f, int ind, long p) { + int c; + word n, nf; + + // Read ASCIIZ material name + printf("%*sMaterial name for faces: \"", ind, ""); + ASCIIZReader(f, ind, p); + + if (fread(&n, sizeof(n), 1, f) != 1) return; + printf("%*sFaces with this material: %d\n", ind, "", n); + while (n-- > 0) { + if (fread(&nf, sizeof(nf), 1, f) != 1) return; + printf("%*s Face %d\n", + ind, "", nf); + } +} + +void MapListReader (FILE *f, int ind, long p) { + word nv; + float c[2]; + + if (fread(&nv, sizeof(nv), 1, f) != 1) return; + printf("%*sVertices: %d\n", ind, "", nv); + while (nv-- > 0) { + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s U: %f, V: %f\n", ind, "", c[0], c[1]); + } +} + +void SmooListReader (FILE *f, int ind, long p) { + dword s; + int i; + + while (ftell(f) < p) { + if (fread(&s, sizeof(s), 1, f) != 1) return; + printf("%*sSmoothing groups: ", ind, ""); + for (i = 0; i < 32; i++) + if (s & (1 << i)) + printf("%d, ", i + 1); + printf("\n"); + } +} + +void TrMatrixReader(FILE *f, int ind, long p) { + float rot[9]; + float trans[3]; + if (fread(&rot, sizeof(rot), 1, f) != 1) return; + printf("%*sRotation matrix:\n", ind, ""); + printf("%*s %f, %f, %f\n", ind, "", rot[0], rot[1], rot[2]); + printf("%*s %f, %f, %f\n", ind, "", rot[3], rot[4], rot[5]); + printf("%*s %f, %f, %f\n", ind, "", rot[6], rot[7], rot[8]); + if (fread(&trans, sizeof(trans), 1, f) != 1) return; + printf("%*sTranslation matrix: %f, %f, %f\n", + ind, "", trans[0], trans[1], trans[2]); +} + +void LightReader(FILE *f, int ind, long p) { + float c[3]; + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s X: %f, Y: %f, Z: %f\n", ind, "", c[0], c[1], c[2]); + // Read rest of chunks inside this one. + ChunkReader(f, ind, p); +} + +void SpotLightReader(FILE *f, int ind, long p) { + float c[5]; + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s Target X: %f, Y: %f, Z: %f; Hotspot %f, Falloff %f\n", + ind, "", c[0], c[1], c[2], c[3], c[4]); +} + +void CameraReader(FILE *f, int ind, long p) { + float c[8]; + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s Position: X: %f, Y: %f, Z: %f\n", ind, "", c[0], c[1], c[2]); + printf("%*s Target: X: %f, Y: %f, Z: %f\n", ind, "", c[3], c[4], c[5]); + printf("%*s Bank: %f, Lens: %f\n", ind, "", c[6], c[7]); +} + +void MatNameReader (FILE *f, int ind, long p) { + int c; + + // Read ASCIIZ object name + printf("%*sMaterial name \"", ind, ""); + ASCIIZReader(f, ind, p); +} + +void MapFileReader(FILE *f, int ind, long p) { + int c; + + // Read ASCIIZ filename + printf("%*sMap filename \"", ind, ""); + ASCIIZReader(f, ind, p); +} + +void FramesReader(FILE *f, int ind, long p) { + dword c[2]; + if (fread(&c, sizeof(c), 1, f) != 1) return; + printf("%*s Start: %ld, End: %ld\n", + ind, "", c[0], c[1]); +} + +void TrackObjNameReader(FILE *f, int ind, long p) { + int c; + word w[2]; + word parent; + + // Read ASCIIZ name + printf("%*sTrack object name \"", ind, ""); + ASCIIZReader(f, ind, p); + if (fread(&w, sizeof(w), 1, f) != 1) return; + if (fread(&parent, sizeof(parent), 1, f) != 1) return; + printf("%*sObject name data: Flags 0x%X, 0x%X, Parent %d\n", + ind, "", w[0], w[1], parent); +} + +void PivotPointReader(FILE *f, int ind, long p) { + float pos[3]; + + if (fread(&pos, sizeof(pos), 1, f) != 1) return; + printf("%*s Pivot at X: %f, Y: %f, Z: %f\n", + ind, "", + pos[0], pos[1], pos[2]); +} + + /* Key info flags for position, rotation and scaling: + Until I know the meaning of each bit in flags I assume all mean + a following float data. + */ + + // NOTE THIS IS NOT A CHUNK, but A PART OF SEVERAL CHUNKS +void SplineFlagsReader(FILE *f, int ind, word flags) { + int i; + float dat; + + for (i = 0; i < 16; i++) + { + static const char *flagnames[] = { + "SPLINETension", + "SPLINEContinuity", + "SPLINEBias", + "SPLINEEase To", + "SPLINEEase From", + }; + if (flags & (1 << i)) { + if (fread(&dat, sizeof(dat), 1, f) != 1) return; + if (i < sizeof(flagnames)/sizeof(*flagnames)) + printf("%*s %-15s = %f\n", + ind, "", flagnames[i], dat); + else + printf("%*s %-15s = %f\n", + ind, "", "Unknown", dat); + } + } +} + +void TrackPosReader(FILE *f, int ind, long p) { + word n, nf; + float pos[3]; + word unkown; + word flags; + + fseek(f, 10, SEEK_CUR); + if (fread(&n, sizeof(n), 1, f) != 1) return; + printf("%*sPosition keys: %d\n", ind, "", n); + fseek(f, 2, SEEK_CUR); + while (n-- > 0) { + if (fread(&nf, sizeof(nf), 1, f) != 1) return; + if (fread(&unkown, sizeof(unkown), 1, f) != 1) return; + if (fread(&flags, sizeof(flags), 1, f) != 1) return; + printf("%*s Frame %3d: Flags 0x%X\n", ind, "", nf, flags); + SplineFlagsReader(f, ind, flags); + if (fread(&pos, sizeof(pos), 1, f) != 1) return; + printf("%*s X: %f, Y: %f, Z: %f\n", + ind, "", pos[0], pos[1], pos[2]); + } +} + +void TrackRotReader(FILE *f, int ind, long p) { + word n, nf; + float pos[4]; + word unkown; + word flags; + + fseek(f, 10, SEEK_CUR); + if (fread(&n, sizeof(n), 1, f) != 1) return; + printf("%*sRotation keys: %d\n", ind, "", n); + fseek(f, 2, SEEK_CUR); + while (n-- > 0) + { + if (fread(&nf, sizeof(nf), 1, f) != 1) + { + printf(" error nf\n"); + return; + } + if (fread(&unkown, sizeof(unkown), 1, f) != 1) + { + printf(" error unknown\n"); + return; + } + if (fread(&flags, sizeof(flags), 1, f) != 1) + { + printf(" error flags\n"); + return; + } + printf("%*s Frame %3d: Flags 0x%X\n", ind, "", nf, flags); + + SplineFlagsReader(f, ind, flags); + if (fread(&pos, sizeof(pos), 1, f) != 1) + { + printf(" error pos\n"); + return; + } + printf("%*s Angle: %f§, X: %f, Y: %f, Z: %f\n",ind, "", pos[0], pos[1], pos[2], pos[3]); + } +} + +void TrackScaleReader(FILE *f, int ind, long p) { + word n, nf; + float pos[3]; + word unkown; + word flags; + + fseek(f, 10, SEEK_CUR); + if (fread(&n, sizeof(n), 1, f) != 1) return; + printf("%*sScale keys: %d\n", ind, "", n); + fseek(f, 2, SEEK_CUR); + while (n-- > 0) { + if (fread(&nf, sizeof(nf), 1, f) != 1) return; + if (fread(&unkown, sizeof(unkown), 1, f) != 1) return; + if (fread(&flags, sizeof(flags), 1, f) != 1) return; + printf("%*s Frame %3d: Flags 0x%X\n", ind, "", nf, flags); + SplineFlagsReader(f, ind, flags); + if (fread(&pos, sizeof(pos), 1, f) != 1) return; + printf("%*s X: %f, Y: %f, Z: %f\n", + ind, "", pos[0], pos[1], pos[2]); + } +} + +void ObjNumberReader(FILE *f, int ind, long p) { + word n; + + if (fread(&n, sizeof(n), 1, f) != 1) return; + printf("%*sObject number: %d\n", ind, "", n); +} + + +// ------------------------------------ + +struct { + word id; + const char *name; + void (*func)(FILE *f, int ind, long p); +} ChunkNames[] = { + {CHUNK_RGBF, "RGB float", RGBFReader}, + {CHUNK_RGBB, "RGB byte", RGBBReader}, + + {CHUNK_PRJ, "Project", NULL}, + {CHUNK_MLI, "Material Library", NULL}, + + {CHUNK_MAIN, "Main", NULL}, + {CHUNK_OBJMESH, "Object Mesh", NULL}, + {CHUNK_BKGCOLOR, "Background color", NULL}, + {CHUNK_AMBCOLOR, "Ambient color", NULL}, + {CHUNK_OBJBLOCK, "Object Block", ObjBlockReader}, + {CHUNK_TRIMESH, "Tri-Mesh", NULL}, + {CHUNK_VERTLIST, "Vertex list", VertListReader}, + {CHUNK_FACELIST, "Face list", FaceListReader}, + {CHUNK_FACEMAT, "Face material", FaceMatReader}, + {CHUNK_MAPLIST, "Mappings list", MapListReader}, + {CHUNK_SMOOLIST, "Smoothings", SmooListReader}, + {CHUNK_TRMATRIX, "Matrix", TrMatrixReader}, + {CHUNK_LIGHT, "Light", LightReader}, + {CHUNK_SPOTLIGHT, "Spotlight", SpotLightReader}, + {CHUNK_CAMERA, "Camera", CameraReader}, + {CHUNK_HIERARCHY, "Hierarchy", NULL}, + + {CHUNK_VIEWPORT, "Viewport info", NULL}, + {CHUNK_MATERIAL, "Material", NULL}, + {CHUNK_MATNAME, "Material name", MatNameReader}, + {CHUNK_AMBIENT, "Ambient color", NULL}, + {CHUNK_DIFFUSE, "Diffuse color", NULL}, + {CHUNK_SPECULAR, "Specular color", NULL}, + {CHUNK_TEXTURE, "Texture map", NULL}, + {CHUNK_BUMPMAP, "Bump map", NULL}, + {CHUNK_MAPFILE, "Map filename", MapFileReader}, + + {CHUNK_KEYFRAMER, "Keyframer data", NULL}, + {CHUNK_AMBIENTKEY, "Ambient key", NULL}, + {CHUNK_TRACKINFO, "Track info", NULL}, + {CHUNK_FRAMES, "Frames", FramesReader}, + {CHUNK_TRACKOBJNAME,"Track Obj. Name", TrackObjNameReader}, + {CHUNK_TRACKPIVOT, "Pivot point", PivotPointReader}, + {CHUNK_TRACKPOS, "Position keys", TrackPosReader}, + {CHUNK_TRACKROTATE, "Rotation keys", TrackRotReader}, + {CHUNK_TRACKSCALE, "Scale keys", TrackScaleReader}, + {CHUNK_OBJNUMBER, "Object number", ObjNumberReader}, + + {CHUNK_TRACKCAMERA, "Camera track", NULL}, + {CHUNK_TRACKCAMTGT, "Camera target track", NULL}, + {CHUNK_TRACKLIGHT, "Pointlight track", NULL}, + {CHUNK_TRACKLIGTGT, "Pointlight target track", NULL}, + {CHUNK_TRACKSPOTL, "Spotlight track", NULL}, + {CHUNK_TRACKFOV, "FOV track", NULL}, + {CHUNK_TRACKROLL, "Roll track", NULL}, +}; + +int FindChunk(word id) { + int i; + for (i = 0; i < sizeof(ChunkNames)/sizeof(ChunkNames[0]); i++) + if (id == ChunkNames[i].id) + return i; + return -1; +} + +// ------------------------------------ + +int Verbose = 0; +int Quiet = 0; + +void ChunkReader(FILE *f, int ind, long p) { + TChunkHeader h; + int n; + long pc; + + while (ftell(f) < p) + { + pc = ftell(f); + if (fread(&h, sizeof(h), 1, f) != 1) + return; + if (h.len == 0) + return; + n = FindChunk(h.id); + if (n < 0) + { + if (Verbose) + printf("%*sUnknown chunk: 0x%04X, offset 0x%lX, size: %d bytes.\n", ind, "", h.id, pc, h.len); + fseek(f, pc + h.len, SEEK_SET); + } + else + { + if (!Quiet || ChunkNames[n].func == NULL) + printf("%*sChunk type \"%s\", offset 0x%lX, size %d bytes\n",ind, "", ChunkNames[n].name, pc, h.len); + pc = pc + h.len; + if (ChunkNames[n].func != NULL) + ChunkNames[n].func(f, ind + 2, pc); + else + { + LogText(" Skip ,because NO CODE \n"); + ChunkReader(f, ind + 2, pc); + } + fseek(f, pc, SEEK_SET); + } + if (ferror(f)) + break; + } +} + +// ------------------------------------ + + +void read_3ds(void) +{ + FILE *f; + long p; + return; + + f = fopen("darci1.3ds", "rb"); + if (f == NULL) + { + printf("Can't open %s!\n"); + return; + } + + + // Find file size. + fseek(f, 0, SEEK_END); + p = ftell(f); + fseek(f, 0, SEEK_SET); + // Go! + ChunkReader(f, 0, p); +} + + +struct TinyXZ radius_pool[MAX_RADIUS*4*MAX_RADIUS*2]; +struct TinyXZ *radius_ptr[MAX_RADIUS+2]; + +void build_radius_info(void) +{ + SBYTE *grid; + SLONG dx,dz; + struct TinyXZ *ptr_rad; + SLONG actual_radius,radius,radius_offset,old_radius=0; + SLONG angle; + SLONG sum_count=0; + SLONG count=0; + + ptr_rad=radius_pool; + + + grid=(SBYTE*)MemAlloc((MAX_RADIUS+1)*(MAX_RADIUS+1)*4); + if(grid) + { + + for(radius=(MAX_RADIUS<<2);radius>3;radius--) + { + if((radius>>2)!=old_radius) + { + old_radius=radius>>2; +// LogText(" radius %d max_radius %d \n",radius>>2,MAX_RADIUS); + radius_ptr[(radius>>2)]=ptr_rad; + + } + for(angle=0;angle<2048;angle+=4) + { + for(radius_offset=-4;radius_offset<4;radius_offset++) + { + + dx=(SIN(angle)*(radius+radius_offset))>>(16+2); + dz=(COS(angle)*(radius+radius_offset))>>(16+2); + actual_radius=Root(SDIST2(dx,dz)); + if(actual_radius==(radius>>2)) + { + if(grid[(dx+MAX_RADIUS)+(dz+MAX_RADIUS)*(MAX_RADIUS*2)]!=-1) + { + grid[(dx+MAX_RADIUS)+(dz+MAX_RADIUS)*(MAX_RADIUS*2)]=-1; + ptr_rad->Dx=dx; + ptr_rad->Dz=dz; + ptr_rad->Angle=angle; + ptr_rad++; + } + } + } + } + } + radius_ptr[0]=ptr_rad; + MemFree(grid); + } + for(radius=1;radius",radius); + ptr_rad=radius_ptr[radius]; + count=0; + while(ptr_radAngle,ptr_rad->Dx,ptr_rad->Dz); + ptr_rad++; + count++; + } + sum_count+=count; +// LogText("\n"); + } +// LogText("count=%d sum %d\n",count,sum_count); +} + +void init_editor(void) +{ + SLONG x,z; + + + load_palette("data\\tex01.pal"); + build_radius_info(); + init_poly_system(); +// clear_map(); +// read_3ds(); + PAP_clear(); + + clear_map(); +extern void init_map(void); + init_map(); +/* + edit_map_eles[0].CubeType.Prim=255; + edit_map_eles[1].CubeType.Prim=CUBE_TYPE_FULL; + edit_map_eles[1].CubeFlags=CUBE_FLAG_ALL; + + for(x=0;x>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + +// LogText(" draw arround (%d,%d,%d)\n",mx,my,mz); + + + + memset((UBYTE*)buffer_flags,0,MAX_RADIUS*(MAX_RADIUS+1)*4*4); + + ptr=&buffer_points[MAX_RADIUS+MAX_RADIUS*MAX_RADIUS*2]; + + point.X=(mx<>8); + + clip_flags=rotate_point_gte(&point,ptr); + buffer_flags[MAX_RADIUS+MAX_RADIUS*MAX_RADIUS*2]=clip_flags; + + for(radius=1;radiusDx; + cdz=ptr_rad->Dz; + + dx=(cdx*ELE_SIZE); + dz=(cdz*ELE_SIZE); + + cdx+=MAX_RADIUS; + cdz+=MAX_RADIUS; + + ptr=&buffer_points[cdx+cdz*MAX_RADIUS*2]; + + point.X=dx+(mx<=0&&mx=0 && mz>8); + + + clip_flags=rotate_point_gte(&point,ptr); +// if( ((clip_flags&EF_BEHIND_YOU)==0) && !(clip_flags & EF_CLIPFLAGS)) + { + buffer_flags[cdx+cdz*MAX_RADIUS*2]=clip_flags; + } + ptr_rad++; + } + } + + ptr_flag=buffer_flags; + for(dz=0;dz=0&&dx+mx-MAX_RADIUS=0&&dz+mz-MAX_RADIUSX-GetLeft(); + y_diff = clicked_point->Y-GetTop(); + temp_rect.SetRect(GetLeft(),GetTop(),GetWidth(),GetHeight()); + last_rect = temp_rect; + while(SHELL_ACTIVE && LeftButton) + { + temp_rect.SetRect(MouseX-x_diff,MouseY-y_diff,temp_rect.GetWidth(),temp_rect.GetHeight()); + if(temp_rect.GetLeft()<0) + temp_rect.MoveRect(0,temp_rect.GetTop()); + if(temp_rect.GetTop()<20) + temp_rect.MoveRect(temp_rect.GetLeft(),20); + if(temp_rect.GetRight()>=WorkScreenPixelWidth) + temp_rect.MoveRect(WorkScreenPixelWidth-temp_rect.GetWidth(),temp_rect.GetTop()); + if(temp_rect.GetBottom()>=WorkScreenHeight) + temp_rect.MoveRect(temp_rect.GetLeft(),WorkScreenHeight-temp_rect.GetHeight()); + + if ( + temp_rect.GetLeft()!=last_rect.GetLeft() || + temp_rect.GetTop()!=last_rect.GetTop() || + temp_rect.GetRight()!=last_rect.GetRight() || + temp_rect.GetBottom()!=last_rect.GetBottom() + ) + { + + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + ShowWorkScreen(0); + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + last_rect = temp_rect; + } + } + MoveWindow(temp_rect.GetLeft(),temp_rect.GetTop()); +} + +//--------------------------------------------------------------- + +void EditorModule::SizeModule(MFPoint *clicked_point) +{ + SLONG height, + x_diff, + y_diff; + EdRect last_rect, + temp_rect; + + + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + + temp_rect.SetRect(GetLeft(),GetTop(),GetWidth(),GetHeight()); + last_rect = temp_rect; + while(SHELL_ACTIVE && LeftButton) + { + x_diff = MouseX-clicked_point->X; + y_diff = MouseY-clicked_point->Y; + + if(GetRight()+x_diff>=WorkWindowWidth) + x_diff = (WorkScreenPixelWidth-1)-GetRight(); + if(GetBottom()+y_diff>=WorkScreenHeight) + y_diff = (WorkScreenHeight-1)-GetBottom(); + + height = GetHeight()+y_diff; + ConstrainHeight(&height); + temp_rect.SetRect(GetLeft(),GetTop(),GetWidth()+x_diff,height); + if ( + temp_rect.GetLeft()!=last_rect.GetLeft() || + temp_rect.GetTop()!=last_rect.GetTop() || + temp_rect.GetRight()!=last_rect.GetRight() || + temp_rect.GetBottom()!=last_rect.GetBottom() + ) + { + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + ShowWorkScreen(0); + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + last_rect = temp_rect; + } + } + SizeWindow(x_diff,y_diff); +} + +//--------------------------------------------------------------- + +void EditorModule::HandleContentClick(UBYTE flags,MFPoint *clicked_point) +{ + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + if(WhereInWindow(clicked_point) == IN_CONTENT) + { + // Left click in content. + } + break; + case RIGHT_CLICK: + if(WhereInWindow(clicked_point) == IN_CONTENT) + { + // Right click in content. + } + break; + } +} + +//--------------------------------------------------------------- + +void EditorModule::HandleControlClick(UBYTE flags,MFPoint *clicked_point) +{ + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + if(WhereInWindow(clicked_point) == IN_CONTROLS) + { + // Left click in content. + } + break; + case RIGHT_CLICK: + if(WhereInWindow(clicked_point) == IN_CONTROLS) + { + // Right click in content. + } + break; + } +} + +//--------------------------------------------------------------- + +void EditorModule::HandleModule(void) +{ + +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/Editor.cpp b/fallen/Editor/Source/Editor.cpp new file mode 100644 index 0000000..c6db193 --- /dev/null +++ b/fallen/Editor/Source/Editor.cpp @@ -0,0 +1,634 @@ +// Editor.cpp +// Guy Simmons, 19th February 1997. + +#include "Editor.hpp" +#include "c:\fallen\headers\sound.h" +#include "mfx.h" + +//#include "DXEngine.h" + +#define FRONT_MODULE CurrentModule +//#define DEMO 1 +//#define DX_TEST 1 + +UBYTE editor_status; +ULONG editor_turn, + update; +ControlSet module_set; +EditorModule *CurrentModule, + *ModuleList; +EditorModule *test1; +EdRect module_bounds; +GameEditor *game_editor; +KeyFrameEditor *key_frame_editor; +KeyFrameEditor2 *key_framer; +LevelEditor *level_editor; + +// +// The current texture set. +// + +SLONG editor_texture_set = 1; + + +void update_modules(void); +void add_module(EditorModule *the_module); + +ControlDef module_def[] = +{ + { BUTTON, 0, "Level Editor", 2, 2, 0, 10 }, + { BUTTON, 0, "Key Frame Editor", 68, 2, 0, 10 }, + { BUTTON, 0, "Game Editor", 159, 2, 0, 10 }, + + { 0 } +}; + +//--------------------------------------------------------------- + +void handle_front_module(ULONG clicked_area,MFPoint *clicked_point) +{ + switch(clicked_area) + { + case OUTSIDE_WINDOW: // Invalid click. + break; + case IN_WINDOW: // Clicked in non relevant part of window. + break; + case IN_TITLE: + FRONT_MODULE->MoveModule(clicked_point); + update_modules(); + break; + case IN_GROW: + FRONT_MODULE->SizeModule(clicked_point); + update_modules(); + break; + case IN_ICONS: + FRONT_MODULE->TopIcons.HandleIconClick(0,clicked_point); + update_modules(); //Only really need to redraw the icon strip + break; + case IN_HSCROLL: + break; + case IN_VSCROLL: + break; + case IN_CONTENT: + FRONT_MODULE->HandleContentClick(LEFT_CLICK,clicked_point); + break; + case IN_CONTROLS: + FRONT_MODULE->HandleControlClick(LEFT_CLICK,clicked_point); + break; + } +} + +//--------------------------------------------------------------- +SLONG should_module_exist(EditorModule *m) +{ + if(m==CurrentModule) + return(1); + + if(CurrentModule!=level_editor && CurrentModule!=key_frame_editor && CurrentModule!=game_editor) + { + // + // only draw keyframer modules + // + if(m!=level_editor && m!=game_editor) + return(1); + } + + + + if(CurrentModule==key_frame_editor) + { + if(m!=level_editor && m!=game_editor) + return(1); + } + return(0); +} +// if(current_module==CurrentModule|| (CurrentModule==key_frame_editor && (current_module!=level_editor) && (current_module!=key_frame_editor) && (current_module!=game_editor) ) ) + +void update_modules(void) +{ + EditorModule *current_module; + + + ClearWorkScreen(0); + current_module = ModuleList; + while(current_module) + { + if(should_module_exist(current_module)) + current_module->DrawWindow(); + current_module = current_module->GetNextModuleLink(); + } + + module_set.ControlSetBounds(&module_bounds); + module_set.DrawControlSet(); + + ShowWorkScreen(0); +} + +//--------------------------------------------------------------- + +void bring_module_to_front(EditorModule *the_module) +{ + if(the_module == CurrentModule) + return; // Already at the end of list (Front of display). + + if(the_module->GetLastModuleLink()) + { // Not at start of list. + the_module->GetLastModuleLink()->SetNextModuleLink(the_module->GetNextModuleLink()); + the_module->GetNextModuleLink()->SetLastModuleLink(the_module->GetLastModuleLink()); + } + else + { // At start of list. + ModuleList = the_module->GetNextModuleLink(); + ModuleList->SetLastModuleLink(NULL); + } + the_module->SetLastModuleLink(NULL); + the_module->SetNextModuleLink(NULL); + add_module(the_module); + + update_modules(); +} + +//--------------------------------------------------------------- + +EditorModule *point_in_module(MFPoint *clicked_point) +{ + EditorModule *clicked_module, + *current_module; + + + clicked_module = NULL; + current_module = ModuleList; + while(current_module) + { +// if(current_module==CurrentModule|| (CurrentModule==key_frame_editor && (current_module!=level_editor) && (current_module!=key_frame_editor) && (current_module!=game_editor) ) ) + // if(current_module==CurrentModule|| ((current_module!=level_editor) && (current_module!=key_frame_editor) && (current_module!=game_editor) ) ) + if(should_module_exist(current_module)) + if(current_module->PointInRect(clicked_point)) + clicked_module = current_module; + current_module = current_module->GetNextModuleLink(); + } + return clicked_module; +} + +//--------------------------------------------------------------- + +void add_module(EditorModule *the_module) +{ + if(CurrentModule==NULL) // Start of list? + { + ModuleList = the_module; + CurrentModule = ModuleList; + CurrentModule->SetStateFlags(ACTIVE); + CurrentModule->SetExternalUpdatePtr(&update); + } + else + { + CurrentModule->SetStateFlags(0); + CurrentModule->SetNextModuleLink(the_module); + the_module->SetLastModuleLink(CurrentModule); + CurrentModule = the_module; + CurrentModule->SetStateFlags(ACTIVE); + CurrentModule->SetExternalUpdatePtr(&update); + } +} + +//--------------------------------------------------------------- + +void create_editor_modules(void) +{ + CurrentModule = NULL; + ModuleList = NULL; + + level_editor = new LevelEditor; + ERROR_MSG(level_editor,"Unable to create LevelEditor object."); + if(level_editor) + { + add_module(level_editor); + level_editor->SetupModule(); + } + + key_frame_editor = new KeyFrameEditor; + ERROR_MSG(key_frame_editor,"Unable to create KeyFrameEditor object."); + if(key_frame_editor) + { + add_module(key_frame_editor); + key_frame_editor->SetupModule(); + key_frame_editor->LinkLevelEditor=level_editor; + } + + game_editor = new GameEditor; + ERROR_MSG(game_editor,"Unable to create GameEditor object."); + if(game_editor) + { + add_module(game_editor); + game_editor->SetupModule(); +// game_editor->LinkLevelEditor=level_editor; + } + +#ifdef GUY + key_framer = new KeyFrameEditor2; + ERROR_MSG(key_frame_editor,"Unable to create KeyFrameEditor2 object."); + if(key_framer) + { + add_module(key_framer); + key_framer->SetupModule(); + } +#endif + +} + +//--------------------------------------------------------------- + +void destroy_editor_modules(void) +{ +#ifdef GUY + if(key_framer) + delete key_framer; +#endif + if(key_frame_editor) + delete key_frame_editor; + + if(level_editor) + delete level_editor; +} + +//--------------------------------------------------------------- + + +MFPoint last_mouse; + +void editor(void) +{ + UWORD clicked; + ULONG clicked_area; + Alert *quit_alert; + EditorModule *clicked_module; + MFPoint mouse_point; + + + editor_status = EDITOR_NORMAL; + editor_turn = 0; + update = 0; + while(SHELL_ACTIVE && (editor_status&EDITOR_NORMAL)) + { + // + // Control + Number keys selects the current texture set. + // + + if (Keys[KB_TILD]) + { + Keys[KB_TILD] = 0; + editor_texture_set = 1; + free_game_textures(FREE_UNSHARED_TEXTURES); + load_game_textures(LOAD_UNSHARED_TEXTURES); + } + if (Keys[KB_PPOINT]) + { + SLONG old_texture_set = editor_texture_set; + + if (!ShiftFlag) + { + if (Keys[KB_P1]) {Keys[KB_P1] = 0; editor_texture_set = 1;} + if (Keys[KB_P2]) {Keys[KB_P2] = 0; editor_texture_set = 2;} + if (Keys[KB_P3]) {Keys[KB_P3] = 0; editor_texture_set = 3;} + if (Keys[KB_P4]) {Keys[KB_P4] = 0; editor_texture_set = 4;} + if (Keys[KB_P5]) {Keys[KB_P5] = 0; editor_texture_set = 5;} + if (Keys[KB_P6]) {Keys[KB_P6] = 0; editor_texture_set = 6;} + if (Keys[KB_P7]) {Keys[KB_P7] = 0; editor_texture_set = 7;} + if (Keys[KB_P8]) {Keys[KB_P8] = 0; editor_texture_set = 8;} + if (Keys[KB_P9]) {Keys[KB_P9] = 0; editor_texture_set = 9;} + if (Keys[KB_P0]) {Keys[KB_P0] = 0; editor_texture_set = 10;} + } + else + { + if (Keys[KB_P1]) {Keys[KB_P1] = 0; editor_texture_set = 11;} + if (Keys[KB_P2]) {Keys[KB_P2] = 0; editor_texture_set = 12;} + if (Keys[KB_P3]) {Keys[KB_P3] = 0; editor_texture_set = 13;} + if (Keys[KB_P4]) {Keys[KB_P4] = 0; editor_texture_set = 14;} + if (Keys[KB_P5]) {Keys[KB_P5] = 0; editor_texture_set = 15;} + if (Keys[KB_P6]) {Keys[KB_P6] = 0; editor_texture_set = 16;} + if (Keys[KB_P7]) {Keys[KB_P7] = 0; editor_texture_set = 17;} + if (Keys[KB_P8]) {Keys[KB_P8] = 0; editor_texture_set = 18;} + if (Keys[KB_P9]) {Keys[KB_P9] = 0; editor_texture_set = 19;} + if (Keys[KB_P0]) {Keys[KB_P0] = 0; editor_texture_set = 20;} + +#ifdef I_AM_A_LOON + #define MAX_TICKS 16 + + static SLONG tick_key [MAX_TICKS]; + static SLONG tick_time[MAX_TICKS]; + static SLONG tick_upto; + + ASSERT(WITHIN(tick_upto, 0, MAX_TICKS - 1)); + + if (Keys[KB_P0]) {Keys[KB_P0] = 0; tick_key[tick_upto] = 0; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P1]) {Keys[KB_P1] = 0; tick_key[tick_upto] = 1; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P2]) {Keys[KB_P2] = 0; tick_key[tick_upto] = 2; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P3]) {Keys[KB_P3] = 0; tick_key[tick_upto] = 3; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P4]) {Keys[KB_P4] = 0; tick_key[tick_upto] = 4; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P5]) {Keys[KB_P5] = 0; tick_key[tick_upto] = 5; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P6]) {Keys[KB_P6] = 0; tick_key[tick_upto] = 6; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P7]) {Keys[KB_P7] = 0; tick_key[tick_upto] = 7; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P8]) {Keys[KB_P8] = 0; tick_key[tick_upto] = 8; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + if (Keys[KB_P9]) {Keys[KB_P9] = 0; tick_key[tick_upto] = 9; tick_time[tick_upto] = GetTickCount(); tick_upto++;} + + if (tick_upto >= MAX_TICKS) + { + tick_upto = 0; + } + + // + // Has the correct rhythm been typed in? + // + + if (tick_key[(tick_upto - 1) & (MAX_TICKS - 1)] == tick_key[(tick_upto - 2) & (MAX_TICKS - 1)] && + tick_key[(tick_upto - 1) & (MAX_TICKS - 1)] == tick_key[(tick_upto - 3) & (MAX_TICKS - 1)] && + tick_key[(tick_upto - 1) & (MAX_TICKS - 1)] == tick_key[(tick_upto - 4) & (MAX_TICKS - 1)] && + tick_key[(tick_upto - 1) & (MAX_TICKS - 1)] == tick_key[(tick_upto - 5) & (MAX_TICKS - 1)]) + { + SLONG t1 = tick_time[(tick_upto - 1) & (MAX_TICKS - 1)] - tick_time[(tick_upto - 2) & (MAX_TICKS - 1)]; + SLONG t2 = tick_time[(tick_upto - 2) & (MAX_TICKS - 1)] - tick_time[(tick_upto - 3) & (MAX_TICKS - 1)]; + SLONG t3 = tick_time[(tick_upto - 3) & (MAX_TICKS - 1)] - tick_time[(tick_upto - 4) & (MAX_TICKS - 1)]; + SLONG t4 = tick_time[(tick_upto - 4) & (MAX_TICKS - 1)] - tick_time[(tick_upto - 5) & (MAX_TICKS - 1)]; + + if (t1 > 0 && t2 > 0 && t3 > 0 && t4 > 0) + { + SLONG same1 = (t1 << 8) / t2; + SLONG same2 = (t3 << 8) / t4; + SLONG quaver; + SLONG crotchet; + SLONG same; + + if (WITHIN(same1, 200, 320) && + WITHIN(same2, 200, 320)) + { + quaver = t1 + t2 >> 1; + crotchet = t3 + t4 >> 1; + + same = (quaver * 2 << 8) / crotchet; + + if (WITHIN(same, 200, 320)) + { +// play_quicker_wave(S_THEHILLSAREALIVE); + MFX_play_ambient(0,S_THEHILLSAREALIVE,MFX_REPLACE); + + // + // The right rhythm! Change the texture set. + // + + editor_texture_set = tick_key[(tick_upto - 1) & (MAX_TICKS - 1)]; + + // + // Make sure it doesn't do it any more. + // + + memset(tick_time, 0, sizeof(tick_time)); + } + } + } + } +#endif + } + + if (editor_texture_set != old_texture_set) + { + free_game_textures(FREE_UNSHARED_TEXTURES); + load_game_textures(LOAD_UNSHARED_TEXTURES); + + update_modules(); + } + } + else + { + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + module_set.HandleControlSet(&mouse_point); + + if(LeftMouse.ButtonState) + { + mouse_point.X = LeftMouse.MouseX; + mouse_point.Y = LeftMouse.MouseY; + LeftMouse.ButtonState = 0; + + if(module_set.PointInControlSet(&mouse_point)) + { + clicked = module_set.HandleControlSetClick(LEFT_CLICK,&mouse_point); + switch(clicked) + { + case 1: + bring_module_to_front(level_editor); + update = 1; + break; + case 2: + bring_module_to_front(key_frame_editor); + update = 1; + break; + case 3: + bring_module_to_front(game_editor); + update = 1; + break; + } + } + else + { + clicked_module = point_in_module(&mouse_point); + if(clicked_module==FRONT_MODULE) + { + handle_front_module ( + clicked_module->WhereInWindow(&mouse_point), + &mouse_point + ); + } + else if(clicked_module) + { + bring_module_to_front(clicked_module); + handle_front_module ( + clicked_module->WhereInWindow(&mouse_point), + &mouse_point + ); + } + } + } + else if(RightMouse.ButtonState) + { + mouse_point.X = RightMouse.MouseX; + mouse_point.Y = RightMouse.MouseY; + RightMouse.ButtonState = 0; + + clicked_module = point_in_module(&mouse_point); + if(clicked_module==FRONT_MODULE) + { + clicked_area = clicked_module->WhereInWindow(&mouse_point); + if(clicked_area==IN_CONTENT) + FRONT_MODULE->HandleContentClick(RIGHT_CLICK,&mouse_point); + else if(clicked_area==IN_CONTROLS) + FRONT_MODULE->HandleControlClick(RIGHT_CLICK,&mouse_point); + } + } + else if(MiddleMouse.ButtonState) + { + mouse_point.X = MiddleMouse.MouseX; + mouse_point.Y = MiddleMouse.MouseY; + MiddleMouse.ButtonState = 0; + + clicked_module = point_in_module(&mouse_point); + if(clicked_module==FRONT_MODULE) + { + clicked_area = clicked_module->WhereInWindow(&mouse_point); + if(clicked_area==IN_CONTENT) + FRONT_MODULE->HandleContentClick(MIDDLE_CLICK,&mouse_point); + else if(clicked_area==IN_CONTROLS) + FRONT_MODULE->HandleControlClick(MIDDLE_CLICK,&mouse_point); + } + } + + if(FRONT_MODULE) + { + FRONT_MODULE->HandleModule(); + } + + if(update) + { + update_modules(); + update = 0; + } + + if(LastKey==KB_ESC) //MD || MiddleButton) + { + if(!FRONT_MODULE->LocalEscape()) + { + LastKey = 0; + quit_alert = new Alert; + editor_status = !quit_alert->HandleAlert("Are you sure you want to quit?",NULL); + delete quit_alert; + update_modules(); + } + } + else if(LastKey==KB_R && ControlFlag) + { + editor_status ^= EDITOR_RECORD; + LastKey = 0; + } + else if(LastKey==KB_C && ControlFlag) + { + if(LockWorkScreen()) + { + extern void screen_shot(void); + screen_shot(); + + // do_single_shot(WorkScreen,CurrentPalette); + UnlockWorkScreen(); + } + LastKey = 0; + } + else if(LastKey==KB_TAB && (Keys[KB_LCONTROL] || Keys[KB_RCONTROL])) + { + if(Keys[KB_LSHIFT] || Keys[KB_RSHIFT]) + { + FRONT_MODULE->ActivateLastTab(); + LastKey = 0; + } + else + { + FRONT_MODULE->ActivateNextTab(); + LastKey = 0; + } + } + + if(editor_status&EDITOR_RECORD) + { + if(last_mouse.X!=MouseX||last_mouse.Y!=MouseY) + { + last_mouse.X = MouseX; + last_mouse.Y = MouseY; + ShowWorkScreen(0); + } + } + editor_turn++; + } + } +} + +//--------------------------------------------------------------- + + +UBYTE editor_loop(void) +{ + GameTexture *the_texture; + SLONG i; + + the_display.MenuOff(); + + editor_texture_set = 0; +/* +#ifndef USE_A3D + LoadWaveList("Data\\SFX\\1622\\","Data\\SFX\\Samples.txt"); +#else + A3DLoadWaveList("Data\\SFX\\1622\\","Data\\SFX\\Samples.txt"); +#endif +*/ + for(i=0;i<15;i++) + { + the_texture = &game_textures[i]; + the_texture->TexturePtr = (UWORD*)MemAlloc(TEXTURE_PAGE_SIZE); + } + free_game_textures(FREE_SHARED_TEXTURES); + + load_game_textures(LOAD_SHARED_TEXTURES); + + if(SetDisplay(800,600,16)==NoError) + { + SetDrawFunctions(16); + SetWorkWindowBounds(0,0,800,600); +/* + while(!LeftButton) + { + ClearWorkScreen(0); + if(LockWorkScreen()) + { + DrawCircleC(400,300,abs(MouseX-400),0xffff); + UnlockWorkScreen(); + ShowWorkScreen(0); + } + } + +*/ + module_bounds.SetRect(0,0,800,20); + LogText("Into editor_loop"); + InterfaceDefaults = new Interface; + if(InterfaceDefaults) + { + InterfaceDefaults->SetupInterfaceDefaults(); + + create_editor_modules(); + + module_set.InitControlSet(module_def); + + update_modules(); + + editor(); + + destroy_editor_modules(); + + delete InterfaceDefaults; + } + ClearWorkScreen(0); + ShowWorkScreen(0); + } + else + LogText(" SET DISPLAY 800,600 ERROR \n"); + + MFX_free_wave_list(); + + free_game_textures(FREE_ALL_TEXTURES); + the_display.MenuOn(); +void free_edit_memory(void); + free_edit_memory(); + + SetDisplay(640,480,16); + + + return 0; +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/Engine.cpp b/fallen/Editor/Source/Engine.cpp new file mode 100644 index 0000000..54a5f6c --- /dev/null +++ b/fallen/Editor/Source/Engine.cpp @@ -0,0 +1,1872 @@ +#include "editor.hpp" +#include "edit.h" +#include "engine.h" +#include "prim.h" +#include "c:\fallen\headers\game.h" +#include "c:\fallen\headers\memory.h" +//#include "trig.h" + + +/* +****************************** +z is large in the distance, and small near the eye + +z>>1 for bucket size + + +****************************** +*/ + + +//#define my_trig_noz my_trig +//#define my_quad_noz my_quad + + +//struct Bucket buckets[MAX_BUCKET_POOL]; +UBYTE bucket_pool[MAX_BUCKET_POOL]; +UWORD select_colour = 0xffff; +struct BucketHead bucket_heads[MAX_BUCKETS]; +UBYTE *current_bucket_pool=bucket_pool; +UBYTE *end_bucket_pool=&bucket_pool[MAX_BUCKET_POOL-100]; + +ULONG (*rotate_point_gte)(struct SVector *v,struct SVector *r); + + +struct EngineStuff engine; + +SLONG poly_count=0; +SLONG vect_count=0; +SLONG small_z=0,big_z=0; + +SLONG view_mode=0; + + +struct ExplodeFaces +{ + struct PrimPoint P[3]; + struct PrimFace3 Face3; + SLONG X,Y,Z; + SLONG VX,VY,VZ; + SLONG Timer; + SWORD AX,AY; +}; + +#define MAX_EX_FACE 20 +struct ExplodeFaces ex_faces[MAX_EX_FACE]; +SLONG next_ex_face=1; +SLONG debug_info=0; +void draw_explode_faces(void); + +#define DEBUG_INFO (1<<0) +#define DEBUG_FPS (1<<1) +#define DEBUG_VECTS (1<<2) + +inline void rotate_point_old(struct EnginePoint* eptr) +{ + SLONG x,y,z; + + eptr->X3d-=engine.X>>8; + eptr->Y3d-=engine.Y>>8; + eptr->Z3d-=engine.Z>>8; + + x = (eptr->X3d*engine.CosY-eptr->Z3d*engine.SinY)>>16; // rotate about y + z = (eptr->X3d*engine.SinY+eptr->Z3d*engine.CosY)>>16; + + y = (eptr->Y3d*engine.CosX-z*engine.SinX)>>16; // rotate about x + eptr->Z3d=((eptr->Y3d*engine.SinX)+z*engine.CosX)>>16; + + eptr->X3d= x*engine.Scale; + eptr->Y3d= y*engine.Scale; + + eptr->X = engine.VW2+((eptr->X3d)>>11); //((eptr->X3d*lens)/eptr->Z3d); + + if(eptr->X<0) + { + eptr->Flags |=EF_OFF_LEFT; + if(eptr->X<-2000) + eptr->X=-2000; + + } + else if(eptr->X>= WorkWindowWidth) + { + if(eptr->X>2000) + eptr->X=2000; + eptr->Flags |=EF_OFF_RIGHT; + } + + eptr->Y = engine.VH2-((eptr->Y3d)>>11); //((eptr->Y3d*lens)/eptr->Z3d); + + if(eptr->Y<0) + { + eptr->Flags |=EF_OFF_TOP; + if(eptr->Y<-2000) + eptr->Y=-2000; + } + else if(eptr->Y>= WorkWindowHeight) + { + eptr->Flags |=EF_OFF_BOTTOM; + if(eptr->Y>2000) + eptr->Y=2000; + } + + eptr->Flags |= EF_TRANSLATED; +} + +#define EYE_DIST 0 + +ULONG rotate_point_gte_perspective(struct SVector *v,struct SVector *r) +{ + SLONG x,y,z,vx,vy,vz; + ULONG flags=0; +/* + if(engine.ClipFlag&ENGINE_CLIPY_FLAG) + if( v->Y > engine.ClipMaxY||v->Y < engine.ClipMinY) + { + flags |=EF_BEHIND_YOU; + return(flags); + } +*/ + vx=v->X-(engine.X>>8); + vy=v->Y-(engine.Y>>8); + vz=v->Z-(engine.Z>>8); +// LogText(" into rotate %d %d %d\n",vx,vy,vz); + +/* + if(abs(vx)>4000||abs(vy)>4000) + { + flags |=EF_BEHIND_YOU; + return(flags); + } +*/ + + + x = ((vx*engine.CosY-vz*engine.SinY)); // rotate about y + z = (vx*engine.SinY+vz*engine.CosY)>>16; + + y = ((vy*engine.CosX-z*engine.SinX)); // rotate about x + r->Z=((vy*engine.SinX)+z*engine.CosX)>>16; +/* + if(engine.ClipFlag&ENGINE_CLIPZ_FLAG) + if( r->Z > engine.ClipZ) + { + flags |=EF_BEHIND_YOU; + return(flags); + } +*/ + if(r->Z<=-(EYE_DIST)) + { + flags |=EF_BEHIND_YOU; + return(flags); + } + else + { + SLONG xdiv,ydiv; + xdiv=( x/(r->Z+EYE_DIST) ); + ydiv=( y/(r->Z+EYE_DIST) ); + + if(abs(xdiv)>(0x7fffffff/2000)||abs(ydiv)>(0x7fffffff/2000)) + { +// LogText("xdiv/ydiv too big %d,%d \n",xdiv,ydiv); + flags |=EF_TOO_BIG|EF_BEHIND_YOU; + return(EF_BEHIND_YOU); + } + + r->X= engine.VW2+(( xdiv*engine.Scale)>>16); + r->Y= engine.VH2+(( ydiv*engine.Scale)>>16); + } + +// LogText(" OUT rotate %d %d (%d)\n",r->X,r->Y,r->Z); + + if(r->X<0) + { + flags |=EF_OFF_LEFT; +// if(r->X<-2000) +// r->X=-2000; + + } + else if(r->X>= WorkWindowWidth) + { +// if(r->X>2000) +// r->X=2000; + flags |=EF_OFF_RIGHT; + } + + + if(r->Y<0) + { + flags |=EF_OFF_TOP; +// if(r->Y<-2000) +// r->Y=-2000; + } + else if(r->Y>= WorkWindowHeight) + { + flags |=EF_OFF_BOTTOM; +// if(r->Y>2000) +// r->Y=2000; + } + flags |= EF_TRANSLATED; +// LogText(" out %d %d %d flag %x \n",r->X,r->Y,r->Z,flags); + return(flags); +} + +ULONG rotate_point_gte_normal(struct SVector *v,struct SVector *r) +{ + SLONG x,y,z,vx,vy,vz; + ULONG flags=0; +/* + if(engine.ClipFlag&ENGINE_CLIPY_FLAG) + { + SLONG dy; + dy=(engine.TrueY-engine.Y)>>8; + + if( v->Y+dy > engine.ClipMaxY||v->Y+dy < engine.ClipMinY) + { + flags |=EF_BEHIND_YOU; + flags |=EF_OFF_LEFT; + return(flags); + } + } +*/ + + if(engine.AngleDY) + { + vx=v->X; + vz=v->Z; + + x = ((vx*engine.CosDY-vz*engine.SinDY)>>16); // rotate about LOCAL y + z = (vx*engine.SinDY+vz*engine.CosDY)>>16; + + vx=x-(engine.X>>8); + vz=z-(engine.Z>>8); + + } + else + { + vx=v->X-(engine.X>>8); + vz=v->Z-(engine.Z>>8); + } + vy=v->Y-(engine.Y>>8); + +#ifndef NO_TRANSFORM + + x = ((vx*engine.CosY-vz*engine.SinY)); // rotate about y + z = (vx*engine.SinY+vz*engine.CosY)>>16; + + y = ((vy*engine.CosX-z*engine.SinX)); // rotate about x + r->Z=((vy*engine.SinX)+z*engine.CosX)>>16; + + { + x>>=11; + y>>=11; + + r->X= engine.VW2+(( x*engine.Scale)>>16); + r->Y= engine.VH2+(( y*engine.Scale)>>16); + } +#else + + r->Z=((vy*engine.SinX)+vz*engine.CosX)>>16; + r->X= engine.VW2+(( (vx<<5)*engine.Scale)>>16); + r->Y= engine.VH2+(( (vy<<5)*engine.Scale)>>16); +#endif + if(r->X<0) + { + flags |=EF_OFF_LEFT; + if(r->X<-2400) + r->X=-2400; + + } + else if(r->X>= WorkWindowWidth) + { + if(r->X>2400) + r->X=2400; + flags |=EF_OFF_RIGHT; + } + + + if(r->Y<0) + { + flags |=EF_OFF_TOP; + if(r->Y<-2400) + r->Y=-2400; + } + else if(r->Y>= WorkWindowHeight) + { + flags |=EF_OFF_BOTTOM; + if(r->Y>2400) + r->Y=2400; + } + flags |= EF_TRANSLATED; + return(flags); +} + + +void init_engine(void) +{ + init_camera(); + rotate_point_gte=rotate_point_gte_perspective; + rotate_point_gte=rotate_point_gte_normal; + engine.ShowDebug=1; + engine.BucketSize=MAX_BUCKETS; + engine.ClipZ=5000; +} + +void add_bucket(void *p_bucket,SLONG z) +{ + struct BucketQuad *the_quad; + struct BucketTri *the_tri; + + if(p_bucket=end_bucket_pool) + { +// LogText(" p_bucket oor HIGH"); + return; + } + if(zbig_z) + big_z=z; + + +/* + if(z<500) + { +// LogText(" add DIRECT z %d == %d\n",z,z+500); + z+=500; + if(z<0) + z=0; + if(z>=engine.BucketSize) //only need this for the small bucket mode in editor + z=engine.BucketSize-1; + ((struct BucketGeneric*)p_bucket)->BucketPtr=bucket_heads[z].BucketPtr; + bucket_heads[z].BucketPtr=p_bucket; + return; + } +*/ + + +// LogText(" add bucked z %d ",z); + z>>=1; + +// z+=875; //(engine.BucketSize>>1); + z+=(engine.BucketSize>>1); + if(z>=engine.BucketSize) + z=engine.BucketSize-1; + if(z<0) + z=0; +// LogText(" == %d \n",z); + ((struct BucketGeneric*)p_bucket)->BucketPtr=bucket_heads[z].BucketPtr; + bucket_heads[z].BucketPtr=p_bucket; +} + + +/* Example bucket use +void draw_block(UWORD prev_block,UWORD c_block) +{ + struct EnginePoint *p_start,*p1; + struct SVector res[8]; + SLONG flags[8],flag; + SLONG c0; + struct Block *p_b; + struct Bucket *p_bucket; + + p_b=&blocks[prev_block]; + p_bucket=&buckets[next_bucket_pool]; + + for(c0=0;c0<4;c0++) + { + flags[c0]=rotate_point_gte(&p_b->V[c0],&res[c0]); + } + + p_b=&blocks[c_block]; + for(c0=0;c0<4;c0++) + { + flags[c0+4]=rotate_point_gte(&p_b->V[c0],&res[c0+4]); + } + + //we now have all 8 points transformed to screen co-ords + //and we have the flag stored so we can do some clipping + +//lid + flag=flags[0]&flags[1]&flags[5]&flags[4]; + if(!(flag & EF_CLIPFLAGS)) + { + p_bucket->Type=BT_QUAD; + p_bucket->DrawType=VM_GT; + setXY4(p_bucket,res[0].X,res[0].Y,res[1].X,res[1].Y,res[5].X,res[5].Y,res[4].X,res[4].Y); + setUV4(p_bucket,0,0,64,0,64,64,0,64); + setShade4(p_bucket,255,255,255,255); + add_face4(p_bucket++,res[0].Z); + } +} +*/ + +void draw_quad(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4) +{ +// vec_mode=VM_GT; + + + my_trig(p1,p2,p3); + my_trig(p3,p4,p1); +} + + +void draw_quad_anti(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4) +{ +// poly_count+=2; + + { +// my_trig(p3,p2,p1); +// my_trig(p1,p4,p3); + + + + my_trig(p1,p2,p3); + my_trig(p4,p3,p2); + } + +} + + +//change poly draw to understand buckets directly +void draw_quad_bucket(struct BucketQuad *p_b,SLONG z) +{ + struct EnginePoint p1,p2,p3,p4; + + if(p_b->DrawFlags&POLY_FLAG_TEXTURED) + { +// if(p_b->TextPage>5) +// LogText(" strange textpage %d \n",p_b->TextPage); + if(p_b->TextPage>25+8) + p_b->TextPage=0; + poly_info.PTexture=tmaps[p_b->TextPage]; //OOR + poly_info.Page=p_b->TextPage; + } + if(edit_info.FlatShade) + { + p_b->DrawFlags&=~POLY_FLAG_GOURAD; + } + + poly_info.DrawFlags=p_b->DrawFlags; + poly_info.Col=p_b->Col; +// LogText(" draw quad %d \n",poly_count); + poly_count+=2; + if(Keys[KB_TAB]) + goto wire; + //if(!ShiftFlag) +/* +// +// these are old poly draw types, no longer supported +// + { + if(view_mode&2) + { + if(p_b->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + if(Keys[KB_P]) + { + my_trigp(&p_b->P[2],&p_b->P[1],&p_b->P[0]); + my_trigp(&p_b->P[1],&p_b->P[2],&p_b->P[3]); + } + else + { + my_trig(&p_b->P[2],&p_b->P[1],&p_b->P[0]); + my_trig(&p_b->P[1],&p_b->P[2],&p_b->P[3]); + } + + } + if(Keys[KB_P]) + { + my_trigp(&p_b->P[0],&p_b->P[1],&p_b->P[2]); + my_trigp(&p_b->P[3],&p_b->P[2],&p_b->P[1]); + } + else + { + my_trig(&p_b->P[0],&p_b->P[1],&p_b->P[2]); + my_trig(&p_b->P[3],&p_b->P[2],&p_b->P[1]); + } + } + else + { + if(p_b->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + if(view_mode&1) + my_quad(&p_b->P[2],&p_b->P[3],&p_b->P[1],&p_b->P[0]); + else + my_quad_noz(&p_b->P[2],&p_b->P[3],&p_b->P[1],&p_b->P[0]); + + } + if(view_mode&1) + my_quad(&p_b->P[0],&p_b->P[1],&p_b->P[3],&p_b->P[2]); + else + my_quad_noz(&p_b->P[0],&p_b->P[1],&p_b->P[3],&p_b->P[2]); + } + } + */ + + if(p_b->DebugFlags&FACE_FLAG_NON_PLANAR) + + { + // 0 1 + // + // 2 3 + + if(p_b->DebugFlags&FACE_FLAG_OTHER_SPLIT) + { + my_trig_noz(&p_b->P[0],&p_b->P[1],&p_b->P[3]); + my_trig_noz(&p_b->P[3],&p_b->P[2],&p_b->P[0]); + } + else + { + my_trig_noz(&p_b->P[0],&p_b->P[1],&p_b->P[2]); + my_trig_noz(&p_b->P[1],&p_b->P[3],&p_b->P[2]); + } + } + else + { + if(p_b->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + my_quad_noz(&p_b->P[2],&p_b->P[3],&p_b->P[1],&p_b->P[0]); + } + { + my_quad_noz(&p_b->P[0],&p_b->P[1],&p_b->P[3],&p_b->P[2]); + } + } + + + + if(p_b->DebugFlags&FACE_FLAG_OUTLINE) + { +wire:; + DrawLineC(p_b->P[0].X,p_b->P[0].Y,p_b->P[1].X,p_b->P[1].Y,255); + DrawLineC(p_b->P[1].X,p_b->P[1].Y,p_b->P[3].X,p_b->P[3].Y,255); + DrawLineC(p_b->P[3].X,p_b->P[3].Y,p_b->P[2].X,p_b->P[2].Y,255); + DrawLineC(p_b->P[2].X,p_b->P[2].Y,p_b->P[0].X,p_b->P[0].Y,255); + return; + } + +/* + if(p_b->DebugInfo) + { + + CBYTE str1[10]; + CBYTE str2[10]; + CBYTE str3[10]; + SLONG x,y; + sprintf(str1,"f%d",p_b->DebugInfo); + sprintf(str2,"W%d",prim_faces4[p_b->DebugInfo].ThingIndex); + sprintf(str3,"S%d",wall_list[-prim_faces4[p_b->DebugInfo].ThingIndex].StoreyHead); + x=(p_b->P[0].X+p_b->P[1].X+p_b->P[2].X+p_b->P[3].X)>>2; + y=(p_b->P[0].Y+p_b->P[1].Y+p_b->P[2].Y+p_b->P[3].Y)>>2; + + if(prim_faces4[p_b->DebugInfo].ThingIndex<0) + if(y>0&&yDebugInfo==28334) +// if(ShiftFlag) + { + CBYTE str[100]; + SLONG x,y; + sprintf(str,"%d",p_b->DebugInfo); + x=(p_b->P[0].X+p_b->P[1].X+p_b->P[2].X+p_b->P[3].X)>>2; + y=(p_b->P[0].Y+p_b->P[1].Y+p_b->P[2].Y+p_b->P[3].Y)>>2; + if(y>0&&y0&&x<320) + { + QuickTextC(x,y,str,0); + QuickTextC(x+1,y+1,str,255); + } + } +#endif +} + +void draw_tri_bucket(struct BucketTri *p_b) +{ + struct EnginePoint p1,p2,p3; + if(p_b->DrawFlags&POLY_FLAG_TEXTURED) + { +// if(p_b->TextPage>5) +// LogText(" strange textpage %d \n",p_b->TextPage); + if(p_b->TextPage>25+8) + p_b->TextPage=0; + + poly_info.PTexture=tmaps[p_b->TextPage]; //OOR + poly_info.Page=p_b->TextPage; + } + if(edit_info.FlatShade) + { + p_b->DrawFlags&=~POLY_FLAG_GOURAD; + } + poly_info.DrawFlags=p_b->DrawFlags; + poly_info.Col=p_b->Col; + + poly_count++; + + if(Keys[KB_TAB]) + { + goto wire; + } +// LogText(" draw tri %d \n",poly_count); +/* + p1.X=p_b->SX[0]; + p2.X=p_b->SX[1]; + p3.X=p_b->SX[2]; + + p1.Y=p_b->SY[0]; + p2.Y=p_b->SY[1]; + p3.Y=p_b->SY[2]; + + p1.Shade=p_b->Shade[0]<<14; + p2.Shade=p_b->Shade[1]<<14; + p3.Shade=p_b->Shade[2]<<14; + + p1.TMapX=p_b->TX[0]; + p2.TMapX=p_b->TX[1]; + p3.TMapX=p_b->TX[2]; + + + p1.TMapY=p_b->TY[0]; + p2.TMapY=p_b->TY[1]; + p3.TMapY=p_b->TY[2]; + my_trig(&p1,&p2,&p3); +*/ + + if(!(view_mode&1)) + { + if(p_b->DrawFlags&POLY_FLAG_DOUBLESIDED) + my_trig_noz(&p_b->P[2],&p_b->P[1],&p_b->P[0]); + my_trig_noz(&p_b->P[0],&p_b->P[1],&p_b->P[2]); +/* + DrawLineC(p_b->P[0].X,p_b->P[0].Y,p_b->P[1].X,p_b->P[1].Y,255); + DrawLineC(p_b->P[1].X,p_b->P[1].Y,p_b->P[2].X,p_b->P[2].Y,255); + DrawLineC(p_b->P[2].X,p_b->P[2].Y,p_b->P[0].X,p_b->P[0].Y,255); +*/ + } + if(p_b->DebugFlags&FACE_FLAG_OUTLINE) + { +wire:; + DrawLineC(p_b->P[0].X,p_b->P[0].Y,p_b->P[1].X,p_b->P[1].Y,255); + DrawLineC(p_b->P[1].X,p_b->P[1].Y,p_b->P[2].X,p_b->P[2].Y,255); + DrawLineC(p_b->P[2].X,p_b->P[2].Y,p_b->P[0].X,p_b->P[0].Y,255); + return; + } + /* + if(prim_faces3[p_b->DebugInfo].FaceFlags&FACE_FLAG_OUTLINE) + { +wire:; + DrawLineC(p_b->P[0].X,p_b->P[0].Y,p_b->P[1].X,p_b->P[1].Y,255); + DrawLineC(p_b->P[1].X,p_b->P[1].Y,p_b->P[2].X,p_b->P[2].Y,255); + DrawLineC(p_b->P[2].X,p_b->P[2].Y,p_b->P[0].X,p_b->P[0].Y,255); + return; + } + */ + + if(0) + { + CBYTE str[100]; + SLONG x,y; + if(p_b->DebugInfo>0) + sprintf(str," z=%d",p_b->DebugInfo); + else + sprintf(str," z=N%d",p_b->DebugInfo); + x=(p1.X+p2.X+p2.X+p3.X)/3; + y=(p1.Y+p2.Y+p2.Y+p3.Y)/3; + if(x>0&&x0&&ySX[0],p_b->SY[0],p_b->SX[1],p_b->SY[1],p_b->Shade[0]); + vect_count++; + DrawLineC(p_b->P[0].X,p_b->P[0].Y,p_b->P[1].X,p_b->P[1].Y,p_b->Col); + +} +void draw_rect_bucket(struct BucketRect *p_b) +{ + DrawBoxC(p_b->P[0].X,p_b->P[0].Y,p_b->Width,p_b->Height,p_b->Col); +} + +void hilite_a_floor_face(SWORD face,UBYTE info_flag) +{ + struct SVector point,res[4]; + SLONG dx,dy,dz; + + dx=selected_prim_xyz.X; + dy=selected_prim_xyz.Y; + dz=selected_prim_xyz.Z; + + point.X=dx*ELE_SIZE; + point.Y=0; + point.Z=(dz*ELE_SIZE); //(engine.Z>>8); + rotate_point_gte(&point,&res[0]); + + point.X=(dx+1)*ELE_SIZE; + point.Y=0; + point.Z=(dz*ELE_SIZE); //(engine.Z>>8); + rotate_point_gte(&point,&res[1]); + + point.X=(dx+1)*ELE_SIZE; + point.Y=0; + point.Z=((dz+1)*ELE_SIZE); //(engine.Z>>8); + rotate_point_gte(&point,&res[2]); + + point.X=(dx)*ELE_SIZE; + point.Y=0; + point.Z=((dz+1)*ELE_SIZE); //(engine.Z>>8); + rotate_point_gte(&point,&res[3]); + + DrawLineC(res[0].X,res[0].Y,res[1].X,res[1].Y,select_colour); + DrawLineC(res[1].X,res[1].Y,res[2].X,res[2].Y,select_colour); + DrawLineC(res[2].X,res[2].Y,res[3].X,res[3].Y,select_colour); + DrawLineC(res[3].X,res[3].Y,res[0].X,res[0].Y,select_colour); + +} + +void hilite_a_face(SWORD face,UBYTE info_flag) +{ + UWORD *points; + SLONG flags[4]; + struct SVector res[4]; + SLONG ox,oy,oz,c0; + struct SVector norm; + SLONG flag_and,flag_or; + CBYTE str[100]; + + SLONG wall; + SLONG storey; + SLONG building; + SLONG thing; + + Thing *p_thing; + if(face<0) + { + points = prim_faces3[-face].Points; + + wall = prim_faces3[-face].ThingIndex; + + if (wall < 0) + { + storey = wall_list[-wall].StoreyHead; + building = storey_list[storey].BuildingHead; + thing = building_list[building].ThingIndex; + + p_thing = TO_THING(thing); + + ox = p_thing->WorldPos.X >> 8; + oy = p_thing->WorldPos.Y >> 8; + oz = p_thing->WorldPos.Z >> 8; + + } + else + { + Thing *p_thing; + + p_thing=TO_THING(wall); + ox=p_thing->WorldPos.X>>8; + oy=p_thing->WorldPos.Y>>8; + oz=p_thing->WorldPos.Z>>8; + } + + engine.X -= ox<<8; + engine.Y -= oy<<8; + engine.Z -= oz<<8; + for(c0=0;c0<3;c0++) + { + struct SVector pp; + pp.X=prim_points[*(points+c0)].X; + pp.Y=prim_points[*(points+c0)].Y; + pp.Z=prim_points[*(points+c0)].Z; + + flags[c0] = rotate_point_gte(&pp,&res[c0]); + } + engine.X += ox<<8; + engine.Y += oy<<8; + engine.Z += oz<<8; + + + + flag_and = flags[0]&flags[1]; + flag_or = flags[0]|flags[1]; + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + DrawLineC(res[0].X,res[0].Y,res[1].X,res[1].Y,select_colour); + + flag_and = flags[1]&flags[2]; + flag_or = flags[1]|flags[2]; + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + DrawLineC(res[1].X,res[1].Y,res[2].X,res[2].Y,select_colour); + + flag_and = flags[0]&flags[2]; + flag_or = flags[0]|flags[2]; + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + DrawLineC(res[2].X,res[2].Y,res[0].X,res[0].Y,select_colour); + + if(ShiftFlag) + if(info_flag) + { + sprintf(str,"TRI Face %d",-face); + QuickTextC(30,31,str,0); + QuickTextC(31,30,str,0); + QuickTextC(30,30,str,255); + + } +/* + calc_normal(face,&norm); + sprintf(str,"NORT F %d %d,%d,%d",face,norm.X,norm.Y,norm.Z); + QuickTextC(res[0].X+1,res[0].Y,str,0); + QuickTextC(res[0].X,res[0].Y+1,str,0); + QuickTextC(res[0].X,res[0].Y,str,255); +*/ + + } + else + { + points = prim_faces4[face].Points; + + thing=prim_faces4[face].ThingIndex; + if(thing<0) + { + thing=wall_list[-thing].StoreyHead; + thing=storey_list[thing].BuildingHead; + thing=building_list[thing].ThingIndex; + + Thing *p_thing = TO_THING(thing); + + ox = p_thing->WorldPos.X >> 8; + oy = p_thing->WorldPos.Y >> 8; + oz = p_thing->WorldPos.Z >> 8; + + } + else + { + ox=map_things[prim_faces4[face].ThingIndex].X; + oy=map_things[prim_faces4[face].ThingIndex].Y; + oz=map_things[prim_faces4[face].ThingIndex].Z; + } + + engine.X -= ox<<8; + engine.Y -= oy<<8; + engine.Z -= oz<<8; + for(c0=0;c0<4;c0++) + { + struct SVector pp; + pp.X=prim_points[*(points+c0)].X; + pp.Y=prim_points[*(points+c0)].Y; + pp.Z=prim_points[*(points+c0)].Z; + + flags[c0] = rotate_point_gte(&pp,&res[c0]); + } + engine.X += ox<<8; + engine.Y += oy<<8; + engine.Z += oz<<8; + + + + flag_and = flags[0]&flags[1]; + flag_or = flags[0]|flags[1]; + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + DrawLineC(res[0].X,res[0].Y,res[1].X,res[1].Y,select_colour); + + flag_and = flags[1]&flags[3]; + flag_or = flags[1]|flags[3]; + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + DrawLineC(res[1].X,res[1].Y,res[3].X,res[3].Y,select_colour); + + flag_and = flags[3]&flags[2]; + flag_or = flags[3]|flags[2]; + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + DrawLineC(res[2].X,res[2].Y,res[3].X,res[3].Y,select_colour); + DrawLineC(res[2].X,res[2].Y,res[0].X,res[0].Y,select_colour); + + flag_and = flags[0]&flags[2]; + flag_or = flags[0]|flags[2]; + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + DrawLineC(res[2].X,res[2].Y,res[0].X,res[0].Y,select_colour); + + if(ShiftFlag) + if(info_flag) + { + sprintf(str,"QUAD Face %d",face); + QuickTextC(30,31,str,0); + QuickTextC(31,30,str,0); + QuickTextC(30,30,str,255); + + } + +// calc_normal(face,&norm); +// sprintf(str,"NORQ F %d %d,%d,%d",face,norm.X,norm.Y,norm.Z); +// sprintf(str,"NORQ F %d ",face); +// QuickTextC(res[0].X+1,res[0].Y,str,0); +// QuickTextC(res[0].X,res[0].Y+1,str,0); +// QuickTextC(res[0].X,res[0].Y,str,255); + } +} + +void render_buckets(UBYTE highlight) +{ + SLONG c0; + struct BucketHead *p; + struct BucketQuad *the_quad; + struct BucketTri *the_tri; + void *bucket; + CBYTE str[100]; + + if(view_mode&8) + p=&bucket_heads[0]; + else + p=&bucket_heads[engine.BucketSize-1]; + + for(c0=0;c0BucketPtr; + { + SLONG count=0; + p->BucketPtr=0; + while(bucket) + { + UWORD temp; + count++; + switch(((struct BucketGeneric*)bucket)->BucketType) + { + case BT_QUAD: + draw_quad_bucket((struct BucketQuad*)bucket,engine.BucketSize-c0); + break; + case BT_TRI: + draw_tri_bucket((struct BucketTri*)bucket); + break; + case BT_VECT: + draw_vect_bucket((struct BucketVect*)bucket); + break; + case BT_RECT: + draw_rect_bucket((struct BucketRect*)bucket); + break; + + } + bucket=((struct BucketGeneric*)bucket)->BucketPtr; + } + } + if(view_mode&8) + p++; + else + p--; + } + + + if(highlight) + { +/* + if(next_face_selected>1) + { + SLONG c0; + for(c0=0;c0>8,engine.Y>>8,engine.Z>>8,engine.AngleX,engine.AngleY,engine.AngleZ); + else + sprintf(str,"sc %d pc=%d ex %d ey %d ez %d ax %d ay %d az %d\n",engine.Scale,poly_count,engine.X>>8,engine.Y>>8,engine.Z>>8,engine.AngleX,engine.AngleY,engine.AngleZ); + QuickTextC(10,10,str,0); + QuickTextC(11,11,str,255); + } +// draw_text(0,0,str,32); + } + if(Keys[KB_D]) + { + Keys[KB_D]=0; + debug_info++; + + } +// LogText(" 0 it \n"); + poly_count=0; + vect_count=0; + current_bucket_pool=bucket_pool; +} + + +void render_view(UBYTE highlight) +{ + static SLONG prev_time; + struct MFTime the_time; + draw_explode_faces(); + +// LogText(" render view scale %d enginex %d \n",engine.Scale,engine.X); + switch(WorkScreenDepth) + { + case 1: + render_span=render_span8; + break; + case 2: + render_span=render_span16; + break; + case 4: + render_span=render_span32; + break; + + } +// draw_blocks(1); + + if(Keys[KB_F2]&&ShiftFlag) + { + Keys[KB_F2]=0; + view_mode^=1; + } + if(Keys[KB_F5]&&ShiftFlag) + { + Keys[KB_F5]=0; + view_mode^=8; + } + if(Keys[KB_F3]&&ShiftFlag) + { + Keys[KB_F3]=0; + view_mode^=2; + if((view_mode&3)==3) + view_mode&=0xfffffffe; + + } + if(Keys[KB_F4]&&ShiftFlag) + { + Keys[KB_F4]=0; + view_mode^=4; + if(view_mode&4) + rotate_point_gte=rotate_point_gte_perspective; + else + rotate_point_gte=rotate_point_gte_normal; + } + Time(&the_time); +#ifdef TEST_3DFX +void render_buckets_3dfx(UBYTE highlight); + render_buckets_3dfx(highlight); +#else + render_buckets(highlight); +#endif +// if(view_mode&1) + draw_all_spans(); + + if((engine.ShowDebug)) //||(ShiftFlag)) + { + CBYTE str[100]; + static SLONG times[10],turn=0; + SLONG time; + turn++; + Time(&the_time); + time=the_time.Ticks; + while((time-prev_time)<31) + { + Time(&the_time); + time=the_time.Ticks; + } + times[turn%10]=time-prev_time; + + { + SLONG c0; + time=0; + for(c0=0;c0<10;c0++) + time+=times[c0]; +// time/=10; + } + time=(time<<8)/10; //time for an averaged frame + if(time==0) + time=1; + time=(1000<<8)/time; + if(debug_info&DEBUG_FPS) + { + sprintf(str," FPS %d sz %d bz %d BS %d ax %d ay %d",time,small_z,big_z,engine.BucketSize,engine.AngleX>>8,engine.AngleY>>8); + QuickTextC(0,23,str,255); + small_z=100000; + big_z=-100000; + } +/* + + + prev_time=time; + + if(!(view_mode&2)) + QuickTextC(10,75,"PERSPECTIVE CORRECT",255); + if((view_mode&4)) + QuickTextC(10,90,"PERSPECTIVE VIEW",255); +*/ + } + prev_time=the_time.Ticks; +// LogText(" after render view scale %d enginex %d \n",engine.Scale,engine.X); +} + + +void init_camera(void) +{ + engine.AngleX=1070<<8; + engine.AngleY=0; + engine.AngleZ=0; + engine.Scale=2688; + + engine.X=0; + engine.Y=0; + engine.Z=0; + set_camera(); +} + +void set_camera_to_base(void) +{ + engine.VH2=engine.VH; +} + +void set_camera_to_mid(void) +{ + engine.VH2=engine.VH>>1; +} + +void set_camera(void) +{ + + engine.VW=WorkWindowWidth; + engine.VH=WorkWindowHeight; + + engine.VW2=engine.VW>>1; + engine.VH2=engine.VH>>1; + + + engine.CosY=COS((engine.AngleY>>8)&2047); + engine.SinY=SIN((engine.AngleY>>8)&2047); + + engine.CosX=COS((engine.AngleX>>8)&2047); + engine.SinX=SIN((engine.AngleX>>8)&2047); + + engine.CosZ=COS((engine.AngleZ>>8)&2047); + engine.SinZ=SIN((engine.AngleZ>>8)&2047); +} + +void set_camera_angledy(SWORD angle) +{ + + if(angle) + { + angle=(angle+2048)&2047; +// LogText("set camera angledy %d \n",angle); + + engine.CosDY=COS(2048-angle); + engine.SinDY=SIN(2048-angle); + engine.AngleDY=angle; + } + else + engine.AngleDY=0; +} + +void clear_camera_angledy(void) +{ +// LogText("CLEAR camera angledy \n"); + engine.AngleDY=0; +} + +void set_camera_plan(void) +{ + SLONG angle; + + engine.VW=WorkWindowWidth; + engine.VH=WorkWindowHeight; + + engine.VW2=engine.VW>>1; + engine.VH2=engine.VH>>1; + + + engine.CosY=COS(0); + engine.SinY=SIN(0); + + engine.CosX=COS(512+1024); + engine.SinX=SIN(512+1024); + + engine.CosZ=COS(0); + engine.SinZ=SIN(0); +} + +void set_camera_front(void) +{ + SLONG angle; + + engine.VW=WorkWindowWidth; + engine.VH=WorkWindowHeight; + + engine.VW2=engine.VW>>1; + engine.VH2=engine.VH>>1; + + + engine.CosY=COS(0); + engine.SinY=SIN(0); + + engine.CosX=COS(1024); + engine.SinX=SIN(1024); + + engine.CosZ=COS(0); + engine.SinZ=SIN(0); +} + +void set_camera_side(void) +{ + SLONG angle; + + engine.VW=WorkWindowWidth; + engine.VH=WorkWindowHeight; + + engine.VW2=engine.VW>>1; + engine.VH2=engine.VH>>1; + + + engine.CosY=COS(512+1024); + engine.SinY=SIN(512+1024); + + engine.CosX=COS(1024); + engine.SinX=SIN(1024); + + engine.CosZ=COS(0); + engine.SinZ=SIN(0); +} + +//mousex,0,mousey +/* +void reverse_transform(SLONG x,SLONG y,SLONG z,SLONG *out_x,SLONG *out_y,SLONG *out_z) +{ + if(sint==0) + return; + x = ((x-view_width_over_2)<<11)/overall_scale; + z = ((z-view_height_over_2)<<11)/overall_scale; + + + + z=-((z<<16)/sint); // I dont know how this formulae works, its crazy + + *out_x = (x*cosa-z*sina)>>16; // rotate about y + *out_z = (x*sina+z*cosa)>>16; + + *out_y=-y; + *out_z=-*out_z; +} +*/ + + +void calc_world_pos_plan(SLONG x,SLONG y) +{ + SLONG temp_x,temp_z; + if(engine.Scale) + { + temp_x=(((x-engine.VW2)<<16)/engine.Scale); + temp_z=(((y-engine.VH2)<<16)/engine.Scale); + engine.MousePosX=(engine.X>>8)+(temp_x>>5); + engine.MousePosZ=(engine.Z>>8)+(temp_z>>5); + } + +} + +void calc_world_pos_front(SLONG x,SLONG y) +{ + SLONG temp_x,temp_y; + + if(engine.Scale) + { + temp_x=(((x-engine.VW2)<<16)/engine.Scale); + temp_y=((-(y-engine.VH2)<<16)/engine.Scale); + engine.MousePosX=(engine.X>>8)+(temp_x>>5); + engine.MousePosY=(engine.Y>>8)+(temp_y>>5); + } +} + + +void dump_face_info(SWORD face) +{ + struct MapThing *p_thing; + SLONG x,y,z; + SLONG c0; + SWORD index[]={0,1,3,2,0}; + + if(face>0) + { + struct PrimFace4 *p_face; + p_face=&prim_faces4[face]; + p_thing=TO_MTHING(p_face->ThingIndex); + x=p_thing->X; + y=p_thing->Y; + z=p_thing->Z; + LogText("QUAD face %d x %d y %d z %d df %x\n",face,x,y,z,p_face->DrawFlags); + LogText("UV %d,%d %d,%d %d,%d %d,%d",p_face->UV[0][0],p_face->UV[0][1],p_face->UV[1][0],p_face->UV[1][1],p_face->UV[2][0],p_face->UV[2][1],p_face->UV[3][0],p_face->UV[3][1]); + for(c0=0;c0<4;c0++) + { + LogText(" (%d)=",p_face->Points[index[c0]]); + LogText(" (%d,%d,%d)",prim_points[p_face->Points[index[c0]]].X,prim_points[p_face->Points[index[c0]]].Y,prim_points[p_face->Points[index[c0]]].Z); + } + } + else + { + struct PrimFace3 *p_face; + face=-face; + p_face=&prim_faces3[face]; + p_thing=TO_MTHING(p_face->ThingIndex); + x=p_thing->X; + y=p_thing->Y; + z=p_thing->Z; + LogText("TRI face %d x %d y %d z %d df %x\n",face,x,y,z,p_face->DrawFlags); + LogText("UV %d,%d %d,%d %d,%d ",p_face->UV[0][0],p_face->UV[0][1],p_face->UV[1][0],p_face->UV[1][1],p_face->UV[2][0],p_face->UV[2][1]); + + for(c0=0;c0<3;c0++) + { + LogText(" (%d)=",p_face->Points[c0]); + LogText(" (%d,%d,%d) ",prim_points[p_face->Points[c0]].X,prim_points[p_face->Points[c0]].Y,prim_points[p_face->Points[c0]].Z); + } + + } + + LogText("\n"); + +} + +void calc_txty(SWORD face,SLONG *tx,SLONG *ty,SWORD mid_x,SWORD mid_y,SWORD mid_z) +{ + + if(face>0) + { + *tx=(prim_faces4[face].UV[0][0]+prim_faces4[face].UV[1][0]+prim_faces4[face].UV[2][0]+prim_faces4[face].UV[3][0])>>2; + *ty=(prim_faces4[face].UV[0][1]+prim_faces4[face].UV[1][1]+prim_faces4[face].UV[2][1]+prim_faces4[face].UV[3][1])>>2; + } +} + +void rotate_point_by_xyz(struct SVector *p,SLONG ax,SLONG ay,SLONG az) +{ + SLONG cosy,siny,cosx,sinx,cosz,sinz; + SLONG rx,ry,rz; + + ax=(ax+2048)&2047; + ay=(ay+2048)&2047; + az=(az+2048)&2047; + + cosx=COS(ax); + sinx=SIN(ax); + cosy=COS(ay); + siny=SIN(ay); + cosz=COS(az); + sinz=SIN(az); + + rx=(p->X*cosy-p->Z*siny)>>16; + rz=(p->X*siny+p->Z*cosy)>>16; + + ry=(p->Y*cosx-rz*sinx)>>16; + rz=(p->Y*sinx+rz*cosx)>>16; + p->X=rx; + p->Y=ry; + p->Z=rz; + +} + +void rotate_ex_face(SWORD index) +{ + + rotate_point_by_xyz((SVector*)&ex_faces[index].P[0],ex_faces[index].AX,ex_faces[index].AY,0); + rotate_point_by_xyz((SVector*)&ex_faces[index].P[1],ex_faces[index].AX,ex_faces[index].AY,0); + rotate_point_by_xyz((SVector*)&ex_faces[index].P[2],ex_faces[index].AX,ex_faces[index].AY,0); + +} + +void remove_ex_face(SWORD index) +{ + ex_faces[index].X=0; + if(index==next_ex_face-1) + next_ex_face--; + +} + +SLONG find_an_empty_explode_face(void) +{ + SLONG c0; + for(c0=1;c0=next_ex_face) + next_ex_face=c0+1; + return(c0); + } + } + return(0); +} + + +void split_explode_face(SWORD index) +{ + SWORD aindex[]={0,1,2,0,1,2}; + SLONG dx,dy,dz; + SLONG len,b_len=0,b_index=0; + SLONG mid_x,mid_y,mid_z,mid_shade,mid_tx,mid_ty; + SLONG face1,face2; + SLONG tri1[3],tri2[3]; + SLONG *tri; + SLONG c0,c1; + for(c0=0;c0<3;c0++) + { + + dx=ex_faces[index].P[aindex[c0+1]].X-ex_faces[index].P[aindex[c0]].X; + dy=ex_faces[index].P[aindex[c0+1]].Y-ex_faces[index].P[aindex[c0]].Y; + dz=ex_faces[index].P[aindex[c0+1]].Z-ex_faces[index].P[aindex[c0]].Z; + len=dx*dx+dy*dy+dz*dz; + if(len>b_len) + { + b_len=len; + b_index=c0; + } + } + + mid_x =(ex_faces[index].P[aindex[b_index]].X+ex_faces[index].P[aindex[b_index+1]].X)>>1; + mid_y =(ex_faces[index].P[aindex[b_index]].Y+ex_faces[index].P[aindex[b_index+1]].Y)>>1; + mid_z =(ex_faces[index].P[aindex[b_index]].Z+ex_faces[index].P[aindex[b_index+1]].Z)>>1; + mid_shade=(ex_faces[index].Face3.Bright[aindex[b_index]]+ex_faces[index].Face3.Bright[aindex[b_index+1]])>>1; + mid_tx =(ex_faces[index].Face3.UV[aindex[b_index]][0]+ex_faces[index].Face3.UV[aindex[b_index]][0])>>1; + mid_ty =(ex_faces[index].Face3.UV[aindex[b_index]][1]+ex_faces[index].Face3.UV[aindex[b_index]][1])>>1; + + face1=find_an_empty_explode_face(); + + if(face1) + { + + switch(b_index) + { + case 0: + tri1[0]=0; + tri1[1]=-1; + tri1[2]=2; + + tri2[0]=-1; + tri2[1]=1; + tri2[2]=2; + break; + + case 1: + tri1[0]=-1; + tri1[1]=0; + tri1[2]=1; + + tri2[0]=-1; + tri2[1]=2; + tri2[2]=0; + break; + + case 2: + tri1[0]=-1; + tri1[1]=0; + tri1[2]=1; + + tri2[0]=-1; + tri2[1]=1; + tri2[2]=2; + break; + } + + tri=tri1; + for(c1=0;c1<2;c1++) + { + + if(face1) + { + + ex_faces[face1].Face3.TexturePage=ex_faces[index].Face3.TexturePage; + ex_faces[face1].Face3.DrawFlags=ex_faces[index].Face3.DrawFlags; + ex_faces[face1].AX=ex_faces[index].AX+(rand()&7); + ex_faces[face1].AY=ex_faces[index].AY+(rand()&7); + ex_faces[face1].VX=ex_faces[index].VX+(rand()&127)-64; + ex_faces[face1].VY=ex_faces[index].VY+(rand()&127)-64; + ex_faces[face1].VZ=ex_faces[index].VZ+(rand()&127)-64; + ex_faces[face1].Timer=ex_faces[index].Timer; + ex_faces[face1].X=ex_faces[index].X+(mid_x<<8); + ex_faces[face1].Y=ex_faces[index].Y+(mid_y<<8); + ex_faces[face1].Z=ex_faces[index].Z+(mid_z<<8); + for(c0=0;c0<3;c0++) + { + if(tri[c0]>=0) + { + // ex_faces[face1].P[c0]=ex_faces[index].P[tri[c0]]; + + ex_faces[face1].P[c0].X=ex_faces[index].P[tri[c0]].X-mid_x; + ex_faces[face1].P[c0].Y=ex_faces[index].P[tri[c0]].Y-mid_y; + ex_faces[face1].P[c0].Z=ex_faces[index].P[tri[c0]].Z-mid_z; + + ex_faces[face1].Face3.UV[c0][0]=ex_faces[index].Face3.UV[tri[c0]][0]; + ex_faces[face1].Face3.UV[c0][1]=ex_faces[index].Face3.UV[tri[c0]][1]; + ex_faces[face1].Face3.Bright[c0]=ex_faces[index].Face3.Bright[tri[c0]]; + } + else + { + ex_faces[face1].P[c0].X=0;//mid_x; //0;// + ex_faces[face1].P[c0].Y=0;//mid_y; //0;// + ex_faces[face1].P[c0].Z=0;//mid_z; //0;// + + ex_faces[face1].Face3.UV[c0][0] =mid_tx; + ex_faces[face1].Face3.UV[c0][1] =mid_ty; + ex_faces[face1].Face3.Bright[c0]=mid_shade; + } + } + tri=tri2; + face1=find_an_empty_explode_face(); + } + } + remove_ex_face(index); + } + +} + + + +void move_explode_faces(void) +{ + SLONG c0; + for(c0=1;c0>8; + ex_faces[c0].VY=((ex_faces[c0].VY*250)>>8)+30; + ex_faces[c0].VZ=(ex_faces[c0].VZ*250)>>8; +*/ + + ex_faces[c0].VY+=70; + rotate_ex_face(c0); + if((rand()&7)==0) + split_explode_face(c0); + + if(ex_faces[c0].Timer--<0) + { + remove_ex_face(c0); + } + + } + } +} + + +void draw_explode_faces(void) +{ + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + ULONG flag_and,flag_or; + SLONG c0; + SLONG az; + SLONG flags[3]; + + SVector res[3]; + + move_explode_faces(); + + for(c0=1;c0DebugInfo=c0; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool += sizeof(struct BucketQuad); + } + } + } +} + + + +void add_explode_face(struct PrimPoint *p0,struct PrimPoint *p1,struct PrimPoint *p2,struct PrimFace3 *p_face,SLONG x,SLONG y,SLONG z,SLONG vx,SLONG vy,SLONG vz) +{ + SLONG index; + SLONG ax,ay,az; + index=find_an_empty_explode_face(); +// y=y+50; + if(index) + { +/* + if(rand()&1) + { + ax=(p0->X+p1->X+p2->X)/3; + ay=(p0->Y+p1->Y+p2->Y)/3; + az=(p0->Z+p1->Z+p2->Z)/3; + } + else +*/ + { + ax=(p0->X); + ay=(p0->Y); + az=(p0->Z); + } + + p0->X-=ax; + p1->X-=ax; + p2->X-=ax; + + p0->Y-=ay; + p1->Y-=ay; + p2->Y-=ay; + + p0->Z-=az; + p1->Z-=az; + p2->Z-=az; + + x+=ax; + y+=ay; + z+=az; + + ex_faces[index].P[0]=*p0; + ex_faces[index].P[1]=*p1; + ex_faces[index].P[2]=*p2; + + ex_faces[index].Face3=(const struct PrimFace3)*p_face; +// memcpy(&ex_faces[index].Face3,p_face,sizeof(struct PrimFace3)); + + ex_faces[index].X=x<<8; + ex_faces[index].Y=y<<8; + ex_faces[index].Z=z<<8; + ex_faces[index].VX=((p0->X-p1->X)<<3)+((rand()&255)-128); + ex_faces[index].VY=(+1000+(rand()&511)); + ex_faces[index].VZ=((p0->Z-p1->Z)<<3)+((rand()&255)-128); + ex_faces[index].Face3.DrawFlags|=POLY_FLAG_DOUBLESIDED; + ex_faces[index].AX=((rand()&63));//<<1; + ex_faces[index].AY=((rand()&63));//<<1; + ex_faces[index].Timer=30+(rand()&7); + } +} + + +UWORD make_poly_into_glass_shatter_prim(SWORD face,SWORD mid_x,SWORD mid_y,SWORD mid_z) +{ + UWORD next_game_point=next_prim_point; + UWORD next_game_face3=next_prim_face3; + UWORD next_game_object=next_prim_object; + SLONG count,cp=0,snp=0,c0,side; + SLONG x1,y1,z1,x2,y2,z2,tx1,ty1,tx2,ty2; + SWORD index[]={0,1,3,2,0}; + SWORD text_x[1000]; + SWORD text_y[1000]; + struct PrimPoint points[1000]; + struct MapThing *p_thing; + UWORD tindex = 0; + SWORD tf; + + struct PrimPoint pp0,pp1,pp2; + struct PrimFace3 face3; + + LogText("shatter face \n"); + dump_face_info(face); + + if(face>0) + { + SLONG dx,dy,tx,ty; +// if(prim_faces4[face].DrawFlags==POLY_NULL) +// return(0); + +// prim_points[next_game_point+cp].X=mid_x; +// prim_points[next_game_point+cp].Y=mid_y; +// prim_points[next_game_point+cp++].Z=mid_z; + + points[cp].X=mid_x; + points[cp].Y=mid_y; + points[cp++].Z=mid_z; + + calc_txty(face,&tx,&ty,mid_x,mid_y,mid_z); + + text_x[0]=tx; + text_y[0]=ty; + + for(side=0;side<4;side++) + { + + x1=prim_points[prim_faces4[face].Points[index[side]]].X; + y1=prim_points[prim_faces4[face].Points[index[side]]].Y; + z1=prim_points[prim_faces4[face].Points[index[side]]].Z; + + x2=prim_points[prim_faces4[face].Points[index[side+1]]].X; + y2=prim_points[prim_faces4[face].Points[index[side+1]]].Y; + z2=prim_points[prim_faces4[face].Points[index[side+1]]].Z; + + tx1=prim_faces4[face].UV[index[side]][0]; + ty1=prim_faces4[face].UV[index[side]][1]; + + tx2=prim_faces4[face].UV[index[side+1]][0]; + ty2=prim_faces4[face].UV[index[side+1]][1]; + + count=(rand()%5)+2; + + for(c0=0;c0<=count;c0++) + { + text_x[cp]=tx1+(((tx2-tx1)*c0)/count); + text_y[cp]=ty1+(((ty2-ty1)*c0)/count); + +/* + prim_points[next_game_point+cp].X=x1+(((x2-x1)*c0)/count); + prim_points[next_game_point+cp].Y=y1+(((y2-y1)*c0)/count); +6 prim_points[next_game_point+cp++].Z=z1+(((z2-z1)*c0)/count); +*/ + + points[cp].X=x1+(((x2-x1)*c0)/count); + points[cp].Y=y1+(((y2-y1)*c0)/count); + points[cp++].Z=z1+(((z2-z1)*c0)/count); + + + } + } + LogText(" GENERATE POINTS %d to %d(inc) \n",next_game_point,cp-1); + + p_thing=&map_things[prim_faces4[face].ThingIndex]; + + + for(tf=1;tfX,p_thing->Y,p_thing->Z,0,0,0); + +// LogText("FRAG %d \n",tf); +// dump_face_info(-(next_game_face3+tf-1)); + + } + + prim_faces4[face].DrawFlags=POLY_NULL; + } + return(tindex); +} + + diff --git a/fallen/Editor/Source/FileReq.cpp b/fallen/Editor/Source/FileReq.cpp new file mode 100644 index 0000000..2e6f1d5 --- /dev/null +++ b/fallen/Editor/Source/FileReq.cpp @@ -0,0 +1,394 @@ +// Guy Simmons +// 20th February 1997. + +#include "Editor.hpp" +// #include "filereq.hpp" + +//--------------------------------------------------------------- + +UBYTE InkeyToAscii[]= +{ + /* 0 - 9 */ 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', + /* 10 - 19 */ '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', + /* 20 - 29 */ 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0, 0, + /* 30 - 39 */ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + /* 40 - 49 */ '\'', '`', 0, '#', 'z', 'x', 'c', 'v', 'b', 'n', + /* 50 - 59 */ 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, + /* 60 - 69 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 70 - 79 */ 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, + /* 80 - 89 */ 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, + /* 90 - 99 */ 0, 0, 0, 0, 0, 0, '/', 0, 0, '(', + /* 100 - 109 */ ')', '/', '*', 0, 0, 0, 0, 0, 0, 0, + /* 110 - 119 */ 0, 0, 0, '.', 0, 0, 0, 0, 0, 0, + /* 120 - 127 */ 0, 0, 0, 0, 0, 0, 0, 0 +}; + +UBYTE InkeyToAsciiShift[]= +{ + /* 0 - 9 */ 0, 0, '!', '"', 'œ', '$', '%', '^', '&', '*', + /* 10 - 19 */ '(', ')', '_', '+', '\b', '\t', 'Q', 'W', 'E', 'R', + /* 20 - 29 */ 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0, 0, + /* 30 - 39 */ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + /* 40 - 49 */ '@', '~', 0, '~', 'Z', 'X', 'C', 'V', 'B', 'N', + /* 50 - 59 */ 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, + /* 60 - 69 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 70 - 79 */ 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, + /* 80 - 89 */ 0, 0, 0, 0, 0, 0, '|', 0, 0, 0, + /* 90 - 99 */ 0, 0, 0, 0, 0, 0, '/', 0, 0, '(', + /* 100 - 109 */ ')', '/', '*', 0, 0, 0, 0, 0, 0, 0, + /* 110 - 119 */ 0, 0, 0, '.', 0, 0, 0, 0, 0, 0, + /* 120 - 127 */ 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +ControlDef controls[] = +{ + { V_SLIDER, 0, "", 270, 40, 0, 255 }, + { 0 } + +}; + +CBYTE a_cunning_plan=0; + +FileRequester::FileRequester(CBYTE *path,CBYTE *extension,CBYTE *title,CBYTE *fname) +{ + SLONG c0; + SLONG x=100,y=100; + EdRect ctrl_rect; + + Path=path; + WildCard=extension; + Title=title; + strcpy(FileName,fname); +/* + SetRect(0,0,300,400); + + OK.SetRect(20,370,40,15); + Cancel.SetRect(220,370,40,15); + TextEdit.SetRect(20,350,150,13); + Controls.InitControlSet(controls); + + ctrl_rect.SetRect(10,101,300,400); + Controls.ControlSetBounds(&ctrl_rect); + + for(c0=0;c0<25;c0++) + { + TextList[c0].SetRect(50,40+c0*12,200,12); + } +*/ +} + +UBYTE edit_and_draw_text(EdRect *rect,CBYTE *str) +{ + CBYTE str2[100]; + static count=0; + count++; + + strcpy(str2,str); + if(count&4) + { + str2[strlen(str2)+1]=0; + str2[strlen(str2)]='-'; + } + + rect->FillRect(CONTENT_COL); + rect->HiliteRect(LOLITE_COL,LOLITE_COL); + QuickTextC(rect->GetLeft()+2,rect->GetTop()+3,str2,0); + + if(LastKey==KB_BS||LastKey==KB_DEL) + { + LastKey=0; + if(strlen(str)) + str[strlen(str)-1]=0; + } + if(LastKey==KB_ENTER) + { + LastKey=0; + return(0); + + } + if(strlen(str)<99) + if(InkeyToAscii[LastKey]) + { + str[strlen(str)+1]=0; + str[strlen(str)]=InkeyToAscii[LastKey]; + LastKey=0; + } + + return(1); +} + +UBYTE do_button(EdRect *rect,CBYTE *str,MFPoint *local_point,UBYTE centered) +{ + SLONG w; + SLONG ret=0; + w=QTStringWidth(str); + + rect->FillRect(CONTENT_COL); + if(rect->PointInRect(local_point)) + { + rect->HiliteRect(LOLITE_COL,HILITE_COL); + if(LeftMouse.ButtonState) + { + LeftMouse.ButtonState=0; + ret=1; + } + } + else + rect->HiliteRect(HILITE_COL,LOLITE_COL); + if(centered) + QuickTextC(rect->GetLeft()+(rect->GetWidth()-w)/2,rect->GetTop()+3,str,0); + else + QuickTextC(rect->GetLeft()+2,rect->GetTop()+3,str,0); + + return(ret); +} + + +SLONG FileRequester::Draw() +{ + CBYTE curr_directory[_MAX_PATH]; + CBYTE filter[100]; + OPENFILENAME ofn; + SLONG save=0,ret=0,c0; + + GetCurrentDirectory(_MAX_PATH, curr_directory); + + if(Title[1]=='a' && Title[2]=='v' && Title[3]=='e') + save=1; + + + sprintf(filter,"Editorfiles %s",WildCard); + filter[strlen(filter)+2]=0; + filter[11]=0; + + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hDDLibWindow; + ofn.hInstance = NULL; + ofn.lpstrFilter = filter; //"Editor File\0*.ucm\0\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 0; + ofn.lpstrFile = FileName; + ofn.nMaxFile = 100; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = Path; + ofn.lpstrTitle = Title; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = &WildCard[2]; + ofn.lCustData = NULL; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + + + if(save) + ret=GetSaveFileName(&ofn); + else + ret=GetOpenFileName(&ofn); + + if (!ret) + { + SetCurrentDirectory(curr_directory); + return FALSE; + } + else + { + SetCurrentDirectory(curr_directory); + } + + for(c0=strlen(FileName);c0>0;c0--) + { + if(FileName[c0]=='\\') + { + SLONG c1=0; + + while(FileName[c0+c1]) + FileName[c1++]=FileName[c0+c1+1]; + break; + } + } + + return(TRUE); + + +#ifdef _MF_WINDOWS_DOG_POO + SLONG c0; +// struct TbFileFind file; + WIN32_FIND_DATA FileData; + HANDLE Handle; + MFPoint local_point; + SLONG exit=0; + UBYTE edit_text_flag=0; + SLONG skip=0; + CBYTE search_path[100]; + SLONG temp_button_state; + +//just draw this once + SetWorkWindowBounds(100+1,100+1,GetWidth(),GetHeight()); + if(LockWorkScreen()) + { + + FillRect(CONTENT_COL); + HiliteRect(HILITE_COL,LOLITE_COL); + QuickText(100,10,Title,0); + +// DrawWindow(); +// Controls.DrawControlSet(); + + UnlockWorkScreen(); + } + + while(SHELL_ACTIVE && !exit) + { + if(Keys[KB_DOWN]) + { + Keys[KB_DOWN]=0; + skip++; + } + if(Keys[KB_UP]) + { + Keys[KB_UP]=0; + skip--; + if(skip<0) + skip=0; + } + + + + if(LockWorkScreen()) + { + + local_point.X =MousePoint.X; + local_point.Y =MousePoint.Y; + + GlobalToLocal(&local_point); + temp_button_state=LeftMouse.ButtonState; +// Do OK & Cancel Buttons + + if(do_button(&OK,"OK",&local_point,1)) + exit=1; + if(do_button(&Cancel,"Cancel",&local_point,1)) + exit=-1; + +// Do Editor Box + if(edit_text_flag) + { + edit_text_flag=edit_and_draw_text(&TextEdit,FileName); + } + else + edit_text_flag=do_button(&TextEdit,FileName,&local_point,0); + + + QuickTextC(50,25,Path,0); + + strcpy(search_path,Path); + strcat(search_path,WildCard); +/* + { + SLONG fcount; + + fcount=1; + Handle = FindFirstFile(search_path, &FileData); + if(Handle != INVALID_HANDLE_VALUE) + { + while(FindNextFile(Handle, &FileData)) + fcount++; + } + + + } +*/ + + Handle = FindFirstFile(search_path, &FileData); + +// skip down the files + if(Handle != INVALID_HANDLE_VALUE) + if(skip) + { + c0=skip; + while(c0) + { + if(Handle != INVALID_HANDLE_VALUE) + FindNextFile(Handle, &FileData); + c0--; + } + } + +// draw file names and check for mouse click + if(Handle != INVALID_HANDLE_VALUE) + for(c0=0;c0<25;c0++) + { + SLONG box_col,text_col=0; + SLONG inrect=0; + + box_col=WHITE_COL; + + if(FileData.cAlternateFileName[0]||FileData.cFileName[0]) + if(TextList[c0].PointInRect(&local_point)) + { + inrect=1; + box_col=0; + text_col=WHITE_COL; + } + + TextList[c0].FillRect(box_col); + TextList[c0].HiliteRect(HILITE_COL,LOLITE_COL); + + + if(FileData.cAlternateFileName[0]) + { //use alternative file names + QuickText(TextList[c0].GetLeft()+10,TextList[c0].GetTop()+2,FileData.cAlternateFileName,text_col); + if(inrect&&LeftMouse.ButtonState) + { + LeftMouse.ButtonState=0; + strcpy(FileName,FileData.cAlternateFileName); + } + } + else + { //use DOS file names + QuickText(TextList[c0].GetLeft()+20,TextList[c0].GetTop()+2,FileData.cFileName,text_col); + if(inrect&&LeftMouse.ButtonState) + { + LeftMouse.ButtonState=0; + strcpy(FileName,FileData.cFileName); + } + } + +//get next filename + if(Handle != INVALID_HANDLE_VALUE) + if(!FindNextFile(Handle, &FileData)) + { + FileData.cAlternateFileName[0]=0; + FileData.cFileName[0]=0; + } + } + if(Handle != INVALID_HANDLE_VALUE) + FindClose(Handle); + + UnlockWorkScreen(); + + if(temp_button_state==LeftMouse.ButtonState) + LeftMouse.ButtonState=0; + + + } + ShowWorkWindow(0); + if(Keys[KB_ESC]) + exit=1; + + + } + if(exit==1) + return(1); + else +#endif + return(0); +} + +//--------------------------------------------------------------- + + diff --git a/fallen/Editor/Source/Game.cpp b/fallen/Editor/Source/Game.cpp new file mode 100644 index 0000000..8b0ef86 --- /dev/null +++ b/fallen/Editor/Source/Game.cpp @@ -0,0 +1,296 @@ +// Game.cpp +// Guy Simmons, 24th March 1997. + +#include "Editor.hpp" +#include "Thing.h" +#include "Structs.h" + +#define GAME_OKAY (1<<0) +#define GAME_EDITOR (1<<1) +#define GAME_RECORD (1<<2) + +#define LEFT_WALK 0 +#define RIGHT_WALK 1 +#define LEFT_STAND 2 +#define RIGHT_STAND 3 +#define LEFT_JUMP 4 +#define LEFT_HIT 5 + +#define CLIP256(x) (x>255?255:x) + +extern SLONG calc_height_at(SLONG x,SLONG z); + +UBYTE palette[768]; +ULONG game_flags; + +void handle_game_control(void); +void handle_character_controls(void); + +//--------------------------------------------------------------- + +void init_game(void) +{ +} + +//--------------------------------------------------------------- + + + + +extern void setup_game(void); +#ifdef POO +void game(void) +{ + UWORD map_chap; + SLONG c0,c1, + test_x; + struct KeyFrameElement *the_element, + *the_next_element; + struct MapThing *t_thing; + struct Matrix33 r_matrix; + + + setup_game(); + + //init_thing(); + + +#define CHAP_X (HALF_ELE_SIZE+(512<X = CHAP_X; +// t_thing->Y = CHAP_Y; +// t_thing->Z = CHAP_Z; + + t_thing->X = map_things[background_prim].X; + t_thing->Y = map_things[background_prim].Y-100; + t_thing->Z = (HALF_ELE_SIZE+(6<X>>ELE_SHIFT,t_thing->Y>>ELE_SHIFT,map_chap); + t_thing->AngleX = 0; + t_thing->AngleY = 0; + t_thing->AngleZ = 0; + t_thing->Type = MAP_THING_TYPE_ROT_MULTI; + t_thing->IndexOther = 1; + + cam_chap = find_empty_map_thing(); + cam_thing = TO_MTHING(cam_chap); + cam_thing->X = CHAP_X; + cam_thing->Y = CHAP_Y; + cam_thing->Z = CHAP_Z-2; + cam_thing->AngleX = 0; + cam_thing->AngleY = 0; + cam_thing->AngleZ = 0; + cam_thing->Type = 0; + engine.Scale=266; + test_x = t_thing->X; + while(SHELL_ACTIVE && (game_flags&GAME_OKAY)) + { +// move_thing_on_cells(map_chap,test_x,t_thing->Y,t_thing->Z); + handle_game_control(); + + if(Keys[KB_LEFT]) + { + anim_offset_x -= 2; + } + else if(Keys[KB_RIGHT]) + { + anim_offset_x += 2; + } + if(Keys[KB_UP]) + { + anim_offset_y -= 2; + } + else if(Keys[KB_DOWN]) + { + anim_offset_y += 2; + } + if(Keys[KB_DEL]) + { + anim_angle_zx -= 4; + } + else if(Keys[KB_PGDN]) + { + anim_angle_zx += 4; + } + + if(Keys[KB_HOME]) + { + anim_angle_zy -= 4; + } + else if(Keys[KB_END]) + { + anim_angle_zy += 4; + } + +// motion = (LEFT_WALK+1); + + if(motion!=(LEFT_JUMP+1) && motion!=(LEFT_HIT+1)) + { + if(Keys[KB_X]) + { + if(motion==(RIGHT_WALK+1)) + { + test_x += 4; +// t_thing->AngleY = 1024; + } + else + { + motion = (RIGHT_WALK+1); + queued_frame = anim_array[RIGHT_WALK]; + } + } + else if(motion==(RIGHT_WALK+1)) + { + motion = (RIGHT_STAND+1); + queued_frame = anim_array[RIGHT_STAND]; + } + + if(Keys[KB_Z]) + { + if(motion==(LEFT_WALK+1)) + { + test_x -= 4; +// t_thing->AngleY = -1024; + } + else + { + motion = (LEFT_WALK+1); + queued_frame = anim_array[LEFT_WALK]; + } + } + else if(motion==(LEFT_WALK+1)) + { + motion = (LEFT_STAND+1); + queued_frame = anim_array[LEFT_STAND]; + } + + if(Keys[KB_SPACE]) + { + motion = (LEFT_JUMP+1); + queued_frame = anim_array[LEFT_JUMP]; + } + } + else + { + if(!next_frame->NextFrame) + { + if(Keys[KB_X]) + { + motion = (LEFT_WALK+1); + queued_frame = anim_array[LEFT_WALK]; + } + else if(motion==(LEFT_JUMP+1)) + { + motion = (LEFT_STAND+1); + queued_frame = anim_array[LEFT_STAND]; + } + } + } + + if(Keys[KB_ENTER] && motion!=(LEFT_HIT+1)) + { + motion = (LEFT_HIT+1); + queued_frame = anim_array[LEFT_HIT]; + } + + if(current_anim) + { +// anim_tween += 16; +// anim_tween += 256/(current_frame->TweenStep+1); + anim_tween += current_frame->TweenStep<<1; + if(anim_tween>256) + { + anim_tween -= 256; + current_frame = next_frame; + if(queued_frame) + { + next_frame = queued_frame; + queued_frame = 0; + } + else + { + if(next_frame->NextFrame) + next_frame = next_frame->NextFrame; + } + } + } + +extern SLONG count; + if(LastKey==KB_R) + { + game_flags |= GAME_RECORD; + count = 0; + LastKey = 0; + } + + SetWorkWindowBounds(0,0,WorkScreenWidth,WorkScreenHeight); + + ClearWorkScreen(0); + + if(LockWorkScreen()) + { + if(current_anim) + { + if(current_frame) + { + t_thing->TweenStage = anim_tween; + t_thing->AnimElements = current_frame->FirstElement; + if(next_frame) + t_thing->NextAnimElements = next_frame->FirstElement; + else + t_thing->NextAnimElements = t_thing->AnimElements; + } + + set_game_camera(t_thing); +// set_camera(); + draw_editor_map(1); +extern void draw_map_thing(SLONG map_thing); + draw_map_thing(map_chap); +extern void interface_thing(void); +//poo interface_thing(); + render_view(0); + } + UnlockWorkScreen(); + ShowWorkScreen(DS_WAIT_VBI); + if(game_flags&GAME_RECORD) + { +extern void do_record_frame(UBYTE *screen,UBYTE *palette); + if(LockWorkScreen()) + { + do_record_frame(WorkScreen,CurrentPalette); + UnlockWorkScreen(); + } + } + } + } + + reset_game(); +} +#endif + +//--------------------------------------------------------------- + +void handle_game_control(void) +{ + if(LastKey==KB_E) + { + if(Keys[KB_LCONTROL] || Keys[KB_RCONTROL]) + game_flags |= GAME_EDITOR; + LastKey = 0; + } + if(LastKey==KB_ESC) + game_flags = 0; + + if(game_flags&GAME_EDITOR) + { + editor_loop(); + game_flags &= ~GAME_EDITOR; +// LastKey = 0; // So we don't exit the game on exiting the editor. + } +} + + diff --git a/fallen/Editor/Source/GameEd.cpp b/fallen/Editor/Source/GameEd.cpp new file mode 100644 index 0000000..6c1dd97 --- /dev/null +++ b/fallen/Editor/Source/GameEd.cpp @@ -0,0 +1,1912 @@ +// GameEd.cpp +// Guy Simmons, 12th January 1998 + +#include "Editor.hpp" +#include "EdCom.h" +#include "Edway.h" +#include "c:\fallen\headers\game.h" +#include "c:\fallen\headers\animtmap.h" +#include "c:\fallen\headers\memory.h" + +#define MODE_PLACE 1 +#define MODE_SELECT 2 + +#define THING_BOX_SIZE 13 +#define WP_BOX_SIZE 9 +#define SH_BOX_SIZE 9 + +//--------------------------------------------------------------- + +extern CBYTE *class_text[]; +extern CBYTE *genus_text[][10]; + +//--------------------------------------------------------------- + +GameEditor::~GameEditor() +{ + DestroyTabs(); +} + +//--------------------------------------------------------------- + +void GameEditor::SetupModule(void) +{ + GameEdDefaults the_defaults; + + + // Setup the module defaults. + the_defaults.Left = 0; + the_defaults.Top = 20; + the_defaults.Width = 780; + the_defaults.Height = 560; + SetupWindow ( + "Game Editor", + (HAS_TITLE|HAS_GROW|HAS_CONTROLS), + the_defaults.Left, + the_defaults.Top, + the_defaults.Width, + the_defaults.Height + ); + SetContentColour(CONTENT_COL); + SetControlsHeight(440); + SetControlsWidth(300); + + // Initialise module members. + HilitedItem.ItemType = 0; + LastItem.ItemType = 0; + SelectedItem.ItemType = 0; + FlashState = TRUE; + EdEngine = engine; + SelectMode = 0; + + // Create the mode tabs. + CreateTabs(); + + if(ThingMode) + { + ThingMode->UpdateTabInfo(); + ThingMode->UpdateClassInfo(); + } + + init_ed_waypoints(); + init_ed_clists(); + + // The Win conditions. + win_conditions = alloc_ed_clist(); + add_condition(win_conditions,alloc_ed_condition()); + sprintf(win_conditions->CListName,"Win Conditions"); + + // The Lose conditions. + lose_conditions = alloc_ed_clist(); + add_condition(lose_conditions,alloc_ed_condition()); + sprintf(lose_conditions->CListName,"Lose Conditions"); +} + +//--------------------------------------------------------------- + +void GameEditor::CreateTabs(void) +{ + EdRect bounds_rect; + + + bounds_rect.SetRect(ControlsLeft(),ControlsTop(),ControlsWidth(),ControlsHeight()); + + SaveMode = new SaveTab; + if(SaveMode) + { + AddTab(SaveMode); + SaveMode->SetupModeTab("Levels",TAB_LEVELS,&bounds_rect,ExternalUpdate); + } + + ThingMode = new ThingTab; + if(ThingMode) + { + AddTab(ThingMode); + ThingMode->SetupModeTab("Things",TAB_THINGS,&bounds_rect,ExternalUpdate); + } + + CommandMode = new CommandTab; + if(CommandMode) + { + AddTab(CommandMode); + CommandMode->SetupModeTab("Commands",TAB_COMMANDS,&bounds_rect,ExternalUpdate); + } + + ConditionMode = new ConditionTab; + if(ConditionMode) + { + AddTab(ConditionMode); + ConditionMode->SetupModeTab("Conditions",TAB_CONDITIONS,&bounds_rect,ExternalUpdate); + } +} + +//--------------------------------------------------------------- + +void GameEditor::DestroyTabs(void) +{ + if(ThingMode) + delete ThingMode; + + if(SaveMode) + delete SaveMode; +} + +//--------------------------------------------------------------- + +void GameEditor::DrawContent(void) +{ + EngineStuff temp_engine; + + + // Backup current engine stuff. + temp_engine = engine; + engine = EdEngine; + + SetContentDrawArea(); + ClearContent(); + + set_camera(); + + GameEdEngine(); + ScanEngine(); + RenderEngine(); + + // Restore engine stuff. + engine = temp_engine; +} + +//--------------------------------------------------------------- + +extern SLONG calc_height_at(SLONG x,SLONG z); + +void GameEditor::HandleContentClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD new_thing; + SLONG mappos; + + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SaveMode->SetSaveState(FALSE); + switch(HilitedItem.ItemType) + { + case ED_ITEM_NONE: + break; + case ED_ITEM_THING: + switch(SelectMode) + { + case SELECT_COND_TAB_THING: + case SELECT_COND_TAB_SWITCH: + ConditionMode->SetTabData(HilitedItem.ItemRef); + ClearSelectMode(); + break; + case SELECT_THING_TAB_THING: + case SELECT_THING_TAB_SWITCH: + ThingMode->SetTabData(HilitedItem.ItemRef); + ClearSelectMode(); + break; + case SELECT_COM_TAB_WAYPOINT: + break; + case SELECT_COM_TAB_THING: + case SELECT_COM_TAB_SWITCH: + CommandMode->SetTabData(HilitedItem.ItemRef); + ClearSelectMode(); + break; + default: + SelectedItem = HilitedItem; + ThingMode->SetCurrentClass(map_things[SelectedItem.ItemRef].Class); + ThingMode->SetCurrentGenus(map_things[SelectedItem.ItemRef].Genus); + ThingMode->SetCurrentThing(SelectedItem.ItemRef); + + DownPoint = *clicked_point; + HandleThingDrag(); + } + break; + case ED_ITEM_MAP_BLOCK: + if(!SelectMode) + { + if ( + ThingMode->GetCurrentClass() && + ThingMode->GetCurrentGenus() + ) + { + mappos = HilitedItem.ItemRef; + new_thing = find_empty_map_thing(); + if(new_thing) + { + add_thing_to_edit_map(mappos>>8,mappos&0x00ff,new_thing); + map_things[new_thing].X = (mappos&0xff00)+128; + map_things[new_thing].Z = ((mappos&0x00ff)<<8)+128; + map_things[new_thing].Y = calc_height_at(map_things[new_thing].X,map_things[new_thing].Z); + map_things[new_thing].Type = MAP_THING_TYPE_ED_THING; + map_things[new_thing].Class = ThingMode->GetCurrentClass(); + map_things[new_thing].Genus = ThingMode->GetCurrentGenus(); + map_things[new_thing].CommandRef = 0; + map_things[new_thing].Data[0] = 256; + + SelectedItem.ItemType = ED_ITEM_THING; + SelectedItem.ItemRef = new_thing; + ThingMode->SetCurrentThing(new_thing); + } + } + } + break; + case ED_ITEM_BUILDING: + SelectedItem = HilitedItem; + ThingMode->SetCurrentClass(CLASS_BUILDING); + ThingMode->SetCurrentGenus(0); + ThingMode->SetCurrentThing(SelectedItem.ItemRef); + break; + case ED_ITEM_WAYPOINT: + switch(SelectMode) + { + case SELECT_NONE: + DownPoint = *clicked_point; + HandleWaypointDrag(); + break; + case SELECT_WAYPOINT: + map_things[SelectedItem.ItemRef].CommandRef = HilitedItem.ItemRef; + ClearSelectMode(); + break; + case SELECT_NEXT_WAYPOINT: + link_next_waypoint(SelectedItem.ItemRef,HilitedItem.ItemRef); + ClearSelectMode(); + break; + case SELECT_PREV_WAYPOINT: + link_prev_waypoint(SelectedItem.ItemRef,HilitedItem.ItemRef); + ClearSelectMode(); + break; + case SELECT_COND_TAB_THING: + case SELECT_COND_TAB_SWITCH: + case SELECT_THING_TAB_THING: + case SELECT_THING_TAB_SWITCH: + break; + case SELECT_COM_TAB_WAYPOINT: + CommandMode->SetTabData(HilitedItem.ItemRef); + ClearSelectMode(); + break; + case SELECT_COM_TAB_THING: + case SELECT_COM_TAB_SWITCH: + break; + } + break; + case ED_ITEM_SIZE_HOOK: + DownPoint = *clicked_point; + HandleSizeDrag(); + break; + } + break; + case MIDDLE_CLICK: + break; + case RIGHT_CLICK: + switch(HilitedItem.ItemType) + { + case ED_ITEM_NONE: + break; + case ED_ITEM_THING: + if(RightButton) + { + DoThingPopup(clicked_point); + } + break; + case ED_ITEM_MAP_BLOCK: + if(RightButton) + { + DoBlockPopup(clicked_point); + } + break; + case ED_ITEM_BUILDING: + break; + case ED_ITEM_WAYPOINT: + if(RightButton) + { + DoWaypointPopup(clicked_point); + } + break; + } + break; + } +} + +//--------------------------------------------------------------- + +void GameEditor::HandleControlClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + + + if(CurrentModeTab()) + { + control_id = CurrentModeTab()->HandleTabClick(flags,clicked_point); + switch(CurrentModeTab()->GetTabID()) + { + case TAB_NONE: + break; + case TAB_THINGS: + switch(ThingMode->GetTabMode()) + { + case THING_MODE_NONE: + break; + case THING_MODE_SELECT_THING: + SetSelectMode(SELECT_THING_TAB_THING); + break; + case THING_MODE_SELECT_SWITCH: + SetSelectMode(SELECT_THING_TAB_SWITCH); + break; + } + break; + case TAB_LEVELS: + break; + case TAB_COMMANDS: + switch(CommandMode->GetTabMode()) + { + case COM_MODE_NONE: + break; + case COM_MODE_SELECT_THING: + SetSelectMode(SELECT_COM_TAB_THING); + break; + case COM_MODE_SELECT_WAYPOINT: + SetSelectMode(SELECT_COM_TAB_WAYPOINT); + break; + case COM_MODE_SELECT_SWITCH: + SetSelectMode(SELECT_COM_TAB_SWITCH); + break; + } + break; + case TAB_CONDITIONS: + switch(ConditionMode->GetTabMode()) + { + case COND_MODE_NONE: + break; + case COND_MODE_SELECT_THING: + SetSelectMode(SELECT_COND_TAB_THING); + break; + case COND_MODE_SELECT_SWITCH: + SetSelectMode(SELECT_COND_TAB_SWITCH); + break; + } + break; + } + } +} + +//--------------------------------------------------------------- + +void GameEditor::HandleModule(void) +{ + BOOL flash = FALSE; + ULONG update = 0; + SLONG dx = 0, + dy = 0, + dz = 0; + MFPoint mouse_point; + MFTime current_time; + static EditFace last_face; + + + Time(¤t_time); + if(current_time.MSeconds>500) + { + flash = TRUE; + } + if(FlashState!=flash) + { + FlashState = flash; + update = 2; + } + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + if(CurrentModeTab()) + { + CurrentModeTab()->HandleTab(&mouse_point); + } + + if(PointInContent(&mouse_point)) + { + update += 1; + } + + if(LastItem.ItemType!=HilitedItem.ItemType || LastItem.ItemRef!=HilitedItem.ItemRef) + { + LastItem = HilitedItem; + update = 2; + } + + if(LastKey==KB_ESC) + { + if(SelectMode) + { + ClearSelectMode(); + LastKey = 0; + } + } + + if(EngineKeys()) + update = 2; + + if(update) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + if(update>1) + ShowWorkWindow(0); + } +} + +//--------------------------------------------------------------- + +void GameEditor::HandleThingDrag(void) +{ + SLONG new_x, + new_y, + new_z, + x_diff, + y_diff; + + + if(ShiftFlag) + { + while(SHELL_ACTIVE && LeftButton) + { + new_x = map_things[SelectedItem.ItemRef].X; + new_y = map_things[SelectedItem.ItemRef].Y; + new_z = map_things[SelectedItem.ItemRef].Z; + y_diff = (DownPoint.Y-MouseY); + + new_y += (y_diff<<11)/EdEngine.Scale; + + DownPoint.Y -= y_diff; + move_thing_on_cells(SelectedItem.ItemRef,new_x,new_y,new_z); + + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + } + else + { + while(SHELL_ACTIVE && LeftButton) + { + new_x = map_things[SelectedItem.ItemRef].X; + new_y = map_things[SelectedItem.ItemRef].Y; + new_z = map_things[SelectedItem.ItemRef].Z; + x_diff = (DownPoint.X-MouseX); + y_diff = (DownPoint.Y-MouseY); + + new_x += ((SIN( ((EdEngine.AngleY>>8)-512)&2047)*x_diff)>>5)/EdEngine.Scale; + new_z += ((COS( ((EdEngine.AngleY>>8)-512)&2047)*x_diff)>>5)/EdEngine.Scale; + new_x += ((SIN( ((EdEngine.AngleY>>8)+1024)&2047)*y_diff)>>5)/EdEngine.Scale; + new_z += ((COS( ((EdEngine.AngleY>>8)+1024)&2047)*y_diff)>>5)/EdEngine.Scale; + + DownPoint.X -= x_diff; + DownPoint.Y -= y_diff; + move_thing_on_cells(SelectedItem.ItemRef,new_x,new_y,new_z); + + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + } +} + +//--------------------------------------------------------------- + +UWORD GameEditor::EngineKeys(void) +{ + UBYTE change = 0; + EngineStuff temp_engine; + + + // Backup current engine stuff. + temp_engine = engine; + engine = EdEngine; + + change |= engine_keys_scroll_game(); + change |= engine_keys_spin(); + change |= engine_keys_zoom(); + + if(change) + change = 2; + + // Restore engine stuff. + EdEngine = engine; + engine = temp_engine; + + return change; +} + +//--------------------------------------------------------------- + +static ControlDef block_popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 block_popup[] = +{ + { "Place Waypoint" }, + { "!" } +}; + +void GameEditor::DoBlockPopup(MFPoint *clicked_point) +{ + UWORD new_wp; + ULONG control_id; + SLONG mappos; + CPopUp *the_control = 0; + MFPoint local_point; + + + local_point = *clicked_point; + GlobalToLocal(&local_point); + block_popup_def.ControlLeft = local_point.X+4; + block_popup_def.ControlTop = local_point.Y-4; + + block_popup_def.TheMenuDef = block_popup; + the_control = new CPopUp(&block_popup_def); + control_id = the_control->TrackControl(&local_point); + + switch(control_id>>8) + { + case 0: + break; + case 1: + new_wp = alloc_ed_waypoint(); + if(new_wp) + { + mappos = HilitedItem.ItemRef; + + edit_waypoints[new_wp].X = (mappos&0xff00)+128; + edit_waypoints[new_wp].Z = ((mappos&0x00ff)<<8)+128; + edit_waypoints[new_wp].Y = calc_height_at(edit_waypoints[new_wp].X,edit_waypoints[new_wp].Z); + } + break; + } +} + +//--------------------------------------------------------------- + +static ControlDef thing_popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 thing_popup[] = +{ + { "Delete Thing" }, + { "^" }, + { "Snap to Floor" }, + { "Snap to Surface" }, + { "^" }, + { "Link to Waypoint" }, + { "!" } +}; + +void GameEditor::DoThingPopup(MFPoint *clicked_point) +{ + ULONG control_id; + SLONG thing_x, + thing_y, + thing_z; + CPopUp *the_control = 0; + MFPoint local_point; + + + local_point = *clicked_point; + GlobalToLocal(&local_point); + thing_popup_def.ControlLeft = local_point.X+4; + thing_popup_def.ControlTop = local_point.Y-4; + + thing_popup_def.TheMenuDef = thing_popup; + the_control = new CPopUp(&thing_popup_def); + control_id = the_control->TrackControl(&local_point); + + thing_x = map_things[HilitedItem.ItemRef].X; + thing_y = map_things[HilitedItem.ItemRef].Y; + thing_z = map_things[HilitedItem.ItemRef].Z; + switch(control_id>>8) + { + case 0: // Null. + break; + case 1: // Delete Thing. + delete_thing(HilitedItem.ItemRef); + HilitedItem.ItemType = ED_ITEM_NONE; + SelectedItem.ItemType = ED_ITEM_NONE; + break; + case 2: // Blank line. + break; + case 3: // Snap to Floor. + move_thing_on_cells(HilitedItem.ItemRef,thing_x,calc_height_at(thing_x,thing_z),thing_z); + break; + case 4: // Snap to Face. + // Stick in the snap to face stuff here. + break; + case 5: // Blank line. + break; + case 6: // Link to Waypoint. + SetSelectMode(SELECT_WAYPOINT); + break; + } + + if(the_control) + { + delete the_control; + } +} + +//--------------------------------------------------------------- + +void GameEditor::HandleWaypointDrag(void) +{ + SLONG new_x, + new_y, + new_z, + x_diff, + y_diff; + EditWaypoint *the_wp; + + + the_wp = &edit_waypoints[HilitedItem.ItemRef]; + if(ShiftFlag) + { + while(SHELL_ACTIVE && LeftButton) + { + new_y = the_wp->Y; + y_diff = (DownPoint.Y-MouseY); + new_y += (y_diff<<11)/EdEngine.Scale; + DownPoint.Y -= y_diff; + the_wp->Y = new_y; + + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + } + else + { + while(SHELL_ACTIVE && LeftButton) + { + new_x = the_wp->X; + new_z = the_wp->Z; + x_diff = (DownPoint.X-MouseX); + y_diff = (DownPoint.Y-MouseY); + + new_x += ((SIN( ((EdEngine.AngleY>>8)-512)&2047)*x_diff)>>5)/EdEngine.Scale; + new_z += ((COS( ((EdEngine.AngleY>>8)-512)&2047)*x_diff)>>5)/EdEngine.Scale; + new_x += ((SIN( ((EdEngine.AngleY>>8)+1024)&2047)*y_diff)>>5)/EdEngine.Scale; + new_z += ((COS( ((EdEngine.AngleY>>8)+1024)&2047)*y_diff)>>5)/EdEngine.Scale; + + DownPoint.X -= x_diff; + DownPoint.Y -= y_diff; + + the_wp->X = new_x; + the_wp->Z = new_z; + + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + } +} + +//--------------------------------------------------------------- + +static ControlDef way_popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 way_popup[] = +{ + { "Delete Waypoint" }, + { "^" }, + { "Link to Next" }, + { "Link to Previous" }, + { "^" }, + { "Snap to Floor" }, + { "Snap to Surface" }, + { "!" } +}; + + +void GameEditor::DoWaypointPopup(MFPoint *clicked_point) +{ + UWORD new_wp; + ULONG control_id; + SLONG c0,mappos; + CPopUp *the_control = 0; + MFPoint local_point; + + + local_point = *clicked_point; + GlobalToLocal(&local_point); + way_popup_def.ControlLeft = local_point.X+4; + way_popup_def.ControlTop = local_point.Y-4; + + way_popup_def.TheMenuDef = way_popup; + the_control = new CPopUp(&way_popup_def); + control_id = the_control->TrackControl(&local_point); + + switch(control_id>>8) + { + case 0: // NULL. + break; + case 1: // Delete Waypoint. + // Search through all the things to clear any waypoint references. + for(c0=1;c0>8)>>ELE_SHIFT; + my = (EdEngine.Y>>8)>>ELE_SHIFT; + mz = (EdEngine.Z>>8)>>ELE_SHIFT; + + // Do the waypoints. + for(c0=0;c0=end_bucket_pool) + goto exit; + + point.X = edit_waypoints[c0].X; + point.Y = edit_waypoints[c0].Y; + point.Z = edit_waypoints[c0].Z; + if(!(rotate_point_gte(&point,&wp_points[c0])&EF_CLIPFLAGS)) + { + ((BucketWaypoint*)current_bucket_pool)->BucketType = BT_WAYPOINT; + ((BucketWaypoint*)current_bucket_pool)->X = wp_points[c0].X; + ((BucketWaypoint*)current_bucket_pool)->Y = wp_points[c0].Y; + ((BucketWaypoint*)current_bucket_pool)->EditRef.ItemType = ED_ITEM_WAYPOINT; + ((BucketWaypoint*)current_bucket_pool)->EditRef.ItemRef = c0; + + base_point = point; + base_point.Y = calc_height_at(base_point.X,base_point.Z); + rotate_point_gte(&base_point,&new_point); + ((BucketWaypoint*)current_bucket_pool)->BaseX = new_point.X; + ((BucketWaypoint*)current_bucket_pool)->BaseY = new_point.Y; + + add_bucket((void *)current_bucket_pool,new_point.Z-300); + current_bucket_pool += sizeof(BucketWaypoint); + } + } + } + + // Do the waypoint connection lines. + for(c0=0;c0=end_bucket_pool) + goto exit; + + ((BucketLine*)current_bucket_pool)->BucketType = BT_LINE; + ((BucketLine*)current_bucket_pool)->X1 = wp_points[c0].X; + ((BucketLine*)current_bucket_pool)->Y1 = wp_points[c0].Y; + ((BucketLine*)current_bucket_pool)->X2 = wp_points[edit_waypoints[c0].Next].X; + ((BucketLine*)current_bucket_pool)->Y2 = wp_points[edit_waypoints[c0].Next].Y; + + add_bucket((void *)current_bucket_pool,1); + current_bucket_pool += sizeof(BucketLine); + } + } + + + memset((UBYTE*)buffer_flags,0,MAX_RADIUS*(MAX_RADIUS+1)*4*4); + ptr = &buffer_points[MAX_RADIUS+MAX_RADIUS*MAX_RADIUS*2]; + + point.X = (mx<Dx; + cdz = ptr_rad->Dz; + + dx = (cdx*ELE_SIZE); + dz = (cdz*ELE_SIZE); + + cdx += MAX_RADIUS; + cdz += MAX_RADIUS; + + ptr = &buffer_points[cdx+cdz*MAX_RADIUS*2]; + + point.X = dx+(mx<>8); + + clip_flags = rotate_point_gte(&point,ptr); +// if( ((clip_flags&EF_BEHIND_YOU)==0) && !(clip_flags & EF_CLIPFLAGS)) + { + buffer_flags[cdx+cdz*MAX_RADIUS*2] = clip_flags; + } + ptr_rad++; + } + } + + + ptr_flag = buffer_flags; + for(dz=0;dz0&&dx+mx-MAX_RADIUS0&&dz+mz-MAX_RADIUSType) + { + case MAP_THING_TYPE_PRIM: + break; + case MAP_THING_TYPE_BUILDING: + if(ThingMode->GetThingFlags()&(1<IndexOther].FacetHead; + while(facet_index) + { + az = DrawFacet ( + facet_index, + p_mthing->X,p_mthing->Y,p_mthing->Z + ); + if(best_z=end_bucket_pool) + goto exit; + + point.X = p_mthing->X; + point.Y = p_mthing->Y; + point.Z = p_mthing->Z; + + base_point = point; + base_point.Y = calc_height_at(base_point.X,base_point.Z); + rotate_point_gte(&base_point,&new_point); + ((BucketMapThing*)current_bucket_pool)->BaseX = new_point.X; + ((BucketMapThing*)current_bucket_pool)->BaseY = new_point.Y; + + rotate_point_gte(&point,&new_point); + ((BucketMapThing*)current_bucket_pool)->BucketType = BT_MAP_THING; + ((BucketMapThing*)current_bucket_pool)->X = new_point.X; + ((BucketMapThing*)current_bucket_pool)->Y = new_point.Y; + ((BucketMapThing*)current_bucket_pool)->EditRef.ItemType = ED_ITEM_THING; + ((BucketMapThing*)current_bucket_pool)->EditRef.ItemRef = CurrentThing; + + add_bucket((void *)current_bucket_pool,new_point.Z-300); + current_bucket_pool += sizeof(BucketMapThing); + + // Do the size thing for switches. + if(p_mthing->Class==CLASS_SWITCH) + { + if(current_bucket_pool>=end_bucket_pool) + goto exit; + + ((BucketSphereArea*)current_bucket_pool)->BucketType = BT_SPHERE_AREA; + ((BucketSphereArea*)current_bucket_pool)->X = new_point.X; + ((BucketSphereArea*)current_bucket_pool)->Y = new_point.Y; + ((BucketSphereArea*)current_bucket_pool)->Radius = (p_mthing->Data[0]*EdEngine.Scale)>>11; + ((BucketSphereArea*)current_bucket_pool)->ShowSizeHook = TRUE; + ((BucketSphereArea*)current_bucket_pool)->EditRef.ItemType = ED_ITEM_SIZE_HOOK; + ((BucketSphereArea*)current_bucket_pool)->EditRef.ItemRef = CurrentThing; + + add_bucket((void *)current_bucket_pool,1); + current_bucket_pool += sizeof(BucketSphereArea); + } + + // Do the link lines. + if(p_mthing->CommandRef) + { + if(current_bucket_pool>=end_bucket_pool) + goto exit; + + ((BucketLine*)current_bucket_pool)->BucketType = BT_LINE; + ((BucketLine*)current_bucket_pool)->X1 = new_point.X; + ((BucketLine*)current_bucket_pool)->Y1 = new_point.Y; + + ((BucketLine*)current_bucket_pool)->X2 = wp_points[p_mthing->CommandRef].X; + ((BucketLine*)current_bucket_pool)->Y2 = wp_points[p_mthing->CommandRef].Y; + + add_bucket((void *)current_bucket_pool,1); + current_bucket_pool += sizeof(BucketLine); + } + break; + } + CurrentThing = map_things[CurrentThing].MapChild; + } + + // Do the map floor. + if(!(edit_map[(dx+mx-MAX_RADIUS)][(dz+mz-MAX_RADIUS)].Flags&FLOOR_HIDDEN) || !(ThingMode->GetThingFlags()&(1<=end_bucket_pool) + goto exit; + + CurrentThing = (((dx+mx-MAX_RADIUS)<<8)|(dz+mz-MAX_RADIUS)); + + az = buffer_points[dx+dz*MAX_RADIUS*2].Z; + + setPolyType4( + current_bucket_pool, + POLY_GT + ); + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + 1 + ); + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + buffer_points[dx+dz*MAX_RADIUS*2].X,buffer_points[dx+dz*MAX_RADIUS*2].Y, + buffer_points[dx+dz*MAX_RADIUS*2+1].X,buffer_points[dx+dz*MAX_RADIUS*2+1].Y, + buffer_points[dx+(dz+1)*MAX_RADIUS*2].X,buffer_points[dx+(dz+1)*MAX_RADIUS*2].Y, + buffer_points[dx+(dz+1)*MAX_RADIUS*2+1].X,buffer_points[dx+(dz+1)*MAX_RADIUS*2+1].Y + ); + + p_map = &edit_map[(dx+mx-MAX_RADIUS)][(dz+mz-MAX_RADIUS)]; + tx = ((struct MiniTextureBits*)(&p_map->Texture))->X<<5; + ty = ((struct MiniTextureBits*)(&p_map->Texture))->Y<<5; + page = ((struct MiniTextureBits*)(&p_map->Texture))->Page; + tsize = 31;//floor_texture_sizes[((struct MiniTextureBits*)(&p_map->Texture))->Size]-1; + switch(((struct MiniTextureBits*)(&p_map->Texture))->Rot) + { + case 0: + setUV4( (struct BucketQuad*)current_bucket_pool,tx,ty,tx+tsize,ty,tx,ty+tsize,tx+tsize,ty+tsize,page); + break; + case 1: + setUV4( (struct BucketQuad*)current_bucket_pool,tx+tsize,ty,tx+tsize,ty+tsize,tx,ty,tx,ty+tsize,page); + break; + case 2: + setUV4( (struct BucketQuad*)current_bucket_pool,tx+tsize,ty+tsize,tx,ty+tsize,tx+tsize,ty,tx,ty,page); + break; + case 3: + setUV4( (struct BucketQuad*)current_bucket_pool,tx,ty+tsize,tx,ty,tx+tsize,ty+tsize,tx+tsize,ty,page); + break; + } + + setZ4((struct BucketQuad*)current_bucket_pool,az,0,0,0); + + setShade4 ((BucketQuad*)current_bucket_pool, + edit_map[(dx+mx-MAX_RADIUS)][(dz+mz-MAX_RADIUS)].Bright, + edit_map[(dx+mx-MAX_RADIUS+1)][(dz+mz-MAX_RADIUS)].Bright, + edit_map[(dx+mx-MAX_RADIUS)][(dz+mz-MAX_RADIUS+1)].Bright, + edit_map[(dx+mx-MAX_RADIUS+1)][(dz+mz-MAX_RADIUS+1)].Bright + ); + + ((BucketQuad*)current_bucket_pool)->DebugInfo = az; + ((BucketQuad*)current_bucket_pool)->DebugFlags = 0; + ((BucketQuad*)current_bucket_pool)->EditRef.ItemType = ED_ITEM_MAP_BLOCK; + ((BucketQuad*)current_bucket_pool)->EditRef.ItemRef = CurrentThing; + add_bucket((void *)current_bucket_pool,az+300); + + current_bucket_pool += sizeof(struct BucketQuad); + } + } + + } + ptr_flag++; + } +exit:; +} + +//--------------------------------------------------------------- + +SLONG GameEditor::DrawFacet(UWORD facet_index,SLONG x,SLONG y,SLONG z) +{ + ULONG flag_and,flag_or; + SLONG az; + SLONG col=0, + cor=0, + cob=0, + cot=0, + total=0; + SLONG first_face=1; + SLONG best_z = 9999999, + min_z = 9999999, + max_z = 9999999, + c0, + facet_flags, + sp,mp,ep; + BuildingFacet *p_facet; + PrimFace3 *p_f3; + PrimFace4 *p_f4; + + + p_facet = &building_facets[facet_index]; + facet_flags = p_facet->FacetFlags; + p_f4 = &prim_faces4[p_facet->StartFace4]; + p_f3 = &prim_faces3[p_facet->StartFace3]; + if(facet_flags&FACET_FLAG_ROOF) + { + first_face = 0; + } + + sp = p_facet->StartPoint; + mp = p_facet->MidPoint; + ep = p_facet->EndPoint; + + engine.X -= x<<8; + engine.Y -= y<<8; + engine.Z -= z<<8; + + for(c0=sp;c0global_res[c0-sp].Z) + min_z = global_res[c0-sp].Z; + if(max_zEndFace4) + for(c0=p_facet->StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + if(current_bucket_pool>=end_bucket_pool) + goto exit; + + p0 = p_f4->Points[0]-sp; + p1 = p_f4->Points[1]-sp; + p2 = p_f4->Points[2]-sp; + p3 = p_f4->Points[3]-sp; + + + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]&global_flags[p3]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]|global_flags[p3]; + + if( (!(flag_and & EF_CLIPFLAGS))&&((flag_or&EF_BEHIND_YOU)==0)) + { + az = ( global_res[p0].Z + + global_res[p1].Z + + global_res[p2].Z + + global_res[p3].Z ) / 4; + + setPolyType4( + current_bucket_pool, + p_f4->DrawFlags + ); + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + ((UBYTE)p_f4->Col2) + ); + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + global_res[p0].X,global_res[p0].Y, + global_res[p1].X,global_res[p1].Y, + global_res[p2].X,global_res[p2].Y, + global_res[p3].X,global_res[p3].Y + ); + +//RUD + if(p_f4->DrawFlags&POLY_FLAG_TEXTURED) + { + setUV4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->UV[0][0],p_f4->UV[0][1], + p_f4->UV[1][0],p_f4->UV[1][1], + p_f4->UV[2][0],p_f4->UV[2][1], + p_f4->UV[3][0],p_f4->UV[3][1], + (UBYTE)p_f4->TexturePage + ); + } + setZ4((struct BucketQuad*)current_bucket_pool,global_res[p0].Z,global_res[p1].Z,global_res[p2].Z,global_res[p3].Z); + + setShade4((struct BucketQuad*)current_bucket_pool, + CLIP256(p_f4->Bright[0]+global_bright[p0]), + CLIP256(p_f4->Bright[1]+global_bright[p1]), + CLIP256(p_f4->Bright[2]+global_bright[p2]), + CLIP256(p_f4->Bright[3]+global_bright[p3])); + + ((BucketQuad*)current_bucket_pool)->DebugInfo = az; + ((BucketQuad*)current_bucket_pool)->DebugFlags = p_f4->FaceFlags; + ((BucketQuad*)current_bucket_pool)->EditRef.ItemType = ED_ITEM_BUILDING; + ((BucketQuad*)current_bucket_pool)->EditRef.ItemRef = CurrentThing; + + + add_bucket((void *)current_bucket_pool,az); + current_bucket_pool += sizeof(struct BucketQuad); + } + else + { + if(flag_and&EF_OFF_LEFT) + col++; + if(flag_and&EF_OFF_RIGHT) + cor++; + if(flag_and&EF_OFF_TOP) + cot++; + if(flag_and&EF_OFF_BOTTOM) + cob++; + } + + p_f4++; + } + + if(p_facet->EndFace3) + for(c0=p_facet->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + if(current_bucket_pool>=end_bucket_pool) + goto exit; + + + p0 = p_f3->Points[0]-sp; + p1 = p_f3->Points[1]-sp; + p2 = p_f3->Points[2]-sp; + + flag_and = global_flags[p0]&global_flags[p1]&global_flags[p2]; + flag_or = global_flags[p0]|global_flags[p1]|global_flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + az = ( global_res[p0].Z + + global_res[p1].Z + + global_res[p2].Z ) / 3; + + setPolyType3( + current_bucket_pool, + p_f3->DrawFlags + ); + + setCol3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->Col2 + ); + + setXY3 ( + (struct BucketTri*)current_bucket_pool, + global_res[p0].X,global_res[p0].Y, + global_res[p1].X,global_res[p1].Y, + global_res[p2].X,global_res[p2].Y + ); + +//RUD + if(p_f3->DrawFlags&POLY_FLAG_TEXTURED) + { + setUV3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->UV[0][0],p_f3->UV[0][1], + p_f3->UV[1][0],p_f3->UV[1][1], + p_f3->UV[2][0],p_f3->UV[2][1], + p_f3->TexturePage + ); + } + + setShade3((struct BucketTri*)current_bucket_pool, + CLIP256(p_f3->Bright[0]+global_bright[p0]), + CLIP256(p_f3->Bright[1]+global_bright[p1]), + CLIP256(p_f3->Bright[2]+global_bright[p2])); + + setZ3((struct BucketQuad*)current_bucket_pool,global_res[p0].Z,global_res[p1].Z,global_res[p2].Z); + + ((BucketTri*)current_bucket_pool)->DebugInfo = c0; + ((BucketTri*)current_bucket_pool)->DebugFlags = p_f3->FaceFlags; + ((BucketTri*)current_bucket_pool)->EditRef.ItemType = ED_ITEM_BUILDING; + ((BucketTri*)current_bucket_pool)->EditRef.ItemRef = CurrentThing; + + add_bucket((void *)current_bucket_pool,az); + current_bucket_pool += sizeof(struct BucketQuad); + } + p_f3++; + } +exit:; + + return(best_z); +} + +//--------------------------------------------------------------- + +#define Z_NORMAL(pa,pb) ((mouse_point.X-(pb).X)*((pb).Y-(pa).Y)-(mouse_point.Y-(pb).Y)*((pb).X-(pa).X)) + +// This is mad, however it works & it's only the editor after all. +void GameEditor::ScanEngine(void) +{ + void *bucket; + ULONG c0, + offset_x, + offset_y; + BucketHead *p; + BucketMapThing *the_map_thing; + BucketQuad *the_quad; + BucketSphereArea *the_sphere; + BucketTri *the_tri; + BucketWaypoint *the_waypoint; + MapThing *t_mthing; + MFPoint mouse_point; + + + HilitedItem.ItemType = ED_ITEM_NONE; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + if(PointInContent(&mouse_point)) + { + GlobalXYToLocal(&mouse_point.X,&mouse_point.Y); + + p = &bucket_heads[engine.BucketSize-1]; + for(c0=0;c0BucketPtr; + { + while(bucket) + { + switch(((BucketGeneric*)bucket)->BucketType) + { + case BT_QUAD: + the_quad = (BucketQuad*)bucket; + if(the_quad->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + if ( + (Z_NORMAL(the_quad->P[0],the_quad->P[1]))>0 && + (Z_NORMAL(the_quad->P[1],the_quad->P[3]))>0 && + (Z_NORMAL(the_quad->P[3],the_quad->P[2]))>0 && + (Z_NORMAL(the_quad->P[2],the_quad->P[0]))>0 + ) + { + HilitedItem = the_quad->EditRef; + } + } + if ( + (Z_NORMAL(the_quad->P[0],the_quad->P[1]))<0 && + (Z_NORMAL(the_quad->P[1],the_quad->P[3]))<0 && + (Z_NORMAL(the_quad->P[3],the_quad->P[2]))<0 && + (Z_NORMAL(the_quad->P[2],the_quad->P[0]))<0 + ) + { + HilitedItem = the_quad->EditRef; + } + break; + case BT_TRI: + the_tri = (BucketTri*)bucket; + if(the_tri->DrawFlags&POLY_FLAG_DOUBLESIDED) + { + if ( + (Z_NORMAL(the_tri->P[0],the_tri->P[1]))>0 && + (Z_NORMAL(the_tri->P[1],the_tri->P[2]))>0 && + (Z_NORMAL(the_tri->P[2],the_tri->P[0]))>0 + ) + { + HilitedItem = the_tri->EditRef; + } + } + if ( + (Z_NORMAL(the_tri->P[0],the_tri->P[1]))<0 && + (Z_NORMAL(the_tri->P[1],the_tri->P[2]))<0 && + (Z_NORMAL(the_tri->P[2],the_tri->P[0]))<0 + ) + { + HilitedItem = the_tri->EditRef; + } + break; + case BT_VECT: + break; + case BT_RECT: + break; + case BT_MAP_THING: + the_map_thing = (BucketMapThing*)bucket; + if ( + mouse_point.X>=the_map_thing->X-(THING_BOX_SIZE>>1) && + mouse_point.XX+(THING_BOX_SIZE>>1) && + mouse_point.Y>=the_map_thing->Y-(THING_BOX_SIZE>>1) && + mouse_point.YY+(THING_BOX_SIZE>>1) + ) + { + t_mthing = TO_MTHING(the_map_thing->EditRef.ItemRef); + if(!SelectMode || SelectMode==SELECT_COND_TAB_THING || SelectMode==SELECT_THING_TAB_THING || SelectMode==SELECT_COM_TAB_THING) + HilitedItem = the_map_thing->EditRef; + else if((SelectMode==SELECT_COND_TAB_SWITCH || SelectMode==SELECT_COM_TAB_SWITCH || SelectMode==SELECT_THING_TAB_SWITCH) && t_mthing->Class==CLASS_SWITCH) + HilitedItem = the_map_thing->EditRef; + } + break; + case BT_WAYPOINT: + the_waypoint = (BucketWaypoint*)bucket; + if ( + mouse_point.X>=the_waypoint->X-(WP_BOX_SIZE>>1) && + mouse_point.XX+(WP_BOX_SIZE>>1) && + mouse_point.Y>=the_waypoint->Y-(WP_BOX_SIZE>>1) && + mouse_point.YY+(WP_BOX_SIZE>>1) + ) + { + HilitedItem = the_waypoint->EditRef; + } + break; + case BT_LINE: + break; + case BT_SPHERE_AREA: + the_sphere = (BucketSphereArea*)bucket; + offset_x = ((SIN(256)*the_sphere->Radius)>>16)+the_sphere->X; + offset_y = (-(COS(256)*the_sphere->Radius)>>16)+the_sphere->Y; + if ( + the_sphere->ShowSizeHook && + mouse_point.X>=offset_x-(SH_BOX_SIZE>>1) && + mouse_point.X>1) && + mouse_point.Y>=offset_y-(SH_BOX_SIZE>>1) && + mouse_point.Y>1) + ) + { + HilitedItem = the_sphere->EditRef; + } + break; + case BT_RECT_AREA: + break; + } + bucket = ((BucketGeneric*)bucket)->BucketPtr; + } + } + p--; + } + } +} + +//--------------------------------------------------------------- + +extern SLONG view_mode; +void draw_quad_bucket(struct BucketQuad *p_b,SLONG z); + +void GameEditor::RenderEngine(void) +{ + void *bucket; + ULONG c0, + draw_colour, + offset_x, + offset_y; + BucketHead *p; + BucketLine *the_line; + BucketMapThing *hilited_thing = NULL, + *selected_thing = NULL, + *the_map_thing; + BucketQuad *the_quad; + BucketRectArea *the_rect; + BucketSphereArea *hilited_sphere = NULL, + *the_sphere; + BucketTri *the_tri; + BucketWaypoint *hilited_waypoint, + *selected_wp, + *the_waypoint; + MFPoint local_point; + + + switch(WorkScreenDepth) + { + case 1: + render_span=render_span8; + break; + case 2: + render_span=render_span16; + break; + case 4: + render_span=render_span32; + break; + + } + + p = &bucket_heads[engine.BucketSize-1]; + for(c0=0;c0BucketPtr; + { + p->BucketPtr = 0; + while(bucket) + { + switch(((BucketGeneric*)bucket)->BucketType) + { + case BT_QUAD: + the_quad = (BucketQuad*)bucket; + if ( + the_quad->EditRef.ItemType==SelectedItem.ItemType && + the_quad->EditRef.ItemRef==SelectedItem.ItemRef && + FlashState + ) + { + poly_info.DrawFlags = the_quad->DrawFlags&(POLY_FLAG_DOUBLESIDED); + poly_info.Col = ACTIVE_COL; + } + else if( + the_quad->EditRef.ItemType==HilitedItem.ItemType && + the_quad->EditRef.ItemRef==HilitedItem.ItemRef && + SelectMode == 0 + ) + { + poly_info.DrawFlags = the_quad->DrawFlags&(POLY_FLAG_DOUBLESIDED); + poly_info.Col = HILITE_COL; + } + else + { + if(the_quad->DrawFlags&POLY_FLAG_TEXTURED) + { + poly_info.PTexture = tmaps[the_quad->TextPage]; //OOR + poly_info.Page = the_quad->TextPage; + } + poly_info.DrawFlags = the_quad->DrawFlags; + poly_info.Col = the_quad->Col; + } + + if(the_quad->DrawFlags&POLY_FLAG_DOUBLESIDED) + my_quad_noz(&the_quad->P[2],&the_quad->P[3],&the_quad->P[1],&the_quad->P[0]); + my_quad_noz(&the_quad->P[0],&the_quad->P[1],&the_quad->P[3],&the_quad->P[2]); + break; + case BT_TRI: + the_tri = (BucketTri*)bucket; + if ( + the_tri->EditRef.ItemType==SelectedItem.ItemType && + the_tri->EditRef.ItemRef==SelectedItem.ItemRef && + FlashState + ) + { + poly_info.DrawFlags = the_tri->DrawFlags&(POLY_FLAG_DOUBLESIDED); + poly_info.Col = ACTIVE_COL; + } + else if ( + the_tri->EditRef.ItemType==HilitedItem.ItemType && + the_tri->EditRef.ItemRef==HilitedItem.ItemRef && + SelectMode == 0 + ) + { + poly_info.DrawFlags = the_tri->DrawFlags&(POLY_FLAG_DOUBLESIDED); + poly_info.Col = HILITE_COL; + } + else + { + if(the_tri->DrawFlags&POLY_FLAG_TEXTURED) + { + poly_info.PTexture = tmaps[the_tri->TextPage]; //OOR + poly_info.Page = the_tri->TextPage; + } + poly_info.DrawFlags = the_tri->DrawFlags; + poly_info.Col = the_tri->Col; + } + if(the_tri->DrawFlags&POLY_FLAG_DOUBLESIDED) + my_trig_noz(&the_tri->P[2],&the_tri->P[1],&the_tri->P[0]); + my_trig_noz(&the_tri->P[0],&the_tri->P[1],&the_tri->P[2]); + break; + case BT_VECT: + break; + case BT_RECT: + break; + case BT_MAP_THING: + the_map_thing = (BucketMapThing*)bucket; + DrawVLineC(the_map_thing->BaseX,the_map_thing->Y,the_map_thing->BaseY,0xffff); + draw_colour = RED_COL; + + if ( + the_map_thing->EditRef.ItemType==HilitedItem.ItemType && + the_map_thing->EditRef.ItemRef==HilitedItem.ItemRef && + (SelectMode == 0 || (SelectMode>=SELECT_COND_TAB_THING && SelectMode<=SELECT_THING_TAB_SWITCH) || (SelectMode>=SELECT_COM_TAB_THING && SelectMode<=SELECT_COM_TAB_SWITCH)) + ) + { + draw_colour = HILITE_COL; + hilited_thing = the_map_thing; + } + else if ( + the_map_thing->EditRef.ItemType==SelectedItem.ItemType && + the_map_thing->EditRef.ItemRef==SelectedItem.ItemRef + ) + { + if(FlashState) + draw_colour = ACTIVE_COL; + selected_thing = the_map_thing; + } + + DrawBoxC( + the_map_thing->X-(THING_BOX_SIZE>>1), + the_map_thing->Y-(THING_BOX_SIZE>>1), + THING_BOX_SIZE, + THING_BOX_SIZE, + draw_colour + ); + + MapText ( + the_map_thing->X+(THING_BOX_SIZE>>1)+2, + the_map_thing->Y-(THING_BOX_SIZE>>1), + genus_text[map_things[the_map_thing->EditRef.ItemRef].Class][map_things[the_map_thing->EditRef.ItemRef].Genus], + 0xffff + ); + break; + case BT_WAYPOINT: + the_waypoint = (BucketWaypoint*)bucket; + DrawVLineC(the_waypoint->BaseX,the_waypoint->Y,the_waypoint->BaseY,0xffff); + draw_colour = GREEN_COL; + + if ( + the_waypoint->EditRef.ItemType==HilitedItem.ItemType && + the_waypoint->EditRef.ItemRef==HilitedItem.ItemRef && + (SelectMode==0 || SelectMode<=SELECT_PREV_WAYPOINT || SelectMode==SELECT_COM_TAB_WAYPOINT) + ) + { + draw_colour = HILITE_COL; + hilited_waypoint = the_waypoint; + } + else if ( + the_waypoint->EditRef.ItemType==SelectedItem.ItemType && + the_waypoint->EditRef.ItemRef==SelectedItem.ItemRef + ) + { + if(FlashState) + draw_colour = ACTIVE_COL; + selected_wp = the_waypoint; + } + DrawBoxC( + the_waypoint->X-(WP_BOX_SIZE>>1), + the_waypoint->Y-(WP_BOX_SIZE>>1), + WP_BOX_SIZE, + WP_BOX_SIZE, + draw_colour + ); + break; + case BT_LINE: + the_line = (BucketLine*)bucket; + DrawLineC(the_line->X1,the_line->Y1,the_line->X2,the_line->Y2,0xffff); + break; + case BT_SPHERE_AREA: + the_sphere = (BucketSphereArea*)bucket; + draw_colour = BLUE_COL; + + offset_x = ((SIN(256)*the_sphere->Radius)>>16)+the_sphere->X; + offset_y = (-(COS(256)*the_sphere->Radius)>>16)+the_sphere->Y; + + if ( + the_sphere->EditRef.ItemType==HilitedItem.ItemType && + the_sphere->EditRef.ItemRef==HilitedItem.ItemRef && + SelectMode == 0 + ) + { + draw_colour = HILITE_COL; + hilited_sphere = the_sphere; + } + DrawCircleC(the_sphere->X,the_sphere->Y,the_sphere->Radius,BLUE_COL); + DrawBoxC( + offset_x-(SH_BOX_SIZE>>1), + offset_y-(SH_BOX_SIZE>>1), + SH_BOX_SIZE, + SH_BOX_SIZE, + draw_colour + ); + break; + case BT_RECT_AREA: + + break; + } + bucket = ((BucketGeneric*)bucket)->BucketPtr; + } + } + p--; + } + + // Draw the info for a hilited item. + switch(HilitedItem.ItemType) + { + case ED_ITEM_NONE: + break; + case ED_ITEM_THING: + if(hilited_thing) + { + MapThingInfo( + hilited_thing->X+(THING_BOX_SIZE>>1)+2, + hilited_thing->Y-(THING_BOX_SIZE>>1)+12, + hilited_thing + ); + } + break; + case ED_ITEM_MAP_BLOCK: + break; + case ED_ITEM_BUILDING: + break; + case ED_ITEM_WAYPOINT: + if(hilited_waypoint) + { + MapWaypointInfo( + hilited_waypoint->X+(WP_BOX_SIZE>>1)+2, + hilited_waypoint->Y-(WP_BOX_SIZE>>1)+12, + hilited_waypoint + ); + } + break; + case ED_ITEM_SIZE_HOOK: + if(hilited_sphere) + { + MapSphereInfo ( + hilited_sphere->X+((SIN(256)*hilited_sphere->Radius)>>16)+(SH_BOX_SIZE>>1)+2, + hilited_sphere->Y-((COS(256)*hilited_sphere->Radius)>>16)+(SH_BOX_SIZE>>1), + hilited_sphere + ); + } + break; + } + + // Connect a line from the selected thing to the mouse pointer. + local_point.X = MouseX; + local_point.Y = MouseY; + if(PointInContent(&local_point)) + { + GlobalToLocal(&local_point); + if(selected_wp!=NULL) + switch(SelectMode) + { + case SELECT_NONE: + break; + case SELECT_WAYPOINT: + DrawLineC(selected_thing->X,selected_thing->Y,local_point.X,local_point.Y,0xffff); + break; + case SELECT_NEXT_WAYPOINT: + case SELECT_PREV_WAYPOINT: + DrawLineC(selected_wp->X,selected_wp->Y,local_point.X,local_point.Y,0xffff); + break; + } + } +} + +//--------------------------------------------------------------- + +void GameEditor::MapText(SLONG x,SLONG y,CBYTE *the_str,ULONG col) +{ + QuickTextC(x-1,y,the_str,0); + QuickTextC(x+1,y,the_str,0); + QuickTextC(x,y+1,the_str,0); + QuickTextC(x,y-1,the_str,0); + QuickTextC(x,y,the_str,col); +} + +//--------------------------------------------------------------- + +void GameEditor::MapThingInfo(SLONG x,SLONG y,BucketMapThing *the_map_thing) +{ + CBYTE info_text[256]; + EdRect info_rect; + + + info_rect.SetRect(x,y,100,50); + info_rect.FillRect(CONTENT_COL); + info_rect.HiliteRect(HILITE_COL,LOLITE_COL); + info_rect.ShrinkRect(2,2); + info_rect.HiliteRect(LOLITE_COL,HILITE_COL); + + sprintf(info_text,"Thing No: %ld",the_map_thing->EditRef.ItemRef); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+1,info_text,0xffff); + + sprintf(info_text,"MapX : %ld",map_things[the_map_thing->EditRef.ItemRef].X); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+11,info_text,0xffff); + + sprintf(info_text,"MapY : %ld",map_things[the_map_thing->EditRef.ItemRef].Z); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+21,info_text,0xffff); + + sprintf(info_text,"Alt : %ld",map_things[the_map_thing->EditRef.ItemRef].Y); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+31,info_text,0xffff); +} + +//--------------------------------------------------------------- + +void GameEditor::MapWaypointInfo(SLONG x,SLONG y,BucketWaypoint *the_waypoint) +{ + CBYTE info_text[256]; + EdRect info_rect; + + + info_rect.SetRect(x,y,100,50); + info_rect.FillRect(CONTENT_COL); + info_rect.HiliteRect(HILITE_COL,LOLITE_COL); + info_rect.ShrinkRect(2,2); + info_rect.HiliteRect(LOLITE_COL,HILITE_COL); + + sprintf(info_text,"Waypoint No: %ld",the_waypoint->EditRef.ItemRef); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+1,info_text,0xffff); + + sprintf(info_text,"MapX : %ld",edit_waypoints[the_waypoint->EditRef.ItemRef].X); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+11,info_text,0xffff); + + sprintf(info_text,"MapY : %ld",edit_waypoints[the_waypoint->EditRef.ItemRef].Z); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+21,info_text,0xffff); + + sprintf(info_text,"Alt : %ld",edit_waypoints[the_waypoint->EditRef.ItemRef].Y); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+31,info_text,0xffff); +} + +//--------------------------------------------------------------- + +void GameEditor::MapSphereInfo(SLONG x,SLONG y,BucketSphereArea *the_sphere) +{ + float radius; + CBYTE info_text[256]; + EdRect info_rect; + + + info_rect.SetRect(x,y,150,30); + info_rect.FillRect(CONTENT_COL); + info_rect.HiliteRect(HILITE_COL,LOLITE_COL); + info_rect.ShrinkRect(2,2); + info_rect.HiliteRect(LOLITE_COL,HILITE_COL); + + radius = map_things[the_sphere->EditRef.ItemRef].Data[0]/128.0; + sprintf(info_text,"Radius (in blocks) : %4.2f",radius); + MapText(info_rect.GetLeft()+1,info_rect.GetTop()+1,info_text,0xffff); +} + +//--------------------------------------------------------------- + +void GameEditor::ClearTabMode(void) +{ + switch(SelectMode) + { + case SELECT_COND_TAB_THING: + case SELECT_COND_TAB_SWITCH: + ConditionMode->SetTabMode(COND_MODE_NONE); + break; + case SELECT_THING_TAB_THING: + case SELECT_THING_TAB_SWITCH: + ThingMode->SetTabMode(THING_MODE_NONE); + break; + case SELECT_COM_TAB_WAYPOINT: + case SELECT_COM_TAB_THING: + case SELECT_COM_TAB_SWITCH: + CommandMode->SetTabMode(COM_MODE_NONE); + break; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/HmTab.cpp b/fallen/Editor/Source/HmTab.cpp new file mode 100644 index 0000000..c9e631b --- /dev/null +++ b/fallen/Editor/Source/HmTab.cpp @@ -0,0 +1,1589 @@ +// +// A simple editor for putting HM stuff around prims +// + +#include "Editor.hpp" +#include "EditMod.hpp" +#include "ModeTab.hpp" +#include "c:\fallen\headers\memory.h" + +#include "c:\fallen\headers\hm.h" + + +// +// The info for each prim. +// + +#define HMTAB_MAX_RES 8 + +typedef struct +{ + UBYTE x_res; + UBYTE y_res; + UBYTE z_res; + UBYTE defined; + + SLONG x_point[HMTAB_MAX_RES]; + SLONG y_point[HMTAB_MAX_RES]; + SLONG z_point[HMTAB_MAX_RES]; + + float x_dgrav; + float y_dgrav; + float z_dgrav; + +} HMTAB_Prim; + +#define HMTAB_MAX_PRIMS 256 + +HMTAB_Prim HMTAB_prim[HMTAB_MAX_PRIMS]; + +// +// The current prim. +// + +SLONG HMTAB_current_prim; + + + +// +// Stuff to help a 3d view. +// + +#define VD_CAM_VIEW_X 1 +#define VD_CAM_VIEW_Y 2 +#define VD_CAM_VIEW_Z 3 + +SLONG VD_window_mid_x; +SLONG VD_window_mid_y; +SLONG VD_window_half_w; +SLONG VD_window_half_h; + +SLONG VD_cam_view; +SLONG VD_cam_scale; +SLONG VD_cam_x; +SLONG VD_cam_y; +SLONG VD_cam_z; + + +// +// Returns the point on screen for the given 3d point. +// + +void VD_transform( + SLONG x_3d, + SLONG y_3d, + SLONG z_3d, + SLONG *x_2d, + SLONG *y_2d) +{ + SLONG xc; + SLONG yc; + + x_3d -= VD_cam_x; + y_3d -= VD_cam_y; + z_3d -= VD_cam_z; + + switch(VD_cam_view) + { + case VD_CAM_VIEW_X: + xc = z_3d; + yc = y_3d; + break; + + case VD_CAM_VIEW_Y: + xc = -z_3d; + yc = x_3d; + break; + + case VD_CAM_VIEW_Z: + xc = -x_3d; + yc = y_3d; + break; + + default: + ASSERT(0); + break; + } + + xc = MUL64(xc, VD_cam_scale); + yc = MUL64(yc, VD_cam_scale); + + *x_2d = VD_window_mid_x + MUL64(xc, VD_window_half_w); + *y_2d = VD_window_mid_y - MUL64(yc, VD_window_half_h); +} + + +// +// Only two out of the three 3d coordinates are filled in, depending on the +// view. +// + +void VD_untransform(SLONG x_2d, SLONG y_2d, SLONG *x_3d, SLONG *y_3d, SLONG *z_3d) +{ + SLONG xc; + SLONG yc; + + xc = DIV64( x_2d - VD_window_mid_x, VD_window_half_w); + yc = DIV64(-y_2d + VD_window_mid_y, VD_window_half_h); + + xc = DIV64(xc, VD_cam_scale); + yc = DIV64(yc, VD_cam_scale); + + switch(VD_cam_view) + { + case VD_CAM_VIEW_X: + *z_3d = xc; + *y_3d = yc; + break; + + case VD_CAM_VIEW_Y: + *z_3d = -xc; + *x_3d = yc; + break; + + case VD_CAM_VIEW_Z: + *x_3d = -xc; + *y_3d = yc; + break; + + default: + ASSERT(0); + break; + } + + *x_3d += VD_cam_x; + *y_3d += VD_cam_y; + *z_3d += VD_cam_z; +} + + +// +// Saves all the prims with interesting info. +// + +void HMTAB_save_primgrids(CBYTE *fname) +{ + SLONG i; + SLONG j; + + HMTAB_Prim *hp; + + HM_Header hm_h; + HM_Primgrid hm_pg; + + FILE *handle; + + handle = fopen(fname, "wb"); + + if (handle == NULL) + { + TRACE("Could not open file %s\n", fname); + + return; + } + + // + // Build the header. + // + + hm_h.version = 1; + hm_h.num_primgrids = 0; + + // + // Count how many primgrids we should save. + // + + for (i = 1; i < next_prim_object; i++) + { + hp = &HMTAB_prim[i]; + + if (hp->defined) + { + if (hp->x_res != 2 || + hp->y_res != 2 || + hp->z_res != 2 || + hp->x_point[0] != 0 || + hp->y_point[0] != 0 || + hp->z_point[0] != 0 || + hp->x_point[1] != 0x10000 || + hp->y_point[1] != 0x10000 || + hp->z_point[1] != 0x10000) + { + hm_h.num_primgrids += 1; + } + } + } + + // + // Save out the header. + // + + if (fwrite(&hm_h, sizeof(HM_Header), 1, handle) != 1) goto file_error; + + // + // Save out each HM_Primgrid in turn. + // + + for (i = 1; i < next_prim_object; i++) + { + hp = &HMTAB_prim[i]; + + if (hp->defined) + { + if (hp->x_res != 2 || + hp->y_res != 2 || + hp->z_res != 2 || + hp->x_point[0] != 0 || + hp->y_point[0] != 0 || + hp->z_point[0] != 0 || + hp->x_point[1] != 0x10000 || + hp->y_point[1] != 0x10000 || + hp->z_point[1] != 0x10000) + { + hm_pg.prim = i; + hm_pg.x_res = hp->x_res; + hm_pg.y_res = hp->y_res; + hm_pg.z_res = hp->z_res; + + for (j = 0; j < HM_MAX_RES; j++) + { + hm_pg.x_point[j] = hp->x_point[j]; + hm_pg.y_point[j] = hp->y_point[j]; + hm_pg.z_point[j] = hp->z_point[j]; + } + + hm_pg.x_dgrav = hp->x_dgrav; + hm_pg.y_dgrav = hp->y_dgrav; + hm_pg.z_dgrav = hp->z_dgrav; + + if (fwrite(&hm_pg, sizeof(HM_Primgrid), 1, handle) != 1) goto file_error; + } + } + } + + fclose(handle); + + return; + + file_error:; + + fclose(handle); + + TRACE("Error saving file %s\n", fname); + + return; +} + +void HMTAB_load_primgrids(CBYTE *fname) +{ + SLONG i; + SLONG j; + + HMTAB_Prim *hp; + + HM_Header hm_h; + HM_Primgrid hm_pg; + + FILE *handle; + + handle = fopen(fname, "rb"); + + if (handle == NULL) + { + TRACE("Could not open file %s\n", fname); + + return; + } + + // + // Load the header. + // + + if (fread(&hm_h, sizeof(HM_Header), 1, handle) != 1) goto file_error; + + if (hm_h.version != 1) + { + TRACE("File %s is an obsolete version\n", fname); + fclose(handle); + return; + } + + // + // Load in each HM_Primgrid in turn. + // + + for (i = 0; i < hm_h.num_primgrids; i++) + { + if (fread(&hm_pg, sizeof(HM_Primgrid), 1, handle) != 1) goto file_error; + + ASSERT(WITHIN(hm_pg.prim, 0, HMTAB_MAX_PRIMS)); + + hp = &HMTAB_prim[hm_pg.prim]; + + hp->defined = TRUE; + hp->x_res = hm_pg.x_res; + hp->y_res = hm_pg.y_res; + hp->z_res = hm_pg.z_res; + + for (j = 0; j < HM_MAX_RES; j++) + { + hp->x_point[j] = hm_pg.x_point[j]; + hp->y_point[j] = hm_pg.y_point[j]; + hp->z_point[j] = hm_pg.z_point[j]; + } + + hp->x_dgrav = hm_pg.x_dgrav; + hp->y_dgrav = hm_pg.y_dgrav; + hp->z_dgrav = hm_pg.z_dgrav; + } + + fclose(handle); + + return; + + file_error:; + + fclose(handle); + + TRACE("Error loading file %s\n", fname); + + return; +} + + + +// +// Draws a prim from the current camera. +// + +void HmTab::draw_prim(UWORD prim) +{ + ASSERT(WITHIN(prim, 1, next_prim_object - 1)); + + PrimObject *po = &prim_objects[prim]; + PrimPoint *pp1; + PrimPoint *pp2; + PrimFace3 *f3; + PrimFace4 *f4; + + SLONG i; + SLONG j; + SLONG p1; + SLONG p2; + SLONG sx1; + SLONG sy1; + SLONG sx2; + SLONG sy2; + + for (i = po->StartFace3; i < po->EndFace3; i++) + { + ASSERT(WITHIN(i, 1, next_prim_face3 - 1)); + + f3 = &prim_faces3[i]; + + for (j = 0; j < 3; j++) + { + p1 = f3->Points[(j + 0) % 3]; + p2 = f3->Points[(j + 1) % 3]; + + ASSERT(WITHIN(p1, 1, next_prim_point - 1)); + ASSERT(WITHIN(p2, 1, next_prim_point - 1)); + + pp1 = &prim_points[p1]; + pp2 = &prim_points[p2]; + + VD_transform( + pp1->X, + pp1->Y, + pp1->Z, + &sx1, + &sy1); + + VD_transform( + pp2->X, + pp2->Y, + pp2->Z, + &sx2, + &sy2); + + DrawLineC(sx1, sy1, sx2, sy2, RED_COL); + } + } + + static UBYTE line_order[4] = {0, 1, 3, 2}; + + for (i = po->StartFace4; i < po->EndFace4; i++) + { + ASSERT(WITHIN(i, 1, next_prim_face4 - 1)); + + f4 = &prim_faces4[i]; + + for (j = 0; j < 4; j++) + { + p1 = f4->Points[line_order[(j + 0) % 4]]; + p2 = f4->Points[line_order[(j + 1) % 4]]; + + ASSERT(WITHIN(p1, 1, next_prim_point - 1)); + ASSERT(WITHIN(p2, 1, next_prim_point - 1)); + + pp1 = &prim_points[p1]; + pp2 = &prim_points[p2]; + + VD_transform( + pp1->X, + pp1->Y, + pp1->Z, + &sx1, + &sy1); + + VD_transform( + pp2->X, + pp2->Y, + pp2->Z, + &sx2, + &sy2); + + DrawLineC(sx1, sy1, sx2, sy2, RED_COL); + } + } +} + +// +// Draw the lines for the given prim and returns the point the mouse is over, or +// -1 if the mouse isn't over any point. +// + +void HmTab::draw_grid(UWORD prim) +{ + SLONG i; + + SLONG x; + SLONG y; + + SLONG x1; + SLONG y1; + SLONG x2; + SLONG y2; + + SLONG px; + SLONG py; + SLONG pz; + + SLONG px1; + SLONG py1; + SLONG pz1; + SLONG px2; + SLONG py2; + SLONG pz2; + + SLONG gx1; + SLONG gy1; + SLONG gx2; + SLONG gy2; + + ASSERT(WITHIN(prim, 1, next_prim_object - 1)); + ASSERT(WITHIN(prim, 1, HMTAB_MAX_PRIMS - 1)); + + PrimInfo *pi = get_prim_info(prim); + PrimObject *po = &prim_objects [prim]; + HMTAB_Prim *hp = &HMTAB_prim [prim]; + + if (!hp->defined) + { + // + // We had better define it! + // + + hp->defined = TRUE; + + hp->x_res = 2; + hp->y_res = 2; + hp->z_res = 2; + + hp->x_point[0] = 0x00000; + hp->x_point[1] = 0x10000; + + hp->y_point[0] = 0x00000; + hp->y_point[1] = 0x10000; + + hp->z_point[0] = 0x00000; + hp->z_point[1] = 0x10000; + + hp->x_dgrav = 0.0F; + hp->y_dgrav = 0.0F; + hp->z_dgrav = 0.0F; + } + + // + // The size of the bounding box of the prim. + // + + SLONG bbdx = pi->maxx - pi->minx; + SLONG bbdy = pi->maxy - pi->miny; + SLONG bbdz = pi->maxz - pi->minz; + + ASSERT(WITHIN(hp->x_res, 2, HMTAB_MAX_RES)); + ASSERT(WITHIN(hp->y_res, 2, HMTAB_MAX_RES)); + ASSERT(WITHIN(hp->z_res, 2, HMTAB_MAX_RES)); + + // + // Work out the bounding box of the grid on the screen. + // + + px1 = pi->minx + MUL64(bbdx, hp->x_point[0]); + px2 = pi->minx + MUL64(bbdx, hp->x_point[hp->x_res - 1]); + + py1 = pi->miny + MUL64(bbdy, hp->y_point[0]); + py2 = pi->miny + MUL64(bbdy, hp->y_point[hp->y_res - 1]); + + pz1 = pi->minz + MUL64(bbdz, hp->z_point[0]); + pz2 = pi->minz + MUL64(bbdz, hp->z_point[hp->z_res - 1]); + + VD_transform(px1, py1, pz1, &gx1, &gy1); + VD_transform(px1, py2, pz2, &gx2, &gy2); + + if (VD_cam_view != VD_CAM_VIEW_X) + { + // + // Draw the grey grid. + // + + for (i = 0; i < hp->x_res; i++) + { + px = pi->minx + MUL64(bbdx, hp->x_point[i]); + + if (VD_cam_view == VD_CAM_VIEW_Y) + { + VD_transform(px, py1, pz1, &x1, &y1); + VD_transform(px, py1, pz2, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + } + else + { + ASSERT(VD_cam_view == VD_CAM_VIEW_Z); + + VD_transform(px, py1, pz1, &x1, &y1); + VD_transform(px, py2, pz1, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + } + } + + // + // Draw a line across the x-axis. + // + + VD_transform(px1, py1, pz1, &x1, &y1); + VD_transform(px2, py1, pz1, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + + // + // Draw all the points. + // + + for (i = 0; i < hp->x_res; i++) + { + px = pi->minx + MUL64(bbdx, hp->x_point[i]); + + VD_transform(px, py1, pz1, &x, &y); + + #define HMTAB_POINT_RADIUS 2 + + x1 = x - HMTAB_POINT_RADIUS; + y1 = y - HMTAB_POINT_RADIUS; + + x2 = x + HMTAB_POINT_RADIUS; + y2 = y + HMTAB_POINT_RADIUS; + + DrawLineC(x1, y1, x2, y1, WHITE_COL); + DrawLineC(x2, y1, x2, y2, WHITE_COL); + DrawLineC(x2, y2, x1, y2, WHITE_COL); + DrawLineC(x1, y2, x1, y1, WHITE_COL); + } + + // + // Label the axis. + // + + VD_transform(px2, py1, pz1, &x, &y); + + QuickTextC(x + 4, y, "X", GREEN_COL); + } + + if (VD_cam_view != VD_CAM_VIEW_Y) + { + // + // Draw the grey grid. + // + + for (i = 0; i < hp->y_res; i++) + { + py = pi->miny + MUL64(bbdy, hp->y_point[i]); + + if (VD_cam_view == VD_CAM_VIEW_X) + { + VD_transform(px1, py, pz1, &x1, &y1); + VD_transform(px1, py, pz2, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + } + else + { + ASSERT(VD_cam_view == VD_CAM_VIEW_Z); + + VD_transform(px1, py, pz1, &x1, &y1); + VD_transform(px2, py, pz1, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + } + } + + // + // Draw a line across the y-axis. + // + + VD_transform(px1, py1, pz1, &x1, &y1); + VD_transform(px1, py2, pz1, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + + // + // Draw all the points. + // + + for (i = 0; i < hp->y_res; i++) + { + py = pi->miny + MUL64(bbdy, hp->y_point[i]); + + VD_transform(px1, py, pz1, &x, &y); + + #define HMTAB_POINT_RADIUS 2 + + x1 = x - HMTAB_POINT_RADIUS; + y1 = y - HMTAB_POINT_RADIUS; + + x2 = x + HMTAB_POINT_RADIUS; + y2 = y + HMTAB_POINT_RADIUS; + + DrawLineC(x1, y1, x2, y1, WHITE_COL); + DrawLineC(x2, y1, x2, y2, WHITE_COL); + DrawLineC(x2, y2, x1, y2, WHITE_COL); + DrawLineC(x1, y2, x1, y1, WHITE_COL); + } + + // + // Label the axis. + // + + VD_transform(px1, py2, pz1, &x, &y); + + QuickTextC(x + 4, y, "Y", GREEN_COL); + } + + if (VD_cam_view != VD_CAM_VIEW_Z) + { + // + // Draw the grey grid. + // + + for (i = 0; i < hp->z_res; i++) + { + pz = pi->minz + MUL64(bbdz, hp->z_point[i]); + + if (VD_cam_view == VD_CAM_VIEW_Y) + { + VD_transform(px1, py1, pz, &x1, &y1); + VD_transform(px2, py1, pz, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + } + else + { + ASSERT(VD_cam_view == VD_CAM_VIEW_X); + + VD_transform(px1, py1, pz, &x1, &y1); + VD_transform(px1, py2, pz, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + } + } + + // + // Draw a line across the z-axis. + // + + VD_transform(px1, py1, pz1, &x1, &y1); + VD_transform(px1, py1, pz2, &x2, &y2); + + DrawLineC(x1,y1, x2,y2, GREY_COL); + + // + // Draw all the points. + // + + for (i = 0; i < hp->z_res; i++) + { + pz = pi->minz + MUL64(bbdz, hp->z_point[i]); + + VD_transform(px1, py1, pz, &x, &y); + + #define HMTAB_POINT_RADIUS 2 + + x1 = x - HMTAB_POINT_RADIUS; + y1 = y - HMTAB_POINT_RADIUS; + + x2 = x + HMTAB_POINT_RADIUS; + y2 = y + HMTAB_POINT_RADIUS; + + DrawLineC(x1, y1, x2, y1, WHITE_COL); + DrawLineC(x2, y1, x2, y2, WHITE_COL); + DrawLineC(x2, y2, x1, y2, WHITE_COL); + DrawLineC(x1, y2, x1, y1, WHITE_COL); + } + + // + // Label the axis. + // + + VD_transform(px1, py1, pz2, &x, &y); + + QuickTextC(x + 4, y, "Z", GREEN_COL); + } +} + +void HmTab::draw_cog(UWORD prim) +{ + UBYTE hm_index; + + SLONG x; + SLONG y; + + float cog_x; + float cog_y; + float cog_z; + + ASSERT(WITHIN(prim, 1, next_prim_object - 1)); + ASSERT(WITHIN(prim, 1, HMTAB_MAX_PRIMS - 1)); + + PrimInfo *pi = get_prim_info(prim); + PrimObject *po = &prim_objects [prim]; + HMTAB_Prim *hp = &HMTAB_prim [prim]; + + if (!hp->defined) + { + // + // We had better define it! + // + + hp->defined = TRUE; + + hp->x_res = 2; + hp->y_res = 2; + hp->z_res = 2; + + hp->x_point[0] = 0x00000; + hp->x_point[1] = 0x10000; + + hp->y_point[0] = 0x00000; + hp->y_point[1] = 0x10000; + + hp->z_point[0] = 0x00000; + hp->z_point[1] = 0x10000; + + hp->x_dgrav = 0.0F; + hp->y_dgrav = 0.0F; + hp->z_dgrav = 0.0F; + } + + // + // Create a hypermatter object. + // + + hm_index = HM_create( + prim, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + hp->x_res, + hp->y_res, + hp->z_res, + hp->x_point, + hp->y_point, + hp->z_point, + hp->x_dgrav, + hp->y_dgrav, + hp->z_dgrav, + 0.0F, 0.0F, 0.0F, 0.0F); + + if (hm_index != HM_NO_MORE_OBJECTS) + { + // + // Find its centre of gravity. + // + + HM_find_cog( + hm_index, + &cog_x, + &cog_y, + &cog_z); + + // + // Draw the cog. + // + + VD_transform( + SLONG(cog_x), + SLONG(cog_y), + SLONG(cog_z), + &x, + &y); + + #define HMTAB_COG_SIZE 8 + + DrawLineC(x, y, x + HMTAB_COG_SIZE, y, GREEN_COL); + DrawLineC(x, y, x - HMTAB_COG_SIZE, y, GREEN_COL); + DrawLineC(x, y, x, y + HMTAB_COG_SIZE, GREEN_COL); + DrawLineC(x, y, x, y - HMTAB_COG_SIZE, GREEN_COL); + + // + // Destroy the hm_object. + // + + HM_destroy(hm_index); + } +} + +// +// Looks for a point in the given HMTAB_prim that is close to the +// mouse and moves it to the mouse position. +// +// (mouse_x, mouse_y) should be in window coordinates. Returns TRUE +// if it was close enough to change a point. +// + +SLONG move_point(UWORD prim, SLONG mouse_x, SLONG mouse_y) +{ + SLONG i; + + SLONG px1; + SLONG py1; + SLONG pz1; + SLONG px2; + SLONG py2; + SLONG pz2; + + SLONG mx; + SLONG my; + SLONG mz; + + SLONG px; + SLONG py; + SLONG pz; + + SLONG x; + SLONG y; + + SLONG dx; + SLONG dy; + SLONG dist; + SLONG change = FALSE; + + ASSERT(WITHIN(prim, 1, next_prim_object - 1)); + ASSERT(WITHIN(prim, 1, HMTAB_MAX_PRIMS - 1)); + + PrimInfo *pi = get_prim_info(prim); + PrimObject *po = &prim_objects [prim]; + HMTAB_Prim *hp = &HMTAB_prim [prim]; + + if (!hp->defined) + { + // + // We had better define it! + // + + hp->defined = TRUE; + + hp->x_res = 2; + hp->y_res = 2; + hp->z_res = 2; + + hp->x_point[0] = 0x00000; + hp->x_point[1] = 0x10000; + + hp->y_point[0] = 0x00000; + hp->y_point[1] = 0x10000; + + hp->z_point[0] = 0x00000; + hp->z_point[1] = 0x10000; + + hp->x_dgrav = 0.0F; + hp->y_dgrav = 0.0F; + hp->z_dgrav = 0.0F; + } + + // + // Where the mouse is in 3d + // + + VD_untransform(mouse_x, mouse_y, &mx, &my, &mz); + + // + // The size of the bounding box of the prim. + // + + SLONG bbdx = pi->maxx - pi->minx; + SLONG bbdy = pi->maxy - pi->miny; + SLONG bbdz = pi->maxz - pi->minz; + + ASSERT(WITHIN(hp->x_res, 2, HMTAB_MAX_RES)); + ASSERT(WITHIN(hp->y_res, 2, HMTAB_MAX_RES)); + ASSERT(WITHIN(hp->z_res, 2, HMTAB_MAX_RES)); + + // + // Work out the bounding box of the grid. + // + + px1 = pi->minx + MUL64(bbdx, hp->x_point[0]); + px2 = pi->minx + MUL64(bbdx, hp->x_point[hp->x_res - 1]); + + py1 = pi->miny + MUL64(bbdy, hp->y_point[0]); + py2 = pi->miny + MUL64(bbdy, hp->y_point[hp->y_res - 1]); + + pz1 = pi->minz + MUL64(bbdz, hp->z_point[0]); + pz2 = pi->minz + MUL64(bbdz, hp->z_point[hp->z_res - 1]); + + if (VD_cam_view != VD_CAM_VIEW_X) + { + for (i = 0; i < hp->x_res; i++) + { + px = pi->minx + MUL64(bbdx, hp->x_point[i]); + + VD_transform(px, py1, pz1, &x, &y); + + dx = abs(x - mouse_x); + dy = abs(y - mouse_y); + + dist = dx + dy; + + if (dist <= 9) + { + // + // Move the point to the position of the mouse. + // + + hp->x_point[i] = DIV64(mx - pi->minx, bbdx); + + change = TRUE; + } + } + } + + if (VD_cam_view != VD_CAM_VIEW_Y) + { + for (i = 0; i < hp->y_res; i++) + { + py = pi->miny + MUL64(bbdy, hp->y_point[i]); + + VD_transform(px1, py, pz1, &x, &y); + + dx = abs(x - mouse_x); + dy = abs(y - mouse_y); + + dist = dx + dy; + + if (dist <= 9) + { + // + // Move the point to the position of the mouse. + // + + hp->y_point[i] = DIV64(my - pi->miny, bbdy); + + change = TRUE; + } + } + } + + if (VD_cam_view != VD_CAM_VIEW_Z) + { + for (i = 0; i < hp->z_res; i++) + { + pz = pi->minz + MUL64(bbdz, hp->z_point[i]); + + VD_transform(px1, py1, pz, &x, &y); + + dx = abs(x - mouse_x); + dy = abs(y - mouse_y); + + dist = dx + dy; + + if (dist <= 9) + { + // + // Move the point to the position of the mouse. + // + + hp->z_point[i] = DIV64(mz - pi->minz, bbdz); + + change = TRUE; + } + } + } + + // + // Make sure that no point of the prim lies outside the hypermatter. + // + + if (hp->x_point[0] > 0) {hp->x_point[0] = 0;} + if (hp->y_point[0] > 0) {hp->y_point[0] = 0;} + if (hp->z_point[0] > 0) {hp->z_point[0] = 0;} + + if (hp->x_point[hp->x_res - 1] < 0x10000) {hp->x_point[hp->x_res - 1] = 0x10000;} + if (hp->y_point[hp->y_res - 1] < 0x10000) {hp->y_point[hp->y_res - 1] = 0x10000;} + if (hp->z_point[hp->z_res - 1] < 0x10000) {hp->z_point[hp->z_res - 1] = 0x10000;} + + return change; +} + + + + + +// +// The buttons in the Tab. +// + +#define CTRL_NEXT_PRIM 1 +#define CTRL_PREV_PRIM 2 + +#define CTRL_RES_X_UP 3 +#define CTRL_RES_X_DOWN 4 +#define CTRL_RES_Y_UP 5 +#define CTRL_RES_Y_DOWN 6 +#define CTRL_RES_Z_UP 7 +#define CTRL_RES_Z_DOWN 8 + +#define CTRL_GRAV_U 9 +#define CTRL_GRAV_D 10 +#define CTRL_GRAV_L 11 +#define CTRL_GRAV_R 12 + +#define CTRL_GRAV_CENTRE 13 + +#define CTRL_SAVE 14 + +ControlDef HMTab_def[] = +{ + {BUTTON, 0, "Next Prim", 10, 20}, + {BUTTON, 0, "Prev Prim", 10, 35}, + + {BUTTON, 0, "X res UP", 10, 60}, + {BUTTON, 0, "X res DOWN", 10, 75}, + + {BUTTON, 0, "Y res UP", 90, 60}, + {BUTTON, 0, "Y res DOWN", 90, 75}, + + {BUTTON, 0, "Z res UP", 170, 60}, + {BUTTON, 0, "Z res DOWN", 170, 75}, + + {BUTTON, 0, "U", 100, 100}, + {BUTTON, 0, "D", 100, 130}, + {BUTTON, 0, "L", 72, 115}, + {BUTTON, 0, "R", 128, 115}, + + {BUTTON, 0, "CENTRE", 85, 115}, + + {BUTTON, 0, "Save", 10, 200}, + + {0} +}; + +// +// The parent of this tab. +// + +EditorModule *HMTAB_parent; + + +HmTab::HmTab(EditorModule *parent) +{ + // + // Install our buttons. + // + + InitControlSet(HMTab_def); + + // + // Set the default camera. + // + + VD_cam_view = VD_CAM_VIEW_X; + VD_cam_x = 0; + VD_cam_y = 0; + VD_cam_z = 0; + VD_cam_scale = 0xa00000; + + // + // Set the default prim. + // + + HMTAB_current_prim = PRIM_OBJ_SOFA; + + // + // Remember our parent, so we can ask her to + // do stuff to us. + // + + HMTAB_parent = parent; + + // + // Load all the primgrid stuff... + // + + HMTAB_load_primgrids("data\\primgrid.dat"); +} + +HmTab::~HmTab() +{ +} + + + +void HmTab::DrawTabContent() +{ + EdRect content_rect; + + // + // Fill with the standard colour. + // + + content_rect = ContentRect; + content_rect.ShrinkRect(1,1); + content_rect.FillRect(CONTENT_COL); + + // + // Draw the buttons. + // + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); +} + +void HmTab::HandleTab(MFPoint *current_point) +{ + SLONG change = FALSE; + + // + // Do the buttons. + // + + HandleControlSet(current_point); + + // + // Do the keyboard. + // + + if (Keys[KB_HOME]) {VD_cam_scale += 0x30000; change = TRUE;} + if (Keys[KB_END ]) {VD_cam_scale -= 0x30000; change = TRUE;} + + SATURATE(VD_cam_scale, 0x800000, 0x4000000); + + if (Keys[KB_TAB]) + { + Keys[KB_TAB] = 0; + + switch(VD_cam_view) + { + case VD_CAM_VIEW_X: VD_cam_view = VD_CAM_VIEW_Y; break; + case VD_CAM_VIEW_Y: VD_cam_view = VD_CAM_VIEW_Z; break; + case VD_CAM_VIEW_Z: VD_cam_view = VD_CAM_VIEW_X; break; + default: + ASSERT(0); + break; + } + + change = TRUE; + } + + if (change) + { + // + // Redraw ourselves.. + // + + RedrawModuleContent = TRUE; + RequestUpdate(); + } +} + +UWORD HmTab::HandleTabClick(UBYTE flags, MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + MFPoint local_point; + + // + // This is a fudge to update the front screen buffer. + // + + ShowWorkScreen(0); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + + // + // Where in the tab is the click? + // + + local_point = *clicked_point; + GlobalToLocal(&local_point); + + // + // Go through all the controls in the tab and see if we have clicked on any of them. + // + + current_control = GetControlList(); + + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // + // A click on this button. + // + + control_id = current_control->TrackControl(&local_point); + + HandleControl(control_id); + + // + // Tidy up display. + // + + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + + ShowWorkWindow(0); + + return control_id; + } + + current_control = current_control->GetNextControl(); + } + + break; + case RIGHT_CLICK: + break; + } + + return 0; +} + +void HmTab::HandleControl(UWORD control_id) +{ + SLONG i; + + SLONG old_x_res; + SLONG old_y_res; + SLONG old_z_res; + + float dup; + float dright; + + SLONG mul; + + ASSERT(WITHIN(HMTAB_current_prim, 1, HMTAB_MAX_PRIMS - 1)); + + HMTAB_Prim *hp = &HMTAB_prim[HMTAB_current_prim]; + + old_x_res = hp->x_res; + old_y_res = hp->y_res; + old_z_res = hp->z_res; + + dup = 0.0F; + dright = 0.0F; + + #define HMTAB_DGRAV (0.1F) + + switch(control_id) + { + case CTRL_NEXT_PRIM: HMTAB_current_prim += 1; break; + case CTRL_PREV_PRIM: HMTAB_current_prim -= 1; break; + + case CTRL_RES_X_UP: hp->x_res += 1; break; + case CTRL_RES_X_DOWN: hp->x_res -= 1; break; + + case CTRL_RES_Y_UP: hp->y_res += 1; break; + case CTRL_RES_Y_DOWN: hp->y_res -= 1; break; + + case CTRL_RES_Z_UP: hp->z_res += 1; break; + case CTRL_RES_Z_DOWN: hp->z_res -= 1; break; + + case CTRL_GRAV_U: dup = +HMTAB_DGRAV; break; + case CTRL_GRAV_D: dup = -HMTAB_DGRAV; break; + + case CTRL_GRAV_R: dright = +HMTAB_DGRAV; break; + case CTRL_GRAV_L: dright = -HMTAB_DGRAV; break; + + case CTRL_GRAV_CENTRE: + hp->x_dgrav = 0.0F; + hp->y_dgrav = 0.0F; + hp->z_dgrav = 0.0F; + break; + + case CTRL_SAVE: HMTAB_save_primgrids("data\\primgrid.dat"); break; + + default: + ASSERT(0); + break; + } + + switch(VD_cam_view) + { + case VD_CAM_VIEW_X: + hp->z_dgrav += dright; + hp->y_dgrav += dup; + break; + + case VD_CAM_VIEW_Y: + hp->z_dgrav -= dright; + hp->x_dgrav += dup; + break; + + case VD_CAM_VIEW_Z: + hp->x_dgrav -= dright; + hp->y_dgrav += dup; + break; + + default: + ASSERT(0); + break; + } + + SATURATE(hp->x_res, 2, HMTAB_MAX_RES - 1); + SATURATE(hp->y_res, 2, HMTAB_MAX_RES - 1); + SATURATE(hp->z_res, 2, HMTAB_MAX_RES - 1); + + if (old_x_res != hp->x_res) + { + // + // We have to squeeze the old points into a smaller area or + // the old points into a bigger area. + // + + mul = DIV64(old_x_res - 1, hp->x_res - 1); + + for (i = 0; i < old_x_res; i++) + { + hp->x_point[i] = MUL64(hp->x_point[i], mul); + } + + if (hp->x_res > old_x_res) + { + hp->x_point[hp->x_res - 1] = 0x10000; + } + } + + if (old_y_res != hp->y_res) + { + // + // We have to squeeze the old points into a smaller area or + // the old points into a bigger area. + // + + mul = DIV64(old_y_res - 1, hp->y_res - 1); + + for (i = 0; i < old_y_res; i++) + { + hp->y_point[i] = MUL64(hp->y_point[i], mul); + } + + if (hp->y_res > old_y_res) + { + hp->y_point[hp->y_res - 1] = 0x10000; + } + } + + if (old_z_res != hp->z_res) + { + // + // We have to squeeze the old points into a smaller area or + // the old points into a bigger area. + // + + mul = DIV64(old_z_res - 1, hp->z_res - 1); + + for (i = 0; i < old_z_res; i++) + { + hp->z_point[i] = MUL64(hp->z_point[i], mul); + } + + if (hp->z_res > old_z_res) + { + hp->z_point[hp->z_res - 1] = 0x10000; + } + } + + // + // In case we have changed the current prim. + // + + { + SATURATE(HMTAB_current_prim, 1, next_prim_object - 1); + + ASSERT(WITHIN(HMTAB_current_prim, 1, HMTAB_MAX_PRIMS - 1)); + + HMTAB_Prim *hp = &HMTAB_prim[HMTAB_current_prim]; + + if (!hp->defined) + { + hp->defined = 1; + + hp->x_res = 2; + hp->y_res = 2; + hp->z_res = 2; + + hp->x_point[0] = 0x00000; + hp->x_point[1] = 0x10000; + + hp->y_point[0] = 0x00000; + hp->y_point[1] = 0x10000; + + hp->z_point[0] = 0x00000; + hp->z_point[1] = 0x10000; + } + } + + // + // Make sure that no point of the prim lies outside the hypermatter. + // + + if (hp->x_point[0] > 0) {hp->x_point[0] = 0;} + if (hp->y_point[0] > 0) {hp->y_point[0] = 0;} + if (hp->z_point[0] > 0) {hp->z_point[0] = 0;} + + if (hp->x_point[hp->x_res - 1] < 0x10000) {hp->x_point[hp->x_res - 1] = 0x10000;} + if (hp->y_point[hp->y_res - 1] < 0x10000) {hp->y_point[hp->y_res - 1] = 0x10000;} + if (hp->z_point[hp->z_res - 1] < 0x10000) {hp->z_point[hp->z_res - 1] = 0x10000;} + + RedrawModuleContent = TRUE; + RequestUpdate(); +} + +void HmTab::DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) +{ + // + // To begin with... + // + + SLONG wwx; + SLONG wwy; + SLONG www; + SLONG wwh; + + SLONG over_x; + SLONG over_y; + SLONG over_z; + + EdRect drawrect; + + RedrawModuleContent=0; + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + SetWorkWindowBounds(x,y,w-1,h-1); + drawrect.SetRect(0,0,w-1,h-1); + drawrect.FillRect(CONTENT_COL_BR); + + // + // Actaul drawing we want to do. + // + + QuickTextC(10, 10, "Hi Guys!", WHITE_COL); + + VD_window_mid_x = w / 2; + VD_window_mid_y = h / 2; + + VD_window_half_w = w / 2; + VD_window_half_h = h / 2; + + draw_prim(HMTAB_current_prim); + draw_grid(HMTAB_current_prim); + draw_cog (HMTAB_current_prim); + + // + // To end with... + // + + SetWorkWindowBounds(wwx, wwy, www, wwh); // Restore clip rectangle. + +} + +SLONG HmTab::HandleModuleContentClick(MFPoint *clicked_point, UBYTE flags, SLONG x, SLONG y, SLONG w, SLONG h) +{ + SLONG mouse_x; + SLONG mouse_y; + + TRACE("clicked_point = (%d,%d)\n", clicked_point->X, clicked_point->Y); + + mouse_x = MouseX - x; + mouse_y = MouseY - y; + + while(move_point(HMTAB_current_prim, mouse_x, mouse_y)) + { + SLONG wwx = WorkWindowRect.Left; + SLONG wwy = WorkWindowRect.Top; + SLONG www = WorkWindowRect.Width; + SLONG wwh = WorkWindowRect.Height; + + SetWorkWindowBounds(x, y, w - 1, h - 1); + + DrawModuleContent (x + 1, y + 1, w, h); + SetWorkWindowBounds(x + 1, y + 1, w, h); + ShowWorkWindow(0); + + if (SHELL_ACTIVE && (LeftButton || RightButton)) + { + // + // The new mouse position... + // + + mouse_x = MouseX - x; + mouse_y = MouseY - y; + } + else + { + // + // Stop dragging. + // + + SetWorkWindowBounds(wwx,wwy,www,wwh); + } + } + + RedrawModuleContent = TRUE; + RequestUpdate(); + + return 0; +} + + + + + + + + + diff --git a/fallen/Editor/Source/Icon.cpp b/fallen/Editor/Source/Icon.cpp new file mode 100644 index 0000000..ef08b64 --- /dev/null +++ b/fallen/Editor/Source/Icon.cpp @@ -0,0 +1,85 @@ +// Icon.cpp +// Mike Diskett, 11th April 1997. + + +#include "Editor.hpp" + +#ifdef EDITOR + +#define ICON_WIDTH 20 +#define ICON_HEIGHT 20 + +//--------------------------------------------------------------- + +void WinBarIcon::DrawIcons(void) +{ + EdRect box_it; + SLONG c0=0; + SLONG x; + + if(WindowIcons) + { + x=GetRight(); + while(WindowIcons[c0].ImageOff) + { + if(WindowIcons[c0].ImageOff==-1) + { + x-=8; + box_it.SetRect(x,GetTop()-2,4,27); + box_it.HiliteRect(HILITE_COL,LOLITE_COL); + + } + else + { + x-=ICON_WIDTH+4; + box_it.SetRect(x,GetTop()+2,ICON_WIDTH,ICON_HEIGHT); + box_it.HiliteRect(HILITE_COL,LOLITE_COL); + if(WindowIcons[c0].Flag) + DrawBSprite(box_it.GetLeft(),box_it.GetTop(),INTERFACE_SPRITE(WindowIcons[c0].ImageOn)); + else + DrawBSprite(box_it.GetLeft(),box_it.GetTop(),INTERFACE_SPRITE(WindowIcons[c0].ImageOff)); +// DrawMonoBSprite(box_it.GetLeft(),box_it.GetTop(),INTERFACE_SPRITE(WindowIcons[c0].ImageOff),0); + } + c0++; + } + } +} +void WinBarIcon::HandleIconClick(UBYTE flags,MFPoint *clicked_point) +{ + EdRect box_it; + SLONG c0=0; + SLONG x; + + if(WindowIcons) + { + x=GetRight(); + while(WindowIcons[c0].ImageOff) + { + if(WindowIcons[c0].ImageOff==-1) + { + x-=8; + } + else + { + x-=ICON_WIDTH+4; + box_it.SetRect(x,GetTop()+2,ICON_WIDTH,ICON_HEIGHT); + if(box_it.PointInRect(clicked_point)) + { + //we have a click on an icon + WindowIcons[c0].Flag^=1; + if(WindowIcons[c0].Function) + WindowIcons[c0].Function(c0); + + } + } + c0++; + } + } +} + +void WinBarIcon::InitIcons(struct AWindowIcon *p_icons) +{ + WindowIcons=p_icons; +} + +#endif diff --git a/fallen/Editor/Source/Intrface.cpp b/fallen/Editor/Source/Intrface.cpp new file mode 100644 index 0000000..95062e8 --- /dev/null +++ b/fallen/Editor/Source/Intrface.cpp @@ -0,0 +1,150 @@ +// Intrface.cpp +// Guy Simmons, 26th October 1996. + +#include "Editor.hpp" + +#ifdef EDITOR + +//**************************************************************************** + +Interface::Interface() +{ + interface_sprite_data = 0; + interface_sprites = 0; +} + +//**************************************************************************** + +Interface::~Interface() +{ + if(interface_sprite_data) + MemFree(interface_sprite_data); + if(interface_sprites) + MemFree(interface_sprites); +} + +//**************************************************************************** + +void Interface::SetupInterfaceDefaults(void) +{ + SLONG blue, + green, + red; + SLONG file_size; + MFFileHandle file_handle; + + + memset(InterfacePalette,0,3*256); + FileLoadAt("Editor\\Data\\palette.pal",InterfacePalette); + + +#ifdef _DEBUG + { + SLONG c0; + for(c0=0;c0<256*3;c0++) + { + LogText(" pal c0 %d \n",c0); + red = InterfacePalette[(c0)]; + red+=32; + if(red>255) + red=255; + InterfacePalette[(c0)]=red; + } + } +#endif + SetPalette(InterfacePalette); + + ContentColourBr = FindColour(InterfacePalette,115+20,128+20,156+20); + ContentColour = FindColour(InterfacePalette,115,128,156); + TextColour = FindColour(InterfacePalette,256,256,256); + HiliteColour = FindColour(InterfacePalette,115+30,128+30,156+30); + LoliteColour = FindColour(InterfacePalette,115-20,128-20,156-20); + SelectColour = FindColour(InterfacePalette,115+10,128+10,156+10); + ActiveColour = FindColour((UBYTE*)InterfacePalette,130,130,130); + WhiteColour = FindColour((UBYTE*)InterfacePalette,255,255,255); + GreyColour = FindColour((UBYTE*)InterfacePalette,128,128,128); + YellowColour = FindColour((UBYTE*)InterfacePalette,255,255,0); + RedColour = FindColour((UBYTE*)InterfacePalette,255,0,0); + GreenColour = FindColour((UBYTE*)InterfacePalette,0,255,0); + BlueColour = FindColour((UBYTE*)InterfacePalette,0,0,255); + + InactiveColour = ContentColour; + + file_handle = FileOpen("Editor\\Data\\intrface.spr"); + ERROR_MSG(!(file_handle==FILE_OPEN_ERROR),"Can't open sprite ref file."); + if(file_handle!=FILE_OPEN_ERROR) + { + file_size = FileSize(file_handle); + interface_sprites = (BSprite*)MemAlloc(file_size); + if(interface_sprites) + { + FileRead(file_handle,interface_sprites,file_size); + } + FileClose(file_handle); + } + + file_handle = FileOpen("Editor\\Data\\intrface.spd"); + ERROR_MSG(!(file_handle==FILE_OPEN_ERROR),"Can't open sprite data file."); + if(file_handle!=FILE_OPEN_ERROR) + { + file_size = FileSize(file_handle); + interface_sprite_data = (UBYTE*)MemAlloc(file_size); + if(interface_sprite_data) + { + FileRead(file_handle,interface_sprite_data,file_size); + } + FileClose(file_handle); + } + + if(interface_sprites && interface_sprite_data) + SetupBSprites(interface_sprites,interface_sprite_data); +/* + { + Alert *quit_alert; + quit_alert = new Alert; + editor_status = !quit_alert->HandleAlert("Gourad People|Stand on Feet"); + delete quit_alert; + } +*/ + +/* + red = 58; + green = 58; + blue = 58; + ActiveColour = 20; //FindColor(palette,red,green,blue); + + InactiveColour = ContentColour; + + interface_data[0].Start = (void**)&interface_sprites; + interface_data[0].SEnd = (void**)&end_interface_sprites; + interface_data[1].Start = (void**)&interface_sprite_data; + interface_data[2].Start = (void**)&interface_pointers; + interface_data[2].SEnd = (void**)&end_interface_pointers; + interface_data[3].Start = (void**)&interface_pointer_data; + interface_data[4].Start = (void**)&interface_font; + interface_data[4].SEnd = (void**)&end_interface_font; + interface_data[5].Start = (void**)&interface_font_data; + LoadAllData(&interface_data[0]); + + setup_interface_sprites[0].Start = &interface_sprites; + setup_interface_sprites[0].End = &end_interface_sprites; + setup_interface_sprites[0].Data = &interface_sprite_data; + setup_interface_sprites[1].Start = &interface_pointers; + setup_interface_sprites[1].End = &end_interface_pointers; + setup_interface_sprites[1].Data = &interface_pointer_data; + setup_interface_sprites[2].Start = &interface_font; + setup_interface_sprites[2].End = &end_interface_font; + setup_interface_sprites[2].Data = &interface_font_data; + SetupAllSprites(setup_interface_sprites); + + SetFont(interface_font); +*/ +} + +//**************************************************************************** + +Interface *InterfaceDefaults; + +//**************************************************************************** + +#endif diff --git a/fallen/Editor/Source/KFDef.c b/fallen/Editor/Source/KFDef.c new file mode 100644 index 0000000..8d8427d --- /dev/null +++ b/fallen/Editor/Source/KFDef.c @@ -0,0 +1,44 @@ +// KFDef.c +// Guy Simmons, 24th March 1997. + + +//--------------------------------------------------------------- +/* +ControlDef kframe_def[] = +{ + { BUTTON, 0, "Load Keyframe Chunk", 2, CONTROLS_HEIGHT-(20+KEY_FRAME_IMAGE_SIZE+20), 0, 10 }, + { H_SLIDER, 0, "", 2, CONTROLS_HEIGHT-20, 6*KEY_FRAME_IMAGE_SIZE, 0 }, + { BUTTON, 0, "New Character", 2, 4, 0, 0 }, + { V_SLIDER, 0, "", 104,20, 0, 200 }, + { EDIT_TEXT, 0, "", 2, 230, 70, 0 }, + { STATIC_TEXT, 0, "Current Prim : ", 2, 246, 0, 0 }, + { PULLDOWN_MENU, 0, "Multi Prim", 2, 262, 70, 0, 0 }, + + { 0 } +}; + +//--------------------------------------------------------------- + +ControlDef content_def[] = +{ + { H_SLIDER, 0, "", 0, CONTROLS_HEIGHT-16, 6*KEY_FRAME_IMAGE_SIZE, 0 }, + { STATIC_TEXT, 0, "FPS", 2, CONTROLS_HEIGHT-(16+KEY_FRAME_IMAGE_SIZE+16), 0, 10 }, + { H_SLIDER, 0, "", 22, CONTROLS_HEIGHT-(16+KEY_FRAME_IMAGE_SIZE+18), 100, 0 }, + { BUTTON, 0, "New Anim", 2, 4, 0, 0 }, + { V_SLIDER, 0, "", 104,20, 0, 200 }, + { EDIT_TEXT, 0, "", 2, 230, 70, 0 }, + { CHECK_BOX, KB_L, "Looped", 2, 246, 70, 0 }, + { BUTTON, 0, "Lo-res test", 2, 260, 70, 0 }, + { BUTTON, 0, "Save Anims", 2, 276, 70, 0 }, + + { 0 } +}; +*/ +//--------------------------------------------------------------- + +MenuDef2 anim_popup[] = +{ + {"Cut"},{"Copy"},{"Paste"},{"Toggle Unused"},{"!"} +}; + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/KFDef2.c b/fallen/Editor/Source/KFDef2.c new file mode 100644 index 0000000..2d68774 --- /dev/null +++ b/fallen/Editor/Source/KFDef2.c @@ -0,0 +1,15 @@ +// KFDef2.c +// Guy Simmons, 20th September 1997. + + +//--------------------------------------------------------------- + +ControlDef kframe_ctrls_def[] = +{ + { BUTTON, 0, "Load Keyframe Chunk", 2, 2, 0, 10 }, + { H_SLIDER, 0, "", 2, (KEY_FRAME_IMAGE_SIZE<<1)-18, KEY_FRAME_COUNT*KEY_FRAME_IMAGE_SIZE, 0 }, + + { 0 } +}; + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/KFrameEd.cpp b/fallen/Editor/Source/KFrameEd.cpp new file mode 100644 index 0000000..0459312 --- /dev/null +++ b/fallen/Editor/Source/KFrameEd.cpp @@ -0,0 +1,6341 @@ +// KFrameEd.cpp +// Guy Simmons, 12th March 1997. + + +#include "Editor.hpp" +#include "FileReq.hpp" +#include "c:\fallen\editor\headers\Prim.h" +#include "c:\fallen\headers\FMatrix.h" +#include "c:\fallen\headers\animtmap.h" +#include "c:\fallen\headers\animate.h" +#include "c:\fallen\headers\memory.h" +#include "c:\fallen\headers\io.h" + +// JCL +#include "c:\fallen\ddengine\headers\Quaternion.h" +#include "c:\fallen\headers\Hierarchy.h" + +#define CONTROLS_HEIGHT 400 +#define CONTROLS_WIDTH 300 +#define KEY_FRAME_IMAGE_SIZE 48 + +#define VIDEO_MODE_PLAY (1) +#define VIDEO_MODE_PAUSE (2) +#define VIDEO_MODE_NEXT_FRAME (3) +#define VIDEO_MODE_PREV_FRAME (4) +#define VIDEO_MODE_PAUSE_BACK (5) + + +UBYTE re_center_flags[400]; +UBYTE unused_flags[400]; + + +void load_recenter_flags(CBYTE *filename) +{ + SLONG c0=0; + SLONG size; + CBYTE name[100]; + MFFileHandle file_handle; + + strcpy(name,filename); + while(name[c0]!='.') + { + c0++; + } + name[c0+1]='r'; + name[c0+2]='e'; + name[c0+3]='c'; + + + file_handle = FileOpen(name); + if(file_handle!=FILE_OPEN_ERROR) + { + FileRead(file_handle,&size,sizeof(size)); + FileRead(file_handle,&re_center_flags[0],size); + if(size>300) + FileRead(file_handle,&unused_flags[0],size); + + FileClose(file_handle); + } + else + { + memset(&re_center_flags[0],0,400); + } + + +} + +void save_recenter_flags(CBYTE *filename) +{ + SLONG c0=0; + SLONG size; + CBYTE name[100]; + MFFileHandle file_handle; + + strcpy(name,filename); + while(name[c0]!='.') + { + c0++; + } + name[c0+1]='r'; + name[c0+2]='e'; + name[c0+3]='c'; + + + file_handle = FileCreate(name,TRUE); + if(file_handle!=FILE_OPEN_ERROR) + { + size=400; + FileWrite(file_handle,&size,sizeof(size)); + FileWrite(file_handle,&re_center_flags[0],size); + FileWrite(file_handle,&unused_flags[0],size); + FileClose(file_handle); + } + + + + +} + + + +#include "KFDef.c" + + +KeyFrameEditor *the_editor; +void draw_key_frames(void); +void draw_anim_frames(void); +void draw_all_anims_box(void); +//void test_draw(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next,struct Matrix33 *rot_mat); +void set_key_framer_camera(); +void set_key_framer_camera_plan(); +void build_tween_matrix(struct Matrix33 *mat,struct CMatrix33 *cmat1,struct CMatrix33 *cmat2,SLONG tween); + +struct KeyFrameChunk edit_chunk1,edit_chunk2; + +struct KeyFrameElement *elements_bank1=0,*elements_bank2=0; + +//extern SLONG test_chunk->KeyFrameCount; +extern struct KeyFrameChunk *test_chunk; +extern struct KeyFrameElement *the_elements; +//extern void load_multi_vue(struct KeyFrameChunk *the_chunk,float scale); +extern void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); +extern void matrix_transform(struct Matrix31* result, struct Matrix33* trans,struct Matrix31* mat2); +extern void matrix_transform_small(struct Matrix31* result, struct Matrix33* trans,struct SMatrix31* mat2); + +// Used by fudgy centering bit. +extern SLONG x_centre, + y_centre, + z_centre; + +void drawkeyframebox(UWORD multi_object,EdRect *bounds_rect,struct KeyFrame *the_frame,struct Matrix33 *r_matrix,SLONG person_id); + +static UWORD local_object_flags=0; + +#define CTRL_LOAD_BUTTON 1 +#define CTRL_FRAME_SLIDER 2 +#define CTRL_NEW_CHAR_BUTTON 3 +#define CTRL_CHAR_SLIDER 3 +#define CTRL_CHAR_NAME_EDIT 4 +#define CTRL_LOAD_BUTTON2 7 +#define CTRL_DRAW_BOTH 8 +#define CTRL_FLIP_BANK 9 +#define CTRL_SYNC_BOTH 10 +#define CTRL_NEXT_MESH 11 +#define CTRL_PREV_MESH 12 + +#define CTRL_RE_CENTER_ALL 13 +#define CTRL_RE_CENTER_START 14 +//#define CTRL_RE_CENTER_END 15 +#define CTRL_RE_CENTER_NONE 15 +#define CTRL_RE_CENTER_XZ 16 +#define CTRL_RE_CENTER_XZ_START 17 + +#define CTRL_MOVE_SEPARATELY 18 + + +#define CTRL_ANIM_FRAME_SLIDER 1 +#define CTRL_ANIM_FPS_TEXT 2 +#define CTRL_ANIM_FPS_SLIDER 3 +#define CTRL_ANIM_NEW_ANIM_BUTTON 4 +#define CTRL_ANIM_ALL_ANIMS_SLIDER 5 +#define CTRL_ANIM_NAME_EDIT 6 +#define CTRL_ANIM_LOOP_SELECT 7 +#define CTRL_ANIM_LORES_TEST 8 +#define CTRL_ANIM_SAVE_ANIMS 9 + +#define CTRL_ANIM_SUPER_SMOOTH 10 +#define CTRL_ANIM_JUST_KEYS 11 +#define CTRL_PAINT_MESH 12 + +#define CTRL_VIDEO_PREV 13 +#define CTRL_VIDEO_PLAY 14 +#define CTRL_VIDEO_NEXT 15 +#define CTRL_VIDEO_PAUSE 16 +#define CTRL_FIGHT_HEIGHT_PLUS 17 +#define CTRL_FIGHT_HEIGHT_MINUS 18 +#define CTRL_FIGHT_DAMAGE_PLUS 19 +#define CTRL_FIGHT_DAMAGE_MINUS 20 +#define CTRL_FIGHT_TWEEN0 21 +#define CTRL_FIGHT_TWEEN1 22 +#define CTRL_FIGHT_TWEEN2 23 +#define CTRL_FIGHT_TWEEN3 24 +#define CTRL_ANIM_USE_QUATERNIONS 25 +#define CTRL_ANIM_TWEAK_SLIDER 26 + +#define CTRL_ANIM_DISTANCE_SLIDER 27 +#define CTRL_ANIM_FLIP_1 28 +#define CTRL_ANIM_FLIP_2 29 +#define CTRL_ANIM_RESET_VIEW 30 +#define CTRL_ANIM_SAVE_GAME_ANIM 31 + + +#define RE_CENTER_NONE 0 +#define RE_CENTER_ALL 1 +#define RE_CENTER_START 2 +#define RE_CENTER_END 3 +#define RE_CENTER_XZ 4 +#define RE_CENTER_XZ_START 5 + +SLONG CurrentMesh; + +ControlDef kframe_def[] = +{ + { BUTTON, 0, "Load Anim Into Bank 1", 2, CONTROLS_HEIGHT-(20+KEY_FRAME_IMAGE_SIZE+40), 0, 10 }, + { H_SLIDER, 0, "", 2, CONTROLS_HEIGHT-20, 6*KEY_FRAME_IMAGE_SIZE, 0 }, +// { BUTTON, 0, "New Character", 2, 4, 0, 0 }, + { V_SLIDER, 0, "", 104,20, 0, 200 }, + { EDIT_TEXT, 0, "", 2, 230, 70, 0 }, + { STATIC_TEXT, 0, "Current Prim : ", 2, 246, 0, 0 }, + { PULLDOWN_MENU, 0, "Multi Prim", 2, 262, 70, 0, 0 }, + { BUTTON, 0, "Load Anim Into Bank 2", 2, CONTROLS_HEIGHT-(20+KEY_FRAME_IMAGE_SIZE+20), 0, 10 }, + { CHECK_BOX, 0, "Don't Draw Both", 200, 230, 0, 0 }, + { BUTTON, 0, "Flip Bank", 200, 250, 0, 0 }, + { BUTTON, 0, "Sync Both", 200, 280, 0, 0 }, + { BUTTON, 0, "Next Mesh", 130, 230, 0, 0 }, + { BUTTON, 0, "Prev Mesh", 130, 245, 0, 0 }, + + { BUTTON, 0, "Re-Cen All", 130, 260, 0, 0 }, + { BUTTON, 0, "Re-Cen Start", 130, 275, 0, 0 }, +// { BUTTON, 0, "Re-Cen End", 130, 290, 0, 0 }, + { BUTTON, 0, "No Center", 230, 305, 0, 0 }, + { BUTTON, 0, "Re-Cen X&Z", 130, 305, 0, 0 }, + { BUTTON, 0, "Re-Cen X&Z(Start)", 130, 290, 0, 0 }, + { CHECK_BOX, 0, "Move Separately", 100, 265, 0, 0 }, + + { 0 } +}; + + + +//--------------------------------------------------------------- + +ControlDef content_def[] = +{ + { H_SLIDER, 0, "", 0, CONTROLS_HEIGHT-16, 6*KEY_FRAME_IMAGE_SIZE, 0 }, + { STATIC_TEXT, 0, "FPS", 2, CONTROLS_HEIGHT-(16+KEY_FRAME_IMAGE_SIZE+16), 0, 10 }, + { H_SLIDER, 0, "", 22, CONTROLS_HEIGHT-(16+KEY_FRAME_IMAGE_SIZE+18), 100, 0 }, + { BUTTON, 0, "New Anim", 2, 4, 0, 0 }, + { V_SLIDER, 0, "", 104,20, 0, 200 }, + { EDIT_TEXT, 0, "", 2, 230, 70, 0 }, + { CHECK_BOX, KB_L, "Looped", 2, 246, 70, 0 }, + { BUTTON, 0, "Lo-res test", 2, 260, 70, 0 }, + { BUTTON, 0, "Save Anims", 2, 276, 70, 0 }, + { CHECK_BOX, 0, "Super Smooth", 182, 260, 70, 0 }, + { CHECK_BOX, 0, "Just Keys", 182, 276, 70, 0 }, + { BUTTON, 0, "Paint Mesh", 2, 296, 70, 0 }, + { BUTTON, 0, "$26", 100+2, 296, 10, 0 }, + { BUTTON, 0, "$25", 100+30, 296, 10, 0 }, + { BUTTON, 0, "$27", 100+60, 296, 10, 0 }, + { BUTTON, 0, "$28", 100+90, 296, 10, 0 }, + { BUTTON, 0, "+", 300+90, 20, 10, 0 }, + { BUTTON, 0, "-", 300+90, 40, 10, 0 }, + { BUTTON, 0, "+", 200+90, 10, 10, 0 }, + { BUTTON, 0, "-", 270+90, 10, 10, 0 }, + { BUTTON, 0, "0", 200+30, 296, 10, 0 }, + { BUTTON, 0, "1", 200+50, 296, 10, 0 }, + { BUTTON, 0, "2", 200+70, 296, 10, 0 }, + { BUTTON, 0, "3", 200+90, 296, 10, 0 }, + { CHECK_BOX, 0, "No Quaternions", 280, 260, 70, 0 }, + { H_SLIDER, 0, "Tweak", 260, 280, 100, 0 }, + { H_SLIDER, 0, "Distance", 200, 240, 100, 0 }, + { CHECK_BOX, 0, "Flip 1", 380, 240, 70, 0 }, + { CHECK_BOX, 0, "Flip 2", 380, 260, 70, 0 }, + { BUTTON, 0, "Reset View", 380, 280, 70, 0 }, + { BUTTON, 0, "SAVE ALL File", 60, 276, 70, 0 }, + + { 0 } +}; + +#define CTRL_KEY_SLIDER 1 +#define CTRL_KEY_SIZE_PLUS 2 +#define CTRL_KEY_SIZE_MINUS 3 + +ControlDef key_def[] = +{ + { H_SLIDER, 0, "", 0, 0, 4*KEY_FRAME_IMAGE_SIZE, 0 }, + { BUTTON, 0, "+", 40+4*KEY_FRAME_IMAGE_SIZE, 0, 12, 0 }, + { BUTTON, 0, "-", 70+4*KEY_FRAME_IMAGE_SIZE, 0, 12, 0 }, + { 0 } +}; + +//--------------------------------------------------------------- + +KeyFrameEditor::~KeyFrameEditor() +{ +// SaveAllAnims(&test_chunk); + reset_anim_stuff(); +} + +//--------------------------------------------------------------- + +class KeyFrameList : public EditorModule +{ + + private: + KeyFrameEditor *ParentEdit; + EdRect KeyFrameRect; + SLONG KeyFrameSize; + + protected: + + public: + KeyFrameList(KeyFrameEditor *parent,SLONG x,SLONG y,Anim *anim,SLONG max); + void DrawContent(void); + void DrawKeyFrames(void); + void HandleContentClick(UBYTE flags,MFPoint *clicked_point); + void HandleModule(void); + void HandleKeyControl(ULONG control_id); + Anim *TheAnim; + ULONG StartPos; + ControlSet KeyControls; + +}; + +KeyFrameList *the_key_list[5]; + +KeyFrameList::KeyFrameList(KeyFrameEditor *parent,SLONG x,SLONG y,Anim *anim,SLONG max) +{ +extern void add_module(EditorModule *the_module); + ParentEdit=parent; + add_module(this); + this->SetupWindow ( + "Key Frames", + (HAS_GROW), + x, + y, + 790, + KEY_FRAME_IMAGE_SIZE+30-5 + ); + SetContentColour(CONTENT_COL); + + KeyControls.InitControlSet(key_def); + + ((CHSlider*)KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->SetValueRange(0,max); + ((CHSlider*)KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->SetCurrentValue(0); +// ((CHSlider*)KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->SetUpdateFunction(); + + KeyFrameRect.SetRect(0,20,ContentWidth(),ContentHeight()-20); + + TheAnim=anim; + + StartPos=0; + + KeyFrameSize=KEY_FRAME_IMAGE_SIZE-5; + + +} + +void KeyFrameList::HandleKeyControl(ULONG control_id) +{ + switch(control_id) + { + case CTRL_KEY_SLIDER: + break; + case CTRL_KEY_SIZE_PLUS: + KeyFrameSize+=4; + if(KeyFrameSize>300) + KeyFrameSize=300; + break; + case CTRL_KEY_SIZE_MINUS: + KeyFrameSize-=4; + if(KeyFrameSize<10) + KeyFrameSize=10; + break; + } + +} +void KeyFrameList::HandleModule(void) +{ + ParentEdit->HandleModuleKeys(); +} + +void KeyFrameList::DrawContent(void) +{ + SetContentDrawArea(); + ClearContent(); + DrawKeyFrames(); + KeyControls.ControlSetBounds(GetContentRect()); + KeyControls.DrawControlSet(); + +// DrawAnimFrames(CurrentAnim[Bank],TRUE); +} + +#define KEY_OFFSET_Y (16) +void KeyFrameList::DrawKeyFrames(void) +{ + CBYTE text[64]; + SLONG c0, + first_frame, + max_frames; + EdRect frame_rect, + hilite_rect; + MFPoint mouse_point; + struct Matrix33 r_matrix; + struct KeyFrame *current_frame; + if(TheAnim) + current_frame = TheAnim->GetFrameList(); + + ParentEdit->SetSelectedFrame(NULL); + + if(test_chunk->MultiObject) + { + SLONG x=0,y=0; + rotate_obj(ParentEdit->GetAnimAngleX(),ParentEdit->GetAnimAngleY(),0,&r_matrix); + max_frames = ContentWidth()/KeyFrameSize; + if((ContentHeight()-20)>=KeyFrameSize*2) + max_frames*=(ContentHeight()-20)/KeyFrameSize; + + first_frame = ((CHSlider*)KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->GetCurrentValue(); + if((first_frame+max_frames)>test_chunk->KeyFrameCount) + max_frames = (test_chunk->KeyFrameCount-first_frame)+1; + + if(TheAnim) + { + SLONG temp; + temp = (TheAnim->GetFrameCount()-first_frame); + if(tempNextFrame; + else + return; + } + } + } + + for(c0=0;c0SetSelectedFrame(current_frame); + } + + if(TheAnim==0) + current_frame=&test_chunk->KeyFrames[first_frame+c0]; + + //ParentEdit->DrawKeyFrame(test_chunk->MultiObject,&frame_rect,current_frame,&r_matrix); + drawkeyframebox(test_chunk->MultiObject,&frame_rect,current_frame,&r_matrix,ParentEdit->GetPersonID()); + { + CBYTE str[100]; + sprintf(str,"%d",current_frame->FrameID); + QuickTextC(2,2,str,WHITE_COL); + } + x+=KeyFrameSize; + if(x>ContentWidth()-KeyFrameSize) + { + x=0; + y+=KeyFrameSize; + if(y>ContentHeight()-KeyFrameSize) + break; + } + if(TheAnim) + { + current_frame=current_frame->NextFrame; + if(current_frame==0) + break; + } + +//md break; + } + } +} + + +void KeyFrameList::HandleContentClick(UBYTE flags,MFPoint *clicked_point) +{ + ULONG cleanup, + update; + SLONG c0, + first_frame, + max_frames, + x_diff, + y_diff; + Control *current_control; + EdRect frame_rect, + last_rect, + temp_rect; + MFPoint local_point; + struct KeyFrame *current_frame; + struct KeyFrame *selected_frame; + + KeyFrameRect.SetRect(ContentLeft(),ContentTop()+20,ContentWidth(),ContentHeight()-20); + +// WindowControls.SetControlDrawArea(); + local_point = *clicked_point; +// WindowControls.GlobalToLocal(&local_point); + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: +// LogText(" click in box x %d y %d box= (%d,%d,%d,%d) \n",local_point.X,local_point.Y,KeyFrameRect.GetLeft(),KeyFrameRect.GetTop(),KeyFrameRect.GetWidth(),KeyFrameRect.GetHeight()); + if(KeyFrameRect.PointInRect(&local_point)) + { + SLONG x=0,y=0; + // Find out which frame has been selected. + if(TheAnim) + current_frame = TheAnim->GetFrameList(); + + selected_frame = 0; + max_frames = ContentWidth()/KeyFrameSize; + if(ContentHeight()>=KeyFrameSize*2) + max_frames*=ContentHeight()/KeyFrameSize; + first_frame = ((CHSlider*)KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->GetCurrentValue(); + + if((first_frame+max_frames)>test_chunk->KeyFrameCount) + max_frames = (test_chunk->KeyFrameCount-first_frame)+1; + if(TheAnim) + { + SLONG temp; + temp = (TheAnim->GetFrameCount()-first_frame); + if(tempKeyFrameCount;c0++) + { + + frame_rect.SetRect ( + ContentLeft()+(x)+2, + ContentTop()+y+2+KEY_OFFSET_Y, + KeyFrameSize, + KeyFrameSize + ); + if(frame_rect.PointInRect(&local_point)) + { + if(TheAnim==0) + { + selected_frame = &test_chunk->KeyFrames[first_frame+c0]; + } + else + { + selected_frame = current_frame; + } + break; + } + x+=KeyFrameSize; + if(x>ContentWidth()-KeyFrameSize) + { + x=0; + y+=KeyFrameSize; + if(y>ContentHeight()-KeyFrameSize) + { + break; + } + } + if(TheAnim) + { + current_frame=current_frame->NextFrame; + if(current_frame==0) + { + break; + } + } + } + + // Allow selected frame to be dragged around. + if(selected_frame>=0) + { + SLONG drop; + // + // drag frames out of a key window, could be main one or scratch pad + // + drop=ParentEdit->DragAndDropFrame(selected_frame,frame_rect.GetLeft(),frame_rect.GetTop(),frame_rect.GetWidth(),frame_rect.GetHeight(),clicked_point,0); + + // never want to delete from main list, or scratch list unless draging to bin + if(drop==0) + { + if(this==the_key_list[0]) + { + the_key_list[0]->TheAnim->RemoveKeyFrame(selected_frame); + } + + } + } + } + else + { + current_control = KeyControls.GetControlList(); + local_point.X-=ContentLeft(); + local_point.Y-=ContentTop(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + current_control->TrackControl(&local_point); + HandleKeyControl(current_control->TrackControl(&local_point)); + + // Tidy up display. + if(LockWorkScreen()) + { +// KeyControls.DrawControlSet(); + DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + current_control = current_control->GetNextControl(); + } + } + + break; + case RIGHT_CLICK: + break; + } +} + + + +void KeyFrameEditor::SetupModule(void) +{ + KeyFrameEdDefaults the_defaults; + + the_key_list[0] = new KeyFrameList(this,0,450,0,60); + the_key_list[1] = new KeyFrameList(this,0,525,0,650); + + + memset(&PersonBits[0],0,MAX_BODY_BITS); + the_editor = this; + the_defaults.Left = 20; + the_defaults.Top = 20; + the_defaults.Width = 760; + the_defaults.Height = 345; + SetupWindow ( + "Key Frame Editor", + (HAS_TITLE|HAS_CONTROLS), + the_defaults.Left, + the_defaults.Top, + the_defaults.Width, + the_defaults.Height + ); + SetContentColour(CONTENT_COL); + SetControlsHeight(CONTROLS_HEIGHT); + SetControlsWidth(CONTROLS_WIDTH); + + CreateKeyFrameTabs(); + + AnimAngleX[0] = 0; + AnimAngleY[0] = -512; + AnimAngleZ[0] = 0; + AnimAngleX[1] = 0; + AnimAngleY[1] = 512; + AnimAngleZ[1] = 0; + + AnimGlobalAngleX = 0; + AnimGlobalAngleY = 0; + AnimGlobalOffsetX = 0; + AnimGlobalOffsetY = 0; + + AnimOffsetX[0] = 0; + AnimOffsetY[0] = 0; + AnimOffsetZ[0] = 0; + + AnimOffsetX[1] = 100; + AnimOffsetY[1] = 0; + AnimOffsetZ[1] = 0; + + AnimScale = 2000; //296; + AnimTween[0] = 0; + AnimTween[1] = 0; +// CurrentElement = 0; + CurrentFrame[0] = 0; + CurrentFrame[1] = 0; + + Bank=0; + + //TestChunk = (KeyFrameChunk*)MemAlloc(sizeof(KeyFrameChunk)); +// TheElements = (KeyFrameElement*)MemAlloc(MAX_NUMBER_OF_ELEMENTS*sizeof(KeyFrameElement)); + //TestChunk->MultiObject = 0; + + setup_anim_stuff(); + + AnimList[0] = NULL; + AnimList[1] = NULL; + + AnimCount[0] = 0; + AnimCount[1] = 0; + + CurrentAnim[0] = NULL; + CurrentAnim[1] = NULL; + + PlayingAnim[0] = 0; + PlayingAnim[1] = 0; + + Flags = 0; + SelectedFrame = NULL; + + KeyFrameRect.SetRect(2,CONTROLS_HEIGHT-(20+KEY_FRAME_IMAGE_SIZE+4),(6*KEY_FRAME_IMAGE_SIZE)+2,KEY_FRAME_IMAGE_SIZE+2); + ((CHSlider*)WindowControls.GetControlPtr(CTRL_FRAME_SLIDER))->SetValueRange(0,test_chunk->KeyFrameCount); + ((CHSlider*)WindowControls.GetControlPtr(CTRL_FRAME_SLIDER))->SetUpdateFunction(draw_key_frames); + + AnimControls.InitControlSet(content_def); + AnimFrameRect.SetRect(0,CONTROLS_HEIGHT-(16+KEY_FRAME_IMAGE_SIZE+4),(9*KEY_FRAME_IMAGE_SIZE)+2,KEY_FRAME_IMAGE_SIZE+2); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetUpdateFunction(draw_anim_frames); +// ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetCurrentValue(0); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FPS_SLIDER))->SetValueRange(0,60); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FPS_SLIDER))->SetCurrentValue(20); + + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_TWEAK_SLIDER))->SetValueRange(0,255); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_TWEAK_SLIDER))->SetCurrentValue(128); + + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_DISTANCE_SLIDER))->SetValueRange(0,255); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_DISTANCE_SLIDER))->SetCurrentValue(100); + + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetUpdateFunction(draw_all_anims_box); + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetFlags(CONTROL_INACTIVE); + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetEditString("No Anim"); + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_DESELECTED); + AnimControls.SetControlState(CTRL_DRAW_BOTH,CTRL_DESELECTED); + AnimControls.SetControlState(CTRL_MOVE_SEPARATELY,CTRL_DESELECTED); + + ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetFlags(CONTROL_INACTIVE); + ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetEditString("No Name"); + + AllAnimsRect.SetRect(2,20,100,200); + CharactersRect.SetRect(2,20,100,200); + BodyPartRect.SetRect(150,20,100,200); + + CurrentCharacter = &TestCharacter; + + SpeedFlag=0; + QuaternionFlag=0; + Flip1 = 0; + Flip2 = 0; + FightColBank=0; + FightingColPtr=0; + PersonID=0; + DontDrawBoth=0; + MoveSeparately=0; +// LoadKeyFrameChunks(); +// LoadAllAnims(); +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::CreateKeyFrameTabs(void) +{ + WindowControls.InitControlSet(kframe_def); +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::DestroyKeyFrameTabs(void) +{ +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::DrawContent(void) +{ + SetContentDrawArea(); + ClearContent(); + + engine.ShowDebug= 0; + set_key_framer_camera(); + + if(CurrentAnim[Bank]) + { + DoCurrentAnim(); + } + if(DontDrawBoth == 0) + { + if (CurrentAnim[(Bank == 0) ? 1 : 0]) + { + SLONG old_bank=Bank; + if(Bank==0) + SetAnimBank(1); + else + SetAnimBank(0); + + DoCurrentAnim(); + + SetAnimBank(old_bank); + } + } + render_view(0); + engine.ShowDebug= 1; + + if(!ShiftFlag) + { + SetContentDrawArea(); + AnimControls.ControlSetBounds(GetContentRect()); + AnimControls.DrawControlSet(); + + DrawAllAnimsBox(); + +// if(CurrentFrame[Bank]&&CurrentFrame[Bank]->FirstElement&&CurrentFrame[Bank]->PrevFrame) //MD + DrawAnimFrames(CurrentAnim[Bank],TRUE); + } +} + +//--------------------------------------------------------------- +extern CBYTE *body_part_names[]; + +void KeyFrameEditor::DrawPeopleTypes(void) +{ + SLONG x,y,c0; + EdRect name_rect; +// MFPoint mouse_point; + + x=CharactersRect.GetLeft(); + y=CharactersRect.GetTop(); + x+=3; + y+=3; + for(c0=0;c0<15;c0++) + { + /* + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + mouse_point.X -= ContentLeft(); + mouse_point.Y -= ContentTop(); + */ + +// GlobalToLocal(&mouse_point); +// mouse_point.X -= + + name_rect.SetRect(x-1,y-1,CharactersRect.GetWidth()-2,13); + if(c0==PersonID) + { + name_rect.FillRect(LOLITE_COL); + } +/* + if(name_rect.PointInRect(&mouse_point)) + { + name_rect.FillRect(HILITE_COL); + } +*/ + + test_chunk->PeopleNames[c0][PEOPLE_NAME_SIZE-1]=0; + QuickTextC(x,y,&test_chunk->PeopleNames[c0][0],0); + y+=13; + } + + x=BodyPartRect.GetLeft(); + y=BodyPartRect.GetTop(); + x+=3; + y+=3; + for(c0=0;c0GetCurrentValue(); + if((first_frame+max_frames)>CurrentAnim[Bank]->GetFrameCount()) + max_frames = (CurrentAnim[Bank]->GetFrameCount()-first_frame); + current_frame = CurrentAnim[Bank]->GetFrameList(); + if(current_frame) + { + for(c0=0;c0NextFrame; + } + for(c0=0;c0NextFrame; + } + if(selected_frame>=0) + { + SLONG drop; + // + // drag frame out of actual editor window + // + + clicked_point->X-=300; + drop=DragAndDropFrame(selected_frame,frame_rect.GetLeft(),frame_rect.GetTop(),frame_rect.GetWidth(),frame_rect.GetHeight(),clicked_point,0); + if(drop==0||drop==1) + { + // drop =1 is back on itself + // drop =2 is into scratch pad + // drop =0 is bin + CurrentAnim[Bank]->RemoveKeyFrame(selected_frame); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + } + + } + } + } + else if(AllAnimsRect.PointInRect(&local_point)) //this is the anim named list thing + { + CurrentAnim[Bank] = DrawAllAnimsBox(); + if(CurrentAnim[Bank]) + { + /* + if(the_key_list[0]) + { + the_key_list[0]->TheAnim=CurrentAnim[Bank]; + ((CHSlider*)the_key_list[0]->KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->SetValueRange(0,the_key_list[0]->TheAnim->GetFrameCount()-1); + the_key_list[0]->DrawContent(); + ShowWorkScreen(0); + } + */ + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_LOOP_SELECT))->SetFlags((UBYTE)(((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_LOOP_SELECT))->GetFlags()&~CONTROL_INACTIVE)); + if(CurrentAnim[Bank]->GetAnimFlags()&ANIM_LOOP) + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_SELECTED); + else + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_DESELECTED); + + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetFlags((UBYTE)(((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->GetFlags()&~CONTROL_INACTIVE)); + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetEditString(CurrentAnim[Bank]->GetAnimName()); + + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); //added by MD to try and fix slider bug + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_TWEAK_SLIDER))->SetCurrentValue(CurrentAnim[Bank]->GetTweakSpeed()); + } + else + { + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_LOOP_SELECT))->SetFlags(CONTROL_INACTIVE); + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetFlags(CONTROL_INACTIVE); + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetEditString("No Anim"); + } + RequestUpdate(); + } + else + { + current_control = AnimControls.GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + HandleAnimControl(current_control->TrackControl(&local_point)); + + // Tidy up display. + if(LockWorkScreen()) + { + AnimControls.DrawControlSet(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + current_control = current_control->GetNextControl(); + } + } + break; + case RIGHT_CLICK: + if(AnimFrameRect.PointInRect(&local_point) && CurrentAnim[Bank]) + { + // + // Right click in keyframe (on current playing animation) to select it + // + selected_frame = NULL; + max_frames = AnimFrameRect.GetWidth()/KEY_FRAME_IMAGE_SIZE; + first_frame = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->GetCurrentValue(); + if((first_frame+max_frames)>CurrentAnim[Bank]->GetFrameCount()) + max_frames = (CurrentAnim[Bank]->GetFrameCount()-first_frame); + current_frame = CurrentAnim[Bank]->GetFrameList(); + if(current_frame) + { + for(c0=0;c0NextFrame; + } + for(c0=0;c0NextFrame; + } + if(selected_frame>=0) + { + CurrentFrame[Bank]=selected_frame; + } + } + } + else + if(AllAnimsRect.PointInRect(&local_point)) + { + // + // Check for right click on anim list, for cut/copy/paste functions + // + temp_anim = DrawAllAnimsBox(); + + local_point = *clicked_point; + GlobalToLocal(&local_point); + popup_def.ControlLeft = local_point.X+4; + popup_def.ControlTop = local_point.Y-4; + popup_def.TheMenuDef = anim_popup; + the_control = new CPopUp(&popup_def); + + if(temp_anim) + { + the_control->SetItemState(1,CTRL_ACTIVE); + the_control->SetItemState(2,CTRL_ACTIVE); + the_control->SetItemState(4,CTRL_ACTIVE); + } + else + { + the_control->SetItemState(1,CTRL_INACTIVE); + the_control->SetItemState(2,CTRL_INACTIVE); + } + if(Flags&GOT_ANIM_COPY) + the_control->SetItemState(3,CTRL_ACTIVE); + else + the_control->SetItemState(3,CTRL_INACTIVE); + + // + // Select Cut,Copy,Paste + // + control_id = the_control->TrackControl(&local_point); + switch(control_id>>8) + { + KeyFrame *frame; + case 1: //cut + buffer_file = FileCreate("Editor\\EdSave\\scrap.dat",TRUE); + if(buffer_file) + { + SaveAnim(buffer_file,temp_anim); + FileClose(buffer_file); + } + frame = temp_anim->GetFrameList(); + while(frame) + { + // + // add frame to anim[0] + // + AnimList[Bank]->AddKeyFrame(frame); + + frame=frame->NextFrame; + if(frame==temp_anim->GetFrameList()) + frame=0; + + } + DestroyAnim(temp_anim); + Flags |= GOT_ANIM_COPY; + break; + case 2: //copy + buffer_file = FileCreate("Editor\\EdSave\\scrap.dat",TRUE); + if(buffer_file) + { + SaveAnim(buffer_file,temp_anim); + FileClose(buffer_file); + } + frame = temp_anim->GetFrameList(); + while(frame) + { + // + // add frame to anim[0] + // + AnimList[Bank]->AddKeyFrame(frame); + + frame=frame->NextFrame; + if(frame==temp_anim->GetFrameList()) + frame=0; + + } + Flags |= GOT_ANIM_COPY; + break; + case 3: //paste + InsertAnim(temp_anim); + buffer_file = FileOpen("Editor\\EdSave\\scrap.dat"); + if(buffer_file) + { + LoadAnim(buffer_file,CurrentAnim[Bank]); + FileClose(buffer_file); + } + break; + case 4: //toggle_unused + { + Anim *current_anim; + SLONG index=0; + + + if(AnimList[Bank]) + { + current_anim = AnimList[Bank]; + while(current_anim!=temp_anim && current_anim) + { + index++; + current_anim = current_anim->GetNextAnim(); + } + } + unused_flags[index]^=1; + } + break; + } + + if(the_control) + { + delete the_control; + } + } + break; + } +} + +//--------------------------------------------------------------- +SLONG KeyFrameEditor::DragAndDropFrame(KeyFrame *selected_frame,SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *clicked_point,ULONG delete_flag) +{ + MFPoint local_point; + ULONG cleanup; + SLONG update; + + SLONG x_diff, + y_diff; + EdRect last_rect, + temp_rect; + SetWorkWindowBounds(0,0,WorkScreenWidth,WorkScreenHeight); + + temp_rect.SetRect ( + ControlsLeft()+x, + ControlsTop()+y, + w, + h + ); + x_diff = clicked_point->X-temp_rect.GetLeft(); + y_diff = clicked_point->Y-temp_rect.GetTop(); + last_rect.SetRect(0,0,0,0); + cleanup = 0; + update = 0; + while(SHELL_ACTIVE && LeftButton) + { + temp_rect.SetRect(MouseX-x_diff,MouseY-y_diff,temp_rect.GetWidth(),temp_rect.GetHeight()); + if(temp_rect.GetLeft()<0) + temp_rect.MoveRect(0,temp_rect.GetTop()); + if(temp_rect.GetTop()<0) + temp_rect.MoveRect(temp_rect.GetLeft(),0); + if(temp_rect.GetRight()>=WorkScreenWidth) + temp_rect.MoveRect(WorkScreenWidth-temp_rect.GetWidth(),temp_rect.GetTop()); + if(temp_rect.GetBottom()>=WorkScreenHeight) + temp_rect.MoveRect(temp_rect.GetLeft(),WorkScreenHeight-temp_rect.GetHeight()); + + if ( + temp_rect.GetLeft()!=last_rect.GetLeft() || + temp_rect.GetTop()!=last_rect.GetTop() || + temp_rect.GetRight()!=last_rect.GetRight() || + temp_rect.GetBottom()!=last_rect.GetBottom() + ) + { + local_point.X = MouseX; + local_point.Y = MouseY; + if(PointInContent(&local_point)) + { + AnimControls.GlobalToLocal(&local_point); + if(AnimFrameRect.PointInRect(&local_point)) + { + cleanup = 1; + update = 1; + } + else if(cleanup) + { + cleanup = 0; + update = 1; + } + } + else if(the_key_list[0]&&the_key_list[0]->WhereInWindow(&local_point)==IN_CONTENT) + { + update=-1; + } + else if(cleanup) + { + cleanup = 0; + update = 1; + } + if(update>0) + { + if(LockWorkScreen()) + { + DrawAnimFrames(CurrentAnim[Bank],TRUE); + UnlockWorkScreen(); + } + SetWorkWindowBounds(0,0,WorkScreenWidth,WorkScreenHeight); + } + else + if(update<0) + { + if(the_key_list[0]) + { + if(LockWorkScreen()) + { + LogText(" draw funny window (because mouse over it)\n"); + + the_key_list[0]->DrawContent(); + UnlockWorkScreen(); + } + SetWorkWindowBounds(0,0,WorkScreenWidth,WorkScreenHeight); + } + + } + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + ShowWorkScreen(0); + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + last_rect = temp_rect; + } + } + local_point.X = MouseX; + local_point.Y = MouseY; + if(PointInContent(&local_point)) + { + AnimControls.GlobalToLocal(&local_point); + if(AnimFrameRect.PointInRect(&local_point) && CurrentAnim[Bank]) + { + CurrentAnim[Bank]->SetCurrentFrame(SelectedFrame); +// CurrentAnim[Bank]->AddKeyFrame(&TestChunk->KeyFrames[selected_frame]); + CurrentAnim[Bank]->AddKeyFrame(selected_frame); +// CurrentAnim[Bank]->RemoveKeyFrame(selected_frame); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_TWEAK_SLIDER))->SetCurrentValue(CurrentAnim[Bank]->GetTweakSpeed()); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + RequestUpdate(); + return(1); + } + } + else if(the_key_list[0]&&the_key_list[0]->TheAnim) + { + if(the_key_list[0]->WhereInWindow(&local_point)==IN_CONTENT) + { + the_key_list[0]->TheAnim->SetCurrentFrame(SelectedFrame); + the_key_list[0]->TheAnim->AddKeyFrame(selected_frame); +// ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + if(LockWorkScreen()) + { + LogText(" draw funny window2 (because mouse over it)\n"); + + the_key_list[0]->DrawContent(); + UnlockWorkScreen(); + } + SetWorkWindowBounds(0,0,WorkScreenWidth,WorkScreenHeight); + RequestUpdate(); + return(2); + } + // + //Instead of deleting, return where it was dropped and let the calling function delete it if necessary + // +/* + else if(delete_flag) + { + + the_key_list[0]->TheAnim->RemoveKeyFrame(selected_frame); + // ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + } +*/ + } + + + RequestUpdate(); + return(0); + +} + +// +// for one body part take the body part index and find a suitably named object +// +void KeyFrameEditor::SetBodyType(SLONG part) +{ + SLONG c0,so,eo; + SLONG index; + + index=PersonBits[part]; + if(index==0) + { + test_chunk->PeopleTypes[PersonID].BodyPart[part]=part; + return; + } + so=prim_multi_objects[test_chunk->MultiObject].StartObject; + eo=prim_multi_objects[test_chunk->MultiObject].EndObject; + + for(c0=so;c0<=eo;c0++) + { +// if(!memcmp(body_part_names[part],prim_objects[c0].ObjectName,strlen(body_part_names[part]))) + if(!memcmp(body_part_names[part],prim_names[c0],strlen(body_part_names[part]))) + { + SLONG value; + SLONG str_len; + +// str_len=strlen(prim_objects[c0].ObjectName); + str_len=strlen(prim_names[c0]); + value=atoi(&prim_names[c0][str_len-2]); + + if(value==index) + { + test_chunk->PeopleTypes[PersonID].BodyPart[part]=c0-so; + return; + + } + + } + } + +} + +// +// For personID set all the object indexes (body parts) in the test_chunk +// +void KeyFrameEditor::SetPersonBits(void) +{ + SLONG c0; + SLONG object_index,index; + + for(c0=0;c0PeopleTypes[PersonID].BodyPart[c0]; + + object_index+=prim_multi_objects[test_chunk->MultiObject].StartObject; + str_len=strlen(prim_names[object_index]); + index=atoi(&prim_names[object_index][str_len-2]); + PersonBits[c0]=index; + } +} +void KeyFrameEditor::HandleControlClick(UBYTE flags,MFPoint *clicked_point) +{ + SLONG c0, + first_frame, + max_frames, + selected_frame; + Control *current_control; + EdRect frame_rect; + MFPoint local_point; + SLONG edit_name=0; + + + WindowControls.SetControlDrawArea(); + local_point = *clicked_point; + WindowControls.GlobalToLocal(&local_point); + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + if(CharactersRect.PointInRect(&local_point)) + { + SLONG x,y,c0; + x=CharactersRect.GetLeft(); + y=CharactersRect.GetTop(); + y+=1; + + for(c0=0;c0<15;c0++) + { + frame_rect.SetRect(x,y,CharactersRect.GetWidth(),13); + if(frame_rect.PointInRect(&local_point)) + { + PersonID = c0; + SetPersonBits(); + ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetFlags((UBYTE)(((CEditText*)AnimControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->GetFlags()&~CONTROL_INACTIVE)); + ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetEditString(test_chunk->PeopleNames[PersonID]); + edit_name=1; + + break; + } + y+=13; + } + } + else + if(BodyPartRect.PointInRect(&local_point)) + { + SLONG x,y,c0; + + x=BodyPartRect.GetLeft(); + y=BodyPartRect.GetTop(); + y+=1; + for(c0=0;c0GetCurrentValue(); +// if((first_frame+max_frames)>KeyFrameCount) +// max_frames = (KeyFrameCount-first_frame)+1; + if((first_frame+max_frames)>test_chunk->KeyFrameCount) + max_frames = (test_chunk->KeyFrameCount-first_frame)+1; +// for(c0=0;c0KeyFrameCount;c0++) + { + WindowControls.SetControlDrawArea(); + frame_rect.SetRect ( + KeyFrameRect.GetLeft()+(c0*KEY_FRAME_IMAGE_SIZE)+2, + KeyFrameRect.GetTop()+2, + KEY_FRAME_IMAGE_SIZE, + KEY_FRAME_IMAGE_SIZE + ); + if(frame_rect.PointInRect(&local_point)) + { + selected_frame = first_frame+c0; + break; + } + } + + // Allow selected frame to be dragged around. + if(selected_frame>=0) + { + // + // Drag Frames out of the main keyframe list + // + DragAndDropFrame(&test_chunk->KeyFrames[selected_frame],frame_rect.GetLeft(),frame_rect.GetTop(),frame_rect.GetWidth(),frame_rect.GetHeight(),clicked_point,0); + } + } + else + { + current_control = WindowControls.GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + HandleControl(current_control->TrackControl(&local_point)); + + // Tidy up display. + if(LockWorkScreen()) + { + WindowControls.DrawControlSet(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + current_control = current_control->GetNextControl(); + } + } + break; + case RIGHT_CLICK: + if(BodyPartRect.PointInRect(&local_point)) + { + SLONG x,y,c0; + + x=BodyPartRect.GetLeft(); + y=BodyPartRect.GetTop(); + y+=1; + for(c0=0;c0<20;c0++) + { + CBYTE str[100]; + + if(body_part_names[c0]==0) + break; + frame_rect.SetRect(x,y,BodyPartRect.GetWidth(),13); + + if(frame_rect.PointInRect(&local_point)) + { +// test_chunk->PeopleTypes[PersonID].BodyPart[c0]--; + PersonBits[c0]--; + SetBodyType(c0); + break; + } + + y+=13; + } + } + break; + } + if(!edit_name) + { + ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetFlags(CONTROL_INACTIVE); + ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetEditString("No Name"); + } +} + +//--------------------------------------------------------------- + +SLONG KeyFrameEditor::HandleModuleKeys(void) +{ + SLONG update=0; + + if(Keys[KB_0]) + { + AnimOffsetX[Bank]=0; + AnimOffsetY[Bank]=0; + + } + if(Keys[KB_1]) + { + AnimAngleX[Bank]=0; + AnimAngleY[Bank]=0; + } + if(Keys[KB_2]) + { + AnimAngleX[Bank]=512; + AnimAngleY[Bank]=0; + } + if(Keys[KB_3]) + { + AnimAngleX[Bank]=0; + AnimAngleY[Bank]=512; + } + if(Keys[KB_4]) + { + AnimAngleX[Bank]=256; + AnimAngleY[Bank]=256; + } + + if(Keys[KB_SPACE]) + { + AnimOffsetX[Bank] =0; + AnimOffsetY[Bank] =0; + AnimOffsetZ[Bank] =0; + + } + if(Keys[KB_LEFT]) + { + if (MoveSeparately) + AnimOffsetX[Bank] -= 20; + else + AnimGlobalOffsetX -= 20; + update = 1; + } + else if(Keys[KB_RIGHT]) + { + if (MoveSeparately) + AnimOffsetX[Bank] += 20; + else + AnimGlobalOffsetX += 20; + update = 1; + } + if(Keys[KB_UP]) + { + if (MoveSeparately) + AnimOffsetY[Bank] -= 20; + else + AnimGlobalOffsetY -= 20; + update = 1; + } + else if(Keys[KB_DOWN]) + { + if (MoveSeparately) + AnimOffsetY[Bank] += 20; + else + AnimGlobalOffsetY += 20; + update = 1; + } + +#define ROTATION_STEP (4 << 3) + + if(Keys[KB_DEL]) + { + if (MoveSeparately) + AnimAngleY[Bank] -= ROTATION_STEP; + else + { + AnimGlobalAngleY -= ROTATION_STEP; + +/* // rotate around the centre of both points. + SLONG centrex = (AnimOffsetX[0] + AnimOffsetX[1]) / 2; + SLONG centrey = (AnimOffsetY[0] + AnimOffsetY[1]) / 2; + SLONG centrez = (AnimOffsetZ[0] + AnimOffsetZ[1]) / 2; + + SLONG sn = SIN(ROTATION_STEP & (2048-1)); + SLONG cs = COS(ROTATION_STEP & (2048-1)); + + SLONG ox, oz; + + ox = AnimOffsetX[0] - centrex; + oz = AnimOffsetZ[0] - centrez; + AnimOffsetX[0] = centrex + ((ox * cs) >> 16) + ((oz * sn) >> 16); + AnimOffsetZ[0] = centrez - ((ox * sn) >> 16) + ((oz * cs) >> 16); + + ox = AnimOffsetX[1] - centrex; + oz = AnimOffsetZ[1] - centrez; + AnimOffsetX[1] = centrex + ((ox * cs) >> 16) + ((oz * sn) >> 16); + AnimOffsetZ[1] = centrez - ((ox * sn) >> 16) + ((oz * cs) >> 16);*/ + + } + update = 1; + } + else if(Keys[KB_PGDN]) + { + if (MoveSeparately) + AnimAngleY[Bank] += ROTATION_STEP; + else + AnimGlobalAngleY += ROTATION_STEP; + + update = 1; + } + + if(Keys[KB_HOME]) + { + if (MoveSeparately) + AnimAngleX[Bank] -= ROTATION_STEP; + else + AnimGlobalAngleX -= ROTATION_STEP; + update = 1; + } + else if(Keys[KB_END]) + { + if (MoveSeparately) + AnimAngleX[Bank] += ROTATION_STEP; + else + AnimGlobalAngleX += ROTATION_STEP; + update = 1; + } + + if(Keys[KB_I]) + { + AnimScale += ShiftFlag?16:64; + update = 1; + } + if(Keys[KB_O]) + { + AnimScale -= ShiftFlag?16:64; + update = 1; + } + + if(FightingColPtr) + { + struct FightCol *edit_fcol; + + edit_fcol=FightingColPtr; + if(ShiftFlag) + { + if(Keys[KB_MINUS]) + { + update = 1; + edit_fcol->Dist1-=4; + } + if(Keys[KB_PLUS]) + { + update = 1; + edit_fcol->Dist1+=4; + } + if(Keys[KB_LBRACE]) + { + update = 1; + FightColBank--; + } + if(Keys[KB_RBRACE]) + { + update = 1; + FightColBank++; + } +/* + if(Keys[KB_QUOTE]) + { + update = 1; + + } +*/ + } + else + { + if(Keys[KB_LBRACE]) + { + update = 1; + edit_fcol->Angle-=4; + } + if(Keys[KB_RBRACE]) + { + update = 1; + edit_fcol->Angle+=4; + } + if(Keys[KB_MINUS]) + { + update = 1; + edit_fcol->Dist2-=4; + } + if(Keys[KB_PLUS]) + { + update = 1; + edit_fcol->Dist2+=4; + } + } + if(edit_fcol->Dist2Dist1+10) + edit_fcol->Dist2=edit_fcol->Dist1+10; + } + + return(update); +} + + +SLONG KeyFrameEditor::GetPartID(UWORD current) +{ + EdRect frame_rect; + SLONG mx,my; + SLONG sx=200,sy=0; + + while(SHELL_ACTIVE) + { + SLONG c0,multi,multi_count; + SLONG col; + + mx=MouseX-WorkWindowRect.Left; + my=MouseY-WorkWindowRect.Top; + + frame_rect.SetRect(sx,sy,50,300); + + frame_rect.FillRect(ACTIVE_COL); + frame_rect.HiliteRect(LOLITE_COL,HILITE_COL); + + multi=test_chunk->MultiObject; + if(RightButton) + { + return(current); + } + if(multi) + { + multi_count=prim_multi_objects[multi].EndObject-prim_multi_objects[multi].StartObject; + for(c0=0;c0<=multi_count;c0++) + { + CBYTE str[100]; + sprintf(str,"%s",prim_names[c0+prim_multi_objects[multi].StartObject]); + + if(c0==current) + col=RED_COL; + else + col=0; + + + if(mx>sx+5&&mxsy+c0*12+5&&myFixed=GetPartID(SelectedFrame->Fixed); + update = 1; + cleanup_content = 1; + } + LastKey = 0; + } + if(LastKey==KB_C) + { + if(SelectedFrame) + { + struct FightCol *fcol; + if(ShiftFlag) + { + fcol=SelectedFrame->Fight; + SelectedFrame->Fight=fcol->Next; + MemFree((void*)fcol); + } + else + { + //SelectedFrame->Fixed=GetPartID(SelectedFrame->Fixed); + fcol=(struct FightCol*)MemAlloc(sizeof(struct FightCol)); + fcol->Next=SelectedFrame->Fight; + fcol->Dist1=100; + fcol->Dist2=200; + fcol->Angle=0; + fcol->AngleHitFrom=0; + FightingColPtr=fcol; + + + SelectedFrame->Fight=fcol; + } + update = 1; + cleanup_content = 1; + } + LastKey = 0; + } + + if(LastKey==KB_A) + { + KeyFrame *selected_frame; + selected_frame = &test_chunk->KeyFrames[SelectedFrame->FrameID-1]; + CurrentAnim[Bank]->SetCurrentFrame(SelectedFrame); + CurrentAnim[Bank]->AddKeyFrame(selected_frame); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + update = 1; + cleanup_content = 1; + LastKey = 0; + } + + if(LastKey==KB_COMMA) + { + if(SelectedFrame && SelectedFrame->TweenStep>0) + { + SelectedFrame->TweenStep -= 1; + AnimTween[Bank]=0; + update = 1; + cleanup_content = 1; + } + LastKey = 0; + } + else if(LastKey==KB_POINT) + { + if(SelectedFrame && SelectedFrame->TweenStep<15) + { + SelectedFrame->TweenStep += 1; + AnimTween[Bank]=0; + update = 1; + cleanup_content = 1; + } + LastKey = 0; + } + } + else if(cleanup_content) + { + update = 1; + cleanup_content = 0; + } + } + else if(cleanup_content) + { + update = 1; + cleanup_content = 0; + } + + update+=HandleModuleKeys(); + + + tweak_speed = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_TWEAK_SLIDER))->GetCurrentValue()+128; + + SLONG t = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_DISTANCE_SLIDER))->GetCurrentValue(); + if (t != AnimOffsetX[1]) + { + AnimOffsetX[1] = t; + RequestUpdate(); + } + if(CurrentAnim[Bank]) + CurrentAnim[Bank]->SetTweakSpeed(tweak_speed-128); + fps = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FPS_SLIDER))->GetCurrentValue(); + if(VideoMode!=VIDEO_MODE_PAUSE && VideoMode!=VIDEO_MODE_PAUSE_BACK) + if(fps) + { + current_time=GetTickCount(); + if((current_time-last_time)>(1000/fps)) + { +// AnimTween[Bank] += 16; + for(bank=0;bank<2;bank++) + if(CurrentFrame[bank]) + { + if(SpeedFlag==0) + { + if(VideoMode==VIDEO_MODE_PREV_FRAME) + AnimTween[bank] -= tweak_speed/(CurrentFrame[bank]->TweenStep+1); + else + AnimTween[bank] += tweak_speed/(CurrentFrame[bank]->TweenStep+1); + } + else + { + if(SpeedFlag==1) + { + if(VideoMode==VIDEO_MODE_PREV_FRAME) + AnimTween[bank] -= 256; + else + AnimTween[bank] += 256; + } + else + { + if(SpeedFlag==2) + { + if(VideoMode==VIDEO_MODE_PREV_FRAME) + AnimTween[bank] -= 8; + else + AnimTween[bank] += 8; + } + } + } + + } + if(VideoMode==VIDEO_MODE_NEXT_FRAME) + VideoMode=VIDEO_MODE_PAUSE; + if(VideoMode==VIDEO_MODE_PREV_FRAME) + VideoMode=VIDEO_MODE_PAUSE_BACK; + update = 1; + last_time = current_time; + } + } + else + { + + } + + if(update) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + if(LockWorkScreen()) + { + DrawControls(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::AddKeyFrameChunk(void) +{ + +} + +//--------------------------------------------------------------- +extern void set_default_people_types(struct KeyFrameChunk *the_chunk); + +void KeyFrameEditor::SetAnimBank(SLONG bank) +{ + switch(bank) + { + case 0: + test_chunk=&edit_chunk1; + the_elements=elements_bank1; + Bank=0; + current_element = 0; + break; + + case 1: + test_chunk=&edit_chunk2; + the_elements=elements_bank2; + Bank=1; + current_element = 0; + break; + } +} + + +UWORD done[512]; +UBYTE next_done=0; + +void add_done(UWORD idone) +{ + done[next_done++]=idone; + +} + +UBYTE allready_done(UWORD idone) +{ + SLONG c0; + for(c0=0;c0FirstElement[SUB_OBJECT_LEFT_FOOT]; + dy = anim_info->OffsetY-FOOT_HEIGHT; + + anim_info=¤t_frame->FirstElement[SUB_OBJECT_PELVIS]; + dx = anim_info->OffsetX; + dz = anim_info->OffsetZ; + + while(current_frame) + { + if(do_all) + { + anim_info=¤t_frame->FirstElement[SUB_OBJECT_LEFT_FOOT]; + dy = anim_info->OffsetY-FOOT_HEIGHT; + + anim_info=¤t_frame->FirstElement[SUB_OBJECT_PELVIS]; + dx = anim_info->OffsetX; + dz = anim_info->OffsetZ; + } + + if(!allready_done(current_frame->FrameID)) + { + add_done(current_frame->FrameID); + + for(c0=0;c0ElementCount;c0++) + { + anim_info=¤t_frame->FirstElement[c0]; + anim_info->OffsetX-=dx; + if(do_y) + anim_info->OffsetY-=dy; + anim_info->OffsetZ-=dz; + } + } + if(!(current_frame->Flags&ANIM_FLAG_LAST_FRAME)) + { + current_frame=current_frame->NextFrame; + } + else + { + current_frame=0; + } + } + +} + + +void KeyFrameEditor::HandleControl(ULONG control_id) +{ + SLONG c0; + FileRequester *fr; + SLONG ele_count; + SLONG max_range; + + + switch(control_id) + { + case 0: + break; + case CTRL_DRAW_BOTH: + if(DontDrawBoth) + { + DontDrawBoth=0; + WindowControls.SetControlState(CTRL_DRAW_BOTH,CTRL_DESELECTED); + } + else + { + DontDrawBoth=1; + WindowControls.SetControlState(CTRL_DRAW_BOTH,CTRL_SELECTED); + } + break; + case CTRL_MOVE_SEPARATELY: + if(MoveSeparately) + { + MoveSeparately=0; + WindowControls.SetControlState(CTRL_MOVE_SEPARATELY,CTRL_DESELECTED); + } + else + { + MoveSeparately=1; + WindowControls.SetControlState(CTRL_MOVE_SEPARATELY,CTRL_SELECTED); + } + break; + case CTRL_FLIP_BANK: + if(test_chunk==&edit_chunk2) + { + SetAnimBank(0); + } + else + { + SetAnimBank(1); + } + + ((CHSlider*)WindowControls.GetControlPtr(CTRL_FRAME_SLIDER))->SetValueRange(0,test_chunk->KeyFrameCount-2); + /* if(AnimList[Bank]) + ((CHSlider*)the_key_list[0]->KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->SetValueRange(0,the_key_list[0]->TheAnim->GetFrameCount()+20); + */ + + max_range = AnimCount[Bank]-22; + if(max_range<0) + max_range = 0; + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetValueRange(0,max_range); +// ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetCurrentValue(max_range); + + break; + case CTRL_NEXT_MESH: + test_chunk->MultiObject++; + if(test_chunk->MultiObject>=next_prim_multi_object) + { + test_chunk->MultiObject--; + + } + break; + case CTRL_PREV_MESH: + test_chunk->MultiObject--; + if(test_chunk->MultiObject<=0) + { + test_chunk->MultiObject++; + + } + break; + case CTRL_RE_CENTER_ALL: + { + + SLONG dx,dy,dz,c0; + struct KeyFrame *current_frame; + Anim *current_anim; + SLONG index=0; + + + if(AnimList[Bank]) + { + current_anim = AnimList[Bank]; + while(current_anim!=CurrentAnim[Bank] && current_anim) + { + index++; + current_anim = current_anim->GetNextAnim(); + } + } + re_center_flags[index]=RE_CENTER_ALL; + + + + + if(CurrentAnim[Bank]) + { + re_center_anim(CurrentAnim[Bank]->GetFrameListStart(),1,1); + } + } + + + break; + case CTRL_RE_CENTER_NONE: + { + + SLONG dx,dy,dz,c0; + struct KeyFrame *current_frame; + Anim *current_anim; + SLONG index=0; + + + if(AnimList[Bank]) + { + current_anim = AnimList[Bank]; + while(current_anim!=CurrentAnim[Bank] && current_anim) + { + index++; + current_anim = current_anim->GetNextAnim(); + } + } + re_center_flags[index]=RE_CENTER_NONE; + } + break; + case CTRL_RE_CENTER_START: + { + + SLONG dx,dy,dz,c0; + struct KeyFrame *current_frame; + Anim *current_anim; + SLONG index=0; + + + if(AnimList[Bank]) + { + current_anim = AnimList[Bank]; + while(current_anim!=CurrentAnim[Bank] && current_anim) + { + index++; + current_anim = current_anim->GetNextAnim(); + } + } + re_center_flags[index]=RE_CENTER_START; + + + + + if(CurrentAnim[Bank]) + { + re_center_anim(CurrentAnim[Bank]->GetFrameListStart(),1,0); + } + } + break; +// case CTRL_RE_CENTER_END: +// break; + case CTRL_RE_CENTER_XZ_START: + { + + SLONG dx,dy,dz,c0; + struct KeyFrame *current_frame; + Anim *current_anim; + SLONG index=0; + + + if(AnimList[Bank]) + { + current_anim = AnimList[Bank]; + while(current_anim!=CurrentAnim[Bank] && current_anim) + { + index++; + current_anim = current_anim->GetNextAnim(); + } + } + re_center_flags[index]=RE_CENTER_XZ_START; + + if(CurrentAnim[Bank]) + { + re_center_anim(CurrentAnim[Bank]->GetFrameListStart(),0,0); + } + } + break; + case CTRL_RE_CENTER_XZ: + { + + SLONG dx,dy,dz,c0; + struct KeyFrame *current_frame; + Anim *current_anim; + SLONG index=0; + + + if(AnimList[Bank]) + { + current_anim = AnimList[Bank]; + while(current_anim!=CurrentAnim[Bank] && current_anim) + { + index++; + current_anim = current_anim->GetNextAnim(); + } + } + re_center_flags[index]=RE_CENTER_XZ; + + if(CurrentAnim[Bank]) + { + re_center_anim(CurrentAnim[Bank]->GetFrameListStart(),0,1); + } + } + break; + case CTRL_SYNC_BOTH: + + if(CurrentAnim[0]) + { + PlayingAnim[0] = CurrentAnim[0]; + CurrentFrame[0] = PlayingAnim[0]->GetFrameList(); + } + + if(CurrentAnim[1]) + { + PlayingAnim[1] = CurrentAnim[1]; + CurrentFrame[1] = PlayingAnim[1]->GetFrameList(); + } + + AnimTween[0] =0; + AnimTween[1] =0; + + break; + + case CTRL_LOAD_BUTTON2: + case CTRL_LOAD_BUTTON: + + if(control_id==CTRL_LOAD_BUTTON) + { + SetAnimBank(0); + } + else + { + SetAnimBank(1); + } + + fr = new FileRequester("DATA\\","*.VUE","Load a VUE file",".VUE"); + if(fr->Draw()) + { + PersonID=0; + set_default_people_types(test_chunk); + +// void setup_anim_stuff(void); +// setup_anim_stuff(); + + ClearAll(); //problem function because it should go after loading the sex file, so you know it exists + +// void load_key_frame_chunks(KeyFrameChunk *the_chunk,CBYTE *vue_name); + { + float shrink=1.0; + // + // bodge ahoy + // +extern SLONG save_psx; + if(save_psx) + { + if(strcmp(fr->FileName,"balrog.VUE")==0) + shrink=4.0; + if(strcmp(fr->FileName,"gargoyle1.VUE")==0) + shrink=4.0; + if(strcmp(fr->FileName,"bane.VUE")==0) + shrink=4.0; + } + + load_key_frame_chunks(test_chunk,fr->FileName,shrink); + load_recenter_flags(test_chunk->ANMName); + } + + delete fr; + RequestUpdate(); + + ((CHSlider*)WindowControls.GetControlPtr(CTRL_FRAME_SLIDER))->SetValueRange(0,test_chunk->KeyFrameCount-2); + LoadAllAnims(test_chunk); + LogText(" keyframe edit load \n"); + LoadChunkTextureInfo(test_chunk); + if(the_key_list[0]) + { + the_key_list[0]->TheAnim=AnimList[Bank]; + if(AnimList[Bank]) + ((CHSlider*)the_key_list[0]->KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->SetValueRange(0,the_key_list[0]->TheAnim->GetFrameCount()+20); + } + SetPersonBits(); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + if(CurrentAnim[Bank]) + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_TWEAK_SLIDER))->SetCurrentValue(CurrentAnim[Bank]->GetTweakSpeed()); + } + + // + // use re_center_flags + // + { + + SLONG dx,dy,dz,c0; + struct KeyFrame *current_frame; + Anim *current_anim; + SLONG index=0; + + + if(AnimList[Bank]) + { + current_anim = AnimList[Bank]; + while(current_anim) + { + current_frame=current_anim->GetFrameListStart(); + switch(re_center_flags[index]) + { + case RE_CENTER_NONE: + break; + case RE_CENTER_ALL: + re_center_anim(current_frame,1,1); + break; + + case RE_CENTER_START: + re_center_anim(current_frame,1,0); + break; + case RE_CENTER_END: + break; + case RE_CENTER_XZ: + re_center_anim(current_frame,0,1); + break; + case RE_CENTER_XZ_START: + re_center_anim(current_frame,0,0); + break; + } + + + index++; + current_anim = current_anim->GetNextAnim(); + } + } + } + + + break; + +// KeyFrameChunk *the_chunk,CBYTE *vue_name) +#ifdef POO_SHIT_GOD_DAMN + + strcpy(test_chunk->VUEName,fr->Path); + strcat(test_chunk->VUEName,fr->FileName); + strcpy(test_chunk->ASCName,test_chunk->VUEName); + strcpy(test_chunk->ANMName,test_chunk->VUEName); + c0=0; + while(test_chunk->ASCName[c0]!='.' && test_chunk->ASCName[c0]!=0)c0++; + if(test_chunk->ASCName[c0]=='.') + { + test_chunk->ASCName[c0+1] = 'A'; + test_chunk->ASCName[c0+2] = 'S'; + test_chunk->ASCName[c0+3] = 'C'; + test_chunk->ASCName[c0+4] = 0; + + test_chunk->ANMName[c0+1] = 'A'; + test_chunk->ANMName[c0+2] = 'N'; + test_chunk->ANMName[c0+3] = 'M'; + test_chunk->ANMName[c0+4] = 0; + } + delete fr; + RequestUpdate(); +void setup_anim_stuff(void); + setup_anim_stuff(); + + if(ele_count=read_multi_asc(test_chunk->ASCName,0)) + { + ClearAll(); + test_chunk->MultiObject = next_prim_multi_object-1; + test_chunk->ElementCount = ele_count; //prim_multi_objects[test_chunk->MultiObject].EndObject-prim_multi_objects[test_chunk->MultiObject].StartObject; + LogText("IN KEYFRAMER element count %d \n",test_chunk->ElementCount); + // Fudgy bit for centering. + { +SLONG c1, + sp,ep; +struct PrimObject *p_obj; + + + for(c0=prim_multi_objects[test_chunk->MultiObject].StartObject;c0MultiObject].EndObject;c0++) + { + p_obj = &prim_objects[c0]; + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + for(c1=sp;c1SetValueRange(0,test_chunk->KeyFrameCount-2); + LoadAllAnims(test_chunk); + LogText(" keyframe edit load \n"); + LoadChunkTextureInfo(test_chunk); + if(the_key_list[0]) + { + the_key_list[0]->TheAnim=AnimList[Bank]; + if(AnimList[Bank]) + ((CHSlider*)the_key_list[0]->KeyControls.GetControlPtr(CTRL_KEY_SLIDER))->SetValueRange(0,the_key_list[0]->TheAnim->GetFrameCount()+20); + } + } + SetPersonBits(); +// ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + + break; +#endif + case CTRL_FRAME_SLIDER: + if(LockWorkScreen()) + { + DrawKeyFrames(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + break; + case CTRL_CHAR_NAME_EDIT: + strcpy(test_chunk->PeopleNames[PersonID],(((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->GetEditString())); +// ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetFlags(CONTROL_ACTIVE); +// ((CEditText*)WindowControls.GetControlPtr(CTRL_CHAR_NAME_EDIT))->SetEditString(test_chunk->PeopleNames[PersonID]); + break; + + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::HandleAnimControl(ULONG control_id) +{ + switch(control_id) + { + case CTRL_ANIM_FRAME_SLIDER: + if(LockWorkScreen()) + { + DrawAnimFrames(CurrentAnim[Bank],FALSE); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + break; + case CTRL_ANIM_FPS_TEXT: + break; + case CTRL_ANIM_FPS_SLIDER: + break; + case CTRL_ANIM_NEW_ANIM_BUTTON: + AppendAnim(); + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetFlags((UBYTE)(((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->GetFlags()&~CONTROL_INACTIVE)); + ((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->SetEditString(CurrentAnim[Bank]->GetAnimName()); + break; + case CTRL_ANIM_ALL_ANIMS_SLIDER: + break; + case CTRL_ANIM_NAME_EDIT: + if(CurrentAnim[Bank]) + CurrentAnim[Bank]->SetAnimName(((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->GetEditString()); + break; + case CTRL_FIGHT_TWEEN0: + CurrentAnim[Bank]->SetAllTweens(0); + break; + case CTRL_FIGHT_TWEEN1: + CurrentAnim[Bank]->SetAllTweens(1); + break; + case CTRL_FIGHT_TWEEN2: + CurrentAnim[Bank]->SetAllTweens(2); + break; + case CTRL_FIGHT_TWEEN3: + CurrentAnim[Bank]->SetAllTweens(3); + break; + + case CTRL_ANIM_LOOP_SELECT: + if(CurrentAnim[Bank]) + { + CurrentAnim[Bank]->SetAnimFlags((UBYTE)(CurrentAnim[Bank]->GetAnimFlags()^ANIM_LOOP)); + if(CurrentAnim[Bank]->GetAnimFlags()&ANIM_LOOP) + { + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_SELECTED); + CurrentAnim[Bank]->StartLooping(); + } + else + { + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_DESELECTED); + CurrentAnim[Bank]->StopLooping(); + } + } + break; + case CTRL_ANIM_SUPER_SMOOTH: + if(CurrentAnim[Bank]) + { + if(SpeedFlag==2) + { + AnimControls.SetControlState(CTRL_ANIM_SUPER_SMOOTH,CTRL_DESELECTED); + SpeedFlag=0; + } + else + { + SpeedFlag=2; + AnimControls.SetControlState(CTRL_ANIM_SUPER_SMOOTH,CTRL_SELECTED); + AnimControls.SetControlState(CTRL_ANIM_JUST_KEYS,CTRL_DESELECTED); + } + } + break; + case CTRL_ANIM_USE_QUATERNIONS: + if(CurrentAnim[Bank]) + { + if(QuaternionFlag==1) + { + AnimControls.SetControlState(CTRL_ANIM_USE_QUATERNIONS,CTRL_DESELECTED); + QuaternionFlag=0; + } + else + { + QuaternionFlag=1; + AnimControls.SetControlState(CTRL_ANIM_USE_QUATERNIONS,CTRL_SELECTED); + } + RequestUpdate(); + } + break; + case CTRL_ANIM_FLIP_1: + if(CurrentAnim[Bank]) + { + if(Flip1==1) + { + AnimControls.SetControlState(CTRL_ANIM_FLIP_1,CTRL_DESELECTED); + Flip1=0; + AnimAngleY[0] += 1024; + if (AnimAngleY[0] > 1024) + AnimAngleY[0] -= 2048; + } + else + { + AnimControls.SetControlState(CTRL_ANIM_FLIP_1,CTRL_SELECTED); + Flip1=1; + AnimAngleY[0] -= 1024; + if (AnimAngleY[0] < -1024) + AnimAngleY[0] += 2048; + } + RequestUpdate(); + } + break; + case CTRL_ANIM_FLIP_2: + if(CurrentAnim[Bank]) + { + if(Flip2==1) + { + AnimControls.SetControlState(CTRL_ANIM_FLIP_2,CTRL_DESELECTED); + Flip2=0; + AnimAngleY[1] += 1024; + if (AnimAngleY[1] > 1024) + AnimAngleY[1] -= 2048; + } + else + { + AnimControls.SetControlState(CTRL_ANIM_FLIP_2,CTRL_SELECTED); + Flip2=1; + AnimAngleY[1] -= 1024; + if (AnimAngleY[1] < -1024) + AnimAngleY[1] += 2048; + } + RequestUpdate(); + } + break; + case CTRL_ANIM_JUST_KEYS: + if(CurrentAnim[Bank]) + { + if(SpeedFlag==1) + { + AnimControls.SetControlState(CTRL_ANIM_JUST_KEYS,CTRL_DESELECTED); + SpeedFlag=0; + } + else + { + SpeedFlag=1; + AnimControls.SetControlState(CTRL_ANIM_SUPER_SMOOTH,CTRL_DESELECTED); + AnimControls.SetControlState(CTRL_ANIM_JUST_KEYS,CTRL_SELECTED); + AnimTween[Bank]=0; + } + } + break; + case CTRL_PAINT_MESH: + { +extern void bring_module_to_front(EditorModule *the_module); + bring_module_to_front(LinkLevelEditor); + LinkLevelEditor->PrimMode->SetPrimTabMode(PRIM_MODE_MULTI); + LinkLevelEditor->PrimMode->SetCurrentPrim(test_chunk->MultiObject); + LinkLevelEditor->BringTabToFront(LinkLevelEditor->PaintMode); + RequestUpdate(); + } + break; + + case CTRL_VIDEO_NEXT: + VideoMode=VIDEO_MODE_NEXT_FRAME; + + break; + + case CTRL_VIDEO_PLAY: + VideoMode=VIDEO_MODE_PLAY; + break; + + case CTRL_VIDEO_PREV: + VideoMode=VIDEO_MODE_PREV_FRAME; + break; + + case CTRL_VIDEO_PAUSE: + VideoMode=VIDEO_MODE_PAUSE; + break; + case CTRL_FIGHT_HEIGHT_PLUS: + if(FightingColPtr) + { + FightingColPtr->Height++; + if(FightingColPtr->Height>3) + FightingColPtr->Height=0; + RequestUpdate(); + } + break; + case CTRL_FIGHT_HEIGHT_MINUS: + if(FightingColPtr) + { + FightingColPtr->Height--; + if(FightingColPtr->Height>3) + FightingColPtr->Height=3; + RequestUpdate(); + } + break; + case CTRL_FIGHT_DAMAGE_PLUS: + if(FightingColPtr) + { + SLONG size=1; + if(ShiftFlag) + size=10; + + if(ControlFlag) + size=50; + + FightingColPtr->Damage+=size; + RequestUpdate(); + } + break; + case CTRL_FIGHT_DAMAGE_MINUS: + if(FightingColPtr) + { + SLONG size=1; + if(ShiftFlag) + size=10; + + if(ControlFlag) + size=50; + + FightingColPtr->Damage-=size; + RequestUpdate(); + } + break; + + + + case CTRL_ANIM_LORES_TEST: + ULONG current_time, + fps, + last_time; + SLONG depth, + height, + width; + struct MFTime the_time; + SLONG tweak_speed; + + + width = WorkScreenPixelWidth; + height = WorkScreenHeight; + depth = WorkScreenDepth; + SetDisplay(320,200,16); + SetDrawFunctions(16); + SetWorkWindowBounds(0,0,320,200); + + while(SHELL_ACTIVE && LastKey!=KB_ESC) + { + ClearWorkScreen(0); + + if(LockWorkScreen()) + { + if(CurrentAnim[Bank]) + { + HandleModuleKeys(); + engine.ShowDebug= 0; + set_key_framer_camera(); + DoCurrentAnim(); + render_view(0); + engine.ShowDebug= 1; + } + + UnlockWorkScreen(); + ShowWorkScreen(0); + } + + fps = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FPS_SLIDER))->GetCurrentValue(); + tweak_speed = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_TWEAK_SLIDER))->GetCurrentValue()+128; + if(fps) + { + //Time(&the_time); + current_time = GetTickCount(); + if((current_time-last_time)>(1000/fps)) + { + // AnimTween[Bank] += 16; + if(CurrentFrame[Bank]) + { + AnimTween[Bank] += tweak_speed/(CurrentFrame[Bank]->TweenStep+1); + } + last_time = current_time; + } + } + } + LastKey = 0; + SetDisplay(width,height,16); + SetDrawFunctions(16); + SetWorkWindowBounds(0,0,width,height); + RequestUpdate(); + break; + case CTRL_ANIM_SAVE_ANIMS: + SaveAllAnims(test_chunk,0); + break; + case CTRL_ANIM_SAVE_GAME_ANIM: + SaveAllAnims(test_chunk,1); + break; + case CTRL_ANIM_RESET_VIEW: + AnimAngleX[0] = 0; + AnimAngleY[0] = -512; + AnimAngleZ[0] = 0; + AnimAngleX[1] = 0; + AnimAngleY[1] = 512; + AnimAngleZ[1] = 0; + + AnimGlobalAngleX = 0; + AnimGlobalAngleY = 0; + AnimGlobalOffsetX = 0; + AnimGlobalOffsetY = 0; + + AnimOffsetX[0] = 0; + AnimOffsetY[0] = 0; + AnimOffsetZ[0] = 0; + + AnimOffsetX[1] = 100; + AnimOffsetY[1] = 0; + AnimOffsetZ[1] = 0; + + AnimScale = 2000; //296; + + Flip1 = 0; + Flip2 = 0; + AnimControls.SetControlState(CTRL_ANIM_FLIP_1,CTRL_DESELECTED); + AnimControls.SetControlState(CTRL_ANIM_FLIP_2,CTRL_DESELECTED); + RequestUpdate(); + + break; + } +} + +//--------------------------------------------------------------- +struct LinkSort +{ + SWORD Z; + SWORD Item; + SWORD Next; +}; + + +struct LinkSort link_sorts[100]; +SLONG link_head; +SWORD next_link_head; + +SLONG calc_z_for_piece(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next,struct Matrix33 *rot_mat) +{ + SLONG flags; + struct SVector res,temp; //max points per object? + struct Matrix31 offset; + SLONG tx,ty,tz; + + + prim=prim; + + + offset.M[0] = (anim_info->OffsetX+(((anim_info_next->OffsetX-anim_info->OffsetX)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (anim_info->OffsetY+(((anim_info_next->OffsetY-anim_info->OffsetY)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (anim_info->OffsetZ+(((anim_info_next->OffsetZ-anim_info->OffsetZ)*tween)>>8))>>TWEEN_OFFSET_SHIFT; +// LogText(" CALCZ %d %d %d\n",offset.M[0],offset.M[1],offset.M[2]); + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); //temp=offset*rot matrix + x += temp.X; + y += temp.Y; + z += temp.Z; + + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; + +//apply local rotation matrix + + + flags=rotate_point_gte((struct SVector*)&temp,&res); + + + engine.X=tx; + engine.Y=ty; + engine.Z=tz; + + return(res.Z); +} + + +void DumpList(void) +{ + SLONG index; + index=link_head; + while(index) + { + LogText(" [z %d item %d] ",link_sorts[index].Z,link_sorts[index].Item); + index=link_sorts[index].Next; + LogText("\n"); + } +} + +void insert_z_in_sort_list(SLONG z,SLONG item) +{ + SLONG prev=0; + SLONG index; +// LogText(" Insert Node z %d item %d \n",z,item); + + link_sorts[next_link_head].Z=z; + link_sorts[next_link_head].Item=item; + + index=link_head; + while(index) + { + if(zFirstElement[c1]; + if(CurrentFrame->NextFrame) + the_next_element = &CurrentFrame->NextFrame->FirstElement[c1]; + else + the_next_element = the_element; + + pz=calc_z_for_piece(c0,x,y,z,tween,the_element,the_next_element,r_matrix); + insert_z_in_sort_list(pz,c1); + az+=pz; + } + if(c1) + az/=c1; + return(az); +} + + + +void test_draw_z(SLONG az,UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next,struct Matrix33 *rot_mat) +{ + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG flags[1560]; + ULONG flag_and,flag_or; + struct SVector res[1560],temp; //max points per object? + SLONG c0; + struct PrimObject *p_obj; + SLONG sp,ep; + struct Matrix33 *mat,*mat_next,mat2,mat_final; + SLONG i,j; +// struct KeyFrameElement *anim_info_next; + struct Matrix31 offset; + SLONG tx,ty,tz; + + + p_obj =&prim_objects[prim]; + p_f4 =&prim_faces4[p_obj->StartFace4]; + p_f3 =&prim_faces3[p_obj->StartFace3]; + +// anim_info_next = &TheElements[anim_info->Next]; +// anim_info_next = &&TestChunkTestChunk->KeyFrames[3].FirstElement; + + mat = &anim_info->Matrix; + mat_next = &anim_info_next->Matrix; + + //move object "tweened quantity" , z&y flipped + offset.M[0] = (anim_info->OffsetX+(((anim_info_next->OffsetX-anim_info->OffsetX)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (anim_info->OffsetY+(((anim_info_next->OffsetY-anim_info->OffsetY)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (anim_info->OffsetZ+(((anim_info_next->OffsetZ-anim_info->OffsetZ)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x += temp.X; + y += temp.Y; + z += temp.Z; +/* + x+=(anim_info->DX+(((anim_info_next->DX-anim_info->DX)*tween)>>8))>>2; + y+=(anim_info->DY+(((anim_info_next->DY-anim_info->DY)*tween)>>8))>>2; + z+=(anim_info->DZ+(((anim_info_next->DZ-anim_info->DZ)*tween)>>8))>>2; +*/ + + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; + +// engine.X=temp.X<<8; + // engine.Y=temp.Y<<8; + //engine.Z=temp.Z<<8; + + //create a temporary "tween" matrix between current and next + /* + for(i=0;i<3;i++) + { + for(j=0;j<3;j++) + { + mat2.M[i][j]=mat->M[i][j]+(((mat_next->M[i][j]-mat->M[i][j])*tween)>>8); + } + } + */ + build_tween_matrix(&mat2,&anim_info->CMatrix,&anim_info_next->CMatrix,tween); + + + +//apply local rotation matrix + matrix_mult33(&mat_final,rot_mat,&mat2); + + + for(c0=sp;c0StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + p0=p_f4->Points[0]-sp; + p1=p_f4->Points[1]-sp; + p2=p_f4->Points[2]-sp; + p3=p_f4->Points[3]-sp; + + flag_and = flags[p0]&flags[p1]&flags[p2]&flags[p3]; + flag_or = flags[p0]|flags[p1]|flags[p2]|flags[p3]; +// LogText(" test draw face %d p0 x (%d,%d,%d)\n",c0,res[p0].X,res[p0].Y,res[p0].Z); +// DrawLineC(engine.VW2,engine.VH2,res[p0].X,res[p0].Y,0); +// if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + +// az=(res[p0].Z+res[p1].Z+res[p2].Z+res[p3].Z)>>2; + + setPolyType4( + current_bucket_pool, + p_f4->DrawFlags + ); + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->Col2 + ); + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y, + res[p3].X,res[p3].Y + ); + + setUV4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->UV[0][0],p_f4->UV[0][1], + p_f4->UV[1][0],p_f4->UV[1][1], + p_f4->UV[2][0],p_f4->UV[2][1], + p_f4->UV[3][0],p_f4->UV[3][1], + p_f4->TexturePage + ); + + setZ4((struct BucketQuad*)current_bucket_pool,-res[p0].Z,-res[p1].Z,-res[p2].Z,-res[p3].Z); + + setShade4 ( + (struct BucketQuad*)current_bucket_pool, + (p_f4->Bright[0]), + (p_f4->Bright[1]), + (p_f4->Bright[2]), + (p_f4->Bright[3]) + ); + ((struct BucketQuad*)current_bucket_pool)->DebugInfo=c0; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } + p_f4++; + } + + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + p0=p_f3->Points[0]-sp; + p1=p_f3->Points[1]-sp; + p2=p_f3->Points[2]-sp; + + flag_and = flags[p0]&flags[p1]&flags[p2]; + flag_or = flags[p0]|flags[p1]|flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { +// az=(res[p0].Z+res[p1].Z+res[p2].Z)/3; + + setPolyType3( + current_bucket_pool, + p_f3->DrawFlags + ); + + setCol3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->Col2 + ); + + setXY3 ( + (struct BucketTri*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y + ); + + setUV3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->UV[0][0],p_f3->UV[0][1], + p_f3->UV[1][0],p_f3->UV[1][1], + p_f3->UV[2][0],p_f3->UV[2][1], + p_f3->TexturePage + ); + + setShade3 ( + (struct BucketTri*)current_bucket_pool, + (p_f3->Bright[0]), + (p_f3->Bright[1]), + (p_f3->Bright[2]) + ); + ((struct BucketTri*)current_bucket_pool)->DebugInfo=c0; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } + p_f3++; + } +} + +//extern void create_bucket_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col); +extern void create_bucket_3d_line_whole(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col); + +void draw_3d_mat_circle(SLONG x,SLONG y,SLONG z,SLONG radius,struct Matrix33 *r_matrix,UWORD col) +{ + SLONG angle=0; + struct SVector offset,res,prev; + SLONG tx,ty,tz; + + tx=(COS(angle&2047)*radius)>>16; + tz=(SIN(angle&2047)*radius)>>16; + + offset.X=x+tx; + offset.Y=y; + offset.Z=z+tz; + matrix_transformZMY((struct Matrix31*)&prev,r_matrix, (struct Matrix31*)&offset); + + for(angle=16;angle<=2048;angle+=16) + { + tx=(COS(angle&2047)*radius)>>16; + tz=(SIN(angle&2047)*radius)>>16; + + offset.X=x+tx; + offset.Y=y; + offset.Z=z+tz; + + matrix_transformZMY((struct Matrix31*)&res,r_matrix, (struct Matrix31*)&offset); + create_bucket_3d_line_whole(prev.X,prev.Y,prev.Z,res.X,res.Y,res.Z,col); + + prev=res; + } +} + +void KeyFrameEditor::DrawCombatEditor(void) +{ + SLONG tx,ty,tz; + SLONG x,y,z; + SLONG angle,angle_step; + struct Matrix33 r_matrix; + SLONG temp_scale; + static SLONG r1=100,r2=200; + struct FightCol *fcol,*edit_fcol=0; + SLONG dy=0; + SLONG count=0,col; + CBYTE str[100]; + + SVECTOR pelvis,pelvis_after; + + pelvis.X=CurrentFrame[Bank]->FirstElement[0].OffsetX; + pelvis.Y=CurrentFrame[Bank]->FirstElement[0].OffsetY; + pelvis.Z=CurrentFrame[Bank]->FirstElement[0].OffsetZ; + + + + + + rotate_obj(AnimAngleX[Bank] + AnimGlobalAngleX,AnimAngleY[Bank] + AnimGlobalAngleY,0,&r_matrix); + + matrix_transformZMY((struct Matrix31*)&pelvis_after,&r_matrix, (struct Matrix31*)&pelvis); + + + fcol=CurrentFrame[Bank]->Fight; + while(fcol) + { + if(count==FightColBank) + { + FightingColPtr=fcol; + edit_fcol=fcol; + } + fcol=fcol->Next; + count++; + } + if(FightColBank>=count) + { + FightColBank=count-1; + edit_fcol=CurrentFrame[Bank]->Fight; + } + if(FightingColPtr) + { + SLONG c0; + EdRect rect; + for(c0=0;c0<4;c0++) + { + rect.SetRect(410,10+(3-c0)*20,16,16); + rect.HiliteRect(LOLITE_COL,HILITE_COL); + if(FightingColPtr->Height==c0) + rect.FillRect(0); + } + sprintf(str,"DAM: %d",FightingColPtr->Damage); + QuickTextC(310,10,str,0); + } +/* + if(edit_fcol) + { + FightingColPtr=edit_fcol; + if(ShiftFlag) + { + if(Keys[KB_MINUS]) + edit_fcol->Dist1--; + if(Keys[KB_PLUS]) + edit_fcol->Dist1++; + } + else + { + if(Keys[KB_MINUS]) + edit_fcol->Dist2--; + if(Keys[KB_PLUS]) + edit_fcol->Dist2++; + } + if(ShiftFlag) + { + if(Keys[KB_LBRACE]) + { + + } + if(Keys[KB_RBRACE]) + { + } + } + else + { + if(Keys[KB_LBRACE]) + { + edit_fcol->Angle--; + } + if(Keys[KB_RBRACE]) + { + edit_fcol->Angle++; + } + } + } +*/ + + + + fcol=CurrentFrame[Bank]->Fight; + count=0; + + while(fcol) + { + r1=fcol->Dist1; + r2=fcol->Dist2; + + + + x=AnimOffsetX[Bank] + AnimGlobalOffsetX+pelvis_after.X; + y=AnimOffsetY[Bank] + AnimGlobalOffsetY+pelvis_after.Y; + z=100+pelvis_after.Z; + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + + temp_scale = engine.Scale; + engine.Scale = AnimScale; + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; + + angle_step=2048/12; + if(count==FightColBank) + { + col=RED_COL; + } + else + { + col=GREY_COL; + } + + for(angle=angle_step>>1;angle<(2048);angle+=angle_step) + { + SLONG dx,dz; + struct SVector offset,res,res2; + + dx=(COS(angle&2047)*300)>>16; + dz=(SIN(angle&2047)*300)>>16; + + offset.X=dx; + offset.Y=dy; + offset.Z=dz; + + matrix_transformZMY((struct Matrix31*)&res,&r_matrix, (struct Matrix31*)&offset); + offset.X=0; + offset.Y=dy; + offset.Z=0; + + matrix_transformZMY((struct Matrix31*)&res2,&r_matrix, (struct Matrix31*)&offset); + create_bucket_3d_line_whole(res2.X,res2.Y,res2.Z,res.X,res.Y,res.Z,col); + } + angle=fcol->Angle<<3; + for(angle=-10;angle<(10);angle+=3) + { + SLONG dx,dz; + struct SVector offset,res,res2; + + dx=(COS((angle+(fcol->Angle<<3)+2048)&2047)*300)>>16; + dz=(SIN((angle+(fcol->Angle<<3)+2048)&2047)*300)>>16; + + offset.X=dx; + offset.Y=dy; + offset.Z=dz; + + matrix_transformZMY((struct Matrix31*)&res,&r_matrix, (struct Matrix31*)&offset); + offset.X=0; + offset.Y=dy; + offset.Z=0; + + matrix_transformZMY((struct Matrix31*)&res2,&r_matrix, (struct Matrix31*)&offset); + create_bucket_3d_line_whole(res2.X,res2.Y,res2.Z,res.X,res.Y,res.Z,col); + } + + draw_3d_mat_circle(0,dy,0,r1,&r_matrix,col); + draw_3d_mat_circle(0,dy,0,r2,&r_matrix,col); + draw_3d_mat_circle(0,dy,0,300,&r_matrix,col); + + + engine.X=tx; + engine.Y=ty; + engine.Z=tz; + engine.Scale = temp_scale; + + fcol=fcol->Next; + dy-=20; + count++; + } +} + +void KeyFrameEditor::DoAnimRecurse(SLONG part_number, struct Matrix33 *mat, SLONG start_object, + struct Matrix31 *parent_pos, struct Matrix33 *parent_mat, + KeyFrameElement *parent_element) +{ + struct KeyFrameElement *the_element, + *the_next_element; + + struct Matrix31 end_pos; + struct Matrix33 end_mat; + + SLONG object_offset; + object_offset=test_chunk->PeopleTypes[PersonID].BodyPart[part_number]; + + if(CurrentFrame[Bank]->Fixed==part_number) + local_object_flags=FACE_FLAG_OUTLINE; + + the_element = &CurrentFrame[Bank]->FirstElement[part_number]; //vue part + if(CurrentFrame[Bank]->NextFrame) + the_next_element = &CurrentFrame[Bank]->NextFrame->FirstElement[part_number]; + else + the_next_element = the_element; + +/* // debug - make sure the bone doesn't scale + if ((body_part_parent_numbers[part_number] != -1) && (CurrentFrame[Bank]->NextFrame)) + { + struct KeyFrameElement *parent_next_element; + parent_next_element = &CurrentFrame[Bank]->NextFrame->FirstElement[body_part_parent_numbers[part_number]]; + + float a, b, c, d1, d2; + a = float(the_element->OffsetX - parent_element->OffsetX); + b = float(the_element->OffsetY - parent_element->OffsetY); + c = float(the_element->OffsetZ - parent_element->OffsetZ); + d1 = sqrt(a*a + b*b + c*c); + + a = float(the_next_element->OffsetX - parent_next_element->OffsetX); + b = float(the_next_element->OffsetY - parent_next_element->OffsetY); + c = float(the_next_element->OffsetZ - parent_next_element->OffsetZ); + d2 = sqrt(a*a + b*b + c*c); + + ASSERT(fabs(d1 - d2) / d1 < 0.2f); + }*/ + + SLONG x, y, z; + + x = AnimOffsetX[Bank]; + y = AnimOffsetY[Bank]; + z = AnimOffsetZ[Bank]; + + SLONG centrex; + SLONG centrey; + SLONG centrez; + +// SLONG centrex = (AnimOffsetX[0] + AnimOffsetX[1]) / 2; +// SLONG centrey = (AnimOffsetY[0] + AnimOffsetY[1]) / 2; +// SLONG centrez = (AnimOffsetZ[0] + AnimOffsetZ[1]) / 2; + + if (DontDrawBoth) + { + centrex = 50; + centrey = 0; + centrez = 0; + } + else + { + centrex = 0; + centrey = 0; + centrez = 0; + } + + + SLONG ox, oy, oz; + SLONG sn, cs; + + sn = SIN(AnimGlobalAngleY & (2048-1)); + cs = COS(AnimGlobalAngleY & (2048-1)); + ox = x - centrex; + oz = z - centrez; + + x = centrex + ((ox * cs) >> 16) + ((oz * sn) >> 16); + z = centrez - ((ox * sn) >> 16) + ((oz * cs) >> 16); + + sn = SIN(AnimGlobalAngleX & (2048-1)); + cs = COS(AnimGlobalAngleX & (2048-1)); + oy = y - centrey; + oz = z - centrez; + + y = centrey + ((oy * cs) >> 16) - ((oz * sn) >> 16); + z = centrez + ((oy * sn) >> 16) + ((oz * cs) >> 16); + + x += AnimGlobalOffsetX; + y += AnimGlobalOffsetY; + + test_draw(start_object+object_offset,x, y, z + 100,AnimTween[Bank], + the_element,the_next_element, + mat, + parent_pos, parent_mat, parent_element, + &end_pos, &end_mat); + + local_object_flags=0; + + // and do my children + SLONG c0 = 0; + while (body_part_children[part_number][c0] != -1) + { + DoAnimRecurse(body_part_children[part_number][c0], mat, start_object, &end_pos, &end_mat, the_element); + c0++; + }; + +} + +void KeyFrameEditor::DoHierarchicalAnim() +{ + SLONG start_object; + SLONG c1; + struct Matrix33 r_matrix; + +// rotate_obj(AnimAngleX[Bank],AnimAngleY[Bank],0,&r_matrix); + rotate_obj(AnimAngleX[Bank] + AnimGlobalAngleX,AnimAngleY[Bank] + AnimGlobalAngleY, 0, &r_matrix); + + if(CurrentFrame[Bank]->FirstElement==0) + return; + + start_object=prim_multi_objects[test_chunk->MultiObject].StartObject; + + DoAnimRecurse(0, &r_matrix, start_object, NULL, NULL, NULL); +} + +void KeyFrameEditor::DoCurrentAnim(void) +{ + SLONG animate = 0, + c0,c1, + temp_scale; + struct Matrix33 r_matrix; + struct KeyFrameElement *the_element, + *the_next_element; + SLONG start_object; + + + if(PlayingAnim[Bank]!=CurrentAnim[Bank]) + { + CurrentFrame[Bank] = 0; + } + + if(CurrentFrame[Bank]==0) + { + PlayingAnim[Bank] = CurrentAnim[Bank]; + CurrentFrame[Bank] = PlayingAnim[Bank]->GetFrameList(); + if(CurrentFrame[Bank]==0) + return; + + /* + // + // Clearly this is bollocks, if you ofset frame is 0 , c0 will always be non zero + // + c0 = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->GetCurrentValue(); + while(c0--&&CurrentFrame[Bank]->NextFrame) + { + CurrentFrame[Bank] = CurrentFrame[Bank]->NextFrame; + } + if(c0) + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetCurrentValue(0); + */ + + } + + + // + // go to next keyframe if animtween >255 + // + { + SLONG bank; + + for(bank=0;bank<2;bank++) + { + if(CurrentFrame[bank]&&CurrentFrame[bank]->FirstElement) //&&CurrentFrame[Bank]->PrevFrame) //MD +//jcl if(AnimTween[bank]>255) + while(AnimTween[bank]>255) + { + AnimTween[bank] -= 255; + if (CurrentFrame[bank]) // jcl - I can't find where the bank wraps, so I'll just duplicate the last frame in this obscure case... + CurrentFrame[bank] = CurrentFrame[bank]->NextFrame; + } +//jcl if(AnimTween[bank]<0) + while(AnimTween[bank]<0) + { + AnimTween[bank] += 255; + if (CurrentFrame[bank]) + CurrentFrame[bank] = CurrentFrame[bank]->PrevFrame; + } + } + } + + if(CurrentFrame[Bank]&&CurrentFrame[Bank]->FirstElement) //&&CurrentFrame[Bank]->PrevFrame) //MD + { + rotate_obj(AnimAngleX[Bank] + AnimGlobalAngleX,AnimAngleY[Bank] + AnimGlobalAngleY,0,&r_matrix); +// rotate_obj(0,AnimAngleY[Bank],0,&r_matrix); +// LogText(" current anim anglex %d angley %d \n",AnimAngleX[Bank],AnimAngleY[Bank]); + + if(CurrentFrame[Bank]) + if(CurrentFrame[Bank]->Fight) + DrawCombatEditor(); + + { + SLONG tx,ty,tz; + SVECTOR p,p1,p2; + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + + temp_scale = engine.Scale; + engine.Scale = AnimScale; + engine.X=0; + engine.Y=0; + engine.Z=0; + + rotate_obj(AnimAngleX[Bank] + AnimGlobalAngleX,AnimAngleY[Bank] + AnimGlobalAngleY,0,&r_matrix); + + p.X=-30; + p.Y=0; + p.Z=0; + matrix_transformZMY((struct Matrix31*)&p1,&r_matrix, (struct Matrix31*)&p); + + p.X=30; + p.Y=0; + p.Z=0; + matrix_transformZMY((struct Matrix31*)&p2,&r_matrix, (struct Matrix31*)&p); + create_bucket_3d_line_whole(p1.X,p1.Y,p1.Z,p2.X,p2.Y,p2.Z,0); + + p.Y=-30; + p.X=0; + p.Z=0; + matrix_transformZMY((struct Matrix31*)&p1,&r_matrix, (struct Matrix31*)&p); + + p.Y=30; + p.X=0; + p.Z=0; + matrix_transformZMY((struct Matrix31*)&p2,&r_matrix, (struct Matrix31*)&p); + create_bucket_3d_line_whole(p1.X,p1.Y,p1.Z,p2.X,p2.Y,p2.Z,0); + + p.Z=-30; + p.Y=0; + p.X=0; + matrix_transformZMY((struct Matrix31*)&p1,&r_matrix, (struct Matrix31*)&p); + + p.Z=30; + p.Y=0; + p.X=0; + matrix_transformZMY((struct Matrix31*)&p2,&r_matrix, (struct Matrix31*)&p); + create_bucket_3d_line_whole(p1.X,p1.Y,p1.Z,p2.X,p2.Y,p2.Z,0); + + engine.X=tx; + engine.Y=ty; + engine.Z=tz; + } + +#ifdef CUNNING_SORT + if(CurrentFrame[Bank]) + { + SLONG o_count,c2,index,az; + + temp_scale = engine.Scale; + engine.Scale = AnimScale; + + o_count=prim_multi_objects[test_chunk->MultiObject].EndObject-prim_multi_objects[test_chunk->MultiObject].StartObject; + index=link_head; + az=build_sort_order_tweened(test_chunk->MultiObject,CurrentFrame[Bank],AnimOffsetX[Bank] + AnimGlobalOffsetX,AnimOffsetY[Bank] + AnimGlobalOffsetY,100,AnimTween[Bank],&r_matrix); +// LogText(" draw ORDER \n["); + for(c2=0;c2<=o_count;c2++) + { + c1=link_sorts[index].Item; + c0=c1+prim_multi_objects[test_chunk->MultiObject].StartObject; +// LogText("%d ",c1); + the_element = &CurrentFrame[Bank]->FirstElement[c1]; + if(VideoMode==VIDEO_MODE_PREV_FRAME||VideoMode==VIDEO_MODE_PAUSE_BACK) + { + if(CurrentFrame[Bank]->PrevFrame) + the_next_element = &CurrentFrame[Bank]->PrevFrame->FirstElement[c1]; + else + the_next_element = the_element; + + } + else + { + if(CurrentFrame[Bank]->NextFrame) + the_next_element = &CurrentFrame[Bank]->NextFrame->FirstElement[c1]; + else + the_next_element = the_element; + } + + test_draw_z(az+(c2<<2),c0,AnimOffsetX[Bank] + AnimGlobalOffsetX,AnimOffsetY[Bank] + AnimGlobalOffsetY,100,AnimTween[Bank],the_element,the_next_element,&r_matrix); + index=link_sorts[index].Next; + } +// LogText("]\n"); + engine.Scale = temp_scale; + } +#else + if(CurrentFrame[Bank]) + { + temp_scale = engine.Scale; + engine.Scale = AnimScale; +// for(c1=0,c0=prim_multi_objects[TestChunk->MultiObject].StartObject;c0<=prim_multi_objects[TestChunk->MultiObject].EndObject;c0++,c1++) + + + if (the_editor->GetQuaternionFlag() && + (test_chunk->ElementCount == 15)) + DoHierarchicalAnim(); + else + { + start_object=prim_multi_objects[test_chunk->MultiObject].StartObject; + for(c1=0;c1ElementCount;c1++) + { + SLONG object_offset; + if(CurrentFrame[Bank]->FirstElement==0) + goto error; + // + // for each vue frame we need an object to draw + // + if(test_chunk->ElementCount==15) + object_offset=test_chunk->PeopleTypes[PersonID].BodyPart[c1]; + else + object_offset=c1; + + // object_offset=test_chunk->PeopleTypes[PersonID].BodyPart[c1]; + + the_element = &CurrentFrame[Bank]->FirstElement[c1]; //vue part + if(CurrentFrame[Bank]->NextFrame) + the_next_element = &CurrentFrame[Bank]->NextFrame->FirstElement[c1]; + else + the_next_element = the_element; + + if(CurrentFrame[Bank]->Fixed==c1) + local_object_flags=FACE_FLAG_OUTLINE; + + // test_draw(start_object+object_offset,0,0,0,0,the_element,the_element,r_matrix); + // test_draw(start_object+object_offset,AnimOffsetX[Bank],AnimOffsetY[Bank],100,AnimTween[Bank],the_element,the_next_element,&r_matrix, NULL, NULL); + +/* // JCL - work out the parent of the element. + SLONG parent = body_part_parent_numbers[c1]; + + struct KeyFrameElement *parent_element, *parent_next_element; + + if (parent == -1) + { + parent_element = NULL; + } + else + { + parent_element = &CurrentFrame[Bank]->FirstElement[parent]; //vue part + if(CurrentFrame[Bank]->NextFrame) + parent_next_element = &CurrentFrame[Bank]->NextFrame->FirstElement[parent]; + else + parent_next_element = the_element; + }*/ + + test_draw(start_object+object_offset,AnimOffsetX[Bank] + AnimGlobalOffsetX,AnimOffsetY[Bank] + AnimGlobalOffsetY,100,AnimTween[Bank],the_element,the_next_element,&r_matrix, NULL, NULL, NULL, NULL, NULL); + + local_object_flags=0; + } + } + + +/* + for(c1=0,c0=prim_multi_objects[test_chunk->MultiObject].StartObject;c0<=prim_multi_objects[test_chunk->MultiObject].EndObject;c0++,c1++) + { + the_element = &CurrentFrame[Bank]->FirstElement[c1]; + if(CurrentFrame[Bank]->NextFrame) + the_next_element = &CurrentFrame[Bank]->NextFrame->FirstElement[c1]; + else + the_next_element = the_element; + + if(CurrentFrame[Bank]->Fixed==c1) + local_object_flags=FACE_FLAG_OUTLINE; + test_draw(c0,AnimOffsetX[Bank],AnimOffsetY[Bank],100,AnimTween[Bank],the_element,the_next_element,&r_matrix); + local_object_flags=0; + } +*/ + engine.Scale = temp_scale; + } +#endif + } + { + CBYTE str[90]; + if(CurrentFrame[Bank]) + sprintf(str,"%d %d",AnimTween[Bank],CurrentFrame[Bank]->FrameID); + else + sprintf(str,"%d %d",AnimTween[Bank],0); + QuickTextC(180,0,str,0); + } +error:; +} + +extern UWORD is_it_clockwise(struct SVector *global_res,SLONG p0,SLONG p1,SLONG p2); +/* +UWORD is_it_clockwise(struct SVector *global_res,SLONG p0,SLONG p1,SLONG p2) +{ + SLONG z; + SLONG vx,vy,wx,wy; + + vx=global_res[p1].X-global_res[p0].X; + wx=global_res[p2].X-global_res[p1].X; + vy=global_res[p1].Y-global_res[p0].Y; + wy=global_res[p2].Y-global_res[p1].Y; + + z=vx*wy-vy*wx; + + if(z>0) + return 1; + else + return 0; +} +*/ + +//--------------------------------------------------------------- +/* + + GUY I HAVE CHANGED HOW X,Y,Z ARE USED, SO IF YOU ARE CALLING THIS FUNCTION ELSE WHERE THEN + IT WILL BE WRONG + +*/ + +//JCL - not needed here #define PI (3.14159625) + +void MATRIX_calc(float *matrix, float yaw, float pitch, float roll) +{ + float cy, cp, cr; + float sy, sp, sr; + + cy = cos(yaw); + cp = cos(pitch); + cr = cos(roll); + + sy = sin(yaw); + sp = sin(pitch); + sr = sin(roll); + + // + // Jan I trust you... but only becuase I've already seen it working! + // + + matrix[0] = cy * cr + sy * sp * sr; + matrix[3] = cy * sr - sy * sp * cr; + matrix[6] = sy * cp; + matrix[1] = -cp * sr; + matrix[4] = cp * cr; + matrix[7] = sp; + matrix[2] = -sy * cr + cy * sp * sr; + matrix[5] = -sy * sr - cy * sp * cr; + matrix[8] = cy * cp; +} + +#define MATRIX_FA_VECTOR_TOO_SMALL (0.0001F) +#define MATRIX_FA_ANGLE_TOO_SMALL (PI / 36000.0F) +#include + +void MATRIX_find_angles(float *matrix,float *yaw,float *pitch,float * roll) +{ + float x; + float y; + float z; + float xz; + + + // + // Look from above at the z-vector to work out the yaw. + // + + x = matrix[6]; + y = matrix[7]; + z = matrix[8]; + + if (fabs(x) + fabs(z) < MATRIX_FA_VECTOR_TOO_SMALL) + { + *yaw = 0.0F; + } + else + { + *yaw = (float)atan2(x, z); + } + + // + // Look down the x vector to at the z-vector to work out the pitch. + // + + xz = sqrt(x*x + z*z); + + if (fabs(xz) + fabs(y) < MATRIX_FA_VECTOR_TOO_SMALL) + { + if (y < 0) + { + *pitch = -PI; + } + else + { + *pitch = +PI; + } + } + else + { + *pitch = (float)atan2(y, xz); + } + + // + // Now... matrix[4] = cos(pitch) * cos(roll) + // matrix[1] = -cos(pitch) * sin(roll) + // + // so... cos(roll) = matrix[4] / cos(pitch) + // sin(roll) = matrix[1] / -cos(pitch) + // + + float cos_roll; + float sin_roll; + float cos_pitch; + + cos_pitch = (float)cos(*pitch); + + if (fabs(cos_pitch) < MATRIX_FA_ANGLE_TOO_SMALL) + { + *roll = 0.0F; + } + else + { + cos_roll = matrix[4] / cos_pitch; + sin_roll = matrix[1] / -cos_pitch; + *roll = (float)atan2(sin_roll, cos_roll); + } + +} + +void convert_mat_to_float(float *mat_f,Matrix33 *mat_m) +{ + //LogText(" mat (%d,%d,%d)(%d,%d,%d)(%d,%d,%d)== ",mat_m->M[0][0],mat_m->M[0][1],mat_m->M[0][2],mat_m->M[1][0],mat_m->M[1][1],mat_m->M[1][2],mat_m->M[2][0],mat_m->M[2][1],mat_m->M[2][2]); + + mat_f[0]=((float)mat_m->M[0][0])/32768.0; + mat_f[1]=((float)mat_m->M[0][1])/32768.0; + mat_f[2]=((float)mat_m->M[0][2])/32768.0; + mat_f[3]=((float)mat_m->M[1][0])/32768.0; + mat_f[4]=((float)mat_m->M[1][1])/32768.0; + mat_f[5]=((float)mat_m->M[1][2])/32768.0; + mat_f[6]=((float)mat_m->M[2][0])/32768.0; + mat_f[7]=((float)mat_m->M[2][1])/32768.0; + mat_f[8]=((float)mat_m->M[2][2])/32768.0; + //LogText(" mat (%f,%f,%f)(%f,%f,%f)(%f,%f,%f) \n",mat_f[0],mat_f[1],mat_f[2],mat_f[3],mat_f[4],mat_f[5],mat_f[6],mat_f[7],mat_f[8]); +} + +void convert_float_to_mat(Matrix33 *mat_m,float *mat_f) +{ + //LogText(" mat (%f,%f,%f)(%f,%f,%f)(%f,%f,%f)== ",mat_f[0],mat_f[1],mat_f[2],mat_f[3],mat_f[4],mat_f[5],mat_f[6],mat_f[7],mat_f[8]); + mat_m->M[0][0]=(SLONG)(mat_f[0]*32768.0); + mat_m->M[0][1]=(SLONG)(mat_f[1]*32768.0); + mat_m->M[0][2]=(SLONG)(mat_f[2]*32768.0); + + mat_m->M[1][0]=(SLONG)(mat_f[3]*32768.0); + mat_m->M[1][1]=(SLONG)(mat_f[4]*32768.0); + mat_m->M[1][2]=(SLONG)(mat_f[5]*32768.0); + + mat_m->M[2][0]=(SLONG)(mat_f[6]*32768.0); + mat_m->M[2][1]=(SLONG)(mat_f[7]*32768.0); + mat_m->M[2][2]=(SLONG)(mat_f[8]*32768.0); + //LogText(" mat (%d,%d,%d)(%d,%d,%d)(%d,%d,%d)\n ",mat_m->M[0][0],mat_m->M[0][1],mat_m->M[0][2],mat_m->M[1][0],mat_m->M[1][1],mat_m->M[1][2],mat_m->M[2][0],mat_m->M[2][1],mat_m->M[2][2]); +} + +float tween_angles(float a1,float a2,SLONG tween) +{ + float da; + UBYTE log=0; + // angles go from -pi to +pi + + + da=a2-a1; +// if(da) +// log=1; + if(log) + LogText(" a1 %f a2 %f da %f tween %d \n",a1,a2,da,tween); + + if(da<-PI) + { + if(log) + LogText(" Dangle over-a %f ->",da); + da=(2.0*PI+da); // 180-181 (-181 should be +179 + if(log) + LogText(" %f \n",da); + } + if(da>PI) + { + if(log) + LogText(" Dangle over-b %f ->",da); + da= -(2.0*PI-da); //181 should be -179 + if(log) + LogText(" %f \n",da); + } + + if(log) + LogText("da %f pre tween \n",da); + + da=da*tween; + if(log) + LogText("da %f mid tween \n",da); + + da=(da)/256.0; + if(log) + LogText("da %f after tween \n",da); + a1+=da; + + if(a1>PI) + { + if(log) + LogText(" a1 over-a %f ->",a1); + a1-=2.0*PI; + if(log) + LogText(" %f \n",a1); + } + if(a1<-PI) + { + if(log) + LogText(" a1 over-a %f ->",a1); + a1+=2.0*PI; + if(log) + LogText(" %f \n",a1); + } + if(log) + LogText("res %f \n",a1); + + return(a1); + +} +/* +void build_tween_matrix(Matrix33 *mat_res,Matrix33 *mat1,Matrix33 *mat2,SLONG tween) +{ + float mata[9],yaw1,pitch1,roll1,yaw2,pitch2,roll2; + + + convert_mat_to_float(mata,mat1); + MATRIX_find_angles(mata,&yaw1,&pitch1,&roll1); + + convert_mat_to_float(mata,mat2); + MATRIX_find_angles(mata,&yaw2,&pitch2,&roll2); + + yaw1=tween_angles(yaw1,yaw2,tween); + pitch1=tween_angles(pitch1,pitch2,tween); + roll1=tween_angles(roll1,roll2,tween); + +// LogText(" y p r %f %f %f \n",yaw1,pitch1,roll1); + + MATRIX_calc(mata,yaw1,pitch1,roll1); + convert_float_to_mat(mat_res,mata); + + //LogText(" yaw %f->%f, pitch %f->%f, roll %f->%f\n",yaw1,yaw2,pitch1,pitch2,roll1,roll2); + +} +*/ + +// void draw_a_rot_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct PrimMultiAnim *anim_info,struct Matrix33 *rot_mat) +//void KeyFrameEditor::test_draw(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next,struct Matrix33 *rot_mat) +void test_draw(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween, + struct KeyFrameElement *anim_info,struct KeyFrameElement *anim_info_next, + struct Matrix33 *rot_mat, + struct Matrix31 *parent_pos, struct Matrix33 *parent_mat, + KeyFrameElement *parent_element, + struct Matrix31 *end_pos, struct Matrix33 *end_mat + ) +{ + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG flags[1560]; + ULONG flag_and,flag_or; + struct SVector res[1560],temp; //max points per object? + SLONG c0; + struct PrimObject *p_obj; + SLONG sp,ep; + SLONG az; + struct Matrix33 *mat,*mat_next,mat2,mat_final; + SLONG i,j; +// struct KeyFrameElement *anim_info_next; + struct Matrix31 offset; + SLONG tx,ty,tz; + SLONG len,len2; + + p_obj =&prim_objects[prim]; + p_f4 =&prim_faces4[p_obj->StartFace4]; + p_f3 =&prim_faces3[p_obj->StartFace3]; + +// anim_info_next = &TheElements[anim_info->Next]; +// anim_info_next = &&TestChunkTestChunk->KeyFrames[3].FirstElement; + + mat = &anim_info->Matrix; + mat_next = &anim_info_next->Matrix; + + //move object "tweened quantity" , z&y flipped + + + //!JCL - temp - use the quaternion from the "parent" node to generate the position. + // or don't bother if we haven't got a parent... + if ((!parent_pos) || (!parent_mat) || (!parent_element) || (the_editor->GetQuaternionFlag() == 0)) + { + offset.M[0] = (anim_info->OffsetX+(((anim_info_next->OffsetX-anim_info->OffsetX)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (anim_info->OffsetY+(((anim_info_next->OffsetY-anim_info->OffsetY)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (anim_info->OffsetZ+(((anim_info_next->OffsetZ-anim_info->OffsetZ)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + + if (end_pos) + { + *end_pos = offset; + + // ramp up the accuracy + end_pos->M[0] *=256; + end_pos->M[1] *=256; + end_pos->M[2] *=256; + } + + offset.M[0] *= 256; + offset.M[1] *= 256; + offset.M[2] *= 256; + } + else + { + + HIERARCHY_Get_Body_Part_Offset(&offset, (Matrix31 *)(&anim_info->OffsetX), + &parent_element->CMatrix, (Matrix31 *)(&parent_element->OffsetX), + parent_mat, parent_pos); + + if (end_pos) + *end_pos = offset; + } + + offset.M[0] >>= 2; // otherwise the matrix rotation overflows... + offset.M[1] >>= 2; + offset.M[2] >>= 2; + + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x = (x * 256) + (temp.X << 2); + y = (y * 256) + (temp.Y << 2); + z = (z * 256) + (temp.Z << 2); + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + +// engine.X=-x<<8; +// engine.Y=-y<<8; +// engine.Z=-z<<8; + engine.X=-x; + engine.Y=-y; + engine.Z=-z; + + SLONG q = the_editor->GetQuaternionFlag(); + if ( q == 0) +// if (1) + { + build_tween_matrix(&mat2,&anim_info->CMatrix,&anim_info_next->CMatrix,tween); + } + else + { + //JCL - temp - use quaternions to interpolate matrices + CQuaternion::BuildTween(&mat2,&anim_info->CMatrix,&anim_info_next->CMatrix,tween); + } + + if (end_mat) + *end_mat = mat2; + + matrix_mult33(&mat_final,rot_mat,&mat2); + + + for(c0=sp;c0StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + p0=p_f4->Points[0]-sp; + p1=p_f4->Points[1]-sp; + p2=p_f4->Points[2]-sp; + p3=p_f4->Points[3]-sp; + if(!is_it_clockwise(res,p0,p1,p2)) + goto next_face4; + + + flag_and = flags[p0]&flags[p1]&flags[p2]&flags[p3]; + flag_or = flags[p0]|flags[p1]|flags[p2]|flags[p3]; +// LogText(" test draw face %d p0 x (%d,%d,%d)\n",c0,res[p0].X,res[p0].Y,res[p0].Z); +// DrawLineC(engine.VW2,engine.VH2,res[p0].X,res[p0].Y,0); +// if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + + az=(res[p0].Z+res[p1].Z+res[p2].Z+res[p3].Z)>>2; + + setPolyType4( + current_bucket_pool, + p_f4->DrawFlags + ); + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->Col2 + ); + if(p_f4->Col2>256) + LogText(" material test draw poly col %d co %d\n",(SLONG)p_f4->Col2,c0); + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y, + res[p3].X,res[p3].Y + ); + + setUV4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->UV[0][0],p_f4->UV[0][1], + p_f4->UV[1][0],p_f4->UV[1][1], + p_f4->UV[2][0],p_f4->UV[2][1], + p_f4->UV[3][0],p_f4->UV[3][1], + p_f4->TexturePage + ); + ASSERT(p_f4->TexturePage>=0); + + setZ4((struct BucketQuad*)current_bucket_pool,-res[p0].Z,-res[p1].Z,-res[p2].Z,-res[p3].Z); + + setShade4 ( + (struct BucketQuad*)current_bucket_pool, + (p_f4->Bright[0]), + (p_f4->Bright[1]), + (p_f4->Bright[2]), + (p_f4->Bright[3]) + ); + ((struct BucketQuad*)current_bucket_pool)->DebugInfo=c0; + ((struct BucketQuad*)current_bucket_pool)->DebugFlags=local_object_flags; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } +next_face4:; + p_f4++; + } + + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + p0=p_f3->Points[0]-sp; + p1=p_f3->Points[1]-sp; + p2=p_f3->Points[2]-sp; +// LogText(" test draw p012 %d %d %d \n",p0,p1,p2); + if(p0<0||p1<0||p2<0) + { + ERROR_MSG(0," point before start_point in test_draw"); + + return; + } + if(!is_it_clockwise(res,p0,p1,p2)) + goto next_face3; + + flag_and = flags[p0]&flags[p1]&flags[p2]; + flag_or = flags[p0]|flags[p1]|flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + az=(res[p0].Z+res[p1].Z+res[p2].Z)/3; + + setPolyType3( + current_bucket_pool, + p_f3->DrawFlags + ); + + setCol3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->Col2 + ); + + setXY3 ( + (struct BucketTri*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y + ); + + setUV3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->UV[0][0],p_f3->UV[0][1], + p_f3->UV[1][0],p_f3->UV[1][1], + p_f3->UV[2][0],p_f3->UV[2][1], + p_f3->TexturePage + ); + ASSERT(p_f3->TexturePage>=0); + + setShade3 ( + (struct BucketTri*)current_bucket_pool, + (p_f3->Bright[0]), + (p_f3->Bright[1]), + (p_f3->Bright[2]) + ); + + ((struct BucketTri*)current_bucket_pool)->DebugInfo=c0; + ((struct BucketTri*)current_bucket_pool)->DebugFlags=p_f3->FaceFlags; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } +next_face3:; + p_f3++; + } +} + +void test_draw_all_get_sizes(SWORD multi_prim,struct KeyFrame *the_frame,SLONG x,SLONG y,SLONG z,SLONG tween,struct Matrix33 *rot_mat,SLONG *width,SLONG *height,SLONG *mid_x,SLONG *mid_y) +{ + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG flags[1560]; + ULONG flag_and,flag_or; + struct SVector res[1560],temp; //max points per object? + struct PrimObject *p_obj; + SLONG sp,ep; + SLONG az; + struct Matrix33 *mat,*mat_next,mat2,mat_final; + struct KeyFrameElement *the_element; + SLONG i,j; +// struct KeyFrameElement *anim_info_next; + struct Matrix31 offset; + SLONG tx,ty,tz; + + SLONG max_x,max_y; + SLONG min_x,min_y; + SLONG mx=0,my=0,count=0; + + SLONG c0,c1,c2; + UWORD prim; + + min_x = min_y = 999999; + max_x = max_y = -999999; + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + if(the_frame->FirstElement==0) + return; + + for(c2=0,c1=prim_multi_objects[multi_prim].StartObject;c1FirstElement[c2++]; +// test_draw(c0,0,0,0,0,the_element,the_element,r_matrix); + prim=c1; + + p_obj =&prim_objects[prim]; + p_f4 =&prim_faces4[p_obj->StartFace4]; + p_f3 =&prim_faces3[p_obj->StartFace3]; + + + mat = &the_element->Matrix; + mat_next = &the_element->Matrix; + + //move object "tweened quantity" , z&y flipped + offset.M[0] = (the_element->OffsetX)>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (the_element->OffsetY)>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (the_element->OffsetZ)>>TWEEN_OFFSET_SHIFT; + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x = temp.X; + y = temp.Y; + z = temp.Z; + + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; + + for(i=0;i<3;i++) + { + for(j=0;j<3;j++) + { + mat2.M[i][j]=mat->M[i][j]+(((mat_next->M[i][j]-mat->M[i][j])*tween)>>8); + } + } + + //apply local rotation matrix + matrix_mult33(&mat_final,rot_mat,&mat2); + + + for(c0=sp;c0max_x) + max_x = res[c0-sp].X; + + if(res[c0-sp].Ymax_y) + max_y = res[c0-sp].Y; + } + } + + engine.X=tx; + engine.Y=ty; + engine.Z=tz; + *width = max_x-min_x; + *height = max_y-min_y; + + if(count) + { + *mid_x=mx/count; + *mid_y=my/count; + } + +} + +void test_draw_game(UWORD prim,SLONG x,SLONG y,SLONG z,SLONG tween,struct GameKeyFrameElement *anim_info,struct GameKeyFrameElement *anim_info_next,struct Matrix33 *rot_mat) +{ + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG flags[1560]; + ULONG flag_and,flag_or; + struct SVector res[1560],temp; //max points per object? + SLONG c0; + struct PrimObject *p_obj; + SLONG sp,ep; + SLONG az; + struct Matrix33 *mat,*mat_next,mat2,mat_final; + SLONG i,j; +// struct KeyFrameElement *anim_info_next; + struct Matrix31 offset; + SLONG tx,ty,tz; + SLONG len,len2; + + p_obj =&prim_objects[prim]; + p_f4 =&prim_faces4[p_obj->StartFace4]; + p_f3 =&prim_faces3[p_obj->StartFace3]; + +// anim_info_next = &TheElements[anim_info->Next]; +// anim_info_next = &&TestChunkTestChunk->KeyFrames[3].FirstElement; + + //mat = &anim_info->CMatrix; + //mat_next = &anim_info_next->CMatrix; + + //move object "tweened quantity" , z&y flipped + + + offset.M[0] = (anim_info->OffsetX+(((anim_info_next->OffsetX-anim_info->OffsetX)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (anim_info->OffsetY+(((anim_info_next->OffsetY-anim_info->OffsetY)*tween)>>8))>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (anim_info->OffsetZ+(((anim_info_next->OffsetZ-anim_info->OffsetZ)*tween)>>8))>>TWEEN_OFFSET_SHIFT; +/* + len=SDIST3(anim_info->OffsetX,anim_info->OffsetY,anim_info->OffsetZ); + len=sqrl(len); + + len2=SDIST3(offset.M[0],offset.M[1],offset.M[2]); + len2=sqrl(len2); + + offset.M[0] = (offset.M[0] *len)/len2; + offset.M[1] = (offset.M[1] *len)/len2; + offset.M[2] = (offset.M[2] *len)/len2; +*/ + + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x += temp.X; + y += temp.Y; + z += temp.Z; + + CMatrix33 m1, m2; + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + build_tween_matrix(&mat2, &m1, &m2 ,tween); + +/* + x+=(anim_info->DX+(((anim_info_next->DX-anim_info->DX)*tween)>>8))>>2; + y+=(anim_info->DY+(((anim_info_next->DY-anim_info->DY)*tween)>>8))>>2; + z+=(anim_info->DZ+(((anim_info_next->DZ-anim_info->DZ)*tween)>>8))>>2; +*/ + + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + +// LogText(" test draw sp %d ep %d \n",sp,ep); + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; + +// engine.X=temp.X<<8; + // engine.Y=temp.Y<<8; + //engine.Z=temp.Z<<8; + + //create a temporary "tween" matrix between current and next +/* + for(i=0;i<3;i++) + { + for(j=0;j<3;j++) + { + mat2.M[i][j]=mat->M[i][j]+(((mat_next->M[i][j]-mat->M[i][j])*tween)>>8); + } + } +*/ + + GetCMatrix(anim_info, &m1); + GetCMatrix(anim_info_next, &m2); + + build_tween_matrix(&mat2, &m1, &m2, tween); + normalise_matrix(&mat2); + +// build_tween_matrix(&mat2,mat,mat_next,tween); +//apply local rotation matrix + matrix_mult33(&mat_final,rot_mat,&mat2); + + + for(c0=sp;c0StartFace4;c0EndFace4;c0++) + { + SLONG p0,p1,p2,p3; + + p0=p_f4->Points[0]-sp; + p1=p_f4->Points[1]-sp; + p2=p_f4->Points[2]-sp; + p3=p_f4->Points[3]-sp; + if(!is_it_clockwise(res,p0,p1,p2)) + goto next_face4; + + + flag_and = flags[p0]&flags[p1]&flags[p2]&flags[p3]; + flag_or = flags[p0]|flags[p1]|flags[p2]|flags[p3]; +// LogText(" test draw face %d p0 x (%d,%d,%d)\n",c0,res[p0].X,res[p0].Y,res[p0].Z); +// DrawLineC(engine.VW2,engine.VH2,res[p0].X,res[p0].Y,0); +// if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + + az=(res[p0].Z+res[p1].Z+res[p2].Z+res[p3].Z)>>2; + + setPolyType4( + current_bucket_pool, + p_f4->DrawFlags + ); + + setCol4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->Col2 + ); + if(p_f4->Col2>256) + LogText(" material test draw poly col %d co %d\n",(SLONG)p_f4->Col2,c0); + + setXY4 ( + (struct BucketQuad*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y, + res[p3].X,res[p3].Y + ); + + setUV4 ( + (struct BucketQuad*)current_bucket_pool, + p_f4->UV[0][0],p_f4->UV[0][1], + p_f4->UV[1][0],p_f4->UV[1][1], + p_f4->UV[2][0],p_f4->UV[2][1], + p_f4->UV[3][0],p_f4->UV[3][1], + p_f4->TexturePage + ); + ASSERT(p_f4->TexturePage>=0); + + setZ4((struct BucketQuad*)current_bucket_pool,-res[p0].Z,-res[p1].Z,-res[p2].Z,-res[p3].Z); + + setShade4 ( + (struct BucketQuad*)current_bucket_pool, + (p_f4->Bright[0]), + (p_f4->Bright[1]), + (p_f4->Bright[2]), + (p_f4->Bright[3]) + ); + ((struct BucketQuad*)current_bucket_pool)->DebugInfo=c0; + ((struct BucketQuad*)current_bucket_pool)->DebugFlags=local_object_flags; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } +next_face4:; + p_f4++; + } + + for(c0=p_obj->StartFace3;c0EndFace3;c0++) + { + SLONG p0,p1,p2; + + p0=p_f3->Points[0]-sp; + p1=p_f3->Points[1]-sp; + p2=p_f3->Points[2]-sp; +// LogText(" test draw p012 %d %d %d \n",p0,p1,p2); + if(p0<0||p1<0||p2<0) + { + ERROR_MSG(0," point before start_point in test_draw"); + + return; + } + if(!is_it_clockwise(res,p0,p1,p2)) + goto next_face3; + + flag_and = flags[p0]&flags[p1]&flags[p2]; + flag_or = flags[p0]|flags[p1]|flags[p2]; + + if((flag_or&EF_BEHIND_YOU)==0) + if(!(flag_and & EF_CLIPFLAGS)) + { + az=(res[p0].Z+res[p1].Z+res[p2].Z)/3; + + setPolyType3( + current_bucket_pool, + p_f3->DrawFlags + ); + + setCol3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->Col2 + ); + + setXY3 ( + (struct BucketTri*)current_bucket_pool, + res[p0].X,res[p0].Y, + res[p1].X,res[p1].Y, + res[p2].X,res[p2].Y + ); + + setUV3 ( + (struct BucketTri*)current_bucket_pool, + p_f3->UV[0][0],p_f3->UV[0][1], + p_f3->UV[1][0],p_f3->UV[1][1], + p_f3->UV[2][0],p_f3->UV[2][1], + p_f3->TexturePage + ); + ASSERT(p_f3->TexturePage>=0); + + setShade3 ( + (struct BucketTri*)current_bucket_pool, + (p_f3->Bright[0]), + (p_f3->Bright[1]), + (p_f3->Bright[2]) + ); + + ((struct BucketTri*)current_bucket_pool)->DebugInfo=c0; + ((struct BucketTri*)current_bucket_pool)->DebugFlags=p_f3->FaceFlags; + + add_bucket((void *)current_bucket_pool,az); + + current_bucket_pool+=sizeof(struct BucketQuad); + } +next_face3:; + p_f3++; + } +} + +void test_draw_all_get_sizes_game(SWORD multi_prim,struct GameKeyFrame *the_frame,SLONG x,SLONG y,SLONG z,SLONG tween,struct Matrix33 *rot_mat,SLONG *width,SLONG *height,SLONG *mid_x,SLONG *mid_y) +{ + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG flags[1560]; + ULONG flag_and,flag_or; + struct SVector res[1560],temp; //max points per object? + struct PrimObject *p_obj; + SLONG sp,ep; + SLONG az; + struct Matrix33 *mat,*mat_next,mat2,mat_final; + struct GameKeyFrameElement *the_element; + SLONG i,j; +// struct KeyFrameElement *anim_info_next; + struct Matrix31 offset; + SLONG tx,ty,tz; + + SLONG max_x,max_y; + SLONG min_x,min_y; + SLONG mx=0,my=0,count=0; + + SLONG c0,c1,c2; + UWORD prim; + + min_x = min_y = 999999; + max_x = max_y = -999999; + + tx=engine.X; + ty=engine.Y; + tz=engine.Z; + if(the_frame->FirstElement==0) + return; + + for(c2=0,c1=prim_multi_objects[multi_prim].StartObject;c1FirstElement[c2++]; +// test_draw(c0,0,0,0,0,the_element,the_element,r_matrix); + prim=c1; + + p_obj =&prim_objects[prim]; + p_f4 =&prim_faces4[p_obj->StartFace4]; + p_f3 =&prim_faces3[p_obj->StartFace3]; + + +// mat = &the_element->Matrix; +// mat_next = &the_element->Matrix; + + //move object "tweened quantity" , z&y flipped + offset.M[0] = (the_element->OffsetX)>>TWEEN_OFFSET_SHIFT; + offset.M[1] = (the_element->OffsetY)>>TWEEN_OFFSET_SHIFT; + offset.M[2] = (the_element->OffsetZ)>>TWEEN_OFFSET_SHIFT; + matrix_transformZMY((struct Matrix31*)&temp,rot_mat, &offset); + x = temp.X; + y = temp.Y; + z = temp.Z; + + // (jcl) don't blame me - I didn't write this... + CMatrix33 m1, m2; + GetCMatrix(the_element, &m1); + GetCMatrix(the_element, &m1); + + build_tween_matrix(&mat2, &m1, &m2,tween); + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + + engine.X=-x<<8; + engine.Y=-y<<8; + engine.Z=-z<<8; +/* + for(i=0;i<3;i++) + { + for(j=0;j<3;j++) + { + mat2.M[i][j]=mat->M[i][j]+(((mat_next->M[i][j]-mat->M[i][j])*tween)>>8); + } + } + */ + //apply local rotation matrix + matrix_mult33(&mat_final,rot_mat,&mat2); + + + for(c0=sp;c0max_x) + max_x = res[c0-sp].X; + + if(res[c0-sp].Ymax_y) + max_y = res[c0-sp].Y; + } + } + + engine.X=tx; + engine.Y=ty; + engine.Z=tz; + *width = max_x-min_x; + *height = max_y-min_y; + + if(count) + { + *mid_x=mx/count; + *mid_y=my/count; + } + +} + +//--------------------------------------------------------------- + + +void KeyFrameEditor::DrawKeyFrame(UWORD multi_object,EdRect *bounds_rect,struct KeyFrame *the_frame,struct Matrix33 *r_matrix) +{ + SLONG c0,c1,c2, + num_points, + end_point, + scale, + scale_y, + start_point, + temp_scale, + temp_x, + temp_y, + temp_z, + temp_vw2, + temp_vh2, + width,height, + *flags; + EdRect outline_rect; + struct KeyFrameElement *the_element; + struct Matrix31 offset; + struct PrimObject *the_obj; + struct SVector *rotate_vectors, + t_vector, + t_vector2; + + SLONG mid_x=0,mid_y=0; + SLONG start_object; + + // Stop the compiler moaning. + multi_object = multi_object; + + if(!test_chunk->MultiObject) + return; + + c1 = 0; + flags = (SLONG*)MemAlloc(sizeof(SLONG)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + rotate_vectors = (struct SVector*)MemAlloc(sizeof(struct SVector)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + + + temp_scale = engine.Scale; + temp_x = engine.X; + temp_y = engine.Y; + temp_z = engine.Z; + temp_vw2 = engine.VW2; + temp_vh2 = engine.VH2; + + engine.X = 0; + engine.Y = 0; + engine.Z = 0; + engine.Scale = 5000; + engine.ShowDebug= 0; + engine.BucketSize= MAX_BUCKETS>>4; + + SetWorkWindowBounds ( + bounds_rect->GetLeft(), + bounds_rect->GetTop(), + bounds_rect->GetWidth(), + bounds_rect->GetHeight() + ); + outline_rect.SetRect( + 0,0, + bounds_rect->GetWidth(),bounds_rect->GetHeight() + ); + set_camera(); +// set_camera_to_base(); + + +//md LogText(" width %d height %d \n",width,height); + test_draw_all_get_sizes(test_chunk->MultiObject,the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + if(width>0 && height>0) + { + + + scale = (bounds_rect->GetWidth()<<16)/width; + scale_y = (bounds_rect->GetHeight()<<16)/height; + if(scale_y>8; + engine.Scale = (5000*scale)>>16; + + //calc new mids with this scale + test_draw_all_get_sizes(test_chunk->MultiObject,the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + + mid_x-=bounds_rect->GetWidth()>>1; + mid_y-=bounds_rect->GetHeight()>>1; + engine.VW2-=mid_x; + engine.VH2-=mid_y; + + } +// LogText(" drawkeyframe scale %d \n",engine.Scale); + + // + // body part system + // + start_object=prim_multi_objects[test_chunk->MultiObject].StartObject; + for(c2=0;c2ElementCount;c2++) + { + SLONG object_offset; + if(the_frame->FirstElement==0) + goto error; + + // + // for each vue frame we need an object to draw + // + + if(test_chunk->ElementCount==15) + object_offset=test_chunk->PeopleTypes[PersonID].BodyPart[c2]; + else + object_offset=c2; //test_chunk->PeopleTypes[PersonID].BodyPart[c2]; + + the_element = &the_frame->FirstElement[c2]; //vue part + test_draw(start_object+object_offset,0,0,0,0,the_element,the_element,r_matrix, NULL, NULL, NULL, NULL, NULL); + } + +/* old system + for(c2=0,c0=prim_multi_objects[test_chunk->MultiObject].StartObject;c0<=prim_multi_objects[test_chunk->MultiObject].EndObject;c0++) + { + if(the_frame->FirstElement==0) + goto error; + the_element = &the_frame->FirstElement[c2++]; + test_draw(c0,0,0,0,0,the_element,the_element,r_matrix); + } +*/ + render_view(0); + outline_rect.OutlineRect(0); + + engine.X = temp_x; + engine.Y = temp_y; + engine.Z = temp_z; + engine.Scale = temp_scale; + engine.ShowDebug= 1; + engine.BucketSize= MAX_BUCKETS; + engine.VW2 = temp_vw2; + engine.VH2 = temp_vh2; +error:; + MemFree(rotate_vectors); + MemFree(flags); +} + +void drawkeyframebox(UWORD multi_object,EdRect *bounds_rect,struct KeyFrame *the_frame,struct Matrix33 *r_matrix,SLONG person_id) +{ + SLONG c0,c1,c2, + num_points, + end_point, + scale, + scale_y, + start_point, + temp_scale, + temp_x, + temp_y, + temp_z, + temp_vw2, + temp_vh2, + width,height, + *flags; + EdRect outline_rect; + struct KeyFrameElement *the_element; + struct Matrix31 offset; + struct PrimObject *the_obj; + struct SVector *rotate_vectors, + t_vector, + t_vector2; + + SLONG mid_x=0,mid_y=0; + SLONG start_object; + + // Stop the compiler moaning. + multi_object = multi_object; + + if(!test_chunk->MultiObject) + return; + + c1 = 0; + flags = (SLONG*)MemAlloc(sizeof(SLONG)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + rotate_vectors = (struct SVector*)MemAlloc(sizeof(struct SVector)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + + + temp_scale = engine.Scale; + temp_x = engine.X; + temp_y = engine.Y; + temp_z = engine.Z; + temp_vw2 = engine.VW2; + temp_vh2 = engine.VH2; + + engine.X = 0; + engine.Y = 0; + engine.Z = 0; + engine.Scale = 5000; + engine.ShowDebug= 0; + engine.BucketSize= MAX_BUCKETS>>4; + + SetWorkWindowBounds ( + bounds_rect->GetLeft(), + bounds_rect->GetTop(), + bounds_rect->GetWidth(), + bounds_rect->GetHeight() + ); + outline_rect.SetRect( + 0,0, + bounds_rect->GetWidth(),bounds_rect->GetHeight() + ); + set_camera(); +// set_camera_to_base(); + + +//md LogText(" width %d height %d \n",width,height); + test_draw_all_get_sizes(test_chunk->MultiObject,the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + if(width>0 && height>0) + { + + + scale = (bounds_rect->GetWidth()<<16)/width; + scale_y = (bounds_rect->GetHeight()<<16)/height; + if(scale_y>8; + engine.Scale = (5000*scale)>>16; + + //calc new mids with this scale + test_draw_all_get_sizes(test_chunk->MultiObject,the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + + mid_x-=bounds_rect->GetWidth()>>1; + mid_y-=bounds_rect->GetHeight()>>1; + engine.VW2-=mid_x; + engine.VH2-=mid_y; + + } +// LogText(" drawkeyframe scale %d \n",engine.Scale); + + // + // body part system + // + start_object=prim_multi_objects[test_chunk->MultiObject].StartObject; + for(c2=0;c2ElementCount;c2++) + { + SLONG object_offset; + if(the_frame->FirstElement==0) + goto error; + + // + // for each vue frame we need an object to draw + // + if(test_chunk->ElementCount==15) + object_offset=test_chunk->PeopleTypes[person_id].BodyPart[c2]; + else + object_offset=c2; + + +// object_offset=test_chunk->PeopleTypes[person_id].BodyPart[c2]; + the_element = &the_frame->FirstElement[c2]; //vue part + test_draw(start_object+object_offset,0,0,0,0,the_element,the_element,r_matrix, NULL, NULL, NULL, NULL, NULL); + } + +/* old system + for(c2=0,c0=prim_multi_objects[test_chunk->MultiObject].StartObject;c0<=prim_multi_objects[test_chunk->MultiObject].EndObject;c0++) + { + if(the_frame->FirstElement==0) + goto error; + the_element = &the_frame->FirstElement[c2++]; + test_draw(c0,0,0,0,0,the_element,the_element,r_matrix); + } +*/ + render_view(0); + outline_rect.OutlineRect(0); + + engine.X = temp_x; + engine.Y = temp_y; + engine.Z = temp_z; + engine.Scale = temp_scale; + engine.ShowDebug= 1; + engine.BucketSize= MAX_BUCKETS; + engine.VW2 = temp_vw2; + engine.VH2 = temp_vh2; +error:; + MemFree(rotate_vectors); + MemFree(flags); +} + +void drawkeyframeboxgamechunk(UWORD multi_object,EdRect *bounds_rect,struct GameKeyFrame *the_frame,struct Matrix33 *r_matrix,SLONG person_id,struct GameKeyFrameChunk *the_chunk) +{ + SLONG c0,c1,c2, + num_points, + end_point, + scale, + scale_y, + start_point, + temp_scale, + temp_x, + temp_y, + temp_z, + temp_vw2, + temp_vh2, + width,height, + *flags; + EdRect outline_rect; + struct GameKeyFrameElement *the_element; + struct Matrix31 offset; + struct PrimObject *the_obj; + struct SVector *rotate_vectors, + t_vector, + t_vector2; + + SLONG mid_x=0,mid_y=0; + SLONG start_object; + + // Stop the compiler moaning. + multi_object = multi_object; + + if(!the_chunk->MultiObject) + return; + + c1 = 0; + flags = (SLONG*)MemAlloc(sizeof(SLONG)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + rotate_vectors = (struct SVector*)MemAlloc(sizeof(struct SVector)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + + + temp_scale = engine.Scale; + temp_x = engine.X; + temp_y = engine.Y; + temp_z = engine.Z; + temp_vw2 = engine.VW2; + temp_vh2 = engine.VH2; + + engine.X = 0; + engine.Y = 0; + engine.Z = 0; + engine.Scale = 5000; + engine.ShowDebug= 0; + engine.BucketSize= MAX_BUCKETS>>4; +/* + SetWorkWindowBounds ( + bounds_rect->GetLeft(), + bounds_rect->GetTop(), + bounds_rect->GetWidth(), + bounds_rect->GetHeight() + ); + + outline_rect.SetRect( + 0,0, + bounds_rect->GetWidth(),bounds_rect->GetHeight() + ); +*/ + set_camera(); +// set_camera_to_base(); + + +//md LogText(" width %d height %d \n",width,height); + test_draw_all_get_sizes_game(the_chunk->MultiObject[0],the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + if(width>0 && height>0) + { + + + scale = (bounds_rect->GetWidth()<<16)/width; + scale_y = (bounds_rect->GetHeight()<<16)/height; + if(scale_y>8; + engine.Scale = (5000*scale)>>16; + + //calc new mids with this scale + test_draw_all_get_sizes_game(the_chunk->MultiObject[0],the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + + mid_x-=bounds_rect->GetWidth()>>1; + mid_y-=bounds_rect->GetHeight()>>1; + engine.VW2-=mid_x; + engine.VH2-=mid_y; + + } +// LogText(" drawkeyframe scale %d \n",engine.Scale); + + // + // body part system + // + start_object=prim_multi_objects[the_chunk->MultiObject[0]].StartObject; + for(c2=0;c2ElementCount;c2++) + { + SLONG object_offset; + if(the_frame->FirstElement==0) + goto error; + + // + // for each vue frame we need an object to draw + // + + object_offset=c2;//the_chunk->PeopleTypes[person_id].BodyPart[c2]; + the_element = &the_frame->FirstElement[c2]; //vue part + test_draw_game(start_object+object_offset,0,0,0,0,the_element,the_element,r_matrix); + } + + render_view(0); + outline_rect.OutlineRect(0); + + engine.X = temp_x; + engine.Y = temp_y; + engine.Z = temp_z; + engine.Scale = temp_scale; + engine.ShowDebug= 1; + engine.BucketSize= MAX_BUCKETS; + engine.VW2 = temp_vw2; + engine.VH2 = temp_vh2; +error:; + MemFree(rotate_vectors); + MemFree(flags); +} + +//--------------------------------------------------------------- +//--------------------------------------------------------------- + +extern void invert_mult(struct Matrix33 *mat,struct PrimPoint *pp); +/* +void KeyFrameEditor::SortMultiObject(struct KeyFrameChunk *the_chunk) +{ + SLONG c0,c1, + sp,ep; + struct KeyFrameElement *the_element; + struct PrimObject *p_obj; + + + p_obj = &prim_objects[prim_multi_objects[the_chunk->MultiObject].StartObject]; + the_element = the_chunk->KeyFrames[0].FirstElement; + for(c0=0;c0ElementCount;c0++,p_obj++,the_element++) + { + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + for(c1=sp;c1OffsetX; + prim_points[c1].Y -= the_element->OffsetY; + prim_points[c1].Z -= the_element->OffsetZ; + invert_mult(&the_element->Matrix,&prim_points[c1]); + } + } +} +*/ +//--------------------------------------------------------------- + +void KeyFrameEditor::DrawKeyFrames(void) +{ + CBYTE text[64]; + SLONG c0, + first_frame, + max_frames; + EdRect frame_rect, + hilite_rect; + MFPoint mouse_point; + struct Matrix33 r_matrix; + + + WindowControls.SetControlDrawArea(); + if(test_chunk->MultiObject) + { + KeyFrameRect.FillRect(ACTIVE_COL); + rotate_obj(AnimAngleX[Bank] + AnimGlobalAngleX,AnimAngleY[Bank] + AnimGlobalAngleY,0,&r_matrix); + max_frames = KeyFrameRect.GetWidth()/KEY_FRAME_IMAGE_SIZE; + first_frame = ((CHSlider*)WindowControls.GetControlPtr(CTRL_FRAME_SLIDER))->GetCurrentValue(); +// if((first_frame+max_frames)>KeyFrameCount) +// max_frames = (KeyFrameCount-first_frame)+1; + if((first_frame+max_frames)>test_chunk->KeyFrameCount) + max_frames = (test_chunk->KeyFrameCount-first_frame)+1; +//md LogText(" DRAW KEY FRAMES\n"); +// LogText(" draw keyframes anglex %d angley %d \n",AnimAngleX[Bank],AnimAngleY[Bank]); + for(c0=0;c0MultiObject,&frame_rect,&test_chunk->KeyFrames[first_frame+c0],&r_matrix); + + sprintf(text,"%d",(first_frame+c0)); + QuickTextC(3,1,text,WHITE_COL); +//md break; + + } + } + WindowControls.SetControlDrawArea(); + KeyFrameRect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::DrawAnimFrames(Anim *the_anim,BOOL hilite) +{ + CBYTE text[16]; + SLONG c0, + first_frame, + max_frames; + EdRect frame_rect, + hilite_rect, + tween_rect; + MFPoint mouse_point; + struct KeyFrame *current_frame; + struct Matrix33 r_matrix; + + + AnimControls.SetControlDrawArea(); + if(the_anim) + { + AnimFrameRect.FillRect(ACTIVE_COL); +//md rotate_obj(AnimAngleX[Bank],AnimAngleY[Bank],0,&r_matrix); + rotate_obj(0,AnimAngleY[Bank],0,&r_matrix); + max_frames = AnimFrameRect.GetWidth()/KEY_FRAME_IMAGE_SIZE; + first_frame = ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->GetCurrentValue(); + if((first_frame+max_frames)>the_anim->GetFrameCount()) + max_frames = (the_anim->GetFrameCount()-first_frame); + current_frame = the_anim->GetFrameList(); + if(current_frame) + { + for(c0=0;c0NextFrame; + } + SelectedFrame = NULL; + for(c0=0;c0MultiObject,&frame_rect,current_frame,&r_matrix); + { + CBYTE str[100]; + sprintf(str,"%d",current_frame->FrameID); + QuickTextC(2,2,str,WHITE_COL); + } + + AnimControls.SetControlDrawArea(); + tween_rect.SetRect ( + AnimFrameRect.GetLeft()+(c0*KEY_FRAME_IMAGE_SIZE)+2, + (AnimFrameRect.GetBottom()-(QTStringHeight()+5))-1, + 22, + QTStringHeight()+5 + ); + tween_rect.FillRect(0); + sprintf(text,"%d",current_frame->TweenStep); + QuickTextC ( + tween_rect.GetLeft()+((tween_rect.GetWidth()-QTStringWidth(text))>>1), + tween_rect.GetTop()+((tween_rect.GetHeight()-QTStringHeight())>>1), + text, + 255 + ); + current_frame = current_frame->NextFrame; + } + } + } + AnimControls.SetControlDrawArea(); + AnimFrameRect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +Anim *KeyFrameEditor::DrawAllAnimsBox(void) +{ + SLONG c0, + first_frame, + text_x, + text_y; + Anim *current_anim, + *selected_anim; + EdRect name_rect; + MFPoint mouse_point; + CBYTE str[100]; + SLONG skip_frames; + + + selected_anim = 0; + AllAnimsRect.FillRect(ACTIVE_COL); + if(AnimList[Bank]) + { + first_frame = ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->GetCurrentValue()+1; + skip_frames=first_frame; + current_anim = AnimList[Bank]; + while(first_frame--) + { + if(current_anim->GetNextAnim()) + current_anim = current_anim->GetNextAnim(); + else + break; + } + + text_x = AllAnimsRect.GetLeft()+2; + text_y = AllAnimsRect.GetTop()+1; + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + GlobalToLocal(&mouse_point); + for(c0=0;c0<22&¤t_anim;c0++) + { + name_rect.SetRect(text_x-1,text_y,AllAnimsRect.GetWidth()-2,QTStringHeight()+1); + if(current_anim==CurrentAnim[Bank]) + { + name_rect.FillRect(LOLITE_COL); + } + if(name_rect.PointInRect(&mouse_point)) + { + name_rect.FillRect(HILITE_COL); + selected_anim = current_anim; + } + sprintf(str,"(%d) %s",c0+skip_frames, current_anim->GetAnimName()); + + if(unused_flags[skip_frames+c0]) + QuickText(text_x,text_y,str,YELLOW_COL); + else + QuickText(text_x,text_y,str,0); + text_y += QTStringHeight()+1; + current_anim = current_anim->GetNextAnim(); + } + } + AllAnimsRect.HiliteRect(LOLITE_COL,HILITE_COL); + return selected_anim; +} + +//--------------------------------------------------------------- +void KeyFrameEditor::ClearAll(void) +{ + + while(AnimList[Bank]) + DestroyAnim(AnimList[Bank]); + + test_chunk->MultiObject=0; + test_chunk->ElementCount=0; + +} + +void KeyFrameEditor::AppendAnim(void) +{ + CBYTE text[32]; + SLONG max_range; + Anim *next_anim, + *the_anim; + + + the_anim = new Anim; + if(the_anim) + { + AnimCount[Bank]++; + sprintf(text,"New Anim %d",AnimCount[Bank]); + the_anim->SetAnimName(text); + if(AnimList[Bank]) + { + next_anim = AnimList[Bank]; + while(1) + { + if(next_anim->GetNextAnim()) + next_anim = next_anim->GetNextAnim(); + else + break; + } + next_anim->SetNextAnim(the_anim); + the_anim->SetLastAnim(next_anim); + } + else + { + AnimList[Bank] = the_anim; + } + CurrentAnim[Bank] = the_anim; + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_DESELECTED); + max_range = AnimCount[Bank]-22; + if(max_range<0) + max_range = 0; + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetValueRange(0,max_range); + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetCurrentValue(max_range); + } +} +void KeyFrameEditor::InsertAnim(Anim *insert_here) +{ + CBYTE text[32]; + SLONG max_range; + Anim *next_anim, + *prev_anim, + *the_anim; + + + the_anim = new Anim; + if(the_anim) + { + AnimCount[Bank]++; + sprintf(text,"New Anim %d",AnimCount[Bank]); + the_anim->SetAnimName(text); + if(insert_here) + { + prev_anim=insert_here->GetLastAnim(); + if(prev_anim) + { + prev_anim->SetNextAnim(the_anim); + insert_here->SetLastAnim(the_anim); + the_anim->SetLastAnim(prev_anim); + the_anim->SetNextAnim(insert_here); + } + else + { + the_anim->SetNextAnim(AnimList[Bank]); + AnimList[Bank]->SetLastAnim(the_anim); + AnimList[Bank]=the_anim; + + } + } + CurrentAnim[Bank] = the_anim; + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_DESELECTED); + max_range = AnimCount[Bank]-22; + if(max_range<0) + max_range = 0; + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetValueRange(0,max_range); + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetCurrentValue(max_range); + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::DestroyAnim(Anim *the_anim) +{ + SLONG max_range; + + + if(the_anim) + { + if(the_anim->GetLastAnim()) + the_anim->GetLastAnim()->SetNextAnim(the_anim->GetNextAnim()); + else + AnimList[Bank] = the_anim->GetNextAnim(); + + if(the_anim->GetNextAnim()) + the_anim->GetNextAnim()->SetLastAnim(the_anim->GetLastAnim()); + + delete the_anim; + + AnimCount[Bank]--; + max_range = AnimCount[Bank]-22; + if(max_range<0) + max_range = 0; + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetValueRange(0,max_range); + ((CVSlider*)AnimControls.GetControlPtr(CTRL_ANIM_ALL_ANIMS_SLIDER))->SetCurrentValue(max_range); + + CurrentAnim[Bank] = 0; + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_DESELECTED); + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::LoadAllAnims(KeyFrameChunk *the_chunk) +{ + SLONG anim_count,version, + c0; + MFFileHandle file_handle; + + + file_handle = FileOpen(the_chunk->ANMName); + if(file_handle!=FILE_OPEN_ERROR) + { + FileRead(file_handle,&anim_count,sizeof(anim_count)); + if(anim_count<0) + { + version=anim_count; + FileRead(file_handle,&anim_count,sizeof(anim_count)); + + LoadBodyPartInfo(file_handle,version,the_chunk); + + } + + for(c0=0;c0GetAnimFlags()&ANIM_LOOP) + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_SELECTED); + else + AnimControls.SetControlState(CTRL_ANIM_LOOP_SELECT,CTRL_DESELECTED); + ((CHSlider*)AnimControls.GetControlPtr(CTRL_ANIM_FRAME_SLIDER))->SetValueRange(0,CurrentAnim[Bank]->GetFrameCount()-1); + AnimTween[Bank] = 0; + CurrentFrame[Bank] = 0; + FileClose(file_handle); + } + else + { + // Unable to open file. + } +} + +//--------------------------------------------------------------- +void KeyFrameEditor::SaveBodyPartInfo(MFFileHandle file_handle,SLONG version,KeyFrameChunk *the_chunk) +{ + SLONG c0,c1; + SLONG data; + + data=MAX_PEOPLE_TYPES; + FileWrite(file_handle,&data,sizeof(data)); + + data=MAX_BODY_BITS; + FileWrite(file_handle,&data,sizeof(data)); + + data=PEOPLE_NAME_SIZE; + FileWrite(file_handle,&data,sizeof(data)); + + for(c0=0;c0PeopleNames[c0],PEOPLE_NAME_SIZE); + for(c1=0;c1PeopleTypes[c0].BodyPart[c1],sizeof(UBYTE)); + } +} + +void KeyFrameEditor::LoadBodyPartInfo(MFFileHandle file_handle,SLONG version,KeyFrameChunk *the_chunk) +{ + SLONG c0,c1; + SLONG no_people,no_body_bits,string_len; + + FileRead(file_handle,&no_people,sizeof(SLONG)); + + FileRead(file_handle,&no_body_bits,sizeof(SLONG)); + + FileRead(file_handle,&string_len,sizeof(SLONG)); + + for(c0=0;c0PeopleNames[c0],string_len); + for(c1=0;c1PeopleTypes[c0].BodyPart[c1],sizeof(UBYTE)); + } +} + +extern SLONG save_a_multi_prim(CBYTE *name,SLONG multi); +void KeyFrameEditor::SaveAllAnims(KeyFrameChunk *the_chunk,SLONG save_all) +{ + Anim *next_anim; + MFFileHandle file_handle; + SLONG version=-1; + + + if(AnimList[Bank]) + { + save_a_multi_prim(the_chunk->ANMName,the_chunk->MultiObject); + + file_handle = FileCreate(the_chunk->ANMName,TRUE); + if(file_handle!=FILE_CREATION_ERROR) + { + FileWrite(file_handle,&version,sizeof(version)); + FileWrite(file_handle,&AnimCount[Bank],sizeof(AnimCount[Bank])); + SaveBodyPartInfo(file_handle,version,the_chunk); + next_anim = AnimList[Bank]; + while(next_anim) + { + SaveAnim(file_handle,next_anim); + next_anim = next_anim->GetNextAnim(); + } + FileClose(file_handle); + } + else + { + SLONG res; + res=GetLastError(); + DebugText(" failed to create %s error %d \n",the_chunk->ANMName,res); + } + } + SaveChunkTextureInfo(the_chunk); + save_recenter_flags(the_chunk->ANMName); + + + if(save_all) + { + void convert_anim(Anim *key_list,GameKeyFrameChunk *game_chunk,KeyFrameChunk *the_chunk); + extern void free_game_chunk(GameKeyFrameChunk *the_chunk); + free_game_chunk(&game_chunk[0]); + + convert_anim(AnimList[Bank],&game_chunk[0],the_chunk); + + { + CBYTE file_name[100]; + SLONG c0=0; + + strcpy(file_name,the_chunk->VUEName); + while(file_name[c0]!='.' && file_name[c0]!=0)c0++; + if(file_name[c0]=='.') + { + file_name[c0+1] = 'A'; + file_name[c0+2] = 'L'; + file_name[c0+3] = 'L'; + file_name[c0+4] = 0; + } + + extern SLONG save_anim_system(struct GameKeyFrameChunk *game_chunk,CBYTE *name); + + save_anim_system(&game_chunk[0],file_name); + free_game_chunk(&game_chunk[0]); + } + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::LoadAnim(MFFileHandle file_handle,Anim *the_anim) +{ + CBYTE anim_name[ANIM_NAME_SIZE]; + SLONG anim_flags, + c0, + frame_count, + frame_id, + tween_step; + KeyFrame *the_frame,*new_frame; + SWORD chunk_id; + SWORD fixed=0; + CBYTE version=0; + + + FileRead(file_handle,&version,1); + + if(version==0||version>20) + { + anim_name[0]=version; + FileRead(file_handle,&anim_name[1],ANIM_NAME_SIZE-1); + version=0; + } + else + FileRead(file_handle,anim_name,ANIM_NAME_SIZE); + + FileRead(file_handle,&anim_flags,sizeof(anim_flags)); + FileRead(file_handle,&frame_count,sizeof(frame_count)); + the_anim->SetAnimName(anim_name); + if(version>3) + { + UBYTE speed; + FileRead(file_handle,&speed,1); + the_anim->SetTweakSpeed(speed); + } + else + the_anim->SetTweakSpeed(128); + + for(c0=0;c00) + FileRead(file_handle,&fixed,sizeof(fixed)); + + the_frame = &test_chunk->KeyFrames[frame_id]; + the_frame->TweenStep = tween_step; + the_frame->Fixed = fixed; + the_frame->Fight = 0; + if(version>1) + { + struct FightCol *fcol,*fcol_prev=0; + SLONG count,c0; + + FileRead(file_handle,&count,sizeof(count)); +// LogText(" fight count load = %d \n",count); + + for(c0=0;c0Next=0; + if(c0==0) + { + the_frame->Fight=fcol; + } + else + { + fcol_prev->Next=fcol; + } + fcol_prev=fcol; + } + } + } + the_anim->AddKeyFrame(the_frame); + the_frame->Fight=0; + } + the_anim->SetAnimFlags(anim_flags); + if(anim_flags&ANIM_LOOP) + the_anim->StartLooping(); +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::SaveAnim(MFFileHandle file_handle,Anim *the_anim) +{ + ULONG anim_flags; + SLONG c0, + frame_count; + KeyFrame *frame_list; + CBYTE version=4; + UBYTE speed; + + + frame_list = the_anim->GetFrameList(); + anim_flags = the_anim->GetAnimFlags(); + frame_count = the_anim->GetFrameCount(); + + FileWrite(file_handle,&version,1); + FileWrite(file_handle,the_anim->GetAnimName(),ANIM_NAME_SIZE); + FileWrite(file_handle,&anim_flags,sizeof(anim_flags)); + FileWrite(file_handle,&frame_count,sizeof(frame_count)); + speed=the_anim->GetTweakSpeed(); + FileWrite(file_handle,&speed,1); + for(c0=0;c0ChunkID,sizeof(frame_list->ChunkID)); + FileWrite(file_handle,&frame_list->FrameID,sizeof(frame_list->FrameID)); + FileWrite(file_handle,&frame_list->TweenStep,sizeof(frame_list->TweenStep)); + FileWrite(file_handle,&frame_list->Fixed,sizeof(frame_list->Fixed)); + if(version>1) + { + fcol=frame_list->Fight; + count=0; + while(fcol) + { + count++; + fcol=fcol->Next; + } + LogText(" fight count save = %d \n",count); + FileWrite(file_handle,&count,sizeof(count)); + fcol=frame_list->Fight; + while(fcol) + { + FileWrite(file_handle,fcol,sizeof(struct FightCol)); + fcol=fcol->Next; + } + } + + frame_list = frame_list->NextFrame; + } +} +//--------------------------------------------------------------- + +void KeyFrameEditor::LoadKeyFrameChunks(void) +{ + SLONG c0; +/* + + test_chunk->KeyFrameCount = 0; + strcpy(test_chunk->VUEName,"data\\"); + strcat(test_chunk->VUEName,"man.vue"); + strcpy(test_chunk->ASCName,test_chunk->VUEName); + strcpy(test_chunk->ANMName,test_chunk->VUEName); + c0=0; + while(test_chunk->ASCName[c0]!='.' && test_chunk->ASCName[c0]!=0)c0++; + if(test_chunk->ASCName[c0]=='.') + { + test_chunk->ASCName[c0+1] = 'A'; + test_chunk->ASCName[c0+2] = 'S'; + test_chunk->ASCName[c0+3] = 'C'; + test_chunk->ASCName[c0+4] = 0; + + test_chunk->ANMName[c0+1] = 'A'; + test_chunk->ANMName[c0+2] = 'N'; + test_chunk->ANMName[c0+3] = 'M'; + test_chunk->ANMName[c0+4] = 0; + } + if(read_multi_asc(test_chunk->ASCName,0)) + { + test_chunk->MultiObject = next_prim_multi_object-1; + test_chunk->ElementCount = prim_multi_objects[test_chunk->MultiObject].EndObject-prim_multi_objects[test_chunk->MultiObject].StartObject; + load_multi_vue(&test_chunk); + LoadChunkTextureInfo(&test_chunk); + } + + */ +} + +//--------------------------------------------------------------- + +void KeyFrameEditor::SaveChunkTextureInfo(KeyFrameChunk *the_chunk) +{ + CBYTE file_name[64]; + SLONG c0 = 0, + c1,c2; + MFFileHandle file_handle; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + struct PrimObject *p_obj; + SLONG save_type=1; + SLONG count=0; + SLONG multi; + + + strcpy(file_name,the_chunk->VUEName); + while(file_name[c0]!='.' && file_name[c0]!=0)c0++; + if(file_name[c0]=='.') + { + file_name[c0+1] = 'T'; + file_name[c0+2] = 'E'; + file_name[c0+3] = 'X'; + file_name[c0+4] = 0; + } + + for(multi=the_chunk->MultiObjectStart;multi<=the_chunk->MultiObjectEnd;multi++) + { + if(count>0) + { + file_name[5]='1'+count-1; + } + + file_handle = FileCreate(file_name,TRUE); + if(file_handle!=FILE_CREATION_ERROR) + { + //SLONG multi=the_chunk->MultiObjectStart; + FileWrite(file_handle,&save_type,sizeof(save_type)); + + // for(multi=the_chunk->MultiObjectStart;multi<=the_chunk->MultiObjectEnd;multi++) + for(c0=prim_multi_objects[multi].StartObject;c0StartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + + count=p_obj->EndFace4-p_obj->StartFace4; + FileWrite(file_handle,&count,sizeof(count)); + for(c1=p_obj->StartFace4;c1EndFace4;c1++,p_f4++) + { + FileWrite(file_handle,&p_f4->DrawFlags,sizeof(p_f4->DrawFlags)); + FileWrite(file_handle,&p_f4->Col2,sizeof(p_f4->Col2)); + FileWrite(file_handle,&p_f4->TexturePage,sizeof(p_f4->TexturePage)); + FileWrite(file_handle,&p_f4->FaceFlags,sizeof(p_f4->FaceFlags)); + + for(c2=0;c2<4;c2++) + { + FileWrite(file_handle,&p_f4->UV[c2][0],sizeof(p_f4->UV[c2][0])); + FileWrite(file_handle,&p_f4->UV[c2][1],sizeof(p_f4->UV[c2][1])); + } + } + + count=p_obj->EndFace3-p_obj->StartFace3; + FileWrite(file_handle,&count,sizeof(count)); + for(c1=p_obj->StartFace3;c1EndFace3;c1++,p_f3++) + { + FileWrite(file_handle,&p_f3->DrawFlags,sizeof(p_f3->DrawFlags)); + FileWrite(file_handle,&p_f3->Col2,sizeof(p_f3->Col2)); + FileWrite(file_handle,&p_f3->TexturePage,sizeof(p_f3->TexturePage)); + FileWrite(file_handle,&p_f3->FaceFlags,sizeof(p_f3->FaceFlags)); + + for(c2=0;c2<3;c2++) + { + FileWrite(file_handle,&p_f3->UV[c2][0],sizeof(p_f3->UV[c2][0])); + FileWrite(file_handle,&p_f3->UV[c2][1],sizeof(p_f3->UV[c2][1])); + } + } + } + FileClose(file_handle); + } + count++; + } +} + +//--------------------------------------------------------------- + + +void KeyFrameEditor::LoadChunkTextureInfo(KeyFrameChunk *the_chunk) +{ + + // + // this is in edutils.cpp + // + load_chunk_texture_info(the_chunk); +/* + CBYTE file_name[64]; + SLONG c0 = 0, + c1,c2; + MFFileHandle file_handle; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + struct PrimObject *p_obj; + SLONG save_type; + + + strcpy(file_name,the_chunk->VUEName); + while(file_name[c0]!='.' && file_name[c0]!=0)c0++; + if(file_name[c0]=='.') + { + file_name[c0+1] = 'T'; + file_name[c0+2] = 'E'; + file_name[c0+3] = 'X'; + file_name[c0+4] = 0; + } + + file_handle = FileOpen(file_name); + if(file_handle!=FILE_OPEN_ERROR) + { + // FileRead(file_handle,&save_type,sizeof(save_type)); + //if(save_type==0) + { + for(c0=prim_multi_objects[the_chunk->MultiObject].StartObject;c0<=prim_multi_objects[the_chunk->MultiObject].EndObject;c0++,c1++) + { + SLONG count; + p_obj = &prim_objects[c0]; + p_f4 = &prim_faces4[p_obj->StartFace4]; + p_f3 = &prim_faces3[p_obj->StartFace3]; + + + //FileRead(file_handle,&count,sizeof(count)); + for(c1=p_obj->StartFace4;c1EndFace4;c1++,p_f4++,count--) + { + FileRead(file_handle,&p_f4->DrawFlags,sizeof(p_f4->DrawFlags)); + FileRead(file_handle,&p_f4->Col2,sizeof(p_f4->Col2)); + FileRead(file_handle,&p_f4->TexturePage,sizeof(p_f4->TexturePage)); + + for(c2=0;c2<4;c2++) + { + FileRead(file_handle,&p_f4->UV[c2][0],sizeof(p_f4->UV[c2][0])); + FileRead(file_handle,&p_f4->UV[c2][1],sizeof(p_f4->UV[c2][1])); + } + } + + //FileRead(file_handle,&count,sizeof(count)); + for(c1=p_obj->StartFace3;c1EndFace3;c1++,p_f3++,count--) + { + FileRead(file_handle,&p_f3->DrawFlags,sizeof(p_f3->DrawFlags)); + FileRead(file_handle,&p_f3->Col2,sizeof(p_f3->Col2)); + FileRead(file_handle,&p_f3->TexturePage,sizeof(p_f3->TexturePage)); + + for(c2=0;c2<3;c2++) + { + FileRead(file_handle,&p_f3->UV[c2][0],sizeof(p_f3->UV[c2][0])); + FileRead(file_handle,&p_f3->UV[c2][1],sizeof(p_f3->UV[c2][1])); + } + } + } + } + FileClose(file_handle); + } +*/ +} + +//--------------------------------------------------------------- + +void draw_key_frames(void) +{ + //MD the_editor->DrawKeyFrames(); +} + +//--------------------------------------------------------------- + +void draw_anim_frames(void) +{ + if(the_editor->GetCurrentAnim()) + the_editor->DrawAnimFrames(the_editor->GetCurrentAnim(),FALSE); +} + +//--------------------------------------------------------------- + +void draw_all_anims_box(void) +{ + the_editor->DrawAllAnimsBox(); +} + +//--------------------------------------------------------------- + +void set_key_framer_camera() +{ + SLONG angle; + set_camera(); + return; + + engine.VW=WorkWindowWidth; + engine.VH=WorkWindowHeight; + + engine.VW2=engine.VW>>1; + engine.VH2=engine.VH>>1; + + + engine.CosY=COS(0); + engine.SinY=SIN(0); + + engine.CosX=COS(0); + engine.SinX=SIN(0); + + engine.CosZ=COS(0); + engine.SinZ=SIN(0); +} + +void set_key_framer_camera_plan() +{ + SLONG angle; + + engine.VW=WorkWindowWidth; + engine.VH=WorkWindowHeight; + + engine.VW2=engine.VW>>1; + engine.VH2=engine.VH>>1; + + + engine.CosY=COS(0); + engine.SinY=SIN(0); + + engine.CosX=COS(512); + engine.SinX=SIN(512); + + engine.CosZ=COS(0); + engine.SinZ=SIN(0); +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/KFramer.cpp b/fallen/Editor/Source/KFramer.cpp new file mode 100644 index 0000000..7a7b830 --- /dev/null +++ b/fallen/Editor/Source/KFramer.cpp @@ -0,0 +1,514 @@ +// KFramer.cpp +// Guy Simmons, 19th September 1997. + + +#include "Editor.hpp" +#include "c:\fallen\headers\memory.h" + +#define CONTROLS_HEIGHT 400 +#define CONTROLS_WIDTH 200 + +#define KEY_FRAME_COUNT 12 +#define KEY_FRAME_IMAGE_SIZE 48 + +#include "KFDef2.c" + + +extern SLONG key_frame_count; +extern struct KeyFrameChunk test_chunk2; + +extern void matrix_transformZMY(Matrix31* result, Matrix33* trans, Matrix31* mat2); +extern void matrix_transform(struct Matrix31* result, struct Matrix33* trans,struct Matrix31* mat2); + +// Used by fudgy centering bit. +extern SLONG x_centre, + y_centre, + z_centre; + +static KeyFrameEditor2 *the_editor; + +void test_draw_all_get_sizes(SWORD multi_prim,struct KeyFrame *the_frame,SLONG x,SLONG y,SLONG z,SLONG tween,struct Matrix33 *rot_mat,SLONG *width,SLONG *height,SLONG *mid_x,SLONG *mid_y); +void update_key_frames(void); + +//--------------------------------------------------------------- + +KeyFrameEditor2::~KeyFrameEditor2() +{ + +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::SetupModule(void) +{ + KeyFrameEdDefaults the_defaults; + + + the_editor = this; + the_defaults.Left = 0; + the_defaults.Top = 0; + the_defaults.Width = CONTROLS_WIDTH+(KEY_FRAME_COUNT*KEY_FRAME_IMAGE_SIZE)+17; + the_defaults.Height = 400; + SetupWindow ( + "Key Frame Editor", + (HAS_TITLE|HAS_CONTROLS), + the_defaults.Left, + the_defaults.Top, + the_defaults.Width, + the_defaults.Height + ); + SetContentColour(CONTENT_COL); + SetControlsHeight(CONTROLS_HEIGHT); + SetControlsWidth(CONTROLS_WIDTH); + + AnimAngleX = 0; + AnimAngleY = 0; + AnimAngleZ = 0; + AnimOffsetX = 0; + AnimOffsetY = 0; + AnimOffsetZ = 0; + AnimScale = 296; + AnimTween = 0; + + KeyFramesControls.InitControlSet(kframe_ctrls_def); + ((CHSlider*)KeyFramesControls.GetControlPtr(CTRL_KF_FRAME_SLIDER))->SetUpdateFunction(update_key_frames); + KeyFramesRect.SetRect(2,KEY_FRAME_IMAGE_SIZE-20,(KEY_FRAME_COUNT*KEY_FRAME_IMAGE_SIZE)+2,KEY_FRAME_IMAGE_SIZE+2); +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::DrawContent(void) +{ + EdRect temp_rect; + + + SetContentDrawArea(); + ClearContent(); + + // Draw key frame controls. + temp_rect.SetRect ( + ContentLeft(), + ContentBottom()-(KEY_FRAME_IMAGE_SIZE<<1)+1, + ContentWidth(), + KEY_FRAME_IMAGE_SIZE<<1 + ); + KeyFramesControls.ControlSetBounds(&temp_rect); + KeyFramesControls.DrawControlSet(); + KeyFramesControls.HiliteControlDrawArea(HILITE_COL,LOLITE_COL); + + // Draw key frames. + DrawKeyFrames(); +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::HandleContentClick(UBYTE flags,MFPoint *clicked_point) +{ + ULONG cleanup, + update; + SLONG c0, + first_frame, + selected_frame, + x_diff, + y_diff; + EdRect frame_rect, + last_rect, + temp_rect; + MFPoint local_point; + + + HandleKeyFramesControl(KeyFramesControls.HandleControlSetClick(flags,clicked_point)); + + local_point = *clicked_point; + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + if(KeyFramesRect.PointInRect(&local_point)) + { + // Find out which frame hass been selected. + selected_frame = -1; + first_frame = ((CHSlider*)KeyFramesControls.GetControlPtr(CTRL_KF_FRAME_SLIDER))->GetCurrentValue(); + + for(c0=0;c0=0) + { + SetWorkWindowBounds(0,0,WorkScreenWidth,WorkScreenHeight); + + temp_rect.SetRect ( + frame_rect.GetLeft(), + frame_rect.GetTop(), + frame_rect.GetWidth(), + frame_rect.GetHeight() + ); + x_diff = clicked_point->X-temp_rect.GetLeft(); + y_diff = clicked_point->Y-temp_rect.GetTop(); + last_rect.SetRect(0,0,0,0); + cleanup = 0; + update = 0; + while(SHELL_ACTIVE && LeftButton) + { + temp_rect.SetRect(MouseX-x_diff,MouseY-y_diff,temp_rect.GetWidth(),temp_rect.GetHeight()); + if(temp_rect.GetLeft()<0) + temp_rect.MoveRect(0,temp_rect.GetTop()); + if(temp_rect.GetTop()<0) + temp_rect.MoveRect(temp_rect.GetLeft(),0); + if(temp_rect.GetRight()>=WorkScreenWidth) + temp_rect.MoveRect(WorkScreenWidth-temp_rect.GetWidth(),temp_rect.GetTop()); + if(temp_rect.GetBottom()>=WorkScreenHeight) + temp_rect.MoveRect(temp_rect.GetLeft(),WorkScreenHeight-temp_rect.GetHeight()); + + if(MouseMoved) + { + MouseMoved = 0; + + // Check to see if the frame is above anything relevent here. + + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + ShowWorkScreen(0); + if(LockWorkScreen()) + { + temp_rect.OutlineInvertedRect(); + UnlockWorkScreen(); + } + } + } + RequestUpdate(); + } + } + break; + case RIGHT_CLICK: + break; + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::HandleControlClick(UBYTE flags,MFPoint *clicked_point) +{ +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::HandleModule(void) +{ + UBYTE update = 0; + MFPoint mouse_point; + static UBYTE cleanup_content = 0; + static MFPoint last_point; + + + if(LastKey) + { + // Handle hot keys for controls here. + } + + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + KeyFramesControls.HandleControlSet(&mouse_point); + + if(PointInContent(&mouse_point)) + { + if(KeyFramesControls.PointInControlSet(&mouse_point)) + { + if(MouseMoved) + { + MouseMoved = 0; + update = 1; + cleanup_content = 1; + } + } + else if(cleanup_content) + { + update = 1; + cleanup_content = 0; + } + } + else if(cleanup_content) + { + update = 1; + cleanup_content = 0; + } + + + + if(update) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + if(LockWorkScreen()) + { + DrawControls(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::HandleKeyFramesControl(ULONG control_id) +{ + SLONG c0; + FileRequester *fr; + + + switch(control_id) + { + case 0: + break; + case CTRL_KF_LOAD_BUTTON: + fr = new FileRequester("DATA\\","*.VUE","Load a VUE file",".VUE"); + fr->Draw(); + strcpy(test_chunk2.VUEName,fr->Path); + strcat(test_chunk2.VUEName,fr->FileName); + strcpy(test_chunk2.ASCName,test_chunk2.VUEName); + strcpy(test_chunk2.ANMName,test_chunk2.VUEName); + c0=0; + while(test_chunk2.ASCName[c0]!='.' && test_chunk2.ASCName[c0]!=0)c0++; + if(test_chunk2.ASCName[c0]=='.') + { + test_chunk2.ASCName[c0+1] = 'A'; + test_chunk2.ASCName[c0+2] = 'S'; + test_chunk2.ASCName[c0+3] = 'C'; + test_chunk2.ASCName[c0+4] = 0; + + test_chunk2.ANMName[c0+1] = 'A'; + test_chunk2.ANMName[c0+2] = 'N'; + test_chunk2.ANMName[c0+3] = 'M'; + test_chunk2.ANMName[c0+4] = 0; + } + delete fr; + RequestUpdate(); + + if(read_multi_asc(test_chunk2.ASCName,0)) + { + test_chunk2.MultiObject = next_prim_multi_object-1; + test_chunk2.ElementCount = prim_multi_objects[test_chunk2.MultiObject].EndObject-prim_multi_objects[test_chunk2.MultiObject].StartObject; + + // Fudgy bit for centering. + { +SLONG c1, + sp,ep; +struct PrimObject *p_obj; + + + for(c0=prim_multi_objects[test_chunk2.MultiObject].StartObject;c0<=prim_multi_objects[test_chunk2.MultiObject].EndObject;c0++) + { + p_obj = &prim_objects[c0]; + sp = p_obj->StartPoint; + ep = p_obj->EndPoint; + + for(c1=sp;c1SetValueRange(0,key_frame_count-(KEY_FRAME_COUNT-1)); +/* + LoadAllAnims(&test_chunk2); + LoadChunkTextureInfo(&test_chunk2); +*/ + } + break; + case CTRL_KF_FRAME_SLIDER: + if(LockWorkScreen()) + { + DrawKeyFrames(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + break; + } +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::DrawKeyFrames(void) +{ + SLONG c0, + first_frame; + EdRect draw_rect, + frame_rect; + MFPoint mouse_point; + struct Matrix33 r_matrix; + + + if(test_chunk2.MultiObject) + { + KeyFramesRect.FillRect(ACTIVE_COL); + rotate_obj((SWORD)AnimAngleX,(SWORD)AnimAngleY,0,&r_matrix); + first_frame = ((CHSlider*)KeyFramesControls.GetControlPtr(CTRL_KF_FRAME_SLIDER))->GetCurrentValue(); + + for(c0=0;c0GetLeft(),KeyFramesControls.ControlGetBounds()->GetTop()); + DrawKeyFrame(test_chunk2.MultiObject,&draw_rect,&test_chunk2.KeyFrames[first_frame+c0],&r_matrix); + } + } + KeyFramesControls.SetControlDrawArea(); + KeyFramesRect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +void KeyFrameEditor2::DrawKeyFrame(UWORD multi_object,EdRect *bounds_rect,struct KeyFrame *the_frame,struct Matrix33 *r_matrix) +{ + SLONG c0,c1,c2, + scale, + scale_y, + temp_scale, + temp_x, + temp_y, + temp_z, + temp_vw2, + temp_vh2, + width,height, + *flags; + EdRect outline_rect; + struct KeyFrameElement *the_element; + struct SVector *rotate_vectors; + SLONG mid_x=0,mid_y=0; + + + // Stop the compiler moaning. + multi_object = multi_object; + + if(!test_chunk2.MultiObject) + return; + + c1 = 0; + flags = (SLONG*)MemAlloc(sizeof(SLONG)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + rotate_vectors = (struct SVector*)MemAlloc(sizeof(struct SVector)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + + + temp_scale = engine.Scale; + temp_x = engine.X; + temp_y = engine.Y; + temp_z = engine.Z; + temp_vw2 = engine.VW2; + temp_vh2 = engine.VH2; + + engine.X = 0; + engine.Y = 0; + engine.Z = 0; + engine.Scale = 5000; + engine.ShowDebug= 0; + engine.BucketSize= MAX_BUCKETS>>4; + + SetWorkWindowBounds ( + bounds_rect->GetLeft(), + bounds_rect->GetTop(), + bounds_rect->GetWidth(), + bounds_rect->GetHeight() + ); + outline_rect.SetRect( + 0,0, + bounds_rect->GetWidth(),bounds_rect->GetHeight() + ); + + set_camera(); +// set_camera_to_base(); + + +//md LogText(" width %d height %d \n",width,height); + test_draw_all_get_sizes(test_chunk2.MultiObject,the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + if(width>0 && height>0) + { + + + scale = (bounds_rect->GetWidth()<<16)/width; + scale_y = (bounds_rect->GetHeight()<<16)/height; + if(scale_y>8; + engine.Scale = (5000*scale)>>16; + + //calc new mids with this scale + test_draw_all_get_sizes(test_chunk2.MultiObject,the_frame,0,0,0,0,r_matrix,&width,&height,&mid_x,&mid_y); + + mid_x-=bounds_rect->GetWidth()>>1; + mid_y-=bounds_rect->GetHeight()>>1; + engine.VW2-=mid_x; + engine.VH2-=mid_y; + + } +// LogText(" drawkeyframe scale %d \n",engine.Scale); + + for(c2=0,c0=prim_multi_objects[test_chunk2.MultiObject].StartObject;c0FirstElement[c2++]; + test_draw((SWORD)c0,0,0,0,0,the_element,the_element,r_matrix, NULL, NULL, NULL, NULL, NULL); + } + render_view(0); + outline_rect.OutlineRect(0); + + engine.X = temp_x; + engine.Y = temp_y; + engine.Z = temp_z; + engine.Scale = temp_scale; + engine.ShowDebug= 1; + engine.BucketSize= MAX_BUCKETS; + engine.VW2 = temp_vw2; + engine.VH2 = temp_vh2; + + MemFree(rotate_vectors); + MemFree(flags); +} + +//--------------------------------------------------------------- + +void update_key_frames(void) +{ + the_editor->DrawKeyFrames(); +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/LevelEd.cpp b/fallen/Editor/Source/LevelEd.cpp new file mode 100644 index 0000000..0bff64c --- /dev/null +++ b/fallen/Editor/Source/LevelEd.cpp @@ -0,0 +1,3798 @@ +// Guy Simmons, 19th Feb ruary 1997. + +#include "Editor.hpp" +#include "engine.h" +#include "c:\fallen\headers\game.h" +#include "c:\fallen\headers\animtmap.h" +#include "c:\fallen\headers\inside2.h" +#include "c:\fallen\headers\memory.h" +#include "c:\fallen\headers\io.h" +//#include "collide.hpp" //needed for ele_shift +//#define ShowWorkWindow(x) {DrawLineC(0,0,WorkWindowWidth-1,WorkWindowHeight-1,255);DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); ShowWorkWindow(x);} + +extern SLONG editor_texture_set; + + +//--------------------------------------------------------------- +extern void icon_load_map(UWORD id); +extern void icon_save_map(UWORD id); +extern void handle_icon_click(UWORD id); +extern void slider_redraw(void); +extern void slider_redraw_in(void); + +#define ICON_LOAD_MAP 0 +#define ICON_SAVE_MAP 1 +#define ICON_TEST_LORES 2 +#define ICON_TOGGLE_GRID 4 +#define ICON_PLACE_LIGHT 6 +#define ICON_CREATE_CITY 8 + + +#define CTRL_PSX_SAVE 1 +#define CTRL_PSX_PAGE1 1 +#define CTRL_PSX_PAGE2 2 +#define CTRL_PSX_PAGE3 3 +#define CTRL_PSX_PAGE4 4 +#define CTRL_PSX_NOREMAP 5 + +#define CTRL_STYLE_POS_SLIDER 1 +#define CTRL_STYLE_NAME_EDIT 2 +#define CTRL_STYLE_SAVE 3 + +#define CTRL_INSTYLE_POS_SLIDER 1 +#define CTRL_INSTYLE_NAME_EDIT 2 +#define CTRL_INSTYLE_SAVE 3 +ControlDef psx_content_def[] = +{ +// { BUTTON, 0, "Save Remap", 20, 480, 70, 0 }, + { BUTTON, 0, "P1", 20, 460, 20, 0 }, + { BUTTON, 0, "P2", 50, 460, 20, 0 }, + { BUTTON, 0, "P3", 80, 460, 20, 0 }, + { BUTTON, 0, "P4", 110, 460, 20, 0 }, + { BUTTON, 0, "No Remap", 200, 480, 70, 0 }, + + { 0 } +}; + +ControlDef style_content_def[] = +{ + { V_SLIDER, 0, "", 1,30, 0, 400 }, + { EDIT_TEXT, 0, "", 20, 460, 120, 0 }, + { BUTTON, 0, "Save Styles", 20, 480, 70, 0 }, + + { 0 } +}; + +ControlDef inside_style_content_def[] = +{ + { V_SLIDER, 0, "", 1,30, 0, 400 }, + { EDIT_TEXT, 0, "", 20, 460, 120, 0 }, + { BUTTON, 0, "Save Styles", 20, 480, 70, 0 }, + + { 0 } +}; + +CBYTE inside_names[64][20]= +{ + "Apartment", + "Hotel", + "WareHouse", + "Office", + "Museum", + "Industrial1", + "Industrial2", + "Police", + "Hospital" +}; + + + + + +struct AWindowIcon win_bar_icons[]= +{ + {handle_icon_click,0,18,18}, //Load + {handle_icon_click,0,19,19}, //Save + {handle_icon_click,1,20,20}, //Test Lores + {0,0,0,-1}, + {handle_icon_click,1,16,17}, //Grid Lines + {0,0,0,-1}, + {handle_icon_click,1,22,22}, //Place Light + {0,0,0,-1}, + {handle_icon_click,1,24,24}, //Create City + {0,0,0,0} +}; + +ControlDef prim_content_def[] = +{ + { H_SLIDER, 0, "", 2, 200, 300,0 }, + + { 0 } +}; +//from edutil.cpp +extern void draw_a_key_frame_at(UWORD prim,SLONG x,SLONG y,SLONG z); +extern void reset_game(void); + +UBYTE back_dat[256*256]; + +SLONG draw_background(void) +{ + SLONG x,y,mod_x; + SLONG c0,c1,width,size,height; + UBYTE *ptr,*ptr_dat; + static UBYTE type=1; + + if(Keys[KB_1]) + { + FileLoadAt("data\\back.dat",back_dat); + type=1; + } + if(Keys[KB_2]) + { + FileLoadAt("data\\back.dat",back_dat); + type=2; + } + if(Keys[KB_3]) + type=3; + if(Keys[KB_4]) + type=4; + + if(type==4) + { + return(type); + } + + + + x=(engine.X>>8)+(engine.AngleY>>5); + x>>=3; + x&=0xff; + + y=((engine.AngleX>>8)); + if(y>1024) + y=y-2048; +// y=y-240; + + + if(y<0) + { + if(-y>WorkScreenHeight) + { + memset(WorkWindow,0,WorkScreenHeight*WorkScreenWidth); + return(type); + } + + memset(WorkWindow,0,-y*WorkScreenWidth); + ptr=(UBYTE*)WorkWindow-y*WorkScreenWidth; + ptr_dat=(UBYTE*)back_dat; + height=WorkScreenHeight+y; + } + else + { + ptr=(UBYTE*)WorkWindow; + ptr_dat=(UBYTE*)back_dat+y*WorkScreenWidth; + if((256-y) width) + size = width; + + memcpy(ptr,&ptr_dat[mod_x],size); + width-=size; + mod_x+=size; + mod_x&=0xff; + ptr+=size; + } + ptr_dat+=256; + } + return(type); +} + +extern void init_hair(SLONG x,SLONG y,SLONG z); +extern void draw_hair(void); + +void do_clip_keys(void) +{ +// if(engine.ClipFlag) +// engine.ClipFlag--; + if(ShiftFlag) + engine.ClipFlag=ENGINE_CLIPZ_FLAG; + else + engine.ClipFlag&=~ENGINE_CLIPZ_FLAG; + + if(Keys[KB_LBRACE]) + { + engine.ClipZ-=25; + engine.ClipFlag=ENGINE_CLIPZ_FLAG; +// engine.ClipFlag=300; + } + if(Keys[KB_RBRACE]) + { + engine.ClipZ+=25; + engine.ClipFlag=ENGINE_CLIPZ_FLAG; +// engine.ClipFlag=300; + } + + +} +extern void mini_game_test(void); +extern void interface_thing2(struct MapThing *p_thing); + +//extern void draw_col_vects(UWORD col_vect_link); +//extern void draw_actual_col_vect(UWORD col_vect); +/* +void draw_map_col_vects(void) +{ + SLONG c0; + for(c0=1;c0>5)&0x1f; + red=(col>>10)&0x1f; + col=(red<<10)+(green<<5)+blue; + + line[x]=col; + } + FileWrite(handle,&line[0],(ULONG)WorkScreenPixelWidth*2); + } + FileClose(handle); + } +} + +LevelEditor *the_leveleditor; +void handle_icon_click(UWORD id) +{ + switch(id) + { + case ICON_LOAD_MAP: + { + + FileRequester *fr; + CBYTE fname[100]; + fr=new FileRequester("data\\","*.map","Load A MAP","temp.map"); + if(fr->Draw()) + { + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + strcpy(edit_info.MapName,fr->FileName); + load_map(fname); + the_leveleditor->BuildMode->ResetBuildTab(); + + } + + delete fr; + } + break; + case ICON_SAVE_MAP: + { + FileRequester *fr; + CBYTE fname[100]; + CBYTE temp_name[100]; + + strcpy(temp_name,edit_info.MapName); + fr=new FileRequester("data\\","*.map","Save A MAP",temp_name); + if(fr->Draw()) + { + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + strcpy(edit_info.MapName,fr->FileName); + save_map(fname,0); + } + + delete fr; + // RequestUpdate(); + } + break; + case ICON_TOGGLE_GRID: + edit_info.GridOn=win_bar_icons[ICON_TOGGLE_GRID].Flag; +// SetDisplay(800,600,8); + break; + case ICON_TEST_LORES: + { +#ifdef DOGPOO +#ifdef TEST_3DFX +extern void Demo3Dfx(void); + Demo3Dfx(); +#else + UBYTE display=0; + SLONG tx,ty,tz; + SLONG back_type=0; + UBYTE test_bloke=0; + UBYTE film=0; + struct MapThing *darci; + +extern struct MapThing *init_test_bloke_system(void); +extern void draw_test_bloke(SLONG x,SLONG y,SLONG z,UBYTE anim,SLONG angle); +// if(!Keys[KB_B]) + { + darci=init_test_bloke_system(); + test_bloke=1; + } + + engine.Y=500<<8; + tx=engine.X>>8; + ty=engine.Y>>8; + tz=engine.Z>>8; + save_map("data/bak.map",1); + rotate_point_gte=rotate_point_gte_perspective; + switch(WorkScreenDepth) + { + case 1: + display=SetDisplay(320,200,8); + break; + case 2: + display=SetDisplay(320,200,16); + break; + case 4: + display=SetDisplay(320,200,32); + break; + } + LogText(" display = %d \n",display); + FileLoadAt("data\\back.dat",back_dat); + SetWorkWindowBounds(0,0,320,199); + + +extern SLONG calc_height_at(SLONG x,SLONG z); + + darci->X=engine.X>>8; + darci->Y=calc_height_at(darci->X,darci->Z); + darci->Z=engine.Z>>8; + + engine.Scale=296; + if(Keys[KB_SPACE]) + { +// mini_game_test(); + } + else + { + + +//FLI anim_record(); + init_hair(MouseX,MouseY,0); + if(display==NoError) + while(SHELL_ACTIVE && !RightButton) + { + SLONG depth; + if(ShiftFlag) + depth=16; + else + if(ControlFlag) + depth=32; + else + depth=8; + if(Keys[KB_6]) + { + display=SetDisplay(320,200,depth); + Keys[KB_6]=0; + } + if(Keys[KB_7]) + { + display=SetDisplay(640,480,depth); + Keys[KB_7]=0; + } + + if(Keys[KB_8]) + { + display=SetDisplay(800,600,depth); + Keys[KB_8]=0; + } + + if(Keys[KB_9]) + { + display=SetDisplay(1024,768,depth); + Keys[KB_9]=0; + } + + if(back_type==4) + ClearWorkScreen(0); + if(LockWorkScreen()) + { + + // DrawBoxC(0,0,640,400,0); + // editor_user_interface(); + do_clip_keys(); + set_camera(); + if(test_bloke) + { + SLONG y; + +extern SLONG calc_height_at(SLONG x,SLONG z); + +// y=calc_height_at(engine.X>>8,engine.Z>>8); +extern SLONG play_x,play_y,play_z; + draw_test_bloke(darci->X,darci->Y,darci->Z,1,0); +// draw_test_bloke(engine.X>>8,y,engine.Z>>8,1,0); + if(ShiftFlag) + { + draw_test_bloke(darci->X-100,0,darci->Z,0,512); + draw_test_bloke(darci->X+100,0,darci->Z,0,1024); + draw_test_bloke(darci->X+300,0,darci->Z,0,1530); + } + } + draw_quick_map(); +// draw_editor_map(1); + // test_poly(); + interface_thing2(darci); +// back_type=draw_background(); + back_type=4; + render_view(0); +//extern void draw_fader(void); +// draw_fader(); + + { + CBYTE str[100]; + sprintf(str,"face %d id %d",darci->OnFace,prim_faces4[darci->OnFace].ID); + QuickTextC(1,179,str,0); + QuickTextC(0,180,str,WHITE_COL); + } +//COL VECTS draw_map_col_vects(); +// draw_hair(); + //FLI anim_make_next_frame((UBYTE*)WorkScreen, PALETTE); + + if(LastKey==KB_C && ControlFlag) + { + do_single_shot(WorkScreen,CurrentPalette); + LastKey = 0; + } + + UnlockWorkScreen(); + if(LastKey==KB_R && ControlFlag) + { + editor_status ^= EDITOR_RECORD; + LastKey = 0; + } + } + + if(LastKey==KB_B) + { + film=1; + } + if(LastKey==KB_N) + { + film=0; + } + + if(film) + screen_shot(); + ShowWorkScreen(0); + } + //FLI anim_stop(); + } +/* + switch(WorkScreenDepth) + { + case 1: + display=SetDisplay(800,600,8); + break; + case 2: + display=SetDisplay(800,600,16); + break; + case 4: + display=SetDisplay(800,600,32); + break; + } +*/ + display=SetDisplay(800,600,16); + rotate_point_gte=rotate_point_gte_normal; + reset_game(); + create_city(BUILD_MODE_EDITOR); +// RequestUpdate(); +#endif +#endif + } + break; + case ICON_PLACE_LIGHT: + the_leveleditor->BringTabIDToFront(TAB_LIGHT); + the_leveleditor->LightMode->Mode=LIGHT_TAB_MODE_PLACE_LIGHT; + break; + case ICON_CREATE_CITY: + create_city(BUILD_MODE_EDITOR); +extern UWORD count_empty_map_things(void); + LogText(" npp %d npf %d npf4 %d npo %d UNUSED th %d \n",next_prim_point,next_prim_face3,next_prim_face4,next_prim_object,count_empty_map_things()); + break; + } +} + +LevelEditor::~LevelEditor() +{ + DestroyLevelTabs(); +} + +void LevelEditor::SetupModule(void) +{ + LevelEdDefaults the_defaults; + + + the_defaults.Left = 0; + the_defaults.Top = 20; + the_defaults.Width = 780; + the_defaults.Height = 560; + SetupWindow ( + "Level Editor", + (HAS_TITLE|HAS_ICONS|HAS_GROW|HAS_CONTROLS), + the_defaults.Left, + the_defaults.Top, + the_defaults.Width, + the_defaults.Height + ); + + TopIcons.InitIcons(win_bar_icons); + + SetContentColour(CONTENT_COL); + //SetControlsHeight(440); + SetControlsHeight(520); + SetControlsWidth(300); + + CreateLevelTabs(); + + hilited_face.Face = 0; + selected_face.Face = 0; + + // Mikes editor stuff. + init_engine(); + + + next_prim_point = 1; + next_prim_face4 = 1; + next_prim_face3 = 1; + next_prim_object = 1; + next_prim_multi_object= 1; + + memset(prim_points,0,sizeof(PrimPoint)*MAX_PRIM_POINTS); + memset(prim_faces4,0,sizeof(PrimFace4)*MAX_PRIM_FACES3); + memset(prim_faces3,0,sizeof(PrimFace3)*MAX_PRIM_FACES4); + memset(prim_objects,0,sizeof(PrimObject)*MAX_PRIM_OBJECTS); + memset(prim_multi_objects,0,sizeof(PrimMultiObject)*MAX_PRIM_MOBJECTS); + + init_editor(); + + background_prim = 0; + + + make_fade_table(PALETTE); + make_mix_map(PALETTE); + the_leveleditor=this; + + PrimSet.InitControlSet(prim_content_def); + +// +// For psx_alt +// + PSXControls.InitControlSet(psx_content_def); + +// +// For style paint +// + StyleControls.InitControlSet(style_content_def); + ((CEditText*)StyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->SetFlags(CONTROL_INACTIVE); + + ((CEditText*)StyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->SetEditString("No Anim"); + + ((CVSlider*)StyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->SetUpdateFunction(slider_redraw); + + ((CVSlider*)StyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->SetValueRange(0,60); + ((CVSlider*)StyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->SetCurrentValue(1); + +// +// For Inside Styles +// + InStyleControls.InitControlSet(inside_style_content_def); + ((CEditText*)InStyleControls.GetControlPtr(CTRL_INSTYLE_NAME_EDIT))->SetFlags(CONTROL_INACTIVE); + + ((CEditText*)InStyleControls.GetControlPtr(CTRL_INSTYLE_NAME_EDIT))->SetEditString("No Anim"); + + ((CVSlider*)InStyleControls.GetControlPtr(CTRL_INSTYLE_POS_SLIDER))->SetUpdateFunction(slider_redraw_in); + + ((CVSlider*)InStyleControls.GetControlPtr(CTRL_INSTYLE_POS_SLIDER))->SetValueRange(0,50); + ((CVSlider*)InStyleControls.GetControlPtr(CTRL_INSTYLE_POS_SLIDER))->SetCurrentValue(1); +} + +//--------------------------------------------------------------- + +void LevelEditor::CreateLevelTabs(void) +{ + EdRect bounds_rect; + + + bounds_rect.SetRect(ControlsLeft(),ControlsTop(),ControlsWidth(),ControlsHeight()); + + TestMode = new ModeTab; + if(TestMode) + { + AddTab(TestMode); + TestMode->SetupModeTab("Test",TAB_NONE,&bounds_rect,ExternalUpdate); + } + + PaintMode = new PaintTab(this); + if(PaintMode) + { + AddTab(PaintMode); + PaintMode->SetupModeTab("Paint",TAB_PAINT,&bounds_rect,ExternalUpdate); + } + + PrimMode = new PrimPickTab(this); + if(PrimMode) + { + AddTab(PrimMode); + PrimMode->SetupModeTab("Prims",TAB_PRIMPICK,&bounds_rect,ExternalUpdate); + } + + LightMode = new LightTab(this); + if(LightMode) + { + AddTab(LightMode); + LightMode->SetupModeTab("Lights",TAB_LIGHT,&bounds_rect,ExternalUpdate); + } + + /* + + ColMode = new ColTab(this); + if(ColMode) + { + AddTab(ColMode); + ColMode->SetupModeTab("Collide",TAB_COL,&bounds_rect,ExternalUpdate); + } + + */ +/* + MapMode = new MapTab(this); + if(MapMode) + { + AddTab(MapMode); + MapMode->SetupModeTab("Map bl",TAB_MAP,&bounds_rect,ExternalUpdate); + } +*/ + BuildMode = new BuildTab(this); + if(BuildMode) + { + AddTab(BuildMode); + BuildMode->SetupModeTab("Buildings",TAB_BUILD,&bounds_rect,ExternalUpdate); + } + + MapEdMode = new MapEdTab(this); + if(MapEdMode) + { + AddTab(MapEdMode); + MapEdMode->SetupModeTab("MapEDIT",TAB_MAPED,&bounds_rect,ExternalUpdate); + MapEdMode->BuildMode=BuildMode; + } + + HmMode = new HmTab(this); + if (HmMode) + { + AddTab(HmMode); + HmMode->SetupModeTab("HmEDIT",TAB_HM,&bounds_rect,ExternalUpdate); + } + + SewerMode = new SewerTab(this); + if (SewerMode) + { + AddTab(SewerMode); + SewerMode->SetupModeTab("InsideEDIT",TAB_SEWER,&bounds_rect,ExternalUpdate); + } +} + + +//--------------------------------------------------------------- + +void LevelEditor::DestroyLevelTabs(void) +{ + /* + if(ColMode) + delete ColMode; + */ + + if(LightMode) + delete LightMode; + + if(PrimMode) + delete PrimMode; + + if(PaintMode) + delete PaintMode; + + if(TestMode) + delete TestMode; + + + //if(MapMode) + // delete MapMode; + + if(MapEdMode) + delete MapEdMode; + + if(BuildMode) + delete BuildMode; + + if (HmMode) + { + delete HmMode; + } + + if (SewerMode) + { + delete SewerMode; + } +} + +//--------------------------------------------------------------- +//CONTENT WINDOW HAS DIFFERENT VIEWS DEPENDING ON TAB SELECTED + +void build_texture(SLONG x,SLONG y,SLONG w,SLONG h,UBYTE page,UBYTE u0,UBYTE v0,UBYTE u1,UBYTE v1,UBYTE u2,UBYTE v2,UBYTE u3,UBYTE v3) +{ + + setPolyType4(current_bucket_pool,POLY_T); + + setXY4((struct BucketQuad*)current_bucket_pool, + x,y, + x+w,y, + x,y+h, + x+w,y+h); + + setUV4NA((struct BucketQuad*)current_bucket_pool, + u0,v0,u1,v1,u2,v2,u3,v3,page); + + + ((struct BucketQuad*)current_bucket_pool)->DebugInfo=0; + +// setShade4((struct BucketQuad*)current_bucket_pool,128,128,128,128); + + add_bucket((void *)current_bucket_pool,1); + current_bucket_pool += sizeof(struct BucketQuad); + +} + + +void LevelEditor::DrawAnimTmapContent(SLONG current_anim_tmap) +{ + EdRect tex_rect; + SLONG w,h=32,count=0; + CBYTE str[100]; + + animate_texture_maps(); + sprintf(str," EDIT ANIM TEXTURE %d",current_anim_tmap); + QuickText(50,10,str,0); + + while(h<200&&count=0&&countGetAnimTmap(); + + local_point=*clicked_point; + + current_texture = PaintMode->GetTexture(); + GlobalToLocal(&local_point); + + while(h<200&&countGetTexturePage()>=0) + { + + for(c0=0;c0<4;c0++) + { + anim_tmaps[current_anim_tmap].UV[count][c0][0]=current_texture->U[c0]; + anim_tmaps[current_anim_tmap].UV[count][c0][1]=current_texture->V[c0]; + } + anim_tmaps[current_anim_tmap].Flags|=(1<GetTexturePage(); + if(page<0) + page=0; + anim_tmaps[current_anim_tmap].Page[count]=page; + } + break; + case RIGHT_CLICK: + for(c0=0;c0<4;c0++) + { + current_texture->U[c0]=anim_tmaps[current_anim_tmap].UV[count][c0][0]; + current_texture->V[c0]=anim_tmaps[current_anim_tmap].UV[count][c0][1]; + } + PaintMode->SetTexturePage(anim_tmaps[current_anim_tmap].Page[count]); + break; + case MIDDLE_CLICK: + anim_tmaps[current_anim_tmap].Flags&=~(1<SetAnimTmap(count); +// current_anim_tmap=count; +// anim_tmaps[current_anim_tmap]=anim_tmaps[count]; + break; + case RIGHT_CLICK: + PaintMode->SetAnimTmap(count); + break; + } + RequestUpdate(); + return; + } + + count++; + } + h+=22; + } + +} + + +void draw_quad_now(SLONG x,SLONG y,SLONG w,SLONG h,UBYTE tx,UBYTE ty,UBYTE page,UBYTE flip,UBYTE flags) +{ + struct MfEnginePoint p1,p2,p3,p4; + UBYTE uv[4][2]; + + p1.X=x; + p1.Y=y; + p2.X=x+w; + p2.Y=y; + p3.X=x; + p3.Y=y+h; + p4.X=x+w; + p4.Y=y+h; + + switch(flip) + { + case 0: + p1.TX=tx; + p1.TY=ty; + p2.TX=tx+31; + p2.TY=ty; + p3.TX=tx; + p3.TY=ty+31; + p4.TX=tx+31; + p4.TY=ty+31; + break; + case 1: //flip x + p1.TX=tx+31; + p1.TY=ty; + p2.TX=tx; + p2.TY=ty; + p3.TX=tx+31; + p3.TY=ty+31; + p4.TX=tx; + p4.TY=ty+31; + break; + case 2: //flip y + p1.TX=tx; + p1.TY=ty+31; + p2.TX=tx+31; + p2.TY=ty+31; + p3.TX=tx; + p3.TY=ty; + p4.TX=tx+31; + p4.TY=ty; + break; + case 3: //flip y + p1.TX=tx+31; + p1.TY=ty+31; + p2.TX=tx; + p2.TY=ty+31; + p3.TX=tx+31; + p3.TY=ty; + p4.TX=tx; + p4.TY=ty; + break; + } + + + poly_info.DrawFlags=flags&(~POLY_FLAG_GOURAD); + poly_info.PTexture=tmaps[page]; + poly_info.Page=page; + my_quad_noz(&p1,&p2,&p4,&p3); +} + + +void LevelEditor::DrawTexStyleContent(void) +{ + SLONG scroll_pos=PaintMode->CurrentStylePos; + SLONG c0,pos; + EdRect tex_rect; + + QuickTextC(10,10," Name MidL MidM MidR Mid2 Mid3 ",0); + + for(c0=0;c0<15;c0++) + { + if(PaintMode->CurrentStyleEdit==c0+scroll_pos) + { + tex_rect.SetRect(25,c0*26+30,110,24); + tex_rect.OutlineRect(0); + } + QuickTextC(25,c0*26+36,&texture_style_names[c0+scroll_pos][0],0); + + for(pos=0;pos<5;pos++) + { +// draw_quad_now(200+pos*38,c0*20+30,16,16,textures_xy[c0+scroll_pos][pos].Tx<<5,textures_xy[c0+scroll_pos][pos].Ty<<5,textures_xy[c0+scroll_pos][pos].Page); + draw_quad_now(140+pos*30,c0*26+30-2,24,24,textures_xy[c0+scroll_pos][pos].Tx<<5,textures_xy[c0+scroll_pos][pos].Ty<<5,textures_xy[c0+scroll_pos][pos].Page,textures_xy[c0+scroll_pos][pos].Flip,textures_flags[c0+scroll_pos][pos]); + } + + } + StyleControls.ControlSetBounds(GetContentRect()); + StyleControls.DrawControlSet(); +} + +void LevelEditor::DrawPSXTexContent(void) +{ + SLONG texpage; + SLONG c0,pos; + EdRect tex_rect; + SLONG x,y; + if(PaintMode->CurrentStylePos>3) + PaintMode->CurrentStylePos=3; + texpage=PaintMode->CurrentStylePos; + + QuickTextC(100,2," PSX Texture Alternatives ",0); + + for(y=0;y<8;y++) + for(x=0;x<8;x++) + { + draw_quad_now(40+x*50,20+y*50,48,48,x*32,y*32,texpage+25,0,POLY_T); + + } + PSXControls.ControlSetBounds(GetContentRect()); + PSXControls.DrawControlSet(); +} + + +void slider_redraw(void) +{ +// the_leveleditor->PaintMode->CurrentStylePos = ((CVSlider*)the_leveleditor->StyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->GetCurrentValue(); +// the_leveleditor->RequestUpdate(); + the_leveleditor->PaintMode->CurrentStylePos = ((CVSlider*)the_leveleditor->StyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->GetCurrentValue(); + if(LockWorkScreen()) + { + the_leveleditor->DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} +void slider_redraw_in(void) +{ +// the_leveleditor->PaintMode->CurrentStylePos = ((CVSlider*)the_leveleditor->StyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->GetCurrentValue(); +// the_leveleditor->RequestUpdate(); + the_leveleditor->PaintMode->CurrentStylePos = ((CVSlider*)the_leveleditor->InStyleControls.GetControlPtr(CTRL_INSTYLE_POS_SLIDER))->GetCurrentValue(); + if(LockWorkScreen()) + { + the_leveleditor->DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} +SLONG LevelEditor::HandleTexStyleClick(UBYTE flags,MFPoint *clicked_point) +{ + SLONG scroll_pos=PaintMode->CurrentStylePos; + SLONG c0,pos; + EdRect tex_rect; + EdTexture *current_texture; + MFPoint local_point; + + local_point=*clicked_point; + + current_texture = PaintMode->GetTexture(); + GlobalToLocal(&local_point); + + + for(c0=0;c0<15;c0++) + { + tex_rect.SetRect(25,c0*26+30,110,24); + if(tex_rect.PointInRect(&local_point)) + { + //want to text edit the name + PaintMode->CurrentStyleEdit=c0+scroll_pos; + ((CEditText*)StyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->SetEditString(&texture_style_names[c0+scroll_pos][0]); + ((CEditText*)StyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->SetFlags((UBYTE)(((CEditText*)StyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->GetFlags()&~CONTROL_INACTIVE)); + + return(1); + + } + for(pos=0;pos<5;pos++) + { + tex_rect.SetRect(140+pos*30,c0*26+30-2,24,24); + if(tex_rect.PointInRect(&local_point)) + { + SLONG x,y; + switch(flags) + { + case LEFT_CLICK: + if(Keys[KB_X]) + { + if(textures_xy[c0+scroll_pos][pos].Flip&1) + textures_xy[c0+scroll_pos][pos].Flip&=~1; + else + textures_xy[c0+scroll_pos][pos].Flip|=1; + Keys[KB_X]=0; + return(1); + } + + if(Keys[KB_Y]) + { + if(textures_xy[c0+scroll_pos][pos].Flip&2) + textures_xy[c0+scroll_pos][pos].Flip&=~2; + else + textures_xy[c0+scroll_pos][pos].Flip|=2; + Keys[KB_Y]=0; + return(1); + } + x= current_texture->U[0]+current_texture->U[1]+current_texture->U[2]+current_texture->U[3]; + y= current_texture->V[0]+current_texture->V[1]+current_texture->V[2]+current_texture->V[3]; + + x>>=(2+5); + y>>=(2+5); + textures_xy[c0+scroll_pos][pos].Tx=x; + textures_xy[c0+scroll_pos][pos].Ty=y; + textures_xy[c0+scroll_pos][pos].Page=PaintMode->GetTexturePage(); + +// texture_info[x+y*8+64*PaintMode->GetTexturePage()].Type=c0+scroll_pos; + return(1); + + break; + case RIGHT_CLICK: + textures_flags[c0+scroll_pos][pos]=DoStylePopup(clicked_point,textures_flags[c0+scroll_pos][pos]); + return(1); + } + } + } + + } + return(0); +} +extern UWORD page_remap[64*8]; + +SLONG LevelEditor::HandlePSXTexClick(UBYTE flags,MFPoint *clicked_point) +{ + SLONG tex_page=PaintMode->CurrentStylePos; + EdRect tex_rect; + EdTexture *current_texture; + MFPoint local_point; + SLONG x,y,u,v,page; + + if(tex_page>3) + tex_page=3; + + local_point=*clicked_point; + + current_texture = PaintMode->GetTexture(); + GlobalToLocal(&local_point); + + for(y=0;y<8;y++) + for(x=0;x<8;x++) + { + tex_rect.SetRect(40+x*50,20+y*50,48,48); + if(tex_rect.PointInRect(&local_point)) + { + switch(flags) + { + case LEFT_CLICK: + u= current_texture->U[0]+current_texture->U[1]+current_texture->U[2]+current_texture->U[3]; + v= current_texture->V[0]+current_texture->V[1]+current_texture->V[2]+current_texture->V[3]; + + u>>=(2+5); + v>>=(2+5); + + page=u+v*8+PaintMode->GetTexturePage()*64; + if(page<8*64) + { + page_remap[page]=PaintMode->CurrentStylePos*64+x+y*8+1; + if(Keys[KB_X]) + { + page_remap[page]|=1<<14; + } + + if(Keys[KB_Y]) + { + page_remap[page]|=1<<15; + } + } + RequestUpdate(); + return(1); + break; + } + + } + + } + + return(0); +} + +void LevelEditor::HandleStyleControl(ULONG control_id) +{ + switch(control_id) + { + case CTRL_STYLE_NAME_EDIT: + if(PaintMode->CurrentStyleEdit) + { +extern void fix_style_names(void); + fix_style_names(); + strcpy(&texture_style_names[PaintMode->CurrentStyleEdit][0],((CEditText*)StyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->GetEditString()); + } + //if(CurrentAnim) + // CurrentAnim->SetAnimName(((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->GetEditString()); + break; + case CTRL_STYLE_SAVE: +extern void save_texture_styles(UBYTE world); + save_texture_styles(editor_texture_set); + + //SaveAllAnims(&test_chunk); + break; + case CTRL_STYLE_POS_SLIDER: + PaintMode->CurrentStylePos = ((CVSlider*)StyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->GetCurrentValue(); + slider_redraw(); + break; + } + +} + +void LevelEditor::HandlePSXControl(ULONG control_id) +{ + switch(control_id) + { +/* + case CTRL_PSX_SAVE: +extern void save_texture_styles(UBYTE world); +// save_texture_styles(editor_texture_set); + + //SaveAllAnims(&test_chunk); + break; +*/ + case CTRL_PSX_PAGE1: + PaintMode->CurrentStylePos=0; + break; + case CTRL_PSX_PAGE2: + PaintMode->CurrentStylePos=1; + break; + case CTRL_PSX_PAGE3: + PaintMode->CurrentStylePos=2; + break; + case CTRL_PSX_PAGE4: + PaintMode->CurrentStylePos=3; + break; + case CTRL_PSX_NOREMAP: + { + EdTexture *current_texture; + SLONG u,v,page; + current_texture = PaintMode->GetTexture(); + u= current_texture->U[0]+current_texture->U[1]+current_texture->U[2]+current_texture->U[3]; + v= current_texture->V[0]+current_texture->V[1]+current_texture->V[2]+current_texture->V[3]; + + u>>=(2+5); + v>>=(2+5); + + page=u+v*8+PaintMode->GetTexturePage()*64; + if(page<8*64) + { + page_remap[page]=0; + } + RequestUpdate(); + } + break; + } + +} + + + +// +// Inside Styles +// + +#define IN_BOX_STEP 22 +#define IN_BOX_SIZE 18 + + +void LevelEditor::DrawTexInStyleContent(void) +{ + SLONG scroll_pos=PaintMode->CurrentStylePos; + SLONG c0,pos; + EdRect tex_rect; + +// QuickTextC(10,10," Name MidL MidM MidR Mid2 Mid3 ",0); + + for(c0=0;c0<15;c0++) + { + if(PaintMode->CurrentStyleEdit==c0+scroll_pos) + { + tex_rect.SetRect(25,c0*26+30,110,24); + tex_rect.OutlineRect(0); + } + QuickTextC(25,c0*26+36,inside_names[c0+scroll_pos],0); + + for(pos=0;pos<16;pos++) + { + SLONG x,y,page,flip,flags,value; +// draw_quad_now(200+pos*38,c0*20+30,16,16,textures_xy[c0+scroll_pos][pos].Tx<<5,textures_xy[c0+scroll_pos][pos].Ty<<5,textures_xy[c0+scroll_pos][pos].Page); + value=inside_tex[c0+scroll_pos][pos]; + + page=value/64+START_PAGE_FOR_FLOOR; + value=value&63; + x=(value&7)<<5; + y=(value&(7<<3))<<2; + +// draw_quad_now(120+pos*20,c0*26+30-2,24,24,textures_xy[c0+scroll_pos][pos].Tx<<5,textures_xy[c0+scroll_pos][pos].Ty<<5,textures_xy[c0+scroll_pos][pos].Page,textures_xy[c0+scroll_pos][pos].Flip,textures_flags[c0+scroll_pos][pos]); + draw_quad_now(120+pos*IN_BOX_STEP,c0*26+30-2,IN_BOX_SIZE,IN_BOX_SIZE,x,y,page,0,POLY_FLAG_TEXTURED); + } + + } + InStyleControls.ControlSetBounds(GetContentRect()); + InStyleControls.DrawControlSet(); +} + +void slider_redraw_inside(void) +{ + if(LockWorkScreen()) + { + the_leveleditor->PaintMode->CurrentStylePos = ((CVSlider*)the_leveleditor->InStyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->GetCurrentValue(); + the_leveleditor->DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} +SLONG LevelEditor::HandleTexInStyleClick(UBYTE flags,MFPoint *clicked_point) +{ + SLONG scroll_pos=PaintMode->CurrentStylePos; + SLONG c0,pos; + EdRect tex_rect; + EdTexture *current_texture; + MFPoint local_point; + + local_point=*clicked_point; + + current_texture = PaintMode->GetTexture(); + GlobalToLocal(&local_point); + + + for(c0=0;c0<15;c0++) + { + tex_rect.SetRect(25,c0*26+30,90,24); + if(tex_rect.PointInRect(&local_point)) + { + //want to text edit the name + PaintMode->CurrentStyleEdit=c0+scroll_pos; + ((CEditText*)InStyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->SetEditString(&texture_style_names[c0+scroll_pos][0]); + ((CEditText*)InStyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->SetFlags((UBYTE)(((CEditText*)InStyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->GetFlags()&~CONTROL_INACTIVE)); + + return(1); + + } + for(pos=0;pos<16;pos++) + { + tex_rect.SetRect(120+pos*IN_BOX_STEP,c0*26+30-2,IN_BOX_SIZE,IN_BOX_SIZE); + if(tex_rect.PointInRect(&local_point)) + { + SLONG x,y; + switch(flags) + { + case LEFT_CLICK: + x= current_texture->U[0]+current_texture->U[1]+current_texture->U[2]+current_texture->U[3]; + y= current_texture->V[0]+current_texture->V[1]+current_texture->V[2]+current_texture->V[3]; + + x>>=(5+2); + y>>=(5+2); + + if(PaintMode->GetTexturePage()>=START_PAGE_FOR_FLOOR) + inside_tex[c0+scroll_pos][pos]=((PaintMode->GetTexturePage()-START_PAGE_FOR_FLOOR)<<6)+(x+(y<<3)); + +// texture_info[x+y*8+64*PaintMode->GetTexturePage()].Type=c0+scroll_pos; + return(1); + + break; + case RIGHT_CLICK: +// textures_flags[c0+scroll_pos][pos]=DoStylePopup(clicked_point,textures_flags[c0+scroll_pos][pos]); + return(1); + } + } + } + + } + return(0); +} + +void save_texture_instyles(UBYTE world) +{ + UWORD temp,temp2; + SLONG save_type=1; + MFFileHandle handle = FILE_OPEN_ERROR; + CBYTE fname[MAX_PATH]; + +// sprintf(fname, "u:\urbanchaos\\textures\\world%d\\instyle.tma", world); + sprintf(fname, "%sinstyle.tma", TEXTURE_WORLD_DIR); + + handle=FileCreate(fname,1); + + if(handle!=FILE_OPEN_ERROR) + { + FileWrite(handle,(UBYTE*)&save_type,4); + temp=9; //how many texture_pages + + temp=64; + temp2=16; + FileWrite(handle,(UBYTE*)&temp,2); + FileWrite(handle,(UBYTE*)&temp2,2); + FileWrite(handle,(UBYTE*)&inside_tex[0][0],sizeof(UBYTE)*temp*temp2); + temp=64; + temp2=20; + FileWrite(handle,(UBYTE*)&temp,2); + FileWrite(handle,(UBYTE*)&temp2,2); + FileWrite(handle,(UBYTE*)&inside_names[0][0],temp*temp2); + + FileClose(handle); + } + +} + +void LevelEditor::HandleInStyleControl(ULONG control_id) +{ + switch(control_id) + { + case CTRL_STYLE_NAME_EDIT: + if(PaintMode->CurrentStyleEdit) + { +extern void fix_style_names(void); + fix_style_names(); + strcpy(&texture_style_names[PaintMode->CurrentStyleEdit][0],((CEditText*)InStyleControls.GetControlPtr(CTRL_STYLE_NAME_EDIT))->GetEditString()); + } + //if(CurrentAnim) + // CurrentAnim->SetAnimName(((CEditText*)AnimControls.GetControlPtr(CTRL_ANIM_NAME_EDIT))->GetEditString()); + break; + case CTRL_STYLE_SAVE: + save_texture_instyles(editor_texture_set); + + //SaveAllAnims(&test_chunk); + break; + case CTRL_STYLE_POS_SLIDER: + PaintMode->CurrentStylePos = ((CVSlider*)InStyleControls.GetControlPtr(CTRL_STYLE_POS_SLIDER))->GetCurrentValue(); + slider_redraw_inside(); + break; + } + +} + +void LevelEditor::DrawContent(void) +{ + EdRect clear_rect; + MapBlock background; +// SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + SetContentDrawArea(); +// ClearContent(); + + clear_rect.SetRect(0,0,ContentWidth()-1,ContentHeight()-1); + clear_rect.FillRect(CONTENT_COL_BR); + switch(CurrentModeTab()->GetTabID()) + { + case TAB_NONE: + set_camera_side(); + draw_editor_map(0); + render_view(1); + break; + case TAB_PAINT: + set_camera(); + hilited_face.Face = 0; + if(PaintMode->GetPaintMode()==ANIM_TMAP_PAINT) + { + DrawAnimTmapContent(PaintMode->GetAnimTmap()); + } + else + if(PaintMode->GetPaintMode()==PSX_TEX_DEFINE) + { + DrawPSXTexContent(); + } + else + if(PaintMode->GetPaintMode()==STYLE_DEFINE) + { + DrawTexStyleContent(); + } + else + if(PaintMode->GetPaintMode()==INSTYLE_DEFINE) + { + DrawTexInStyleContent(); + } + else + if(PaintMode->GetPaintMode()==FLOOR_PAINT) + { + UWORD temp; + MapBlock background; + SLONG mx,my,mz; + MFPoint mouse_point; + + temp=BuildMode->Texture; + BuildMode->SetViewToEngine(); + BuildMode->Texture=2; + + + if(PaintMode->SubMode==FLOOR_PASTE_BRUSH) + { + mouse_point.X=MouseX; + mouse_point.Y=MouseY; + GlobalToLocal(&mouse_point); + BuildMode->CalcMapCoord(&mx,&my,&mz,ContentLeft(),ContentTop(),ContentWidth(),ContentHeight(),&mouse_point); + background.Cut(mx>>ELE_SHIFT,mz>>ELE_SHIFT,PaintMode->CutMapBlock.GetWidth(),PaintMode->CutMapBlock.GetDepth(),0); + PaintMode->CutMapBlock.Paste(mx>>ELE_SHIFT,mz>>ELE_SHIFT,PASTE_TEXTURE,0); + } + + BuildMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + + //restore background + if(PaintMode->SubMode==FLOOR_PASTE_BRUSH) + { + background.Paste(mx>>ELE_SHIFT,mz>>ELE_SHIFT,PASTE_TEXTURE,0); + BuildMode->DrawContentRect(mx,mz,mx+(PaintMode->CutMapBlock.GetWidth()<CutMapBlock.GetDepth()<DrawBrush(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + BuildMode->Texture=temp; + } + else + if(PrimMode) + { + switch(PrimMode->GetPrimTabMode()) + { + case PRIM_MODE_MULTI: + draw_a_key_frame_at(PrimMode->GetCurrentPrim(),(engine.X>>8)+edit_info.DX,(engine.Y>>8)-edit_info.DY,(engine.Z>>8)); + animate_texture_maps(); + render_view(1); + if(SelectFlag<5) + SelectFlag=0; + else + if(LockWorkScreen()) + { + PaintMode->DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + break; + case PRIM_MODE_SINGLE: + case PRIM_MODE_BACK: + if(PrimMode->GetCurrentPrim()) + { + animate_texture_maps(); + draw_a_prim_at(PrimMode->GetCurrentPrim(),(engine.X>>8)+edit_info.DX,(engine.Y>>8)-edit_info.DY,(engine.Z>>8),0); +// draw_a_building_at(PrimMode->GetCurrentPrim(),engine.X>>8,engine.Y>>8,engine.Z>>8); + if(SelectFlag<5) + SelectFlag=0; + else + if(LockWorkScreen()) + { + PaintMode->DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +// PaintMode->DrawTabContent(); + } + else + draw_editor_map(0); + render_view(1); + break; + } + } + break; + case TAB_PRIMPICK: + PrimMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + + PrimSet.ControlSetBounds(GetContentRect()); +// PrimSet.DrawControlSet(); + break; + case TAB_LIGHT: + LightMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + break; + /* + case TAB_COL: + ColMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + break; + */ + case TAB_MAP: + MapMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + break; + case TAB_MAPED: + UWORD temp; + SLONG mx,my,mz; + MFPoint mouse_point; + + temp=BuildMode->Texture; + BuildMode->SetViewToEngine(); + if(MapEdMode->Texture) + { + BuildMode->Texture=6; + } + else + { + BuildMode->Texture=4; + } + BuildMode->RoofTop=MapEdMode->RoofTop; + + + if(MapEdMode->Mode==FLOOR_PASTE_BRUSH) + { + mouse_point.X=MouseX; + mouse_point.Y=MouseY; + GlobalToLocal(&mouse_point); + BuildMode->CalcMapCoord(&mx,&my,&mz,ContentLeft(),ContentTop(),ContentWidth(),ContentHeight(),&mouse_point); + background.Cut(mx>>ELE_SHIFT,mz>>ELE_SHIFT,MapEdMode->CutMapBlock.GetWidth(),MapEdMode->CutMapBlock.GetDepth(),MapEdMode->RoofTop); + MapEdMode->CutMapBlock.Paste(mx>>ELE_SHIFT,mz>>ELE_SHIFT,PASTE_ALTITUDE,MapEdMode->RoofTop); + } + + + BuildMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + + //restore background + if(MapEdMode->Mode==FLOOR_PASTE_BRUSH) + { + background.Paste(mx>>ELE_SHIFT,mz>>ELE_SHIFT,PASTE_ALTITUDE,MapEdMode->RoofTop); + BuildMode->DrawContentRect(mx,mz,mx+(MapEdMode->CutMapBlock.GetWidth()<CutMapBlock.GetDepth()<Mode==FLOOR_HOLD_BRUSH) + { + + mx=MapEdMode->CutMapBlock.GetX()<CutMapBlock.GetZ()<DrawContentRect(mx,mz,mx+(MapEdMode->CutMapBlock.GetWidth()<CutMapBlock.GetDepth()<DrawBrush(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + BuildMode->Texture=temp; + break; + case TAB_BUILD: + BuildMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + SewerMode->OutsideEditStorey=BuildMode->EditStorey; + SewerMode->EditStorey=storey_list[BuildMode->EditStorey].InsideStorey; + SewerMode->EditBuilding=BuildMode->EditBuilding; + + if(storey_list[BuildMode->EditStorey].InsideIDIndex) + SewerMode->CurrentFloorType=room_ids[storey_list[BuildMode->EditStorey].InsideIDIndex].FloorType; + + SewerMode->SetView(storey_list[BuildMode->EditStorey].DX,storey_list[BuildMode->EditStorey].DZ); + break; + + case TAB_HM: + HmMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + break; + + case TAB_SEWER: + SewerMode->DrawModuleContent(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + break; + + } +} + + + +void LevelEditor::DragEngine(UBYTE flags,MFPoint *clicked_point) +{ + SLONG wwx,wwy,www,wwh; + SLONG screen_change=0; + SLONG last_world_mouse; + SLONG ox,oy,oz; + + MFPoint local_point; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + local_point=*clicked_point; + + GlobalToLocal(&local_point); + ox=edit_info.DX; + oy=edit_info.DY; + oz=edit_info.DZ; + + { + SLONG old_x,old_y,old_z; + + +// edit_info.DX=0; +// edit_info.DY=0; +// edit_info.DZ=0; + + old_x=(local_point.X<<11)/engine.Scale; + old_y=(local_point.Y<<11)/engine.Scale; + + while(SHELL_ACTIVE && (MiddleButton||Keys[KB_SPACE])) + { + local_point.X = MouseX; + local_point.Y = MouseY; + GlobalToLocal(&local_point); +// last_world_mouse=SetWorldMouse(0); + edit_info.DX=ox+((local_point.X<<11)/engine.Scale)-old_x; + edit_info.DY=oy+((local_point.Y<<11)/engine.Scale)-old_y; + DrawContent(); + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + } + } +} +//--------------------------------------------------------------- +//content clicks do different things depending on the tab selected + +void LevelEditor::HandleContentClick(UBYTE flags,MFPoint *clicked_point) +{ + ULONG update = 0; + SLONG c0; + EdTexture *current_texture; + MFPoint local_point; + + switch(CurrentModeTab()->GetTabID()) + { + case TAB_PAINT: + switch(PaintMode->GetPaintMode()) + { + case INSTYLE_DEFINE: + if(!HandleTexInStyleClick(flags,clicked_point)) + { + Control *current_control; + + InStyleControls.SetControlDrawArea(); + local_point = *clicked_point; + InStyleControls.GlobalToLocal(&local_point); + current_control = InStyleControls.GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + HandleInStyleControl(current_control->TrackControl(&local_point)); + + // Tidy up display. + if(LockWorkScreen()) + { + InStyleControls.DrawControlSet(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + current_control = current_control->GetNextControl(); + } + + } + else + { + if(LockWorkScreen()) + { + DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + } + break; + case PSX_TEX_DEFINE: + if(!HandlePSXTexClick(flags,clicked_point)) + { + Control *current_control; + + PSXControls.SetControlDrawArea(); + local_point = *clicked_point; + PSXControls.GlobalToLocal(&local_point); + current_control = PSXControls.GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + HandlePSXControl(current_control->TrackControl(&local_point)); + + // Tidy up display. + if(LockWorkScreen()) + { + StyleControls.DrawControlSet(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + current_control = current_control->GetNextControl(); + } + + } + else + { + if(LockWorkScreen()) + { + DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + } + break; + case STYLE_DEFINE: + if(!HandleTexStyleClick(flags,clicked_point)) + { + Control *current_control; + + StyleControls.SetControlDrawArea(); + local_point = *clicked_point; + StyleControls.GlobalToLocal(&local_point); + current_control = StyleControls.GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + HandleStyleControl(current_control->TrackControl(&local_point)); + + // Tidy up display. + if(LockWorkScreen()) + { + StyleControls.DrawControlSet(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + current_control = current_control->GetNextControl(); + } + + } + else + { + if(LockWorkScreen()) + { + DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + } + break; + case ANIM_TMAP_PAINT: + HandleAnimTmapClick(flags,clicked_point); + break; + case PALETTE_PAINT: + case TEXTURE_PAINT: + case FLOOR_PAINT: + case PLANAR_PAINT: + case STYLE_PAINT: + SLONG paint_city=0; + if(PrimMode) + { + switch(PrimMode->GetPrimTabMode()) + { + case PRIM_MODE_SINGLE: + case PRIM_MODE_BACK: + if(!PrimMode->GetCurrentPrim()) + { + paint_city=1; + } + } + } + + switch(flags) + { + case NO_CLICK: + break; + case MIDDLE_CLICK: + DragEngine(flags,clicked_point); + break; + + case LEFT_CLICK: + current_texture = PaintMode->GetTexture(); + if(PaintMode->SubMode==FLOOR_CUT_BRUSH) + { + PaintMode->CutFloorBrush(BuildMode,&local_point); + + } + else + if(ControlFlag&&!paint_city) + { + MFPoint point1,point2; + SLONG con_top,con_left; + point1.X = MouseX; + point1.Y = MouseY; + // point1 = *clicked_point; + GlobalToLocal(&point1); + while(SHELL_ACTIVE && LeftButton) + { + engine_keys_scroll(); + engine_keys_spin(); + engine_keys_zoom(); + + point2.X = MouseX;//-con_left; + point2.Y = MouseY;//-con_top; + GlobalToLocal(&point2); + + edit_info.SelectRect.SetRect(point1.X,point1.Y,point2.X-point1.X,point2.Y-point1.Y); + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + edit_info.SelectRect.OutlineRect(WHITE_COL); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + edit_info.SelectRect.NormalRect(); + SelectFlag=1; + RequestUpdate(); + } + else + while(SHELL_ACTIVE && LeftButton) + { + if(PaintMode->SubMode==FLOOR_PASTE_BRUSH) + { + MFPoint point1; + SLONG mx,my,mz; + + point1.X = MouseX; + point1.Y = MouseY; + GlobalToLocal(&point1); + BuildMode->CalcMapCoord(&mx,&my,&mz,ContentLeft(),ContentTop(),ContentWidth(),ContentHeight(),&point1); + PaintMode->CutMapBlock.Paste(mx>>ELE_SHIFT,mz>>ELE_SHIFT,PASTE_TEXTURE|(AltFlag?PASTE_ALTITUDE:0),0); + + } + else + if(ShiftFlag&&hilited_face.Face&&!paint_city) + { //selecting lots of faces + if(!face_is_in_list(hilited_face.Face)) + add_face_to_list(hilited_face.Face); + } + else + { +/* + if(paint_city&&ShiftFlag) + { + if(hilited_face.Face>0) + { + SLONG face; + face=hilited_face.Face; + set_wall_texture_info(-prim_faces4[face].ThingIndex,(SBYTE)texture_mode->GetTexturePage(),current_texture); + } + + } +*/ + if(!ShiftFlag) + if(ApplyTexture(&hilited_face)) + { + update = 1; + + } + } + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + editor_turn++; + + } + break; + case RIGHT_CLICK: + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + if(ControlFlag&&!paint_city) + { + MFPoint point1,point2; + SLONG con_top,con_left; + point1.X = MouseX; + point1.Y = MouseY; + GlobalToLocal(&point1); + // con_left=ContentLeft(); + // con_top=ContentTop(); + while(SHELL_ACTIVE && RightButton) + { + point2.X = MouseX;//-con_left; + point2.Y = MouseY;//-con_top; + GlobalToLocal(&point2); + edit_info.SelectRect.SetRect(point1.X,point1.Y,point2.X-point1.X,point2.Y-point1.Y); + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + edit_info.SelectRect.OutlineRect(WHITE_COL); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + edit_info.SelectRect.NormalRect(); + SelectFlag=-1; + RequestUpdate(); + } + else + { + + current_texture = PaintMode->GetTexture(); + if(hilited_face.PEle) + { + selected_face = hilited_face; + if(ShiftFlag&&hilited_face.Face&&hilited_face.PEle!=(struct EditMapElement*)-2) + { //selecting lots of faces + if(face_is_in_list(hilited_face.Face)) + add_face_to_list(hilited_face.Face); + } + else + if(hilited_face.PEle==(struct EditMapElement*)-2) + { + + struct MiniTextureBits *tex; + LogText(" get floor tex co-ords for on screen edit \n"); + if(edit_info.RoofTex) + { + tex=(struct MiniTextureBits*)(&tex_map[selected_face.MapX][selected_face.MapZ]); + } + else + { + tex=(struct MiniTextureBits*)(&edit_map[selected_face.MapX][selected_face.MapZ].Texture); + } + PaintMode->ConvertMiniTex(tex); + } + else + if(hilited_face.PEle==(struct EditMapElement*)-1) + { + if(hilited_face.Face<0) + { + PaintMode->MyUndo.ApplyTexturePrim3(0,prim_faces3[-hilited_face.Face].TexturePage,-hilited_face.Face, + prim_faces3[-hilited_face.Face].UV[0][0], + prim_faces3[-hilited_face.Face].UV[0][1], + prim_faces3[-hilited_face.Face].UV[1][0], + prim_faces3[-hilited_face.Face].UV[1][1], + prim_faces3[-hilited_face.Face].UV[2][0], + prim_faces3[-hilited_face.Face].UV[2][1]); + + for(c0=0;c0<3;c0++) + { + // prim_faces3[-edit_face.Face].TexturePage = (UWORD)TextureMode->GetTexturePage(); + current_texture->U[c0] = prim_faces3[-hilited_face.Face].UV[c0][0]; + current_texture->V[c0] = prim_faces3[-hilited_face.Face].UV[c0][1]; + } + PaintMode->SetTexturePage(prim_faces3[-hilited_face.Face].TexturePage); + PaintMode->SetTextureFlags(PaintMode->GetTextureFlags()&~FLAGS_QUADS); + + PaintMode->SetCurrentColour(prim_faces3[-hilited_face.Face].Col2); + + + } + else + { + if(prim_faces4[hilited_face.Face].FaceFlags & FACE_FLAG_ANIMATE) + { + PaintMode->SetTexturePage(-prim_faces4[hilited_face.Face].TexturePage); + } + else + { + PaintMode->MyUndo.ApplyTexturePrim4(0,prim_faces3[hilited_face.Face].TexturePage,hilited_face.Face, + prim_faces4[hilited_face.Face].UV[0][0], + prim_faces4[hilited_face.Face].UV[0][1], + prim_faces4[hilited_face.Face].UV[1][0], + prim_faces4[hilited_face.Face].UV[1][1], + prim_faces4[hilited_face.Face].UV[2][0], + prim_faces4[hilited_face.Face].UV[2][1], + prim_faces4[hilited_face.Face].UV[3][0], + prim_faces4[hilited_face.Face].UV[3][1]); + for(c0=0;c0<4;c0++) + { + // prim_faces4[edit_face.Face].TexturePage = (UWORD)TextureMode->GetTexturePage(); + current_texture->U[c0] = prim_faces4[hilited_face.Face].UV[c0][0]; + current_texture->V[c0] = prim_faces4[hilited_face.Face].UV[c0][1]; + } + + + { + SLONG dx,dy; + dx=-current_texture->U[0]+current_texture->U[1]; + dy=-current_texture->V[0]+current_texture->V[1]; + + if(dx>0&&dy==0) + { + PaintMode->CurrentTextureRot=0; + } + else + if(dx==0&&dy>0) + { + PaintMode->CurrentTextureRot=1; + } + else + if(dx<0&&dy==0) + { + PaintMode->CurrentTextureRot=2; + } + else + if(dx==0&&dy<0) + { + PaintMode->CurrentTextureRot=3; + } + + + } + + + + PaintMode->SetTexturePage(prim_faces4[hilited_face.Face].TexturePage); + PaintMode->SetTextureFlags(PaintMode->GetTextureFlags()|FLAGS_QUADS); + if(prim_faces4[hilited_face.Face].ThingIndex<0) + { + SLONG wall; + wall=prim_faces4[hilited_face.Face].ThingIndex; + + PaintMode->CurrentStyleEdit=wall_list[wall].TextureStyle; + + } + + PaintMode->SetCurrentColour(prim_faces4[hilited_face.Face].Col2); + } + } + if(paint_city) + PaintMode->SetTextureFlags((PaintMode->GetTextureFlags())|FLAGS_SHOW_TEXTURE); + else + PaintMode->SetTextureFlags((PaintMode->GetTextureFlags()&~FLAGS_FIXED)|FLAGS_SHOW_TEXTURE); + } + else + { + PaintMode->ConvertFixedToFree(&selected_face.PEle->Textures[selected_face.Face]); + PaintMode->SetTextureFlags(PaintMode->GetTextureFlags()|FLAGS_QUADS|FLAGS_FIXED); + } + + if(RightButton) + { + DoFacePopup(clicked_point); + update = 1; + } + if(LockWorkScreen()) + { + CurrentModeTab()->DrawTab(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + } + break; + } + break; + } + break; + case TAB_PRIMPICK: + //in here we may be pasteing a 3ds prim + //we may be dragging it somewhere + { + + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + + if(PrimMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + } + + break; + case TAB_LIGHT: + { + + + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + + if(LightMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + } + + break; + /* + case TAB_COL: + { + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + + if(ColMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + } + + break; + */ + case TAB_MAP: + { + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + if(MapMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + } + + break; + case TAB_MAPED: + { + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + + if(MapEdMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + } + break; + case TAB_BUILD: + { + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + + if(BuildMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + SewerMode->OutsideEditStorey=BuildMode->EditStorey; + SewerMode->EditStorey=storey_list[BuildMode->EditStorey].InsideStorey; + SewerMode->EditBuilding=BuildMode->EditBuilding; + + SewerMode->SetView(storey_list[BuildMode->EditStorey].DX,storey_list[BuildMode->EditStorey].DZ); + + if(SewerMode->OutsideEditStorey) + { + SLONG inside,index; + index=storey_list[SewerMode->OutsideEditStorey].InsideIDIndex; //building_list[building].StoreyHead; + if(index) + { + SewerMode->CurrentFloorType=room_ids[index].FloorType; + } + + } + + } + break; + case TAB_HM: + { + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + + if(HmMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + } + + case TAB_SEWER: + { + MFPoint local_point; + local_point=*clicked_point; + GlobalToLocal(&local_point); + + + if(SewerMode->HandleModuleContentClick(&local_point,flags,ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + } + + + } + if(update) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + clicked_point = clicked_point; +} + +//--------------------------------------------------------------- + +void LevelEditor::HandleControlClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + + + if(CurrentModeTab()) + { + control_id = CurrentModeTab()->HandleTabClick(flags,clicked_point); + } +} + +//--------------------------------------------------------------- +extern void zoom_map_onto_screen(void); + +void ApplyShadow(struct EditFace *edit_face,SLONG shadow) +{ + SLONG c0; + + if(edit_face->PEle==(struct EditMapElement*)-2) + { + { + edit_map[edit_face->MapX][edit_face->MapZ].Flags=(edit_map[edit_face->MapX][edit_face->MapZ].Flags&~7)|shadow; + } + } +} + + +void LevelEditor::HandleModule(void) +{ + ULONG update = 0; + SLONG c0, + temp_u, + temp_v; + EdTexture *current_texture; + MFPoint mouse_point; + MFTime the_time; + static SLONG last_msecond; + static EditFace last_face; + + /* + + if(LastKey==KB_P0) + { + switch(CurrentModeTab()->GetTabID()) + { + case TAB_NONE: + break; + case TAB_PRIMPICK: + case TAB_PAINT: + case TAB_LIGHT: + //case TAB_COL: + case TAB_MAP: + case TAB_MAPED: + zoom_map_onto_screen(); + update = 2; + break; + } + LastKey=0; + } + + */ + + + if(Keys[KB_J]) + { + Keys[KB_J]=0; +void swap_maps(); + swap_maps(); + + } + + if((CurrentModeTab()->GetTabID()==TAB_PAINT)) + { + if(PrimMode) + { + switch(PrimMode->GetPrimTabMode()) + { + case PRIM_MODE_SINGLE: + case PRIM_MODE_MULTI: + case PRIM_MODE_BACK: + if(PrimMode->GetCurrentPrim()) + { + + + if(LastKey==KB_S&&(!ShiftFlag)) + { + + SelectFlag=3; + update = 1; + } + + if(LastKey==KB_S&&(ShiftFlag)) + { + SelectFlag=4; + update = 1; + } + } + } + } + } +/* + if(LastKey==KB_Q) + { + ApplyShadow(&hilited_face,0); + update = 2; + LastKey=0; + } + + if(LastKey==KB_W) + { + ApplyShadow(&hilited_face,1); + update = 2; + LastKey=0; + } + if(LastKey==KB_E) + { + ApplyShadow(&hilited_face,2); + update = 2; + LastKey=0; + } + if(LastKey==KB_R) + { + ApplyShadow(&hilited_face,3); + update = 2; + LastKey=0; + } + if(LastKey==KB_T) + { + ApplyShadow(&hilited_face,4); + update = 2; + LastKey=0; + } + + if(LastKey==KB_Y) + { + ApplyShadow(&hilited_face,5); + update = 2; + LastKey=0; + } + */ + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + if(CurrentModeTab()) + { + CurrentModeTab()->HandleTab(&mouse_point); + switch(CurrentModeTab()->GetTabID()) + { + case TAB_NONE: + break; + case TAB_PAINT: + current_texture = PaintMode->GetTexture(); + if(LastKey==KB_SPACE) + { + MFPoint local_point; + + local_point.X = MouseX; + local_point.Y = MouseY; + + DragEngine(0,&local_point); + } + + if(PointInContent(&mouse_point)) + { + update = 2; + } + if(PaintMode->SubMode==FLOOR_PASTE_BRUSH) + update=2; + else if(hilited_face.Face) + { + hilited_face.Face = 0; + hilited_face.Bucket= 0; + update = 1; + } + + if(LastKey==KB_Z) + { + if(PaintMode->SubMode==FLOOR_PASTE_BRUSH) + { + PaintMode->CutMapBlock.Rotate(1); + } + else + if(selected_face.PEle==(struct EditMapElement*)-2) + { + struct MiniTextureBits *tex; + if(edit_info.RoofTex) + { + tex=(struct MiniTextureBits*)(&tex_map[selected_face.MapX][selected_face.MapZ]); + } + else + { + tex=(struct MiniTextureBits*)(&edit_map[selected_face.MapX][selected_face.MapZ].Texture); + } + PaintMode->CurrentTextureRot++; + PaintMode->CurrentTextureRot&=3; + tex->Rot=PaintMode->CurrentTextureRot; + PaintMode->ConvertMiniTex(tex); + + } + else + { + + PaintMode->CurrentTextureRot++; + PaintMode->CurrentTextureRot&=3; + + temp_u = current_texture->U[0]; + temp_v = current_texture->V[0]; + if(PaintMode->GetTextureFlags()&FLAGS_QUADS) + { + current_texture->U[0] = current_texture->U[1]; + current_texture->V[0] = current_texture->V[1]; + current_texture->U[1] = current_texture->U[3]; + current_texture->V[1] = current_texture->V[3]; + current_texture->U[3] = current_texture->U[2]; + current_texture->V[3] = current_texture->V[2]; + } + else + { + for(c0=0;c0<2;c0++) + { + current_texture->U[c0] = current_texture->U[c0+1]; + current_texture->V[c0] = current_texture->V[c0+1]; + } + } + current_texture->U[2] = temp_u; + current_texture->V[2] = temp_v; + ApplyTexture(&selected_face); + } + update = 2; + LastKey = 0; + } + if(LastKey==KB_X) + { + if(PaintMode->GetTextureFlags()&FLAGS_QUADS) + { + SWAP(current_texture->U[0],current_texture->U[1]); + SWAP(current_texture->V[0],current_texture->V[1]); + SWAP(current_texture->U[2],current_texture->U[3]); + SWAP(current_texture->V[2],current_texture->V[3]); + + } + ApplyTexture(&selected_face); + update = 2; + LastKey = 0; + } + break; + case TAB_PRIMPICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + PrimMode->SetWorldMouse(0); +/* + if(PrimMode->HiLightObjects(ContentLeft()+1,ContentTop()+1,ContentWidth(),ContentHeight())) + { + ShowWorkWindow(0); + } +*/ + if(PrimMode->RedrawModuleContent) + DrawContent(); + break; + case TAB_LIGHT: + if(LightMode->RedrawModuleContent) + DrawContent(); + break; + /* + case TAB_COL: + if(ColMode->RedrawModuleContent) + DrawContent(); + break; + */ + case TAB_MAP: + if(MapMode->RedrawModuleContent) + DrawContent(); + break; + case TAB_BUILD: + if(BuildMode->RedrawModuleContent) + DrawContent(); + { + MFPoint mouse_point; + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + if(GetContentRect()->PointInRect(&mouse_point)) + { + BuildMode->MouseInContent(); + } + SewerMode->OutsideEditStorey=BuildMode->EditStorey; + SewerMode->EditStorey=storey_list[BuildMode->EditStorey].InsideStorey; + SewerMode->EditBuilding=BuildMode->EditBuilding; + if(storey_list[BuildMode->EditStorey].InsideIDIndex) + SewerMode->CurrentFloorType=room_ids[storey_list[BuildMode->EditStorey].InsideIDIndex].FloorType; + + SewerMode->SetView(storey_list[BuildMode->EditStorey].DX,storey_list[BuildMode->EditStorey].DZ); + + + } + break; + case TAB_SEWER: + if(BuildMode->RedrawModuleContent) + DrawContent(); + { + MFPoint mouse_point; + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + if(GetContentRect()->PointInRect(&mouse_point)) + { + SewerMode->MouseInContent(); + } + + } + break; + case TAB_MAPED: + if(MapEdMode->RedrawModuleContent) + DrawContent(); + { + MFPoint mouse_point; + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + if(GetContentRect()->PointInRect(&mouse_point)) + { + MapEdMode->MouseInContent(); + } + + } + break; + + case TAB_HM: + if (HmMode->RedrawModuleContent) + { + DrawContent(); + } + break; + } + } + + // This weird bit of code only updates the front display if the user + // changes the view in any way (scroll, rotate etc.) or the currently + // hilited poly changes. + Time(&the_time); + if(hilited_face.Face!=last_face.Face) + { + last_face = hilited_face; + update = 2; + } + if(selected_face.Face && (the_time.MSeconds/251)!=last_msecond) + { + last_msecond = the_time.MSeconds/251; + select_colour = ~select_colour; + update = 2; + } + if(CurrentModeTab()) + { + SLONG temp_update=0; + CurrentModeTab()->HandleTab(&mouse_point); + switch(CurrentModeTab()->GetTabID()) + { + + case TAB_BUILD: + update=BuildMode->DoKeys(); + break; + case TAB_SEWER: + update=SewerMode->DoKeys(); + break; + + case TAB_MAPED: +extern ULONG engine_keys_scroll_plan(void); + //temp_update|=engine_keys_zoom(); + update += BuildMode->DoZoom(); + temp_update|=engine_keys_scroll_plan(); + update += (temp_update<<1); + break; + case TAB_PAINT: + if(PaintMode->GetPaintMode()==FLOOR_PAINT) + { + + update += BuildMode->DoZoom(); + update += (editor_user_interface(2)<<1); + } + else + update += (editor_user_interface(1)<<1); + break; + + case TAB_HM: + + // + // The HM tab does it own keys thankyou very much!!! + // + + break; + + default: + update += (editor_user_interface(0)<<1); + break; + + } + } + + if(update) + { + if(LockWorkScreen()) + { + DrawContent(); + DrawGrowBox(); + UnlockWorkScreen(); + } + if(update>1) + ShowWorkWindow(0); + } + +} + +//--------------------------------------------------------------- + +static ControlDef popup_def = { POPUP_MENU, 0, ""}; +MenuDef2 face_popup[] = +{ + { "~Gouraud" }, + { "~Textured" }, + { "~Masked" }, + { "~Transparent" }, + { "~Alpha" }, + { "~Tiled" }, + { "~2Sided" }, + { "~Walkable" }, + { "~Other Split" }, + { "~Non Planar" }, + { "~Env-mapped" }, + { "~Tinted" }, + { "!" } +}; + + + + + + + + + + + + + + + + +SLONG find_texture_point_for_face(SWORD face) +{ + SLONG stx=99999,sty=99999; + SLONG x,y; + SLONG tx,ty; + SLONG point,tp=0; + + if(face<0) //tri's + { + for(point=0;point<3;point++) + { + x=prim_points[prim_faces3[-face].Points[point]].X; + y=prim_points[prim_faces3[-face].Points[point]].Y; + + if(x+y>7; + scale_point_y=((prim_points[prim_faces3[-face].Points[tp]].Y-sy)*edit_info.TileScale)>>7; + dx=stx-(stx+scale_point_x&0xffffffe0); + dy=sty-(sty+scale_point_y&0xffffffe0); + for(point=0;point<3;point++) + { + + x=((prim_points[prim_faces3[-face].Points[point]].X-sx)*edit_info.TileScale)>>7; + y=((prim_points[prim_faces3[-face].Points[point]].Y-sy)*edit_info.TileScale)>>7; + + if(stx+x+dx>255) + prim_faces3[-face].UV[point][0]=255; + else + prim_faces3[-face].UV[point][0]=stx+x+dx; + if(sty+y+dy>255) + prim_faces3[-face].UV[point][1]=255; + else + prim_faces3[-face].UV[point][1]=sty+y+dy; + } + } + else + { + + stx=stx&0xffffffe0; + sty=sty&0xffffffe0; + tp=find_texture_point_for_face(face); + scale_point_x=((prim_points[prim_faces4[face].Points[tp]].X-sx)*edit_info.TileScale)>>7; + scale_point_y=((prim_points[prim_faces4[face].Points[tp]].Y-sy)*edit_info.TileScale)>>7; + dx=stx-(stx+scale_point_x&0xffffffe0); + dy=sty-(sty+scale_point_y&0xffffffe0); + if(ShiftFlag) + { + dx=0; + dy=0; + } + for(point=0;point<4;point++) + { + + x=((prim_points[prim_faces4[face].Points[point]].X-sx)*edit_info.TileScale)>>7; + y=((prim_points[prim_faces4[face].Points[point]].Y-sy)*edit_info.TileScale)>>7; + + if(stx+x+dx>255) + prim_faces4[face].UV[point][0]=255; + else + prim_faces4[face].UV[point][0]=stx+x+dx; + if(sty+y+dy>255) + prim_faces4[face].UV[point][1]=255; + else + prim_faces4[face].UV[point][1]=sty+y+dy; + } + } + } +} + +#define POPUP_HEIGHT 10*20 +void LevelEditor::DoFacePopup(MFPoint *clicked_point) +{ + ULONG flags; + ULONG c0, + control_id; + CPopUp *the_control = 0; + MFPoint local_point; + UBYTE old_flags; + + local_point = *clicked_point; + GlobalToLocal(&local_point); + popup_def.ControlLeft = local_point.X+4; + popup_def.ControlTop = local_point.Y-4; + +// if(local_point.Y+POPUP_HEIGHT>ContentHeight()) +// local_point.Y=ContentHeight()-POPUP_HEIGHT; + + if(CurrentModeTab()) + { + switch(CurrentModeTab()->GetTabID()) + { + case TAB_NONE: + break; + case TAB_PAINT: + if(hilited_face.PEle==(struct EditMapElement*)-2) + { + return; + + } + else + if(hilited_face.PEle==(struct EditMapElement*)-1) + { + + if(hilited_face.Face<0) + flags = prim_faces3[-hilited_face.Face].DrawFlags; + else + flags = prim_faces4[hilited_face.Face].DrawFlags; + } + else + if(hilited_face.PEle) + { + flags=hilited_face.PEle->Textures[hilited_face.Face].DrawFlags; + + } + if(hilited_face.Face>0) + { + if(prim_faces4[hilited_face.Face].FaceFlags&FACE_FLAG_OTHER_SPLIT) + { + flags|=1<<8; + + } + if(prim_faces4[hilited_face.Face].FaceFlags&FACE_FLAG_NON_PLANAR) + { + flags|=1<<9; + } + + // + // Set 'flags' depending on the environment and tint flags. + // + + if (prim_faces4[hilited_face.Face].FaceFlags & FACE_FLAG_ENVMAP) {flags |= 1 << 10;} + if (prim_faces4[hilited_face.Face].FaceFlags & FACE_FLAG_TINT) {flags |= 1 << 11;} + } + + if (hilited_face.Face < 0) + { + // + // Set 'flags' depending on the environment and tint flags. + // + + if (prim_faces3[-hilited_face.Face].FaceFlags & FACE_FLAG_ENVMAP) {flags |= 1 << 10;} + if (prim_faces3[-hilited_face.Face].FaceFlags & FACE_FLAG_TINT) {flags |= 1 << 11;} + } + + old_flags=flags; +// face_popup[7].ItemFlags = 0; + for(c0=0;c0<12;c0++) + { + face_popup[c0].ItemFlags = 0; + if(flags&(1<TrackControl(&local_point); + flags = 0; +/* + if(next_face_selected>1&&face_is_in_list(hilited_face.Face)) + if(face_popup[7].ItemFlags&MENU_CHECK_MASK) + { + fix_all_selected_faces_for_tile_mode(); + return; + } +*/ + + for(c0=0;c0<12;c0++) + { + if(face_popup[c0].ItemFlags&MENU_CHECK_MASK) + flags |= (1<0) + { + if(face_popup[8].ItemFlags&MENU_CHECK_MASK) + { + prim_faces4[hilited_face.Face].FaceFlags|=FACE_FLAG_OTHER_SPLIT; + + } + if(face_popup[9].ItemFlags&MENU_CHECK_MASK) + { + prim_faces4[hilited_face.Face].FaceFlags|=FACE_FLAG_NON_PLANAR; + } + + // + // Set the envinronment map and tint flags. + // + + prim_faces4[hilited_face.Face].FaceFlags &= ~FACE_FLAG_ENVMAP; + prim_faces4[hilited_face.Face].FaceFlags &= ~FACE_FLAG_TINT; + + if (face_popup[10].ItemFlags & MENU_CHECK_MASK) {prim_faces4[hilited_face.Face].FaceFlags |= FACE_FLAG_ENVMAP;} + if (face_popup[11].ItemFlags & MENU_CHECK_MASK) {prim_faces4[hilited_face.Face].FaceFlags |= FACE_FLAG_TINT;} + } + + if (hilited_face.Face < 0) + { + // + // Set the envinronment map and tint flags. + // + + prim_faces3[-hilited_face.Face].FaceFlags &= ~FACE_FLAG_ENVMAP; + prim_faces3[-hilited_face.Face].FaceFlags &= ~FACE_FLAG_TINT; + + if (face_popup[10].ItemFlags & MENU_CHECK_MASK) {prim_faces3[-hilited_face.Face].FaceFlags |= FACE_FLAG_ENVMAP;} + if (face_popup[11].ItemFlags & MENU_CHECK_MASK) {prim_faces3[-hilited_face.Face].FaceFlags |= FACE_FLAG_TINT;} + } + + if(hilited_face.PEle==(struct EditMapElement*)-2) + { + + } + else + if(hilited_face.PEle==(struct EditMapElement*)-1) + { + if(next_face_selected>1&&face_is_in_list(hilited_face.Face)) + { + SLONG c0; + if((flags&POLY_FLAG_TILED)&&!(old_flags&POLY_FLAG_TILED) ) + { + //tiled mode just selecteD + fix_all_selected_faces_for_tile_mode(); + } + + for(c0=1;c0Textures[hilited_face.Face].DrawFlags=flags; + } + break; + case TAB_PRIMPICK: + break; + } + } + if(the_control) + { + delete the_control; + } +} + +UBYTE LevelEditor::DoStylePopup(MFPoint *clicked_point,UBYTE flags) +{ + ULONG c0, + control_id; + CPopUp *the_control = 0; + MFPoint local_point; + UBYTE old_flags; + + local_point = *clicked_point; + GlobalToLocal(&local_point); + popup_def.ControlLeft = local_point.X+4; + popup_def.ControlTop = local_point.Y-4; + + + if(CurrentModeTab()) + { + old_flags=flags; + face_popup[7].ItemFlags = 0; + for(c0=0;c0<7;c0++) + { + face_popup[c0].ItemFlags = 0; + if(flags&(1<TrackControl(&local_point); + flags = 0; + + for(c0=0;c0<7;c0++) + { + if(face_popup[c0].ItemFlags&MENU_CHECK_MASK) + flags |= (1<U[0]+current_texture->U[1]+current_texture->U[2]+current_texture->U[3]; + y= current_texture->V[0]+current_texture->V[1]+current_texture->V[2]+current_texture->V[3]; + + x>>=(2+5); + y>>=(2+5); +/* + if(PaintMode->GetPaintMode()==STYLE_PAINT) + { + type=PaintMode->CurrentStyleEdit; + } + else +*/ + +// http://smfeng.yeah.net + /* + if(type==0) + { + index=page*64+x+y*8; + + type=texture_info[index].Type; + + sub_type=texture_info[index].SubType; + } + */ + + LogText("NUKE set wall %d walls storey %d style %d \n",wall,wall_list[wall].StoreyHead,type); + + + if(side==0) + wall_list[wall].TextureStyle=type; + else + wall_list[wall].TextureStyle2=type; + if(!ControlFlag) + { + storey=wall_list[wall].StoreyHead; + wall_index=storey_list[storey].WallHead; + while(wall_index) + { + LogText(" set wall texture index %d \n",wall_index); + if(side==0) + wall_list[wall_index].TextureStyle=type; + else + wall_list[wall_index].TextureStyle2=type; + + wall_index=wall_list[wall_index].Next; + } + } +} + +//--------------------------------------------------------------- + +void LevelEditor::TextureFace(SWORD face,PaintTab *texture_mode) +{ + SLONG c0; + EdTexture *current_texture; + + + + if(texture_mode->GetPaintMode()==PALETTE_PAINT) + { + if(face<0) + { + if ( + !(prim_faces3[-face].DrawFlags&POLY_FLAG_TEXTURED) && + prim_faces3[-face].Col2==texture_mode->GetCurrentColour() + ) + return; + } + else + { + if ( + !(prim_faces4[face].DrawFlags&POLY_FLAG_TEXTURED) && + prim_faces4[face].Col2==texture_mode->GetCurrentColour() + ) + return; + } + } + else + { + current_texture = texture_mode->GetTexture(); + + if(face<0) + { + if ( + prim_faces3[-face].DrawFlags&POLY_FLAG_TEXTURED && + prim_faces3[-face].TexturePage==(SBYTE)texture_mode->GetTexturePage() && + prim_faces3[-face].UV[0][0]==current_texture->U[0] && + prim_faces3[-face].UV[0][1]==current_texture->V[0] && + prim_faces3[-face].UV[1][0]==current_texture->U[1] && + prim_faces3[-face].UV[1][1]==current_texture->V[1] && + prim_faces3[-face].UV[2][0]==current_texture->U[2] && + prim_faces3[-face].UV[2][1]==current_texture->V[2] + ) + return; + } + else + { + + if ( + prim_faces4[face].DrawFlags&POLY_FLAG_TEXTURED && + prim_faces4[face].TexturePage==(UBYTE)texture_mode->GetTexturePage() && + prim_faces4[face].UV[0][0]==current_texture->U[0] && + prim_faces4[face].UV[0][1]==current_texture->V[0] && + prim_faces4[face].UV[1][0]==current_texture->U[1] && + prim_faces4[face].UV[1][1]==current_texture->V[1] && + prim_faces4[face].UV[2][0]==current_texture->U[2] && + prim_faces4[face].UV[2][1]==current_texture->V[2] && + prim_faces4[face].UV[3][0]==current_texture->U[3] && + prim_faces4[face].UV[3][1]==current_texture->V[3] + ) + return; + } + } + + if(face<0) + { + texture_mode->MyUndo.ApplyPrim3(0,-face,&prim_faces3[-face]); + } + else + { + texture_mode->MyUndo.ApplyPrim4(0,face,&prim_faces4[face]); + } + + if(texture_mode->GetPaintMode()==PALETTE_PAINT) + { + if(face<0) + { + prim_faces3[-face].DrawFlags &= ~(POLY_FLAG_TEXTURED); + prim_faces3[-face].Col2 = texture_mode->GetCurrentColour(); + } + else + { + prim_faces4[face].DrawFlags &= ~(POLY_FLAG_TEXTURED); + prim_faces4[face].Col2 = texture_mode->GetCurrentColour(); + } + } + else + { + if(face<0) + { + prim_faces3[-face].DrawFlags |= POLY_FLAG_TEXTURED; + prim_faces3[-face].TexturePage = (SBYTE)texture_mode->GetTexturePage(); + for(c0=0;c0<3;c0++) + { + prim_faces3[-face].UV[c0][0] = current_texture->U[c0]; + prim_faces3[-face].UV[c0][1] = current_texture->V[c0]; + } + } + else + { + if(texture_mode->GetTexturePage()<0) + { + prim_faces4[face].TexturePage=-texture_mode->GetTexturePage(); + prim_faces4[face].FaceFlags|=FACE_FLAG_ANIMATE; + } + else + { + prim_faces4[face].DrawFlags |= POLY_FLAG_TEXTURED; + prim_faces4[face].TexturePage = (SBYTE)texture_mode->GetTexturePage(); + + for(c0=0;c0<4;c0++) + { + prim_faces4[face].UV[c0][0] = current_texture->U[c0]; + prim_faces4[face].UV[c0][1] = current_texture->V[c0]; + } + if(prim_faces4[face].FaceFlags&FACE_FLAG_WALKABLE) + { + // + // try and paint roof texture to floor + // + SLONG mx=0,mz=0; + for(c0=0;c0<4;c0++) + { + mx+=prim_points[prim_faces4[face].Points[c0]].X; + mz+=prim_points[prim_faces4[face].Points[c0]].Z; + } + mx>>=2; + mz>>=2; + + edit_map[mx>>ELE_SHIFT][mz>>ELE_SHIFT].Texture=PaintMode->ConvertTexToMiniTex(); + } + + if(prim_faces4[face].ThingIndex<0) + { // face is part of a buildtab building, so set walls texture info + UBYTE type=0; + if(PaintMode->GetPaintMode()==STYLE_PAINT) + { + type=PaintMode->CurrentStyleEdit; + set_wall_texture_info(-prim_faces4[face].ThingIndex,(SBYTE)texture_mode->GetTexturePage(),current_texture,type,(prim_faces4[face].FaceFlags&FACE_FLAG_TEX2)?1:0); + } + else + { + // + // apply an individual texture to a wall face + // +extern void apply_texture_to_wall_face(SLONG face,SLONG texture); + SLONG t; + SLONG x=0,y=0,c0; + + for(c0=0;c0<4;c0++) + { + x+=current_texture->U[c0]; + y+=current_texture->V[c0]; + } + x>>=2; + y>>=2; + + x>>=5; + y>>=5; + + t=x+y*8+texture_mode->GetTexturePage()*64; + if(t<128) + { + if(current_texture->U[0]>current_texture->U[1]) + t|=0x80; + apply_texture_to_wall_face(face,t); + } + + } + + } + } + } + } +} + +void calc_face_midpoint(SWORD face,SLONG *x,SLONG *y,SLONG *z) +{ + SLONG x1=0,y1=0,z1=0,point; + if(face>0) + { + for(point=0;point<4;point++) + { + x1+=prim_points[prim_faces4[face].Points[point]].X; + y1+=prim_points[prim_faces4[face].Points[point]].Y; + z1+=prim_points[prim_faces4[face].Points[point]].Z; + } + } + *x=x1>>2; + *y=y1>>2; + *z=z1>>2; + +} + +SLONG find_map_coord(SLONG *x,SLONG *y,SLONG *z,struct EditMapElement *p_ele) +{ +/* + SLONG index; + struct EditMapElement *p_ele2; + SLONG mx,my,mz,dx,dy,dz; + + mx=(engine.X>>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + for(dx=-12;dx<12;dx++) + for(dy=-12;dy<12;dy++) + for(dz=-12;dz<12;dz++) + { + index=edit_map[(dx+mx)][(dy+my)].Depth[(dz+mz)]; +// draw_map_thing(index); + if(index) + { + p_ele2=&edit_map_eles[index]; + if(p_ele2==p_ele) + { + *x=mx+dx; + *y=my+dy; + *z=mz+dz; + return(1); + } + } + } +*/ + return(0); +} + +SLONG static_face_no; +SLONG flood_fill_texture(SLONG x,SLONG y,SLONG z,ULONG tex_bits) +{ +/* + struct EditMapElement *PEle; + SLONG tx,ty,tz; + SLONG index; + struct TextureBits tex_bits2; + *(ULONG*)&tex_bits2=tex_bits; + + tx=x; + ty=y; + tz=z; + + index=edit_map[(x)][(y)].Depth[(z)]; + if(index) + { + PEle=&edit_map_eles[index]; + PEle->Textures[static_face_no]=tex_bits2; + switch(static_face_no) + { + case CUBE_INDEX_FRONT: + case CUBE_INDEX_BACK: + if(index=edit_map[(x+1)][(y)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x+1,y,z,tex_bits); + } + if(index=edit_map[(x-1)][(y)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x-1,y,z,tex_bits); + } + if(index=edit_map[(x)][(y-1)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y-1,z,tex_bits); + } + if(index=edit_map[(x)][(y+1)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y+1,z,tex_bits); + } + + break; + case CUBE_INDEX_TOP: + case CUBE_INDEX_BOTTOM: + if(index=edit_map[(x+1)][(y)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x+1,y,z,tex_bits); + } + if(index=edit_map[(x-1)][(y)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x-1,y,z,tex_bits); + } + if(index=edit_map[(x)][(y)].Depth[(z-1)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y,z-1,tex_bits); + } + if(index=edit_map[(x)][(y)].Depth[(z+1)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y,z+1,tex_bits); + } + break; + + case CUBE_INDEX_LEFT: + case CUBE_INDEX_RIGHT: + if(index=edit_map[(x)][(y)].Depth[(z-1)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y,z-1,tex_bits); + } + if(index=edit_map[(x)][(y)].Depth[(z+1)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y,z+1,tex_bits); + } + if(index=edit_map[(x)][(y-1)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y-1,z,tex_bits); + } + if(index=edit_map[(x)][(y+1)].Depth[(z)]) + { + + PEle=&edit_map_eles[index]; + if(*(ULONG*)&PEle->Textures[static_face_no]!=tex_bits) + flood_fill_texture(x,y+1,z,tex_bits); + } + break; + } + } +*/ + return(0); +} + + +extern UWORD make_poly_into_glass_shatter_prim(SWORD face,SWORD mid_x,SWORD mid_y,SWORD mid_z); +BOOL LevelEditor::ApplyTexture(struct EditFace *edit_face) +{ + SLONG c0; + + + if(edit_face->PEle==(struct EditMapElement*)-2) + { + if(PaintMode==PALETTE_PAINT) + { + + } + else + { + LogText(" paint texture to floor at %d %d \n",edit_face->MapX,edit_face->MapZ); + // + // apply texture to floor + // + + if(PaintMode->GetTexturePage()<0) + { + edit_map[edit_face->MapX][edit_face->MapZ].Texture=-PaintMode->GetTexturePage(); //-CurrentTexturePage; //PaintMode->ConvertTexToMiniTex(); + edit_map[edit_face->MapX][edit_face->MapZ].Walkable=-1; //CurrentTexturePage; //PaintMode->ConvertTexToMiniTex(); + + } + else + { + if(edit_info.RoofTex) + { + tex_map[edit_face->MapX][edit_face->MapZ]=PaintMode->ConvertTexToMiniTex(); + } + else + { + edit_map[edit_face->MapX][edit_face->MapZ].Texture=PaintMode->ConvertTexToMiniTex(); + } + } + } + + + } + else + if(edit_face->PEle==(struct EditMapElement*)-1) + { + SLONG mid_x,mid_y,mid_z; + +// calc_face_midpoint(edit_face->Face,&mid_x,&mid_y,&mid_z); +// make_poly_into_glass_shatter_prim(edit_face->Face,mid_x,mid_y,mid_z); + + if(face_is_in_list(edit_face->Face)) + { + for(c0=1;c0Face,PaintMode); +// next_face_selected=1; + } + return 1; + } + else if(edit_face->PEle) + { + SLONG x,y,width,height,page; + SLONG mx,my,mz; + ULONG texbits; + PaintMode->ConvertFreeToFixedEle(&edit_face->PEle->Textures[edit_face->Face],&x,&y,&width,&height,&page); + if(ShiftFlag) + { + + texbits=(*(ULONG*)&edit_face->PEle->Textures[edit_face->Face]); + + find_map_coord(&mx,&my,&mz,edit_face->PEle); + static_face_no=edit_face->Face; + flood_fill_texture(mx,my,mz,texbits); + } + return 1; + } + return 0; +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/LightTab.cpp b/fallen/Editor/Source/LightTab.cpp new file mode 100644 index 0000000..8bb70ee --- /dev/null +++ b/fallen/Editor/Source/LightTab.cpp @@ -0,0 +1,1593 @@ +#include "Editor.hpp" + +#include "LightTab.hpp" +#include "engine.h" +#include "c:\fallen\headers\memory.h" + +static counter; +#define SHADOW_LIGHT_SHIFT (5) +//#define ShowWorkWindow(x) {DrawLineC(0+(counter-1)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,0);DrawLineC(0+(counter++)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,255);DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); ShowWorkWindow(x);} + +//--------------------------------------------------------------- +//debug stuff +/* +void cross_work_window(void) +{ + DrawLineC(0,0,WorkWindowWidth-1,WorkWindowHeight-1,255); + DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); + +} +*/ +//--------------------------------------------------------------- + +void apply_ambient_to_floor(void); +void remove_ambient_from_floor(void); + +#define CTRL_LIGHT_X_AXIS_FREE 1 +#define CTRL_LIGHT_Y_AXIS_FREE 2 +#define CTRL_LIGHT_Z_AXIS_FREE 3 +#define CTRL_LIGHT_PLACE 4 +#define CTRL_LIGHT_SMOOTH_LOTS 5 +#define CTRL_LIGHT_PLACE_AMBIENT 6 +#define CTRL_LIGHT_BRIGHT 7 +#define CTRL_LIGHT_SHADOW 8 +#define CTRL_LIGHT_DELETE 9 +#define CTRL_LIGHT_FINISH_AMBIENT 10 + +#define CTRL_LIGHT_WHITE 11 +#define CTRL_LIGHT_PALE_BLUE 12 +#define CTRL_LIGHT_ORANGE 13 +#define CTRL_LIGHT_YELLOW 14 +#define CTRL_LIGHT_RED 15 +#define CTRL_LIGHT_BLUE 16 +#define CTRL_LIGHT_SLIDE_RED 17 +#define CTRL_LIGHT_SLIDE_GREEN 18 +#define CTRL_LIGHT_SLIDE_BLUE 19 + +#define CTRL_LIGHT_NORMAL 20 +#define CTRL_LIGHT_BROKEN 21 +#define CTRL_LIGHT_FLASH 22 +#define CTRL_LIGHT_PARAM 23 + + +ControlDef light_tab_def[] = +{ + { CHECK_BOX, 0, "X Free", 20, 150, 0, 10 }, + { CHECK_BOX, 0, "Y Free", 20, 165, 0, 10 }, + { CHECK_BOX, 0, "Z Free", 20, 180, 0, 10 }, + { BUTTON, 0, "Place a Light" , 20, 50, 0, 0 }, + { BUTTON, 0, "Smooth Shades For Group", 20, 65, 0, 0 }, + { BUTTON, 0, "Replace Ambient", 20, 80, 0, 0 }, + { H_SLIDER, 0, "", 20, 100, 250,0 }, + { CHECK_BOX, 0, "Shadow", 20, 115, 0, 10 }, + { BUTTON, 0, "DELETE ALL LIGHTS", 180, 50, 0, 0 }, + { BUTTON, 0, "Finish ambient", 20, 130, 0, 0 }, + { BUTTON, 0, "White", 20, 200, 0, 0 }, + { BUTTON, 0, "Pale blue", 20, 215, 0, 0 }, + { BUTTON, 0, "Orange", 20, 230, 0, 0 }, + { BUTTON, 0, "Yellow", 20, 245, 0, 0 }, + { BUTTON, 0, "Red", 20, 260, 0, 0 }, + { BUTTON, 0, "Blue", 20, 275, 0, 0 }, + { H_SLIDER, 0, "", 90, 207, 150,0 }, + { H_SLIDER, 0, "", 90, 227, 150,0 }, + { H_SLIDER, 0, "", 90, 247, 150,0 }, + { CHECK_BOX, 0, "Normal", 20, 295, 0, 0 }, + { CHECK_BOX, 0, "Broken", 20, 310, 0, 0 }, + { CHECK_BOX, 0, "Flash", 20, 325, 0, 0 }, + { H_SLIDER, 0, "", 90, 310, 150,0 }, + { 0 } +}; + + + +LightTab *the_lighttab; +static light_x,light_y,light_z,light_bright; + +void redraw_tab(void); +void scan_apply_ambient(SLONG face,SLONG x,SLONG y,SLONG z,SLONG extra); +void link_all_lights(void); +void scan_undo_ambient(SLONG face,SLONG x,SLONG y,SLONG z,SLONG extra); +//--------------------------------------------------------------- + +LightTab::LightTab(EditorModule *parent) +{ + Parent=parent; + + InitControlSet(light_tab_def); + AxisMode=3; + + SetControlState(CTRL_LIGHT_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_LIGHT_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_LIGHT_Z_AXIS_FREE,CTRL_SELECTED); + + ((CHSlider*)GetControlPtr(CTRL_LIGHT_BRIGHT))->SetValueRange(0,4096); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_BRIGHT))->SetCurrentValue(512); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_BRIGHT))->SetUpdateFunction(redraw_tab); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + CurrentLight=0; + Mode=0; + Shadow=0; + + the_lighttab=this; + + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED))->SetValueRange(0,255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED))->SetUpdateFunction(redraw_tab); + + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetValueRange(0,255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetUpdateFunction(redraw_tab); + + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE))->SetValueRange(0,255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE))->SetUpdateFunction(redraw_tab); + + ((CHSlider*)GetControlPtr(CTRL_LIGHT_PARAM))->SetValueRange(0,100); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_PARAM))->SetCurrentValue(50); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_PARAM))->SetUpdateFunction(redraw_tab); + +} + +LightTab::~LightTab() +{ +} + + +void LightTab::DrawTabContent(void) +{ + EdRect content_rect; + + + + content_rect = ContentRect; + content_rect.ShrinkRect(1,1); + content_rect.FillRect(CONTENT_COL); + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + if(CurrentLight) + { + SLONG bright; + static SLONG old_bright; + bright = ((CHSlider*)GetControlPtr(CTRL_LIGHT_BRIGHT))->GetCurrentValue(); + if(bright!=old_bright) + { + apply_light_to_map(map_things[CurrentLight].X,map_things[CurrentLight].Y,map_things[CurrentLight].Z,-map_things[CurrentLight].IndexOther); + old_bright=map_things[CurrentLight].IndexOther; + map_things[CurrentLight].IndexOther=bright; + apply_light_to_map(map_things[CurrentLight].X,map_things[CurrentLight].Y,map_things[CurrentLight].Z,map_things[CurrentLight].IndexOther); +// RedrawModuleContent=1; + } + + map_things[CurrentLight].AngleX = ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->GetCurrentValue(); + map_things[CurrentLight].AngleY = ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->GetCurrentValue(); + map_things[CurrentLight].AngleZ = ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->GetCurrentValue(); + + map_things[CurrentLight].IndexOrig = ((CHSlider*)GetControlPtr(CTRL_LIGHT_PARAM ))->GetCurrentValue(); + + switch(map_things[CurrentLight].IndexOrig) + { + case LIGHT_TYPE_NORMAL: + case LIGHT_TYPE_BROKEN: + case LIGHT_TYPE_PULSE: + map_things[CurrentLight].IndexOrig >>= 1; + break; + } + } + + DrawControlSet(); + ShowWorkWindow(0); +// DrawPrims(); +} + + + +SLONG sum_shared_brightness(SWORD shared_point) +{ + SLONG c0,point; + SLONG face; + SLONG bright=0; + SLONG count=0; + + for(c0=1;c00) + { + for(point=0;point<4;point++) + { + if(prim_faces4[face].Points[point]==shared_point) + { + bright+=prim_faces4[face].Bright[point]; + count++; + } + } + + } + } + if(count) + return(bright/count); + else + return(0); +} + +void set_shared_brightness(SWORD shared_point,SWORD bright) +{ + SLONG c0,point; + SLONG face; + + for(c0=1;c00) + { + for(point=0;point<4;point++) + { + if(prim_faces4[face].Points[point]==shared_point) + { + prim_faces4[face].Bright[point]=bright; + } + } + } + } +} + +void LightTab::SmoothGroup(void) +{ + SLONG c0,c1,point; + SLONG face; + SLONG bright; + + for(c0=1;c00) + { + prim_faces4[face].FaceFlags|=FACE_FLAG_SMOOTH; + for(point=0;point<4;point++) + { + bright=sum_shared_brightness(prim_faces4[face].Points[point]); + set_shared_brightness(prim_faces4[face].Points[point],bright); + } + } + } +} + + + + +void apply_ambient_to_floor(void) +{ + SLONG x,z; + SLONG bright,temp_bright; + + bright=(edit_info.amb_bright*(-edit_info.amb_dy))>>9; + + if(bright<0) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + else + if(bright>128) + bright=128; + +// bright=64; + + for(x=0;x>9; +// bright=edit_info.amb_bright>>1; + + if(bright<0) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + else + if(bright>128) + bright=128; + + for(x=0;xMode) + { + + case LIGHT_TAB_MODE_PLACE_AMBIENT: + + scan_function=scan_undo_ambient; + scan_map(); + remove_ambient_from_floor(); + + + edit_info.amb_bright = ((CHSlider*)the_lighttab->GetControlPtr(CTRL_LIGHT_BRIGHT))->GetCurrentValue(); +// link_all_lights(); + scan_function=scan_apply_ambient; + scan_map(); + apply_ambient_to_floor(); + the_lighttab->DrawTabContent(); + the_lighttab->Parent->DrawContent(); +// the_lighttab->DrawTabContent(); + + SetWorkWindowBounds(the_lighttab->Parent->GetLeft(), + the_lighttab->Parent->GetTop(), + the_lighttab->Parent->GetWidth(), + the_lighttab->Parent->GetHeight()); + + break; + + default: + + the_lighttab->DrawTabContent(); + the_lighttab->Parent->DrawContent(); + SetWorkWindowBounds(the_lighttab->Parent->GetLeft(), + the_lighttab->Parent->GetTop(), + the_lighttab->Parent->GetWidth(), + the_lighttab->Parent->GetHeight()); + break; + } + +} + +//--------------------------------------------------------------- + +void LightTab::DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG wwx,wwy,www,wwh; + EdRect drawrect; + + RedrawModuleContent=0; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + View1.SetRect(x,y,w-1,h/2-3); + View2.SetRect(x,y+h/2+4,w-1,h/2-4); + + SetWorkWindowBounds(x,y,w-1,h/2-3); + drawrect.SetRect(0,0,w-1,h/2-3); + + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + set_camera_plan(); + draw_editor_map(0); + render_view(0); + hilight_map_things(MAP_THING_TYPE_LIGHT); + + if(Mode==LIGHT_TAB_MODE_PLACE_AMBIENT) + draw_3d_line(engine.X>>8,engine.Y>>8,engine.Z>>8,(engine.X>>8)+(edit_info.amb_dx>>2),(engine.Y>>8)+(edit_info.amb_dy>>2),(engine.Z>>8)+(edit_info.amb_dz>>2),WHITE_COL); + + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + drawrect.SetRect(0,0,w-1,h/2-4); + +// drawrect.FillRect(LOLITE_COL); + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + + set_camera_front(); + draw_editor_map(0); + render_view(0); + hilight_map_things(MAP_THING_TYPE_LIGHT); + + if(Mode==LIGHT_TAB_MODE_PLACE_AMBIENT) + draw_3d_line(engine.X>>8,engine.Y>>8,engine.Z>>8,(engine.X>>8)+(edit_info.amb_dx>>2),(engine.Y>>8)+(edit_info.amb_dy>>2),(engine.Z>>8)+(edit_info.amb_dz>>2),WHITE_COL); + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT +} + +//--------------------------------------------------------------- + + +void LightTab::HandleTab(MFPoint *current_point) +{ + SLONG update = 0; + + + ModeTab::HandleTab(current_point); + KeyboardInterface(); + +} + +inline SLONG is_point_in_box(SLONG x,SLONG y,SLONG left,SLONG top,SLONG w,SLONG h) +{ + if(x>left&&xtop&&y3) + AxisMode=0; + switch(AxisMode) + { + case 0: + SetControlState(CTRL_LIGHT_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_LIGHT_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=X_AXIS; + break; + case 1: + SetControlState(CTRL_LIGHT_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_LIGHT_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=Y_AXIS; + break; + case 2: + SetControlState(CTRL_LIGHT_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_Z_AXIS_FREE,CTRL_SELECTED); + Axis=Z_AXIS; + break; + case 3: + SetControlState(CTRL_LIGHT_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_LIGHT_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_LIGHT_Z_AXIS_FREE,CTRL_SELECTED); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + break; + } + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); + } + return(0); +} + +inline SLONG normalise_xyz(SLONG *x,SLONG *y,SLONG *z) +{ + SLONG dist; + + dist=(*x)*(*x)+(*y)*(*y)+(*z)*(*z); + dist=sqrl(dist); + + if(dist==0) + dist=1; + + *x=(*x<<8)/dist; + *y=(*y<<8)/dist; + *z=(*z<<8)/dist; + + return(dist); +} + + +void scan_apply_light(SLONG face,SLONG x,SLONG y,SLONG z,SLONG extra) +{ + SVector normal; + SLONG dx,dy,dz,dist; + SLONG point,bright; + SLONG angle_light; + + SLONG lnx,lny,lnz; + + + + if(face<0) + { //tris +#ifdef NORMAL + dx=dy=dz=0; + for(point=0;point<3;point++) + { + dx+=(prim_points[prim_faces3[-face].Points[point]].X); + dy+=(prim_points[prim_faces3[-face].Points[point]].Y); + dz+=(prim_points[prim_faces3[-face].Points[point]].Z); + } + dx/=3; + dy/=3; + dz/=3; + + dx+=x; + dy+=y; + dz+=z; + + lnx=dx-light_x; + lny=dy-light_y; + lnz=dz-light_z; + + dist=normalise_xyz(&lnx,&lny,&lnz); + + calc_normal(-face,&normal); + angle_light=(normal.X*lnx+normal.Y*lny+normal.Z*lnz)>>8; + if(angle_light<0) + return; +#endif + for(point=0;point<3;point++) + { + dx=light_x-(x+prim_points[prim_faces3[-face].Points[point]].X); + dy=light_y-(y+prim_points[prim_faces3[-face].Points[point]].Y); + dz=light_z-(z+prim_points[prim_faces3[-face].Points[point]].Z); + + dist=dx*dx+dy*dy+dz*dz; + if(dist==0) + dist=1; + + + bright=(light_bright<<11)/dist; //scale brightness because of distance +#ifdef NORMAL + bright=(angle_light*bright)>>8; //scale brightness because of angle to light +#endif + bright+=prim_faces3[-face].Bright[point]; + if(bright>=32767) + bright=32767; + prim_faces3[-face].Bright[point]=bright; + } + } + else + if(face>0) + { //quads +#ifdef NORMAL + dx=dy=dz=0; + for(point=0;point<4;point++) + { + dx+=(prim_points[prim_faces4[face].Points[point]].X); + dy+=(prim_points[prim_faces4[face].Points[point]].Y); + dz+=(prim_points[prim_faces4[face].Points[point]].Z); + } + dx/=4; + dy/=4; + dz/=4; + + dx+=x; + dy+=y; + dz+=z; + + lnx=dx-light_x; + lny=dy-light_y; + lnz=dz-light_z; + + normalise_xyz(&lnx,&lny,&lnz); + + + calc_normal(face,&normal); + angle_light=(normal.X*lnx+normal.Y*lny+normal.Z*lnz)>>8; + if(angle_light<0) + return; +#endif + for(point=0;point<4;point++) + { + dx=light_x-(x+prim_points[prim_faces4[face].Points[point]].X); + dy=light_y-(y+prim_points[prim_faces4[face].Points[point]].Y); + dz=light_z-(z+prim_points[prim_faces4[face].Points[point]].Z); + + dist=dx*dx+dy*dy+dz*dz; + if(dist==0) + dist=1; + + bright=(light_bright<<11)/dist; +#ifdef NORMAL + bright=(angle_light*bright)>>8; //scale brightness because of angle to light +#endif + + bright+=prim_faces4[face].Bright[point]; + if(bright>=32767) + bright=32767; + prim_faces4[face].Bright[point]=bright; + } + } +} + +static light_head=0; + +void link_all_lights(void) +{ + SLONG c0; + + for(c0=1;c0>8; + if(angle_light<0) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + else + bright=(angle_light*edit_info.amb_bright)>>9; //scale brightness because of angle to light + + if(bright>SHADOW_LIGHT_SHIFT) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + + if(bright>128) + bright=128; + + if(edit_info.amb_flags&2) + { + prim_faces3[-face].Bright[0]=bright; + prim_faces3[-face].Bright[1]=bright; + prim_faces3[-face].Bright[2]=bright; + } + else + { + prim_faces3[-face].Bright[0]+=bright; + prim_faces3[-face].Bright[1]+=bright; + prim_faces3[-face].Bright[2]+=bright; + } + + } + else + if(face>0) + { //quads + dx=dy=dz=0; + + lnx=edit_info.amb_dx; + lny=edit_info.amb_dy; + lnz=edit_info.amb_dz; + + calc_normal(face,&normal); + angle_light=(normal.X*lnx+normal.Y*lny+normal.Z*lnz)>>8; + if(angle_light<0) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + else + bright=(angle_light*edit_info.amb_bright)>>9; //scale brightness because of angle to light + + if(bright>SHADOW_LIGHT_SHIFT) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + + if(bright>128) + bright=128; + +// if(bright>3) +// bright=edit_info.amb_bright>>3; + + if(edit_info.amb_flags&2) + { + prim_faces4[face].Bright[0]=bright; + prim_faces4[face].Bright[1]=bright; + prim_faces4[face].Bright[2]=bright; + prim_faces4[face].Bright[3]=bright; + } + else + { + prim_faces4[face].Bright[0]+=bright; + prim_faces4[face].Bright[1]+=bright; + prim_faces4[face].Bright[2]+=bright; + prim_faces4[face].Bright[3]+=bright; + } +// apply_all_lights_to_this_face(face,x,y,z,extra); + } +} +void scan_unlight(SLONG face,SLONG x,SLONG y,SLONG z,SLONG extra) +{ + if(face<0) + { //tris + prim_faces3[-face].Bright[0]=0; + prim_faces3[-face].Bright[1]=0; + prim_faces3[-face].Bright[2]=0; + + } + else + if(face>0) + { //quads + prim_faces4[face].Bright[0]=0; + prim_faces4[face].Bright[1]=0; + prim_faces4[face].Bright[2]=0; + prim_faces4[face].Bright[3]=0; + } + +} + +void scan_undo_ambient(SLONG face,SLONG x,SLONG y,SLONG z,SLONG extra) +{ + SVector normal; + SLONG dx,dy,dz,dist; + SLONG point,bright; + SLONG angle_light; + + SLONG lnx,lny,lnz; + + return; + + + + if(face<0) + { //tris + + lnx=edit_info.amb_dx; + lny=edit_info.amb_dy; + lnz=edit_info.amb_dz; + + calc_normal(face,&normal); + angle_light=(normal.X*lnx+normal.Y*lny+normal.Z*lnz)>>9; + if(angle_light<0) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + else + bright=(angle_light*edit_info.amb_bright)>>8; //scale brightness because of angle to light + + if(bright>SHADOW_LIGHT_SHIFT) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + + if(bright>128) + bright=128; + + prim_faces3[-face].Bright[0]-=bright; + prim_faces3[-face].Bright[1]-=bright; + prim_faces3[-face].Bright[2]-=bright; + CLIPV_0(prim_faces3[-face].Bright[0]); + CLIPV_0(prim_faces3[-face].Bright[1]); + CLIPV_0(prim_faces3[-face].Bright[2]); +// apply_all_lights_to_this_face(face,x,y,z,extra); + + } + else + if(face>0) + { //quads + dx=dy=dz=0; + + lnx=edit_info.amb_dx; + lny=edit_info.amb_dy; + lnz=edit_info.amb_dz; + + calc_normal(face,&normal); + angle_light=(normal.X*lnx+normal.Y*lny+normal.Z*lnz)>>8; + if(angle_light<0) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + else + bright=(angle_light*edit_info.amb_bright)>>9; //scale brightness because of angle to light + + + if(bright>SHADOW_LIGHT_SHIFT) + bright=edit_info.amb_bright>>SHADOW_LIGHT_SHIFT; + + if(bright>128) + bright=128; + + prim_faces4[face].Bright[0]-=bright; + prim_faces4[face].Bright[1]-=bright; + prim_faces4[face].Bright[2]-=bright; + prim_faces4[face].Bright[3]-=bright; + CLIPV_0(prim_faces4[face].Bright[0]); + CLIPV_0(prim_faces4[face].Bright[1]); + CLIPV_0(prim_faces4[face].Bright[2]); + CLIPV_0(prim_faces4[face].Bright[3]); +// apply_all_lights_to_this_face(face,x,y,z,extra); + } +} + +void apply_light_to_floor(SLONG x,SLONG y,SLONG z,SLONG light_bright) +{ + SLONG mx,mz,dx,dz; + + SLONG ldx,ldy,ldz,dist; + SLONG bright; + + mx=x>>ELE_SHIFT; + mz=z>>ELE_SHIFT; + + for(dx=-32;dx<32;dx++) + for(dz=-32;dz<32;dz++) + { + if(dx+mx>0&&dx+mx0&&dz+mz>SHADOW_LIGHT_SHIFT; + else + if(bright>128) + bright=128; + + edit_map[mx+dx][mz+dz].Bright=bright; + } + } +} + +void apply_light_to_map(SLONG x,SLONG y,SLONG z,SLONG bright) +{ + return; + apply_light_to_floor(x,y,z,bright); + light_x=x; + light_y=y; + light_z=z; + light_bright=bright; + scan_function=scan_apply_light; + scan_map(); +} + + +SWORD CreateALightThing(SLONG x,SLONG y,SLONG z,SLONG bright) +{ + UWORD map_thing; + struct MapThing *p_mthing; + + map_thing=find_empty_map_thing(); + if(!map_thing) + return(0); + add_thing_to_edit_map(x>>ELE_SHIFT,z>>ELE_SHIFT,map_thing); + p_mthing=TO_MTHING(map_thing); + p_mthing->X=x; + p_mthing->Y=y; + p_mthing->Z=z; + + p_mthing->Type=MAP_THING_TYPE_LIGHT; + p_mthing->IndexOther=(SWORD)bright; + apply_light_to_map(x,y,z,bright); + + return(map_thing); +} + +SWORD LightTab::CreateLightThing(SLONG x,SLONG y,SLONG z,SLONG bright) +{ + UWORD map_thing; + struct MapThing *p_mthing; + + map_thing=find_empty_map_thing(); + if(!map_thing) + return(0); + add_thing_to_edit_map(x>>ELE_SHIFT,z>>ELE_SHIFT,map_thing); + p_mthing=TO_MTHING(map_thing); + p_mthing->X=x; + p_mthing->Y=y; + p_mthing->Z=z; + + p_mthing->Type=MAP_THING_TYPE_LIGHT; + p_mthing->SubType = LIGHT_TYPE_NORMAL; + p_mthing->IndexOther=(SWORD)bright; + + p_mthing->AngleX = ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->GetCurrentValue(); + p_mthing->AngleY = ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->GetCurrentValue(); + p_mthing->AngleZ = ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->GetCurrentValue(); + + p_mthing->IndexOrig = ((CHSlider*)GetControlPtr(CTRL_LIGHT_PARAM ))->GetCurrentValue(); + + apply_light_to_map(x,y,z,bright); + + return(map_thing); +} + + + +SLONG LightTab::ClickOnLight(MFPoint *clicked_point) +{ + MFPoint local_point; + SLONG x,y,w,h; + SLONG drag; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + + SetWorkWindowBounds(x,y,w-1,h/2-3); + set_camera_plan(); + + local_point = *clicked_point; + drag=select_map_things(clicked_point,MAP_THING_TYPE_LIGHT); + + + if(!drag) + { + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + set_camera_front(); + local_point =*clicked_point; + local_point.Y-=h/2; + drag=select_map_things(&local_point,MAP_THING_TYPE_LIGHT); + } + if(drag) + { + return(drag); + } + return(0); +} + +SLONG LightTab::DragALight(UBYTE flags,MFPoint *clicked_point,UWORD copy) +{ + SLONG dx,dy,dz; + UWORD index; + EdRect prim_rect; + struct MapThing *p_mthing; + static UBYTE col=0; + SLONG screen_change=0; + MFPoint local_point; + SLONG x,y,w,h; + SLONG drag; + SLONG wwx,wwy,www,wwh; + SLONG ox,oy,oz; + + SLONG last_world_mouse; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + + SetWorkWindowBounds(x,y,w-1,h/2-3); + set_camera_plan(); + + local_point = *clicked_point; + drag=select_map_things(clicked_point,MAP_THING_TYPE_LIGHT); + + + if(!drag) + { + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + set_camera_front(); + local_point =*clicked_point; + local_point.Y-=h/2; + drag=select_map_things(&local_point,MAP_THING_TYPE_LIGHT); + } + + if(copy) + { + drag=CreateLightThing(map_things[drag].X, + map_things[drag].Y, + map_things[drag].Z, + map_things[drag].IndexOther); + } + + + engine.MousePosX=map_things[drag].X; + engine.MousePosY=map_things[drag].Y; + engine.MousePosZ=map_things[drag].Z; + ox=map_things[drag].X; + oy=map_things[drag].Y; + oz=map_things[drag].Z; + + if(drag) //drag in plan view + { + SLONG offset_x,offset_y,offset_z; + last_world_mouse=SetWorldMouse(0); + offset_x=map_things[drag].X-engine.MousePosX; + offset_y=map_things[drag].Y-engine.MousePosY; + offset_z=map_things[drag].Z-engine.MousePosZ; + + CurrentLight=drag; + + while(SHELL_ACTIVE && ((copy==0&&LeftButton)||(copy==1&&RightButton))) + { + SLONG nx,ny,nz; + last_world_mouse=SetWorldMouse(0); + + nx=map_things[drag].X; + ny=map_things[drag].Y; + nz=map_things[drag].Z; + + if(GridFlag) + { + SLONG grid_and; + grid_and=~(HALF_ELE_SIZE-1); + if(Axis&X_AXIS) + nx=(engine.MousePosX+offset_x)&grid_and; + if(Axis&Y_AXIS) + ny=(engine.MousePosY+offset_y)&grid_and; + if(Axis&Z_AXIS) + nz=(engine.MousePosZ+offset_z)&grid_and; + } + else + { + if(Axis&X_AXIS) + nx=engine.MousePosX+offset_x; + if(Axis&Y_AXIS) + ny=engine.MousePosY+offset_y; + if(Axis&Z_AXIS) + nz=engine.MousePosZ+offset_z; + } + + apply_light_to_map(map_things[drag].X,map_things[drag].Y,map_things[drag].Z,-map_things[drag].IndexOther); + move_thing_on_cells(drag,nx,ny,nz); + apply_light_to_map(nx,ny,nz,map_things[drag].IndexOther); + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + SetWorkWindowBounds(this->ContentLeft()+1,this->ContentTop()+1,this->ContentWidth(),this->ContentHeight()); +// ContentRect.FillRect(CONTENT_COL); + + DrawBox(0,0,this->ContentWidth(),this->ContentHeight(),CONTENT_COL); + set_camera(); + draw_editor_map(0); + render_view(0); + ShowWorkWindow(0); + editor_user_interface(0); + KeyboardInterface(); + } + +// MyUndo.MoveObject(0,drag,ox,oy,oz); + if(!last_world_mouse) + { + delete_thing(drag); + CurrentLight=0; + } + RequestUpdate(); + } +// SetWorkWindowBounds(this->ContentLeft()+1,this->ContentTop()+1,this->ContentWidth(),this->ContentHeight()); +// DrawBox(0,0,this->ContentWidth(),this->ContentHeight(),CONTENT_COL); +// ContentRect.FillRect(CONTENT_COL); +// UpdatePrimPickWindow(); + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); +} +void LightTab::SetAmbientAngle(void) +{ + SLONG bright; + //there has been a left click in a content window + while(SHELL_ACTIVE && LeftButton) + { + + if(SetWorldMouse(0)) + { +// link_all_lights(); + scan_function=scan_undo_ambient; + scan_map(); + remove_ambient_from_floor(); + + edit_info.amb_dx=engine.MousePosX-(engine.X>>8); + edit_info.amb_dy=engine.MousePosY-(engine.Y>>8); + edit_info.amb_dz=engine.MousePosZ-(engine.Z>>8); + normalise_xyz(&edit_info.amb_dx,&edit_info.amb_dy,&edit_info.amb_dz); + + edit_info.amb_bright = ((CHSlider*)GetControlPtr(CTRL_LIGHT_BRIGHT))->GetCurrentValue(); +// link_all_lights(); + scan_function=scan_apply_ambient; + scan_map(); + apply_ambient_to_floor(); + + if(LockWorkScreen()) + { + // DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) + Parent->DrawContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + { + SetWorkWindowBounds(this->ContentLeft()+1,this->ContentTop()+1,this->ContentWidth(),this->ContentHeight()); + + DrawBox(0,0,this->ContentWidth(),this->ContentHeight(),CONTENT_COL); + set_camera(); + draw_editor_map(0); + render_view(0); + ShowWorkWindow(0); + editor_user_interface(0); + KeyboardInterface(); + } + + + // RedrawModuleContent=1; + } + } + +} +SLONG LightTab::DragEngine(UBYTE flags,MFPoint *clicked_point) +{ + SLONG wwx,wwy,www,wwh; + SLONG screen_change=0; + SLONG last_world_mouse; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + + { + SLONG start_x=0,start_y=0,start_z=0,flag=0; + SLONG old_x,old_y,old_z; + SLONG nx,ny,nz; + + old_x=nx=engine.X; + old_y=ny=engine.Y; + old_z=nz=engine.Z; + + while(SHELL_ACTIVE && MiddleButton) + { + last_world_mouse=SetWorldMouse(0); + if(last_world_mouse) + { + if(!flag) + { + flag=1; + start_x=engine.MousePosX<<8; + start_y=engine.MousePosY<<8; + start_z=engine.MousePosZ<<8; + } + + nx=engine.MousePosX<<8; + ny=engine.MousePosY<<8; + nz=engine.MousePosZ<<8; + + engine.X = (old_x+(-nx+start_x)); + engine.Y = (old_y+(-ny+start_y)); + engine.Z = (old_z+(-nz+start_z)); + +// engine.Z=nz<<8; + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + engine.X=old_x; + engine.Y=old_y; + engine.Z=old_z; + + } + } + if(flag) + { + engine.X= (old_x+(-nx+start_x)); + engine.Y= (old_y+(-ny+start_y)); + engine.Z= (old_z+(-nz+start_z)); + } + } + return(screen_change); + +} + +SLONG LightTab::HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h) +{ + SWORD thing; + SWORD bright; + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + if(Mode!=LIGHT_TAB_MODE_PLACE_AMBIENT) + if(ClickOnLight(clicked_point)) + Mode=LIGHT_TAB_MODE_WAIT; + + switch (Mode) + { + case LIGHT_TAB_MODE_PLACE_AMBIENT: + SetAmbientAngle(); + break; + case LIGHT_TAB_MODE_REPEAT_PLACE_LIGHT: + Mode=LIGHT_TAB_MODE_WAIT; + + case LIGHT_TAB_MODE_WAIT: + DragALight(flags,clicked_point,0); + break; + case LIGHT_TAB_MODE_PLACE_LIGHT: + if(SetWorldMouse(1)) + { + bright = ((CHSlider*)GetControlPtr(CTRL_LIGHT_BRIGHT))->GetCurrentValue(); + CurrentLight=CreateLightThing(engine.MousePosX,engine.MousePosY,engine.MousePosZ,bright); + Mode=0; + } + return(1); + } + break; + case RIGHT_CLICK: + if(Mode!=LIGHT_TAB_MODE_PLACE_AMBIENT) + if(ClickOnLight(clicked_point)) + Mode=LIGHT_TAB_MODE_WAIT; //if you have clicked on a light you must want to drag it + switch (Mode) + { + case LIGHT_TAB_MODE_PLACE_AMBIENT: + SetAmbientAngle(); + break; + case LIGHT_TAB_MODE_WAIT: + DragALight(flags,clicked_point,1); + break; + case LIGHT_TAB_MODE_REPEAT_PLACE_LIGHT: + case LIGHT_TAB_MODE_PLACE_LIGHT: + if(SetWorldMouse(1)) + { + bright = ((CHSlider*)GetControlPtr(CTRL_LIGHT_BRIGHT))->GetCurrentValue(); + CurrentLight=CreateLightThing(engine.MousePosX,engine.MousePosY,engine.MousePosZ,bright); + Mode=LIGHT_TAB_MODE_REPEAT_PLACE_LIGHT; + } + return(1); + } + // Right click in content. + break; + case MIDDLE_CLICK: + DragEngine(flags,clicked_point); + break; + } + return(0); + +} + +UWORD LightTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + MFPoint local_point; + + + // This is a fudge to update the front screen buffer. + ShowWorkScreen(0); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + { + current_control = GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + control_id = current_control->TrackControl(&local_point); + HandleControl(control_id); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + return control_id; + } + current_control = current_control->GetNextControl(); + } + } + + break; + case RIGHT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + break; + } + return 0; +} + +//--------------------------------------------------------------- + +SLONG LightTab::SetWorldMouse(ULONG flag) +{ + MFPoint mouse_point; + MFPoint local_point; + SVector point,out; + SLONG wwx,wwy,www,wwh; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + + local_point = mouse_point; + Parent->GlobalToLocal(&local_point); + if(is_point_in_box(local_point.X,local_point.Y,0,0,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()/2-3); + set_camera_plan(); + calc_world_pos_plan(local_point.X,local_point.Y); + if(flag) + engine.MousePosY=engine.Y>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(1); + } + else + if(is_point_in_box(local_point.X,local_point.Y,0,Parent->ContentHeight()/2,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+Parent->ContentHeight()/2+3,Parent->ContentWidth()-1,Parent->ContentHeight()/2-4); + set_camera_front(); + calc_world_pos_front(local_point.X,local_point.Y-Parent->ContentHeight()/2); + if(flag) + engine.MousePosZ=engine.Z>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(1); + + } + else + return(0); + +} + +void delete_all_lights(void) +{ + SLONG c0; + + + for(c0=1;c0SetCurrentValue(256); + CurrentLight=0; + Mode=LIGHT_TAB_MODE_PLACE_AMBIENT; + break; + case CTRL_LIGHT_SHADOW: + ToggleControlSelectedState(CTRL_LIGHT_SHADOW); + break; + case CTRL_LIGHT_DELETE: + delete_all_lights(); + RequestUpdate(); + Mode=0; + break; + + case CTRL_LIGHT_WHITE: + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->SetCurrentValue(255); + RequestUpdate(); + break; + + case CTRL_LIGHT_PALE_BLUE: + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetCurrentValue(235); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->SetCurrentValue(225); + RequestUpdate(); + break; + + case CTRL_LIGHT_ORANGE: + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetCurrentValue(235); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->SetCurrentValue( 85); + RequestUpdate(); + break; + + case CTRL_LIGHT_YELLOW: + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->SetCurrentValue(105); + RequestUpdate(); + break; + + case CTRL_LIGHT_RED: + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->SetCurrentValue(255); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetCurrentValue( 55); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->SetCurrentValue( 55); + RequestUpdate(); + break; + + case CTRL_LIGHT_BLUE: + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_RED ))->SetCurrentValue( 75); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_GREEN))->SetCurrentValue( 75); + ((CHSlider*)GetControlPtr(CTRL_LIGHT_SLIDE_BLUE ))->SetCurrentValue(255); + RequestUpdate(); + break; + + case CTRL_LIGHT_NORMAL: + SetControlState(CTRL_LIGHT_NORMAL, CTRL_SELECTED); + SetControlState(CTRL_LIGHT_BROKEN, CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_FLASH, CTRL_DESELECTED); + RequestUpdate(); + + if (CurrentLight) + { + map_things[CurrentLight].SubType = LIGHT_TYPE_NORMAL; + } + + break; + + case CTRL_LIGHT_BROKEN: + SetControlState(CTRL_LIGHT_NORMAL, CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_BROKEN, CTRL_SELECTED); + SetControlState(CTRL_LIGHT_FLASH, CTRL_DESELECTED); + RequestUpdate(); + + if (CurrentLight) + { + map_things[CurrentLight].SubType = LIGHT_TYPE_BROKEN; + } + + break; + + case CTRL_LIGHT_FLASH: + SetControlState(CTRL_LIGHT_NORMAL, CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_BROKEN, CTRL_DESELECTED); + SetControlState(CTRL_LIGHT_FLASH, CTRL_SELECTED); + RequestUpdate(); + + if (CurrentLight) + { + map_things[CurrentLight].SubType = LIGHT_TYPE_PULSE; + } + + break; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/Main.cpp b/fallen/Editor/Source/Main.cpp new file mode 100644 index 0000000..413a108 --- /dev/null +++ b/fallen/Editor/Source/Main.cpp @@ -0,0 +1,583 @@ +// Main.cpp +// Guy Simmons, 10th February 1997. + + +//#ifdef EDITOR +#include "Editor.hpp" +//#endif + +#include "Stealth.h" +#include "poly.h" +#include "c:\fallen\headers\io.h" +#include "c:\fallen\headers\noserver.h" + + +extern void game(void); + +extern SLONG editor_texture_set; + + +//--------------------------------------------------------------- + +GameTexture game_textures[NUM_GAME_TEXTURES]; + + +UWORD page_lookup[64*8]; + +//--------------------------------------------------------------- +SLONG load_rect_into_page(UWORD *ptr,SLONG xpos,SLONG ypos,SLONG w,SLONG h,CBYTE *name) +{ + SLONG x,y; + TGA_Pixel *tga; + UWORD col; + TGA_Info ret; + + tga=(TGA_Pixel*)MemAlloc( 4 * 256 * 256 ); + if(!tga) + return(0); + + // ret=TGA_load(name,256,256,(TGA_Pixel*)tga); + ret=TGA_load(name,256,256,(TGA_Pixel*)tga,-1); + + + if(!ret.valid) + return(0); + + for(y=0;yTexturePtr = (UWORD*)MemAlloc(TEXTURE_PAGE_SIZE); + if(the_texture->TexturePtr==0) + ASSERT(0); +// ASSERT(i!=16); + + memset((UBYTE*)the_texture->TexturePtr,0,256*256*2); +/* + if(i==14) + { + //the_texture->TexturePtr=&game_textures[8]; + the_texture = &game_textures[8]; + } + if(i>14) + { + the_texture = &game_textures[i]; + } +*/ + + load_splitup_texture_page(the_texture->TexturePtr,dir,page); +// if(i!=14) + { + the_texture->PalPtr = (UBYTE*)MemAlloc(256*3); + tmaps[i] = the_texture->TexturePtr; + } + + if(the_texture->PalPtr) + { + // + // The palettes aren't loaded anymore- but just in case something + // somewhere uses them- create a random palette. + // + + for (j = 0; j < 256 * 3; j++) + { + the_texture->PalPtr[j] = rand(); + } + + pals[count_pal] = the_texture->PalPtr; + count_pal++; + } + + } + + // + // Load the textures styles. + // + +void load_texture_instyles(UBYTE editor, UBYTE world); + load_texture_instyles(TRUE, editor_texture_set); + load_texture_styles(TRUE, editor_texture_set); + load_game_textures_psx(flags); +} + +void load_game_textures_psx(UBYTE flags) +{ + SLONG c0; + GameTexture *the_texture; + CBYTE dir[128]; + UWORD page; + SLONG i,j,count_pal=0; + +#ifdef NO_SERVER + CBYTE textures[]="server\\gary64"; +#else + CBYTE textures[]="u:\\urbanchaos\\gary64"; +#endif + + + sprintf(dir, "%s\\world%d\\",textures, editor_texture_set); +// strcpy(TEXTURE_WORLD_DIR,dir); + + for(i=0;i<8;i++) + { + + switch(i) + { + case 0: + case 1: + case 2: + case 3: + if(!(flags&LOAD_UNSHARED_TEXTURES)) + continue; + sprintf(dir, "%s\\world%d\\",textures, editor_texture_set); + page=i*16; + break; + case 4: + case 5: + case 6: + case 7: + if(!(flags&LOAD_SHARED_TEXTURES)) + continue; + sprintf(dir, "%s\\shared\\",textures); + page=i*64; + break; + case 8: //1 for insides +// if(!(flags&LOAD_UNSHARED_TEXTURES)) +// continue; + sprintf(dir, "%s\\world%d\\insides\\",textures, editor_texture_set); + page=0; + break; + case 9: + case 10: //2 for pepole + if(!(flags&LOAD_SHARED_TEXTURES)) + continue; + sprintf(dir, "%s\\shared\\people\\",textures); + page=(i-9)*64; + break; + case 11: + case 12: // 3 for prims + case 13: + if(!(flags&LOAD_SHARED_TEXTURES)) + continue; + sprintf(dir, "%s\\shared\\prims\\",textures); + page=(i-11)*64; + ASSERT(page!=93); + break; + case 14: //special people2 + if(!(flags&LOAD_SHARED_TEXTURES)) + continue; + sprintf(dir, "%s\\shared\\people2\\",textures); + page-=14; + break; + + } + the_texture = &game_textures[i+25]; + the_texture->TexturePtr = (UWORD*)MemAlloc(TEXTURE_PAGE_SIZE); + if(the_texture->TexturePtr==0) + { + MessageBox( + NULL, + "You don't have enough free disk space! Try deleting some files and trying again.", "Out of disk space", MB_ICONERROR | MB_OK); + + ASSERT(0); + } + + memset((UBYTE*)the_texture->TexturePtr,0,256*256*2); + + + load_splitup_texture_page_remap(the_texture->TexturePtr,dir,page); + the_texture->PalPtr = (UBYTE*)MemAlloc(256*3); + tmaps[i+25] = the_texture->TexturePtr; + + + if(the_texture->PalPtr) + { + // + // The palettes aren't loaded anymore- but just in case something + // somewhere uses them- create a random palette. + // + + for (j = 0; j < 256 * 3; j++) + { + the_texture->PalPtr[j] = rand(); + } + + pals[count_pal] = the_texture->PalPtr; + count_pal++; + } + + } + + // + // Load the textures styles. + // + +} + +/* +void load_game_textures(void) +{ + SLONG i; + SLONG j; + + ULONG count=0; + ULONG count_pal=0; + GameTexture *the_texture; + TGA_Pixel *temp_page; + + CBYTE fname[256]; + + temp_page=(TGA_Pixel*)MemAlloc( 4 * 256 * 256 ); + if(temp_page) + { + for (i = 0; i < NUM_GAME_TEXTURES; i++) + { + if (i < 4) + { + // + // This is a world texture. + // + + sprintf(fname, "data\\textures\\world%d\\editor\\gen%02d.tga", editor_texture_set, i + 1); + } + else + { + // + // This is a shared texture. + // + + sprintf(fname, "data\\textures\\shared\\editor\\gen%02d.tga", i + 1); + } + + the_texture = &game_textures[i]; + + the_texture->TexturePtr = (UWORD*)MemAlloc(TEXTURE_PAGE_SIZE); + if(the_texture->TexturePtr) + { + SLONG x,y; + TGA_load(fname,256,256,(TGA_Pixel*)temp_page); + for(y=0;y<256;y++) + for(x=0;x<256;x++) + { + UWORD col,r,g,b; + r=temp_page[x+y*256].red; + g=temp_page[x+y*256].green; + b=temp_page[x+y*256].blue; + + col = the_display.GetFormattedPixel(r,g,b); + the_texture->TexturePtr[x+y*256]=col; + + } + tmaps[count] = the_texture->TexturePtr; + count++; + } + + the_texture->PalPtr = (UBYTE*)MemAlloc(256*3); + + if(the_texture->PalPtr) + { + // + // The palettes aren't loaded anymore- but just in case something + // somewhere uses them- create a random palette. + // + + for (j = 0; j < 256 * 3; j++) + { + the_texture->PalPtr[j] = rand(); + } + + pals[count_pal] = the_texture->PalPtr; + count_pal++; + } + } + + MemFree(temp_page); + } +} +*/ +//--------------------------------------------------------------- + +void free_game_textures(UBYTE flags) +{ + SLONG i; + + GameTexture *the_texture; + + for (i = 0; i < NUM_GAME_TEXTURES; i++) + { + switch(i) + { + case 0: + case 1: + case 2: + case 3: + if(!(flags&FREE_UNSHARED_TEXTURES)) + continue; + break; + case 4: + case 5: + case 6: + case 7: + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 8: //1 for insides + if(!(flags&FREE_UNSHARED_TEXTURES)) + continue; + break; + case 9: + case 10: //2 for pepole + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 11: + case 12: // 3 for prims + case 13: + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 14: //special people2 + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 15: //special people2 + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + + case 16: + case 17: + case 18: + case 19: + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 20: + case 21: + case 22: + case 23: + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 24: //1 for insides + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 25: + case 26: //2 for pepole + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 27: + case 28: // 3 for prims + case 29: + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + case 30: //special people2 + if(!(flags&FREE_SHARED_TEXTURES)) + continue; + break; + + } + + the_texture = &game_textures[i]; + + if(the_texture->TexturePtr) + { + MemFree(the_texture->TexturePtr); + the_texture->TexturePtr = 0; + } + if(the_texture->PalPtr) + { + MemFree(the_texture->PalPtr); + the_texture->PalPtr = 0; + + } + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/MapEdTab.cpp b/fallen/Editor/Source/MapEdTab.cpp new file mode 100644 index 0000000..1b3ff10 --- /dev/null +++ b/fallen/Editor/Source/MapEdTab.cpp @@ -0,0 +1,1450 @@ +#include "Editor.hpp" + +#include "MapEdTab.hpp" +#include "engine.h" +//#include "collide.hpp" + +static counter; + +//#define ShowWorkWindow(x) {DrawLineC(0+(counter-1)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,0);DrawLineC(0+(counter++)&255,0,WorkWindowWidth-1,WorkWindowHeight-1,255);DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); ShowWorkWindow(x);} + +//--------------------------------------------------------------- +//debug stuff +/* +void cross_work_window(void) +{ + DrawLineC(0,0,WorkWindowWidth-1,WorkWindowHeight-1,255); + DrawLineC(0,WorkWindowHeight-1,WorkWindowWidth-1,0,255); + +} +*/ +//--------------------------------------------------------------- + + +#define MAPED_MODE_WAIT 0 + + +#define CTRL_MAPED_X_AXIS_FREE 1 +#define CTRL_MAPED_Y_AXIS_FREE 2 +#define CTRL_MAPED_Z_AXIS_FREE 3 +#define CTRL_MAPED_V_SLIDE_LEVEL 4 +#define CTRL_MAPED_PAINT 5 +#define CTRL_MAPED_MARK_BLOCK 6 +#define CTRL_MAPED_COPY_BLOCK 7 +#define CTRL_MAPED_WIBBLE 8 +#define CTRL_MAPED_FLATTEN 9 +#define CTRL_MAPED_ROOF_TOP 10 +#define CTRL_MAPED_TEXTURE 11 + +#define MAPED_MODE_PAINT 0 +#define MAPED_MODE_MARK 1 +#define MAPED_MODE_PASTE 2 +#define MAPED_MODE_LINE_DRAW 3 +#define MAPED_MODE_RECT_DRAW 4 + + +ControlDef maped_tab_def[] = +{ + { CHECK_BOX, 0, "X Free", 120, 300-10, 0, 10 }, + { CHECK_BOX, 0, "Y Free", 120, 313-10, 0, 10 }, + { CHECK_BOX, 0, "Z Free", 120, 326-10, 0, 10 }, + { V_SLIDER, 0, "", 272, 40, 0, 257 }, + { BUTTON, 0, "Paint", 10, 180, 0, 0 }, + { BUTTON, 0, "Mark Block", 10, 160, 0, 0 }, + { BUTTON, 0, "Copy", 10, 200, 0, 0 }, + { BUTTON, 0, "WibbleMap",10, 30, 0, 0 }, + { BUTTON, 0, "Flatten Map",10, 50, 0, 0 }, + { CHECK_BOX, 0, "Roof Tops", 200, 180-10, 0, 10 }, + { CHECK_BOX, 0, "Textures", 200, 180+5, 0, 10 }, + { 0 } +}; + + +MapEdTab *the_maped; + +//--------------------------------------------------------------- + +MapEdTab::MapEdTab(EditorModule *parent) +{ + Parent=parent; + + InitControlSet(maped_tab_def); + AxisMode=3; + + SetControlState(CTRL_MAPED_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAPED_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAPED_Z_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAPED_ROOF_TOP,CTRL_DESELECTED); + SetControlState(CTRL_MAPED_TEXTURE,CTRL_DESELECTED); + ((CVSlider*)GetControlPtr(CTRL_MAPED_V_SLIDE_LEVEL))->SetValueRange(0,128); + ((CVSlider*)GetControlPtr(CTRL_MAPED_V_SLIDE_LEVEL))->SetCurrentValue(125); +// ((CVSlider*)GetControlPtr(CTRL_PRIM_V_SLIDE_PRIM))->SetUpdateFunction(redraw_all_prims); + + Axis=X_AXIS|Y_AXIS|Z_AXIS; + RoofTop=0; + Texture=0; + RedrawModuleContent=0; + Mode=0; + the_maped=this; +} + +MapEdTab::~MapEdTab() +{ +} + +void MapEdTab::Clear(void) +{ +// clear_all_col_info(); +} + +void MapEdTab::DrawTabContent(void) +{ + EdRect content_rect; + + + content_rect = ContentRect; + content_rect.ShrinkRect(1,1); + content_rect.FillRect(CONTENT_COL); + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); +} + + +//--------------------------------------------------------------- +extern void hilight_col_info(void); + + + +void MapEdTab::DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG wwx,wwy,www,wwh; + EdRect drawrect; + + SLONG dx,dy,dz,width,height,count_across,count_high; + SLONG c0,c1; + SLONG mx,my,mz; + SLONG index; + struct EditMapElement *p_ele; + +#ifdef POO +// my=((CVSlider*)GetControlPtr(CTRL_MAPED_V_SLIDE_LEVEL))->GetCurrentValue(); +// my=((CVSlider*)GetControlPtr(CTRL_MAPED_V_SLIDE_LEVEL))->GetCurrentValue(); + + my=(engine.Y>>8)>>ELE_SHIFT; + mx=(engine.X>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + + RedrawModuleContent=0; + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + SetWorkWindowBounds(x,y,w-1,h-1); + drawrect.SetRect(0,0,w-1,h-1); + drawrect.FillRect(CONTENT_COL_BR); + + width=((16<<5)*engine.Scale)>>16; + + count_across=((w/(width+1))>>1)+1; + count_high=(h/(width+1))>>1; + + for(dx=-count_across;dxCubeType.Prim; + DrawBoxC(0+(w>>1)+dx*(width+1),0+(h>>1)+dz*(width+1),width,width,0); + } + else + DrawBoxC(0+(w>>1)+dx*(width+1),0+(h>>1)+dz*(width+1),width,width,1); + + if(my<127) + { + index=edit_map[(dx+mx)][(my+1)].Depth[(dz+mz)]; + if(index) + { + p_ele=&edit_map_eles[index]; + index=p_ele->CubeType.Prim; + DrawVLineC((w>>1)+dx*(width+1)-1,(h>>1)+dz*(width+1)-1,(h>>1)+(dz+1)*(width+1),2); + DrawVLineC((w>>1)+(dx+1)*(width+1),(h>>1)+dz*(width+1)-1,(h>>1)+(dz+1)*(width+1),2); + DrawHLineC((w>>1)+dx*(width+1)-1,(w>>1)+(dx+1)*(width+1),(h>>1)+dz*(width+1)-1,2); + DrawHLineC((w>>1)+dx*(width+1)-1,(w>>1)+(dx+1)*(width+1),(h>>1)+(dz+1)*(width+1),2); + } + } + + if(my>0) + { + index=edit_map[(dx+mx)][(my-1)].Depth[(dz+mz)]; + if(index) + { + p_ele=&edit_map_eles[index]; + index=p_ele->CubeType.Prim; + DrawPixelC(0+(w>>1)+dx*(width+1)+(width>>1),0+(h>>1)+dz*(width+1)+(width>>1),2); + } + } + } + + switch(Mode) + { + case MAPED_MODE_MARK: + { + static col=0; + SLONG x1,y1,x2,y2; + col++; + + x1=(w>>1)+(X1-mx)*(width+1)-1; + x2=(w>>1)+(X2-mx+1)*(width+1)-1; + y1=(h>>1)+(Z1-mz)*(width+1)-1; + y2=(h>>1)+(Z2-mz+1)*(width+1)-1; + DrawVLineC(x1,y1,y2,(col&1)+4); + DrawVLineC(x2,y1,y2,(col&1)+4); + DrawHLineC(x1,x2,y1,(col&1)+4); + DrawHLineC(x1,x2,y2,(col&1)+4); + } + break; + case MAPED_MODE_PASTE: + MFPoint mouse_point; + SLONG screen_mapx,screen_mapy,screen_mapz; + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); +// DrawBoxC(mouse_point.X,mouse_point.Y,40,40,99); + + CalcMapCoord(&screen_mapx,&screen_mapy,&screen_mapz,x,y,w,h,&mouse_point); +//map to screen + for(dx=X1;dx<=X2;dx++) + for(dz=Z1;dz<=Z2;dz++) + { + index=edit_map[(dx)][(Y1)].Depth[(dz)]; + if(index) + { + p_ele=&edit_map_eles[index]; + index=p_ele->CubeType.Prim; + + DrawBoxC(0+(w>>1)+(screen_mapx+dx-X1-mx)*(width+1),0+(h>>1)+(screen_mapz+dz-Z1-mz)*(width+1),width,width,0); + } + } + break; + } +*/ + + + + +///* + + View1.SetRect(x,y,w-1,h/2-3); + View2.SetRect(x,y+h/2+4,w-1,h/2-4); + + SetWorkWindowBounds(x,y,w-1,h/2-3); + drawrect.SetRect(0,0,w-1,h/2-3); + + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + set_camera_plan(); + draw_editor_map(0); + render_view(1); +// hilight_map_things(MAP_THING_TYPE_COL); + hilight_col_info(); + + + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + drawrect.SetRect(0,0,w-1,h/2-4); + +// drawrect.FillRect(LOLITE_COL); + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + + set_camera_front(); + draw_editor_map(0); + render_view(1); +// hilight_map_things(MAP_THING_TYPE_COL); + hilight_col_info(); +//*/ + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT +#endif +} + +//--------------------------------------------------------------- + + +void MapEdTab::HandleTab(MFPoint *current_point) +{ + SLONG update = 0; + + + ModeTab::HandleTab(current_point); + KeyboardInterface(); + +} + +inline SLONG is_point_in_box(SLONG x,SLONG y,SLONG left,SLONG top,SLONG w,SLONG h) +{ + if(x>left&&xtop&&y3) + AxisMode=0; + switch(AxisMode) + { + case 0: + SetControlState(CTRL_MAPED_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAPED_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAPED_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=X_AXIS; + break; + case 1: + SetControlState(CTRL_MAPED_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAPED_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAPED_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=Y_AXIS; + break; + case 2: + SetControlState(CTRL_MAPED_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAPED_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAPED_Z_AXIS_FREE,CTRL_SELECTED); + Axis=Z_AXIS; + break; + case 3: + SetControlState(CTRL_MAPED_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAPED_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAPED_Z_AXIS_FREE,CTRL_SELECTED); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + break; + } + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); + } + if(Keys[KB_SPACE]) + { + Mode=0; + RequestUpdate(); + } + if(Mode==FLOOR_HOLD_BRUSH) + { + if(Keys[KB_F]) + { + FlattenArea(); + RequestUpdate(); + } + if(Keys[KB_S]) + { + SmoothArea(); + RequestUpdate(); + Keys[KB_S]=0; + } + if(Keys[KB_Z]) + { + SlopeArea(); + RequestUpdate(); + Keys[KB_Z]=0; + } + } + if(Keys[KB_B]) + { + if(ShiftFlag) + { + Mode=FLOOR_CUT_BRUSH_DEF; + } + else + { + Mode=FLOOR_CUT_BRUSH; + } + } + return(0); +} + +//#define QDIST3(x,y,z) (x>y ? (x>z ? x+(y>>2)+(z>>2) : z+(x>>2)+(y>>2)) : (y>z ? (y+(x>>2)+(z>>2) : z+(x>>2)+(y>>2) )) + + + +SLONG MapEdTab::DragEngine(UBYTE flags,MFPoint *clicked_point) +{ + SLONG wwx,wwy,www,wwh; + SLONG screen_change=0; + SLONG last_world_mouse; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + + { + SLONG start_x=0,start_y=0,start_z=0,flag=0; + SLONG old_x,old_y,old_z; + SLONG nx,ny,nz; + + old_x=nx=engine.X; + old_y=ny=engine.Y; + old_z=nz=engine.Z; + + while(SHELL_ACTIVE && MiddleButton) + { + last_world_mouse=SetWorldMouse(0); + if(last_world_mouse) + { + if(!flag) + { + flag=1; + start_x=engine.MousePosX<<8; + start_y=engine.MousePosY<<8; + start_z=engine.MousePosZ<<8; + } + + nx=engine.MousePosX<<8; + ny=engine.MousePosY<<8; + nz=engine.MousePosZ<<8; + + engine.X = (old_x+(-nx+start_x)); + engine.Y = (old_y+(-ny+start_y)); + engine.Z = (old_z+(-nz+start_z)); + +// engine.Z=nz<<8; + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + engine.X=old_x; + engine.Y=old_y; + engine.Z=old_z; + + } + } + if(flag) + { + engine.X= (old_x+(-nx+start_x)); + engine.Y= (old_y+(-ny+start_y)); + engine.Z= (old_z+(-nz+start_z)); + } + } + return(screen_change); + +} + +SLONG MapEdTab::CalcMapCoord(SLONG *mapx,SLONG *mapy,SLONG *mapz,SLONG x,SLONG y,SLONG w,SLONG h,MFPoint *clicked_point) +{ + SLONG width,count_across,count_high; + SLONG mx,my,mz; + SLONG dx,dy; + + my=(engine.Y>>8)>>ELE_SHIFT; + mx=(engine.X>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + width=((16<<5)*engine.Scale)>>16; + LogText(" w %d h %d click xy %d,%d width %d res x %d res y %d \n",w,h,clicked_point->X,clicked_point->Y,width,(clicked_point->X-(w>>1))/(width+1),(clicked_point->Y-(h>>1))/(width+1)); + + dx=(clicked_point->X-(w>>1)); + dy=(clicked_point->Y-(h>>1)); + + if(dx>0) + *mapx=dx/(width+1)+mx; + else + *mapx=((dx)/(width+1))+mx-1; + + + if(dy>0) + *mapz=dy/(width+1)+mz; + else + *mapz=((dy)/(width+1))+mz-1; + + *mapy=my; + return(1); +} + +extern void insert_cube(SWORD x,SWORD y,SWORD z); +extern void remove_cube(SLONG x,SLONG y,SLONG z); + + + +SLONG MapEdTab::MouseInContent(void) +{ + if(Mode==FLOOR_PASTE_BRUSH) + { + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + SetWorkWindowBounds(x,y,w-1,h-1); + Parent->DrawContent(); + + //DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + + } + return(0); + +} + +SLONG MapEdTab::DragPaint(UBYTE flags) +{ +/* + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + SLONG col; + SLONG screen_change=0; + MFPoint mouse_point; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + SetWorkWindowBounds(x,y,w-1,h-1); + + while(LeftButton) + { + SLONG mx,my,mz,index; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + + index=edit_map[(mx)][(my)].Depth[(mz)]; + if(!index) + insert_cube(mx,my,mz); + + + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; +// editor_user_interface(); +// KeyboardInterface(); + } + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); +*/ + return(0); + +} + +SLONG MapEdTab::DragMark(UBYTE flags) +{ + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + SLONG col = 0; + SLONG screen_change=0; + SLONG mx,my,mz,index; + + MFPoint mouse_point; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + SetWorkWindowBounds(x,y,w-1,h-1); + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + X1=mx; + Y1=my; + Z1=mz; + + while(SHELL_ACTIVE && LeftButton) + { + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + Parent->GlobalToLocal(&mouse_point); + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,&mouse_point); + X2=mx; + Y2=my; + Z2=mz; + + + + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + } + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); + +} + +void MapEdTab::ChangeMapAltitude(SLONG mx,SLONG mz,SLONG step,UBYTE offset_flag) +{ + //if the co_ord is within a cut rectangle then raise/lower whole rectangle + if(Mode==FLOOR_HOLD_BRUSH) + { + if(mx>CutMapBlock.GetX()&&mxCutMapBlock.GetZ()&&mzCutMapBlock.GetX()&&mxCutMapBlock.GetZ()&&mzCutMapBlock.GetX()&&mxCutMapBlock.GetZ()&&mz1&&CutMapBlock.GetWidth()>1) + { + SLONG dx,dz; + SLONG yl1,yl2,dly; + SLONG yr1,yr2,dry; + + if(RoofTop) + { + yl1=edit_map_roof_height[CutMapBlock.GetX()][CutMapBlock.GetZ()]; + yl2=edit_map_roof_height[CutMapBlock.GetX()][CutMapBlock.GetZ()+CutMapBlock.GetDepth()-1]; + } + else + { + yl1=edit_map[CutMapBlock.GetX()][CutMapBlock.GetZ()].Y; + yl2=edit_map[CutMapBlock.GetX()][CutMapBlock.GetZ()+CutMapBlock.GetDepth()-1].Y; + + } + dly=((yl2-yl1)<<16)/(CutMapBlock.GetDepth()-1); + + if(RoofTop) + { + yr1=edit_map_roof_height[CutMapBlock.GetX()+CutMapBlock.GetWidth()-1][CutMapBlock.GetZ()]; + yr2=edit_map_roof_height[CutMapBlock.GetX()+CutMapBlock.GetWidth()-1][CutMapBlock.GetZ()+CutMapBlock.GetDepth()-1]; + } + else + { + yr1=edit_map[CutMapBlock.GetX()+CutMapBlock.GetWidth()-1][CutMapBlock.GetZ()].Y; + yr2=edit_map[CutMapBlock.GetX()+CutMapBlock.GetWidth()-1][CutMapBlock.GetZ()+CutMapBlock.GetDepth()-1].Y; + + } + dry=((yr2-yr1)<<16)/(CutMapBlock.GetDepth()-1); + + yl1<<=16; + yr1<<=16; + + for(dz=CutMapBlock.GetZ()+1;dz>16); + edit_map_roof_height[CutMapBlock.GetX()+CutMapBlock.GetWidth()-1][dz]=yr1>>16; + } + else + { + edit_map[CutMapBlock.GetX()][dz].Y=(yl1>>16); + edit_map[CutMapBlock.GetX()+CutMapBlock.GetWidth()-1][dz].Y=yr1>>16; + + } + } + + for(dz=CutMapBlock.GetZ();dz>16; + } + else + { + edit_map[dx][dz].Y=yl1>>16; + } + + + } + } + + /* + for(dx=CutMapBlock.GetX();dx>ELE_SHIFT][mz>>ELE_SHIFT]; + } + else + { + starty=edit_map[mx>>ELE_SHIFT][mz>>ELE_SHIFT].Y; + + } + prev_alt=starty; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + + while(SHELL_ACTIVE && LeftButton) + { + SLONG alt; + SLONG req_alt,dy; + alt=(MouseY-alt1)>>1; + + req_alt=alt+starty; + dy=prev_alt-req_alt; +// edit_map[mx>>ELE_SHIFT][mz>>ELE_SHIFT].Y=alt+starty; + if(ControlFlag) + { + dy=req_alt; + ChangeMapAltitude(mx>>ELE_SHIFT,mz>>ELE_SHIFT,dy,0); + + } + else + { + ChangeMapAltitude(mx>>ELE_SHIFT,mz>>ELE_SHIFT,dy,1); + } + + Parent->DrawContent(); + ShowWorkWindow(0); + prev_alt=req_alt; + } + + SetWorkWindowBounds(wwx,wwy,www,wwh); + +} + +SLONG MapEdTab::HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h) +{ + SWORD thing; + SWORD bright; + SLONG mx,my,mz; + SLONG step=1; + + + switch(Mode) + { + case 0: + case FLOOR_HOLD_BRUSH: + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + + if(ShiftFlag) + { + Mode=FLOOR_CUT_BRUSH_DEF; + CutFloorBrush(clicked_point,1); + } + else + { + BuildMode->CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + DragAltitude(mx,mz); + + } +/* + LogText(" LEFT \n"); + + mx=mx>>ELE_SHIFT; + mz=mz>>ELE_SHIFT; + if(ShiftFlag) + step=10; + if(ControlFlag) + step=100; + ChangeMapAltitude(mx,mz,step); + //edit_map[mx][mz].Y+=step; +*/ + return(1); + + break; + case RIGHT_CLICK: + Mode=FLOOR_CUT_BRUSH; + CutFloorBrush(clicked_point,2); +/* + LogText(" RIGHT \n"); + + BuildMode->CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + mx=mx>>ELE_SHIFT; + mz=mz>>ELE_SHIFT; + if(ShiftFlag) + step=10; + if(ControlFlag) + step=100; + ChangeMapAltitude(mx,mz,-step); +*/ + //edit_map[mx][mz].Y-=step; +// remove_cube(mx,my,mz); + return(1); + + break; + case MIDDLE_CLICK: + //DragEngine(flags,clicked_point); + //if(SubMode==FLOOR_CUT_BRUSH) +/* + { + LogText(" MIDDLE \n"); + CutFloorBrush(clicked_point); + } +*/ + break; + } + break; + case FLOOR_PASTE_BRUSH: + switch(flags) + { + case LEFT_CLICK: + BuildMode->CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + CutMapBlock.Paste(mx>>ELE_SHIFT,mz>>ELE_SHIFT,PASTE_ALTITUDE,RoofTop); + break; + + case RIGHT_CLICK: + Mode=FLOOR_CUT_BRUSH; + CutFloorBrush(clicked_point,2); + break; + } + break; + + case FLOOR_CUT_BRUSH: + case FLOOR_CUT_BRUSH_DEF: + switch(flags) + { + case LEFT_CLICK: + CutFloorBrush(clicked_point,1); + break; + } + break; + + + } + if(flags==MIDDLE_CLICK) + LogText(" middle2\n"); + + +/* + switch(Mode) + { + case MAPED_MODE_MARK: + DragMark(flags); + break; + case MAPED_MODE_PASTE: + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + { + + SLONG mx,my,mz,dx,dz,index; + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + //map to screen + for(dx=X1;dx<=X2;dx++) + for(dz=Z1;dz<=Z2;dz++) + { + index=edit_map[(dx)][(Y1)].Depth[(dz)]; + if(index) + { + insert_cube(mx+dx-X1,my,mz+dz-Z1); + } + } + } + break; + } + break; + + case 0: + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + insert_cube(mx,my,mz); + DragPaint(flags); + + return(1); + + switch (Mode) + { + // case MAPED_MODE_WAIT: + // DragACol(flags,clicked_point,0); + break; + + } + break; + case RIGHT_CLICK: + + CalcMapCoord(&mx,&my,&mz,x,y,w,h,clicked_point); + remove_cube(mx,my,mz); + return(1); + + switch (Mode) + { + } + // Right click in content. + break; + case MIDDLE_CLICK: + DragEngine(flags,clicked_point); + break; + } + break; + } +*/ + return(0); + +} + + +UWORD MapEdTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + MFPoint local_point; + + + // This is a fudge to update the front screen buffer. + ShowWorkScreen(0); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + { + current_control = GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + control_id = current_control->TrackControl(&local_point); + HandleControl(control_id); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + return control_id; + } + current_control = current_control->GetNextControl(); + } + } + + break; + case RIGHT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + break; + } + return 0; +} + +void MapEdTab::CutFloorBrush(MFPoint *current_point,SLONG button) +{ + + MFPoint point1,point2; + SLONG con_top,con_left; + SLONG x,y,w,h; + SLONG mx1,my1,mz1; + SLONG mx2,my2,mz2; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + point1.X = MouseX; + point1.Y = MouseY; + Parent->GlobalToLocal(&point1); + BuildMode->CalcMapCoord(&mx1,&my1,&mz1,x,y,w,h,&point1); +// point1 = *clicked_point; + while(SHELL_ACTIVE && ((LeftButton&&button==1)||(RightButton&&button==2))) + { + engine_keys_scroll(); + engine_keys_spin(); + engine_keys_zoom(); + + point2.X = MouseX;//-con_left; + point2.Y = MouseY;//-con_top; + Parent->GlobalToLocal(&point2); + BuildMode->CalcMapCoord(&mx2,&my2,&mz2,x,y,w,h,&point2); + + if(LockWorkScreen()) + { + Parent->DrawContent(); + Parent->DrawGrowBox(); + BuildMode->Texture=2; + BuildMode->DrawContentRect(mx1,mz1,mx2,mz2,WHITE_COL); + BuildMode->Texture=0; + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + { + SLONG mw,mh; + mw=mx2-mx1; + if(mw<0) + { + mw=-mw; + mx1=mx2; + } + mh=mz2-mz1; + if(mh<0) + { + mh=-mh; + mz1=mz2; + } + CutMapBlock.Cut(mx1>>ELE_SHIFT,mz1>>ELE_SHIFT,mw>>ELE_SHIFT,mh>>ELE_SHIFT,RoofTop); + if(Mode==FLOOR_CUT_BRUSH_DEF) + { + Mode=FLOOR_HOLD_BRUSH; + } + else + { + Mode=FLOOR_PASTE_BRUSH; + } + + } + + RequestUpdate(); +} + + +//--------------------------------------------------------------- + +SLONG MapEdTab::SetWorldMouse(ULONG flag) +{ + MFPoint mouse_point; + MFPoint local_point; + SVector point,out; + SLONG wwx,wwy,www,wwh; + SLONG temp; + + temp=engine.ClipFlag; + engine.ClipFlag=0; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + + local_point = mouse_point; + Parent->GlobalToLocal(&local_point); + if(is_point_in_box(local_point.X,local_point.Y,0,0,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()/2-3); + set_camera_plan(); + calc_world_pos_plan(local_point.X,local_point.Y); + if(flag) + engine.MousePosY=engine.Y>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + engine.ClipFlag=temp; + return(1); + } + else + { + + engine.ClipFlag=temp; + return(0); + } + +} + +SLONG calc_edit_height_at(SLONG x,SLONG z) +{ + DepthStrip *me; + SLONG new_y,h0,h1,h2,h3; + + if(x<0||z<0||x>EDIT_MAP_WIDTH<<8||z>EDIT_MAP_WIDTH<<8) + return(0); + me=&edit_map[(x>>ELE_SHIFT)][(z>>ELE_SHIFT)]; +// me=&MAP2((x>>ELE_SHIFT),(z>>ELE_SHIFT)); + + h1=me->Y<>8) >=(MAP_WIDTH)) + h0=h1; + else + h0=((me+1)->Y)<>8) >=(MAP_HEIGHT)) + { + h2=h1; + h3=h0; + } + else + { + h2=((me+MAP_WIDTH)->Y)<Y)<>ELE_SHIFT)+(((h2-h1)*(z))>>ELE_SHIFT)); + else + new_y=(h3+(((h2-h3)*(ELE_SIZE-x))>>ELE_SHIFT)+(((h0-h3)*(ELE_SIZE-z))>>ELE_SHIFT)); + + return(new_y); +} + + +extern void set_map_height(SLONG x,SLONG z,SLONG y); + + +void fix_furn_height(void) +{ + SLONG c0; + for(c0=1;c0>10); + } + fix_furn_height(); +} + +void flatten_map(void) +{ + SLONG dx,dz; + for(dx=0;dxBackground) + if(p_map->X) + { + set_camera_angledy(p_map->AngleY); + prim=map_things[p_map->Background].IndexOther; + draw_a_prim_at(prim,p_map->X,p_map->Y,p_map->Z,1); + clear_camera_angledy(); + } + } +} + + + + +MapTab::MapTab(EditorModule *parent) +{ + Parent=parent; + + InitControlSet(map_tab_def); + AxisMode=3; + + SetControlState(CTRL_MAP_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAP_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAP_Z_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAP_DEF_MODE,CTRL_SELECTED); + ((CEditText*)GetControlPtr(CTRL_MAP_EDIT_TEXT))->SetFlags(CONTROL_INACTIVE); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + Mode=0; + DefMode=1; +// map_info[0].Plane.Depth=320; + the_maptab=this; +} + +MapTab::~MapTab() +{ +} + +void MapTab::Clear(void) +{ +} + +void delete_map_info(SWORD index) +{ + SLONG c0; + for(c0=index;c0Mode) + { + + + default: + + the_maptab->DrawTabContent(); + the_maptab->Parent->DrawContent(); + SetWorkWindowBounds(the_maptab->Parent->GetLeft(), + the_maptab->Parent->GetTop(), + the_maptab->Parent->GetWidth(), + the_maptab->Parent->GetHeight()); + break; + } + +} + +//--------------------------------------------------------------- +extern void hilight_map_info(UBYTE view_flag); + +void MapTab::DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG wwx,wwy,www,wwh; + EdRect drawrect; + + RedrawModuleContent=0; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + if(DefMode) + { + SetWorkWindowBounds(x,y,w-1,h-3); + drawrect.SetRect(0,0,w-1,h-3); + + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + set_camera_front(); + draw_editor_map(0); + render_view(0); + hilight_map_info(0); + + } + else + { + + SetWorkWindowBounds(x,y,w-1,h/2-3); + drawrect.SetRect(0,0,w-1,h/2-3); + + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + set_camera_plan(); +// draw_editor_map(0); + draw_world_map(); + render_view(0); + hilight_map_info(1); + + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + drawrect.SetRect(0,0,w-1,h/2-4); + + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + + set_camera_front(); +// draw_editor_map(0); + draw_world_map(); + render_view(0); + // hilight_map_things(MAP_THING_TYPE_MAP); + hilight_map_info(1); + } + + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT +} + +//--------------------------------------------------------------- + + +void MapTab::HandleTab(MFPoint *current_point) +{ + SLONG update = 0; + + + ModeTab::HandleTab(current_point); + KeyboardInterface(); + +} + +inline SLONG is_point_in_box(SLONG x,SLONG y,SLONG left,SLONG top,SLONG w,SLONG h) +{ + if(x>left&&xtop&&y3) + AxisMode=0; + switch(AxisMode) + { + case 0: + SetControlState(CTRL_MAP_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAP_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAP_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=X_AXIS; + break; + case 1: + SetControlState(CTRL_MAP_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAP_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAP_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=Y_AXIS; + break; + case 2: + SetControlState(CTRL_MAP_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAP_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_MAP_Z_AXIS_FREE,CTRL_SELECTED); + Axis=Z_AXIS; + break; + case 3: + SetControlState(CTRL_MAP_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAP_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_MAP_Z_AXIS_FREE,CTRL_SELECTED); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + break; + } + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); + } + return(0); +} + +//#define QDIST3(x,y,z) (x>y ? (x>z ? x+(y>>2)+(z>>2) : z+(x>>2)+(y>>2)) : (y>z ? (y+(x>>2)+(z>>2) : z+(x>>2)+(y>>2) )) + + +inline SLONG normalise_xyz(SLONG *x,SLONG *y,SLONG *z) +{ + SLONG dist; + + dist=(*x)*(*x)+(*y)*(*y)+(*z)*(*z); + dist=sqrl(dist); + + if(dist==0) + dist=1; + + *x=(*x<<8)/dist; + *y=(*y<<8)/dist; + *z=(*z<<8)/dist; + + return(dist); +} + + +UWORD CreateMapPlane(SLONG x,SLONG y,SLONG z) +{ + z=z; + map_info[next_map_info].Left=x; + map_info[next_map_info].Right=x+300; + map_info[next_map_info].Top=y; + map_info[next_map_info].Bottom=y+300; +// map_info[next_map_info].Depth=z; + next_map_info++; + return(next_map_info-1); +} + + +/* +void draw_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG col) +{ + struct SVector point[2]; + struct SVector res[2]; + SLONG sx,sy,sz,c0; + ULONG f1,f2; + point[0].X=x1; + point[0].Y=y1; + point[0].Z=z1; + f1=rotate_point_gte(&point[0],&res[0]); + + point[1].X=x2; + point[1].Y=y2; + point[1].Z=z2; + f2=rotate_point_gte(&point[1],&res[1]); + f1=f1&f2; + if(!(f1 & EF_CLIPFLAGS)) + DrawLineC(res[0].X,res[0].Y,res[1].X,res[1].Y,col); +} +*/ +void draw_3d_text(SLONG x1,SLONG y1,SLONG z1,CBYTE *str,SLONG col) +{ + struct SVector point; + struct SVector res; + ULONG f1; + point.X=x1; + point.Y=y1; + point.Z=z1; + f1=rotate_point_gte(&point,&res); + + if(!(f1 & EF_CLIPFLAGS)) + QuickTextC(res.X,res.Y,str,col); +} + +void draw_a_map_info(UBYTE view_flag,UWORD index) +{ + struct MapInfo *p_map; + SLONG col=WHITE_COL; + EdRect rect; + CBYTE str[100]; + p_map=&map_info[index]; + + if(view_flag) + { + + if(p_map->Background) + if(p_map->X) + { + + set_camera_angledy(p_map->AngleY); + calc_prims_screen_box(map_things[p_map->Background].IndexOther,p_map->X,p_map->Y,p_map->Z,&rect); + clear_camera_angledy(); + rect.OutlineRect(WHITE_COL); + + sprintf(str," %s back %d index %d \n",p_map->Name,p_map->Background,index); + QuickTextC(rect.GetLeft()+3,rect.GetTop()+3,str,col); + } + } + else + { + draw_3d_line(p_map->Left,p_map->Top,0,p_map->Right,p_map->Top,0,col); + draw_3d_line(p_map->Right,p_map->Top,0,p_map->Right,p_map->Bottom,0,col); + draw_3d_line(p_map->Left,p_map->Bottom,0,p_map->Right,p_map->Bottom,0,col); + draw_3d_line(p_map->Left,p_map->Bottom,0,p_map->Left,p_map->Top,0,col); +// sprintf(str," %s back %d x %d y %d z %d \n",p_map->Name,p_map->Background,p_map->X,p_map->Y,p_map->Z); + draw_3d_text(p_map->Left+3,p_map->Top+3,0,p_map->Name,col); + + } +} + +void hilight_map_info(UBYTE view_flag) +{ + SLONG c0; + if(next_map_info>1) + for(c0=1;c0SetRect(res[0].X,res[0].Y,res[1].X-res[0].X,res[1].Y-res[0].Y); + rect->NormalRect(); + rect->SetRect(rect->GetLeft()-3,rect->GetTop()-3,rect->GetWidth()+6,rect->GetHeight()+6); + rect->OutlineRect(WHITE_COL); +} + +static void create_box_from_point(EdRect *rect,SLONG x1,SLONG y1,SLONG z1) +{ + struct SVector point[1]; + struct SVector res[1]; + ULONG f1,f2; + point[0].X=x1; + point[0].Y=y1; + point[0].Z=z1; + f1=rotate_point_gte(&point[0],&res[0]); + + rect->SetRect(res[0].X,res[0].Y,10,10); + rect->NormalRect(); + rect->SetRect(rect->GetLeft()-10,rect->GetTop()-10,rect->GetWidth()+10,rect->GetHeight()+10); + rect->OutlineRect(WHITE_COL); +} + + +SLONG select_this_map_info(SLONG index,MFPoint *mouse) +{ + struct MapInfo *p_map; + EdRect rect; + + p_map=&map_info[index]; + + //corners + + create_box_from_point(&rect,p_map->Left,p_map->Top,0); + if(rect.PointInRect(mouse)) + return(5); + create_box_from_point(&rect,p_map->Right,p_map->Top,0); + if(rect.PointInRect(mouse)) + return(6); + create_box_from_point(&rect,p_map->Right,p_map->Bottom,0); + if(rect.PointInRect(mouse)) + return(7); + create_box_from_point(&rect,p_map->Left,p_map->Bottom,0); + if(rect.PointInRect(mouse)) + return(8); + + + //edges + create_box_from_vect(&rect,p_map->Left,p_map->Top,0,p_map->Right,p_map->Top,0); + if(rect.PointInRect(mouse)) + return(1); + create_box_from_vect(&rect,p_map->Right,p_map->Top,0,p_map->Right,p_map->Bottom,0); + if(rect.PointInRect(mouse)) + return(2); + create_box_from_vect(&rect,p_map->Left,p_map->Bottom,0,p_map->Right,p_map->Bottom,0); + if(rect.PointInRect(mouse)) + return(3); + create_box_from_vect(&rect,p_map->Left,p_map->Top,0,p_map->Left,p_map->Bottom,0); + if(rect.PointInRect(mouse)) + return(4); + + //whole thing + create_box_from_vect(&rect,p_map->Left,p_map->Top,0,p_map->Right,p_map->Bottom,0); + if(rect.PointInRect(mouse)) + return(SELECT_WHOLE_THING); + + return(0); +} + +extern void calc_prims_world_box(UWORD prim,SLONG x,SLONG y,SLONG z, EdRect *rect); + +void calc_things_world_box(SLONG map_thing,EdRect *rect) +{ + struct MapThing *p_mthing; + + p_mthing=TO_MTHING(map_thing); + switch(p_mthing->Type) + { + case MAP_THING_TYPE_PRIM: + //3ds Prim Mesh + calc_prims_world_box(p_mthing->IndexOther,p_mthing->X,p_mthing->Y,p_mthing->Z,rect); + break; + case MAP_THING_TYPE_LIGHT: + break; + + case MAP_THING_TYPE_SPRITE: + case MAP_THING_TYPE_AGENT: + break; + + } +} + + +void SetBackgroundForMap(SWORD map) +{ + SWORD index; + struct MapThing *p_thing; + EdRect rect; + EdRect map_rect; + struct MapInfo *p_map; + p_map=&map_info[map]; + + map_rect.SetRect(p_map->Left,p_map->Top,p_map->Bottom-p_map->Top,p_map->Right-p_map->Left); + index=background_prim; + while(index) + { + p_thing=TO_MTHING(index); + calc_things_world_box(index,&rect); + if(map_rect.IntersectRect(&rect)) + { + p_map->Background=index; + return; + } + index=p_thing->IndexNext; + } + + +} + + +SLONG select_map_info(MFPoint *mouse,SLONG *ret) +{ + SLONG c0; + + for(c0=1;c0Background) + { + + p_mthing=TO_MTHING(p_map->Background); + + set_camera_angledy(p_map->AngleY); + calc_prims_screen_box(p_mthing->IndexOther,p_map->X,p_map->Y,p_map->Z,&rect); + clear_camera_angledy(); + rect.OutlineRect(WHITE_COL); + + if(rect.PointInRect(mouse)) + { + return(c0); + } + } + } + return(0); +} + + +void normal_info(struct MapInfo *p_map) +{ + if(p_map->RightLeft) + SWAP(p_map->Left,p_map->Right); + + if(p_map->BottomTop) + SWAP(p_map->Top,p_map->Bottom); + + +} + +SLONG MapTab::DragAMapDef(UBYTE flags,MFPoint *clicked_point,UWORD copy) +{ + SLONG side; + SLONG drag=0; + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + SLONG window=0; + SLONG col = 0; + SLONG screen_change=0; + SLONG last_world_mouse; + + flags=flags; + copy=copy; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + + SetWorkWindowBounds(x,y,w-1,h-3); + set_camera_front(); + drag=select_map_info(clicked_point,&side); + + + if(drag) + { + struct MapInfo *p_map; + p_map=&map_info[drag]; + + CurrentMap=drag; + + while(SHELL_ACTIVE && LeftButton) + { + last_world_mouse=SetWorldMouse(0); + + if(last_world_mouse) + { + switch(side) + { + case 1: //top + map_info[CurrentMap].Top=engine.MousePosY; + break; + case 3: //bot + map_info[CurrentMap].Bottom=engine.MousePosY; + break; + case 2: //right + map_info[CurrentMap].Right=engine.MousePosX; + break; + case 4: //left + map_info[CurrentMap].Left=engine.MousePosX; + break; + case 5: //topleft + map_info[CurrentMap].Top=engine.MousePosY; + map_info[CurrentMap].Left=engine.MousePosX; + break; + case 6: //topright + map_info[CurrentMap].Right=engine.MousePosX; + map_info[CurrentMap].Top=engine.MousePosY; + break; + case 7: //botright + map_info[CurrentMap].Right=engine.MousePosX; + map_info[CurrentMap].Bottom=engine.MousePosY; + break; + case 8: //botleft + map_info[CurrentMap].Left=engine.MousePosX; + map_info[CurrentMap].Bottom=engine.MousePosY; + break; + } + } + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + +/* + SetWorkWindowBounds(this->ContentLeft()+1,this->ContentTop()+1,this->ContentWidth(),this->ContentHeight()); + + DrawBox(0,0,this->ContentWidth(),this->ContentHeight(),CONTENT_COL); + + set_camera(); + draw_editor_map(0); + render_view(0); + ShowWorkWindow(0); +*/ + editor_user_interface(0); + KeyboardInterface(); + } + normal_info(&map_info[CurrentMap]); + + SetBackgroundForMap(CurrentMap); + + if(!last_world_mouse) + { //delete col + delete_map_info(drag); + CurrentMap=0; + } + + RequestUpdate(); + } + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); + +} + +SLONG MapTab::DragAMapDefXYZ(UBYTE flags,MFPoint *clicked_point,UWORD copy) +{ + SLONG drag=0; + SLONG x,y,w,h; + SLONG wwx,wwy,www,wwh; + SLONG window=0; + SLONG col = 0; + SLONG screen_change=0; + SLONG last_world_mouse; + SLONG old_angley,old_mousex; + MFPoint local_point; + + flags=flags; + copy=copy; + + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + + SetWorkWindowBounds(x,y,w-1,(h/2)-3); + set_camera_plan(); + drag=select_map_infoxyz(clicked_point); + + if(!drag) + { + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + set_camera_front(); + local_point =*clicked_point; + local_point.Y-=h/2; + drag=select_map_infoxyz(&local_point); + } + + if(drag) + { + SLONG dx,dy,dz; + struct MapInfo *p_map; + p_map=&map_info[drag]; + + CurrentMap=drag; + last_world_mouse=SetWorldMouse(0); + dx=map_info[drag].X-engine.MousePosX; + dy=map_info[drag].Y-engine.MousePosY; + dz=map_info[drag].Z-engine.MousePosZ; + + engine.MousePosX=map_info[drag].X; + engine.MousePosY=map_info[drag].Y; + engine.MousePosZ=map_info[drag].Z; + old_angley=map_info[drag].AngleY; + old_mousex=MouseX; + + while(SHELL_ACTIVE && (LeftButton||RightButton)) + { + SLONG nx,ny,nz; + last_world_mouse=SetWorldMouse(0); + + + + nx=map_info[drag].X; + ny=map_info[drag].Y; + nz=map_info[drag].Z; + + if(last_world_mouse) + { + if(Axis&X_AXIS) + nx=engine.MousePosX+dx; + if(Axis&Y_AXIS) + ny=engine.MousePosY+dy; + if(Axis&Z_AXIS) + nz=engine.MousePosZ+dz; + if(LeftButton) + { + map_info[CurrentMap].X=nx; + map_info[CurrentMap].Y=ny; + map_info[CurrentMap].Z=nz; + } + if(RightButton) + { + map_info[CurrentMap].AngleY=old_angley+((-MouseX+old_mousex)<<2); + if(map_info[CurrentMap].AngleY<0) + map_info[CurrentMap].AngleY=(2048+map_info[CurrentMap].AngleY)&2047; + } + } + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + editor_user_interface(0); + KeyboardInterface(); + } + + if(!last_world_mouse) + { + CurrentMap=0; + } + + RequestUpdate(); + } + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); + +} + +SLONG MapTab::DragEngine(UBYTE flags,MFPoint *clicked_point) +{ + SLONG wwx,wwy,www,wwh; + SLONG screen_change=0; + SLONG last_world_mouse; + + flags=flags; + clicked_point=clicked_point; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + + { + SLONG start_x=0,start_y=0,start_z=0,flag=0; + SLONG old_x,old_y,old_z; + SLONG nx,ny,nz; + + old_x=nx=engine.X; + old_y=ny=engine.Y; + old_z=nz=engine.Z; + + while(SHELL_ACTIVE && MiddleButton) + { + last_world_mouse=SetWorldMouse(0); + if(last_world_mouse) + { + if(!flag) + { + flag=1; + start_x=engine.MousePosX<<8; + start_y=engine.MousePosY<<8; + start_z=engine.MousePosZ<<8; + } + + nx=engine.MousePosX<<8; + ny=engine.MousePosY<<8; + nz=engine.MousePosZ<<8; + + engine.X = (old_x+(-nx+start_x)); + engine.Y = (old_y+(-ny+start_y)); + engine.Z = (old_z+(-nz+start_z)); + +// engine.Z=nz<<8; + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + engine.X=old_x; + engine.Y=old_y; + engine.Z=old_z; + + } + } + if(flag) + { + engine.X= (old_x+(-nx+start_x)); + engine.Y= (old_y+(-ny+start_y)); + engine.Z= (old_z+(-nz+start_z)); + } + } + return(screen_change); + +} + +void MapTab::SetMapPos(SLONG x,SLONG y,SLONG z) +{ + map_info[CurrentMap].X=x; + map_info[CurrentMap].Y=y; + map_info[CurrentMap].Z=z; + map_info[CurrentMap].AngleY=0; +} + +SLONG MapTab::HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h) +{ + x=x; + y=y; + w=w; + h=h; + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + + switch (Mode) + { + case MAP_MODE_DEFINE_MAP: + if(SetWorldMouse(1)) + { + CurrentMap=CreateMapPlane(engine.MousePosX,engine.MousePosY,engine.MousePosZ); + strcpy(map_info[CurrentMap].Name,((CEditText*)GetControlPtr(CTRL_MAP_EDIT_TEXT))->GetEditString()); + + Mode=0; + } + return(1); + + case MAP_MODE_WAIT: + if(DefMode) + DragAMapDef(flags,clicked_point,0); + else + DragAMapDefXYZ(flags,clicked_point,0); + + break; + case MAP_MODE_SELECT_AND_PLACE: + { + SLONG side; + CurrentMap=select_map_info(clicked_point,&side); + DefMode=0; + SetControlState(CTRL_MAP_DEF_MODE,CTRL_DESELECTED); + Mode=MAP_MODE_PLACE_CURRENT_MAP; + RequestUpdate(); + } + return(1); + case MAP_MODE_PLACE_CURRENT_MAP: + if(SetWorldMouse(1)) + { + SetMapPos(engine.MousePosX,engine.MousePosY,engine.MousePosZ); + RequestUpdate(); + Mode=0; + } + break; + + } + break; + case RIGHT_CLICK: + switch (Mode) + { + case MAP_MODE_WAIT: + if(!DefMode) + DragAMapDefXYZ(flags,clicked_point,0); + break; + } + // Right click in content. + break; + case MIDDLE_CLICK: + DragEngine(flags,clicked_point); + break; + } + return(0); + +} + +UWORD MapTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + MFPoint local_point; + + + // This is a fudge to update the front screen buffer. + ShowWorkScreen(0); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + { + current_control = GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + control_id = current_control->TrackControl(&local_point); + HandleControl(control_id); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + return control_id; + } + current_control = current_control->GetNextControl(); + } + } + + break; + case RIGHT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + break; + } + return 0; +} + +//--------------------------------------------------------------- + +SLONG MapTab::SetWorldMouse(ULONG flag) +{ + MFPoint mouse_point; + MFPoint local_point; + SLONG wwx,wwy,www,wwh; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + + local_point = mouse_point; + Parent->GlobalToLocal(&local_point); + if(DefMode) + { + if(is_point_in_box(local_point.X,local_point.Y,0,0,Parent->ContentWidth()-1,Parent->ContentHeight())) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()-4); + set_camera_front(); + calc_world_pos_front(local_point.X,local_point.Y); + if(flag) + engine.MousePosZ=engine.Z>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(1); + + } + else + return(0); + + } + else + { + + if(is_point_in_box(local_point.X,local_point.Y,0,0,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()/2-3); + set_camera_plan(); + calc_world_pos_plan(local_point.X,local_point.Y); + if(flag) + engine.MousePosY=engine.Y>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(1); + } + else + if(is_point_in_box(local_point.X,local_point.Y,0,Parent->ContentHeight()/2,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+Parent->ContentHeight()/2+3,Parent->ContentWidth()-1,Parent->ContentHeight()/2-4); + set_camera_front(); + calc_world_pos_front(local_point.X,local_point.Y-Parent->ContentHeight()/2); + if(flag) + engine.MousePosZ=engine.Z>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(1); + + } + else + return(0); + } + +} + + +void MapTab::HandleControl(UWORD control_id) +{ + switch(control_id&0xff) + { + + case CTRL_MAP_X_AXIS_FREE: + ToggleControlSelectedState(CTRL_MAP_X_AXIS_FREE); + if(Axis&X_AXIS) + Axis&=~X_AXIS; + else + Axis|=X_AXIS; + break; + case CTRL_MAP_Y_AXIS_FREE: + ToggleControlSelectedState(CTRL_MAP_Y_AXIS_FREE); + if(Axis&Y_AXIS) + Axis&=~Y_AXIS; + else + Axis|=Y_AXIS; + break; + case CTRL_MAP_Z_AXIS_FREE: + ToggleControlSelectedState(CTRL_MAP_Z_AXIS_FREE); + if(Axis&Z_AXIS) + Axis&=~Z_AXIS; + else + Axis|=Z_AXIS; + break; + case CTRL_MAP_DEFINE_MAP: + DefMode=1; + SetControlState(CTRL_MAP_DEF_MODE,CTRL_SELECTED); + Mode=MAP_MODE_DEFINE_MAP; + ((CEditText*)GetControlPtr(CTRL_MAP_EDIT_TEXT))->SetFlags( ((CEditText*)GetControlPtr(CTRL_MAP_EDIT_TEXT))->GetFlags()&~CONTROL_INACTIVE); + ((CEditText*)GetControlPtr(CTRL_MAP_EDIT_TEXT))->SetEditString("No Name"); + RequestUpdate(); + break; + case CTRL_MAP_DEF_MODE: + ToggleControlSelectedState(CTRL_MAP_DEF_MODE); + DefMode^=1; + RequestUpdate(); + break; +/* + case CTRL_ANIM_NAME_EDIT: + if(CurrentMap) + strcpy(map_info[CurrentMap].Name,((CEditText*)GetControlPtr(CTRL_MAP_EDIT_TEXT))->GetEditString()); + RequestUpdate(); + break; +*/ + case CTRL_MAP_SELECT_AND_PLACE: + Mode=MAP_MODE_SELECT_AND_PLACE; + DefMode=1; + SetControlState(CTRL_MAP_DEF_MODE,CTRL_SELECTED); + RequestUpdate(); + break; + case CTRL_MAP_ZOOM_1: + engine.Scale=896; + RequestUpdate(); + break; + + case CTRL_MAP_ZOOM_2: + engine.Scale=200; + RequestUpdate(); + break; + case CTRL_MAP_ZOOM_3: + engine.Scale=60; + RequestUpdate(); + break; +/* + case CTRL_MAP_DELETE: + delete_all_lights(); + RequestUpdate(); + Mode=0; + break; +*/ + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/ModeTab.cpp b/fallen/Editor/Source/ModeTab.cpp new file mode 100644 index 0000000..2c0afde --- /dev/null +++ b/fallen/Editor/Source/ModeTab.cpp @@ -0,0 +1,184 @@ +// ModeTab.cpp +// Guy Simmons, 18th February 1997. + +#include "Editor.hpp" + + +//--------------------------------------------------------------- + +ModeTab::ModeTab() +{ + SetLastTabLink(NULL); + SetNextTabLink(NULL); + SetExternalUpdatePtr(0); +} + +//--------------------------------------------------------------- + +void ModeTab::SetupModeTab(CBYTE *the_title,UWORD id,EdRect *bounding_rect,ULONG *update_ptr) +{ + Title = the_title; + SetTabArea(bounding_rect); + SetTabID(id); + SetExternalUpdatePtr(update_ptr); +} + +//--------------------------------------------------------------- + +void ModeTab::SetTabArea(EdRect *bounding_rect) +{ + if(LastModeTab) + { + if(Title) + { + TitleRect.SetRect ( + LastModeTab->TitleRight()+1, + bounding_rect->GetTop(), + QTStringWidth(Title)+6, + QTStringHeight()+6 + ); + } + } + else + { + if(Title) + { + TitleRect.SetRect ( + bounding_rect->GetLeft(), + bounding_rect->GetTop(), + QTStringWidth(Title)+6, + QTStringHeight()+6 + ); + } + } + ContentRect.SetRect ( + bounding_rect->GetLeft(), + TitleRect.GetBottom(), + bounding_rect->GetWidth(), + bounding_rect->GetHeight()-TitleRect.GetHeight() + ); + ControlSetBounds(&ContentRect); +} + +//--------------------------------------------------------------- + +void ModeTab::MoveTabArea(EdRect *bounding_rect) +{ + SLONG offset_x; + + + offset_x = bounding_rect->GetLeft()-ContentRect.GetLeft(); + TitleRect.MoveRect(TitleRect.GetLeft()+offset_x,bounding_rect->GetTop()); + ContentRect.MoveRect(bounding_rect->GetLeft(),TitleRect.GetBottom()); + ControlSetBounds(&ContentRect); +} + +//--------------------------------------------------------------- + +void ModeTab::SetTabDrawArea(void) +{ + SetWorkWindowBounds ( + ContentLeft()+1, + ContentTop()+1, + ContentWidth()-2, + ContentHeight()-2 + ); +} + +//--------------------------------------------------------------- + +void ModeTab::ClearTab(void) +{ + EdRect clear_rect; + + clear_rect.SetRect(0,0,ContentWidth()-1,ContentHeight()-1); + clear_rect.FillRect(CONTENT_COL); +} + +//--------------------------------------------------------------- + +void ModeTab::DrawTab(void) +{ + EdRect title_rect; + + + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + + TitleRect.FillRect(CONTENT_COL); + if(GetStateFlags()) + { + ContentRect.HiliteRect(HILITE_COL,LOLITE_COL); + TitleRect.HiliteRect(HILITE_COL,LOLITE_COL); + DrawHLineC ( + TitleRect.GetLeft()+1, + TitleRect.GetRight()-1, + TitleRect.GetBottom(), + CONTENT_COL + ); + QuickTextC ( + TitleRect.GetLeft()+3, + TitleRect.GetTop()+3, + Title, + 0 + ); + + DrawTabContent(); + } + else + { + title_rect = TitleRect; + title_rect.ShrinkRect(1,0); + title_rect.OffsetRect(0,1); + title_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + title_rect.GetLeft()+2, + title_rect.GetTop()+3, + Title, + 0 + ); + } +} + +//--------------------------------------------------------------- + +void ModeTab::DrawTabContent(void) +{ + EdRect content_rect; + + + content_rect = ContentRect; + content_rect.ShrinkRect(1,1); + content_rect.FillRect(CONTENT_COL); + + QuickTextC ( + ContentRect.GetLeft()+4, + ContentRect.GetTop()+4, + "No DrawTabContent function.",0 + ); +} + +//--------------------------------------------------------------- + +void ModeTab::HandleTab(MFPoint *current_point) +{ + HandleControlSet(current_point); +} + +//--------------------------------------------------------------- + +UWORD ModeTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + clicked_point = clicked_point; + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + break; + case RIGHT_CLICK: + break; + } + return 0; +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/Move.cpp b/fallen/Editor/Source/Move.cpp new file mode 100644 index 0000000..dce92b0 --- /dev/null +++ b/fallen/Editor/Source/Move.cpp @@ -0,0 +1,65 @@ +// Move.cpp +// Guy Simmons, 27th March 1997. + +#include "Editor.hpp" +#include "Structs.h" + +#ifdef DOGPOO +//--------------------------------------------------------------- + +SLONG get_distance(Coord *position1,Coord *position2) +{ +/* + return ( + Hypotenuse ( + Hypotenuse ( + position2->X-(SLONG)position1->X, + position2->Z-(SLONG)position1->Z + ), + position2->Y-(SLONG)position1->Y + ) + ); +*/ + return 0; +} + +//--------------------------------------------------------------- + +SLONG get_approx_distance(Coord *position1,Coord *position2) +{ + return 0; +} + +//--------------------------------------------------------------- + +SLONG get_distance_xz(Coord *position1,Coord *position2) +{ +/* + return ( + Hypotenuse ( + position2->X-position1->X, + position2->Z-position1->Z + ) + ); +*/ + return 0; +} + +//--------------------------------------------------------------- + +SLONG get_angle_xz(Coord *position1,Coord *position2) +{ +// return(Arctan(position2->X-position1->X,position2->Z-position1->Z)); + return 0; +} + +//--------------------------------------------------------------- + +SLONG get_angle_yz(Coord *position1,Coord *position2) +{ +// return(Arctan(position2->Y-position1->Y,-get_distance_xz(position1,position2))); + return 0; +} + +//--------------------------------------------------------------- +#endif \ No newline at end of file diff --git a/fallen/Editor/Source/PaintTab.cpp b/fallen/Editor/Source/PaintTab.cpp new file mode 100644 index 0000000..6f89a97 --- /dev/null +++ b/fallen/Editor/Source/PaintTab.cpp @@ -0,0 +1,3537 @@ +// Guy Simmons +// 20th February 1997. + +//eaworldhq@eahq-exchange.ea.com + + +#include "Editor.hpp" +#include "c:\fallen\headers\game.h" +#include "c:\fallen\headers\animtmap.h" +#include "c:\fallen\ddlibrary\headers\tga.h" +#include "c:\fallen\headers\memory.h" +#define SET_TEXTURE_COORDS texture_x=TextureX;if(texture_x>(256-(1<(256-(1<SetValueRange(1,256); + ((CHSlider*)GetControlPtr(CTRL_TEX_TILE_SIZE))->SetCurrentValue(edit_info.TileScale); + ((CHSlider*)GetControlPtr(CTRL_TEX_TILE_SIZE))->SetUpdateFunction(new_tile_size); + +void new_scroll_pos(void); + ((CVSlider*)StyleSet.GetControlPtr(CTRL_STYLE_PAINT_SLIDER))->SetUpdateFunction(new_scroll_pos); + ((CVSlider*)StyleSet.GetControlPtr(CTRL_STYLE_PAINT_SLIDER))->SetValueRange(0,60); + ((CVSlider*)StyleSet.GetControlPtr(CTRL_STYLE_PAINT_SLIDER))->SetCurrentValue(1); + + CurrentStyleEdit=0; + CurrentStylePos=1; + the_painttab=this; + UpdateTabInfo(); + UpdatePaletteInfo(); + UpdateTextureInfo(); + + for(c0=0;c0<4;c0++) + { + CurrentTexture.U[c0]=0; + CurrentTexture.V[c0]=0; + } +} + +PaintTab::~PaintTab() +{ + CutMapBlock.Free(); +} + +void fix_all_selected_faces_for_tile_mode(void); +extern void find_highest_selected_tmap(SLONG *tx,SLONG *ty); +/* +void scale_selected_tmaps(SLONG scale) +{ + SLONG c0,c1; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG tx,ty; + + find_highest_selected_tmap(&tx,&ty); + scale+=32; + + + for(c0=1;c00) + { + p_f4=&prim_faces4[face_selected_list[c0]]; + for(c1=0;c1<4;c1++) + { + SLONG wx,wy; + + wx=p_f4->UV[c1][0]; + wy=p_f4->UV[c1][1]; + wx=(((wx-tx)*scale)>>5)+tx; + wy=(((wy-ty)*scale)>>5)+ty; + + p_f4->UV[c1][0]=wx; + p_f4->UV[c1][1]=wy; + } + } + else + if(face_selected_list[c0]<0) + { + p_f3=&prim_faces3[-face_selected_list[c0]]; + for(c1=0;c1<3;c1++) + { + p_f3->UV[c1][0]=(((p_f3->UV[c1][0]-tx)*scale)>>7)+p_f4->UV[c1][0]; + p_f3->UV[c1][1]=(((p_f3->UV[c1][1]-ty)*scale)>>7)+p_f3->UV[c1][1]; + } + + } + } +} +*/ +void new_tile_size(void) +{ + edit_info.TileScale = ((CHSlider*)the_painttab->GetControlPtr(CTRL_TEX_TILE_SIZE))->GetCurrentValue(); + if(edit_info.TileFlag) + { +// fix_all_selected_faces_for_tile_mode(); + } + else + { + // scale_selected_tmaps(tx,ty,edit_info.TileScale); + } +// the_painttab->UpdateTexture(); + the_painttab->Parent->DrawContent(); +// the_painttab->DrawTabContent(); +/* + SetWorkWindowBounds(the_painttab->Parent->GetLeft(), + the_painttab->Parent->GetTop(), + the_painttab->Parent->GetWidth(), + the_painttab->Parent->GetHeight()); +*/ +} + +void new_scroll_pos(void) +{ + the_painttab->CurrentStylePos = ((CVSlider*)the_painttab->StyleSet.GetControlPtr(CTRL_STYLE_PAINT_SLIDER))->GetCurrentValue(); + the_painttab->RequestUpdate(); + +} +//--------------------------------------------------------------- + +void PaintTab::UpdateTabInfo(void) +{ + ((CStaticText*)GetControlPtr(CTRL_PAINT_TEXT))->SetString1(mode_menu[PaintMode].ItemText); +} + +//--------------------------------------------------------------- +extern SLONG editor_texture_set; + +void PaintTab::DrawTabContent(void) +{ + EdRect bounds_rect, + content_rect; + + + content_rect = ContentRect; + content_rect.ShrinkRect(1,1); + content_rect.FillRect(CONTENT_COL); + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + + DrawControlSet(); + extern UWORD diff_page_count1,diff_page_count2; + { + CBYTE str[100]; + sprintf(str,"diff tex(world %d) %d shared %d",editor_texture_set,diff_page_count1,diff_page_count2); + QuickText(0,0,str,0); + QuickText(1,0,str,WHITE_COL); + } + + + switch(PaintMode) + { + case PALETTE_PAINT: + UpdatePaletteInfo(); + DrawPalette(); +// DrawControlSet(); +// PaintRect.HiliteRect(LOLITE_COL,HILITE_COL); + PaintRect.HiliteRect(LOLITE_COL,HILITE_COL); + break; + case INSTYLE_DEFINE: + case STYLE_DEFINE: + case PSX_TEX_DEFINE: + case ANIM_TMAP_PAINT: + case FLOOR_PAINT: + case TEXTURE_PAINT: + case PLANAR_PAINT: + UpdateTextureInfo(); + DrawTexture(); +// bounds_rect.SetRect(ContentLeft(),ContentTop(),ContentWidth(),ContentHeight()); +// TextureSet.ControlSetBounds(&bounds_rect); +// TextureSet.DrawControlSet(); +// PaintRect.HiliteRect(LOLITE_COL,HILITE_COL); + break; + case STYLE_PAINT: + DrawStyleTexture(); + bounds_rect.SetRect(ContentLeft(),ContentTop(),ContentWidth(),ContentHeight()); + StyleSet.ControlSetBounds(&bounds_rect); + StyleSet.DrawControlSet(); + break; + default: + break; + + } + + // + // Default control set used by all + // +} + +//--------------------------------------------------------------- + +void draw_selected_face_textures(SLONG tx,SLONG ty,SLONG zoom) +{ + SLONG c0; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + +// zoom=1; + + for(c0=1;c00) + { + SLONG x1,y1,x2,y2,x3,y3,x4,y4; + p_f4=&prim_faces4[face_selected_list[c0]]; + x1=((p_f4->UV[0][0]+tx)*zoom); + y1=((p_f4->UV[0][1]+ty)*zoom); + x2=((p_f4->UV[1][0]+tx)*zoom); + y2=((p_f4->UV[1][1]+ty)*zoom); + x3=((p_f4->UV[2][0]+tx)*zoom); + y3=((p_f4->UV[2][1]+ty)*zoom); + x4=((p_f4->UV[3][0]+tx)*zoom); + y4=((p_f4->UV[3][1]+ty)*zoom); + + DrawLineC(x1,y1,x2,y2,WHITE_COL); + DrawLineC(x2,y2,x4,y4,WHITE_COL); + DrawLineC(x4,y4,x3,y3,WHITE_COL); + DrawLineC(x3,y3,x1,y1,WHITE_COL); + } + else + if(face_selected_list[c0]<0) + { + SLONG x1,y1,x2,y2,x3,y3; + p_f3=&prim_faces3[-face_selected_list[c0]]; + x1=(p_f3->UV[0][0]+tx)*zoom; + y1=(p_f3->UV[0][1]+ty)*zoom; + x2=(p_f3->UV[1][0]+tx)*zoom; + y2=(p_f3->UV[1][1]+ty)*zoom; + x3=(p_f3->UV[2][0]+tx)*zoom; + y3=(p_f3->UV[2][1]+ty)*zoom; + + DrawLineC(x1,y1,x2,y2,WHITE_COL); + DrawLineC(x2,y2,x3,y3,WHITE_COL); + DrawLineC(x3,y3,x1,y1,WHITE_COL); + } + } +} + +extern void build_texture(SLONG x,SLONG y,SLONG w,SLONG h,UBYTE page,UBYTE u0,UBYTE v0,UBYTE u1,UBYTE v1,UBYTE u2,UBYTE v2,UBYTE u3,UBYTE v3); + +void PaintTab::DrawAnimTmapSelector(void) +{ + SLONG w,h,count; + EdRect tex_rect; + w=AnimRect.GetLeft(); + count=ShowAnimTmap; + + for(h=AnimRect.GetTop();(h=0) + { + + switch(WorkScreenDepth) + { + case 1: + { +/* + UBYTE *texture_ptr; + UBYTE *rect_ptr; + UBYTE *buffer_ptr; + UBYTE texture_buffer[256]; + + + SET_TEXTURE_COORDS + + rect_ptr = WorkWindow+PaintRect.GetLeft()+1+((PaintRect.GetTop()+1)*WorkScreenWidth); + if(Keys[KB_9]) + texture_ptr = tmap2+texture_x+(texture_y*256); + else + texture_ptr = game_textures[CurrentTexturePage].TexturePtr+texture_x+(texture_y*256); + c0 = 256; + + while(c0) + { + buffer_ptr = &texture_buffer[255]; + c1 = 1<>TextureZoom; + while(zoom--) + { + *(buffer_ptr--) = pixel; + } + c1--; + } + + zoom = 256>>TextureZoom; + c0 -= zoom; + while(zoom) + { + memcpy(rect_ptr,texture_buffer,256); + rect_ptr += WorkScreenWidth; + zoom--; + } + texture_ptr += 256; + } +*/ + } + break; + + case 2: +/* + if (Keys[KB_8]) + { + UBYTE *texture_ptr; + UWORD *rect_ptr; + UWORD *buffer_ptr; + UWORD texture_buffer[256]; + + + SET_TEXTURE_COORDS + + rect_ptr = ((UWORD*)WorkWindow)+PaintRect.GetLeft()+1+((PaintRect.GetTop()+1)*WorkScreenPixelWidth); + if(Keys[KB_9]) + texture_ptr = tmap2+texture_x+(texture_y*256); + else + texture_ptr = game_textures[CurrentTexturePage].TexturePtr+texture_x+(texture_y*256); + c0 = 256; + + while(c0) + { + buffer_ptr = &texture_buffer[255]; + c1 = 1<>TextureZoom; + while(zoom--) + { + *(buffer_ptr--) = pixel; + } + c1--; + } + + zoom = 256>>TextureZoom; + c0 -= zoom; + while(zoom) + { + memcpy(rect_ptr,texture_buffer,256*2); + rect_ptr += WorkScreenPixelWidth; + zoom--; + } + texture_ptr += 256; + } + } + else +*/ + { + // + // Ugh! Whats this!!! + // + + SET_TEXTURE_COORDS + + UWORD *rect_ptr = ((UWORD*)WorkWindow)+PaintRect.GetLeft()+1+((PaintRect.GetTop()+1)*WorkScreenPixelWidth); + UWORD *text_ptr = game_textures[CurrentTexturePage].TexturePtr; + + SLONG i; + SLONG j; + + SLONG zoom = 256 >> TextureZoom; + SLONG unzoom = 8 - TextureZoom; + + if (zoom == 1) + { + for (i = 0; i < 256; i++) + { + memcpy(rect_ptr, text_ptr, 512); + + text_ptr += 256; + rect_ptr += WorkScreenPixelWidth; + } + if(show_info) + if(CurrentTexturePage<8) + { + CBYTE str[100]; + SLONG x,y,page; + page=CurrentTexturePage*64; +extern UWORD page_count[]; + for(y=0;y<8;y++) + for(x=0;x<8;x++) + { + //sprintf(str,"%d",page_count[page]); + sprintf(str,"%d(%d)",page_count[page],page); + QuickText(PaintRect.GetLeft()+x*32,PaintRect.GetTop()+y*32,str,0); + QuickText(PaintRect.GetLeft()+x*32+1,PaintRect.GetTop()+y*32+1,str,WHITE_COL); + if(page_remap[page]) + { + SLONG u,v,flip=0; + UWORD rpage; + + rpage=page_remap[page]-1; + + u=(rpage&7)<<5; + v=((rpage>>3)&7)<<5; + if(rpage&(1<<14)) + flip=1; + if(rpage&(1<<15)) + flip|=2; + + draw_quad_now(PaintRect.GetLeft()+x*32+16,PaintRect.GetTop()+y*32+16,16,16,u,v,((rpage>>6)&7)+25,flip,POLY_T); + + } + page++; + } + } + + } + else + { + + for (i = 0; i < 256; i++) + for (j = 0; j < 256; j++) + { + rect_ptr[i + j * WorkScreenPixelWidth] = text_ptr[((i >> unzoom) + texture_x) + ((j >> unzoom) + texture_y) * 256]; + } + if(show_info) + if(CurrentTexturePage<8) + { + CBYTE str[100]; + SLONG x,y,page; + page=CurrentTexturePage*64; +extern UWORD page_count[]; + for(y=0;y<8;y++) + for(x=0;x<8;x++) + { + SLONG zoom_x,zoom_y; + + zoom_x=((x*32)<=0&&zoom_x<246&&zoom_y>=0&&zoom_y<246) + { + sprintf(str,"%d(%d)",page_count[page],page); + QuickText(PaintRect.GetLeft()+zoom_x,PaintRect.GetTop()+zoom_y,str,0); + QuickText(PaintRect.GetLeft()+zoom_x+1,PaintRect.GetTop()+zoom_y+1,str,WHITE_COL); + + if(page_remap[page]) + { + SLONG u,v,flip=0; + UWORD rpage; + + rpage=page_remap[page]-1; + + u=(rpage&7)<<5; + v=((rpage>>3)&7)<<5; + if(rpage&(1<<14)) + flip=1; + if(rpage&(1<<15)) + flip|=2; + + draw_quad_now(PaintRect.GetLeft()+zoom_x+(16<>6)&7)+25,flip,POLY_T); + + } + + } + page++; + } + } + + } + } + + break; + + } + //show fade table + /* + { + SLONG x,y; + for(y=0;y<64;y++) + { + memcpy(rect_ptr,&fade_tables[y<<8],256); + rect_ptr += WorkScreenWidth; + memcpy(rect_ptr,&fade_tables[y<<8],256); + rect_ptr += WorkScreenWidth; + memcpy(rect_ptr,&fade_tables[y<<8],256); + rect_ptr += WorkScreenWidth; + memcpy(rect_ptr,&fade_tables[y<<8],256); + rect_ptr += WorkScreenWidth; + } + } + */ + + if(TextureFlags&FLAGS_SHOW_TEXTURE) + { + SetWorkWindowBounds ( + ContentLeft()+PaintRect.GetLeft()+2, + ContentTop()+PaintRect.GetTop()+2, + 256, + 256 + ); + SetWorkWindowBounds ( + ContentLeft()+PaintRect.GetLeft()+2, + ContentTop()+PaintRect.GetTop()+2, + 256, + 256 + ); + zoom = 256>>TextureZoom; + + for(c0=0;c0<4;c0++) + { + x[c0] = (CurrentTexture.U[c0]-texture_x)*zoom; + y[c0] = (CurrentTexture.V[c0]-texture_y)*zoom; + } + + DrawLineC(x[0],y[0],x[1],y[1],WHITE_COL); + DrawLineC(x[2],y[2],x[0],y[0],WHITE_COL); + if(TextureFlags&FLAGS_QUADS) + { + DrawLineC(x[1],y[1],x[3],y[3],WHITE_COL); + DrawLineC(x[3],y[3],x[2],y[2],WHITE_COL); + } + else + DrawLineC(x[1],y[1],x[2],y[2],WHITE_COL); + + // if(!(TextureFlags&FLAGS_FIXED)) + { + if(TextureFlags&FLAGS_QUADS) + for(c0=0;c0<4;c0++) + { + ClickRect[c0].SetRect(x[c0]-3,y[c0]-3,7,7); + ClickRect[c0].OutlineRect(WHITE_COL); +// ClickRect[c0].HiliteRect(HILITE_COL,LOLITE_COL); + } + else + for(c0=0;c0<3;c0++) + { + ClickRect[c0].SetRect(x[c0]-3,y[c0]-3,7,7); + ClickRect[c0].OutlineRect(WHITE_COL); +// ClickRect[c0].HiliteRect(HILITE_COL,LOLITE_COL); + } + } + if(next_face_selected) + draw_selected_face_textures(-texture_x,-texture_y,zoom); + // draw_selected_face_textures(-texture_x+((PaintRect.GetLeft()+2)),-texture_y+((PaintRect.GetTop()+2)),zoom); + } + } +} + +//--------------------------------------------------------------- + +void PaintTab::UpdateTexture(void) +{ + if(LockWorkScreen()) + { + DrawTexture(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} + +//--------------------------------------------------------------- + +UBYTE bit_tab[10] = { 0,1,2,3,4,4,4,4,4,4 }; + +void PaintTab::UpdateTextureInfo(void) +{ + CBYTE str[20]; + if(CurrentTexturePage>=0) + ((CStaticText*)GetControlPtr(CTRL_TEX_PAGE_TEXT))->SetString1(texture_menu[CurrentTexturePage].ItemText); +// ((CStaticText*)TextureSet.GetControlPtr(CTRL_TEX_PAGE_TEXT))->SetString1(texture_menu[CurrentTexturePage].ItemText); + sprintf(str,"%d x %d",TextureWidth,TextureHeight); + + ((CStaticText*)GetControlPtr(CTRL_TEX_SIZE_TEXT))->SetString1(str); +//md ((CStaticText*)TextureSet.GetControlPtr(CTRL_TEX_SIZE_TEXT))->SetString1(str); +// ((CStaticText*)GetControlPtr(CTRL_TEX_SIZE_TEXT))->SetString1(texture_size[bit_tab[TextureSize>>4]].ItemText); + +// TextureSet.SetControlState(CTRL_TEX_NO_LIGHT,(edit_info.FlatShade ? CTRL_SELECTED : CTRL_DESELECTED)); + SetControlState(CTRL_TEX_NO_HIDDEN,(edit_info.NoHidden ? CTRL_SELECTED : CTRL_DESELECTED)); + SetControlState(CTRL_TEX_USE_CLIPPED,(edit_info.Clipped&2 ? CTRL_SELECTED : CTRL_DESELECTED)); + SetControlState(CTRL_TEX_ROOF_TEX,(edit_info.RoofTex ? CTRL_SELECTED : CTRL_DESELECTED)); + SetControlState(CTRL_TEX_SELECT_DRAWN,(SelectDrawn ? CTRL_SELECTED : CTRL_DESELECTED)); + SetControlState(CTRL_TEX_QUAD_BOX,(TextureFlags&FLAGS_QUADS ? CTRL_SELECTED : CTRL_DESELECTED)); + SetControlState(CTRL_TEX_FIXED_BOX,(TextureFlags&FLAGS_FIXED ? CTRL_SELECTED : CTRL_DESELECTED)); +// TextureSet.SetControlState(CTRL_TEX_SIZE_MENUW,(TextureFlags&FLAGS_FIXED ? CTRL_ACTIVE : CTRL_INACTIVE)); +// TextureSet.SetControlState(CTRL_TEX_SIZE_MENUH,(TextureFlags&FLAGS_FIXED ? CTRL_ACTIVE : CTRL_INACTIVE)); + if(SelectFlag==5) + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_SELECTED )); + else + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_DESELECTED )); + if(SelectFlag==6) + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_SELECTED )); + else + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_DESELECTED )); + +} + +//--------------------------------------------------------------- + +void PaintTab::DrawPalette(void) +{ + ULONG c0,c1, + colour, + *rect_ptr, + *temp_ptr; + EdRect colour_rect; + + LogText(" draw pal currentcol %d \n",CurrentColour); + + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + rect_ptr = (ULONG*)(WorkWindow+PaintRect.GetLeft()*2+2+((PaintRect.GetTop()+1)*WorkScreenWidth)); + for(c0=0;c0<256;c0++) + { + colour = pal_to_16[c0]*0x00010001; + temp_ptr = rect_ptr+((c0&0x0f)<<3)+(((c0&0xff0)>>2)*WorkScreenWidth); + for(c1=0;c1<16;c1++,temp_ptr+=(WorkScreenWidth>>2)) + { + *(temp_ptr+0) = colour; + *(temp_ptr+1) = colour; + *(temp_ptr+2) = colour; + *(temp_ptr+3) = colour; + *(temp_ptr+4) = colour; + *(temp_ptr+5) = colour; + *(temp_ptr+6) = colour; + *(temp_ptr+7) = colour; + } + } + + colour_rect.SetRect ( + (PaintRect.GetLeft()+1)+((CurrentColour&0x0f)<<4), + (PaintRect.GetTop()+1)+(CurrentColour&0xf0), + 16, + 16 + ); + colour_rect.OutlineRect(WHITE_COL); +} + +//--------------------------------------------------------------- + +void PaintTab::UpdatePalette(void) +{ + if(LockWorkScreen()) + { + DrawPalette(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} + +//--------------------------------------------------------------- + +void PaintTab::UpdatePaletteInfo(void) +{ + +} + +//--------------------------------------------------------------- + +void PaintTab::do_undo_me_bloody_self_then(SLONG index) +{ + struct GenericUndo *p_u; + SLONG c0; + if(index<0) + p_u=&MyUndo.undo_undo_info[-index]; + else + p_u=&MyUndo.undo_info[index]; + + switch(p_u->Type) + { + case UNDO_MOVE_TEXTURE: + p_u->Type=0; + MyUndo.MoveTexture(index<0?0:1,CurrentTexturePage,0,CurrentTexture.U[0],CurrentTexture.V[0],CurrentTexture.U[1],CurrentTexture.V[1], + CurrentTexture.U[2],CurrentTexture.V[2],CurrentTexture.U[3],CurrentTexture.V[3]); + + CurrentTexturePage=p_u->Texture.Page; + CurrentTexture.U[0]=p_u->Texture.U[0]; + CurrentTexture.U[1]=p_u->Texture.U[1]; + CurrentTexture.U[2]=p_u->Texture.U[2]; + CurrentTexture.U[3]=p_u->Texture.U[3]; + CurrentTexture.V[0]=p_u->Texture.V[0]; + CurrentTexture.V[1]=p_u->Texture.V[1]; + CurrentTexture.V[2]=p_u->Texture.V[2]; + CurrentTexture.V[3]=p_u->Texture.V[3]; +// if(selected_face.Face) + if(selected_face.PEle) + { + if(selected_face.PEle==(struct EditMapElement*)-2) + { + + } + else + if(selected_face.PEle==(struct EditMapElement*)-1) + { + if(selected_face.Face<0) + { + prim_faces3[-selected_face.Face].TexturePage = (UWORD)CurrentTexturePage; + for(c0=0;c0<3;c0++) + { + prim_faces3[-selected_face.Face].UV[c0][0] = CurrentTexture.U[c0]; + prim_faces3[-selected_face.Face].UV[c0][1] = CurrentTexture.V[c0]; + } + } + else + { + prim_faces4[selected_face.Face].TexturePage = (UWORD)CurrentTexturePage; + for(c0=0;c0<4;c0++) + { + prim_faces4[selected_face.Face].UV[c0][0] = CurrentTexture.U[c0]; + prim_faces4[selected_face.Face].UV[c0][1] = CurrentTexture.V[c0]; + } + } + } + if(LockWorkScreen()) + { + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + break; + } +} + +void PaintTab::CutFloorBrush(BuildTab *BuildMode,MFPoint *current_point) +{ + + MFPoint point1,point2; + SLONG con_top,con_left; + SLONG x,y,w,h; + SLONG mx1,my1,mz1; + SLONG mx2,my2,mz2; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + point1.X = MouseX; + point1.Y = MouseY; + Parent->GlobalToLocal(&point1); + BuildMode->CalcMapCoord(&mx1,&my1,&mz1,x,y,w,h,&point1); +// point1 = *clicked_point; + while(SHELL_ACTIVE && LeftButton) + { + engine_keys_scroll(); + engine_keys_spin(); + engine_keys_zoom(); + + point2.X = MouseX;//-con_left; + point2.Y = MouseY;//-con_top; + Parent->GlobalToLocal(&point2); + BuildMode->CalcMapCoord(&mx2,&my2,&mz2,x,y,w,h,&point2); + + if(LockWorkScreen()) + { + Parent->DrawContent(); + Parent->DrawGrowBox(); + BuildMode->Texture=2; + BuildMode->DrawContentRect(mx1,mz1,mx2,mz2,WHITE_COL); + BuildMode->Texture=0; + UnlockWorkScreen(); + } + ShowWorkWindow(0); + } + { + SLONG mw,mh; + mw=mx2-mx1; + if(mw<0) + { + mw=-mw; + mx1=mx2; + } + mh=mz2-mz1; + if(mh<0) + { + mh=-mh; + mz1=mz2; + } + CutMapBlock.Cut(mx1>>ELE_SHIFT,mz1>>ELE_SHIFT,mw>>ELE_SHIFT,mh>>ELE_SHIFT,0); + SubMode=FLOOR_PASTE_BRUSH; + + } + + RequestUpdate(); +} + +void PaintTab::HandleTab(MFPoint *current_point) +{ + ULONG control_id; + SLONG update = 0; + + +// ModeTab::HandleTab(current_point); + if(PaintMode==PALETTE_PAINT) + PaletteSet.HandleControlSet(current_point); + else + if(PaintMode==STYLE_PAINT) + StyleSet.HandleControlSet(current_point); + else + HandleControlSet(current_point); + + if(PaintMode==ANIM_TMAP_PAINT) + { + if(CurrentTexturePage<0) + CurrentTexturePage=0; + + } + if(PaintMode==FLOOR_PAINT) + { + if(Keys[KB_B]) + { + SubMode=FLOOR_CUT_BRUSH; + SubStatus=0; + } + } + + if(Keys[KB_U]) + { + SLONG index; + Keys[KB_U]=0; + index=MyUndo.DoUndo(ShiftFlag?1:0); + if(index) + do_undo_me_bloody_self_then(index); + update = 1; + } + if(Keys[KB_PMINUS]) + { + if(TextureZoom<8) + { + TextureZoom++; + update = 1; + } + } + else if(Keys[KB_PPLUS]) + { + if(TextureZoom>0) + { + TextureZoom--; + update = 1; + } + } + if(Keys[KB_P4]) + { + if(TextureX>0) + { + TextureX--; + update = 1; + } + } + else if(Keys[KB_P6]) + { + if(TextureX<(256-(1<0) + { + TextureY--; + update = 1; + } + } + else if(Keys[KB_P2]) + { + if(TextureY<(256-(1<20) + CurrentTexturePage=20; + + if(LastKey) + { + control_id = HandleControlSetKey(LastKey); + if(control_id) + { + HandleControl(control_id); + LastKey = 0; + } + else + { + if(PaintMode==PALETTE_PAINT) + { + if(LastKey==KB_LBRACE) + { + CurrentColour = (CurrentColour-1)&0xff; + update = 1; + LastKey = 0; + } + else if(LastKey==KB_RBRACE) + { + CurrentColour = (CurrentColour+1)&0xff; + update = 1; + LastKey = 0; + } + else + { + control_id = PaletteSet.HandleControlSetKey(LastKey); + if(control_id) + { + HandlePaletteControl(control_id); + LastKey = 0; + } + } + } + else + if(PaintMode==STYLE_PAINT) + { + if(LastKey==KB_LBRACE) + { + update = 1; + LastKey = 0; + } + else if(LastKey==KB_RBRACE) + { + update = 1; + LastKey = 0; + } + else + { + control_id = StyleSet.HandleControlSetKey(LastKey); + if(control_id) + { + HandleStyleControl(control_id); + LastKey = 0; + } + } + } + else + { + control_id = HandleControlSetKey(LastKey); //ts + if(control_id) + { + HandleTextureControl(control_id); + LastKey = 0; + } + } + } + } +/* + if(Keys[KB_F]) + { + Keys[KB_F]=0; + TextureFlags ^= FLAGS_FIXED; + if(TextureFlags & FLAGS_FIXED) + SetControlState(CTRL_TEX_FIXED_BOX,CTRL_SELECTED); + else + SetControlState(CTRL_TEX_FIXED_BOX,CTRL_DESELECTED); + if(LockWorkScreen()) + { + + DrawControlSet(); +// DrawTabContent(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + UpdateTexture(); + return; + } +*/ + } + + if(update) + { + if(PaintMode==PALETTE_PAINT) + UpdatePalette(); + else + UpdateTexture(); + } +} + +//--------------------------------------------------------------- + +#define DRAG_NORMAL 0 +#define DRAG_SHIFT 1 +#define DRAG_SHIFT_H 2 +#define DRAG_SHIFT_V 3 +#define DRAG_CONTROL 4 + +ULONG hooks[4][2] = +{ + { 2,1 }, + { 3,0 }, + { 0,3 }, + { 1,2 } +}; + +void PaintTab::SelectAnimTexture(MFPoint *clicked_point) +{ + SLONG x,y; + + x=clicked_point->X-AnimRect.GetLeft(); + y=clicked_point->Y-AnimRect.GetTop(); + + y=(y/19)+ShowAnimTmap; + if(PaintMode==ANIM_TMAP_PAINT) + { + + } + else + { + CurrentTexturePage=-y; + RequestUpdate(); + } +} + +void PaintTab::SetEditAnimTexture(MFPoint *clicked_point) +{ + SLONG x,y; + + x=clicked_point->X-AnimRect.GetLeft(); + y=clicked_point->Y-AnimRect.GetTop(); + + y=(y/19)+ShowAnimTmap; + if(PaintMode==ANIM_TMAP_PAINT) + { + + } + else + { + SetPaintMode(ANIM_TMAP_PAINT); +// PaintMode=ANIM_TMAP_PAINT; + CurrentTexturePage=0; + CurrentAnimTmap=y; + RequestUpdate(); + } +} + +UWORD PaintTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + ULONG control_id; + SLONG zoom; + Control *current_control; + MFPoint current_point, + local_point; + + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + if(AnimRect.PointInRect(&local_point)&&RightButton==0&&PaintMode!=STYLE_PAINT) + { + SelectAnimTexture(&local_point); + UpdateTexture(); + } + else + if( (PaintRect.PointInRect(&local_point)) && (RightButton==0) && (PaintMode!=STYLE_PAINT) ) + { + if(PaintMode==FLOOR_PAINT||PaintMode==TEXTURE_PAINT||PaintMode==ANIM_TMAP_PAINT||PaintMode==STYLE_DEFINE||PaintMode==PSX_TEX_DEFINE||PaintMode==INSTYLE_DEFINE) + { + SelectTexture(clicked_point); + SubMode=0; + } + else + if(PaintMode==PALETTE_PAINT) + SelectColour(clicked_point); + else + if(PaintMode==PLANAR_PAINT) + PlanarMapping(clicked_point); + + } + else + { + if(PaintMode==STYLE_PAINT) + { + SelectStyle(clicked_point); + } + + local_point = *clicked_point; + GlobalToLocal(&local_point); +/* + control_id = HandleControlSetClick(flags,&local_point); + HandleControl(control_id); +*/ + + current_control = GetControlList();//ts + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + control_id = current_control->TrackControl(&local_point); + HandleControl(control_id); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + return control_id; + } + current_control = current_control->GetNextControl(); + } + +/* + if(control_id) + { + return control_id; + } + else +*/ + { + if(PaintMode==PALETTE_PAINT) + { + control_id = PaletteSet.HandleControlSetClick(flags,clicked_point); + HandlePaletteControl(control_id); + } + else + if(PaintMode==STYLE_PAINT) + { + control_id = StyleSet.HandleControlSetClick(flags,clicked_point); + HandleStyleControl(control_id); + } + else + { + control_id = HandleControlSetClick(flags,clicked_point); //ts + HandleTextureControl(control_id); + } + } + } + break; + case RIGHT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + if(PaintMode==STYLE_PAINT) + { + } + else + if(AnimRect.PointInRect(&local_point)) + { + SetEditAnimTexture(&local_point); + UpdateTexture(); + } + else + if(PaintRect.PointInRect(&local_point)) + { + zoom = 0; + SubMode=0; + while(SHELL_ACTIVE && RightButton) + { + current_point.X = MouseX; + current_point.Y = MouseY; + GlobalToLocal(¤t_point); + if(current_point.X!=local_point.X || current_point.Y!=local_point.Y) + { + if(LeftButton) + { + zoom += local_point.Y-current_point.Y; + if((zoom/4)) + { + TextureZoom += zoom/4; + zoom = 0; + } + if(TextureZoom<0) + TextureZoom = 0; + else if(TextureZoom>8) + TextureZoom = 8; + } + else + { + TextureX += local_point.X-current_point.X; + TextureY += local_point.Y-current_point.Y; + if(TextureX<0) + TextureX = 0; + else if(TextureX>(256-(1<(256-(1<GetCurrentValue(); //ts + + RequestUpdate(); + break; + + case CTRL_PAINT_MENU: + PaintMode = (control_id>>8)-1; + RequestUpdate(); + break; + case CTRL_PAINT_TEXT: + break; + case CTRL_TEX_PAGE_TEXT: + break; + case CTRL_TEX_PAGE_MENU: + CurrentTexturePage = (control_id>>8)-1; + if(CurrentTexturePage>max_textures) + { + CurrentTexturePage=max_textures; + + } + break; + case CTRL_TEX_HIDE_L: + if(edit_info.HideMap&1) + { + edit_info.HideMap&=~1; + SetControlState(CTRL_TEX_HIDE_L,CTRL_DESELECTED); + } + else + { + SetControlState(CTRL_TEX_HIDE_L,CTRL_SELECTED); + edit_info.HideMap|=1; + } + + break; + case CTRL_TEX_HIDE_R: + if(edit_info.HideMap&2) + { + edit_info.HideMap&=~2; + SetControlState(CTRL_TEX_HIDE_R,CTRL_DESELECTED); + } + else + { + SetControlState(CTRL_TEX_HIDE_R,CTRL_SELECTED); + edit_info.HideMap|=2; + } + break; + case CTRL_TEX_INFO: + show_info^=1; + break; + case CTRL_TEX_CLEAR: + { + Alert rus; + if(rus.HandleAlert("Remove painted textures?",NULL)==1) + { + remove_painted_textures(); + } + if(rus.HandleAlert("Remove style textures?",NULL)==1) + { + remove_style_textures(); + } + } + break; + + case CTRL_BUILD_OTHER: +extern SLONG build_psx; + build_psx^=1; + create_city(BUILD_MODE_EDITOR); + break; + case CTRL_TEX_HIDE_ROOF: + if(edit_info.HideMap&4) + { + edit_info.HideMap&=~4; + SetControlState(CTRL_TEX_HIDE_ROOF,CTRL_DESELECTED); + } + else + { + SetControlState(CTRL_TEX_HIDE_ROOF,CTRL_SELECTED); + edit_info.HideMap|=4; + } + break; + + case CTRL_TEX_QUAD_BOX: +// ToggleControlSelectedState(CTRL_TEX_QUAD_BOX); + TextureFlags ^= FLAGS_QUADS; + break; + case CTRL_TEX_FIXED_BOX: +// ToggleControlSelectedState(CTRL_TEX_FIXED_BOX); + TextureFlags ^= FLAGS_FIXED; +// ToggleControlActiveState(CTRL_TEX_SIZE_MENU); + break; +/* + case CTRL_TEX_SIZE_MENUW: +// TextureWidth = 1<<((control_id>>8)+2); + TextureWidth = 32; //texture_sizes[(control_id>>8)-1]; + break; + case CTRL_TEX_SIZE_MENUH: +// TextureHeight = 1<<((control_id>>8)+2); + TextureHeight = 32;//texture_sizes[(control_id>>8)-1]; + break; +*/ + case CTRL_TEX_SIZE_TEXT: + break; + case CTRL_TEX_IMPORT_TEX: + { + FileRequester *fr; + CBYTE fname[100]; + fr=new FileRequester("data\\","*.tex","Save A Prim","temp.tex"); + if(fr->Draw()) + { + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + import_tex(fname); + } + delete fr; + RequestUpdate(); + } + break; + case CTRL_TEX_LOAD_ANIMTMAP: + load_animtmaps(); + break; + case CTRL_TEX_SAVE_ANIMTMAP: + save_animtmaps(); + break; + case CTRL_TEX_ANIMTMAP_UP: + if(ShowAnimTmap>1) + { + ShowAnimTmap--; + RequestUpdate(); + } + break; + case CTRL_TEX_ANIMTMAP_DOWN: + if(ShowAnimTmap<64) + { + ShowAnimTmap++; + RequestUpdate(); + } + break; + case CTRL_TEX_PLANAR_MAP: + DoPlanarMap(); + break; + case CTRL_TEX_PLANAR_MAPF: + DoPlanarMapF(); + break; + case CTRL_TEX_SELECT_DRAWN: + SelectDrawn ^= 1; + break; +// case CTRL_TEX_NO_LIGHT: +// edit_info.FlatShade^=1; +// break; + case CTRL_TEX_NO_HIDDEN: + edit_info.NoHidden^=1; + break; + case CTRL_TEX_ROOF_TEX: + edit_info.RoofTex^=1; + break; + case CTRL_TEX_USE_CLIPPED: + edit_info.Clipped^=2; + break; + case CTRL_TEX_SET_CLIPPED: +extern void find_map_clip(SLONG *minx,SLONG *maxx,SLONG *minz,SLONG *maxz); + { + + SLONG minx,maxx,minz,maxz; + + find_map_clip(&minx,&maxx,&minz,&maxz); + edit_info.MinX=minx; + edit_info.MinZ=minz; + edit_info.MaxX=maxx; + edit_info.MaxZ=maxz; + edit_info.Clipped=2; + + } + + break; + } + + UpdateTextureInfo(); + UpdateTabInfo(); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} + +//--------------------------------------------------------------- + +void PaintTab::HandlePaletteControl(UWORD control_id) +{ + UpdatePaletteInfo(); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} + +void PaintTab::HandleStyleControl(UWORD control_id) +{ + + switch(control_id&0xff) + { + case CTRL_STYLE_PAINT_SLIDER: + new_scroll_pos(); +// RequestUpdate(); + break; + } + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} + +void PaintTab::DoPlanarMap(void) +{ + if(LockWorkScreen()) + { + if(SelectFlag==5) + { + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_DESELECTED )); //ts + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_DESELECTED )); + SelectFlag=0; + } + else + if(SelectFlag==6) + { + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_SELECTED )); + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_DESELECTED )); + SelectFlag=5; + } + else + { + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_SELECTED )); + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_DESELECTED )); + SelectFlag=5; + + } + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + ShowWorkWindow(0); + RequestUpdate(); + +} +void PaintTab::DoPlanarMapF(void) +{ + if(LockWorkScreen()) + { + if(SelectFlag==6) + { + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_DESELECTED )); + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_DESELECTED )); + SelectFlag=0; + } + else + if(SelectFlag==5) + { + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_DESELECTED )); + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_SELECTED )); + SelectFlag=6; + } + else + { + SetControlState(CTRL_TEX_PLANAR_MAP,(CTRL_DESELECTED )); + SetControlState(CTRL_TEX_PLANAR_MAPF,(CTRL_SELECTED )); + SelectFlag=6; + + } + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + ShowWorkWindow(0); + RequestUpdate(); + +} + +//--------------------------------------------------------------- + +void PaintTab::HandleTextureControl(UWORD control_id) +{ + + switch(control_id&0xff) + { + case CTRL_TEX_PAGE_TEXT: + break; + case CTRL_TEX_PAGE_MENU: + CurrentTexturePage = (control_id>>8)-1; + if(CurrentTexturePage>max_textures) + { + CurrentTexturePage=max_textures; + + } + break; + case CTRL_TEX_QUAD_BOX: +// ToggleControlSelectedState(CTRL_TEX_QUAD_BOX); + TextureFlags ^= FLAGS_QUADS; + break; + case CTRL_TEX_FIXED_BOX: +// ToggleControlSelectedState(CTRL_TEX_FIXED_BOX); + TextureFlags ^= FLAGS_FIXED; +// ToggleControlActiveState(CTRL_TEX_SIZE_MENU); + break; +/* + case CTRL_TEX_SIZE_MENUW: +// TextureWidth = 1<<((control_id>>8)+2); + TextureWidth = 32; //texture_sizes[(control_id>>8)-1]; + break; + case CTRL_TEX_SIZE_MENUH: +// TextureHeight = 1<<((control_id>>8)+2); + TextureHeight = 32;//texture_sizes[(control_id>>8)-1]; + break; +*/ + case CTRL_TEX_SIZE_TEXT: + break; + case CTRL_TEX_IMPORT_TEX: + { + FileRequester *fr; + CBYTE fname[100]; + fr=new FileRequester("data\\","*.tex","Save A Prim","temp.tex"); + if(fr->Draw()) + { + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + import_tex(fname); + } + delete fr; + RequestUpdate(); + } + break; + case CTRL_TEX_LOAD_ANIMTMAP: + load_animtmaps(); + break; + case CTRL_TEX_SAVE_ANIMTMAP: + save_animtmaps(); + break; + case CTRL_TEX_ANIMTMAP_UP: + if(ShowAnimTmap>1) + { + ShowAnimTmap--; + RequestUpdate(); + } + break; + case CTRL_TEX_ANIMTMAP_DOWN: + if(ShowAnimTmap<64) + { + ShowAnimTmap++; + RequestUpdate(); + } + break; + case CTRL_TEX_PLANAR_MAP: + DoPlanarMap(); + break; + case CTRL_TEX_PLANAR_MAPF: + DoPlanarMapF(); + break; + case CTRL_TEX_SELECT_DRAWN: + SelectDrawn ^= 1; + break; +// case CTRL_TEX_NO_LIGHT: +// edit_info.FlatShade^=1; +// break; + case CTRL_TEX_NO_HIDDEN: + edit_info.NoHidden^=1; + break; + case CTRL_TEX_ROOF_TEX: + edit_info.RoofTex^=1; + break; + case CTRL_TEX_USE_CLIPPED: + edit_info.Clipped^=2; + break; + case CTRL_TEX_SET_CLIPPED: +extern void find_map_clip(SLONG *minx,SLONG *maxx,SLONG *minz,SLONG *maxz); + { + + SLONG minx,maxx,minz,maxz; + + find_map_clip(&minx,&maxx,&minz,&maxz); + edit_info.MinX=minx; + edit_info.MinZ=minz; + edit_info.MaxX=maxx; + edit_info.MaxZ=maxz; + edit_info.Clipped=2; + + } + + break; + } + UpdateTextureInfo(); +// DrawTabContent(); + +// Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} + +//--------------------------------------------------------------- + +void PaintTab::SelectColour(MFPoint *clicked_point) +{ + MFPoint local_point; + + + local_point = *clicked_point; + GlobalToLocal(&local_point); + + local_point.X -= PaintRect.GetLeft()+2; + local_point.Y -= PaintRect.GetTop()+2; + + CurrentColour = ((local_point.X&0xff)>>4)+(local_point.Y&0xf0); + UpdatePalette(); +} + +//--------------------------------------------------------------- +void find_highest_selected_tmap(SLONG *tx,SLONG *ty) +{ + SLONG c0,c1; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + *tx=1000000; + *ty=1000000; + + for(c0=1;c00) + { + p_f4=&prim_faces4[face_selected_list[c0]]; + for(c1=0;c1<4;c1++) + { + if(p_f4->UV[c1][1]<*ty||(p_f4->UV[c1][1]==*ty&&p_f4->UV[c1][0]<*tx)) + { + *tx=p_f4->UV[c1][0]; + *ty=p_f4->UV[c1][1]; + } + } + } + else + if(face_selected_list[c0]<0) + { + p_f3=&prim_faces3[-face_selected_list[c0]]; + for(c1=0;c1<3;c1++) + { + if(p_f3->UV[c1][1]<*ty||(p_f3->UV[c1][1]==*ty&&p_f3->UV[c1][0]<*tx)) + { + *tx=p_f3->UV[c1][0]; + *ty=p_f3->UV[c1][1]; + } + } + + } + } +} + +void offset_selected_tmaps(SLONG tx,SLONG ty,UBYTE page,SLONG sx,SLONG sy,SLONG flag) +{ + SLONG c0,c1; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + + for(c0=1;c00) + { + p_f4=&prim_faces4[face_selected_list[c0]]; + p_f4->TexturePage=page; + for(c1=0;c1<4;c1++) + { + if( (p_f4->UV[c1][0]==sx&&p_f4->UV[c1][1]==sy) || flag) + { + p_f4->UV[c1][0]+=tx; + p_f4->UV[c1][1]+=ty; + } + } + } + else + if(face_selected_list[c0]<0) + { + p_f3=&prim_faces3[-face_selected_list[c0]]; + p_f3->TexturePage=page; + for(c1=0;c1<3;c1++) + { + if((p_f3->UV[c1][0]==sx&&p_f3->UV[c1][1]==sy) ||flag) + { + p_f3->UV[c1][0]+=tx; + p_f3->UV[c1][1]+=ty; + } + } + + } + } +} + +void scale_selected_tmaps(SWORD scale) +{ + SLONG c0,c1; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG mid_x=0,mid_y=0,count=0; + + for(c0=1;c00) + { + p_f4=&prim_faces4[face_selected_list[c0]]; + for(c1=0;c1<4;c1++) + { + mid_x+=p_f4->UV[c1][0]; + mid_y+=p_f4->UV[c1][1]; + count++; + } + } + else + if(face_selected_list[c0]<0) + { + p_f3=&prim_faces3[-face_selected_list[c0]]; + for(c1=0;c1<3;c1++) + { + mid_x+=p_f3->UV[c1][0]; + mid_y+=p_f3->UV[c1][1]; + count++; + } + } + } + + if(count) + { + mid_x/=count; + mid_y/=count; + for(c0=1;c00) + { + p_f4=&prim_faces4[face_selected_list[c0]]; + for(c1=0;c1<4;c1++) + { + SLONG temp; + + temp=p_f4->UV[c1][0]; + temp-=mid_x; + temp=((temp*scale)/256); + temp+=mid_x; + p_f4->UV[c1][0]=temp; + + temp=p_f4->UV[c1][1]; + temp-=mid_y; + temp=((temp*scale)/256); + temp+=mid_y; + p_f4->UV[c1][1]=temp; + + } + } + else + if(face_selected_list[c0]<0) + { + p_f3=&prim_faces3[-face_selected_list[c0]]; + for(c1=0;c1<3;c1++) + { + SLONG temp; + + temp=p_f3->UV[c1][0]; + temp-=mid_x; + temp=((temp*scale)/256); + temp+=mid_x; + p_f3->UV[c1][0]=temp; + + temp=p_f3->UV[c1][1]; + temp-=mid_y; + temp=((temp*scale)/256); + temp+=mid_y; + p_f3->UV[c1][1]=temp; + + } + } + } + } + +} + +void offset_selected_tex_page(SWORD offset) +{ + SLONG c0,c1; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG mid_x=0,mid_y=0,count=0; + SLONG u,v,page; + + for(c0=1;c00) + { + p_f4=&prim_faces4[face_selected_list[c0]]; + page=p_f4->TexturePage; + if(offset==64) + page++; + else + if(offset==-64) + page--; + + if(page<0) + page=14; + + for(c1=0;c1<4;c1++) + { + u=p_f4->UV[c1][0]; + v=p_f4->UV[c1][1]; + + if(offset==1) + { + u+=32; + if(u>255) + { + u-=256; + v+=32; + if(v>255) + { + page++; + if(page>14) + page=0; + v-=256; + } + } + } + else + if(offset==-1) + { + u-=32; + if(u<0) + { + u+=256; + v-=32; + if(v<0) + { + page--; + if(page<0) + page=14; + v+=256; + } + } + + } + + p_f4->UV[c1][0]=u; + p_f4->UV[c1][1]=v; + count++; + } + p_f4->TexturePage=page; + } + else + if(face_selected_list[c0]<0) + { + p_f3=&prim_faces3[-face_selected_list[c0]]; + page=p_f3->TexturePage; + if(offset==64) + page++; + else + if(offset==-64) + page--; + + if(page<0) + page=14; + for(c1=0;c1<3;c1++) + { + u=p_f3->UV[c1][0]; + v=p_f3->UV[c1][1]; + + if(offset==1) + { + u+=32; + if(u>255) + { + u-=255; + v+=32; + if(v>255) + { + page++; + if(page>14) + page=0; + v-=255; + } + } + } + else + if(offset==-1) + { + u-=32; + if(u<0) + { + u+=255; + v-=32; + if(v<0) + { + page--; + if(page<0) + page=14; + v+=255; + } + } + + } + + p_f3->UV[c1][0]=u; + p_f3->UV[c1][1]=v; + + count++; + } + p_f3->TexturePage=page; + } + } + +} + +void PaintTab::PlanarMapping(MFPoint *clicked_point) +{ + SLONG c0,c1, + scale, + texture_x, + texture_y, + dx, + dy, + zoom; + MFPoint current_point, + fixed_point, + local_point; + + + local_point = *clicked_point; + GlobalToLocal(&local_point); + + zoom = 256>>TextureZoom; + TextureFlags |= FLAGS_SHOW_TEXTURE; +// local_point.X = (((local_point.X-(PaintRect.GetLeft()+2))>>(8-TextureZoom))); +// local_point.Y = (((local_point.Y-(PaintRect.GetTop()+2))>>(8-TextureZoom))); + LogText(" Planar local point %d,%d \n",local_point.X,local_point.Y); + LogText(" Planar paint rect %d,%d \n",PaintRect.GetLeft(),PaintRect.GetTop()); + + local_point.X = (((local_point.X-(PaintRect.GetLeft()+2)))); + local_point.Y = (((local_point.Y-(PaintRect.GetTop()+2)))); + LogText(" Planar local point %d,%d AFTER -paintrect\n",local_point.X,local_point.Y); + + + SET_TEXTURE_COORDS +// local_point.X = (local_point.X+texture_x); +// local_point.Y = (local_point.Y+texture_y); +// find_highest_selected_tmap(&dx,&dy); +// LogText(" highest texture %d,%d \n",dx,dy); + +// dx-=local_point.X; +// dy-=local_point.Y; +// offset_selected_tmaps(dx,dy); + while(SHELL_ACTIVE && LeftButton) + { + current_point.X = MouseX; + current_point.Y = MouseY; + GlobalToLocal(¤t_point); + + zoom = 256>>TextureZoom; +// current_point.X = (((current_point.X-(PaintRect.GetLeft()+2))>>(8-TextureZoom))); +// current_point.Y = (((current_point.Y-(PaintRect.GetTop()+2))>>(8-TextureZoom))); + + current_point.X = (((current_point.X-(PaintRect.GetLeft()+2)))); + current_point.Y = (((current_point.Y-(PaintRect.GetTop()+2)))); + + SET_TEXTURE_COORDS +// current_point.X = (current_point.X+texture_x); +// current_point.Y = (current_point.Y+texture_y); + + if(current_point.X!=local_point.X || current_point.Y!=local_point.Y) + { + dx = local_point.X-current_point.X; + dy = local_point.Y-current_point.Y; +// offset_selected_tmaps(-dx,-dy,CurrentTexturePage); + UpdateTexture(); + local_point = current_point; + } + if(LockWorkScreen()) + { + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } + UpdateTexture(); +} + + +void PaintTab::SelectTexture(MFPoint *clicked_point) +{ + ULONG drag_flags, + update, + x_quad, + y_quad; + SLONG angle, + c0,c1, + scale, + texture_x, + texture_y, + x_offset, + y_offset, + zoom; + EdTexture temp_texture; + MFPoint current_point, + fixed_point, + local_point; + + + local_point = *clicked_point; + GlobalToLocal(&local_point); + + zoom = 256>>TextureZoom; + local_point.X = (((local_point.X-(PaintRect.GetLeft()+2))>>(8-TextureZoom))); + local_point.Y = (((local_point.Y-(PaintRect.GetTop()+2))>>(8-TextureZoom))); + + SET_TEXTURE_COORDS + local_point.X = (local_point.X+texture_x); + local_point.Y = (local_point.Y+texture_y); + + if(TextureWidth==8) + current_point.X = local_point.X&~7; + else + current_point.X = local_point.X&~15; + + if(TextureHeight==8) + current_point.Y = local_point.Y&~7; + else + current_point.Y = local_point.Y&~15; + + if(TextureFlags&FLAGS_QUADS) + c1 = 4; + else + c1 = 3; + + if(TextureFlags&FLAGS_FIXED) + { + fixed_point=current_point; + if(TextureFlags&FLAGS_QUADS) + { + update = 0; + for(c0=0;c0>TextureZoom; + current_point.X = (((current_point.X-(PaintRect.GetLeft()+2))>>(8-TextureZoom))); + current_point.Y = (((current_point.Y-(PaintRect.GetTop()+2))>>(8-TextureZoom))); + + SET_TEXTURE_COORDS + current_point.X = (current_point.X+texture_x); + current_point.Y = (current_point.Y+texture_y); + + if(current_point.X!=local_point.X || current_point.Y!=local_point.Y) + { + x_offset = local_point.X-current_point.X; + y_offset = local_point.Y-current_point.Y; + if(TextureFlags&FLAGS_QUADS) + { + CurrentTexture.U[c0] -= x_offset; + CurrentTexture.V[c0] -= y_offset; + + switch(c0) + { + case 0: + if(CurrentTexture.U[0]>=CurrentTexture.U[1]-1) + CurrentTexture.U[0]=CurrentTexture.U[1]-1; + if(CurrentTexture.V[0]>=CurrentTexture.V[2]-1) + CurrentTexture.V[0]=CurrentTexture.V[2]-1; + break; + case 1: + if(CurrentTexture.U[1]<=CurrentTexture.U[0]+1) + CurrentTexture.U[1]=CurrentTexture.U[0]+1; + if(CurrentTexture.V[1]>=CurrentTexture.V[2]-1) + CurrentTexture.V[1]=CurrentTexture.V[2]-1; + break; + case 2: + if(CurrentTexture.U[2]>=CurrentTexture.U[1]-1) + CurrentTexture.U[2]=CurrentTexture.U[1]-1; + if(CurrentTexture.V[2]<=CurrentTexture.V[0]+1) + CurrentTexture.V[2]=CurrentTexture.V[0]+1; + break; + case 3: + if(CurrentTexture.U[3]<=CurrentTexture.U[0]+1) + CurrentTexture.U[3]=CurrentTexture.U[0]+1; + if(CurrentTexture.V[3]<=CurrentTexture.V[0]+1) + CurrentTexture.V[3]=CurrentTexture.V[0]+1; + break; + } + } + + + + if(c0<2) + width=CurrentTexture.U[1]-CurrentTexture.U[0]; + else + { + width=CurrentTexture.U[3]-CurrentTexture.U[2]; + if(c0==2) + CurrentTexture.U[0]=CurrentTexture.U[2]; + + } + + TextureWidth=32; //width; //&~31; + + if(c0==1||c0==3) + { + height=CurrentTexture.V[3]-CurrentTexture.V[1]; + if(c0==1) + CurrentTexture.V[0]=CurrentTexture.V[1]; + } + else + height=CurrentTexture.V[2]-CurrentTexture.V[0]; + + TextureHeight=32; //height; //&~31; + + sx=CurrentTexture.U[0]; + sy=CurrentTexture.V[0]; + + CurrentTexture.U[1]=sx+TextureWidth; + CurrentTexture.V[1]=sy; + CurrentTexture.U[2]=sx; + CurrentTexture.V[2]=sy+TextureHeight; + CurrentTexture.U[3]=sx+TextureWidth; + CurrentTexture.V[3]=sy+TextureHeight; + + UpdateTexture(); + local_point = current_point; + } + } //end of while loop + + TextureHeight=32; //(TextureHeight+7)&~15; + TextureWidth=32; //(TextureWidth+7)&~15; + + if(TextureHeight<=0) + TextureHeight=8; + if(TextureWidth<=0) + TextureWidth=8; + + + + CurrentTexture.U[0]=(CurrentTexture.U[0]+7)&~15; + CurrentTexture.V[0]=(CurrentTexture.V[0]+7)&~15; + + sx=CurrentTexture.U[0]; + sy=CurrentTexture.V[0]; + + CurrentTexture.U[1]=sx+TextureWidth; + CurrentTexture.V[1]=sy; + CurrentTexture.U[2]=sx; + CurrentTexture.V[2]=sy+TextureHeight; + CurrentTexture.U[3]=sx+TextureWidth; + CurrentTexture.V[3]=sy+TextureHeight; + UpdateTexture(); + local_point = current_point; +#ifndef PAINT2 + if(selected_face.PEle) + { + ApplyTexture(&selected_face); + if(LockWorkScreen()) + { + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +#endif + + break; + } + } + if(!update) + { + current_point=fixed_point; + CurrentTexture.U[0] = current_point.X; + CurrentTexture.V[0] = current_point.Y; + CurrentTexture.U[1] = current_point.X+(TextureWidth-1); + CurrentTexture.V[1] = current_point.Y; + CurrentTexture.U[3] = current_point.X+(TextureWidth-1); + CurrentTexture.V[3] = current_point.Y+(TextureHeight-1); + CurrentTexture.U[2] = current_point.X; + CurrentTexture.V[2] = current_point.Y+(TextureHeight-1); + TextureFlags |= FLAGS_SHOW_TEXTURE; + UpdateTexture(); + } + + + } + else + { + x_quad = (local_point.X&(TextureWidth-1))&~((TextureWidth-1)>>1) ? 1 : 0; + y_quad = (local_point.Y&(TextureHeight-1))&~((TextureHeight-1)>>1) ? 1 : 0; + CurrentTexture.U[0] = current_point.X+(x_quad*(TextureWidth-1)); + CurrentTexture.V[0] = current_point.Y+(y_quad*(TextureHeight-1)); + CurrentTexture.U[1] = current_point.X+((1^y_quad)*(TextureWidth-1)); + CurrentTexture.V[1] = current_point.Y+(x_quad*(TextureHeight-1)); + CurrentTexture.U[2] = current_point.X+(y_quad*(TextureWidth-1)); + CurrentTexture.V[2] = current_point.Y+((1^x_quad)*(TextureHeight-1)); + TextureFlags |= FLAGS_SHOW_TEXTURE; + UpdateTexture(); + } +#ifndef PAINT2 + if(selected_face.PEle) + { + ApplyTexture(&selected_face); + if(LockWorkScreen()) + { + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +#endif + } + else + { + update = 0; + for(c0=0;c0>TextureZoom; + current_point.X = (((current_point.X-(PaintRect.GetLeft()+2))>>(8-TextureZoom))); + current_point.Y = (((current_point.Y-(PaintRect.GetTop()+2))>>(8-TextureZoom))); + + SET_TEXTURE_COORDS + current_point.X = (current_point.X+texture_x); + current_point.Y = (current_point.Y+texture_y); + + if(current_point.X!=local_point.X || current_point.Y!=local_point.Y) + { + x_offset = local_point.X-current_point.X; + y_offset = local_point.Y-current_point.Y; + if(selected_face.PEle==(struct EditMapElement*)-1 && face_is_in_list(selected_face.Face)) + { + SLONG p; + SLONG sx,sy; + SLONG flag=0; + + if(ShiftFlag) + flag=1; + + if(selected_face.Face<0) + { + sx=prim_faces3[-selected_face.Face].UV[c0][0]; + sy=prim_faces3[-selected_face.Face].UV[c0][1]; + } + else + { + sx=prim_faces4[selected_face.Face].UV[c0][0]; + sy=prim_faces4[selected_face.Face].UV[c0][1]; + } + offset_selected_tmaps(-x_offset,-y_offset,CurrentTexturePage,sx,sy,flag); + + for(p=0;pX)>=abs(MouseY-clicked_point->Y)) + drag_flags = DRAG_SHIFT_H; + else + drag_flags = DRAG_SHIFT_V; + x_offset=0; + y_offset=0; + break; + case DRAG_SHIFT_H: + CurrentTexture.U[c0] -= x_offset; + y_offset=0; + break; + case DRAG_SHIFT_V: + CurrentTexture.V[c0] -= y_offset; + x_offset=0; + break; + case DRAG_CONTROL: + CurrentTexture.U[c0] -= x_offset; + CurrentTexture.V[c0] -= y_offset; + CurrentTexture.U[hooks[c0][0]] -= x_offset; + CurrentTexture.V[hooks[c0][1]] -= y_offset; + break; + } + + + } + else + { + switch(drag_flags) + { + case DRAG_NORMAL: + CurrentTexture.U[c0] -= x_offset; + CurrentTexture.V[c0] -= y_offset; + break; + case DRAG_SHIFT_H: + CurrentTexture.U[c0] -= x_offset; + break; + case DRAG_SHIFT_V: + CurrentTexture.V[c0] -= y_offset; + break; + case DRAG_CONTROL: + CurrentTexture.U[c0] -= x_offset; + CurrentTexture.V[c0] -= y_offset; + break; + } + } + + UpdateTexture(); + local_point = current_point; +//#ifndef PAINT2 +// if(selected_face.PEle) + { + ApplyTexture(&selected_face); + if(LockWorkScreen()) + { + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +//#endif + } + } + break; + } + } + if(!update) + { + if ( + ( + TextureFlags&FLAGS_QUADS + && + check_big_point_triangle( + MouseX-PaintRect.GetLeft(),MouseY-PaintRect.GetTop(), + ClickRect[1].GetLeft(),ClickRect[1].GetTop(), + ClickRect[2].GetLeft(),ClickRect[2].GetTop(), + ClickRect[3].GetLeft(),ClickRect[3].GetTop() + ) + ) + || + check_big_point_triangle( + MouseX-PaintRect.GetLeft(),MouseY-PaintRect.GetTop(), + ClickRect[2].GetLeft(),ClickRect[2].GetTop(), + ClickRect[1].GetLeft(),ClickRect[1].GetTop(), + ClickRect[0].GetLeft(),ClickRect[0].GetTop() + ) + ) + { + drag_flags = DRAG_NORMAL; + if(Keys[KB_LSHIFT] || Keys[KB_RSHIFT]) + { + drag_flags = DRAG_SHIFT; + } + angle = 0; + scale = 1; + update = 0; + temp_texture = CurrentTexture; + x_offset = 0; + y_offset = 0; + for(c0=0;c0>TextureZoom; + current_point.X = (((current_point.X-(PaintRect.GetLeft()+2))>>(8-TextureZoom))); + current_point.Y = (((current_point.Y-(PaintRect.GetTop()+2))>>(8-TextureZoom))); + + SET_TEXTURE_COORDS + current_point.X = (current_point.X+texture_x); + current_point.Y = (current_point.Y+texture_y); + + if(current_point.X!=local_point.X || current_point.Y!=local_point.Y) + { + switch(drag_flags) + { + case DRAG_NORMAL: + x_offset -= local_point.X-current_point.X; + y_offset -= local_point.Y-current_point.Y; + break; + case DRAG_SHIFT: + if(abs(MouseX-clicked_point->X)>=abs(MouseY-clicked_point->Y)) + drag_flags = DRAG_SHIFT_H; + else + drag_flags = DRAG_SHIFT_V; + break; + case DRAG_SHIFT_H: + x_offset -= local_point.X-current_point.X; + break; + case DRAG_SHIFT_V: + y_offset -= local_point.Y-current_point.Y; + break; + } + + update = 1; + local_point = current_point; + } + if(Keys[KB_LEFT]) + { + angle = (angle-3)&2047; + update = 1; + } + else if(Keys[KB_RIGHT]) + { + angle = (angle+3)&2047; + update = 1; + } + if(Keys[KB_UP]) + { + if(scale<100) + scale++; + } + else if(Keys[KB_DOWN]) + { + if(scale>1) + scale--; + } + if(update) + { + for(c0=0;c0>16); + CurrentTexture.V[c0] = y_offset+((((temp_texture.U[c0]*SIN(angle))+(temp_texture.V[c0]*COS(angle)))*scale)>>16); + } + + UpdateTexture(); +#ifndef PAINT2 + if(selected_face.PEle) + { + ApplyTexture(&selected_face); + if(LockWorkScreen()) + { + Parent->DrawContent(); + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +#endif + update = 0; + } + } + } + } + } +} + +//--------------------------------------------------------------- + +UWORD PaintTab::ConvertFreeToFixedEle(struct TextureBits *t,SLONG *x,SLONG *y,SLONG *width,SLONG *height,SLONG *page) +{ + SLONG size; + t->X=CurrentTexture.U[0]>>3; + t->Y=CurrentTexture.V[0]>>3; + + t->Page=CurrentTexturePage; + switch(TextureWidth) + { + case 8: + size=0; + break; + case 16: + size=1; + break; + case 32: + size=2; + break; + case 64: + size=3; + break; + case 96: + size=4; + break; + case 128: + size=5; + break; + case 160: + size=6; + break; + case 192: + size=7; + break; + } + size=32; + t->Width=size; + + switch(TextureHeight) + { + case 8: + size=0; + break; + case 16: + size=1; + break; + case 32: + size=2; + break; + case 64: + size=3; + break; + case 96: + size=4; + break; + case 128: + size=5; + break; + case 160: + size=6; + break; + case 192: + size=7; + break; + } + size=32; + t->Height=size; + *x=t->X; + *y=t->Y; + *width=t->Width; + *height=t->Height; + *page=t->Page; + + return(1); +} + +void PaintTab::ConvertFixedToFree(struct TextureBits *t) +{ + UBYTE sx,sy,w,h; + + sx=t->X<<3; + sy=t->Y<<3; + w=texture_sizes[t->Width]; + h=texture_sizes[t->Height]; + + CurrentTexture.U[0]=sx; + CurrentTexture.V[0]=sy; + CurrentTexture.U[1]=sx+w; + CurrentTexture.V[1]=sy; + CurrentTexture.U[2]=sx; + CurrentTexture.V[2]=sy+h; + CurrentTexture.U[3]=sx+w; + CurrentTexture.V[3]=sy+h; + TextureWidth=32; //w; + TextureHeight=32; //w; + +} + +void PaintTab::ConvertMiniTex(struct MiniTextureBits *tex) +{ + SLONG sx,sy,w; + SLONG rot; + + sx=tex->X<<5; + sy=tex->Y<<5; + rot=tex->Rot; + w=32;//floor_texture_sizes[tex->Size]; + CurrentTextureRot=tex->Rot; + CurrentTexturePage=tex->Page; + + CurrentTexture.U[0]=sx; + CurrentTexture.V[0]=sy; + CurrentTexture.U[1]=sx+w; + CurrentTexture.V[1]=sy; + CurrentTexture.U[2]=sx; + CurrentTexture.V[2]=sy+w; + CurrentTexture.U[3]=sx+w; + CurrentTexture.V[3]=sy+w; + + for(;rot>0;rot--) + { + SLONG temp_u,temp_v; + temp_u = CurrentTexture.U[0]; + temp_v = CurrentTexture.V[0]; + CurrentTexture.U[0] = CurrentTexture.U[1]; + CurrentTexture.V[0] = CurrentTexture.V[1]; + CurrentTexture.U[1] = CurrentTexture.U[3]; + CurrentTexture.V[1] = CurrentTexture.V[3]; + CurrentTexture.U[3] = CurrentTexture.U[2]; + CurrentTexture.V[3] = CurrentTexture.V[2]; + CurrentTexture.U[2] = temp_u; + CurrentTexture.V[2] = temp_v; + + } + + TextureWidth=w; + TextureHeight=w; + + +} +UWORD PaintTab::ConvertTexToMiniTex(void) +{ + UBYTE x1, y1, x2, y2, x3, y3, x4, y4, page; + struct MiniTextureBits tex; + + tex.X=(CurrentTexture.U[0]+CurrentTexture.U[1]+CurrentTexture.U[2]+CurrentTexture.U[3])>>7; + tex.Y=(CurrentTexture.V[0]+CurrentTexture.V[1]+CurrentTexture.V[2]+CurrentTexture.V[3])>>7; + tex.Page=CurrentTexturePage; + tex.Size=0; + tex.Rot=CurrentTextureRot; + return(*((UWORD*)&tex)); +} + +BOOL PaintTab::ApplyTexture(struct EditFace *edit_face) +{ + SLONG c0; + + + if(edit_face->PEle==(struct EditMapElement*)-2) + { + + if(PaintMode==PALETTE_PAINT) + { + + } + else + { + edit_map[edit_face->MapX][edit_face->MapZ].Texture=ConvertTexToMiniTex(); + } + } + else + if(edit_face->PEle==(struct EditMapElement*)-1) + { + if(edit_face->Face<0) + { + MyUndo.ApplyPrim3(0,-edit_face->Face,&prim_faces3[-edit_face->Face]); + } + else + { + MyUndo.ApplyPrim4(0,edit_face->Face,&prim_faces4[edit_face->Face]); + } + if(PaintMode==PALETTE_PAINT) + { + if(edit_face->Face<0) + { + prim_faces3[-edit_face->Face].DrawFlags &= ~(POLY_FLAG_TEXTURED); + prim_faces3[-edit_face->Face].Col2 = CurrentColour; + } + else + { + prim_faces4[edit_face->Face].DrawFlags &= ~(POLY_FLAG_TEXTURED); + prim_faces4[edit_face->Face].Col2 = CurrentColour; + } + } + else + { + if(edit_face->Face<0) + { + prim_faces3[-edit_face->Face].DrawFlags |= POLY_FLAG_TEXTURED; + prim_faces3[-edit_face->Face].TexturePage = (UWORD)CurrentTexturePage; + for(c0=0;c0<3;c0++) + { + prim_faces3[-edit_face->Face].UV[c0][0] = CurrentTexture.U[c0]; + prim_faces3[-edit_face->Face].UV[c0][1] = CurrentTexture.V[c0]; + } + } + else + { + prim_faces4[edit_face->Face].DrawFlags |= POLY_FLAG_TEXTURED; + prim_faces4[edit_face->Face].TexturePage = (UWORD)CurrentTexturePage; + for(c0=0;c0<4;c0++) + { + prim_faces4[edit_face->Face].UV[c0][0] = CurrentTexture.U[c0]; + prim_faces4[edit_face->Face].UV[c0][1] = CurrentTexture.V[c0]; + } + if(prim_faces4[edit_face->Face].ThingIndex<0) + { +extern void set_wall_texture_info(SLONG wall,UBYTE page,EdTexture *current_texture,UBYTE type,UBYTE side); + UBYTE type=0; + if(PaintMode==STYLE_PAINT) + { + type=CurrentStyleEdit; + set_wall_texture_info(-prim_faces4[edit_face->Face].ThingIndex,(SBYTE)CurrentTexturePage,&CurrentTexture,type,(prim_faces4[edit_face->Face].FaceFlags&FACE_FLAG_TEX2)?1:0); + } + else + { + // + // apply an individual texture to a wall face + // +extern void apply_texture_to_wall_face(SLONG face,SLONG texture); + SLONG t; + SLONG x=0,y=0,c0; + + for(c0=0;c0<4;c0++) + { + x+=CurrentTexture.U[c0]; + y+=CurrentTexture.V[c0]; + } + x>>=7; + y>>=7; + + t=x+y*8+CurrentTexturePage*64; + apply_texture_to_wall_face(edit_face->Face,t); + + } + + } + } + } + return 1; + } + else if(edit_face->PEle) + { + SLONG x,y,width,height,page; +// ConvertFreeToFixedEle(&edit_face->PEle->Textures[edit_face->Face]); + ConvertFreeToFixedEle(&edit_face->PEle->Textures[edit_face->Face],&x,&y,&width,&height,&page); + return 1; + } + return 0; +} + + +void paint_texture_to_wall(SLONG wall,SLONG pos,SLONG texture) +{ + ASSERT(pos<200); + + if(wall_list[wall].Tcount<=pos) + { + SLONG size; + UBYTE *old=0; + if(wall_list[wall].Textures&&wall_list[wall].Tcount) + old=wall_list[wall].Textures; + + size=pos+1; + if(size<8) + size=8; + wall_list[wall].Textures=(UBYTE*)MemAlloc(size+1); + if(wall_list[wall].Textures==0) + { + wall_list[wall].Tcount=0; + return; + } + if(old && wall_list[wall].Tcount) + { + memcpy(wall_list[wall].Textures,old,wall_list[wall].Tcount+1); + MemFree(old); + } + wall_list[wall].Tcount=size; + + } + wall_list[wall].Textures[pos]=texture; +} +void paint_texture_to_wall2(SLONG wall,SLONG pos,SLONG texture) +{ + ASSERT(pos<200); + + if(wall_list[wall].Tcount2<=pos) + { + SLONG size; + UBYTE *old=0; + if(wall_list[wall].Textures2 && wall_list[wall].Tcount2) + old=wall_list[wall].Textures2; + + size=pos+1; + if(size<8) + size=8; + wall_list[wall].Textures2=(UBYTE*)MemAlloc(size+1); + if(wall_list[wall].Textures2==0) + { + wall_list[wall].Tcount2=0; + return; + } + if(old && wall_list[wall].Tcount2) + { + memcpy(wall_list[wall].Textures2,old,wall_list[wall].Tcount2+1); + MemFree(old); + } + wall_list[wall].Tcount2=size; + + } + wall_list[wall].Textures2[pos]=texture; +} + +void remove_painted_textures(void) +{ + SLONG c0; + for(c0=0;c0>=2; + my>>=2; + mz>>=2; + + if (wall > 0) + { + struct MapThing *p_mthing; + SLONG thing; + + storey = wall_list[wall].StoreyHead; + building = storey_list[storey].BuildingHead; + thing = building_list[building].ThingIndex; + p_mthing=TO_MTHING(thing); + + mx+=p_mthing->X; + my+=p_mthing->Y; + mz+=p_mthing->Z; + + + } + + // + // find the start point for this wall, storey or another wall + // + storey=wall_list[wall].StoreyHead; + if(storey_list[storey].WallHead==wall) + { + head=-storey; + x1=storey_list[storey].DX; + z1=storey_list[storey].DZ; + } + else + { + SLONG index; + index=storey_list[storey].WallHead; + while(index) + { + if(wall_list[index].Next==wall) + { + head=index; + x1=wall_list[index].DX; + z1=wall_list[index].DZ; + break; + } + + index=wall_list[index].Next; + } + + } + + ASSERT(head); + + dx=mx-x1; + dz=mz-z1; + + dist=Root(dx*dx+dz*dz); + dist>>=8; + + // + // dist is now the face number along this facet to paint + // +/* + if(head<0) + { + paint_texture_to_storey(wall,dist,texture); + } + else + */ + { + + if(prim_faces4[face].FaceFlags&FACE_FLAG_TEX2) + { + // this wall is double sided and so uses different texture info + paint_texture_to_wall2(wall,dist,texture); + } + else + { + paint_texture_to_wall(wall,dist,texture); + } + } + + + +} +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/Poly.cpp b/fallen/Editor/Source/Poly.cpp new file mode 100644 index 0000000..9dccd08 --- /dev/null +++ b/fallen/Editor/Source/Poly.cpp @@ -0,0 +1,5863 @@ +#include "editor.hpp" +#include "game.h" +//#include "poly.h" +//#include "edit.h" +//#include "math.h" + +/****************************************************************************/ +/* DRAW.C - All drawing to the screen should be done here. */ +/****************************************************************************/ + +//assume anti clockwise + +UWORD *tmaps[50]; +UBYTE *pals[50]; + +//UBYTE tmap[256*256]; +//UBYTE tmap2[256*256]; +UBYTE fade_tables[256*65]; +UBYTE brightness[256]; +UBYTE mix_map[256*256]; + +SLONG div_table[65536]; //65536/x +UWORD yc_to_555[8][256*64]; +ULONG yc_to_888[65536]; +UWORD pal_to_16[256]; +UWORD filter_is[64]; +UBYTE filter_age[64]; + +// WORD/UWORD +#define QDIV(x,d) (d<0? ((-x*div_table[-d])>>16) : ((x*div_table[d])>>16) ) +#define QDIV64(x,d) (d<0? ((-MUL64(x,div_table[-d]))) : ((MUL64(x,div_table[d]))) ) + +//#define DEBUG_SPAN 1 +#define Z_SORT 1 + +static SLONG ASMstep_tx,ASMstep_ty,ASMstep_shade; +static SLONG ASMtx,ASMty,ASMshade; +static UWORD *ASMtext_page; +static UWORD *ASMpal_address; +static UWORD *ASMfade_page; +static SLONG ASMCol; +struct PolyInfo poly_info; + + +struct PolyParameters +{ + SLONG Y; + SLONG LeftX; + SLONG RightX; + SLONG LeftShade; + SLONG LeftTextX; + SLONG LeftTextY; + SLONG StepShade; + SLONG StepTextX; + SLONG StepTextY; +}; + +struct FloatPolyParameters +{ + SLONG Y; + SLONG LeftX; + SLONG RightX; + SLONG LeftShade; + + float FLeftTextX; + float FLeftTextY; + SLONG StepShade; + float FStepTextX; + float FStepTextY; + float Q; + float StepQ; + +}; + +struct Boint +{ + SLONG RightX; + SLONG LeftX; + SLONG LeftTX; + SLONG LeftTY; + SLONG LeftShade; + SLONG LeftZ; + SLONG RightZ; + SLONG RightTX; + SLONG RightTY; + SLONG RightShade; + struct Boint *PNext; + SLONG DrawFlags; +// SLONG Y; +}; + +struct Boint *z_spans[1000]; +// +// z_buffer off +// +#define MAX_BOINT 20000 + +struct Boint boint_pool[MAX_BOINT]; +UWORD next_boint=1; +struct Boint *current_boint=&boint_pool[0]; + +SLONG debug_y=200; +SLONG count_find=0,count_insert=0,count_chop_lhs=0,count_chop_rhs=0; + +inline ULONG span_overlaps(struct Boint *new_span,struct Boint *old_span) +{ +// if(new_span->LeftX==old_span->LeftX&&new_span->RightX==old_span->RightX) +// return(2); + + if(new_span->LeftX>=old_span->RightX) +// if(new_span->RightX<=old_span->LeftX||new_span->LeftX>=old_span->RightX) + return(0); + else + return(1); +/* + SLONG hw1,hw2,mx1,mx2; + hw1=(new_span->RightX-new_span->LeftX)>>1; + hw2=(old_span->RightX-old_span->LeftX)>>1; + + mx1=new_span->LeftX+hw1; + mx1=new_span->LeftX+hw1; +*/ +} + +inline SLONG spans_might_intersect(struct Boint *new_span,struct Boint *old_span) +{ +/* + if(new_span->LeftZRightZ) + return(1); //new behind old + else + return(2); //new behind old +*/ + + if( (new_span->RightZ<=old_span->LeftZ&&new_span->RightZ<=old_span->RightZ) && + (new_span->LeftZ <=old_span->LeftZ&&new_span->LeftZ <=old_span->RightZ)) + return(1); //new behind old + + if( (new_span->RightZ>=old_span->LeftZ&&new_span->RightZ>=old_span->RightZ) && + (new_span->LeftZ >=old_span->LeftZ&&new_span->LeftZ >=old_span->RightZ)) + return(2); //new infront of old + return(0); +} + + +inline SLONG calc_intersection(struct Boint *new_span,struct Boint *old_span) +{ + SLONG r,s; + SLONG div; + + r=(new_span->LeftZ-old_span->LeftZ)*(old_span->RightX-old_span->LeftX)-(new_span->LeftX-old_span->LeftX)*(old_span->RightZ-old_span->LeftZ); + div=( (new_span->RightX-new_span->LeftX)*(old_span->RightZ-old_span->LeftZ)-(new_span->RightZ-new_span->LeftZ)*(old_span->RightX-old_span->LeftX) ); + if(div==0) + return(-1); + r=(r<<16)/div; + + s=(new_span->LeftZ-old_span->LeftZ)*(new_span->RightX-new_span->LeftX)-(new_span->LeftX-old_span->LeftX)*(new_span->RightZ-new_span->LeftZ); + s=(r<<16)/div; + + if(r>0 && r<(1<<16) && s>0 && s<(1<<16)) + { + return(r); + } + else + return(-1); +} + +inline void clip_lhs_span(struct Boint *chopee,SLONG x) +{ + SLONG ratio; + count_chop_lhs++; +// if(debug_y==chopee->Y) +// LogText(" Clip LHS Span x %d %d new X %d \n",chopee->LeftX,chopee->RightX,x); + ratio=((x-chopee->LeftX)<<16)/ (chopee->RightX-chopee->LeftX); +#ifdef DEBUG_SPAN + { + SLONG c0; + if(chopee->LeftXLeftX;c0Y,2); + + } +#endif + +// chopee->LeftShade= ((((chopee->RightShade-chopee->LeftShade)>>16)*ratio)>>0)+chopee->LeftShade; +// chopee->LeftTX= ((((chopee->RightTX-chopee->LeftTX)>>16)*ratio)>>0)+chopee->LeftTX; +// chopee->LeftTY= ((((chopee->RightTY-chopee->LeftTY)>>16)*ratio)>>0)+chopee->LeftTY; + + + chopee->LeftShade= MUL64((chopee->RightShade-chopee->LeftShade),ratio)+chopee->LeftShade; + chopee->LeftTX= MUL64((chopee->RightTX-chopee->LeftTX),ratio)+chopee->LeftTX; + chopee->LeftTY= MUL64((chopee->RightTY-chopee->LeftTY),ratio)+chopee->LeftTY; + chopee->LeftZ= MUL64((chopee->RightZ-chopee->LeftZ),ratio)+chopee->LeftZ; + chopee->LeftX= x; +} + +inline void clip_rhs_span(struct Boint *chopee,SLONG x) +{ + SLONG ratio; + count_chop_rhs++; + // if(debug_y==chopee->Y) + // LogText(" Clip RHS Span x %d %d new X %d \n",chopee->LeftX,chopee->RightX,x); + + ratio=((x-chopee->LeftX)<<16)/ (chopee->RightX-chopee->LeftX); +#ifdef DEBUG_SPAN + { + SLONG c0; + if(xRightX) + for(c0=x;c0RightX;c0++) + if(c0&1) + DrawPixelC(c0,chopee->Y,1); + + } +#endif + + chopee->RightShade= MUL64((chopee->RightShade-chopee->LeftShade),ratio)+chopee->LeftShade; + chopee->RightTX= MUL64((chopee->RightTX-chopee->LeftTX),ratio)+chopee->LeftTX; + chopee->RightTY= MUL64((chopee->RightTY-chopee->LeftTY),ratio)+chopee->LeftTY; + chopee->RightZ= MUL64((chopee->RightZ-chopee->LeftZ),ratio)+chopee->LeftZ; + chopee->RightX = x; +} + +extern void insert_span(struct Boint *span,struct Boint **head); + +void do_nowt(void) +{ + +} + +#define check_spans(x) {} +// {check_spans2(x);do_nowt();} + + + + +ULONG check_spans2(struct Boint **head) +{ +/* + struct Boint *p=*head; + struct Boint *prev=0; + if(debug_y!=1000) + return(0); + while(p) + { + if( (prev) && p->LeftX<=prev->LeftX) + { + + LogText(" span error %d \n",p->Y); + debug_y=p->Y; + return(1); + } + prev=p; + p=p->PNext; + } + return(0); +*/ + return(0); +} +inline void delete_span(struct Boint *span,struct Boint **head,struct Boint *prev) +{ + if(prev) + { + prev->PNext=span->PNext; + } + else + *head=span->PNext; +} + +inline void sort_add_span(struct Boint *span,struct Boint **head,struct Boint *prev) +{ + struct Boint *p=*head; +// struct Boint *prev=0; +// if(debug_y==span->Y) +// LogText(" Sort Add Span x %d %d z %d %d \n",span->LeftX,span->RightX,span->LeftZ,span->RightZ); + if(prev) + { + + if(prev->LeftX<=span->LeftX) + { + p=prev->PNext; + + + } + else + prev=0; + } + + while(p) + { + count_insert++; + if(span->LeftX<=p->LeftX) + { + if(prev) + { + span->PNext=prev->PNext; + prev->PNext=span; + } + else + { + span->PNext=*head; + *head=span; + } + return; + } + prev=p; + p=p->PNext; + } + if(prev) + { + span->PNext=prev->PNext; + prev->PNext=span; + } + else + { + span->PNext=*head; + *head=span; + } +} + + + +inline ULONG chop_span(struct Boint **head,struct Boint *prev,struct Boint *chopee,struct Boint *choper,UBYTE chop_new) +{ + if(choper->RightX>=chopee->RightX) + { + + if(choper->LeftX<=chopee->LeftX) + { +// remove chopee span from link list +// if(debug_y==chopee->Y) +// LogText(" remove chopee completely %d \n",chop_new); +#ifdef DEBUG_SPAN + { + SLONG c0; + if(chopee->LeftXRightX) + for(c0=chopee->LeftX;c0RightX;c0++) + DrawPixelC(c0,chopee->Y,1); + + } +#endif + if(chop_new) + return(1); + else + return(-1); + } + else + { + //remove rhs of chopee at point choper->LeftX + if(chopee->LeftX==choper->LeftX) + { +// if(debug_y==chopee->Y) +// LogText(" remove chopee completely bodge %d \n",chop_new); + if(chop_new) + return(1); + else + return(-1); + + } + else + { + +// if(debug_y==chopee->Y) +// LogText(" remove RHS1 %d",chop_new); + clip_rhs_span(chopee,choper->LeftX); + } + } + } + else + { + if(choper->LeftX>chopee->LeftX) + { + // remove all of choper from middle of chopee, splitting chopee into 2 +#ifdef DEBUG_SPAN + { + SLONG c0; + if(choper->LeftXRightX) + for(c0=choper->LeftX;c0RightX;c0++) + DrawPixelC(c0,choper->Y,2); + + } +#endif + + if(!chop_new) + { +// if(debug_y==chopee->Y) +// LogText(" new one cuts whole in old one \n"); + //new one cuts middle out of one that existed + if(next_boint++>MAX_BOINT) + return(0); + *current_boint=*chopee; + clip_lhs_span(current_boint,choper->RightX); + clip_rhs_span(chopee,choper->LeftX); + current_boint->PNext=chopee->PNext; + chopee->PNext=choper; + choper->PNext=current_boint; +// chopee->PNext=current_boint; + + + next_boint++; + current_boint++; + return(1); + } + else + { + // new span needs to be split +// if(debug_y==chopee->Y) +// LogText(" new span has chuck removed from middle \n"); + + +//this appears to cause sort errors!!!! + + + if(next_boint++>MAX_BOINT) + return(0); + *current_boint=*chopee; + + clip_rhs_span(chopee,choper->LeftX); + clip_lhs_span(current_boint,choper->RightX); + sort_add_span(chopee,head,prev); //span split, lhs sort added , RHS can be bolted onto thing that split us + +// current_boint->PNext=choper->PNext; +// choper->PNext=current_boint++; + next_boint++; + insert_span(current_boint++,head); //ooo brave bloke doing a recursive add into a linked list + return(1); + + } + + + } + else + { + //remove lhs of chopee at point choper->LeftX + clip_lhs_span(chopee,choper->RightX); + } + + } + return(0); +} + +ULONG span_exists(struct Boint *span,struct Boint **head) +{ + struct Boint *p; + SLONG count; + p=*head; + count=0; + while(p&&count++<100) + { + if(p==span) + { + count=100; + return(1); + } + p=p->PNext; + } + return(0); + +} + +void show_line(struct Boint **head,CBYTE *str) +{ + struct Boint *p; + p=*head; + LogText("%s\n",str); + while(p) + { + LogText("%x X%d..%d Z %d..%d\n",p,p->LeftX,p->RightX,p->LeftZ,p->RightZ); + p=p->PNext; + } + +} + + +void insert_span(struct Boint *span,struct Boint **head) +{ + struct Boint *p,*prev=0; + SLONG count; + struct Boint *insert_here=0; + + span->PNext=0; +/* + if(debug_y==span->Y) + { + + LogText(" INSERT SPAN %x X%d %d Z %d..%d\n",span,span->LeftX,span->RightX,span->LeftZ,span->RightZ); + show_line(head,"RASTER BEFORE"); + } +*/ + if(span->LeftX>=span->RightX) + { +// span->RightX=span->LeftX; + goto exit; + } + p=*head; + if(p==0) + { + *head=span; + goto exit; + } +#ifdef Z_SORT + count=0; + while(p) //&&count++<100) + { + + count_find++; +// if(span->LeftX<=p->LeftX) +// insert_here=prev; + if(span->RightX<=p->LeftX) + { + + sort_add_span(span,head,prev); +/* + + if(insert_here) + { + span->PNext=insert_here->PNext; + insert_here->PNext=span; + } + else + { + span->PNext=*head; + *head=span; + } +*/ + goto exit; + } + + if(span_overlaps(span,p)) + { + SLONG done=0,type; + //new span overlaps this one, the result will be either new one will lose a piece + //or old one loses a piece, loseing a piece may come from the middle results in a boint split into 2 + if((type=spans_might_intersect(span,p))==0) + { +/* + SLONG t; + if( (t=calc_intersection(span,p))!=-1) + { + //it intersects 0LeftZ+span->RightZ)>>1 < (p->LeftZ+p->RightZ)>>1) + type=1; + else + type=2; + + } + + } + + if(!done) + { + if(type==1) + { //new span is behind this one + if(chop_span(head,prev,span,p,1)) //chop some off new span + { + //none of this span can be seen + goto exit; + } + } + else + { //new span is in front of this one + type=chop_span(head,prev,p,span,0); //chop some off old span + if(type==-1) //chop some off old span + { + //need to remove current span from list + if(prev) + { + prev->PNext=p->PNext; + goto skip_calc_prev; + } + else + { + *head=p->PNext; + goto skip_calc_prev; + } + + } + if(type==1) //span has been imbeded in the middle of this one + goto exit; + } + } + + + } + prev=p; +skip_calc_prev:; + p=p->PNext; + } +#endif +/* + if(insert_here) + { + span->PNext=insert_here->PNext; + insert_here->PNext=span; + } + else + { + sort_add_span(span,head); //,prev); + // span->PNext=*head; +// *head=span; + } +*/ + if(prev) + { +// prev->PNext=span; +// span->PNext=0; //prev->PNext; + sort_add_span(span,head,prev); + } + else + { + span->PNext=*head; + *head=span; + } +exit:; +// if(debug_y==span->Y) +// show_line(head,"RASTER AFTER"); +// span->PNext=*head; +// *head=span; +} + + + + +SLONG FileSaveAt(CBYTE *name,UBYTE *ptr,ULONG size) +{ + MFFileHandle handle = FILE_OPEN_ERROR; + handle=FileCreate(name,1); + if(handle!=FILE_OPEN_ERROR) + { + FileWrite(handle,(UBYTE*)ptr,size); + FileClose(handle); + return(0); + } + return(-1); +} + +extern UBYTE palette[768]; + +void make_555_table(void) +{ + UBYTE pal_no; + SLONG col,bright; + SLONG r,g,b; + UBYTE *pal; +// pal=palette; + + for(pal_no=0;pal_no<8;pal_no++) + { + pal=pals[pal_no]; + for (col=0;col<256 ;col++ ) + { + for (bright=0;bright<64;bright++ ) + { + r=pal[(col*3)+0]; + g=pal[(col*3)+1]; + b=pal[(col*3)+2]; + + r=(r*bright>>5); + g=(g*bright>>5); + b=(b*bright>>5); + if(r>255) + r=255; + if(g>255) + g=255; + if(b>255) + b=255; + + + yc_to_555[pal_no][col+(bright<<8)]=the_display.GetFormattedPixel(r,g,b); //((r>>3)<<11)|((g>>2)<<5)|((b>>3)<<0); + //yc_to_555[pal_no][col+(bright<<8)]=((r>>3)<<11)|((g>>2)<<5)|((b>>3)<<0); + //yc_to_888[pal_no][col+(bright<<6)]=(r<<16)|(g<<8)|(b); //0xf800; //((b>>3)<<10)|((r>>3)<<5)|((g>>3)<<0); + } + } + } + pal=pals[0]; + for(col=0;col<256 ;col++ ) + { + r=pal[(col*3)+0]; + g=pal[(col*3)+1]; + b=pal[(col*3)+2]; + + pal_to_16[col]=the_display.GetFormattedPixel(r,g,b); + + } +} + +void draw_fader(void) +{ + UWORD *ptr,*ptr2; + SLONG x,y; + + ptr=(UWORD*)WorkScreen; + for(x=0;x<256;x++) + for(y=0;y<64;y++) + { + ptr[y*320+x]=yc_to_555[0][x+y*256]; + } +} + +void init_poly_system(void) +{ + SLONG c0; +// memset(boint_pool,0,sizeof(struct Boint)*(MAX_BOINT-1)); + for(c0=1;c0<1<<16;c0++) + { + div_table[c0]=(1<<16)/c0; + } + make_555_table(); + memset(&filter_is[0],0xff,32); +} + +void init_tmap(void) +{ +/* + FileLoadAt("data/tex01.dat",tmap); + tmaps[0]=tmap; + tmaps[1]=tmap; + tmaps[2]=tmap; + tmaps[3]=tmap; +*/ +} + +extern SLONG find_colour(UBYTE *pal,SLONG r,SLONG g,SLONG b); +/* +SLONG find_colour(UBYTE *pal,SLONG r,SLONG g,SLONG b) +{ + SLONG found=-1,dist=0x7fffffff,c0,dist2,tr,tg,tb; + for(c0=0;c0<256;c0++) + { + tr=*pal++; + tg=*pal++; + tb=*pal++; + + tr-=r; + tg-=g; + tb-=b; + + dist2=abs(tr*tr)+abs(tg*tg)+abs(tb*tb); + if(dist2>1; + g=(g+g1)>>1; + b=(b+b1)>>1; + if(r>255) + r=255; + if(g>255) + g=255; + if(b>255) + b=255; + mix_map[col2*256+col1]=find_colour(pal,r,g,b); + } + } + FileSaveAt("data/mix.dat",mix_map,256*256); + } +} + +void make_fade_table(UBYTE *pal) +{ + SLONG col,bright,r,g,b,temp_bright; + UBYTE *p; + if(FileExists("data/fade.dat")) + { + FileLoadAt("data/fade.dat",fade_tables); + } + else + { + for(bright=0;bright<64;bright++) + { + p=pal; + for(col=0;col<256;col++) + { + r=*p++; + g=*p++; + b=*p++; + + if(bright<=32) + temp_bright=bright; + else + temp_bright=((bright-32)<<1)+32; + + if(bright==32) + { + r++; + } + + r=(r*temp_bright)>>5; + g=(g*temp_bright)>>5; + b=(b*temp_bright)>>5; + if(r>255) + r=255; + if(g>255) + g=255; + if(b>255) + b=255; + fade_tables[bright*256+col]=find_colour(pal,r,g,b); + } + } + FileSaveAt("data/fade.dat",fade_tables,64*256); + } +} + +UWORD is_it_clockwise(const struct MfEnginePoint *point1,const struct MfEnginePoint *point2,const struct MfEnginePoint *point3) +{ + SLONG z; + SLONG vx,vy,wx,wy; + + vx=point2->X-point1->X; + wx=point3->X-point2->X; + vy=point2->Y-point1->Y; + wy=point3->Y-point2->Y; + z=vx*wy-vy*wx; + + if(z>0) + return 1; + else + return 0; +} + +// eax= Shade.0-16|-|TexY 16-24 +// ebx= TexX.0-16|-|Shade16-24 +// ecx= TexY.0-16|-|TexX 16-24 + +// " mov eax,ASMstep_shade"\ +// " mov ebx,ASMstep_tx"\ +// " mov ecx,ASMstep_ty"\ +// ASMtx=start_text_x; + +#ifdef _MSC_VER +void RENDER_SETUP(UBYTE *,SLONG,SLONG,SLONG,SLONG) +{ + +} +#else +void RENDER_SETUP(UBYTE *,SLONG,SLONG,SLONG,SLONG); +#pragma aux RENDER_SETUP =\ + " rol eax,16"\ + " rol ebx,16"\ + " rol ecx,16"\ + " mov dl,cl"\ + " mov cl,bl"\ + " mov bl,al"\ + " mov al,dl"\ + " mov ASMstep_shade,eax"\ + " mov ASMstep_tx,ebx"\ + " mov ASMstep_ty,ecx"\ + " mov eax,ASMshade"\ + " mov ebx,ASMtx"\ + " mov ecx,ASMty"\ + parm[edi][esi][eax][ebx][ecx]\ + modify[eax ebx ecx edx] +// value[eax] +#endif + +#ifdef _MSC_VER +void RENDER_SETUP2(void) +{ + +} +#else +void RENDER_SETUP2(void); +#pragma aux RENDER_SETUP2 =\ + " rol eax,16"\ + " rol ebx,16"\ + " rol ecx,16"\ + " mov dl,cl"\ + " mov cl,bl"\ + " mov bl,al"\ + " mov al,dl"\ + " xor edx,edx"\ + modify[eax ebx ecx edx] +#endif + +#ifdef _MSC_VER +void RENDER_MSC_GT(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page + +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dl,[ebp+edx] + inc edi + mov dh,bl + mov dl,fade_tables[edx] + mov [edi],dl + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} + +void RENDER_GO_GT(void) +{ +} + +#else +void RENDER_GO_GT(void); +#pragma aux RENDER_GO_GT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " mov dl,[ebp+edx]"\ + " inc edi"\ + " mov dh,bl"\ + " mov dl,fade_tables[edx]"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx] +// value[eax] +#endif + +#ifdef _MSC_VER +void RENDER_GO_COL(void) +{ + +} +#else +void RENDER_GO_COL(void); +#pragma aux RENDER_GO_COL =\ + " mov ecx,ASMCol"\ + modify[ecx] +#endif + +#ifdef _MSC_VER +void RENDER_MSC_G(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + +//setup + rol eax,16 + mov bl,al + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov eax,ASMshade + +//setup2 + rol eax,16 + rol ebx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + mov ecx,ASMCol +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + mov dh,al + inc edi + mov dh,bl + mov dl,cl + mov dl,fade_tables[edx] + mov [edi],dl + dec esi + jnz lp + pop esi + pop edi + + } +} + +void RENDER_MSC_G16(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + +//setup + rol eax,16 + mov bl,al + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov eax,ASMshade + +//setup2 + rol eax,16 + rol ebx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + mov ecx,ASMCol +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + mov dh,al + add edi,2 + mov dh,bl + mov dl,cl + mov dx,yc_to_555[edx*2] + mov [edi],dx + dec esi + jnz lp + pop esi + pop edi + + } +} + +#else +SLONG RENDER_GO_G(void); +#pragma aux RENDER_GO_G =\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " inc edi"\ + " mov ch,bl"\ + " mov dl,fade_tables[ecx]"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + + +#ifdef _MSC_VER +void RENDER_MSC_50F(UBYTE *param_ptr_screen,SLONG param_width) +{ + + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov eax,param_width +//setup + mov ecx,ASMCol + +//setup2 + +// do render loop +lp: + inc edi + mov ch,[edi] +// mov [edi],cl + mov dl,mix_map[ecx] + mov [edi],dl + dec eax + jnz lp + pop esi + pop edi + } +} +#else +SLONG RENDER_GO_50F(void); +#pragma aux RENDER_GO_50F =\ + " lp:"\ + " inc edi"\ + " mov [edi],cl"\ + " dec esi"\ + " jnz lp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + + +#ifdef _MSC_VER +void RENDER_MSC_F(UBYTE *param_ptr_screen,SLONG param_width) +{ + + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov eax,param_width +//setup + mov ecx,ASMCol + +//setup2 + +// do render loop +lp: + inc edi + mov [edi],cl + dec eax + jnz lp + pop esi + pop edi + + } +} +void RENDER_MSC_F16(UBYTE *param_ptr_screen,SLONG param_width) +{ + + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov eax,param_width +//setup + mov ecx,ASMCol + +//setup2 + +// do render loop +lp: + add edi,2 + mov [edi],cx + dec eax + jnz lp + pop esi + pop edi + + } +} +#else +SLONG RENDER_GO_F(void); +#pragma aux RENDER_GO_F =\ + " lp:"\ + " inc edi"\ + " mov [edi],cl"\ + " dec esi"\ + " jnz lp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + + +#ifdef _MSC_VER +void RENDER_MSC_T16(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + xor eax,eax + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp +// mov ebp,ASMtext_page + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dx,[ebp+edx*2] + add edi,2 +// mov dh,0 + //mov dh,bl + //mov dl,fade_tables[edx] +// mov ebp,ASMpal_address +// mov dx,[ebp+edx*2] + mov [edi],dx + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} +SLONG RENDER_GO_T16(void) +{ + return 0; +} +#endif + +#ifdef _MSC_VER + +void RENDER_MSC_GT16(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dx,[ebp+edx*2] + add edi,2 +// mov dh,bl +// mov ebp,ASMfade_page +// mov dx,[ebp+edx*2] + mov [edi],dx + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} + +void RENDER_MSC_TGT16(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov ebp,ASMtext_page + and edx,0x1f1f + mov dx,[ebp+edx*2] + add edi,2 +// mov dh,bl +// mov dx,yc_to_555[edx*2] +// mov ebp,ASMfade_page +// mov dx,[ebp+edx*2] + mov [edi],dx + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} + +SLONG RENDER_GO_GT16(void) +{ + return 0; +} +#else +SLONG RENDER_GO_GT16(void); +#pragma aux RENDER_GO_GT16 =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " mov dl,[ebp+edx]"\ + " add edi,2"\ + " mov dh,bl"\ + " mov dx,yc_to_555[edx*2]"\ + " mov [edi],dx"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +SLONG RENDER_GO_GT32(void) +{ + return 0; +} +#else +SLONG RENDER_GO_GT32(void); +#pragma aux RENDER_GO_GT32 =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " xor edx,edx"\ + " mov dh,al"\ + " mov dl,cl"\ + " mov dl,[ebp+edx]"\ + " add edi,4"\ + " mov dh,bl"\ + " mov edx,yc_to_888[edx*4]"\ + " mov [edi],edx"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +SLONG RENDER_GO_TGT(void) +{ + return 0; +} +#else +SLONG RENDER_GO_TGT(void); +#pragma aux RENDER_GO_TGT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + "lp: add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " and dx,0x1f1f"\ + " mov dl,[ebp+edx]"\ + " inc edi"\ + " mov dh,bl"\ + " mov dl,fade_tables[edx]"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] + +#endif + +#ifdef _MSC_VER +SLONG RENDER_GO_TT(void) +{ + return 0; +} +#else +SLONG RENDER_GO_TT(void); +#pragma aux RENDER_GO_TT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + "lp: add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " and dx,0x1f1f"\ + " mov dl,[ebp+edx]"\ + " inc edi"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +void RENDER_MSC_50GT(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dl,[ebp+edx] + inc edi + mov dh,bl + mov dl,fade_tables[edx] + mov dh,[edi] + mov dl,mix_map[edx] + mov [edi],dl + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} +SLONG RENDER_GO_50GT(void) +{ + return 0; +} +#else +SLONG RENDER_GO_50GT(void); +#pragma aux RENDER_GO_50GT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + "lp: add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " mov dl,[ebp+edx]"\ + " inc edi"\ + " mov dh,bl"\ + " mov dl,fade_tables[edx]"\ + " mov dh,[edi]"\ + " mov dl,mix_map[edx]"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +void RENDER_MSC_50T(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + xor eax,eax + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dl,[ebp+edx] + inc edi + mov dh,[edi] + mov dl,mix_map[edx] + mov [edi],dl + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} +SLONG RENDER_GO_50T(void) +{ + return 0; +} +#else +SLONG RENDER_GO_50T(void); +#pragma aux RENDER_GO_50T =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + "lp: add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " mov dl,[ebp+edx]"\ + " inc edi"\ + " mov dh,[edi]"\ + " mov dl,mix_map[edx]"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +SLONG RENDER_GO_50MGT(void) +{ + return 0; +} +#else +SLONG RENDER_GO_50MGT(void); +#pragma aux RENDER_GO_50MGT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " inc edi"\ + " mov dl,[ebp+edx]"\ + " or dl,dl "\ + " jz skip"\ + " mov dh,bl"\ + " mov dl,fade_tables[edx]"\ + " mov dh,[edi]"\ + " mov dl,mix_map[edx]"\ + " mov [edi],dl"\ + "skip: dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +void RENDER_MSC_MGT(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dl,[ebp+edx] + inc edi + or dl,dl + jz skip + mov dh,bl + mov dl,fade_tables[edx] + mov [edi],dl +skip: + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} + +void RENDER_MSC_MGT16(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_shade,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + mov eax,param_step_shade + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + + mov dx,[ebp+edx*2] + add edi,2 +// mov dh,bl + or dx,dx + jz skip +// mov dx,yc_to_555[edx*2] +// mov ebp,ASMfade_page +// mov dx,[ebp+edx*2] + mov [edi],dx + +/* + mov dl,[ebp+edx] + add edi,2 + or dl,dl + jz skip + mov dh,bl + mov dx,yc_to_555[edx*2] + mov [edi],dx +*/ +skip: + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} + +#else +SLONG RENDER_GO_MGT(void); +#pragma aux RENDER_GO_MGT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " inc edi"\ + " mov dl,[ebp+edx]"\ + " or dl,dl "\ + " jz skip"\ + " mov dh,bl"\ + " mov dl,fade_tables[edx]"\ + " mov [edi],dl"\ + "skip: dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +void RENDER_MSC_MT(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + xor eax,eax + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dl,[ebp+edx] + inc edi + or dl,dl + jz skip + mov [edi],dl +skip: + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} + +void RENDER_MSC_MT16(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + xor eax,eax + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + + + mov dx,[ebp+edx*2] + add edi,2 + or dx,dx + jz skip +// mov dh,0 + +// mov ebp,ASMpal_address +// mov dx,[ebp+edx*2] + mov [edi],dx + + +skip: + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} +#else +SLONG RENDER_GO_MT(void); +#pragma aux RENDER_GO_MT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " inc edi"\ + " mov dl,[ebp+edx]"\ + " or dl,dl "\ + " jz skip"\ + " mov [edi],dl"\ + "skip: dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +void RENDER_MSC_T(UBYTE *param_ptr_screen,SLONG param_width,SLONG param_step_texx,SLONG param_step_texy) +{ + // RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + __asm + { + push edi + push esi + mov edi,param_ptr_screen + mov esi,param_width + xor eax,eax + mov ebx,param_step_texx + mov ecx,param_step_texy +//setup + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + mov ASMstep_shade,eax + mov ASMstep_tx,ebx + mov ASMstep_ty,ecx + mov eax,ASMshade + mov ebx,ASMtx + mov ecx,ASMty + +//setup2 + rol eax,16 + rol ebx,16 + rol ecx,16 + mov dl,cl + mov cl,bl + mov bl,al + mov al,dl + xor edx,edx + +// do render loop + push ebp + mov ebp,ASMtext_page +lp: + add eax,ASMstep_shade + adc ebx,ASMstep_tx + adc ecx,ASMstep_ty + adc eax,0 + mov dh,al + mov dl,cl + mov dl,[ebp+edx] + inc edi + //mov dh,bl + //mov dl,fade_tables[edx] + mov [edi],dl + dec esi + jnz lp + pop ebp + pop esi + pop edi + + } +} +SLONG RENDER_GO_T(void) +{ + return 0; +} +#else +SLONG RENDER_GO_T(void); +#pragma aux RENDER_GO_T =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " mov dl,[ebp+edx]"\ + " inc edi"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +SLONG RENDER_GO_AMT(void) +{ + return 0; +} +#else +SLONG RENDER_GO_AMT(void); +#pragma aux RENDER_GO_AMT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " inc edi"\ + " mov dh,[ebp+edx]"\ + " or dh,dh "\ + " jz skip"\ + " mov dl,[edi]"\ + " mov dl,fade_tables[edx]"\ + " mov [edi],dl"\ + "skip: dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + +#ifdef _MSC_VER +SLONG RENDER_GO_AT(void) +{ + return 0; +} +#else +SLONG RENDER_GO_AT(void); +#pragma aux RENDER_GO_AT =\ + " push ebp"\ + " mov ebp,ASMtext_page"\ + " lp:"\ + " add eax,ASMstep_shade"\ + " adc ebx,ASMstep_tx"\ + " adc ecx,ASMstep_ty"\ + " adc eax,0"\ + " mov dh,al"\ + " mov dl,cl"\ + " mov dh,[ebp+edx]"\ + " inc edi"\ + " mov dl,[edi]"\ + " mov dl,fade_tables[edx]"\ + " mov [edi],dl"\ + " dec esi"\ + " jnz lp"\ + " pop ebp"\ + modify[edi esi eax ebx ecx edx]\ + value[eax] +#endif + + +//inline void SCAN_LINE_GT(const SLONG y,SLONG lx,SLONG rx,SLONG s1,SLONG shade_step,SLONG tx1,SLONG textx_step,SLONG ty1,SLONG texty_step) +//const SLONG y,SLONG lx,SLONG rx,SLONG s1,SLONG shade_step,SLONG tx1,SLONG textx_step,SLONG ty1,SLONG texty_step) +#define POLY_TEXT_SHIFT 7 + + + + +void PSCAN_LINE_GT(struct FloatPolyParameters *poly) +{ + UBYTE *ptr; + SLONG width; + struct FloatPolyParameters lpoly; + + lpoly.Y =poly->Y; + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + lpoly.FLeftTextX=poly->FLeftTextX; //CLIP + lpoly.FLeftTextY=poly->FLeftTextY; //CLIP + lpoly.StepShade=poly->StepShade; + lpoly.FStepTextX=poly->FStepTextX; + lpoly.FStepTextY=poly->FStepTextY; + lpoly.Q =poly->Q; + lpoly.StepQ =poly->StepQ; + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.FLeftTextX+=poly->FStepTextX*(-lpoly.LeftX); + lpoly.FLeftTextY+=poly->FStepTextY*(-lpoly.LeftX); + lpoly.Q+=poly->StepQ*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"C" version + UBYTE col; + while(width) + { + SLONG tx,ty; + tx=(SLONG)(lpoly.FLeftTextX/lpoly.Q); + ty=(SLONG)(lpoly.FLeftTextY/lpoly.Q); + if(tx<0||tx>255||ty<0||ty>255) + tx=ty=0; + + col=ASMtext_page[(tx)+((ty<<8))]; +// *ptr++=col; + *ptr++=fade_tables[col+((lpoly.LeftShade>>8)&0xff00)]; + width--; + lpoly.LeftShade+=lpoly.StepShade; + lpoly.FLeftTextX+=lpoly.FStepTextX; + lpoly.FLeftTextY+=lpoly.FStepTextY; + lpoly.Q +=lpoly.StepQ; + } + } +} + + + +void SCAN_LINE_GT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + +/* + { + CBYTE str[100]; + sprintf(str," %d -> %d ",poly->LeftX>>16,poly->RightX>>16); + QuickTextC(poly->LeftX>>16,(poly->Y-280)*10,str,1); + } +*/ + + +// memcpy(&lpoly,poly,sizeof(struct PolyParameters)); + +// lpoly.Y =poly->Y; + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP +// lpoly.StepShade=poly->StepShade; +// lpoly.StepTextX=poly->StepTextX; +// lpoly.StepTextY=poly->StepTextY; + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + ASMshade= lpoly.LeftShade; + + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_GT(); + } +} + +void SCAN_LINE_TGT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + ASMshade= lpoly.LeftShade; + + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_TGT(); + } +} + +void SCAN_LINE_50GT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + ASMshade= lpoly.LeftShade; + +#ifdef _MSC_VER + RENDER_MSC_50GT(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); +#else + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_50GT(); +#endif + } +} + +void SCAN_LINE_50MGT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + ASMshade= lpoly.LeftShade; + + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_50MGT(); + } +} + +void SCAN_LINE_MGT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + ASMshade= lpoly.LeftShade; + +#ifdef _MSC_VER + RENDER_MSC_MGT(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); +#else + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_MGT(); +#endif + } +} + +void SCAN_LINE_MT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + +#ifdef _MSC_VER + RENDER_MSC_MT(ptr_screen-1,width,poly->StepTextX,poly->StepTextY); +#else + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_MT(); +#endif + } +} + + +void SCAN_LINE_T(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + +#ifdef _MSC_VER + RENDER_MSC_T(ptr_screen-1,width,poly->StepTextX,poly->StepTextY); +#else + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_T(); +#endif + } +} + +void SCAN_LINE_50T(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + +#ifdef _MSC_VER + RENDER_MSC_50T(ptr_screen-1,width,poly->StepTextX,poly->StepTextY); +#else + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_50T(); +#endif + } +} + +void SCAN_LINE_AT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_AT(); + } +} + +void SCAN_LINE_AMT(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP + lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftTextX=poly->LeftTextX>>POLY_TEXT_SHIFT; //CLIP + lpoly.LeftTextY=poly->LeftTextY>>POLY_TEXT_SHIFT; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftTextX+=poly->StepTextX*(-lpoly.LeftX); + lpoly.LeftTextY+=poly->StepTextY*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + if(width) + { //"ASM" version + + ASMtx = lpoly.LeftTextX; + ASMty = lpoly.LeftTextY; + + RENDER_SETUP(ptr_screen-1,width,poly->StepShade,poly->StepTextX,poly->StepTextY); + RENDER_SETUP2(); + RENDER_GO_AMT(); + } +} + + + +void SCAN_LINE_G(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP +// lpoly.RightX =(poly->RightX+(1<<15))>>16; //CLIP + lpoly.RightX =(poly->RightX)>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + while(width) + { + *ptr_screen++=fade_tables[poly_info.Col+((lpoly.LeftShade>>8)&0xff00)]; + width--; + lpoly.LeftShade+=poly->StepShade; + } +} + +void SCAN_LINE_AG(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP +// lpoly.RightX =(poly->RightX+(1<<15))>>16; //CLIP + lpoly.RightX =(poly->RightX)>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + while(width) + { + *ptr_screen=fade_tables[*ptr_screen+((lpoly.LeftShade>>8)&0xff00)]; + ptr_screen++; + width--; + lpoly.LeftShade+=poly->StepShade; + } +} + +void SCAN_LINE_50G(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP +// lpoly.RightX =(poly->RightX+(1<<15))>>16; //CLIP + lpoly.RightX =(poly->RightX)>>16; //CLIP +// lpoly.RightX =poly->RightX>>16; //CLIP + lpoly.LeftShade=poly->LeftShade; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftShade+=poly->StepShade*(-lpoly.LeftX); + lpoly.LeftX=0; + + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + while(width) + { + *ptr_screen=mix_map[(*ptr_screen<<8)+fade_tables[poly_info.Col+((lpoly.LeftShade>>8)&0xff00)]]; + ptr_screen++; + width--; + lpoly.LeftShade+=poly->StepShade; + } +} + + +void SCAN_LINE_F(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + + lpoly.LeftX =poly->LeftX>>16; //CLIP +// lpoly.RightX =(poly->RightX+(1<<15))>>16; //CLIP + lpoly.RightX =(poly->RightX)>>16; //CLIP +// lpoly.RightX =poly->RightX>>16; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftX=0; + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + + while(width) + { + *ptr_screen++=poly_info.Col; + width--; + } +} + +void SCAN_LINE_50F(struct PolyParameters *poly) +{ + UBYTE *ptr_screen; + SLONG width; + struct PolyParameters lpoly; + SLONG col; + + lpoly.LeftX =poly->LeftX>>16; //CLIP +// lpoly.RightX =(poly->RightX+(1<<15))>>16; //CLIP + lpoly.RightX =(poly->RightX)>>16; //CLIP + // lpoly.RightX =poly->RightX>>16; //CLIP + + if(lpoly.LeftX>=WorkWindowWidth || lpoly.RightX<0) + return; + + + if(lpoly.RightX>=WorkWindowWidth) + { + lpoly.RightX = WorkWindowWidth-1; + } + + width=lpoly.RightX-lpoly.LeftX; + + if(width<=0) + return; + + if(lpoly.LeftX<0) + { + lpoly.LeftX=0; + width=lpoly.RightX; + } + + ptr_screen=WorkWindow+lpoly.LeftX+(WorkScreenWidth*poly->Y); + col=poly_info.Col<<8; + while(width) + { + *ptr_screen=mix_map[col+*ptr_screen]; + ++ptr_screen; + width--; + } +} + +void SCAN_LINE_NULL(struct PolyParameters *poly) +{ + poly_info.Col=(MouseX+MouseY)&255; + SCAN_LINE_G(poly); +} + + +/* +void SCAN_LINE_GT(struct PolyParameter *p) +{ + UBYTE *ptr,col,col2; + SLONG p,shade; + UBYTE *ptr_text; + SLONG start_text_x,textx; + SLONG start_text_y,texty; + + + if(rx<0) + return; + + p=rx-lx; + if(p<=0) + return; + + + start_text_x=tx1; + start_text_y=ty1; + + + if(rx>=WorkWindowWidth) + { + rx=WorkWindowWidth; + p=rx-lx; + if(p<0) + return; + } + + + if(lx<0) + { + s1+=shade_step*(-lx); + start_text_x+=textx_step*(-lx); + start_text_y+=texty_step*(-lx); + p=rx; + lx=0; + } + ptr=WorkWindow+lx+(WorkScreenWidth*y); + +#ifndef SHIP_IT + if((s1>>16)>=64) + s1=63<<16; + if(((s1+shade_step*p)>>16)>64) + shade_step=((63<<16)-s1)/p; + + if(s1<0) + s1=0; + if(((s1+shade_step*p)>>16)<0) + shade_step=(0-s1)/p; +#endif + +#ifdef KEYBOARD +// if(!KeyOn[KB_H]) + { //"C" version + UBYTE *optr; + optr=ptr; + while(p) + { + col=tmap[(start_text_x>>16)+((start_text_y>>8)&0xff00)]; + *ptr++=fade_tables[col+((s1>>8)&0xff00)]; + p--; + s1+=shade_step; + start_text_x+=textx_step; + start_text_y+=texty_step; + } +// if(KeyOn[KB_O]) + { + *(ptr-1)=128; + *(optr)=128; + } + } +// else +#else + if(p) + { //"ASM" version + +// ASMstep_shade=shade_step; +// ASMstep_tx=textx_step; +// ASMstep_ty=texty_step; + ASMtx=start_text_x; + ASMty=start_text_y; + ASMshade=s1; + + RENDER_SETUP(ptr-1,p,shade_step,textx_step,texty_step); + RENDER_SETUP2(); + RENDER_GO_GT(); + } +#endif +} +*/ + + + + + +#define DITHER_WIDTH 256 +void build_dither_tmap(SLONG tx,SLONG ty,UBYTE *dest) +{ + UBYTE *ptr_s,*ptr_d; + SLONG x,y; +/* +// +// no longer 8 but compatible +// + ptr_s=&poly_info.PTexture[((tx>>5)<<5)+((ty>>5)<<5)*256]; + ptr_d=dest; + + for(y=0;y<32;y++) + { + *ptr_d++=*ptr_s; + for(x=1;x<32;x++) + { + *ptr_d=mix_map[*ptr_s+(*(ptr_s+1))*256]; + ptr_d++; + *ptr_d=*++ptr_s; + ptr_d++; + } + *(ptr_d++)=*ptr_s; + ptr_d+=DITHER_WIDTH*2-64; + ptr_s+=256-31; + } + + ptr_d=dest+DITHER_WIDTH; + for(y=0;y<32;y++) + { + for(x=0;x<64;x++) + { + *ptr_d=mix_map[*(ptr_d+DITHER_WIDTH)+(*(ptr_d-DITHER_WIDTH)<<8)]; + ptr_d++; + } + ptr_d+=DITHER_WIDTH*2-64; + } +*/ +} + + +SLONG find_and_use_block(SLONG *dx,SLONG *dy,SLONG id) +{ + SLONG best=-1,best_age=2; + SLONG c0; + for(c0=0;c0<16;c0++) + { + if(filter_is[c0]==0xffff) + { + best=c0; + goto early_out; + } + if(filter_age[c0]>=best_age) //>= allows reuse this frame + { + best_age=filter_age[c0]; + best=c0; + } + } +early_out:; + if(best>=0) + { + + *dx=(best&3)<<6; + *dy=(best&12)<<4; +// LogText("Find and USE block id %x at %d age %d \n",id,best,filter_age[best]); + filter_age[best]=1; + filter_is[best]=id; + return(1); + } +// LogText("Find failed"); + return(0); +} + +static SLONG local_edit_turn=-1; +inline SLONG filter_poly_tmap(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,SLONG *dx,SLONG *dy) +{ + SLONG tx,ty,use_x,use_y; + SLONG id; +/* +// LogText("FILTER POLY3 \n"); + + if(local_edit_turn==-1) + { + SLONG c0; +// LogText("CLEAR LIST\n"); + for(c0=0;c0<16;c0++) + { + filter_age[c0]=99; + filter_is[c0]=0xffff; + } + + } + if(editor_turn!=local_edit_turn) + { + SLONG c0; +// LogText("FILTERED TMAPS TRI\n"); +// LogText("---=----------\n"); + local_edit_turn=editor_turn; + for(c0=0;c0<16;c0++) + { + filter_age[c0]++; + if(filter_age[c0]==0) + filter_age[c0]=255; +// LogText("%d is %x age %d\n",c0,filter_is[c0],filter_age[c0]); + } + + } + + tx=(p1->TX+p2->TX+p3->TX)/3; + ty=(p1->TY+p2->TY+p3->TY)/3; + id=(tx>>5)+((ty>>5)<<3)+(poly_info.Page<<6); +// LogText("NEW TRI to FILTER tx %d ty %d page %d id %x\n",tx,ty,poly_info.Page,id); + if(find_and_use_block(&use_x,&use_y,id)==0) + return(0); + build_dither_tmap(tx,ty,&tmap2[use_x+(use_y<<8)]); +// LogText("TRI build dither tx %d ty %d from use_x %d use_Y %d \n",tx,ty,use_x,use_y); + ASMtext_page=tmap2; + *dx=(tx>>5)<<5; + *dy=(ty>>5)<<5; + *dx-=use_x>>1; + *dy-=use_y>>1; + p1->TX=(p1->TX-*dx)<<1; + p1->TY=(p1->TY-*dy)<<1; + p2->TX=(p2->TX-*dx)<<1; + p2->TY=(p2->TY-*dy)<<1; + p3->TX=(p3->TX-*dx)<<1; + p3->TY=(p3->TY-*dy)<<1; +*/ + return(1); +} + +inline SLONG filter_poly_tmap4(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4,SLONG *dx,SLONG *dy) +{ + SLONG tx,ty,use_x,use_y; + SLONG id; + +/* + +// LogText("FILTER POLY4 \n"); + + if(local_edit_turn==-1) + { + SLONG c0; +// LogText("CLEAR TMAPS\n"); +// LogText("---=----------\n"); + for(c0=0;c0<16;c0++) + { + +// LogText("%d is %x age %d\n",c0,filter_is[c0],filter_age[c0]); + filter_is[c0]=0xffff; + filter_age[c0]=99; + } + + } + if(editor_turn!=local_edit_turn) + { + SLONG c0; +// LogText("FILTERED TMAPS\n"); +// LogText("---=----------\n"); + local_edit_turn=editor_turn; + for(c0=0;c0<16;c0++) + { + +// LogText("%d is %x age %d\n",c0,filter_is[c0],filter_age[c0]); + filter_age[c0]++; + if(filter_age[c0]==0) + filter_age[c0]=255; + } + + } + + tx=(p1->TX+p2->TX+p3->TX+p4->TX)>>2; + ty=(p1->TY+p2->TY+p3->TY+p4->TY)>>2; + id=(tx>>5)+((ty>>5)<<3)+(poly_info.Page<<6); + if(find_and_use_block(&use_x,&use_y,id)==0) + return(0); + build_dither_tmap(tx,ty,&tmap2[use_x+(use_y<<8)]); +// LogText("build dither tx %d ty %d from use_x %d use_Y %d \n",tx,ty,use_x,use_y); + ASMtext_page=tmap2; + *dx=(tx>>5)<<5; + *dy=(ty>>5)<<5; + *dx-=use_x>>1; + *dy-=use_y>>1; + p1->TX=(p1->TX-*dx)<<1; + p1->TY=(p1->TY-*dy)<<1; + p2->TX=(p2->TX-*dx)<<1; + p2->TY=(p2->TY-*dy)<<1; + p3->TX=(p3->TX-*dx)<<1; + p3->TY=(p3->TY-*dy)<<1; + p4->TX=(p4->TX-*dx)<<1; + p4->TY=(p4->TY-*dy)<<1; + */ + return(1); +} + + +inline SLONG allready_filtered(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,SLONG *dx,SLONG *dy) +{ + SLONG c0; + SLONG tx,ty; + SLONG id; + +/* + + tx=(p1->TX+p2->TX+p3->TX)/3; + ty=(p1->TY+p2->TY+p3->TY)/3; + id=(tx>>5)+((ty>>5)<<3)+(poly_info.Page<<6); + for(c0=0;c0<16;c0++) + { + if(filter_is[c0]==id) + { + *dx=(tx>>5)<<5; + *dy=(ty>>5)<<5; + + *dx-=(c0&3)<<5; + *dy-=(c0&12)<<3; + ASMtext_page=tmap2; + + p1->TX=(p1->TX-*dx)<<1; + p1->TY=(p1->TY-*dy)<<1; + p2->TX=(p2->TX-*dx)<<1; + p2->TY=(p2->TY-*dy)<<1; + p3->TX=(p3->TX-*dx)<<1; + p3->TY=(p3->TY-*dy)<<1; + return(1); + } + } +// LogText("TRI NOT Allready Filtered tx %d ty %x id %d page %d \n",tx,ty,id,poly_info.Page); +*/ + return(0); +} + +inline SLONG allready_filtered4(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4,SLONG *dx,SLONG *dy) +{ +/* + SLONG c0; + SLONG tx,ty; + SLONG id; + + tx=(p1->TX+p2->TX+p3->TX+p4->TX)>>2; + ty=(p1->TY+p2->TY+p3->TY+p4->TY)>>2; + + id=(tx>>5)+((ty>>5)<<3)+(poly_info.Page<<6); + for(c0=0;c0<16;c0++) + { + if(filter_is[c0]==id) + { + *dx=(tx>>5)<<5; + *dy=(ty>>5)<<5; + + *dx-=(c0&3)<<5; + *dy-=(c0&12)<<3; + ASMtext_page=tmap2; + + p1->TX=(p1->TX-*dx)<<1; + p1->TY=(p1->TY-*dy)<<1; + p2->TX=(p2->TX-*dx)<<1; + p2->TY=(p2->TY-*dy)<<1; + p3->TX=(p3->TX-*dx)<<1; + p3->TY=(p3->TY-*dy)<<1; + p4->TX=(p4->TX-*dx)<<1; + p4->TY=(p4->TY-*dy)<<1; + return(1); + } + } +// LogText("QUA NOT Allready Filtered tx %d ty %x id %d page %d \n",tx,ty,id,poly_info.Page); +*/ + return(0); +} + +struct FPointer +{ + void (*FunctionPointer)(struct PolyParameters*); +}; + +struct FPointer p_functions[]= +{ + {SCAN_LINE_F}, //0 flat + {SCAN_LINE_G}, //1 Gourad Shaded + {SCAN_LINE_T}, //2 Textured + {SCAN_LINE_GT}, //3 Gourad & Textured + {SCAN_LINE_NULL}, //4 cant have just masked + {SCAN_LINE_NULL}, //5 masked & gourad + {SCAN_LINE_MT}, //6 Masked Textures + {SCAN_LINE_MGT}, //7 Masked Gourad Textured + {SCAN_LINE_50F}, //8 Semi Transparent flat coloured face + {SCAN_LINE_50G}, //9 Semi Transparent Gourad face + {SCAN_LINE_50T}, //10 Semi Transparent Textured face + {SCAN_LINE_50GT}, //11 Semi Transparent Gourad & Textured Face + {SCAN_LINE_NULL}, //12 50M + {SCAN_LINE_NULL}, //13 50MG + {SCAN_LINE_NULL}, //14 50MT + {SCAN_LINE_50MGT}, //15 Semi Transparent Masked Gourad & Textured Face + + {SCAN_LINE_NULL}, //16 flat + {SCAN_LINE_AG}, //17 Gourad Shaded + {SCAN_LINE_AT}, //18 Textured + {SCAN_LINE_NULL}, //19 Gourad & Textured + {SCAN_LINE_NULL}, //20 cant have just masked + {SCAN_LINE_NULL}, //21 masked & gourad + {SCAN_LINE_AMT}, //22 Masked Textures + {SCAN_LINE_NULL}, //23 Masked Gourad Textured + {SCAN_LINE_NULL}, //24 Semi Transparent flat coloured face + {SCAN_LINE_NULL}, //25 Semi Transparent Gourad face + {SCAN_LINE_NULL}, //26 Semi Transparent Textured face + {SCAN_LINE_NULL}, //27 Semi Transparent Gourad & Textured Face + {SCAN_LINE_NULL}, //28 50M + {SCAN_LINE_NULL}, //29 50MG + {SCAN_LINE_NULL}, //30 50MT + {SCAN_LINE_NULL}, //31 Semi Transparent Masked Gourad & Textured Face + + {SCAN_LINE_F}, //0 TILED flat + {SCAN_LINE_G}, //1 TILED Gourad Shaded + {SCAN_LINE_T}, //2 TILED Textured + {SCAN_LINE_TGT}, //3 TILED Gourad & Textured + {SCAN_LINE_NULL}, //4 TILED cant have just masked + {SCAN_LINE_NULL}, //5 TILED masked & gourad + {SCAN_LINE_MT}, //6 TILED Masked Textures + {SCAN_LINE_MGT}, //7 TILED Masked Gourad Textured + {SCAN_LINE_50F}, //8 TILED Semi Transparent flat coloured face + {SCAN_LINE_50G}, //9 TILED Semi Transparent Gourad face + {SCAN_LINE_50T}, //10 TILED Semi Transparent Textured face + {SCAN_LINE_50GT}, //11 TILED Semi Transparent Gourad & Textured Face + {SCAN_LINE_NULL}, //12 TILED 50M + {SCAN_LINE_NULL}, //13 TILED 50MG + {SCAN_LINE_NULL}, //14 TILED 50MT + {SCAN_LINE_50MGT}, //15 TILED Semi Transparent Masked Gourad & Textured Face + {SCAN_LINE_NULL}, //16 TILED flat + + {SCAN_LINE_AG}, //17 TILED Gourad Shaded + {SCAN_LINE_AT}, //18 TILED Textured + {SCAN_LINE_NULL}, //19 TILED Gourad & Textured + {SCAN_LINE_NULL}, //20 TILED cant have just masked + {SCAN_LINE_NULL}, //21 TILED masked & gourad + {SCAN_LINE_AMT}, //22 TILED Masked Textures + {SCAN_LINE_NULL}, //23 TILED Masked Gourad Textured + {SCAN_LINE_NULL}, //24 TILED Semi Transparent flat coloured face + {SCAN_LINE_NULL}, //25 TILED Semi Transparent Gourad face + {SCAN_LINE_NULL}, //26 TILED Semi Transparent Textured face + {SCAN_LINE_NULL}, //27 TILED Semi Transparent Gourad & Textured Face + {SCAN_LINE_NULL}, //28 TILED 50M + {SCAN_LINE_NULL}, //29 TILED 50MG + {SCAN_LINE_NULL}, //30 TILED 50MT + {SCAN_LINE_NULL} //31 TILED Semi Transparent Masked Gourad & Textured Face +}; + +#define PSWAP(x,y) {struct MfEnginePoint *t; t=x ; x=y ; y=t; } + +inline void bodge_textures(SLONG *dtx,SLONG *dty) +{ + if(*dtx>1<<16) + *dtx-=1<<15; + else + if(*dtx<-1<<16) + *dtx+=1<<15; + + if(*dty>1<<16) + *dty-=1<<15; + else + if(*dty<-1<<16) + *dty+=1<<15; +} + + +//p1 is top p2 is p1->p2 is left hand side p1->p3 is right hand side +void calc_steps_for_tri(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,SLONG dy_lhs,SLONG dy_rhs,struct PolyParameters *poly) +{ + SLONG length,ratio; + SLONG dtx,dty; + + if(dy_lhs==dy_rhs) + { + length=p3->X-p2->X; + + if(length==0) + length=999999; + + poly->StepShade=((p3->Shade-p2->Shade)<<14)/length; + dtx=(p3->TX-p2->TX)<<16; + dty=(p3->TY-p2->TY)<<16; + + bodge_textures(&dtx,&dty); + + poly->StepTextX=(dtx)/length; + poly->StepTextY=(dty)/length; + } + else + if(dy_lhsX -p1->X )<<16)/ratio+(p1->X ); + mid_shade=((p3->Shade-p1->Shade)<<23)/ratio+(p1->Shade<<7); + mid_textx=((p3->TX -p1->TX )<<23)/ratio+(p1->TX <<7); + mid_texty=((p3->TY -p1->TY )<<23)/ratio+(p1->TY <<7); + + length=((mid_x)-p2->X); + + if(length==0) + length=999999; + + dtx=(mid_textx-(p2->TX <<7))<<9; + dty=(mid_texty-(p2->TY <<7))<<9; + + bodge_textures(&dtx,&dty); + + poly->StepShade=((mid_shade-(p2->Shade<<7))<<7)/length; + poly->StepTextX=(dtx)/length; + poly->StepTextY=(dty)/length; + } + else + if(dy_lhs>dy_rhs) + { + SLONG mid_shade,mid_textx,mid_texty,mid_x; + + ratio=(dy_lhs<<16)/dy_rhs; + + mid_x =((p2->X -p1->X )<<16)/ratio+(p1->X ); + mid_shade=((p2->Shade-p1->Shade)<<23)/ratio+(p1->Shade<<7); + mid_textx=((p2->TX -p1->TX )<<23)/ratio+(p1->TX <<7); + mid_texty=((p2->TY -p1->TY )<<23)/ratio+(p1->TY <<7); + + length=p3->X-(mid_x); + + if(length==0) + length=999999; + + dtx=((p3->TX<<7)-mid_textx)<<9; + dty=((p3->TY<<7)-mid_texty)<<9; + + bodge_textures(&dtx,&dty); + + poly->StepShade=(((p3->Shade<<7)-mid_shade)<<7)/length; + poly->StepTextX=(dtx)/length; + poly->StepTextY=(dty)/length; + } +} + +#define can_texture_be_filtered(a,b,c) 0 +#define can_texture_be_filtered4(a,b,c,d) 0 + +/* +SLONG can_texture_be_filtered(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3) +{ + SLONG id1,id2,id3; + if(Keys[KB_0]) + return(0); + + + id1=(p1->TX>>5)+((p1->TY>>5)<<3); + id2=(p2->TX>>5)+((p2->TY>>5)<<3); + id3=(p3->TX>>5)+((p3->TY>>5)<<3); + + if(id1==id2&&id2==id3) + return(1); + else + return(0); + +} +SLONG can_texture_be_filtered4(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4) +{ + SLONG id1,id2,id3,id4; + if(Keys[KB_0]) + return(0); + + + id1=(p1->TX>>5)+((p1->TY>>5)<<3); + id2=(p2->TX>>5)+((p2->TY>>5)<<3); + id3=(p3->TX>>5)+((p3->TY>>5)<<3); + id4=(p4->TX>>5)+((p4->TY>>5)<<3); + + if(id1==id2&&id2==id3&&id3==id4) + return(1); + else + return(0); + +} +*/ + +ULONG calc_texture_offset(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3) +{ + SLONG tx,ty; + tx=p1->TX; + ty=p1->TY; + + if(p2->TXTX; + if(p2->TYTY; + + if(p3->TXTX; + if(p3->TYTY; + + tx&=0xffffffe0; + ty&=0xffffffe0; + + return(tx+(ty<<8)); + +} +ULONG calc_texture_offset4(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4) +{ + SLONG tx,ty; + tx=p1->TX; + ty=p1->TY; + + if(p2->TX+p2->TYTX; + ty=p2->TY; + } + if(p3->TX+p3->TYTX; + ty=p3->TY; + } + if(p4->TX+p4->TYTX; + ty=p4->TY; + } + + tx&=0xffffffe0; + ty&=0xffffffe0; + + return(tx+(ty<<8)); + +} +//#define FILTERING_ON 1 + +void my_trig(struct MfEnginePoint *p3,struct MfEnginePoint *p2,struct MfEnginePoint *p1) +{ + SLONG dx_lhs,dy_lhs,dx_rhs,dy_rhs,dx2,dy2; + +//shades + SLONG ds_lhs,ds_2; + SLONG dtx_lhs,dtx_2; + SLONG dty_lhs,dty_2; + SLONG flat_top=0; +#ifdef FILTERING_ON + SLONG f_dx=0,f_dy=0; + SLONG filtered=0,can_filter=0; +#endif + struct PolyParameters poly; + struct FPointer raster_fill; +// p1->Shade=1; + if(is_it_clockwise(p1,p2,p3)) + return; + +#ifdef FILTERING_ON + if(poly_info.DrawFlags&POLY_FLAG_TEXTURED) + can_filter=can_texture_be_filtered(p1,p2,p3); +#endif + + raster_fill.FunctionPointer=p_functions[poly_info.DrawFlags&POLY_MODES].FunctionPointer; + + ASMtext_page=poly_info.PTexture; + + if(ASMtext_page==0) + return; + + if(poly_info.DrawFlags&POLY_FLAG_TILED) + { + ASMtext_page+=calc_texture_offset(p1,p2,p3); +#ifdef FILTERING_ON + can_filter=0; +#endif + } + + if(p2->YY&&p2->Y<=p3->Y) + { // p2 is at top + + PSWAP(p2,p1); + PSWAP(p2,p3); //this to remain clockwise + } + else + if(p3->YY&&p3->Y<=p2->Y) + { + // p3 is at top + + { + PSWAP(p3,p1); + PSWAP(p3,p2); //this to remain clockwise + } + } + +#ifdef FILTERING_ON + if(can_filter) + filtered=allready_filtered(p1,p2,p3,&f_dx,&f_dy); +#endif + +//we know p1 is the highest + { + dy_lhs=(p2->Y-p1->Y); + if(dy_lhs==0) //flat top with p2,p1 + { + SLONG dtx,dty; + SLONG dist; + flat_top=1; + + dty_lhs=0; //((p2->TY-p1->TY)<<16)/dy_lhs; + dtx_lhs=0; //((p2->TX-p1->TX)<<16)/dy_lhs; + ds_lhs=0; //((p2->Shade-p1->Shade))/dy_lhs; + dx_lhs=0; + dist=p1->X-p2->X; + if(dist) + { + dtx=(p1->TX-p2->TX)<<16; + dty=(p1->TY-p2->TY)<<16; + + bodge_textures(&dtx,&dty); + + poly.StepShade=((p1->Shade-p2->Shade)<<14)/dist; + poly.StepTextX=(dtx)/dist; + poly.StepTextY=(dty)/dist; + } + + + } + else + { +// dty_lhs=((p2->TY-p1->TY)<<24)/dy_lhs; +// dtx_lhs=((p2->TX-p1->TX)<<24)/dy_lhs; + ds_lhs=((p2->Shade-p1->Shade)<<14)/dy_lhs; + dx_lhs=((p2->X-p1->X)<<16)/dy_lhs; + } + + dy_rhs=(p3->Y-p1->Y); + if(dy_rhs==0) //flat top with p3,p1 + { + SLONG dtx,dty; + SLONG dist; + + dx_rhs=0; + + flat_top=1; + dist=p1->X-p3->X; + if(dist) + { + dtx=(p1->TX-p3->TX)<<16; + dty=(p1->TY-p3->TY)<<16; + + bodge_textures(&dtx,&dty); + + poly.StepShade=((p1->Shade-p3->Shade)<<14)/dist; + poly.StepTextX=(dtx)/dist; + poly.StepTextY=(dty)/dist; + } + } + else + { + dx_rhs=((p3->X-p1->X)<<16)/dy_rhs; + } + + poly.LeftShade=p1->Shade<<14; + poly.LeftX=(p1->X<<16);//+(1<<15); + poly.Y=p1->Y; + + if(!flat_top) + calc_steps_for_tri(p1,p2,p3,dy_lhs,dy_rhs,&poly); + +#ifdef FILTERING_ON +/*-----------** +** FILTERING ** +**-----------*/ + if(can_filter) + if(!filtered) +// if(Keys[KB_B]) +// if(abs(poly.StepTextX)< (1<<10) || abs(poly.StepTextY)< (1<<10)) + { + filtered=filter_poly_tmap(p1,p2,p3,&f_dx,&f_dy); + if(!flat_top&&filtered) + calc_steps_for_tri(p1,p2,p3,dy_lhs,dy_rhs,&poly); + + if(dy_lhs==0) + { + SLONG dtx,dty,dist; + dist=p1->X-p2->X; + if(dist) + { + dtx=(p1->TX-p2->TX)<<16; + dty=(p1->TY-p2->TY)<<16; + + bodge_textures(&dtx,&dty); + + poly.StepShade=((p1->Shade-p2->Shade)<<14)/dist; + poly.StepTextX=(dtx)/dist; + poly.StepTextY=(dty)/dist; + } + } + } +#endif + + if(dy_lhs!=0) + { + dty_lhs=((p2->TY-p1->TY)<<23)/dy_lhs; + dtx_lhs=((p2->TX-p1->TX)<<23)/dy_lhs; + } + +//************************ END OF FILTERING + +//texturex step along sides + poly.LeftTextX=p1->TX<<23; +//texturey step along sides + poly.LeftTextY=p1->TY<<23; + + + + if(dy_lhsX-p2->X)<<16; + dx2=(temp_dx)/dy2; + ds_2=((p3->Shade-p2->Shade)<<14)/dy2; + dtx_2=((p3->TX-p2->TX)<<23)/dy2; + dty_2=((p3->TY-p2->TY)<<23)/dy2; + } + else + { //RHS shorter than LHS + + dy2=dy_lhs-dy_rhs; + if(dy2==0) + dy2=1; + dx2=((p2->X-p3->X)<<16)/dy2; + + } + } +#ifdef DEBUG_POLY + { + CBYTE str[100]; + sprintf(str,"stx %d sty %d tdx %d tdy %d",stx,sty,dtx_lhs,dty_lhs); + QuickText((p2->X+p1->X+p3->X)/3,380,str,1); + } +#endif +//now scan the edges and render between edges + { + SLONG count; +// CBYTE str[100]; + + poly.RightX=poly.LeftX; + + count=MIN(dy_rhs,dy_lhs); +// sprintf(str,"count %d,dy_lhs %d,dy_rhs %d",count,dy_lhs,dy_rhs); +// draw_text(80,0,str,32); + + if(count!=0) //if not flat top + { + if(poly.Y<0) // if clipped off top of screen + { + poly.Y=-poly.Y; // poly.Y is lines to skip + if(count>=poly.Y) + { // will be on screen before this count finishes + poly.LeftX+=dx_lhs*poly.Y; + poly.RightX+=dx_rhs*poly.Y; + poly.LeftShade+=ds_lhs*poly.Y; + + poly.LeftTextX+=dtx_lhs*poly.Y; + poly.LeftTextY+=dty_lhs*poly.Y; + count-=poly.Y; + poly.Y=0; + + } + else + { + poly.LeftX+=dx_lhs*count; + poly.RightX+=dx_rhs*count; + poly.LeftShade+=ds_lhs*count; + + poly.LeftTextX+=dtx_lhs*count; + poly.LeftTextY+=dty_lhs*count; + poly.Y=-poly.Y+count; + count=0; + } + } + if(poly.Y>=WorkWindowHeight) + goto clip_out; + + //do the top part of the triangle + while(count>0) + { + raster_fill.FunctionPointer(&poly); +// SCAN_LINE_GT(&poly); +// SCAN_LINE_GT(poly.Y,poly.LeftX>>16,poly.RightX>>16,poly.LeftShade,poly.StepShade,poly.LeftTextX>>8,poly.StepTextX,poly.LeftTextY>>POLY_TEXT_SHIFT,poly.StepTextY); + poly.LeftX+=dx_lhs; + poly.RightX+=dx_rhs; + poly.LeftShade+=ds_lhs; + + poly.LeftTextX+=dtx_lhs; + poly.LeftTextY+=dty_lhs; + poly.Y++; + count--; + if(poly.Y>=WorkWindowHeight) + goto clip_out; + } + } + else + { +// flat top +// ft=1; + if(p2->Y==p1->Y) + { + poly.LeftTextY=p2->TY<<23; + poly.LeftTextX=p2->TX<<23; + poly.LeftShade=p2->Shade<<14; + poly.LeftX=(p2->X<<16);//+(1<<15); + + poly.RightX=(p1->X<<16);//+(1<<15); + } + else + { + poly.LeftTextY=p1->TY<<23; + poly.LeftTextX=p1->TX<<23; + poly.LeftShade=p1->Shade<<14; + poly.LeftX=(p1->X<<16);//+(1<<15); + + poly.RightX=(p3->X<<16);//+(1<<15); + + } + + + } + + //setup for bottom half of tri + if(dy_lhsX<<16; + + poly.LeftTextX=p2->TX<<23; + poly.LeftTextY=p2->TY<<23; + + } + else + if(dy_lhs>dy_rhs) + { + //rhs kinks + + count=dy_lhs-dy_rhs; + dx_rhs=dx2; + poly.RightX=p3->X<<16; + } + + //clip + if(poly.Y<0) + { + poly.Y=-poly.Y; // poly.Y is lines to skip + if(count>=poly.Y) + { // will be on screen before this count finishes + poly.LeftX+=dx_lhs*poly.Y; + poly.RightX+=dx_rhs*poly.Y; + poly.LeftShade+=ds_lhs*poly.Y; + + poly.LeftTextX+=dtx_lhs*poly.Y; + poly.LeftTextY+=dty_lhs*poly.Y; + count-=poly.Y; + poly.Y=0; + } + else + goto clip_out; + } + if(poly.Y>=WorkWindowHeight) + goto clip_out; + + + while(count>0) + { + raster_fill.FunctionPointer(&poly); +// SCAN_LINE_GT(&poly); + + poly.LeftX+=dx_lhs; + poly.RightX+=dx_rhs; + poly.LeftShade+=ds_lhs; + poly.LeftTextX+=dtx_lhs; + poly.LeftTextY+=dty_lhs; + poly.Y++; + count--; + if(poly.Y>=WorkWindowHeight) + goto clip_out; + } + } + +clip_out:; + +#ifdef FILTERING_ON + if(filtered) + { + p1->TX=(p1->TX>>1)+f_dx; + p1->TY=(p1->TY>>1)+f_dy; + p2->TX=(p2->TX>>1)+f_dx; + p2->TY=(p2->TY>>1)+f_dy; + p3->TX=(p3->TX>>1)+f_dx; + p3->TY=(p3->TY>>1)+f_dy; + } +#endif +// p1->Shade=128; +} + + +//p1 is top p2 is p1->p2 is left hand side p1->p3 is right hand side +void pcalc_steps_for_tri(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,SLONG dy_lhs,SLONG dy_rhs,struct FloatPolyParameters *poly) +{ + SLONG length,ratio; + float dtx,dty,dq,q1,q2,q3; + q1=1.0/(float)p1->Z3d; + q2=1.0/(float)p2->Z3d; + q3=1.0/(float)p3->Z3d; + + if(dy_lhs==dy_rhs) + { + length=p3->X-p2->X; + + if(length==0) + length=999999; + + poly->StepShade=((p3->Shade-p2->Shade)<<14)/length; + dtx=((float)p3->TX/(float)p3->Z3d-(float)p2->TX/(float)p2->Z3d); + dty=((float)p3->TY/(float)p3->Z3d-(float)p2->TY/(float)p2->Z3d); + + poly->StepQ=(q3-q2)/(float)length; + poly->FStepTextX=(dtx)/(float)length; + poly->FStepTextY=(dty)/(float)length; + } + else + if(dy_lhsX -p1->X )<<16)/ratio+(p1->X ); + mid_shade=((p3->Shade-p1->Shade)<<23)/ratio+(p1->Shade<<7); +// mid_z =((p3->Z3d -p1->Z3d )<<16)/ratio+(p1->Z3d); +// mid_textx=((p3->TX -p1->TX )<<23)/ratio+(p1->TX <<7); +// mid_texty=((p3->TY -p1->TY )<<23)/ratio+(p1->TY <<7); + + mid_textx=((float)(p3->TX -p1->TX ))/ratiof+((float)p1->TX); + mid_texty=((float)(p3->TY -p1->TY ))/ratiof+((float)p1->TY); + + mid_q =(q3 -q1 )/ratiof+(q1); + length=(mid_x)-p2->X; + + if(length==0) + length=999999; + + dtx=mid_textx*mid_q-((float)p2->TX/(float)p2->Z3d ); + dty=mid_texty*mid_q-((float)p2->TY/(float)p2->Z3d ); + +// dtx=((float)(mid_textx>>7)/(float)mid_z-((float)p2->TX/(float)p2->Z3d )); +// dty=((float)(mid_texty>>7)/(float)mid_z-((float)p2->TY/(float)p2->Z3d )); + + poly->StepQ=(mid_q-q2)/length; + poly->StepShade=((mid_shade-(p2->Shade<<7))<<7)/length; + poly->FStepTextX=(dtx)/length; + poly->FStepTextY=(dty)/length; + } + else + if(dy_lhs>dy_rhs) + { + SLONG mid_shade,mid_x; +// SLONG mid_z; + float mid_textx,mid_texty; + float mid_q,ratiof; + + ratio=(dy_lhs<<16)/dy_rhs; + ratiof=(float)dy_lhs/(float)dy_rhs; + + mid_x =((p2->X -p1->X )<<16)/ratio+(p1->X ); + mid_shade=((p2->Shade-p1->Shade)<<23)/ratio+(p1->Shade<<7); +// mid_z =((p2->Z3d -p1->Z3d )<<16)/ratio+(p1->Z3d); + mid_textx=((float)(p2->TX - p1->TX))/ratiof+(p1->TX); + mid_texty=((float)(p2->TY - p1->TY))/ratiof+(p1->TY); + mid_q =(q2 -q1 )/ratiof+(q1); + + length=p3->X-(mid_x); + + if(length==0) + length=999999; + + dtx=((float)p3->TX/(float)p3->Z3d )-mid_textx*mid_q; + dty=((float)p3->TY/(float)p3->Z3d )-mid_texty*mid_q; + +// dtx=(((float)p3->TX/(float)p3->Z3d)-(float)mid_textx/(float)mid_z); +// dty=(((float)p3->TY/(float)p3->Z3d)-(float)mid_texty/(float)mid_z); + + poly->StepQ=(q3-mid_q)/length; + poly->StepShade=(((p3->Shade<<7)-mid_shade)<<7)/length; + poly->FStepTextX=(dtx)/length; + poly->FStepTextY=(dty)/length; + } +} +#undef FILTERING_ON + +void my_trigp(struct MfEnginePoint *p3,struct MfEnginePoint *p2,struct MfEnginePoint *p1) +{ + SLONG dx_lhs,dy_lhs,dx_rhs,dy_rhs,dx2,dy2; + +//shades + SLONG ds_lhs,ds_2; + float dtx_lhs,dty_lhs; + float dtx_2,dty_2; + + float q_lhs,dq_lhs,dq2,q1,q2,q3; + + SLONG flat_top=0; + SLONG f_dx=0,f_dy=0; +#ifdef FILTERING_ON + SLONG filtered=0,can_filter=0; +#endif + struct FloatPolyParameters poly; +// struct FPointer raster_fill; +// p1->Shade=1; + + if(is_it_clockwise(p1,p2,p3)) + return; + +#ifdef FILTERING_ON + if(poly_info.DrawFlags&POLY_FLAG_TEXTURED) + can_filter=can_texture_be_filtered(p1,p2,p3); +#endif +// raster_fill.FunctionPointer=p_functions[poly_info.DrawFlags&POLY_MODES].FunctionPointer; + + ASMtext_page=poly_info.PTexture; + if(ASMtext_page==0) + return; + + if(poly_info.DrawFlags&POLY_FLAG_TILED) + { + ASMtext_page+=calc_texture_offset(p1,p2,p3); +#ifdef FILTERING_ON + can_filter=0; +#endif + } + + if(p2->YY&&p2->Y<=p3->Y) + { // p2 is at top + + PSWAP(p2,p1); + PSWAP(p2,p3); //this to remain clockwise + } + else + if(p3->YY&&p3->Y<=p2->Y) + { + // p3 is at top + + { + PSWAP(p3,p1); + PSWAP(p3,p2); //this to remain clockwise + } + } + + + q1=1.0/(float)p1->Z3d; + q2=1.0/(float)p2->Z3d; + q3=1.0/(float)p3->Z3d; + +#ifdef FILTERING_ON + if(can_filter) + filtered=allready_filtered(p1,p2,p3,&f_dx,&f_dy); +#endif + +//we know p1 is the highest + { + dy_lhs=(p2->Y-p1->Y); + if(dy_lhs==0) //flat top with p2,p1 + { + float dtx,dty; + SLONG dist; + flat_top=1; + + dty_lhs=0; //((p2->TY-p1->TY)<<16)/dy_lhs; + dtx_lhs=0; //((p2->TX-p1->TX)<<16)/dy_lhs; + ds_lhs=0; //((p2->Shade-p1->Shade))/dy_lhs; + dx_lhs=0; + dq_lhs=0; + dist=p1->X-p2->X; + if(dist) + { + dtx=((float)p1->TX/(float)p1->Z3d-(float)p2->TX/(float)p2->Z3d); + dty=((float)p1->TY/(float)p1->Z3d-(float)p2->TY/(float)p2->Z3d); + + poly.StepShade=((p1->Shade-p2->Shade)<<14)/dist; + poly.FStepTextX=((dtx)/(float)dist); + poly.FStepTextY=((dty)/(float)dist); + } + } + else + { +// dty_lhs=((p2->TY-p1->TY)<<24)/dy_lhs; +// dtx_lhs=((p2->TX-p1->TX)<<24)/dy_lhs; + ds_lhs=((p2->Shade-p1->Shade)<<14)/dy_lhs; + dx_lhs=((p2->X-p1->X)<<16)/dy_lhs; + dq_lhs=((q2-q1))/dy_lhs; + + } + + dy_rhs=(p3->Y-p1->Y); + if(dy_rhs==0) //flat top with p3,p1 + { + float dtx,dty; + SLONG dist; + + dx_rhs=0; + + flat_top=1; + dist=p1->X-p3->X; + if(dist) + { + dtx=((float)p1->TX/(float)p1->Z3d)-((float)p3->TX/(float)p3->Z3d); + dty=((float)p1->TY/(float)p1->Z3d)-((float)p3->TY/(float)p3->Z3d); + + poly.StepShade=((p1->Shade-p3->Shade)<<14)/dist; + poly.FStepTextX=((dtx)/(float)dist); + poly.FStepTextY=((dty)/(float)dist); + } + } + else + { + dx_rhs=((p3->X-p1->X)<<16)/dy_rhs; + } + + poly.LeftShade=p1->Shade<<14; + poly.LeftX=(p1->X<<16);//+(1<<15); + poly.Q=q1; + poly.Y=p1->Y; + + if(!flat_top) + pcalc_steps_for_tri(p1,p2,p3,dy_lhs,dy_rhs,&poly); + +#ifdef FILTERING_ON +/*-----------** +** FILTERING ** +**-----------*/ + if(can_filter) + if(!filtered) +// if(Keys[KB_B]) +// if(abs(poly.StepTextX)< (1<<10) || abs(poly.StepTextY)< (1<<10)) + { + filtered=filter_poly_tmap(p1,p2,p3,&f_dx,&f_dy); + if(!flat_top&&filtered) + pcalc_steps_for_tri(p1,p2,p3,dy_lhs,dy_rhs,&poly); + + if(dy_lhs==0) + { + SLONG dist; + float dtx,dty; + dist=p1->X-p2->X; + if(dist) + { + dtx=((float)p1->TX/(float)p1->Z3d-(float)p2->TX/(float)p2->Z3d); + dty=((float)p1->TY/(float)p1->Z3d-(float)p2->TY/(float)p2->Z3d); + + poly.StepShade=((p1->Shade-p2->Shade)<<14)/dist; + poly.FStepTextX=(float)((dtx)/dist); + poly.FStepTextY=(float)((dty)/dist); + } + } + } +#endif + + if(dy_lhs!=0) + { + float dtx,dty; + dtx=((float)p2->TX/(float)p2->Z3d-(float)p1->TX/(float)p1->Z3d); + dty=((float)p2->TY/(float)p2->Z3d-(float)p1->TY/(float)p1->Z3d); + dtx_lhs=(float)(dtx)/dy_lhs; + dty_lhs=(float)(dty)/dy_lhs; + } + +//************************ END OF FILTERING + +//texturex step along sides + poly.FLeftTextX=(float)p1->TX/(float)p1->Z3d; +//texturey step along sides + poly.FLeftTextY=(float)p1->TY/(float)p1->Z3d; + + + + if(dy_lhsX-p2->X)<<16; + dx2=(temp_dx)/dy2; + dq2=(q3-q2)/dy2; + ds_2=((p3->Shade-p2->Shade)<<14)/dy2; + + dtx=((float)p3->TX/(float)p3->Z3d-(float)p2->TX/(float)p2->Z3d); + dty=((float)p3->TY/(float)p3->Z3d-(float)p2->TY/(float)p2->Z3d); + dtx_2=(dtx)/dy2; + dty_2=(dty)/dy2; + } + else + { //RHS shorter than LHS + + dy2=dy_lhs-dy_rhs; + if(dy2==0) + dy2=1; + dx2=((p2->X-p3->X)<<16)/dy2; + dq2=(q2-q3)/dy2; + + } + } +//now scan the edges and render between edges + { + SLONG count; +// CBYTE str[100]; + + poly.RightX=poly.LeftX; + + count=MIN(dy_rhs,dy_lhs); +// sprintf(str,"count %d,dy_lhs %d,dy_rhs %d",count,dy_lhs,dy_rhs); +// draw_text(80,0,str,32); + + if(count!=0) //if not flat top + { + if(poly.Y<0) // if clipped off top of screen + { + poly.Y=-poly.Y; // poly.Y is lines to skip + if(count>=poly.Y) + { // will be on screen before this count finishes + poly.LeftX+=dx_lhs*poly.Y; + poly.RightX+=dx_rhs*poly.Y; + poly.LeftShade+=ds_lhs*poly.Y; + + poly.FLeftTextX+=dtx_lhs*poly.Y; + poly.FLeftTextY+=dty_lhs*poly.Y; + poly.Q+=dq_lhs*poly.Y; + count-=poly.Y; + poly.Y=0; + + } + else + { + poly.LeftX+=dx_lhs*count; + poly.RightX+=dx_rhs*count; + poly.LeftShade+=ds_lhs*count; + + poly.FLeftTextX+=dtx_lhs*count; + poly.FLeftTextY+=dty_lhs*count; + poly.Y=-poly.Y+count; + poly.Q+=dq_lhs*count; + count=0; + } + } + if(poly.Y>=WorkWindowHeight) + goto clip_out; + + //do the top part of the triangle + while(count>0) + { + PSCAN_LINE_GT(&poly); +// raster_fill.FunctionPointer(&poly); +// SCAN_LINE_GT(&poly); +// SCAN_LINE_GT(poly.Y,poly.LeftX>>16,poly.RightX>>16,poly.LeftShade,poly.StepShade,poly.LeftTextX>>8,poly.StepTextX,poly.LeftTextY>>POLY_TEXT_SHIFT,poly.StepTextY); + poly.LeftX+=dx_lhs; + poly.RightX+=dx_rhs; + poly.LeftShade+=ds_lhs; + + poly.FLeftTextX+=dtx_lhs; + poly.FLeftTextY+=dty_lhs; + poly.Q+=dq_lhs; + poly.Y++; + count--; + if(poly.Y>=WorkWindowHeight) + goto clip_out; + } + } + else + { +// flat top +// ft=1; + if(p2->Y==p1->Y) + { + poly.FLeftTextY=(float)((float)p2->TY/(float)p2->Z3d); + poly.FLeftTextX=(float)((float)p2->TX/(float)p2->Z3d); + poly.LeftShade=p2->Shade<<14; + poly.LeftX=(p2->X<<16);//+(1<<15); + poly.Q=q2; + + poly.RightX=(p1->X<<16);//+(1<<15); + } + else + { + poly.FLeftTextY=(float)((float)p1->TY/(float)p1->Z3d); + poly.FLeftTextX=(float)((float)p1->TX/(float)p1->Z3d); + poly.LeftShade=p1->Shade<<14; + poly.LeftX=(p1->X<<16);//+(1<<15); + poly.Q=q1; + + poly.RightX=(p3->X<<16);//+(1<<15); + + } + + + } + + //setup for bottom half of tri + if(dy_lhsX<<16);//+(1<<15); + poly.FLeftTextY=(float)((float)p2->TY/(float)p2->Z3d); + poly.FLeftTextX=(float)((float)p2->TX/(float)p2->Z3d); + + } + else + { + //rhs kinks + + count=dy_lhs-dy_rhs; + dx_rhs=dx2; + } + + //clip + if(poly.Y<0) + { + poly.Y=-poly.Y; // poly.Y is lines to skip + if(count>=poly.Y) + { // will be on screen before this count finishes + poly.LeftX+=dx_lhs*poly.Y; + poly.RightX+=dx_rhs*poly.Y; + poly.LeftShade+=ds_lhs*poly.Y; + + poly.FLeftTextX+=(float)(dtx_lhs*poly.Y); + poly.FLeftTextY+=(float)(dty_lhs*poly.Y); + poly.Q+=dq_lhs*poly.Y; + count-=poly.Y; + poly.Y=0; + } + else + goto clip_out; + } + if(poly.Y>=WorkWindowHeight) + goto clip_out; + + + while(count>0) + { +// raster_fill.FunctionPointer(&poly); + PSCAN_LINE_GT(&poly); + + poly.LeftX+=dx_lhs; + poly.RightX+=dx_rhs; + poly.LeftShade+=ds_lhs; + poly.FLeftTextX+=dtx_lhs; + poly.FLeftTextY+=dty_lhs; + poly.Q+=dq_lhs; + poly.Y++; + count--; + if(poly.Y>=WorkWindowHeight) + goto clip_out; + } + } + +clip_out:; + +#ifdef FILTERING_ON + if(filtered) + { + p1->TX=(p1->TX>>1)+f_dx; + p1->TY=(p1->TY>>1)+f_dy; + p2->TX=(p2->TX>>1)+f_dx; + p2->TY=(p2->TY>>1)+f_dy; + p3->TX=(p3->TX>>1)+f_dx; + p3->TY=(p3->TY>>1)+f_dy; + } +#endif +// p1->Shade=128; +} + +void rotate_a_point(struct MfEnginePoint *p1,SLONG cx,SLONG cy,SLONG a) +{ + SLONG dx,dy; + + dx=p1->X-cx; + dy=p1->Y-cy; + + p1->X=(dx*COS(a)-dy*SIN(a))>>16; + p1->Y=(dx*SIN(a)+dy*COS(a))>>16; + + p1->X+=cx; + p1->Y+=cy; + +} + + + +struct Boint span_info[1024]; + + +void (*render_span)(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags); + +void render_span8(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags) +{ + SLONG width; + SLONG step_shade,step_tx,step_ty; + + width=p_b->RightX-p_b->LeftX; + if(width<=0) + return; +/* + step_shade=((p_b->RightShade - p_b->LeftShade))/width; + step_tx =((p_b->RightTX - p_b->LeftTX ))/width; + step_ty =((p_b->RightTY - p_b->LeftTY ))/width; +*/ + step_shade=QDIV64((p_b->RightShade - p_b->LeftShade),width+1); + step_tx =QDIV64((p_b->RightTX - p_b->LeftTX ),width+1); + step_ty =QDIV64((p_b->RightTY - p_b->LeftTY ),width+1); + + + + if(p_b->LeftX >= WorkWindowWidth || p_b -> RightX<0) + return; + + + if(p_b->RightX > WorkWindowWidth) + { + p_b->RightX = WorkWindowWidth; + width=p_b->RightX-p_b->LeftX; + if(width<=0) + return; + } + + if(p_b->LeftX < 0) + { + p_b->LeftShade+=step_shade*(-p_b->LeftX); + p_b->LeftTX+=step_tx*(-p_b->LeftX); + p_b->LeftTY+=step_ty*(-p_b->LeftX); + p_b->LeftX=0; + + width=p_b->RightX; + } +// ptr_screen=WorkWindow+p_b->LeftX+(WorkScreenWidth*y); + if(width) + { //"ASM" version + + ASMtx = p_b->LeftTX; + ASMty = p_b->LeftTY; + ASMshade= p_b->LeftShade; + + ptr_screen+=p_b->LeftX; +// RENDER_GO_GT(); + + switch(draw_flags&0x3f) + { + case POLY_F: +#ifdef _MSC_VER + RENDER_MSC_F(ptr_screen-1,width); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_COL(); + RENDER_GO_F(); +#endif + break; + case POLY_50F: +#ifdef _MSC_VER + RENDER_MSC_50F(ptr_screen-1,width); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_COL(); + RENDER_GO_50F(); +#endif + break; + case POLY_G: +#ifdef _MSC_VER + RENDER_MSC_G(ptr_screen-1,width,step_shade); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_COL(); + RENDER_GO_G(); +#endif + break; + case POLY_TGT: + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_TGT(); + break; + case POLY_GT: +#ifdef _MSC_VER + RENDER_MSC_GT(ptr_screen-1,width,step_shade,step_tx,step_ty); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_GT(); +#endif + break; + case POLY_MGT: +#ifdef _MSC_VER + RENDER_MSC_MGT(ptr_screen-1,width,step_shade,step_tx,step_ty); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_MGT(); +#endif + break; + case POLY_50GT: +#ifdef _MSC_VER + RENDER_MSC_50GT(ptr_screen-1,width,step_shade,step_tx,step_ty); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_50GT(); +#endif + break; + case POLY_50T: +#ifdef _MSC_VER + RENDER_MSC_50T(ptr_screen-1,width,step_tx,step_ty); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_50T(); +#endif + + break; + case POLY_50MGT: + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_50MGT(); + break; + case POLY_MT: +#ifdef _MSC_VER + RENDER_MSC_MT(ptr_screen-1,width,step_tx,step_ty); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_MT(); +#endif + break; + case POLY_T: +#ifdef _MSC_VER + RENDER_MSC_T(ptr_screen-1,width,step_tx,step_ty); +#else + RENDER_SETUP(ptr_screen-1,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_T(); +#endif + break; + } + + } + +// *ptr_screen=255; +// *(ptr_screen+(width)-1)=255; +} + +void render_span16(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags) +{ + SLONG width; + SLONG step_shade,step_tx,step_ty; + + width=p_b->RightX-p_b->LeftX; + + //p_b->LeftShade<<=2; + //p_b->RightShade<<=2; + + if(width<=0) + return; + step_shade=QDIV64((p_b->RightShade - p_b->LeftShade),width+1); + step_tx =QDIV64((p_b->RightTX - p_b->LeftTX ),width+1); + step_ty =QDIV64((p_b->RightTY - p_b->LeftTY ),width+1); + + if(p_b->LeftX >= WorkWindowWidth || p_b -> RightX<0) + return; + + + if(p_b->RightX > WorkWindowWidth) + { + p_b->RightX = WorkWindowWidth; + width=p_b->RightX-p_b->LeftX; + if(width<=0) + return; + } + + if(p_b->LeftX < 0) + { + p_b->LeftShade+=step_shade*(-p_b->LeftX); + p_b->LeftTX+=step_tx*(-p_b->LeftX); + p_b->LeftTY+=step_ty*(-p_b->LeftX); + p_b->LeftX=0; + + width=p_b->RightX; + } +// ptr_screen=WorkWindow+p_b->LeftX+(WorkScreenWidth*y); + if(width) + { //"ASM" version + + ASMtx = p_b->LeftTX; + ASMty = p_b->LeftTY; + ASMshade= p_b->LeftShade; + + ptr_screen+=p_b->LeftX*2; + + switch(draw_flags&0x3f) + { + case POLY_G: +#ifdef _MSC_VER + RENDER_MSC_G16(ptr_screen-2,width,step_shade); +#endif + break; + case POLY_F: +#ifdef _MSC_VER + RENDER_MSC_F16(ptr_screen-2,width); +#endif + break; + case POLY_MT: +#ifdef _MSC_VER + RENDER_MSC_MT16(ptr_screen-2,width,step_tx,step_ty); +#endif + break; + case POLY_T: +#ifdef _MSC_VER + RENDER_MSC_T16(ptr_screen-2,width,step_tx,step_ty); + +#endif + break; + case POLY_TGT: +#ifdef _MSC_VER + RENDER_MSC_TGT16(ptr_screen-2,width,step_shade,step_tx,step_ty); +#endif + break; + + case POLY_GT: +#ifdef _MSC_VER + if(ASMtext_page) + RENDER_MSC_GT16(ptr_screen-2,width,step_shade,step_tx,step_ty); + else + { + LogText(" weirdness\n"); + } +#else + RENDER_SETUP(ptr_screen-2,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_GT16(); +#endif + break; + case POLY_MGT: +#ifdef _MSC_VER + RENDER_MSC_MGT16(ptr_screen-2,width,step_shade,step_tx,step_ty); +#endif + default: + break; + } + } +} + +void render_span32(struct Boint *p_b,UBYTE *ptr_screen,SLONG draw_flags) +{ + SLONG width; + SLONG step_shade,step_tx,step_ty; + + width=p_b->RightX-p_b->LeftX; + if(width<=0) + return; + + p_b->LeftShade<<=2; + p_b->RightShade<<=2; +/* + step_shade=((p_b->RightShade - p_b->LeftShade))/width; + step_tx =((p_b->RightTX - p_b->LeftTX ))/width; + step_ty =((p_b->RightTY - p_b->LeftTY ))/width; +*/ + step_shade=QDIV64((p_b->RightShade - p_b->LeftShade),width); + step_tx =QDIV64((p_b->RightTX - p_b->LeftTX ),width); + step_ty =QDIV64((p_b->RightTY - p_b->LeftTY ),width); + + + + if(p_b->LeftX >= WorkWindowWidth || p_b -> RightX<0) + return; + + + if(p_b->RightX >= WorkWindowWidth) + { + p_b->RightX = WorkWindowWidth-1; + width=p_b->RightX-p_b->LeftX; + if(width<=0) + return; + } + + if(p_b->LeftX < 0) + { + p_b->LeftShade+=step_shade*(-p_b->LeftX); + p_b->LeftTX+=step_tx*(-p_b->LeftX); + p_b->LeftTY+=step_ty*(-p_b->LeftX); + p_b->LeftX=0; + + width=p_b->RightX; + } + if(width) + { //"ASM" version + + ASMtx = p_b->LeftTX; + ASMty = p_b->LeftTY; + ASMshade= p_b->LeftShade; + + ptr_screen+=p_b->LeftX*4; + + switch(draw_flags&0x1f) + { + default: + RENDER_SETUP(ptr_screen-4,width,step_shade,step_tx,step_ty); + RENDER_SETUP2(); + RENDER_GO_GT32(); + break; + } + } +} + +#define FILTERING_ON 1 + + +inline void average_points(struct MfEnginePoint *mid,struct MfEnginePoint *p1,struct MfEnginePoint *p2) +{ + mid->X=(p1->X+p2->X)>>1; + mid->Y=(p1->Y+p2->Y)>>1; + mid->TX=(p1->TX+p2->TX)>>1; + mid->TY=(p1->TY+p2->TY)>>1; + mid->Shade=(p1->Shade+p2->Shade)>>1; +} + +inline void pers_average_points(struct MfEnginePoint *mid,struct MfEnginePoint *p1,struct MfEnginePoint *p2) +{ + float as,at,aq; + float az,atx,aty; + + atx=((float)(p1->TX+p2->TX ))/2.0; + aty=((float)(p1->TY+p2->TY ))/2.0; +/* + az=((float)(p1->Z3d+p2->Z3d))/2.0; + + aq=1.0/az; + + as=atx/az; + + + at=aty/az; +*/ + aq=((1.0/(float)p1->Z3d)+(1.0/(float)p2->Z3d))/2.0; + + as=atx*aq; + at=aty*aq; + + mid->X=(p1->X+p2->X)>>1; + mid->Y=(p1->Y+p2->Y)>>1; + mid->TX=(SLONG)(as/aq); + mid->TY=(SLONG)(at/aq); + mid->Shade=(p1->Shade+p2->Shade)>>1; + mid->Z3d=(p1->Z3d+p2->Z3d)>>1; +} + +inline void pers_average_points4(struct MfEnginePoint *mid,struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4) +{ + float as,at,aq; + float az,atx,aty; + + + atx=((float)(p1->TX+p2->TX+p3->TX+p4->TX))/4.0; + aty=((float)(p1->TY+p2->TY+p3->TY+p4->TY))/4.0; +/* + az=((float)(p1->Z3d+p2->Z3d+p3->Z3d+p4->Z3d))/4.0; + + aq=1.0/az; + as=atx/az; + at=aty/az; +*/ + aq=((1.0/(float)p1->Z3d)+(1.0/(float)p2->Z3d)+(1.0/(float)p3->Z3d)+(1.0/(float)p4->Z3d))/2.0; + + as=atx*aq; + at=aty*aq; + + + mid->X=(p1->X+p2->X+p3->X+p4->X)>>2; + mid->Y=(p1->Y+p2->Y+p3->Y+p4->Y)>>2; + mid->TX=(SLONG)(as/aq); + mid->TY=(SLONG)(at/aq); + mid->Shade=(p1->Shade+p2->Shade+p3->Shade+p4->Shade)>>2; + mid->Z3d=(p1->Z3d+p2->Z3d+p3->Z3d+p4->Z3d)>>2; +} + +inline void average_points4(struct MfEnginePoint *mid,struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4) +{ + mid->X=(p1->X+p2->X+p3->X+p4->X)>>2; + mid->Y=(p1->Y+p2->Y+p3->Y+p4->Y)>>2; + mid->TX=(p1->TX+p2->TX+p3->TX+p4->TX)>>2; + mid->TY=(p1->TY+p2->TY+p3->TY+p4->TY)>>2; + mid->Shade=(p1->Shade+p2->Shade+p3->Shade+p4->Shade)>>2; +} + +//scan from p1 to p2 filling in the span info +inline void scan_a_line_noz(struct MfEnginePoint *p1,struct MfEnginePoint *p2) +{ + SLONG dx,dy,cx,cy; + SLONG tx,ty,dtx,dty; + SLONG shade,d_shade; + SLONG side=0; + struct Boint *ptr_side; + { +/* + CBYTE str[100]; + sprintf(str,"(%d,%d)",p1->X,p1->Y); + QuickTextC(p1->X,p1->Y,str,0); + QuickTextC(p1->X+1,p1->Y+1,str,255); + + sprintf(str,"(%d,%d)",p2->X,p2->Y); + QuickTextC(p2->X,p2->Y,str,0); + QuickTextC(p2->X+1,p2->Y+1,str,255); +*/ + + + } + if(p1->Y>p2->Y) + { + struct MfEnginePoint *ptemp; + ptemp=p2; + p2=p1; + p1=ptemp; + side=1; + } + + + dy=p2->Y-p1->Y; + dx=p2->X-p1->X; + + if(dy==0) + return; + + cx=p1->X<<16; + cy=p1->Y; + + + tx=p1->TX<<16; + ty=p1->TY<<16; + + dtx=p2->TX-p1->TX; + dty=p2->TY-p1->TY; + + shade = (p1->Shade)<<14; //14 + d_shade = (p2->Shade-p1->Shade); + + + if(dy==0) + { + return; + } + else + { + + dx = (dx<<16)/dy; +// dx = QDIV64((dx<<16),dy); + dtx = QDIV64((dtx<<16),dy); + dty = QDIV64((dty<<16),dy); + d_shade = QDIV64((d_shade<<14),dy); //14 + + + if(cy<0) + { + SLONG over=-cy; + + cx += dx*over; + tx += dtx*over; + ty += dty*over; + shade+= d_shade*over; + dy-=over; + cy = 0; + if(dy<=0) + { + return; + } + } + + ptr_side=&span_info[cy]; + + if(side==0) + { + + for(;dy>=0;dy--,cy++) + { + if(cy>WorkWindowHeight) + { + return; + } + + ptr_side->RightX = (cx)>>16; + ptr_side->RightTX= tx; + ptr_side->RightTY= ty; + ptr_side->RightShade=shade; + + cx += dx; + tx += dtx; + ty += dty; + shade+= d_shade; + ptr_side++; + } + (ptr_side-1)->RightX = p2->X; + } + else + { + for(;dy>=0;dy--,cy++) + { + if(cy>WorkWindowHeight) + { + return; + } + + ptr_side->LeftX = (cx)>>16; + ptr_side->LeftTX= tx; + ptr_side->LeftTY= ty; + ptr_side->LeftShade=shade; + + cx += dx; + tx += dtx; + ty += dty; + shade+= d_shade; + ptr_side++; + } + (ptr_side-1)->LeftX = p2->X; + } + } +} + +/* + p1 p5 p2 + + + p8 p9 p6 + + + p4 p7 p3 +*/ + + +void my_quad_noz(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3,struct MfEnginePoint *p4) +{ + SLONG top,bottom; + SLONG left,right; + struct Boint *p_span; + UBYTE *ptr_screen; + +#ifdef FILTERING_ON + SLONG f_dx=0,f_dy=0; + SLONG filtered=0,can_filter=0; +#endif + + top = MIN( MIN( MIN(p1->Y,p2->Y),p3->Y ),p4->Y ); + bottom = MAX( MAX( MAX(p1->Y,p2->Y),p3->Y ),p4->Y ); + + left = MIN( MIN( MIN(p1->X,p2->X),p3->X ),p4->X ); + right = MAX( MAX( MAX(p1->X,p2->X),p3->X ),p4->X ); + ASMCol=poly_info.Col; + ASMfade_page=yc_to_555[poly_info.Page]; + ASMpal_address=&yc_to_555[poly_info.Page][32*256]; + + +/* + if(bottom-top>128||right-left>128) + { + struct MfEnginePoint p5,p6,p7,p8,p9; + + average_points(&p5,p1,p2); + average_points(&p6,p2,p3); + average_points(&p7,p3,p4); + average_points(&p8,p4,p1); + average_points4(&p9,p1,p2,p3,p4); + + my_quad(&p8,p1,&p5,&p9); + my_quad(&p5,p2,&p6,&p9); + my_quad(&p7,&p9,&p6,p3); + my_quad(&p8,&p9,&p7,p4); + return; + } +*/ + + if(bottom<0||top>=WorkWindowHeight) + return; + +#ifdef FILTERING_ON + if(poly_info.DrawFlags&POLY_FLAG_TEXTURED) + can_filter=can_texture_be_filtered4(p1,p2,p3,p4); +#endif + + ASMtext_page=poly_info.PTexture; + if(ASMtext_page==0) + return; + if(poly_info.DrawFlags&POLY_FLAG_TILED) + { + ASMtext_page+=calc_texture_offset4(p1,p2,p3,p4); +#ifdef FILTERING_ON + can_filter=0; +#endif + } + +/*-----------** +** FILTERING ** +**-----------*/ +#ifdef FILTERING_ON + if(can_filter) + filtered=allready_filtered4(p1,p2,p3,p4,&f_dx,&f_dy); + + if(can_filter&&!filtered) + { + filtered=filter_poly_tmap4(p1,p2,p3,p4,&f_dx,&f_dy); + } +#endif + + + scan_a_line_noz(p1,p2); + scan_a_line_noz(p2,p3); + scan_a_line_noz(p3,p4); + scan_a_line_noz(p4,p1); + + + if(top<0) + top=0; + if(bottom>WorkWindowHeight) + bottom=WorkWindowHeight; + + p_span=&span_info[top]; +// ptr_screen=WorkWindow+p_b->LeftX+(WorkScreenWidth*y); + ptr_screen=WorkWindow+top*WorkScreenWidth; //(UBYTE*)((ULONG)WorkWindow+(ULONG)top(ULONG)*WorkScreenWidth); + for(;topTX=(p1->TX>>1)+f_dx; + p1->TY=(p1->TY>>1)+f_dy; + p2->TX=(p2->TX>>1)+f_dx; + p2->TY=(p2->TY>>1)+f_dy; + p3->TX=(p3->TX>>1)+f_dx; + p3->TY=(p3->TY>>1)+f_dy; + p4->TX=(p4->TX>>1)+f_dx; + p4->TY=(p4->TY>>1)+f_dy; + } +#endif + + +} + + +void my_trig_noz(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p3) +{ + SLONG top,bottom; + SLONG left,right; + struct Boint *p_span; + UBYTE *ptr_screen; + +#ifdef FILTERING_ON + SLONG f_dx=0,f_dy=0; + SLONG filtered=0,can_filter=0; +#endif + + top = MIN( MIN(p1->Y,p2->Y),p3->Y ); + bottom = MAX( MAX(p1->Y,p2->Y),p3->Y ); + + left = MIN( MIN(p1->X,p2->X),p3->X ); + right = MAX( MAX(p1->X,p2->X),p3->X ); + ASMCol=poly_info.Col; + ASMfade_page=&yc_to_555[poly_info.Page][0]; + ASMpal_address=&yc_to_555[poly_info.Page][32*256]; + + if(bottom<0||top>=WorkWindowHeight) + return; + +#ifdef FILTERING_ON + if(poly_info.DrawFlags&POLY_FLAG_TEXTURED) + can_filter=can_texture_be_filtered(p1,p2,p3); +#endif + + ASMtext_page=poly_info.PTexture; + if(ASMtext_page==0) + return; + + if(poly_info.DrawFlags&POLY_FLAG_TILED) + { + ASMtext_page+=calc_texture_offset(p1,p2,p3); +#ifdef FILTERING_ON + can_filter=0; +#endif + } + +/*-----------** +** FILTERING ** +**-----------*/ +#ifdef FILTERING_ON + if(can_filter) + filtered=allready_filtered(p1,p2,p3,&f_dx,&f_dy); + + if(can_filter&&!filtered) + { + filtered=filter_poly_tmap(p1,p2,p3,&f_dx,&f_dy); + } +#endif + + + scan_a_line_noz(p1,p2); + scan_a_line_noz(p2,p3); + scan_a_line_noz(p3,p1); + + if(top<0) + top=0; + if(bottom>WorkWindowHeight) + bottom=WorkWindowHeight; + + p_span=&span_info[top]; +// ptr_screen=WorkWindow+p_b->LeftX+(WorkScreenWidth*y); + ptr_screen=WorkWindow+top*WorkScreenWidth; //(UBYTE*)((ULONG)WorkWindow+(ULONG)top(ULONG)*WorkScreenWidth); + for(;topTX=(p1->TX>>1)+f_dx; + p1->TY=(p1->TY>>1)+f_dy; + p2->TX=(p2->TX>>1)+f_dx; + p2->TY=(p2->TY>>1)+f_dy; + p3->TX=(p3->TX>>1)+f_dx; + p3->TY=(p3->TY>>1)+f_dy; + } +#endif + + +} + + +ULONG poly_def; +//scan from p1 to p2 filling in the span info +inline void scan_a_line(struct Boint *p_b,SLONG top,struct MfEnginePoint *p1,struct MfEnginePoint *p2) +{ + SLONG dx,dy,cx,cy,dz,cz; + SLONG tx,ty,dtx,dty; + SLONG shade,d_shade; + struct Boint *ptr_side; + + dz=p2->Z3d-p1->Z3d; + dy=p2->Y-p1->Y; + dx=p2->X-p1->X; + + if(dy==0) + { + return; + } + + cz=p1->Z3d<<16; + cx=p1->X<<16; + cy=p1->Y; + + + tx=p1->TX<<16; + ty=p1->TY<<16; + + dtx=p2->TX-p1->TX; + dty=p2->TY-p1->TY; + + shade = (p1->Shade)<<14; //14 + d_shade = (p2->Shade-p1->Shade); + + + if(dy==0) + { + return; + } + else + if(dy<0) + { + + dy=-dy; + + dx = (dx<<16)/dy; + dz = (dz<<16)/dy; +// dx = QDIV64((dx<<16),dy); + dtx = QDIV64((dtx<<16),dy); + dty = QDIV64((dty<<16),dy); + d_shade = QDIV64((d_shade<<14),dy); //14 + + if(cy>=WorkWindowHeight) + { + SLONG over=cy-(WorkWindowHeight-1); + + cz += dz*over; + cx += dx*over; + tx += dtx*over; + ty += dty*over; + shade+= d_shade*over; + dy -=over; + cy = WorkWindowHeight-1; + if(dy<=0) + { + + return; + } + } + + +// ptr_side=&span_info[cy]; + ptr_side=&p_b[cy-top]; + + for(;dy>=0;dy--,cy--) + { + if(cy<0) + { + return; + } + ptr_side->LeftX = cx>>16; + ptr_side->LeftZ = cz>>16; + ptr_side->LeftTX= tx; + ptr_side->LeftTY= ty; + ptr_side->LeftShade=shade; + ptr_side->DrawFlags=poly_info.DrawFlags; + +// ptr_side->Y=cy; + + cx += dx; + cz += dz; + tx += dtx; + ty += dty; + shade+= d_shade; + ptr_side--; + } + } + else + { + + dx = (dx<<16)/dy; + dz = (dz<<16)/dy; +// dx = QDIV64((dx<<16),dy); + dtx = QDIV64((dtx<<16),dy); + dty = QDIV64((dty<<16),dy); + d_shade = QDIV64((d_shade<<14),dy); //14 + + + if(cy<0) + { + SLONG over=-cy; + + cz += dz*over; + cx += dx*over; + tx += dtx*over; + ty += dty*over; + shade+= d_shade*over; + dy-=over; + cy = 0; + if(dy<=0) + { + return; + } + } + +// ptr_side=&span_info[cy]; + ptr_side=&p_b[cy-top]; + + for(;dy>=0;dy--,cy++) + { + if(cy>=WorkWindowHeight) + { + return; + } + + ptr_side->RightX = cx>>16; + ptr_side->RightZ = cz>>16; + ptr_side->RightTX= tx; + ptr_side->RightTY= ty; + ptr_side->RightShade=shade; + +// ptr_side->Y=cy; + cx += dx; + cz += dz; + tx += dtx; + ty += dty; + shade+= d_shade; + ptr_side++; + } + } +} + +/* + p1 p5 p2 + + + p8 p9 p6 + + + p4 p7 p3 +*/ + +#undef FILTERING_ON +void my_quad(struct MfEnginePoint *p1,struct MfEnginePoint *p2,struct MfEnginePoint *p4,struct MfEnginePoint *p3) +{ + SLONG top,bottom; + SLONG left,right; + struct Boint *p_span; + UBYTE *ptr_screen; + +#ifdef FILTERING_ON + SLONG f_dx=0,f_dy=0; + SLONG filtered=0,can_filter=0; +#endif + ASMCol=poly_info.Col; + if(!is_it_clockwise(p1,p2,p3)) + return; + p1->X%=320; + p2->X%=320; + p3->X%=320; + p4->X%=320; + + p1->Y%=200; + p2->Y%=200; + p3->Y%=200; + p4->Y%=200; + + top = MIN( MIN( MIN(p1->Y,p2->Y),p3->Y ),p4->Y ); + bottom = MAX( MAX( MAX(p1->Y,p2->Y),p3->Y ),p4->Y ); + + left = MIN( MIN( MIN(p1->X,p2->X),p3->X ),p4->X ); + right = MAX( MAX( MAX(p1->X,p2->X),p3->X ),p4->X ); + + + if(bottom<0||top>=WorkWindowHeight) + return; + + ASMtext_page=poly_info.PTexture; + if(ASMtext_page==0) + return; + + poly_def=(ULONG)p1*(ULONG)p2*(ULONG)p3; +/*-----------** +** FILTERING ** +**-----------*/ +#ifdef FILTERING_ON +// if(poly_info.DrawFlags&POLY_FLAG_TEXTURED) + can_filter=can_texture_be_filtered4(p1,p2,p3,p4); + + if(can_filter) + filtered=allready_filtered4(p1,p2,p3,p4,&f_dx,&f_dy); + + if(can_filter&&!filtered) + { + filtered=filter_poly_tmap4(p1,p2,p3,p4,&f_dx,&f_dy); + } +#endif + if(top<0) + top=0; + if(bottom>WorkWindowHeight) + bottom=WorkWindowHeight; + + scan_a_line(current_boint,top,p1,p2); + scan_a_line(current_boint,top,p2,p3); + scan_a_line(current_boint,top,p3,p4); + scan_a_line(current_boint,top,p4,p1); + + + + { + struct Boint **p_head; + p_head=&z_spans[top]; + p_span=current_boint; //[top]; + current_boint+=(bottom-top)+1; + next_boint+=(bottom-top); + if(next_bointLeftZ=(p_span->LeftZ+p_span->RightZ)>>1; + insert_span(p_span,p_head); + p_span++; + p_head++; + } + } + +//clip_out:; + +#ifdef FILTERING_ON + if(filtered) + { + p1->TX=(p1->TX>>1)+f_dx; + p1->TY=(p1->TY>>1)+f_dy; + p2->TX=(p2->TX>>1)+f_dx; + p2->TY=(p2->TY>>1)+f_dy; + p3->TX=(p3->TX>>1)+f_dx; + p3->TY=(p3->TY>>1)+f_dy; + p4->TX=(p4->TX>>1)+f_dx; + p4->TY=(p4->TY>>1)+f_dy; + } +#endif +} + + +void draw_a_single_span(UBYTE *p_screen,struct Boint p_b) +{ + +} +void draw_all_spans(void) +{ + SLONG c0; + SLONG count; + struct Boint **b,*p_c; + UBYTE *p_screen; + ULONG dont_draw=0,dump=0; + SLONG y=0; + if(Keys[KB_A]) + dont_draw=1; + if(Keys[KB_D]) + dump=1; + + p_screen=WorkWindow; + b=&z_spans[0]; + for(c0=0;c0>1;c0++) + { + p_c=*b; + count=0; + if(!dont_draw) + while(p_c&&count++<150) + { + render_span(p_c,p_screen,p_c->DrawFlags); +#ifdef DEBUG_SPAN + p_screen[count]=count+1; +#endif + p_c=p_c->PNext; + } + if(dump) + { + CBYTE str[100]; + sprintf(str," DUMP SCREEN y %d ",y); + show_line(b,str); + } + if(MouseY==y&&LeftButton) + { + show_line(b,"WHOLE SPAN"); + LeftButton=0; + } + *b=0; + b++; + y++; + p_screen+=WorkScreenWidth; + } + current_boint=&boint_pool[0]; + { + CBYTE str[100]; + sprintf(str,"Z BUFFERED %d cfind %d cin %d clhs %d crhs %d",next_boint,count_find,count_insert,count_chop_lhs,count_chop_rhs); + QuickTextC(10,50,str,255); + + } + next_boint=1; + count_find=0,count_insert=0,count_chop_lhs=0,count_chop_rhs=0; +} + +void test_poly(void) +{ + static struct MfEnginePoint p1,p2,p3,p4,p5,p6; + static init=0; + + if(init==0) + { + init=1; + p1.Z3d=64; + p1.X=108; + p1.Y=84+100; + p1.TX=0; + p1.TY=0; + p1.Shade=128; + + p2.Z3d=64; + p2.X=268; + p2.Y=84+100; + p2.TX=31; + p2.TY=0; + p2.Shade=128; + + p3.Z3d=64; + p3.X=427; + p3.Y=284+100; + p3.TX=0; + p3.TY=31; + p3.Shade=128; + + p4.Z3d=64; + p4.X=164; + p4.Y=20+100; + p4.TX=31; + p4.TY=31; + p4.Shade=128; + + p5.X=260; + p5.Y=352; + p5.TX=196; + p5.TY=0; + p5.Shade=128; + + p6.X=457; + p6.Y=352; + p6.TX=0; + p6.TY=196; + p6.Shade=128; + + + } + + if(Keys[KB_PLUS]) + { + Keys[KB_PLUS]=0; + p1.TX<<=1; + p1.TY<<=1; + p2.TX<<=1; + p2.TY<<=1; + p3.TX<<=1; + p3.TY<<=1; + p4.TX<<=1; + p4.TY<<=1; + } + + if(Keys[KB_MINUS]) + { + Keys[KB_MINUS]=0; + p1.TX>>=1; + p1.TY>>=1; + p2.TX>>=1; + p2.TY>>=1; + p3.TX>>=1; + p3.TY>>=1; + p4.TX>>=1; + p4.TY>>=1; + } + + if(Keys[KB_G]&&!ShiftFlag) + { + + rotate_a_point(&p1,200,200,1); + rotate_a_point(&p2,200,200,1); + rotate_a_point(&p3,200,200,1); + rotate_a_point(&p4,200,200,1); + + } + + if(Keys[KB_H]&&!ShiftFlag) + p2.X++; + if(Keys[KB_H]&&ShiftFlag) + p2.X--; + + if(Keys[KB_J]&&!ShiftFlag) + p3.X++; + if(Keys[KB_J]&&ShiftFlag) + p3.X--; + + if(Keys[KB_K]&&!ShiftFlag) + p4.X++; + if(Keys[KB_K]&&ShiftFlag) + p4.X--; + + if(Keys[KB_V]&&!ShiftFlag) + p1.Y++; + if(Keys[KB_V]&&ShiftFlag) + p1.Y--; + + if(Keys[KB_B]&&!ShiftFlag) + p2.Y++; + if(Keys[KB_B]&&ShiftFlag) + p2.Y--; + + if(Keys[KB_N]&&!ShiftFlag) + p3.Y++; + if(Keys[KB_N]&&ShiftFlag) + p3.Y--; + + if(Keys[KB_M]&&!ShiftFlag) + p4.Y++; + if(Keys[KB_M]&&ShiftFlag) + p4.Y--; + + poly_info.Page=0; + poly_info.PTexture=tmaps[0]; + poly_info.DrawFlags=POLY_FLAG_GOURAD|POLY_FLAG_SEMI_TRANS; //|POLY_FLAG_TEXTURED; + poly_info.Col=255; + my_trig(&p1,&p2,&p3); + my_trig(&p3,&p2,&p1); + my_trig(&p1,&p2,&p4); + my_trig(&p4,&p2,&p1); +// my_trigp(&p4,&p2,&p1); +} + + +#define DITHER_WIDTH 256 +void double_work_window(void) +{ + UBYTE *ptr_s,*ptr_d; + SLONG x=0,y=0; + ptr_s=WorkWindow; + ptr_d=WorkWindow; + if(Keys[KB_D]) + { + for(y=(WorkWindowHeight/2)-1;y>=0;y--) + { + for(x=(WorkWindowWidth/2)-1;x>=0;x--) + { + ptr_d[(x*2)+(y*2*WorkScreenWidth)]=ptr_s[(x)+(y*WorkScreenWidth)]; + ptr_d[(x*2+1)+(y*2*WorkScreenWidth)]=ptr_s[(x)+(y*WorkScreenWidth)]; + } + } + for(y=1;y=0;y--) + { + for(x=(WorkWindowWidth/2)-1;x>=0;x--) + { + ptr_d[(x*2)+(y*2*WorkScreenWidth)]=ptr_s[(x)+(y*WorkScreenWidth)]; + } + } + for(y=0;yX*COS(angle_x)-point->Z*SIN(angle_x); + rz=point->X*SIN(angle_x)+point->Z*COS(angle_x); + + point->X=rx>>16; + point->Z=rz>>16; +} +*/ +SLONG angle_prim_y=0; +void rotate_prim_thing(UWORD thing) +{ + +// anglex=map_things[thing].AngleY; + if(LastKey==KB_H) + { + LastKey=0; + angle_prim_y+=64; + angle_prim_y=((angle_prim_y+2048)&2047); + } + if(LastKey==KB_J) + { + LastKey=0; + angle_prim_y-=64; + angle_prim_y=((angle_prim_y+2048)&2047); + } + map_things[thing].AngleY=angle_prim_y; + + /* + SLONG c0; + struct PrimObject *p_obj,*p_obj_o; + struct PrimPoint p; + SLONG sp,ep,offset_p; + + p_obj =&prim_objects[map_things[thing].IndexOther]; + p_obj_o =&prim_objects[map_things[thing].IndexOrig]; + + if( (p_obj->EndPoint-p_obj->StartPoint)!=(p_obj_o->EndPoint-p_obj_o->StartPoint) ) + return; + + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + offset_p=sp-p_obj_o->StartPoint; + + if(LastKey==KB_H) + { + LastKey=0; + angle_x+=64; + angle_x=((angle_x+2048)&2047); + } + if(LastKey==KB_J) + { + LastKey=0; + angle_x-=64; + angle_x=((angle_x+2048)&2047); + } + + for(c0=sp;c0SetValueRange(0,266/3); + ((CVSlider*)GetControlPtr(CTRL_PRIM_V_SLIDE_PRIM))->SetCurrentValue(0); + ((CVSlider*)GetControlPtr(CTRL_PRIM_V_SLIDE_PRIM))->SetUpdateFunction(redraw_all_prims); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + PrimScale=2688; + BackScale=40; + UpdatePrimInfo(); +} + +PrimPickTab::~PrimPickTab() +{ + UBYTE blah = 1; +} + +//--------------------------------------------------------------- + +void PrimPickTab::UpdatePrimInfo(void) +{ + // + // Checks/unchecks the collide buttons. + // + + SetControlState(CTRL_PRIM_COLLIDE_NONE, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_COLLIDE_BOX, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_COLLIDE_CYLINDER, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_COLLIDE_SMALLBOX, CTRL_DESELECTED); + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + switch(prim_objects[CurrentPrim].coltype) + { + case PRIM_COLLIDE_NONE: SetControlState(CTRL_PRIM_COLLIDE_NONE, CTRL_SELECTED); break; + case PRIM_COLLIDE_BOX: SetControlState(CTRL_PRIM_COLLIDE_BOX, CTRL_SELECTED); break; + case PRIM_COLLIDE_CYLINDER: SetControlState(CTRL_PRIM_COLLIDE_CYLINDER, CTRL_SELECTED); break; + case PRIM_COLLIDE_SMALLBOX: SetControlState(CTRL_PRIM_COLLIDE_SMALLBOX, CTRL_SELECTED); break; + } + } + + // + // Checks/unchecks the shadow buttons. + // + + SetControlState(CTRL_PRIM_SHADOW_NONE, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_SHADOW_BOXEDGE, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_SHADOW_CYLINDER, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_SHADOW_FOURLEGS, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_SHADOW_FULLBOX, CTRL_DESELECTED); + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + switch(prim_objects[CurrentPrim].shadowtype) + { + case PRIM_SHADOW_NONE: SetControlState(CTRL_PRIM_SHADOW_NONE, CTRL_SELECTED); break; + case PRIM_SHADOW_BOXEDGE: SetControlState(CTRL_PRIM_SHADOW_BOXEDGE, CTRL_SELECTED); break; + case PRIM_SHADOW_CYLINDER: SetControlState(CTRL_PRIM_SHADOW_CYLINDER, CTRL_SELECTED); break; + case PRIM_SHADOW_FOURLEGS: SetControlState(CTRL_PRIM_SHADOW_FOURLEGS, CTRL_SELECTED); break; + case PRIM_SHADOW_FULLBOX: SetControlState(CTRL_PRIM_SHADOW_FULLBOX, CTRL_SELECTED); break; + } + } + + // + // The prim flags. + // + + SetControlState(CTRL_PRIM_FLAG_LAMPOST, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_FLAG_GLARE, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_FLAG_ON_FLOOR, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_FLAG_TREE, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_FLAG_JUST_FLOOR, CTRL_DESELECTED); + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + if (prim_objects[CurrentPrim].flag & PRIM_FLAG_LAMPOST ) {SetControlState(CTRL_PRIM_FLAG_LAMPOST, CTRL_SELECTED);} + if (prim_objects[CurrentPrim].flag & PRIM_FLAG_GLARE) {SetControlState(CTRL_PRIM_FLAG_GLARE, CTRL_SELECTED);} + if (prim_objects[CurrentPrim].flag & PRIM_FLAG_ON_FLOOR) {SetControlState(CTRL_PRIM_FLAG_ON_FLOOR, CTRL_SELECTED);} + if (prim_objects[CurrentPrim].flag & PRIM_FLAG_JUST_FLOOR) {SetControlState(CTRL_PRIM_FLAG_JUST_FLOOR, CTRL_SELECTED);} + if (prim_objects[CurrentPrim].flag & PRIM_FLAG_TREE) {SetControlState(CTRL_PRIM_FLAG_TREE, CTRL_SELECTED);} + } + + if (edit_info.Inside ) + { + SetControlState(CTRL_PRIM_FLAG_INSIDE, CTRL_SELECTED); + } + else + { + SetControlState(CTRL_PRIM_FLAG_INSIDE, CTRL_DESELECTED); + } + + // + // Checks/unchecks the damageable flags. + // + + SetControlState(CTRL_PRIM_DAMAGABLE, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_LEANS, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_CRUMPLES, CTRL_DESELECTED); + SetControlState(CTRL_PRIM_EXPLODES, CTRL_DESELECTED); + + if (prim_objects[CurrentPrim].damage & PRIM_DAMAGE_DAMAGABLE) + { + SetControlState(CTRL_PRIM_DAMAGABLE, CTRL_SELECTED); + + if (prim_objects[CurrentPrim].damage & PRIM_DAMAGE_LEAN) {SetControlState(CTRL_PRIM_LEANS, CTRL_SELECTED);} + if (prim_objects[CurrentPrim].damage & PRIM_DAMAGE_CRUMPLE) {SetControlState(CTRL_PRIM_CRUMPLES, CTRL_SELECTED);} + if (prim_objects[CurrentPrim].damage & PRIM_DAMAGE_EXPLODES) {SetControlState(CTRL_PRIM_EXPLODES, CTRL_SELECTED);} + } + + // + // This crashes?!... + // + +// ((CStaticText*)GetControlPtr(CTRL_PRIM_MODE_TEXT))->SetString1(prim_mode_menu[PrimTabMode].ItemText); +} + +//--------------------------------------------------------------- + +void PrimPickTab::DrawTabContent(void) +{ + EdRect content_rect; + + if(PrimTabMode==PRIM_MODE_SINGLE) + ((CVSlider*)GetControlPtr(CTRL_PRIM_V_SLIDE_PRIM))->SetValueRange(0,266/3); + else + ((CVSlider*)GetControlPtr(CTRL_PRIM_V_SLIDE_PRIM))->SetValueRange(0,next_prim_multi_object+9); + + content_rect = ContentRect; + content_rect.ShrinkRect(1,1); + content_rect.FillRect(CONTENT_COL); + +// ShowAngles(); +/* + if(ValueButton) + ValueButton->DrawValueGadget(); +*/ + + DrawPrims(); + DrawControlSet(); +} + +//--------------------------------------------------------------- + +void PrimPickTab::DrawAPrimInRect(ULONG prim,SLONG x,SLONG y,SLONG w,SLONG h) +{ + CBYTE *text; + SLONG *flags; //[560]; + struct SVector *res; //[560]; //max points per object? + SLONG c0; + struct PrimObject *p_obj; + SLONG sp,ep; + SLONG min_x=999999,max_x=-999999,min_y=999999,max_y=-999999; + SLONG width,height,scale,scale_y; + EdRect rect; + SLONG os; + + flags=(SLONG*)MemAlloc(sizeof(SLONG)*13000); + if(flags==0) + return; + + res=(struct SVector*)MemAlloc(sizeof(struct SVector)*13000); + if(res==0) + { + MemFree(flags); + return; + } + + + os=engine.Scale; + engine.Scale=1000; + +//set clip to content window + SetWorkWindowBounds ( + ContentLeft()+PrimRect.GetLeft()+x+1, + ContentTop()+PrimRect.GetTop()+y+1, + w, + h + ); + + rect.SetRect(0,0,w,h); + if(prim==CurrentPrim) + rect.FillRect(LOLITE_COL); + +// rect.HiliteRect(LOLITE_COL,LOLITE_COL); + +// SetWorkWindowBounds(ContentLeft()+x,ContentTop()+y,w,h); + +/* + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + + rect.SetRect(x,y,w,h); + if(prim==CurrentPrim) + rect.FillRect(HILITE_COL); + else + rect.FillRect(LOLITE_COL); + rect.HiliteRect(LOLITE_COL,LOLITE_COL); + + SetWorkWindowBounds(ContentLeft()+x,ContentTop()+y,w,h); +*/ + set_camera(); + +// p_rect->FillRect(CONTENT_COL); + p_obj =&prim_objects[prim]; + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + for(c0=sp;c0max_x) + max_x=res[c0-sp].X; + + if(res[c0-sp].Ymax_y) + max_y=res[c0-sp].Y; + } + width=max_x-min_x; + height=max_y-min_y; + + if(width==0||height==0) + { + } + else + { + CBYTE str[100]; + + scale =(w<<16)/width; + scale_y=(h<<16)/height; + + if(scale_y>8; + engine.Scale=(1000*scale)>>16; + draw_a_prim_at(prim,0,0,0,0); + render_view(1); + + text = prim_names[prim]; + + sprintf(str,"(%d,%d) %s",prim,prim<256?prim_count[prim]:0,text); + DrawBoxC(rect.GetLeft()+1,rect.GetTop()+1,QTStringWidth(text),QTStringHeight()+1,0); + QuickText(rect.GetLeft()+1,rect.GetTop()+1,str,TEXT_COL); + rect.OutlineRect(0); + + } + + engine.Scale=os; + + MemFree(res); + MemFree(flags); +} + +void PrimPickTab::DrawABuildingInRect(ULONG prim,SLONG x,SLONG y,SLONG w,SLONG h) +{ + CBYTE *text; + SLONG *flags; //[560]; + struct SVector *res; //[560]; //max points per object? + SLONG c0; + struct BuildingObject *p_obj; + SLONG sp,ep; + SLONG min_x=999999,max_x=-999999,min_y=999999,max_y=-999999; + SLONG width,height,scale,scale_y; + EdRect rect; + SLONG os; + + flags=(SLONG*)MemAlloc(sizeof(SLONG)*3000); + if(flags==0) + return; + + res=(struct SVector*)MemAlloc(sizeof(struct SVector)*3000); + if(res==0) + { + MemFree(flags); + return; + } + + + os=engine.Scale; + engine.Scale=1000; + + SetWorkWindowBounds ( + ContentLeft()+PrimRect.GetLeft()+x+1, + ContentTop()+PrimRect.GetTop()+y+1, + w, + h + ); + + rect.SetRect(0,0,w,h); + if(prim==CurrentPrim) + rect.FillRect(LOLITE_COL); + + set_camera(); + + p_obj =&building_objects[prim]; + + sp=p_obj->StartPoint; + ep=p_obj->EndPoint; + + LogText(" build in rect prim %d sp %d ep %d \n",prim,sp,ep); + + for(c0=sp;c0max_x) + max_x=res[c0-sp].X; + + if(res[c0-sp].Ymax_y) + max_y=res[c0-sp].Y; + } + width=max_x-min_x; + height=max_y-min_y; + LogText(" build widh %d height %d \n",width,height); + + if(width==0||height==0) + { + } + else + { + scale =(w<<16)/width; + scale_y=(h<<16)/height; + + if(scale_y>8; + engine.Scale=(1000*scale)>>16; + draw_a_building_at(prim,0,0,0); + render_view(1); + +// text = prim_objects[prim].ObjectName; +// DrawBoxC(rect.GetLeft()+1,rect.GetTop()+1,QTStringWidth(text),QTStringHeight()+1,0); +// QuickText(rect.GetLeft()+1,rect.GetTop()+1,text,TEXT_COL); + rect.OutlineRect(0); + + engine.Scale=os; + } + + MemFree(res); + MemFree(flags); +} + +//--------------------------------------------------------------- + +void PrimPickTab::DrawAMultiPrimInRect(ULONG prim,SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG c0,c1,c2, + num_points, + max_x,max_y, + min_x,min_y, + end_point, + scale, + scale_y, + start_point, + temp_scale, + temp_x, + temp_y, + temp_z, + width,height, + *flags; + EdRect bounds_rect, + outline_rect; + struct KeyFrame *the_frame; + struct KeyFrameElement *the_element; + struct Matrix31 offset; + struct Matrix33 r_matrix; + struct PrimObject *the_obj; + struct SVector *rotate_vectors, + t_vector, + t_vector2; + + +// This bit bodged in for now. +extern struct KeyFrameChunk *test_chunk; + if(!test_chunk->MultiObject) + return; + the_frame = &test_chunk->KeyFrames[0]; +// + + c1 = 0; + flags = (SLONG*)MemAlloc(sizeof(SLONG)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + rotate_vectors = (struct SVector*)MemAlloc(sizeof(struct SVector)*3000); + ERROR_MSG(flags,"Unable to allocate memory for DrawKeyFrame"); + + min_x = min_y = 999999; + max_x = max_y = -999999; + + temp_scale = engine.Scale; + temp_x = engine.X; + temp_y = engine.Y; + temp_z = engine.Z; + + engine.X = 0; + engine.Y = 0; + engine.Z = 0; + engine.Scale = 5000; + engine.ShowDebug= 0; + engine.BucketSize= MAX_BUCKETS>>4; + + SetWorkWindowBounds ( + ContentLeft()+PrimRect.GetLeft()+x+1, + ContentTop()+PrimRect.GetTop()+y+1, + w, + h + ); + bounds_rect.SetRect(0,0,w,h); + if(prim==CurrentPrim) + bounds_rect.FillRect(LOLITE_COL); + +/* + outline_rect.SetRect( + 0,0, + bounds_rect.GetWidth(),bounds_rect.GetHeight() + ); +*/ + set_camera(); + set_camera_to_base(); + + rotate_obj(0,0,0,&r_matrix); + + for(c2=0,c0=prim_multi_objects[prim].StartObject;c0StartPoint; + end_point = the_obj->EndPoint; + num_points = end_point-start_point; + + the_element = &the_frame->FirstElement[c2++]; + offset.M[0] = the_element->OffsetX; + offset.M[1] = the_element->OffsetY; + offset.M[2] = the_element->OffsetZ; + matrix_transformZMY((struct Matrix31*)&t_vector,&r_matrix, &offset); + + engine.X -= t_vector.X<<8; + engine.Y -= t_vector.Y<<8; + engine.Z -= t_vector.Z<<8; + + for(c1=0;c1max_x) + max_x = rotate_vectors[c1].X; + if(rotate_vectors[c1].Ymax_y) + max_y = rotate_vectors[c1].Y; + } + + engine.X += t_vector.X<<8; + engine.Y += t_vector.Y<<8; + engine.Z += t_vector.Z<<8; + } + + width = max_x-min_x; + height = max_y-min_y; + + if(width>0 && height>0) + { + scale = (bounds_rect.GetWidth()<<16)/width; + scale_y = (bounds_rect.GetHeight()<<16)/height; + if(scale_y>8; + engine.Scale = (5000*scale)>>16; + } + + for(c2=0,c0=prim_multi_objects[prim].StartObject;c0FirstElement[c2++]; + test_draw(c0,0,0,0,0,the_element,the_element,&r_matrix, NULL, NULL, NULL, NULL, NULL); + } + render_view(1); + bounds_rect.OutlineRect(0); + + engine.X = temp_x; + engine.Y = temp_y; + engine.Z = temp_z; + engine.Scale = temp_scale; + engine.ShowDebug= 1; + engine.BucketSize= MAX_BUCKETS; + + MemFree(rotate_vectors); + MemFree(flags); +} + +//--------------------------------------------------------------- + +// for both views +SLONG PrimPickTab::HiLightObjects(SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG mx,my,mz; + SLONG screen_change=0; + SLONG wwx,wwy,www,wwh; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + mx=(engine.X>>8)>>ELE_SHIFT; + my=(engine.Y>>8)>>ELE_SHIFT; + mz=(engine.Z>>8)>>ELE_SHIFT; + + SetWorkWindowBounds(x,y,w-1,h/2-3); + set_camera_plan(); + + screen_change=hilight_map_things(MAP_THING_TYPE_PRIM); + screen_change|=hilight_map_things(MAP_THING_TYPE_ANIM_PRIM); + + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + if(View2Mode) + { + set_camera_side(); + } + else + { + set_camera_front(); + } + + screen_change|=hilight_map_things(MAP_THING_TYPE_PRIM); + screen_change|=hilight_map_things(MAP_THING_TYPE_ANIM_PRIM); + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + + return(screen_change); +} + +void PrimPickTab::DrawModuleContent(SLONG x,SLONG y,SLONG w,SLONG h) +{ + SLONG wwx, + wwy, + www, + wwh; + EdRect drawrect; + + + RedrawModuleContent=0; + + + // Back up clipping rect. + wwx = WorkWindowRect.Left; + wwy = WorkWindowRect.Top; + www = WorkWindowRect.Width; + wwh = WorkWindowRect.Height; +/* + View1.SetRect(x,y,w-1,h/2-8); + View2.SetRect(x,y+h/2+8,w-1,h/2-16); + + SetWorkWindowBounds ( + View1.GetLeft(), + View1.GetTop(), + View1.GetWidth(), + View1.GetHeight() + ); + + View1.FillRect(CONTENT_COL); + View1.OutlineRect(0); + + SetWorkWindowBounds ( + View2.GetLeft(), + View2.GetTop(), + View2.GetWidth(), + View2.GetHeight() + ); + + View2.FillRect(CONTENT_COL); + View2.OutlineRect(0); +*/ + + View1.SetRect(x,y,w-1,h/2-3); + View2.SetRect(x,y+h/2+4,w-1,h/2-4); + + SetWorkWindowBounds(x,y,w-1,h/2-3); + drawrect.SetRect(0,0,w-1,h/2-3); + + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + set_camera_plan(); +extern void find_map_clip(SLONG *minx,SLONG *maxx,SLONG *minz,SLONG *maxz); + { + + SLONG minx,maxx,minz,maxz; + + find_map_clip(&minx,&maxx,&minz,&maxz); + edit_info.MinX=minx; + edit_info.MinZ=minz; + edit_info.MaxX=maxx; + edit_info.MaxZ=maxz; + edit_info.Clipped|=1; + + } + + draw_editor_map(0); + render_view(1); + + switch(PrimTabMode) + { + case PRIM_MODE_SINGLE: + case PRIM_MODE_MULTI: + case PRIM_MODE_ANIM_KEY: + case PRIM_MODE_ANIM_MORPH: + hilight_map_things(MAP_THING_TYPE_PRIM); + hilight_map_things(MAP_THING_TYPE_ANIM_PRIM); + break; +// case PRIM_MODE_BACK: +// hilight_map_backgrounds(0); + break; + } + + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + drawrect.SetRect(0,0,w-1,h/2-4); + +// drawrect.FillRect(LOLITE_COL); + drawrect.FillRect(CONTENT_COL_BR); + drawrect.HiliteRect(HILITE_COL,HILITE_COL); + + if(View2Mode) + { + set_camera_side(); + } + else + { + set_camera_front(); + } + + + draw_editor_map(0); + + render_view(1); + switch(PrimTabMode) + { + case PRIM_MODE_SINGLE: + case PRIM_MODE_MULTI: + case PRIM_MODE_ANIM_KEY: + case PRIM_MODE_ANIM_MORPH: + hilight_map_things(MAP_THING_TYPE_PRIM); + hilight_map_things(MAP_THING_TYPE_ANIM_PRIM); + break; +// case PRIM_MODE_BACK: +// hilight_map_backgrounds(0); + break; + } + + { + CBYTE str[50]; + + sprintf(str, "Current prim %d", CurrentPrim); + + QuickTextC(10, 40, str, RED_COL); + QuickTextC(11, 41, str, WHITE_COL); + } + + // Restore clipping rect. + SetWorkWindowBounds(wwx,wwy,www,wwh); + edit_info.Clipped&=~1; +} + +void PrimPickTab::DrawPrims(void) +{ + SLONG ox,oy,oz,x,y,prim=1; + SLONG wwx,wwy,www,wwh; + + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + + PrimRect.FillRect(ACTIVE_COL); + PrimRect.HiliteRect(LOLITE_COL,HILITE_COL); + + { + SLONG c0; + + memset(prim_count,0,512); + prim_diff=0; + + for(c0=0;c0Type) + { + case MAP_THING_TYPE_PRIM: + if(t_mthing->IndexOther<256) + { + prim_count[t_mthing->IndexOther]++; + if(prim_count[t_mthing->IndexOther]==1) + prim_diff++; + } + break; + } + } + } + { + CBYTE str[100]; + sprintf(str," %d..%d DIFFERENT PRIMS %d",next_prim_point,MAX_PRIM_POINTS,prim_diff); + QuickTextC(1,1,str,0); + } + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; +// SetWorkWindowBounds(PrimRect.GetLeft()+1,PrimRect.GetTop()+1,PrimRect.GetWidth()-1,PrimRect.GetHeight()-1); + +// PrimRect.FillRect(CONTENT_COL); +// PrimRect.HiliteRect(LOLITE_COL,LOLITE_COL); + ox=engine.X; + oy=engine.Y; + oz=engine.Z; + + engine.X=0; + engine.Y=0; + engine.Z=0; + + engine.ShowDebug=0; + engine.BucketSize=MAX_BUCKETS>>4; + + prim = (((CVSlider*)GetControlPtr(CTRL_PRIM_V_SLIDE_PRIM))->GetCurrentValue()*3)+1; + + if(PrimTabMode==PRIM_MODE_ANIM_KEY) + { + EdRect frame_rect,rect; + struct Matrix33 r_matrix; + rotate_obj(0,0,0,&r_matrix); + + for(y=1;y<255;y+=85) + for(x=1;x<255;x+=85) + { + SetWorkWindowBounds (ContentLeft()+PrimRect.GetLeft()+x+1, + ContentTop()+PrimRect.GetTop()+y+1, + 85,85); + + rect.SetRect(0,0,85,85); + if(prim==CurrentPrim) + rect.FillRect(LOLITE_COL); + +extern void drawkeyframeboxgamechunk(UWORD multi_object,EdRect *bounds_rect,struct GameKeyFrame *the_frame,struct Matrix33 *r_matrix,SLONG person_id,struct GameKeyFrameChunk *the_chunk); + + if(anim_chunk[prim].MultiObject[0]) + drawkeyframeboxgamechunk(anim_chunk[prim].MultiObject[0],&rect,anim_chunk[prim].AnimList[1],&r_matrix,0,&anim_chunk[prim]); + prim++; + } + } + else + if(PrimTabMode==PRIM_MODE_SINGLE) + { + EdRect frame_rect,rect; + struct Matrix33 r_matrix; + rotate_obj(0,0,0,&r_matrix); + + for(y=1;y<255;y+=85) + for(x=1;x<255;x+=85) + { + + if(prim < next_prim_object) + DrawAPrimInRect(prim++,x,y,85,85); + + } + } + else + { + for(y=1;y<255;y+=85) + for(x=1;x<255;x+=85) + { + if(prim < next_prim_multi_object) + DrawAMultiPrimInRect(prim++,x,y,85,85); + } + } + + engine.ShowDebug=1; + engine.BucketSize=MAX_BUCKETS; + +// draw_a_prim_at(3,0,0,0); + + engine.X=ox; + engine.Y=oy; + engine.Z=oz; +/* + { + SetWorkWindowBounds(ContentLeft(),ContentTop(),300,300); + CBYTE str[100]; + sprintf(str,"CURRENT_PRIM= %d dtv1 %d dtv2 %d x %d y %d z %d",CurrentPrim,DragThingView1,DragThingView2,engine.MousePosX,engine.MousePosY,engine.MousePosZ); + DrawBox(20,20,300,10,0); + QuickTextC(20+1,20+1,str,255); + } +*/ + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + RedrawTabContent=0; + +} + +void PrimPickTab::UpdatePrimPickWindow(void) +{ + if(LockWorkScreen()) + { + DrawControlSet(); + DrawPrims(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); +} + + +void redraw_all_prims(void) +{ + the_primpicktab->DrawTabContent(); +} +//--------------------------------------------------------------- + + +void PrimPickTab::HandleTab(MFPoint *current_point) +{ + SLONG update = 0; + + + ModeTab::HandleTab(current_point); +/* + if(Keys[KB_PMINUS]) + { + if(TextureZoom<8) + { + TextureZoom++; + update = 1; + } + } + else if(Keys[KB_PPLUS]) + { + if(TextureZoom>0) + { + TextureZoom--; + update = 1; + } + } + if(Keys[KB_P4]) + { + if(TextureX>0) + { + TextureX--; + update = 1; + } + } + else if(Keys[KB_P6]) + { + if(TextureX<(256-(1<0) + { + TextureY--; + update = 1; + } + } + else if(Keys[KB_P2]) + { + if(TextureY<(256-(1<left&&xtop&&y3) + AxisMode=0; + switch(AxisMode) + { + case 0: + SetControlState(CTRL_PRIM_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_PRIM_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_PRIM_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=X_AXIS; + break; + case 1: + SetControlState(CTRL_PRIM_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_PRIM_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_PRIM_Z_AXIS_FREE,CTRL_DESELECTED); + Axis=Y_AXIS; + break; + case 2: + SetControlState(CTRL_PRIM_X_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_PRIM_Y_AXIS_FREE,CTRL_DESELECTED); + SetControlState(CTRL_PRIM_Z_AXIS_FREE,CTRL_SELECTED); + Axis=Z_AXIS; + break; + case 3: + SetControlState(CTRL_PRIM_X_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_PRIM_Y_AXIS_FREE,CTRL_SELECTED); + SetControlState(CTRL_PRIM_Z_AXIS_FREE,CTRL_SELECTED); + Axis=X_AXIS|Y_AXIS|Z_AXIS; + break; + } + + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + DrawControlSet(); + ShowWorkWindow(0); + } + return(0); +} + + + + +void find_things_min_point(SLONG drag,SLONG *px,SLONG *py,SLONG *pz) +{ + SLONG c0; + SLONG mx,my,mz; + + *px=99999; + *py=99999; + *pz=99999; + + if(drag) + { + SLONG sp,ep; + sp=prim_objects[drag].StartPoint; + ep=prim_objects[drag].EndPoint; + + for(c0=sp;c0*px) + *px=prim_points[c0].X; + if(prim_points[c0].Y>*py) + *py=prim_points[c0].Y; + if(prim_points[c0].Z>*pz) + *pz=prim_points[c0].Z; + } + } +} + +void find_things_min_point_corner(SLONG drag,SLONG *px,SLONG *py,SLONG *pz) +{ + SLONG c0; + SLONG mx,my,mz; + SLONG dist,mdist=99999,best=0; + + *py=99999; + + if(drag) + { + SLONG sp,ep; + sp=prim_objects[drag].StartPoint; + ep=prim_objects[drag].EndPoint; + + for(c0=sp;c0*py) + *py=prim_points[c0].Y; + + dist=prim_points[c0].X+prim_points[c0].Z; + + if(dist>mdist) + { + mdist=dist; + best=c0; + } + } + } + if(best) + { + *px=prim_points[best].X; +// *py=prim_points[best].Y; + *pz=prim_points[best].Z; + } +} + +// +// button 0 is left +// button 1 is right (for creating a new prim identical to the last + +SLONG PrimPickTab::DragAPrim(UBYTE flags,MFPoint *clicked_point,SLONG button) +{ + static UBYTE col=0; + SLONG screen_change=0; + MFPoint local_point; + SLONG x,y,w,h; + SLONG drag; + SLONG wwx,wwy,www,wwh; + SLONG ox,oy,oz; + + SLONG px=0,py=0,pz=0; + + + + + // Stop compiler moaning. + flags = flags; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + x=Parent->ContentLeft(); + y=Parent->ContentTop(); + w=Parent->ContentWidth(); + h=Parent->ContentHeight(); + + col++; + + SetWorkWindowBounds(x,y,w-1,h/2-3); + set_camera_plan(); + + local_point = *clicked_point; +/* + switch(PrimTabMode) + { + case PRIM_MODE_SINGLE: + drag=select_map_things(clicked_point,MAP_THING_TYPE_PRIM); + break; + case PRIM_MODE_MULTI: + break; + case PRIM_MODE_SINGLE: + case PRIM_MODE_ANIM_KEY: + case PRIM_MODE_ANIM_MORPH: + + drag=select_map_things(clicked_point,MAP_THING_TYPE_PRIM); + if(drag==0) + drag=select_map_things(clicked_point,MAP_THING_TYPE_ANIM_PRIM); + break; +// case PRIM_MODE_BACK: +// drag=select_map_backgrounds(clicked_point,0); + break; + } + */ + +extern void find_map_clip(SLONG *minx,SLONG *maxx,SLONG *minz,SLONG *maxz); + { + + SLONG minx,maxx,minz,maxz; + + find_map_clip(&minx,&maxx,&minz,&maxz); + edit_info.MinX=minx; + edit_info.MinZ=minz; + edit_info.MaxX=maxx; + edit_info.MaxZ=maxz; + edit_info.Clipped|=1; + + } + + drag=select_map_things(clicked_point,MAP_THING_TYPE_PRIM); + if(drag==0) + drag=select_map_things(clicked_point,MAP_THING_TYPE_ANIM_PRIM); + + + if(!drag) + { + SetWorkWindowBounds(x,y+h/2+4,w-1,h/2-4); + if(View2Mode) + { + set_camera_side(); + } + else + { + set_camera_front(); + } + local_point =*clicked_point; + local_point.Y-=h/2; + drag=select_map_things(&local_point,MAP_THING_TYPE_PRIM); + if(drag==0) + drag=select_map_things(&local_point,MAP_THING_TYPE_ANIM_PRIM); +/* + switch(PrimTabMode) + { + case PRIM_MODE_SINGLE: + case PRIM_MODE_MULTI: + case PRIM_MODE_ANIM_KEY: + case PRIM_MODE_ANIM_MORPH: + drag=select_map_things(&local_point,MAP_THING_TYPE_PRIM); + if(drag==0) + drag=select_map_things(&local_point,MAP_THING_TYPE_ANIM_PRIM); + break; +// case PRIM_MODE_BACK: +// drag=select_map_backgrounds(&local_point,0); + break; + } +*/ + } + + if(drag) + { + SLONG index; + + index=map_things[drag].IndexOther; + if(GridCorner) + { + if(GridMax) + { + find_things_max_point_corner(index,&px,&py,&pz); + } + else + { + find_things_min_point_corner(index,&px,&py,&pz); + } + } + else + { + if(GridMax) + { + find_things_max_point(index,&px,&py,&pz); + } + else + { + find_things_min_point(index,&px,&py,&pz); + } + } + } + + engine.MousePosX=map_things[drag].X; + engine.MousePosY=map_things[drag].Y; + engine.MousePosZ=map_things[drag].Z; + ox=map_things[drag].X; + oy=map_things[drag].Y; + oz=map_things[drag].Z; + + + + if(drag) //drag in plan view + { + SLONG offset_x,offset_y,offset_z; + SLONG in=1; + + if(button) + { + SLONG old_thing; + old_thing=drag; + // right button so create a new identical prim and drag it + + drag=place_prim_at(map_things[drag].IndexOther,map_things[drag].X,map_things[drag].Y,map_things[drag].Z); + if(drag==0) + return(0); + + map_things[drag].AngleY=map_things[old_thing].AngleY; + map_things[drag].X-engine.MousePosX; + } + + SetWorldMouse(0); + offset_x=map_things[drag].X-engine.MousePosX; + offset_y=map_things[drag].Y-engine.MousePosY; + offset_z=map_things[drag].Z-engine.MousePosZ; +// set_user_rotate(map_things[drag].AngleX,0,0); + + angle_prim_y=map_things[drag].AngleY; + + + while(SHELL_ACTIVE && ( (button==0) ? LeftButton : RightButton)) + { + SLONG nx,ny,nz; + in=SetWorldMouse(0); + + nx=map_things[drag].X; + ny=map_things[drag].Y; + nz=map_things[drag].Z; + + if(GridFlag) + { + SLONG grid_and; + grid_and=~(HALF_ELE_SIZE-1); + if(Axis&X_AXIS) + nx=((engine.MousePosX+offset_x)&grid_and)-px; + + if(py<0) + { + if(Axis&Y_AXIS) + ny=((engine.MousePosY+offset_y)&grid_and)+((-py)&0x7f); + } + else + { + if(Axis&Y_AXIS) + ny=((engine.MousePosY+offset_y)&grid_and)-((py)&0x7f); + } + if(Axis&Z_AXIS) + nz=((engine.MousePosZ+offset_z)&grid_and)-(pz); + } + else + { + if(Axis&X_AXIS) + nx=engine.MousePosX+offset_x; + if(Axis&Y_AXIS) + ny=engine.MousePosY+offset_y; + if(Axis&Z_AXIS) + nz=engine.MousePosZ+offset_z; + } + + if(PrimTabMode==PRIM_MODE_BACK) + { + map_things[drag].X=nx; + map_things[drag].Y=ny; + map_things[drag].Z=nz; +// LogText("Drag To nx %d ny %d nz %d \n",nx,ny,nz); + } + else + move_thing_on_cells(drag,nx,ny,nz); + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + SetWorkWindowBounds(this->ContentLeft()+1,this->ContentTop()+1,this->ContentWidth(),this->ContentHeight()); +// ContentRect.FillRect(CONTENT_COL); + + DrawBox(0,0,this->ContentWidth(),this->ContentHeight(),CONTENT_COL); + set_camera(); + draw_editor_map(0); + render_view(1); + ShowWorkWindow(0); + editor_user_interface(0); + KeyboardInterface(); + if(PrimTabMode!=PRIM_MODE_BACK) + rotate_prim_thing(drag); + } + if(!in) + { + delete_thing(drag); + } + + MyUndo.MoveObject(0,drag,ox,oy,oz); + + } + SetWorkWindowBounds(this->ContentLeft()+1,this->ContentTop()+1,this->ContentWidth(),this->ContentHeight()); + DrawBox(0,0,this->ContentWidth(),this->ContentHeight(),CONTENT_COL); +// ContentRect.FillRect(CONTENT_COL); + UpdatePrimPickWindow(); + + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + edit_info.Clipped&=~1; + + return(screen_change); +} + +SLONG PrimPickTab::DragEngine(UBYTE flags,MFPoint *clicked_point) +{ + SLONG wwx,wwy,www,wwh; + SLONG screen_change=0; + SLONG last_world_mouse; + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + + { + SLONG start_x=0,start_y=0,start_z=0,flag=0; + SLONG old_x,old_y,old_z; + SLONG nx,ny,nz; + + old_x=nx=engine.X; + old_y=ny=engine.Y; + old_z=nz=engine.Z; + + while(SHELL_ACTIVE && MiddleButton) + { + last_world_mouse=SetWorldMouse(0); + if(last_world_mouse) + { + if(!flag) + { + flag=1; + start_x=engine.MousePosX<<8; + start_y=engine.MousePosY<<8; + start_z=engine.MousePosZ<<8; + } + + nx=engine.MousePosX<<8; + ny=engine.MousePosY<<8; + nz=engine.MousePosZ<<8; + + engine.X = (old_x+(-nx+start_x)); + engine.Y = (old_y+(-ny+start_y)); + engine.Z = (old_z+(-nz+start_z)); + +// engine.Z=nz<<8; + + DrawModuleContent(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth(),Parent->ContentHeight()); + ShowWorkWindow(0); + screen_change=1; + + engine.X=old_x; + engine.Y=old_y; + engine.Z=old_z; + + } + } + if(flag) + { + engine.X= (old_x+(-nx+start_x)); + engine.Y= (old_y+(-ny+start_y)); + engine.Z= (old_z+(-nz+start_z)); + } + } + return(screen_change); + +} + +extern SLONG calc_edit_height_at(SLONG x,SLONG z); + +SLONG PrimPickTab::HandleModuleContentClick(MFPoint *clicked_point,UBYTE flags,SLONG x,SLONG y,SLONG w,SLONG h) +{ + SWORD thing; + + + // Stop compiler moaning. + x = x; + y = y; + w = w; + h = h; + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + if(CurrentPrim==0) + { + DragAPrim(flags,clicked_point,0); + } + else + { + SetWorldMouse(1); +// set_user_rotate(0,0,0); + angle_prim_y=0; + switch(PrimTabMode) + { + case PRIM_MODE_SINGLE: + + if(ShiftFlag|| (prim_objects[CurrentPrim].flag & PRIM_FLAG_ON_FLOOR) ) + { + SLONG px,py,pz,y; + find_things_min_point(CurrentPrim,&px,&py,&pz); + +extern SLONG find_alt_for_this_pos(SLONG x,SLONG z); + y=find_alt_for_this_pos(engine.MousePosX,engine.MousePosZ); + //y=calc_edit_height_at(engine.MousePosX,engine.MousePosZ); + + y-=py; + thing=place_prim_at(CurrentPrim,engine.MousePosX,y,engine.MousePosZ); + if(ShiftFlag) + map_things[thing].Flags|=FLAG_EDIT_PRIM_ON_FLOOR; + } + else + if(ShiftFlag|| (prim_objects[CurrentPrim].flag & PRIM_FLAG_JUST_FLOOR) ) + { + SLONG px,py,pz,y; + find_things_min_point(CurrentPrim,&px,&py,&pz); + +extern SLONG find_alt_for_this_pos(SLONG x,SLONG z); + //y=find_alt_for_this_pos(engine.MousePosX,engine.MousePosZ); + y=calc_edit_height_at(engine.MousePosX,engine.MousePosZ); + + y-=py; + thing=place_prim_at(CurrentPrim,engine.MousePosX,y,engine.MousePosZ); +// map_things[thing].Flags|=FLAG_EDIT_PRIM_ON_FLOOR; + } + else + { + thing=place_prim_at(CurrentPrim,engine.MousePosX,engine.MousePosY,engine.MousePosZ); + } + break; + case PRIM_MODE_ANIM_KEY: +SLONG place_anim_prim_at(UWORD prim,SLONG x,SLONG y,SLONG z); + if(ShiftFlag) + { + SLONG px,py,pz,y; +/* HERE HERE HERE */ find_things_min_point(CurrentPrim,&px,&py,&pz); + +extern SLONG find_alt_for_this_pos(SLONG x,SLONG z); + + y=find_alt_for_this_pos(px,pz); +// y=find_alt_for_this_pos(engine.MousePosX,engine.MousePosZ); + +// y=calc_edit_height_at(engine.MousePosX,engine.MousePosZ); + y-=py; + thing=place_prim_at(CurrentPrim,engine.MousePosX,y,engine.MousePosZ); + } + else + { + + thing=place_anim_prim_at(CurrentPrim,engine.MousePosX,engine.MousePosY,engine.MousePosZ); + } + break; + + } + + MyUndo.PlaceObject(0,CurrentPrim,thing,engine.MousePosX,engine.MousePosY,engine.MousePosZ); + CurrentPrim=0; + UpdatePrimInfo(); + return(1); + } + break; + case RIGHT_CLICK: + if(CurrentPrim==0) + DragAPrim(flags,clicked_point,1); + + // Right click in content. + break; + case MIDDLE_CLICK: + DragEngine(flags,clicked_point); + break; + } + return(0); + +} + +UWORD PrimPickTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UWORD control_id; + Control *current_control; + MFPoint local_point; + + + // This is a fudge to update the front screen buffer. + ShowWorkScreen(0); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + if(PrimRect.PointInRect(&local_point)) + { + SLONG max, + x, + y, + + prim = (((CVSlider*)GetControlPtr(CTRL_PRIM_V_SLIDE_PRIM))->GetCurrentValue()*3)+1; + + switch(PrimTabMode) + { + case PRIM_MODE_SINGLE: + max = next_prim_object; //next_prim_object + max=266; + break; + case PRIM_MODE_MULTI: + max = next_prim_multi_object; + break; + case PRIM_MODE_ANIM_KEY: + case PRIM_MODE_ANIM_MORPH: + max=256; + } + + for(y=1;y<255;y+=85) + for(x=1;x<255;x+=85) + { + if(prim < max) + if(is_point_in_box(local_point.X,local_point.Y,PrimRect.GetLeft()+x,PrimRect.GetTop()+y,85,85)) + { + if(CurrentPrim!=prim) + { + RedrawTabContent=1; + CurrentPrim=prim; + UpdatePrimInfo(); + extern SLONG HMTAB_current_prim; + HMTAB_current_prim = prim; + } + else + { + CurrentPrim=0; + UpdatePrimInfo(); + } + + UpdatePrimPickWindow(); + + } + prim++; + } + } + else + { + current_control = GetControlList(); + while(current_control) + { + if(!(current_control->GetFlags()&CONTROL_INACTIVE) && current_control->PointInControl(&local_point)) + { + // Handle control. + control_id = current_control->TrackControl(&local_point); + HandleControl(control_id); + + // Tidy up display. + if(LockWorkScreen()) + { + DrawTab(); + UnlockWorkScreen(); + } + ShowWorkWindow(0); + + return control_id; + } + current_control = current_control->GetNextControl(); + } + } + + break; + case RIGHT_CLICK: + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + local_point = *clicked_point; + GlobalToLocal(&local_point); + break; + } + return 0; +} + +//--------------------------------------------------------------- + +SLONG PrimPickTab::SetWorldMouse(ULONG flag) +{ + MFPoint mouse_point; + MFPoint local_point; + SLONG wwx,wwy,www,wwh; + + + wwx=WorkWindowRect.Left; + wwy=WorkWindowRect.Top; + www=WorkWindowRect.Width; + wwh=WorkWindowRect.Height; + + mouse_point.X = MouseX; + mouse_point.Y = MouseY; + + + local_point = mouse_point; + Parent->GlobalToLocal(&local_point); + if(is_point_in_box(local_point.X,local_point.Y,0,0,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()/2-3); + set_camera_plan(); + calc_world_pos_plan(local_point.X,local_point.Y); + if(flag) + engine.MousePosY=engine.Y>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(1); + } + else + if(is_point_in_box(local_point.X,local_point.Y,0,Parent->ContentHeight()/2,Parent->ContentWidth()-1,Parent->ContentHeight()/2)) + { + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+Parent->ContentHeight()/2+3,Parent->ContentWidth()-1,Parent->ContentHeight()/2-4); + if(View2Mode) + { + set_camera_side(); + } + else + { + set_camera_front(); + } + calc_world_pos_front(local_point.X,local_point.Y-Parent->ContentHeight()/2); + if(flag) + engine.MousePosZ=engine.Z>>8; + SetWorkWindowBounds(wwx,wwy,www,wwh); //RESTORE CLIP RECT + return(1); + + } +/* + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+1,Parent->ContentWidth()-1,Parent->ContentHeight()/2-3); + set_camera_plan(); + point.X=engine.MousePosX; + point.Y=engine.MousePosY; + point.Z=engine.MousePosZ; + + rotate_point_gte(&point,&out); + + DrawLineC(out.X-10,out.Y,out.X+10,out.Y,1); + DrawLineC(out.X,out.Y-10,out.X,out.Y+10,1); + + SetWorkWindowBounds(Parent->ContentLeft()+1,Parent->ContentTop()+Parent->ContentHeight()/2+3,Parent->ContentWidth()-1,Parent->ContentHeight()/2-4); + set_camera_front(); + point.X=engine.MousePosX; + point.Y=engine.MousePosY; + point.Z=engine.MousePosZ; + + rotate_point_gte(&point,&out); + + DrawLineC(out.X-10,out.Y,out.X+10,out.Y,1); + DrawLineC(out.X,out.Y-10,out.X,out.Y+10,1); + ShowWorkWindow(0); +*/ + return(0); +} + + + +void add_a_background_thing(UWORD prim,SLONG x,SLONG y,SLONG z) +{ + UWORD map_thing; + struct MapThing *p_mthing; + + map_thing=find_empty_map_thing(); + if(!map_thing) + return; + p_mthing=TO_MTHING(map_thing); + p_mthing->X=x; + p_mthing->Y=y; + p_mthing->Z=z; + + p_mthing->IndexOther=prim; + p_mthing->IndexNext=background_prim; + background_prim=map_thing; + set_things_faces(map_thing); + p_mthing->Type=MAP_THING_TYPE_PRIM; + scan_function=scan_apply_ambient; + scan_map_thing(map_thing); + +} + +extern void clear_map2(void); + +void PrimPickTab::HandleControl(UWORD control_id) +{ + switch(control_id&0xff) + { + /* + case CTRL_PRIM_APPEND_NEW: + { + FileRequester *fr; + CBYTE fname[100]; + + clear_map2(); +// clear_prims(); + load_all_prims("allprim.sav"); + + fr=new FileRequester("objects\\","*.*","Load A Prim","hello"); + if(fr->Draw()) + { + + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + read_asc(fname,100,1); + compress_prims(); + record_prim_status(); + save_all_prims("allprim.sav"); + } + delete fr; + UpdatePrimPickWindow(); + RequestUpdate(); + } + break; + */ + case CTRL_PRIM_REPLACE: + if(CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + FileRequester *fr; + CBYTE fname[100]; + + clear_map2(); +// clear_prims(); + load_all_individual_prims(); + + fr=new FileRequester("objects\\","*.*","Load A Prim","hello"); + if(fr->Draw()) + { + SLONG temp; + + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + temp=next_prim_object; + next_prim_object=CurrentPrim; + + read_asc(fname,100,1); + next_prim_object=temp; + compress_prims(); + record_prim_status(); + + save_prim_object(CurrentPrim); + + //save_all_individual_prims(); + } + delete fr; + UpdatePrimPickWindow(); + RequestUpdate(); + } + break; + case CTRL_PRIM_SAVE: + + if (CurrentPrim) + { +// revert_to_prim_status(); + save_prim_object(CurrentPrim); + //save_all_individual_prims(); + } + break; + case CTRL_PRIM_X_AXIS_FREE: + ToggleControlSelectedState(CTRL_PRIM_X_AXIS_FREE); + if(Axis&X_AXIS) + Axis&=~X_AXIS; + else + Axis|=X_AXIS; + break; + case CTRL_PRIM_Y_AXIS_FREE: + ToggleControlSelectedState(CTRL_PRIM_Y_AXIS_FREE); + if(Axis&Y_AXIS) + Axis&=~Y_AXIS; + else + Axis|=Y_AXIS; + break; + case CTRL_PRIM_Z_AXIS_FREE: + ToggleControlSelectedState(CTRL_PRIM_Z_AXIS_FREE); + if(Axis&Z_AXIS) + Axis&=~Z_AXIS; + else + Axis|=Z_AXIS; + break; + case CTRL_PRIM_GRID_ON: + ToggleControlSelectedState(CTRL_PRIM_GRID_ON); + GridFlag^=1; + break; + case CTRL_PRIM_GRID_MAX: + ToggleControlSelectedState(CTRL_PRIM_GRID_MAX); + GridMax^=1; + break; + case CTRL_PRIM_GRID_CORNER: + ToggleControlSelectedState(CTRL_PRIM_GRID_CORNER); + GridCorner^=1; + break; + case CTRL_PRIM_LOAD_BACKGROUND: +/* + { + FileRequester *fr; + CBYTE fname[100]; + fr=new FileRequester("data\\","*.asc","Load A Prim","hello"); + if(fr->Draw()) + { + UWORD temp; + strcpy(fname,fr->Path); + strcat(fname,fr->FileName); + read_asc(fname,640,1); + temp=copy_prim_to_end(next_prim_object-1,0,0); + add_a_background_thing(temp,HALF_ELE_SIZE+(512<Type) + { + case MAP_THING_TYPE_PRIM: + if(t_mthing->IndexOther==CurrentPrim) + { + delete_thing(c0); + prim_count[CurrentPrim]=0; + } + break; + } + } + } + +// save_map("data/bak.map",1); +// clear_map(); +// RequestUpdate(); + + + break; + case CTRL_PRIM_MODE_MENU: + PrimTabMode = (control_id>>8)-1; + switch(PrimTabMode) + { + case PRIM_MODE_SINGLE: + case PRIM_MODE_MULTI: + case PRIM_MODE_ANIM_KEY: + case PRIM_MODE_ANIM_MORPH: +// BackScale=engine.Scale; +// engine.Scale=PrimScale; +// RequestUpdate(); + break; +// case PRIM_MODE_BACK: +// PrimScale=engine.Scale; +// engine.Scale=BackScale; +// RequestUpdate(); +// break; + } + UpdatePrimInfo(); + break; + case CTRL_PRIM_MODE_TEXT: + break; + +/* + AngleY++; + break; + case CTRL_CAM_BUTTON_ZPLUS: + AngleZ++; + break; + case CTRL_CAM_BUTTON_XMINUS: + AngleX--; + break; + case CTRL_CAM_BUTTON_YMINUS: + AngleY--; + break; + case CTRL_CAM_BUTTON_ZMINUS: + AngleZ--; + break; +*/ + case CTRL_PRIM_COLLIDE_NONE: + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].coltype = PRIM_COLLIDE_NONE; + UpdatePrimInfo(); + } + break; + case CTRL_PRIM_COLLIDE_BOX: + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].coltype = PRIM_COLLIDE_BOX; + UpdatePrimInfo(); + } + break; + case CTRL_PRIM_COLLIDE_CYLINDER: + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].coltype = PRIM_COLLIDE_CYLINDER; + UpdatePrimInfo(); + } + break; + + case CTRL_PRIM_COLLIDE_SMALLBOX: + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].coltype = PRIM_COLLIDE_SMALLBOX; + UpdatePrimInfo(); + } + break; + + case CTRL_PRIM_SHADOW_NONE: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].shadowtype = PRIM_SHADOW_NONE;} UpdatePrimInfo(); break; + case CTRL_PRIM_SHADOW_BOXEDGE: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].shadowtype = PRIM_SHADOW_BOXEDGE;} UpdatePrimInfo(); break; + case CTRL_PRIM_SHADOW_CYLINDER: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].shadowtype = PRIM_SHADOW_CYLINDER;} UpdatePrimInfo(); break; + case CTRL_PRIM_SHADOW_FOURLEGS: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].shadowtype = PRIM_SHADOW_FOURLEGS;} UpdatePrimInfo(); break; + case CTRL_PRIM_SHADOW_FULLBOX: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].shadowtype = PRIM_SHADOW_FULLBOX;} UpdatePrimInfo(); break; + + case CTRL_PRIM_FLAG_LAMPOST: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].flag ^= PRIM_FLAG_LAMPOST; UpdatePrimInfo();} break; + case CTRL_PRIM_FLAG_GLARE: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].flag ^= PRIM_FLAG_GLARE; UpdatePrimInfo();} break; + case CTRL_PRIM_FLAG_TREE: if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) {prim_objects[CurrentPrim].flag ^= PRIM_FLAG_TREE; UpdatePrimInfo();} break; + case CTRL_PRIM_FLAG_ON_FLOOR: + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + + prim_objects[CurrentPrim].flag ^= PRIM_FLAG_ON_FLOOR; + if(prim_objects[CurrentPrim].flag & PRIM_FLAG_ON_FLOOR) + { + prim_objects[CurrentPrim].flag &=~ PRIM_FLAG_JUST_FLOOR; + } + UpdatePrimInfo(); + } + break; + case CTRL_PRIM_FLAG_JUST_FLOOR: + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + + prim_objects[CurrentPrim].flag ^= PRIM_FLAG_JUST_FLOOR; + if(prim_objects[CurrentPrim].flag & PRIM_FLAG_JUST_FLOOR) + { + prim_objects[CurrentPrim].flag &=~ PRIM_FLAG_ON_FLOOR; + } + UpdatePrimInfo(); + } + break; + case CTRL_PRIM_FLAG_INSIDE: + { + + edit_info.Inside^=1; + UpdatePrimInfo(); + } + break; + + case CTRL_PRIM_VIEW_SIDE: + + if(View2Mode==0) + { + View2Mode=1; + SetControlState(CTRL_PRIM_VIEW_SIDE, CTRL_SELECTED); + } + else + { + View2Mode=0; + SetControlState(CTRL_PRIM_VIEW_SIDE, CTRL_DESELECTED); + + } + break; + + case CTRL_PRIM_GROW: + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + SLONG i; + PrimObject *po; + + // + // Grow the selected prim. + // + + po = &prim_objects[CurrentPrim]; + + for (i = po->StartPoint; i < po->EndPoint; i++) + { + prim_points[i].X += prim_points[i].X >> 2; + prim_points[i].Y += prim_points[i].Y >> 2; + prim_points[i].Z += prim_points[i].Z >> 2; + } + + void update_modules(void); + + update_modules(); + } + + break; + + case CTRL_PRIM_SHRINK: + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + SLONG i; + PrimObject *po; + + // + // Shrink the selected prims. + // + + po = &prim_objects[CurrentPrim]; + + for (i = po->StartPoint; i < po->EndPoint; i++) + { + prim_points[i].X -= prim_points[i].X >> 2; + prim_points[i].Y -= prim_points[i].Y >> 2; + prim_points[i].Z -= prim_points[i].Z >> 2; + } + + void update_modules(void); + + update_modules(); + } + + break; + + case CTRL_PRIM_DAMAGABLE: + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].damage ^= PRIM_DAMAGE_DAMAGABLE; + + UpdatePrimInfo(); + } + + break; + + case CTRL_PRIM_LEANS: + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].damage ^= PRIM_DAMAGE_LEAN; + prim_objects[CurrentPrim].damage |= PRIM_DAMAGE_DAMAGABLE; + + if (prim_objects[CurrentPrim].damage & PRIM_DAMAGE_LEAN) + { + prim_objects[CurrentPrim].damage &= ~PRIM_DAMAGE_CRUMPLE; + } + + UpdatePrimInfo(); + } + + break; + + case CTRL_PRIM_CRUMPLES: + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].damage ^= PRIM_DAMAGE_CRUMPLE; + prim_objects[CurrentPrim].damage |= PRIM_DAMAGE_DAMAGABLE; + + if (prim_objects[CurrentPrim].damage & PRIM_DAMAGE_CRUMPLE) + { + prim_objects[CurrentPrim].damage &= ~PRIM_DAMAGE_LEAN; + } + + UpdatePrimInfo(); + } + + break; + + case CTRL_PRIM_EXPLODES: + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + prim_objects[CurrentPrim].damage |= PRIM_DAMAGE_DAMAGABLE; + prim_objects[CurrentPrim].damage ^= PRIM_DAMAGE_EXPLODES; + + UpdatePrimInfo(); + } + + break; + + case CTRL_PRIM_CENTRE_PIVOT: + + if (CurrentPrim && PrimTabMode == PRIM_MODE_SINGLE) + { + SLONG i; + + SLONG min_x = +INFINITY; + SLONG min_y = +INFINITY; + SLONG min_z = +INFINITY; + + SLONG max_x = -INFINITY; + SLONG max_y = -INFINITY; + SLONG max_z = -INFINITY; + + SLONG mid_x; + SLONG mid_y; + SLONG mid_z; + + PrimObject *po; + + // + // Shrink the selected prims. + // + + po = &prim_objects[CurrentPrim]; + + for (i = po->StartPoint; i < po->EndPoint; i++) + { + if (prim_points[i].X < min_x) {min_x = prim_points[i].X;} + if (prim_points[i].Y < min_y) {min_y = prim_points[i].Y;} + if (prim_points[i].Z < min_z) {min_z = prim_points[i].Z;} + + if (prim_points[i].X > max_x) {max_x = prim_points[i].X;} + if (prim_points[i].Y > max_y) {max_y = prim_points[i].Y;} + if (prim_points[i].Z > max_z) {max_z = prim_points[i].Z;} + } + + mid_x = min_x + max_x >> 1; + mid_y = min_y + max_y >> 1; + mid_z = min_z + max_z >> 1; + + for (i = po->StartPoint; i < po->EndPoint; i++) + { + prim_points[i].X -= mid_x; + prim_points[i].Y -= mid_y; + prim_points[i].Z -= mid_z; + } + + void update_modules(void); + + update_modules(); + } + + break; + } +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/Primativ.cpp b/fallen/Editor/Source/Primativ.cpp new file mode 100644 index 0000000..a7f0173 --- /dev/null +++ b/fallen/Editor/Source/Primativ.cpp @@ -0,0 +1,283 @@ +// Primativ.cpp +// Guy Simmons, 26th October 1996. + +#include "Editor.hpp" +#ifdef EDITOR + + +//**************************************************************************** + + +void EdRect::SetRect(SLONG left,SLONG top,SLONG width,SLONG height) +{ + Top = top; + Left = left; + Bottom = (SLONG)top+(height-1); + Right = (SLONG)left+(width-1); + Width = width; + Height = height; +} + +void EdRect::NormalRect(void) +{ + if(Right=0 && y1= WorkWindowWidth) + x2 = WorkWindowWidth-1; + + the_line = WorkWindow+x1+(y1*WorkScreenWidth); + for(c0=x1;c0=0 && y1= WorkWindowWidth) + x2 = WorkWindowWidth-1; + + the_line = (UWORD*)WorkWindow+x1+(y1*WorkScreenWidth>>1); + for(c0=x1;c0=0 && y1= WorkWindowWidth) + x2 = WorkWindowWidth-1; + + the_line = (ULONG*)WorkWindow+x1+(y1*WorkScreenWidth>>2); + for(c0=x1;c0=0 && x1= WorkWindowHeight) + y2 = WorkWindowHeight-1; + + the_line = WorkWindow+x1+(y1*WorkScreenWidth); + for(c0=y1;c0=0 && x1= WorkWindowHeight) + y2 = WorkWindowHeight-1; + + the_line = (UWORD*)WorkWindow+x1+(y1*WorkScreenWidth>>1); + for(c0=y1;c0=0 && x1= WorkWindowHeight) + y2 = WorkWindowHeight-1; + + the_line = (ULONG*)WorkWindow+x1+(y1*WorkScreenWidth>>2); + for(c0=y1;c0>1)) + *the_line = (ULONG)(*(the_line)^0xaaaaaa); + } + break; + } + } +} + +void EdRect::OutlineInvertedRect(void) +{ + draw_h_xord_line(Left,Right,Top); + draw_h_xord_line(Left,Right,Bottom); + draw_v_xord_line(Left,Top,Bottom); + draw_v_xord_line(Right,Top,Bottom); +} + +//**************************************************************************** + +void EdRect::HiliteRect(ULONG hilite,ULONG lolite) +{ + DrawVLineC(Right,Top,Bottom,lolite); + DrawHLineC(Left,Right,Bottom,lolite); + DrawVLineC(Left,Top,Bottom,hilite); + DrawHLineC(Left,Right,Top,hilite); +} + +//**************************************************************************** + +void EdRect::FillRect(ULONG colour) +{ + DrawBoxC(Left,Top,Width,Height,colour); +} + + +//**************************************************************************** + +void EdRect::IndentRect(ULONG hilite,ULONG lolite) +{ + DrawVLineC(Right,Top,Bottom,lolite); + DrawHLineC(Left,Right,Bottom,lolite); + DrawVLineC(Left,Top,Bottom,hilite); + DrawHLineC(Left,Right,Top,hilite); + + DrawVLineC(Right-2,Top+2,Bottom-2,hilite); + DrawHLineC(Left+2,Right-2,Bottom-2,lolite); + DrawVLineC(Left+2,Top+2,Bottom-2,hilite); + DrawHLineC(Left+2,Right-2,Top+2,hilite); +} + +//**************************************************************************** + +BOOL EdRect::PointInRect(MFPoint *the_point) +{ + if(the_point->X >= Left && the_point->X <= Right) + { + if(the_point->Y >= Top && the_point->Y <= Bottom) + return 1; + } + return 0; +} + +//**************************************************************************** + +//assumes rectangles are normal (i.e right is on the right + +BOOL EdRect::IntersectRect(EdRect *the_rect) +{ + SLONG flags=0; + MFPoint p; + + if(the_rect->RightLeft) + return(0); + + if(the_rect->Left>this->Right) + return(0); + + if(the_rect->Top>this->Bottom) + return(0); + + if(the_rect->BottomTop) + return(0); + + return(1); +} + +//**************************************************************************** + +#endif diff --git a/fallen/Editor/Source/Quaternion.cpp b/fallen/Editor/Source/Quaternion.cpp new file mode 100644 index 0000000..0eb3f3e --- /dev/null +++ b/fallen/Editor/Source/Quaternion.cpp @@ -0,0 +1,260 @@ +#include + +#include "Editor.hpp" +#include "Quaternion.h" + + +// JCL 22/12/98 +// lots of code shamelessly ripped from the Gamasutra Web site. + +//*************************************************************************************************** + +#define DELTA 0.05f //! guess???????????? + +void QuatSlerp(CQuaternion *from, CQuaternion *to, float t, CQuaternion *res) +{ + float to1[4]; +#ifdef TARGET_DC + // Why the PC guys need doubles, I'll never know... + float omega, cosom, sinom, scale0, scale1; +#else + double omega, cosom, sinom, scale0, scale1; +#endif + + // calc cosine + cosom = from->x * to->x + from->y * to->y + from->z * to->z + from->w * to->w; + + // adjust signs (if necessary) + if ( cosom <0.0f ) + { + cosom = -cosom; + + to1[0] = - to->x; + to1[1] = - to->y; + to1[2] = - to->z; + to1[3] = - to->w; + } + else + { + to1[0] = to->x; + to1[1] = to->y; + to1[2] = to->z; + to1[3] = to->w; + } + + // calculate coefficients + + if ( (1.0f - cosom) > DELTA ) + { + // standard case (slerp) + omega = acos(cosom); + sinom = sin(omega); + scale0 = sin((1.0f - t) * omega) / sinom; + scale1 = sin(t * omega) / sinom; + + } + else + { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0f - t; + scale1 = t; + } + + // calculate final values + res->x = scale0 * from->x + scale1 * to1[0]; + res->y = scale0 * from->y + scale1 * to1[1]; + res->z = scale0 * from->z + scale1 * to1[2]; + res->w = scale0 * from->w + scale1 * to1[3]; +} + +//*************************************************************************************************** +void QuatMul(CQuaternion *q1, CQuaternion *q2, CQuaternion *res) +{ + float A, B, C, D, E, F, G, H; + + A = (q1->w + q1->x) * (q2->w + q2->x); + B = (q1->z - q1->y) * (q2->y - q2->z); + C = (q1->x - q1->w) * (q2->y - q2->z); + D = (q1->y + q1->z) * (q2->x - q2->w); + E = (q1->x + q1->z) * (q2->x + q2->y); + F = (q1->x - q1->z) * (q2->x - q2->y); + G = (q1->w + q1->y) * (q2->w - q2->z); + H = (q1->w - q1->y) * (q2->w + q2->z); + + res->w = B + (-E - F + G + H) / 2; + res->x = A - ( E + F + G + H) / 2; + res->y = -C + ( E - F + G - H) / 2; + res->z = -D + ( E - F - G + H) / 2; +} + +//*************************************************************************************************** +void EulerToQuat(float roll, float pitch, float yaw, CQuaternion * quat) +{ + float cr, cp, cy, sr, sp, sy, cpcy, spsy; + + // calculate trig identities + cr = cos(roll/2); + cp = cos(pitch/2); + cy = cos(yaw/2); + + sr = sin(roll/2); + sp = sin(pitch/2); + sy = sin(yaw/2); + + cpcy = cp * cy; + spsy = sp * sy; + + quat->w = cr * cpcy + sr * spsy; + quat->x = sr * cpcy - cr * spsy; + quat->y = cr * sp * cy + sr * cp * sy; + quat->z = cr * cp * sy - sr * sp * cy; +} + +//*************************************************************************************************** +void QuatToMatrix(CQuaternion *quat, FloatMatrix *fm) +{ + float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + + // calculate coefficients + x2 = quat->x + quat->x; y2 = quat->y + quat->y; + z2 = quat->z + quat->z; + xx = quat->x * x2; xy = quat->x * y2; xz = quat->x * z2; + yy = quat->y * y2; yz = quat->y * z2; zz = quat->z * z2; + wx = quat->w * x2; wy = quat->w * y2; wz = quat->w * z2; + + fm->M[0][0] = 1.0f - (yy + zz); fm->M[1][0] = xy - wz; + fm->M[2][0] = xz + wy; + + fm->M[0][1] = xy + wz; fm->M[1][1] = 1.0f - (xx + zz); + fm->M[2][1] = yz - wx; + + fm->M[0][2] = xz - wy; fm->M[1][2] = yz + wx; + fm->M[2][2] = 1.0f - (xx + yy); +} + +//*************************************************************************************************** +void MatrixToQuat(FloatMatrix *fm, CQuaternion *quat) +{ + float tr, s, q[4]; + int i, j, k; + + int nxt[3] = {1, 2, 0}; + + tr = fm->M[0][0] + fm->M[1][1] + fm->M[2][2]; + + // check the diagonal + if (tr > 0.0f) + { + s = sqrt (tr + 1.0f); + quat->w = s / 2.0f; + s = 0.5f / s; + quat->x = (fm->M[1][2] - fm->M[2][1]) * s; + quat->y = (fm->M[2][0] - fm->M[0][2]) * s; + quat->z = (fm->M[0][1] - fm->M[1][0]) * s; + } + else + { + // diagonal is negative + i = 0; + if (fm->M[1][1] > fm->M[0][0]) i = 1; + if (fm->M[2][2] > fm->M[i][i]) i = 2; + j = nxt[i]; + k = nxt[j]; + + s = sqrt ((fm->M[i][i] - (fm->M[j][j] + fm->M[k][k])) + 1.0f); + + q[i] = s * 0.5f; + + if (s != 0.0f) s = 0.5f / s; + + q[3] = (fm->M[j][k] - fm->M[k][j]) * s; + q[j] = (fm->M[i][j] + fm->M[j][i]) * s; + q[k] = (fm->M[i][k] + fm->M[k][i]) * s; + + quat->x = q[0]; + quat->y = q[1]; + quat->z = q[2]; + quat->w = q[3]; + } +} + +//*************************************************************************************************** +//*************************************************************************************************** + +// temporary matrix conversion stuff + +void cmat_to_fmat(CMatrix33 *cm, FloatMatrix *fm) +{ + fm->M[0][0] = float(((cm->M[0] & CMAT0_MASK) >> 20)) / 512.f; + fm->M[0][1] = float(((cm->M[0] & CMAT1_MASK) >> 10)) / 512.f; + fm->M[0][2] = float(((cm->M[0] & CMAT2_MASK) >> 00)) / 512.f; + + fm->M[1][0] = float(((cm->M[1] & CMAT0_MASK) >> 20)) / 512.f; + fm->M[1][1] = float(((cm->M[1] & CMAT1_MASK) >> 10)) / 512.f; + fm->M[1][2] = float(((cm->M[1] & CMAT2_MASK) >> 00)) / 512.f; + + fm->M[2][0] = float(((cm->M[2] & CMAT0_MASK) >> 20)) / 512.f; + fm->M[2][1] = float(((cm->M[2] & CMAT1_MASK) >> 10)) / 512.f; + fm->M[2][2] = float(((cm->M[2] & CMAT2_MASK) >> 00)) / 512.f; + + // this is pretty damn shite. + if (fm->M[0][0] >= 1.f) fm->M[0][0] -= 2.f; + if (fm->M[0][1] >= 1.f) fm->M[0][1] -= 2.f; + if (fm->M[0][2] >= 1.f) fm->M[0][2] -= 2.f; + if (fm->M[1][0] >= 1.f) fm->M[1][0] -= 2.f; + if (fm->M[1][1] >= 1.f) fm->M[1][1] -= 2.f; + if (fm->M[1][2] >= 1.f) fm->M[1][2] -= 2.f; + if (fm->M[2][0] >= 1.f) fm->M[2][0] -= 2.f; + if (fm->M[2][1] >= 1.f) fm->M[2][1] -= 2.f; + if (fm->M[2][2] >= 1.f) fm->M[2][2] -= 2.f; +} + +//*************************************************************************************************** +void fmat_to_mat(FloatMatrix *fm, Matrix33 *m) +{ + m->M[0][0] = SLONG(fm->M[0][0] * 32768.f); + m->M[0][1] = SLONG(fm->M[0][1] * 32768.f); + m->M[0][2] = SLONG(fm->M[0][2] * 32768.f); + + m->M[1][0] = SLONG(fm->M[1][0] * 32768.f); + m->M[1][1] = SLONG(fm->M[1][1] * 32768.f); + m->M[1][2] = SLONG(fm->M[1][2] * 32768.f); + + m->M[2][0] = SLONG(fm->M[2][0] * 32768.f); + m->M[2][1] = SLONG(fm->M[2][1] * 32768.f); + m->M[2][2] = SLONG(fm->M[2][2] * 32768.f); +} + + +//*************************************************************************************************** +//*************************************************************************************************** + +void build_tween_matrix(struct Matrix33 *mat,struct CMatrix33 *cmat1,struct CMatrix33 *cmat2,SLONG tween); + +// external stuff + +void CQuaternion::BuildTween(struct Matrix33 *dest,struct CMatrix33 *m1,struct CMatrix33 *m2,SLONG tween) +{ + // 1st attempt - (slow) + // * construct the quaternions from the compressed integer matrices + // * SLERP the quaternions using the tween value + // * construct a non-compressed integer matrix from the resulting quaternion + + FloatMatrix f1, f2, f3; + + cmat_to_fmat(m1, &f1); + cmat_to_fmat(m2, &f2); + + float t = float(tween) / 256.f; + float u = 1.f - t; + + CQuaternion q1, q2, q3; + + MatrixToQuat(&f1, &q1); + MatrixToQuat(&f2, &q2); + QuatSlerp(&q1, &q2, t, &q3); + QuatToMatrix(&q3, &f3); + + fmat_to_mat(&f3, dest); +} diff --git a/fallen/Editor/Source/SaveTab.cpp b/fallen/Editor/Source/SaveTab.cpp new file mode 100644 index 0000000..ddb19f8 --- /dev/null +++ b/fallen/Editor/Source/SaveTab.cpp @@ -0,0 +1,879 @@ +// SaveTab.cpp +// Guy Simmons, 26th January 1998. + +#include "Editor.hpp" +#include "EdCom.h" +#include "Edway.h" + +#include "SaveTab.def" + +#include "..\..\Headers\Game.h" +#include "..\..\Headers\Level.h" +#include "..\..\Headers\Command.h" + +//--------------------------------------------------------------- + +#define CTRL_LOAD_BUTTON 1 +#define CTRL_SAVE_BUTTON 2 + +//--------------------------------------------------------------- + +SaveTab::SaveTab() +{ + CBYTE lev_name[32]; + + + CurrentLevel = 0; + HilitedLevel = 0; + SaveState = TRUE; + + InitControlSet(save_tab_def); + + MapLevels(); + + sprintf(lev_name,"Level %d",CurrentLevel); + ((CStaticText*)GetControlPtr(3))->SetString1(lev_name); +} + +//--------------------------------------------------------------- + +SaveTab::~SaveTab() +{ +} + +//--------------------------------------------------------------- + +void SaveTab::DrawTabContent(void) +{ + SetTabDrawArea(); + ClearTab(); + + DrawControlSet(); + + DrawLevelBox(); +} + +//--------------------------------------------------------------- + +UWORD SaveTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + CBYTE lev_name[32]; + UWORD select_pos; + MFPoint local_point; + + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + local_point = *clicked_point; + GlobalToLocal(&local_point); + select_pos = LevelHilitePos(&local_point); + if(select_pos) + { + CurrentLevel = select_pos-1; + sprintf(lev_name,"Level %d",CurrentLevel); + ((CStaticText*)GetControlPtr(3))->SetString1(lev_name); + } + else + { + local_point = *clicked_point; + switch(HandleControlSetClick(flags,&local_point)) + { + case 0: + break; + case CTRL_LOAD_BUTTON: + LoadLevel(); + break; + case CTRL_SAVE_BUTTON: + SaveLevel(); + break; + } + } + break; + case RIGHT_CLICK: + break; + } + return 0; +} + +//--------------------------------------------------------------- + +void SaveTab::HandleTab(MFPoint *current_point) +{ + UBYTE update = 0; + UWORD select_pos; + MFPoint local_point; + static BOOL cleanup = FALSE; + + + ModeTab::HandleTab(current_point); + + local_point = *current_point; + GlobalToLocal(&local_point); + + select_pos = LevelHilitePos(&local_point); + if(select_pos) + { + update = 1; + cleanup = TRUE; + } + + if(!update && cleanup) + { + update = 1; + cleanup = FALSE; + } + + if(update) + { + if(LockWorkScreen()) + { + DrawLevelBox(); + + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } +} + +//--------------------------------------------------------------- + +void SaveTab::HandleControl(UWORD control_id) +{ + +} + +//--------------------------------------------------------------- + +void SaveTab::DrawLevelBox(void) +{ + CBYTE lev_name[32]; + UWORD select_pos; + SLONG c0,c1, + level_count = 0, + x_offset, + y_offset, + x_step, + y_step; + EdRect item_rect, + levels_rect; + MFPoint local_point; + + + SetTabDrawArea(); + + local_point.X = MouseX; + local_point.Y = MouseY; + GlobalToLocal(&local_point); + + select_pos = LevelHilitePos(&local_point); + + x_step = QTStringWidth("Level")+30; + y_step = QTStringHeight()+4; + x_offset = (ContentWidth()-(5*x_step))>>1; + y_offset = (ContentHeight()-(20*y_step))-10; + + levels_rect.SetRect(x_offset,y_offset,(5*x_step),(20*y_step)); + levels_rect.FillRect(CONTENT_COL); + + for(c0=0;c0<20;c0++) + { + for(c1=0;c1<5;c1++) + { + item_rect.SetRect ( + x_offset+(c1*x_step), + y_offset+(c0*y_step)+((y_step-QTStringHeight())>>1), + x_step, + y_step + ); + if(select_pos==(level_count+1)) + item_rect.FillRect(HILITE_COL); + else if(level_count==CurrentLevel) + item_rect.FillRect(SELECT_COL); + else if(GetMapBit(level_count)) + item_rect.FillRect(ACTIVE_COL); + + sprintf(lev_name,"Level %d",level_count); + QuickTextC ( + item_rect.GetLeft()+4, + item_rect.GetTop(), + lev_name, + 0 + ); + level_count++; + } + } + + levels_rect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +UWORD SaveTab::LevelHilitePos(MFPoint *current_point) +{ + SLONG c0,c1, + level_count = 0, + x_offset, + y_offset, + x_step, + y_step; + EdRect item_rect, + levels_rect; + + + x_step = QTStringWidth("Level")+30; + y_step = QTStringHeight()+4; + x_offset = (ContentWidth()-(5*x_step))>>1; + y_offset = (ContentHeight()-(20*y_step))-10; + levels_rect.SetRect(x_offset,y_offset,(5*x_step),(20*y_step)); + + if(levels_rect.PointInRect(current_point)) + { + for(c0=0;c0<20;c0++) + { + for(c1=0;c1<5;c1++) + { + item_rect.SetRect ( + x_offset+(c1*x_step), + y_offset+(c0*y_step)+((y_step-QTStringHeight())>>1), + x_step, + y_step + ); + if(item_rect.PointInRect(current_point)) + { + return level_count+1; + } + + level_count++; + } + } + } + return 0; +} + +//--------------------------------------------------------------- + +void SaveTab::MapLevels(void) +{ + CBYTE level_name[256]; + ULONG c0; + + + ZeroMemory(LevelsMap,sizeof(LevelsMap)); + for(c0=0;c0<128;c0++) + { + sprintf(level_name,"\\Fallen\\Levels\\Level%3.3d.lev",c0); + if(FileExists(level_name)) + SetMapBit(c0); + } +} + +//--------------------------------------------------------------- + +UWORD comlist_mapping_table[MAX_EDIT_COMLISTS], + conlist_mapping_table[MAX_EDIT_CLISTS], + thing_mapping_table[MAX_MAP_THINGS], + waypoint_mapping_table[MAX_EDIT_WAYPOINTS]; + +void SaveTab::LoadLevel(void) +{ + CBYTE level_name[256]; + UBYTE version; + UWORD ed_thing, + new_thing, + new_waypoint; + ULONG c0,c1, + clist_count, + thing_count, + waypoint_count; + Alert save_alert; + CommandDef the_com_def; + CommandListDef the_comlist_def; + ConditionDef the_con_def; + ConditionListDef the_conlist_def; + EditCommand *the_command; + EditComList *the_comlist; + EditCondition *the_condition; + EditCondList *the_conlist; + MFFileHandle load_file; + ThingDef the_t_def; + WaypointDef the_w_def; + + + if(SaveState==FALSE) + { + if(!save_alert.HandleAlert("The current level has not been saved.","Do you wish to continue?")) + { + RequestUpdate(); + return; + } + RequestUpdate(); + } + + // Delete all of the existing things. + for(c0=0;c0>8,the_t_def.Z>>8,new_thing); + + // Set up mapping table. + thing_mapping_table[the_t_def.EdThingRef] = new_thing; + } + } + } + +// +// Load Waypoints. +// + // Get the waypoint count. + FileRead(load_file,&waypoint_count,sizeof(waypoint_count)); + + for(c0=0;c0CListName,the_conlist_def.ListName,sizeof(the_conlist->CListName)); + + for(c1=0;c1Flags = the_con_def.Flags; + the_condition->ConditionType = the_con_def.ConditionType; + the_condition->GroupRef = the_con_def.GroupRef; + the_condition->Data1 = the_con_def.Data1; + the_condition->Data2 = the_con_def.Data2; + the_condition->Data3 = the_con_def.Data3; + } + } + } + } +// +// Remap the conditions. +// + for(c0=1;c0ConditionType) + { + case CON_NONE: + break; + case CON_THING_DEAD: + the_condition->Data1 = thing_mapping_table[the_condition->Data1]; + break; + case CON_ALL_GROUP_DEAD: + break; + case CON_PERCENT_GROUP_DEAD: + break; + case CON_THING_NEAR_PLAYER: + the_condition->Data1 = thing_mapping_table[the_condition->Data1]; + the_condition->Data2 = (UWORD)65536; + break; + case CON_GROUP_NEAR_PLAYER: + break; + case CON_CLASS_NEAR_PLAYER: + break; + case CON_THING_NEAR_THING: + the_condition->Data1 = thing_mapping_table[the_condition->Data1]; + the_condition->Data2 = thing_mapping_table[the_condition->Data2]; + the_condition->Data3 = (UWORD)65536; + break; + case CON_GROUP_NEAR_THING: + break; + case CON_CLASS_NEAR_THING: + break; + case CON_CLASS_COUNT: + break; + case CON_GROUP_COUNT: + break; + case CON_SWITCH_TRIGGERED: + the_condition->Data1 = thing_mapping_table[the_condition->Data1]; + break; + case CON_TIME: + break; + case CON_CLIST_FULFILLED: + the_condition->Data1 = conlist_mapping_table[the_condition->Data1]; + break; + } + } + } +// +// Load Commands. +// + // Get the command list count. + FileRead(load_file,&clist_count,sizeof(clist_count)); + + for(c0=0;c0ComListName,the_comlist_def.ListName,sizeof(the_comlist->ComListName)); + + for(c1=0;c1Flags = the_com_def.Flags; + the_command->CommandType = the_com_def.CommandType; + the_command->GroupRef = the_com_def.GroupRef; + the_command->Data1 = the_com_def.Data1; + the_command->Data2 = the_com_def.Data2; + the_command->Data3 = the_com_def.Data3; + } + } + } + } +// +// Remap the commands. +// + for(c0=1;c0CommandType) + { + case COM_NONE: + break; + case COM_ATTACK_PLAYER: + break; + case COM_ATTACK_THING: + case COM_DEFEND_THING: + case COM_WAIT_FOR_TRIGGER: + the_command->Data1 = thing_mapping_table[the_command->Data1]; + break; + case COM_ATTACK_GROUP: + break; + case COM_ATTACK_CLASS: + break; + case COM_DEFEND_PLAYER: + break; + case COM_DEFEND_GROUP: + break; + case COM_DEFEND_CLASS: + break; + case COM_PATROL_WAYPOINT: + break; + case COM_START_TIMER: + break; + case COM_WAIT_FOR_CLIST: + the_command->Data1 = conlist_mapping_table[the_command->Data1]; + break; + case COM_FOLLOW_PLAYER: + break; + } + + switch(the_command->Data2) + { + case COM_S_NONE: + break; + case COM_S_UNTIL_TRIGGER: + case COM_S_WHILE_TRIGGER: + the_command->Data3 = thing_mapping_table[the_command->Data3]; + break; + case COM_S_UNTIL_CLIST: + case COM_S_WHILE_CLIST: + the_command->Data3 = conlist_mapping_table[the_command->Data3]; + break; + } + } + } + +// +// Remap Thing references. +// + for(c0=0;c0Flags; + current_condition.ConditionType = the_condition->ConditionType; + current_condition.GroupRef = the_condition->GroupRef; + current_condition.Data1 = the_condition->Data1; + current_condition.Data2 = the_condition->Data2; + current_condition.Data3 = the_condition->Data3; + FileWrite(save_file,¤t_condition,sizeof(current_condition)); + + the_condition = the_condition->Next; + } + } + } + +// +// Save Commands. +// + // Write out the number of command lists. + FileWrite(save_file,&ed_comlist_count,sizeof(ed_comlist_count)); + + // Save out all command lists. + for(c0=1;c0Flags; + current_command.CommandType = the_command->CommandType; + current_command.GroupRef = the_command->GroupRef; + current_command.Data1 = the_command->Data1; + current_command.Data2 = the_command->Data2; + current_command.Data3 = the_command->Data3; + FileWrite(save_file,¤t_command,sizeof(current_command)); + + the_command = the_command->Next; + } + } + } + + // Seek back to the thing count & write it out. + FileSeek(save_file,SEEK_MODE_BEGINNING,sizeof(version)); + FileWrite(save_file,&thing_count,sizeof(thing_count)); + + FileClose(save_file); + } + + SaveState = TRUE; + MapLevels(); +} + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/SaveTab.def b/fallen/Editor/Source/SaveTab.def new file mode 100644 index 0000000..a53f5d6 --- /dev/null +++ b/fallen/Editor/Source/SaveTab.def @@ -0,0 +1,14 @@ + + +//--------------------------------------------------------------- + +ControlDef save_tab_def[] = +{ + { BUTTON, 0, "Load Level", 2, 20, 0, 0 }, + { BUTTON, 0, "Save Level", 2, 40, 0, 0 }, + { STATIC_TEXT, 0, "Current Level : ",2, 60, 0, 10 }, + + { 0 } +}; + +//--------------------------------------------------------------- diff --git a/fallen/Editor/Source/Thing.cpp b/fallen/Editor/Source/Thing.cpp new file mode 100644 index 0000000..de2eb8c --- /dev/null +++ b/fallen/Editor/Source/Thing.cpp @@ -0,0 +1,139 @@ +// Thing.cpp +// Guy Simmons, 14th October 1997. + +#include "Editor.hpp" + +#include "DarkCity.h" +#include "Structs.h" +#include "Thing.h" +#include "map.h" +#include "prim.h" + + +extern void apply_light_to_map(SLONG x,SLONG y,SLONG z,SLONG bright); + + + + +//**************************************** +// old style thing functions +// courtesy of miked +//**************************************** +//its only the editor, no need for 2 way link lists + + +//data +struct MapThing map_things[MAX_MAP_THINGS]; + + +UWORD find_empty_map_thing(void) +{ + SLONG c0; + for(c0=1;c0=EDIT_MAP_WIDTH||z<0||z>=EDIT_MAP_DEPTH) + { + ERROR_MSG(1," add thing off map"); + return; + } + if(edit_map[x][z].MapThingIndex) + { + map_things[edit_map[x][z].MapThingIndex].MapParent=thing; + map_things[thing].MapChild=edit_map[x][z].MapThingIndex; + map_things[thing].MapParent=0; + edit_map[x][z].MapThingIndex=thing; + } + else + { + edit_map[x][z].MapThingIndex=thing; +// LogText(" add thing x %d z %d \n",x,z); + map_things[thing].MapChild=0; + map_things[thing].MapParent=0; + } +} + +void delete_thing_from_edit_map(SLONG x,SLONG z,UWORD thing) +{ + if(x<0||x>=EDIT_MAP_WIDTH||z<0||z>=EDIT_MAP_DEPTH) + { + ERROR_MSG(1," del thing off map"); + return; + } + + //does the thing we are deleting have a parent + if(map_things[thing].MapParent) + { + map_things[map_things[thing].MapParent].MapChild=map_things[thing].MapChild; + + //if thing has a child then must update the childs parent + if(map_things[thing].MapChild) + { + map_things[map_things[thing].MapChild].MapParent = map_things[thing].MapParent; + } + } + else + //removing directly off mapwho + { + edit_map[x][z].MapThingIndex=map_things[thing].MapChild; + if(map_things[thing].MapChild) + map_things[map_things[thing].MapChild].MapParent=0; + } + +} + +SLONG move_thing_on_cells(UWORD thing,SLONG x,SLONG y,SLONG z) +{ + if( (x>>ELE_SHIFT) != (map_things[thing].X>>ELE_SHIFT)|| + (z>>ELE_SHIFT) != (map_things[thing].Z>>ELE_SHIFT) ) + { + delete_thing_from_edit_map((map_things[thing].X>>ELE_SHIFT),(map_things[thing].Z>>ELE_SHIFT),thing); + add_thing_to_edit_map(x>>ELE_SHIFT,(z>>ELE_SHIFT),thing); + } + map_things[thing].X=x; + map_things[thing].Y=y; + map_things[thing].Z=z; + return(1); +} + + +void delete_thing(SWORD index) +{ + struct MapThing *p_mthing; + p_mthing=TO_MTHING(index); + + switch(p_mthing->Type) + { + case MAP_THING_TYPE_LIGHT: + apply_light_to_map(p_mthing->X,p_mthing->Y,p_mthing->Z,-p_mthing->IndexOther); + break; + } + delete_thing_from_edit_map(p_mthing->X>>ELE_SHIFT,p_mthing->Z>>ELE_SHIFT,index); + p_mthing->Type=0; +} + diff --git a/fallen/Editor/Source/ThingTab.cpp b/fallen/Editor/Source/ThingTab.cpp new file mode 100644 index 0000000..25e4778 --- /dev/null +++ b/fallen/Editor/Source/ThingTab.cpp @@ -0,0 +1,681 @@ +// ThingTab.cpp +// Guy Simmons, 15th January 1998. + +#include "Editor.hpp" + + +//--------------------------------------------------------------- + +#define CTRL_CLASS_MENU 1 +#define CTRL_CLASS_TEXT 2 +#define CTRL_CLASS_CHECKS 3 + +#define CTRL_GENUS_MENU 1 +#define CTRL_GENUS_TEXT 2 +#define CTRL_ITEM_3 3 +#define CTRL_ITEM_4 4 + +#define UPDATE_NONE 0 +#define UPDATE_ALL 1 +#define UPDATE_CLASS_SET 2 + +#define MAX_VIEW_LISTS 15 +#define LISTS_X 2 +#define LISTS_Y 2 +#define LISTS_WIDTH 150 +#define LISTS_HEIGHT ((MAX_VIEW_LISTS*8)+3) + +#include "ThingTab.def" + +//--------------------------------------------------------------- + +extern CBYTE *class_text[]; +extern CBYTE *genus_text[][10]; + +//--------------------------------------------------------------- + +ThingTab::ThingTab() +{ + CurrentClass = 0; + CurrentGenus = 0; + CurrentThing = 0; + ThingFlags = 0xffff; + TabData = 0; + TabMode = THING_MODE_NONE; + + InitControlSet(thing_tab_def); + UpdateCheckBoxes(); + CurrentSetRect.SetRect(0,30,ContentRect.GetWidth(),100); +} + +//--------------------------------------------------------------- + +ThingTab::~ThingTab() +{ +} + +//--------------------------------------------------------------- + +void ThingTab::DrawTabContent(void) +{ + SLONG message_height, + message_width; + EdRect message_rect; + + + SetTabDrawArea(); + ClearTab(); + + DrawControlSet(); + DrawClassSet(); + + switch(TabMode) + { + case THING_MODE_NONE: + break; + case THING_MODE_SELECT_THING: + message_height = QTStringHeight()+12; + message_width = QTStringWidth("Select A Thing")+12; + message_rect.SetRect( + 150-(message_width>>1), + 220-(message_height>>1), + message_width, + message_height + ); + message_rect.FillRect(RED_COL); + message_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + message_rect.GetLeft()+6, + message_rect.GetTop()+6, + "Select A Thing", + 0 + ); + break; + case THING_MODE_SELECT_SWITCH: + message_height = QTStringHeight()+12; + message_width = QTStringWidth("Select A Trigger")+12; + message_rect.SetRect( + 150-(message_width>>1), + 220-(message_height>>1), + message_width, + message_height + ); + message_rect.FillRect(RED_COL); + message_rect.HiliteRect(HILITE_COL,LOLITE_COL); + QuickTextC ( + message_rect.GetLeft()+6, + message_rect.GetTop()+6, + "Select A Trigger", + 0 + ); + break; + } +} + +//--------------------------------------------------------------- + +void ThingTab::UpdateTab(UBYTE update_level) +{ + if(update_level) + { + if(LockWorkScreen()) + { + switch(update_level) + { + case UPDATE_ALL: + DrawTabContent(); + break; + case UPDATE_CLASS_SET: + DrawClassSet(); + break; + } + UnlockWorkScreen(); + ShowWorkWindow(0); + } + } +} + +//--------------------------------------------------------------- + +UWORD ThingTab::HandleTabClick(UBYTE flags,MFPoint *clicked_point) +{ + UBYTE update = UPDATE_NONE; + ULONG control_id = 0; + MFPoint local_point; + + + if(TabMode) + { + return 0; + } + if(TabData) + { + *DataPtr = TabData; + TabData = 0; + update = UPDATE_ALL; + UpdateClassInfo(); + } + + SetTabDrawArea(); + + switch(flags) + { + case NO_CLICK: + break; + case LEFT_CLICK: + local_point = *clicked_point; + control_id = HandleControlSetClick(flags,&local_point); + HandleControl(control_id); + + local_point = *clicked_point; + control_id = CurrentSet.HandleControlSetClick(flags,&local_point); + if(CurrentClass==CLASS_BUILDING) + HandleBuildingControl(control_id); + else + HandleClassControl(control_id); + update = UPDATE_ALL; + break; + case RIGHT_CLICK: + break; + } + + UpdateTab(update); + + return 0; +} + +//--------------------------------------------------------------- + +void ThingTab::HandleTab(MFPoint *current_point) +{ + UBYTE update = UPDATE_NONE; + static BOOL cleanup = FALSE; + + + if(TabMode) + { + cleanup = TRUE; + return; + } + if(TabData) + { + *DataPtr = TabData; + TabData = 0; + update = UPDATE_ALL; + UpdateClassInfo(); + } + + ModeTab::HandleTab(current_point); + + if(CurrentSet.HandleControlSet(current_point)) + cleanup = TRUE; + + if(update==UPDATE_NONE && cleanup) + { + update = UPDATE_ALL; + cleanup = FALSE; + } + + UpdateTab(update); +} + +//--------------------------------------------------------------- + +void ThingTab::HandleControl(UWORD control_id) +{ + SLONG control = control_id&0xff; + + + if(control) + { + if((control) > CTRL_CLASS_CHECKS) + { + ThingFlags ^= (1<<(control-CTRL_CLASS_CHECKS)); + UpdateCheckBoxes(); + + } + else + { + switch(control) + { + case CTRL_CLASS_MENU: + CurrentClass = (control_id>>8)-1; + CurrentGenus = 0; + break; + } + UpdateTabInfo(); + UpdateClassInfo(); + } + } +} + +//--------------------------------------------------------------- + +void ThingTab::HandleClassControl(UWORD control_id) +{ + EditComList *the_list; + + + if(control_id) + { + switch(control_id&0xff) + { + case CTRL_GENUS_MENU: + CurrentGenus = (control_id>>8); + if(CurrentClass==CLASS_PERSON) + { + CurrentGenus += PERSON_ROPER; + } + else if(CurrentClass==CLASS_SWITCH) + { + class_defs[CLASS_SWITCH] = switch_defs[CurrentGenus]; + UpdateTabInfo(); + } + + if(CurrentThing) + { +// map_things[CurrentThing].Genus = CurrentGenus; + } + break; + case CTRL_GENUS_TEXT: + break; + case CTRL_ITEM_3: + switch(CurrentClass) + { + case CLASS_PLAYER: + break; + case CLASS_CAMERA: + break; + case CLASS_BUILDING: + break; + case CLASS_PERSON: + the_list = SelectCommandList(); + if(the_list) + { + map_things[CurrentThing].Data[0] = (SLONG)(the_list-edit_comlists); + } + break; + case CLASS_SWITCH: + if(CurrentGenus==SWITCH_THING) + { + TabMode = THING_MODE_SELECT_THING; + DataPtr = &map_things[CurrentThing].Data[1]; + } + break; + case CLASS_VEHICLE: + + // + // MAKE IT LIKE PEOPLE! + // + + the_list = SelectCommandList(); + if(the_list) + { + map_things[CurrentThing].Data[0] = (SLONG)(the_list-edit_comlists); + } + break; + case CLASS_SPECIAL: + break; + } + break; + case CTRL_ITEM_4: + break; + } + } + UpdateClassInfo(); +} + +//--------------------------------------------------------------- + +void ThingTab::HandleBuildingControl(UWORD control_id) +{ + MapThing *t_mthing; + + + if(control_id) + { + t_mthing = TO_MTHING(CurrentThing); + switch(control_id&0xff) + { + case 0: + break; + case 1: + break; + case 2: + t_mthing->EditorFlags ^= 0x01; + CurrentSet.SetControlState(2,(t_mthing->EditorFlags&0x01 ? CTRL_SELECTED : CTRL_DESELECTED)); + break; + case 3: + TabMode = THING_MODE_SELECT_SWITCH; + DataPtr = (SLONG*)&map_things[CurrentThing].EditorData; + break; + } + } +} + +//--------------------------------------------------------------- + +EditComList *ThingTab::SelectCommandList(void) +{ + BOOL exit = FALSE; + UBYTE update = 2; + UWORD select_pos; + SLONG c0; + ControlSet select_set; + EditComList *current_list, + *hilited_list, + *selected_list = NULL; + EdRect bounds_rect, + item_rect, + lists_rect; + MFPoint current_point; + + + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + bounds_rect.SetRect ( + (WorkScreenPixelWidth-(LISTS_WIDTH+20))>>1, + (WorkScreenHeight-(LISTS_HEIGHT+7))>>1, + LISTS_WIDTH+20, + LISTS_HEIGHT+7 + ); + select_set.ControlSetBounds(&bounds_rect); + select_set.InitControlSet(select_command_def); + if(ed_comlist_count>MAX_VIEW_LISTS) + { + ((CVSlider*)select_set.GetControlPtr(1))->SetValueRange(0,ed_comlist_count-MAX_VIEW_LISTS); + } + ((CVSlider*)select_set.GetControlPtr(1))->SetCurrentValue(0); + + while(SHELL_ACTIVE && !exit) + { + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + current_point.X = MouseX; + current_point.Y = MouseY; + + if(select_set.HandleControlSet(¤t_point)) + update = 1; + + lists_rect.SetRect(LISTS_X,LISTS_Y,LISTS_WIDTH,LISTS_HEIGHT); + current_point.X -= bounds_rect.GetLeft(); + current_point.Y -= bounds_rect.GetTop(); + select_pos = 0; + if(lists_rect.PointInRect(¤t_point)) + { + for(c0=0;c0GetCurrentValue(); + while(current_list && c0) + { + c0--; + current_list = current_list->Next; + } + + c0 = 0; + hilited_list = NULL; + while(current_list && c0ComListName,0); + + c0++; + current_list = current_list->Next; + } + + lists_rect.HiliteRect(LOLITE_COL,HILITE_COL); + } + + if(update<=2) + { + select_set.DrawControlSet(); + } + + UnlockWorkScreen(); + ShowWorkWindow(0); + } + update = 0; + } + } + select_set.FiniControlSet(); + + return selected_list; +} + +//--------------------------------------------------------------- + +void ThingTab::DrawClassSet(void) +{ + EdRect bounds_rect; + + + bounds_rect.SetRect(ContentLeft()+3,ContentTop()+40,ContentWidth()-6,100); + CurrentSet.ControlSetBounds(&bounds_rect); + CurrentSet.SetControlDrawArea(); + CurrentSet.FillControlDrawArea(CONTENT_COL); + CurrentSet.DrawControlSet(); + CurrentSet.HiliteControlDrawArea(LOLITE_COL,LOLITE_COL); + + SetTabDrawArea(); +} + +//--------------------------------------------------------------- + +void ThingTab::UpdateTabInfo(void) +{ + MapThing *t_mthing; + + + ((CStaticText*)GetControlPtr(CTRL_CLASS_TEXT))->SetString1(class_text[CurrentClass]); + + CurrentSet.InitControlSet(class_defs[CurrentClass]); + + if(CurrentClass==CLASS_BUILDING && CurrentThing) + { + t_mthing = TO_MTHING(CurrentThing); + CurrentSet.SetControlState(2,(t_mthing->EditorFlags&0x01 ? CTRL_SELECTED : CTRL_DESELECTED)); + } + + UpdateTab(UPDATE_ALL); +} + +//--------------------------------------------------------------- + +void ThingTab::UpdateClassInfo(void) +{ + CBYTE text[64]; + MapThing *t_mthing; + + + if(CurrentClass==CLASS_BUILDING && CurrentThing) + { + t_mthing = TO_MTHING(CurrentThing); + + // Show the building ID. + sprintf(text,"%ld",t_mthing->BuildingList); + ((CStaticText*)CurrentSet.GetControlPtr(1))->SetString1(text); + + // Set the 'Locked' check box state + CurrentSet.SetControlState(2,(t_mthing->EditorFlags&0x01 ? CTRL_SELECTED : CTRL_DESELECTED)); + + // Show the current unlock switch. + if(t_mthing->EditorData) + sprintf(text,"%ld",t_mthing->EditorData); + else + sprintf(text,"None"); + ((CStaticText*)CurrentSet.GetControlPtr(4))->SetString1(text); + } + else if(CurrentClass==CLASS_SWITCH) + { + class_defs[CLASS_SWITCH] = switch_defs[CurrentGenus]; + UpdateTabInfo(); + ((CStaticText*)CurrentSet.GetControlPtr(CTRL_GENUS_TEXT))->SetString1(genus_text[CurrentClass][CurrentGenus]); + } + else if(CurrentThing) + ((CStaticText*)CurrentSet.GetControlPtr(CTRL_GENUS_TEXT))->SetString1(genus_text[CurrentClass][CurrentGenus]); + + + switch(CurrentClass) + { + case CLASS_PLAYER: + break; + case CLASS_CAMERA: + break; + case CLASS_BUILDING: + + break; + case CLASS_PERSON: + if(map_things[CurrentThing].Class==CLASS_PERSON) + { + if(CurrentThing) + { + CurrentSet.SetControlState(CTRL_ITEM_3,CTRL_ACTIVE); + sprintf(text,"%s",edit_comlists[map_things[CurrentThing].Data[0]].ComListName); + } + else + { + CurrentSet.SetControlState(CTRL_ITEM_3,CTRL_INACTIVE); + sprintf(text,"None"); + } + ((CStaticText*)CurrentSet.GetControlPtr(CTRL_ITEM_4))->SetString1(text); + } + break; + case CLASS_SWITCH: + switch(CurrentGenus) + { + case SWITCH_NONE: + break; + case SWITCH_PLAYER: + break; + case SWITCH_THING: + if(map_things[CurrentThing].Genus==SWITCH_THING) + { + if(CurrentThing) + { + CurrentSet.SetControlState(CTRL_ITEM_3,CTRL_ACTIVE); + sprintf(text,"%ld",map_things[CurrentThing].Data[1]); + } + else + { + CurrentSet.SetControlState(CTRL_ITEM_3,CTRL_INACTIVE); + sprintf(text,"0"); + } + ((CStaticText*)CurrentSet.GetControlPtr(CTRL_ITEM_4))->SetString1(text); + } + break; + case SWITCH_GROUP: + break; + case SWITCH_CLASS: + break; + } + break; + case CLASS_VEHICLE: + + if(map_things[CurrentThing].Class==CLASS_VEHICLE) + { + if(CurrentThing) + { + CurrentSet.SetControlState(CTRL_ITEM_3,CTRL_ACTIVE); + sprintf(text,"%s",edit_comlists[map_things[CurrentThing].Data[0]].ComListName); + } + else + { + CurrentSet.SetControlState(CTRL_ITEM_3,CTRL_INACTIVE); + sprintf(text,"None"); + } + ((CStaticText*)CurrentSet.GetControlPtr(CTRL_ITEM_4))->SetString1(text); + } + + break; + case CLASS_SPECIAL: + break; + } + + UpdateTab(UPDATE_CLASS_SET); +} + +//--------------------------------------------------------------- + +void ThingTab::UpdateCheckBoxes(void) +{ + SLONG c0; + + + for(c0=0;c0<11;c0++) + { + SetControlState(CTRL_CLASS_CHECKS+c0,(ThingFlags&(1<>1); + + if(title_width > title_right) + { + QuickText(title_left+title_right,title_top,"...",TEXT_COL); + } + QuickText(title_left,title_top,Title,TEXT_COL); + } + if(Flags&HAS_ICONS) + { + IconRect.HiliteRect(LOLITE_COL,HILITE_COL); + TopIcons.DrawIcons(); + } + if(Flags&HAS_HSCROLL) + { + HScrollRect.HiliteRect(LOLITE_COL,HILITE_COL); + } + if(Flags&HAS_VSCROLL) + { + VScrollRect.HiliteRect(LOLITE_COL,HILITE_COL); + } + ContentRect.HiliteRect(LOLITE_COL,HILITE_COL); +} + +//--------------------------------------------------------------- + +void Window::DrawWindowContent(void) +{ + SetContentDrawArea(); + if(Flags&HAS_CONTROLS) + DrawControls(); + DrawContent(); + DrawGrowBox(); +} + +//--------------------------------------------------------------- + +void Window::DrawWindow(void) +{ +// if(Update && LockWorkScreen()) + if(LockWorkScreen()) + { + DrawWindowFrame(); + DrawWindowContent(); + UnlockWorkScreen(); + Update = 0; + } +// SetWorkWindowBounds(0,0,WorkScreenWidth,WorkScreenHeight); +// ShowWorkWindow(0); +} + +//--------------------------------------------------------------- + +void Window::DrawControls(void) +{ + ModeTab *current_tab; + + + if(TabList) + { + current_tab = TabList; + while(current_tab) + { + current_tab->DrawTab(); + current_tab = current_tab->GetNextTabLink(); + } + } + else if(WindowControls.GetControlCount()) + { + WindowControls.DrawControlSet(); + } + else + { + QuickText(2,2,"This module has no Tabs or Controls",TEXT_COL); + } +} + +//--------------------------------------------------------------- + +void Window::DrawContent(void) +{ + SetWorkWindowBounds(ContentLeft()+1,ContentTop()+1,ContentWidth()-1,ContentHeight()-1); + + QuickText(2,2,"This module has no DrawContent function",TEXT_COL); +} + +//--------------------------------------------------------------- + +void Window::MoveWindow(SLONG x,SLONG y) +{ + MoveRect(x,y); + SetAreaSizes(); +} + +//--------------------------------------------------------------- + +void Window::SizeWindow(SLONG dx,SLONG dy) +{ + SLONG height; + + height = GetHeight()+dy; + ConstrainHeight(&height); + SetRect(GetLeft(),GetTop(),GetWidth()+dx,height); + SetAreaSizes(); +} + +//--------------------------------------------------------------- + +ULONG Window::WhereInWindow(MFPoint *the_point) +{ + ModeTab *clicked_tab = 0, + *current_tab; + + + if(PointInRect(the_point)) + { + if(Flags&HAS_TITLE) + { + if(TitleRect.PointInRect(the_point)) + return IN_TITLE; + } + else + { + if(TitleRect.PointInRect(the_point)) + return IN_TITLE; + } + + if(Flags&HAS_ICONS) + { + if(IconRect.PointInRect(the_point)) + return IN_ICONS; + } + if(Flags&HAS_GROW) + { + if(GrowRect.PointInRect(the_point)) + return IN_GROW; + } + if(Flags&HAS_HSCROLL) + { + if(HScrollRect.PointInRect(the_point)) + return IN_HSCROLL; + } + if(Flags&HAS_VSCROLL) + { + if(VScrollRect.PointInRect(the_point)) + return IN_VSCROLL; + } + if(Flags&HAS_CONTROLS) + { + if(ControlRect.PointInRect(the_point)) + { + current_tab = TabList; + while(current_tab) + { + if(current_tab->PointInTitle(the_point)) + { + clicked_tab = current_tab; + if(clicked_tab) + { + BringTabToFront(clicked_tab); + if(LockWorkScreen()) + { + DrawWindowContent(); + UnlockWorkScreen(); + } + ShowWorkScreen(0); + } + return OUTSIDE_WINDOW; + } + current_tab = current_tab->GetNextTabLink(); + } + return IN_CONTROLS; + } + } + if(ContentRect.PointInRect(the_point)) + return IN_CONTENT; + return IN_WINDOW; + } + return OUTSIDE_WINDOW; +} + +//--------------------------------------------------------------- + +void Window::ConstrainHeight(SLONG *new_height) +{ + if(*new_height<8) + *new_height = 8; + if(Flags&HAS_TITLE) + { + if(*new_height < 28) + { + *new_height = 28; + } + if(Flags&(HAS_GROW|HAS_HSCROLL)) + { + if(*new_height < 40) + *new_height = 40; + } + } + else if(Flags&(HAS_GROW|HAS_HSCROLL)) + { + if(*new_height < 20) + *new_height = 20; + } +} + +//--------------------------------------------------------------- + +void Window::SetAreaSizes(void) +{ + ModeTab *current_tab; + SLONG content_offset=3; + + + if(Flags&HAS_TITLE) + { + TitleRect.SetRect(GetLeft()+3,GetTop()+3,GetWidth()-6,18); + } + else + { + TitleRect.SetRect(GetLeft(),GetTop(),GetWidth()-6,5); + content_offset=0; + } + + if(Flags&HAS_ICONS) + { + IconRect.SetRect(GetLeft()+3,TitleRect.GetBottom()+3,GetWidth()-6,25); + TopIcons.SetRect(GetLeft()+3,TitleRect.GetBottom()+3,GetWidth()-6,25); + } + else + { + IconRect.SetRect(GetLeft(),TitleRect.GetBottom()+3,0,0); + } + + if(Flags&HAS_CONTROLS) + { + ControlRect.SetRect(GetLeft()+3,IconRect.GetBottom()+3,ControlAreaWidth,ControlAreaHeight); + current_tab = TabList; + while(current_tab) + { + current_tab->MoveTabArea(&ControlRect); + current_tab = current_tab->GetNextTabLink(); + } + if(ControlRect.GetBottom() > GetBottom()) + { + SetRect(GetLeft(),GetTop(),GetWidth(),GetHeight()+(ControlRect.GetBottom()-GetBottom())+3); + } + } + else + { + ControlRect.SetRect(GetLeft(),0,0,0); + } + WindowControls.ControlSetBounds(&ControlRect); + + if(Flags&HAS_GROW) + { + GrowRect.SetRect(GetRight()-14,GetBottom()-14,14,14); + } + else + { + GrowRect.SetRect(0,0,0,0); + } + if(Flags&HAS_HSCROLL) + { + if(Flags&(HAS_VSCROLL|HAS_GROW)) + { + HScrollRect.SetRect(GetLeft()+3,GetBottom()-12,GetWidth()-18,10); + } + else + { + HScrollRect.SetRect(GetLeft()+3,GetBottom()-12,GetWidth()-6,10); + } + } + else + { + HScrollRect.SetRect(GetLeft(),GetBottom(),0,0); + } + if(Flags&HAS_VSCROLL) + { + if(Flags&(HAS_HSCROLL|HAS_GROW)) + { + VScrollRect.SetRect(GetRight()-12,IconRect.GetBottom()+3,10,(GetBottom()-14)-(IconRect.GetBottom()+3)); + } + else + { + VScrollRect.SetRect(GetRight()-12,IconRect.GetBottom()+3,10,(GetBottom()-2)-(IconRect.GetBottom()+3)); + } + } + else + { + VScrollRect.SetRect(GetRight(),IconRect.GetBottom()+3,0,0); + } + + ContentRect.SetRect ( + ControlRect.GetRight()+3, + IconRect.GetBottom()+content_offset, + (VScrollRect.GetLeft()-2)-(ControlRect.GetRight()+3), + (HScrollRect.GetTop()-2)-(IconRect.GetBottom()+content_offset) + ); + Update = 1; +} + +//--------------------------------------------------------------- + +void Window::DrawGrowBox(void) +{ + if(Flags&HAS_GROW) + { + SetWorkWindowBounds(0,0,WorkScreenPixelWidth,WorkScreenHeight); + if(!(Flags&(HAS_HSCROLL|HAS_VSCROLL))) + { + GrowRect.FillRect(CONTENT_COL); + DrawHLineC ( + GrowRect.GetLeft()-1, + ContentRect.GetRight(), + GrowRect.GetTop()-1, + HILITE_COL + ); + DrawVLineC ( + GrowRect.GetLeft()-1, + GrowRect.GetTop()-1, + ContentRect.GetBottom(), + HILITE_COL + ); + } + DrawMonoBSprite(GrowRect.GetLeft(),GrowRect.GetTop(),INTERFACE_SPRITE(GROW_ICON),0); + SetContentDrawArea(); + } +} + +//--------------------------------------------------------------- + +void Window::BringTabToFront(ModeTab *the_tab) +{ + if(the_tab == CurrentTab) + return; // Already at the end of list (Front of display). + + + if(the_tab->GetLastTabLink()) + { // Not at start of list. + the_tab->GetLastTabLink()->SetNextTabLink(the_tab->GetNextTabLink()); + the_tab->GetNextTabLink()->SetLastTabLink(the_tab->GetLastTabLink()); + } + else + { // At start of list. + TabList = the_tab->GetNextTabLink(); + TabList->SetLastTabLink(NULL); + } + the_tab->SetLastTabLink(NULL); + the_tab->SetNextTabLink(NULL); + AddTab(the_tab); +} + +//--------------------------------------------------------------- + +void Window::BringTabIDToFront(UWORD id) +{ + ModeTab *current_tab; + + + current_tab = TabList; + while(current_tab) + { + if(current_tab->GetTabID()==id) + { + BringTabToFront(current_tab); + return; + } + current_tab = current_tab->GetNextTabLink(); + } +} + +//--------------------------------------------------------------- + +void Window::ActivateNextTab(void) +{ + ModeTab *clicked_tab; + + + if(TabList) + { + if(CurrentTab->GetNextTabLink()) + { + clicked_tab = CurrentTab->GetNextTabLink(); + } + else + { + clicked_tab = TabList; + } + BringTabToFront(clicked_tab); + if(LockWorkScreen()) + { + DrawWindowContent(); + UnlockWorkScreen(); + } + ShowWorkScreen(0); + } +} + +//--------------------------------------------------------------- + +void Window::ActivateLastTab(void) +{ + ModeTab *clicked_tab, + *current_tab; + + + if(TabList) + { + if(CurrentTab->GetLastTabLink()) + { + clicked_tab = CurrentTab->GetLastTabLink(); + } + else + { + current_tab = TabList; + while(current_tab->GetNextTabLink()) + current_tab = current_tab->GetNextTabLink(); + clicked_tab = current_tab; + } + BringTabToFront(clicked_tab); + if(LockWorkScreen()) + { + DrawWindowContent(); + UnlockWorkScreen(); + } + ShowWorkScreen(0); + } +} + +//--------------------------------------------------------------- + +void Window::AddTab(ModeTab *the_tab) +{ + if(CurrentTab == NULL) // Start of list? + { + TabList = the_tab; + CurrentTab = TabList; + CurrentTab->SetStateFlags(TAB_ACTIVE); + } + else + { + CurrentTab->SetStateFlags(0); + CurrentTab->SetNextTabLink(the_tab); + the_tab->SetLastTabLink(CurrentTab); + CurrentTab = the_tab; + CurrentTab->SetStateFlags(TAB_ACTIVE); + } +} + +//--------------------------------------------------------------- + +void Window::HandleTab(MFPoint *current_point) +{ + CurrentTab->HandleTab(current_point); +} + +//--------------------------------------------------------------- + +#endif diff --git a/fallen/Editor/Source/building.cpp b/fallen/Editor/Source/building.cpp new file mode 100644 index 0000000..bf4604e --- /dev/null +++ b/fallen/Editor/Source/building.cpp @@ -0,0 +1,5806 @@ +#include "Editor.hpp" + +#include "game.h" +#include "engine.h" +#include "math.h" +#include "thing.h" +#include "map.h" + +#pragma warning( disable : 4244) + +extern void do_quad_clip_list(SWORD face,SLONG p0,SLONG p1,SLONG p2,SLONG p3); //prim.cpp +extern void do_tri_clip_list(SWORD face,SLONG p0,SLONG p1,SLONG p2); //prim.cpp +extern UWORD calc_lights(SLONG x,SLONG y,SLONG z,struct SVECTOR *p_vect); + +extern struct SVECTOR global_res[]; //max points per object? +extern SLONG global_flags[]; +extern UWORD global_bright[]; +extern float global_light[]; + +#define SORT_LEVEL_LONG_LEDGE 1 +#define SORT_LEVEL_FIRE_ESCAPE 3 + +extern SLONG calc_height_at(SLONG x,SLONG z); +extern void insert_collision_vect(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,UBYTE prim,UBYTE prim_extra,SWORD face); +extern SLONG dist_between_vertex_and_vector(SLONG x1,SLONG y1,SLONG x2,SLONG y2,SLONG px,SLONG py); + +struct PrimFace4* create_a_quad(UWORD p1,UWORD p0,UWORD p3,UWORD p2,SWORD texture_style,SWORD texture_piece); +void build_face_texture_info(struct PrimFace4* p_f4,UWORD texture); +struct PrimFace3* create_a_tri(UWORD p2,UWORD p1,UWORD p0,SWORD texture_id,SWORD texture_piece); + +struct BuildingFacet building_facets[MAX_BUILDING_FACETS]; +struct BuildingObject building_objects[MAX_BUILDING_OBJECTS]; + +UWORD next_building_object=1; +UWORD end_building_object=MAX_BUILDING_OBJECTS-2; + +UWORD next_building_facet=1; +UWORD end_building_facet=MAX_BUILDING_FACETS-2; + + +//data + +struct FWindow window_list[MAX_WINDOWS]; +struct FWall wall_list[MAX_WALLS]; +struct FStorey storey_list[MAX_STOREYS]; +struct FBuilding building_list[MAX_BUILDINGS]; + + +/* + + ************************** + Create city code + ---------------- + ************************** + +*/ + +static SLONG build_seed=0x12345678; + +SLONG build_rand(void) +{ + build_seed=(build_seed*12345678)+12345678; +// LogText(" build_seed %x \n",build_seed); + return(build_seed>>16); +} + +void set_build_seed(SLONG seed) +{ + build_seed=seed; +} + + +void add_walk_face_to_map(SWORD face,SLONG x,SLONG z) +{ + if(next_walk_link>=(MAX_WALK_POOL-4)) + { + LogText(" failed out of walk mem \n"); + return; + } + walk_links[next_walk_link].Face=face; + walk_links[next_walk_link].Next=edit_map[x][z].Walkable; + edit_map[x][z].Walkable=next_walk_link; + next_walk_link++; +} + + +void scan_walk_triangle(SLONG x0, SLONG y0, SLONG z0,SLONG x1, SLONG y1, SLONG z1,SLONG x2, SLONG y2, SLONG z2,SLONG face) +{ + + SLONG px,py,pz; + SLONG face_x,face_y,face_z; + SLONG c0; + SLONG s,t,step_s,step_t; + SLONG vx,vy,vz,wx,wy,wz; + struct DepthStrip *me; + SLONG prev_x,prev_z; + SLONG quad; + SLONG len; + CBYTE str[100]; + UBYTE info=0; + + face_x = x0; + face_y = y0; + face_z = z0; + + vx = x1 - x0; + vy = y1 - y0; //vector from point 0 to point 1 + vz = z1 - z0; + + wx = x2 - x0; //vector from point 1 to point 2 + wy = y2 - y0; + wz = z2 - z0; + + len=(sqrl(vx*vx+vy*vy+vz*vz)>>7); + if(len<2) + len=2; + step_s=(1<<7)/len; + len=(sqrl(wx*wx+wy*wy+wz*wz)>>7); + if(len<2) + len=2; + step_t=(1<<7)/len; + + if(step_s==0) + step_s=256; + if(step_t==0) + step_t=256; + + prev_x=-1; + prev_z=-1; + for(s=5; s<(255) ; s+=step_s) + for(t=5; t<(255) && ((s+t)<(256)); t+=step_t) + { + px=face_x+((s*vx)>>8)+((t*wx)>>8); + pz=face_z+((s*vz)>>8)+((t*wz)>>8); + if((px>>8)!=prev_x||(pz>>8)!=prev_z) + { + py=face_y+((s*vy)>>8)+((t*wy)>>8); + + if((px>>8)>0&&(px>>8)>8)>0&&(pz>>8)>8,pz>>8); + add_walk_face_to_map(face,px>>8,pz>>8); + } + prev_x=px>>8; + prev_z=pz>>8; + } + + } +} + +// 0 1 +// +// 2 3 +void add_quad_to_walkable_list(SWORD face) +{ + SLONG x[4],y[4],z[4]; + SLONG c0,p0; + struct PrimFace4 *p_f4; + p_f4=&prim_faces4[face]; + + for(c0=0;c0<4;c0++) + { + p0=p_f4->Points[c0]; + x[c0]=prim_points[p0].X; + y[c0]=prim_points[p0].Y; + z[c0]=prim_points[p0].Z; + } + scan_walk_triangle(x[0],y[0],z[0],x[1],y[1],z[1],x[2],y[2],z[2],face); + scan_walk_triangle(x[1],y[1],z[1],x[3],y[3],z[3],x[2],y[2],z[2],face); + +} + +void add_tri_to_walkable_list(SWORD face) +{ + SLONG x,z; + SLONG p0; + struct PrimFace3 *p_f3; + + p_f3=&prim_faces3[face]; + //for now just take one corner and add it to map at that corner + p0=p_f3->Points[0]; + x=prim_points[p0].X>>ELE_SHIFT; + z=prim_points[p0].Z>>ELE_SHIFT; + add_walk_face_to_map(-face,x,z); +} + +SLONG place_building_at(UWORD prim,SLONG x,SLONG y,SLONG z) +{ + UWORD map_thing; + struct MapThing *p_mthing; + + //y=0; + //LogText(" place building prim %d x %d y %d z %d \n",prim,x,y,z); + + map_thing=find_empty_map_thing(); +// LogText(" map thing %d \n",map_thing); + if(!map_thing) + return(0); + add_thing_to_edit_map(x>>ELE_SHIFT,z>>ELE_SHIFT,map_thing); + p_mthing=TO_MTHING(map_thing); + p_mthing->X=x; + p_mthing->Y=y; + p_mthing->Z=z; + + p_mthing->Type=MAP_THING_TYPE_BUILDING; + p_mthing->IndexOther=prim; + p_mthing->IndexOrig=prim; +// apply_ambient_light_to_object(prim,edit_info.amb_dx,edit_info.amb_dy,edit_info.amb_dz,edit_info.amb_bright); + + return(map_thing); +} + + +void add_point(SLONG x,SLONG y,SLONG z) +{ + prim_points[next_prim_point].X=x; + prim_points[next_prim_point].Y=y; + prim_points[next_prim_point++].Z=z; +} + +SLONG build_row_wall_points_at_y(SLONG y,SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG wall) +{ + SLONG wcount,wwidth,wallwidth,dx,dz,dist; + + SLONG start_point; + + start_point=next_prim_point; + + wwidth=BLOCK_SIZE; + + dx=abs(x2-x1); + dz=abs(z2-z1); + + dist=sqrl(SDIST2(dx,dz)); + if(dist==0) + return(0); + + if(wall_list[wall].WallFlags&FLAG_WALL_AUTO_WINDOWS) + { + wcount=dist/(BLOCK_SIZE*4); + wwidth=dist/(wcount*2+1); + wall_list[wall].WindowCount=wcount; + + } + else + { + wcount=wall_list[wall].WindowCount; + wwidth=BLOCK_SIZE; + } + + dx=(x2-x1); + dz=(z2-z1); + + if(wcount<0) + return(0); + + wallwidth=(dist-(wcount*wwidth))/(wcount+1); + + dx=(dx<<10)/dist; + dz=(dz<<10)/dist; + + + add_point(x1,y,z1); + + while(wcount) + { + x1=x1+((dx*wallwidth)>>10); + z1=z1+((dz*wallwidth)>>10); + add_point(x1,y,z1); + + + x1=x1+((dx*wwidth)>>10); + z1=z1+((dz*wwidth)>>10); + add_point(x1,y,z1); + + wcount--; + + } + x1=x1+((dx*wallwidth)>>10); + z1=z1+((dz*wallwidth)>>10); + add_point(x1,y,z1); + + return(start_point); + +} + +SLONG build_row_wall_only_points_at_y(SLONG y,SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG wall) +{ + SLONG wcount,wwidth,dx,dz,dist; + + SLONG start_point; + + start_point=next_prim_point; + + dx=abs(x2-x1); + dz=abs(z2-z1); + + dist=sqrl(SDIST2(dx,dz)); + if(dist==0) + return(0); + + wcount=(dist/(BLOCK_SIZE*4)); + if(wcount==0) + wcount=1; + wwidth=dist/(wcount); + wall_list[wall].WindowCount=wcount; + + dx=(x2-x1); + dz=(z2-z1); + + + dx=(dx<<10)/dist; + dz=(dz<<10)/dist; + + add_point(x1,y,z1); + wcount--; + + while(wcount) + { + + x1=x1+((dx*wwidth)>>10); + z1=z1+((dz*wwidth)>>10); + add_point(x1,y,z1); + + wcount--; + + } + add_point(x2,y,z2); //make sure last point is spot on. + + return(start_point); + +} + +SLONG build_row_window_depth_points_at_y(SLONG y,SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG wall) +{ + + SLONG wcount,wwidth,wallwidth,dx,dz,dist; + SLONG pdx,pdz; + + SLONG start_point; + + start_point=next_prim_point; + + + + dx=abs(x2-x1); + dz=abs(z2-z1); + + dist=sqrl(SDIST2(dx,dz)); + if(dist==0) + return(0); + + if(wall_list[wall].WallFlags&FLAG_WALL_AUTO_WINDOWS) + { + wcount=dist/(BLOCK_SIZE*4); + wwidth=dist/(wcount*2+1); + wall_list[wall].WindowCount=wcount; + + } + else + { + wcount=wall_list[wall].WindowCount; + wwidth=BLOCK_SIZE; + } + + dx=(x2-x1); + dz=(z2-z1); + + if(wcount<0) + return(0); + + wallwidth=(dist-(wcount*wwidth))/(wcount+1); + + dx=(dx<<10)/dist; + dz=(dz<<10)/dist; + + pdx=-dz; + pdz=dx; + + pdx=(pdx*20)>>10; + pdz=(pdz*20)>>10; + + x1+=pdx; + z1+=pdz; + + +// add_point(x1,y,z1); + + while(wcount) + { + x1=x1+((dx*wallwidth)>>10); + z1=z1+((dz*wallwidth)>>10); + add_point(x1,y,z1); + + + x1=x1+((dx*wwidth)>>10); + z1=z1+((dz*wwidth)>>10); + add_point(x1,y,z1); + + wcount--; + + } + x1=x1+((dx*wallwidth)>>10); + z1=z1+((dz*wallwidth)>>10); +// add_point(x1,y,z1); + + return(start_point); + +} + +struct Edge +{ + SWORD X; + SWORD Type; + SWORD Next; + SWORD Prev; +}; + +struct Edge *edge_pool_ptr; +static UWORD *edge_heads_ptr; +static ULONG next_edge; +static ULONG edge_min_z; +static UWORD *flag_blocks; +static UWORD *cut_blocks; +static SLONG global_y; +#define MAX_BOUND_SIZE (200) + + +void insert_point(SLONG z,SLONG x,SWORD type) +{ + SLONG edge; + + LogText(" insert point (%x,%x) \n",x,z); + + edge_pool_ptr[next_edge].X=x; + edge_pool_ptr[next_edge].Type=type; + + edge=edge_heads_ptr[z]; + if(edge) + { + while(edge) + { + if(edge_pool_ptr[edge].X>x) + { + SLONG prev; + prev=edge_pool_ptr[edge].Prev; + + if(prev) + { + // insert between current one and previous + edge_pool_ptr[prev].Next=next_edge; + edge_pool_ptr[edge].Prev=next_edge; + edge_pool_ptr[next_edge].Next=edge; + edge_pool_ptr[next_edge].Prev=prev; + next_edge++; + } + else + { + // insert before current one and head of list + edge_heads_ptr[z]=next_edge; + edge_pool_ptr[edge].Prev=next_edge; + edge_pool_ptr[next_edge].Next=edge; + edge_pool_ptr[next_edge].Prev=0; + next_edge++; + + } + return; + } + else + if(edge_pool_ptr[edge].X==x) + { +// LogText(" allready exists cancel \n"); + return; + } + + if(edge_pool_ptr[edge].Next==0) + { + //append after current + edge_pool_ptr[edge].Next=next_edge; + edge_pool_ptr[next_edge].Next=0; + edge_pool_ptr[next_edge].Prev=edge; + next_edge++; + return; + + } + edge=edge_pool_ptr[edge].Next; + } + } + else + { + edge_heads_ptr[z]=next_edge; + edge_pool_ptr[next_edge].Prev=0; + edge_pool_ptr[next_edge].Next=0; + next_edge++; + } +} + +#define SIDEWAY_EDGE (1) +#define NORMAL_EDGE (2) + +#define CUT_BLOCK_TOP (0) +#define CUT_BLOCK_BOTTOM (1) +#define CUT_BLOCK_LEFT (2) +#define CUT_BLOCK_RIGHT (3) + +void set_cut_blocks(SLONG x,SLONG z) // x is in pixels // zis in blocks +{ + + LogText(" cut block [%d][%d] top x %d x %x\n",x>>ELE_SHIFT,z+1,x,x); + LogText(" cut block [%d][%d] bottom x %d x %x\n",x>>ELE_SHIFT,z,x,x); +// z=z-(edge_min_z>>ELE_SHIFT); + cut_blocks[(x>>ELE_SHIFT)*4+((z)*MAX_BOUND_SIZE*4+CUT_BLOCK_TOP)]=x; + cut_blocks[(x>>ELE_SHIFT)*4+((z-1)*MAX_BOUND_SIZE*4+CUT_BLOCK_BOTTOM)]=x; +} + +void set_cut_blocks_z(SLONG x,SLONG z) // x is in blocks z is in pixels +{ + + LogText(" cut block [%d][%d] left z %d z %x\n",x,z>>ELE_SHIFT,z,z); + LogText(" cut block [%d][%d] right z %d z %x\n",x-1,z>>ELE_SHIFT,z,z); + cut_blocks[(x)*4+(((z>>ELE_SHIFT)-0)*MAX_BOUND_SIZE*4+CUT_BLOCK_LEFT)]=z; + cut_blocks[(x-1)*4+(((z>>ELE_SHIFT)-0)*MAX_BOUND_SIZE*4+CUT_BLOCK_RIGHT)]=z; +} + +void scan_line_z(SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG flag) +{ + SLONG dx,dz,count; + SLONG x,z; + SWORD type; +// LogText(" scan line z x1 %d z1 %d x2 %d z2 %d \n",x1,z1,x2,z2); + LogText(" scan lineZ (%x,%x)->(%x,%x) \n",x1,(z1>>ELE_SHIFT),x2,(z2>>ELE_SHIFT)); + + + dz=z2-z1; + dx=x2-x1; +// LogText(" dx %d dz %d \n",dx,dz); + { + x1>>=ELE_SHIFT; + x2>>=ELE_SHIFT; + dx=x2-x1; + + z=z1<<16; + count=dx; +// LogText(" x1 %d x2 %d dx %d \n",x1,x2,dx); + + if(count<0) + { +// LogText(" neg count %d z1 %d z2 %d \n",count,z1,z2); + dz=-(dz<<16)/count; + x1--; + z+=dz; +// else +// count--; + +// LogText("A x1 %d x2 %d dx %d dz %x count %d\n",x1,x2,dx,dz,count); + while(count) + { + if(dz) + { +// LogText(" mid scan z %d z %x\n",(z>>16)&0xff,z); + if((z>>16)&0xff) + { + set_cut_blocks_z(x1,z>>16); + } + + } + + z+=dz; + x1--; + count++; + } + } + + if(count>0) + { + dz=(dz<<16)/count; +// if(flag) +// count++; + + //LogText("B x1 %d x2 %d dx %d count %d\n",x1,x2,dx,count); + while(count) + { + if(dz) + { + //LogText(" mid scan z %d z %x\n",(z>>16)&0xff,z); + if((z>>16)&0xff) + { + set_cut_blocks_z(x1,z>>16); + } + } + z+=dz; + x1++; + count--; + } + } + } +} + +UBYTE scan_line(SLONG x1,SLONG z1,SLONG x2,SLONG z2,SLONG flag) +{ + SLONG dx,dz,count; + SLONG x,z; + SWORD type; + LogText(" scan line (%x,%x)->(%x,%x) \n",x1,(z1>>ELE_SHIFT),x2,(z2>>ELE_SHIFT)); + + + if(z1==z2) + type=SIDEWAY_EDGE; + else + type=NORMAL_EDGE; + + dz=z2-z1; + dx=x2-x1; + //if(abs(dz)>abs(dx)) + { + //LogText(" dz longest \n"); + z1>>=ELE_SHIFT; + z2>>=ELE_SHIFT; + dz=z2-z1; + + x=x1<<16; + count=dz; + + if(count<0) + { +// LogText(" neg count %d z1 %d z2 %d \n",count,z1,z2); + dx=-(dx<<16)/count; + //z1--; + //count++; + //x+=dx; +// if(!flag) + z1--; + x+=dx; +// else +// count--; + + while(count) + { + insert_point(z1,x>>16,type); + if(dx) + { + LogText(" scan x %d \n",(x>>16)&0xff); + if((x>>16)&0xff) + { + set_cut_blocks(x>>16,z1); + } + + } + + x+=dx; + z1--; + count++; + } + } + + if(count>0) + { + dx=(dx<<16)/count; +// if(flag) +// count++; + + while(count) + { + insert_point(z1,x>>16,type); + if(dx) + { + LogText(" scan x2 %d \n",(x>>16)&0xff); + if((x>>16)&0xff) + { + set_cut_blocks(x>>16,z1); + } + } + x+=dx; + z1++; + count--; + } + } + } +/* + else + { + LogText(" dx longest \n"); + x1>>=ELE_SHIFT; + x2>>=ELE_SHIFT; + dx=x2-x1; + + z=z1<<16; + count=dx; + + if(count<0) + { + LogText(" neg count %d z1 %d z2 %d \n",count,z1,z2); + dz=-(dz<<16)/count; + while(count<0) + { + insert_point((z>>16)>>ELE_SHIFT,x1<0) + { + dz=(dz<<16)/count; + + while(count) + { + insert_point((z>>16)>>ELE_SHIFT,x1<(%x) \n",x1,(z1>>ELE_SIZE),x2); + + //LogText(" scan bottom before x %d x2 %d z %d\n",x,x2,z); + + x2=x2>>ELE_SHIFT; + x=(x>>ELE_SHIFT); + if(x>x2) + { + SLONG temp; + temp=x; + x=x2; + x2=temp; + } + //LogText(" scan bottom x %d x2 %d z %d\n",x,x2,z); + + for(;x<=x2;x++) + { + if(flag_blocks[(x)+(z>>ELE_SHIFT)*MAX_BOUND_SIZE]==0) + { + dy=edit_map[x][((z+edge_min_z)>>ELE_SHIFT)].Y<>ELE_SIZE); + flag_blocks[(x)+(z>>ELE_SHIFT)*MAX_BOUND_SIZE]=next_prim_point-1; + } + //else + //LogText(" x %d z %d contains %d \n",x,z>>ELE_SHIFT,flag_blocks[(x)+(z>>ELE_SHIFT)*MAX_BOUND_SIZE]); + } +} + + +// scan horizontal edges +void build_bottom_edge_list(SLONG storey,SLONG y) +{ + UWORD wall; + SLONG px,pz; + + px=storey_list[storey].DX; + pz=storey_list[storey].DZ-edge_min_z; + wall=storey_list[storey].WallHead; + + while(wall) + { + //add end points to the fray, incase we missed any + if(flag_blocks[(px>>ELE_SHIFT)+(pz>>ELE_SHIFT)*MAX_BOUND_SIZE]==0) + { + SLONG dy; + dy=edit_map[px>>ELE_SHIFT][((pz+edge_min_z)>>ELE_SHIFT)].Y<>ELE_SHIFT)+(pz>>ELE_SHIFT)*MAX_BOUND_SIZE]=next_prim_point-1; + } + // LogText(" find bottom edge wall %d \n",wall); + if(pz==wall_list[wall].DZ-edge_min_z) + scan_bottom_line(px,pz,wall_list[wall].DX,y); + px=wall_list[wall].DX; + pz=wall_list[wall].DZ-edge_min_z; + wall=wall_list[wall].Next; + } + +} + + +void bin_edge_list(void) +{ + MemFree((UBYTE*)edge_pool_ptr); + MemFree((UBYTE*)edge_heads_ptr); + MemFree((UBYTE*)flag_blocks); + MemFree((UBYTE*)cut_blocks); +} + + + +#define BOUNDS(x,z) if(xmax_x) max_x=x; if(zmax_z) max_z=z; + +#define INSIDE (0) +#define ON_EDGE (1) +#define OUTSIDE (2) + + +void dump_edge_list(UWORD size) +{ + SLONG c0; + SLONG edge; + + for(c0=0;c0>3))>>(ELE_SHIFT-3))+10 ) +#define MYFY(x) ( (((x)*(box_depth>>3))>>(ELE_SHIFT-3))+10) + +void show_grid(SLONG width,SLONG depth,SLONG min_x) +{ + SLONG xt,xb,zl,zr; + SLONG x,z; + SLONG box_width,box_depth; + SetWorkWindowBounds(0,0,800,600); + DrawBox(0,0,800,600,0xfff); + + box_depth=(580/depth); + box_width=(780/width); + + + LogText(" show grid width %d depth %d min_x %d \n",width,depth,min_x); + + + + for(z=0;z>1)-7,z1+2,xt_s,0); + QuickTextC(x1+((box_width)>>1)-7,z1+box_depth-12,xb_s,0); + QuickTextC(x1+2,z1+(box_depth>>1)-6,zl_s,0); + QuickTextC(x1+box_width-30,z1+(box_depth>>1)-6,zr_s,0); +#ifdef POO + + if(xt) + DrawLineC(x1+(box_width>>1),z1+(box_depth>>1),MYFX(xt),z1,0x1f); + + //DrawLineC(x1+(box_width>>1),z1+(box_depth>>1),MYFX(xt),z1,0x1f); + if(xb) + DrawLineC(x1+(box_width>>1),z1+(box_depth>>1),MYFX(xb),z1+box_depth,0x1f0); + + if(zl) + DrawLineC(x1+(box_width>>1),z1+(box_depth>>1),x1,MYFY(zl),0x1f); + + if(zr) + DrawLineC(x1+(box_width>>1),z1+(box_depth>>1),x1+box_width,MYFY(zr),0x1f0); +#endif + + } + } + ShowWorkScreen(0); + while(!RightButton) + { + } + while(RightButton); +} + + + +#define set_UV4(x0,y0,x1,y1,x2,y2,x3,y3) UV[0][0]=(x0);UV[0][1]=(y0);UV[1][0]=(x1);UV[1][1]=(y1);UV[2][0]=(x3);UV[2][1]=(y3);UV[3][0]=(x2);UV[3][1]=(y2); + +// mx,mz are map co_ords 0..MAP_WIDTH +void build_free_tri_texture_info(struct PrimFace3 *p_f3,SLONG mx,SLONG mz) +{ + UBYTE tx,ty,page; + SLONG tsize; + SLONG rot; + UBYTE UV[4][2]; + UWORD texture,p; + + SLONG dtx_down,dty_down; + SLONG dtx_down_r,dty_down_r; + //SLONG dtx_across,dty_across; + + texture=edit_map[mx][mz].Texture; + + tx=((struct MiniTextureBits*)(&texture))->X<<5; + ty=((struct MiniTextureBits*)(&texture))->Y<<5; + page=(UBYTE)(((struct MiniTextureBits*)(&texture))->Page); + tsize=floor_texture_sizes[((struct MiniTextureBits*)(&texture))->Size]-1; + rot=((struct MiniTextureBits*)(&texture))->Rot; +// rot=(rot3)&3; + switch(rot) + { + case 0: + set_UV4( tx,ty,tx+tsize,ty,tx,ty+tsize,tx+tsize,ty+tsize); + break; + case 1: + set_UV4( tx+tsize,ty,tx+tsize,ty+tsize,tx,ty,tx,ty+tsize); + break; + case 2: + set_UV4( tx+tsize,ty+tsize,tx,ty+tsize,tx+tsize,ty,tx,ty); + break; + case 3: + set_UV4( tx,ty+tsize,tx,ty,tx+tsize,ty+tsize,tx+tsize,ty); + break; + } + + dtx_down=UV[3][0]-UV[0][0]; + dty_down=UV[3][1]-UV[0][1]; + + dtx_down_r=UV[2][0]-UV[1][0]; + dty_down_r=UV[2][1]-UV[1][1]; + + p_f3->TexturePage=page; + + LogText(" U[0].X %d U[0].Y %d\n",UV[0][0],UV[0][1]); + LogText(" U[1].X %d U[1].Y %d\n",UV[1][0],UV[1][1]); + LogText(" U[2].X %d U[2].Y %d\n",UV[2][0],UV[2][1]); + LogText(" U[3].X %d U[3].Y %d\n",UV[3][0],UV[3][1]); + + for(p=0;p<3;p++) + { + SLONG x1,z1; + SLONG lx,ly; + SLONG rx,ry; + + + x1=prim_points[p_f3->Points[p]].X-(mx<Points[p]].Z-(mz<>8; + ly=(z1*dty_down)>>8; + lx+=UV[0][0]; + ly+=UV[0][1]; + + rx=(z1*dtx_down_r)>>8; + ry=(z1*dty_down_r)>>8; + + rx+=UV[1][0]; + ry+=UV[1][1]; + + LogText("left (%d,%d) right (%d,%d)\n",lx,ly,rx,ry); + + p_f3->UV[p][0]=lx+(((rx-lx)*x1)>>8); + p_f3->UV[p][1]=ly+(((ry-ly)*x1)>>8); + + LogText("result (%d,%d) \n",lx+(((rx-lx)*x1)>>8),ly+(((ry-ly)*x1)>>8)); + } +} + +void build_free_quad_texture_info(struct PrimFace4 *p_f4,SLONG mx,SLONG mz) +{ + UBYTE tx,ty,page; + SLONG tsize; + SLONG rot; + UBYTE UV[4][2]; + UWORD texture,p; + + SLONG dtx_down,dty_down; + SLONG dtx_down_r,dty_down_r; + SLONG dtx_across,dty_across; + + texture=edit_map[mx][mz].Texture; + + tx=((struct MiniTextureBits*)(&texture))->X<<5; + ty=((struct MiniTextureBits*)(&texture))->Y<<5; + page=(UBYTE)(((struct MiniTextureBits*)(&texture))->Page); + tsize=floor_texture_sizes[((struct MiniTextureBits*)(&texture))->Size]-1; + rot=((struct MiniTextureBits*)(&texture))->Rot; +// rot=(rot3)&3; + switch(rot) + { + case 0: + set_UV4( tx,ty,tx+tsize,ty,tx,ty+tsize,tx+tsize,ty+tsize); + break; + case 1: + set_UV4( tx+tsize,ty,tx+tsize,ty+tsize,tx,ty,tx,ty+tsize); + break; + case 2: + set_UV4( tx+tsize,ty+tsize,tx,ty+tsize,tx+tsize,ty,tx,ty); + break; + case 3: + set_UV4( tx,ty+tsize,tx,ty,tx+tsize,ty+tsize,tx+tsize,ty); + break; + } + + dtx_down=UV[3][0]-UV[0][0]; + dty_down=UV[3][1]-UV[0][1]; + + dtx_down_r=UV[2][0]-UV[1][0]; + dty_down_r=UV[2][1]-UV[1][1]; + + p_f4->TexturePage=page; + + LogText(" U[0].X %d U[0].Y %d\n",UV[0][0],UV[0][1]); + LogText(" U[1].X %d U[1].Y %d\n",UV[1][0],UV[1][1]); + LogText(" U[2].X %d U[2].Y %d\n",UV[2][0],UV[2][1]); + LogText(" U[3].X %d U[3].Y %d\n",UV[3][0],UV[3][1]); + + for(p=0;p<4;p++) + { + SLONG x1,z1; + SLONG lx,ly; + SLONG rx,ry; + + + x1=prim_points[p_f4->Points[p]].X-(mx<Points[p]].Z-(mz<>8; + ly=(z1*dty_down)>>8; + lx+=UV[0][0]; + ly+=UV[0][1]; + + rx=(z1*dtx_down_r)>>8; + ry=(z1*dty_down_r)>>8; + + rx+=UV[1][0]; + ry+=UV[1][1]; + + LogText(" left (%d,%d) right (%d,%d)\n",lx,ly,rx,ry); + + p_f4->UV[p][0]=lx+(((rx-lx)*x1)>>8); + p_f4->UV[p][1]=ly+(((ry-ly)*x1)>>8); + + LogText(" result (%d,%d) \n",lx+(((rx-lx)*x1)>>8),ly+(((ry-ly)*x1)>>8)); + } +} + +//edge_min_z subtracted from z's +//x's are in world co-ords + + +void scan_45(SLONG x1,SLONG z1,SLONG dx,SLONG dz) +{ + UBYTE type=0; + SLONG count; + SLONG pp,p0,p1,p2,p3; + struct PrimFace3 *p_f3; + + count=abs(dx)>>ELE_SHIFT; + x1=x1>>ELE_SHIFT; + z1=z1>>ELE_SHIFT; + + if(dx<0) + { + dx=-1; + type|=1; + } + else + { + dx=1; + } + + if(dz<0) + { + type|=2; + dz=-1; + } + else + { + dz=1; + } + + pp=flag_blocks[(x1)+z1*MAX_BOUND_SIZE]; + while(count) + { + x1+=dx; + z1+=dz; + + p1=flag_blocks[(x1)+z1*MAX_BOUND_SIZE]; + p2=flag_blocks[(x1-dx)+z1*MAX_BOUND_SIZE]; + p3=flag_blocks[(x1)+(z1-dz)*MAX_BOUND_SIZE]; + switch(type) + { //(vector goes from pp to p1) + case 0: //SE + // pp p3 + // + // p2 p1 + p_f3=create_a_tri(p2,p1,pp,0,0); + build_free_tri_texture_info(p_f3,x1-dx,z1-dz+(edge_min_z>>ELE_SHIFT)); + break; + case 1: //SW + // p3 pp + // + // p1 p2 + p_f3=create_a_tri(p1,pp,p3,0,0); + build_free_tri_texture_info(p_f3,x1,z1-dz+(edge_min_z>>ELE_SHIFT)); + break; + case 2: //NE + // p2 p1 + // + // pp p3 + p_f3=create_a_tri(pp,p3,p1,0,0); + build_free_tri_texture_info(p_f3,x1-dx,z1+(edge_min_z>>ELE_SHIFT)); + break; + case 3: //NW + // p1 p2 + // + // p3 pp + p_f3=create_a_tri(p1,pp,p2,0,0); + build_free_tri_texture_info(p_f3,x1,z1+(edge_min_z>>ELE_SHIFT)); + break; + } + + pp=p1; + count--; + } +} + +void build_roof_grid(SLONG storey,SLONG y) +{ + SLONG min_x=9999999,max_x=0,min_z=9999999,max_z=0; + SLONG width,depth; + SLONG x,z; + + SLONG wall; + struct PrimFace4 *p_f4; + struct PrimFace3 *p_f3; + SLONG face_wall; + //return; + face_wall=-storey_list[storey].WallHead; + +// LogText(" build roof grid for storey %d at y %d \n",storey,y); + + global_y=edit_map[(storey_list[storey].DX>>ELE_SHIFT)][storey_list[storey].DZ>>ELE_SHIFT].Y<>ELE_SHIFT; + depth=(max_z-min_z)>>ELE_SHIFT; + + edge_min_z=min_z; + +//now step over whole rect, flagging poins as either inside or outside or on the edge of the building + build_edge_list(storey,0); + dump_edge_list(depth); + + for(z=0;z>ELE_SHIFT)][(z+(edge_min_z>>ELE_SHIFT))]; + //me->Flags|=FLOOR_HIDDEN; + dy=edit_map[(x>>ELE_SHIFT)][z+(edge_min_z>>ELE_SHIFT)].Y<