82 Commits

Author SHA1 Message Date
Muzychenko Andrey
16b527e3cf Added AddressSanitizer to Windows build config, disabled by default.
VS older that 2019 do not support it.
Game passes ASan checks at the moment of writing.
2021-11-09 16:50:09 +03:00
Muzychenko Andrey
683204519c Added UTF-8 path support on Windows.
Ref issue #82.
2021-11-06 19:22:56 +03:00
Muzychenko Andrey
ecdf802d68 Added game data loading from user folder (SDL_GetPrefPath).
Ref issue #80.
2021-11-05 10:16:27 +03:00
Muzychenko Andrey
dc00dbde0d Fixed bug with mission accept scores.
Ref issue #81.
2021-11-04 18:46:04 +03:00
Muzychenko Andrey
862fe13dcd Added game controller exit shortcut: back/select when paused.
Ref issue #79.
2021-11-01 09:09:19 +03:00
Muzychenko Andrey
6c299ed103 Updated plans in readme 2021-10-30 12:51:24 +03:00
Muzychenko Andrey
fc1975a607 Fixed bug: dialogs not shown when main menu is hidden.
Ref issue #76.
2021-10-30 12:34:17 +03:00
Muzychenko Andrey
e61bbd634c Added fallback to SW SDL renderer. 2021-10-30 10:12:30 +03:00
Muzychenko Andrey
917b68d630 Added NN scaling for PINBALL2.MID.
It does not scale well.
Wii port should rather use non-compressed PB_MSGFT_bin.
2021-10-28 13:03:05 +03:00
MaikelChan
46d3ae324c Added 3DS port to README. (#74) 2021-10-28 07:53:57 +03:00
Iscle
d27740bd38 Fix compiler warnings (#73) 2021-10-26 17:15:45 +03:00
Muzychenko Andrey
cfd30419c2 Added Windows XP build configuration.
Removed unused SDL inits.
2021-10-26 17:11:53 +03:00
Muzychenko Andrey
3ec96b84ad PresentVScreen: fixed sub pixel offset.
SDL<2.0.10 uses crude approximation.
2021-10-25 08:03:30 +03:00
MaikelChan
34cb964ea5 Change texture filtering without restarting. (#67) 2021-10-25 06:42:36 +03:00
MaikelChan
5789492021 Adjusted screen coordinates so menu doesn't overlap (#66)
* Optimized final blit to the screen render target.

When bumping the table, instead of offseting the table pixels by CPU, just memcpy all the pixels to vScreenTex once, and then render two separate quads from that texture: one for the board and the other for the sidebar. Then change the coordinates of the board quad when bumping.

* Main menu bar doesn't cover game area

* Forgot to also take into account changing UI scale.
2021-10-24 18:38:23 +03:00
MaikelChan
38cf08e298 Optimized final blit to the screen render target. (#65)
When bumping the table, instead of offseting the table pixels by CPU, just memcpy all the pixels to vScreenTex once, and then render two separate quads from that texture: one for the board and the other for the sidebar. Then change the coordinates of the board quad when bumping.
2021-10-24 07:13:51 +03:00
Muzychenko Andrey
5cd01807b2 winmain: converted int to bool.
Cleaned up some of the PR changes.
2021-10-23 09:02:51 +03:00
toxie
57af3af800 Increase precision of mode_countdown_ handling (#52)
* fix harmless warnings and properly try/catch allocations via new

otherwise the error handling will never be triggered

* increase precision of mode_countdown_ handling

potentially there could be modes running a bit too long, depending on passed in ms (which were implicitly truncated before when passing in)

also fix some harmless warnings

* document warnings that i cannot handle on my own

* revert changes to have a new cleaner PR after review/cherry picks

* increase precision of mode_countdown_ handling

potentially there could be modes running a bit too long, depending on passed in ms (which were implicitly truncated before when passing in)

also fix some harmless warnings and add comments where original code is 'correct' but weird
2021-10-23 07:33:04 +03:00
Desgging
8e07b7fc3f Full Tilt hack - ball doesn't delay at ramp hole (#63) 2021-10-23 07:31:25 +03:00
IntriguingTiles
0076f8947c Add Wii U port to readme (#60) 2021-10-22 12:34:25 +03:00
Muzychenko Andrey
43ce86571c MinGW: added rc compiler to toolchain.
Ref issue #54.
2021-10-19 08:13:21 +03:00
extrowerk
4188cd3455 Update FindSDL2.cmake (#53)
Fix for Haiku, because nobody can write a cross-platform build tool.
2021-10-19 08:06:37 +03:00
Muzychenko Andrey
685dfe78c2 TPlunger: removed duplicated code.
Ref PR#52.
2021-10-18 10:52:13 +03:00
Muzychenko Andrey
348d79ef38 Bugs and suggestions from PR# 48. 2021-10-18 09:31:47 +03:00
MaikelChan
9088c44b3e Add Wii port to the README (#51) 2021-10-18 08:17:07 +03:00
Muzychenko Andrey
06b760e8dd Player controls: added mouse and game controller remapping.
Fixed duplicate button id.
2021-10-17 18:18:29 +03:00
Muzychenko Andrey
d06aa1c736 Changed SDL_mixer version guard.
SDL_MIXER_COMPILEDVERSION is not in Windows release of mixer v2.0.1, so it is back to basics with SDL_MIXER_PATCHLEVEL.
MIX_INIT_FLUIDSYNTH was renamed in 2.0.2, according to headers from Windows releases.
Ref PR #42, #46
2021-10-17 12:00:30 +03:00
Mariotaku
787c623cfe Backward compatibility for mixer version check (#46)
SDL_MIXER_VERSION_ATLEAST isn't available in SDL Mixer 2.0.1, which will cause build errors.
2021-10-17 09:00:49 +03:00
Iscle
b7bf1563e5 Update README.md (#45)
Co-authored-by: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com>
2021-10-17 07:58:00 +03:00
Mariotaku
f56abf0596 Compatibility and game controller patches (#42)
* Compatibility for old CMake versions (3.0)
Compatibility for SDL Mixer 2.0.1
Basic controller support: LB, RB for flippers, A for plunger, DPAD for table bump

* Update SpaceCadetPinball/Sound.cpp

Co-authored-by: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com>
2021-10-17 07:52:05 +03:00
haruna
a7e3503e2c fix: lint README to make more linkable (#40)
* fix: lint README to make more linkable

* restore blank lines between `Known source ports` and `Source`
2021-10-17 07:49:17 +03:00
Muzychenko Andrey
2ee40560ee Update CONTRIBUTING.md
Added issue part.
2021-10-16 15:06:44 +03:00
Muzychenko Andrey
5682640e36 Create CONTRIBUTING.md 2021-10-16 14:51:44 +03:00
Mariotaku
7ec2ab9a76 Added webOS source port entry (#43) 2021-10-16 14:26:15 +03:00
Muzychenko Andrey
82d4d8719f Added link to Switch source port.
Mentioned macOS as supported.
2021-10-15 14:07:25 +03:00
Muzychenko Andrey
f302687c7f high_score: fixed new score not shifting older scores.
Issue #33.
2021-10-15 13:30:55 +03:00
Tomáš Hübelbauer
fd973f049c Fix a typo (#32) 2021-10-15 07:26:16 +03:00
Muzychenko Andrey
5947727f80 Tweaked ball mouse control cheat. 2021-10-10 17:13:43 +03:00
Muzychenko Andrey
69ecce88df Score: inject 3DPB msg font into dat struct.
Fixed double free in sound.
2021-10-10 12:22:21 +03:00
Muzychenko Andrey
43593b168d Sound: added channel recycling.
Added sound channel count (aka voices) user option.
Added 3DPB font to sprite viewer.
Added version number to about dialog.
2021-10-09 17:28:30 +03:00
Muzychenko Andrey
d80074b9b6 Added Windows subsystem entry point for release builds. 2021-10-09 12:33:33 +03:00
Muzychenko Andrey
69027eca53 Mingw build: static link, posix g++, SDL2 list order. 2021-10-07 16:47:07 +03:00
Muzychenko Andrey
ac289c7f48 Fixed TLightGroup message 45 and 46, used by TLightBargraph.
Issue #25.
2021-10-07 14:17:43 +03:00
Nixola
87e44b700b Mingw cross compilation (#24)
* Fixed icon filename capitalization

* Created mingw cmake toolchain

* Adjusted CMakeLists.txt for compatibility

* Small mingwcc.cmake cleanup

* Added cross-compilation instructions to readme

* Update README.md

Fixed typo

Co-authored-by: Nicola Orlando <nicolaorlando24@gmail.com>
Co-authored-by: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com>
2021-10-07 12:53:56 +03:00
Muzychenko Andrey
48721e5811 Fixed flipper animation frame skip bug.
It is from original 3DPB, not present in FT.
2021-10-07 08:01:34 +03:00
Muzychenko Andrey
7ee508118c Fixed TKickout temporary Z in FT mode. 2021-10-06 12:42:22 +03:00
Muzychenko Andrey
8c4f38c0af Cheats: flipped literals, made some toggle, added GUI. 2021-10-05 16:48:13 +03:00
Muzychenko Andrey
167a2c2bd1 Demangled and simplified pbctrl_bdoor_controller. 2021-10-04 17:04:09 +03:00
Muzychenko Andrey
f1c6c48b36 Enabled icon in Windows build. 2021-10-03 18:57:19 +03:00
Muzychenko Andrey
8d2745fc33 Added support for sub-millisecond frame times. 2021-10-03 18:06:19 +03:00
Muzychenko Andrey
5e03978cd7 cmake: disabled link to SDL2main.
Ref #19.
2021-10-03 15:41:57 +03:00
Muzychenko Andrey
261457a959 TPinballComponent: replaced calloc operator new with member initialization. 2021-10-02 18:58:54 +03:00
oz
93de90b680 Replaced memory with new.
Cleaned up gdrv, zdrv, render.
2021-10-02 17:45:31 +03:00
Muzychenko Andrey
dc5915b4f8 Added links to Emscripten source port.
Ref #12
2021-10-02 08:04:54 +03:00
Muzychenko Andrey
c3b6daefc9 Added uncapped UPS option.
Issue #18.
2021-10-02 07:42:08 +03:00
Muzychenko Andrey
81c2034a16 Replaced objlist_class with std::vector.
Fixed minor bug in TLightGroup.
Cleaned up some warnings.
2021-10-01 18:55:44 +03:00
Muzychenko Andrey
8a421a2623 Implemented player controls dialog.
This last missing major feature brings v2 into feature parity with the original and closer to release.
Ref issues #16, #17.
2021-10-01 09:05:38 +03:00
Muzychenko Andrey
a281000308 midi: added support for FULLTILT16 music. 2021-09-30 08:51:48 +03:00
Muzychenko Andrey
03deda2f9d Added event wait timeout when idle.
Added show menu button to prevent lockout; this somewhat ruins no menu aesthetic.
Cleaned up 3DPB vs. FT methods in midi.
2021-09-29 17:53:49 +03:00
Muzychenko Andrey
ba5a0f3044 Compressed and encoded embedded 3DPB font.
Exposed ImGui function for decompressing embedded data.
2021-09-29 10:08:45 +03:00
Muzychenko Andrey
b37f5d6d76 Fixed ShowMenu option interrupting ImGui::NewFrame. 2021-09-29 07:46:13 +03:00
Muzychenko Andrey
593b4d161c Merge pull request #14 from prototux/option_nogui
Add an option to show or hide the menu
2021-09-29 07:32:01 +03:00
prototux
7c29c05d64 Fixed the keyboard shortcut for show menu 2021-09-29 06:09:24 +02:00
prototux
89f4b6d535 Fixed the keyboard shortcut for show menu 2021-09-29 06:06:08 +02:00
Muzychenko Andrey
373351c2ba Merge pull request #15 from ajhs-io/updatereadme
Update README.md to include macOS build instructions
2021-09-29 06:11:21 +03:00
Muzychenko Andrey
65037e0e69 Bug-fix: storage for non-inline static constexpr.
Somehow none of the compilers I test with cought this.
2021-09-29 06:07:00 +03:00
Alexander Steffen
e2a2037a99 Update README.md to include macOS build instructions
Include instructions for successful build of Space Cadet Pinball on both Intel macOS and Apple Silicon macOS. Small formatting fix.
2021-09-28 21:42:22 -04:00
prototux
b843e9a6cb Added an option to show or hide the menu. 2021-09-29 02:21:21 +02:00
Muzychenko Andrey
b4cb827d73 winmain: reworked main loop for smoother frame times.
imgui_sdl: added handling for device lost.
midi: load PINBALL.MID in uppercase and using absolute path.
Added UPS/FPS options, by default 120/60.
2021-09-28 08:14:18 +03:00
Muzychenko Andrey
22ce8ac538 gdrv: blit no more, present render:vScreen directly.
Improved split bitmap handling.
2021-09-25 16:52:19 +03:00
Muzychenko Andrey
625a6e7498 Fixed md error in readme.
What is GFM? We just don't know.
2021-09-23 12:21:18 +03:00
Muzychenko Andrey
fd9de493e6 Added linear filter option for vScreen texture.
Rollback blit to backing storage – its persistence is not guaranteed.
Added project URL to About dialog.
Added source ports table to readme.
2021-09-23 12:16:58 +03:00
Muzychenko Andrey
4c196a9290 Added table resolution and UI scale options.
gdrv: blit directly to backing store of vScreen texture.
Added missing cheat_bump_rank sub, oops.
Fixed some warnings.
2021-09-22 15:50:07 +03:00
Muzychenko Andrey
c63c6701ac gdrv: RGBA buffers, pre-applied palettes, SDL bitmap origin.
Refactored partman.
Added sprite viewer.
2021-09-21 13:14:39 +03:00
Muzychenko Andrey
8bae7a5b05 Added user settings persistence.
Using ImGui .ini writer.
2021-09-16 10:57:46 +03:00
Muzychenko Andrey
af5a70785e Enabled pch in CMake.
No need to remove old pch includes.
2021-09-15 12:20:57 +03:00
Muzychenko Andrey
c5b7c0ad16 Fixed some of the memory leaks and Clang warnings.
DrMemory and Valgrind work with regular debug builds.
2021-09-14 15:33:18 +03:00
Muzychenko Andrey
28e2417ef9 Made it compile with GCC on Linux.
Fixed GCC warnings and Windows specifics.
Restored C++11, switch to 14 was not supposed to happen.
Not 100% sure about my Find* module section.
2021-09-09 11:40:54 +03:00
Muzychenko Andrey
2fe6d6d33a Removed windows.h dependency.
Added support for music in MDS format.
2021-09-06 16:27:58 +03:00
Muzychenko Andrey
e0638c598d Added GUI, some menus dont work yet.
Fixed uniform scaling.
Removed splash screen.
2021-09-05 10:47:05 +03:00
Muzychenko Andrey
9a10d72e1f gdrv: simplified bitmap, fixed blit, improved SDL present.
Removed some Windows dependencies.
2021-09-01 11:02:57 +03:00
Muzychenko Andrey
a09ea75d80 SDL port v1, Windows only for now.
Working: graphics, sound, music (3dpb only).
Not working: GUI, user settings.
2021-08-27 13:29:41 +03:00
141 changed files with 54964 additions and 10171 deletions

10
.gitignore vendored
View File

@@ -266,11 +266,13 @@ __pycache__/
/Export
/DrMem
/Doc private
# Cmake stuff
# Windows local libraries
/Libs
/out
# WinXp stuff
#CMake generated
out/
/cmake-build-debug
# Windows XP stuff
DebugWinXp/
ReleaseWinXp/

219
CMakeLists.txt Normal file
View File

@@ -0,0 +1,219 @@
cmake_minimum_required(VERSION 3.0)
project(SpaceCadetPinball)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/bin)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMakeModules")
# On Windows, set paths to SDL-devel packages here
if(WIN32)
list(APPEND SDL2_PATH "${CMAKE_CURRENT_LIST_DIR}/Libs/SDL2")
list(APPEND SDL2_MIXER_PATH "${CMAKE_CURRENT_LIST_DIR}/Libs/SDL2_mixer")
endif()
# Link mingw libs static
if(MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
endif()
# SDL2main is not needed
set(SDL2_BUILDING_LIBRARY ON)
find_package(SDL2 REQUIRED)
FIND_PACKAGE(SDL2_mixer REQUIRED)
include_directories(${SDL2_INCLUDE_DIR} ${SDL2_MIXER_INCLUDE_DIR})
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
message(STATUS "Include dir='${dir}'")
endforeach()
set(SOURCE_FILES
SpaceCadetPinball/control.cpp
SpaceCadetPinball/control.h
SpaceCadetPinball/EmbeddedData.cpp
SpaceCadetPinball/EmbeddedData.h
SpaceCadetPinball/fullscrn.cpp
SpaceCadetPinball/fullscrn.h
SpaceCadetPinball/gdrv.cpp
SpaceCadetPinball/gdrv.h
SpaceCadetPinball/GroupData.cpp
SpaceCadetPinball/GroupData.h
SpaceCadetPinball/high_score.cpp
SpaceCadetPinball/high_score.h
SpaceCadetPinball/loader.cpp
SpaceCadetPinball/loader.h
SpaceCadetPinball/maths.cpp
SpaceCadetPinball/maths.h
SpaceCadetPinball/midi.cpp
SpaceCadetPinball/midi.h
SpaceCadetPinball/nudge.cpp
SpaceCadetPinball/nudge.h
SpaceCadetPinball/options.cpp
SpaceCadetPinball/options.h
SpaceCadetPinball/partman.cpp
SpaceCadetPinball/partman.h
SpaceCadetPinball/pb.cpp
SpaceCadetPinball/pb.h
SpaceCadetPinball/pch.h
SpaceCadetPinball/pinball.cpp
SpaceCadetPinball/pinball.h
SpaceCadetPinball/proj.cpp
SpaceCadetPinball/proj.h
SpaceCadetPinball/render.cpp
SpaceCadetPinball/render.h
SpaceCadetPinball/score.cpp
SpaceCadetPinball/score.h
SpaceCadetPinball/Sound.cpp
SpaceCadetPinball/Sound.h
SpaceCadetPinball/SpaceCadetPinball.cpp
SpaceCadetPinball/TBall.cpp
SpaceCadetPinball/TBall.h
SpaceCadetPinball/TBlocker.cpp
SpaceCadetPinball/TBlocker.h
SpaceCadetPinball/TBumper.cpp
SpaceCadetPinball/TBumper.h
SpaceCadetPinball/TCircle.cpp
SpaceCadetPinball/TCircle.h
SpaceCadetPinball/TCollisionComponent.cpp
SpaceCadetPinball/TCollisionComponent.h
SpaceCadetPinball/TComponentGroup.cpp
SpaceCadetPinball/TComponentGroup.h
SpaceCadetPinball/TDemo.cpp
SpaceCadetPinball/TDemo.h
SpaceCadetPinball/TDrain.cpp
SpaceCadetPinball/TDrain.h
SpaceCadetPinball/TEdgeBox.h
SpaceCadetPinball/TEdgeManager.cpp
SpaceCadetPinball/TEdgeManager.h
SpaceCadetPinball/TEdgeSegment.cpp
SpaceCadetPinball/TEdgeSegment.h
SpaceCadetPinball/TFlagSpinner.cpp
SpaceCadetPinball/TFlagSpinner.h
SpaceCadetPinball/TFlipper.cpp
SpaceCadetPinball/TFlipper.h
SpaceCadetPinball/TFlipperEdge.cpp
SpaceCadetPinball/TFlipperEdge.h
SpaceCadetPinball/TGate.cpp
SpaceCadetPinball/TGate.h
SpaceCadetPinball/THole.cpp
SpaceCadetPinball/THole.h
SpaceCadetPinball/timer.cpp
SpaceCadetPinball/timer.h
SpaceCadetPinball/TKickback.cpp
SpaceCadetPinball/TKickback.h
SpaceCadetPinball/TKickout.cpp
SpaceCadetPinball/TKickout.h
SpaceCadetPinball/TLight.cpp
SpaceCadetPinball/TLight.h
SpaceCadetPinball/TLightBargraph.cpp
SpaceCadetPinball/TLightBargraph.h
SpaceCadetPinball/TLightGroup.cpp
SpaceCadetPinball/TLightGroup.h
SpaceCadetPinball/TLightRollover.cpp
SpaceCadetPinball/TLightRollover.h
SpaceCadetPinball/TLine.cpp
SpaceCadetPinball/TLine.h
SpaceCadetPinball/TOneway.cpp
SpaceCadetPinball/TOneway.h
SpaceCadetPinball/TPinballComponent.cpp
SpaceCadetPinball/TPinballComponent.h
SpaceCadetPinball/TPinballTable.cpp
SpaceCadetPinball/TPinballTable.h
SpaceCadetPinball/TPlunger.cpp
SpaceCadetPinball/TPlunger.h
SpaceCadetPinball/TPopupTarget.cpp
SpaceCadetPinball/TPopupTarget.h
SpaceCadetPinball/TRamp.cpp
SpaceCadetPinball/TRamp.h
SpaceCadetPinball/TRollover.cpp
SpaceCadetPinball/TRollover.h
SpaceCadetPinball/TSink.cpp
SpaceCadetPinball/TSink.h
SpaceCadetPinball/TSoloTarget.cpp
SpaceCadetPinball/TSoloTarget.h
SpaceCadetPinball/TSound.cpp
SpaceCadetPinball/TSound.h
SpaceCadetPinball/TTableLayer.cpp
SpaceCadetPinball/TTableLayer.h
SpaceCadetPinball/TTextBox.cpp
SpaceCadetPinball/TTextBox.h
SpaceCadetPinball/TTextBoxMessage.cpp
SpaceCadetPinball/TTextBoxMessage.h
SpaceCadetPinball/TTimer.cpp
SpaceCadetPinball/TTimer.h
SpaceCadetPinball/TTripwire.cpp
SpaceCadetPinball/TTripwire.h
SpaceCadetPinball/TWall.cpp
SpaceCadetPinball/TWall.h
SpaceCadetPinball/winmain.cpp
SpaceCadetPinball/winmain.h
SpaceCadetPinball/zdrv.cpp
SpaceCadetPinball/zdrv.h
SpaceCadetPinball/imconfig.h
SpaceCadetPinball/imgui_internal.h
SpaceCadetPinball/imgui.cpp
SpaceCadetPinball/imgui.h
SpaceCadetPinball/imgui_sdl.cpp
SpaceCadetPinball/imgui_sdl.h
SpaceCadetPinball/imgui_draw.cpp
SpaceCadetPinball/imgui_widgets.cpp
SpaceCadetPinball/imgui_tables.cpp
SpaceCadetPinball/imgui_demo.cpp
SpaceCadetPinball/imgui_impl_sdl.cpp
SpaceCadetPinball/imgui_impl_sdl.h
SpaceCadetPinball/imstb_textedit.h
SpaceCadetPinball/imstb_rectpack.h
SpaceCadetPinball/imstb_truetype.h
)
# On Windows, include resource file with the icon
if(WIN32)
set_source_files_properties(SpaceCadetPinball/SpaceCadetPinball.rc LANGUAGE RC)
list(APPEND SOURCE_FILES SpaceCadetPinball/SpaceCadetPinball.rc)
endif(WIN32)
add_executable(SpaceCadetPinball ${SOURCE_FILES})
# Skip pch on foreign code
set_source_files_properties(
SpaceCadetPinball/imgui.cpp
SpaceCadetPinball/imgui_sdl.cpp
SpaceCadetPinball/imgui_draw.cpp
SpaceCadetPinball/imgui_widgets.cpp
SpaceCadetPinball/imgui_tables.cpp
SpaceCadetPinball/imgui_demo.cpp
SpaceCadetPinball/imgui_impl_sdl.cpp
PROPERTIES SKIP_PRECOMPILE_HEADERS 1
)
if(${CMAKE_VERSION} VERSION_GREATER "3.16.0" OR ${CMAKE_VERSION} VERSION_EQUAL "3.16.0")
target_precompile_headers(SpaceCadetPinball
PUBLIC
SpaceCadetPinball/pch.h
)
endif()
target_link_libraries(SpaceCadetPinball ${SDL2_LIBRARY} ${SDL2_MIXER_LIBRARY})
# On Windows, copy DLL to output
if(WIN32)
list(GET SDL2_LIBRARY -1 SDL2_DLL_PATH)
list(GET SDL2_MIXER_LIBRARY -1 SDL2_MIXER_DLL_PATH)
get_filename_component(SDL2_DLL_PATH ${SDL2_DLL_PATH} DIRECTORY)
get_filename_component(SDL2_MIXER_DLL_PATH ${SDL2_MIXER_DLL_PATH} DIRECTORY)
if(MINGW)
string(REGEX REPLACE "lib$" "bin" SDL2_DLL_PATH ${SDL2_DLL_PATH})
string(REGEX REPLACE "lib$" "bin" SDL2_MIXER_DLL_PATH ${SDL2_MIXER_DLL_PATH})
endif()
message(STATUS "copy paths='${SDL2_DLL_PATH}' '${SDL2_MIXER_DLL_PATH}'")
add_custom_command(TARGET SpaceCadetPinball POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2_DLL_PATH}/SDL2.dll" $<TARGET_FILE_DIR:SpaceCadetPinball>
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2_MIXER_DLL_PATH}/SDL2_mixer.dll" $<TARGET_FILE_DIR:SpaceCadetPinball>
)
endif()

173
CMakeModules/FindSDL2.cmake Normal file
View File

@@ -0,0 +1,173 @@
# This module defines
# SDL2_LIBRARY, the name of the library to link against
# SDL2_FOUND, if false, do not try to link to SDL2
# SDL2_INCLUDE_DIR, where to find SDL.h
#
# This module responds to the the flag:
# SDL2_BUILDING_LIBRARY
# If this is defined, then no SDL2main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the the proper link flags
# as part of the returned SDL2_LIBRARY variable.
#
# Don't forget to include SDLmain.h and SDLmain.m your project for the
# OS X framework based version. (Other versions link to -lSDL2main which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL2_LIBRARY
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
#
#
# $SDL2DIR is an environment variable that would
# correspond to the ./configure --prefix=$SDL2DIR
# used in building SDL2.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL guidelines.
# Added a search for SDL2main which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL2_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
# This needed to change because "proper" SDL convention
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL2/ (see FreeBSD).
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# message("<FindSDL2.cmake>")
SET(SDL2_SEARCH_PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
${SDL2_PATH}
)
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES include/SDL2 include SDL2
PATHS ${SDL2_SEARCH_PATHS}
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(PATH_SUFFIXES lib64 lib/x64 lib)
else()
set(PATH_SUFFIXES lib/x86 lib)
endif()
FIND_LIBRARY(SDL2_LIBRARY_TEMP
NAMES SDL2
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES ${PATH_SUFFIXES}
PATHS ${SDL2_SEARCH_PATHS}
)
IF(NOT SDL2_BUILDING_LIBRARY)
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDL2main for compatibility even though they don't
# necessarily need it.
FIND_LIBRARY(SDL2MAIN_LIBRARY
NAMES SDL2main
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES ${PATH_SUFFIXES}
PATHS ${SDL2_SEARCH_PATHS}
)
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# SDL2 may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional link flag, -mwindows
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows
IF(MINGW)
SET(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "mwindows for MinGW")
ENDIF(MINGW)
IF(SDL2_LIBRARY_TEMP)
# For SDL2main
IF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2MAIN_LIBRARY)
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(SDL2MAIN_LIBRARY)
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL2_LIBRARY_TEMP ${CMAKE_THREAD_LIBS_INIT} ${SDL2_LIBRARY_TEMP})
ENDIF(NOT APPLE)
# For MinGW library
IF(MINGW)
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(MINGW)
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
ENDIF(SDL2_LIBRARY_TEMP)
# message("</FindSDL2.cmake>")
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)

View File

@@ -0,0 +1,100 @@
# Locate SDL_MIXER library
#
# This module defines:
#
# ::
#
# SDL2_MIXER_LIBRARIES, the name of the library to link against
# SDL2_MIXER_INCLUDE_DIRS, where to find the headers
# SDL2_MIXER_FOUND, if false, do not try to link against
# SDL2_MIXER_VERSION_STRING - human-readable string containing the version of SDL_MIXER
#
#
#
# For backward compatibility the following variables are also set:
#
# ::
#
# SDLMIXER_LIBRARY (same value as SDL2_MIXER_LIBRARIES)
# SDLMIXER_INCLUDE_DIR (same value as SDL2_MIXER_INCLUDE_DIRS)
# SDLMIXER_FOUND (same value as SDL2_MIXER_FOUND)
#
#
#
# $SDLDIR is an environment variable that would correspond to the
# ./configure --prefix=$SDLDIR used in building SDL.
#
# Created by Eric Wing. This was influenced by the FindSDL.cmake
# module, but with modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
#=============================================================================
# Copyright 2005-2009 Kitware, Inc.
# Copyright 2012 Benjamin Eikel
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
find_path(SDL2_MIXER_INCLUDE_DIR SDL_mixer.h
HINTS
ENV SDL2MIXERDIR
ENV SDL2DIR
PATH_SUFFIXES SDL2
# path suffixes to search inside ENV{SDLDIR}
include/SDL2 include
PATHS ${SDL2_MIXER_PATH}
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(VC_LIB_PATH_SUFFIX lib/x64)
else()
set(VC_LIB_PATH_SUFFIX lib/x86)
endif()
find_library(SDL2_MIXER_LIBRARY
NAMES SDL2_mixer
HINTS
ENV SDL2MIXERDIR
ENV SDL2DIR
PATH_SUFFIXES lib bin ${VC_LIB_PATH_SUFFIX}
PATHS ${SDL2_MIXER_PATH}
)
if(SDL2_MIXER_INCLUDE_DIR AND EXISTS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h")
file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+[0-9]+$")
string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MAJOR "${SDL2_MIXER_VERSION_MAJOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MINOR "${SDL2_MIXER_VERSION_MINOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_PATCH "${SDL2_MIXER_VERSION_PATCH_LINE}")
set(SDL2_MIXER_VERSION_STRING ${SDL2_MIXER_VERSION_MAJOR}.${SDL2_MIXER_VERSION_MINOR}.${SDL2_MIXER_VERSION_PATCH})
unset(SDL2_MIXER_VERSION_MAJOR_LINE)
unset(SDL2_MIXER_VERSION_MINOR_LINE)
unset(SDL2_MIXER_VERSION_PATCH_LINE)
unset(SDL2_MIXER_VERSION_MAJOR)
unset(SDL2_MIXER_VERSION_MINOR)
unset(SDL2_MIXER_VERSION_PATCH)
endif()
set(SDL2_MIXER_LIBRARIES ${SDL2_MIXER_LIBRARY})
set(SDL2_MIXER_INCLUDE_DIRS ${SDL2_MIXER_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_mixer
REQUIRED_VARS SDL2_MIXER_LIBRARIES SDL2_MIXER_INCLUDE_DIRS
VERSION_VAR SDL2_MIXER_VERSION_STRING)
# for backward compatibility
set(SDLMIXER_LIBRARY ${SDL2_MIXER_LIBRARIES})
set(SDLMIXER_INCLUDE_DIR ${SDL2_MIXER_INCLUDE_DIRS})
set(SDLMIXER_FOUND ${SDL2_MIXER_FOUND})
mark_as_advanced(SDL2_MIXER_LIBRARY SDL2_MIXER_INCLUDE_DIR)

61
CMakeSettings.json Normal file
View File

@@ -0,0 +1,61 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"addressSanitizerEnabled": false
},
{
"name": "x86-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ],
"addressSanitizerEnabled": false
},
{
"name": "x86-Release",
"generator": "Ninja",
"configurationType": "Release",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DCMAKE_WIN32_EXECUTABLE:BOOL=1",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ]
},
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "Release",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DCMAKE_WIN32_EXECUTABLE:BOOL=1",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ]
},
{
"name": "x86-Release-WinXP",
"generator": "Visual Studio 16 2019",
"configurationType": "Release",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DCMAKE_WIN32_EXECUTABLE:BOOL=1 -T v141_xp",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ]
}
]
}

11
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,11 @@
# Issues
Dont forget to mention game version, which release or branch it came from.\
Source port issues are handled in their respective repositories.
# Pull request
No source ports in main repository.\
I have no way to test and maintain most of them.\
The best I can do is to add a link.
There is no guaranty that any particular PR will be accepted.\
If you are unsure, ask first, make PR second.

View File

@@ -1,3 +0,0 @@
rc /Fo.\DrMem\SpaceCadetPinball.res ".\SpaceCadetPinball\SpaceCadetPinball.rc"
cl /Zi /MT /MP /EHsc /O /Ob0 /cgthreads4 /Fo.\DrMem\ /Fe.\DrMem\myapp.exe ".\SpaceCadetPinball\*.cpp" Comctl32.lib Winmm.lib Htmlhelp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ".\DrMem\SpaceCadetPinball.res"

View File

@@ -1,39 +1,91 @@
# SpaceCadetPinball
**Summary:** Reverse engineering of `3D Pinball for Windows Space Cadet`, a game bundled with Windows.
<!-- markdownlint-disable-file MD033 -->
**How to play:** Place compiled exe into a folder containing original game resources (not included).\
# SpaceCadetPinball
## Summary
Reverse engineering of `3D Pinball for Windows Space Cadet`, a game bundled with Windows.
## How to play
Place compiled executable into a folder containing original game resources (not included).\
Supports data files from Windows and Full Tilt versions of the game.
\
\
\
\
\
\
**Source:**
## Known source ports
| Platform | Author | URL |
| ------------------ | --------------- | ---------------------------------------------------------------------------------------------------------- |
| PS Vita | Axiom | <https://github.com/suicvne/SpaceCadetPinball_Vita> |
| Emscripten | alula | <https://github.com/alula/SpaceCadetPinball> <br> Play online: <https://alula.github.io/SpaceCadetPinball> |
| Nintendo Switch | averne | <https://github.com/averne/SpaceCadetPinball-NX> |
| webOS TV | mariotaku | <https://github.com/webosbrew/SpaceCadetPinball> |
| Android (WIP) | Iscle | https://github.com/Iscle/SpaceCadetPinball |
| Nintendo Wii | MaikelChan | https://github.com/MaikelChan/SpaceCadetPinball |
| Nintendo 3DS | MaikelChan | https://github.com/MaikelChan/SpaceCadetPinball/tree/3ds |
| Nintendo Wii U | IntriguingTiles | https://github.com/IntriguingTiles/SpaceCadetPinball-WiiU |
Platforms covered by this project: desktop Windows, Linux and macOS.
<br>
<br>
<br>
<br>
<br>
<br>
## Source
* `pinball.exe` from `Windows XP` (SHA-1 `2A5B525E0F631BB6107639E2A69DF15986FB0D05`) and its public PDB
* `CADET.EXE` 32bit version from `Full Tilt! Pinball` (SHA-1 `3F7B5699074B83FD713657CD94671F2156DBEDC4`)
**Tools used:** `Ghidra`, `Ida`, `Visual Studio`
## Tools used
`Ghidra`, `Ida`, `Visual Studio`
## What was done
**What was done:**
* All structures were populated, globals and locals named.
* All subs were decompiled, C pseudo code was converted to compilable C++. Loose (namespace?) subs were assigned to classes.
**Compiling:**\
Project uses `C++11` features and depends on Windows libs.\
Compile with Visual Studio; tested with 2017 and 2019.
## Compiling
Project uses `C++11` and depends on `SDL2` libs.
### On Windows
Download and unpack devel packages for `SDL2` and `SDL2_mixer`.\
Set paths to them in `CMakeLists.txt`, see suggested placement in `/Libs`.\
Compile with Visual Studio; tested with 2019.
### On Linux
Install devel packages for `SDL2` and `SDL2_mixer`.\
Compile with CMake; tested with GCC 10, Clang 11.\
To cross-compile for Windows, install a 64-bit version of mingw and its `SDL2` and `SDL2_mixer` distributions, then use the `mingwcc.cmake` toolchain.
### On macOS
* **Homebrew**: Install the `SDL2`, `SDL2_mixer` homebrew packages.
* **MacPorts**: Install the `libSDL2`, `libSDL2_mixer` macports packages.
Compile with CMake. Ensure that `CMAKE_OSX_ARCHITECTURES` variable is set for either `x86_64` Apple Intel or `arm64` for Apple Silicon.
Tested with: macOS Big Sur (Intel) with Xcode 13 & macOS Montery Beta (Apple Silicon) with Xcode 13.
## Plans
**Plans:**
* ~~Decompile original game~~
* ~~Resizable window, scaled graphics~~
* ~~Loader for high-res sprites from CADET.DAT~~
* ~~Cross-platform port using SDL2, SDL2_mixer, ImGui~~
* Text translations
* Misc features of Full Tilt: 3 music tracks, multiball, centered textboxes, etc.
* Maybe: Text translations
* Maybe: Android port
* Maybe x2: support for other two tables
* Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched
**On 64-bit bug that killed the game:**\
## On 64-bit bug that killed the game
I did not find it, decompiled game worked in x64 mode on the first try.\
It was either lost in decompilation or introduced in x64 port/not present in x86 build.\
Based on public description of the bug (no ball collision), I guess that the bug was in `TEdgeManager::TestGridBox`

View File

@@ -1,55 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31624.102
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpaceCadetPinball", "SpaceCadetPinball\SpaceCadetPinball.vcxproj", "{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
ReleaseWinXp|ARM = ReleaseWinXp|ARM
ReleaseWinXp|ARM64 = ReleaseWinXp|ARM64
ReleaseWinXp|x64 = ReleaseWinXp|x64
ReleaseWinXp|x86 = ReleaseWinXp|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|ARM.ActiveCfg = Debug|ARM
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|ARM.Build.0 = Debug|ARM
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|ARM64.ActiveCfg = Debug|ARM64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|ARM64.Build.0 = Debug|ARM64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x64.ActiveCfg = Debug|x64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x64.Build.0 = Debug|x64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x86.ActiveCfg = Debug|Win32
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Debug|x86.Build.0 = Debug|Win32
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|ARM.ActiveCfg = Release|ARM
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|ARM.Build.0 = Release|ARM
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|ARM64.ActiveCfg = Release|ARM64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|ARM64.Build.0 = Release|ARM64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x64.ActiveCfg = Release|x64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x64.Build.0 = Release|x64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x86.ActiveCfg = Release|Win32
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.Release|x86.Build.0 = Release|Win32
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|ARM.ActiveCfg = ReleaseWinXp|ARM
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|ARM.Build.0 = ReleaseWinXp|ARM
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|ARM64.ActiveCfg = ReleaseWinXp|ARM64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|ARM64.Build.0 = ReleaseWinXp|ARM64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|x64.ActiveCfg = ReleaseWinXp|x64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|x64.Build.0 = ReleaseWinXp|x64
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|x86.ActiveCfg = ReleaseWinXp|Win32
{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}.ReleaseWinXp|x86.Build.0 = ReleaseWinXp|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4B620E0B-FD42-4AEC-BC4A-261C1669A1B5}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,46 @@
#include "EmbeddedData.h"
#if 1
// File: './PB_MSGFT.bin' (21702 bytes)
// Exported using binary_to_compressed_c.cpp
const char EmbeddedData::PB_MSGFT_bin_compressed_data_base85[5380 + 1] =
"7])#######>s+cc'/###Y[fi'.Y`+V*KI@%CtjT%QRR8%D[eW$G$^m&MQ>3'QK#n&FnJm&Vp:0(SWPN'SgYn&E09q%`sYn&V9B6&Z#dn&Hnj5&8uhV$Q?p2'L0K6&;@@<$SA`.2EIes$"
"RTp6&A.MZ#?@R8%]IN:-42$4CT5(a4`%5DN$rJfLe7^-#`cb*&]u#K262Q_/CR*a4qTjjMHug;-PgRfM-sJfL9#?9RqM>=-/WDa->?1I$[R/qLuqJfLxj/gLPCg;-r28r7H-ge$wKiWh"
"vR.(8.C@lL/<T4MnLT_-VeJe?G-Cx9BEwcMYV$2Mbo4VMm4`;-#K5p%o-L&#*rE2C]x+@'aY.FRpjot7kXjJ2'CDiL)e./M^c'hM2s@/M):*NMt3*NM[i,aOcHLaP7?K4MI1$##0ucDN"
")J7FN7^e*N4s(eMcPi+8VZKd4^dTd%_IAgWJCSrL>r&gL-0pKN?lgwL[BCTM5>UkL]`kgMw3US->aDY$,oF&#9&j-HA3nw'/%=2C:FW'8..w-$ae`n*a2Kwp:(t-$X<8w^V`w_/*TKs-"
";c>]OW>pgLSHJ_%=0[GMZMFgMmZGhN>4ZtMsg&gL%o^wL)<N;-`2<r&6lNh#2dNgL8]&,Mdj/,MmM&jL5/K;-Na+p7*O(C&4*'a4exMQ(*k2b$k9Em8W.=2C.bIgj-e$AOZ$Qt$u-d,M"
"]mC#8rKXk4^eFX(_4+X_xDe'&+rVF7o)I&#.@T(/D85gj;aIqe9[?29#RGf$ZG^;%(/lJ2A/#dM-,r]$m4qP8.biQj_A5W-m'14+m[(Rs6]f>e6#%'Qg@c(NAvYT%Lc68%WcU4+%pwTM"
"3nf8RF:g1We=0W$c%q44SR%UM(nj-$_')B6-&R]4vlm*Mw7gV-1?=$g1cap9>;)6Ms=UkL8L)^%Q`1IN,Dn]-ICHh,flTq)s?[o#Ov1b91_ZGMW($a$Xl1s)?ESw.`EqS-n5TW&goD*8"
"9[o?9r3R4$LjYI8n2?2CNT3hc)N:(&%6l'&fDxGMi1$##2j(/NMxGp79r*C9Y&o8Bdh8x0fbMmLkv^)&qwuND;t#hO?mxC%*vbJ2jlW*I2.=2C3[;dMtk?m%Z-'TR[u,JWj>Lh$'j#n8"
"`=ujDCQ@J&GeJR9Dfd--eIi,i(]^@%71pauR?VIM)NiIMa6`;-2][N'=,HXCh4`/:lwLG'7i=k#C[-L,$oi/:XaAQ(por''<3,d;kRF&#,56vPnbR'M13oj%nSZEcXG:@-/g#pL;2669"
"4WIvRsv]O&LwQHM3l_;-TD[V9R;5r)j4<?[Kc_x&7b4H;fVdX1FIuwTDTIgs<:#-M[lk0MGiF58<P(C&?/%*<[x7RNPrJ&#dOl63[bR5'U62HO&ANf%qvedMHdfZMdL?.'1>NE5:t4X8"
"^/l3+Z#_K:7,G$IR.V^)E]JF%wY'q7o&Xt&mV(J;ptLQ(v>Y1'xwvq72F?T0EdRf&=$Rd=oNOg$&;mVQjQn?Gq['dk>IY)NJ27BO`<G-&$JZQ8jbGmU#/a+&vh-'v.xJk$C7+E<^V?hG"
"dew$I?##@&3+G&#v5'q7jXF&#1uDb7t?wctq)Z&'U4ZeMT2Vb8.M>r)aF749_4Y_-11jv7U-W&H9n7mL.iL;-o_)+O08)>&=]4^Z`K[r7t9#f$^t7j91r,QqSILQ89aTx9/p/hLX%co7"
"rr;p&6*Mb%a,#?POJri%XKxI4A.Eu$ZArt8`97r72T):2X[x&=8GWX(l0^&=3SaJ2R6Q&#a;;6&*]iO9q;H*5?rMY$V)9O$<,Dh:trF_JNx&?>0dY,.h5*g$BC5v([3p6EJs#t&_DIu%"
"l5A@':GuP8BD[`&V'/W-hs+^ZrT<j&AC1O+c3Ke=)pul&a)i#>2qF&#t`V^=mb3dXkx/W&WCCgLV8UM9ew4oh;#Bgh;Kas-#`?Q8]JeKul^]m8ctB6X%1fN^#qR<^LFPa*vp(?>?Lc'&"
"?Swa<=Mc'&U2u`4w080:h%dm:draZ%U_%?P1_W3M#>w.%?Pm7$)N?@-`bPl$uQh'&]ZDA>fa(4Dq#1a)+a;i#I;[#>G27w%l0=S,=%h)&D=57*dR6@.[?kc%Ia(E<#kPFYb/3M2#D*F."
"i<,UVYB<ia.(o(#iDbJ2%+/L,+m[&#[8=L3'_aNMms7jLn'j*OHi`k=k=Uk+rJbJ2)]=Z>oe)vS2.Kg%QRJ^?UbmC?c67l)rTjj&]1lgLNih`<Rbh&?S^3k<?&2Oblx^r9TXQhM.evhL"
"rbxh<x;tB8EL]BH;':Q:h6IHF.r]K%CaKH=G8lwM&M9%%W>^q)[T%AOPFJZ$YMg58He`q2I6w:@,[F&#YJ7#:s8fdMM_%Z>]8M'S/8D_6.;jbMa.h1&`d8m8@C-tJ]6^w'6kv;]cdTD&"
"gv7*P`Bbc%9*l8KZ@,6;n<nw'QqnP']22*<q>)F7K.4e;/6F2aYML@--;ZT%Z-DIm`KJ<-?22$Xp&Z7@AK@kX;-FQ85ohKaa.k<9wi4ed]XJQ(d@sv7f3i/<]gMeMk+V'F>]ZYo)kMB%"
"P^mkie1Fp=Q]2U2i$a#P;.r.*QD>Q8?Wi[(fp.M$s$&(SdVJT@bq):i/2u-MQ;6L-TV,<-9K$n:glR0<,k<nL4%3JNRXr2%K25O4Vs]E-27Dt--D5LMup+x9[R=5r4uMV8-T_Lj,%$t&"
"1N'q#Dju#[HMGp'2G2e#MB;*Qg1rAM:Mxp^Ws:o^Z'?/CWD;,`ZBMH-abHQ%@STBoJpaN3l)P*<T$l?KFeR5'+8>3B&ZaJ2fMhG;HY:_A9TAdM3qB#>B?C[I>Y2m&NIb#>[haJ2@5('O"
"^o8V%qfQ^?FtjW;2,j;9RD&e@hg_$'e59U)b=;s%2Q_698exI.DM5Kji033&f]fEW5@a$>aV`sBWbm-NOg9[%u<Wm8HNR[@J$_g%eKan:#>%K;/c`'6)RC`N'AeA-ow,=&k_3TRfnxv$"
"n()<-0klw$aeIjMB*;.&@&fJ.DUo,;H(6+Y9N[mfE^A0:^IRqL@PD6MxZN$'.21q7#<fR3`9<dMD+'k$FluDN7oto&J$s58,1?j<Bj8$&pVXmA?N,F>3NoIDf3l3+Q5#Q8erke#?2tHW"
"9xMY$Qtr&OfkCX%nou#PV:8Z$i1dm8,%(@0n*7EH5=+nMk`rS@It$@'M9XCf(DSgWZf=k%dZ<aNj4XC,b(jL3BUu)N/K8_%9j#3%MUE1M[ks@<^f/w%@wYL%+Qv-$EdOam:DvP&Kf)F7"
"f<0j(OX1=?V7EI-i,]mAUl>QqYTc<%Q4_$f`-<iM#=Sc;7W9XqO=_,M(BbP<;,.@'Q>1n85X?hGidK_mlK8f$Lt@KCDihv@C^Hn:dLDc##bp_-Q[J;gcdAh:8_2cYtoL/;=tq$'^XRvR"
"@B`/9Lu%=BWKR3<:kRvRFbG-&BU+a<41bJ2e[SoUAjo?MX'-a&&R[k4C4A_8_RrS&t25394Xk,k(XDY&.Svj9176e4'8]u%&.(B@pM?.%,ABgLs[1]$$SF&#NfBdMmp$>+LqZdM.ih;-"
"ba1Q*noHj<w8_@'eBDE)uMSi$v0t3MM/%4C(b1;0&VaBDth'HkAb,e)u^&4+M.^:^wrD''=Lh4++Qt[nS17Y'IGu58=v&EYlE<R%KW;R<'w:Z>R=iJs?0@Y)=%&3MHXWn891[w'@aop7"
"JUx>._mko&:V6j9BY%`?=TA?&erCj9OTF&#xR7p&Il:Q8B>u`4]/g;-L=hRAS,=LsLISn&w1aZ@&*9,(lv]Gu)#)f;M4.`AK?`<?2cu/*H0e-7/OO[7aVA/&f%YKN]XV5FNCS8:2tV#&"
"HkekL:VL;-t]`t%ax_N9F$w.O$$1<(okXQV?qll$oXwZPsa`a'<rLu]V9(X%BDfcZ+u4)'WNIM$8saH=JU^gLo3Wb$1x9HV-FRjP?hDG-MQ/f-Pr6<-6;c`%-b'9Rtj*CO>i>9'KZ_h#"
"^96>DuNT@-1XurCV<@`&oe6N;n##?-eGVD&ftt?0=4vV%^>WAJF%3q%k>k(7Q+x4ARL:a4auH6Mg3%4CGo5mACC$=12^0^#DOUV-8)xZgO=1eZ2e+d;J6G]:lRpX'=)I6TBV+@(Q2r,;"
"bwgtoAeYd&TrtGM2T6i$dn;m8:[o(m+?B4&bnsG;DT^_I-l9n$.^d7+_^wGMrnXo&0D]gUfQGNA4`F&#4aIZ>wIf#.q0Ii&i1s`FCAR]ea+h`(x#%#AL'U=R;<t7/97Y^=W<6pgm?33&"
"EN[v>B=Wac>bpg%'I49R=,.78DdN)Y1D[A-cCULM&<;Y&qs<NBdmuR_(7emL9*-M;7CYn*eNU`-%sd&''>Rg:@6q=8e(sP:YG,iLf,jlJh&s22](6=*bX]a<UuO&#V.g:CFq<<:_DT;'"
"E%dgL`3.s-2mZo@>Fu`4jmlsHvJ]c5,kAY'hgE&OEpvw&A@^B'%;Xk#=3`2;0n`=g/K(w'Zok,M82^m@`:bH=>6r`$p.0QJ;#qDlbS;s?OP5'Z.a%G=NsX0NUQ1X%7Bbm8-<T*YrC3)="
"9whv@Avo*E,VNC7+eIm%M4k#>Kdgtq,WOvYaNWhZMOH##TWvNb@(%9rSllV$+^8I%OuBv$`)bJ2UiCQ8gjo6*uS)`%-`W/%?)c;-d&?s%GWRh*@O/w7=$O#Rix,`%`a=&FC6$XLYxDH;"
"Y5=2C`Fws7Bhki$MJ$-++`_8RWmU9R$ui$G;6Na,I8g$&g5<NKm=mQqg/mW%5e7QAG+gVgal^)O-iT`$h1?qtQq,KlOeMo>x9f$nwTWJ']jk=-3^^m2vZ8@(#O,W8$Gj9DZRV49/J=P;"
"``a;&#pbJ28k)e<?_`xfPn;J:H@xNOWj9hjtlH.'lq8-;L&4TBpL0@%49Tp7SRqw.Rfu<'^<FK:ll)FPwl'LMBIDJD/uwd;%V6XA1<.G:-IbQ)=HJv&ZF--M3v[O.m_=p^)A6wJGUn@'"
"SK``-)or4#NImdM.O?a$`nOE<Y0:+?v=PkLN34S2T=B<H=k[1E&8,c'whm;-[f*$%_7MaNZg*`+-jD4:XW_c/Y2nZ>AA`/s+j&BH>:oB&&g1<-N:md$bSYm8#u^7).4H0&q3n0#B[G&#"
"%baa*`3t,;Nm>v]^JtC(mC:/%*WN7:aarL7;f[=-XbnHbSm`I&Z?ap7[pZ@1dIa:8FZkL:p,kRM^$lf%92@v&mCeA-XHFK&t/c9BBP)CZSu>*(]G8l#>aD<okffx2c@-c*EUkE<_`fG5"
"8Wjb:XgxcPEcZ6)8q&_S/]^GMZr6Tg?oOb*i^qpIUDGn(<UI@ZPbm##S%o,;V^8U)_.idDhTF&##h$<?'s-+6W@-C?k+kx'_MuAO;3r2'NH0K:(._r(PCZY#Ij[1$:j61U$h,A-av4A="
"W)Y?e>L'k$XRf2Nn-8V8*lb`69FF3N@uNe+.AYXS9ALPSV/-Y$<H=n/4####";
#endif

View File

@@ -0,0 +1,8 @@
#pragma once
class EmbeddedData
{
public:
static const char PB_MSGFT_bin_compressed_data_base85[5380 + 1];
};

View File

@@ -0,0 +1,362 @@
#include "pch.h"
#include "GroupData.h"
#include "EmbeddedData.h"
#include "fullscrn.h"
#include "gdrv.h"
#include "pb.h"
#include "pinball.h"
#include "zdrv.h"
EntryData::~EntryData()
{
if (Buffer)
{
if (EntryType == FieldTypes::Bitmap8bit)
{
delete reinterpret_cast<gdrv_bitmap8*>(Buffer);
}
else if (EntryType == FieldTypes::Bitmap16bit)
{
delete reinterpret_cast<zmap_header_type*>(Buffer);
}
else
delete[] Buffer;
}
}
GroupData::GroupData(int groupId)
{
GroupId = groupId;
}
void GroupData::AddEntry(EntryData* entry)
{
auto addEntry = true;
switch (entry->EntryType)
{
case FieldTypes::GroupName:
GroupName = entry->Buffer;
break;
case FieldTypes::Bitmap8bit:
{
auto srcBmp = reinterpret_cast<gdrv_bitmap8*>(entry->Buffer);
if (srcBmp->BitmapType == BitmapTypes::Spliced)
{
// Get rid of spliced bitmap early on, to simplify render pipeline
auto bmp = new gdrv_bitmap8(srcBmp->Width, srcBmp->Height, srcBmp->Width);
auto zMap = new zmap_header_type(srcBmp->Width, srcBmp->Height, srcBmp->Width);
SplitSplicedBitmap(*srcBmp, *bmp, *zMap);
NeedsSort = true;
addEntry = false;
AddEntry(new EntryData(FieldTypes::Bitmap8bit, reinterpret_cast<char*>(bmp)));
AddEntry(new EntryData(FieldTypes::Bitmap16bit, reinterpret_cast<char*>(zMap)));
delete entry;
}
else
{
SetBitmap(srcBmp);
}
break;
}
case FieldTypes::Bitmap16bit:
{
SetZMap(reinterpret_cast<zmap_header_type*>(entry->Buffer));
break;
}
default: break;
}
if (addEntry)
Entries.push_back(entry);
}
void GroupData::FinalizeGroup()
{
if (NeedsSort)
{
// Entries within a group are sorted by EntryType, in ascending order.
// Dat files follow this rule, zMaps inserted in the middle break it.
NeedsSort = false;
std::sort(Entries.begin(), Entries.end(), [](const EntryData* lhs, const EntryData* rhs)
{
return lhs->EntryType < rhs->EntryType;
});
Entries.shrink_to_fit();
}
}
gdrv_bitmap8* GroupData::GetBitmap(int resolution) const
{
return Bitmaps[resolution];
}
zmap_header_type* GroupData::GetZMap(int resolution) const
{
return ZMaps[resolution];
}
void GroupData::SplitSplicedBitmap(const gdrv_bitmap8& srcBmp, gdrv_bitmap8& bmp, zmap_header_type& zMap)
{
assertm(srcBmp.BitmapType == BitmapTypes::Spliced, "GroupData: wrong bitmap type");
std::memset(bmp.IndexedBmpPtr, 0xff, bmp.Stride * bmp.Height);
bmp.XPosition = srcBmp.XPosition;
bmp.YPosition = srcBmp.YPosition;
bmp.Resolution = srcBmp.Resolution;
zdrv::fill(&zMap, zMap.Width, zMap.Height, 0, 0, 0xFFFF);
zMap.Resolution = srcBmp.Resolution;
auto tableWidth = fullscrn::resolution_array[srcBmp.Resolution].TableWidth;
auto src = reinterpret_cast<uint16_t*>(srcBmp.IndexedBmpPtr);
auto srcChar = reinterpret_cast<char**>(&src);
for (int dstInd = 0;;)
{
auto stride = static_cast<int16_t>(*src++);
if (stride < 0)
break;
// Stride is in terms of dst stride, hardcoded to match vScreen width in current resolution
if (stride > bmp.Width)
{
stride += bmp.Width - tableWidth;
assertm(stride >= 0, "Spliced bitmap: negative computed stride");
}
dstInd += stride;
for (auto count = *src++; count; count--)
{
auto depth = *src++;
bmp.IndexedBmpPtr[dstInd] = **srcChar;
zMap.ZPtr1[dstInd] = depth;
(*srcChar)++;
dstInd++;
}
}
}
void GroupData::SetBitmap(gdrv_bitmap8* bmp)
{
assertm(Bitmaps[bmp->Resolution] == nullptr, "GroupData: bitmap override");
Bitmaps[bmp->Resolution] = bmp;
auto zMap = ZMaps[bmp->Resolution];
if (zMap)
{
assertm(bmp->Width == zMap->Width && bmp->Height == zMap->Height,
"GroupData: mismatched bitmap/zMap dimensions");
}
}
void GroupData::SetZMap(zmap_header_type* zMap)
{
// Flip zMap to match with flipped non-indexed bitmaps
zdrv::FlipZMapHorizontally(*zMap);
assertm(ZMaps[zMap->Resolution] == nullptr, "GroupData: zMap override");
ZMaps[zMap->Resolution] = zMap;
auto bmp = Bitmaps[zMap->Resolution];
if (bmp)
{
assertm(bmp->Width == zMap->Width && bmp->Height == zMap->Height,
"GroupData: mismatched bitmap/zMap dimensions");
}
}
DatFile::~DatFile()
{
for (auto group : Groups)
{
if (!group)
continue;
for (const auto entry : group->GetEntries())
{
delete entry;
}
delete group;
}
}
char* DatFile::field(int groupIndex, FieldTypes targetEntryType)
{
assertm(targetEntryType != FieldTypes::Bitmap8bit && targetEntryType != FieldTypes::Bitmap16bit,
"partman: Use specific get for bitmaps");
auto group = Groups[groupIndex];
for (const auto entry : group->GetEntries())
{
if (entry->EntryType == targetEntryType)
{
return entry->Buffer;
}
if (entry->EntryType > targetEntryType)
break;
}
return nullptr;
}
char* DatFile::field_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN)
{
assertm(targetEntryType != FieldTypes::Bitmap8bit && targetEntryType != FieldTypes::Bitmap16bit,
"partman: Use specific get for bitmaps");
auto group = Groups[groupIndex];
auto skipCount = 0;
for (const auto entry : group->GetEntries())
{
if (entry->EntryType > targetEntryType)
break;
if (entry->EntryType == targetEntryType)
if (skipCount++ == skipFirstN)
return entry->Buffer;
}
return nullptr;
}
int DatFile::field_size_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN)
{
auto group = Groups[groupIndex];
auto skipCount = 0;
for (const auto entry : group->GetEntries())
{
if (entry->EntryType > targetEntryType)
return 0;
if (entry->EntryType == targetEntryType)
if (skipCount++ == skipFirstN)
return entry->FieldSize;
}
return 0;
}
int DatFile::field_size(int groupIndex, FieldTypes targetEntryType)
{
return field_size_nth(groupIndex, targetEntryType, 0);
}
int DatFile::record_labeled(LPCSTR targetGroupName)
{
auto targetLength = strlen(targetGroupName);
for (int groupIndex = Groups.size() - 1; groupIndex >= 0; --groupIndex)
{
auto groupName = field(groupIndex, FieldTypes::GroupName);
if (!groupName)
continue;
auto index = 0u;
for (; index < targetLength; index++)
if (targetGroupName[index] != groupName[index])
break;
if (index == targetLength && !targetGroupName[index] && !groupName[index])
return groupIndex;
}
return -1;
}
char* DatFile::field_labeled(LPCSTR lpString, FieldTypes fieldType)
{
auto groupIndex = record_labeled(lpString);
return groupIndex < 0 ? nullptr : field(groupIndex, fieldType);
}
gdrv_bitmap8* DatFile::GetBitmap(int groupIndex)
{
auto group = Groups[groupIndex];
return group->GetBitmap(fullscrn::GetResolution());
}
zmap_header_type* DatFile::GetZMap(int groupIndex)
{
auto group = Groups[groupIndex];
return group->GetZMap(fullscrn::GetResolution());
}
void DatFile::Finalize()
{
if (!pb::FullTiltMode)
{
int groupIndex = record_labeled("pbmsg_ft");
assertm(groupIndex < 0, "DatFile: pbmsg_ft is already in .dat");
// Load 3DPB font into dat to simplify pipeline
auto rcData = reinterpret_cast<MsgFont*>(ImFontAtlas::DecompressCompressedBase85Data(
EmbeddedData::PB_MSGFT_bin_compressed_data_base85));
AddMsgFont(rcData, "pbmsg_ft");
IM_FREE(rcData);
// PINBALL2.MID is an alternative font provided in 3DPB data
// Scaled down because it is too large for top text box
/*auto file = pinball::make_path_name("PINBALL2.MID");
auto fileHandle = fopenu(file.c_str(), "rb");
fseek(fileHandle, 0, SEEK_END);
auto fileSize = static_cast<uint32_t>(ftell(fileHandle));
auto rcData = reinterpret_cast<MsgFont*>(new uint8_t[fileSize]);
fseek(fileHandle, 0, SEEK_SET);
fread(rcData, 1, fileSize, fileHandle);
fclose(fileHandle);
auto groupId = Groups.back()->GroupId + 1u;
AddMsgFont(rcData, "pbmsg_ft");
delete[] rcData;
for (auto i = groupId; i < Groups.size(); i++)
Groups[i]->GetBitmap(0)->ScaleIndexed(0.84f, 0.84f);*/
}
for (auto group : Groups)
{
group->FinalizeGroup();
}
}
void DatFile::AddMsgFont(MsgFont* font, const std::string& fontName)
{
auto groupId = Groups.back()->GroupId + 1;
auto ptrToData = reinterpret_cast<char*>(font->Data);
for (auto charInd = 32; charInd < 128; charInd++, groupId++)
{
auto curChar = reinterpret_cast<MsgFontChar*>(ptrToData);
assertm(curChar->Width == font->CharWidths[charInd], "Score: mismatched font width");
ptrToData += curChar->Width * font->Height + 1;
auto bmp = new gdrv_bitmap8(curChar->Width, font->Height, true);
auto srcPtr = curChar->Data;
auto dstPtr = &bmp->IndexedBmpPtr[bmp->Stride * (bmp->Height - 1)];
for (auto y = 0; y < font->Height; ++y)
{
memcpy(dstPtr, srcPtr, curChar->Width);
srcPtr += curChar->Width;
dstPtr -= bmp->Stride;
}
auto group = new GroupData(groupId);
group->AddEntry(new EntryData(FieldTypes::Bitmap8bit, reinterpret_cast<char*>(bmp)));
if (charInd == 32)
{
// First font group holds font name and gap width
auto groupName = new char[fontName.length() + 1];
strcpy(groupName, fontName.c_str());
group->AddEntry(new EntryData(FieldTypes::GroupName, groupName));
auto gaps = new char[2];
*reinterpret_cast<int16_t*>(gaps) = font->GapWidth;
group->AddEntry(new EntryData(FieldTypes::ShortArray, gaps));
}
else
{
auto groupName = new char[30];
sprintf(groupName, "char %d='%c'", charInd, charInd);
group->AddEntry(new EntryData(FieldTypes::GroupName, groupName));
}
Groups.push_back(group);
}
}

View File

@@ -0,0 +1,128 @@
#pragma once
struct zmap_header_type;
struct gdrv_bitmap8;
enum class FieldTypes : int16_t
{
// One 16 bit signed integer
ShortValue = 0,
// Sprite bitmap, 8bpp, indexed color
Bitmap8bit = 1,
Unknown2 = 2,
// Group name, char[]. Not all groups have names.
GroupName = 3,
Unknown4 = 4,
// Palette, contains 256 RBGA 4-byte colors.
Palette = 5,
Unknown6 = 6,
Unknown7 = 7,
Unknown8 = 8,
// String, char[]
String = 9,
// Array of 16 bit signed integers
ShortArray = 10,
// Array of 32 bit floats
FloatArray = 11,
// Sprite depth map, 16bpp, unsigned
Bitmap16bit = 12,
};
struct EntryData
{
EntryData() = default;
EntryData(FieldTypes entryType, char* buffer): EntryType(entryType), FieldSize(-1), Buffer(buffer)
{
}
~EntryData();
FieldTypes EntryType{};
int FieldSize{};
char* Buffer{};
};
#pragma pack(push, 1)
struct MsgFontChar
{
uint8_t Width;
char Data[1];
};
struct MsgFont
{
int16_t GapWidth;
int16_t Unknown1;
int16_t Height;
uint8_t CharWidths[128];
MsgFontChar Data[1];
};
#pragma pack(pop)
static_assert(sizeof(MsgFont) == 136, "Wrong size of MsgFont");
class GroupData
{
public:
int GroupId;
std::string GroupName;
GroupData(int groupId);
void AddEntry(EntryData* entry);
void FinalizeGroup();
const std::vector<EntryData*>& GetEntries() const { return Entries; }
const EntryData* GetEntry(size_t index) const { return Entries[index]; }
size_t EntryCount() const { return Entries.size(); }
void ReserveEntries(size_t count) { Entries.reserve(count); }
gdrv_bitmap8* GetBitmap(int resolution) const;
zmap_header_type* GetZMap(int resolution) const;
private:
std::vector<EntryData*> Entries;
gdrv_bitmap8* Bitmaps[3]{};
zmap_header_type* ZMaps[3]{};
bool NeedsSort = false;
static void SplitSplicedBitmap(const gdrv_bitmap8& srcBmp, gdrv_bitmap8& bmp, zmap_header_type& zMap);
void SetBitmap(gdrv_bitmap8* bmp);
void SetZMap(zmap_header_type* zMap);
};
class DatFile
{
public:
std::string AppName;
std::string Description;
std::vector<GroupData*> Groups;
~DatFile();
char* field_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN);
char* field(int groupIndex, FieldTypes entryType);
int field_size_nth(int groupIndex, FieldTypes targetEntryType, int skipFirstN);
int field_size(int groupIndex, FieldTypes targetEntryType);
int record_labeled(LPCSTR targetGroupName);
char* field_labeled(LPCSTR lpString, FieldTypes fieldType);
gdrv_bitmap8* GetBitmap(int groupIndex);
zmap_header_type* GetZMap(int groupIndex);
void Finalize();
private:
void AddMsgFont(MsgFont* font, const std::string& fontName);
};

View File

@@ -1,270 +1,83 @@
#include "pch.h"
#include "Sound.h"
#include "pb.h"
#include "pinball.h"
#include "WaveMix.h"
#include "winmain.h"
int Sound::num_channels;
HWND Sound::wavemix_window;
HANDLE Sound::pMem;
unsigned int Sound::enabled_flag;
int Sound::channel_time[8];
MIXWAVE* Sound::channel_wavePtr[8];
void (*Sound::callback_ptr)(int, MIXWAVE*, int);
HMODULE Sound::HInstance;
bool Sound::enabled_flag = false;
int* Sound::TimeStamps = nullptr;
int Sound::Init(HINSTANCE hInstance, int voices, void (* someFuncPtr)(int, MIXWAVE*, int))
bool Sound::Init(int channels, bool enableFlag)
{
WNDCLASSA WndClass;
char FileName[300];
int channelCount = voices;
if (voices > 8)
channelCount = 8;
num_channels = channelCount;
if (wavemix_window || pMem)
return 0;
enabled_flag = -1;
for (int i = 0; i < channelCount; ++i)
{
channel_time[i] = 0;
channel_wavePtr[i] = nullptr;
}
callback_ptr = someFuncPtr;
if (!someFuncPtr)
callback_ptr = NullCallback;
pinball::make_path_name(FileName, "wavemix.inf", 300);
FILE* wavemixIniFile = nullptr;
fopen_s(&wavemixIniFile, FileName, "r");
if (wavemixIniFile)
{
fclose(wavemixIniFile);
}
else
{
/*FT does not have the file, defaults work OK*/
if (!pb::FullTiltMode)
MessageBoxW(winmain::hwnd_frame, pinball::get_rc_Wstring(42, 0), L"", 0x2000u);
Mix_Init(MIX_INIT_MID_Proxy);
auto result = Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024);
SetChannels(channels);
Enable(enableFlag);
return !result;
}
WndClass.style = 0;
WndClass.lpfnWndProc = SoundCallBackWndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = nullptr;
WndClass.hCursor = nullptr;
WndClass.hbrBackground = nullptr;
WndClass.lpszMenuName = nullptr;
WndClass.lpszClassName = "WaveMixSoundGuy";
RegisterClassA(&WndClass);
wavemix_window = CreateWindowExA(
0,
"WaveMixSoundGuy",
nullptr,
0x80000000,
0x80000000,
0,
0x80000000,
0,
nullptr,
nullptr,
hInstance,
nullptr);
if (!wavemix_window)
return 0;
HInstance = hInstance;
HANDLE hMixSession = WaveMix::Init();
pMem = hMixSession;
if (!hMixSession)
return 0;
WaveMix::OpenChannel(hMixSession, num_channels, 2u);
return 1;
}
void Sound::Enable(int channelFrom, int channelTo, int enableFlag)
void Sound::Enable(bool enableFlag)
{
if (pMem)
{
if (channelTo >= num_channels)
channelTo = num_channels - 1;
if (channelFrom >= 0 && channelTo < num_channels)
{
for (int index = channelFrom; index <= channelTo; ++index)
{
int channelFlag = 1 << index;
if (enableFlag)
{
enabled_flag |= channelFlag;
}
else
{
enabled_flag &= ~channelFlag;
Flush(index, index);
}
}
}
}
}
void Sound::Idle()
{
if (pMem)
WaveMix::Pump();
enabled_flag = enableFlag;
if (!enableFlag)
Mix_HaltChannel(-1);
}
void Sound::Activate()
{
if (pMem)
WaveMix::Activate(pMem, true);
Mix_Resume(-1);
}
void Sound::Deactivate()
{
if (pMem)
WaveMix::Activate(pMem, false);
Mix_Pause(-1);
}
void Sound::Close()
{
if (wavemix_window)
{
DestroyWindow(wavemix_window);
wavemix_window = nullptr;
delete[] TimeStamps;
TimeStamps = nullptr;
Mix_CloseAudio();
Mix_Quit();
}
if (pMem)
void Sound::PlaySound(Mix_Chunk* wavePtr, int time)
{
WaveMix::CloseChannel(pMem, 0, 1);
WaveMix::CloseSession(pMem);
pMem = nullptr;
if (wavePtr && enabled_flag)
{
if (Mix_Playing(-1) == num_channels)
{
auto oldestChannel = std::min_element(TimeStamps, TimeStamps + num_channels) - TimeStamps;
Mix_HaltChannel(oldestChannel);
}
auto channel = Mix_PlayChannel(-1, wavePtr, 0);
if (channel != -1)
TimeStamps[channel] = time;
}
}
void Sound::PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops)
Mix_Chunk* Sound::LoadWaveFile(const std::string& lpName)
{
MIXPLAYPARAMS mixParams{};
auto wavFile = fopenu(lpName.c_str(), "r");
if (!wavFile)
return nullptr;
fclose(wavFile);
if (!pMem)
return;
if (maxChannel >= num_channels)
maxChannel = num_channels - 1;
if (!wavePtr || minChannel < 0 || maxChannel >= num_channels)
return;
if ((dwFlags & 0x8000) != 0 && num_channels > 0)
{
int index2 = 0;
bool ok = false;
while (channel_wavePtr[index2] != wavePtr)
{
if (++index2 >= num_channels)
{
ok = true;
break;
}
}
if (!ok)
return;
return Mix_LoadWAV(lpName.c_str());
}
int playChannel = minChannel;
if (minChannel < maxChannel)
void Sound::FreeSound(Mix_Chunk* wave)
{
int curChannel = minChannel;
do
{
++curChannel;
if ((1 << curChannel) & enabled_flag &&
channel_time[curChannel] < channel_time[playChannel])
{
playChannel = curChannel;
}
}
while (curChannel < maxChannel);
if (wave)
Mix_FreeChunk(wave);
}
if ((1 << playChannel) & enabled_flag)
void Sound::SetChannels(int channels)
{
mixParams.hMixSession = pMem;
mixParams.hWndNotify = wavemix_window;
mixParams.dwFlags = dwFlags;
mixParams.wSize = 28;
mixParams.wLoops = loops;
mixParams.iChannel = playChannel;
mixParams.lpMixWave = wavePtr;
if (channels <= 0)
channels = 8;
callback_ptr(1, wavePtr, playChannel);
channel_time[playChannel] = timeGetTime();
channel_wavePtr[playChannel] = wavePtr;
WaveMix::Play(&mixParams);
}
}
MIXWAVE* Sound::LoadWaveFile(LPCSTR lpName)
{
return pMem ? WaveMix::OpenWave(pMem, lpName, HInstance, 1u) : nullptr;
}
void Sound::FreeSound(MIXWAVE* wave)
{
if (wave && pMem)
WaveMix::FreeWave(pMem, wave);
}
void Sound::Flush(int channelFrom, int channelTo)
{
if (pMem)
{
if (channelTo >= num_channels)
channelTo = num_channels - 1;
if (channelFrom >= 0 && channelTo < num_channels)
{
for (auto index = channelFrom; index <= channelTo; index++)
{
WaveMix::FlushChannel(pMem, index, 0);
channel_time[index] = 0;
channel_wavePtr[index] = nullptr;
}
}
}
}
void Sound::NullCallback(int a1, MIXWAVE* a2, int a3)
{
}
LRESULT Sound::SoundCallBackWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg != MM_WOM_DONE)
return DefWindowProcA(hWnd, Msg, wParam, lParam);
auto wavePtr = reinterpret_cast<MIXWAVE*>(lParam);
int channel = -1;
for (auto index = 0; index < num_channels; ++index)
{
if (channel_wavePtr[index] == wavePtr &&
(channel < 0 || channel_time[index] < channel_time[channel]))
{
channel = index;
}
}
if (channel >= 0)
{
channel_time[channel] = 0;
channel_wavePtr[channel] = nullptr;
}
callback_ptr(2, wavePtr, channel);
return 0;
num_channels = channels;
delete[] TimeStamps;
TimeStamps = new int[num_channels]();
Mix_AllocateChannels(num_channels);
}

View File

@@ -1,28 +1,20 @@
#pragma once
#include "WaveMix.h"
class Sound
{
public:
static int Init(HINSTANCE hInstance, int voices, void (* someFuncPtr)(int, MIXWAVE*, int));
static void Enable(int channelFrom, int channelTo, int enableFlag);
static void Idle();
static bool Init(int channels, bool enableFlag);
static void Enable(bool enableFlag);
static void Activate();
static void Deactivate();
static void Close();
static void PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops);
static MIXWAVE* LoadWaveFile(LPCSTR lpName);
static void FreeSound(MIXWAVE* wave);
static void Flush(int channelFrom, int channelTo);
static void NullCallback(int a1, MIXWAVE* a2, int a3);
static LRESULT __stdcall SoundCallBackWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
static void PlaySound(Mix_Chunk* wavePtr, int time);
static Mix_Chunk* LoadWaveFile(const std::string& lpName);
static void FreeSound(Mix_Chunk* wave);
static void SetChannels(int channels);
private:
static int num_channels;
static HWND wavemix_window;
static HANDLE pMem;
static unsigned int enabled_flag;
static int channel_time[8];
static MIXWAVE* channel_wavePtr[8];
static void (* callback_ptr)(int, MIXWAVE*, int);
static HMODULE HInstance;
static bool enabled_flag;
static int* TimeStamps;
};

View File

@@ -3,81 +3,58 @@
#include "pch.h"
#include <iostream>
#include "objlist_class.h"
#include "partman.h"
#include "gdrv.h"
#include "loader.h"
#include "pb.h"
#include "pinball.h"
#include "score.h"
#include "TPinballTable.h"
#include "TTextBox.h"
#include "winmain.h"
int main()
int MainActual(LPCSTR lpCmdLine)
{
// Todo: get rid of restart to change resolution.
int returnCode;
do
{
// Testing with UI
char cmdLine[1]{};
WinMain(GetModuleHandleA(nullptr), nullptr, cmdLine, 10);
return 0;
returnCode = winmain::WinMain(lpCmdLine);
}
while (winmain::RestartRequested());
return returnCode;
}
std::cout << "Hello World!\n";
gdrv::init(nullptr, nullptr);
auto dib = gdrv::DibCreate(8, 1, 1);
gdrv::DibSetUsage(dib, nullptr, 1);
auto d = objlist_class<void>(2, 4);
for (size_t i = 0; i < 100; i++)
int main(int argc, char* argv[])
{
d.Add((void*)i);
std::string cmdLine;
for (int i = 1; i < argc; i++)
cmdLine += argv[i];
return MainActual(cmdLine.c_str());
}
d.Delete((void*)3);
auto xx = sizeof(datFileHeader);
#if _WIN32
#include <windows.h>
lstrcpyA(winmain::DatFileName, "PINBALL.DAT");
pb::init();
auto datFile = pb::record_table;
assert(partman::field_size_nth(datFile, 0, datFieldTypes::String, 0) == 43);
assert(partman::field_size_nth(datFile, 2, datFieldTypes::Palette, 0) == 1024);
assert(partman::field_size_nth(datFile, 101, datFieldTypes::FloatArray, 4) == 32);
assert(strcmp(partman::field(datFile, 0, datFieldTypes::String), "3D-Pinball: Copyright 1994, Cinematronics") == 0);
assert(strcmp(partman::field(datFile, 540, datFieldTypes::GroupName), "table_objects") == 0);
assert(partman::record_labeled(datFile, "background") == 2);
assert(partman::record_labeled(datFile, "a_bump1") == 372);
assert(memcmp(partman::field_labeled(datFile, "table_size", datFieldTypes::ShortArray), new short[2]{ 600, 416 }, 2 * 2) == 0);
//loader::error(25, 26);
loader::get_sound_id(18);
visualStruct visual1{};
loader::material(96, &visual1);
loader::query_visual(283, 0, &visual1);
visualKickerStruct kicker1{};
loader::kicker(509, &kicker1);
auto score1 = score::create("score1", nullptr);
auto pinballTable = pb::MainTable;
//pinballTable->find_component(1);
for (int i = 0; i < 190; i++)
// Windows subsystem main
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
auto rsc = pinball::get_rc_string(i, 0);
if (rsc)
printf_s("%d:\t%s\n", i, rsc);
return MainActual(lpCmdLine);
}
//DatParser::Parse(dataFileName);
std::cout << "Goodby World!\n";
// fopen to _wfopen adapter, for UTF-8 paths
FILE* fopenu(const char* path, const char* opt)
{
wchar_t* wideArgs[2]{};
for (auto& arg : wideArgs)
{
auto src = wideArgs[0] ? opt : path;
auto length = MultiByteToWideChar(CP_UTF8, 0, src, -1, nullptr, 0);
arg = new wchar_t[length];
MultiByteToWideChar(CP_UTF8, 0, src, -1, arg, length);
}
auto fileHandle = _wfopen(wideArgs[0], wideArgs[1]);
for (auto arg : wideArgs)
delete[] arg;
return fileHandle;
}
#endif
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
// Debug program: F5 or Debug > Start Debugging menu

File diff suppressed because it is too large Load Diff

View File

@@ -1,441 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Header Files\TEdgeSegment">
<UniqueIdentifier>{0aa40751-a44a-400e-8809-ee817161e8e0}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\TEdgeSegment">
<UniqueIdentifier>{d70e7fca-2294-41a4-9cf8-78052bdb9aa4}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\TCollisionComponent">
<UniqueIdentifier>{01aed326-d2ec-457a-b99f-08ef32ed97fa}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\TCollisionComponent">
<UniqueIdentifier>{7ed2796a-da4b-4edd-8783-53e45d8d1c88}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\TPinballComponent">
<UniqueIdentifier>{9ee086c2-1a95-48fb-92d8-4b7e7f6682ff}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\TPinballComponent">
<UniqueIdentifier>{33813da8-81ac-449c-b19a-9756272519b9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="objlist_class.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="partman.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="loader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pinball.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="score.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TPinballComponent.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TBall.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TComponentGroup.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TLight.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TLightBargraph.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TLightGroup.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TSound.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TTextBox.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TTimer.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="winmain.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="options.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Sound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pb.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="render.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="fullscrn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gdrv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="maths.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="zdrv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TEdgeSegment.h">
<Filter>Header Files\TEdgeSegment</Filter>
</ClInclude>
<ClInclude Include="TCollisionComponent.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TCircle.h">
<Filter>Header Files\TEdgeSegment</Filter>
</ClInclude>
<ClInclude Include="TLine.h">
<Filter>Header Files\TEdgeSegment</Filter>
</ClInclude>
<ClInclude Include="TWall.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TBumper.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TBlocker.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TDemo.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TDrain.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TFlagSpinner.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TFlipper.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TGate.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="THole.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TKickback.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TKickout.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TOneway.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TPlunger.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TPopupTarget.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TRamp.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TRollover.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TSink.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TSoloTarget.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TTableLayer.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TPinballTable.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TTripwire.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="TLightRollover.h">
<Filter>Header Files\TCollisionComponent</Filter>
</ClInclude>
<ClInclude Include="proj.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="midi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nudge.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TTextBoxMessage.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="high_score.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="control.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TEdgeManager.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TEdgeBox.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="TFlipperEdge.h">
<Filter>Header Files\TEdgeSegment</Filter>
</ClInclude>
<ClInclude Include="WaveMix.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="splash.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SpaceCadetPinball.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="partman.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="loader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pinball.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="score.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TPinballComponent.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TPinballTable.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TBall.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TComponentGroup.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TLight.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TLightBargraph.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TLightGroup.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TSound.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TTextBox.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TTimer.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="memory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="winmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="options.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Sound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pb.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="render.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fullscrn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gdrv.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="maths.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="zdrv.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TEdgeSegment.cpp">
<Filter>Source Files\TEdgeSegment</Filter>
</ClCompile>
<ClCompile Include="TCollisionComponent.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TCircle.cpp">
<Filter>Source Files\TEdgeSegment</Filter>
</ClCompile>
<ClCompile Include="TLine.cpp">
<Filter>Source Files\TEdgeSegment</Filter>
</ClCompile>
<ClCompile Include="TWall.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TBlocker.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TBumper.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TDemo.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TDrain.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TFlagSpinner.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TFlipper.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TGate.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="THole.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TKickback.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TKickout.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TOneway.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TPlunger.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TPopupTarget.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TRamp.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TRollover.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TSink.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TSoloTarget.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TTableLayer.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TTripwire.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="TLightRollover.cpp">
<Filter>Source Files\TCollisionComponent</Filter>
</ClCompile>
<ClCompile Include="proj.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="midi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="nudge.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TTextBoxMessage.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="high_score.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="control.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TEdgeManager.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TEdgeBox.cpp">
<Filter>Source Files\TPinballComponent</Filter>
</ClCompile>
<ClCompile Include="TFlipperEdge.cpp">
<Filter>Source Files\TEdgeSegment</Filter>
</ClCompile>
<ClCompile Include="WaveMix.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="splash.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="NatvisFile.natvis" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="SpaceCadetPinball.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="PB_MSGFT.bin">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Image Include="Icon_1.ico">
<Filter>Resource Files</Filter>
</Image>
<Image Include="splash_bitmap.bmp">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
</Project>

View File

@@ -5,7 +5,6 @@
#include "fullscrn.h"
#include "loader.h"
#include "maths.h"
#include "objlist_class.h"
#include "pb.h"
#include "proj.h"
#include "render.h"
@@ -32,7 +31,7 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
Position.X = 0.0;
Position.Y = 0.0;
ListBitmap = new objlist_class<gdrv_bitmap8>(0, 4);
ListBitmap = new std::vector<gdrv_bitmap8*>();
/*Full tilt: ball is ballN, where N[0,2] resolution*/
if (pb::FullTiltMode)
@@ -40,25 +39,18 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
auto groupIndex = loader::query_handle(ballGroupName);
Offset = *loader::query_float_attribute(groupIndex, 0, 500);
auto visualCount = loader::query_visual_states(groupIndex);
auto index = 0;
if (visualCount > 0)
{
auto visualZPtr = VisualZArray;
do
for (auto index = 0; index < visualCount; ++index)
{
loader::query_visual(groupIndex, index, &visual);
if (ListBitmap)
ListBitmap->Add(visual.Bitmap);
ListBitmap->push_back(visual.Bitmap);
auto visVec = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, index, 501));
auto zDepth = proj::z_distance(visVec);
++index;
*visualZPtr = zDepth;
++visualZPtr;
VisualZArray[index] = zDepth;
}
while (index < visualCount);
}
RenderSprite = render::create_sprite(VisualType::Ball, nullptr, nullptr, 0, 0, nullptr);
RenderSprite = render::create_sprite(VisualTypes::Ball, nullptr, nullptr, 0, 0, nullptr);
PinballTable->CollisionCompOffset = Offset;
Position.Z = Offset;
}
@@ -79,13 +71,13 @@ void TBall::Repaint()
auto zDepth = proj::z_distance(&Position);
auto zArrPtr = VisualZArray;
int index;
for (index = 0; index < ListBitmap->GetCount() - 1; ++index, zArrPtr++)
auto index = 0u;
for (; index < ListBitmap->size() - 1; ++index, zArrPtr++)
{
if (*zArrPtr <= zDepth) break;
}
auto bmp = ListBitmap->Get(index);
auto bmp = ListBitmap->at(index);
render::ball_set(
RenderSprite,
bmp,
@@ -138,10 +130,9 @@ void TBall::throw_ball(TBall* ball, vector_type* acceleration, float angleMult,
{
ball->CollisionComp = nullptr;
ball->Acceleration = *acceleration;
float rnd = static_cast<float>(rand());
float angle = (1.0f - (rnd * 0.00003051850947599719f + rnd * 0.00003051850947599719f)) * angleMult;
float rnd = RandFloat();
float angle = (1.0f - (rnd + rnd)) * angleMult;
maths::RotateVector(&ball->Acceleration, angle);
rnd = static_cast<float>(rand());
ball->Speed = (1.0f - (rnd * 0.00003051850947599719f + rnd * 0.00003051850947599719f)) * (speedMult1 *
speedMult2) + speedMult1;
rnd = RandFloat();
ball->Speed = (1.0f - (rnd + rnd)) * (speedMult1 * speedMult2) + speedMult1;
}

View File

@@ -17,21 +17,20 @@ public :
static void throw_ball(TBall* ball, struct vector_type* acceleration, float angleMult, float speedMult1,
float speedMult2);
vector_type Position;
vector_type Acceleration;
vector_type Position{};
vector_type Acceleration{};
float Speed;
float RayMaxDistance;
float TimeDelta;
float TimeNow;
vector_type InvAcceleration;
vector_type RampFieldForce;
vector_type InvAcceleration{};
vector_type RampFieldForce{};
TCollisionComponent* CollisionComp;
int FieldFlag;
TEdgeSegment* Collisions[5];
TEdgeSegment* Collisions[5]{};
int EdgeCollisionCount;
vector_type CollisionOffset;
vector_type CollisionOffset{};
int CollisionFlag;
float Offset;
int Unknown29;
float VisualZArray[50];
float VisualZArray[50]{};
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "timer.h"
@@ -46,7 +45,7 @@ int TBlocker::Message(int code, float value)
case 52:
ActiveFlag = 1;
loader::play_sound(SoundIndex4);
render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0));
break;
case 59:
break;

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "timer.h"
#include "TPinballTable.h"
@@ -29,8 +28,9 @@ int TBumper::Message(int code, float value)
case 11:
{
auto nextBmp = static_cast<int>(floor(value));
if (2 * nextBmp > ListBitmap->GetCount() - 1)
nextBmp = (ListBitmap->GetCount() - 1) / 2;
auto maxBmp = static_cast<int>(ListBitmap->size()) - 1;
if (2 * nextBmp > maxBmp)
nextBmp = maxBmp / 2;
if (nextBmp < 0)
nextBmp = 0;
if (nextBmp != BmpIndex)
@@ -48,7 +48,7 @@ int TBumper::Message(int code, float value)
case 12:
{
auto nextBmp = BmpIndex + 1;
auto maxBmp = ListBitmap->GetCount() - 1;
auto maxBmp = static_cast<int>(ListBitmap->size()) - 1;
if (2 * nextBmp > maxBmp)
nextBmp = maxBmp / 2;
TBumper::Message(11, static_cast<float>(nextBmp));
@@ -124,8 +124,8 @@ int TBumper::get_scoring(int index)
void TBumper::TimerExpired(int timerId, void* caller)
{
auto bump = static_cast<TBumper*>(caller);
auto bmp = bump->ListBitmap->Get(bump->BmpIndex * 2);
auto zMap = bump->ListZMap->Get(bump->BmpIndex * 2);
auto bmp = bump->ListBitmap->at(bump->BmpIndex * 2);
auto zMap = bump->ListZMap->at(bump->BmpIndex * 2);
bump->Timer = 0;
render::sprite_set(
bump->RenderSprite,
@@ -139,8 +139,8 @@ void TBumper::TimerExpired(int timerId, void* caller)
void TBumper::Fire()
{
int bmpIndex = 2 * BmpIndex + 1;
auto bmp = ListBitmap->Get(bmpIndex);
auto zMap = ListZMap->Get(bmpIndex);
auto bmp = ListBitmap->at(bmpIndex);
auto zMap = ListZMap->at(bmpIndex);
render::sprite_set(
RenderSprite,
bmp,

View File

@@ -28,6 +28,6 @@ public:
float OriginalThreshold;
int SoundIndex4;
int SoundIndex3;
int Scores[4];
TBumper_player_backup PlayerData[4];
int Scores[4]{};
TBumper_player_backup PlayerData[4]{};
};

View File

@@ -6,7 +6,7 @@ class TCircle :
public TEdgeSegment
{
public:
circle_type Circle;
circle_type Circle{};
TCircle(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup, vector_type* center,
float radius);

View File

@@ -2,17 +2,15 @@
#include "TCollisionComponent.h"
#include "loader.h"
#include "maths.h"
#include "objlist_class.h"
#include "TEdgeSegment.h"
#include "TPinballTable.h"
TCollisionComponent::TCollisionComponent(TPinballTable* table, int groupIndex, bool createWall) : TPinballComponent(
table, groupIndex, true)
TCollisionComponent::TCollisionComponent(TPinballTable* table, int groupIndex, bool createWall) :
TPinballComponent(table, groupIndex, true)
{
visualStruct visual{};
EdgeList = new objlist_class<TEdgeSegment>(4, 4);
ActiveFlag = 1;
if (GroupName != nullptr)
UnusedBaseFlag = 1;
@@ -42,22 +40,15 @@ TCollisionComponent::TCollisionComponent(TPinballTable* table, int groupIndex, b
TCollisionComponent::~TCollisionComponent()
{
for (TEdgeSegment* edge; EdgeList->GetCount() > 0;)
{
edge = EdgeList->Get(0);
EdgeList->Delete(edge);
for (auto edge : EdgeList)
delete edge;
}
delete EdgeList;
}
void TCollisionComponent::port_draw()
{
for (int index = EdgeList->GetCount() - 1; index >= 0; index--)
{
EdgeList->Get(index)->port_draw();
}
for (auto edge : EdgeList)
edge->port_draw();
}
int TCollisionComponent::DefaultCollision(TBall* ball, vector_type* nextPosition, vector_type* direction)

View File

@@ -8,7 +8,7 @@ class TBall;
class TCollisionComponent : public TPinballComponent
{
public:
objlist_class<TEdgeSegment>* EdgeList;
std::vector<TEdgeSegment*> EdgeList;
float Elasticity;
float Smoothness;
float Boost;

View File

@@ -4,13 +4,11 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "timer.h"
#include "TPinballTable.h"
TComponentGroup::TComponentGroup(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false)
{
List = new objlist_class<TPinballComponent>(4, 4);
Timer = 0;
if (groupIndex > 0)
{
@@ -21,7 +19,7 @@ TComponentGroup::TComponentGroup(TPinballTable* table, int groupIndex) : TPinbal
{
auto component = table->find_component(*shortArrPtr);
if (component)
List->Add(component);
List.push_back(component);
}
}
}
@@ -33,7 +31,6 @@ TComponentGroup::~TComponentGroup()
timer::kill(Timer);
Timer = 0;
}
delete List;
}
int TComponentGroup::Message(int code, float value)
@@ -48,11 +45,11 @@ int TComponentGroup::Message(int code, float value)
if (value > 0.0f)
this->Timer = timer::set(value, this, NotifyTimerExpired);
}
else if (code <= 1007 || code > 1011 && code != 1020 && code != 1022)
else if (code <= 1007 || (code > 1011 && code != 1020 && code != 1022))
{
for (int i = 0; i < List->GetCount(); i++)
for (auto component : List)
{
List->Get(i)->Message(code, value);
component->Message(code, value);
}
}
return 0;

View File

@@ -11,6 +11,6 @@ public:
int Message(int code, float value) override;
static void NotifyTimerExpired(int timerId, void* caller);
objlist_class<TPinballComponent>* List;
std::vector<TPinballComponent*> List;
int Timer;
};

View File

@@ -105,8 +105,7 @@ void TDemo::Collision(TBall* ball, vector_type* nextPosition, vector_type* direc
case 1400:
if (!FlipLeftTimer && !FlipLeftFlag)
{
float time = FlipTimerTime1 + FlipTimerTime2 - static_cast<float>(rand()) *
0.00003051850947599719f * (FlipTimerTime2 + FlipTimerTime2);
float time = FlipTimerTime1 + FlipTimerTime2 - RandFloat() * (FlipTimerTime2 + FlipTimerTime2);
FlipLeftTimer = timer::set(time, this, FlipLeft);
}
break;
@@ -116,8 +115,7 @@ void TDemo::Collision(TBall* ball, vector_type* nextPosition, vector_type* direc
case 1402:
if (!FlipRightTimer && !FlipRightFlag)
{
float time = FlipTimerTime1 + FlipTimerTime2 - static_cast<float>(rand()) *
0.00003051850947599719f * (FlipTimerTime2 + FlipTimerTime2);
float time = FlipTimerTime1 + FlipTimerTime2 - RandFloat() * (FlipTimerTime2 + FlipTimerTime2);
FlipRightTimer = timer::set(time, this, FlipRight);
}
break;
@@ -128,7 +126,7 @@ void TDemo::Collision(TBall* ball, vector_type* nextPosition, vector_type* direc
if (!PlungerFlag)
{
PinballTable->Message(1004, ball->TimeNow);
float time = static_cast<float>(rand()) * 0.00003051850947599719f + 2.0f;
float time = RandFloat() + 2.0f;
PlungerFlag = timer::set(time, this, PlungerRelease);
}
break;
@@ -172,8 +170,8 @@ void TDemo::FlipRight(int timerId, void* caller)
}
demo->PinballTable->Message(1002, pb::time_next);
demo->FlipRightFlag = 1;
float time = demo->UnFlipTimerTime1 + demo->UnFlipTimerTime2 - static_cast<float>(rand()) *
0.00003051850947599719f * (demo->UnFlipTimerTime2 + demo->UnFlipTimerTime2);
float time = demo->UnFlipTimerTime1 + demo->UnFlipTimerTime2 - RandFloat() *
(demo->UnFlipTimerTime2 + demo->UnFlipTimerTime2);
timer::set(time, demo, UnFlipRight);
}
}
@@ -190,8 +188,8 @@ void TDemo::FlipLeft(int timerId, void* caller)
}
demo->PinballTable->Message(1000, pb::time_next);
demo->FlipLeftFlag = 1;
float time = demo->UnFlipTimerTime1 + demo->UnFlipTimerTime2 - static_cast<float>(rand()) *
0.00003051850947599719f * (demo->UnFlipTimerTime2 + demo->UnFlipTimerTime2);
float time = demo->UnFlipTimerTime1 + demo->UnFlipTimerTime2 - RandFloat() *
(demo->UnFlipTimerTime2 + demo->UnFlipTimerTime2);
timer::set(time, demo, UnFlipLeft);
}
}

View File

@@ -1,16 +0,0 @@
#include "pch.h"
#include "TEdgeBox.h"
#include "objlist_class.h"
TEdgeBox::TEdgeBox()
{
EdgeList = new objlist_class<TEdgeSegment>(0, 4);
FieldList = new objlist_class<field_effect_type>(0, 1);
}
TEdgeBox::~TEdgeBox()
{
delete EdgeList;
delete FieldList;
}

View File

@@ -1,6 +1,4 @@
#pragma once
#include "objlist_class.h"
struct field_effect_type;
class TEdgeSegment;
@@ -8,10 +6,6 @@ class TEdgeSegment;
class TEdgeBox
{
public:
TEdgeBox();
~TEdgeBox();
objlist_class<TEdgeSegment>* EdgeList;
objlist_class<field_effect_type>* FieldList;
std::vector<TEdgeSegment*> EdgeList{};
std::vector<field_effect_type*> FieldList{};
};

View File

@@ -3,7 +3,6 @@
#include "maths.h"
#include "objlist_class.h"
#include "TBall.h"
#include "TEdgeBox.h"
#include "TEdgeSegment.h"
@@ -29,32 +28,32 @@ TEdgeManager::~TEdgeManager()
int TEdgeManager::box_x(float x)
{
return static_cast<int>((max(0, min(floor((x - X) * AdvanceXInv), (MaxBoxX - 1)))));
return std::max(0, std::min(static_cast<int>(floor((x - X) * AdvanceXInv)), MaxBoxX - 1));
}
int TEdgeManager::box_y(float y)
{
return static_cast<int>((max(0, min(floor((y - Y) * AdvanceYInv), (MaxBoxY - 1)))));
return std::max(0, std::min(static_cast<int>(floor((y - Y) * AdvanceYInv)), MaxBoxY - 1));
}
int TEdgeManager::increment_box_x(int x)
{
return min(x + 1, MaxBoxX - 1);
return std::min(x + 1, MaxBoxX - 1);
}
int TEdgeManager::increment_box_y(int y)
{
return min(y + 1, MaxBoxY - 1);
return std::min(y + 1, MaxBoxY - 1);
}
void TEdgeManager::add_edge_to_box(int x, int y, TEdgeSegment* edge)
{
BoxArray[x + y * MaxBoxX].EdgeList->Add(edge);
BoxArray[x + y * MaxBoxX].EdgeList.push_back(edge);
}
void TEdgeManager::add_field_to_box(int x, int y, field_effect_type* field)
{
BoxArray[x + y * MaxBoxX].FieldList->Add(field);
BoxArray[x + y * MaxBoxX].FieldList.push_back(field);
}
int TEdgeManager::TestGridBox(int x, int y, float* distPtr, TEdgeSegment** edgeDst, ray_type* ray, TBall* ball,
@@ -64,9 +63,9 @@ int TEdgeManager::TestGridBox(int x, int y, float* distPtr, TEdgeSegment** edgeD
{
TEdgeBox* edgeBox = &BoxArray[x + y * MaxBoxX];
TEdgeSegment** edgePtr = &EdgeArray[edgeIndex];
for (auto index = edgeBox->EdgeList->GetCount() - 1; index >= 0; --index)
for (auto it = edgeBox->EdgeList.rbegin(); it != edgeBox->EdgeList.rend(); ++it)
{
auto edge = edgeBox->EdgeList->Get(index);
auto edge = *it;
if (!edge->ProcessedFlag && *edge->ActiveFlag && (edge->CollisionGroup & ray->FieldFlag))
{
if (!ball->already_hit(edge))
@@ -94,9 +93,9 @@ void TEdgeManager::FieldEffects(TBall* ball, vector_type* dstVec)
TEdgeBox* edgeBox = &BoxArray[box_x(ball->Position.X) + box_y(ball->Position.Y) *
MaxBoxX];
for (int index = edgeBox->FieldList->GetCount() - 1; index >= 0; --index)
for (auto it = edgeBox->FieldList.rbegin(); it != edgeBox->FieldList.rend(); ++it)
{
auto field = edgeBox->FieldList->Get(index);
auto field = *it;
if (*field->Flag2Ptr && ball->FieldFlag & field->Mask)
{
if (field->CollisionComp->FieldEffect(ball, &vec))

View File

@@ -35,5 +35,5 @@ public:
float X;
float Y;
TEdgeBox* BoxArray;
TEdgeSegment* EdgeArray[1000];
TEdgeSegment* EdgeArray[1000]{};
};

View File

@@ -1,7 +1,6 @@
#include "pch.h"
#include "TEdgeSegment.h"
#include "objlist_class.h"
#include "TCircle.h"
#include "TCollisionComponent.h"
#include "TLine.h"
@@ -41,7 +40,7 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
circle->place_in_grid();
}
collComp->EdgeList->Add(circle);
collComp->EdgeList.push_back(circle);
break;
}
case wall_type::Line:
@@ -58,7 +57,7 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
line->WallValue = reinterpret_cast<void*>(wallValue);
line->Offset(offset);
line->place_in_grid();
collComp->EdgeList->Add(line);
collComp->EdgeList.push_back(line);
}
break;
}
@@ -94,8 +93,8 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
vec2.X = centerX2 - centerX1;
vec2.Y = centerY2 - center.Y;
maths::cross(&vec1, &vec2, &dstVec);
if (dstVec.Z > 0.0f && offset > 0.0f ||
dstVec.Z < 0.0f && offset < 0.0f)
if ((dstVec.Z > 0.0f && offset > 0.0f) ||
(dstVec.Z < 0.0f && offset < 0.0f))
{
float radius = offset * 1.001f;
auto circle = new TCircle(collComp, activeFlagPtr, collisionGroup, &center, radius);
@@ -104,7 +103,7 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
{
circle->WallValue = reinterpret_cast<void*>(wallValue);
circle->place_in_grid();
collComp->EdgeList->Add(circle);
collComp->EdgeList.push_back(circle);
}
}
}
@@ -121,7 +120,7 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
line->WallValue = reinterpret_cast<void*>(wallValue);
line->Offset(offset);
line->place_in_grid();
collComp->EdgeList->Add(line);
collComp->EdgeList.push_back(line);
}
prevCenter = center;

View File

@@ -16,7 +16,7 @@ public:
TCollisionComponent* CollisionComponent;
char* ActiveFlag;
char ProcessedFlag;
void* WallValue;
void* WallValue{};
unsigned int CollisionGroup;
TEdgeSegment(TCollisionComponent* collComp, char* activeFlag, unsigned int collisionGroup);

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "TBall.h"
#include "timer.h"
@@ -26,7 +25,7 @@ TFlagSpinner::TFlagSpinner(TPinballTable* table, int groupIndex) : TCollisionCom
if (line)
{
line->place_in_grid();
EdgeList->Add(line);
EdgeList.push_back(line);
}
line = new TLine(this, &ActiveFlag, visual.CollisionGroup, &end, &start);
@@ -34,7 +33,7 @@ TFlagSpinner::TFlagSpinner(TPinballTable* table, int groupIndex) : TCollisionCom
if (line)
{
line->place_in_grid();
EdgeList->Add(line);
EdgeList.push_back(line);
}
SpeedDecrement = 0.64999998f;
@@ -61,8 +60,8 @@ int TFlagSpinner::Message(int code, float value)
Timer = 0;
}
BmpIndex = 0;
auto bmp = ListBitmap->Get(0);
auto zMap = ListZMap->Get(0);
auto bmp = ListBitmap->at(0);
auto zMap = ListZMap->at(0);
render::sprite_set(
RenderSprite,
bmp,
@@ -108,7 +107,7 @@ void TFlagSpinner::NextFrame()
{
BmpIndex += SpinDirection;
int bmpIndex = BmpIndex;
int bmpCount = ListBitmap->GetCount();
int bmpCount = ListBitmap->size();
if (bmpIndex >= bmpCount)
BmpIndex = 0;
else if (bmpIndex < 0)
@@ -123,8 +122,8 @@ void TFlagSpinner::NextFrame()
control::handler(62, this);
}
auto bmp = ListBitmap->Get(BmpIndex);
auto zMap = ListZMap->Get(BmpIndex);
auto bmp = ListBitmap->at(BmpIndex);
auto zMap = ListZMap->at(BmpIndex);
render::sprite_set(
RenderSprite,
bmp,

View File

@@ -15,14 +15,14 @@ public:
static void SpinTimer(int timerId, void* caller);
float Speed;
float Speed{};
float MaxSpeed;
float MinSpeed;
float SpeedDecrement;
int SpinDirection;
int BmpIndex;
int SpinDirection{};
int BmpIndex{};
int Timer;
TEdgeSegment* PrevCollider;
int Scores[2];
int Scores[2]{};
};

View File

@@ -4,11 +4,11 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "pb.h"
#include "render.h"
#include "TFlipperEdge.h"
#include "timer.h"
#include "TPinballTable.h"
TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false)
{
@@ -51,8 +51,8 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
FlipperEdge = flipperEdge;
if (flipperEdge)
{
ExtendAnimationFrameTime = flipperEdge->ExtendTime / static_cast<float>(ListBitmap->GetCount() - 1);
RetractAnimationFrameTime = flipperEdge->RetractTime / static_cast<float>(ListBitmap->GetCount() - 1);
ExtendAnimationFrameTime = flipperEdge->ExtendTime / static_cast<float>(ListBitmap->size() - 1);
RetractAnimationFrameTime = flipperEdge->RetractTime / static_cast<float>(ListBitmap->size() - 1);
}
BmpIndex = 0;
InputTime = 0.0;
@@ -65,7 +65,7 @@ TFlipper::~TFlipper()
int TFlipper::Message(int code, float value)
{
if (code == 1 || code == 2 || code > 1008 && code <= 1011 || code == 1022)
if (code == 1 || code == 2 || (code > 1008 && code <= 1011) || code == 1022)
{
float timerTime;
int command = code;
@@ -135,7 +135,7 @@ void TFlipper::Collision(TBall* ball, vector_type* nextPosition, vector_type* di
void TFlipper::TimerExpired(int timerId, void* caller)
{
auto flip = static_cast<TFlipper*>(caller);
int bmpCountSub1 = flip->ListBitmap->GetCount() - 1;
int bmpCountSub1 = flip->ListBitmap->size() - 1;
auto newBmpIndex = static_cast<int>(floor((pb::time_now - flip->InputTime) / flip->TimerTime));
if (newBmpIndex > bmpCountSub1)
@@ -173,8 +173,8 @@ void TFlipper::TimerExpired(int timerId, void* caller)
flip->Timer = timer::set(flip->TimerTime, flip, TimerExpired);
}
auto bmp = flip->ListBitmap->Get(flip->BmpIndex);
auto zMap = flip->ListZMap->Get(flip->BmpIndex);
auto bmp = flip->ListBitmap->at(flip->BmpIndex);
auto zMap = flip->ListZMap->at(flip->BmpIndex);
render::sprite_set(
flip->RenderSprite,
bmp,

View File

@@ -19,8 +19,8 @@ public:
int BmpIndex;
TFlipperEdge* FlipperEdge;
int Timer;
float ExtendAnimationFrameTime;
float RetractAnimationFrameTime;
float TimerTime;
float ExtendAnimationFrameTime{};
float RetractAnimationFrameTime{};
float TimerTime{};
float InputTime;
};

View File

@@ -78,7 +78,7 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
auto distance1 = sqrt(dy * dy + dx * dx) + table->CollisionCompOffset + vecT1->Z;
DistanceDivSq = distance1 * distance1;
float minMoveTime = min(ExtendTime, RetractTime);
float minMoveTime = std::min(ExtendTime, RetractTime);
auto distance = maths::Distance(vecT1, vecT2);
CollisionTimeAdvance = minMoveTime / (distance / CircleT1Radius + distance / CircleT1Radius);
@@ -109,7 +109,6 @@ float TFlipperEdge::FindCollisionDistance(ray_type* ray)
{
if (FlipperFlag == 0)
{
EdgeCollisionFlag = 0;
CollisionFlag1 = 0;
CollisionFlag2 = 0;
set_control_points(ogRay->TimeNow);
@@ -428,7 +427,7 @@ float TFlipperEdge::flipper_angle(float timeNow)
else
angle = 1.0;
angle = min(1, max(angle, 0));
angle = std::min(1.0f, std::max(angle, 0.0f));
if (FlipperFlag == 2)
angle = 1.0f - angle;
return angle * AngleMax;
@@ -439,10 +438,10 @@ int TFlipperEdge::is_ball_inside(float x, float y)
vector_type testPoint{};
float dx = RotOrigin.X - x;
float dy = RotOrigin.Y - y;
if ((A2.X - A1.X) * (y - A1.Y) - (A2.Y - A1.Y) * (x - A1.X) >= 0.0f &&
if (((A2.X - A1.X) * (y - A1.Y) - (A2.Y - A1.Y) * (x - A1.X) >= 0.0f &&
(B1.X - A2.X) * (y - A2.Y) - (B1.Y - A2.Y) * (x - A2.X) >= 0.0f &&
(B2.X - B1.X) * (y - B1.Y) - (B2.Y - B1.Y) * (x - B1.X) >= 0.0f &&
(A1.X - B2.X) * (y - B2.Y) - (A1.Y - B2.Y) * (x - B2.X) >= 0.0f ||
(A1.X - B2.X) * (y - B2.Y) - (A1.Y - B2.Y) * (x - B2.X) >= 0.0f) ||
dy * dy + dx * dx <= CirclebaseRadiusSq ||
(T1.Y - y) * (T1.Y - y) + (T1.X - x) * (T1.X - x) < CircleT1RadiusSq)
{

View File

@@ -23,7 +23,7 @@ public:
int FlipperFlag;
float Elasticity;
float Smoothness;
vector_type RotOrigin;
vector_type RotOrigin{};
float CirclebaseRadius;
float CircleT1Radius;
float CirclebaseRadiusSq;
@@ -31,28 +31,28 @@ public:
float CirclebaseRadiusMSq;
float CircleT1RadiusMSq;
float AngleMax;
float Angle2;
float Angle2{};
float Angle1;
int CollisionFlag1;
int CollisionFlag2;
vector_type CollisionLinePerp;
vector_type A1Src;
vector_type A2Src;
vector_type B1Src;
vector_type B2Src;
int CollisionFlag2{};
vector_type CollisionLinePerp{};
vector_type A1Src{};
vector_type A2Src{};
vector_type B1Src{};
vector_type B2Src{};
float CollisionMult;
vector_type T1Src;
vector_type T2Src;
vector_type T1Src{};
vector_type T2Src{};
float DistanceDivSq;
float CollisionTimeAdvance;
vector_type CollisionDirection;
vector_type CollisionDirection{};
int EdgeCollisionFlag;
float InputTime;
float AngleStopTime;
float AngleMult;
float ExtendTime;
float RetractTime;
vector_type NextBallPosition;
vector_type NextBallPosition{};
static float flipper_sin_angle, flipper_cos_angle;
static vector_type A1, A2, B1, B2, T1;

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
TGate::TGate(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
@@ -15,7 +14,7 @@ TGate::TGate(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
SoundIndex4 = visual.SoundIndex4;
SoundIndex3 = visual.SoundIndex3;
ActiveFlag = 1;
render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0));
control::handler(1024, this);
}
@@ -32,7 +31,7 @@ int TGate::Message(int code, float value)
else if (code == 54 || code == 1024)
{
ActiveFlag = 1;
render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0));
if (code == 54)
loader::play_sound(SoundIndex4);
}

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "pb.h"
#include "TBall.h"
#include "timer.h"
@@ -37,7 +36,7 @@ THole::THole(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
if (tCircle)
{
tCircle->place_in_grid();
EdgeList->Add(tCircle);
EdgeList.push_back(tCircle);
}
ZSetValue = loader::query_float_attribute(groupIndex, 0, 408)[2];

View File

@@ -16,7 +16,7 @@ public:
static void TimerExpired(int timerId, void* caller);
int BallCapturedFlag;
int BallCapturedSecondStage;
int BallCapturedSecondStage{};
int Timer;
float Unknown3;
float Unknown4;
@@ -24,6 +24,6 @@ public:
float ZSetValue;
int FieldFlag;
float GravityPull;
circle_type Circle;
field_effect_type Field;
circle_type Circle{};
field_effect_type Field{};
};

View File

@@ -5,7 +5,6 @@
#include "control.h"
#include "loader.h"
#include "maths.h"
#include "objlist_class.h"
#include "render.h"
#include "timer.h"
#include "TPinballTable.h"
@@ -14,8 +13,8 @@ TKickback::TKickback(TPinballTable* table, int groupIndex): TCollisionComponent(
{
MessageField = 0;
Timer = 0;
ActiveFlag = 0;
TimerTime = 0.69999999f;
KickActiveFlag = 0;
TimerTime = 0.7f;
TimerTime2 = 0.1f;
Threshold = 1000000000.0f;
}
@@ -28,7 +27,7 @@ int TKickback::Message(int code, float value)
if (ListBitmap)
render::sprite_set_bitmap(RenderSprite, nullptr);
Timer = 0;
ActiveFlag = 0;
KickActiveFlag = 0;
Threshold = 1000000000.0;
}
return 0;
@@ -44,14 +43,14 @@ void TKickback::Collision(TBall* ball, vector_type* nextPosition, vector_type* d
}
else
{
if (!ActiveFlag)
if (!KickActiveFlag)
{
Threshold = 1000000000.0;
ActiveFlag = 1;
KickActiveFlag = 1;
Timer = timer::set(TimerTime, this, TimerExpired);
}
if (DefaultCollision(ball, nextPosition, direction))
ActiveFlag = 0;
KickActiveFlag = 0;
}
}
@@ -59,15 +58,15 @@ void TKickback::TimerExpired(int timerId, void* caller)
{
auto kick = static_cast<TKickback*>(caller);
if (kick->ActiveFlag)
if (kick->KickActiveFlag)
{
kick->Threshold = 0.0;
kick->Timer = timer::set(kick->TimerTime2, kick, TimerExpired);
loader::play_sound(kick->HardHitSoundId);
if (kick->ListBitmap)
{
auto bmp = kick->ListBitmap->Get(1);
auto zMap = kick->ListZMap->Get(1);
auto bmp = kick->ListBitmap->at(1);
auto zMap = kick->ListZMap->at(1);
render::sprite_set(
kick->RenderSprite,
bmp,
@@ -80,8 +79,8 @@ void TKickback::TimerExpired(int timerId, void* caller)
{
if (kick->ListBitmap)
{
auto bmp = kick->ListBitmap->Get(0);
auto zMap = kick->ListZMap->Get(0);
auto bmp = kick->ListBitmap->at(0);
auto zMap = kick->ListZMap->at(0);
render::sprite_set(
kick->RenderSprite,
bmp,

View File

@@ -15,5 +15,5 @@ public:
float TimerTime;
float TimerTime2;
int Timer;
int ActiveFlag;
int KickActiveFlag;
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "pb.h"
#include "TBall.h"
#include "TCircle.h"
@@ -41,7 +40,7 @@ TKickout::TKickout(TPinballTable* table, int groupIndex, bool someFlag): TCollis
if (tCircle)
{
tCircle->place_in_grid();
EdgeList->Add(tCircle);
EdgeList.push_back(tCircle);
}
Circle.RadiusSq = visual.FloatArr[2] * visual.FloatArr[2];

View File

@@ -24,14 +24,14 @@ public:
float TimerTime1;
float TimerTime2;
float CollisionBallSetZ;
TBall* Ball;
TBall* Ball{};
float FieldMult;
circle_type Circle;
float OriginalBallZ;
vector_type BallAcceleration;
circle_type Circle{};
float OriginalBallZ{};
vector_type BallAcceleration{};
float ThrowAngleMult;
float ThrowSpeedMult1;
float ThrowSpeedMult2;
field_effect_type Field;
int Scores[5];
field_effect_type Field{};
int Scores[5]{};
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "timer.h"
#include "TPinballTable.h"
@@ -143,14 +142,14 @@ int TLight::Message(int code, float value)
schedule_timeout(value);
break;
case 11:
BmpIndex2 = static_cast<int>(floor(value));
if (BmpIndex2 > ListBitmap->GetCount())
BmpIndex2 = ListBitmap->GetCount();
bmpIndex = 0;
BmpIndex2 = static_cast<int>(floor(value));
if (BmpIndex2 > static_cast<int>(ListBitmap->size()))
BmpIndex2 = ListBitmap->size();
if (BmpIndex2 < 0)
BmpIndex2 = 0;
Flasher.BmpArr[0] = nullptr;
Flasher.BmpArr[1] = ListBitmap->Get(BmpIndex2);
Flasher.BmpArr[1] = ListBitmap->at(BmpIndex2);
if (FlasherActive == 0)
{
if (!FlasherFlag1)
@@ -169,8 +168,8 @@ int TLight::Message(int code, float value)
break;
case 12:
bmpIndex = BmpIndex2 + 1;
if (bmpIndex > ListBitmap->GetCount())
bmpIndex = ListBitmap->GetCount();
if (bmpIndex > static_cast<int>(ListBitmap->size()))
bmpIndex = ListBitmap->size();
Message(11, static_cast<float>(bmpIndex));
break;
case 13:
@@ -257,7 +256,7 @@ void TLight::Reset()
Flasher.Sprite = RenderSprite;
Flasher.BmpArr[0] = nullptr;
if (ListBitmap)
Flasher.BmpArr[1] = ListBitmap->Get(0);
Flasher.BmpArr[1] = ListBitmap->at(0);
Flasher.Unknown4 = 0;
Flasher.Unknown3 = 0;
MessageField = 0;

View File

@@ -40,17 +40,16 @@ public:
static void flasher_start(struct flasher_type* flash, int bmpIndex);
static void flasher_callback(int timerId, void* caller);
flasher_type Flasher;
int BmpIndex1;
flasher_type Flasher{};
int BmpIndex1{};
int FlasherActive;
int FlasherFlag1;
int FlasherFlag2;
int TurnOffAfterFlashingFg;
int BmpIndex2;
float FlasherDelay[2];
int FlasherFlag1{};
int FlasherFlag2{};
int TurnOffAfterFlashingFg{};
int BmpIndex2{};
float FlasherDelay[2]{};
int Timer1;
int Timer2;
int Unknown19;
float Unknown20F;
TLight_player_backup PlayerData[4];
float Unknown20F{};
TLight_player_backup PlayerData[4]{};
};

View File

@@ -4,8 +4,6 @@
#include "control.h"
#include "loader.h"
#include "memory.h"
#include "objlist_class.h"
#include "timer.h"
#include "TPinballTable.h"
@@ -18,11 +16,11 @@ TLightBargraph::TLightBargraph(TPinballTable* table, int groupIndex) : TLightGro
float* floatArr = loader::query_float_attribute(groupIndex, 0, 904);
if (floatArr)
{
int count = 2 * List->GetCount();
TimerTimeArray = memory::allocate<float>(count);
auto count = 2 * List.size();
TimerTimeArray = new float[count];
if (TimerTimeArray)
{
for (int i = 0; i < count; ++floatArr)
for (auto i = 0u; i < count; ++floatArr)
TimerTimeArray[i++] = *floatArr;
}
}
@@ -31,8 +29,7 @@ TLightBargraph::TLightBargraph(TPinballTable* table, int groupIndex) : TLightGro
TLightBargraph::~TLightBargraph()
{
if (TimerTimeArray)
memory::free(TimerTimeArray);
delete[] TimerTimeArray;
}
int TLightBargraph::Message(int code, float value)
@@ -49,7 +46,7 @@ int TLightBargraph::Message(int code, float value)
TimerBargraph = 0;
}
auto timeIndex = static_cast<int>(floor(value));
auto maxCount = 2 * List->GetCount();
auto maxCount = static_cast<int>(List.size()) * 2;
if (timeIndex >= maxCount)
timeIndex = maxCount - 1;
if (timeIndex >= 0)

View File

@@ -13,7 +13,7 @@ public:
static void BargraphTimerExpired(int timerId, void* caller);
float* TimerTimeArray;
int TimerBargraph;
int TimeIndex;
int PlayerTimerIndexBackup[4];
int TimerBargraph{};
int TimeIndex{};
int PlayerTimerIndexBackup[4]{};
};

View File

@@ -4,17 +4,15 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "timer.h"
#include "TLight.h"
#include "TPinballTable.h"
TLightGroup::TLightGroup(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false)
{
List = new objlist_class<TLight>(4, 4);
Timer = 0;
NotifyTimer = 0;
Reset();
TLightGroup::Reset();
if (groupIndex > 0)
{
int count;
@@ -24,19 +22,15 @@ TLightGroup::TLightGroup(TPinballTable* table, int groupIndex) : TPinballCompone
{
auto comp = dynamic_cast<TLight*>(table->find_component(*groupIndArr));
if (comp)
List->Add(comp);
List.push_back(comp);
++index;
}
}
}
TLightGroup::~TLightGroup()
{
delete List;
}
int TLightGroup::Message(int code, float value)
{
auto const count = static_cast<int>(List.size());
switch (code)
{
case 1011:
@@ -71,8 +65,7 @@ int TLightGroup::Message(int code, float value)
break;
case 24:
{
auto count = List->GetCount();
auto lastLight = List->Get(count - 1);
auto lastLight = List.at(count - 1);
if (lastLight->FlasherActive || lastLight->FlasherFlag2 || lastLight->FlasherFlag1)
break;
if (MessageField2)
@@ -85,12 +78,12 @@ int TLightGroup::Message(int code, float value)
auto bmpIndex1 = lastLight->BmpIndex1;
for (auto index = count - 1; index > 0; --index)
{
auto lightCur = List->Get(index);
auto lightPrev = List->Get(index - 1);
auto lightCur = List.at(index);
auto lightPrev = List.at(index - 1);
lightCur->Message(lightPrev->BmpIndex1 != 0, 0.0);
lightCur->MessageField = lightPrev->MessageField;
}
auto firstLight = List->Get(0);
auto firstLight = List.at(0);
firstLight->Message(bmpIndex1 != 0, 0.0);
firstLight->MessageField = lightMessageField;
reschedule_animation(value);
@@ -98,23 +91,22 @@ int TLightGroup::Message(int code, float value)
}
case 25:
{
auto count = List->GetCount();
auto lastLight = List->Get(count - 1);
auto lastLight = List.at(count - 1);
if (lastLight->FlasherActive || lastLight->FlasherFlag2 || lastLight->FlasherFlag1)
break;
if (MessageField2)
{
TLightGroup::Message(34, 0.0);
}
auto firstLight = List->Get(0);
auto firstLight = List.at(0);
AnimationFlag = 1;
MessageField2 = code;
auto lightMessageField = firstLight->MessageField;
auto bmpIndex1 = firstLight->BmpIndex1;
for (auto index = 0; index < count - 1; index++)
{
auto lightCur = List->Get(index);
auto lightNext = List->Get(index + 1);
auto lightCur = List.at(index);
auto lightNext = List.at(index + 1);
lightCur->Message(lightNext->BmpIndex1 != 0, 0.0);
lightCur->MessageField = lightNext->MessageField;
}
@@ -129,16 +121,15 @@ int TLightGroup::Message(int code, float value)
start_animation();
MessageField2 = code;
AnimationFlag = 0;
auto count = List->GetCount();
auto lastLight = List->Get(count - 1);
auto lastLight = List.at(count - 1);
auto flasherFlag2 = lastLight->FlasherFlag2;
for (auto i = count - 1; i > 0; --i)
{
auto lightCur = List->Get(i);
auto lightPrev = List->Get(i - 1);
auto lightCur = List.at(i);
auto lightPrev = List.at(i - 1);
lightCur->Message((lightPrev->FlasherFlag2 != 0) + 8, 0.0);
}
auto firstLight = List->Get(0);
auto firstLight = List.at(0);
firstLight->Message((flasherFlag2 != 0) + 8, 0);
reschedule_animation(value);
break;
@@ -149,16 +140,15 @@ int TLightGroup::Message(int code, float value)
start_animation();
MessageField2 = code;
AnimationFlag = 0;
auto count = List->GetCount();
auto firstLight = List->Get(0);
auto firstLight = List.at(0);
auto flasherFlag2 = firstLight->FlasherFlag2;
for (auto i = 0; i < count - 1; i++)
{
auto lightCur = List->Get(i);
auto lightNext = List->Get(i + 1);
auto lightCur = List.at(i);
auto lightNext = List.at(i + 1);
lightCur->Message((lightNext->FlasherFlag2 != 0) + 8, 0.0);
}
auto lastLight = List->Get(count - 1);
auto lastLight = List.at(count - 1);
lastLight->Message((flasherFlag2 != 0) + 8, 0);
reschedule_animation(value);
break;
@@ -169,13 +159,11 @@ int TLightGroup::Message(int code, float value)
start_animation();
MessageField2 = code;
AnimationFlag = 0;
auto count = List->GetCount();
for (auto i = 0; i < count - 1; i++)
for (auto light : List)
{
if (rand() % 100 > 70)
{
auto light = List->Get(i);
auto randVal = static_cast<float>(rand()) * 0.00003051850947599719f * value * 3.0f + 0.1f;
auto randVal = RandFloat() * value * 3.0f + 0.1f;
light->Message(9, randVal);
}
}
@@ -188,10 +176,8 @@ int TLightGroup::Message(int code, float value)
start_animation();
MessageField2 = code;
AnimationFlag = 0;
auto count = List->GetCount();
for (auto i = 0; i < count - 1; i++)
for (auto light : List)
{
auto light = List->Get(i);
auto randVal = static_cast<float>(rand() % 100 > 70);
light->Message(18, randVal);
}
@@ -201,22 +187,18 @@ int TLightGroup::Message(int code, float value)
case 30:
{
auto noBmpInd1Count = 0;
auto countSub1 = List->GetCount() - 1;
if (countSub1 < 0)
break;
for (auto i = countSub1; i >= 0; i--)
for (auto light : List)
{
if (!List->Get(i)->BmpIndex1)
if (!light->BmpIndex1)
++noBmpInd1Count;
}
if (!noBmpInd1Count)
break;
auto randModCount = rand() % noBmpInd1Count;
for (auto i = countSub1; i >= 0; i--)
for (auto it = List.rbegin(); it != List.rend(); ++it)
{
auto light = List->Get(i);
auto light = *it;
if (!light->BmpIndex1 && randModCount-- == 0)
{
light->Message(1, 0.0);
@@ -231,22 +213,18 @@ int TLightGroup::Message(int code, float value)
case 31:
{
auto bmpInd1Count = 0;
auto countSub1 = List->GetCount() - 1;
if (countSub1 < 0)
break;
for (auto i = countSub1; i >= 0; i--)
for (auto light : List)
{
if (List->Get(i)->BmpIndex1)
if (light->BmpIndex1)
++bmpInd1Count;
}
if (!bmpInd1Count)
break;
auto randModCount = rand() % bmpInd1Count;
for (auto i = countSub1; i >= 0; i--)
for (auto it = List.rbegin(); it != List.rend(); ++it)
{
auto light = List->Get(i);
auto light = *it;
if (light->BmpIndex1 && randModCount-- == 0)
{
light->Message(0, 0.0);
@@ -263,7 +241,7 @@ int TLightGroup::Message(int code, float value)
auto index = next_light_up();
if (index < 0)
break;
List->Get(index)->Message(1, 0.0);
List.at(index)->Message(1, 0.0);
if (MessageField2)
start_animation();
return 1;
@@ -273,7 +251,7 @@ int TLightGroup::Message(int code, float value)
auto index = next_light_down();
if (index < 0)
break;
List->Get(index)->Message(0, 0.0);
List.at(index)->Message(0, 0.0);
if (MessageField2)
start_animation();
return 1;
@@ -292,10 +270,10 @@ int TLightGroup::Message(int code, float value)
case 35:
{
auto index = static_cast<int>(floor(value));
if (index >= List->GetCount() || index < 0)
if (index >= count || index < 0)
break;
auto light = List->Get(index);
auto light = List.at(index);
light->Message(1, 0.0);
if (MessageField2)
start_animation();
@@ -304,10 +282,10 @@ int TLightGroup::Message(int code, float value)
case 36:
{
auto index = static_cast<int>(floor(value));
if (index >= List->GetCount() || index < 0)
if (index >= count || index < 0)
break;
auto light = List->Get(index);
auto light = List.at(index);
light->Message(0, 0.0);
if (MessageField2)
start_animation();
@@ -316,16 +294,15 @@ int TLightGroup::Message(int code, float value)
case 37:
{
auto bmp1Count = 0;
auto countSub1 = List->GetCount() - 1;
for (auto i = countSub1; i >= 0; i--)
for (auto light : List)
{
if (List->Get(i)->BmpIndex1)
if (light->BmpIndex1)
++bmp1Count;
}
return bmp1Count;
}
case 38:
return List->GetCount();
return count;
case 39:
return MessageField2;
case 40:
@@ -337,7 +314,7 @@ int TLightGroup::Message(int code, float value)
break;
if (MessageField2 || AnimationFlag)
TLightGroup::Message(34, 0.0);
List->Get(index)->Message(15, value);
List.at(index)->Message(15, value);
return 1;
}
case 42:
@@ -347,7 +324,7 @@ int TLightGroup::Message(int code, float value)
break;
if (MessageField2 || AnimationFlag)
TLightGroup::Message(34, 0.0);
List->Get(index)->Message(16, value);
List.at(index)->Message(16, value);
return 1;
}
case 43:
@@ -359,10 +336,9 @@ int TLightGroup::Message(int code, float value)
break;
case 44:
{
auto countSub1 = List->GetCount() - 1;
for (auto index = countSub1; index >= 0; index--)
for (auto it = List.rbegin(); it != List.rend(); ++it)
{
auto light = List->Get(index);
auto light = *it;
if (light->BmpIndex1)
{
light->Message(0, 0.0);
@@ -374,7 +350,6 @@ int TLightGroup::Message(int code, float value)
}
case 45:
{
auto count = List->GetCount();
control::handler(code, this);
auto index = static_cast<int>(floor(value));
if (index >= 0 && index < count)
@@ -382,13 +357,13 @@ int TLightGroup::Message(int code, float value)
// Turn off lights (index, end]
for (auto i = count - 1; i > index; i--)
{
List->Get(i)->Message(20, 0.0);
List.at(i)->Message(20, 0.0);
}
// Turn on lights [begin, index]
for (auto i = index; i >= 0; i--)
{
List->Get(i)->Message(19, 0.0);
List.at(i)->Message(19, 0.0);
}
}
break;
@@ -398,14 +373,14 @@ int TLightGroup::Message(int code, float value)
auto index = next_light_down();
if (index >= 0)
{
List->Get(index)->Message(4, 0.0);
List.at(index)->Message(4, 0.0);
}
break;
}
default:
for (auto index = List->GetCount() - 1; index >= 0; index--)
for (auto it = List.rbegin(); it != List.rend(); ++it)
{
List->Get(index)->Message(code, value);
(*it)->Message(code, value);
}
break;
}
@@ -443,9 +418,9 @@ void TLightGroup::reschedule_animation(float time)
void TLightGroup::start_animation()
{
for (int index = List->GetCount() - 1; index >= 0; --index)
for (auto it = List.rbegin(); it != List.rend(); ++it)
{
auto light = List->Get(index);
auto light = *it;
if (light->BmpIndex1)
light->Message(9, 0.0);
else
@@ -455,19 +430,19 @@ void TLightGroup::start_animation()
int TLightGroup::next_light_up()
{
for (int index = 0; index < List->GetCount(); ++index)
for (auto index = 0u; index < List.size(); ++index)
{
if (!List->Get(index)->BmpIndex1)
return index;
if (!List[index]->BmpIndex1)
return static_cast<int>(index);
}
return -1;
}
int TLightGroup::next_light_down()
{
for (int index = List->GetCount() - 1; index >= 0; --index)
for (auto index = static_cast<int>(List.size()) - 1; index >= 0; --index)
{
if (List->Get(index)->BmpIndex1)
if (List.at(index)->BmpIndex1)
return index;
}
return -1;

View File

@@ -18,7 +18,7 @@ class TLightGroup :
{
public:
TLightGroup(TPinballTable* table, int groupIndex);
~TLightGroup() override;
~TLightGroup() override = default;
int Message(int code, float value) override;
virtual void Reset();
void reschedule_animation(float time);
@@ -29,12 +29,12 @@ public:
static void TimerExpired(int timerId, void* caller);
static void NotifyTimerExpired(int timerId, void* caller);
objlist_class<TLight>* List;
float Timer1Time;
std::vector<TLight*> List;
float Timer1Time{};
float Timer1TimeDefault;
int MessageField2;
int AnimationFlag;
int MessageField2{};
int AnimationFlag{};
int NotifyTimer;
int Timer;
TLightGroup_player_backup PlayerData[4];
TLightGroup_player_backup PlayerData[4]{};
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "TBall.h"
#include "timer.h"
@@ -58,7 +57,7 @@ void TLightRollover::Collision(TBall* ball, vector_type* nextPosition, vector_ty
control::handler(63, this);
RolloverFlag = RolloverFlag == 0;
if (ListBitmap)
render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0));
}
}
}

View File

@@ -6,7 +6,7 @@ class TLine :
public TEdgeSegment
{
public:
line_type Line;
line_type Line{};
float X0, Y0, X1, Y1;
TLine(TCollisionComponent* collCmp, char* activeFlag, unsigned int collisionGroup, float x0, float y0, float x1, float y1);
TLine(TCollisionComponent* collCmp, char* activeFlag, unsigned int collisionGroup, vector_type* start, vector_type* end);

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "TBall.h"
#include "TLine.h"
#include "TPinballTable.h"
@@ -27,7 +26,7 @@ TOneway::TOneway(TPinballTable* table, int groupIndex) : TCollisionComponent(tab
{
line->Offset(table->CollisionCompOffset);
line->place_in_grid();
EdgeList->Add(line);
EdgeList.push_back(line);
}
line = new TLine(this, &ActiveFlag, visual.CollisionGroup, &linePt1, &linePt2);
@@ -36,7 +35,7 @@ TOneway::TOneway(TPinballTable* table, int groupIndex) : TCollisionComponent(tab
{
line->Offset(-table->CollisionCompOffset * 0.8f);
Line->place_in_grid();
EdgeList->Add(Line);
EdgeList.push_back(Line);
}
}
}

View File

@@ -14,5 +14,5 @@ public:
int get_scoring(int index) override;
TLine* Line;
int Scores[6];
int Scores[6]{};
};

View File

@@ -1,7 +1,6 @@
#include "pch.h"
#include "TPinballComponent.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "TPinballTable.h"
@@ -19,7 +18,7 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool
GroupName = nullptr;
Control = nullptr;
if (table)
table->ComponentList->Add(this);
table->ComponentList.push_back(this);
if (groupIndex >= 0)
GroupName = loader::query_name(groupIndex);
if (loadVisuals && groupIndex >= 0)
@@ -31,45 +30,31 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool
if (visual.Bitmap)
{
if (!ListBitmap)
ListBitmap = new objlist_class<gdrv_bitmap8>(visualCount, 4);
ListBitmap = new std::vector<gdrv_bitmap8*>();
if (ListBitmap)
ListBitmap->Add(visual.Bitmap);
ListBitmap->push_back(visual.Bitmap);
}
if (visual.ZMap)
{
if (!ListZMap)
ListZMap = new objlist_class<zmap_header_type>(visualCount, 4);
ListZMap = new std::vector<zmap_header_type*>();
if (ListZMap)
ListZMap->Add(visual.ZMap);
}
}
zmap_header_type* zMap = nullptr;
if (ListZMap)
zMap = ListZMap->Get(0);
if (ListBitmap)
{
/* Full tilt hack - spliced bitmap includes zMap
* Users access bitmap-zMap in pairs, pad zMap list with 0 for such users
* zdrv does not access zMap when drawing spliced bitmap*/
if (!ListZMap)
{
ListZMap = new objlist_class<zmap_header_type>(0, 4);
for (int index = 0; index < ListBitmap->GetCount(); index++)
{
assertm(ListBitmap->Get(index)->BitmapType == BitmapType::Spliced, "Wrong zMap padding");
ListZMap->Add(visual.ZMap);
ListZMap->push_back(visual.ZMap);
}
}
auto zMap = ListZMap ? ListZMap->at(0) : nullptr;
if (ListBitmap)
{
rectangle_type bmp1Rect{}, tmpRect{};
auto rootBmp = ListBitmap->Get(0);
auto rootBmp = ListBitmap->at(0);
bmp1Rect.XPosition = rootBmp->XPosition - table->XOffset;
bmp1Rect.YPosition = rootBmp->YPosition - table->YOffset;
bmp1Rect.Width = rootBmp->Width;
bmp1Rect.Height = rootBmp->Height;
for (int index = 1; index < ListBitmap->GetCount(); index++)
for (auto index = 1u; index < ListBitmap->size(); index++)
{
auto bmp = ListBitmap->Get(index);
auto bmp = ListBitmap->at(index);
tmpRect.XPosition = bmp->XPosition - table->XOffset;
tmpRect.YPosition = bmp->YPosition - table->YOffset;
tmpRect.Width = bmp->Width;
@@ -78,7 +63,7 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool
}
RenderSprite = render::create_sprite(
visualCount > 0 ? VisualType::Sprite : VisualType::None,
visualCount > 0 ? VisualTypes::Sprite : VisualTypes::None,
rootBmp,
zMap,
rootBmp->XPosition - table->XOffset,
@@ -92,9 +77,14 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool
TPinballComponent::~TPinballComponent()
{
TPinballTable* table = PinballTable;
if (table)
table->ComponentList->Delete(this);
if (PinballTable)
{
// ComponentList contains one reference to each component.
auto& components = PinballTable->ComponentList;
auto position = std::find(components.begin(), components.end(), this);
if (position != components.end())
components.erase(position);
}
delete ListBitmap;
delete ListZMap;
@@ -121,13 +111,3 @@ int TPinballComponent::get_scoring(int index)
{
return 0;
}
void* TPinballComponent::operator new(size_t Size)
{
return calloc(1u, Size);
}
void TPinballComponent::operator delete(void* p)
{
free(p); /*Original does not have this*/
}

View File

@@ -1,5 +1,4 @@
#pragma once
#include "objlist_class.h"
struct zmap_header_type;
struct gdrv_bitmap8;
@@ -25,18 +24,14 @@ public:
virtual void put_scoring(int index, int score);
virtual int get_scoring(int index);
void* operator new(size_t Size);
void operator delete(void* p);
char UnusedBaseFlag;
char ActiveFlag;
int MessageField;
char* GroupName;
int Unknown4;
component_control* Control;
int GroupIndex;
render_sprite_type_struct* RenderSprite;
TPinballTable* PinballTable;
objlist_class<gdrv_bitmap8>* ListBitmap;
objlist_class<zmap_header_type>* ListZMap;
std::vector<gdrv_bitmap8*>* ListBitmap;
std::vector<zmap_header_type*>* ListZMap;
};

View File

@@ -4,12 +4,9 @@
#include "control.h"
#include "loader.h"
#include "memory.h"
#include "objlist_class.h"
#include "pb.h"
#include "pinball.h"
#include "render.h"
#include "Sound.h"
#include "TBall.h"
#include "TBlocker.h"
#include "TBumper.h"
@@ -48,8 +45,6 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false)
{
int shortArrLength;
ComponentList = new objlist_class<TPinballComponent>(32, 16);
BallList = new objlist_class<TBall>(3, 1);
CurScoreStruct = nullptr;
ScoreBallcount = nullptr;
ScorePlayerNumber1 = nullptr;
@@ -64,7 +59,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false)
PlayerCount = 0;
auto ballObj = new TBall(this);
BallList->Add(ballObj);
BallList.push_back(ballObj);
if (ballObj)
ballObj->ActiveFlag = 0;
new TTableLayer(this);
@@ -103,7 +98,7 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false)
Plunger = new TPlunger(this, groupIndex);
break;
case 1002:
LightGroup->List->Add(new TLight(this, groupIndex));
LightGroup->List.push_back(new TLight(this, groupIndex));
break;
case 1003:
FlipperL = new TFlipper(this, groupIndex);
@@ -198,63 +193,55 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false)
TPinballTable::~TPinballTable()
{
for (int scoreIndex = 0; scoreIndex < 4; scoreIndex++)
for (auto& PlayerScore : PlayerScores)
{
memory::free(PlayerScores[scoreIndex].ScoreStruct);
delete PlayerScore.ScoreStruct;
}
if (ScorePlayerNumber1)
{
memory::free(ScorePlayerNumber1);
delete ScorePlayerNumber1;
ScorePlayerNumber1 = nullptr;
}
if (ScoreBallcount)
{
memory::free(ScoreBallcount);
delete ScoreBallcount;
ScoreBallcount = nullptr;
}
delete LightGroup;
while (ComponentList->GetCount() > 0)
while (!ComponentList.empty())
{
delete ComponentList->Get(0);
// Component destructor removes it from the list.
delete ComponentList[0];
}
delete BallList;
delete ComponentList;
control::ClearLinks();
}
TPinballComponent* TPinballTable::find_component(LPCSTR componentName)
{
int objCount = ComponentList->GetCount();
if (objCount > 0)
for (auto component : ComponentList)
{
for (int index = 0; index < objCount; ++index)
const char* groupName = component->GroupName;
if (groupName && !strcmp(groupName, componentName))
{
TPinballComponent* obj = ComponentList->Get(index);
const CHAR* groupName = obj->GroupName;
if (groupName && !lstrcmpA(groupName, componentName))
{
return obj;
return component;
}
}
}
MessageBoxA(nullptr, "Table cant find:", componentName, 0x2000u);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Table cant find:", componentName, nullptr);
return nullptr;
}
TPinballComponent* TPinballTable::find_component(int groupIndex)
{
char Buffer[40]{};
int objCount = ComponentList->GetCount();
if (objCount > 0)
for (auto component : ComponentList)
{
for (int index = 0; index < objCount; ++index)
{
TPinballComponent* obj = ComponentList->Get(index);
if (obj->GroupIndex == groupIndex)
return obj;
if (component->GroupIndex == groupIndex)
return component;
}
}
_itoa_s(groupIndex, Buffer, 10);
MessageBoxA(nullptr, "Table cant find (lh):", Buffer, 0x2000u);
snprintf(Buffer, sizeof Buffer, "%d", groupIndex);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Table cant find (lh):", Buffer, nullptr);
return nullptr;
}
@@ -303,13 +290,13 @@ void TPinballTable::tilt(float time)
{
pinball::InfoTextBox->Clear();
pinball::MissTextBox->Clear();
pinball::InfoTextBox->Display(pinball::get_rc_Wstring(35, 0), -1.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(35, 0), -1.0);
loader::play_sound(SoundIndex3);
TiltTimeoutTimer = timer::set(30.0, this, tilt_timeout);
for (int i = 0; i < ComponentList->GetCount(); i++)
for (auto component : ComponentList)
{
ComponentList->Get(i)->Message(1011, time);
component->Message(1011, time);
}
LightGroup->Message(8, 0);
TiltLockFlag = 1;
@@ -320,15 +307,15 @@ void TPinballTable::tilt(float time)
void TPinballTable::port_draw()
{
for (int index = ComponentList->GetCount() - 1; index >= 0; index--)
for (auto component : ComponentList)
{
ComponentList->Get(index)->port_draw();
component->port_draw();
}
}
int TPinballTable::Message(int code, float value)
{
LPWSTR rc_text;
LPSTR rc_text;
switch (code)
{
case 1000:
@@ -362,9 +349,9 @@ int TPinballTable::Message(int code, float value)
case 1008:
case 1009:
case 1010:
for (int i = 0; i < ComponentList->GetCount(); i++)
for (auto component : ComponentList)
{
ComponentList->Get(i)->Message(code, value);
component->Message(code, value);
}
break;
case 1012:
@@ -381,10 +368,10 @@ int TPinballTable::Message(int code, float value)
LightGroup->Message(34, 0.0);
LightGroup->Message(20, 0.0);
Plunger->Message(1016, 0.0);
if (Demo->ActiveFlag)
rc_text = pinball::get_rc_Wstring(30, 0);
if (Demo && Demo->ActiveFlag)
rc_text = pinball::get_rc_string(30, 0);
else
rc_text = pinball::get_rc_Wstring(26, 0);
rc_text = pinball::get_rc_string(26, 0);
pinball::InfoTextBox->Display(rc_text, -1.0);
if (Demo)
Demo->Message(1014, 0.0);
@@ -406,7 +393,7 @@ int TPinballTable::Message(int code, float value)
{
CheatsUsed = 0;
Message(1024, 0.0);
auto ball = BallList->Get(0);
auto ball = BallList[0];
ball->Position.Y = 0.0;
ball->Position.X = 0.0;
ball->Position.Z = -0.8f;
@@ -443,25 +430,20 @@ int TPinballTable::Message(int code, float value)
}
BallCount = MaxBallCount;
Sound::Idle();
ChangeBallCount(BallCount);
score::set(ScorePlayerNumber1, CurrentPlayer + 1);
score::update(ScorePlayerNumber1);
Sound::Idle();
for (auto scoreIndex = 4 - PlayerCount; scoreIndex > 0; scoreIndex--)
{
score::set(PlayerScores[scoreIndex].ScoreStruct, -1);
}
Sound::Idle();
ScoreSpecial3Flag = 0;
ScoreSpecial2Flag = 0;
UnknownP71 = 0;
pinball::InfoTextBox->Clear();
Sound::Idle();
pinball::MissTextBox->Clear();
Sound::Idle();
LightGroup->Message(28, 0.2f);
auto time = loader::play_sound(SoundIndex1);
LightShowTimer = timer::set(time, this, LightShow_timeout);
@@ -477,11 +459,11 @@ int TPinballTable::Message(int code, float value)
{
if (PlayerCount <= 1)
{
wchar_t* textboxText;
char* textboxText;
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_Wstring(30, 0);
textboxText = pinball::get_rc_string(30, 0);
else
textboxText = pinball::get_rc_Wstring(26, 0);
textboxText = pinball::get_rc_string(26, 0);
pinball::InfoTextBox->Display(textboxText, -1.0);
break;
}
@@ -513,37 +495,37 @@ int TPinballTable::Message(int code, float value)
score::set(ScorePlayerNumber1, nextPlayer + 1);
score::update(ScorePlayerNumber1);
for (int i = 0; i < ComponentList->GetCount(); i++)
for (auto component : ComponentList)
{
ComponentList->Get(i)->Message(1020, static_cast<float>(nextPlayer));
component->Message(1020, static_cast<float>(nextPlayer));
}
wchar_t* textboxText = nullptr;
char* textboxText = nullptr;
switch (nextPlayer)
{
case 0:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_Wstring(30, 0);
textboxText = pinball::get_rc_string(30, 0);
else
textboxText = pinball::get_rc_Wstring(26, 0);
textboxText = pinball::get_rc_string(26, 0);
break;
case 1:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_Wstring(31, 0);
textboxText = pinball::get_rc_string(31, 0);
else
textboxText = pinball::get_rc_Wstring(27, 0);
textboxText = pinball::get_rc_string(27, 0);
break;
case 2:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_Wstring(32, 0);
textboxText = pinball::get_rc_string(32, 0);
else
textboxText = pinball::get_rc_Wstring(28, 0);
textboxText = pinball::get_rc_string(28, 0);
break;
case 3:
if (Demo->ActiveFlag)
textboxText = pinball::get_rc_Wstring(33, 0);
textboxText = pinball::get_rc_string(33, 0);
else
textboxText = pinball::get_rc_Wstring(29, 0);
textboxText = pinball::get_rc_string(29, 0);
break;
default:
break;
@@ -560,13 +542,13 @@ int TPinballTable::Message(int code, float value)
case 1022:
loader::play_sound(SoundIndex2);
pinball::MissTextBox->Clear();
pinball::InfoTextBox->Display(pinball::get_rc_Wstring(34, 0), -1.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(34, 0), -1.0);
EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout);
break;
case 1024:
for (int i = 0; i < ComponentList->GetCount(); i++)
for (auto component : ComponentList)
{
ComponentList->Get(i)->Message(1024, 0);
component->Message(1024, 0);
}
if (ReplayTimer)
timer::kill(ReplayTimer);
@@ -608,14 +590,14 @@ void TPinballTable::EndGame_timeout(int timerId, void* caller)
table->EndGameTimeoutTimer = 0;
pb::end_game();
for (int i = 0; i < table->ComponentList->GetCount(); i++)
for (auto component : table->ComponentList)
{
table->ComponentList->Get(i)->Message(1022, 0);
component->Message(1022, 0);
}
if (table->Demo)
table->Demo->Message(1022, 0.0);
control::handler(67, pinball::MissTextBox);
pinball::InfoTextBox->Display(pinball::get_rc_Wstring(24, 0), -1.0);
pinball::InfoTextBox->Display(pinball::get_rc_string(24, 0), -1.0);
}
void TPinballTable::LightShow_timeout(int timerId, void* caller)
@@ -640,9 +622,9 @@ void TPinballTable::tilt_timeout(int timerId, void* caller)
table->TiltTimeoutTimer = 0;
if (table->TiltLockFlag)
{
for (int i = 0; i < table->BallList->GetCount(); i++)
for (auto ball : table->BallList)
{
table->Drain->Collision(table->BallList->Get(i), &vec, &vec, 0.0, nullptr);
table->Drain->Collision(ball, &vec, &vec, 0.0, nullptr);
}
}
}

View File

@@ -45,54 +45,54 @@ public:
scoreStruct* CurScoreStruct;
scoreStruct* ScoreBallcount;
scoreStruct* ScorePlayerNumber1;
int CheatsUsed;
int SoundIndex1;
int SoundIndex2;
int SoundIndex3;
int CheatsUsed{};
int SoundIndex1{};
int SoundIndex2{};
int SoundIndex3{};
int BallInSink;
int CurScore;
int CurScoreE9;
int CurScore{};
int CurScoreE9{};
int LightShowTimer;
int EndGameTimeoutTimer;
int TiltTimeoutTimer;
score_struct_super PlayerScores[4];
score_struct_super PlayerScores[4]{};
int PlayerCount;
int CurrentPlayer;
TPlunger* Plunger;
TDrain* Drain;
TDemo* Demo;
int XOffset;
int YOffset;
int Width;
int Height;
objlist_class<TPinballComponent>* ComponentList;
objlist_class<TBall>* BallList;
TDemo* Demo{};
int XOffset{};
int YOffset{};
int Width{};
int Height{};
std::vector<TPinballComponent*> ComponentList;
std::vector<TBall*> BallList;
TLightGroup* LightGroup;
float GravityDirVectMult;
float GravityAngleX;
float GravityAnglY;
float CollisionCompOffset;
float PlungerPositionX;
float PlungerPositionY;
int ScoreMultiplier;
int ScoreAdded;
int ScoreSpecial1;
int ScoreSpecial2;
int ScoreSpecial2Flag;
int ScoreSpecial3;
int ScoreSpecial3Flag;
int UnknownP71;
int BallCount;
float GravityDirVectMult{};
float GravityAngleX{};
float GravityAnglY{};
float CollisionCompOffset{};
float PlungerPositionX{};
float PlungerPositionY{};
int ScoreMultiplier{};
int ScoreAdded{};
int ScoreSpecial1{};
int ScoreSpecial2{};
int ScoreSpecial2Flag{};
int ScoreSpecial3{};
int ScoreSpecial3Flag{};
int UnknownP71{};
int BallCount{};
int MaxBallCount;
int ExtraBalls;
int UnknownP75;
int BallLockedCounter;
int ExtraBalls{};
int UnknownP75{};
int BallLockedCounter{};
int MultiballFlag;
int UnknownP78;
int ReplayActiveFlag;
int UnknownP78{};
int ReplayActiveFlag{};
int ReplayTimer;
int UnknownP81;
int UnknownP82;
int UnknownP81{};
int UnknownP82{};
int TiltLockFlag;
private:

View File

@@ -5,7 +5,6 @@
#include "control.h"
#include "loader.h"
#include "maths.h"
#include "objlist_class.h"
#include "pb.h"
#include "render.h"
#include "TBall.h"
@@ -27,7 +26,7 @@ TPlunger::TPlunger(TPinballTable* table, int groupIndex) : TCollisionComponent(t
MaxPullback = 100;
Elasticity = 0.5f;
Smoothness = 0.5f;
PullbackIncrement = static_cast<int>(100.0 / (ListBitmap->GetCount() * 8.0));
PullbackIncrement = static_cast<int>(100.0 / (ListBitmap->size() * 8.0));
Unknown4F = 0.025f;
float* floatArr = loader::query_float_attribute(groupIndex, 0, 601);
table->PlungerPositionX = floatArr[0];
@@ -38,7 +37,7 @@ void TPlunger::Collision(TBall* ball, vector_type* nextPosition, vector_type* di
{
if (PinballTable->TiltLockFlag)
Message(1017, 0.0);
coef = static_cast<float>(rand()) * 0.00003051850947599719f * Boost * 0.1f + Boost;
coef = RandFloat() * Boost * 0.1f + Boost; // it is intended that the passed in coef is never used!
maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, Threshold, coef);
}
@@ -55,31 +54,9 @@ int TPlunger::Message(int code, float value)
PullbackTimer(0, this);
}
return 0;
case 1005:
case 1009:
case 1010:
{
Threshold = 0.0;
if (PullbackTimer_)
timer::kill(PullbackTimer_);
PullbackTimer_ = 0;
if (code == 1005)
loader::play_sound(SoundIndexP2);
auto bmp = ListBitmap->Get(0);
auto zMap = ListZMap->Get(0);
render::sprite_set(
RenderSprite,
bmp,
zMap,
bmp->XPosition - PinballTable->XOffset,
bmp->YPosition - PinballTable->YOffset);
timer::set(Unknown4F, this, PlungerReleasedTimer);
break;
}
case 1015:
{
auto ball = PinballTable->BallList->Get(0);
auto ball = PinballTable->BallList.at(0);
ball->Message(1024, 0.0);
ball->Position.X = PinballTable->PlungerPositionX;
ball->Position.Y = PinballTable->PlungerPositionY;
@@ -101,19 +78,26 @@ int TPlunger::Message(int code, float value)
Boost = static_cast<float>(MaxPullback);
timer::set(0.2f, this, PlungerReleasedTimer);
break;
case 1005:
case 1009:
case 1010:
case 1024:
{
if (code == 1024)
{
if (BallFeedTimer_)
timer::kill(BallFeedTimer_);
BallFeedTimer_ = 0;
}
Threshold = 0.0;
if (PullbackTimer_)
timer::kill(PullbackTimer_);
PullbackTimer_ = 0;
if (code == 1005)
loader::play_sound(SoundIndexP2);
auto bmp = ListBitmap->Get(0);
auto zMap = ListZMap->Get(0);
auto bmp = ListBitmap->at(0);
auto zMap = ListZMap->at(0);
render::sprite_set(
RenderSprite,
bmp,
@@ -151,10 +135,10 @@ void TPlunger::PullbackTimer(int timerId, void* caller)
plunger->Boost = static_cast<float>(plunger->MaxPullback);
}
int index = static_cast<int>(floor(
static_cast<float>(plunger->ListBitmap->GetCount() - 1) *
static_cast<float>(plunger->ListBitmap->size() - 1) *
(plunger->Boost / static_cast<float>(plunger->MaxPullback))));
auto bmp = plunger->ListBitmap->Get(index);
auto zMap = plunger->ListZMap->Get(index);
auto bmp = plunger->ListBitmap->at(index);
auto zMap = plunger->ListZMap->at(index);
render::sprite_set(
plunger->RenderSprite,
bmp,

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "timer.h"
#include "TPinballTable.h"
@@ -91,7 +90,7 @@ void TPopupTarget::TimerExpired(int timerId, void* caller)
auto target = static_cast<TPopupTarget*>(caller);
target->Timer = 0;
target->ActiveFlag = 1;
render::sprite_set_bitmap(target->RenderSprite, target->ListBitmap->Get(0));
render::sprite_set_bitmap(target->RenderSprite, target->ListBitmap->at(0));
if (timerId)
{
if (target->SoftHitSoundId)

View File

@@ -16,6 +16,6 @@ public:
int Timer;
float TimerTime;
int Scores[3];
int PlayerMessagefieldBackup[4];
int Scores[3]{};
int PlayerMessagefieldBackup[4]{};
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "TBall.h"
#include "TEdgeSegment.h"
#include "TLine.h"
@@ -35,7 +34,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
start.X = floatArr4[4];
start.Y = floatArr4[5];
Line1 = new TLine(this, &ActiveFlag, 1 << static_cast<int>(floor(floatArr4[0])), &start, &end);
EdgeList->Add(Line1);
EdgeList.push_back(Line1);
if (Line1)
{
Line1->WallValue = nullptr;
@@ -53,7 +52,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
&end2,
&start2);
Line2 = new TLine(this, &ActiveFlag, CollisionGroup, start2, end2);
EdgeList->Add(Line2);
EdgeList.push_back(Line2);
if (Line2)
{
Line2->WallValue = nullptr;
@@ -71,7 +70,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
&end3,
&start3);
Line3 = new TLine(this, &ActiveFlag, CollisionGroup, start3, end3);
EdgeList->Add(Line3);
EdgeList.push_back(Line3);
if (Line3)
{
Line3->WallValue = nullptr;
@@ -90,10 +89,10 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
auto pVec2 = reinterpret_cast<vector_type*>(&plane->V2);
auto pVec3 = reinterpret_cast<vector_type*>(&plane->V3);
xMin = min(min(min(plane->V3.X, plane->V1.X), plane->V2.X), xMin);
yMin = min(min(min(plane->V3.Y, plane->V1.Y), plane->V2.Y), xMin); // Sic
xMax = max(max(max(plane->V3.X, plane->V1.X), plane->V2.X), xMin);
yMax = max(max(max(plane->V3.Y, plane->V1.Y), plane->V2.Y), xMin);
xMin = std::min(std::min(std::min(plane->V3.X, plane->V1.X), plane->V2.X), xMin);
yMin = std::min(std::min(std::min(plane->V3.Y, plane->V1.Y), plane->V2.Y), xMin); // Sic
xMax = std::max(std::max(std::max(plane->V3.X, plane->V1.X), plane->V2.X), xMin);
yMax = std::max(std::max(std::max(plane->V3.Y, plane->V1.Y), plane->V2.Y), xMin);
vector_type* pointOrder[4] = {pVec1, pVec2, pVec3, pVec1};
for (auto pt = 0; pt < 3; pt++)
@@ -118,7 +117,7 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
if (collisionGroup)
{
auto line = new TLine(this, &ActiveFlag, collisionGroup, point1, point2);
EdgeList->Add(line);
EdgeList.push_back(line);
if (line)
{
line->WallValue = plane;

View File

@@ -17,8 +17,8 @@ public:
int FieldEffect(TBall* ball, vector_type* vecDst) override;
void port_draw() override;
int Scores[4];
field_effect_type Field;
int Scores[4]{};
field_effect_type Field{};
int CollisionGroup;
int RampFlag1;
int RampPlaneCount;

View File

@@ -5,7 +5,6 @@
#include "control.h"
#include "gdrv.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "TBall.h"
#include "TEdgeSegment.h"
@@ -20,9 +19,8 @@ TRollover::TRollover(TPinballTable* table, int groupIndex, bool createWall) : TC
TRollover::TRollover(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false)
{
RolloverFlag = 0;
if (ListBitmap)
render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0));
build_walls(groupIndex);
}
@@ -34,7 +32,7 @@ int TRollover::Message(int code, float value)
this->ActiveFlag = 1;
this->RolloverFlag = 0;
if (this->ListBitmap)
render::sprite_set_bitmap(this->RenderSprite, this->ListBitmap->Get(0));
render::sprite_set_bitmap(this->RenderSprite, this->ListBitmap->at(0));
}
return 0;
}
@@ -63,7 +61,7 @@ void TRollover::Collision(TBall* ball, vector_type* nextPosition, vector_type* d
if (ListBitmap)
{
if (!RolloverFlag)
bmp = ListBitmap->Get(0);
bmp = ListBitmap->at(0);
render::sprite_set_bitmap(RenderSprite, bmp);
}
}

View File

@@ -18,6 +18,6 @@ public:
static void TimerExpired(int timerId, void* caller);
char RolloverFlag;
int Scores[2];
char RolloverFlag{};
int Scores[2]{};
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "TPinballTable.h"
#include "TBall.h"
@@ -95,7 +94,7 @@ void TSink::Collision(TBall* ball, vector_type* nextPosition, vector_type* direc
void TSink::TimerExpired(int timerId, void* caller)
{
auto sink = static_cast<TSink*>(caller);
auto ball = sink->PinballTable->BallList->Get(0);
auto ball = sink->PinballTable->BallList.at(0);
ball->CollisionComp = nullptr;
ball->ActiveFlag = 1;
ball->Position.X = sink->BallPosition.X;

View File

@@ -17,13 +17,13 @@ public:
int Timer;
float TimerTime;
vector_type BallPosition;
vector_type BallAcceleration;
vector_type BallPosition{};
vector_type BallAcceleration{};
float ThrowAngleMult;
float ThrowSpeedMult1;
float ThrowSpeedMult2;
int SoundIndex4;
int SoundIndex3;
int Scores[3];
int PlayerMessagefieldBackup[4];
int Scores[3]{};
int PlayerMessagefieldBackup[4]{};
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "loader.h"
#include "objlist_class.h"
#include "render.h"
#include "timer.h"
#include "TPinballTable.h"
@@ -41,8 +40,8 @@ int TSoloTarget::Message(int code, float value)
if (ListBitmap)
{
auto index = 1 - ActiveFlag;
auto bmp = ListBitmap->Get(index);
auto zMap = ListZMap->Get(index);
auto bmp = ListBitmap->at(index);
auto zMap = ListZMap->at(index);
render::sprite_set(
RenderSprite,
bmp,

View File

@@ -14,9 +14,8 @@ public:
static void TimerExpired(int timerId, void* caller);
int Unknown0;
int Timer;
float TimerTime;
int SoundIndex4;
int Scores[1];
int Scores[1]{};
};

View File

@@ -4,7 +4,6 @@
#include "fullscrn.h"
#include "loader.h"
#include "objlist_class.h"
#include "pb.h"
#include "proj.h"
#include "render.h"
@@ -33,7 +32,7 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f
rect.YPosition = 0;
rect.Width = bmp->Width;
rect.Height = bmp->Height;
render::create_sprite(VisualType::None, bmp, visual.ZMap, 0, 0, &rect);
render::create_sprite(VisualTypes::None, bmp, visual.ZMap, 0, 0, &rect);
PinballTable->SoundIndex1 = visual.SoundIndex4;
PinballTable->SoundIndex2 = visual.SoundIndex3;
@@ -71,10 +70,10 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f
Boost = 15.0f;
auto visArrPtr = visual.FloatArr;
Unknown1F = min(visArrPtr[0], min(visArrPtr[2], visArrPtr[4]));
Unknown2F = min(visArrPtr[1], min(visArrPtr[3], visArrPtr[5]));
Unknown3F = max(visArrPtr[0], max(visArrPtr[2], visArrPtr[4]));
Unknown4F = max(visArrPtr[1], max(visArrPtr[3], visArrPtr[5]));
Unknown1F = std::min(visArrPtr[0], std::min(visArrPtr[2], visArrPtr[4]));
Unknown2F = std::min(visArrPtr[1], std::min(visArrPtr[3], visArrPtr[5]));
Unknown3F = std::max(visArrPtr[0], std::max(visArrPtr[2], visArrPtr[4]));
Unknown4F = std::max(visArrPtr[1], std::max(visArrPtr[3], visArrPtr[5]));
auto a2 = Unknown4F - Unknown2F;
auto a1 = Unknown3F - Unknown1F;
edge_manager = new TEdgeManager(Unknown1F, Unknown2F, a1, a2);
@@ -91,7 +90,7 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f
if (line)
{
line->place_in_grid();
EdgeList->Add(line);
EdgeList.push_back(line);
}
visArrPtr += 2;
@@ -112,7 +111,7 @@ TTableLayer::~TTableLayer()
int TTableLayer::FieldEffect(TBall* ball, vector_type* vecDst)
{
vecDst->X = GraityDirX - (0.5f - static_cast<float>(rand()) * 0.00003051850947599719f + ball->Acceleration.X) *
vecDst->X = GraityDirX - (0.5f - RandFloat() + ball->Acceleration.X) *
ball->Speed * GraityMult;
vecDst->Y = GraityDirY - ball->Acceleration.Y * ball->Speed * GraityMult;
return 1;

View File

@@ -27,9 +27,8 @@ public:
float Unknown4F;
float GraityDirX;
float GraityDirY;
int Unknown7;
float GraityMult;
field_effect_type Field;
field_effect_type Field{};
static TEdgeManager* edge_manager;
};

View File

@@ -4,7 +4,6 @@
#include "control.h"
#include "fullscrn.h"
#include "loader.h"
#include "pb.h"
#include "render.h"
#include "score.h"
#include "timer.h"
@@ -76,7 +75,7 @@ void TTextBox::Clear()
gdrv_bitmap8* bmp = BgBmp;
if (bmp)
gdrv::copy_bitmap(
&render::vscreen,
render::vscreen,
Width,
Height,
OffsetX,
@@ -85,15 +84,7 @@ void TTextBox::Clear()
OffsetX,
OffsetY);
else
gdrv::fill_bitmap(&render::vscreen, Width, Height, OffsetX, OffsetY, 0);
gdrv::blit(
&render::vscreen,
OffsetX,
OffsetY,
OffsetX + render::vscreen.XPosition,
OffsetY + render::vscreen.YPosition,
Width,
Height);
gdrv::fill_bitmap(render::vscreen, Width, Height, OffsetX, OffsetY, 0);
if (Timer)
{
if (Timer != -1)
@@ -109,12 +100,12 @@ void TTextBox::Clear()
}
}
void TTextBox::Display(const wchar_t* text, float time)
void TTextBox::Display(const char* text, float time)
{
if (!text)
return;
if (Message1 && !lstrcmpW(text, Message2->Text))
if (Message1 && !strcmp(text, Message2->Text))
{
Message2->Refresh(time);
if (Message2 == Message1)
@@ -153,12 +144,12 @@ void TTextBox::Display(const wchar_t* text, float time)
}
}
void TTextBox::Draw(bool redraw)
void TTextBox::Draw()
{
auto bmp = BgBmp;
if (bmp)
gdrv::copy_bitmap(
&render::vscreen,
render::vscreen,
Width,
Height,
OffsetX,
@@ -167,17 +158,11 @@ void TTextBox::Draw(bool redraw)
OffsetX,
OffsetY);
else
gdrv::fill_bitmap(&render::vscreen, Width, Height, OffsetX, OffsetY, 0);
gdrv::fill_bitmap(render::vscreen, Width, Height, OffsetX, OffsetY, 0);
bool display = false;
while (Message1)
{
if (redraw)
{
display = true;
break;
}
if (Message1->Time == -1.0f)
{
if (!Message1->NextMessage)
@@ -189,9 +174,7 @@ void TTextBox::Draw(bool redraw)
}
else if (Message1->TimeLeft() >= -2.0f)
{
if (Timer > 0)
timer::kill(Timer);
Timer = timer::set(max(Message1->TimeLeft(), 0.25f), this, TimerExpired);
Timer = timer::set(std::max(Message1->TimeLeft(), 0.25f), this, TimerExpired);
display = true;
break;
}
@@ -206,20 +189,13 @@ void TTextBox::Draw(bool redraw)
auto font = Font;
if (!font)
{
gdrv::blit(
&render::vscreen,
OffsetX,
OffsetY,
OffsetX + render::vscreen.XPosition,
OffsetY + render::vscreen.YPosition,
Width,
Height);
gdrv::grtext_draw_ttext_in_box(
Message1->Text,
render::vscreen.XPosition + OffsetX,
render::vscreen.YPosition + OffsetY,
render::vscreen->XPosition + OffsetX,
render::vscreen->YPosition + OffsetY,
Width,
Height);
Height,
255);
return;
}
@@ -231,7 +207,7 @@ void TTextBox::Draw(bool redraw)
break;
auto totalWidth = 0;
wchar_t* textEndSpace = nullptr;
char* textEndSpace = nullptr;
auto textEnd = text;
while (true)
{
@@ -269,10 +245,10 @@ void TTextBox::Draw(bool redraw)
auto height = charBmp->Height;
auto width = charBmp->Width;
if (render::background_bitmap)
gdrv::copy_bitmap_w_transparency(&render::vscreen, width, height, offX, y, charBmp, 0,
gdrv::copy_bitmap_w_transparency(render::vscreen, width, height, offX, y, charBmp, 0,
0);
else
gdrv::copy_bitmap(&render::vscreen, width, height, offX, y, charBmp, 0, 0);
gdrv::copy_bitmap(render::vscreen, width, height, offX, y, charBmp, 0, 0);
font = Font;
offX += charBmp->Width + font->GapWidth;
}
@@ -283,13 +259,4 @@ void TTextBox::Draw(bool redraw)
++text;
}
}
gdrv::blit(
&render::vscreen,
OffsetX,
OffsetY,
OffsetX + render::vscreen.XPosition,
OffsetY + render::vscreen.YPosition,
Width,
Height);
}

View File

@@ -21,8 +21,8 @@ public:
~TTextBox() override;
int Message(int code, float value) override;
void Clear();
void Display(const wchar_t* text, float time);
void Draw(bool redraw = false);
void Display(const char* text, float time);
void Draw();
static void TimerExpired(int timerId, void* tb);
};

View File

@@ -1,19 +1,18 @@
#include "pch.h"
#include "TTextBoxMessage.h"
#include "memory.h"
#include "pb.h"
TTextBoxMessage::TTextBoxMessage(const wchar_t* text, float time)
TTextBoxMessage::TTextBoxMessage(const char* text, float time)
{
NextMessage = nullptr;
Time = time;
EndTicks = pb::time_ticks + static_cast<int>(time * 1000.0f);
if (text)
{
const auto textLen = lstrlenW(text) + 1;
Text = memory::allocate<wchar_t>(textLen);
const auto textLen = strlen(text) + 1;
Text = new char[textLen];
if (Text)
lstrcpynW(Text, text, textLen);
strncpy(Text, text, textLen);
}
else
Text = nullptr;
@@ -21,8 +20,7 @@ TTextBoxMessage::TTextBoxMessage(const wchar_t* text, float time)
TTextBoxMessage::~TTextBoxMessage()
{
if (Text)
memory::free(Text);
delete[] Text;
}
float TTextBoxMessage::TimeLeft() const

View File

@@ -3,11 +3,11 @@ class TTextBoxMessage
{
public:
TTextBoxMessage* NextMessage;
wchar_t* Text;
char* Text;
float Time;
int EndTicks;
TTextBoxMessage(const wchar_t* text, float time);
TTextBoxMessage(const char* text, float time);
~TTextBoxMessage();
float TimeLeft() const;
void Refresh(float time);

View File

@@ -6,7 +6,7 @@
#include "TBall.h"
#include "TPinballTable.h"
TTripwire::TTripwire(TPinballTable* table, int groupIndex) : TRollover(table, groupIndex, 1)
TTripwire::TTripwire(TPinballTable* table, int groupIndex) : TRollover(table, groupIndex, true)
{
}

View File

@@ -3,7 +3,6 @@
#include "control.h"
#include "objlist_class.h"
#include "render.h"
#include "timer.h"
@@ -12,8 +11,7 @@ TWall::TWall(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
if (RenderSprite)
render::sprite_set_bitmap(RenderSprite, nullptr);
if (ListBitmap)
BmpPtr = ListBitmap->Get(0);
Timer = 0;
BmpPtr = ListBitmap->at(0);
}
int TWall::Message(int code, float value)

View File

@@ -17,7 +17,7 @@ public:
static void TimerExpired(int timerId, void* caller);
int Timer;
gdrv_bitmap8* BmpPtr;
int Scores[1];
int Timer{};
gdrv_bitmap8* BmpPtr{};
int Scores[1]{};
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,244 +0,0 @@
#pragma once
/* flag values for play params */
#define WMIX_QUEUEWAVE 0x00
#define WMIX_CLEARQUEUE 0x01
#define WMIX_USELRUCHANNEL 0x02
#define WMIX_HIPRIORITY 0x04
#define WMIX_WAIT 0x08
#define WMIX_CustomVolume 0x10
#define MAXCHANNELS 16
#define MAXQUEUEDWAVES 100
struct GLOBALS;
struct volume_struct
{
uint16_t L;
uint16_t R;
};
struct MIXWAVE
{
PCMWAVEFORMAT pcm;
WAVEHDR wh;
char szWaveFilename[16];
short wMagic;
};
struct MIXPLAYPARAMS
{
WORD wSize;
HANDLE hMixSession;
int iChannel;
MIXWAVE* lpMixWave;
HWND hWndNotify;
DWORD dwFlags;
WORD wLoops;
volume_struct Volume;
};
struct CHANNELNODE
{
CHANNELNODE* next;
MIXPLAYPARAMS PlayParams;
MIXWAVE* lpMixWave;
DWORD dwNumSamples;
DWORD dwStartPos;
DWORD dwEndPos;
unsigned char* lpPos;
unsigned char* lpEnd;
volume_struct Volume;
};
struct MIXCONFIG
{
WORD wSize;
DWORD dwFlags;
WORD wChannels;
WORD wSamplingRate;
uint16_t WaveBlockCount;
uint16_t WaveBlockLen;
int16_t CmixPtrDefaultFlag;
uint16_t ResetMixDefaultFlag;
uint16_t GoodWavePos;
uint16_t wDeviceID;
uint16_t PauseBlocks;
int16_t ShowDebugDialogs;
HKEY RegistryKey;
};
struct XWAVEHDR
{
WAVEHDR wh;
BOOL fAvailable;
DWORD dwWavePos;
GLOBALS* g;
struct XWAVEHDR* QNext;
};
struct PLAYQUEUE
{
XWAVEHDR* first;
XWAVEHDR* last;
};
struct GLOBALS
{
WORD wMagic1;
int16_t unknown0;
HWND hWndApp;
int unknown2;
HWAVEOUT hWaveOut;
int fActive;
int SettingsDialogActiveFlag;
unsigned int wDeviceID;
char szDevicePName[96];
WAVEOUTCAPSA WaveoutCaps;
volume_struct DefaultVolume;
volume_struct ChannelVolume[MAXCHANNELS];
CHANNELNODE* aChannel[MAXCHANNELS];
int iChannels;
DWORD MRUChannel[MAXCHANNELS];
DWORD dwMRU;
PCMWAVEFORMAT PCM;
DWORD dwWaveBlockLen;
int WaveBlockCount;
int PauseBlocks;
XWAVEHDR** WaveBlockArray;
DWORD dwCurrentSample;
DWORD dwBaseTime;
int fGoodGetPos;
DWORD dwWaveOutPos;
void (*CmixPtr)(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volume, int iNumWaves,
uint16_t length);
int (* pfnRemix)(DWORD, CHANNELNODE*);
DWORD (* pfnSampleAdjust)(DWORD, DWORD);
CHANNELNODE* pWaitList;
int16_t wMagic2;
int16_t unknown112;
};
struct dialog_template
{
DLGTEMPLATE Dialog;
WORD menu;
WORD windowClass;
WCHAR Header[1];
};
struct dialog_item_template
{
DLGITEMTEMPLATE Item;
WORD sysClass;
WORD idClass;
WCHAR Header[1];
};
class WaveMix
{
public:
static HANDLE Init();
static HANDLE ConfigureInit(MIXCONFIG* lpConfig);
static int CloseSession(HANDLE hMixSession);
static int OpenChannel(HANDLE hMixSession, int iChannel, unsigned int dwFlags);
static int CloseChannel(HANDLE hMixSession, int iChannel, unsigned int dwFlags);
static int FlushChannel(HANDLE hMixSession, int iChannel, unsigned int dwFlags);
static MIXWAVE* OpenWave(HANDLE hMixSession, LPCSTR szWaveFilename, HINSTANCE hInst, unsigned int dwFlags);
static int FreeWave(HANDLE hMixSession, MIXWAVE* lpMixWave);
static int Activate(HANDLE hMixSession, bool fActivate);
static void Pump();
static int Play(MIXPLAYPARAMS* lpMixPlayParams);
private:
static GLOBALS* SessionToGlobalDataPtr(HANDLE hMixSession);
static int Startup(HMODULE hModule);
static int SetIniFileName(HMODULE hModule);
static void InitChannelNodes();
static void InitVolumeTable();
static void ShowWaveOutDevices();
static int RemoveInvalidIniNameCharacters(char* lpString);
static int ReadConfigSettings(MIXCONFIG* lpConfig);
static int ReadRegistryForAppSpecificConfigs(MIXCONFIG* lpConfig);
static int ReadRegistryInt(HKEY hKey, LPCSTR lpSubKey, int defaultValue);
static int DefaultGoodWavePos(unsigned int uDeviceID);
static int DefaultPauseBlocks(int waveBlocks);
static int Configure(GLOBALS* hMixSession, HWND hWndParent, MIXCONFIG* lpConfig, int* flag1Ptr, int saveConfigFlag);
static int GetConfig(HANDLE hMixSession, MIXCONFIG* lpConfig);
static unsigned MyWaveOutGetPosition(HWAVEOUT hWaveOut, int fGoodGetPos);
static void FreeChannelNode(CHANNELNODE* channel);
static int ResetRemix(DWORD dwRemixSamplePos, CHANNELNODE* channel);
static XWAVEHDR* RemoveFromPlayingQueue(XWAVEHDR* lpXWH);
static void DestroyPlayQueue();
static void SwapWaveBlocks();
static XWAVEHDR* GetWaveBlock();
static int MixerPlay(XWAVEHDR* lpXWH, int fWriteBlocks);
static XWAVEHDR* AddToPlayingQueue(XWAVEHDR* lpXWH);
static void MyWaveOutReset(HWAVEOUT hWaveOut);
static void SetWaveOutPosition(unsigned int newPosition);
static DWORD SubFactor(DWORD a1, DWORD a2);
static DWORD AddFactor(DWORD a1, DWORD a2);
static dialog_template* MakeSettingsDlgTemplate();
static dialog_template* MakeDlgTemplate(size_t* totalSize, unsigned style, int16_t x, int16_t y, int16_t cx,
int16_t cy,
const wchar_t* String);
static dialog_template* AddDlgControl(size_t* totalSize, dialog_template* dlgTemplate, int16_t idClass,
unsigned style,
WORD id, int16_t x, int16_t y, int16_t cx, int16_t cy,
const wchar_t* String);
static void DestroySettingsDlgTemplate(LPCVOID pMem);
static int Settings_OnInitDialog(HWND hWnd, WPARAM wParam, MIXCONFIG* lpMixconfig);
static int Settings_OnCommand(HWND hWnd, int command, LPARAM lParam, int wParam);
static int ReadRegistryToGetMachineSpecificInfSection(unsigned wDeviceId, LPSTR lpString1, int maxLength);
static const char* GetOperatingSystemPrefix();
static unsigned int FigureOutDMABufferSize(unsigned int waveBlockLen, PCMWAVEFORMAT* pcm);
static int NoResetRemix(DWORD dwRemixSamplePos, CHANNELNODE* channel);
static void SaveConfigSettings(unsigned dwFlags);
static void ShowCurrentSettings();
static unsigned int GetWaveDevice();
static void FreeWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks);
static int AllocWaveBlocks(HWAVEOUT hwo, XWAVEHDR** waveBlocks);
static void ReleaseWaveDevice(GLOBALS* globals);
static HPSTR WaveFormatConvert(PCMWAVEFORMAT* lpOutWF, PCMWAVEFORMAT* lpInWF, HPSTR lpInData, DWORD* dwDataSize);
static HPSTR BitsPerSampleAlign(HPSTR lpInData, WORD nInBPS, WORD nOutBPS, DWORD* dwDataSize);
static HPSTR ChannelAlign(HPSTR lpInData, WORD nInChannels, WORD nOutChannels, WORD nBytesPerSample,
DWORD* dwDataSize);
static HPSTR SamplesPerSecAlign(HPSTR lpInData, DWORD nInSamplesPerSec, DWORD nOutSamplesPerSec,
WORD nBytesPerSample, WORD nChannels, DWORD* dwDataSize);
static void AvgSample(HPSTR lpOutData, HPSTR lpInData, unsigned nSkip, int nBytesPerSample, int nChannels);
static void RepSample(HPSTR lpOutData, HPSTR lpInData, unsigned nRep, int nBytesPerSample, int nChannels);
static bool IsValidLPMIXWAVE(MIXWAVE* lpMixWave);
static void FreePlayedBlocks();
static int HasCurrentOutputFormat(MIXWAVE* lpMixWave);
static CHANNELNODE* GetChannelNode();
static void ResetWavePosIfNoChannelData();
static void cmixit(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volumeArr, int iNumWaves,
uint16_t length);
static LRESULT __stdcall WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
static INT_PTR __stdcall SettingsDlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
static int initialized_flag;
static char FileName[276];
static CHANNELNODE channel_nodes[MAXQUEUEDWAVES];
static CHANNELNODE* free_channel_nodes;
static unsigned char volume_table[11][256];
static int debug_flag;
static void (*cmixit_ptr)(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volume,
int iNumWaves, uint16_t length);
static HMODULE HModule;
static GLOBALS *Globals, *GlobalsActive;
static PCMWAVEFORMAT gpFormat;
static int ShowDebugDialogs;
static char string_buffer[256];
static PLAYQUEUE play_queue;
static CHANNELNODE* play_channel_array[MAXCHANNELS];
static XWAVEHDR* block_array1[10];
static XWAVEHDR* block_array2[10];
static unsigned char* play_data[MAXCHANNELS];
static volume_struct play_volume[MAXCHANNELS];
static int play_counter;
};

File diff suppressed because it is too large Load Diff

View File

@@ -71,6 +71,7 @@ public:
static component_tag_base *wormhole_tag_array1[3], *wormhole_tag_array2[3], *wormhole_tag_array3[3];
static void make_links(TPinballTable* table);
static void ClearLinks();
static TPinballComponent* make_component_link(component_tag_base* tag);
static void handler(int code, TPinballComponent* cmp);
static void pbctrl_bdoor_controller(char key);

View File

@@ -9,17 +9,9 @@
int fullscrn::screen_mode;
HWND fullscrn::hWnd;
tagRECT fullscrn::WindowRect1, fullscrn::WindowRect2;
rectangle_type fullscrn::WHRect;
int fullscrn::fullscrn_flag1;
int fullscrn::display_changed;
int fullscrn::ChangeDisplay, fullscrn::ignoreNextDisplayChangeFg;
int fullscrn::trick = 1;
int fullscrn::MenuEnabled;
HMENU fullscrn::MenuHandle;
int fullscrn::resolution = 0;
int fullscrn::maxResolution = 0;
const resolution_info fullscrn::resolution_array[3] =
{
{640, 480, 600, 416, 501},
@@ -31,42 +23,9 @@ float fullscrn::ScaleY = 1;
int fullscrn::OffsetX = 0;
int fullscrn::OffsetY = 0;
void fullscrn::init(int width, int height, int isFullscreen, HWND winHandle, HMENU menuHandle, int changeDisplay)
void fullscrn::init()
{
WHRect.XPosition = 0;
WHRect.YPosition = 0;
ChangeDisplay = changeDisplay;
hWnd = winHandle;
MenuHandle = menuHandle;
WHRect.Width = width;
WHRect.Height = height;
GetWindowRect(GetDesktopWindow(), &fullscrn::WindowRect1);
int widht2 = width + 2 * GetSystemMetrics(SM_CXBORDER);
int height2 = height + 2 * GetSystemMetrics(SM_CYBORDER);
int menuHeight = GetSystemMetrics(SM_CYMENU);
int captionHeight = GetSystemMetrics(SM_CYCAPTION);
int borderHeight = WindowRect1.bottom - WindowRect1.top - height2;
WindowRect2.bottom = borderHeight / 2 - 2 + height2 + 4;
WindowRect2.right = (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2 + widht2 + 4;
WindowRect2.left = (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2;
WindowRect2.top = borderHeight / 2 - (captionHeight + menuHeight) - 2;
/*RECT client{0,0,width,height};
AdjustWindowRect(&client, winmain::WndStyle, true);*/
MoveWindow(
hWnd,
(WindowRect1.right - WindowRect1.left - widht2) / 2 - 2,
WindowRect2.top,
WindowRect2.right - WindowRect2.left + 10,
WindowRect2.bottom - WindowRect2.top + 10,
0);
// Todo: WH + 10 hack: original request 640x480 window but somehow receives 650x490, even thought spyxx says it is 640x480
fullscrn_flag1 = 0;
window_size_changed();
assertm(ScaleX == 1 && ScaleY == 1, "Wrong default client size");
}
void fullscrn::shutdown()
@@ -83,72 +42,27 @@ int fullscrn::set_screen_mode(int isFullscreen)
screen_mode = isFullscreen;
if (isFullscreen)
{
if (IsWindowVisible(hWnd))
GetWindowRect(hWnd, &WindowRect2);
enableFullscreen();
BYTE1(fullscrn_flag1) |= 0x80u;
InvalidateRect(hWnd, nullptr, 1);
set_menu_mode(0);
result = disableWindowFlagsDisDlg();
result = 1;
}
else
{
disableFullscreen();
BYTE1(fullscrn_flag1) |= 0x80u;
InvalidateRect(hWnd, nullptr, 1);
set_menu_mode(1);
result = RedrawWindow(nullptr, nullptr, nullptr, 0x185u);
result = 1;
}
return result;
}
int fullscrn::disableWindowFlagsDisDlg()
{
long style = GetWindowLongA(hWnd, -16);
return SetWindowLongA(hWnd, -16, style & ~(WS_CAPTION | WS_THICKFRAME));
}
int fullscrn::setWindowFlagsDisDlg()
{
int style = GetWindowLongA(hWnd, -16);
return SetWindowLongA(hWnd, -16, style | WS_CAPTION | WS_THICKFRAME);
}
int fullscrn::enableFullscreen()
{
tagRECT Rect{};
DEVMODEA DevMode{};
if (ChangeDisplay && !display_changed)
if (!display_changed)
{
DevMode.dmSize = sizeof DevMode;
DevMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
DevMode.dmPelsWidth = resolution_array[resolution].ScreenWidth;
DevMode.dmPelsHeight = resolution_array[resolution].ScreenHeight;
DevMode.dmBitsPerPel = 32;
disableWindowFlagsDisDlg();
if (trick)
if (SDL_SetWindowFullscreen(winmain::MainWindow, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0)
{
GetWindowRect(GetDesktopWindow(), &Rect);
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, Rect.right - Rect.left + 1,
Rect.bottom - Rect.top + 1, SWP_NOREDRAW);
}
ignoreNextDisplayChangeFg = 1;
LONG changeDispResult = ChangeDisplaySettingsA(&DevMode, CDS_FULLSCREEN);
if (changeDispResult == DISP_CHANGE_RESTART)
{
DevMode.dmFields &= ~DM_BITSPERPEL;
ignoreNextDisplayChangeFg = 1;
changeDispResult = ChangeDisplaySettingsA(&DevMode, CDS_FULLSCREEN);
}
display_changed = changeDispResult == DISP_CHANGE_SUCCESSFUL;
if (display_changed)
display_changed = 1;
return 1;
}
GetWindowRect(GetDesktopWindow(), &Rect);
disableWindowFlagsDisDlg();
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, Rect.right - Rect.left + 1, Rect.bottom - Rect.top + 1, SWP_NOREDRAW);
}
return 0;
}
@@ -156,154 +70,13 @@ int fullscrn::disableFullscreen()
{
if (display_changed)
{
if (SDL_SetWindowFullscreen(winmain::MainWindow, 0) == 0)
display_changed = 0;
ignoreNextDisplayChangeFg = 1;
ChangeDisplaySettingsA(nullptr, CDS_FULLSCREEN);
if (trick)
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
setWindowFlagsDisDlg();
SetWindowPos(
hWnd,
HWND_TOP,
WindowRect2.left,
WindowRect2.top,
WindowRect2.right - WindowRect2.left,
WindowRect2.bottom - WindowRect2.top,
SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
bool fullscrn::set_menu_mode(int menuEnabled)
{
BOOL result;
MenuEnabled = menuEnabled;
GetWindowCenter();
if (MenuEnabled)
{
fullscrn_flag1 |= 2u;
InvalidateRect(hWnd, nullptr, 1);
result = SetMenu(hWnd, MenuHandle);
}
else
{
fullscrn_flag1 |= 1u;
InvalidateRect(hWnd, nullptr, 1);
result = SetMenu(hWnd, nullptr);
}
return result;
}
void fullscrn::GetWindowCenter()
{
int yPos;
tagRECT Rect{};
if (screen_mode)
{
GetWindowRect(GetDesktopWindow(), &Rect);
render::vscreen.XPosition = (Rect.right - render::vscreen.Width - Rect.left) / 2;
yPos = (Rect.bottom - render::vscreen.Height - Rect.top) / 2;
}
else
{
render::vscreen.XPosition = 0;
yPos = GetSystemMetrics(15);
}
render::vscreen.YPosition = yPos;
if (MenuEnabled)
render::vscreen.YPosition -= GetSystemMetrics(15);
}
void fullscrn::force_redraw()
{
BYTE1(fullscrn_flag1) |= 0x80u;
}
void fullscrn::center_in(HWND parent, HWND child)
{
LONG right;
tagRECT childRect{}, parentRect{}, desktopRect{};
GetWindowRect(parent, &parentRect);
GetWindowRect(child, &childRect);
GetWindowRect(GetDesktopWindow(), &desktopRect);
if (display_changed)
{
desktopRect.bottom = 480;
desktopRect.left = 0;
desktopRect.top = 0;
right = 640;
desktopRect.right = 640;
parentRect.left = 0;
parentRect.top = 0;
parentRect.right = 640;
parentRect.bottom = 480;
}
else
{
right = desktopRect.right;
}
int childHeight = childRect.bottom - childRect.top;
int smthWidth = parentRect.left + (parentRect.right + childRect.left - childRect.right - parentRect.left) / 2;
int smthHeight = parentRect.top + (parentRect.bottom + childRect.top - childRect.bottom - parentRect.top) / 2;
if (childRect.right - childRect.left + smthWidth > right)
smthWidth = right - (childRect.right - childRect.left);
if (childHeight + smthHeight > desktopRect.bottom)
smthHeight = desktopRect.bottom - childHeight;
if (smthWidth < desktopRect.left)
smthWidth = desktopRect.left;
if (smthHeight < desktopRect.top)
smthHeight = desktopRect.top;
MoveWindow(child, smthWidth, smthHeight, childRect.right - childRect.left, childRect.bottom - childRect.top, 0);
}
int fullscrn::displaychange()
{
int result = 0;
if (ignoreNextDisplayChangeFg)
{
ignoreNextDisplayChangeFg = 0;
}
else
{
if (screen_mode && display_changed)
{
display_changed = 0;
screen_mode = 0;
setWindowFlagsDisDlg();
BYTE1(fullscrn_flag1) |= 0x80u;
InvalidateRect(hWnd, nullptr, 1);
set_menu_mode(1);
SetWindowPos(
hWnd,
HWND_TOP,
WindowRect2.left,
WindowRect2.top,
WindowRect2.right - WindowRect2.left,
WindowRect2.bottom - WindowRect2.top,
SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);
result = 1;
}
else
{
SetWindowPos(
hWnd,
HWND_TOP,
WindowRect2.left,
WindowRect2.top,
WindowRect2.right - WindowRect2.left,
WindowRect2.bottom - WindowRect2.top,
SWP_NOZORDER | SWP_NOACTIVATE);
}
center_in(GetDesktopWindow(), hWnd);
}
return result;
}
void fullscrn::activate(int flag)
{
if (screen_mode)
@@ -311,146 +84,49 @@ void fullscrn::activate(int flag)
if (!flag)
{
set_screen_mode(0);
SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
}
}
void fullscrn::fillRect(int right, int bottom, int left, int top)
{
RECT rc;
auto brush = CreateSolidBrush(0);
if (brush)
{
auto dc = winmain::_GetDC(hWnd);
if (dc)
{
auto prevBrush = SelectObject(dc, brush);
rc.right = left + right + 1;
rc.bottom = top + bottom + 1;
rc.left = left;
rc.top = top;
FillRect(dc, &rc, brush);
SelectObject(dc, prevBrush);
ReleaseDC(hWnd, dc);
}
DeleteObject(brush);
}
}
unsigned fullscrn::convert_mouse_pos(unsigned int mouseXY)
{
uint16_t x = mouseXY & 0xffFF - render::vscreen.XPosition;
uint16_t y = (mouseXY >> 16) - render::vscreen.YPosition;
return x | y << 16;
}
void fullscrn::getminmaxinfo(MINMAXINFO* maxMin)
{
/*Block down-scaling lower than min resolution*/
maxMin->ptMinTrackSize = POINT
{
resolution_array[0].ScreenWidth / 2,
resolution_array[0].ScreenHeight / 2
};
}
void fullscrn::paint()
{
int menuHeight;
if (screen_mode)
{
if ((fullscrn_flag1 & 0x8000) == 0 && fullscrn_flag1)
{
if (fullscrn_flag1 & 1)
{
menuHeight = GetSystemMetrics(SM_CYMENU);
fillRect(WindowRect1.right - 1, menuHeight, 0, 0);
}
}
else
{
if (MenuEnabled)
menuHeight = GetSystemMetrics(SM_CYMENU);
else
menuHeight = 0;
fillRect(WindowRect1.right, menuHeight + WindowRect1.bottom, 0, 0);
}
}
pb::paint();
fullscrn_flag1 = 0;
}
int fullscrn::GetResolution()
{
return resolution;
}
void fullscrn::SetResolution(int resolution)
void fullscrn::SetResolution(int value)
{
if (!pb::FullTiltMode)
resolution = 0;
assertm(resolution >= 0 && resolution <= 2, "Resolution value out of bounds");
fullscrn::resolution = resolution;
value = 0;
assertm(value >= 0 && value <= 2, "Resolution value out of bounds");
resolution = value;
}
int fullscrn::GetMaxResolution()
{
return maxResolution;
}
void fullscrn::SetMaxResolution(int resolution)
{
assertm(resolution >= 0 && resolution <= 2, "Resolution value out of bounds");
maxResolution = resolution;
}
int fullscrn::get_max_supported_resolution()
{
if (!pb::FullTiltMode)
return 0;
auto resolutionWH = get_screen_resolution();
auto width = LOWORD(resolutionWH);
auto height = HIWORD(resolutionWH);
auto result = 0;
for (auto index = 1; index < 3; ++index)
{
auto resPtr = &resolution_array[index];
if (resPtr->ScreenWidth <= width && resPtr->ScreenHeight <= height)
result = index;
}
return result;
}
int fullscrn::get_screen_resolution()
{
auto height = static_cast<uint16_t>(GetSystemMetrics(SM_CYSCREEN));
return static_cast<uint16_t>(GetSystemMetrics(SM_CXSCREEN)) | (height << 16);
return pb::FullTiltMode ? 2 : 0;
}
void fullscrn::window_size_changed()
{
/*No scaling in fullscreen mode*/
if (display_changed)
{
ScaleY = ScaleX = 1;
OffsetX = OffsetY = 0;
return;
}
RECT client{};
GetClientRect(hWnd, &client);
int width, height;
SDL_GetRendererOutputSize(winmain::Renderer, &width, &height);
int menuHeight = options::Options.ShowMenu ? winmain::MainMenuHeight : 0;
height -= menuHeight;
auto res = &resolution_array[resolution];
ScaleX = static_cast<float>(client.right) / res->TableWidth;
ScaleY = static_cast<float>(client.bottom) / res->TableHeight;
ScaleX = static_cast<float>(width) / res->TableWidth;
ScaleY = static_cast<float>(height) / res->TableHeight;
OffsetX = OffsetY = 0;
if (options::Options.UniformScaling)
{
ScaleY = ScaleX = min(ScaleX, ScaleY);
OffsetX = static_cast<int>(floor((client.right - res->TableWidth * ScaleX) / 2));
OffsetY = static_cast<int>(floor((client.bottom - res->TableHeight * ScaleY) / 2));
ScaleY = ScaleX = std::min(ScaleX, ScaleY);
OffsetX = static_cast<int>(floor((width - res->TableWidth * ScaleX) / 2));
OffsetY = static_cast<int>(floor((height - res->TableHeight * ScaleY) / 2));
}
render::DestinationRect = SDL_Rect
{
OffsetX, OffsetY + menuHeight,
width - OffsetX * 2, height - OffsetY * 2
};
}

View File

@@ -1,10 +1,4 @@
#pragma once
#include "maths.h"
#define BYTEn(x, n) (*((unsigned char*)&(x)+n))
#define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0)
#define BYTE2(x) BYTEn(x, 2)
struct resolution_info
{
@@ -18,49 +12,25 @@ struct resolution_info
class fullscrn
{
public:
static int screen_mode;
static HWND hWnd;
static tagRECT WindowRect1, WindowRect2;
static rectangle_type WHRect;
static int fullscrn_flag1;
static int display_changed;
static int ChangeDisplay, ignoreNextDisplayChangeFg;
static int trick;
static const resolution_info resolution_array[3];
static float ScaleX;
static float ScaleY;
static int OffsetX;
static int OffsetY;
static void init(int width, int height, int isFullscreen, HWND winHandle, HMENU menuHandle, int changeDisplay);
static void init();
static void shutdown();
static int set_screen_mode(int isFullscreen);
static void force_redraw();
static void center_in(HWND parent, HWND child);
static int displaychange();
static void activate(int flag);
static unsigned convert_mouse_pos(unsigned int mouseXY);
static void getminmaxinfo(MINMAXINFO* maxMin);
static void paint();
static bool set_menu_mode(int menuEnabled);
static int GetResolution();
static void SetResolution(int resolution);
static void SetResolution(int value);
static int GetMaxResolution();
static void SetMaxResolution(int resolution);
static int get_max_supported_resolution();
static int get_screen_resolution();
static void window_size_changed();
private :
static int MenuEnabled;
static HMENU MenuHandle;
static int resolution;
static int maxResolution;
static void GetWindowCenter();
static int disableWindowFlagsDisDlg();
static int setWindowFlagsDisDlg();
static int enableFullscreen();
static int disableFullscreen();
static void fillRect(int right, int bottom, int left, int top);
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,80 +1,74 @@
#pragma once
enum class BitmapType : char
enum class BitmapTypes : uint8_t
{
None = 0,
RawBitmap = 1,
DibBitmap = 2,
Spliced = 4,
Spliced = 3,
};
struct Rgba
{
uint8_t Blue;
uint8_t Green;
uint8_t Red;
uint8_t Alpha;
};
union ColorRgba
{
ColorRgba() = default;
explicit ColorRgba(uint32_t color)
: Color(color)
{
}
explicit ColorRgba(Rgba rgba)
: rgba(rgba)
{
}
uint32_t Color;
Rgba rgba;
};
static_assert(sizeof(ColorRgba) == 4, "Wrong size of RGBA color");
struct gdrv_bitmap8
{
BITMAPINFO* Dib;
char* BmpBufPtr2;
char* BmpBufPtr1;
gdrv_bitmap8(int width, int height, bool indexed);
gdrv_bitmap8(const struct dat8BitBmpHeader& header);
~gdrv_bitmap8();
void ScaleIndexed(float scaleX, float scaleY);
ColorRgba* BmpBufPtr1;
char* IndexedBmpPtr;
int Width;
int Height;
int Stride;
BitmapType BitmapType;
int Color6;
int IndexedStride;
BitmapTypes BitmapType;
int XPosition;
int YPosition;
};
struct LOGPALETTEx256 : LOGPALETTE
{
PALETTEENTRY palPalEntry2[256 - 1];
LOGPALETTEx256() : palPalEntry2{}
{
palVersion = 0x300;
palNumEntries = 256;
}
unsigned Resolution;
SDL_Texture* Texture;
};
class gdrv
{
public:
static HPALETTE palette_handle;
static int sequence_handle;
static HDC sequence_hdc;
static int use_wing;
static int init(HINSTANCE hInst, HWND hWnd);
static int uninit();
static void get_focus();
static BITMAPINFO* DibCreate(int16_t bpp, int width, int height);
static void DibSetUsage(BITMAPINFO* dib, HPALETTE hpal, int someFlag);
static int create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height);
static int create_bitmap(gdrv_bitmap8* bmp, int width, int height);
static int create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag);
static int create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size);
static int destroy_bitmap(gdrv_bitmap8* bmp);
static int display_palette(PALETTEENTRY* plt);
static void start_blit_sequence();
static void blit_sequence(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth,
int DestHeight);
static void end_blit_sequence();
static void blit(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth, int DestHeight);
static void blat(gdrv_bitmap8* bmp, int xDest, int yDest);
static void fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, char fillChar);
static int display_palette(ColorRgba* plt);
static void fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, uint8_t fillChar);
static void copy_bitmap(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp,
int srcXOff, int srcYOff);
static void copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff,
gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff);
static void grtext_draw_ttext_in_box(LPCWSTR text, int xOff, int yOff, int width, int height);
static void grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6);
static void ApplyPalette(gdrv_bitmap8& bmp);
static void CreatePreview(gdrv_bitmap8& bmp);
private:
/*COLORONCOLOR or HALFTONE*/
static const int stretchMode = COLORONCOLOR;
static HWND hwnd;
static HINSTANCE hinst;
static int grtext_blue;
static int grtext_green;
static int grtext_red;
static int StretchDIBitsScaled(HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc,
int SrcWidth, int SrcHeight, gdrv_bitmap8* bmp, UINT iUsage,
DWORD rop);
static ColorRgba current_palette[256];
};

View File

@@ -1,110 +1,73 @@
#include "pch.h"
#include "high_score.h"
#include "fullscrn.h"
#include "memory.h"
#include "options.h"
#include "resource.h"
#include "winmain.h"
#include "pinball.h"
#include "score.h"
int high_score::dlg_enter_name;
int high_score::dlg_score;
int high_score::dlg_position;
LPCWSTR high_score::default_name;
char high_score::default_name[32]{};
high_score_struct* high_score::dlg_hst;
bool high_score::ShowDialog = false;
winhelp_entry high_score::help[21]
int high_score::read(high_score_struct* table)
{
winhelp_entry{0x70, 0x3E9},
winhelp_entry{0x191, 0x3EB},
winhelp_entry{0x1F5, 0x3EB},
winhelp_entry{0x259, 0x3EB},
winhelp_entry{0x192, 0x3EB},
winhelp_entry{0x193, 0x3EB},
winhelp_entry{0x194, 0x3EB},
winhelp_entry{0x195, 0x3EB},
winhelp_entry{0x1F6, 0x3EB},
winhelp_entry{0x1F7, 0x3EB},
winhelp_entry{0x1F8, 0x3EB},
winhelp_entry{0x1F9, 0x3EB},
winhelp_entry{0x2BD, 0x3EB},
winhelp_entry{0x2BE, 0x3EB},
winhelp_entry{0x2BF, 0x3EB},
winhelp_entry{0x2C0, 0x3EB},
winhelp_entry{0x2C1, 0x3EB},
winhelp_entry{0x2C2, 0x3EB},
winhelp_entry{0x2C3, 0x3EB},
winhelp_entry{0x2C4, 0x3EB},
winhelp_entry{0, 0},
};
char Buffer[20];
int high_score::read(high_score_struct* table, int* ptrToSmth)
{
char scoreBuffer[20];
wchar_t nameBuffer[20];
int scoreSum = 0;
int checkSum = 0;
clear_table(table);
char* buf1 = memory::allocate(300u);
if (!buf1)
return 1;
char* buf2 = memory::allocate(300u);
auto optPath = pinball::get_rc_string(166, 0);
for (auto position = 0; position < 5; ++position)
{
auto tablePtr = &table[position];
wsprintfW(nameBuffer, L"%d.Name", position);
options::get_string(optPath, nameBuffer, tablePtr->Name, L"", 32);
tablePtr->Name[31] = 0;
snprintf(Buffer, sizeof Buffer, "%d", position);
strcat(Buffer, ".Name");
auto name = options::get_string(Buffer, "");
strncpy(tablePtr->Name, name.c_str(), sizeof tablePtr->Name);
sprintf_s(scoreBuffer, "%d.Score", position);
options::get_string(optPath, scoreBuffer, buf1, "", 300);
tablePtr->Score = atol(buf1);
snprintf(Buffer, sizeof Buffer, "%d", position);
strcat(Buffer, ".Score");
tablePtr->Score = options::get_int(Buffer, tablePtr->Score);
for (auto i = lstrlenW(tablePtr->Name) - 1; i >= 0; i--)
scoreSum += tablePtr->Name[i];
scoreSum += tablePtr->Score;
for (int i = static_cast<int>(strlen(tablePtr->Name)); --i >= 0; checkSum += tablePtr->Name[i])
{
}
checkSum += tablePtr->Score;
}
scramble_number_string(scoreSum, buf1);
options::get_string(optPath, "Verification", buf2, "", 300);
if (lstrcmpA(buf1, buf2))
auto verification = options::get_int("Verification", 7);
if (checkSum != verification)
clear_table(table);
memory::free(buf1);
memory::free(buf2);
return 0;
}
int high_score::write(high_score_struct* table, int* ptrToSmth)
int high_score::write(high_score_struct* table)
{
char scoreBuffer[20];
wchar_t nameBuffer[20];
char Buffer[20];
int scoreSum = 0;
CHAR* buf = memory::allocate(300u);
if (!buf)
return 1;
auto optPath = pinball::get_rc_string(166, 0);
int checkSum = 0;
for (auto position = 0; position < 5; ++position)
{
auto tablePtr = &table[position];
wsprintfW(nameBuffer, L"%d.Name", position);
options::set_string(optPath, nameBuffer, tablePtr->Name);
snprintf(Buffer, sizeof Buffer, "%d", position);
strcat(Buffer, ".Name");
options::set_string(Buffer, tablePtr->Name);
sprintf_s(scoreBuffer, "%d.Score", position);
_ltoa_s(tablePtr->Score, buf, 300, 10);
options::set_string(optPath, scoreBuffer, buf);
snprintf(Buffer, sizeof Buffer, "%d", position);
strcat(Buffer, ".Score");
options::set_int(Buffer, tablePtr->Score);
for (auto i = lstrlenW(tablePtr->Name) - 1; i >= 0; i--)
scoreSum += tablePtr->Name[i];
scoreSum += tablePtr->Score;
for (int i = static_cast<int>(strlen(tablePtr->Name)); --i >= 0; checkSum += tablePtr->Name[i])
{
}
checkSum += tablePtr->Score;
}
scramble_number_string(scoreSum, buf);
options::set_string(optPath, "Verification", buf);
memory::free(buf);
options::set_int("Verification", checkSum);
return 0;
}
@@ -131,7 +94,7 @@ int high_score::get_score_position(high_score_struct* table, int score)
return -1;
}
int high_score::place_new_score_into(high_score_struct* table, int score, LPWSTR name, int position)
int high_score::place_new_score_into(high_score_struct* table, int score, LPSTR scoreStr, int position)
{
if (position >= 0)
{
@@ -149,152 +112,120 @@ int high_score::place_new_score_into(high_score_struct* table, int score, LPWSTR
}
high_score_struct* posTable = &table[position];
posTable->Score = score;
if (lstrlenW(name) >= 31)
name[31] = 0;
lstrcpyW(posTable->Name, name);
if (strlen(scoreStr) >= 31)
scoreStr[31] = 0;
strncpy(posTable->Name, scoreStr, sizeof posTable->Name);
posTable->Name[31] = 0;
}
return position;
}
void high_score::scramble_number_string(int Value, char* Buffer)
{
_ltoa_s(Value, Buffer, 300, 10);
}
void high_score::show_high_score_dialog(high_score_struct* table)
{
dlg_enter_name = 0;
dlg_score = 0;
dlg_hst = table;
DialogBoxParamW(winmain::hinst, L"dlg_highscores", winmain::hwnd_frame, HighScore, 0);
ShowDialog = true;
}
void high_score::show_and_set_high_score_dialog(high_score_struct* table, int score, int pos, LPCWSTR defaultName)
void high_score::show_and_set_high_score_dialog(high_score_struct* table, int score, int pos, LPCSTR defaultName)
{
dlg_position = pos;
dlg_score = score;
dlg_hst = table;
dlg_enter_name = 1;
default_name = defaultName;
while (DialogBoxParamW(winmain::hinst, L"dlg_highscores", winmain::hwnd_frame, HighScore, 0))
{
}
strncpy(default_name, defaultName, sizeof default_name - 1);
ShowDialog = true;
}
INT_PTR high_score::HighScore(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
void high_score::RenderHighScoreDialog()
{
HWND parent;
int nIDDlgItem;
wchar_t name[32];
switch (msg)
{
case WM_CLOSE:
SendMessageA(hWnd, WM_COMMAND, WM_DESTROY, 0);
break;
case WM_HELP:
WinHelpA(static_cast<HWND>(reinterpret_cast<HELPINFO*>(lParam)->hItemHandle), "pinball.hlp", HELP_WM_HELP,
(ULONG_PTR)help);
break;
case WM_CONTEXTMENU:
WinHelpA((HWND)wParam, "pinball.hlp", HELP_CONTEXTMENU, (ULONG_PTR)help);
break;
case WM_INITDIALOG:
show_high_scores(hWnd, dlg_hst);
for (nIDDlgItem = DLG_HIGHSCORES_EditName1; nIDDlgItem < 611; ++nIDDlgItem)
{
ShowWindow(GetDlgItem(hWnd, nIDDlgItem), SW_HIDE);
}
if (dlg_enter_name == 1)
if (ShowDialog == true)
{
ShowDialog = false;
if (dlg_position == -1)
{
dlg_enter_name = 0;
return 1;
return;
}
HWND nameTextBox = GetDlgItem(hWnd, dlg_position + DLG_HIGHSCORES_EditName1);
ShowWindow(nameTextBox, SW_SHOW);
EnableWindow(nameTextBox, 1);
SetFocus(nameTextBox);
if (default_name)
ImGui::OpenPopup("High Scores");
}
bool unused_open = true;
if (ImGui::BeginPopupModal("High Scores", &unused_open, ImGuiWindowFlags_AlwaysAutoResize))
{
SetWindowTextW(nameTextBox, default_name);
SendMessageA(nameTextBox, EM_SETSEL, 0, -1);
}
SendMessageA(nameTextBox, EM_SETLIMITTEXT, 31u, 0);
if (ImGui::BeginTable("table1", 3, 0))
{
char buf[36];
ImGui::TableSetupColumn("Rank");
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Score");
ImGui::TableHeadersRow();
for (int offset = 0, row = 0; row < 5; row++)
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
snprintf(buf, sizeof buf, "%d", row);
ImGui::TextUnformatted(buf);
auto currentRow = &dlg_hst[row + offset];
auto score = currentRow->Score;
ImGui::TableNextColumn();
if (dlg_enter_name == 1 && dlg_position == row)
{
offset = -1;
score = dlg_score;
ImGui::PushItemWidth(200);
ImGui::InputText("", default_name, IM_ARRAYSIZE(default_name));
}
else
{
SetFocus(hWnd);
ImGui::TextUnformatted(currentRow->Name);
}
parent = GetParent(hWnd);
if (parent)
fullscrn::center_in(parent, hWnd);
return 0;
case WM_COMMAND:
switch (wParam)
{
case DLG_HIGHSCORES_Ok:
if (dlg_enter_name != 1)
{
break;
ImGui::TableNextColumn();
score::string_format(score, buf);
ImGui::TextUnformatted(buf);
}
GetDlgItemTextW(hWnd, dlg_position + DLG_HIGHSCORES_EditName1, name, 32);
name[31] = 0;
place_new_score_into(dlg_hst, dlg_score, name, dlg_position);
break;
case DLG_HIGHSCORES_Cancel:
break;
case DLG_HIGHSCORES_Clear:
if (MessageBoxW(hWnd, pinball::get_rc_Wstring(40, 0),
pinball::get_rc_Wstring(41, 0), MB_DEFBUTTON2 | MB_OKCANCEL) == 1)
ImGui::EndTable();
}
ImGui::Separator();
if (ImGui::Button("Ok"))
{
if (dlg_enter_name)
{
default_name[31] = 0;
place_new_score_into(dlg_hst, dlg_score, default_name, dlg_position);
}
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel"))
ImGui::CloseCurrentPopup();
ImGui::SameLine();
if (ImGui::Button("Clear"))
ImGui::OpenPopup("Confirm");
if (ImGui::BeginPopupModal("Confirm", nullptr, ImGuiWindowFlags_MenuBar))
{
ImGui::TextUnformatted(pinball::get_rc_string(40, 0));
if (ImGui::Button("OK", ImVec2(120, 0)))
{
clear_table(dlg_hst);
if (dlg_enter_name)
EndDialog(hWnd, 1);
else
EndDialog(hWnd, 0);
ImGui::CloseCurrentPopup();
}
return 0;
default:
return 0;
ImGui::SetItemDefaultFocus();
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(120, 0)))
{
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
dlg_enter_name = 0;
EndDialog(hWnd, 0);
return 1;
}
return 0;
}
void high_score::show_high_scores(HWND hDlg, high_score_struct* table)
{
high_score_struct* tablePtr = table;
int nextPosition = 0;
for (int i = 0; i < 5; ++i)
{
if (dlg_enter_name == 1 && dlg_position == i)
{
hsdlg_show_score(hDlg, L" ", dlg_score, i);
nextPosition = 1;
}
hsdlg_show_score(hDlg, tablePtr->Name, tablePtr->Score, i + nextPosition);
++tablePtr;
}
}
void high_score::hsdlg_show_score(HWND hDlg, LPCWSTR name, int score, int position)
{
CHAR scoreStr[36];
if (position < 5)
{
score::string_format(score, scoreStr);
if (scoreStr[0])
{
SetWindowTextW(GetDlgItem(hDlg, position + DLG_HIGHSCORES_StaticName1), name);
SetWindowTextA(GetDlgItem(hDlg, position + DLG_HIGHSCORES_Score1), scoreStr);
}
ImGui::EndPopup();
}
}

View File

@@ -1,9 +1,8 @@
#pragma once
#include "pinball.h"
struct high_score_struct
{
wchar_t Name[32];
char Name[32];
int Score;
};
@@ -11,23 +10,20 @@ struct high_score_struct
class high_score
{
public:
static int read(high_score_struct* table, int* ptrToSmth);
static int write(high_score_struct* table, int* ptrToSmth);
static int read(high_score_struct* table);
static int write(high_score_struct* table);
static void clear_table(high_score_struct* table);
static int get_score_position(high_score_struct* table, int score);
static int place_new_score_into(high_score_struct* table, int score, LPWSTR name, int position);
static void scramble_number_string(int Value, char* Buffer);
static int place_new_score_into(high_score_struct* table, int score, LPSTR scoreStr, int position);
static void show_high_score_dialog(high_score_struct* table);
static void show_and_set_high_score_dialog(high_score_struct* table, int score, int pos, LPCWSTR defaultName);
static INT_PTR __stdcall HighScore(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static void show_high_scores(HWND hDlg, high_score_struct* table);
static void hsdlg_show_score(HWND hDlg, LPCWSTR name, int score, int position);
static void show_and_set_high_score_dialog(high_score_struct* table, int score, int pos, LPCSTR defaultName);
static void RenderHighScoreDialog();
private :
static int dlg_enter_name;
static int dlg_score;
static int dlg_position;
static LPCWSTR default_name;
static char default_name[32];
static high_score_struct* dlg_hst;
static winhelp_entry help[21];
static bool ShowDialog;
};

View File

@@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
//-----------------------------------------------------------------------------
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Disable all of Dear ImGui or don't implement standard windows.
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Include imgui_user.h at the end of imgui.h as a convenience
//#define IMGUI_INCLUDE_IMGUI_USER_H
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
// #define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
/*
#define IM_VEC2_CLASS_EXTRA \
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
operator MyVec2() const { return MyVec2(x,y); }
#define IM_VEC4_CLASS_EXTRA \
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
// This adds a small runtime cost which is why it is not enabled by default.
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui
{
void MyFunction(const char* name, const MyMatrix44& v);
}
*/

11866
SpaceCadetPinball/imgui.cpp Normal file

File diff suppressed because it is too large Load Diff

2907
SpaceCadetPinball/imgui.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,443 @@
// dear imgui: Platform Backend for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// (Prefer SDL 2.0.5+ for full feature support.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#include "imgui.h"
#include "imgui_impl_sdl.h"
// SDL
#include <SDL.h>
#include <SDL_syswm.h>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
#else
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
#endif
#define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
// SDL Data
struct ImGui_ImplSDL2_Data
{
SDL_Window* Window;
Uint64 Time;
bool MousePressed[3];
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
char* ClipboardTextData;
bool MouseCanUseGlobalState;
ImGui_ImplSDL2_Data() { memset(this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
}
// Functions
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
bd->ClipboardTextData = SDL_GetClipboardText();
return bd->ClipboardTextData;
}
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
{
SDL_SetClipboardText(text);
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
switch (event->type)
{
case SDL_MOUSEWHEEL:
{
if (event->wheel.x > 0) io.MouseWheelH += 1;
if (event->wheel.x < 0) io.MouseWheelH -= 1;
if (event->wheel.y > 0) io.MouseWheel += 1;
if (event->wheel.y < 0) io.MouseWheel -= 1;
return true;
}
case SDL_MOUSEBUTTONDOWN:
{
if (event->button.button == SDL_BUTTON_LEFT) { bd->MousePressed[0] = true; }
if (event->button.button == SDL_BUTTON_RIGHT) { bd->MousePressed[1] = true; }
if (event->button.button == SDL_BUTTON_MIDDLE) { bd->MousePressed[2] = true; }
return true;
}
case SDL_TEXTINPUT:
{
io.AddInputCharactersUTF8(event->text.text);
return true;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
int key = event->key.keysym.scancode;
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
#ifdef _WIN32
io.KeySuper = false;
#else
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
#endif
return true;
}
case SDL_WINDOWEVENT:
{
if (event->window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
io.AddFocusEvent(true);
else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
io.AddFocusEvent(false);
return true;
}
}
return false;
}
static bool ImGui_ImplSDL2_Init(SDL_Window* window)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
// Check and store if we are on a SDL backend that supports global mouse position
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
bool mouse_can_use_global_state = false;
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
const char* sdl_backend = SDL_GetCurrentVideoDriver();
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
mouse_can_use_global_state = true;
#endif
// Setup backend capabilities flags
ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = "imgui_impl_sdl";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
bd->Window = window;
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_KP_ENTER;
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
io.ClipboardUserData = NULL;
// Load mouse cursors
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
#ifdef _WIN32
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(window, &info))
io.ImeWindowHandle = info.info.win.window;
#else
(void)window;
#endif
// Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
// you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
#if SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
#endif
return true;
}
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
{
IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
return ImGui_ImplSDL2_Init(window);
}
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
{
#if !SDL_HAS_VULKAN
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window);
}
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
{
#if !defined(_WIN32)
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window);
}
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
{
return ImGui_ImplSDL2_Init(window);
}
void ImGui_ImplSDL2_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
io.BackendPlatformName = NULL;
io.BackendPlatformUserData = NULL;
IM_DELETE(bd);
}
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
ImVec2 mouse_pos_prev = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
// Update mouse buttons
int mouse_x_local, mouse_y_local;
Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local);
io.MouseDown[0] = bd->MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = bd->MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = bd->MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
bd->MousePressed[0] = bd->MousePressed[1] = bd->MousePressed[2] = false;
// Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing)
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
SDL_Window* focused_window = SDL_GetKeyboardFocus();
SDL_Window* hovered_window = SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH ? SDL_GetMouseFocus() : NULL; // This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH.
SDL_Window* mouse_window = NULL;
if (hovered_window && bd->Window == hovered_window)
mouse_window = hovered_window;
else if (focused_window && bd->Window == focused_window)
mouse_window = focused_window;
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
SDL_CaptureMouse(ImGui::IsAnyMouseDown() ? SDL_TRUE : SDL_FALSE);
#else
// SDL 2.0.3 and non-windowed systems: single-viewport only
SDL_Window* mouse_window = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) ? bd->Window : NULL;
#endif
if (mouse_window == NULL)
return;
// Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
SDL_WarpMouseInWindow(bd->Window, (int)mouse_pos_prev.x, (int)mouse_pos_prev.y);
// Set Dear ImGui mouse position from OS position + get buttons. (this is the common behavior)
if (bd->MouseCanUseGlobalState)
{
// Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
// Unlike local position obtained earlier this will be valid when straying out of bounds.
int mouse_x_global, mouse_y_global;
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
int window_x, window_y;
SDL_GetWindowPosition(mouse_window, &window_x, &window_y);
io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
}
else
{
io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local);
}
}
static void ImGui_ImplSDL2_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
SDL_ShowCursor(SDL_FALSE);
}
else
{
// Show OS mouse cursor
SDL_SetCursor(bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
SDL_ShowCursor(SDL_TRUE);
}
}
static void ImGui_ImplSDL2_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Get gamepad
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
if (!game_controller)
{
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
return;
}
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767);
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
#undef MAP_BUTTON
#undef MAP_ANALOG
}
void ImGui_ImplSDL2_NewFrame()
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDL2_Init()?");
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
SDL_GetWindowSize(bd->Window, &w, &h);
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
w = h = 0;
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
static Uint64 frequency = SDL_GetPerformanceFrequency();
Uint64 current_time = SDL_GetPerformanceCounter();
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
bd->Time = current_time;
ImGui_ImplSDL2_UpdateMousePosAndButtons();
ImGui_ImplSDL2_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplSDL2_UpdateGamepads();
}

View File

@@ -0,0 +1,34 @@
// dear imgui: Platform Backend for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct SDL_Window;
typedef union SDL_Event SDL_Event;
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
#endif

Some files were not shown because too many files have changed in this diff Show More