From 18b7fb9abf7cc85d7b1952a9ee8201c1775dc897 Mon Sep 17 00:00:00 2001 From: scawful Date: Thu, 28 Nov 2024 11:50:47 -0500 Subject: [PATCH] backend-infra-engineer: Pre-0.2.2 2024 Q4 snapshot --- .github/workflows/cmake.yml | 6 + .gitignore | 13 + CMakeLists.txt | 37 +- Doxyfile | 18 +- LICENSE | 6 +- README.md | 30 +- assets/asm/ZSCustomOverworld.asm | 3563 ++++++++++ assets/asm/yaze.asm | 22 + assets/yaze.png | Bin 0 -> 6580 bytes cmake/absl.cmake | 4 + cmake/asar.cmake | 48 +- cmake/gtest.cmake | 11 + cmake/imgui.cmake | 17 +- cmake/mingw64.cmake | 21 + cmake/sdl2.cmake | 23 +- docs/asm-style-guide.md | 244 + docs/build-instructions.md | 61 +- docs/changelog.md | 47 + docs/compression.md | 66 - docs/contributing.md | 139 + docs/getting-started.md | 63 +- docs/infrastructure.md | 170 +- docs/yaze.org | 63 + incl/dungeon.h | 61 + incl/overworld.h | 47 + incl/snes_color.h | 32 + incl/snes_tile.h | 40 + incl/sprite.h | 23 + incl/system/extension.h | 91 + incl/yaze.h | 125 + src/CMakeLists.txt | 180 +- src/app/CMakeLists.txt | 40 - src/app/app.cmake | 73 + src/app/core/common.cc | 380 +- src/app/core/common.h | 209 +- src/app/core/constants.h | 736 -- src/app/core/controller.cc | 595 +- src/app/core/controller.h | 57 +- src/app/core/core.cmake | 33 + src/app/core/labeling.h | 53 - src/app/core/platform/app_delegate.h | 50 +- src/app/core/platform/app_delegate.mm | 30 +- src/app/core/platform/clipboard.cc | 10 +- src/app/core/platform/clipboard.h | 25 +- src/app/core/platform/clipboard.mm | 4 +- src/app/core/platform/file_dialog.cc | 145 + src/app/core/platform/file_dialog.h | 92 +- src/app/core/platform/file_dialog.mm | 72 +- src/app/core/platform/file_path.h | 14 + src/app/core/platform/file_path.mm | 10 +- src/app/core/platform/font_loader.cc | 182 +- src/app/core/platform/font_loader.h | 31 +- src/app/core/platform/font_loader.mm | 27 +- src/app/core/platform/renderer.h | 83 + src/app/core/platform/view_controller.h | 29 + src/app/core/{labeling.cc => project.cc} | 76 +- src/app/core/project.h | 172 +- src/app/core/testable.h | 19 - src/app/core/utils/file_util.cc | 74 + src/app/core/utils/file_util.h | 24 + src/app/core/utils/sdl_deleter.h | 40 + src/app/editor/code/assembly_editor.cc | 13 +- src/app/editor/code/assembly_editor.h | 8 +- src/app/editor/code/memory_editor.h | 16 +- src/app/editor/dungeon/dungeon_editor.cc | 70 +- src/app/editor/dungeon/dungeon_editor.h | 12 +- src/app/editor/editor.cc | 52 + .../editor/{CMakeLists.txt => editor.cmake} | 16 +- src/app/editor/{utils => }/editor.h | 44 +- .../{master_editor.cc => editor_manager.cc} | 334 +- .../{master_editor.h => editor_manager.h} | 83 +- src/app/editor/graphics/gfx_group_editor.cc | 22 +- src/app/editor/graphics/gfx_group_editor.h | 27 +- src/app/editor/graphics/graphics_editor.cc | 216 +- src/app/editor/graphics/graphics_editor.h | 25 +- src/app/editor/graphics/palette_editor.cc | 173 +- src/app/editor/graphics/palette_editor.h | 78 +- src/app/editor/graphics/screen_editor.cc | 330 +- src/app/editor/graphics/screen_editor.h | 67 +- src/app/editor/graphics/tile16_editor.cc | 108 +- src/app/editor/graphics/tile16_editor.h | 35 +- src/app/editor/master_editor_test.cc | 10 - src/app/editor/message/message_data.cc | 182 + src/app/editor/message/message_data.h | 179 +- src/app/editor/message/message_editor.cc | 675 +- src/app/editor/message/message_editor.h | 273 +- src/app/editor/message/message_editor_test.cc | 7 - src/app/editor/music/music_editor.h | 17 +- src/app/editor/overworld/entity.cc | 41 +- src/app/editor/overworld/entity.h | 13 +- .../{ => overworld}/overworld_editor.cc | 877 ++- .../editor/{ => overworld}/overworld_editor.h | 215 +- src/app/editor/overworld/refresh.cc | 157 - src/app/editor/sprite/sprite_editor.cc | 13 +- src/app/editor/sprite/sprite_editor.h | 2 +- src/app/editor/sprite/zsprite.h | 6 +- src/app/editor/system/command_manager.cc | 143 + src/app/editor/system/command_manager.h | 83 + src/app/editor/system/constant_manager.h | 77 + src/app/editor/system/extension_manager.cc | 85 + src/app/editor/system/extension_manager.h | 29 + src/app/editor/{utils => system}/flags.h | 12 +- src/app/editor/system/history_manager.h | 32 + src/app/editor/system/popup_manager.cc | 19 + src/app/editor/system/popup_manager.h | 21 + src/app/editor/system/resource_manager.h | 30 + .../editor/{ => system}/settings_editor.cc | 8 +- src/app/editor/{ => system}/settings_editor.h | 2 +- src/app/editor/utils/gfx_context.cc | 26 - src/app/editor/utils/gfx_context.h | 36 - src/app/editor/utils/keyboard_shortcuts.h | 25 - src/app/editor/utils/recent_files.h | 64 - src/app/emu/audio/apu.h | 1 + src/app/emu/audio/spc700.cc | 1 - src/app/emu/cpu/cpu.h | 3 +- src/app/emu/debug/debugger.h | 56 - src/app/emu/debug/log.h | 43 - src/app/emu/{debug => }/emu.cc | 46 +- src/app/emu/{CMakeLists.txt => emu.cmake} | 18 +- src/app/emu/emulator.cc | 113 +- src/app/emu/emulator.h | 45 +- src/app/emu/{debug => memory}/asm_parser.h | 0 src/app/emu/memory/dma.cc | 140 +- src/app/emu/memory/dma_channel.h | 24 +- src/app/emu/memory/memory.cc | 175 +- src/app/emu/memory/memory.h | 84 +- src/app/emu/snes.cc | 1 - src/app/emu/snes.h | 9 +- src/app/gfx/bitmap.cc | 301 +- src/app/gfx/bitmap.h | 201 +- src/app/gfx/compression.cc | 62 +- src/app/gfx/compression.h | 25 +- src/app/gfx/gfx.cmake | 10 + src/app/gfx/scad_format.cc | 6 +- src/app/gfx/snes_color.cc | 22 +- src/app/gfx/snes_color.h | 53 +- src/app/gfx/snes_palette.cc | 236 +- src/app/gfx/snes_palette.h | 224 +- src/app/gfx/snes_tile.cc | 76 +- src/app/gfx/snes_tile.h | 91 +- src/app/gfx/tilesheet.cc | 138 +- src/app/gfx/tilesheet.h | 142 +- src/app/gui/canvas.cc | 123 +- src/app/gui/canvas.h | 94 +- src/app/gui/color.cc | 8 +- src/app/gui/color.h | 2 +- src/app/gui/gui.cmake | 9 + src/app/gui/input.cc | 30 +- src/app/gui/input.h | 11 +- src/app/gui/{ => modules}/asset_browser.cc | 5 +- src/app/gui/{ => modules}/asset_browser.h | 13 +- src/app/gui/style.cc | 162 +- src/app/gui/style.h | 81 +- src/app/gui/zeml.cc | 26 +- src/app/gui/zeml.h | 2 - src/app/{yaze.cc => main.cc} | 36 +- src/app/rom.cc | 370 +- src/app/rom.h | 372 +- src/app/rom_test.cc | 20 - src/app/zelda3/common.h | 297 +- src/app/zelda3/dungeon/object_renderer.cc | 51 +- src/app/zelda3/dungeon/object_renderer.h | 32 +- src/app/zelda3/dungeon/room.cc | 174 +- src/app/zelda3/dungeon/room.h | 506 +- src/app/zelda3/dungeon/room_entrance.h | 302 +- src/app/zelda3/dungeon/room_names.h | 453 -- src/app/zelda3/dungeon/room_object.cc | 49 +- src/app/zelda3/dungeon/room_object.h | 153 +- src/app/zelda3/dungeon/room_tag.h | 94 + src/app/zelda3/music/spc700.def | 26 - src/app/zelda3/music/tracker.cc | 146 +- src/app/zelda3/music/tracker.h | 43 +- src/app/zelda3/overworld/overworld.cc | 497 +- src/app/zelda3/overworld/overworld.h | 221 +- src/app/zelda3/overworld/overworld_map.cc | 285 +- src/app/zelda3/overworld/overworld_map.h | 74 +- src/app/zelda3/screen/dungeon_map.h | 13 +- src/app/zelda3/screen/inventory.cc | 9 +- src/app/zelda3/screen/inventory.h | 6 +- src/app/zelda3/screen/title_screen.cc | 13 +- src/app/zelda3/screen/title_screen.h | 2 +- src/app/zelda3/sprite/overlord.h | 43 + src/app/zelda3/sprite/sprite.cc | 86 +- src/app/zelda3/sprite/sprite.h | 382 +- src/app/zelda3/sprite/sprite_builder.cc | 153 + src/app/zelda3/sprite/sprite_builder.h | 131 + .../zelda3/{CMakeLists.txt => zelda3.cmake} | 1 + src/cli/{command_handler.h => command.h} | 150 +- src/cli/handlers/compress.cc | 33 + src/cli/handlers/patch.cc | 61 + .../tile16_transfer.cc} | 15 +- src/cli/patch.cc | 205 - src/cli/patch.h | 29 - src/cli/python/yaze_py.cc | 60 + src/cli/python/yaze_py.cmake | 50 + src/cli/z3ed.cc | 32 +- src/cli/{CMakeLists.txt => z3ed.cmake} | 16 +- src/ios/Media.xcassets/Contents.json | 6 + .../yaze.appiconset/Contents.json | 14 + .../Media.xcassets/yaze.appiconset/yaze.png | Bin 0 -> 6580 bytes src/ios/iOS/Info-iOS.plist | 120 + src/ios/iOS/LaunchScreen.storyboard | 27 + src/ios/main.mm | 394 + src/ios/yaze.xcodeproj/project.pbxproj | 6321 +++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 5 + .../Bookmarks/bookmarks.plist | 131 + .../UserInterfaceState.xcuserstate | Bin 0 -> 407072 bytes .../WorkspaceSettings.xcsettings | 14 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + .../xcschemes/xcschememanagement.plist | 39 + src/lib/abseil-cpp | 2 +- src/lib/asar | 2 +- src/lib/imgui | 2 +- src/lib/imgui_memory_editor.h | 24 +- src/lib/imgui_test_engine | 2 +- src/test/CMakeLists.txt | 63 +- src/test/core/testing.h | 48 + src/test/emu/cpu_test.cc | 14 +- src/test/emu/ppu_test.cc | 111 +- src/test/emu/spc700_test.cc | 12 +- src/test/gfx/compression_test.cc | 39 +- src/test/gfx/snes_palette_test.cc | 54 +- src/test/integration/test_editor.cc | 101 + src/test/integration/test_editor.h | 53 + .../emu/memory => test/mocks}/mock_memory.h | 0 src/test/rom_test.cc | 246 + src/test/yaze_test.cc | 22 +- src/test/zelda3/dungeon_room_test.cc | 37 + src/test/zelda3/message_test.cc | 49 + src/test/zelda3/overworld_test.cc | 58 + src/test/zelda3/room_object_test.cc | 28 - src/test/zelda3/sprite_builder_test.cc | 66 + src/{ => win32}/yaze.ico | Bin src/{ => win32}/yaze.rc | 0 src/{ => win32}/yaze.res | Bin src/yaze.cc | 123 + 238 files changed, 22057 insertions(+), 8538 deletions(-) create mode 100644 assets/asm/ZSCustomOverworld.asm create mode 100644 assets/asm/yaze.asm create mode 100644 assets/yaze.png create mode 100644 cmake/gtest.cmake create mode 100644 cmake/mingw64.cmake create mode 100644 docs/asm-style-guide.md create mode 100644 docs/changelog.md delete mode 100644 docs/compression.md create mode 100644 docs/contributing.md create mode 100644 docs/yaze.org create mode 100644 incl/dungeon.h create mode 100644 incl/overworld.h create mode 100644 incl/snes_color.h create mode 100644 incl/snes_tile.h create mode 100644 incl/sprite.h create mode 100644 incl/system/extension.h create mode 100644 incl/yaze.h delete mode 100644 src/app/CMakeLists.txt create mode 100644 src/app/app.cmake create mode 100644 src/app/core/core.cmake delete mode 100644 src/app/core/labeling.h create mode 100644 src/app/core/platform/file_dialog.cc create mode 100644 src/app/core/platform/renderer.h create mode 100644 src/app/core/platform/view_controller.h rename src/app/core/{labeling.cc => project.cc} (73%) delete mode 100644 src/app/core/testable.h create mode 100644 src/app/core/utils/file_util.cc create mode 100644 src/app/core/utils/file_util.h create mode 100644 src/app/core/utils/sdl_deleter.h create mode 100644 src/app/editor/editor.cc rename src/app/editor/{CMakeLists.txt => editor.cmake} (63%) rename src/app/editor/{utils => }/editor.h (50%) rename src/app/editor/{master_editor.cc => editor_manager.cc} (79%) rename src/app/editor/{master_editor.h => editor_manager.h} (52%) delete mode 100644 src/app/editor/master_editor_test.cc create mode 100644 src/app/editor/message/message_data.cc delete mode 100644 src/app/editor/message/message_editor_test.cc rename src/app/editor/{ => overworld}/overworld_editor.cc (60%) rename src/app/editor/{ => overworld}/overworld_editor.h (60%) delete mode 100644 src/app/editor/overworld/refresh.cc create mode 100644 src/app/editor/system/command_manager.cc create mode 100644 src/app/editor/system/command_manager.h create mode 100644 src/app/editor/system/constant_manager.h create mode 100644 src/app/editor/system/extension_manager.cc create mode 100644 src/app/editor/system/extension_manager.h rename src/app/editor/{utils => system}/flags.h (90%) create mode 100644 src/app/editor/system/history_manager.h create mode 100644 src/app/editor/system/popup_manager.cc create mode 100644 src/app/editor/system/popup_manager.h create mode 100644 src/app/editor/system/resource_manager.h rename src/app/editor/{ => system}/settings_editor.cc (92%) rename src/app/editor/{ => system}/settings_editor.h (99%) delete mode 100644 src/app/editor/utils/gfx_context.cc delete mode 100644 src/app/editor/utils/gfx_context.h delete mode 100644 src/app/editor/utils/keyboard_shortcuts.h delete mode 100644 src/app/editor/utils/recent_files.h delete mode 100644 src/app/emu/debug/debugger.h delete mode 100644 src/app/emu/debug/log.h rename src/app/emu/{debug => }/emu.cc (87%) rename src/app/emu/{CMakeLists.txt => emu.cmake} (53%) rename src/app/emu/{debug => memory}/asm_parser.h (100%) create mode 100644 src/app/gfx/gfx.cmake create mode 100644 src/app/gui/gui.cmake rename src/app/gui/{ => modules}/asset_browser.cc (98%) rename src/app/gui/{ => modules}/asset_browser.h (96%) rename src/app/{yaze.cc => main.cc} (59%) delete mode 100644 src/app/rom_test.cc delete mode 100644 src/app/zelda3/dungeon/room_names.h create mode 100644 src/app/zelda3/dungeon/room_tag.h delete mode 100644 src/app/zelda3/music/spc700.def create mode 100644 src/app/zelda3/sprite/overlord.h create mode 100644 src/app/zelda3/sprite/sprite_builder.cc create mode 100644 src/app/zelda3/sprite/sprite_builder.h rename src/app/zelda3/{CMakeLists.txt => zelda3.cmake} (89%) rename src/cli/{command_handler.h => command.h} (58%) create mode 100644 src/cli/handlers/compress.cc create mode 100644 src/cli/handlers/patch.cc rename src/cli/{command_handler.cc => handlers/tile16_transfer.cc} (88%) delete mode 100644 src/cli/patch.cc delete mode 100644 src/cli/patch.h create mode 100644 src/cli/python/yaze_py.cc create mode 100644 src/cli/python/yaze_py.cmake rename src/cli/{CMakeLists.txt => z3ed.cmake} (66%) create mode 100644 src/ios/Media.xcassets/Contents.json create mode 100644 src/ios/Media.xcassets/yaze.appiconset/Contents.json create mode 100644 src/ios/Media.xcassets/yaze.appiconset/yaze.png create mode 100644 src/ios/iOS/Info-iOS.plist create mode 100644 src/ios/iOS/LaunchScreen.storyboard create mode 100644 src/ios/main.mm create mode 100644 src/ios/yaze.xcodeproj/project.pbxproj create mode 100644 src/ios/yaze.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/Bookmarks/bookmarks.plist create mode 100644 src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/WorkspaceSettings.xcsettings create mode 100644 src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 src/test/core/testing.h create mode 100644 src/test/integration/test_editor.cc create mode 100644 src/test/integration/test_editor.h rename src/{app/emu/memory => test/mocks}/mock_memory.h (100%) create mode 100644 src/test/rom_test.cc create mode 100644 src/test/zelda3/dungeon_room_test.cc create mode 100644 src/test/zelda3/message_test.cc create mode 100644 src/test/zelda3/overworld_test.cc delete mode 100644 src/test/zelda3/room_object_test.cc create mode 100644 src/test/zelda3/sprite_builder_test.cc rename src/{ => win32}/yaze.ico (100%) rename src/{ => win32}/yaze.rc (100%) rename src/{ => win32}/yaze.res (100%) create mode 100644 src/yaze.cc diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 80384621..c7d32cae 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -37,6 +37,12 @@ jobs: - name: Install Abseil-cpp run: sudo apt install libabsl-dev + - name: Install Boost and Boost Python + run: sudo apt install libboost-all-dev libboost-python-dev + + - name: Install CPython headers + run: sudo apt install python3-dev libpython3-dev + - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type diff --git a/.gitignore b/.gitignore index a22892fc..b52d20e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ +.favorites.json build/ .cache/ .vscode/ +disasm/ +src/etc src/lib/SDL2 src/lib/cmake src/lib/GL @@ -17,3 +20,13 @@ src/lib/libSDL2main.a checks.json assets/lib/libasar.dll cmake/yaze.plist.in +etc/ +latex/ +html/ +docs/zarby_algos.md +docs/overworld-expansion.md +assets/asm/EditorCore.asm +src/app/emu/cpu/internal/old_cpu.cc +build-windows +src/lib/libpng +src/lib/zlib \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index d3428b8d..eea47774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,23 @@ -# CMake Specifications -cmake_minimum_required(VERSION 3.10) - # Yet Another Zelda3 Editor # by scawful -project(yaze VERSION 0.10) +cmake_minimum_required(VERSION 3.10) +project(yaze VERSION 0.2.0 + DESCRIPTION "Yet Another Zelda3 Editor" + LANGUAGES CXX) -# C++ Standard Specifications +# Build Flags +set(YAZE_BUILD_APP ON) +set(YAZE_BUILD_LIB ON) +set(YAZE_BUILD_EMU ON) +set(YAZE_BUILD_Z3ED ON) +set(YAZE_BUILD_PYTHON OFF) +set(YAZE_BUILD_TESTS ON) +set(YAZE_INSTALL_LIB OFF) + +# libpng features in bitmap.cc +add_definitions("-DYAZE_LIB_PNG=1") + +# C++ Standard and CMake Specifications set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) @@ -14,21 +26,24 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(BUILD_SHARED_LIBS OFF) -set(CMAKE_FIND_FRAMEWORK LAST) +set(CMAKE_FIND_FRAMEWORK LAST) +set(CMAKE_SHARED_MODULE_PREFIX "") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dlinux -Dstricmp=strcasecmp") +if (MACOS) + set(CMAKE_INSTALL_PREFIX /usr/local) +endif() # Abseil Standard Specifications include(cmake/absl.cmake) -# Video Libraries -find_package(PNG REQUIRED) +# SDL2 and PNG include(cmake/sdl2.cmake) -# Asar -add_subdirectory(src/lib/asar/src) +# Asar include(cmake/asar.cmake) # ImGui include(cmake/imgui.cmake) # Project Files -add_subdirectory(src) \ No newline at end of file +add_subdirectory(src) diff --git a/Doxyfile b/Doxyfile index 22d0cd5a..0dfa6199 100644 --- a/Doxyfile +++ b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = "yaze" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = "0.2.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -61,20 +61,20 @@ PROJECT_BRIEF = Link to the Past ROM Editor # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = "src/win32/yaze.ico" # With the PROJECT_ICON tag one can specify an icon that is included in the tabs # when the HTML document is shown. Doxygen will copy the logo to the output # directory. -PROJECT_ICON = +PROJECT_ICON = "src/win32/yaze.ico" # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = +OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 # sub-directories (in 2 levels) under the output directory of each output format @@ -1168,7 +1168,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = getting-started.md # The Fortran standard specifies that for fixed formatted Fortran code all # characters from position 72 are to be considered as comment. A common @@ -1190,7 +1190,7 @@ FORTRAN_COMMENT_AFTER = 72 # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, # multi-line macros, enums or list initialized variables directly into the @@ -1402,7 +1402,7 @@ HTML_COLORSTYLE = AUTO_LIGHT # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_HUE = 280 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use gray-scales only. A @@ -2798,7 +2798,7 @@ PLANTUML_INCLUDE_PATH = # Minimum value: 0, maximum value: 10000, default value: 50. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_GRAPH_MAX_NODES = 50 +DOT_GRAPH_MAX_NODES = 25 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # generated by dot. A depth value of 3 means that only nodes reachable from the @@ -2810,7 +2810,7 @@ DOT_GRAPH_MAX_NODES = 50 # Minimum value: 0, maximum value: 1000, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. -MAX_DOT_GRAPH_DEPTH = 0 +MAX_DOT_GRAPH_DEPTH = 2 # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This diff --git a/LICENSE b/LICENSE index 9a09e586..435fc725 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2022 Justin Scofield +Copyright (C) 2024 Justin Scofield This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,3 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . +Dependencies: +- SDL2 +- ImGui +- Abseil \ No newline at end of file diff --git a/README.md b/README.md index ed1eae11..29c4f795 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Yet Another Zelda3 Editor -- Platform: Windows, macOS, GNU/Linux -- Dependencies: SDL2, ImGui +- Platform: Windows, macOS, iOS, GNU/Linux +- Dependencies: SDL2, ImGui, abseil-cpp ## Description General purpose editor for The Legend of Zelda: A Link to the Past for the Super Nintendo. +Provides bindings in C and Python for building custom tools and utilities. + Takes heavy inspiration from ALTTP community efforts such as [Hyrule Magic](https://www.romhacking.net/utilities/200/) and [ZScream](https://github.com/Zarby89/ZScreamDungeon) Building and installation @@ -14,23 +16,27 @@ Building and installation [CMake](http://www.cmake.org "CMake") is required to build yaze 1. Clone the repository +2. Create the build directory and configuration +3. Build and run the application +4. (Optional) Run the tests ``` git clone --recurse-submodules https://github.com/scawful/yaze.git -``` - -2. Create the build directory and configuration - -``` cmake -S . -B build -``` - -3. Build and run. - -``` cmake --build build ``` +By default this will build all targets. + +- **yaze**: Editor Application +- **yaze_c**: C Library +- **yaze_emu**: SNES Emulator +- **yaze_py**: Python Module +- **yaze_test**: Unit Tests +- **z3ed**: Command Line Interface + +Dependencies are included as submodules and will be built automatically. For those who want to reduce compile times, consider installing the dependencies on your system. See [build-instructions.md](docs/build-instructions.md) for more information. + ## Documentation - For users, please refer to [getting_started.md](docs/getting-started.md) for instructions on how to use yaze. diff --git a/assets/asm/ZSCustomOverworld.asm b/assets/asm/ZSCustomOverworld.asm new file mode 100644 index 00000000..fd305071 --- /dev/null +++ b/assets/asm/ZSCustomOverworld.asm @@ -0,0 +1,3563 @@ +; ============================================================================== +; ZScream Custom Overworld ASM +; ============================================================================== +; ============================================================================== +; Non-Expanded Space +; ============================================================================== + +pushpc + +AnimatedTileGFXSet = $0FC0 +TransGFXModuleIndex = $0CF3 + +Sound_LoadLightWorldSongBank = $808913 +DecompOwAnimatedTiles = $80D394 +GetAnimatedSpriteTile = $80D4DB +GetAnimatedSpriteTile_variable = $80D4ED +LoadTransAuxGFX_sprite_continue = $00D706 +Do3To4High16Bit = $80DF4F +Do3To4Low16Bit = $00DFB8 +InitTilesets = $80E19B +CopyFontToVram = $80E556 +Decomp_bg_variable = $00E78F + +DeleteCertainAncillaeStopDashing = $828B0C +Overworld_FinishTransGfx_firstHalf_Retrun = $02ABC5 +Overworld_LoadSubscreenAndSilenceSFX1 = $82AF19 +Dungeon_LoadPalettes_cacheSettings = $82C65F +LoadSubscreenOverlay = $82FD0D + +Link_ItemReset_FromOverworldThings = $87B107 + +Tagalong_Init = $899EFC +Sprite_ReinitWarpVortex = $89AF89 +Sprite_ResetAll = $89C44E +Sprite_OverworldReloadAll = $89C499 + +Overworld_SetFixedColorAndScroll = $8BFE70 + +Overworld_LoadPalettes = $8ED5A8 +Palette_SetOwBgColor_Long = $8ED618 +LoadGearPalettes_bunny = $8ED6DD + +Palette_SpriteAux3 = $9BEC77 +Palette_MainSpr = $9BEC9E +Palette_SpriteAux1 = $9BECC5 +Palette_SpriteAux2 = $9BECE4 +Palette_Sword = $9BED03 +Palette_Shield = $9BED29 +Palette_MiscSpr = $9BED6E +Palette_ArmorAndGloves = $9BEDF9 +Palette_Hud = $9BEE52 +Palette_OverworldBgMain = $9BEEC7 + +; ============================================================================== +; Fixing old hooks: +; ============================================================================== + +; Loads the transparent color under some load conditions. +org $0BFEB6 + STA.l $7EC500 + +; Main Palette loading routine. +org $0ED5E7 + JSL $9BEEA8 ; Palette_OverworldBgAux3 + +; After leaving special areas like Zora's and the Master Sword area. +org $02E94A + JSL $8ED5A8 ; Overworld_LoadPalettes + +; ============================================================================== +; Expanded Space +; ============================================================================== + +; Reserved ZS space. +; Avoid moving this at all costs. If you do, you will have to change where ZS +; saves this data as well and previous data will be lost or corrupted. +org $288000 ; $140000 +Pool: +{ + .BGColorTable ; $140000 + ; Valid values: + ; 555 color value $0000 to $7FFF. + + ; LW + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ; DW + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ; SW + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + ;dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 + warnpc $288140 + + org $288140 ; $140140 + .EnableTable ; 0x20 + ; Valid values: + ; $00 - Disabled + ; $FF - Enabled + + org $288140 ; $140140 + .EnableBGColor ; 0x01 + db $01 + + org $288141 ; $140141 + .EnableMainPalette ; 0x01 + db $01 + + org $288142 ; $140142 + .EnableMosaic ; 0x01 Unused for now. + db $01 + + ; When non 0 this will allow animated tiles to be updated between OW + ; transitions. Default is $FF. + org $288143 ; $140143 + .EnableAnimated ; 0x01 + db $01 + + ; When non 0 this will allow Subscreen Overlays to be updated between OW + ; transitions. Default is $FF. + org $288144 ; $140144 + .EnableSubScreenOverlay ; 0x01 + db $01 + + ; This is a reserved value that ZS will write to when it has applied the + ; ASM. That way the next time ZS loads the ROM it knows to read the custom + ; values instead of using the default ones. The current version is 02. + org $288145 ; $140145 + .ZSAppliedASM ; 0x01 + db $02 + + ; When non 0 this will cause rain to appear on all areas in the beginning + ; phase. Default is $FF. + org $288146 ; $140146 + .EnableBeginningRain ; 0x01 + db $FF + + ; When non 0 this will disable the ambiant sound that plays in the mire + ; area after the event is triggered. Default is $FF. + org $288147 ; $140147 + .EnableRainMireEvent ; 0x01 + db $FF + + ; When non 0 this will make the game reload all gfx in between OW + ; transitions. Default is $FF. + org $288148 ; $140143 + .EnableTransitionGFXGroupLoad ; 0x01 + db $01 + + ; The bridge color is different from the Master Sword area so we are going to + ; hard code it here for now. + org $288149 ; $140149 + .BGColorTable_Bridge ; 0x02 + dw $2669 ; Defualt vanilla LW green. + + ; The rest of these are extra bytes that can be used for anything else + ; later on. + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00 + warnpc $288160 + + org $288160 ; $140160 + .MainPaletteTable ; 0xA0 + ; Valid values: + ; Main overworld palette index $00 to $05. + ; $00 is the normal light world palette. + ; $01 is the normal dark world palette. + ; $02 is the normal light world death mountain palette. + ; $03 is the normal dark world death mountain palette. + ; $04 is the Triforce room palette. + ; $05 is the title screen palette? + + ; LW + ;db $00, $00, $00, $02, $00, $20, $00, $20 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ; DW + ;db $01, $01, $01, $03, $01, $03, $01, $03 + ;db $01, $01, $01, $01, $01, $01, $01, $01 + ;db $01, $01, $01, $01, $01, $01, $01, $01 + ;db $01, $01, $01, $01, $01, $01, $01, $01 + ;db $01, $01, $01, $01, $01, $01, $01, $01 + ;db $01, $01, $01, $01, $01, $01, $01, $01 + ;db $01, $01, $01, $01, $01, $01, $01, $01 + ;db $01, $01, $01, $01, $01, $01, $01, $01 + ; SW + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $04, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + warnpc $288200 + + org $288200 ; $140200 + .MosaicTable ; 0xA0 + ; Valid values: + ; $01 to enable mosaic, $00 to disable. + + ; LW + ;db $01, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ; DW + ;db $01, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ; SW + ;db $01, $01, $00, $00, $00, $00, $00, $00 + ;db $01, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + ;db $00, $00, $00, $00, $00, $00, $00, $00 + warnpc $2882A0 + + ; Not the same as OWGFXGroupTable_sheet7. The game uses a combination of $59 + ; and $5B to create the sheet in sheet #7. This is done by first transfering + ; all the gfx that is needed for the bottom half of the sheet (the door + ; frames for example) which is different depending on whether we are in the + ; LW or DW. It then loads the actual animated tile frames into a buffer + ; where it can transfer over from durring NMI based on whether we are on + ; Death Mountain or not (LW or DW). This table is to control the latter. + org $2882A0 ; $1402A0 + .AnimatedTable ; 0xA0 + ; Valid values: + ; GFX index $00 to $FF. + ; In vanilla, $59 are the DW door frames and clouds and $5B are the Lw door + ; frames and the regular water tiles. + + ; LW + ;db $5B, $5B, $5B, $59, $5B, $59, $5B, $59 + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ; DW + ;db $5B, $5B, $5B, $59, $5B, $59, $5B, $59 + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ; SW + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + ;db $5B, $5B, $5B, $5B, $5B, $5B, $5B, $5B + warnpc $288340 + + org $288340 ; $140340 + .OverlayTable ; 0x140 + ; Valid values: + ; Can be any value $00 to $FF but is stored as 2 bytes instead of one to + ; help the code out below. $FF is for no overlay area. Hopefully no crazy + ; person decides to expand their overworld to $FF areas. + + ; $0093 is the triforce room curtain overlay. + ; $0094 is the under the bridge overlay. + ; $0095 is the sky background overlay. + ; $0096 is the pyramid background overlay. + ; $0097 is the first fog overlay. + + ; $009C is the lava background overlay. + ; $009D is the second fog overlay. + ; $009E is the tree canopy overlay. + ; $009F is the rain overlay. + + ; LW + ;dw $009D, $00FF, $00FF, $0095, $00FF, $0095, $00FF, $0095 + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ; DW + ;dw $009D, $00FF, $00FF, $009C, $00FF, $009C, $00FF, $009C + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $0096, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $009F, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ; SP + ;dw $0097, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $0093, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + ;dw $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF, $00FF + warnpc $288480 + + org $288480 ; $140480 + .OWGFXGroupTable ; 0x500 (0xA0 * 0x08) + + ; 0xFF is used instead of 0x00 as the "don't change the sheet" value. That + ; way, we can actually use sheet 00 if we want. Just in case 0xFF is used + ; and there is no sheet to load when warping using the bird, unloading the + ; map, or exiting a dungeon, the DefaultGFXGroups values are used. + + ; LW + org $288480 ; $140480 + .OWGFXGroupTable_sheet0 + ;db $3A ; 0x00 sheet 0 + + org $288481 ; $140481 + .OWGFXGroupTable_sheet1 + ;db $3B ; 0x00 sheet 1 + + org $288482 ; $140482 + .OWGFXGroupTable_sheet2 + ;db $3C ; 0x00 sheet 2 + + org $288483 ; $140483 + .OWGFXGroupTable_sheet3 + ;db $3D ; 0x00 sheet 3 + + org $288484 ; $140484 + .OWGFXGroupTable_sheet4 + ;db $57 ; 0x00 sheet 4 + + org $288485 ; $140485 + .OWGFXGroupTable_sheet5 + ;db $4C ; 0x00 sheet 5 + + org $288486 ; $140486 + .OWGFXGroupTable_sheet6 + ;db $3E ; 0x00 sheet 6 + + org $288487 ; $140487 + .OWGFXGroupTable_sheet7 + ;db $5B ; 0x00 sheet 7 + + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x01 + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x02 + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x03 + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x04 + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x05 + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x06 + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x07 + + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x08 + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x09 + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x0A + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x0B + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x0C + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x0D + ;db $3A, $3B, $3C, $3D, $56, $4F, $3E, $5B ; 0x0E + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x0F + + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x10 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x11 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x12 + ;db $3A, $3B, $3C, $3D, $50, $4B, $3E, $5B ; 0x13 + ;db $3A, $3B, $3C, $3D, $50, $4B, $3E, $5B ; 0x14 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x15 + ;db $3A, $3B, $3C, $3D, $50, $4B, $3E, $5B ; 0x16 + ;db $3A, $3B, $3C, $3D, $50, $4B, $3E, $5B ; 0x17 + + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x18 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x19 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x1A + ;db $3A, $3B, $3C, $3D, $52, $49, $3E, $5B ; 0x1B + ;db $3A, $3B, $3C, $3D, $52, $49, $3E, $5B ; 0x1C + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x1D + ;db $3A, $3B, $3C, $3D, $55, $4A, $3E, $5B ; 0x1E + ;db $3A, $3B, $3C, $3D, $55, $4A, $3E, $5B ; 0x1F + + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x20 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x21 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x22 + ;db $3A, $3B, $3C, $3D, $52, $49, $3E, $5B ; 0x23 + ;db $3A, $3B, $3C, $3D, $52, $49, $3E, $5B ; 0x24 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x25 + ;db $3A, $3B, $3C, $3D, $55, $4A, $3E, $5B ; 0x26 + ;db $3A, $3B, $3C, $3D, $55, $4A, $3E, $5B ; 0x27 + + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x28 + ;db $3A, $3B, $3C, $3D, $50, $4B, $3E, $5B ; 0x29 + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x2A + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x2B + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x2C + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x2D + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x2E + ;db $3A, $3B, $3C, $3D, $55, $4A, $3E, $5B ; 0x2F + + ;db $3A, $3B, $3C, $3D, $55, $54, $3E, $5B ; 0x30 + ;db $3A, $3B, $3C, $3D, $55, $54, $3E, $5B ; 0x31 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x32 + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x33 + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x34 + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x35 + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x36 + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x37 + + ;db $3A, $3B, $3C, $3D, $55, $54, $3E, $5B ; 0x38 + ;db $3A, $3B, $3C, $3D, $55, $54, $3E, $5B ; 0x39 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x3A + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x3B + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x3C + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x3D + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x3E + ;db $3A, $3B, $3C, $3D, $51, $4E, $3E, $5B ; 0x3F + + ; DW + ;db $42, $43, $44, $45, $2D, $2E, $3F, $59 ; 0x40 + ;db $42, $43, $44, $45, $2D, $2E, $3F, $59 ; 0x41 + ;db $42, $43, $44, $45, $2D, $2E, $3F, $59 ; 0x42 + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x43 + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x44 + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x45 + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x46 + ;db $42, $43, $44, $45, $60, $34, $3F, $59 ; 0x47 + + ;db $42, $43, $44, $45, $2D, $2E, $3F, $59 ; 0x48 + ;db $42, $43, $44, $45, $2D, $2E, $3F, $59 ; 0x49 + ;db $42, $43, $44, $45, $2D, $2E, $3F, $59 ; 0x4A + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x4B + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x4C + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x4D + ;db $42, $43, $44, $45, $33, $34, $3F, $59 ; 0x4E + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x4F + + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x50 + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x51 + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x52 + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x53 + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x54 + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x55 + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x56 + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x57 + + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x58 + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x59 + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x5A + ;db $42, $43, $44, $45, $35, $36, $3F, $59 ; 0x5B + ;db $42, $43, $44, $45, $35, $36, $3F, $59 ; 0x5C + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x5D + ;db $42, $43, $44, $45, $2B, $2C, $3F, $59 ; 0x5E + ;db $42, $43, $44, $45, $2B, $2C, $3F, $59 ; 0x5F + + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x60 + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x61 + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x62 + ;db $42, $43, $44, $45, $35, $36, $3F, $59 ; 0x63 + ;db $42, $43, $44, $45, $35, $36, $3F, $59 ; 0x64 + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x65 + ;db $42, $43, $44, $45, $2B, $2C, $3F, $59 ; 0x66 + ;db $42, $43, $44, $45, $2B, $2C, $3F, $59 ; 0x67 + + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x68 + ;db $42, $43, $44, $45, $2F, $30, $3F, $59 ; 0x69 + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x6A + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x6B + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x6C + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x6D + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x6E + ;db $42, $43, $44, $45, $2B, $2C, $3F, $59 ; 0x6F + + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x70 + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x71 + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x72 + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x73 + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x74 + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x75 + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x76 + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x77 + + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x78 + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x79 + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x7A + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x7B + ;db $42, $43, $44, $45, $37, $38, $3F, $59 ; 0x7C + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x7D + ;db $42, $43, $44, $45, $31, $32, $3F, $59 ; 0x7E + ;db $42, $43, $44, $45, $20, $2B, $3F, $59 ; 0x7F + + ; SW + ;db $3A, $3B, $3C, $3D, $47, $48, $3E, $5B ; 0x80 + ;db $3A, $3B, $3C, $3D, $47, $48, $3E, $5B ; 0x81 + ;db $3A, $3B, $3C, $3D, $47, $48, $3E, $5B ; 0x82 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x83 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x84 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x85 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x86 + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x87 + + ;db $3A, $3B, $3C, $17, $40, $41, $39, $5B ; 0x88 + ;db $3A, $3B, $3C, $3D, $47, $48, $3E, $5B ; 0x89 + ;db $3A, $3B, $3C, $3D, $47, $48, $3E, $5B ; 0x8A + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x8B + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x8C + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x8D + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x8E + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x8F + + ;db $3A, $3B, $3C, $08, $00, $22, $1B, $5B ; 0x90 + ;db $3A, $3B, $3C, $08, $00, $22, $1B, $5B ; 0x91 + ;db $3A, $3B, $3C, $06, $53, $1F, $18, $5B ; 0x92 + ;db $3A, $3B, $3C, $08, $53, $22, $1B, $5B ; 0x93 + ;db $3A, $3B, $3C, $3D, $53, $47, $48, $5B ; 0x94 + ;db $3A, $3B, $3C, $3D, $53, $56, $4F, $5B ; 0x95 + ;db $3A, $3B, $3C, $3D, $35, $36, $3E, $5B ; 0x96 + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x97 + + ;db $3A, $3B, $3C, $08, $00, $22, $1B, $5B ; 0x98 + ;db $3A, $3B, $3C, $08, $00, $22, $1B, $5B ; 0x99 + ;db $3A, $3B, $3C, $06, $53, $1F, $18, $5B ; 0x9A + ;db $3A, $3B, $3C, $06, $53, $1F, $18, $5B ; 0x9B + ;db $3A, $3B, $3C, $3D, $53, $33, $34, $5B ; 0x9C + ;db $3A, $3B, $3C, $3D, $53, $57, $4C, $5B ; 0x9D + ;db $3A, $3B, $3C, $3D, $57, $4C, $3E, $5B ; 0x9E + ;db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B ; 0x9F + warnpc $288980 + + ; TODO: Add a way to edit these within ZS? Unsure. + org $288980 ; $140980 + .DefaultGFXGroups + + ; LW + org $288980 ; $140980 + .DefaultGFXGroups_sheet0 + db $3A ; Sheet 0 + + org $288981 ; $140981 + .DefaultGFXGroups_sheet1 + db $3B ; Sheet 1 + + org $288982 ; $140982 + .DefaultGFXGroups_sheet2 + db $3C ; Sheet 2 + + org $288983 ; $140983 + .DefaultGFXGroups_sheet3 + db $3D ; Sheet 3 + + org $288984 ; $140984 + .DefaultGFXGroups_sheet4 + db $53 ; Sheet 4 + + org $288985 ; $140985 + .DefaultGFXGroups_sheet5 + db $4D ; Sheet 5 + + org $288986 ; $140986 + .DefaultGFXGroups_sheet6 + db $3E ; Sheet 6 + + org $288987 ; $140987 + .DefaultGFXGroups_sheet7 + db $5B ; Sheet 7 + + ; DW + db $42, $43, $44, $45, $2F, $30, $3F, $59 + + ; SW + db $3A, $3B, $3C, $3D, $47, $48, $3E, $5B + + warnpc $288998 ; $140998 +} + +; Debug addresses: +; $00D8D5 ; W7 Animated tiles on warp. +!Func00D8D5 = $01 +; $00DA63 ; W8 Enable/Disable subscreen. +!Func00DA63 = $01 +; $00E133 ; T2.5 (probably) ; Makes the game decompress the 3 static OW tile +; sheets on transition. +!Func00E133 = $01 +; $006221 ; Changes the InitTilesets function to call from the long tables. +!Func00E221 = $01 +; $00EEBB ; Zeros out the BG color when mirror warping to the pyramid area. +!Func00EEBB = $01 +; $00FF7C ; W9 BG scrolling for HC and the pyramid area. +!Func00FF7C = $01 + +; Some old but now unused addresses: +; $028027 +; $029C0C +; $029D1E +; $029F82 + +; $0283EE ; E2 ; Changes the function that loads overworld properties when +; exiting a dungeon. Includes removing asm that plays music in certain areas +; and changing how animated tiles are loaded. +!Func0283EE = $01 +; $028632 ; Changes a function that loads animated tiles under certain +; conditions. +!Func028632 = $01 +; $029AA6 ; E1 ; Changes part of a function that changes the sub mask color +; when leaving dungeons. +!Func029AA6 = $01 +; $02AF58 ; T2 S2 W2 Main subscreen loading function. +!Func02AF58 = $01 +; $02B2D4 ; W1 turns on subscreen for pyramid. +!Func02B2D4 = $01 +; $02B3A1 ; W6 Activate subscreen durring pyramid warp. +!Func02B3A1 = $01 +; $02BC44 ; Controls overworld vertical subscreen movement for the pyramid BG. +!Func02BC44 = $01 +; $02C02D ; T4 Changes how the pyramid BG scrolls durring transition. +!Func02C02D = $01 +; $02C692 ; W3 Main palette loading routine. +!Func02C692 = $01 +; $02A4CD ; Rain animation code. +!Func02A4CD = $01 +; $02AADB ; T1 Mosaic. +!Func02AADB = $01 +; $02ABBE ; T3 transition animated and main palette. +!Func02ABBE = $01 +; $0ABC5A ; Loads the animated tiles after the overworld map is closed. +!Func0ABC5A = $01 +; $0AB8F5 ; Loads different animated tiles when returning from bird travel. +!Func0AB8F5 = $01 +; $0BFEC6 ; W5 Load overlay, fixed color, and BG color. +!Func0BFEC6 = $01 +; $0ED627 ; S1 W4 Transparent color durring warp and during special area enter. +!Func0ED627 = $01 +; $0ED8AE ; Resets the area special color after the screen flashes. +!Func0ED8AE = $01 + +; Start of expanded space. +org $2892B8 ; $1412B8 +pushpc + +; ============================================================================== + +if !Func00D8D5 = 1 + +; Replaces a function that decompresses animated tiles in certain mirror warp +; conditions. +org $00D8D5 ; $0058D5 +AnimateMirrorWarp_DecompressAnimatedTiles: +{ + PHX + + ; The decompression function increases it by 1 so subtract 1 here. + JSL ReadAnimatedTable : DEC : TAY + + PLX + + JSL DecompOwAnimatedTiles + + RTL +} +warnpc $00D8EE + +else + +; Undo the function above: +org $00D8D5 ; $0058D5 +db $A0, $58, $A5, $8A, $29, $BF, $C9, $03 +db $F0, $0A, $C9, $05, $F0, $06, $C9, $07 +db $F0, $02, $A0, $5A, $22, $94, $D3, $00 +db $6B + +endif + +pullpc +ReadAnimatedTable: +{ + PHB : PHK : PLB + + REP #$30 ; Set A, X, and Y in 16bit mode. + LDA.b $8A : TAX + AND.w #$00C0 : LSR #3 : TAY ; (Area / 8) = LW, DW, or SW *8 + SEP #$20 ; Set A in 8bit mode. + + ; $00 crashes the game so just double check that. + LDA.w Pool_AnimatedTable, X : BNE .not007 + LDA.w Pool_DefaultGFXGroups_sheet7, Y + + BRA .notFF7 + + .not007 + + ; Load the default sheet if the value is FF. + CMP.b #$FF : BNE .notFF7 + LDA.w Pool_DefaultGFXGroups_sheet7, Y + + .notFF7 + + SEP #$10 ; Set X and Y in 8bit mode. + + PLB + + RTL +} +pushpc + +; ============================================================================== + +if !Func00DA63 = 1 + +org $00D8F4 ; $0058F4 + SheetsTable_0AA4: + +; The first half of this function enables or disables BG1 for subscreen overlay +; use depending on the area. The second half reloads global sprite #2 sheet +; (rock vs skulls, different bush gfx, fish vs bone fish, etc.) based on what +; world we are in. +org $00DA63 ; $005A63 +AnimateMirrorWarp_LoadSubscreen: +{ + JSL ActivateSubScreen + + ; From this point on it is the vanilla function. + PHB : PHK : PLB + + ; TODO: Eventually un-hardcode this. + ; X = 0 for LW, 8 for DW + LDA.l SheetsTable_0AA4, X : TAY + + ; Get the pointer for one of the 2 Global sprite #2 sheets. + LDA.w $D1B1, Y : STA.b $00 + LDA.w $D0D2, Y : STA.b $01 + LDA.w $CFF3, Y : STA.b $02 : STA.b $05 + + PLB + + REP #$31 ; Set A, X, and Y in 16bit mode. +1 no idea. + + ; Source address is determined above, number of tiles is 0x0040, base + ; target address is $7F0000. + LDX.w #$0000 + LDY.w #$0040 + + LDA.b $00 + + JSR.w Do3To4High16Bit + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + RTL +} +warnpc $00DABB + +else + +; Undo the function above: +org $00DA63 ; $005A63 +db $64, $1D, $A5, $8A, $F0, $24, $C9, $70 +db $F0, $20, $C9, $40, $F0, $1C, $C9, $5B +db $F0, $18, $C9, $03, $F0, $14, $C9, $05 +db $F0, $10, $C9, $07, $F0, $0C, $C9, $43 +db $F0, $08, $C9, $45, $F0, $04, $C9, $47 +db $D0, $04, $A9, $01, $85, $1D, $8B, $4B +db $AB, $BF, $F4, $D8, $00, $A8, $B9, $B1 +db $D1, $85, $00, $B9, $D2, $D0, $85, $01 +db $B9, $F3, $CF, $85, $02, $85, $05, $AB +db $C2, $31, $A2, $00, $00, $A0, $40, $00 +db $A5, $00, $20, $4F, $DF, $E2, $30, $6B + +endif + +pullpc +ActivateSubScreen: +{ + STZ.b $1D + + PHX + + REP #$20 ; Set A in 16bit mode. + + LDA.b $8A : BNE .notForest + ; Check if we have the master sword. + LDA.l $7EF300 : AND.w #$0040 : BEQ .notForest + ; The forest canopy overlay. + BRA .turnOn + + .notForest + + ; Check if we need to disable the rain in the misery mire. + LDA.w Pool_EnableRainMireEvent : BEQ .notMire + LDA.b $8A : CMP.w #$0070 : BNE .notMire + ; Has Misery Mire been triggered yet? + LDA.l $7EF2F0 : AND.w #$0020 : BNE .notMire + BRA .turnOn + + .notMire + + ; Check if we are in the beginning phase, if not, no rain. + ; If $7EF3C5 >= 0x02. + LDA.l $7EF3C5 : AND.w #$00FF : CMP.w #$0002 : BCS .noRain + BRA .turnOn + + .noRain + + ; Get the overlay value for this overworld area. + JSL ReadOverlayArray : CMP.w #$00FF : BEQ .normal + ; If not $FF, assume we want an overlay. + + .turnOn + SEP #$20 ; Set A in 8bit mode. + + ; Turn on BG1. + LDA.b #$01 : STA.b $1D + + .normal + + SEP #$20 ; Set A in 8bit mode. + + PLX + + RTL +} +pushpc + +; ============================================================================== + +if !Func00EEBB = 1 + +; Zeros out the BG color when mirror warping to the pyramid area. +; TODO: This is done in the vanilla I think as just a precaution at the apex of +; the fade to white to make sure all of the colors truly are white but it may +; not actually be needed. +org $00EEBB ; $006EBB +Func00EEBB: +{ + ; Check if we are warping to an area with the pyramid BG. + JSL ReadOverlayArray : CMP.w #$0096 : BNE .notHyruleCastle + ; This is annoying but I just needed a little bit of extra space. + JSL EraseBGColors + + .notHyruleCastle + + SEP #$20 ; Set A in 8bit mode. + + LDA.b #$08 : STA.w $06BB + + STZ.w $06BA + + RTL +} +warnpc $00EEE0 + +else + +; Undo the function above: +org $00EEBB ; $006EBB +db $A5, $8A, $C9, $1B, $00, $D0, $13, $A9 +db $00, $00, $8F, $00, $C3, $7E, $8F, $40 +db $C3, $7E, $8F, $00, $C5, $7E, $8F, $40 +db $C5. $7E, $E2, $20, $A9, $08, $8D, $BB +db $06, $9C, $BA, $06, $6B + +endif + +pullpc +EraseBGColors: +{ + LDA.w #$0000 : STA.l $7EC300 : STA.l $7EC340 : STA.l $7EC500 : STA.l $7EC540 + + RTL +} +pushpc + +; ============================================================================== + +if !Func00FF7C = 1 + +; Controls the BG scrolling for HC and the pyramid area. +org $00FF7C ; $007F7C +Func00FF7C: +{ + LDA.w $1C80 : ORA.w $1C90 : ORA.w $1CA0 : ORA.w $1CB0 : CMP.b $E2 : BNE .BRANCH_DELTA + SEP #$30 ; Set A, X, and Y in 8bit mode. + + STZ.b $9B + + INC.b $B0 + + JSL Overworld_SetFixedColorAndScroll + + REP #$30 ; Set A, X, and Y in 16bit mode. + + ; Check if we are warping to an area with the pyramid BG. + JSL ReadOverlayArray : CMP.w #$0096 : BEQ .dont_align_bgs + LDA.b $E2 : STA.b $E0 : STA.w $0120 : STA.w $011E + LDA.b $E8 : STA.b $E6 : STA.w $0122 : STA.w $0124 + + .dont_align_bgs + .BRANCH_DELTA + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + RTL +} +; This end point also uses up a null block at the end of the function. +warnpc $00FFC0 + +else + +; Undo the function above: +org $00FF7C ; $007F7C +db $AD, $80, $1C, $0D, $90, $1C, $0D, $A0 +db $1C, $0D, $B0, $1C, $C5, $E2, $D0, $28 +db $E2, $20, $64, $9B, $E6, $B0, $22, $70 +db $FE, $0B, $A5, $8A, $29, $3F, $C9, $1B +db $F0, $16, $C2, $20, $A5, $E2, $85, $E0 +db $8D, $20, $01, $8D, $1E, $01, $A5, $E8 +db $85, $E6, $8D, $22, $01, $8D, $24, $01 +db $E2, $30, $6B, $FF, $FF, $FF, $FF, $FF +db $FF, $FF, $FF, $FF + +endif + +; ============================================================================== + +if !Func0283EE = 1 + +; Replaces a bunch of calls to a shared function. +; Intro_SetupScreen: +org $028027 ; $010027 + JSR.w PreOverworld_LoadProperties_LoadMain_LoadMusicIfNeeded + +warnpc $02802B + +; Dungeon_LoadSongBankIfNeeded: +org $029C0C ; $011C0C + JMP PreOverworld_LoadProperties_LoadMain_LoadMusicIfNeeded + +warnpc $029C0F + +; Mirror_LoadMusic: +org $029D1E ; $011D1E + JSR.w PreOverworld_LoadProperties_LoadMain_LoadMusicIfNeeded + +warnpc $029D21 + +; GanonEmerges_LOadPyramidArea: +org $029F82 ; $011F82 + JSR.w PreOverworld_LoadProperties_LoadMain_LoadMusicIfNeeded + +warnpc $029F85 + +; Changes the function that loads overworld properties when exiting a dungeon. +; Includes removing asm that plays music in certain areas and changing how +; animated tiles are loaded. +org $0283EE ; $0103EE +PreOverworld_LoadProperties_LoadMain: +{ + LDX.b #$F3 + + ; If the volume was set to half, set it back to full. + LDA.w $0132 : CMP.b #$F2 : BEQ .setToFull + ; If we're in the dark world + ; If area number is < 0x40 or >= 80 we are not in the dark world. + LDA.b $8A : CMP.b #$40 : BCC .setNormalSong + CMP.b #$80 : BCS .setNormalSong + ; Does Link have a moon pearl? + LDA.l $7EF357 : BNE .setNormalSong + ; If not, play the music that plays when you're a bunny in the + ; Dark World. + LDX.b #$04 + + BRA .setToFull + + .setNormalSong + + LDX.b $8A + LDA.l $7F5B00, X : AND.b #$0F : TAX + + .setToFull + + ; The value written here will take effect during NMI. + STX.w $0132 + + ; Set the ambient sound. Removed becuase this is also done later on. + ;LDX.b $8A + ;LDA.l $7F5B00, X : LSR #4 : STA.w $012D + + ; The decompression function increases it by 1 so subtract 1 here. + JSL ReadAnimatedTable : DEC : TAY + + JSL DecompOwAnimatedTiles + + ; Decompress all other graphics. + JSL InitTilesets + + ; Load palettes for overworld. + JSR.w Overworld_LoadAreaPalettes + + LDX.b $8A + + LDA.l $7EFD40, X : STA.b $00 + + LDA.l $00FD1C, X + + ; Load some other palettes. + JSL Overworld_LoadPalettes + + ; Sets the background color (changes depending on area). + JSL Palette_SetOwBgColor_Long + + LDA.b $10 : CMP.b #$08 : BNE .specialArea2 + ; Copies $7EC300[0x200] to $7EC500[0x200]. + JSR.w Dungeon_LoadPalettes_cacheSettings + + BRA .normalArea2 + + .specialArea2 + + ; Apparently special overworld handles palettes a bit differently? + JSR.w $C6EB ; $0146EB IN ROM + + .normalArea2 + + ; Sets fixed colors and scroll values. + JSL Overworld_SetFixedColorAndScroll + + ; Set darkness level to zero for the overworld. + LDA.b #$00 : STA.l $7EC017 + + ; Sets up properties in the event a tagalong shows up. + JSL Tagalong_Init + + ; Set animated sprite gfx for area 0x00 and 0x40. + LDA.b $8A : AND.b #$3F : BNE .notForestArea + LDA.b #$1E + + JSL GetAnimatedSpriteTile_variable + + .notForestArea + + ; Cache the overworld mode 0x09. + LDA.b #$09 : STA.w $010C + JSL Sprite_OverworldReloadAll ; $09C499 + + ; Are we in the dark world? If so, there's no warp vortex there. + LDA.b $8A : AND.b #$40 : BNE .noWarpVortex + JSL Sprite_ReinitWarpVortex + + .noWarpVortex + + ; Check if Blind disguised as a crystal maiden was following us when + ; we left the dungeon area. + LDA.l $7EF3CC : CMP.b #$06 : BNE .notBlindGirl + ; If it is Blind, kill her! + LDA.b #$00 : STA.l $7EF3CC + + .notBlindGirl + + ; Reset player variables. + STZ.b $6C ; In doorway flag + STZ.b $3A ; BY Bitfield + STZ.b $3C ; B Button timer + STZ.b $50 ; Link strafe + STZ.b $5E ; Link speed handler + STZ.w $0351 ; Link feet gfx fx + + ; Reinitialize many of Link's gameplay variables. + JSR.w $8B0C ; $010B0C IN ROM + + LDA.l $7EF357 : BNE .notBunny + LDA.l $7EF3CA : BEQ .notBunny + LDA.b #$01 : STA.w $02E0 : STA.b $56 + + LDA.b #$17 : STA.b $5D + + JSL LoadGearPalettes_bunny + + .notBunny + + ; Set screen to mode 1 with BG3 priority. + LDA.b #$09 : STA.b $94 + + LDA.b #$00 : STA.l $7EC005 + + STZ.w $046C ; Collision BG1 flag + STZ.b $EE ; Reset Link layer to BG2 + STZ.w $0476 ; Another layer flag + + INC.b $11 ; SCAWFUL: We should verify what submodule this is moving to. + INC.b $16 ; NMI HUD Update flag + + STZ.w $0402 : STZ.w $0403 + + ; Vanilla alternate entry point. Called in 4 different locations all of + ; which are overwritten above. + .LoadMusicIfNeeded + + LDA.w $0136 : BEQ .no_music_load_needed + SEI + + ; Shut down NMI until music loads. + STZ.w $4200 + + ; Stop all HDMA. + STZ.w $420C + + STZ.w $0136 + + LDA.b #$FF : STA.w $2140 + + JSL Sound_LoadLightWorldSongBank + + ; Re-enable NMI and joypad. + LDA.b #$81 : STA.w $4200 + + .no_music_load_needed + + ; PLACE CUSTOM GFX LOAD HERE! + ;JSL CheckForChangeGraphicsNormalLoadCastle + + RTS +} +warnpc $02856A ; $01056A + +else + +; Undo the function above: +org $028027 ; $010027 + db $20, $4C, $85, $C2 + +org $029C0C ; $011C0C + db $4C, $4C, $85, $A5 + +org $029D1E ; $011D1E + db $20, $4C, $85 + +org $029F82 ; $011F82 + db $20, $4C, $85 + +org $0283EE ; $0103EE +db $A0, $58, $A2, $02, $A5, $8A, $C9, $03 +db $F0, $6F, $C9, $05, $F0, $6B, $C9, $07 +db $F0, $67, $A2, $09, $A5, $8A, $C9, $43 +db $F0, $5F, $C9, $45, $F0, $5B, $C9, $47 +db $F0, $57, $A0, $5A, $A5, $8A, $C9, $40 +db $B0, $3A, $A2, $07, $AF, $C5, $F3, $7E +db $C9, $03, $90, $02, $A2, $02, $A5, $A0 +db $C9, $E3, $F0, $3D, $C9, $18, $F0, $39 +db $C9, $2F, $F0, $35, $A5, $A0, $C9, $1F +db $D0, $06, $A5, $8A, $C9, $18, $F0, $29 +db $A2, $05, $AF, $00, $F3, $7E, $29, $40 +db $F0, $02, $A2, $02, $A5, $A0, $F0, $19 +db $C9, $E1, $F0, $15, $A2, $F3, $AD, $32 +db $01, $C9, $F2, $F0, $30, $A2, $02, $AF +db $C5, $F3, $7E, $C9, $02, $B0, $02, $A2 +db $03, $AF, $CA, $F3, $7E, $F0, $1E, $A2 +db $0D, $A5, $8A, $C9, $40, $F0, $0E, $C9 +db $43, $F0, $0A, $C9, $45, $F0, $06, $C9 +db $47, $F0, $02, $A2, $09, $AF, $57, $F3 +db $7E, $D0, $02, $A2, $04, $8E, $32, $01 +db $22, $94, $D3, $00, $22, $9B, $E1, $00 +db $20, $92, $C6, $A6, $8A, $BF, $40, $FD +db $7E, $85, $00, $BF, $1C, $FD, $00, $22 +db $A8, $D5, $0E, $22, $18, $D6, $0E, $A5 +db $10, $C9, $08, $D0, $05, $20, $5F, $C6 +db $80, $03, $20, $EB, $C6, $22, $70, $FE +db $0B, $A9, $00, $8F, $17, $C0, $7E, $22 +db $FC, $9E, $09, $A5, $8A, $29, $3F, $D0 +db $06, $A9, $1E, $22, $ED, $D4, $00, $A9 +db $09, $8D, $0C, $01, $22, $99, $C4, $09 +db $A5, $8A, $29, $40, $D0, $04, $22, $89 +db $AF, $09, $A2, $05, $AF, $C5, $F3, $7E +db $C9, $02, $B0, $02, $A2, $01, $8E, $2D +db $01, $AF, $CC, $F3, $7E, $C9, $06, $D0 +db $06, $A9, $00, $8F, $CC, $F3, $7E, $64 +db $6C, $64, $3A, $64, $3C, $64, $50, $64 +db $5E, $9C, $51, $03, $20, $0C, $8B, $AF +db $57, $F3, $7E, $D0, $15, $AF, $CA, $F3 +db $7E, $F0, $0F, $A9, $01, $8D, $E0, $02 +db $85, $56, $A9, $17, $85, $5D, $22, $DD +db $D6, $0E, $A9, $09, $85, $94, $A9, $00 +db $8F, $05, $C0, $7E, $9C, $6C, $04, $64 +db $EE, $9C, $76, $04, $E6, $11, $E6, $16 +db $9C, $02, $04, $9C, $03, $04, $AD, $36 +db $01, $F0, $18, $78, $9C, $00, $42, $9C +db $0C, $42, $9C, $36, $01, $A9, $FF, $8D +db $40, $21, $22, $13, $89, $00, $A9, $81 +db $8D, $00, $42, $60 + +endif + +; ============================================================================== + +if !Func028632 = 1 + +; Changes a function that loads animated tiles under certain conditions. +org $028632 ; $010632 +Func028632: +{ + ; The decompression function increases it by 1 so subtract 1 here. + JSL ReadAnimatedTable : DEC : TAY + + JSL DecompOwAnimatedTiles + + ; SCAWFUL: Verify the submodule ID being manipulated here. + LDA.b $11 : LSR A : TAX + + ; SCAWFUL: Spriteset1 $0AA3 is being modified, let's verify the table. + LDA.l $0285E2, X : STA.w $0AA3 + + LDA.l $0285F3, X : PHA + + JSL InitTilesets + + ; Load Palettes. + JSR.w Overworld_LoadAreaPalettes + PLA : STA.b $00 + + LDX.b $8A + + LDA.l $00FD1C, X + + JSL Overworld_LoadPalettes + + LDA.b #$01 : STA.w $0AB2 + + JSL Palette_Hud + + LDA.l $11 : BNE .BRANCH_4 + JSL CopyFontToVram + + .BRANCH_4 + + JSR.w Dungeon_LoadPalettes_cacheSettings + JSL Overworld_SetFixedColorAndScroll + + LDA.l $8A : CMP.b #$80 : BCC .BRANCH_5 + JSL Palette_SetOwBgColor_Long + + .BRANCH_5 + + LDA.b #$09 : STA.b $94 + + INC.b $B0 + + RTS +} +warnpc $028697 + +else + +; Undo the function above: +org $028632 ; $010632 +db $A0, $58, $A5, $8A, $29, $BF, $C9, $03 +db $F0, $0A, $C9, $05, $F0, $06, $C9, $07 +db $F0, $02, $A0, $5A, $22, $94, $D3, $00 +db $A5, $11, $4A, $AA, $BF, $E2, $85, $02 +db $8D, $A3, $0A, $BF, $F3, $85, $02, $48 +db $22, $9B, $E1, $00, $20, $92, $C6, $68 +db $85, $00, $A6, $8A, $BF, $1C, $FD, $00 +db $22, $A8, $D5, $0E, $A9, $01, $8D, $B2 +db $0A, $22, $52, $EE, $1B, $A5, $11, $D0 +db $04, $22, $56, $E5, $00, $20, $5F, $C6 +db $22, $70, $FE, $0B, $A5, $8A, $C9, $80 +db $90, $04, $22, $18, $D6, $0E, $A9, $09 +db $85, $94, $E6, $B0, $60 + +endif + +; ============================================================================== + +if !Func029AA6 = 1 + +; Changes part of a function that changes the sub mask color when leaving +; dungeons. +org $029AA6 ; $011AA6 +Func029AA6: +{ + ; Setup fixed color values based on area number. + LDX.w #$4C26 + LDY.w #$8C4C + + ; TODO: Wtf why is this 0x00? + ; Check for LW death mountain. + JSL ReadOverlayArray : CMP.w #$0095 : BEQ .mountain + LDX.w #$4A26 : LDY.w #$874A + + ; Check for DW death mountain. + CMP.w #$009C : BEQ .mountain + BRA .other + + .mountain + + STX.b $9C : STY.b $9D + + .other + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + RTS +} +warnpc $029AD3 + +else + +; Undo the function above: +org $029AA6 ; $011AA6 +db $A5, $8A, $C9, $03, $00, $F0, $1F, $C9 +db $05, $00, $F0, $1A, $C9, $07, $00, $F0 +db $15, $A2, $26, $4A, $A0, $4A, $87, $C9 +db $43, $00, $F0, $0A, $C9, $45, $00, $F0 +db $05, $C9, $47, $00, $D0, $04, $86, $9C +db $84, $9D, $E2, $30, $60 + +endif + +; ============================================================================== + +if !Func02AF58 = 1 + +; Main subscreen overlay loading function. Changed so that they will load +; from a table. This does not change the event overlays like the lost woods +; changing to the tree canopy, the master sword area or the misery mire rain. +; This also does not change the overlay for under the bridge because it shares +; an area with the master sword. +org $02AF58 ; $012F58 +CustomOverworld_LoadSubscreenOverlay_PostInit: +{ + SEP #$20 ; Set A in 8bit mode. + + ; Check to see if we are using the mirror so that our $A0 doesn't + ; accidentally persist and we trigger rain sounds when we don't want them. + LDA.b $11 : CMP.b #$23 : BEQ .mirrorWarp + CMP.b #$24 : BEQ .mirrorWarp + CMP.b #$2C : BEQ .mirrorWarp + ; We can't warp to or from a special area anyway so this is fine. + + REP #$20 ; Set A in 16bit mode. + + ; Check to see if we are in a SW overworld area. + LDA.b $8A : CMP.w #$0080 : BCC .notExtendedArea + ; $0182 is the exit room number used for getting to Zora's Domain. + LDA.b $A0 : CMP.w #$0182 : BNE .notZoraFalls + SEP #$20 ; Set A in 8bit mode. + + ; Play rain (waterfall) sound. + ; TODO: Write a patch to change/disable this. + LDA.b #$01 : STA.w $012D + + REP #$20 ; Set A in 16bit mode. + + .notZoraFalls + + ; Check for exit rooms (the faked way of getting from one overworld + ; area to another). $0180 is the exit room number used for getting + ; into the mastersword area. + LDA.b $A0 : CMP.w #$0180 : BNE .notMasterSwordArea + ; If the Master sword is retrieved, don't do the mist overlay. + LDA.l $7EF300 : AND.w #$0040 : BNE .masterSwordRecieved + JSL ReadOverlayArray : TAX + + .loadOverlayShortcut + + ; Save the overlay for later. + PHX + + JMP .loadSubScreenOverlay + + .masterSwordRecieved + + ; TODO: Write a patch to change what overlay is loaded here? + BRA .noSubscreenOverlay + + .notMasterSwordArea + + ; TODO: Write a patch to change what overlay is loaded here? + ; The second mastersword/under the bridge area. + LDX.w #$0094 + + ; $0181 is the exit room number used for getting into the under the + ; bridge area. + LDA.b $A0 : CMP.w #$0181 : BEQ .loadOverlayShortcut + ; TODO: Write a patch to change what overlay is loaded here? + ; The second Triforce room area. + LDX.w #$0093 + + ; $0189 is the exit room number used for getting to the + ; Triforce room. + CMP.w #$0189 : BEQ .loadOverlayShortcut + .noSubscreenOverlay + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + STZ.b $1D ; Clear TSQ PPU Register, to be handled in NMI. + + INC.b $11 ; SCAWFUL: Verify the submodule we are moving to. + + RTS + + .notExtendedArea + .mirrorWarp + + REP #$20 ; Set A in 16bit mode. + + JSL ReadOverlayArray : TAX + + LDA.b $8A : BNE .notForest + ; Check if we have the master sword. + LDA.l $7EF300 : AND.w #$0040 : BEQ .notForest + ; TODO: Write a patch to change this? + ; The forest canopy overlay. + LDX.w #$009E + + .notForest + + ; Check if we need to disable the rain in the misery mire. + LDA.l Pool_EnableRainMireEvent : BEQ .notMire + LDA.b $8A : CMP.w #$0070 : BNE .notMire + ; Has Misery Mire been triggered yet? + LDA.l $7EF2F0 : AND.w #$0020 : BNE .notMire + ; The rain overlay. + LDX.w #$009F + + SEP #$20 ; Set A in 8bit mode. + + ; Load the rain sound effect. + ; This is done here because of some jank in the vanilla code in + ; this function a bit further down. Basically it loads the + ; overlay's ambient sound instead of the acutal areas, which + ; only seems to benefit us here. + LDA.b #$01 : STA.w $012D + + REP #$20 ; Set A in 16bit mode. + + .notMire + + ; Check if we are in the beginning phase, if not, no rain. + ; If $7EF3C5 >= 0x02. + LDA.l Pool_EnableBeginningRain : BEQ .noRain + LDA.l $7EF3C5 : AND.w #$00FF : CMP.w #$0002 : BCS .noRain + ; The rain overlay. + LDX.w #$009F + + .noRain + + ; Store the overlay for later. + PHX + + ; If the value is 0xFF that means we didn't set any overlay so load the + ; pyramid one by default. + CPX.w #$00FF : BNE .notFF + ; The pyramid background. + LDX.w #$0096 + + .notFF + + ; $01300B ALTERNATE ENTRY POINT ; TODO: Verify this. If it is an alternate + ; entry I can't find where it is referenced anywhere. + .loadSubScreenOverlay + STY.b $84 + + STX.b $8A : STX.b $8C + + ; Overworld map16 buffer manipulation during scrolling. + LDA.b $84 : SEC : SBC.w #$0400 : AND.w #$0F80 : ASL A : XBA : STA.b $88 + LDA.b $84 : SEC : SBC.w #$0010 : AND.w #$003E : LSR A : STA.b $86 + + STZ.w $0418 : STZ.w $0410 : STZ.w $0416 + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + ; Color +/- buffered register. + LDA.b #$82 : STA.b $99 + + ; Puts OBJ, BG2, and BG3 on the main screen. + LDA.b #$16 : STA.b $1C + + ; Puts BG1 on the subscreen. + LDA.b #$01 : STA.b $1D + + ; Pull the 16 bit overlay from earlier and just discard the high byte. + PLX : PLA + + ; One possible configuration for $2131 (CGADSUB). + LDA.b #$72 + + ; Comparing different screen types. + CPX.b #$97 : BEQ .loadOverlay ; Fog 1 + CPX.b #$94 : BEQ .loadOverlay ; Master sword/bridge 2 + CPX.b #$93 : BEQ .loadOverlay ; Triforce room 2 + CPX.b #$9D : BEQ .loadOverlay ; Fog 2 + CPX.b #$9E : BEQ .loadOverlay ; Tree canopy + CPX.b #$9F : BEQ .loadOverlay ; Rain + ; Alternative setting for CGADSUB (only background is enabled on + ; subscreen). + LDA.b #$20 + + CPX.b #$95 : BEQ .loadOverlay ; Sky + CPX.b #$9C : BEQ .loadOverlay ; Lava + CPX.b #$96 : BEQ .loadOverlay ; Pyramid BG + LDX.b $11 + + ; TODO: Investigate what these checks are for. + CPX.b #$23 : BEQ .loadOverlay + CPX.b #$2C : BEQ .loadOverlay + STZ.b $1D + + .loadOverlay + + ; Apply the selected settings to CGADSUB's mirror ($9A). + STA.b $9A + + JSR.w LoadSubscreenOverlay + + ; This is the "under the bridge" area. + LDA.b $8C : CMP.b #$94 : BNE .notUnderBridge + ; All this is doing is setting the X coordinate of BG1 to 0x0100 + ; rather than 0x0000. (this area uses the second half of the data only, + ; similar to the master sword area). + LDA.b $E7 : ORA.b #$01 : STA.b $E7 + + .notUnderBridge + + REP #$20 ; Set A in 16bit mode. + + ; We were pretending to be in a different area to load the subscreen + ; overlay, so we're restoring all those settings. + LDA.l $7EC213 : STA.b $8A + LDA.l $7EC215 : STA.b $84 + LDA.l $7EC217 : STA.b $88 + LDA.l $7EC219 : STA.b $86 + + LDA.l $7EC21B : STA.w $0418 + LDA.l $7EC21D : STA.w $0410 + LDA.l $7EC21F : STA.w $0416 + + SEP #$20 ; Set A in 8bit mode. + + RTS +} +warnpc $02B0D2 ; $0130D2 + +else + +; Undo the function above: +org $02AF58 ; $012F58 +db $A5, $8A, $C9, $80, $00, $90, $44, $A2 +db $97, $00, $A5, $A0, $C9, $80, $01, $D0 +db $12, $A2, $80, $00, $BF, $80, $F2, $7E +db $A2, $97, $00, $29, $40, $00, $D0, $24 +db $4C, $0B, $B0, $A2, $94, $00, $C9, $81 +db $01, $F0, $F5, $A2, $93, $00, $C9, $89 +db $01, $F0, $ED, $C9, $82, $01, $F0, $05 +db $C9, $83, $01, $D0, $07, $E2, $30, $A9 +db $01, $8D, $2D, $01, $E2, $30, $64, $1D +db $E6, $11, $60, $29, $3F, $00, $D0, $1B +db $A5, $8A, $29, $40, $00, $D0, $0F, $A2 +db $80, $00, $BF, $80, $F2, $7E, $A2, $9E +db $00, $29, $40, $00, $D0, $4D, $A2, $9D +db $00, $80, $48, $A2, $95, $00, $A5, $8A +db $C9, $03, $00, $F0, $3E, $C9, $05, $00 +db $F0, $39, $C9, $07, $00, $F0, $34, $A2 +db $9C, $00, $C9, $43, $00, $F0, $2C, $C9 +db $45, $00, $F0, $27, $C9, $47, $00, $F0 +db $22, $C9, $70, $00, $D0, $0B, $AF, $F0 +db $F2, $7E, $29, $20, $00, $D0, $14, $80 +db $0F, $A2, $96, $00, $AF, $C5, $F3, $7E +db $29, $FF, $00, $C9, $02, $00, $B0, $03 +db $A2, $9F, $00, $84, $84, $86, $8A, $86 +db $8C, $A5, $84, $38, $E9, $00, $04, $29 +db $80, $0F, $0A, $EB, $85, $88, $A5, $84 +db $38, $E9, $10, $00, $29, $3E, $00, $4A +db $85, $86, $9C, $18, $04, $9C, $10, $04 +db $9C, $16, $04, $E2, $30, $A9, $82, $85 +db $99, $A9, $16, $85, $1C, $A9, $01, $85 +db $1D, $DA, $A6, $8A, $BF, $00, $5B, $7F +db $4A, $4A, $4A, $4A, $8D, $2D, $01, $FA +db $A9, $72, $E0, $97, $F0, $39, $E0, $94 +db $F0, $35, $E0, $93, $F0, $31, $E0, $9D +db $F0, $2D, $E0, $9E, $F0, $29, $E0, $9F +db $F0, $25, $A9, $20, $E0, $95, $F0, $1F +db $E0, $9C, $F0, $1B, $AF, $13, $C2, $7E +db $AA, $A9, $20, $E0, $5B, $F0, $10, $E0 +db $1B, $D0, $0A, $A6, $11, $E0, $23, $F0 +db $06, $E0, $2C, $F0, $02, $64, $1D, $85 +db $9A, $20, $0D, $FD, $A5, $8C, $C9, $94 +db $D0, $06, $A5, $E7, $09, $01, $85, $E7 +db $C2, $20, $AF, $13, $C2, $7E, $85, $8A +db $AF, $15, $C2, $7E, $85, $84, $AF, $17 +db $C2, $7E, $85, $88, $AF, $19, $C2, $7E +db $85, $86, $AF, $1B, $C2, $7E, $8D, $18 +db $04, $AF, $1D, $C2, $7E, $8D, $10, $04 +db $AF, $1F, $C2, $7E, $8D, $16, $04, $E2 +db $20, $60 + +endif + +; ============================================================================== + +if !Func02B2D4 = 1 + +; Turns on the subscreen if the pyramid is loaded. +org $02B2D4 ; $0132D4 +Func02B2D4: +{ + JSR.w Overworld_LoadSubscreenAndSilenceSFX1 + + ; In vanilla a check for the overlay is done here but we don't need + ; it at all. It is handled in Func02B3A1 later on. + ;JSL EnableSubScreenCheckForPyramid + + RTL +} +warnpc $02B2E6 ; $0132E6 + +else + +; Undo the function above: +org $02B2D4 ; $0132D4 +db $20, $19, $AF, $A5, $8A, $C9, $1B, $F0 +db $04, $C9, $5B, $D0, $04, $A9, $01, $85 +db $1D, $6B + +endif + +pullpc +EnableSubScreenCheckForPyramid: +{ + REP #$20 ; Set A in 16bit mode. + + JSL ReadOverlayArray + + CMP.w #$0096 : BNE .notPyramidOrCastle + SEP #$20 ; Set A in 8bit mode. + LDA.b #$01 : STA.b $1D + + .notPyramidOrCastle + + SEP #$20 ; Set A in 8bit mode. + + RTL +} +pushpc + +; ============================================================================== + +if !Func02B3A1 = 1 + +; Handles activating the subscreen and special BG color when warping to an area +; with the pyramid BG. +org $02B3A1 ; $0133A1 +Func02B3A1: +{ + JSL EnableSubScreenCheckForPyramid + + REP #$20 ; Set A in 16bit mode. + + LDX.b #$00 + + LDA.w #$7FFF + + .setBgPalettesToWhite + STA.l $7EC540, X + STA.l $7EC560, X + STA.l $7EC580, X + + STA.l $7EC5A0, X + STA.l $7EC5C0, X + STA.l $7EC5E0, X + + INX #2 : CPX.b #$20 : BNE .setBgPalettesToWhite + + ; Also set the background color to white. + STA.l $7EC500 + + JSL ReadOverlayArray + + ; This sets the color to transparent so that we don't see an additional + ; white layer on top of the pyramid bg. + CMP.w #$0096 : BNE .notPyramidOfPower + LDA.w #$0000 : STA.l $7EC500 : STA.l $7EC540 + + .notPyramidOfPower + + SEP #$20 ; Set A in 8bit mode. + + JSL Sprite_ResetAll + JSL Sprite_OverworldReloadAll + JSL Link_ItemReset_FromOverworldThings + JSR.w DeleteCertainAncillaeStopDashing + + LDA.b #$14 : STA.b $5D + + LDA.b $8A : AND.b #$40 : BNE .darkWorld + JSL Sprite_ReinitWarpVortex + + .darkWorld + + RTL +} +warnpc $02B40A ; $01340A + +else + +; Undo the function above: +org $02B3A1 ; $0133A1 +db $A5, $8A, $C9, $1B, $F0, $04, $C9, $5B +db $D0, $04, $A9, $01, $85, $1D, $C2, $20 +db $A2, $00, $A9, $FF, $7F, $9F, $40, $C5 +db $7E, $9F, $60, $C5, $7E, $9F, $80, $C5 +db $7E, $9F, $A0, $C5, $7E, $9F, $C0, $C5 +db $7E, $9F, $E0, $C5, $7E, $E8, $E8, $E0 +db $20, $D0, $E2, $8F, $00, $C5, $7E, $A5 +db $8A, $C9, $5B, $00, $D0, $0B, $A9, $00 +db $00, $8F, $00, $C5, $7E, $8F, $40, $C5 +db $7E, $E2, $20, $22, $4E, $C4, $09, $22 +db $99, $C4, $09, $22, $07, $B1, $07, $20 +db $0C, $8B, $A9, $14, $85, $5D, $A5, $8A +db $29, $40, $D0, $04, $22, $89, $AF, $09 +db $6B + +endif + +; ============================================================================== + +if !Func02BC44 = 1 + +; Controls overworld vertical subscreen movement for the pyramid BG. +org $02BC44 ; $013C44 +Func02BC44: +{ + ; Check for the pyramid BG. + JSL ReadOverlayArray : CMP.w #$0096 : BNE .BRANCH_IOTA + JSL BGControl + BRA .BRANCH_IOTA + + warnpc $02BC60 ; $013C60 + + org $02BC60 ; $013C60 + .BRANCH_IOTA +} +warnpc $02BC60 + +else + +; Undo the function above: +org $02BC44 ; $013C44 +db $A5, $8A, $29, $3F, $00, $C9, $1B, $00 +db $D0, $12, $A9, $00, $06, $C5, $E6, $90 +db $02, $85, $E6, $A9, $C0, $06, $C5, $E6 +db $B0, $02, $85, $E6 + +endif + +pullpc +ReadOverlayArray: +{ + PHB : PHK : PLB + + LDA.b $8A : ASL : TAX + LDA.w Pool_OverlayTable, X + + PLB + + RTL +} + +BGControl: +{ + ; TODO: These comparison values will need to be calulated somehow or set + ; depending on the area. Right now they are hardcoded to work with the + ; pyramid area. + + ; Check link's Y position. This will need to be changed per area and per + ; need. + LDA.b $20 : CMP.w #$08E0 : BCC .startShowingMountains + ; Lock the position so that nothing shows through the trees. + LDA.w #$06C0 : STA.b $E6 + + RTL + + .startShowingMountains + + ; Don't let the BG scroll down further than the "top" of the bg when + ; walking up. + LDA.w #$0600 : CMP.b $E6 : BCC .dontLock ; #$0600 + STA.b $E6 + + .dontLock + + ; Don't let the BG scroll up further than the "bottom" of the bg when + ; walking down. + LDA.w #$06C0 : CMP.b $E6 : BCS .dontLock2 ; #$06C0 + STA.b $E6 ; $TODO: I had this at $E2 for some reason. + + .dontLock2 + + RTL +} +pushpc + +; ============================================================================== + +if !Func02C02D = 1 + +; Changes how the pyramid BG scrolls durring transition. +org $02C02D ; $01402D +Func02C02D: +{ + PHA + JSL ReadOverlayArray2 + PLA + + ; Check for the pyramid BG. + CPY.b #$96 : BEQ .dontMoveBg1 + ; This shifts the BG over by a half small area's width. This is to + ; line up the mountain with the tower in the distance at the appropriate + ; location when coming into the pyramid area from the right. + STA.b $E0, X + + ; NOTE: There is currently a bug in vanilla where if you exit a dungeon + ; into the LW death mountain the sky background will become miss-aligned + ; and this movement will cause the sky to flicker or jump when moving to + ; another area. In order to fix this you would have to find the + ; alignment exit code and change how the game aligns BG2 when exiting. + ; Possibly when using the bird too. + + .dontMoveBg1 +} +warnpc $02C039 ; $014039 + +else + +; Undo the function above: +org $02C02D ; $01402D +db $A4, $8A, $C0, $1B, $F0, $06, $C0, $5B +db $F0, $02, $95, $E0 + +endif + +pullpc +ReadOverlayArray2: +{ + PHX + + ; A is already 16 bit here. + REP #$10 ; Set X and Y in 16bit mode. + + JSL ReadOverlayArray : TAY + + SEP #$10 ; Set X and Y in 8bit mode. + + PLX + + RTL +} +pushpc + +; ============================================================================== + +if !Func02C692 = 1 + +; Replaces a call to a shared function. Normally this is goes to .lightworld +; to change the main color palette manually but we change it here so that it +; just uses the same table as everything else. +org $02A07A ; $01207A + JSR.w Overworld_LoadAreaPalettes + +warnpc $02A07D ; $01207D + +; The main overworld palette loading routine un-hardcoded to load the custom +; main palette. +org $02C692 ; $014692 +Overworld_LoadAreaPalettes: +{ + LDX.b $8A + LDA.l Pool_MainPaletteTable, X + + ; $0AB3 = + ; 0 - LW + ; 1 - DW + ; 2 - LW death mountain + ; 3 - DW death mountain + ; 4 - triforce room + STA.w $0AB3 + + ; Reset pal buffer high byte. + STZ.w $0AA9 + + ; Load SP1 through SP4. + JSL Palette_MainSpr + + ; Load SP0 (2nd half) and SP6 (2nd half). + JSL Palette_MiscSpr + + ; Load SP5 (1st half). + JSL Palette_SpriteAux1 + + ; Load SP6 (1st half). + JSL Palette_SpriteAux2 + + ; Load SP5 (2nd half, 1st 3 colors), which is the sword palette. + JSL Palette_Sword + + ; Load SP5 (2nd half, next 4 colors), which is the shield. + JSL Palette_Shield + + ; Load SP7 (full) Link's whole palette, including Armor. + JSL Palette_ArmorAndGloves + + LDX.b #$01 + + ; Changes the Palette_SpriteAux3 load depending on if we are in the LW or + ; not. Will probably need it own custom table in the future? not sure. + LDA.l $7EF3CA : AND.b #$40 : BEQ .lightWorld2 + LDX.b #$03 + + .lightWorld2 + + ; Reset pal buffer0. + STX.w $0AAC + + ; Load SP0 (first half) (or SP7 (first half)). + JSL Palette_SpriteAux3 + + ; Load BP0 and BP1 (first halves). + JSL Palette_Hud + + ; Load BP2 through BP5 (first halves). + JSL Palette_OverworldBgMain + + RTS +} +warnpc $02C6EB ; $0146EB + +else + +; Undo the function above: +org $02A07A ; $01207A +db $20, $AD, $C6 + +org $02C692 ; $14692 +db $A2, $02, $A5, $8A, $29, $3F, $C9, $03 +db $F0, $0A, $C9, $05, $F0, $06, $C9, $07 +db $F0, $02, $A2, $00, $A5, $8A, $29, $40 +db $F0, $01, $E8, $8E, $B3, $0A, $9C, $A9 +db $0A, $22, $9E, $EC, $1B, $22, $6E, $ED +db $1B, $22, $C5, $EC, $1B, $22, $E4, $EC +db $1B, $22, $03, $ED, $1B, $22, $29, $ED +db $1B, $22, $F9, $ED, $1B, $A2, $01, $AF +db $CA, $F3, $7E, $29, $40, $F0, $02, $A2 +db $03, $8E, $AC, $0A, $22, $77, $EC, $1B +db $22, $52, $EE, $1B, $22, $C7, $EE, $1B +db $60 + +endif + +; ============================================================================== + +if !Func02A4CD = 1 + +; Rain animation code. Just replaces a single check that checks for the +; misery mire to instead check the current overlay to see if it's rain. +org $02A4CD ; $0124CD +RainAnimation: +{ + LDA.b $8C : CMP.b #$9F : BEQ .rainOverlaySet + ; Check the progress indicator. + LDA.l $7EF3C5 : CMP.b #$02 : BRA .skipMovement + .rainOverlaySet + + ; If misery mire has been opened already, we're done. + ;LDA.l $7EF2F0 : AND.b #$20 : BNE .skipMovement + ; Check the frame counter. + ; On the third frame do a flash of lightning. + LDA.b $1A + + ; On the 0x03rd frame, cue the lightning. + CMP.b #$03 : BEQ .lightning + ; On the 0x05th frame, normal light level. + CMP.b #$05 : BEQ .normalLight + ; On the 0x24th frame, cue the thunder. + CMP.b #$24 : BEQ .thunder + ; On the 0x2Cth frame, normal light level. + CMP.b #$2C : BEQ .normalLight + ; On the 0x58th frame, cue the lightning. + CMP.b #$58 : BEQ .lightning + ; On the 0x5Ath frame, normal light level. + CMP.b #$5A : BNE .moveOverlay + + .normalLight + + ; Keep the screen semi-dark. + LDA.b #$72 + + BRA .setBrightness + + .thunder + + ; Play the thunder sound when outdoors. + LDX.b #$36 : STX.w $012E + + .lightning + + ; Make the screen flash with lightning. + LDA.b #$32 + + .setBrightness + + STA.b $9A + + .moveOverlay + + ; Overlay is only moved every 4th frame. + LDA.b $1A : AND.b #$03 : BNE .skipMovement + LDA.w $0494 : INC A : AND.b #$03 : STA.w $0494 : TAX + + LDA.b $E1 : CLC : ADC.l $02A46D, X : STA.b $E1 + LDA.b $E7 : CLC : ADC.l $02A471, X : STA.b $E7 + + .skipMovement + + RTL +} +warnpc $02A52D ; $01252D + +else + +; Undo the function above: +org $02A4CD ; $0124CD +db $A5, $8A, $C9, $70, $F0, $08, $AF, $C5 +db $F3, $7E, $C9, $02, $B0, $51, $AF, $F0 +db $F2, $7E, $29, $20, $D0, $49, $A5, $1A +db $C9, $03, $F0, $1D, $C9, $05, $F0, $10 +db $C9, $24, $F0, $10, $C9, $2C, $F0, $08 +db $C9, $58, $F0, $0D, $C9, $5A, $D0, $0D +db $A9, $72, $80, $07, $A2, $36, $8E, $2E +db $01, $A9, $32, $85, $9A, $A5, $1A, $29 +db $03, $D0, $1C, $AD, $94, $04, $1A, $29 +db $03, $8D, $94, $04, $AA, $A5, $E1, $18 +db $7F, $6D, $A4, $02, $85, $E1, $A5, $E7 +db $18, $7F, $71, $A4, $02, $85, $E7, $6B + +endif + +; ============================================================================== + +if !Func02AADB = 1 + +; Main Mosaic Hook. Changes it to use a table instead of hardcoded to the woods +; areas. +org $02AADB ; $012ADB + JML MosaicAreaCheck + +warnpc $02AADF ; $012ADF + +else + +; Undo the function above: +org $02AADB ; $012ADB +db $29, $3F, $F0, $06 + +endif + +pullpc +MosaicAreaCheck: +{ + PHB : PHK : PLB + + ; Check if the area we are in needs a mosaic. + TAX + LDA.w Pool_MosaicTable, X + + BEQ .noMosaic1 + PLB + JML $02AAE5 + + .noMosaic1 + + ; Check if the area we are going to needs a mosaic. + LDX.b $8A + LDA.w Pool_MosaicTable, X + + BEQ .noMosaic2 + PLB + JML $02AAE5 + + .noMosaic2 + + PLB + JML $02AAF4 +} +pushpc + +; ============================================================================== + +; Repairs an old ZS call. +org $02ABB8 ; $012BB8 +db $A9, $09, $80, $02 + +if !Func02ABBE = 1 + +org $02ABBE ; $012BBE + JSL NewOverworld_FinishTransGfx + NOP : NOP : NOP + +warnpc $02ABC5 ; $012BC5 + +else + +; Undo the function above: +org $02ABBE ; $012BBE +db $85, $17, $8D, $10, $07, $E6, $11 + +endif + +pullpc +; Loads the animated tiles after most of the transition gfx changes take place. +NewOverworld_FinishTransGfx: +{ + PHB : PHK : PLB + + ; First frame + LDA.w TransGFXModuleIndex : BNE .notLoad + JSR CheckForChangeGraphicsTransitionLoad + + ; Trigger NMI module: NMI_UpdateBgChrSlots_3_to_4. + LDA.b #$09 + + ; Signal for a graphics transfer in the NMI routine later. + STA.b $17 : STA.w $0710 + + ; Move on to next submodule. + INC.b $11 + + ; Move on to next subsubmodule. + INC.w TransGFXModuleIndex + + BRA .return + + .notLoad + + ; Second frame + CMP.b #$01 : BNE .notFinish + ; Trigger NMI module: NMI_UpdateBgChrSlots_5_to_6. + LDA.b #$0A + + ; Signal for a graphics transfer in the NMI routine later. + STA.b $17 : STA.w $0710 + + ; Don't move on to the next submodule yet. + + ; Move on to next subsubmodule. + INC.w TransGFXModuleIndex + + BRA .return + + .notFinish + + ; Third frame + CMP.b #$02 : BNE .notMain1 + LDA.w Pool_EnableTransitionGFXGroupLoad : BEQ .moveOn + ; Prep the new static gfx tile sets. + JSR LoadTransMainGFX + JSR NewPrepTransAuxGFX + + ; Trigger NMI module: NMI_UpdateChr_Bg0. + LDA.b #$0E + + ; Signal for a graphics transfer in the NMI routine later. + STA.b $17 : STA.w $0710 + + ; Move on to next subsubmodule. + INC.w TransGFXModuleIndex + + BRA .return + + .notMain1 + + ; Fourth frame + LDA.w Pool_EnableTransitionGFXGroupLoad : BEQ .moveOn + ; Trigger NMI module: NMI_DoNothing which we replaced with + ; NMI_UpdateChr_Bg2HalfAndAnimated down below. + LDA.b #$06 + + ; Signal for a graphics transfer in the NMI routine later. + STA.b $17 : STA.w $0710 + + .moveOn + + ; Move on to next submodule. + INC.b $11 + + .return + + PLB + + RTL +} + +CheckForChangeGraphicsTransitionLoad: +{ + ; Are we currently in a mosaic? + LDA.b $11 : CMP.b #$0F : BEQ .mosaic + ; Are we entering a special area? + CMP.b #$1A : BEQ .mosaic + ; Are we leaving a special area? + CMP.b #$26 : BEQ .mosaic + ; Just a normal transition, Not a mosaic. + LDA.l Pool_EnableAnimated : BEQ .dontUpdateAnimated1 + ; Check to see if we need to update the animated tiles + ; by checking what was previously loaded. + JSL ReadAnimatedTable : CMP.w AnimatedTileGFXSet : BEQ .dontUpdateAnimated1 + STA.w AnimatedTileGFXSet : DEC : TAY + + ; This forces the game toupdate the animated tiles + ; when going from one area to another. + JSL DecompOwAnimatedTiles + + .dontUpdateAnimated1 + + LDA.w Pool_EnableMainPalette : BEQ .dontUpdateMain1 + ; Check to see if we need to update the main palette by + ; checking what was previously loaded. + LDX.b $8A + LDA.w Pool_MainPaletteTable, X : CMP.w $0AB3 : BEQ .dontUpdateMain1 + STA.w $0AB3 + + ; Run the modified routine that loads the buffer + ; and normal color ram. + JSL Palette_OverworldBgMain2 + + .dontUpdateMain1 + + LDA.w Pool_EnableBGColor : BEQ .dontUpdateBGColor1 + REP #$30 ; Set A, X, and Y in 16bit mode. + + LDA.b $8A : ASL : TAX ; Get area code and times it by 2. + + ; Where ZS saves the array of palettes + LDA.w Pool_BGColorTable, X + STA.l $7EC300 : STA.l $7EC500 + STA.l $7EC540 : STA.l $7EC340 + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + ; Don't update the CRAM until later when the overlays are + ; loaded so that way the BG overlays have a chance to hide + ; the cracks. + ;INC.b $15 + + .dontUpdateBGColor1 + + RTS + + .mosaic + + ; Check to see if we need to update the animated tiles by checking what + ; was previously loaded. + JSL ReadAnimatedTable : CMP.w AnimatedTileGFXSet : BEQ .dontUpdateAnimated2 + STA.w AnimatedTileGFXSet : DEC : TAY + + ; This forces the game to update the animated tiles when going + ; from one area to another. + JSL DecompOwAnimatedTiles + + .dontUpdateAnimated2 + + ; Check to see if we need to update the main palette by checking + ; what was previously loaded. + LDX.b $8A + LDA.w Pool_MainPaletteTable, X : CMP.w $0AB3 : BEQ .dontUpdateMain2 + STA.w $0AB3 + + ; Run the vanilla routine that only loads the buffer. + JSL Palette_OverworldBgMain + + .dontUpdateMain2 + + REP #$30 ; Set A, X, and Y in 16bit mode. + + ; $0181 is the exit room number used for getting into the under the bridge + ; area. + LDA.b $A0 : CMP.w #$0181 : BNE .notBridge + LDA.w Pool_BGColorTable_Bridge + + BRA .storeColor + + .notBridge + + LDA.b $8A : ASL : TAX ; Get area code and times it by 2. + + LDA.w Pool_BGColorTable, X ; Where ZS saves the array of palettes. + + .storeColor + + ; Set transparent color. only set the buffer so it fades in right + ; during mosaic transition. + STA.l $7EC300 : STA.l $7EC340 + + LDX.w #$4020 : STX.b $9C + LDX.w #$8040 : STX.b $9D + + LDX.w #$4F33 + LDY.w #$894F + + ; Change the fixed color depending on our sub screen overlay. + ; Lost woods and skull woods. + JSL ReadOverlayArray : CMP.w #$009D : BEQ .noSpecialColor + CMP.w #$0040 : BEQ .noSpecialColor + ; Pyramid area. + CMP.w #$0096 : BEQ .specialColor + LDX.w #$4C26 + LDY.w #$8C4C + + ; LW death mountain. + CMP.w #$0095 : BEQ .specialColor + LDX.w #$4A26 + LDY.w #$874A + + ; DW death mountain. + CMP.w #$009C : BEQ .specialColor + BRA .noSpecialColor + + .specialColor + + STX.b $9C + STY.b $9D + + .noSpecialColor + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + ; Don't update the CRAM until later when the overlays are loaded so + ; that way the BG overlays have a chance to hide the cracks. + ;INC.b $15 + + ; PLACE CUSTOM GFX LOAD HERE! + ;JML CheckForChangeGraphicsTransitionLoadCastle + + CheckForChangeGraphicsTransitionLoadRetrun: + + RTS + + SkipOverworld_FinishTransGfx_firstHalf: + + ; Move on to next submodule. + INC.b $11 + + RTS +} + +; The following 2 functions are copied from the palettes.asm but they only +; copied colors into the buffer so these copy colors into the normal ram as +; well. +Palette_OverworldBgMain2: +{ + REP #$21 + + LDA.w $0AB3 : ASL A : TAX + + LDA.l $1BEC3B, X : ADC.w #$E6C8 : STA.b $00 + + REP #$10 + + ; Target BP2 through BP6 (first halves). + ; Each palette has 7 colors. + ; Load 5 palettes. + LDA.w #$0042 + LDX.w #$0006 + LDY.w #$0004 + + JSR.w Palette_MultiLoad2 + + SEP #$30 + + RTL +} + +Palette_MultiLoad2: +{ + ; Description: Generally used to load multiple palettes for BGs. + ; Upon close inspection, one sees that this algorithm is almost the same as + ; the last subroutine. + ; Name = Palette_MultiLoad(A, X, Y). + + ; Parameters: X = (number of colors in the palette - 1). + ; A = offset to add to $7EC300, in other words, where to write + ; in palette memory. + ; Y = (number of palettes to load - 1). + + STA.b $04 ; Save the values for future reference. + STX.b $06 + STY.b $08 + + ; The absolute address at $00 was planted in the calling function. This + ; value is the bank #$1B ( => D in Rom) The address is found from $0AB6 and + ; of course, store it at $02. + LDA.w #$001B : STA.b $02 + + .nextPalette + ; $0AA8 + A parameter will be the X value. + LDA.w $0AA8 : CLC : ADC.b $04 : TAX + + LDY.b $06 ; Tell me how long the palette is. + + .copyColors + ; We're loading A from the address set up in the calling function. + LDA.b [$00] : STA.l $7EC300, X : STA.l $7EC500, X + + ; Increment the absolute portion of the address by two, and + ; decrease the color count by one. + INC.b $00 : INC.b $00 + + INX #2 + + ; So basically loop (Y+1) times, taking (Y * 2 bytes) to $7EC300, X. + DEY : BPL .copyColors + + ; This technique bumps us up to the next 4bpp (16 color) palette. + LDA.b $04 : CLC : ADC.w #$0020 : STA.b $04 + + ; Decrease the number of palettes we have to load. + DEC.b $08 + + BPL .nextPalette + + ; We're done loading palettes. + + RTS +} + +LoadTransMainGFX: +{ + ; Setup the decompression buffer address. + ; $00[3] = $7E6000 + STZ.b $00 + LDA.b #$40 : STA.b $01 + LDA.b #$7E : STA.b $02 + + REP #$30 + ; $0E = $8A * 8 + LDA.b $8A : AND.w #$00FF : ASL #3 : STA.b $0E + SEP #$20 + + ; Sheet 0 (static 0) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet0, X : CMP.b #$FF : BEQ .noBgGfxChange0 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange0 + + SEP #$10 + ; Increment buffer address by 0x0600. + LDA.b $01 : CLC : ADC.b #$06 : STA.b $01 + REP #$10 + + ; Sheet 1 (static 1) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet1, X : CMP.b #$FF : BEQ .noBgGfxChange1 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange1 + + SEP #$10 + ; Increment buffer address by 0x0600. + LDA.b $01 : CLC : ADC.b #$06 : STA.b $01 + REP #$10 + + ; Sheet 2 (static 2) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet2, X : CMP.b #$FF : BEQ .noBgGfxChange2 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange2 + + SEP #$10 + ; Increment buffer address by 0x0600. + LDA.b $01 : CLC : ADC.b #$06 : STA.b $01 + REP #$10 + + ; Sheet 7 (animated) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet7, X : CMP.b #$FF : BEQ .noBgGfxChange7 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange7 + + RTS +} + +NewPrepTransAuxGFX: +{ + ; Prepares the transition graphics to be transferred to VRAM during NMI. + ; This could occur either during this frame or any subsequent frame. + + ; Set bank for source address. + LDA.b #$7E : STA.b $02 : STA.b $05 + + REP #$31 + + ; Source address is $7E6000, number of tiles is 0x40, + ; base address is $7F0000. + LDX.w #$0000 + LDY.w #$0040 + LDA.w #$4000 + + ; The first graphics pack always uses the higher 8 palette values. + JSL Do3To4High16BitLONG + + ; Number of tiles for next set is 0xC0. + LDY.w #$00C0 + + LDA.b $03 + + JSL Do3To4Low16BitLONG + + SEP #$30 + + RTS +} +pushpc + +; ============================================================================== + +if !Func0ABC5A = 1 + +org $0ABC5A ; $053C5A + JSL CheckForChangeGraphicsNormalLoad + +warnpc $0ABC5E ; $053C5E + +else + +; Undo the function above: +org $0ABC5A ; $053C5A +db $22, $9B, $E1, $00 + +endif + +; Loads the animated tiles after the overworld map is closed. +pullpc +CheckForChangeGraphicsNormalLoad: +{ + PHB : PHK : PLB + + JSL InitTilesets ; Replaced code. + + JSL ReadAnimatedTable : STA.w AnimatedTileGFXSet : DEC : TAY + + ; This function is not needed here and is handled somewhere else. This + ; forces the game to update the animated tiles when going from one area to + ; another. + ;JSL DecompOwAnimatedTiles + + ; PLACE CUSTOM GFX LOAD HERE! + ;JSL CheckForChangeGraphicsNormalLoadCastle + + PLB + + RTL +} +pushpc + +; ============================================================================== + +if !Func0AB8F5 = 1 + +; Loads different animated tiles when returning from bird travel. +org $0AB8F5 ; $0538F5 +Func0AB8F5: +{ + JSL ReadAnimatedTable : STA.w AnimatedTileGFXSet : DEC : TAY + + ; From this point on it is the vanilla function. + JSL DecompOwAnimatedTiles + JSL Overworld_SetFixedColorAndScroll + + STZ.w $0AA9 + STZ.w $0AB2 + + JSL InitTilesets + + INC.w $0200 ; SCAWFUL: Verify the interface submodule ID being used here. + ; Provides context on where in the jump table we're at. + + STZ.b $B2 + + JSL $02B1F4 ; $0131F4 IN ROM + + ; Play sound effect indicating we're coming out of map mode. + LDA.b #$10 : STA.w $012F + + JSL LoadAmbientSound + + ; If it's a different music track than was playing where we came from, + ; simply change to it (as opposed to setting volume back to full). + LDA.l $7F5B00, X : AND.b #$0F : TAX : CPX.w $0130 : BNE .different_music + ; Otherwise, just set the volume back to full. + LDX.b #$F3 + + .different_music + + STX.w $012C + + ; PLACE CUSTOM GFX LOAD HERE! + ;JSL CheckForChangeGraphicsNormalLoadCastle + + RTL +} +warnpc $0AB948 ; $053948 + +else + +; Undo the function above: +org $0AB8F5 ; $0538F5 +db $A0, $58, $A5, $8A, $29, $BF, $C9, $03 +db $F0, $0A, $C9, $05, $F0, $06, $C9, $07 +db $F0, $02, $A0, $5A, $22, $94, $D3, $00 +db $22, $70, $FE, $0B, $9C, $A9, $0A, $9C +db $B2, $0A, $22, $9B, $E1, $00, $EE, $00 +db $02, $64, $B2, $22, $F4, $B1, $02, $A9 +db $10, $8D, $2F, $01, $A6, $8A, $BF, $00 +db $5B, $7F, $4A, $4A, $4A, $4A, $8D, $2D +db $01, $BF, $00, $5B, $7F, $29, $0F, $AA +db $EC, $30, $01, $D0, $02, $A2, $F3, $8E +db $2C, $01, $6B + +endif + +pullpc +LoadAmbientSound: +{ + PHB : PHK : PLB + + ; Reset the ambient sound effect to what it was. + LDX.b $8A : LDA.l $7F5B00, X : LSR #4 : STA.w $012D + + ; Check if we need to stop the rain sound in the misery mire. + LDA.w Pool_EnableRainMireEvent : BEQ .disableRainSound + LDA.b $8A : CMP.b #$70 : BNE .disableRainSound + ; Has Misery Mire been triggered yet? + LDA.l $7EF2F0 : AND.b #$20 : BNE .disableRainSound + LDA.b #$01 : STA.w $012D + + .disableRainSound + + PLB + + RTL +} +pushpc + +; ============================================================================== + +if !Func0BFEC6 = 1 + +; Loads different special transparent colors and overlay speeds based on the +; overlay duringtransition and under other certain cases. Exact cases need to be +; investigated. When leaving dungeon. +org $0BFEC6 ; $05FEC6 +Overworld_LoadBGColorAndSubscreenOverlay: +{ + JSL ReplaceBGColor + + ; Set fixed color to neutral. + LDA.w #$4020 : STA.b $9C + LDA.w #$8040 : STA.b $9D + + ; Check if we need to load the rain in the misery mire. + LDA.l Pool_EnableRainMireEvent : BEQ .notMire + LDA.b $8A : CMP.w #$0070 : BNE .notMire + ; Has Misery Mire been triggered yet? + LDA.l $7EF2F0 : AND.w #$0020 : BNE .notMire + JMP .subscreenOnAndReturn + + .notMire + + JSL ReadOverlayArray + + ; Check for misery mire. + CMP.w #$009F : BNE .notRain + JMP .subscreenOnAndReturn + + .notRain + + ; Change the fixed color depending on our sub screen overlay. + ; Check for lost woods?, skull woods, and pyramid area. + CMP.w #$009D : BEQ .noCustomFixedColor + CMP.w #$0096 : BEQ .noCustomFixedColor + LDX.w #$4C26 + LDY.w #$8C4C + + ; Check for LW Death mountain. + CMP.w #$0095 : BEQ .setCustomFixedColor + LDX.w #$4A26 + LDY.w #$874A + + ; Check for DW Death mountain. (not turtle rock?). + CMP.w #$009C : BEQ .setCustomFixedColor + SEP #$30 ; Set A, X, and Y in 8bit mode. + + ; Update CGRAM this frame. + INC.b $15 + + RTL + + .setCustomFixedColor + + STX.b $9C + STY.b $9D ; Set the fixed color addition color values. + + .noCustomFixedColor + + LDA.b $11 : AND.w #$00FF : CMP.w #$0004 : BEQ .BRANCH_11 + ; Make sure BG2 and BG1 Y scroll values are synchronized. + ; Same for X scroll. + LDA.b $E8 : STA.b $E6 + LDA.b $E2 : STA.b $E0 + + ; Just because I need a bit more space. + JSL ReadOverlayArray + + ; Are we at Hyrule Castle or Pyramid of Power? + CMP.w #$0096 : BNE .subscreenOnAndReturn + JSL NeedSomeSpaceForWhateverThisIs + + BRA .subscreenOnAndReturn + + .BRANCH_11 + + ; Check for the pyramid BG. + JSL ReadOverlayArray : CMP.w #$0096 : BNE .subscreenOnAndReturn + ; Synchronize Y scrolls on BG0 and BG1. Same for X scrolls. + LDA.b $E8 : STA.b $E6 + LDA.b $E2 : STA.b $E0 + + LDA.w $0410 : AND.w #$00FF : CMP.w #$0008 : BEQ .BRANCH_12 + ; Handles scroll for special areas maybe? + LDA.w #$0838 : STA.b $E0 + + .BRANCH_12 + + LDA.w #$06C0 : STA.b $E6 + + .subscreenOnAndReturn + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + ; Put BG0 on the subscreen. + LDA.b #$01 : STA.b $1D + + ; Update palette. + INC.b $15 + + RTL +} +warnpc $0BFFA8 ; $05FFA8 + +else + +; Undo the function above: +org $0BFEC6 ; $05FEC6 +db $A9, $20, $40, $85, $9C, $A9, $40, $80 +db $85, $9D, $A5, $8A, $F0, $40, $C9, $70 +db $00, $D0, $03, $4C, $9D, $FF, $C9, $40 +db $00, $F0, $33, $C9, $5B, $00, $F0, $2E +db $A2, $26, $4C, $A0, $4C, $8C, $C9, $03 +db $00, $F0, $1F, $C9, $05, $00, $F0, $1A +db $C9, $07, $00, $F0, $15, $A2, $26, $4A +db $A0, $4A, $87, $C9, $43, $00, $F0, $0A +db $C9, $45, $00, $F0, $05, $E2, $30, $E6 +db $15, $6B, $86, $9C, $84, $9D, $A5, $11 +db $29, $FF, $00, $C9, $04, $00, $F0, $58 +db $A5, $E8, $85, $E6, $A5, $E2, $85, $E0 +db $A5, $8A, $29, $3F, $00, $C9, $1B, $00 +db $D0, $6D, $A5, $E2, $38, $E9, $78, $07 +db $4A, $A8, $29, $00, $40, $F0, $05, $98 +db $09, $00, $80, $A8, $84, $00, $A5, $E2 +db $38, $E5, $00, $85, $E0, $A5, $E6, $C9 +db $C0, $06, $90, $17, $38, $E9, $00, $06 +db $29, $FF, $03, $C9, $80, $01, $B0, $06 +db $4A, $09, $00, $06, $80, $0E, $A9, $C0 +db $06, $80, $09, $A5, $E6, $29, $FF, $00 +db $4A, $09, $00, $06, $85, $E6, $80, $27 +db $A5, $8A, $29, $3F, $00, $C9, $1B, $00 +db $D0, $1D, $A5, $E8, $85, $E6, $A5, $E2 +db $85, $E0, $AD, $10, $04, $29, $FF, $00 +db $C9, $08, $00, $F0, $05, $A9, $38, $08 +db $85, $E0, $A9, $C0, $06, $85, $E6, $E2 +db $20, $A9, $01, $85, $1D, $E2, $30, $E6 +db $15, $6B + +endif + +pullpc +ReplaceBGColor: +{ + PHB : PHK : PLB + + ; TODO: This may need to check if we are in a warp and then if so load the + ; custom color. If not, then chceck if its enabled or not. + ;SEP #$20 ; Set A in 8bit mode. + + ;LDA.w Pool_EnableBGColor : BNE .custom + ;REP #$20 ; Set A in 16bit mode. + + ;PLB + + ;RTL + + ;.custom + + ;REP #$20 ; Set A in 16bit mode. + + LDA.b $8A : ASL : TAX ; Get area code and times it by 2. + LDA.w Pool_BGColorTable, X ; Get the color. + + ;STA.l $7EC300 : STA.l $7EC340 ; Set the BG color. + STA.l $7EC500 : STA.l $7EC540 + + PLB + + RTL +} + +; TODO: Doccument this better and fiture out what it actually does. +NeedSomeSpaceForWhateverThisIs: +{ + LDA.b $E2 : SEC : SBC.w #$0778 : LSR A : TAY : AND.w #$4000 : BEQ .BRANCH_7 + TYA : ORA.w #$8000 : TAY + + .BRANCH_7 + + STY.b $00 + + LDA.b $E2 : SEC : SBC.b $00 : STA.b $E0 + + LDA.b $E6 : CMP.w #$06C0 : BCC .BRANCH_9 + SEC : SBC.w #$0600 : AND.w #$03FF : CMP.w #$0180 : BCS .BRANCH_8 + LSR A : ORA.w #$0600 + + BRA .BRANCH_10 + + .BRANCH_8 + + LDA.w #$06C0 + + BRA .BRANCH_10 + + .BRANCH_9 + + LDA.b $E6 : AND.w #$00FF : LSR A : ORA.w #$0600 + + .BRANCH_10 + + ; Set BG1 vertical scroll. + STA.b $E6 + + RTL +} +pushpc + +; ============================================================================== + +if !Func0ED627 = 1 + +; Loads the transparent color under some load conditions such as the mirror\ +; warp. +; TODO: Investigate the other conditions. Exiting dungeons. +org $0ED627 ; $075627 + JML InitColorLoad2 + NOP + +warnpc $0ED62C ; $07562C + +else + +; Undo the function above: +org $0ED627 ; $075627 +db $A5, $8A, $C9, $80, $00 + +endif + +org $0ED652 +InitColorLoad2_Return: + +pullpc +InitColorLoad2: +{ + PHB : PHK : PLB + + ; $0181 is the exit room number used for getting into the under the bridge + ; area. + LDA.b $A0 : CMP.w #$0181 : BNE .notBridge + LDA.w Pool_BGColorTable_Bridge + + BRA .storeColor + + .notBridge + + LDA.b $8A : ASL : TAX ; Get area code and times it by 2. + LDA.w Pool_BGColorTable, X ; Get the color. + + .storeColor + + STA.l $7EC300 : STA.l $7EC340 ; Set transparent color. + ;STA.l $7EC500 : STA.l $7EC540 + + INC.b $15 + + PLB + + JML InitColorLoad2_Return +} +pushpc + +; ============================================================================== + +if !Func0ED8AE = 1 + +; Resets the area special color after the screen flashes. +org $0ED8AE ; $0758AE +Func0ED8AE: +{ + LDA.b $1B : BNE .noSpecialColor + REP #$30 ; Set A, X, and Y in 16bit mode. + + LDX.w #$4020 : STX.b $9C + LDX.w #$8040 : STX.b $9D + + LDX.w #$4F33 + LDY.w #$894F + + ; Change the fixed color depending on our sub screen overlay. + ; Lost woods and skull woods. + JSL ReadOverlayArray : CMP.w #$009D : BEQ .noSpecialColor + CMP.w #$0040 : BEQ .noSpecialColor + ; Pyramid area. + CMP.w #$0096 : BEQ .specialColor + LDX.w #$4C26 + LDY.w #$8C4C + + ; LW death mountain. + CMP.w #$0095 : BEQ .specialColor + LDX.w #$4A26 + LDY.w #$874A + + ; DW death mountain. + CMP.w #$009C : BEQ .specialColor + BRA .noSpecialColor + + .specialColor + + STX.b $9C + STY.b $9D + + .noSpecialColor + + SEP #$30 ; Set A, X, and Y in 8bit mode. + + RTL +} +warnpc $0ED8FB ; $0758FB + +else + +; Undo the function above: +org $0ED8AE ; $0758AE +db $A5, $1B, $D0, $46, $C2, $10, $A2, $20 +db $40, $86, $9C, $A2, $40, $80, $86, $9D +db $A2, $33, $4F, $A0, $4F, $89, $A5, $8A +db $F0, $30, $C9, $40, $F0, $2C, $C9, $5B +db $F0, $24, $A2, $26, $4C, $A0, $4C, $8C +db $C9, $03, $F0, $1A, $C9, $05, $F0, $16 +db $C9, $07, $F0, $12, $A2, $26, $4A, $A0 +db $4A, $87, $C9, $43, $F0, $08, $C9, $45 +db $F0, $04, $C9, $47, $D0, $04, $86, $9C +db $84, $9D, $E2, $10, $6B + +endif + +; ============================================================================== + +if !Func00E133 = 1 + +; Interupts the vanilla LoadTransAuxGFX function +org $00D673 ; $005673 + JML NewLoadTransAuxGFX + +warnpc $00D677 ; $005677 + +org $008C8A ; $000C8A +dw NMI_UpdateChr_Bg2HalfAndAnimated + +warnpc $00D677 ; $005677 + +; Replaces the UNREACHABLE_00D585 which is unused. +org $00D585 ; $005585 +Decomp_bg_variableLONG: +{ + PHB : PHK : PLB + + JSR Decomp_bg_variable + + PLB + + RTL +} + +Do3To4Low16BitLONG: +{ + PHB : PHK : PLB + + JSR.w Do3To4Low16Bit + + PLB + + RTL +} + +Do3To4High16BitLONG: +{ + PHB : PHK : PLB + + JSR.w Do3To4High16Bit + + PLB + + RTL +} + +NMI_UpdateChr_Bg2HalfAndAnimated: +{ + JSL NMI_UpdateChr_Bg2HalfAndAnimatedLONG + + RTS +} + +warnpc $00D5CB ; $0055CB + +else + +; Undo the functions above: +org $00D673 ; $005673 +db $A9, $60, $85, $01 + +org $008C8A ; $000C8A +db $4B, $8E + +; This is the old 0AA1 table. Will eventually be unused so I'll leave this here +; for future use. +org $00E073 ; $006073 +db $00, $01, $10, $06, $0E, $1F, $18, $0F +db $00, $01, $10, $08, $0E, $22, $1B, $0F +db $00, $01, $10, $06, $0E, $1F, $18, $0F +db $00, $01, $13, $07, $0E, $23, $1C, $0F +db $00, $01, $10, $07, $0E, $21, $18, $0F +db $00, $01, $10, $09, $0E, $20, $19, $0F +db $02, $03, $12, $0B, $0E, $21, $1A, $0F +db $00, $01, $11, $0C, $0E, $24, $1B, $0F +db $00, $01, $11, $08, $0E, $22, $1B, $0F +db $00, $01, $11, $0C, $0E, $25, $1A, $0F +db $00, $01, $11, $0C, $0E, $26, $1B, $0F +db $00, $01, $14, $0A, $0E, $27, $1D, $0F +db $00, $01, $11, $0A, $0E, $28, $1E, $0F +db $02, $03, $12, $0B, $0E, $29, $16, $0F +db $00, $01, $15, $0D, $0E, $2A, $18, $0F +db $00, $01, $10, $07, $0E, $23, $1C, $0F +db $00, $01, $13, $07, $0E, $04, $05, $0F +db $00, $01, $13, $07, $0E, $04, $05, $0F +db $00, $01, $10, $09, $0E, $20, $1B, $0F +db $00, $01, $10, $09, $0E, $2A, $17, $0F +db $02, $03, $12, $0B, $0E, $21, $1C, $0F +db $00, $08, $11, $1B, $22, $2E, $5D, $5B +db $00, $08, $10, $18, $20, $2B, $5D, $5B +db $00, $08, $10, $18, $20, $2B, $5D, $5B +db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B +db $42, $43, $44, $45, $20, $2B, $3F, $5D +db $00, $08, $10, $18, $20, $2B, $5D, $5B +db $00, $08, $10, $18, $20, $2B, $5D, $5B +db $00, $08, $10, $18, $20, $2B, $5D, $5B +db $00, $08, $10, $18, $20, $2B, $5D, $5B +db $00, $08, $10, $18, $20, $2B, $5D, $5B +db $71, $72, $71, $72, $20, $2B, $5D, $5B +db $3A, $3B, $3C, $3D, $53, $4D, $3E, $5B +db $42, $43, $44, $45, $20, $2B, $3F, $59 +db $00, $72, $71, $72, $20, $2B, $5D, $0F +db $16, $39, $1D, $17, $40, $41, $39, $1E +db $00, $46, $39, $72, $40, $41, $39, $0F + +org $00D585 ; $005585 +db $A0, $08, $00, $84, $0E, $85, $00, $18 +db $69, $10, $00, $85, $03, $A0, $07, $00 +db $A7, $00, $9F, $00, $90, $7E, $E6, $00 +db $E6, $00, $A7, $03, $29, $FF, $00, $9F +db $10, $90, $7E, $E6, $03, $E8, $E8, $88 +db $10, $E6, $8A, $18, $69, $10, $00, $AA +db $A5, $03, $29, $78, $00, $D0, $08, $A5 +db $03, $18, $69, $80, $01, $85, $03, $A5 +db $03, $C6, $0E, $D0, $C0, $60 + +endif + +pullpc + +NewLoadTransAuxGFX: +{ + PHB : PHK : PLB + + LDA.w Pool_EnableTransitionGFXGroupLoad : BNE .notNormalLoad + ; Replaced code: + LDA.b #$60 : STA.b $01 + + PLB + + JML $00D677 ; $005677 Return to regular code. + + .notNormalLoad + + ; Setup the decompression buffer address. + ; $00[3] = $7E6000 + STZ.b $00 + LDA.b #$60 : STA.b $01 + LDA.b #$7E : STA.b $02 + + REP #$30 + ; $0E = $8A * 8 + LDA.b $8A : AND.w #$00FF : ASL #3 : STA.b $0E + SEP #$20 + + ; Sheet 3 (variable 0) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet3, X : CMP.b #$FF : BEQ .noBgGfxChange3 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange3 + + SEP #$10 + ; Increment buffer address by 0x0600. + LDA.b $01 : CLC : ADC.b #$06 : STA.b $01 + REP #$10 + + ; Sheet 4 (variable 1) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet4, X : CMP.b #$FF : BEQ .noBgGfxChange4 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange4 + + SEP #$10 + ; Increment buffer address by 0x0600. + LDA.b $01 : CLC : ADC.b #$06 : STA.b $01 + REP #$10 + + ; Sheet 5 (variable 2) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet5, X : CMP.b #$FF : BEQ .noBgGfxChange5 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange5 + + SEP #$10 + ; Increment buffer address by 0x0600. + LDA.b $01 : CLC : ADC.b #$06 : STA.b $01 + REP #$10 + + ; Sheet 6 (variable 3) + LDX.b $0E + LDA.w Pool_OWGFXGroupTable_sheet6, X : CMP.b #$FF : BEQ .noBgGfxChange6 + SEP #$10 + + TAY + + JSL Decomp_bg_variableLONG + + .noBgGfxChange6 + + SEP #$10 + ; Increment buffer address by 0x0600. + LDA.b $01 : CLC : ADC.b #$06 : STA.b $01 + REP #$10 + + STZ.w TransGFXModuleIndex + + PLB + + JML LoadTransAuxGFX_sprite_continue ; $005706 Return to regular code. +} + +NMI_UpdateChr_Bg2HalfAndAnimatedLONG: +{ + PHB : PHK : PLB + + REP #$20 + + ; Sheet 1 + ; Set VRAM target to $3000 (word). + LDA.w #$2800 : STA.w $2116 + + ; Increment on writes to $2119. + LDY.b #$80 : STY.w $2115 + + ; Target is $2118, write two registers once ($2118 / $2119). + LDA.w #$1801 : STA.w $4300 + + ; Source address is $7F1000. + LDA.w #$1000 : STA.w $4302 + LDY.b #$7F : STY.w $4304 + + ; Write 0x0800 bytes. + LDA.w #$0800 : STA.w $4305 + + ; Transfer data on channel 1. + LDY.b #$01 : STY.w $420B + + ; Sheet 2 + ; Set VRAM target to $3000 (word). + LDA.w #$3E00 : STA.w $2116 + + ; Increment on writes to $2119. + LDY.b #$80 : STY.w $2115 + + ; Target is $2118, write two registers once ($2118 / $2119). + LDA.w #$1801 : STA.w $4300 + + ; Only copy the latter half of the sheet to prevent the animated tiles from + ; flickering on transition. + ; Source address is $7F1C00. + LDA.w #$1C00 : STA.w $4302 + LDY.b #$7F : STY.w $4304 + + ; Write 0x08400 bytes. + LDA.w #$0400 : STA.w $4305 + + ; Transfer data on channel 1. + LDY.b #$01 : STY.w $420B + + SEP #$20 + + STZ.w $0710 + + PLB + + RTL +} +pushpc + +; ============================================================================== + +if !Func00E221 = 1 + +org $00E221 ; $006221 + JML InitTilesetsLongCalls + +warnpc $00E225 ; $006225 + +org $00D904 ; $005904 + JML AnimateMirrorWarp_DecompressNewTileSetsLongCalls + +warnpc $00D908 ; $005908 + +org $00D97D ; $00597D + JML AnimateMirrorWarp_DecompressNewTileSetsLongCalls2 + +warnpc $00D981 ; $005981 + +org $00D9BC ; $0059BC + JML AnimateMirrorWarp_DecompressBackgroundsALongCalls + +warnpc $00D9C1 ; $0059C1 + +org $00DA2F ; $005A2F + JML AnimateMirrorWarp_DecompressBackgroundsCLongCalls + +else + +; Undo the functions above: +org $00E221 ; $006221 +db $AD, $A1, $0A, $29 + +org $00D904 ; $005904 +db $AD, $A1, $0A, $29 + +org $00D97D ; $00597D +db $BF, $EF, $D8, $00 + +org $00D9BC ; $0059BC +db $BF, $F1, $D8, $00 + +org $00DA2F ; $005A2F +db $BF, $F3, $D8, $00 + +endif + +pullpc +InitTilesetsLongCalls: +{ + PHB : PHK : PLB + + SEP #$20 + ; TODO: This will eventually be changed when changing the dungeon GFX. + ; Only trigger the new code when in the: + LDA.b $10 : CMP.b #$08 : BEQ .outdoors ; Pre-overworld main module + CMP.b #$0E : BEQ .outdoors ; Text Mode/Item Screen/Map module + REP #$30 + LDA.w $0AA1 : AND.w #$00FF ; Replaced code. + + PLB + + JML $00E227 ; $006227 Return to normal code. + + .outdoors + + REP #$30 + LDA.b $8A : AND.w #$00FF : ASL #3 : TAX + LDA.b $8A : AND.w #$00C0 : LSR #3 : TAY ; (Area / 8) = LW, DW, or SW *8 + SEP #$20 + + LDA.w Pool_OWGFXGroupTable_sheet0, X : CMP.b #$FF : BNE .notFF0 + LDA.w Pool_DefaultGFXGroups_sheet0, Y + + .notFF0 + + STA.b $0D + + LDA.w Pool_OWGFXGroupTable_sheet1, X : CMP.b #$FF : BNE .notFF1 + LDA.w Pool_DefaultGFXGroups_sheet1, Y + + .notFF1 + + STA.b $0C + + LDA.w Pool_OWGFXGroupTable_sheet2, X : CMP.b #$FF : BNE .notFF2 + LDA.w Pool_DefaultGFXGroups_sheet2, Y + + .notFF2 + + STA.b $0B + + LDA.w Pool_OWGFXGroupTable_sheet3, X : CMP.b #$FF : BNE .notFF3 + LDA.w Pool_DefaultGFXGroups_sheet3, Y + + .notFF3 + + STA.l $7EC2F8 : STA.b $0A + + LDA.w Pool_OWGFXGroupTable_sheet4, X : CMP.b #$FF : BNE .notFF4 + LDA.w Pool_DefaultGFXGroups_sheet4, Y + + .notFF4 + + STA.l $7EC2F9 : STA.b $09 + + LDA.w Pool_OWGFXGroupTable_sheet5, X : CMP.b #$FF : BNE .notFF5 + LDA.w Pool_DefaultGFXGroups_sheet5, Y + + .notFF5 + + STA.l $7EC2FA : STA.b $08 + + LDA.w Pool_OWGFXGroupTable_sheet6, X : CMP.b #$FF : BNE .notFF6 + LDA.w Pool_DefaultGFXGroups_sheet6, Y + + .notFF6 + + STA.l $7EC2FB : STA.b $07 + + LDA.w Pool_OWGFXGroupTable_sheet7, X : CMP.b #$FF : BNE .notFF7 + LDA.w Pool_DefaultGFXGroups_sheet7, Y + + .notFF7 + + STA.b $06 + + PLB + + JML $00E282 ; $006282 Skip normal sheet load. +} + +AnimateMirrorWarp_DecompressNewTileSetsLongCalls: +{ + PHB : PHK : PLB + + LDA.b $8A : AND.w #$00FF : ASL #3 : TAX + LDA.b $8A : AND.w #$00C0 : LSR #3 : TAY ; (Area / 8) = LW, DW, or SW *8 + SEP #$20 + + LDA.w Pool_OWGFXGroupTable_sheet3, X : CMP.b #$FF : BNE .notFF3 + LDA.w Pool_DefaultGFXGroups_sheet3, Y + + .notFF3 + + STA.l $7EC2F8 + + LDA.w Pool_OWGFXGroupTable_sheet4, X : CMP.b #$FF : BNE .notFF4 + LDA.w Pool_DefaultGFXGroups_sheet4, Y + + .notFF4 + + STA.l $7EC2F9 + + LDA.w Pool_OWGFXGroupTable_sheet5, X : CMP.b #$FF : BNE .notFF5 + LDA.w Pool_DefaultGFXGroups_sheet5, Y + + .notFF5 + + STA.l $7EC2FA + + LDA.w Pool_OWGFXGroupTable_sheet6, X : CMP.b #$FF : BNE .notFF6 + LDA.w Pool_DefaultGFXGroups_sheet6, Y + + .notFF6 + + STA.l $7EC2FB + + PLB + + JML $00D949 ; $005949 Skip normal sheet load. +} + +AnimateMirrorWarp_DecompressNewTileSetsLongCalls2: +{ + PHB : PHK : PLB + + REP #$30 + LDA.b $8A : AND.w #$00FF : ASL #3 : TAX + LDA.b $8A : AND.w #$00C0 : LSR #3 : TAY ; (Area / 8) = LW, DW, or SW *8 + SEP #$20 + + LDA.w Pool_OWGFXGroupTable_sheet1, X : CMP.b #$FF : BNE .notFF1 + LDA.w Pool_DefaultGFXGroups_sheet1, Y + + .notFF1 + + STA.b $08 + + LDA.w Pool_OWGFXGroupTable_sheet0, X : CMP.b #$FF : BNE .notFF0 + LDA.w Pool_DefaultGFXGroups_sheet0, Y + + .notFF0 + + TAY + + SEP #$10 + + PLB + + JML $00D988 ; $005988 Skip normal sheet load. +} + +AnimateMirrorWarp_DecompressBackgroundsALongCalls: +{ + PHB : PHK : PLB + + REP #$30 + LDA.b $8A : AND.w #$00FF : ASL #3 : TAX + LDA.b $8A : AND.w #$00C0 : LSR #3 : TAY ; (Area / 8) = LW, DW, or SW *8 + SEP #$20 + + LDA.w Pool_OWGFXGroupTable_sheet3, X : CMP.b #$FF : BNE .notFF3 + LDA.w Pool_DefaultGFXGroups_sheet3, Y + + .notFF3 + + STA.b $08 + + LDA.w Pool_OWGFXGroupTable_sheet2, X : CMP.b #$FF : BNE .notFF2 + LDA.w Pool_DefaultGFXGroups_sheet2, Y + + .notFF2 + + TAY + + SEP #$10 + + PLB + + JML $00D9C7 ; $0059C7 Skip normal sheet load. +} + +AnimateMirrorWarp_DecompressBackgroundsCLongCalls: +{ + PHB : PHK : PLB + + REP #$30 + LDA.b $8A : AND.w #$00FF : ASL #3 : TAX + LDA.b $8A : AND.w #$00C0 : LSR #3 : TAY ; (Area / 8) = LW, DW, or SW *8 + SEP #$20 + + LDA.w Pool_OWGFXGroupTable_sheet7, X : CMP.b #$FF : BNE .notFF7 + LDA.w Pool_DefaultGFXGroups_sheet7, Y + + .notFF7 + + STA.b $08 : STA AnimatedTileGFXSet + + LDA.w Pool_OWGFXGroupTable_sheet6, X : CMP.b #$FF : BNE .notFF6 + LDA.w Pool_DefaultGFXGroups_sheet6, Y + + .notFF6 + + TAY + + SEP #$10 + + PLB + + JML $00DA3A ; $005A3A Skip normal sheet load. +} +pushpc + +; ============================================================================== + +; A second pullpc is needed here just in case someone incorperates this ASM into +; their own code base. +pullpc +pullpc diff --git a/assets/asm/yaze.asm b/assets/asm/yaze.asm new file mode 100644 index 00000000..1bfd2eb2 --- /dev/null +++ b/assets/asm/yaze.asm @@ -0,0 +1,22 @@ +; ========================================================= +; yaze custom assembly code +; ========================================================= + +namespace yaze +{ + +!YAZE_CUSTOM_MOSAIC = 1 + + +if !YAZE_CUSTOM_MOSAIC != 0 + incsrc "mosaic_change.asm" +endif + +!ZS_CUSTOM_OVERWORLD = 1 + +if !ZS_CUSTOM_OVERWORLD != 0 + incsrc "ZSCustomOverworld.asm" +endif + +} +namespace off \ No newline at end of file diff --git a/assets/yaze.png b/assets/yaze.png new file mode 100644 index 0000000000000000000000000000000000000000..022145765afc339fd4110c6aa5346aeb3640f263 GIT binary patch literal 6580 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7&zE~RK2WrGXn!-OQy4PfTy#wLP1e}T4qiv z1B1rI+KILvhaF^&#$Wd84w2DW^k~9Dt4IOS!Yf)L3!PSqMwJ@u{K7rUL`74tuPOWB z!TzJGn!7iz<6GCH@PqNun+Ho?D5?I_*WA+a@xc!H_wQ`q-D7lGd?>`&fN#aD)Fr}& zhO?tZo7ZzVI@q%bPMERs{L&!LioW&LKYmn+KaRZj{GW`i*S(Ymf0cQuyAlQS1^n}) zte)3C;?VZw`e^xahNHMj-IHB!K1n}cbeQRUkHpL`Hiaz_I%ON~99)yK;z;n3K-a4p z@h5hzDY*A&O<2~NQvZL43gV(8pIMzvRN2s>xocruu z^=8JT8Wia);1ZqmnEikA{kyYTPjZ@T%CPT>%lVzm!tsvj?5^B;`P*fmSw7e^hezFx z&t)*4zvTMus4pBZ?y~8vyFF_Ud(1lqX8&C&9(_-iYl?6k_$^r*%=cn9>#pl}?nV8! zsAVv^68eeF!h*%Ed&=H-AKwL}=l`FV`Sm+9&#j_5+aU2WV6?C$dAqwXtYC;>P`Ki;O^-g5Z=fq&cGnvZBqSo@J6k71{tFoTPf4};3DR3@O6 z0zeE*Lm+}66O{BA96$s(72;(QXCl~2B27fHokoTe3;=Wm*j>J0{XrIiw_bLCK8D_F zc=CLI^}h*OQEB@b8$9wrLDv8x7&t&g1Bk%KQ~)ag#S;TTCUGV#J4|8FlYI$!_hsWQj6 zAAdUR{+C5BK5wu4S@a(#&p)mSr+7hL9|WFqU@!m$0ZEYua=HSDU?7w-8o;WEGh6|z zmXL`^R$@2YA-$RNQS8Zf`}p*4m+QYXy8J$8_b+mGxx$T&(*>Js?d*F5a%9~1Gj=`& zRbhj}<1;`m!Je?Ni;|FP9YAIiX*enA5v-P0hGX|N9#K+Uj>i}b|Bw*S_=*SYR+3;i zlEWUfOZyb;p2WZ3_WFzV|KBn$K9|4!MBibu*L(4hu48{$=BPHk!QAL!FdF zf+u+|*u0xl;dvC-+oiw;x9k9KYyis;QRaE?1y%M zbx~YpG=Th!Q4=VDMTs++5^Y=fi{{bofz&l{K4+_r;1D(;PN zbA^qg!A;BHj?M=5OzT5k?f<{s`HO?0!&rB-;2*Z8(XJ_j12~Z*RRbgxu=v`ZR??T) zGuFn&F$aZC6=YC&|Ns7%|MhJ7j4MYII?WP#nK|RhRa(FPJg=3Dpk0Fp;i&;aHmc@7U# z0j!od!|@n{)yn_3HztFM{|3i@*EZh>m0*OZ0()BlC=Ly>GfYcOs(#EbXuk{+@^tlc JS?83{1OUa{T2TN1 literal 0 HcmV?d00001 diff --git a/cmake/absl.cmake b/cmake/absl.cmake index 42fed470..fed9eb81 100644 --- a/cmake/absl.cmake +++ b/cmake/absl.cmake @@ -1,4 +1,8 @@ +if (MINGW) + add_subdirectory(src/lib/abseil-cpp) +else() find_package(absl) +endif() set(ABSL_PROPAGATE_CXX_STD ON) set(ABSL_CXX_STANDARD 17) set(ABSL_USE_GOOGLETEST_HEAD ON) diff --git a/cmake/asar.cmake b/cmake/asar.cmake index 278a264a..26548cdb 100644 --- a/cmake/asar.cmake +++ b/cmake/asar.cmake @@ -1,33 +1,39 @@ -get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES) -target_include_directories(asar-static PRIVATE ${ASAR_INCLUDE_DIR}) +# Asar Assembler for 65816 SNES Assembly +add_subdirectory(src/lib/asar/src) + set(ASAR_GEN_EXE OFF) set(ASAR_GEN_DLL ON) set(ASAR_GEN_LIB ON) set(ASAR_GEN_EXE_TEST OFF) set(ASAR_GEN_DLL_TEST OFF) +set(ASAR_STATIC_SRC_DIR "${CMAKE_SOURCE_DIR}/src/lib/asar/src/asar") + +get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES) +list(APPEND ASAR_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/src/lib/asar/src") +target_include_directories(asar-static PRIVATE ${ASAR_INCLUDE_DIR}) set(ASAR_STATIC_SRC - "../src/lib/asar/src/asar/interface-lib.cpp" - "../src/lib/asar/src/asar/addr2line.cpp" - "../src/lib/asar/src/asar/arch-65816.cpp" - "../src/lib/asar/src/asar/arch-spc700.cpp" - "../src/lib/asar/src/asar/arch-superfx.cpp" - "../src/lib/asar/src/asar/assembleblock.cpp" - "../src/lib/asar/src/asar/crc32.cpp" - "../src/lib/asar/src/asar/libcon.cpp" - "../src/lib/asar/src/asar/libsmw.cpp" - "../src/lib/asar/src/asar/libstr.cpp" - "../src/lib/asar/src/asar/macro.cpp" - "../src/lib/asar/src/asar/main.cpp" - "../src/lib/asar/src/asar/asar_math.cpp" - "../src/lib/asar/src/asar/virtualfile.cpp" - "../src/lib/asar/src/asar/warnings.cpp" - "../src/lib/asar/src/asar/errors.cpp" - "../src/lib/asar/src/asar/platform/file-helpers.cpp" + "${ASAR_STATIC_SRC_DIR}/interface-lib.cpp" + "${ASAR_STATIC_SRC_DIR}/addr2line.cpp" + "${ASAR_STATIC_SRC_DIR}/arch-65816.cpp" + "${ASAR_STATIC_SRC_DIR}/arch-spc700.cpp" + "${ASAR_STATIC_SRC_DIR}/arch-superfx.cpp" + "${ASAR_STATIC_SRC_DIR}/assembleblock.cpp" + "${ASAR_STATIC_SRC_DIR}/crc32.cpp" + "${ASAR_STATIC_SRC_DIR}/libcon.cpp" + "${ASAR_STATIC_SRC_DIR}/libsmw.cpp" + "${ASAR_STATIC_SRC_DIR}/libstr.cpp" + "${ASAR_STATIC_SRC_DIR}/macro.cpp" + "${ASAR_STATIC_SRC_DIR}/main.cpp" + "${ASAR_STATIC_SRC_DIR}/asar_math.cpp" + "${ASAR_STATIC_SRC_DIR}/virtualfile.cpp" + "${ASAR_STATIC_SRC_DIR}/warnings.cpp" + "${ASAR_STATIC_SRC_DIR}/errors.cpp" + "${ASAR_STATIC_SRC_DIR}/platform/file-helpers.cpp" ) if(WIN32 OR MINGW) - list(APPEND ASAR_STATIC_SRC "../src/lib/asar/src/asar/platform/windows/file-helpers-win32.cpp") + list(APPEND ASAR_STATIC_SRC "${ASAR_STATIC_SRC_DIR}/platform/windows/file-helpers-win32.cpp") else() - list(APPEND ASAR_STATIC_SRC "../src/lib/asar/src/asar/platform/linux/file-helpers-linux.cpp") + list(APPEND ASAR_STATIC_SRC "${ASAR_STATIC_SRC_DIR}/platform/linux/file-helpers-linux.cpp") endif() \ No newline at end of file diff --git a/cmake/gtest.cmake b/cmake/gtest.cmake new file mode 100644 index 00000000..6d534a93 --- /dev/null +++ b/cmake/gtest.cmake @@ -0,0 +1,11 @@ +# GoogleTest ------------------------------------------------------------------ +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) +enable_testing() \ No newline at end of file diff --git a/cmake/imgui.cmake b/cmake/imgui.cmake index 2e7cf648..bde97cee 100644 --- a/cmake/imgui.cmake +++ b/cmake/imgui.cmake @@ -10,24 +10,18 @@ target_compile_definitions(ImGui PUBLIC set(IMGUI_FILE_DLG_PATH ${CMAKE_SOURCE_DIR}/src/lib/ImGuiFileDialog) file(GLOB IMGUI_FILE_DLG_SOURCES ${IMGUI_FILE_DLG_PATH}/*.cpp) add_library("ImGuiFileDialog" STATIC ${IMGUI_FILE_DLG_SOURCES}) -target_include_directories(ImGuiFileDialog PUBLIC ${IMGUI_PATH}) -target_compile_definitions(ImGuiFileDialog PUBLIC - IMGUI_IMPL_OPENGL_LOADER_CUSTOM= GL_GLEXT_PROTOTYPES=1) +target_include_directories(ImGuiFileDialog PUBLIC ${IMGUI_PATH} ${CMAKE_SOURCE_DIR}/src/lib) set(IMGUI_COLOR_TEXT_EDIT_PATH ${CMAKE_SOURCE_DIR}/src/lib/ImGuiColorTextEdit) file(GLOB IMGUI_COLOR_TEXT_EDIT_SOURCES ${IMGUI_COLOR_TEXT_EDIT_PATH}/*.cpp) add_library("ImGuiColorTextEdit" STATIC ${IMGUI_COLOR_TEXT_EDIT_SOURCES}) -target_include_directories(ImGuiColorTextEdit PUBLIC ${IMGUI_PATH}) -target_compile_definitions(ImGuiColorTextEdit PUBLIC - IMGUI_IMPL_OPENGL_LOADER_CUSTOM= GL_GLEXT_PROTOTYPES=1) +target_include_directories(ImGuiColorTextEdit PUBLIC ${IMGUI_PATH} ${CMAKE_SOURCE_DIR}/src/lib) set(IMGUI_TEST_ENGINE_PATH ${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine/imgui_test_engine) file(GLOB IMGUI_TEST_ENGINE_SOURCES ${IMGUI_TEST_ENGINE_PATH}/*.cpp) add_library("ImGuiTestEngine" STATIC ${IMGUI_TEST_ENGINE_SOURCES}) -target_include_directories(ImGuiTestEngine PUBLIC ${IMGUI_PATH}) +target_include_directories(ImGuiTestEngine PUBLIC ${IMGUI_PATH} ${CMAKE_SOURCE_DIR}/src/lib) target_link_libraries(ImGuiTestEngine PUBLIC ImGui) -target_compile_definitions(ImGuiTestEngine PUBLIC - IMGUI_IMPL_OPENGL_LOADER_CUSTOM= GL_GLEXT_PROTOTYPES=1) set( IMGUI_SRC @@ -40,4 +34,7 @@ set( ${IMGUI_PATH}/misc/cpp/imgui_stdlib.cpp ${IMGUI_FILE_DLG_PATH}/ImGuiFileDialog.cpp ${IMGUI_COLOR_TEXT_EDIT_PATH}/TextEditor.cpp -) \ No newline at end of file +) + +# For integration test +add_definitions("-DIMGUI_ENABLE_TEST_ENGINE -DIMGUI_TEST_ENGINE_ENABLE_COROUTINE_STDTHREAD_IMPL=1") \ No newline at end of file diff --git a/cmake/mingw64.cmake b/cmake/mingw64.cmake new file mode 100644 index 00000000..a172fdf1 --- /dev/null +++ b/cmake/mingw64.cmake @@ -0,0 +1,21 @@ +# cmake -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw64.cmake -B build/build-windows && cmake --build ./build/build-windows + +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + +set(CMAKE_FIND_ROOT_PATH /usr/local/opt/mingw-w64) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -pipe -g -feliminate-unused-debug-types") + +# Static link the C++ standard library +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") \ No newline at end of file diff --git a/cmake/sdl2.cmake b/cmake/sdl2.cmake index d3464c60..94cc6531 100644 --- a/cmake/sdl2.cmake +++ b/cmake/sdl2.cmake @@ -1,6 +1,27 @@ # SDL2 -if (UNIX) +if (UNIX OR MINGW) add_subdirectory(src/lib/SDL) else() find_package(SDL2) +endif() + +set(SDL_TARGETS SDL2::SDL2) + +if(WIN32 OR MINGW) + list(PREPEND SDL_TARGETS SDL2::SDL2main ws2_32) + add_definitions(-DSDL_MAIN_HANDLED) +endif() + +# libpng +if (MINGW) + set(ZLIB_ROOT ${CMAKE_SOURCE_DIR}/build-windows/src/lib/zlib) + set(ZLIB_LIBRARY ${CMAKE_SOURCE_DIR}/build-windows/lib/libzlib.dll.a) + include_directories(${CMAKE_SOURCE_DIR}/src/lib/zlib ${CMAKE_SOURCE_DIR}/src/lib/libpng) + set(ZLIB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/lib/zlib) + set(YAZE_BUILD_PYTHON OFF) + set(YAZE_BUILD_EXTENSIONS OFF) + add_subdirectory(src/lib/zlib) + add_subdirectory(src/lib/libpng) +else() + find_package(PNG REQUIRED) endif() \ No newline at end of file diff --git a/docs/asm-style-guide.md b/docs/asm-style-guide.md new file mode 100644 index 00000000..1d2d94b2 --- /dev/null +++ b/docs/asm-style-guide.md @@ -0,0 +1,244 @@ +# Asm Style Guide + +65816 Assembly is the assembly language used by the Super Nintendo Entertainment System (SNES) and its Ricoh 5A22 processor. This style guide provides conventions and best practices for writing 65816 assembly code in the context of the yaze project. Following these guidelines will help maintain consistency and readability across the codebase. + +This guide is based primarily on the [Oracle of Secrets](https://github.com/scawful/Oracle-of-Secrets) codebase and is meant for the [Asar](https://github.com/RPGHacker/asar) assembler and derives influence from the [Asar 1.9 Manual](https://rpghacker.github.io/asar/asar_19/manual/). + +Custom assembly code applied to the game should be included through the `yaze.asm` file found in `assets/asm`. This file can be applied to the ROM by the editor using the Asar library or included into a projects codebase for use with the Asar assembler. + +## Table of Contents + +- [File Structure](#file-structure) +- [Labels and Symbols](#labels-and-symbols) +- [Comments](#comments) +- [Directives](#directives) +- [Instructions](#instructions) +- [Macros](#macros) +- [Loops and Branching](#loops-and-branching) +- [Data Structures](#data-structures) +- [Code Organization](#code-organization) +- [Custom Code](#custom-code) + + +## File Structure + +- **File Extension**: Use `.asm` as the file extension for 65816 assembly files. +- **Header Comments**: Include a header comment at the beginning of each file describing its purpose and the author. + +Example: + +```asm +; ========================================================= +; File: my_file.asm +; Purpose: [Brief description of the file’s functionality] +; Author: [Your Name] +; ========================================================= +``` + +- **Section Headers**: Use clear and consistent section headers to divide code into logical blocks. Each major section (e.g., sprite properties, main logic, subroutines) should start with a delineated header. + +Example: + +```asm +; ========================================================= +; Minecart Sprite Properties +; ========================================================= +``` + +- **Macro Definitions and Includes**: Place macros and include directives at the beginning of the file to keep them organized and easily accessible. + +## Labels and Symbols + +- **Naming Conventions**: + - **Global Labels**: Use descriptive names in `PascalCase` for global labels (e.g., `Sprite_Minecart_Main`). + - **Local Labels**: Prefix local labels with a dot (`.`) to indicate their limited scope (e.g., `.check_direction`). + - **Constants and Flags**: Use `ALL_CAPS_WITH_UNDERSCORES` for constants and flags (e.g., `!MINECART_SPEED`, `!HARVESTING_FLAG`). + - **Variables**: Use `CamelCase` for variable names to maintain readability (e.g., `LinkInCart`, `SpriteDirection`). + +- **Alignment**: Align labels to the left margin for better readability. Indent instructions and comments to separate them from labels. + +Example: + +```asm +Sprite_Minecart_Main: +{ + JSR HandleTileDirections + JSR HandleDynamicSwitchTileDirections + RTS +} +``` + + +## Comments + +- **Purpose**: Comments should explain why the code exists and what it is intended to do, especially for complex logic. +- **Placement**: + - Comments can be placed above the code block they describe for longer explanations. + - Inline comments can be used for single lines of code where the purpose might not be immediately clear. +- **Clarity**: Avoid stating the obvious. Focus on explaining the logic rather than restating the code. + +Example: + +```asm +LDA $22 : SEC : SBC $3F : STA $31 ; Adjust X position for camera movement +``` + +## Directives + +- **Organization**: Use `%macro`, `include`, and other Asar directives in a structured manner, keeping related directives grouped together. +- **Usage**: Ensure all directives are used consistently throughout the codebase, following the naming conventions and formatting rules established. + +Example: + +```asm +%macro InitMovement + LDA.b $22 : STA.b $3F + LDA.b $23 : STA.b $41 + LDA.b $20 : STA.b $3E + LDA.b $21 : STA.b $40 +endmacro +``` + +## Instructions + +- **Single Line Instructions**: Combine multiple instructions on a single line using colons (`:`) where appropriate for related operations. +- **Separation**: Use line breaks to separate distinct sections of code logically, improving readability. +- **Optimization**: Always consider the most efficient instruction for the task at hand, especially in performance-critical sections. + +Example: + +```asm +LDA #$01 : STA !LinkInCart ; Set Link in cart flag +``` + +## Macros + +- **Naming**: Use `PascalCase` for macro names, with the first letter of each word capitalized (e.g., `InitMovement`, `MoveCart`). +- **Parameters**: Clearly define and document parameters within macros to ensure they are used correctly. +- **Reuse**: Encourage the reuse of macros to avoid code duplication and simplify maintenance. + +Example: + +```asm +%macro HandlePlayerCamera + LDA $22 : SEC : SBC $3F : STA $31 + LDA $20 : SEC : SBC $3E : STA $30 + JSL Link_HandleMovingAnimation_FullLongEntry + JSL HandleIndoorCameraAndDoors + RTS +endmacro +``` + +## Loops and Branching + +- **Branch Labels**: Use meaningful names for branch labels, prefixed with a dot (`.`) for local branches. +- **Optimization**: Minimize the number of instructions within loops and branches to improve performance. + +Example: + +```asm +.loop_start + LDA $00 : CMP #$10 : BEQ .end_loop + INC $00 + BRA .loop_start +.end_loop + RTS +``` + +## Data Structures + +- **Alignment**: Align data tables and structures clearly, and use comments to describe the purpose and layout of each. +- **Access**: Ensure that data structures are accessed consistently, with clear boundaries between read and write operations. + +Example: + +```asm +.DirectionTileLookup +{ + db $02, $00, $04, $00 ; North + db $00, $00, $03, $01 ; East + db $00, $02, $00, $04 ; South + db $03, $01, $00, $00 ; West +} +``` + +- **Structs**: Use structs to group related data together, improving readability and maintainability. + +Example: + +```asm +struct AncillaAdd_HookshotData $099AF8 + .speed_y: skip 4 + .speed_x: skip 4 + .offset_y: skip 8 + .offset_x: skip 8 +endstruct + +AncillaAdd_Hookshot: + ; $099AF0 + .speed_y + db -64 ; up + db 64 ; down + db 0 ; left + db 0 ; right + ; $099AFC + .speed_x + db 0 ; up + db 0 ; down + db -64 ; left + db 64 ; right + ; $099B00 + .offset_y + dw 4 ; up + dw 20 ; down + dw 8 ; left + dw 8 ; right + ; $099B08 + .offset_x + dw 0 ; up + dw 0 ; down + dw -4 ; left + dw 11 ; right +``` + +## Code Organization + +- **Logical Grouping**: Organize code into logical sections, with related routines and macros grouped together. +- **Separation of Concerns**: Ensure that each section of code is responsible for a specific task or set of related tasks, avoiding tightly coupled code. +- **Modularity**: Write code in a modular way, making it easier to reuse and maintain. +- **Status Registers and Stack Operations**: Indent code blocks when using status register operations (REP, SEP, PHX, PLX, etc.) to improve readability. + +Example: + +```asm +; ========================================================= +; Minecart Sprite Logic +; ========================================================= +Sprite_Minecart_Main: +{ + JSR HandleTileDirections + JSR HandleDynamicSwitchTileDirections + PHX + JSR HandleMinecartMovement + PLX + + REP #$20 + LDA !SpriteDirection : STA $00 + SEP #$20 + RTS +} +``` + +## Custom Code + +- **Integration**: Include custom assembly code in the `yaze.asm` file to ensure it is applied correctly to the ROM. The module should include a define and conditional statement to allow users to disable the module if needed. + +Example: + +```asm +!YAZE_CUSTOM_MOSAIC = 1 + +if !YAZE_CUSTOM_MOSAIC != 0 + incsrc "mosaic_change.asm" +endif +``` \ No newline at end of file diff --git a/docs/build-instructions.md b/docs/build-instructions.md index d562c2fc..b24d4526 100644 --- a/docs/build-instructions.md +++ b/docs/build-instructions.md @@ -1,27 +1,58 @@ # Build Instructions +For VSCode users, use the following CMake extensions + +- https://marketplace.visualstudio.com/items?itemName=twxs.cmake +- https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools + +Yaze uses CMake to build the project. If you are unexperienced with CMake, please refer to the [CMake documentation](https://cmake.org/documentation/). + +The gui editor is built using SDL2 and ImGui. For reference on how to use ImGui, see the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide. For SDL2, see the [SDL2 documentation](https://wiki.libsdl.org/). + +For those who want to reduce compile times, consider installing the dependencies on your system. + ## Windows -For VSCode users, use the following CMake extensions with MinGW-w64 - -https://marketplace.visualstudio.com/items?itemName=twxs.cmake -https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools - -https://www.msys2.org/ +Recommended to use [msys2](https://www.msys2.org/) for a Unix-like environment on Windows. Add to environment variables `C:\msys64\mingw64\bin` Install the following packages using `pacman -S ` -`mingw-w64-x86_64-gcc` -`mingw-w64-x86_64-gcc-libs` -`mingw-w64-x86_64-cmake` -`mingw-w64-x86_64-glew` -`mingw-w64-x86_64-lib-png` +- `mingw-w64-x86_64-gcc` +- `mingw-w64-x86_64-gcc-libs` +- `mingw-w64-x86_64-cmake` +- `mingw-w64-x86_64-sdl2` +- `mingw-w64-x86_64-libpng` +- `mingw-w64-x86_64-abseil-cpp` + +For `yaze_py` you will need Boost Python + +- `mingw-w64-x86_64-boost` # macOS -- Clang 15.0.1 x86_64-apple-darrwin22.5.0 -- SDL2 Source v2.26.5 -- Removed snes_spc -- Removed asar_static \ No newline at end of file +Prefer to use clang provided with XCode command line tools over gcc. + +Install the following packages using `brew install ` + +- `cmake` +- `sdl2` +- `zlib` +- `libpng` +- `abseil` +- `boost-python3` + +# iOS + +Xcode is required to build for iOS. Currently testing with iOS 18 on iPad Pro. + +The xcodeproject file is located in the `ios` directory. + +You will need to link `SDL2.framework` and `libpng.a` to the project. + +# GNU/Linux + +You can use your package manager to install the same dependencies as macOS. + +I trust you know how to use your package manager. \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 00000000..63caeec4 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,47 @@ +# Changelog + +## 0.0.1 (06-08-2022) + +- Started project +- Added ImGui +- Added SDL2 +- Added yaze_test target with gtest + +## 0.0.2 - 0.0.4 + +- TODO: Track changes over this time + +## 0.0.5 (11-21-2023) + +- DungeonEditor +- DungeonObjectRenderer + +## 0.0.6 (11-22-2023) + +- ScreenEditor DungeonMap +- Tile16 Editor +- Canvas updates + +## 0.0.7 (01-27-2024) + +- OverworldEntities + - Entrances + - Exits + - Items + - Sprites + +## 0.1.0 (05-11-2024) + +- TODO: Track changes over this time + +## 0.2.0 (07-20-2024) + +- iOS app support +- Graphics Sheet Browser +- Project Files + +## 0.2.1 (08-20-2024) + +- Improved MessageEditor parsing +- Added integration test window +- Bitmap bug fixes diff --git a/docs/compression.md b/docs/compression.md deleted file mode 100644 index 6395426d..00000000 --- a/docs/compression.md +++ /dev/null @@ -1,66 +0,0 @@ -# LC_LZ2 Compression - -The compression algorithm has multiple implementations with varying levels of quality, based primarily on the implementations made in skarsnik/sneshacking, Zarby89/ZScreamDungeon and ZCompress with optimizations made for C++. - -Currently, the Compress and Uncompress methods from Hyrule Magic are used and all other compression methods are considered deprecated. - -## Key Definitions - -### Constants and Macros: -- `BUILD_HEADER(command, length)`: Macro to build a header from a command and a length. -- Command Constants: Constants to represent different commands like `kCommandDirectCopy`, `kCommandByteFill`, etc. -- Length and Mode Constants: Such as `kMaxLengthNormalHeader`, `kNintendoMode1`, etc. - -### Data Structures: - -#### 1. CompressionCommand: - - **arguments**: 2D array representing the command arguments for each possible command. - - **cmd_size**: Array storing the size of each possible command. - - **data_size**: Array storing the size of the data processed by each possible command. - -#### 2. CompressionPiece: - - **command**: Represents the compression command. - - **length**: Length of the compressed data piece. - - **argument_length**: Length of the argument. - - **argument**: Argument as a string. - - **next**: Pointer to the next compression piece. - -#### 3. CompressionContext (for Compression V3): - - Contains vectors to store raw and compressed data, compression pieces, and compression string. - - Various counters and flags for compression control. - - Current compression command details. - -## Compression Functions - -### Version 1: -- **Byte Repeat**: `CheckByteRepeat` -- **Word Repeat**: `CheckWordRepeat` -- **Increasing Byte**: `CheckIncByte` -- **Intra Copy**: `CheckIntraCopy` -- **Validation and Alternatives**: `ValidateForByteGain` & `CompressionCommandAlternative` - -### Version 2: -- **Byte Repeat**: `CheckByteRepeatV2` -- **Word Repeat**: `CheckWordRepeatV2` -- **Increasing Byte**: `CheckIncByteV2` -- **Intra Copy**: `CheckIntraCopyV2` -- **Validation and Alternatives**: `ValidateForByteGainV2` & `CompressionCommandAlternativeV2` - -### Version 3: -Using `CompressionContext` to handle compression. -- **Initialization**: `InitializeCompression` -- **Command Checks**: Such as `CheckByteRepeatV3` -- **Determining Best Compression**: `DetermineBestCompression` -- **Handling Direct Copy**: `HandleDirectCopy` -- **Adding Compression to Chain**: `AddCompressionToChain` - -## Decompression Functions: -- `SetBuffer`: Prepares a buffer from data. -- `memfill`: Fills memory. -- **Decompression**: Such as `DecompressV2`, `DecompressGraphics`, and `DecompressOverworld`. - -## Utility Functions: -- **Printing**: Such as `PrintCompressionPiece` and `PrintCompressionChain`. -- **Compression String Creation**: `CreateCompressionString` -- **Compression Result Validation**: Such as `ValidateCompressionResult` and its V3 variant. -- **Compression Piece Manipulation**: Like `SplitCompressionPiece` and its V3 variant. diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 00000000..4531e184 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,139 @@ +# Contributing + +This project is looking for contributors to help improve the software and enhance the user experience. If you are interested in contributing, please read the following guidelines and suggestions for areas where you can make a difference. + +Discussion on the editor and its development can be found on the [Oracle of Secrets Discord](https://discord.gg/MBFkMTPEmk) server. + +## Style Guide + +When contributing to the project, please follow these guidelines to ensure consistency and readability across the codebase: + +C++ Code should follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) with the following exceptions: + +- Boost libraries are allowed, but require cross platform compatibility. + +Objective-C Code should follow the [Google Objective-C Style Guide](https://google.github.io/styleguide/objcguide.html). + +Python Code should follow the [PEP 8 Style Guide](https://pep8.org/). + +Assembly code should follow the [65816 Style Guide](docs/asm-style-guide.md). + +## Testing Facilities + +The project includes the `yaze_test` target which defines unit tests and an integration test window. The unit tests make use of GoogleTest and GoogleMock. The integration test window is an ImGui window build out of the yaze::app::core::Controller and yaze::test::integration::TestEditor. The integration test window can be accessed by passing the argument `integration` to the target. + +New modules should define unit tests in the `src/test` directory and integration tests in the `src/test/integration` directory. The `yaze_test` target will automatically include all tests in these directories. + +## Key Areas of Contribution + +### 1. Extensions System + +Yaze *(stylized as yaze)* emphasizes extensibility. The `yaze_ext` library allows developers to build and integrate extensions using C, C++, or Python. This system is central to yaze's modular design, enabling new features, custom editors, or tools to be added without modifying the core codebase. + +- C/C++ Extensions: Utilize the `yaze_extension` interface to integrate custom functionality into the editor. You can add new tabs, manipulate ROM data, or extend the editor’s capabilities with custom tools. +- Python Extensions: Currently unimplemented, Python extensions will allow developers to write scripts that interact with the editor, modify ROM data, or automate repetitive tasks. + +Examples of Extensions: + +- UI enhancements like additional menus, panels, or status displays. +- Rom manipulation tools for editing data structures, such as the overworld maps or dungeon objects. +- Custom editors for specific tasks, like file format conversion, data visualization, or event scripting. + +### 2. Sprite Builder System + +The sprite builder system in yaze is based on the [ZSpriteMaker](https://github.com/Zarby89/ZSpriteMaker/) project and allows users to create custom sprites for use in ROM hacks. The goal is to support ZSM files and provide an intuitive interface for editing sprites without the need for writing assembly code. Contributions to the sprite builder system might include: + +- Implementing new features for sprite editing, such as palette management, animation preview, or tileset manipulation. +- Extending the sprite builder interface by writing assembly code for sprite behavior. + +### 3. Emulator Subsystem + +yaze includes an emulator subsystem that allows developers to test their modifications directly within the editor. The emulator can currently run certain test ROMs but lacks the ability to play any complex games with audio because of timing issues with the APU and Spc700. Contributions to the emulator subsystem might include: + +- Improving the accuracy and performance of the emulator to support more games and features. +- Implementing new debugging tools, such as memory viewers, breakpoints, or trace logs. +- Extending the emulator to support additional features, such as save states, cheat codes, or multiplayer modes. + +### 4. Editor Management + +The `EditorManager` class manages the core functionalities of YAZE, including rendering the UI, handling user input, and managing multiple editors. While this class is central to yaze's operations, it has many responsibilities. You can help by: + +- Refactoring `EditorManager` to delegate responsibilities to specialized managers (e.g., `MenuManager`, `TabManager`, `StatusManager`). +- Optimizing the rendering and update loop to improve performance, especially when handling large textures or complex editors. +- Implementing new features that streamline the editing process, such as better keyboard shortcuts, command palette integration, or project management tools. + +### 5. User Interface and UX + +yaze's UI is built with ImGui, offering a flexible and customizable interface. Contributions to the UI might include: + +- Designing and implementing new themes or layouts to improve the user experience. +- Adding new UI components, such as toolbars, context menus, or customizable panels. +- Improving the accessibility of the editor, ensuring it is usable by a wide range of users, including those with disabilities. + +### 6. ROM Manipulation + +The `Rom` class is at the heart of yaze's ability to modify and interact with ROM data. Contributions here might involve: + +- Optimizing the loading and saving processes to handle larger ROMs or more complex modifications efficiently. +- Extensions should be able to change the way the `Rom` class interacts with the ROM data with custom pointers to expanded data structures. + +### 7. Testing and Documentation + +Quality assurance and documentation are critical to yaze's success. Contributions in this area include: + +- Writing unit tests for new and existing features to ensure they work correctly and remain stable over time. +- Contributing to the documentation, both for end-users and developers, to make yaze easier to use and extend. +- Creating tutorials or guides that help new developers get started with building extensions or contributing to the project. + +## Building the Project + +For detailed instructions on building YAZE, including its dependencies and supported platforms, refer to [build-instructions.md](docs/build-instructions.md). + +## Getting Started + +1. Clone the Repository: + +```bash +git clone https://github.com/yourusername/yaze.git +cd yaze +``` + +2. Initialize the Submodules: + +```bash +git submodule update --init --recursive +``` + +3. Build the Project: + +Follow the instructions in the [build-instructions.md](docs/build-instructions.md). file to configure and build the project on your target platform. + +4. Run the Application: + +After building, you can run the application on your chosen platform and start exploring the existing features. + +## Contributing your Changes + +1. Fork the Repository: + +Create a fork of the project on GitHub and clone your fork to your local machine. + +2. Create a Branch: + +Create a new branch for your feature or bugfix. + +```bash +git checkout -b feature/my-new-feature +``` + +3. Implement Your Changes: + +Follow the guidelines above to implement new features, extensions, or improvements. + +4. Test Your Changes: + +Ensure your changes don’t introduce new bugs or regressions. Write unit tests where applicable. + +5. Submit a Pull Request: + +Push your changes to your fork and submit a pull request to the main repository. Provide a clear description of your changes and why they are beneficial. diff --git a/docs/getting-started.md b/docs/getting-started.md index 736c3815..a7105228 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,23 +1,60 @@ -# Getting Started with YAZE +# Getting Started -This software allows you to modify the classic SNES game "The Legend of Zelda: A Link to the Past" by editing its ROM file. With this editor, you can change various aspects of the game, such as the maps, sprites, items, and more. +This software allows you to modify "The Legend of Zelda: A Link to the Past" (US or JP) ROMs. + +This editor is built to be compatible with ZScream projects and is designed to be cross platform. Please note that this project is currently a work in progress, and some features may not be fully implemented or may be subject to change. -## Prerequisites -Before you start using YAZE, make sure you have the following: +## General Tips -- A copy of "The Legend of Zelda: A Link to the Past" ROM file (US or JP) -- Basic knowledge of hexadecimal and binary data +- Experiment flags determine whether certain features are enabled or not. To change your flags, go to `File` > `Options` > `Experiment Flags` or in the Settings tab. +- Backup files are enabled by default. Each save will produce a timestamped copy of your ROM before you last saved. You can disable this feature in the settings. -## Usage -To use the Link to the Past ROM Editor, follow these steps: +## Extending Functionality -Open the ROM file using the "File" menu. +In addition to the built-in features, this software provides a pure C library interface and a Python module that can be used for building extensions and custom sprites without assembly. In the editor these can be loaded under the `Extensions` menu. -... +This feature is still in development and is not yet fully documented. + +## Supported Features + +| Feature | Status | Details | +|---------|--------|-------------| +| Overworld Maps | Done | Edit and save tile32 data. | +| Overworld Map Properties | Done | Edit and save map properties. | +| Overworld Entrances | Done | Edit and save entrance data. | +| Overworld Exits | Done | Edit and save exit data. | +| Overworld Sprites | In Progress | Edit sprite positions, add and remove sprites. | +| Tile16 Editing | Todo | Edit and save tile16 data. | +| Dungeon | In Progress | View dungeon room metadata and edit room data. | +| Palette | In Progress | Edit and save palettes, palette groups. | +| Graphics Sheets | In Progress | Edit and save graphics sheets. | +| Graphics Groups | Done | Edit and save graphics groups. | +| Sprite | Todo | View-only sprite data. | +| Custom Sprites | Todo | Edit and create custom sprite data. | +| Music | Todo | Edit music data. | +| Dungeon Maps | Todo | Edit dungeon maps. | +| Scad Format | Done-ish | Open and view scad files (SCR, CGX, COL) | +| Hex Editing | Done | View and edit ROM data in hex. | +| Asar Patching | In Progress | Apply Asar patches to your ROM or Project. | + +## Command Line Interface + +Included with the editor is a command line interface (CLI) that allows you to perform various operations on your ROMs from the command line. This aims to reduce the need for multiple tools in zelda3 hacking like Zcompress, LunarExpand, LunarAddress, Asar, and others. + +| Command | Arg | Params | Status | +|---------|-----|--------|--------| +| Apply BPS Patch | -a | rom_file bps_file | In progress | +| Create BPS Patch | -c | bps_file src_file modified_file | Not started | +| Asar Patch | -asar | asm_file rom_file | In progress | +| Open ROM | -o | rom_file | Complete | +| Backup ROM | -b | rom_file [new_file] | In progress | +| Expand ROM | -x | rom_file file_size | Not started | +| Transfer Tile16 | -t | src_rom dest_rom tile32_id_list(csv) | Complete | +| Export Graphics | -e | rom_file bin_file | In progress | +| Import Graphics | -i | bin_file rom_file | Not started | +| SNES to PC Address | -s | address | Complete | +| PC to SNES Address | -p | address | Complete | -Save your changes using the "File" menu. -Backup files are enabled by default. Each save will produce a timestamped copy of your ROM before you last saved. -That's it! With these instructions, you should be able to get started with using YAZE. Happy editing! \ No newline at end of file diff --git a/docs/infrastructure.md b/docs/infrastructure.md index 0b53b3f8..61e70294 100644 --- a/docs/infrastructure.md +++ b/docs/infrastructure.md @@ -1,140 +1,86 @@ -# YAZE Infrastructure Overview +# Infrastructure Overview For developers to reference. +The goal of yaze is to build a cross platform editor for the Legend of Zelda: A Link to the Past. The project is built using C++20, SDL2, and ImGui. The project is built using CMake and is designed to be modular and extensible. The project is designed to be built on Windows, macOS, iOS, and Linux. + +## Targets + +- **yaze**: Desktop application for Windows/macOS/Linux +- **z3ed**: Command Line Interface +- **yaze_c**: C Library +- **yaze_py**: Python Module +- **yaze_test**: Unit test executable +- **yaze_ios**: iOS application + ## Directory Structure -- **.github/workflows**: Contains `yaze_test` workflow config. -- **assets**: Hosts assets like fonts. +- **assets**: Hosts assets like fonts, icons, assembly source, etc. - **cmake**: Contains CMake configurations. - **docs**: Contains documentation for users and developers. - - [Getting Started](./getting-started.md) - - [LC_LZ2 Compression](./compression.md) - **src**: Contains source files. - - **app**: Contains the GUI editor `yaze` - - **cli**: Contains the command line interface `z3ed` - - **lib**: Contains git submodule dependencies. - - Abseil-cpp - - Asar - - ImGui - - ImGuiFileDialog - - ImGuiColorTextEdit - - imgui_memory_editor - - SDL2 -- **test**: Contains testing interface `yaze_test` + - **app**: Contains the GUI editor `yaze` + - **app/emu**: Contains a standalone Snes emulator application `yaze_emu` + - **cli**: Contains the command line interface `z3ed` + - **incl**: Contains the data headers for `yaze_c` + - **ios**: Contains the iOS application `yaze_ios` + - **lib**: Contains the dependencies as git submodules + - **py**: Contains the Python module `yaze_py` + - **test**: Contains testing interface `yaze_test` + - **win32**: Contains Windows resource file and icon -### Flow of Control +## Dependencies -- [app/yaze.cc](../src/app/yaze.cc) +See [build-instructions.md](docs/build-instructions.md) for more information. + +- **SDL2**: Graphics library +- **ImGui**: GUI library +- **Abseil**: C++ library +- **libpng**: Image library +- **Boost**: Python library + +## Flow of Control + +- app/yaze.cc - Initializes `absl::FailureSignalHandler` for stack tracing. - Runs the `core::Controller` loop. -- [app/core/controller.cc](../src/app/core/controller.cc) +- app/core/controller.cc - Initializes SDLRenderer and SDLWindow - Initializes ImGui, fonts, themes, and clipboard. - Handles user input from keyboard and mouse. - - Updates `editor::MasterEditor` - Renders the output to the screen. - Handles the teardown of SDL and ImGui resources. -- [app/editor/master_editor.cc](../src/app/editor/master_editor.cc) - - Handles the main menu bar. - - File - - Open - [app::ROM::LoadFromFile](../src/app/rom.cc#l=90) - - Save - [app::ROM::SaveToFile](../src/app/rom.cc#l=301) - - Edit - - View - - Emulator - - HEX Editor - - ASM Editor - - Palette Editor - - Memory Viewer - - ImGui Demo - - GUI Tools - - Runtime Metrics - - Style Editor - - Help +- app/editor/editor_manager.cc + - Handles the main menu bar - Handles `absl::Status` errors as popups delivered to the user. + - Dispatches messages to the various editors. - Update all the editors in a tab view. - - [app/editor/assembly_editor.cc](../src/app/editor/assembly_editor.cc) - - [app/editor/dungeon_editor.cc](../src/app/editor/dungeon_editor.cc) - - [app/editor/graphics_editor.cc](../src/app/editor/graphics_editor.cc) - - [app/editor/music_editor.cc](../src/app/editor/music_editor.cc) - - [app/editor/overworld_editor.cc](../src/app/editor/overworld_editor.cc) - - [app/editor/screen_editor.cc](../src/app/editor/screen_editor.cc) - - [app/editor/sprite_editor.cc](../src/app/editor/sprite_editor.cc) + - app/editor/code/assembly_editor.cc + - app/editor/dungeon/dungeon_editor.cc + - app/editor/graphics/graphics_editor.cc + - app/editor/graphics/gfx_group_editor.cc + - app/editor/graphics/palette_editor.cc + - app/editor/graphics/tile16_editor.cc + - app/editor/message/message_editor.cc + - app/editor/music/music_editor.cc + - app/editor/overworld/overworld_editor.cc + - app/editor/graphics/screen_editor.cc + - app/editor/sprite/sprite_editor.cc + - app/editor/system/settings_editor.cc -## ROM -- [app/rom.cc](../src/app/rom.cc) -- [app/rom.h](../src/app/rom.h) ---- +## Rom -This `ROM` class provides methods to manipulate and access data from a ROM. +- app/rom.cc +- app/rom.h -- **Key Methods**: - - `Load2BppGraphics()`: Loads 2BPP graphics data from specified sheets. - - `LoadAllGraphicsData()`: Loads all graphics data, both compressed and uncompressed, converting where necessary. - - `LoadFromFile(const absl::string_view& filename, bool z3_load)`: Loads ROM data from a file. It also handles headers and Zelda 3 specific data if requested. - - `LoadFromPointer(uchar* data, size_t length)`: Loads ROM data from a provided pointer. - - `LoadFromBytes(const Bytes& data)`: Loads ROM data from bytes. - - `LoadAllPalettes()`: Loads all color palettes used in the ROM. This includes palettes for various elements like sprites, shields, swords, etc. - - `UpdatePaletteColor(...)`: Updates a specific color within a named palette group. +The Rom class provides methods to manipulate and access data from a ROM. -- **Internal Data Structures**: - - `rom_data_`: A container that holds the ROM data. - - `graphics_bin_`: Holds the graphics data. - - `palette_groups_`: A map containing various palette groups, each having its own set of color palettes. - -- **Special Notes**: - - The class interacts with various external functionalities, such as decompression algorithms (`gfx::DecompressV2`) and color conversion (`gfx::SnesTo8bppSheet`). - - Headers in the ROM data, if present, are identified and removed. - - Specific Zelda 3 data can be loaded if specified. - - Palettes are categorized into multiple groups (e.g., `ow_main`, `ow_aux`, `hud`, etc.) and loaded accordingly. +Currently implemented as a singleton with SharedRom which is not great but has helped with development velocity. Potential room for improvement is to refactor the editors to take the ROM as a parameter. ## Bitmap -- [app/gfx/bitmap.cc](../src/app/gfx/bitmap.cc) -- [app/gfx/bitmap.h](../src/app/gfx/bitmap.cc) ---- +- app/gfx/bitmap.cc +- app/gfx/bitmap.h -This class is responsible for creating, managing, and manipulating bitmap data, which can be displayed on the screen using the ImGui library. +This class is responsible for creating, managing, and manipulating bitmap data, which can be displayed on the screen using SDL2 Textures and the ImGui draw list. It also provides functions for exporting these bitmaps to the clipboard in PNG format using libpng. -### Key Attributes: - -1. **Width, Height, Depth, and Data Size**: These represent the dimensions and data size of the bitmap. -2. **Pixel Data**: Points to the raw data of the bitmap. -3. **Texture and Surface**: Use SDL to manage the graphical representation of the bitmap data. Both these attributes have custom deleters, ensuring proper resource management. - -### Main Functions: - -1. **Constructors**: Multiple constructors allow for different ways to create a Bitmap instance, like specifying width, height, depth, and data. -2. **Create**: This set of overloaded functions provides ways to create a bitmap from different data sources. -3. **CreateFromSurface**: Allows for the creation of a bitmap from an SDL_Surface. -4. **Apply**: Changes the bitmap's data to a new set of Bytes. -5. **Texture Operations**: - - **CreateTexture**: Creates an SDL_Texture from the bitmap's data for rendering. - - **UpdateTexture**: Updates the SDL_Texture with the latest bitmap data. -6. **SaveSurfaceToFile**: Saves the SDL_Surface to a file. -7. **SetSurface**: Assigns a new SDL_Surface to the bitmap. -8. **Palette Functions**: - - **ApplyPalette (Overloaded)**: This allows for the application of a SNESPalette or a standard SDL_Color palette to the bitmap. -9. **WriteToPixel**: Directly writes a value to a specified position in the pixel data. - -## Z3ED cli - -| Command | Arg | Params | Status | -|---------|-----|--------|--------| -| Apply BPS Patch | -a | rom_file bps_file | In progress | -| Create BPS Patch | -c | bps_file src_file modified_file | Not started | -| Open ROM | -o | rom_file | Complete | -| Backup ROM | -b | rom_file [new_file] | In progress | -| Expand ROM | -x | rom_file file_size | Not started | -| Transfer Tile16 | -t | src_rom dest_rom tile32_id_list(csv) | Complete | -| Export Graphics | -e | rom_file bin_file | In progress | -| Import Graphics | -i | bin_file rom_file | Not started | -| SNES to PC Address | -s | address | Complete | -| PC to SNES Address | -p | address | Complete | - - -## Further Development Ideas -- Extend `zelda3` namespace with additional functionalities. -- Optimize program performance. -- Introduce new features in the GUI editor. diff --git a/docs/yaze.org b/docs/yaze.org new file mode 100644 index 00000000..df78744e --- /dev/null +++ b/docs/yaze.org @@ -0,0 +1,63 @@ +#+TITLE: yaze todo +#+SUBTITLE: yet another zelda3 editor todo list +#+AUTHOR: @scawful +#+TODO: TODO ACTIVE FEEDBACK VERIFY | DONE + +* Daily Log + +<2024-11-14 Thu> +Been making lots of adjustments and cleaning up old code. Primarily improving the dungeon map editor and supporting bin graphics for my Oracle of Secrets dungeon maps. Additionally, working to support saving for resources like graphics sheets and expanded the project file system. + +<2024-09-07 Sat> +Various header cleanup using the LSP in emacs to detect unused includes. +Making adjustments to font loading so the editor can be opened from terminal/emacs. +Currently the font files and the zeml files require the binary to be relative to `assets/layouts` and `assets/fonts` +I've set it up so that the macOS app bundles the resources into the `yaze.app` so that the binary can be run from anywhere. This will need to be adjusted for other platforms. + +<2024-09-02 Mon> +Extracted the DisplayPalette function out of the PaletteEditor and into its own standalone function. + +<2024-09-01 Sun> +Started learning spacemacs and org-mode. + +* Editors +** Overworld +*** TODO ZSCustomOverworld implementation. +**** DONE Custom Overworld Map Settings Inputs +**** DONE Load ZSCOW data from ROM in OverworldMap +**** TODO Add Main Palette support +**** TODO Add Custom Area BG Color support + +*** TODO Fix sprite icon draw positions +*** TODO Fix exit icon draw positions + +** Dungeon +*** TODO Draw dungeon objects + +** Graphics +*** TODO Tile16 Editor +- [ ] Draw tile8 to tile16 quadrant. + +*** TODO Fix graphics sheet pencil drawing + +** Message +*** TODO Fix Message Parsing + +** Palette +*** TODO Persist color changes for saving to ROM. + +** Screens +*** ACTIVE Dungeon Maps +*** ACTIVE Inventory Menu +*** TODO Overworld Map +*** TODO Title Screen +*** TODO Naming Screen + +* Infrastructure +** File Handling +*** TODO Update recent files manager to bundle the recent files list with the application +*** DONE Create a util for handling file operations from the bundled resources. +** Font Loading +*** TODO Make font sizes variables so they can be reloaded by the user. +** ZEML +*** DONE Package layout files with the executable to avoid relative file lookup diff --git a/incl/dungeon.h b/incl/dungeon.h new file mode 100644 index 00000000..d476e1f7 --- /dev/null +++ b/incl/dungeon.h @@ -0,0 +1,61 @@ +#ifndef YAZE_BASE_DUNGEON_H_ +#define YAZE_BASE_DUNGEON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct z3_object_door { + short id; + uint8_t x; + uint8_t y; + uint8_t size; + uint8_t type; + uint8_t layer; +} z3_object_door; + +typedef struct z3_dungeon_destination { + uint8_t index; + uint8_t target; + uint8_t target_layer; +} z3_dungeon_destination; + +typedef struct z3_staircase { + uint8_t id; + uint8_t room; + const char *label; +} z3_staircase; + +typedef struct z3_chest { + uint8_t x; + uint8_t y; + uint8_t item; + bool picker; + bool big_chest; +} z3_chest; + +typedef struct z3_chest_data { + uint8_t id; + bool size; +} z3_chest_data; + +typedef enum z3_dungeon_background2 { + Off, + Parallax, + Dark, + OnTop, + Translucent, + Addition, + Normal, + Transparent, + DarkRoom +} z3_dungeon_background2; + +#ifdef __cplusplus +} +#endif + +#endif // YAZE_BASE_DUNGEON_H_ diff --git a/incl/overworld.h b/incl/overworld.h new file mode 100644 index 00000000..086857db --- /dev/null +++ b/incl/overworld.h @@ -0,0 +1,47 @@ +#ifndef YAZE_OVERWORLD_H +#define YAZE_OVERWORLD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "sprite.h" + +/** + * @brief Primitive of an overworld map. + */ +typedef struct z3_overworld_map { + uint8_t id; /**< ID of the overworld map. */ + uint8_t parent_id; + uint8_t quadrant_id; + uint8_t world_id; + uint8_t game_state; + uint8_t area_graphics; + uint8_t area_palette; + + uint8_t sprite_graphics[3]; + uint8_t sprite_palette[3]; + uint8_t area_music[4]; + uint8_t static_graphics[16]; +} z3_overworld_map; + +/** + * @brief Primitive of the overworld. + */ +typedef struct z3_overworld { + void *impl; // yaze::app::Overworld* + + uint8_t *tile32_data; /**< Pointer to the 32x32 tile data. */ + uint8_t *tile16_data; /**< Pointer to the 16x16 tile data. */ + + z3_sprite **sprites; /**< Pointer to the sprites per map. */ + z3_overworld_map **maps; /**< Pointer to the overworld maps. */ +} z3_overworld; + +#ifdef __cplusplus +} +#endif + +#endif // YAZE_OVERWORLD_H diff --git a/incl/snes_color.h b/incl/snes_color.h new file mode 100644 index 00000000..db23db0c --- /dev/null +++ b/incl/snes_color.h @@ -0,0 +1,32 @@ +#ifndef YAZE_BASE_SNES_COLOR_H_ +#define YAZE_BASE_SNES_COLOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief Primitive of 16-bit RGB SNES color. + */ +typedef struct snes_color { + uint16_t red; /**< Red component of the color. */ + uint16_t blue; /**< Blue component of the color. */ + uint16_t green; /**< Green component of the color. */ +} snes_color; + +/** + * @brief Primitive of a SNES color palette. + */ +typedef struct snes_palette { + unsigned int id; /**< ID of the palette. */ + unsigned int size; /**< Size of the palette. */ + snes_color* colors; /**< Pointer to the colors in the palette. */ +} snes_palette; + +#ifdef __cplusplus +} +#endif + +#endif // YAZE_BASE_SNES_COLOR_H_ diff --git a/incl/snes_tile.h b/incl/snes_tile.h new file mode 100644 index 00000000..922bbf4d --- /dev/null +++ b/incl/snes_tile.h @@ -0,0 +1,40 @@ +#ifndef YAZE_INCL_SNES_TILE_H +#define YAZE_INCL_SNES_TILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct snes_tile8 { + uint32_t id; + uint32_t palette_id; + uint8_t data[64]; +} snes_tile8; + +typedef struct snes_tile_info { + uint16_t id; + uint8_t palette; + bool priority; + bool vertical_mirror; + bool horizontal_mirror; +} snes_tile_info; + +typedef struct snes_tile16 { + snes_tile_info tiles[4]; +} snes_tile16; + +typedef struct snes_tile32 { + uint16_t t0; + uint16_t t1; + uint16_t t2; + uint16_t t3; +} snes_tile32; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/incl/sprite.h b/incl/sprite.h new file mode 100644 index 00000000..fc7761bd --- /dev/null +++ b/incl/sprite.h @@ -0,0 +1,23 @@ +#ifndef YAZE_BASE_SPRITE_H_ +#define YAZE_BASE_SPRITE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief Primitive of a sprite. + */ +typedef struct z3_sprite { + const char* name; /**< Name of the sprite. */ + uint8_t id; /**< ID of the sprite. */ + uint8_t subtype; /**< Subtype of the sprite. */ +} z3_sprite; + +#ifdef __cplusplus +} +#endif + +#endif // YAZE_BASE_SPRITE_H_ \ No newline at end of file diff --git a/incl/system/extension.h b/incl/system/extension.h new file mode 100644 index 00000000..7c9e2f60 --- /dev/null +++ b/incl/system/extension.h @@ -0,0 +1,91 @@ +#ifndef EXTENSION_INTERFACE_H +#define EXTENSION_INTERFACE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "yaze.h" + +typedef void (*yaze_initialize_func)(yaze_editor_context* context); +typedef void (*yaze_cleanup_func)(void); +typedef void (*yaze_extend_ui_func)(yaze_editor_context* context); +typedef void (*yaze_manipulate_rom_func)(z3_rom* rom); +typedef void (*yaze_command_func)(void); +typedef void (*yaze_event_hook_func)(void); + +typedef enum { + YAZE_EVENT_ROM_LOADED, + YAZE_EVENT_ROM_SAVED, + YAZE_EVENT_SPRITE_MODIFIED, + YAZE_EVENT_PALETTE_CHANGED, +} yaze_event_type; + +/** + * @brief Extension interface for Yaze. + * + * @details Yaze extensions can be written in C or Python. + */ +typedef struct yaze_extension { + const char* name; + const char* version; + + /** + * @brief Function to initialize the extension. + * + * @details This function is called when the extension is loaded. It can be + * used to set up any resources or state needed by the extension. + */ + yaze_initialize_func initialize; + + /** + * @brief Function to clean up the extension. + * + * @details This function is called when the extension is unloaded. It can be + * used to clean up any resources or state used by the extension. + */ + yaze_cleanup_func cleanup; + + /** + * @brief Function to manipulate the ROM. + * + * @param rom The ROM to manipulate. + * + */ + yaze_manipulate_rom_func manipulate_rom; + + /** + * @brief Function to extend the UI. + * + * @param context The editor context. + * + * @details This function is called when the extension is loaded. It can be + * used to add custom UI elements to the editor. The context parameter + * provides access to the project, command registry, event dispatcher, and + * ImGui context. + */ + yaze_extend_ui_func extend_ui; + + /** + * @brief Register commands in the yaze_command_registry. + */ + yaze_command_func register_commands; + + /** + * @brief Register custom tools in the yaze_command_registry. + */ + yaze_command_func register_custom_tools; + + /** + * @brief Register event hooks in the yaze_event_dispatcher. + */ + void (*register_event_hooks)(yaze_event_type event, + yaze_event_hook_func hook); + +} yaze_extension; + +#ifdef __cplusplus +} +#endif + +#endif // EXTENSION_INTERFACE_H diff --git a/incl/yaze.h b/incl/yaze.h new file mode 100644 index 00000000..a0a9a0a9 --- /dev/null +++ b/incl/yaze.h @@ -0,0 +1,125 @@ +#ifndef YAZE_H +#define YAZE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "dungeon.h" +#include "overworld.h" +#include "snes_color.h" +#include "sprite.h" + +typedef struct z3_rom z3_rom; + +typedef struct yaze_project yaze_project; +typedef struct yaze_command_registry yaze_command_registry; +typedef struct yaze_event_dispatcher yaze_event_dispatcher; + +/** + * @brief Extension editor context. + */ +typedef struct yaze_editor_context { + z3_rom* rom; + yaze_project* project; + + yaze_command_registry* command_registry; + yaze_event_dispatcher* event_dispatcher; +} yaze_editor_context; + +/** + * @brief Initialize the Yaze library. + */ +int yaze_init(yaze_editor_context*); + +/** + * @brief Clean up the Yaze library. + */ +void yaze_cleanup(yaze_editor_context*); + +/** + * @brief Primitive of a Yaze project. + */ +struct yaze_project { + const char* name; + const char* filepath; + const char* rom_filename; + const char* code_folder; + const char* labels_filename; +}; + +yaze_project yaze_load_project(const char* filename); + +/** + * @brief Primitive of a Zelda3 ROM. + */ +struct z3_rom { + const char* filename; + const uint8_t* data; + size_t size; + void* impl; // yaze::app::Rom* +}; + +/** + * @brief Load a Zelda3 ROM from a file. + */ +z3_rom* yaze_load_rom(const char* filename); + +/** + * @brief Unload a Zelda3 ROM. + */ +void yaze_unload_rom(z3_rom* rom); + +/** + * @brief Primitive of a Bitmap + */ +typedef struct yaze_bitmap { + int width; + int height; + uint8_t bpp; + uint8_t* data; +} yaze_bitmap; + +/** + * @brief Load a bitmap from a file. + */ +yaze_bitmap yaze_load_bitmap(const char* filename); + +/** + * @brief Get a color from a palette set. + */ +snes_color yaze_get_color_from_paletteset(const z3_rom* rom, int palette_set, + int palette, int color); + +/** + * @brief Load the overworld from a Zelda3 ROM. + */ +z3_overworld* yaze_load_overworld(const z3_rom* rom); + +/** + * @brief Check the version of the Yaze library. + */ +void yaze_check_version(const char* version); + +/** + * @brief Command registry. + */ +struct yaze_command_registry { + void (*register_command)(const char* name, void (*command)(void)); +}; + +/** + * @brief Event dispatcher. + */ +struct yaze_event_dispatcher { + void (*register_event_hook)(void (*event_hook)(void)); +}; + +#ifdef __cplusplus +} +#endif + +#endif // YAZE_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 81fd937b..58c2a023 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,32 +1,3 @@ -set( - YAZE_APP_CORE_SRC - app/core/common.cc - app/core/controller.cc - app/core/labeling.cc - app/emu/emulator.cc -) - -set( - YAZE_APP_GFX_SRC - app/gfx/bitmap.cc - app/gfx/compression.cc - app/gfx/scad_format.cc - app/gfx/snes_palette.cc - app/gfx/snes_tile.cc - app/gfx/snes_color.cc - app/gfx/tilesheet.cc -) - -set( - YAZE_GUI_SRC - app/gui/asset_browser.cc - app/gui/canvas.cc - app/gui/input.cc - app/gui/style.cc - app/gui/color.cc - app/gui/zeml.cc -) - set( YAZE_APP_EMU_SRC app/emu/audio/apu.cc @@ -43,70 +14,125 @@ set( app/emu/snes.cc ) -set(SDL_TARGETS SDL2::SDL2) +set(YAZE_RESOURCE_FILES + ${CMAKE_SOURCE_DIR}/assets/layouts/overworld.zeml + ${CMAKE_SOURCE_DIR}/assets/font/Karla-Regular.ttf + ${CMAKE_SOURCE_DIR}/assets/font/Roboto-Medium.ttf + ${CMAKE_SOURCE_DIR}/assets/font/Cousine-Regular.ttf + ${CMAKE_SOURCE_DIR}/assets/font/DroidSans.ttf + ${CMAKE_SOURCE_DIR}/assets/font/NotoSansJP.ttf + ${CMAKE_SOURCE_DIR}/assets/font/IBMPlexSansJP-Bold.ttf + ${CMAKE_SOURCE_DIR}/assets/font/MaterialIcons-Regular.ttf +) -if(WIN32 OR MINGW) - list(PREPEND SDL_TARGETS SDL2::SDL2main ws2_32) - add_definitions(-DSDL_MAIN_HANDLED) -endif() - -if (WIN32 OR MINGW OR UNIX AND NOT APPLE) - list(APPEND YAZE_APP_CORE_SRC - app/core/platform/font_loader.cc - app/core/platform/clipboard.cc +foreach (FILE ${YAZE_RESOURCE_FILES}) + file(RELATIVE_PATH NEW_FILE "${CMAKE_SOURCE_DIR}/assets" ${FILE}) + get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY) + set_source_files_properties(${FILE} + PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}" ) +endforeach() + +if (YAZE_BUILD_APP) + include(app/app.cmake) +endif() +if (YAZE_BUILD_EMU) + include(app/emu/emu.cmake) +endif() +if (YAZE_BUILD_Z3ED) + include(cli/z3ed.cmake) +endif() +if (YAZE_BUILD_PYTHON) + include(cli/python/yaze_py.cmake) +endif() +if (YAZE_BUILD_TESTS) + include(test/CMakeLists.txt) endif() -if(APPLE) - list(APPEND YAZE_APP_CORE_SRC - app/core/platform/file_dialog.mm - app/core/platform/app_delegate.mm - app/core/platform/font_loader.mm - app/core/platform/clipboard.mm - app/core/platform/file_path.mm - ) - - find_library(COCOA_LIBRARY Cocoa) - if(NOT COCOA_LIBRARY) - message(FATAL_ERROR "Cocoa not found") - endif() - set(CMAKE_EXE_LINKER_FLAGS "-framework ServiceManagement -framework Foundation -framework Cocoa") -endif() - -include(app/CMakeLists.txt) -# include(cli/CMakeLists.txt) Excluded for now, macOS include breaks action build - -if (UNIX) - target_compile_definitions(yaze PRIVATE "linux") - target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp") -endif() - -if(MACOS) - set(MACOSX_BUNDLE_ICON_FILE ${CMAKE_SOURCE_DIR}/yaze.ico) - set_target_properties(yaze - PROPERTIES - BUNDLE True - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/yaze.plist.in +if(MACOS) + set(MACOSX_BUNDLE_ICON_FILE ${CMAKE_SOURCE_DIR}/win32/yaze.ico) + set_target_properties(yaze + PROPERTIES + BUNDLE True + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/yaze.plist.in + RESOURCE ${YAZE_RESOURCE_FILES} ) elseif(UNIX) - set_target_properties(yaze + set_target_properties(yaze PROPERTIES BUNDLE True ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ) + target_compile_definitions(yaze PRIVATE "linux") + target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp") else() -set_target_properties(yaze + set_target_properties(yaze PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" - LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/yaze.res" -) + LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/win32/yaze.res" + ) endif() -add_subdirectory(test) \ No newline at end of file +# Yaze C API +if (YAZE_BUILD_LIB) + add_library( + yaze_c SHARED + ./yaze.cc + app/rom.cc + ${YAZE_APP_EMU_SRC} + ${YAZE_APP_CORE_SRC} + ${YAZE_APP_EDITOR_SRC} + ${YAZE_APP_GFX_SRC} + ${YAZE_APP_ZELDA3_SRC} + ${YAZE_GUI_SRC} + ${IMGUI_SRC} + ${IMGUI_TEST_ENGINE_SOURCES} + ) + + target_include_directories( + yaze_c PUBLIC + lib/ + app/ + ${CMAKE_SOURCE_DIR}/incl/ + ${CMAKE_SOURCE_DIR}/src/ + ${PNG_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIR} + ) + + target_link_libraries( + yaze_c PRIVATE + ${ABSL_TARGETS} + ${SDL_TARGETS} + ${PNG_LIBRARIES} + ${CMAKE_DL_LIBS} + ImGuiTestEngine + ImGui + ) + + if (YAZE_INSTALL_LIB) + install(TARGETS yaze_c + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib/static) + + install( + FILES + yaze.h + incl/sprite.h + incl/snes_tile.h + incl/snes_color.h + incl/overworld.h + incl/dungeon.h + DESTINATION + include + ) + endif() +endif() diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt deleted file mode 100644 index 6f6dd4eb..00000000 --- a/src/app/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -include(app/editor/CMakeLists.txt) -include(app/zelda3/CMakeLists.txt) - -add_executable( - yaze - app/yaze.cc - app/rom.cc - ${YAZE_APP_EMU_SRC} - ${YAZE_APP_CORE_SRC} - ${YAZE_APP_EDITOR_SRC} - ${YAZE_APP_GFX_SRC} - ${YAZE_APP_ZELDA3_SRC} - ${YAZE_GUI_SRC} - ${IMGUI_SRC} - ${IMGUI_TEST_ENGINE_SOURCES} -) - -target_include_directories( - yaze PUBLIC - lib/ - app/ - ${CMAKE_SOURCE_DIR}/src/ - ${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine - ${PNG_INCLUDE_DIRS} - ${SDL2_INCLUDE_DIR} -) - -target_link_libraries( - yaze PUBLIC - ${ABSL_TARGETS} - ${SDL_TARGETS} - ${PNG_LIBRARIES} - ${CMAKE_DL_LIBS} - ImGuiTestEngine - ImGui -) - -if (APPLE) - target_link_libraries(yaze PUBLIC ${COCOA_LIBRARY}) -endif() \ No newline at end of file diff --git a/src/app/app.cmake b/src/app/app.cmake new file mode 100644 index 00000000..a00f9c96 --- /dev/null +++ b/src/app/app.cmake @@ -0,0 +1,73 @@ +include(app/core/core.cmake) +include(app/editor/editor.cmake) +include(app/gfx/gfx.cmake) +include(app/gui/gui.cmake) +include(app/zelda3/zelda3.cmake) + +if (APPLE) +add_executable( + yaze + MACOSX_BUNDLE + app/main.cc + app/rom.cc + ${YAZE_APP_EMU_SRC} + ${YAZE_APP_CORE_SRC} + ${YAZE_APP_EDITOR_SRC} + ${YAZE_APP_GFX_SRC} + ${YAZE_APP_ZELDA3_SRC} + ${YAZE_GUI_SRC} + ${IMGUI_SRC} + + # Bundled Resources + ${YAZE_RESOURCE_FILES} +) +else() +add_executable( + yaze + app/main.cc + app/rom.cc + ${YAZE_APP_EMU_SRC} + ${YAZE_APP_CORE_SRC} + ${YAZE_APP_EDITOR_SRC} + ${YAZE_APP_GFX_SRC} + ${YAZE_APP_ZELDA3_SRC} + ${YAZE_GUI_SRC} + ${IMGUI_SRC} +) +endif() + +target_include_directories( + yaze PUBLIC + lib/ + app/ + ${ASAR_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/incl/ + ${CMAKE_SOURCE_DIR}/src/ + ${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine + ${PNG_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIR} +) + +target_link_libraries( + yaze PUBLIC + asar-static + ${ABSL_TARGETS} + ${SDL_TARGETS} + ${PNG_LIBRARIES} + ${CMAKE_DL_LIBS} + ImGui + ImGuiTestEngine +) + +if (APPLE) + target_link_libraries(yaze PUBLIC ${COCOA_LIBRARY}) +endif() + +if (WIN32 OR MINGW) + target_link_libraries( + yaze PUBLIC + ${CMAKE_SOURCE_DIR}/build/build-windows/bin/libpng16.dll + zlib + mingw32 + ws2_32) +endif() diff --git a/src/app/core/common.cc b/src/app/core/common.cc index d751994d..4cfe1919 100644 --- a/src/app/core/common.cc +++ b/src/app/core/common.cc @@ -1,107 +1,60 @@ #include "common.h" -#include "imgui/imgui.h" +#include -#include #include -#include +#include #include -#include #include +#include +#include "absl/status/statusor.h" #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" namespace yaze { namespace app { namespace core { -std::shared_ptr ExperimentFlags::flags_; +namespace { -std::string UppercaseHexByte(uint8_t byte, bool leading) { - if (leading) { - std::string result = absl::StrFormat("0x%02X", byte); - return result; - } - std::string result = absl::StrFormat("%02X", byte); - return result; -} -std::string UppercaseHexWord(uint16_t word) { - std::string result = absl::StrFormat("0x%04X", word); - return result; -} -std::string UppercaseHexLong(uint32_t dword) { - std::string result = absl::StrFormat("0x%06X", dword); - return result; -} - -uint32_t SnesToPc(uint32_t addr) { - if (addr >= 0x808000) { - addr -= 0x808000; - } - uint32_t temp = (addr & 0x7FFF) + ((addr / 2) & 0xFF8000); - return (temp + 0x0); -} - -uint32_t PcToSnes(uint32_t addr) { - uint8_t *b = reinterpret_cast(&addr); - b[2] = static_cast(b[2] * 2); - - if (b[1] >= 0x80) { - b[2] += 1; - } else { - b[1] += 0x80; - } - - return addr; -} - -uint32_t MapBankToWordAddress(uint8_t bank, uint16_t addr) { - uint32_t result = 0; - result = (bank << 16) | addr; - return result; -} - -int AddressFromBytes(uint8_t addr1, uint8_t addr2, uint8_t addr3) { - return (addr1 << 16) | (addr2 << 8) | addr3; -} - -// hextodec has been imported from SNESDisasm to parse hex numbers -int HexToDec(char *input, int length) { - int result = 0; - int value; - int ceiling = length - 1; - int power16 = 16; - - int j = ceiling; - - for (; j >= 0; j--) { - if (input[j] >= 'A' && input[j] <= 'F') { - value = input[j] - 'F'; - value += 15; - } else { - value = input[j] - '9'; - value += 9; +void encode(uint64_t data, std::vector &output) { + while (true) { + uint8_t x = data & 0x7f; + data >>= 7; + if (data == 0) { + output.push_back(0x80 | x); + break; } - - if (j == ceiling) { - result += value; - continue; - } - - result += (value * power16); - power16 *= 16; + output.push_back(x); + data--; } - - return result; } -bool StringReplace(std::string &str, const std::string &from, - const std::string &to) { - size_t start = str.find(from); - if (start == std::string::npos) return false; +uint64_t decode(const std::vector &input, size_t &offset) { + uint64_t data = 0; + uint64_t shift = 1; + while (true) { + uint8_t x = input[offset++]; + data += (x & 0x7f) * shift; + if (x & 0x80) break; + shift <<= 7; + data += shift; + } + return data; +} - str.replace(start, from.length(), to); - return true; +uint32_t crc32(const std::vector &data) { + uint32_t crc = ::crc32(0L, Z_NULL, 0); + return ::crc32(crc, data.data(), data.size()); +} + +// "load little endian value at the given byte offset and shift to get its +// value relative to the base offset (powers of 256, essentially)" +unsigned ldle(uint8_t const *const p_arr, unsigned const p_index) { + uint32_t v = p_arr[p_index]; + v <<= (8 * p_index); + return v; } void stle(uint8_t *const p_arr, size_t const p_index, unsigned const p_val) { @@ -125,25 +78,6 @@ void stle2(uint8_t *const p_arr, unsigned const p_val) { void stle3(uint8_t *const p_arr, unsigned const p_val) { stle(p_arr, 3, p_val); } -void stle16b(uint8_t *const p_arr, uint16_t const p_val) { - stle0(p_arr, p_val); - stle1(p_arr, p_val); -} -// "Store little endian 16-bit value using a byte pointer, offset by an -// index before dereferencing" -void stle16b_i(uint8_t *const p_arr, size_t const p_index, - uint16_t const p_val) { - stle16b(p_arr + (p_index * 2), p_val); -} -// "load little endian value at the given byte offset and shift to get its -// value relative to the base offset (powers of 256, essentially)" -unsigned ldle(uint8_t const *const p_arr, unsigned const p_index) { - uint32_t v = p_arr[p_index]; - - v <<= (8 * p_index); - - return v; -} // Helper function to get the first byte in a little endian number uint32_t ldle0(uint8_t const *const p_arr) { return ldle(p_arr, 0); } @@ -156,32 +90,244 @@ uint32_t ldle2(uint8_t const *const p_arr) { return ldle(p_arr, 2); } // Helper function to get the third byte in a little endian number uint32_t ldle3(uint8_t const *const p_arr) { return ldle(p_arr, 3); } -// Load little endian halfword (16-bit) dereferenced from -uint16_t ldle16b(uint8_t const *const p_arr) { - uint16_t v = 0; - v |= (ldle0(p_arr) | ldle1(p_arr)); +} // namespace - return v; +std::string UppercaseHexByte(uint8_t byte, bool leading) { + if (leading) { + std::string result = absl::StrFormat("0x%02X", byte); + return result; + } + std::string result = absl::StrFormat("%02X", byte); + return result; } -// Load little endian halfword (16-bit) dereferenced from an arrays of bytes. -// This version provides an index that will be multiplied by 2 and added to the -// base address. -uint16_t ldle16b_i(uint8_t const *const p_arr, size_t const p_index) { - return ldle16b(p_arr + (2 * p_index)); +std::string UppercaseHexWord(uint16_t word, bool leading) { + if (leading) { + std::string result = absl::StrFormat("0x%04X", word); + return result; + } + std::string result = absl::StrFormat("%04X", word); + return result; +} +std::string UppercaseHexLong(uint32_t dword) { + std::string result = absl::StrFormat("0x%06X", dword); + return result; +} +std::string UppercaseHexLongLong(uint64_t qword) { + std::string result = absl::StrFormat("0x%08X", qword); + return result; } -// Initialize the static member -std::stack ImGuiIdIssuer::idStack; +bool StringReplace(std::string &str, const std::string &from, + const std::string &to) { + size_t start = str.find(from); + if (start == std::string::npos) return false; + + str.replace(start, from.length(), to); + return true; +} + +std::shared_ptr ExperimentFlags::flags_; uint32_t Get24LocalFromPC(uint8_t *data, int addr, bool pc) { - uint32_t ret = (PcToSnes(addr) & 0xFF0000) | (data[addr + 1] << 8) | data[addr]; + uint32_t ret = + (PcToSnes(addr) & 0xFF0000) | (data[addr + 1] << 8) | data[addr]; if (pc) { return SnesToPc(ret); } return ret; } +void stle16b_i(uint8_t *const p_arr, size_t const p_index, + uint16_t const p_val) { + stle16b(p_arr + (p_index * 2), p_val); +} + +void stle16b(uint8_t *const p_arr, uint16_t const p_val) { + stle0(p_arr, p_val); + stle1(p_arr, p_val); +} + +uint16_t ldle16b(uint8_t const *const p_arr) { + uint16_t v = 0; + v |= (ldle0(p_arr) | ldle1(p_arr)); + return v; +} + +uint16_t ldle16b_i(uint8_t const *const p_arr, size_t const p_index) { + return ldle16b(p_arr + (2 * p_index)); +} + +void CreateBpsPatch(const std::vector &source, + const std::vector &target, + std::vector &patch) { + patch.clear(); + patch.insert(patch.end(), {'B', 'P', 'S', '1'}); + + encode(source.size(), patch); + encode(target.size(), patch); + encode(0, patch); // No metadata + + size_t source_offset = 0; + size_t target_offset = 0; + int64_t source_rel_offset = 0; + int64_t target_rel_offset = 0; + + while (target_offset < target.size()) { + if (source_offset < source.size() && + source[source_offset] == target[target_offset]) { + size_t length = 0; + while (source_offset + length < source.size() && + target_offset + length < target.size() && + source[source_offset + length] == target[target_offset + length]) { + length++; + } + encode((length - 1) << 2 | 0, patch); // SourceRead + source_offset += length; + target_offset += length; + } else { + size_t length = 0; + while ( + target_offset + length < target.size() && + (source_offset + length >= source.size() || + source[source_offset + length] != target[target_offset + length])) { + length++; + } + if (length > 0) { + encode((length - 1) << 2 | 1, patch); // TargetRead + for (size_t i = 0; i < length; i++) { + patch.push_back(target[target_offset + i]); + } + target_offset += length; + } + } + + // SourceCopy + if (source_offset < source.size()) { + size_t length = 0; + int64_t offset = source_offset - source_rel_offset; + while (source_offset + length < source.size() && + target_offset + length < target.size() && + source[source_offset + length] == target[target_offset + length]) { + length++; + } + if (length > 0) { + encode((length - 1) << 2 | 2, patch); + encode((offset < 0 ? 1 : 0) | (abs(offset) << 1), patch); + source_offset += length; + target_offset += length; + source_rel_offset = source_offset; + } + } + + // TargetCopy + if (target_offset > 0) { + size_t length = 0; + int64_t offset = target_offset - target_rel_offset; + while (target_offset + length < target.size() && + target[target_offset - 1] == target[target_offset + length]) { + length++; + } + if (length > 0) { + encode((length - 1) << 2 | 3, patch); + encode((offset < 0 ? 1 : 0) | (abs(offset) << 1), patch); + target_offset += length; + target_rel_offset = target_offset; + } + } + } + + patch.resize(patch.size() + 12); // Make space for the checksums + uint32_t source_checksum = crc32(source); + uint32_t target_checksum = crc32(target); + uint32_t patch_checksum = crc32(patch); + + memcpy(patch.data() + patch.size() - 12, &source_checksum, sizeof(uint32_t)); + memcpy(patch.data() + patch.size() - 8, &target_checksum, sizeof(uint32_t)); + memcpy(patch.data() + patch.size() - 4, &patch_checksum, sizeof(uint32_t)); +} + +void ApplyBpsPatch(const std::vector &source, + const std::vector &patch, + std::vector &target) { + if (patch.size() < 4 || patch[0] != 'B' || patch[1] != 'P' || + patch[2] != 'S' || patch[3] != '1') { + throw std::runtime_error("Invalid patch format"); + } + + size_t patch_offset = 4; + uint64_t target_size = decode(patch, patch_offset); + uint64_t metadata_size = decode(patch, patch_offset); + patch_offset += metadata_size; + + target.resize(target_size); + size_t source_offset = 0; + size_t target_offset = 0; + int64_t source_rel_offset = 0; + int64_t target_rel_offset = 0; + + while (patch_offset < patch.size() - 12) { + uint64_t data = decode(patch, patch_offset); + uint64_t command = data & 3; + uint64_t length = (data >> 2) + 1; + + switch (command) { + case 0: // SourceRead + while (length--) { + target[target_offset++] = source[source_offset++]; + } + break; + case 1: // TargetRead + while (length--) { + target[target_offset++] = patch[patch_offset++]; + } + break; + case 2: // SourceCopy + { + int64_t offsetData = decode(patch, patch_offset); + source_rel_offset += (offsetData & 1 ? -1 : +1) * (offsetData >> 1); + while (length--) { + target[target_offset++] = source[source_rel_offset++]; + } + } break; + case 3: // TargetCopy + { + uint64_t offsetData = decode(patch, patch_offset); + target_rel_offset += (offsetData & 1 ? -1 : +1) * (offsetData >> 1); + while (length--) { + target[target_offset++] = target[target_rel_offset++]; + } + } + default: + throw std::runtime_error("Invalid patch command"); + } + } + + uint32_t source_checksum; + uint32_t target_checksum; + uint32_t patch_checksum; + memcpy(&source_checksum, patch.data() + patch.size() - 12, sizeof(uint32_t)); + memcpy(&target_checksum, patch.data() + patch.size() - 8, sizeof(uint32_t)); + memcpy(&patch_checksum, patch.data() + patch.size() - 4, sizeof(uint32_t)); + + if (source_checksum != crc32(source) || target_checksum != crc32(target) || + patch_checksum != + crc32(std::vector(patch.begin(), patch.end() - 4))) { + throw std::runtime_error("Checksum mismatch"); + } +} + +absl::StatusOr CheckVersion(const char *version) { + std::string version_string = version; + if (version_string != kYazeVersion) { + std::string message = + absl::StrFormat("Yaze version mismatch: expected %s, got %s", + kYazeVersion.data(), version_string.c_str()); + return absl::InvalidArgumentError(message); + } + return version_string; +} + } // namespace core } // namespace app } // namespace yaze diff --git a/src/app/core/common.h b/src/app/core/common.h index 0fd56f7b..f4f0791d 100644 --- a/src/app/core/common.h +++ b/src/app/core/common.h @@ -1,17 +1,16 @@ #ifndef YAZE_CORE_COMMON_H #define YAZE_CORE_COMMON_H -#include "imgui/imgui.h" - -#include #include #include -#include #include #include -#include #include +#include "absl/status/statusor.h" +#include "absl/strings/str_format.h" +#include "absl/container/flat_hash_map.h" + namespace yaze { namespace app { @@ -21,16 +20,21 @@ namespace app { */ namespace core { +std::string UppercaseHexByte(uint8_t byte, bool leading = false); +std::string UppercaseHexWord(uint16_t word, bool leading = false); +std::string UppercaseHexLong(uint32_t dword); +std::string UppercaseHexLongLong(uint64_t qword); + +bool StringReplace(std::string &str, const std::string &from, + const std::string &to); + /** * @class ExperimentFlags * @brief A class to manage experimental feature flags. */ class ExperimentFlags { - public: +public: struct Flags { - // Bitmap manager abstraction to manage graphics bin of Rom. - bool kUseBitmapManager = true; - // Log instructions to the GUI debugger. bool kLogInstructions = true; @@ -56,22 +60,18 @@ class ExperimentFlags { // Use the new platform specific file dialog wrappers. bool kNewFileDialogWrapper = true; - // Platform specific loading of fonts from the system. Currently - // only supports macOS. - bool kLoadSystemFonts = true; - // Uses texture streaming from SDL for my dynamic updates. bool kLoadTexturesAsStreaming = true; // Save dungeon map edits to the Rom. bool kSaveDungeonMaps = false; + // Save graphics sheet to the Rom. + bool kSaveGraphicsSheet = false; + // Log to the console. bool kLogToConsole = false; - // Load audio device for emulator - bool kLoadAudioDevice = false; - // Overworld flags struct Overworld { // Load and render overworld sprites to the screen. Unstable. @@ -91,6 +91,9 @@ class ExperimentFlags { // Save overworld properties to the Rom. bool kSaveOverworldProperties = true; + + // Load custom overworld data from the ROM and enable UI. + bool kLoadCustomOverworld = false; } overworld; }; @@ -109,8 +112,44 @@ class ExperimentFlags { } return flags_.get(); } + std::string Serialize() const { + std::string result; + result += + "kLogInstructions: " + std::to_string(flags_->kLogInstructions) + "\n"; + result += + "kUseNewImGuiInput: " + std::to_string(flags_->kUseNewImGuiInput) + + "\n"; + result += + "kSaveAllPalettes: " + std::to_string(flags_->kSaveAllPalettes) + "\n"; + result += + "kSaveGfxGroups: " + std::to_string(flags_->kSaveGfxGroups) + "\n"; + result += "kSaveWithChangeQueue: " + + std::to_string(flags_->kSaveWithChangeQueue) + "\n"; + result += "kDrawDungeonRoomGraphics: " + + std::to_string(flags_->kDrawDungeonRoomGraphics) + "\n"; + result += "kNewFileDialogWrapper: " + + std::to_string(flags_->kNewFileDialogWrapper) + "\n"; + result += "kLoadTexturesAsStreaming: " + + std::to_string(flags_->kLoadTexturesAsStreaming) + "\n"; + result += + "kSaveDungeonMaps: " + std::to_string(flags_->kSaveDungeonMaps) + "\n"; + result += "kLogToConsole: " + std::to_string(flags_->kLogToConsole) + "\n"; + result += "kDrawOverworldSprites: " + + std::to_string(flags_->overworld.kDrawOverworldSprites) + "\n"; + result += "kSaveOverworldMaps: " + + std::to_string(flags_->overworld.kSaveOverworldMaps) + "\n"; + result += "kSaveOverworldEntrances: " + + std::to_string(flags_->overworld.kSaveOverworldEntrances) + "\n"; + result += "kSaveOverworldExits: " + + std::to_string(flags_->overworld.kSaveOverworldExits) + "\n"; + result += "kSaveOverworldItems: " + + std::to_string(flags_->overworld.kSaveOverworldItems) + "\n"; + result += "kSaveOverworldProperties: " + + std::to_string(flags_->overworld.kSaveOverworldProperties) + "\n"; + return result; + } - private: +private: static std::shared_ptr flags_; }; @@ -119,9 +158,8 @@ class ExperimentFlags { * @brief A class to manage a value that can be modified and notify when it * changes. */ -template -class NotifyValue { - public: +template class NotifyValue { +public: NotifyValue() : value_(), modified_(false), temp_value_() {} NotifyValue(const T &value) : value_(value), modified_(false), temp_value_() {} @@ -154,69 +192,108 @@ class NotifyValue { bool modified() const { return modified_; } - private: +private: T value_; bool modified_; T temp_value_; }; -class ImGuiIdIssuer { - private: - static std::stack idStack; +static bool log_to_console = false; +static std::string log_file_out = "log.txt"; - public: - // Generate and push a new ID onto the stack - static ImGuiID GetNewID() { - static int counter = 1; // Start from 1 to ensure uniqueness - ImGuiID child_id = ImGui::GetID((void *)(intptr_t)counter++); - idStack.push(child_id); - return child_id; +template +static void logf(const absl::FormatSpec &format, const Args &...args) { + std::string message = absl::StrFormat(format, args...); + if (log_to_console) { + std::cout << message << std::endl; } + static std::ofstream fout(log_file_out, std::ios::out | std::ios::app); + fout << message << std::endl; +} - // Pop all IDs from the stack (can be called explicitly or upon program exit) - static void Cleanup() { - while (!idStack.empty()) { - idStack.pop(); - } - } +struct StructuredLog { + std::string raw_message; + std::string category; }; +static absl::flat_hash_map> log_categories; + +template +static void logm(const std::string &category, + const absl::FormatSpec &format, const Args &...args) { + std::string message = absl::StrFormat(format, args...); + if (log_to_console) { + std::cout << category << ": " << message << std::endl; + } + if (log_categories.contains(category)) { + log_categories[category].push_back(message); + } else { + log_categories[category] = {message}; + } +} + class Logger { - public: +public: static void log(std::string message) { - static std::ofstream fout("log.txt", std::ios::out | std::ios::app); + static std::ofstream fout(log_file_out, std::ios::out | std::ios::app); fout << message << std::endl; } - - // log to console - static void logc(std::string message) { logs.emplace_back(message); } - - static std::vector logs; }; -std::string UppercaseHexByte(uint8_t byte, bool leading = false); -std::string UppercaseHexWord(uint16_t word); -std::string UppercaseHexLong(uint32_t dword); +constexpr uint32_t kFastRomRegion = 0x808000; -uint32_t SnesToPc(uint32_t addr); -uint32_t PcToSnes(uint32_t addr); +inline uint32_t SnesToPc(uint32_t addr) noexcept { + if (addr >= kFastRomRegion) { + addr -= kFastRomRegion; + } + uint32_t temp = (addr & 0x7FFF) + ((addr / 2) & 0xFF8000); + return (temp + 0x0); +} -uint32_t MapBankToWordAddress(uint8_t bank, uint16_t addr); +inline uint32_t PcToSnes(uint32_t addr) { + uint8_t *b = reinterpret_cast(&addr); + b[2] = static_cast(b[2] * 2); -int AddressFromBytes(uint8_t addr1, uint8_t addr2, uint8_t addr3); -int HexToDec(char *input, int length); + if (b[1] >= 0x80) { + b[2] += 1; + } else { + b[1] += 0x80; + } -bool StringReplace(std::string &str, const std::string &from, - const std::string &to); + return addr; +} +inline int AddressFromBytes(uint8_t bank, uint8_t high, uint8_t low) noexcept { + return (bank << 16) | (high << 8) | low; +} + +inline uint32_t MapBankToWordAddress(uint8_t bank, uint16_t addr) noexcept { + uint32_t result = 0; + result = (bank << 16) | addr; + return result; +} + +uint32_t Get24LocalFromPC(uint8_t *data, int addr, bool pc = true); + +/** + * @brief Store little endian 16-bit value using a byte pointer, offset by an + * index before dereferencing + */ void stle16b_i(uint8_t *const p_arr, size_t const p_index, uint16_t const p_val); -uint16_t ldle16b_i(uint8_t const *const p_arr, size_t const p_index); - -uint16_t ldle16b(uint8_t const *const p_arr); void stle16b(uint8_t *const p_arr, uint16_t const p_val); +/** + * @brief Load little endian halfword (16-bit) dereferenced from an arrays of + * bytes. This version provides an index that will be multiplied by 2 and added + * to the base address. + */ +uint16_t ldle16b_i(uint8_t const *const p_arr, size_t const p_index); + +// Load little endian halfword (16-bit) dereferenced from +uint16_t ldle16b(uint8_t const *const p_arr); + struct FolderItem { std::string name; std::vector subfolders; @@ -225,10 +302,20 @@ struct FolderItem { typedef struct FolderItem FolderItem; -uint32_t Get24LocalFromPC(uint8_t *data, int addr, bool pc = true); +void CreateBpsPatch(const std::vector &source, + const std::vector &target, + std::vector &patch); -} // namespace core -} // namespace app -} // namespace yaze +void ApplyBpsPatch(const std::vector &source, + const std::vector &patch, + std::vector &target); + +constexpr std::string_view kYazeVersion = "0.2.1"; + +absl::StatusOr CheckVersion(const char *version); + +} // namespace core +} // namespace app +} // namespace yaze #endif diff --git a/src/app/core/constants.h b/src/app/core/constants.h index a5e37676..4594aae6 100644 --- a/src/app/core/constants.h +++ b/src/app/core/constants.h @@ -1,15 +1,6 @@ #ifndef YAZE_APP_CORE_CONSTANTS_H #define YAZE_APP_CORE_CONSTANTS_H -#include - -#include "absl/strings/string_view.h" - -#define TAB_BAR(w) if (ImGui::BeginTabBar(w)) { -#define END_TAB_BAR() \ - ImGui::EndTabBar(); \ - } - #define TAB_ITEM(w) if (ImGui::BeginTabItem(w)) { #define END_TAB_ITEM() \ ImGui::EndTabItem(); \ @@ -121,732 +112,5 @@ using ushort = unsigned short; using uint = unsigned int; using uchar = unsigned char; -using Bytes = std::vector; - -using OWBlockset = std::vector>; -struct OWMapTiles { - OWBlockset light_world; // 64 maps - OWBlockset dark_world; // 64 maps - OWBlockset special_world; // 32 maps -}; -using OWMapTiles = struct OWMapTiles; - -namespace yaze { -namespace app { -namespace core { - -constexpr uint32_t kRedPen = 0xFF0000FF; -constexpr float kYazeVersion = 0.2; - -// ============================================================================ -// Magic numbers -// ============================================================================ - -/// Bit set for object priority -constexpr ushort TilePriorityBit = 0x2000; - -/// Bit set for object hflip -constexpr ushort TileHFlipBit = 0x4000; - -/// Bit set for object vflip -constexpr ushort TileVFlipBit = 0x8000; - -/// Bits used for tile name -constexpr ushort TileNameMask = 0x03FF; - -constexpr int Uncompressed3BPPSize = 0x0600; -constexpr int UncompressedSheetSize = 0x0800; - -constexpr int NumberOfRooms = 296; - -constexpr int NumberOfColors = 3143; - -// ============================================================================ -// Game Graphics -// ============================================================================ - -constexpr int tile_address = 0x1B52; // JP = Same -constexpr int tile_address_floor = 0x1B5A; // JP = Same -constexpr int subtype1_tiles = 0x8000; // JP = Same -constexpr int subtype2_tiles = 0x83F0; // JP = Same -constexpr int subtype3_tiles = 0x84F0; // JP = Same -constexpr int gfx_animated_pointer = 0x10275; // JP 0x10624 //long pointer - -constexpr int hud_palettes = 0xDD660; -constexpr int maxGfx = 0xC3FB5; - -constexpr int kTilesheetWidth = 128; -constexpr int kTilesheetHeight = 32; -constexpr int kTilesheetDepth = 8; - -// TEXT EDITOR RELATED CONSTANTS -constexpr int gfx_font = 0x70000; // 2bpp format -constexpr int text_data = 0xE0000; -constexpr int text_data2 = 0x75F40; -constexpr int pointers_dictionaries = 0x74703; -constexpr int characters_width = 0x74ADF; - -constexpr int entrance_gfx_group = 0x5D97; - -// ============================================================================ -// Gravestones related variables -// ============================================================================ - -constexpr int GravesYTilePos = 0x49968; // short (0x0F entries) -constexpr int GravesXTilePos = 0x49986; // short (0x0F entries) -constexpr int GravesTilemapPos = 0x499A4; // short (0x0F entries) -constexpr int GravesGFX = 0x499C2; // short (0x0F entries) - -constexpr int GravesXPos = 0x4994A; // short (0x0F entries) -constexpr int GravesYLine = 0x4993A; // short (0x08 entries) -constexpr int GravesCountOnY = 0x499E0; // Byte 0x09 entries - -constexpr int GraveLinkSpecialHole = 0x46DD9; // short -constexpr int GraveLinkSpecialStairs = 0x46DE0; // short - -// ============================================================================ -// Names -// ============================================================================ - -static const std::string RoomEffect[] = {"Nothing", - "Nothing", - "Moving Floor", - "Moving Water", - "Trinexx Shell", - "Red Flashes", - "Light Torch to See Floor", - "Ganon's Darkness"}; - -static const std::string RoomTag[] = {"Nothing", - - "NW Kill Enemy to Open", - "NE Kill Enemy to Open", - "SW Kill Enemy to Open", - "SE Kill Enemy to Open", - "W Kill Enemy to Open", - "E Kill Enemy to Open", - "N Kill Enemy to Open", - "S Kill Enemy to Open", - "Clear Quadrant to Open", - "Clear Full Tile to Open", - - "NW Push Block to Open", - "NE Push Block to Open", - "SW Push Block to Open", - "SE Push Block to Open", - "W Push Block to Open", - "E Push Block to Open", - "N Push Block to Open", - "S Push Block to Open", - "Push Block to Open", - "Pull Lever to Open", - "Collect Prize to Open", - - "Hold Switch Open Door", - "Toggle Switch to Open Door", - "Turn off Water", - "Turn on Water", - "Water Gate", - "Water Twin", - "Moving Wall Right", - "Moving Wall Left", - "Crash", - "Crash", - "Push Switch Exploding Wall", - "Holes 0", - "Open Chest (Holes 0)", - "Holes 1", - "Holes 2", - "Defeat Boss for Dungeon Prize", - - "SE Kill Enemy to Push Block", - "Trigger Switch Chest", - "Pull Lever Exploding Wall", - "NW Kill Enemy for Chest", - "NE Kill Enemy for Chest", - "SW Kill Enemy for Chest", - "SE Kill Enemy for Chest", - "W Kill Enemy for Chest", - "E Kill Enemy for Chest", - "N Kill Enemy for Chest", - "S Kill Enemy for Chest", - "Clear Quadrant for Chest", - "Clear Full Tile for Chest", - - "Light Torches to Open", - "Holes 3", - "Holes 4", - "Holes 5", - "Holes 6", - "Agahnim Room", - "Holes 7", - "Holes 8", - "Open Chest for Holes 8", - "Push Block for Chest", - "Clear Room for Triforce Door", - "Light Torches for Chest", - "Kill Boss Again"}; - -static const std::string SecretItemNames[] = { - "Nothing", "Green Rupee", "Rock hoarder", "Bee", "Health pack", - "Bomb", "Heart ", "Blue Rupee", - - "Key", "Arrow", "Bomb", "Heart", "Magic", - "Full Magic", "Cucco", "Green Soldier", "Bush Stal", "Blue Soldier", - - "Landmine", "Heart", "Fairy", "Heart", - "Nothing ", // 22 - - "Hole", "Warp", "Staircase", "Bombable", "Switch"}; - -static const std::string TileTypeNames[] = { - "$00 Nothing (standard floor)", - "$01 Collision", - "$02 Collision", - "$03 Collision", - "$04 Collision", - "$05 Nothing (unused?)", - "$06 Nothing (unused?)", - "$07 Nothing (unused?)", - "$08 Deep water", - "$09 Shallow water", - "$0A Unknown? Possibly unused", - "$0B Collision (different in Overworld and unknown)", - "$0C Overlay mask", - "$0D Spike floor", - "$0E GT ice", - "$0F Ice palace ice", - "$10 Slope ◤", - "$11 Slope ◥", - "$12 Slope ◣", - "$13 Slope ◢", - "$14 Nothing (unused?)", - "$15 Nothing (unused?)", - "$16 Nothing (unused?)", - "$17 Nothing (unused?)", - "$18 Slope ◤", - "$19 Slope ◥", - "$1A Slope ◣", - "$1B Slope ◢", - "$1C Layer 2 overlay", - "$1D North single-layer auto stairs", - "$1E North layer-swap auto stairs", - "$1F North layer-swap auto stairs", - "$20 Pit", - "$21 Nothing (unused?)", - "$22 Manual stairs", - "$23 Pot switch", - "$24 Pressure switch", - "$25 Nothing (unused but referenced by somaria blocks)", - "$26 Collision (near stairs?)", - "$27 Brazier/Fence/Statue/Block/General hookable things", - "$28 North ledge", - "$29 South ledge", - "$2A East ledge", - "$2B West ledge", - "$2C ◤ ledge", - "$2D ◣ ledge", - "$2E ◥ ledge", - "$2F ◢ ledge", - "$30 Straight inter-room stairs south/up 0", - "$31 Straight inter-room stairs south/up 1", - "$32 Straight inter-room stairs south/up 2", - "$33 Straight inter-room stairs south/up 3", - "$34 Straight inter-room stairs north/down 0", - "$35 Straight inter-room stairs north/down 1", - "$36 Straight inter-room stairs north/down 2", - "$37 Straight inter-room stairs north/down 3", - "$38 Straight inter-room stairs north/down edge", - "$39 Straight inter-room stairs south/up edge", - "$3A Star tile (inactive on load)", - "$3B Star tile (active on load)", - "$3C Nothing (unused?)", - "$3D South single-layer auto stairs", - "$3E South layer-swap auto stairs", - "$3F South layer-swap auto stairs", - "$40 Thick grass", - "$41 Nothing (unused?)", - "$42 Gravestone / Tower of hera ledge shadows??", - "$43 Skull Woods entrance/Hera columns???", - "$44 Spike", - "$45 Nothing (unused?)", - "$46 Desert Tablet", - "$47 Nothing (unused?)", - "$48 Diggable ground", - "$49 Nothing (unused?)", - "$4A Diggable ground", - "$4B Warp tile", - "$4C Nothing (unused?) | Something unknown in overworld", - "$4D Nothing (unused?) | Something unknown in overworld", - "$4E Square corners in EP overworld", - "$4F Square corners in EP overworld", - "$50 Green bush", - "$51 Dark bush", - "$52 Gray rock", - "$53 Black rock", - "$54 Hint tile/Sign", - "$55 Big gray rock", - "$56 Big black rock", - "$57 Bonk rocks", - "$58 Chest 0", - "$59 Chest 1", - "$5A Chest 2", - "$5B Chest 3", - "$5C Chest 4", - "$5D Chest 5", - "$5E Spiral stairs", - "$5F Spiral stairs", - "$60 Rupee tile", - "$61 Nothing (unused?)", - "$62 Bombable floor", - "$63 Minigame chest", - "$64 Nothing (unused?)", - "$65 Nothing (unused?)", - "$66 Crystal peg down", - "$67 Crystal peg up", - "$68 Upwards conveyor", - "$69 Downwards conveyor", - "$6A Leftwards conveyor", - "$6B Rightwards conveyor", - "$6C North vines", - "$6D South vines", - "$6E West vines", - "$6F East vines", - "$70 Pot/Hammer peg/Push block 00", - "$71 Pot/Hammer peg/Push block 01", - "$72 Pot/Hammer peg/Push block 02", - "$73 Pot/Hammer peg/Push block 03", - "$74 Pot/Hammer peg/Push block 04", - "$75 Pot/Hammer peg/Push block 05", - "$76 Pot/Hammer peg/Push block 06", - "$77 Pot/Hammer peg/Push block 07", - "$78 Pot/Hammer peg/Push block 08", - "$79 Pot/Hammer peg/Push block 09", - "$7A Pot/Hammer peg/Push block 0A", - "$7B Pot/Hammer peg/Push block 0B", - "$7C Pot/Hammer peg/Push block 0C", - "$7D Pot/Hammer peg/Push block 0D", - "$7E Pot/Hammer peg/Push block 0E", - "$7F Pot/Hammer peg/Push block 0F", - "$80 North/South door", - "$81 East/West door", - "$82 North/South shutter door", - "$83 East/West shutter door", - "$84 North/South layer 2 door", - "$85 East/West layer 2 door", - "$86 North/South layer 2 shutter door", - "$87 East/West layer 2 shutter door", - "$88 Some type of door (?)", - "$89 East/West transport door", - "$8A Some type of door (?)", - "$8B Some type of door (?)", - "$8C Some type of door (?)", - "$8D Some type of door (?)", - "$8E Entrance door", - "$8F Entrance door", - "$90 Layer toggle shutter door (?)", - "$91 Layer toggle shutter door (?)", - "$92 Layer toggle shutter door (?)", - "$93 Layer toggle shutter door (?)", - "$94 Layer toggle shutter door (?)", - "$95 Layer toggle shutter door (?)", - "$96 Layer toggle shutter door (?)", - "$97 Layer toggle shutter door (?)", - "$98 Layer+Dungeon toggle shutter door (?)", - "$99 Layer+Dungeon toggle shutter door (?)", - "$9A Layer+Dungeon toggle shutter door (?)", - "$9B Layer+Dungeon toggle shutter door (?)", - "$9C Layer+Dungeon toggle shutter door (?)", - "$9D Layer+Dungeon toggle shutter door (?)", - "$9E Layer+Dungeon toggle shutter door (?)", - "$9F Layer+Dungeon toggle shutter door (?)", - "$A0 North/South Dungeon swap door", - "$A1 Dungeon toggle door (?)", - "$A2 Dungeon toggle door (?)", - "$A3 Dungeon toggle door (?)", - "$A4 Dungeon toggle door (?)", - "$A5 Dungeon toggle door (?)", - "$A6 Nothing (unused?)", - "$A7 Nothing (unused?)", - "$A8 Layer+Dungeon toggle shutter door (?)", - "$A9 Layer+Dungeon toggle shutter door (?)", - "$AA Layer+Dungeon toggle shutter door (?)", - "$AB Layer+Dungeon toggle shutter door (?)", - "$AC Layer+Dungeon toggle shutter door (?)", - "$AD Layer+Dungeon toggle shutter door (?)", - "$AE Layer+Dungeon toggle shutter door (?)", - "$AF Layer+Dungeon toggle shutter door (?)", - "$B0 Somaria ─", - "$B1 Somaria │", - "$B2 Somaria ┌", - "$B3 Somaria └", - "$B4 Somaria ┐", - "$B5 Somaria ┘", - "$B6 Somaria ⍰ 1 way", - "$B7 Somaria ┬", - "$B8 Somaria ┴", - "$B9 Somaria ├", - "$BA Somaria ┤", - "$BB Somaria ┼", - "$BC Somaria ⍰ 2 way", - "$BD Somaria ┼ crossover", - "$BE Pipe entrance", - "$BF Nothing (unused?)", - "$C0 Torch 00", - "$C1 Torch 01", - "$C2 Torch 02", - "$C3 Torch 03", - "$C4 Torch 04", - "$C5 Torch 05", - "$C6 Torch 06", - "$C7 Torch 07", - "$C8 Torch 08", - "$C9 Torch 09", - "$CA Torch 0A", - "$CB Torch 0B", - "$CC Torch 0C", - "$CD Torch 0D", - "$CE Torch 0E", - "$CF Torch 0F", - "$D0 Nothing (unused?)", - "$D1 Nothing (unused?)", - "$D2 Nothing (unused?)", - "$D3 Nothing (unused?)", - "$D4 Nothing (unused?)", - "$D5 Nothing (unused?)", - "$D6 Nothing (unused?)", - "$D7 Nothing (unused?)", - "$D8 Nothing (unused?)", - "$D9 Nothing (unused?)", - "$DA Nothing (unused?)", - "$DB Nothing (unused?)", - "$DC Nothing (unused?)", - "$DD Nothing (unused?)", - "$DE Nothing (unused?)", - "$DF Nothing (unused?)", - "$E0 Nothing (unused?)", - "$E1 Nothing (unused?)", - "$E2 Nothing (unused?)", - "$E3 Nothing (unused?)", - "$E4 Nothing (unused?)", - "$E5 Nothing (unused?)", - "$E6 Nothing (unused?)", - "$E7 Nothing (unused?)", - "$E8 Nothing (unused?)", - "$E9 Nothing (unused?)", - "$EA Nothing (unused?)", - "$EB Nothing (unused?)", - "$EC Nothing (unused?)", - "$ED Nothing (unused?)", - "$EE Nothing (unused?)", - "$EF Nothing (unused?)", - "$F0 Door 0 bottom", - "$F1 Door 1 bottom", - "$F2 Door 2 bottom", - "$F3 Door 3 bottom", - "$F4 Door X bottom? (unused?)", - "$F5 Door X bottom? (unused?)", - "$F6 Door X bottom? (unused?)", - "$F7 Door X bottom? (unused?)", - "$F8 Door 0 top", - "$F9 Door 1 top", - "$FA Door 2 top", - "$FB Door 3 top", - "$FC Door X top? (unused?)", - "$FD Door X top? (unused?)", - "$FE Door X top? (unused?)", - "$FF Door X top? (unused?)"}; - -static const std::string kSpriteDefaultNames[]{ - "00 Raven", - "01 Vulture", - "02 Flying Stalfos Head", - "03 No Pointer (Empty", - "04 Pull Switch (good", - "05 Pull Switch (unused", - "06 Pull Switch (bad", - "07 Pull Switch (unused", - "08 Octorock (one way", - "09 Moldorm (Boss", - "0A Octorock (four way", - "0B Chicken", - "0C Octorock (?", - "0D Buzzblock", - "0E Snapdragon", - "0F Octoballoon", - "10 Octoballon Hatchlings", - "11 Hinox", - "12 Moblin", - "13 Mini Helmasaure", - "14 Gargoyle's Domain Gate", - "15 Antifairy", - "16 Sahasrahla / Aginah", - "17 Bush Hoarder", - "18 Mini Moldorm", - "19 Poe", - "1A Dwarves", - "1B Arrow in wall", - "1C Statue", - "1D Weathervane", - "1E Crystal Switch", - "1F Bug-Catching Kid", - "20 Sluggula", - "21 Push Switch", - "22 Ropa", - "23 Red Bari", - "24 Blue Bari", - "25 Talking Tree", - "26 Hardhat Beetle", - "27 Deadrock", - "28 Storytellers", - "29 Blind Hideout attendant", - "2A Sweeping Lady", - "2B Storytellers", - "2C Lumberjacks", - "2D Telepathic Stones", - "2E Multipurpose Sprite", - "2F Race Npc", - "30 Person?", - "31 Fortune Teller", - "32 Angry Brothers", - "33 Pull for items", - "34 Scared Girl", - "35 Innkeeper", - "36 Witch", - "37 Waterfall", - "38 Arrow Target", - "39 Average Middle", - "3A Half Magic Bat", - "3B Dash Item", - "3C Village Kid", - "3D Signs? Chicken lady also showed up / Scared ladies outside houses.", - "3E Rock Hoarder", - "3F Tutorial Soldier", - "40 Lightning Lock", - "41 Blue Sword Soldier / Used by guards to detect player", - "42 Green Sword Soldier", - "43 Red Spear Soldier", - "44 Assault Sword Soldier", - "45 Green Spear Soldier", - "46 Blue Archer", - "47 Green Archer", - "48 Red Javelin Soldier", - "49 Red Javelin Soldier 2", - "4A Red Bomb Soldiers", - "4B Green Soldier Recruits", - "4C Geldman", - "4D Rabbit", - "4E Popo", - "4F Popo 2", - "50 Cannon Balls", - "51 Armos", - "52 Giant Zora", - "53 Armos Knights (Boss", - "54 Lanmolas (Boss", - "55 Fireball Zora", - "56 Walking Zora", - "57 Desert Palace Barriers", - "58 Crab", - "59 Bird", - "5A Squirrel", - "5B Spark (Left to Right", - "5C Spark (Right to Left", - "5D Roller (vertical moving", - "5E Roller (vertical moving", - "5F Roller", - "60 Roller (horizontal moving", - "61 Beamos", - "62 Master Sword", - "63 Devalant (Non", - "64 Devalant (Shooter", - "65 Shooting Gallery Proprietor", - "66 Moving Cannon Ball Shooters (Right", - "67 Moving Cannon Ball Shooters (Left", - "68 Moving Cannon Ball Shooters (Down", - "69 Moving Cannon Ball Shooters (Up", - "6A Ball N' Chain Trooper", - "6B Cannon Soldier", - "6C Mirror Portal", - "6D Rat", - "6E Rope", - "6F Keese", - "70 Helmasaur King Fireball", - "71 Leever", - "72 Activator for the ponds (where you throw in items", - "73 Uncle / Priest", - "74 Running Man", - "75 Bottle Salesman", - "76 Princess Zelda", - "77 Antifairy (Alternate", - "78 Village Elder", - "79 Bee", - "7A Agahnim", - "7B Agahnim Energy Ball", - "7C Hyu", - "7D Big Spike Trap", - "7E Guruguru Bar (Clockwise", - "7F Guruguru Bar (Counter Clockwise", - "80 Winder", - "81 Water Tektite", - "82 Antifairy Circle", - "83 Green Eyegore", - "84 Red Eyegore", - "85 Yellow Stalfos", - "86 Kodongos", - "87 Flames", - "88 Mothula (Boss", - "89 Mothula's Beam", - "8A Spike Trap", - "8B Gibdo", - "8C Arrghus (Boss", - "8D Arrghus spawn", - "8E Terrorpin", - "8F Slime", - "90 Wallmaster", - "91 Stalfos Knight", - "92 Helmasaur King", - "93 Bumper", - "94 Swimmers", - "95 Eye Laser (Right", - "96 Eye Laser (Left", - "97 Eye Laser (Down", - "98 Eye Laser (Up", - "99 Pengator", - "9A Kyameron", - "9B Wizzrobe", - "9C Tadpoles", - "9D Tadpoles", - "9E Ostrich (Haunted Grove", - "9F Flute", - "A0 Birds (Haunted Grove", - "A1 Freezor", - "A2 Kholdstare (Boss", - "A3 Kholdstare's Shell", - "A4 Falling Ice", - "A5 Zazak Fireball", - "A6 Red Zazak", - "A7 Stalfos", - "A8 Bomber Flying Creatures from Darkworld", - "A9 Bomber Flying Creatures from Darkworld", - "AA Pikit", - "AB Maiden", - "AC Apple", - "AD Lost Old Man", - "AE Down Pipe", - "AF Up Pipe", - "B0 Right Pip", - "B1 Left Pipe", - "B2 Good bee again?", - "B3 Hylian Inscription", - "B4 Thief?s chest (not the one that follows you", - "B5 Bomb Salesman", - "B6 Kiki", - "B7 Maiden following you in Blind Dungeon", - "B8 Monologue Testing Sprite", - "B9 Feuding Friends on Death Mountain", - "BA Whirlpool", - "BB Salesman / chestgame guy / 300 rupee giver guy / Chest game thief", - "BC Drunk in the inn", - "BD Vitreous (Large Eyeball", - "BE Vitreous (Small Eyeball", - "BF Vitreous' Lightning", - "C0 Monster in Lake of Ill Omen / Quake Medallion", - "C1 Agahnim teleporting Zelda to dark world", - "C2 Boulders", - "C3 Gibo", - "C4 Thief", - "C5 Medusa", - "C6 Four Way Fireball Spitters (spit when you use your sword", - "C7 Hokku", - "C8 Big Fairy who heals you", - "C9 Tektite", - "CA Chain Chomp", - "CB Trinexx", - "CC Another part of trinexx", - "CD Yet another part of trinexx", - "CE Blind The Thief (Boss)", - "CF Swamola", - "D0 Lynel", - "D1 Bunny Beam", - "D2 Flopping fish", - "D3 Stal", - "D4 Landmine", - "D5 Digging Game Proprietor", - "D6 Ganon", - "D7 Copy of Ganon", - "D8 Heart", - "D9 Green Rupee", - "DA Blue Rupee", - "DB Red Rupee", - "DC Bomb Refill (1)", - "DD Bomb Refill (4)", - "DE Bomb Refill (8)", - "DF Small Magic Refill", - "E0 Full Magic Refill", - "E1 Arrow Refill (5)", - "E2 Arrow Refill (10)", - "E3 Fairy", - "E4 Key", - "E5 Big Key", - "E6 Shield", - "E7 Mushroom", - "E8 Fake Master Sword", - "E9 Magic Shop dude / His items", - "EA Heart Container", - "EB Heart Piece", - "EC Bushes", - "ED Cane Of Somaria Platform", - "EE Mantle", - "EF Cane of Somaria Platform (Unused)", - "F0 Cane of Somaria Platform (Unused)", - "F1 Cane of Somaria Platform (Unused)", - "F2 Medallion Tablet", - "F3", - "F4 Falling Rocks", - "F5", - "F6", - "F7", - "F8", - "F9", - "FA", - "FB", - "FC", - "FD", - "FE", - "FF", -}; - -static const std::string overlordnames[] = { - "Overlord_SpritePositionTarget", - "Overlord_AllDirectionMetalBallFactory", - "Overlord_CascadeMetalBallFactory", - "Overlord_StalfosFactory", - "Overlord_StalfosTrap", - "Overlord_SnakeTrap", - "Overlord_MovingFloor", - "Overlord_ZolFactory", - "Overlord_WallMasterFactory", - "Overlord_CrumbleTilePath 1", - "Overlord_CrumbleTilePath 2", - "Overlord_CrumbleTilePath 3", - "Overlord_CrumbleTilePath 4", - "Overlord_CrumbleTilePath 5", - "Overlord_CrumbleTilePath 6", - "Overlord_PirogusuFactory 1", - "Overlord_PirogusuFactory 2", - "Overlord_PirogusuFactory 3", - "Overlord_PirogusuFactory 4", - "Overlord_FlyingTileFactory", - "Overlord_WizzrobeFactory", - "Overlord_ZoroFactory", - "Overlord_StalfosTrapTriggerWindow", - "Overlord_RedStalfosTrap", - "Overlord_ArmosCoordinator", - "Overlord_BombTrap", -}; - -} // namespace core -} // namespace app -} // namespace yaze #endif \ No newline at end of file diff --git a/src/app/core/controller.cc b/src/app/core/controller.cc index 12f843bf..7da81fa3 100644 --- a/src/app/core/controller.cc +++ b/src/app/core/controller.cc @@ -2,30 +2,18 @@ #include -#include "imgui/backends/imgui_impl_sdl2.h" -#include "imgui/backends/imgui_impl_sdlrenderer2.h" -#include "imgui/imgui.h" -#include "imgui/imgui_internal.h" - -#if defined(__APPLE__) && defined(__MACH__) -#include -#if TARGET_IPHONE_SIMULATOR == 1 -#include "imgui/backends/imgui_impl_metal.h" -#elif TARGET_OS_IPHONE == 1 -#include "imgui/backends/imgui_impl_metal.h" -#elif TARGET_OS_MAC == 1 - -#endif -#endif - +#include #include #include "absl/status/status.h" #include "absl/strings/str_format.h" #include "app/core/platform/font_loader.h" -#include "app/editor/master_editor.h" -#include "app/gui/icons.h" +#include "app/editor/editor_manager.h" #include "app/gui/style.h" +#include "core/utils/file_util.h" +#include "imgui/backends/imgui_impl_sdl2.h" +#include "imgui/backends/imgui_impl_sdlrenderer2.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -38,7 +26,6 @@ constexpr ImGuiWindowFlags kMainEditorFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar; -using ::ImVec2; using ImGui::Begin; using ImGui::End; using ImGui::GetIO; @@ -61,205 +48,66 @@ void NewMasterFrame() { } } -void InitializeKeymap() { +} // namespace + +absl::Status Controller::OnEntry(std::string filename) { +#if defined(__APPLE__) && defined(__MACH__) +#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 + platform_ = Platform::kiOS; +#elif TARGET_OS_MAC == 1 + platform_ = Platform::kMacOS; +#endif +#elif defined(_WIN32) + platform_ = Platform::kWindows; +#elif defined(__linux__) + platform_ = Platform::kLinux; +#else + platform_ = Platform::kUnknown; +#endif + RETURN_IF_ERROR(CreateWindow()) + RETURN_IF_ERROR(CreateRenderer()) + RETURN_IF_ERROR(CreateGuiContext()) + RETURN_IF_ERROR(LoadAudioDevice()) + editor_manager_.SetupScreen(filename); + active_ = true; + return absl::OkStatus(); +} + +void Controller::OnInput() { + int wheel = 0; + SDL_Event event; ImGuiIO &io = ImGui::GetIO(); - io.KeyMap[ImGuiKey_LeftSuper] = SDL_GetScancodeFromKey(SDLK_LGUI); - io.KeyMap[ImGuiKey_Backspace] = SDL_GetScancodeFromKey(SDLK_BACKSPACE); - io.KeyMap[ImGuiKey_LeftShift] = SDL_GetScancodeFromKey(SDLK_LSHIFT); - io.KeyMap[ImGuiKey_Enter] = SDL_GetScancodeFromKey(SDLK_RETURN); - io.KeyMap[ImGuiKey_UpArrow] = SDL_GetScancodeFromKey(SDLK_UP); - io.KeyMap[ImGuiKey_DownArrow] = SDL_GetScancodeFromKey(SDLK_DOWN); - io.KeyMap[ImGuiKey_LeftArrow] = SDL_GetScancodeFromKey(SDLK_LEFT); - io.KeyMap[ImGuiKey_RightArrow] = SDL_GetScancodeFromKey(SDLK_RIGHT); - io.KeyMap[ImGuiKey_Delete] = SDL_GetScancodeFromKey(SDLK_DELETE); - io.KeyMap[ImGuiKey_Escape] = SDL_GetScancodeFromKey(SDLK_ESCAPE); - io.KeyMap[ImGuiKey_Tab] = SDL_GetScancodeFromKey(SDLK_TAB); - io.KeyMap[ImGuiKey_LeftCtrl] = SDL_GetScancodeFromKey(SDLK_LCTRL); - io.KeyMap[ImGuiKey_PageUp] = SDL_GetScancodeFromKey(SDLK_PAGEUP); - io.KeyMap[ImGuiKey_PageDown] = SDL_GetScancodeFromKey(SDLK_PAGEDOWN); - io.KeyMap[ImGuiKey_Home] = SDL_GetScancodeFromKey(SDLK_HOME); - io.KeyMap[ImGuiKey_Space] = SDL_GetScancodeFromKey(SDLK_SPACE); - io.KeyMap[ImGuiKey_1] = SDL_GetScancodeFromKey(SDLK_1); - io.KeyMap[ImGuiKey_2] = SDL_GetScancodeFromKey(SDLK_2); - io.KeyMap[ImGuiKey_3] = SDL_GetScancodeFromKey(SDLK_3); - io.KeyMap[ImGuiKey_4] = SDL_GetScancodeFromKey(SDLK_4); - io.KeyMap[ImGuiKey_5] = SDL_GetScancodeFromKey(SDLK_5); - io.KeyMap[ImGuiKey_6] = SDL_GetScancodeFromKey(SDLK_6); - io.KeyMap[ImGuiKey_7] = SDL_GetScancodeFromKey(SDLK_7); - io.KeyMap[ImGuiKey_8] = SDL_GetScancodeFromKey(SDLK_8); - io.KeyMap[ImGuiKey_9] = SDL_GetScancodeFromKey(SDLK_9); - io.KeyMap[ImGuiKey_0] = SDL_GetScancodeFromKey(SDLK_0); - io.KeyMap[ImGuiKey_A] = SDL_GetScancodeFromKey(SDLK_a); - io.KeyMap[ImGuiKey_B] = SDL_GetScancodeFromKey(SDLK_b); - io.KeyMap[ImGuiKey_C] = SDL_GetScancodeFromKey(SDLK_c); - io.KeyMap[ImGuiKey_D] = SDL_GetScancodeFromKey(SDLK_d); - io.KeyMap[ImGuiKey_E] = SDL_GetScancodeFromKey(SDLK_e); - io.KeyMap[ImGuiKey_F] = SDL_GetScancodeFromKey(SDLK_f); - io.KeyMap[ImGuiKey_G] = SDL_GetScancodeFromKey(SDLK_g); - io.KeyMap[ImGuiKey_H] = SDL_GetScancodeFromKey(SDLK_h); - io.KeyMap[ImGuiKey_I] = SDL_GetScancodeFromKey(SDLK_i); - io.KeyMap[ImGuiKey_J] = SDL_GetScancodeFromKey(SDLK_j); - io.KeyMap[ImGuiKey_K] = SDL_GetScancodeFromKey(SDLK_k); - io.KeyMap[ImGuiKey_L] = SDL_GetScancodeFromKey(SDLK_l); - io.KeyMap[ImGuiKey_M] = SDL_GetScancodeFromKey(SDLK_m); - io.KeyMap[ImGuiKey_N] = SDL_GetScancodeFromKey(SDLK_n); - io.KeyMap[ImGuiKey_O] = SDL_GetScancodeFromKey(SDLK_o); - io.KeyMap[ImGuiKey_P] = SDL_GetScancodeFromKey(SDLK_p); - io.KeyMap[ImGuiKey_Q] = SDL_GetScancodeFromKey(SDLK_q); - io.KeyMap[ImGuiKey_R] = SDL_GetScancodeFromKey(SDLK_r); - io.KeyMap[ImGuiKey_S] = SDL_GetScancodeFromKey(SDLK_s); - io.KeyMap[ImGuiKey_T] = SDL_GetScancodeFromKey(SDLK_t); - io.KeyMap[ImGuiKey_U] = SDL_GetScancodeFromKey(SDLK_u); - io.KeyMap[ImGuiKey_V] = SDL_GetScancodeFromKey(SDLK_v); - io.KeyMap[ImGuiKey_W] = SDL_GetScancodeFromKey(SDLK_w); - io.KeyMap[ImGuiKey_X] = SDL_GetScancodeFromKey(SDLK_x); - io.KeyMap[ImGuiKey_Y] = SDL_GetScancodeFromKey(SDLK_y); - io.KeyMap[ImGuiKey_Z] = SDL_GetScancodeFromKey(SDLK_z); - io.KeyMap[ImGuiKey_F1] = SDL_GetScancodeFromKey(SDLK_F1); - io.KeyMap[ImGuiKey_F2] = SDL_GetScancodeFromKey(SDLK_F2); - io.KeyMap[ImGuiKey_F3] = SDL_GetScancodeFromKey(SDLK_F3); - io.KeyMap[ImGuiKey_F4] = SDL_GetScancodeFromKey(SDLK_F4); - io.KeyMap[ImGuiKey_F5] = SDL_GetScancodeFromKey(SDLK_F5); - io.KeyMap[ImGuiKey_F6] = SDL_GetScancodeFromKey(SDLK_F6); - io.KeyMap[ImGuiKey_F7] = SDL_GetScancodeFromKey(SDLK_F7); - io.KeyMap[ImGuiKey_F8] = SDL_GetScancodeFromKey(SDLK_F8); - io.KeyMap[ImGuiKey_F9] = SDL_GetScancodeFromKey(SDLK_F9); - io.KeyMap[ImGuiKey_F10] = SDL_GetScancodeFromKey(SDLK_F10); - io.KeyMap[ImGuiKey_F11] = SDL_GetScancodeFromKey(SDLK_F11); - io.KeyMap[ImGuiKey_F12] = SDL_GetScancodeFromKey(SDLK_F12); -} -void ImGui_ImplSDL2_SetClipboardText(void *user_data, const char *text) { - SDL_SetClipboardText(text); -} - -const char *ImGui_ImplSDL2_GetClipboardText(void *user_data) { - return SDL_GetClipboardText(); -} - -void InitializeClipboard() { - ImGuiIO &io = ImGui::GetIO(); - io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; - io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; - io.ClipboardUserData = nullptr; -} - -void HandleKeyDown(SDL_Event &event, editor::MasterEditor &editor) { - ImGuiIO &io = ImGui::GetIO(); - io.KeysDown[event.key.keysym.scancode] = (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); - io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); - - switch (event.key.keysym.sym) { - case SDLK_BACKSPACE: - case SDLK_LSHIFT: - case SDLK_LCTRL: - case SDLK_TAB: - io.KeysDown[event.key.keysym.scancode] = (event.type == SDL_KEYDOWN); - break; - case SDLK_z: - editor.emulator().snes().SetButtonState(1, 0, true); - break; - case SDLK_a: - editor.emulator().snes().SetButtonState(1, 1, true); - break; - case SDLK_RSHIFT: - editor.emulator().snes().SetButtonState(1, 2, true); - break; - case SDLK_RETURN: - editor.emulator().snes().SetButtonState(1, 3, true); - break; - case SDLK_UP: - editor.emulator().snes().SetButtonState(1, 4, true); - break; - case SDLK_DOWN: - editor.emulator().snes().SetButtonState(1, 5, true); - break; - case SDLK_LEFT: - editor.emulator().snes().SetButtonState(1, 6, true); - break; - case SDLK_RIGHT: - editor.emulator().snes().SetButtonState(1, 7, true); - break; - case SDLK_x: - editor.emulator().snes().SetButtonState(1, 8, true); - break; - case SDLK_s: - editor.emulator().snes().SetButtonState(1, 9, true); - break; - case SDLK_d: - editor.emulator().snes().SetButtonState(1, 10, true); - break; - case SDLK_c: - editor.emulator().snes().SetButtonState(1, 11, true); - break; - default: - break; + while (SDL_PollEvent(&event)) { + ImGui_ImplSDL2_ProcessEvent(&event); + switch (event.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: { + ImGuiIO &io = ImGui::GetIO(); + io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); + io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); + io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); + io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); + break; + } + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_CLOSE: + active_ = false; + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + io.DisplaySize.x = static_cast(event.window.data1); + io.DisplaySize.y = static_cast(event.window.data2); + break; + default: + break; + } + break; + default: + break; + } } -} -void HandleKeyUp(SDL_Event &event, editor::MasterEditor &editor) { - ImGuiIO &io = ImGui::GetIO(); - 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); - io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); - - switch (event.key.keysym.sym) { - case SDLK_z: - editor.emulator().snes().SetButtonState(1, 0, false); - break; - case SDLK_a: - editor.emulator().snes().SetButtonState(1, 1, false); - break; - case SDLK_RSHIFT: - editor.emulator().snes().SetButtonState(1, 2, false); - break; - case SDLK_RETURN: - editor.emulator().snes().SetButtonState(1, 3, false); - break; - case SDLK_UP: - editor.emulator().snes().SetButtonState(1, 4, false); - break; - case SDLK_DOWN: - editor.emulator().snes().SetButtonState(1, 5, false); - break; - case SDLK_LEFT: - editor.emulator().snes().SetButtonState(1, 6, false); - break; - case SDLK_RIGHT: - editor.emulator().snes().SetButtonState(1, 7, false); - break; - case SDLK_x: - editor.emulator().snes().SetButtonState(1, 8, false); - break; - case SDLK_s: - editor.emulator().snes().SetButtonState(1, 9, false); - break; - case SDLK_d: - editor.emulator().snes().SetButtonState(1, 10, false); - break; - case SDLK_c: - editor.emulator().snes().SetButtonState(1, 11, false); - break; - default: - break; - } -} - -void ChangeWindowSizeEvent(SDL_Event &event) { - ImGuiIO &io = ImGui::GetIO(); - io.DisplaySize.x = static_cast(event.window.data1); - io.DisplaySize.y = static_cast(event.window.data2); -} - -void HandleMouseMovement(int &wheel) { - ImGuiIO &io = ImGui::GetIO(); int mouseX; int mouseY; const int buttons = SDL_GetMouseState(&mouseX, &mouseY); @@ -272,169 +120,80 @@ void HandleMouseMovement(int &wheel) { io.MouseWheel = static_cast(wheel); } -} // namespace - -absl::Status Controller::OnEntry(std::string filename) { -#if defined(__APPLE__) && defined(__MACH__) -#if TARGET_IPHONE_SIMULATOR == 1 - /* iOS in Xcode simulator */ - platform_ = Platform::kiOS; -#elif TARGET_OS_IPHONE == 1 - /* iOS */ - platform_ = Platform::kiOS; -#elif TARGET_OS_MAC == 1 - /* macOS */ - platform_ = Platform::kMacOS; -#endif -#elif defined(_WIN32) - platform_ = Platform::kWindows; -#elif defined(__linux__) - platform_ = Platform::kLinux; -#else - platform_ = Platform::kUnknown; -#endif - - RETURN_IF_ERROR(CreateSDL_Window()) - RETURN_IF_ERROR(CreateRenderer()) - RETURN_IF_ERROR(CreateGuiContext()) - if (flags()->kLoadAudioDevice) { - RETURN_IF_ERROR(LoadAudioDevice()) - master_editor_.emulator().set_audio_buffer(audio_buffer_); - master_editor_.emulator().set_audio_device_id(audio_device_); +absl::Status Controller::OnLoad() { + if (editor_manager_.quit()) { + active_ = false; } - InitializeKeymap(); - master_editor_.SetupScreen(renderer_, filename); - active_ = true; +#if TARGET_OS_IPHONE != 1 + if (platform_ != Platform::kiOS) { + NewMasterFrame(); + } +#endif + RETURN_IF_ERROR(editor_manager_.Update()); +#if TARGET_OS_IPHONE != 1 + if (platform_ != Platform::kiOS) { + End(); + } +#endif return absl::OkStatus(); } -void Controller::OnInput() { - int wheel = 0; - SDL_Event event; - ImGuiIO &io = ImGui::GetIO(); - - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYDOWN: - HandleKeyDown(event, master_editor_); - break; - case SDL_KEYUP: - HandleKeyUp(event, master_editor_); - break; - case SDL_TEXTINPUT: - io.AddInputCharactersUTF8(event.text.text); - break; - case SDL_MOUSEWHEEL: - wheel = event.wheel.y; - break; - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_CLOSE: - CloseWindow(); - break; - case SDL_WINDOWEVENT_SIZE_CHANGED: - ChangeWindowSizeEvent(event); - break; - default: - break; - } - break; - default: - break; - } - } - - HandleMouseMovement(wheel); -} - -absl::Status Controller::OnLoad() { - if (master_editor_.quit()) { - active_ = false; - } - NewMasterFrame(); - RETURN_IF_ERROR(master_editor_.Update()); +absl::Status Controller::OnTestLoad() { + RETURN_IF_ERROR(test_editor_->Update()); return absl::OkStatus(); } void Controller::DoRender() const { ImGui::Render(); - SDL_RenderClear(renderer_.get()); - ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), renderer_.get()); - SDL_RenderPresent(renderer_.get()); + SDL_RenderClear(Renderer::GetInstance().renderer()); + ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), + Renderer::GetInstance().renderer()); + SDL_RenderPresent(Renderer::GetInstance().renderer()); } void Controller::OnExit() { - ImGui::DestroyContext(); - if (flags()->kLoadAudioDevice) { - SDL_PauseAudioDevice(audio_device_, 1); - SDL_CloseAudioDevice(audio_device_); - delete audio_buffer_; - } - switch (platform_) { - case Platform::kMacOS: - case Platform::kWindows: - case Platform::kLinux: - ImGui_ImplSDLRenderer2_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - break; - case Platform::kiOS: - // Deferred - break; - default: - break; - } + SDL_PauseAudioDevice(audio_device_, 1); + SDL_CloseAudioDevice(audio_device_); + ImGui_ImplSDLRenderer2_Shutdown(); + ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); SDL_Quit(); } -absl::Status Controller::CreateSDL_Window() { - auto sdl_flags = SDL_INIT_VIDEO | SDL_INIT_TIMER; +absl::Status Controller::CreateWindow() { + auto sdl_flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; if (flags()->kUseNewImGuiInput) { sdl_flags |= SDL_INIT_GAMECONTROLLER; } - if (flags()->kLoadAudioDevice) { - sdl_flags |= SDL_INIT_AUDIO; - } - if (SDL_Init(sdl_flags) != 0) { return absl::InternalError( absl::StrFormat("SDL_Init: %s\n", SDL_GetError())); - } else { - SDL_DisplayMode displayMode; - SDL_GetCurrentDisplayMode(0, &displayMode); - int screenWidth = displayMode.w * 0.8; - int screenHeight = displayMode.h * 0.8; - - window_ = std::unique_ptr( - SDL_CreateWindow("Yet Another Zelda3 Editor", // window title - SDL_WINDOWPOS_UNDEFINED, // initial x position - SDL_WINDOWPOS_UNDEFINED, // initial y position - screenWidth, // width, in pixels - screenHeight, // height, in pixels - SDL_WINDOW_RESIZABLE), - sdl_deleter()); - if (window_ == nullptr) { - return absl::InternalError( - absl::StrFormat("SDL_CreateWindow: %s\n", SDL_GetError())); - } } + + SDL_DisplayMode display_mode; + SDL_GetCurrentDisplayMode(0, &display_mode); + int screen_width = display_mode.w * 0.8; + int screen_height = display_mode.h * 0.8; + + window_ = std::unique_ptr( + SDL_CreateWindow("Yet Another Zelda3 Editor", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + screen_width, // width, in pixels + screen_height, // height, in pixels + SDL_WINDOW_RESIZABLE), + core::SDL_Deleter()); + if (window_ == nullptr) { + return absl::InternalError( + absl::StrFormat("SDL_CreateWindow: %s\n", SDL_GetError())); + } + return absl::OkStatus(); } absl::Status Controller::CreateRenderer() { - renderer_ = std::unique_ptr( - SDL_CreateRenderer(window_.get(), -1, - SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), - sdl_deleter()); - if (renderer_ == nullptr) { - return absl::InternalError( - absl::StrFormat("SDL_CreateRenderer: %s\n", SDL_GetError())); - } else { - SDL_SetRenderDrawBlendMode(renderer_.get(), SDL_BLENDMODE_BLEND); - SDL_SetRenderDrawColor(renderer_.get(), 0x00, 0x00, 0x00, 0x00); - } - return absl::OkStatus(); + return Renderer::GetInstance().CreateRenderer(window_.get()); } absl::Status Controller::CreateGuiContext() { @@ -443,20 +202,16 @@ absl::Status Controller::CreateGuiContext() { ImGuiIO &io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - if (flags()->kUseNewImGuiInput) { io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; } - // Initialize ImGui for SDL - ImGui_ImplSDL2_InitForSDLRenderer(window_.get(), renderer_.get()); - ImGui_ImplSDLRenderer2_Init(renderer_.get()); + // Initialize ImGui based on the backend + ImGui_ImplSDL2_InitForSDLRenderer(window_.get(), + Renderer::GetInstance().renderer()); + ImGui_ImplSDLRenderer2_Init(Renderer::GetInstance().renderer()); - if (flags()->kLoadSystemFonts) { - LoadSystemFonts(); - } else { - RETURN_IF_ERROR(LoadFontFamilies()); - } + RETURN_IF_ERROR(LoadFontFamilies()); // Set the default style gui::ColorsYaze(); @@ -469,94 +224,8 @@ absl::Status Controller::CreateGuiContext() { } absl::Status Controller::LoadFontFamilies() const { - ImGuiIO &io = ImGui::GetIO(); - - const char *font_path = "assets/font/"; - static const char *KARLA_REGULAR = "Karla-Regular.ttf"; - static const char *ROBOTO_MEDIUM = "Roboto-Medium.ttf"; - static const char *COUSINE_REGULAR = "Cousine-Regular.ttf"; - static const char *DROID_SANS = "DroidSans.ttf"; - static const char *NOTO_SANS_JP = "NotoSansJP.ttf"; - static const char *IBM_PLEX_JP = "IBMPlexSansJP-Bold.ttf"; - static const float FONT_SIZE_DEFAULT = 14.0f; - static const float FONT_SIZE_DROID_SANS = 16.0f; - static const float ICON_FONT_SIZE = 18.0f; - - // Icon configuration - static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0}; - ImFontConfig icons_config; - icons_config.MergeMode = true; - icons_config.GlyphOffset.y = 5.0f; - icons_config.GlyphMinAdvanceX = 13.0f; - icons_config.PixelSnapH = true; - - // Japanese font configuration - ImFontConfig japanese_font_config; - japanese_font_config.MergeMode = true; - icons_config.GlyphOffset.y = 5.0f; - icons_config.GlyphMinAdvanceX = 13.0f; - icons_config.PixelSnapH = true; - - // List of fonts to be loaded - std::vector font_paths = {KARLA_REGULAR, ROBOTO_MEDIUM, - COUSINE_REGULAR, IBM_PLEX_JP}; - - // Load fonts with associated icon and Japanese merges - for (const auto &font_path : font_paths) { - float font_size = - (font_path == DROID_SANS) ? FONT_SIZE_DROID_SANS : FONT_SIZE_DEFAULT; - - std::string actual_font_path; -#ifdef __APPLE__ -#if TARGET_OS_IOS == 1 - const std::string kBundlePath = GetBundleResourcePath(); - actual_font_path = kBundlePath + font_path; -#else - actual_font_path = std::filesystem::absolute(font_path).string(); -#endif -#else - actual_font_path = font_path; -#endif - - if (!io.Fonts->AddFontFromFileTTF(actual_font_path.data(), font_size)) { - return absl::InternalError( - absl::StrFormat("Failed to load font from %s", actual_font_path)); - } - - // Merge icon set - std::string actual_icon_font_path = ""; - const char *icon_font_path = FONT_ICON_FILE_NAME_MD; -#if defined(__APPLE__) && defined(__MACH__) -#if TARGET_OS_IOS == 1 - const std::string kIconBundlePath = GetBundleResourcePath(); - actual_icon_font_path = kIconBundlePath + "MaterialIcons-Regular.ttf"; -#else - actual_icon_font_path = std::filesystem::absolute(icon_font_path).string(); -#endif -#else -#endif - io.Fonts->AddFontFromFileTTF(actual_icon_font_path.data(), ICON_FONT_SIZE, - &icons_config, icons_ranges); - - // Merge Japanese font - std::string actual_japanese_font_path = ""; - const char *japanese_font_path = NOTO_SANS_JP; -#if defined(__APPLE__) && defined(__MACH__) -#if TARGET_OS_IOS == 1 - const std::string kJapaneseBundlePath = GetBundleResourcePath(); - actual_japanese_font_path = kJapaneseBundlePath + japanese_font_path; -#else - actual_japanese_font_path = - std::filesystem::absolute(japanese_font_path).string(); -#endif -#else -#endif - io.Fonts->AddFontFromFileTTF(actual_japanese_font_path.data(), 18.0f, - &japanese_font_config, - io.Fonts->GetGlyphRangesJapanese()); - } - - return absl::OkStatus(); + // LoadSystemFonts(); + return LoadPackageFonts(); } absl::Status Controller::LoadAudioDevice() { @@ -572,9 +241,39 @@ absl::Status Controller::LoadAudioDevice() { return absl::InternalError( absl::StrFormat("Failed to open audio: %s\n", SDL_GetError())); } - audio_buffer_ = new int16_t[audio_frequency_ / 50 * 4]; - master_editor_.emulator().set_audio_buffer(audio_buffer_); + // audio_buffer_ = new int16_t[audio_frequency_ / 50 * 4]; + audio_buffer_ = std::make_shared(audio_frequency_ / 50 * 4); SDL_PauseAudioDevice(audio_device_, 0); + editor_manager_.emulator().set_audio_buffer(audio_buffer_.get()); + editor_manager_.emulator().set_audio_device_id(audio_device_); + return absl::OkStatus(); +} + +absl::Status Controller::LoadConfigFiles() { + // Create and load a dotfile for the application + // This will store the user's preferences and settings + std::string config_directory = GetConfigDirectory(platform_); + + // Create the directory if it doesn't exist + if (!std::filesystem::exists(config_directory)) { + if (!std::filesystem::create_directory(config_directory)) { + return absl::InternalError(absl::StrFormat( + "Failed to create config directory %s", config_directory)); + } + } + + // Check if the config file exists + std::string config_file = config_directory + "yaze.cfg"; + if (!std::filesystem::exists(config_file)) { + // Create the file if it doesn't exist + std::ofstream file(config_file); + if (!file.is_open()) { + return absl::InternalError( + absl::StrFormat("Failed to create config file %s", config_file)); + } + file.close(); + } + return absl::OkStatus(); } diff --git a/src/app/core/controller.h b/src/app/core/controller.h index 6df680d0..726189d2 100644 --- a/src/app/core/controller.h +++ b/src/app/core/controller.h @@ -2,20 +2,18 @@ #define YAZE_APP_CORE_CONTROLLER_H #include -#include "imgui/backends/imgui_impl_sdl2.h" -#include "imgui/backends/imgui_impl_sdlrenderer2.h" -#include "imgui/imconfig.h" -#include "imgui/imgui.h" -#include "imgui/imgui_internal.h" #include #include "absl/status/status.h" -#include "app/core/common.h" -#include "app/editor/master_editor.h" -#include "app/editor/utils/editor.h" -#include "app/gui/icons.h" -#include "app/gui/style.h" +#include "app/core/platform/renderer.h" +#include "app/core/utils/file_util.h" +#include "app/editor/editor_manager.h" +#include "app/editor/editor.h" +#include "imgui/backends/imgui_impl_sdl2.h" +#include "imgui/backends/imgui_impl_sdlrenderer2.h" +#include "imgui/imconfig.h" +#include "imgui/imgui.h" int main(int argc, char **argv); @@ -23,8 +21,6 @@ namespace yaze { namespace app { namespace core { -enum class Platform { kUnknown, kMacOS, kiOS, kWindows, kLinux }; - /** * @brief Main controller for the application. * @@ -37,45 +33,40 @@ class Controller : public ExperimentFlags { absl::Status OnEntry(std::string filename = ""); void OnInput(); absl::Status OnLoad(); + absl::Status OnTestLoad(); void DoRender() const; void OnExit(); - absl::Status CreateSDL_Window(); + absl::Status CreateWindow(); absl::Status CreateRenderer(); absl::Status CreateGuiContext(); absl::Status LoadFontFamilies() const; absl::Status LoadAudioDevice(); + absl::Status LoadConfigFiles(); - auto master_editor() -> editor::MasterEditor & { return master_editor_; } + void SetupScreen(std::string filename = "") { + editor_manager_.SetupScreen(filename); + } + auto editor_manager() -> editor::EditorManager & { return editor_manager_; } + auto renderer() -> SDL_Renderer * { + return Renderer::GetInstance().renderer(); + } + auto window() -> SDL_Window * { return window_.get(); } + void init_test_editor(editor::Editor *editor) { test_editor_ = editor; } + void set_active(bool active) { active_ = active; } private: - struct sdl_deleter { - void operator()(SDL_Window *p) const { - if (p) { - SDL_DestroyWindow(p); - } - } - void operator()(SDL_Renderer *p) const { - if (p) { - SDL_DestroyRenderer(p); - } - } - void operator()(SDL_Texture *p) const { SDL_DestroyTexture(p); } - }; - - void CloseWindow() { active_ = false; } - friend int ::main(int argc, char **argv); bool active_; Platform platform_; - editor::MasterEditor master_editor_; + editor::Editor *test_editor_; + editor::EditorManager editor_manager_; int audio_frequency_ = 48000; - int16_t *audio_buffer_; SDL_AudioDeviceID audio_device_; + std::shared_ptr audio_buffer_; std::shared_ptr window_; - std::shared_ptr renderer_; }; } // namespace core diff --git a/src/app/core/core.cmake b/src/app/core/core.cmake new file mode 100644 index 00000000..ebb8bcc2 --- /dev/null +++ b/src/app/core/core.cmake @@ -0,0 +1,33 @@ +set( + YAZE_APP_CORE_SRC + app/core/common.cc + app/core/controller.cc + app/emu/emulator.cc + app/core/project.cc + app/core/utils/file_util.cc +) + +if (WIN32 OR MINGW OR UNIX AND NOT APPLE) + list(APPEND YAZE_APP_CORE_SRC + app/core/platform/font_loader.cc + app/core/platform/clipboard.cc + app/core/platform/file_dialog.cc + ) +endif() + +if(APPLE) + list(APPEND YAZE_APP_CORE_SRC + app/core/platform/file_dialog.mm + app/core/platform/app_delegate.mm + app/core/platform/font_loader.cc + app/core/platform/font_loader.mm + app/core/platform/clipboard.mm + app/core/platform/file_path.mm + ) + + find_library(COCOA_LIBRARY Cocoa) + if(NOT COCOA_LIBRARY) + message(FATAL_ERROR "Cocoa not found") + endif() + set(CMAKE_EXE_LINKER_FLAGS "-framework ServiceManagement -framework Foundation -framework Cocoa") +endif() diff --git a/src/app/core/labeling.h b/src/app/core/labeling.h deleted file mode 100644 index 95787bdf..00000000 --- a/src/app/core/labeling.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef YAZE_APP_CORE_LABELING_H_ -#define YAZE_APP_CORE_LABELING_H_ - -#include -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "app/core/common.h" -#include "app/core/constants.h" - -namespace yaze { -namespace app { -namespace core { - -// Default types -static constexpr absl::string_view kDefaultTypes[] = { - "Dungeon Names", "Dungeon Room Names", "Overworld Map Names"}; - -struct ResourceLabelManager { - bool LoadLabels(const std::string& filename); - bool SaveLabels(); - void DisplayLabels(bool* p_open); - void EditLabel(const std::string& type, const std::string& key, - const std::string& newValue); - void SelectableLabelWithNameEdit(bool selected, const std::string& type, - const std::string& key, - const std::string& defaultValue); - std::string CreateOrGetLabel(const std::string& type, const std::string& key, - const std::string& defaultValue); - std::string CreateOrGetLabel(const std::string& type, const std::string& key, - const absl::string_view& defaultValue); - - bool labels_loaded_ = false; - std::string filename_; - struct ResourceType { - std::string key_name; - std::string display_description; - }; - - std::unordered_map> - labels_; -}; - -} // namespace core -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_CORE_LABELING_H_ \ No newline at end of file diff --git a/src/app/core/platform/app_delegate.h b/src/app/core/platform/app_delegate.h index aab3df42..159aa3d7 100644 --- a/src/app/core/platform/app_delegate.h +++ b/src/app/core/platform/app_delegate.h @@ -1,13 +1,57 @@ #ifndef YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H #define YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H -#ifdef TARGET_OS_MAC +#if defined(__APPLE__) && defined(__MACH__) +/* Apple OSX and iOS (Darwin). */ +#import +#include + +#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 +/* iOS in Xcode simulator */ +#import +#import + +@interface AppDelegate : UIResponder +@property(strong, nonatomic) UIWindow *window; + +@property UIDocumentPickerViewController *documentPicker; +@property(nonatomic, copy) void (^completionHandler)(NSString *selectedFile); +- (void)PresentDocumentPickerWithCompletionHandler: + (void (^)(NSString *selectedFile))completionHandler; + +// TODO: Setup a tab bar controller for multiple yaze instances +@property(nonatomic) UITabBarController *tabBarController; + +// TODO: Setup a font picker for the text editor and display settings +@property(nonatomic) UIFontPickerViewController *fontPicker; + +// TODO: Setup the pencil kit for drawing +@property PKToolPicker *toolPicker; +@property PKCanvasView *canvasView; + +// TODO: Setup the file manager for file operations +@property NSFileManager *fileManager; + +@end + +#elif TARGET_OS_MAC == 1 #ifdef __cplusplus extern "C" { #endif -void InitializeCocoa(); +/** + * @brief Initialize the Cocoa application. + */ +void yaze_initialize_cocoa(); + +/** + * @brief Run the Cocoa application delegate. + */ +void yaze_run_cocoa_app_delegate(const char *filename); #ifdef __cplusplus } // extern "C" @@ -15,4 +59,6 @@ void InitializeCocoa(); #endif // TARGET_OS_MAC +#endif // defined(__APPLE__) && defined(__MACH__) + #endif // YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H diff --git a/src/app/core/platform/app_delegate.mm b/src/app/core/platform/app_delegate.mm index 141df9e8..e03dec3c 100644 --- a/src/app/core/platform/app_delegate.mm +++ b/src/app/core/platform/app_delegate.mm @@ -2,7 +2,7 @@ #import "app/core/platform/app_delegate.h" #import "app/core/controller.h" #import "app/core/platform/file_dialog.h" -#import "app/editor/utils/editor.h" +#import "app/editor/editor.h" #import "app/rom.h" #if defined(__APPLE__) && defined(__MACH__) @@ -11,12 +11,9 @@ #import -#if TARGET_IPHONE_SIMULATOR == 1 +#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 /* iOS in Xcode simulator */ -#elif TARGET_OS_IPHONE == 1 -/* iOS */ - #elif TARGET_OS_MAC == 1 /* macOS */ #import @@ -209,7 +206,8 @@ } - (void)openFileAction:(id)sender { - if (!yaze::app::SharedRom::shared_rom_->LoadFromFile(FileDialogWrapper::ShowOpenFileDialog()) + if (!yaze::app::SharedRom::shared_rom_ + ->LoadFromFile(yaze::app::core::FileDialogWrapper::ShowOpenFileDialog()) .ok()) { NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:@"Error"]; @@ -227,7 +225,9 @@ NSLog(@"Open Recent File action triggered"); } -extern "C" void InitializeCocoa() { +@end + +extern "C" void yaze_initialize_cococa() { @autoreleasepool { AppDelegate *delegate = [[AppDelegate alloc] init]; [NSApplication sharedApplication]; @@ -236,7 +236,21 @@ extern "C" void InitializeCocoa() { } } -@end +extern "C" void yaze_run_cocoa_app_delegate(const char *filename) { + yaze_initialize_cococa(); + yaze::app::core::Controller controller; + RETURN_VOID_IF_ERROR(controller.OnEntry(filename)); + while (controller.IsActive()) { + @autoreleasepool { + controller.OnInput(); + if (auto status = controller.OnLoad(); !status.ok()) { + break; + } + controller.DoRender(); + } + } + controller.OnExit(); +} #endif diff --git a/src/app/core/platform/clipboard.cc b/src/app/core/platform/clipboard.cc index 5c22b209..5607bd0c 100644 --- a/src/app/core/platform/clipboard.cc +++ b/src/app/core/platform/clipboard.cc @@ -3,6 +3,14 @@ #include #include +namespace yaze { +namespace app { +namespace core { + void CopyImageToClipboard(const std::vector& data) {} void GetImageFromClipboard(std::vector& data, int& width, - int& height) {} \ No newline at end of file + int& height) {} + +} // namespace core +} // namespace app +} // namespace yaze \ No newline at end of file diff --git a/src/app/core/platform/clipboard.h b/src/app/core/platform/clipboard.h index 4c02f592..325808ba 100644 --- a/src/app/core/platform/clipboard.h +++ b/src/app/core/platform/clipboard.h @@ -1,27 +1,18 @@ #ifndef YAZE_APP_CORE_PLATFORM_CLIPBOARD_H #define YAZE_APP_CORE_PLATFORM_CLIPBOARD_H -#ifdef _WIN32 - -void CopyImageToClipboard(const std::vector& data); -void GetImageFromClipboard(std::vector& data, int& width, int& height); - -#elif defined(__APPLE__) - #include #include -void CopyImageToClipboard(const std::vector& data); -void GetImageFromClipboard(std::vector& data, int& width, int& height); +namespace yaze { +namespace app { +namespace core { -#elif defined(__linux__) +void CopyImageToClipboard(const std::vector &data); +void GetImageFromClipboard(std::vector &data, int &width, int &height); -#include -#include - -void CopyImageToClipboard(const std::vector& data); -void GetImageFromClipboard(std::vector& data, int& width, int& height); - -#endif +} // namespace core +} // namespace app +} // namespace yaze #endif // YAZE_APP_CORE_PLATFORM_CLIPBOARD_H \ No newline at end of file diff --git a/src/app/core/platform/clipboard.mm b/src/app/core/platform/clipboard.mm index bdaba4a7..e756b29e 100644 --- a/src/app/core/platform/clipboard.mm +++ b/src/app/core/platform/clipboard.mm @@ -6,7 +6,7 @@ #ifdef TARGET_OS_MAC #import -void CopyImageToClipboard(const std::vector& pngData) { +void yaze::app::core::CopyImageToClipboard(const std::vector& pngData) { NSData* data = [NSData dataWithBytes:pngData.data() length:pngData.size()]; NSImage* image = [[NSImage alloc] initWithData:data]; @@ -15,7 +15,7 @@ void CopyImageToClipboard(const std::vector& pngData) { [pasteboard writeObjects:@[ image ]]; } -void GetImageFromClipboard(std::vector& pixel_data, int& width, int& height) { +void yaze::app::core::GetImageFromClipboard(std::vector& pixel_data, int& width, int& height) { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSArray* classArray = [NSArray arrayWithObject:[NSImage class]]; NSDictionary* options = [NSDictionary dictionary]; diff --git a/src/app/core/platform/file_dialog.cc b/src/app/core/platform/file_dialog.cc new file mode 100644 index 00000000..1643d1dd --- /dev/null +++ b/src/app/core/platform/file_dialog.cc @@ -0,0 +1,145 @@ +#include "file_dialog.h" + +#ifdef _WIN32 +// Include Windows-specific headers +#include +#include +#endif // _WIN32 + +namespace yaze { +namespace app { +namespace core { + +#ifdef _WIN32 + + std::string FileDialogWrapper::ShowOpenFileDialog() { + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + IFileDialog *pfd = NULL; + HRESULT hr = + CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileDialog, + reinterpret_cast(&pfd)); + std::string file_path_windows; + if (SUCCEEDED(hr)) { + // Show the dialog + hr = pfd->Show(NULL); + if (SUCCEEDED(hr)) { + IShellItem *psiResult; + hr = pfd->GetResult(&psiResult); + if (SUCCEEDED(hr)) { + // Get the file path + PWSTR pszFilePath; + psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath); + char str[128]; + wcstombs(str, pszFilePath, 128); + file_path_windows = str; + psiResult->Release(); + CoTaskMemFree(pszFilePath); + } + } + pfd->Release(); + } + + CoUninitialize(); + return file_path_windows; +} + + std::string FileDialogWrapper::ShowOpenFolderDialog() { + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + IFileDialog *pfd = NULL; + HRESULT hr = + CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileDialog, + reinterpret_cast(&pfd)); + std::string folder_path_windows; + if (SUCCEEDED(hr)) { + // Show the dialog + DWORD dwOptions; + hr = pfd->GetOptions(&dwOptions); + if (SUCCEEDED(hr)) { + hr = pfd->SetOptions(dwOptions | FOS_PICKFOLDERS); + if (SUCCEEDED(hr)) { + hr = pfd->Show(NULL); + if (SUCCEEDED(hr)) { + IShellItem *psiResult; + hr = pfd->GetResult(&psiResult); + if (SUCCEEDED(hr)) { + // Get the folder path + PWSTR pszFolderPath; + psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszFolderPath); + char str[128]; + wcstombs(str, pszFolderPath, 128); + folder_path_windows = str; + psiResult->Release(); + CoTaskMemFree(pszFolderPath); + } + } + } + } + pfd->Release(); + } + + CoUninitialize(); + return folder_path_windows; +} + +std::vector FileDialogWrapper::GetSubdirectoriesInFolder( + const std::string &folder_path) { + std::vector subdirectories; + WIN32_FIND_DATA findFileData; + HANDLE hFind = FindFirstFile((folder_path + "\\*").c_str(), &findFileData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (strcmp(findFileData.cFileName, ".") != 0 && + strcmp(findFileData.cFileName, "..") != 0) { + subdirectories.push_back(findFileData.cFileName); + } + } + } while (FindNextFile(hFind, &findFileData) != 0); + FindClose(hFind); + } + return subdirectories; +} + +std::vector FileDialogWrapper::GetFilesInFolder( + const std::string &folder_path) { + std::vector files; + WIN32_FIND_DATA findFileData; + HANDLE hFind = FindFirstFile((folder_path + "\\*").c_str(), &findFileData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + files.push_back(findFileData.cFileName); + } + } while (FindNextFile(hFind, &findFileData) != 0); + FindClose(hFind); + } + return files; +} + +#elif defined(__linux__) + +std::string FileDialogWrapper::ShowOpenFileDialog() { + return "Linux: Open file dialog"; +} + +std::string FileDialogWrapper::ShowOpenFolderDialog() { + return "Linux: Open folder dialog"; +} + +std::vector FileDialogWrapper::GetSubdirectoriesInFolder( + const std::string& folder_path) { + return {"Linux: Subdirectories in folder"}; +} + +std::vector FileDialogWrapper::GetFilesInFolder( + const std::string& folder_path) { + return {"Linux: Files in folder"}; +} + +#endif + +} // namespace core +} // namespace app +} // namespace yaze \ No newline at end of file diff --git a/src/app/core/platform/file_dialog.h b/src/app/core/platform/file_dialog.h index 8d7257c2..6276f86e 100644 --- a/src/app/core/platform/file_dialog.h +++ b/src/app/core/platform/file_dialog.h @@ -1,61 +1,25 @@ #ifndef YAZE_APP_CORE_PLATFORM_FILE_DIALOG_H #define YAZE_APP_CORE_PLATFORM_FILE_DIALOG_H -#include - -#ifdef _WIN32 -// Include Windows-specific headers -#include -#include - -class FileDialogWrapper { - public: - static std::string ShowOpenFileDialog() { - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - - IFileDialog *pfd = NULL; - HRESULT hr = - CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, - IID_IFileDialog, reinterpret_cast(&pfd)); - std::string file_path_windows; - if (SUCCEEDED(hr)) { - // Show the dialog - hr = pfd->Show(NULL); - if (SUCCEEDED(hr)) { - IShellItem *psiResult; - hr = pfd->GetResult(&psiResult); - if (SUCCEEDED(hr)) { - // Get the file path - PWSTR pszFilePath; - psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath); - char str[128]; - wcstombs(str, pszFilePath, 128); - file_path_windows = str; - psiResult->Release(); - CoTaskMemFree(pszFilePath); - } - } - pfd->Release(); - } - - CoUninitialize(); - return file_path_windows; - } -}; - -#elif defined(__APPLE__) - -#include "TargetConditionals.h" - #include #include -#ifdef TARGET_OS_MAC -// Other kinds of Mac OS +namespace yaze { +namespace app { +namespace core { class FileDialogWrapper { public: + /** + * @brief ShowOpenFileDialog opens a file dialog and returns the selected + * filepath. + */ static std::string ShowOpenFileDialog(); + + /** + * @brief ShowOpenFolderDialog opens a file dialog and returns the selected + * folder path. + */ static std::string ShowOpenFolderDialog(); static std::vector GetSubdirectoriesInFolder( const std::string& folder_path); @@ -63,34 +27,8 @@ class FileDialogWrapper { const std::string& folder_path); }; -#elif TARGET_OS_IPHONE - -// iOS -class FileDialogWrapper { - public: - static std::string ShowOpenFileDialog(); - static std::string ShowOpenFolderDialog(); - static std::vector GetSubdirectoriesInFolder( - const std::string& folder_path); - static std::vector GetFilesInFolder( - const std::string& folder_path); -}; - -#endif - -#elif defined(__linux__) - -class FileDialogWrapper { - public: - static std::string ShowOpenFileDialog() { - // Linux-specific file dialog implementation using GTK - // ... - return "file_path_linux"; - } -}; - -#else -#error "Unsupported platform." -#endif +} // namespace core +} // namespace app +} // namespace yaze #endif // YAZE_APP_CORE_PLATFORM_FILE_DIALOG_H diff --git a/src/app/core/platform/file_dialog.mm b/src/app/core/platform/file_dialog.mm index a81a47cb..8b11a3d6 100644 --- a/src/app/core/platform/file_dialog.mm +++ b/src/app/core/platform/file_dialog.mm @@ -1,8 +1,8 @@ +#include "app/core/platform/file_dialog.h" #include #include - -#include "app/core/platform/file_dialog.h" +#include "imgui/imgui.h" #if defined(__APPLE__) && defined(__MACH__) /* Apple OSX and iOS (Darwin). */ @@ -10,32 +10,48 @@ #import -#if TARGET_IPHONE_SIMULATOR == 1 +#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 /* iOS in Xcode simulator */ -std::string FileDialogWrapper::ShowOpenFileDialog() { return ""; } +#import +#import -std::string FileDialogWrapper::ShowOpenFolderDialog() { return ""; } +#include "app/core/platform/app_delegate.h" -std::vector FileDialogWrapper::GetFilesInFolder(const std::string& folder) { +namespace { +static std::string selectedFile; + +void ShowOpenFileDialogImpl(void (^completionHandler)(std::string)) { + AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; + [appDelegate PresentDocumentPickerWithCompletionHandler:^(NSString *filePath) { + selectedFile = std::string([filePath UTF8String]); + completionHandler(selectedFile); + }]; +} + +std::string ShowOpenFileDialogSync() { + __block std::string result; + + ShowOpenFileDialogImpl(^(std::string filePath) { + result = filePath; + }); + + return result; +} +} + +std::string yaze::app::core::FileDialogWrapper::ShowOpenFileDialog() { + return ShowOpenFileDialogSync(); +} + +std::string yaze::app::core::FileDialogWrapper::ShowOpenFolderDialog() { return ""; } + +std::vector yaze::app::core::FileDialogWrapper::GetFilesInFolder( + const std::string &folder) { return {}; } -std::vector FileDialogWrapper::GetSubdirectoriesInFolder(const std::string& folder) { - return {}; -} - -#elif TARGET_OS_IPHONE == 1 -/* iOS */ - -std::string FileDialogWrapper::ShowOpenFileDialog() { return ""; } - -std::string FileDialogWrapper::ShowOpenFolderDialog() { return ""; } - -std::vector FileDialogWrapper::GetFilesInFolder(const std::string& folder) { - return {}; -} - -std::vector FileDialogWrapper::GetSubdirectoriesInFolder(const std::string& folder) { +std::vector yaze::app::core::FileDialogWrapper::GetSubdirectoriesInFolder( + const std::string &folder) { return {}; } @@ -44,7 +60,7 @@ std::vector FileDialogWrapper::GetSubdirectoriesInFolder(const std: #import -std::string FileDialogWrapper::ShowOpenFileDialog() { +std::string yaze::app::core::FileDialogWrapper::ShowOpenFileDialog() { NSOpenPanel* openPanel = [NSOpenPanel openPanel]; [openPanel setCanChooseFiles:YES]; [openPanel setCanChooseDirectories:NO]; @@ -59,7 +75,7 @@ std::string FileDialogWrapper::ShowOpenFileDialog() { return ""; } -std::string FileDialogWrapper::ShowOpenFolderDialog() { +std::string yaze::app::core::FileDialogWrapper::ShowOpenFolderDialog() { NSOpenPanel* openPanel = [NSOpenPanel openPanel]; [openPanel setCanChooseFiles:NO]; [openPanel setCanChooseDirectories:YES]; @@ -74,7 +90,8 @@ std::string FileDialogWrapper::ShowOpenFolderDialog() { return ""; } -std::vector FileDialogWrapper::GetFilesInFolder(const std::string& folder) { +std::vector yaze::app::core::FileDialogWrapper::GetFilesInFolder( + const std::string& folder) { std::vector filenames; NSFileManager* fileManager = [NSFileManager defaultManager]; NSDirectoryEnumerator* enumerator = @@ -89,7 +106,8 @@ std::vector FileDialogWrapper::GetFilesInFolder(const std::string& return filenames; } -std::vector FileDialogWrapper::GetSubdirectoriesInFolder(const std::string& folder) { +std::vector yaze::app::core::FileDialogWrapper::GetSubdirectoriesInFolder( + const std::string& folder) { std::vector subdirectories; NSFileManager* fileManager = [NSFileManager defaultManager]; NSDirectoryEnumerator* enumerator = @@ -113,4 +131,4 @@ std::vector FileDialogWrapper::GetSubdirectoriesInFolder(const std: // Unsupported platform #endif // TARGET_OS_MAC -#endif // __APPLE__ && __MACH__ +#endif // __APPLE__ && __MACH__ \ No newline at end of file diff --git a/src/app/core/platform/file_path.h b/src/app/core/platform/file_path.h index 5cffc9de..c06ef3e3 100644 --- a/src/app/core/platform/file_path.h +++ b/src/app/core/platform/file_path.h @@ -1,6 +1,20 @@ #ifndef YAZE_APP_CORE_PLATFORM_FILE_PATH_H #define YAZE_APP_CORE_PLATFORM_FILE_PATH_H +#include + +namespace yaze { +namespace app { +namespace core { + +/** + * @brief GetBundleResourcePath returns the path to the bundle resource + * directory. Specific to MacOS. + */ std::string GetBundleResourcePath(); +} // namespace core +} // namespace app +} // namespace yaze + #endif // YAZE_APP_CORE_PLATFORM_FILE_PATH_H diff --git a/src/app/core/platform/file_path.mm b/src/app/core/platform/file_path.mm index 74dccef7..617e80cf 100644 --- a/src/app/core/platform/file_path.mm +++ b/src/app/core/platform/file_path.mm @@ -1,3 +1,5 @@ +#include "file_path.h" + #include #include @@ -5,17 +7,15 @@ #include #include -#if TARGET_IPHONE_SIMULATOR == 1 -std::string GetBundleResourcePath() {} -#elif TARGET_OS_IPHONE == 1 -std::string GetBundleResourcePath() { +#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 +std::string yaze::app::core::GetBundleResourcePath() { NSBundle* bundle = [NSBundle mainBundle]; NSString* resourceDirectoryPath = [bundle bundlePath]; NSString* path = [resourceDirectoryPath stringByAppendingString:@"/"]; return [path UTF8String]; } #elif TARGET_OS_MAC == 1 -std::string GetBundleResourcePath() { +std::string yaze::app::core::GetBundleResourcePath() { NSBundle* bundle = [NSBundle mainBundle]; NSString* resourceDirectoryPath = [bundle bundlePath]; NSString* path = [resourceDirectoryPath stringByAppendingString:@"/"]; diff --git a/src/app/core/platform/font_loader.cc b/src/app/core/platform/font_loader.cc index 0c87a33b..18d8c3a3 100644 --- a/src/app/core/platform/font_loader.cc +++ b/src/app/core/platform/font_loader.cc @@ -1,17 +1,124 @@ #include "app/core/platform/font_loader.h" +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "app/core/platform/file_path.h" +#include "app/gui/icons.h" #include "imgui/imgui.h" -#include -#include +namespace yaze { +namespace app { +namespace core { + +absl::Status LoadPackageFonts() { + ImGuiIO &io = ImGui::GetIO(); + + static const char *KARLA_REGULAR = "Karla-Regular.ttf"; + static const char *ROBOTO_MEDIUM = "Roboto-Medium.ttf"; + static const char *COUSINE_REGULAR = "Cousine-Regular.ttf"; + static const char *DROID_SANS = "DroidSans.ttf"; + static const char *NOTO_SANS_JP = "NotoSansJP.ttf"; + static const char *IBM_PLEX_JP = "IBMPlexSansJP-Bold.ttf"; + static const float FONT_SIZE_DEFAULT = 16.0f; + static const float FONT_SIZE_DROID_SANS = 18.0f; + static const float ICON_FONT_SIZE = 18.0f; + + // Icon configuration + static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0}; + ImFontConfig icons_config; + icons_config.MergeMode = true; + icons_config.GlyphOffset.y = 5.0f; + icons_config.GlyphMinAdvanceX = 13.0f; + icons_config.PixelSnapH = true; + + // Japanese font configuration + ImFontConfig japanese_font_config; + japanese_font_config.MergeMode = true; + icons_config.GlyphOffset.y = 5.0f; + icons_config.GlyphMinAdvanceX = 13.0f; + icons_config.PixelSnapH = true; + + // List of fonts to be loaded + std::vector font_paths = { + KARLA_REGULAR, ROBOTO_MEDIUM, COUSINE_REGULAR, IBM_PLEX_JP, DROID_SANS}; + + // Load fonts with associated icon and Japanese merges + for (const auto &font_path : font_paths) { + float font_size = + (font_path == DROID_SANS) ? FONT_SIZE_DROID_SANS : FONT_SIZE_DEFAULT; + + std::string actual_font_path; +#ifdef __APPLE__ +#if TARGET_OS_IOS == 1 + const std::string kBundlePath = GetBundleResourcePath(); + actual_font_path = kBundlePath + font_path; +#else + actual_font_path = absl::StrCat(GetBundleResourcePath(), + "Contents/Resources/font/", font_path); +#endif +#else + actual_font_path = std::filesystem::absolute(font_path).string(); +#endif + + if (!io.Fonts->AddFontFromFileTTF(actual_font_path.data(), font_size)) { + return absl::InternalError( + absl::StrFormat("Failed to load font from %s", actual_font_path)); + } + + // Merge icon set + std::string actual_icon_font_path = ""; + const char *icon_font_path = FONT_ICON_FILE_NAME_MD; +#if defined(__APPLE__) && defined(__MACH__) +#if TARGET_OS_IOS == 1 + const std::string kIconBundlePath = GetBundleResourcePath(); + actual_icon_font_path = kIconBundlePath + "MaterialIcons-Regular.ttf"; +#else + actual_icon_font_path = + absl::StrCat(GetBundleResourcePath(), + "Contents/Resources/font/MaterialIcons-Regular.ttf"); +#endif +#else + actual_icon_font_path = std::filesystem::absolute(icon_font_path).string(); +#endif + io.Fonts->AddFontFromFileTTF(actual_icon_font_path.data(), ICON_FONT_SIZE, + &icons_config, icons_ranges); + + // Merge Japanese font + std::string actual_japanese_font_path = ""; + const char *japanese_font_path = NOTO_SANS_JP; +#if defined(__APPLE__) && defined(__MACH__) +#if TARGET_OS_IOS == 1 + const std::string kJapaneseBundlePath = GetBundleResourcePath(); + actual_japanese_font_path = kJapaneseBundlePath + japanese_font_path; +#else + actual_japanese_font_path = + absl::StrCat(GetBundleResourcePath(), "Contents/Resources/font/", + japanese_font_path); +#endif +#else + actual_japanese_font_path = + std::filesystem::absolute(japanese_font_path).string(); +#endif + io.Fonts->AddFontFromFileTTF(actual_japanese_font_path.data(), 18.0f, + &japanese_font_config, + io.Fonts->GetGlyphRangesJapanese()); + } + return absl::OkStatus(); +} #ifdef _WIN32 #include -int CALLBACK EnumFontFamExProc(const LOGFONT* lpelfe, const TEXTMETRIC* lpntme, +int CALLBACK EnumFontFamExProc(const LOGFONT *lpelfe, const TEXTMETRIC *lpntme, DWORD FontType, LPARAM lParam) { // Step 3: Load the font into ImGui - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF(lpelfe->lfFaceName, 16.0f); return 1; @@ -34,8 +141,8 @@ void LoadSystemFonts() { RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, &maxValueNameSize, &maxValueDataSize, NULL, NULL); - char* valueName = new char[maxValueNameSize + 1]; // +1 for null terminator - BYTE* valueData = new BYTE[maxValueDataSize + 1]; // +1 for null terminator + char *valueName = new char[maxValueNameSize + 1]; // +1 for null terminator + BYTE *valueData = new BYTE[maxValueDataSize + 1]; // +1 for null terminator // Enumerate all font entries for (DWORD i = 0; i < valueCount; i++) { @@ -52,7 +159,9 @@ void LoadSystemFonts() { valueData, &valueDataSize) == ERROR_SUCCESS) { if (valueType == REG_SZ) { // Add the font file path to the vector - std::string fontPath((char*)valueData); + std::string fontPath(reinterpret_cast(valueData), + valueDataSize); + fontPaths.push_back(fontPath); } } @@ -64,10 +173,57 @@ void LoadSystemFonts() { RegCloseKey(hKey); } - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); - for (const auto& fontPath : fontPaths) { - io.Fonts->AddFontFromFileTTF(fontPath.c_str(), 16.0f); + // List of common font face names + static const std::unordered_set commonFontFaceNames = { + "arial", + "times", + "cour", + "verdana", + "tahoma", + "comic", + "Impact", + "ariblk", + "Trebuchet MS", + "Georgia", + "Palatino Linotype", + "Lucida Sans Unicode", + "Tahoma", + "Lucida Console"}; + + for (auto &fontPath : fontPaths) { + // Check if the font path has a "C:\" prefix + if (fontPath.substr(0, 2) != "C:") { + // Add "C:\Windows\Fonts\" prefix to the font path + fontPath = absl::StrFormat("C:\\Windows\\Fonts\\%s", fontPath.c_str()); + } + + // Check if the font file has a .ttf or .TTF extension + std::string extension = fontPath.substr(fontPath.find_last_of(".") + 1); + if (extension == "ttf" || extension == "TTF") { + // Get the font face name from the font path + std::string fontFaceName = + fontPath.substr(fontPath.find_last_of("\\/") + 1); + fontFaceName = fontFaceName.substr(0, fontFaceName.find_last_of(".")); + + // Check if the font face name is in the common font face names list + if (commonFontFaceNames.find(fontFaceName) != commonFontFaceNames.end()) { + io.Fonts->AddFontFromFileTTF(fontPath.c_str(), 16.0f); + + // Merge icon set + // Icon configuration + static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0}; + ImFontConfig icons_config; + static const float ICON_FONT_SIZE = 18.0f; + icons_config.MergeMode = true; + icons_config.GlyphOffset.y = 5.0f; + icons_config.GlyphMinAdvanceX = 13.0f; + icons_config.PixelSnapH = true; + io.Fonts->AddFontFromFileTTF(FONT_ICON_FILE_NAME_MD, ICON_FONT_SIZE, + &icons_config, icons_ranges); + } + } } } @@ -78,4 +234,8 @@ void LoadSystemFonts() { // ... } -#endif \ No newline at end of file +#endif + +} // namespace core +} // namespace app +} // namespace yaze \ No newline at end of file diff --git a/src/app/core/platform/font_loader.h b/src/app/core/platform/font_loader.h index a0752dda..685dcc2b 100644 --- a/src/app/core/platform/font_loader.h +++ b/src/app/core/platform/font_loader.h @@ -1,26 +1,17 @@ -// FontLoader.h -#ifndef FONTLOADER_H -#define FONTLOADER_H +#ifndef YAZE_APP_CORE_PLATFORM_FONTLOADER_H +#define YAZE_APP_CORE_PLATFORM_FONTLOADER_H -#include "TargetConditionals.h" +#include "absl/status/status.h" -#ifdef _WIN32 -#include -// Windows specific function declaration for loading system fonts into ImGui -int CALLBACK EnumFontFamExProc(const LOGFONT* lpelfe, const TEXTMETRIC* lpntme, - DWORD FontType, LPARAM lParam); -#elif __APPLE__ - -#ifdef TARGET_OS_MAC +namespace yaze { +namespace app { +namespace core { void LoadSystemFonts(); +absl::Status LoadPackageFonts(); -#elif TARGET_OS_IPHONE +} // namespace core +} // namespace app +} // namespace yaze -void LoadSystemFonts(); - -#endif - -#endif - -#endif // FONTLOADER_H +#endif // YAZE_APP_CORE_PLATFORM_FONTLOADER_H diff --git a/src/app/core/platform/font_loader.mm b/src/app/core/platform/font_loader.mm index 3b8e0a7d..48e0a258 100644 --- a/src/app/core/platform/font_loader.mm +++ b/src/app/core/platform/font_loader.mm @@ -1,32 +1,20 @@ -// FontLoader.mm #include "app/core/platform/font_loader.h" -#include "imgui/imgui.h" - -#include "app/gui/icons.h" - -#if defined(__APPLE__) && defined(__MACH__) -/* Apple OSX and iOS (Darwin). */ +#import #include -#import +#include "app/gui/icons.h" +#include "imgui/imgui.h" -#if TARGET_IPHONE_SIMULATOR == 1 -/* iOS in Xcode simulator */ -void LoadSystemFonts() {} - -#elif TARGET_OS_IPHONE == 1 +#if TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1 /* iOS */ -void LoadSystemFonts() {} +void yaze::app::core::LoadSystemFonts() {} #elif TARGET_OS_MAC == 1 /* macOS */ - #import -// MacOS Implementation -void LoadSystemFonts() { - // List of common macOS system fonts +void yaze::app::core::LoadSystemFonts() { NSArray *fontNames = @[ @"Helvetica", @"Times New Roman", @"Courier", @"Arial", @"Verdana" ]; for (NSString *fontName in fontNames) { @@ -67,8 +55,5 @@ void LoadSystemFonts() { } } } -#else -// Unsupported platform -#endif #endif diff --git a/src/app/core/platform/renderer.h b/src/app/core/platform/renderer.h new file mode 100644 index 00000000..1f173fa9 --- /dev/null +++ b/src/app/core/platform/renderer.h @@ -0,0 +1,83 @@ +#ifndef YAZE_APP_CORE_PLATFORM_RENDERER_H +#define YAZE_APP_CORE_PLATFORM_RENDERER_H + +#include + +#include + +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "app/core/utils/sdl_deleter.h" +#include "app/gfx/bitmap.h" + +namespace yaze { +namespace app { +namespace core { + +/** + * @class Renderer + * @brief The Renderer class represents the renderer for the Yaze application. + * + * This class is a singleton that provides functionality for creating and + * rendering bitmaps to the screen. It also includes methods for updating + * bitmaps on the screen. + */ +class Renderer { + public: + static Renderer &GetInstance() { + static Renderer instance; + return instance; + } + + absl::Status CreateRenderer(SDL_Window *window) { + renderer_ = std::unique_ptr(SDL_CreateRenderer( + window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED)); + if (renderer_ == nullptr) { + return absl::InternalError( + absl::StrFormat("SDL_CreateRenderer: %s\n", SDL_GetError())); + } + SDL_SetRenderDrawBlendMode(renderer_.get(), SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer_.get(), 0x00, 0x00, 0x00, 0x00); + return absl::OkStatus(); + } + + auto renderer() -> SDL_Renderer * { return renderer_.get(); } + + /** + * @brief Used to render a bitmap to the screen. + */ + void RenderBitmap(gfx::Bitmap *bitmap) { + bitmap->CreateTexture(renderer_.get()); + } + + /** + * @brief Used to update a bitmap on the screen. + */ + void UpdateBitmap(gfx::Bitmap *bitmap) { + bitmap->UpdateTexture(renderer_.get()); + } + + absl::Status CreateAndRenderBitmap(int width, int height, int depth, + const std::vector &data, + gfx::Bitmap &bitmap, + gfx::SnesPalette &palette) { + bitmap.Create(width, height, depth, data); + RETURN_IF_ERROR(bitmap.ApplyPalette(palette)); + RenderBitmap(&bitmap); + return absl::OkStatus(); + } + + private: + Renderer() = default; + + std::unique_ptr renderer_; + + Renderer(const Renderer &) = delete; + Renderer &operator=(const Renderer &) = delete; +}; + +} // namespace core +} // namespace app +} // namespace yaze + +#endif diff --git a/src/app/core/platform/view_controller.h b/src/app/core/platform/view_controller.h new file mode 100644 index 00000000..7c4318a3 --- /dev/null +++ b/src/app/core/platform/view_controller.h @@ -0,0 +1,29 @@ +#ifndef YAZE_APP_CORE_PLATFORM_VIEW_CONTROLLER_H +#define YAZE_APP_CORE_PLATFORM_VIEW_CONTROLLER_H + +#ifdef __APPLE__ +#include + +#if TARGET_OS_OSX +#include "imgui_impl_osx.h" +@interface AppViewController : NSViewController +@end +#else +@interface AppViewController : UIViewController +@property(nonatomic) yaze::app::core::Controller *controller; +@property(nonatomic) UIHoverGestureRecognizer *hoverGestureRecognizer; +@property(nonatomic) UIPinchGestureRecognizer *pinchRecognizer; +@property(nonatomic) UISwipeGestureRecognizer *swipeRecognizer; +@property(nonatomic) UILongPressGestureRecognizer *longPressRecognizer; +@end +#endif + +@interface AppViewController () +@property(nonatomic, readonly) MTKView *mtkView; +@property(nonatomic, strong) id device; +@property(nonatomic, strong) id commandQueue; +@end + +#endif // __APPLE__ + +#endif // YAZE_APP_CORE_PLATFORM_APP_VIEW_CONTROLLER_H diff --git a/src/app/core/labeling.cc b/src/app/core/project.cc similarity index 73% rename from src/app/core/labeling.cc rename to src/app/core/project.cc index db464091..98051bf2 100644 --- a/src/app/core/labeling.cc +++ b/src/app/core/project.cc @@ -1,22 +1,66 @@ -#include "app/core/labeling.h" +#include "project.h" +#include +#include + +#include "app/core/constants.h" +#include "app/gui/icons.h" #include "imgui/imgui.h" #include "imgui/misc/cpp/imgui_stdlib.h" -#include -#include -#include -#include -#include -#include - -#include "app/core/common.h" -#include "app/core/constants.h" -#include "app/gui/icons.h" - namespace yaze { namespace app { -namespace core { + +absl::Status Project::Open(const std::string& project_path) { + filepath = project_path; + name = project_path.substr(project_path.find_last_of("/") + 1); + + std::ifstream in(project_path); + + if (!in.good()) { + return absl::InternalError("Could not open project file."); + } + + std::string line; + std::getline(in, name); + std::getline(in, filepath); + std::getline(in, rom_filename_); + std::getline(in, code_folder_); + std::getline(in, labels_filename_); + std::getline(in, keybindings_file); + + while (std::getline(in, line)) { + if (line == kEndOfProjectFile) { + break; + } + } + + in.close(); + + return absl::OkStatus(); +} + +absl::Status Project::Save() { + RETURN_IF_ERROR(CheckForEmptyFields()); + + std::ofstream out(filepath + "/" + name + ".yaze"); + if (!out.good()) { + return absl::InternalError("Could not open project file."); + } + + out << name << std::endl; + out << filepath << std::endl; + out << rom_filename_ << std::endl; + out << code_folder_ << std::endl; + out << labels_filename_ << std::endl; + out << keybindings_file << std::endl; + + out << kEndOfProjectFile << std::endl; + + out.close(); + + return absl::OkStatus(); +} bool ResourceLabelManager::LoadLabels(const std::string& filename) { std::ifstream file(filename); @@ -124,6 +168,11 @@ void ResourceLabelManager::SelectableLabelWithNameEdit( } } +std::string ResourceLabelManager::GetLabel(const std::string& type, + const std::string& key) { + return labels_[type][key]; +} + std::string ResourceLabelManager::CreateOrGetLabel( const std::string& type, const std::string& key, const std::string& defaultValue) { @@ -136,6 +185,5 @@ std::string ResourceLabelManager::CreateOrGetLabel( return labels_[type][key]; } -} // namespace core } // namespace app } // namespace yaze diff --git a/src/app/core/project.h b/src/app/core/project.h index 113716f3..cfe21019 100644 --- a/src/app/core/project.h +++ b/src/app/core/project.h @@ -1,26 +1,20 @@ #ifndef YAZE_APP_CORE_PROJECT_H #define YAZE_APP_CORE_PROJECT_H -#include "absl/strings/match.h" - +#include #include #include -#include #include #include "absl/status/status.h" -#include "absl/strings/string_view.h" #include "app/core/common.h" +#include "app/core/utils/file_util.h" namespace yaze { namespace app { -constexpr absl::string_view kProjectFileExtension = ".yaze"; -constexpr absl::string_view kProjectFileFilter = - "Yaze Project Files (*.yaze)\0*.yaze\0"; -constexpr absl::string_view kPreviousRomFilenameDelimiter = - "PreviousRomFilename"; -constexpr absl::string_view kEndOfProjectFile = "EndOfProjectFile"; +const std::string kRecentFilesFilename = "recent_files.txt"; +constexpr char kEndOfProjectFile[] = "EndOfProjectFile"; /** * @struct Project @@ -31,81 +25,12 @@ constexpr absl::string_view kEndOfProjectFile = "EndOfProjectFile"; * user can have different rom file names for a single project and keep track of * backups. */ - struct Project : public core::ExperimentFlags { - /** - * @brief Creates a new project. - * - * @param project_name The name of the project. - * @param project_path The path to the project. - * @return An absl::Status indicating the success or failure of the project - * creation. - */ - absl::Status Create(const std::string &project_name) { + absl::Status Create(const std::string& project_name) { name = project_name; project_opened_ = true; return absl::OkStatus(); } - - absl::Status Open(const std::string &project_path) { - filepath = project_path; - name = project_path.substr(project_path.find_last_of("/") + 1); - - std::ifstream in(project_path); - - if (!in.good()) { - return absl::InternalError("Could not open project file."); - } - - std::string line; - std::getline(in, name); - std::getline(in, filepath); - std::getline(in, rom_filename_); - std::getline(in, code_folder_); - std::getline(in, labels_filename_); - - while (std::getline(in, line)) { - if (line == kEndOfProjectFile) { - break; - } - - if (absl::StrContains(line, kPreviousRomFilenameDelimiter)) { - previous_rom_filenames_.push_back( - line.substr(line.find(kPreviousRomFilenameDelimiter) + - kPreviousRomFilenameDelimiter.size() + 1)); - } - } - - in.close(); - - return absl::OkStatus(); - } - - absl::Status Save() { - RETURN_IF_ERROR(CheckForEmptyFields()); - - std::ofstream out(filepath + "/" + name + ".yaze"); - if (!out.good()) { - return absl::InternalError("Could not open project file."); - } - - out << name << std::endl; - out << filepath << std::endl; - out << rom_filename_ << std::endl; - out << code_folder_ << std::endl; - out << labels_filename_ << std::endl; - - for (const auto &filename : previous_rom_filenames_) { - out << kPreviousRomFilenameDelimiter << " " << filename << std::endl; - } - - out << kEndOfProjectFile << std::endl; - - out.close(); - - return absl::OkStatus(); - } - absl::Status CheckForEmptyFields() { if (name.empty() || filepath.empty() || rom_filename_.empty() || code_folder_.empty() || labels_filename_.empty()) { @@ -116,20 +41,93 @@ struct Project : public core::ExperimentFlags { return absl::OkStatus(); } - - absl::Status SerializeExperimentFlags() { - auto flags = mutable_flags(); - // TODO: Serialize flags - return absl::OkStatus(); - } + absl::Status Open(const std::string &project_path); + absl::Status Save(); bool project_opened_ = false; std::string name; + std::string flags = ""; std::string filepath; std::string rom_filename_ = ""; std::string code_folder_ = ""; std::string labels_filename_ = ""; - std::vector previous_rom_filenames_; + std::string keybindings_file = ""; +}; + +// Default types +static constexpr absl::string_view kDefaultTypes[] = { + "Dungeon Names", "Dungeon Room Names", "Overworld Map Names"}; + +struct ResourceLabelManager { + bool LoadLabels(const std::string& filename); + bool SaveLabels(); + void DisplayLabels(bool* p_open); + void EditLabel(const std::string& type, const std::string& key, + const std::string& newValue); + void SelectableLabelWithNameEdit(bool selected, const std::string& type, + const std::string& key, + const std::string& defaultValue); + std::string GetLabel(const std::string& type, const std::string& key); + std::string CreateOrGetLabel(const std::string& type, const std::string& key, + const std::string& defaultValue); + + bool labels_loaded_ = false; + std::string filename_; + struct ResourceType { + std::string key_name; + std::string display_description; + }; + + std::unordered_map> + labels_; +}; + +class RecentFilesManager { + public: + RecentFilesManager() : RecentFilesManager(kRecentFilesFilename) {} + RecentFilesManager(const std::string& filename) : filename_(filename) {} + + void AddFile(const std::string& file_path) { + // Add a file to the list, avoiding duplicates + auto it = std::find(recent_files_.begin(), recent_files_.end(), file_path); + if (it == recent_files_.end()) { + recent_files_.push_back(file_path); + } + } + + void Save() { + std::ofstream file(filename_); + if (!file.is_open()) { + return; // Handle the error appropriately + } + + for (const auto& file_path : recent_files_) { + file << file_path << std::endl; + } + } + + void Load() { + std::ifstream file(filename_); + if (!file.is_open()) { + return; + } + + recent_files_.clear(); + std::string line; + while (std::getline(file, line)) { + if (!line.empty()) { + recent_files_.push_back(line); + } + } + } + + const std::vector& GetRecentFiles() const { + return recent_files_; + } + + private: + std::string filename_; + std::vector recent_files_; }; } // namespace app diff --git a/src/app/core/testable.h b/src/app/core/testable.h deleted file mode 100644 index 1199f3de..00000000 --- a/src/app/core/testable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef YAZE_APP_CORE_TESTABLE_H -#define YAZE_APP_CORE_TESTABLE_H - -#include - -namespace yaze { -namespace app { -namespace core { -class GuiTestable { - public: - virtual void RegisterTests(ImGuiTestEngine* e) = 0; - - ImGuiTestEngine* test_engine; -}; -} // namespace core -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_CORE_TESTABLE_H \ No newline at end of file diff --git a/src/app/core/utils/file_util.cc b/src/app/core/utils/file_util.cc new file mode 100644 index 00000000..1b332a9a --- /dev/null +++ b/src/app/core/utils/file_util.cc @@ -0,0 +1,74 @@ +#include "file_util.h" + +#if defined(_WIN32) +#include +#else +#include +#include +#endif + +#include +#include + +namespace yaze { +namespace app { +namespace core { + +std::string GetFileExtension(const std::string &filename) { + size_t dot = filename.find_last_of("."); + if (dot == std::string::npos) { + return ""; + } + return filename.substr(dot + 1); +} + +std::string GetFileName(const std::string &filename) { + size_t slash = filename.find_last_of("/"); + if (slash == std::string::npos) { + return filename; + } + return filename.substr(slash + 1); +} + +std::string LoadFile(const std::string &filename, Platform platform) { + std::string contents; + std::string filepath = GetConfigDirectory(platform) + "/" + filename; + std::ifstream file(filepath); + if (file.is_open()) { + std::stringstream buffer; + buffer << file.rdbuf(); + contents = buffer.str(); + file.close(); + } + return contents; +} + +void SaveFile(const std::string &filename, const std::string &contents, + Platform platform) { + std::string filepath = GetConfigDirectory(platform) + "/" + filename; + std::ofstream file(filepath); + if (file.is_open()) { + file << contents; + file.close(); + } +} + +std::string GetConfigDirectory(Platform platform) { + std::string config_directory = ".yaze"; + switch (platform) { + case Platform::kWindows: + config_directory = "~/AppData/Roaming/yaze"; + break; + case Platform::kMacOS: + case Platform::kLinux: + config_directory = "~/.config/yaze"; + break; + default: + break; + } + return config_directory; +} + +} // namespace core +} // namespace app +} // namespace yaze diff --git a/src/app/core/utils/file_util.h b/src/app/core/utils/file_util.h new file mode 100644 index 00000000..67dd7ff1 --- /dev/null +++ b/src/app/core/utils/file_util.h @@ -0,0 +1,24 @@ +#ifndef YAZE_APP_CORE_UTILS_FILE_UTIL_H +#define YAZE_APP_CORE_UTILS_FILE_UTIL_H + +#include + +namespace yaze { +namespace app { +namespace core { + +enum class Platform { kUnknown, kMacOS, kiOS, kWindows, kLinux }; + +std::string GetFileExtension(const std::string &filename); +std::string GetFileName(const std::string &filename); +std::string LoadFile(const std::string &filename, Platform platform); +std::string GetConfigDirectory(Platform platform); + +void SaveFile(const std::string &filename, const std::string &data, + Platform platform); + +} // namespace core +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_CORE_UTILS_FILE_UTIL_H diff --git a/src/app/core/utils/sdl_deleter.h b/src/app/core/utils/sdl_deleter.h new file mode 100644 index 00000000..8fd4100d --- /dev/null +++ b/src/app/core/utils/sdl_deleter.h @@ -0,0 +1,40 @@ +#ifndef YAZE_APP_CORE_UTILS_SDL_DELETER_H_ +#define YAZE_APP_CORE_UTILS_SDL_DELETER_H_ + +#include + +namespace yaze { +namespace app { +namespace core { + +/** + * @brief Deleter for SDL_Window and SDL_Renderer. + */ +struct SDL_Deleter { + void operator()(SDL_Window *p) const { SDL_DestroyWindow(p); } + void operator()(SDL_Renderer *p) const { SDL_DestroyRenderer(p); } +}; + +/** + * @brief Deleter for SDL_Texture. + */ +struct SDL_Texture_Deleter { + void operator()(SDL_Texture *p) const { + SDL_DestroyTexture(p); + } +}; + +/** + * @brief Deleter for SDL_Surface. + */ +struct SDL_Surface_Deleter { + void operator()(SDL_Surface *p) const { + SDL_FreeSurface(p); + } +}; + +} // namespace core +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_CORE_UTILS_SDL_DELETER_H_ diff --git a/src/app/editor/code/assembly_editor.cc b/src/app/editor/code/assembly_editor.cc index 2f783b8e..d833ce05 100644 --- a/src/app/editor/code/assembly_editor.cc +++ b/src/app/editor/code/assembly_editor.cc @@ -1,16 +1,17 @@ #include "assembly_editor.h" #include "ImGuiColorTextEdit/TextEditor.h" - +#include "ImGuiFileDialog/ImGuiFileDialog.h" +#include "absl/strings/str_cat.h" #include "app/core/platform/file_dialog.h" #include "app/gui/icons.h" -#include "app/gui/input.h" -#include "core/constants.h" namespace yaze { namespace app { namespace editor { +using core::FileDialogWrapper; + namespace { std::vector RemoveIgnoredFiles( @@ -57,11 +58,11 @@ core::FolderItem LoadFolder(const std::string& folder) { auto root_files = FileDialogWrapper::GetFilesInFolder(current_folder.name); current_folder.files = RemoveIgnoredFiles(root_files, ignored_files); - for (const auto& folder : + for (const auto& subfolder : FileDialogWrapper::GetSubdirectoriesInFolder(current_folder.name)) { core::FolderItem folder_item; - folder_item.name = folder; - std::string full_folder = current_folder.name + "/" + folder; + folder_item.name = subfolder; + std::string full_folder = current_folder.name + "/" + subfolder; auto folder_files = FileDialogWrapper::GetFilesInFolder(full_folder); for (const auto& files : folder_files) { // Remove subdirectory files diff --git a/src/app/editor/code/assembly_editor.h b/src/app/editor/code/assembly_editor.h index 35022c99..192f9327 100644 --- a/src/app/editor/code/assembly_editor.h +++ b/src/app/editor/code/assembly_editor.h @@ -1,15 +1,11 @@ #ifndef YAZE_APP_EDITOR_ASSEMBLY_EDITOR_H #define YAZE_APP_EDITOR_ASSEMBLY_EDITOR_H -#include "ImGuiColorTextEdit/TextEditor.h" -#include "ImGuiFileDialog/ImGuiFileDialog.h" - -#include -#include #include +#include "ImGuiColorTextEdit/TextEditor.h" #include "app/core/common.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gui/style.h" namespace yaze { diff --git a/src/app/editor/code/memory_editor.h b/src/app/editor/code/memory_editor.h index 7b49cbea..01ecc981 100644 --- a/src/app/editor/code/memory_editor.h +++ b/src/app/editor/code/memory_editor.h @@ -1,27 +1,20 @@ #ifndef YAZE_APP_EDITOR_CODE_MEMORY_EDITOR_H #define YAZE_APP_EDITOR_CODE_MEMORY_EDITOR_H -#include "imgui/imgui.h" -#include "imgui/misc/cpp/imgui_stdlib.h" -#include "imgui_memory_editor.h" - #include "absl/status/status.h" -#include "app/core/common.h" #include "app/core/constants.h" #include "app/core/platform/file_dialog.h" #include "app/core/project.h" #include "app/editor/code/assembly_editor.h" #include "app/editor/code/memory_editor.h" #include "app/editor/dungeon/dungeon_editor.h" +#include "app/editor/editor.h" #include "app/editor/graphics/graphics_editor.h" #include "app/editor/graphics/palette_editor.h" #include "app/editor/graphics/screen_editor.h" #include "app/editor/music/music_editor.h" -#include "app/editor/overworld_editor.h" +#include "app/editor/overworld/overworld_editor.h" #include "app/editor/sprite/sprite_editor.h" -#include "app/editor/utils/editor.h" -#include "app/editor/utils/gfx_context.h" -#include "app/editor/utils/recent_files.h" #include "app/emu/emulator.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" @@ -30,6 +23,9 @@ #include "app/gui/input.h" #include "app/gui/style.h" #include "app/rom.h" +#include "imgui/imgui.h" +#include "imgui/misc/cpp/imgui_stdlib.h" +#include "imgui_memory_editor.h" namespace yaze { namespace app { @@ -46,7 +42,7 @@ struct MemoryEditorWithDiffChecker : public SharedRom { static Rom comparison_rom; ImGui::Begin("Hex Editor", &show_memory_editor); if (ImGui::Button("Compare Rom")) { - auto file_name = FileDialogWrapper::ShowOpenFileDialog(); + auto file_name = core::FileDialogWrapper::ShowOpenFileDialog(); PRINT_IF_ERROR(comparison_rom.LoadFromFile(file_name)); show_compare_rom = true; } diff --git a/src/app/editor/dungeon/dungeon_editor.cc b/src/app/editor/dungeon/dungeon_editor.cc index c23e5d47..b6b42d3d 100644 --- a/src/app/editor/dungeon/dungeon_editor.cc +++ b/src/app/editor/dungeon/dungeon_editor.cc @@ -1,9 +1,7 @@ #include "dungeon_editor.h" -#include "imgui/imgui.h" - -#include "app/core/common.h" -#include "app/core/labeling.h" +#include "absl/container/flat_hash_map.h" +#include "app/core/platform/renderer.h" #include "app/gfx/snes_palette.h" #include "app/gui/canvas.h" #include "app/gui/color.h" @@ -11,13 +9,15 @@ #include "app/gui/input.h" #include "app/rom.h" #include "app/zelda3/dungeon/object_names.h" -#include "app/zelda3/dungeon/room_names.h" +#include "imgui/imgui.h" #include "zelda3/dungeon/room.h" namespace yaze { namespace app { namespace editor { +using core::Renderer; + using ImGui::BeginChild; using ImGui::BeginTabBar; using ImGui::BeginTabItem; @@ -50,21 +50,22 @@ absl::Status DungeonEditor::Update() { refresh_graphics_ = false; } - TAB_BAR("##DungeonEditorTabBar") - TAB_ITEM("Room Editor") - status_ = UpdateDungeonRoomView(); - END_TAB_ITEM() - TAB_ITEM("Usage Statistics") - if (is_loaded_) { - static bool calc_stats = false; - if (!calc_stats) { - CalculateUsageStats(); - calc_stats = true; + if (ImGui::BeginTabBar("##DungeonEditorTabBar")) { + TAB_ITEM("Room Editor") + status_ = UpdateDungeonRoomView(); + END_TAB_ITEM() + TAB_ITEM("Usage Statistics") + if (is_loaded_) { + static bool calc_stats = false; + if (!calc_stats) { + CalculateUsageStats(); + calc_stats = true; + } + DrawUsageStats(); } - DrawUsageStats(); + END_TAB_ITEM() + ImGui::EndTabBar(); } - END_TAB_ITEM() - END_TAB_BAR() return absl::OkStatus(); } @@ -72,7 +73,7 @@ absl::Status DungeonEditor::Update() { absl::Status DungeonEditor::Initialize() { auto dungeon_man_pal_group = rom()->palette_group().dungeon_main; for (int i = 0; i < 0x100 + 40; i++) { - rooms_.emplace_back(zelda3::dungeon::Room(i)); + rooms_.emplace_back(zelda3::dungeon::Room(/*room_id=*/i)); rooms_[i].LoadHeader(); rooms_[i].LoadRoomFromROM(); if (flags()->kDrawDungeonRoomGraphics) { @@ -107,7 +108,7 @@ absl::Status DungeonEditor::Initialize() { ASSIGN_OR_RETURN(current_palette_group_, gfx::CreatePaletteGroupFromLargePalette(full_palette_)); - graphics_bin_ = *rom()->mutable_bitmap_manager(); + graphics_bin_ = rom()->gfx_sheets(); // Create a vector of pointers to the current block bitmaps for (int block : rooms_[current_room_id_].blocks()) { room_gfx_sheets_.emplace_back(&graphics_bin_[block]); @@ -120,14 +121,14 @@ absl::Status DungeonEditor::RefreshGraphics() { int block = rooms_[current_room_id_].blocks()[i]; RETURN_IF_ERROR(graphics_bin_[block].ApplyPaletteWithTransparent( current_palette_group_[current_palette_id_], 0)); - rom()->UpdateBitmap(&graphics_bin_[block], true); + Renderer::GetInstance().UpdateBitmap(&graphics_bin_[block]); } auto sprites_aux1_pal_group = rom()->palette_group().sprites_aux1; for (int i = 9; i < 16; i++) { int block = rooms_[current_room_id_].blocks()[i]; RETURN_IF_ERROR(graphics_bin_[block].ApplyPaletteWithTransparent( sprites_aux1_pal_group[current_palette_id_], 0)); - rom()->UpdateBitmap(&graphics_bin_[block], true); + Renderer::GetInstance().UpdateBitmap(&graphics_bin_[block]); } return absl::OkStatus(); } @@ -195,14 +196,15 @@ absl::Status DungeonEditor::UpdateDungeonRoomView() { TableNextRow(); TableNextColumn(); - TAB_BAR("##DungeonRoomTabBar"); - TAB_ITEM("Rooms"); - DrawRoomSelector(); - END_TAB_ITEM(); - TAB_ITEM("Entrances"); - DrawEntranceSelector(); - END_TAB_ITEM(); - END_TAB_BAR(); + if (ImGui::BeginTabBar("##DungeonRoomTabBar")) { + TAB_ITEM("Rooms"); + DrawRoomSelector(); + END_TAB_ITEM(); + TAB_ITEM("Entrances"); + DrawEntranceSelector(); + END_TAB_ITEM(); + ImGui::EndTabBar(); + } TableNextColumn(); DrawDungeonTabView(); @@ -320,7 +322,7 @@ void DungeonEditor::DrawRoomSelector() { for (const auto each_room_name : zelda3::dungeon::kRoomNames) { rom()->resource_label()->SelectableLabelWithNameEdit( current_room_id_ == i, "Dungeon Room Names", - core::UppercaseHexByte(i), zelda3::dungeon::kRoomNames[i].data()); + core::UppercaseHexByte(i), each_room_name.data()); if (ImGui::IsItemClicked()) { // TODO: Jump to tab if room is already open current_room_id_ = i; @@ -498,7 +500,7 @@ void DungeonEditor::DrawRoomGraphics() { top_left_y = room_gfx_canvas_.zero_point().y + height * current_block; } room_gfx_canvas_.draw_list()->AddImage( - (void*)graphics_bin_[block].texture(), + (ImTextureID)(intptr_t)graphics_bin_[block].texture(), ImVec2(room_gfx_canvas_.zero_point().x + 2, top_left_y), ImVec2(room_gfx_canvas_.zero_point().x + 0x100, room_gfx_canvas_.zero_point().y + offset)); @@ -547,7 +549,7 @@ void DungeonEditor::DrawObjectRenderer() { current_object_ = i; object_renderer_.LoadObject(i, rooms_[current_room_id_].mutable_blocks()); - rom()->RenderBitmap(object_renderer_.bitmap()); + Renderer::GetInstance().RenderBitmap(object_renderer_.bitmap()); object_loaded_ = true; } i += 1; @@ -827,4 +829,4 @@ void DungeonEditor::DrawUsageGrid() { } // namespace editor } // namespace app -} // namespace yaze \ No newline at end of file +} // namespace yaze diff --git a/src/app/editor/dungeon/dungeon_editor.h b/src/app/editor/dungeon/dungeon_editor.h index fdf52529..4a8aea3d 100644 --- a/src/app/editor/dungeon/dungeon_editor.h +++ b/src/app/editor/dungeon/dungeon_editor.h @@ -1,16 +1,14 @@ #ifndef YAZE_APP_EDITOR_DUNGEONEDITOR_H #define YAZE_APP_EDITOR_DUNGEONEDITOR_H -#include "imgui/imgui.h" - #include "app/core/common.h" -#include "app/core/labeling.h" +#include "absl/container/flat_hash_map.h" #include "app/editor/graphics/gfx_group_editor.h" #include "app/editor/graphics/palette_editor.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gui/canvas.h" -#include "app/gui/icons.h" #include "app/rom.h" +#include "imgui/imgui.h" #include "zelda3/dungeon/room.h" #include "zelda3/dungeon/room_entrance.h" #include "zelda3/dungeon/room_object.h" @@ -100,7 +98,6 @@ class DungeonEditor : public Editor, bool object_loaded_ = false; bool palette_showing_ = false; bool refresh_graphics_ = false; - bool show_object_render_ = false; uint16_t current_entrance_id_ = 0; uint16_t current_room_id_ = 0; @@ -120,12 +117,11 @@ class DungeonEditor : public Editor, gui::Canvas object_canvas_; gfx::Bitmap room_gfx_bmp_; - gfx::BitmapManager graphics_bin_; + std::array graphics_bin_; std::vector room_gfx_sheets_; std::vector rooms_; std::vector entrances_; - std::vector room_graphics_; zelda3::dungeon::DungeonObjectRenderer object_renderer_; absl::flat_hash_map spriteset_usage_; diff --git a/src/app/editor/editor.cc b/src/app/editor/editor.cc new file mode 100644 index 00000000..44055a1b --- /dev/null +++ b/src/app/editor/editor.cc @@ -0,0 +1,52 @@ +#include "editor.h" + +#include "app/core/constants.h" +#include "imgui/imgui.h" + +namespace yaze { +namespace app { +namespace editor { + +absl::Status DrawEditor(EditorLayoutParams *params) { + if (params->editor == nullptr) { + return absl::InternalError("Editor is not initialized"); + } + + // Draw the editors based on h_split and v_split in a recursive manner + if (params->v_split) { + ImGui::BeginTable("##VerticalSplitTable", 2); + + ImGui::TableNextColumn(); + if (params->left) + RETURN_IF_ERROR(DrawEditor(params->left)); + + ImGui::TableNextColumn(); + if (params->right) + RETURN_IF_ERROR(DrawEditor(params->right)); + + ImGui::EndTable(); + } else if (params->h_split) { + ImGui::BeginTable("##HorizontalSplitTable", 1); + + ImGui::TableNextColumn(); + if (params->top) + RETURN_IF_ERROR(DrawEditor(params->top)); + + ImGui::TableNextColumn(); + if (params->bottom) + RETURN_IF_ERROR(DrawEditor(params->bottom)); + + ImGui::EndTable(); + } else { + // No split, just draw the single editor + ImGui::Text("%s Editor", + kEditorNames[static_cast(params->editor->type())]); + RETURN_IF_ERROR(params->editor->Update()); + } + + return absl::OkStatus(); +} + +} // namespace editor +} // namespace app +} // namespace yaze diff --git a/src/app/editor/CMakeLists.txt b/src/app/editor/editor.cmake similarity index 63% rename from src/app/editor/CMakeLists.txt rename to src/app/editor/editor.cmake index 30b76767..2a0516f3 100644 --- a/src/app/editor/CMakeLists.txt +++ b/src/app/editor/editor.cmake @@ -1,21 +1,21 @@ set( YAZE_APP_EDITOR_SRC + app/editor/editor.cc + app/editor/editor_manager.cc app/editor/dungeon/dungeon_editor.cc - app/editor/master_editor.cc - app/editor/master_editor_test.cc - app/editor/settings_editor.cc - app/editor/overworld_editor.cc + app/editor/overworld/overworld_editor.cc app/editor/sprite/sprite_editor.cc app/editor/music/music_editor.cc app/editor/message/message_editor.cc - app/editor/message/message_editor_test.cc + app/editor/message/message_data.cc app/editor/code/assembly_editor.cc app/editor/graphics/screen_editor.cc app/editor/graphics/graphics_editor.cc app/editor/graphics/palette_editor.cc app/editor/graphics/tile16_editor.cc app/editor/graphics/gfx_group_editor.cc - app/editor/utils/gfx_context.cc - app/editor/overworld/refresh.cc app/editor/overworld/entity.cc -) \ No newline at end of file + app/editor/system/settings_editor.cc + app/editor/system/command_manager.cc + app/editor/system/extension_manager.cc +) diff --git a/src/app/editor/utils/editor.h b/src/app/editor/editor.h similarity index 50% rename from src/app/editor/utils/editor.h rename to src/app/editor/editor.h index 872388ed..685b487b 100644 --- a/src/app/editor/utils/editor.h +++ b/src/app/editor/editor.h @@ -1,7 +1,14 @@ #ifndef YAZE_APP_CORE_EDITOR_H #define YAZE_APP_CORE_EDITOR_H +#include + #include "absl/status/status.h" +#include "app/editor/system/command_manager.h" +#include "app/editor/system/constant_manager.h" +#include "app/editor/system/extension_manager.h" +#include "app/editor/system/history_manager.h" +#include "app/editor/system/resource_manager.h" namespace yaze { namespace app { @@ -12,6 +19,14 @@ namespace app { */ namespace editor { +struct EditorContext { + ConstantManager constant_manager; + CommandManager command_manager; + ExtensionManager extension_manager; + HistoryManager history_manager; + ResourceManager resource_manager; +}; + enum class EditorType { kAssembly, kDungeon, @@ -25,7 +40,7 @@ enum class EditorType { kSettings, }; -constexpr std::array kEditorNames = { +constexpr std::array kEditorNames = { "Assembly", "Dungeon", "Graphics", "Music", "Overworld", "Palette", "Screen", "Sprite", "Message", "Settings", }; @@ -56,10 +71,35 @@ class Editor { protected: EditorType type_; + EditorContext context_; }; +/** + * @brief Dynamic Editor Layout Parameters + */ +typedef struct EditorLayoutParams { + bool v_split; + bool h_split; + int v_split_pos; + int h_split_pos; + Editor *editor = nullptr; + EditorLayoutParams *left = nullptr; + EditorLayoutParams *right = nullptr; + EditorLayoutParams *top = nullptr; + EditorLayoutParams *bottom = nullptr; + + EditorLayoutParams() { + v_split = false; + h_split = false; + v_split_pos = 0; + h_split_pos = 0; + } +} EditorLayoutParams; + +absl::Status DrawEditor(EditorLayoutParams *params); + } // namespace editor } // namespace app } // namespace yaze -#endif // YAZE_APP_CORE_EDITOR_H \ No newline at end of file +#endif // YAZE_APP_CORE_EDITOR_H diff --git a/src/app/editor/master_editor.cc b/src/app/editor/editor_manager.cc similarity index 79% rename from src/app/editor/master_editor.cc rename to src/app/editor/editor_manager.cc index 94bce89d..c1e0eb80 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/editor_manager.cc @@ -1,48 +1,39 @@ -#include "master_editor.h" - -#include "ImGuiColorTextEdit/TextEditor.h" -#include "ImGuiFileDialog/ImGuiFileDialog.h" -#include "abseil-cpp/absl/strings/match.h" -#include "imgui/backends/imgui_impl_sdl2.h" -#include "imgui/backends/imgui_impl_sdlrenderer2.h" -#include "imgui/imgui.h" -#include "imgui/misc/cpp/imgui_stdlib.h" -#include "imgui_internal.h" -#include "imgui_memory_editor.h" +#include "editor_manager.h" #include "absl/status/status.h" -#include "app/core/common.h" +#include "absl/strings/match.h" #include "app/core/constants.h" #include "app/core/platform/file_dialog.h" +#include "app/core/project.h" #include "app/editor/code/assembly_editor.h" #include "app/editor/dungeon/dungeon_editor.h" #include "app/editor/graphics/graphics_editor.h" #include "app/editor/graphics/palette_editor.h" #include "app/editor/graphics/screen_editor.h" #include "app/editor/music/music_editor.h" -#include "app/editor/overworld_editor.h" +#include "app/editor/overworld/overworld_editor.h" #include "app/editor/sprite/sprite_editor.h" -#include "app/editor/utils/flags.h" -#include "app/editor/utils/recent_files.h" +#include "app/editor/system/flags.h" #include "app/emu/emulator.h" -#include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" -#include "app/gui/canvas.h" #include "app/gui/icons.h" #include "app/gui/input.h" #include "app/gui/style.h" #include "app/rom.h" +#include "editor/editor.h" +#include "imgui/imgui.h" +#include "imgui/misc/cpp/imgui_stdlib.h" namespace yaze { namespace app { namespace editor { using namespace ImGui; +using core::FileDialogWrapper; namespace { - -bool BeginCentered(const char *name) { - ImGuiIO const &io = GetIO(); + +bool BeginCentered(const char* name) { + ImGuiIO const& io = GetIO(); ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f); SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGuiWindowFlags flags = @@ -58,21 +49,18 @@ bool IsEditorActive(Editor* editor, std::vector& active_editors) { } // namespace -void MasterEditor::SetupScreen(std::shared_ptr renderer, - std::string filename) { - sdl_renderer_ = renderer; - rom()->SetupRenderer(renderer); +void EditorManager::SetupScreen(std::string filename) { if (!filename.empty()) { PRINT_IF_ERROR(rom()->LoadFromFile(filename)); } overworld_editor_.InitializeZeml(); + InitializeCommands(); } -absl::Status MasterEditor::Update() { +absl::Status EditorManager::Update() { ManageKeyboardShortcuts(); DrawYazeMenu(); - DrawFileDialog(); DrawStatusPopup(); DrawAboutPopup(); DrawInfoPopup(); @@ -85,12 +73,15 @@ absl::Status MasterEditor::Update() { rom_assets_loaded_ = true; } - ManageActiveEditors(); + if (dynamic_layout_) + RETURN_IF_ERROR(DrawDynamicLayout()) + else + ManageActiveEditors(); return absl::OkStatus(); } -void MasterEditor::ManageActiveEditors() { +void EditorManager::ManageActiveEditors() { // Show popup pane to select an editor to add static bool show_add_editor = false; if (show_add_editor) OpenPopup("AddEditor"); @@ -253,16 +244,23 @@ void MasterEditor::ManageActiveEditors() { } } -void MasterEditor::ManageKeyboardShortcuts() { +absl::Status EditorManager::DrawDynamicLayout() { + // Dynamic layout for multiple editors to be open at once + // Allows for tiling and resizing of editors using ImGui + return DrawEditor(&root_layout_); +} + +void EditorManager::ManageKeyboardShortcuts() { bool ctrl_or_super = (GetIO().KeyCtrl || GetIO().KeySuper); + editor_context_.command_manager.ShowWhichKey(); + // If CMD + R is pressed, reload the top result of recent files if (IsKeyDown(ImGuiKey_R) && ctrl_or_super) { static RecentFilesManager manager("recent_files.txt"); manager.Load(); if (!manager.GetRecentFiles().empty()) { auto front = manager.GetRecentFiles().front(); - std::cout << "Reloading: " << front << std::endl; OpenRomOrProject(front); } } @@ -311,55 +309,113 @@ void MasterEditor::ManageKeyboardShortcuts() { } } -void MasterEditor::DrawFileDialog() { - gui::FileDialogPipeline("ChooseFileDlgKey", ".sfc,.smc", std::nullopt, [&]() { - std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); - status_ = rom()->LoadFromFile(filePathName); - static RecentFilesManager manager("recent_files.txt"); +void EditorManager::InitializeCommands() { + if (root_layout_.editor == nullptr) { + root_layout_.editor = &overworld_editor_; + } - // Load existing recent files - manager.Load(); + // New editor popup for window management commands + static EditorLayoutParams new_layout; + if (ImGui::BeginPopup("NewEditor")) { + ImGui::Text("New Editor"); + ImGui::Separator(); + if (ImGui::Button("Overworld")) { + new_layout.editor = &overworld_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Dungeon")) { + new_layout.editor = &dungeon_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Graphics")) { + new_layout.editor = &graphics_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Music")) { + new_layout.editor = &music_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Palette")) { + new_layout.editor = &palette_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Screen")) { + new_layout.editor = &screen_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Sprite")) { + new_layout.editor = &sprite_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Code")) { + new_layout.editor = &assembly_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Settings")) { + new_layout.editor = &settings_editor_; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Message")) { + new_layout.editor = &message_editor_; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } - // Add a new file - manager.AddFile(filePathName); - - // Save the updated list - manager.Save(); - }); + editor_context_.command_manager.RegisterPrefix("window", 'w', + "window management", ""); + editor_context_.command_manager.RegisterSubcommand( + "window", "vsplit", '/', "vertical split", + "split windows vertically and place editor in new window", [this]() { + ImGui::OpenPopup("NewEditor"); + root_layout_.v_split = true; + }); + editor_context_.command_manager.RegisterSubcommand( + "window", "hsplit", '-', "horizontal split", + "split windows horizontally and place editor in new window", [this]() { + ImGui::OpenPopup("NewEditor"); + root_layout_.h_split = true; + }); + editor_context_.command_manager.RegisterSubcommand( + "window", "close", 'd', "close", "close the current editor", [this]() { + if (root_layout_.editor != nullptr) { + root_layout_.editor = nullptr; + } + }); } -void MasterEditor::DrawStatusPopup() { +void EditorManager::DrawStatusPopup() { + static absl::Status prev_status; if (!status_.ok()) { show_status_ = true; - prev_status_ = status_; + prev_status = status_; } if (show_status_ && (BeginCentered("StatusWindow"))) { Text("%s", ICON_MD_ERROR); - Text("%s", prev_status_.ToString().c_str()); + Text("%s", prev_status.ToString().c_str()); Spacing(); NextColumn(); Columns(1); Separator(); NewLine(); SameLine(128); - if (Button("OK", gui::kDefaultModalSize) || - IsKeyPressed(GetKeyIndex(ImGuiKey_Space))) { + if (Button("OK", gui::kDefaultModalSize) || IsKeyPressed(ImGuiKey_Space)) { show_status_ = false; status_ = absl::OkStatus(); } SameLine(); if (Button(ICON_MD_CONTENT_COPY, ImVec2(50, 0))) { - SetClipboardText(prev_status_.ToString().c_str()); + SetClipboardText(prev_status.ToString().c_str()); } End(); } } -void MasterEditor::DrawAboutPopup() { +void EditorManager::DrawAboutPopup() { if (about_) OpenPopup("About"); if (BeginPopupModal("About", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { - Text("Yet Another Zelda3 Editor - v%.2f", core::kYazeVersion); + Text("Yet Another Zelda3 Editor - v%s", core::kYazeVersion.data()); Text("Written by: scawful"); Spacing(); Text("Special Thanks: Zarby89, JaredBrian"); @@ -373,15 +429,15 @@ void MasterEditor::DrawAboutPopup() { } } -void MasterEditor::DrawInfoPopup() { +void EditorManager::DrawInfoPopup() { if (rom_info_) OpenPopup("ROM Information"); if (BeginPopupModal("ROM Information", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { - Text("Title: %s", rom()->title()); - Text("ROM Size: %ld", rom()->size()); + Text("Title: %s", rom()->title().c_str()); + Text("ROM Size: %s", core::UppercaseHexLongLong(rom()->size()).c_str()); if (Button("Close", gui::kDefaultModalSize) || - IsKeyPressed(GetKeyIndex(ImGuiKey_Space))) { + IsKeyPressed(ImGuiKey_Escape)) { rom_info_ = false; CloseCurrentPopup(); } @@ -389,33 +445,19 @@ void MasterEditor::DrawInfoPopup() { } } -void MasterEditor::DrawYazeMenu() { +void EditorManager::DrawYazeMenu() { static bool show_display_settings = false; - static bool show_command_line_interface = false; if (BeginMenuBar()) { - DrawFileMenu(); - DrawEditMenu(); - DrawViewMenu(); - DrawTestMenu(); - DrawProjectMenu(); - DrawHelpMenu(); - + DrawYazeMenuBar(); SameLine(GetWindowWidth() - GetStyle().ItemSpacing.x - - CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 150); - // Modify the style of the button to have no background color + CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 110); PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); if (Button(ICON_MD_DISPLAY_SETTINGS)) { show_display_settings = !show_display_settings; } - - if (Button(ICON_MD_TERMINAL)) { - show_command_line_interface = !show_command_line_interface; - } PopStyleColor(); - - Text("%s", absl::StrCat("yaze v", core::kYazeVersion).c_str()); - + Text("yaze v%s", core::kYazeVersion.data()); EndMenuBar(); } @@ -424,27 +466,9 @@ void MasterEditor::DrawYazeMenu() { gui::DrawDisplaySettings(); End(); } - - if (show_command_line_interface) { - Begin("Command Line Interface", &show_command_line_interface, - ImGuiWindowFlags_None); - Text("Enter a command:"); - End(); - } } -void MasterEditor::OpenRomOrProject(const std::string& filename) { - if (absl::StrContains(filename, ".yaze")) { - status_ = current_project_.Open(filename); - if (status_.ok()) { - status_ = OpenProject(); - } - } else { - status_ = rom()->LoadFromFile(filename); - } -} - -void MasterEditor::DrawFileMenu() { +void EditorManager::DrawYazeMenuBar() { static bool save_as_menu = false; static bool new_project_menu = false; @@ -476,7 +500,6 @@ void MasterEditor::DrawFileMenu() { MENU_ITEM("Save As..") { save_as_menu = true; } if (rom()->is_loaded()) { - MENU_ITEM("Reload") { status_ = rom()->Reload(); } MENU_ITEM("Close") { status_ = rom()->Close(); rom_assets_loaded_ = false; @@ -492,8 +515,8 @@ void MasterEditor::DrawFileMenu() { } if (MenuItem("Open Project")) { // Open an existing project - status_ = - current_project_.Open(FileDialogWrapper::ShowOpenFileDialog()); + status_ = current_project_.Open( + core::FileDialogWrapper::ShowOpenFileDialog()); if (status_.ok()) { status_ = OpenProject(); } @@ -582,9 +605,7 @@ void MasterEditor::DrawFileMenu() { } End(); } -} -void MasterEditor::DrawEditMenu() { if (BeginMenu("Edit")) { MENU_ITEM2("Undo", "Ctrl+Z") { status_ = current_editor_->Undo(); } MENU_ITEM2("Redo", "Ctrl+Y") { status_ = current_editor_->Redo(); } @@ -593,12 +614,10 @@ void MasterEditor::DrawEditMenu() { MENU_ITEM2("Copy", "Ctrl+C") { status_ = current_editor_->Copy(); } MENU_ITEM2("Paste", "Ctrl+V") { status_ = current_editor_->Paste(); } Separator(); - MENU_ITEM2("Find", "Ctrl+F") {} + MENU_ITEM2("Find", "Ctrl+F") { status_ = current_editor_->Find(); } EndMenu(); } -} -void MasterEditor::DrawViewMenu() { static bool show_imgui_metrics = false; static bool show_memory_editor = false; static bool show_asm_editor = false; @@ -606,28 +625,17 @@ void MasterEditor::DrawViewMenu() { static bool show_palette_editor = false; static bool show_emulator = false; + if (show_imgui_demo) ShowDemoWindow(); + if (show_imgui_metrics) ShowMetricsWindow(&show_imgui_metrics); + if (show_memory_editor) memory_editor_.Update(show_memory_editor); + if (show_asm_editor) assembly_editor_.Update(show_asm_editor); + if (show_emulator) { Begin("Emulator", &show_emulator, ImGuiWindowFlags_MenuBar); emulator_.Run(); End(); } - if (show_imgui_metrics) { - ShowMetricsWindow(&show_imgui_metrics); - } - - if (show_memory_editor) { - memory_editor_.Update(show_memory_editor); - } - - if (show_imgui_demo) { - ShowDemoWindow(); - } - - if (show_asm_editor) { - assembly_editor_.Update(show_asm_editor); - } - if (show_palette_editor) { Begin("Palette Editor", &show_palette_editor); status_ = palette_editor_.Update(); @@ -635,6 +643,7 @@ void MasterEditor::DrawViewMenu() { } if (BeginMenu("View")) { + MenuItem("Dynamic Layout", nullptr, &dynamic_layout_); MenuItem("Emulator", nullptr, &show_emulator); Separator(); MenuItem("Memory Editor", nullptr, &show_memory_editor); @@ -647,23 +656,9 @@ void MasterEditor::DrawViewMenu() { MenuItem("ImGui Metrics", nullptr, &show_imgui_metrics); EndMenu(); } -} -void MasterEditor::DrawTestMenu() { - static bool show_tests_ = false; - - if (BeginMenu("Tests")) { - MenuItem("Run Tests", nullptr, &show_tests_); - EndMenu(); - } - -} - -void MasterEditor::DrawProjectMenu() { static bool show_resource_label_manager = false; - if (current_project_.project_opened_) { - // Project Menu if (BeginMenu("Project")) { Text("Name: %s", current_project_.name.c_str()); Text("ROM: %s", current_project_.rom_filename_.c_str()); @@ -674,16 +669,7 @@ void MasterEditor::DrawProjectMenu() { EndMenu(); } } - if (show_resource_label_manager) { - rom()->resource_label()->DisplayLabels(&show_resource_label_manager); - if (current_project_.project_opened_ && - !current_project_.labels_filename_.empty()) { - current_project_.labels_filename_ = rom()->resource_label()->filename_; - } - } -} -void MasterEditor::DrawHelpMenu() { static bool open_rom_help = false; static bool open_supported_features = false; static bool open_manage_project = false; @@ -752,11 +738,10 @@ void MasterEditor::DrawHelpMenu() { Text("Project Menu"); Text("Create a new project or open an existing one."); Text("Save the project to save the current state of the project."); - Text( + TextWrapped( "To save a project, you need to first open a ROM and initialize your " "code path and labels file. Label resource manager can be found in " - "the " - "View menu. Code path is set in the Code editor after opening a " + "the View menu. Code path is set in the Code editor after opening a " "folder."); if (Button("Close", gui::kDefaultModalSize)) { @@ -765,58 +750,51 @@ void MasterEditor::DrawHelpMenu() { } EndPopup(); } + + if (show_resource_label_manager) { + rom()->resource_label()->DisplayLabels(&show_resource_label_manager); + if (current_project_.project_opened_ && + !current_project_.labels_filename_.empty()) { + current_project_.labels_filename_ = rom()->resource_label()->filename_; + } + } } -void MasterEditor::LoadRom() { - if (flags()->kNewFileDialogWrapper) { - auto file_name = FileDialogWrapper::ShowOpenFileDialog(); - PRINT_IF_ERROR(rom()->LoadFromFile(file_name)); +void EditorManager::LoadRom() { + auto file_name = FileDialogWrapper::ShowOpenFileDialog(); + auto load_rom = rom()->LoadFromFile(file_name); + if (load_rom.ok()) { static RecentFilesManager manager("recent_files.txt"); manager.Load(); manager.AddFile(file_name); manager.Save(); - } else { - ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open ROM", - ".sfc,.smc", "."); } } -void MasterEditor::SaveRom() { +void EditorManager::SaveRom() { if (flags()->kSaveDungeonMaps) { status_ = screen_editor_.SaveDungeonMaps(); RETURN_VOID_IF_ERROR(status_); } - if (flags()->overworld.kSaveOverworldMaps) { - RETURN_VOID_IF_ERROR( - status_ = overworld_editor_.overworld()->CreateTile32Tilemap()); - status_ = overworld_editor_.overworld()->SaveMap32Tiles(); - RETURN_VOID_IF_ERROR(status_); - status_ = overworld_editor_.overworld()->SaveMap16Tiles(); - RETURN_VOID_IF_ERROR(status_); - status_ = overworld_editor_.overworld()->SaveOverworldMaps(); - RETURN_VOID_IF_ERROR(status_); - } - if (flags()->overworld.kSaveOverworldEntrances) { - status_ = overworld_editor_.overworld()->SaveEntrances(); - RETURN_VOID_IF_ERROR(status_); - } - if (flags()->overworld.kSaveOverworldExits) { - status_ = overworld_editor_.overworld()->SaveExits(); - RETURN_VOID_IF_ERROR(status_); - } - if (flags()->overworld.kSaveOverworldItems) { - status_ = overworld_editor_.overworld()->SaveItems(); - RETURN_VOID_IF_ERROR(status_); - } - if (flags()->overworld.kSaveOverworldProperties) { - status_ = overworld_editor_.overworld()->SaveMapProperties(); - RETURN_VOID_IF_ERROR(status_); - } + + status_ = overworld_editor_.Save(); + RETURN_VOID_IF_ERROR(status_); status_ = rom()->SaveToFile(backup_rom_, save_new_auto_); } -absl::Status MasterEditor::OpenProject() { +void EditorManager::OpenRomOrProject(const std::string& filename) { + if (absl::StrContains(filename, ".yaze")) { + status_ = current_project_.Open(filename); + if (status_.ok()) { + status_ = OpenProject(); + } + } else { + status_ = rom()->LoadFromFile(filename); + } +} + +absl::Status EditorManager::OpenProject() { RETURN_IF_ERROR(rom()->LoadFromFile(current_project_.rom_filename_)); if (!rom()->resource_label()->LoadLabels(current_project_.labels_filename_)) { diff --git a/src/app/editor/master_editor.h b/src/app/editor/editor_manager.h similarity index 52% rename from src/app/editor/master_editor.h rename to src/app/editor/editor_manager.h index cc5e495f..cdb23019 100644 --- a/src/app/editor/master_editor.h +++ b/src/app/editor/editor_manager.h @@ -1,17 +1,9 @@ -#ifndef YAZE_APP_EDITOR_MASTER_EDITOR_H -#define YAZE_APP_EDITOR_MASTER_EDITOR_H +#ifndef YAZE_APP_EDITOR_EDITOR_MANAGER_H +#define YAZE_APP_EDITOR_EDITOR_MANAGER_H #define IMGUI_DEFINE_MATH_OPERATORS -#include "ImGuiColorTextEdit/TextEditor.h" -#include "ImGuiFileDialog/ImGuiFileDialog.h" -#include "imgui/imgui.h" -#include "imgui/misc/cpp/imgui_stdlib.h" -#include "imgui_memory_editor.h" - #include "absl/status/status.h" -#include "app/core/common.h" -#include "app/core/constants.h" #include "app/core/project.h" #include "app/editor/code/assembly_editor.h" #include "app/editor/code/memory_editor.h" @@ -21,15 +13,10 @@ #include "app/editor/graphics/screen_editor.h" #include "app/editor/message/message_editor.h" #include "app/editor/music/music_editor.h" -#include "app/editor/overworld_editor.h" -#include "app/editor/settings_editor.h" +#include "app/editor/overworld/overworld_editor.h" #include "app/editor/sprite/sprite_editor.h" -#include "app/editor/utils/gfx_context.h" +#include "app/editor/system/settings_editor.h" #include "app/emu/emulator.h" -#include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" -#include "app/gui/canvas.h" -#include "app/gui/icons.h" #include "app/gui/input.h" #include "app/rom.h" @@ -38,28 +25,19 @@ namespace app { namespace editor { /** - * @class MasterEditor - * @brief The MasterEditor class represents the main editor for a Rom in the - * Yaze application. + * @class EditorManager + * @brief The EditorManager controls the main editor window and manages the + * various editor classes. * - * This class inherits from SharedRom, GfxContext, and ExperimentFlags, and - * provides functionality for setting up the screen, updating the editor, and - * shutting down the editor. It also includes methods for drawing various menus - * and popups, saving the Rom, and managing editor-specific flags. - * - * The MasterEditor class contains instances of various editor classes such as + * The EditorManager class contains instances of various editor classes such as * AssemblyEditor, DungeonEditor, GraphicsEditor, MusicEditor, OverworldEditor, * PaletteEditor, ScreenEditor, and SpriteEditor. The current_editor_ member * variable points to the currently active editor in the tab view. * - * @note This class assumes the presence of an SDL_Renderer object for rendering - * graphics. */ -class MasterEditor : public SharedRom, - public context::GfxContext, - public core::ExperimentFlags { +class EditorManager : public SharedRom, public core::ExperimentFlags { public: - MasterEditor() { + EditorManager() { current_editor_ = &overworld_editor_; active_editors_.push_back(&overworld_editor_); active_editors_.push_back(&dungeon_editor_); @@ -67,37 +45,33 @@ class MasterEditor : public SharedRom, active_editors_.push_back(&palette_editor_); active_editors_.push_back(&sprite_editor_); active_editors_.push_back(&message_editor_); + active_editors_.push_back(&screen_editor_); } - void SetupScreen(std::shared_ptr renderer, - std::string filename = ""); + void SetupScreen(std::string filename = ""); absl::Status Update(); - auto emulator() -> emu::Emulator& { return emulator_; } + auto emulator() -> emu::Emulator & { return emulator_; } auto quit() { return quit_; } - auto overworld_editor() -> OverworldEditor& { return overworld_editor_; } private: void ManageActiveEditors(); - void ManageKeyboardShortcuts(); - void OpenRomOrProject(const std::string& filename); + absl::Status DrawDynamicLayout(); + + void ManageKeyboardShortcuts(); + void InitializeCommands(); - void DrawFileDialog(); void DrawStatusPopup(); void DrawAboutPopup(); void DrawInfoPopup(); void DrawYazeMenu(); - void DrawFileMenu(); - void DrawEditMenu(); - void DrawViewMenu(); - void DrawTestMenu(); - void DrawProjectMenu(); - void DrawHelpMenu(); + void DrawYazeMenuBar(); void LoadRom(); void SaveRom(); + void OpenRomOrProject(const std::string &filename); absl::Status OpenProject(); bool quit_ = false; @@ -107,16 +81,21 @@ class MasterEditor : public SharedRom, bool save_new_auto_ = true; bool show_status_ = false; bool rom_assets_loaded_ = false; + bool dynamic_layout_ = false; absl::Status status_; - absl::Status prev_status_; - - std::shared_ptr sdl_renderer_; emu::Emulator emulator_; - Project current_project_; + std::vector active_editors_; + std::vector active_layouts_; + EditorLayoutParams root_layout_; + + Project current_project_; + EditorContext editor_context_; + + Editor *current_editor_ = nullptr; AssemblyEditor assembly_editor_; DungeonEditor dungeon_editor_; GraphicsEditor graphics_editor_; @@ -128,14 +107,10 @@ class MasterEditor : public SharedRom, SettingsEditor settings_editor_; MessageEditor message_editor_; MemoryEditorWithDiffChecker memory_editor_; - - ImVector active_tabs_; - std::vector active_editors_; - Editor* current_editor_ = nullptr; }; } // namespace editor } // namespace app } // namespace yaze -#endif // YAZE_APP_EDITOR_MASTER_EDITOR_H +#endif // YAZE_APP_EDITOR_EDITOR_MANAGER_H diff --git a/src/app/editor/graphics/gfx_group_editor.cc b/src/app/editor/graphics/gfx_group_editor.cc index c5905cf2..b3bd3c75 100644 --- a/src/app/editor/graphics/gfx_group_editor.cc +++ b/src/app/editor/graphics/gfx_group_editor.cc @@ -1,22 +1,14 @@ #include "gfx_group_editor.h" -#include "imgui/imgui.h" - -#include - #include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "app/editor/graphics/palette_editor.h" -#include "app/editor/utils/editor.h" +#include "absl/strings/str_cat.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" #include "app/gui/color.h" -#include "app/gui/icons.h" #include "app/gui/input.h" #include "app/rom.h" -#include "app/zelda3/overworld/overworld.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -27,7 +19,6 @@ using ImGui::BeginGroup; using ImGui::BeginTabBar; using ImGui::BeginTabItem; using ImGui::BeginTable; -using ImGui::ColorButton; using ImGui::EndChild; using ImGui::EndGroup; using ImGui::EndTabBar; @@ -39,7 +30,6 @@ using ImGui::IsItemClicked; using ImGui::PopID; using ImGui::PushID; using ImGui::SameLine; -using ImGui::Selectable; using ImGui::Separator; using ImGui::SetNextItemWidth; using ImGui::TableHeadersRow; @@ -123,7 +113,7 @@ void GfxGroupEditor::DrawBlocksetViewer(bool sheet_only) { BeginGroup(); for (int i = 0; i < 8; i++) { int sheet_id = rom()->main_blockset_ids[selected_blockset_][i]; - auto sheet = rom()->bitmap_manager()[sheet_id]; + auto sheet = rom()->gfx_sheets().at(sheet_id); gui::BitmapCanvasPipeline(blockset_canvas_, sheet, 256, 0x10 * 0x04, 0x20, true, false, 22); } @@ -176,7 +166,7 @@ void GfxGroupEditor::DrawRoomsetViewer() { BeginGroup(); for (int i = 0; i < 4; i++) { int sheet_id = rom()->room_blockset_ids[selected_roomset_][i]; - auto sheet = rom()->bitmap_manager()[sheet_id]; + auto sheet = rom()->gfx_sheets().at(sheet_id); gui::BitmapCanvasPipeline(roomset_canvas_, sheet, 256, 0x10 * 0x04, 0x20, true, false, 23); } @@ -214,7 +204,7 @@ void GfxGroupEditor::DrawSpritesetViewer(bool sheet_only) { BeginGroup(); for (int i = 0; i < 4; i++) { int sheet_id = rom()->spriteset_ids[selected_spriteset_][i]; - auto sheet = rom()->bitmap_manager()[115 + sheet_id]; + auto sheet = rom()->gfx_sheets().at(115 + sheet_id); gui::BitmapCanvasPipeline(spriteset_canvas_, sheet, 256, 0x10 * 0x04, 0x20, true, false, 24); } @@ -229,7 +219,7 @@ void DrawPaletteFromPaletteGroup(gfx::SnesPalette &palette) { if (palette.empty()) { return; } - for (int n = 0; n < palette.size(); n++) { + for (size_t n = 0; n < palette.size(); n++) { PushID(n); if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y); diff --git a/src/app/editor/graphics/gfx_group_editor.h b/src/app/editor/graphics/gfx_group_editor.h index fb4d8d40..14cd4c0c 100644 --- a/src/app/editor/graphics/gfx_group_editor.h +++ b/src/app/editor/graphics/gfx_group_editor.h @@ -1,21 +1,10 @@ #ifndef YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H #define YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H -#include "imgui/imgui.h" - -#include - #include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "app/editor/utils/editor.h" -#include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" -#include "app/gui/icons.h" -#include "app/gui/style.h" #include "app/rom.h" -#include "app/zelda3/overworld/overworld.h" namespace yaze { namespace app { @@ -40,13 +29,7 @@ class GfxGroupEditor : public SharedRom { selected_spriteset_ = spriteset; } - void InitBlockset(gfx::Bitmap* tile16_blockset) { - tile16_blockset_bmp_ = tile16_blockset; - } - private: - int preview_palette_id_ = 0; - int last_sheet_id_ = 0; uint8_t selected_blockset_ = 0; uint8_t selected_roomset_ = 0; uint8_t selected_spriteset_ = 0; @@ -57,17 +40,9 @@ class GfxGroupEditor : public SharedRom { gui::Canvas spriteset_canvas_; gfx::SnesPalette palette_; - gfx::PaletteGroup palette_group_; - gfx::Bitmap* tile16_blockset_bmp_; - - std::vector tile16_individual_data_; - std::vector tile16_individual_; - - gui::BitmapViewer gfx_group_viewer_; - zelda3::overworld::Overworld overworld_; }; } // namespace editor } // namespace app } // namespace yaze -#endif // YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H \ No newline at end of file +#endif // YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H diff --git a/src/app/editor/graphics/graphics_editor.cc b/src/app/editor/graphics/graphics_editor.cc index fe238599..d43a751b 100644 --- a/src/app/editor/graphics/graphics_editor.cc +++ b/src/app/editor/graphics/graphics_editor.cc @@ -1,30 +1,33 @@ #include "graphics_editor.h" #include "ImGuiFileDialog/ImGuiFileDialog.h" -#include "imgui/imgui.h" -#include "imgui/misc/cpp/imgui_stdlib.h" -#include "imgui_memory_editor.h" - #include "absl/status/status.h" #include "absl/status/statusor.h" #include "app/core/platform/clipboard.h" +#include "app/core/platform/renderer.h" #include "app/editor/graphics/palette_editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/compression.h" #include "app/gfx/scad_format.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" -#include "app/gui/asset_browser.h" #include "app/gui/canvas.h" #include "app/gui/color.h" +#include "app/gui/icons.h" #include "app/gui/input.h" +#include "app/gui/modules/asset_browser.h" #include "app/gui/style.h" #include "app/rom.h" +#include "imgui/imgui.h" +#include "imgui/misc/cpp/imgui_stdlib.h" +#include "imgui_memory_editor.h" namespace yaze { namespace app { namespace editor { +using core::Renderer; + using gfx::kPaletteGroupAddressesKeys; using ImGui::Button; using ImGui::InputInt; @@ -32,70 +35,56 @@ using ImGui::InputText; using ImGui::SameLine; using ImGui::TableNextColumn; -static constexpr absl::string_view kGfxToolsetColumnNames[] = { - "#memoryEditor", - "##separator_gfx1", -}; - constexpr ImGuiTableFlags kGfxEditTableFlags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_SizingFixedFit; -constexpr ImGuiTabBarFlags kGfxEditTabBarFlags = - ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | - ImGuiTabBarFlags_FittingPolicyResizeDown | - ImGuiTabBarFlags_TabListPopupButton; - -constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable | - ImGuiTableFlags_Resizable | - ImGuiTableFlags_SizingStretchSame; - absl::Status GraphicsEditor::Update() { - TAB_BAR("##TabBar") - status_ = UpdateGfxEdit(); - TAB_ITEM("Sheet Browser") - if (asset_browser_.Initialized == false) { - asset_browser_.Initialize(rom()->mutable_bitmap_manager()); + if (ImGui::BeginTabBar("##TabBar")) { + status_ = UpdateGfxEdit(); + TAB_ITEM("Sheet Browser") + if (asset_browser_.Initialized == false) { + asset_browser_.Initialize(rom()->gfx_sheets()); + } + asset_browser_.Draw(rom()->gfx_sheets()); + END_TAB_ITEM() + status_ = UpdateScadView(); + status_ = UpdateLinkGfxView(); + ImGui::EndTabBar(); } - asset_browser_.Draw(rom()->mutable_bitmap_manager()); - - END_TAB_ITEM() - status_ = UpdateScadView(); - status_ = UpdateLinkGfxView(); - END_TAB_BAR() CLEAR_AND_RETURN_STATUS(status_) return absl::OkStatus(); } absl::Status GraphicsEditor::UpdateGfxEdit() { - TAB_ITEM("Sheet Editor") + if (ImGui::BeginTabItem("Sheet Editor")) { + if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags, + ImVec2(0, 0))) { + for (const auto& name : + {"Tilesheets", "Current Graphics", "Palette Controls"}) + ImGui::TableSetupColumn(name); - if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags, - ImVec2(0, 0))) { - for (const auto& name : - {"Tilesheets", "Current Graphics", "Palette Controls"}) - ImGui::TableSetupColumn(name); + ImGui::TableHeadersRow(); - ImGui::TableHeadersRow(); + NEXT_COLUMN(); + status_ = UpdateGfxSheetList(); - NEXT_COLUMN(); - status_ = UpdateGfxSheetList(); + NEXT_COLUMN(); + if (rom()->is_loaded()) { + DrawGfxEditToolset(); + status_ = UpdateGfxTabView(); + } - NEXT_COLUMN(); - if (rom()->is_loaded()) { - DrawGfxEditToolset(); - status_ = UpdateGfxTabView(); + NEXT_COLUMN(); + if (rom()->is_loaded()) { + status_ = UpdatePaletteColumn(); + } } + ImGui::EndTable(); - NEXT_COLUMN(); - if (rom()->is_loaded()) { - status_ = UpdatePaletteColumn(); - } + ImGui::EndTabItem(); } - ImGui::EndTable(); - - END_TAB_ITEM() return absl::OkStatus(); } @@ -127,8 +116,8 @@ void GraphicsEditor::DrawGfxEditToolset() { TableNextColumn(); if (Button(ICON_MD_CONTENT_COPY)) { std::vector png_data = - rom()->bitmap_manager().shared_bitmap(current_sheet_).GetPngData(); - CopyImageToClipboard(png_data); + rom()->gfx_sheets().at(current_sheet_).GetPngData(); + core::CopyImageToClipboard(png_data); } HOVER_HINT("Copy to Clipboard"); @@ -136,14 +125,14 @@ void GraphicsEditor::DrawGfxEditToolset() { if (Button(ICON_MD_CONTENT_PASTE)) { std::vector png_data; int width, height; - GetImageFromClipboard(png_data, width, height); + core::GetImageFromClipboard(png_data, width, height); if (png_data.size() > 0) { rom() - ->mutable_bitmap_manager() - ->mutable_bitmap(current_sheet_) - ->Create(width, height, 8, png_data); - rom()->UpdateBitmap( - rom()->mutable_bitmap_manager()->mutable_bitmap(current_sheet_)); + ->mutable_gfx_sheets() + ->at(current_sheet_) + .Create(width, height, 8, png_data); + Renderer::GetInstance().UpdateBitmap( + &rom()->mutable_gfx_sheets()->at(current_sheet_)); } } HOVER_HINT("Paste from Clipboard"); @@ -163,7 +152,7 @@ void GraphicsEditor::DrawGfxEditToolset() { } TableNextColumn(); - auto bitmap = rom()->bitmap_manager()[current_sheet_]; + auto bitmap = rom()->gfx_sheets()[current_sheet_]; auto palette = bitmap.palette(); for (int i = 0; i < 8; i++) { ImGui::SameLine(); @@ -192,28 +181,28 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() { static ImGuiSelectionBasicStorage selection; ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect( - flags, selection.Size, rom()->bitmap_manager().size()); + ImGuiMultiSelectIO* ms_io = + ImGui::BeginMultiSelect(flags, selection.Size, kNumGfxSheets); selection.ApplyRequests(ms_io); ImGuiListClipper clipper; - clipper.Begin(rom()->bitmap_manager().size()); + clipper.Begin(kNumGfxSheets); if (ms_io->RangeSrcItem != -1) clipper.IncludeItemByIndex( (int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped. - for (auto& [key, value] : rom()->bitmap_manager()) { + int key = 0; + for (auto& value : rom()->gfx_sheets()) { ImGui::BeginChild(absl::StrFormat("##GfxSheet%02X", key).c_str(), ImVec2(0x100 + 1, 0x40 + 1), true, ImGuiWindowFlags_NoDecoration); ImGui::PopStyleVar(); - gui::Canvas graphics_bin_canvas_; graphics_bin_canvas_.DrawBackground(ImVec2(0x100 + 1, 0x40 + 1)); graphics_bin_canvas_.DrawContextMenu(); if (value.is_active()) { auto texture = value.texture(); graphics_bin_canvas_.draw_list()->AddImage( - (void*)texture, + (ImTextureID)(intptr_t)texture, ImVec2(graphics_bin_canvas_.zero_point().x + 2, graphics_bin_canvas_.zero_point().y + 2), ImVec2(graphics_bin_canvas_.zero_point().x + @@ -240,6 +229,8 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() { graphics_bin_canvas_.draw_list()->AddText( text_pos, IM_COL32(125, 255, 125, 255), absl::StrFormat("%02X", key).c_str()); + + key++; } graphics_bin_canvas_.DrawGrid(16.0f); graphics_bin_canvas_.DrawOverlay(); @@ -256,6 +247,10 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() { absl::Status GraphicsEditor::UpdateGfxTabView() { static int next_tab_id = 0; + constexpr ImGuiTabBarFlags kGfxEditTabBarFlags = + ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | + ImGuiTabBarFlags_FittingPolicyResizeDown | + ImGuiTabBarFlags_TabListPopupButton; if (ImGui::BeginTabBar("##GfxEditTabBar", kGfxEditTabBarFlags)) { if (ImGui::TabItemButton(ICON_MD_ADD, ImGuiTabItemFlags_Trailing | @@ -285,18 +280,17 @@ absl::Status GraphicsEditor::UpdateGfxTabView() { ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); - gfx::Bitmap& current_bitmap = - *rom()->mutable_bitmap_manager()->mutable_bitmap(sheet_id); + gfx::Bitmap& current_bitmap = rom()->mutable_gfx_sheets()->at(sheet_id); auto draw_tile_event = [&]() { current_sheet_canvas_.DrawTileOnBitmap(tile_size_, ¤t_bitmap, current_color_); - rom()->UpdateBitmap(¤t_bitmap, true); + Renderer::GetInstance().UpdateBitmap(¤t_bitmap); }; current_sheet_canvas_.UpdateColorPainter( - rom()->bitmap_manager()[sheet_id], current_color_, draw_tile_event, - tile_size_, current_scale_); + rom()->mutable_gfx_sheets()->at(sheet_id), current_color_, + draw_tile_event, tile_size_, current_scale_); ImGui::EndChild(); ImGui::EndTabItem(); @@ -328,7 +322,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() { current_sheet_ = id; // ImVec2(0x100, 0x40), current_sheet_canvas_.UpdateColorPainter( - rom()->bitmap_manager()[id], current_color_, + rom()->mutable_gfx_sheets()->at(id), current_color_, [&]() { }, @@ -365,11 +359,12 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() { if (refresh_graphics_ && !open_sheets_.empty()) { RETURN_IF_ERROR( - rom()->bitmap_manager()[current_sheet_].ApplyPaletteWithTransparent( - palette, edit_palette_sub_index_)); - rom()->UpdateBitmap( - rom()->mutable_bitmap_manager()->mutable_bitmap(current_sheet_), - true); + rom() + ->mutable_gfx_sheets() + ->data()[current_sheet_] + .ApplyPaletteWithTransparent(palette, edit_palette_sub_index_)); + Renderer::GetInstance().UpdateBitmap( + &rom()->mutable_gfx_sheets()->data()[current_sheet_]); refresh_graphics_ = false; } } @@ -391,9 +386,9 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() { link_canvas_.DrawGrid(16.0f); int i = 0; - for (auto [key, link_sheet] : *rom()->mutable_link_graphics()) { + for (auto link_sheet : *rom()->mutable_link_graphics()) { int x_offset = 0; - int y_offset = core::kTilesheetHeight * i * 4; + int y_offset = gfx::kTilesheetHeight * i * 4; link_canvas_.DrawContextMenu(&link_sheet); link_canvas_.DrawBitmap(link_sheet, x_offset, y_offset, 4); i++; @@ -435,6 +430,10 @@ absl::Status GraphicsEditor::UpdateScadView() { ImGui::End(); } + constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Resizable | + ImGuiTableFlags_SizingStretchSame; + BEGIN_TABLE("#gfxEditTable", 4, kGfxEditFlags) SETUP_COLUMN("File Import (BIN, CGX, ROM)") SETUP_COLUMN("Palette (COL)") @@ -458,17 +457,18 @@ absl::Status GraphicsEditor::UpdateScadView() { NEXT_COLUMN() if (super_donkey_) { - if (refresh_graphics_) { - for (int i = 0; i < graphics_bin_.size(); i++) { - status_ = graphics_bin_[i].ApplyPalette( - col_file_palette_group_[current_palette_index_]); - rom()->UpdateBitmap(&graphics_bin_[i]); - } - refresh_graphics_ = false; - } + // TODO: Implement the Super Donkey 1 graphics decompression + // if (refresh_graphics_) { + // for (int i = 0; i < kNumGfxSheets; i++) { + // status_ = graphics_bin_[i].ApplyPalette( + // col_file_palette_group_[current_palette_index_]); + // Renderer::GetInstance().UpdateBitmap(&graphics_bin_[i]); + // } + // refresh_graphics_ = false; + // } // Load the full graphics space from `super_donkey_1.bin` - gui::GraphicsBinCanvasPipeline(0x100, 0x40, 0x20, num_sheets_to_load_, 3, - super_donkey_, graphics_bin_); + // gui::GraphicsBinCanvasPipeline(0x100, 0x40, 0x20, num_sheets_to_load_, 3, + // super_donkey_, graphics_bin_); } else if (cgx_loaded_ && col_file_) { // Load the CGX graphics gui::BitmapCanvasPipeline(import_canvas_, cgx_bitmap_, 0x100, 16384, 0x20, @@ -485,6 +485,11 @@ absl::Status GraphicsEditor::UpdateScadView() { } absl::Status GraphicsEditor::DrawToolset() { + static constexpr absl::string_view kGfxToolsetColumnNames[] = { + "#memoryEditor", + "##separator_gfx1", + }; + if (ImGui::BeginTable("GraphicsToolset", 2, ImGuiTableFlags_SizingFixedFit, ImVec2(0, 0))) { for (const auto& name : kGfxToolsetColumnNames) @@ -535,7 +540,7 @@ absl::Status GraphicsEditor::DrawCgxImport() { cgx_bitmap_.Create(0x80, 0x200, 8, decoded_cgx_); if (col_file_) { cgx_bitmap_.ApplyPalette(decoded_col_); - rom()->RenderBitmap(&cgx_bitmap_); + Renderer::GetInstance().RenderBitmap(&cgx_bitmap_); } } @@ -570,7 +575,7 @@ absl::Status GraphicsEditor::DrawScrImport() { scr_bitmap_.Create(0x100, 0x100, 8, decoded_scr_data_); if (scr_loaded_) { scr_bitmap_.ApplyPalette(decoded_col_); - rom()->RenderBitmap(&scr_bitmap_); + Renderer::GetInstance().RenderBitmap(&scr_bitmap_); } } @@ -594,7 +599,7 @@ absl::Status GraphicsEditor::DrawPaletteControls() { /*z3_load=*/false); auto col_data_ = gfx::GetColFileData(temp_rom_.data()); if (col_file_palette_group_.size() != 0) { - col_file_palette_group_.Clear(); + col_file_palette_group_.clear(); } auto col_file_palette_group_status = gfx::CreatePaletteGroupFromColFile(col_data_); @@ -707,7 +712,8 @@ absl::Status GraphicsEditor::DrawClipboardImport() { if (Button("Paste From Clipboard")) { const char* text = ImGui::GetClipboardText(); if (text) { - const auto clipboard_data = Bytes(text, text + strlen(text)); + const auto clipboard_data = + std::vector(text, text + strlen(text)); ImGui::MemFree((void*)text); status_ = temp_rom_.LoadFromBytes(clipboard_data); is_open_ = true; @@ -762,7 +768,7 @@ absl::Status GraphicsEditor::DecompressImportData(int size) { temp_rom_.data(), current_offset_, size)) auto converted_sheet = gfx::SnesTo8bppSheet(import_data_, 3); - bin_bitmap_.Create(core::kTilesheetWidth, 0x2000, core::kTilesheetDepth, + bin_bitmap_.Create(gfx::kTilesheetWidth, 0x2000, gfx::kTilesheetDepth, converted_sheet); if (rom()->is_loaded()) { @@ -775,7 +781,7 @@ absl::Status GraphicsEditor::DecompressImportData(int size) { } } - rom()->RenderBitmap(&bin_bitmap_); + Renderer::GetInstance().RenderBitmap(&bin_bitmap_); gfx_loaded_ = true; return absl::OkStatus(); @@ -790,11 +796,10 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() { auto decompressed_data, gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000)) auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3); - graphics_bin_[i] = - gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, converted_sheet); + gfx_sheets_[i] = gfx::Bitmap(gfx::kTilesheetWidth, gfx::kTilesheetHeight, + gfx::kTilesheetDepth, converted_sheet); if (col_file_) { - status_ = graphics_bin_[i].ApplyPalette( + status_ = gfx_sheets_[i].ApplyPalette( col_file_palette_group_[current_palette_index_]); } else { // ROM palette @@ -802,10 +807,10 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() { auto palette_group = rom()->palette_group().get_group( kPaletteGroupAddressesKeys[current_palette_]); z3_rom_palette_ = *palette_group->mutable_palette(current_palette_index_); - status_ = graphics_bin_[i].ApplyPalette(z3_rom_palette_); + status_ = gfx_sheets_[i].ApplyPalette(z3_rom_palette_); } - rom()->RenderBitmap(&graphics_bin_[i]); + Renderer::GetInstance().RenderBitmap(&gfx_sheets_[i]); i++; } @@ -816,21 +821,20 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() { auto decompressed_data, gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000)) auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3); - graphics_bin_[i] = - gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, converted_sheet); + gfx_sheets_[i] = gfx::Bitmap(gfx::kTilesheetWidth, gfx::kTilesheetHeight, + gfx::kTilesheetDepth, converted_sheet); if (col_file_) { - status_ = graphics_bin_[i].ApplyPalette( + status_ = gfx_sheets_[i].ApplyPalette( col_file_palette_group_[current_palette_index_]); } else { // ROM palette auto palette_group = rom()->palette_group().get_group( kPaletteGroupAddressesKeys[current_palette_]); z3_rom_palette_ = *palette_group->mutable_palette(current_palette_index_); - status_ = graphics_bin_[i].ApplyPalette(z3_rom_palette_); + status_ = gfx_sheets_[i].ApplyPalette(z3_rom_palette_); } - rom()->RenderBitmap(&graphics_bin_[i]); + Renderer::GetInstance().RenderBitmap(&gfx_sheets_[i]); i++; } super_donkey_ = true; diff --git a/src/app/editor/graphics/graphics_editor.h b/src/app/editor/graphics/graphics_editor.h index 99974792..2d6d7a52 100644 --- a/src/app/editor/graphics/graphics_editor.h +++ b/src/app/editor/graphics/graphics_editor.h @@ -1,22 +1,19 @@ #ifndef YAZE_APP_EDITOR_GRAPHICS_EDITOR_H #define YAZE_APP_EDITOR_GRAPHICS_EDITOR_H -#include "ImGuiFileDialog/ImGuiFileDialog.h" -#include "imgui/imgui.h" -#include "imgui/misc/cpp/imgui_stdlib.h" -#include "imgui_memory_editor.h" +#include #include "absl/status/status.h" -#include "absl/status/statusor.h" #include "app/editor/graphics/palette_editor.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" -#include "app/gui/asset_browser.h" +#include "app/gui/modules/asset_browser.h" #include "app/gui/canvas.h" -#include "app/gui/input.h" #include "app/rom.h" #include "app/zelda3/overworld/overworld.h" +#include "imgui/imgui.h" +#include "imgui_memory_editor.h" namespace yaze { namespace app { @@ -167,8 +164,8 @@ class GraphicsEditor : public SharedRom, public Editor { MemoryEditor cgx_memory_editor_; MemoryEditor col_memory_editor_; PaletteEditor palette_editor_; - Bytes import_data_; - Bytes graphics_buffer_; + std::vector import_data_; + std::vector graphics_buffer_; std::vector decoded_cgx_; std::vector cgx_data_; std::vector extra_cgx_data_; @@ -179,9 +176,8 @@ class GraphicsEditor : public SharedRom, public Editor { gfx::Bitmap scr_bitmap_; gfx::Bitmap bin_bitmap_; gfx::Bitmap link_full_sheet_; - gfx::BitmapTable graphics_bin_; - gfx::BitmapTable clipboard_graphics_bin_; - gfx::BitmapTable link_graphics_; + std::array gfx_sheets_; + gfx::PaletteGroup col_file_palette_group_; gfx::SnesPalette z3_rom_palette_; gfx::SnesPalette col_file_palette_; @@ -189,11 +185,12 @@ class GraphicsEditor : public SharedRom, public Editor { gui::Canvas import_canvas_; gui::Canvas scr_canvas_; gui::Canvas super_donkey_canvas_; + gui::Canvas graphics_bin_canvas_; gui::Canvas current_sheet_canvas_{"CurrentSheetCanvas", ImVec2(0x80, 0x20), gui::CanvasGridSize::k8x8}; gui::Canvas link_canvas_{ "LinkCanvas", - ImVec2(core::kTilesheetWidth * 4, core::kTilesheetHeight * 0x10 * 4), + ImVec2(gfx::kTilesheetWidth * 4, gfx::kTilesheetHeight * 0x10 * 4), gui::CanvasGridSize::k16x16}; absl::Status status_; }; diff --git a/src/app/editor/graphics/palette_editor.cc b/src/app/editor/graphics/palette_editor.cc index 8f3a315f..b62b17e7 100644 --- a/src/app/editor/graphics/palette_editor.cc +++ b/src/app/editor/graphics/palette_editor.cc @@ -1,13 +1,11 @@ #include "palette_editor.h" -#include "imgui/imgui.h" - #include "absl/status/status.h" +#include "absl/strings/str_cat.h" #include "app/gfx/snes_palette.h" -#include "app/gui/canvas.h" #include "app/gui/color.h" -#include "app/gui/icons.h" #include "app/gui/style.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -86,6 +84,93 @@ static inline float color_saturate(float f) { 0.5f)) // Saturated, always output 0..255 } // namespace +absl::Status DisplayPalette(gfx::SnesPalette& palette, bool loaded) { + static ImVec4 color = ImVec4(0, 0, 0, 255.f); + static ImVec4 current_palette[256] = {}; + ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview | + ImGuiColorEditFlags_NoDragDrop | + ImGuiColorEditFlags_NoOptions; + + // Generate a default palette. The palette will persist and can be edited. + static bool init = false; + if (loaded && !init) { + for (int n = 0; n < palette.size(); n++) { + ASSIGN_OR_RETURN(auto color, palette.GetColor(n)); + current_palette[n].x = color.rgb().x / 255; + current_palette[n].y = color.rgb().y / 255; + current_palette[n].z = color.rgb().z / 255; + current_palette[n].w = 255; // Alpha + } + init = true; + } + + static ImVec4 backup_color; + bool open_popup = ColorButton("MyColor##3b", color, misc_flags); + SameLine(0, GetStyle().ItemInnerSpacing.x); + open_popup |= Button("Palette"); + if (open_popup) { + OpenPopup("mypicker"); + backup_color = color; + } + + if (BeginPopup("mypicker")) { + TEXT_WITH_SEPARATOR("Current Overworld Palette"); + ColorPicker4("##picker", (float*)&color, + misc_flags | ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoSmallPreview); + SameLine(); + + BeginGroup(); // Lock X position + Text("Current ==>"); + SameLine(); + Text("Previous"); + + if (Button("Update Map Palette")) { + } + + ColorButton( + "##current", color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40)); + SameLine(); + + if (ColorButton( + "##previous", backup_color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40))) + color = backup_color; + + // List of Colors in Overworld Palette + Separator(); + Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(current_palette); n++) { + PushID(n); + if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y); + + if (ColorButton("##palette", current_palette[n], kPalButtonFlags2, + ImVec2(20, 20))) + color = ImVec4(current_palette[n].x, current_palette[n].y, + current_palette[n].z, color.w); // Preserve alpha! + + if (BeginDragDropTarget()) { + if (const ImGuiPayload* payload = + AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)¤t_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = + AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)¤t_palette[n], payload->Data, sizeof(float) * 4); + EndDragDropTarget(); + } + + PopID(); + } + EndGroup(); + EndPopup(); + } + + return absl::OkStatus(); +} + absl::Status PaletteEditor::Update() { if (rom()->is_loaded()) { // Initialize the labels @@ -348,7 +433,7 @@ absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i, // SNES Format CustomFormatString(buf, IM_ARRAYSIZE(buf), "$%04X", - ConvertRGBtoSNES(ImVec4(col[0], col[1], col[2], 1.0f))); + ConvertRgbToSnes(ImVec4(col[0], col[1], col[2], 1.0f))); if (Selectable(buf)) SetClipboardText(buf); EndPopup(); @@ -358,84 +443,6 @@ absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i, return absl::OkStatus(); } -void PaletteEditor::DisplayPalette(gfx::SnesPalette& palette, bool loaded) { - static ImVec4 color = ImVec4(0, 0, 0, 255.f); - ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview | - ImGuiColorEditFlags_NoDragDrop | - ImGuiColorEditFlags_NoOptions; - - // Generate a default palette. The palette will persist and can be edited. - static bool init = false; - if (loaded && !init) { - status_ = InitializeSavedPalette(palette); - init = true; - } - - static ImVec4 backup_color; - bool open_popup = ColorButton("MyColor##3b", color, misc_flags); - SameLine(0, GetStyle().ItemInnerSpacing.x); - open_popup |= Button("Palette"); - if (open_popup) { - OpenPopup("mypicker"); - backup_color = color; - } - - if (BeginPopup("mypicker")) { - TEXT_WITH_SEPARATOR("Current Overworld Palette"); - ColorPicker4("##picker", (float*)&color, - misc_flags | ImGuiColorEditFlags_NoSidePreview | - ImGuiColorEditFlags_NoSmallPreview); - SameLine(); - - BeginGroup(); // Lock X position - Text("Current ==>"); - SameLine(); - Text("Previous"); - - if (Button("Update Map Palette")) { - } - - ColorButton( - "##current", color, - ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, - ImVec2(60, 40)); - SameLine(); - - if (ColorButton( - "##previous", backup_color, - ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, - ImVec2(60, 40))) - color = backup_color; - - // List of Colors in Overworld Palette - Separator(); - Text("Palette"); - for (int n = 0; n < IM_ARRAYSIZE(saved_palette_); n++) { - PushID(n); - if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y); - - if (ColorButton("##palette", saved_palette_[n], kPalButtonFlags2, - ImVec2(20, 20))) - color = ImVec4(saved_palette_[n].x, saved_palette_[n].y, - saved_palette_[n].z, color.w); // Preserve alpha! - - if (BeginDragDropTarget()) { - if (const ImGuiPayload* payload = - AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) - memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 3); - if (const ImGuiPayload* payload = - AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) - memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 4); - EndDragDropTarget(); - } - - PopID(); - } - EndGroup(); - EndPopup(); - } -} - absl::Status PaletteEditor::EditColorInPalette(gfx::SnesPalette& palette, int index) { if (index >= palette.size()) { diff --git a/src/app/editor/graphics/palette_editor.h b/src/app/editor/graphics/palette_editor.h index 9ee54cb8..6f32df6c 100644 --- a/src/app/editor/graphics/palette_editor.h +++ b/src/app/editor/graphics/palette_editor.h @@ -1,15 +1,17 @@ #ifndef YAZE_APP_EDITOR_PALETTE_EDITOR_H #define YAZE_APP_EDITOR_PALETTE_EDITOR_H -#include "imgui/imgui.h" +#include +#include +#include #include "absl/status/status.h" #include "app/editor/graphics/gfx_group_editor.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gfx/snes_palette.h" -#include "app/gui/canvas.h" -#include "app/gui/icons.h" +#include "app/gfx/snes_color.h" #include "app/rom.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -26,56 +28,51 @@ struct PaletteChange { class PaletteEditorHistory { public: - // Record a change in the palette editor - void RecordChange(const std::string& groupName, size_t paletteIndex, - size_t colorIndex, const gfx::SnesColor& originalColor, - const gfx::SnesColor& newColor) { - // Check size and remove the oldest if necessary - if (recentChanges.size() >= maxHistorySize) { - recentChanges.pop_front(); + void RecordChange(const std::string& group_name, size_t palette_index, + size_t color_index, const gfx::SnesColor& original_color, + const gfx::SnesColor& new_color) { + if (recent_changes_.size() >= kMaxHistorySize) { + recent_changes_.pop_front(); } - // Push the new change - recentChanges.push_back( - {groupName, paletteIndex, colorIndex, originalColor, newColor}); + recent_changes_.push_back( + {group_name, palette_index, color_index, original_color, new_color}); } - // Get recent changes for display in the palette editor - const std::deque& GetRecentChanges() const { - return recentChanges; - } - - // Restore the original color - gfx::SnesColor RestoreOriginalColor(const std::string& groupName, - size_t paletteIndex, - size_t colorIndex) const { - for (const auto& change : recentChanges) { - if (change.group_name == groupName && - change.palette_index == paletteIndex && - change.color_index == colorIndex) { + gfx::SnesColor RestoreOriginalColor(const std::string& group_name, + size_t palette_index, + size_t color_index) const { + for (const auto& change : recent_changes_) { + if (change.group_name == group_name && + change.palette_index == palette_index && + change.color_index == color_index) { return change.original_color; } } - // Handle error or return default (this is just an example, - // handle as appropriate for your application) return gfx::SnesColor(); } - auto size() const { return recentChanges.size(); } + auto size() const { return recent_changes_.size(); } gfx::SnesColor& GetModifiedColor(size_t index) { - return recentChanges[index].new_color; + return recent_changes_[index].new_color; } gfx::SnesColor& GetOriginalColor(size_t index) { - return recentChanges[index].original_color; + return recent_changes_[index].original_color; + } + + const std::deque& GetRecentChanges() const { + return recent_changes_; } private: - std::deque recentChanges; - static const size_t maxHistorySize = 50; // or any other number you deem fit + std::deque recent_changes_; + static const size_t kMaxHistorySize = 50; }; } // namespace palette_internal +absl::Status DisplayPalette(gfx::SnesPalette& palette, bool loaded); + /** * @class PaletteEditor * @brief Allows the user to view and edit in game palettes. @@ -101,7 +98,6 @@ class PaletteEditor : public SharedRom, public Editor { absl::Status EditColorInPalette(gfx::SnesPalette& palette, int index); absl::Status ResetColorToOriginal(gfx::SnesPalette& palette, int index, const gfx::SnesPalette& originalPalette); - void DisplayPalette(gfx::SnesPalette& palette, bool loaded); absl::Status DrawPaletteGroup(int category, bool right_side = false); void DrawCustomPalette(); @@ -110,16 +106,6 @@ class PaletteEditor : public SharedRom, public Editor { private: absl::Status HandleColorPopup(gfx::SnesPalette& palette, int i, int j, int n); - absl::Status InitializeSavedPalette(const gfx::SnesPalette& palette) { - for (int n = 0; n < palette.size(); n++) { - ASSIGN_OR_RETURN(auto color, palette.GetColor(n)); - saved_palette_[n].x = color.rgb().x / 255; - saved_palette_[n].y = color.rgb().y / 255; - saved_palette_[n].z = color.rgb().z / 255; - saved_palette_[n].w = 255; // Alpha - } - return absl::OkStatus(); - } absl::Status status_; gfx::SnesColor current_color_; @@ -137,4 +123,4 @@ class PaletteEditor : public SharedRom, public Editor { } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/editor/graphics/screen_editor.cc b/src/app/editor/graphics/screen_editor.cc index 9680d968..a8c55329 100644 --- a/src/app/editor/graphics/screen_editor.cc +++ b/src/app/editor/graphics/screen_editor.cc @@ -1,44 +1,45 @@ #include "screen_editor.h" -#include "imgui/imgui.h" - -#include #include #include -#include #include -#include "absl/status/statusor.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "app/core/common.h" #include "app/core/constants.h" +#include "app/core/platform/file_dialog.h" +#include "app/core/platform/renderer.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/gfx/tilesheet.h" #include "app/gui/canvas.h" #include "app/gui/icons.h" #include "app/gui/input.h" -#include "app/zelda3/dungeon/room.h" +#include "imgui/imgui.h" namespace yaze { namespace app { namespace editor { -absl::Status ScreenEditor::Update() { - TAB_BAR("##TabBar") - TAB_ITEM("Dungeon Maps") - if (rom()->is_loaded()) { - DrawDungeonMapsEditor(); - } - END_TAB_ITEM() - DrawInventoryMenuEditor(); - DrawOverworldMapEditor(); - DrawTitleScreenEditor(); - DrawNamingScreenEditor(); - END_TAB_BAR() +using core::Renderer; - return absl::OkStatus(); +constexpr uint32_t kRedPen = 0xFF0000FF; + +absl::Status ScreenEditor::Update() { + if (ImGui::BeginTabBar("##ScreenEditorTabBar")) { + if (ImGui::BeginTabItem("Dungeon Maps")) { + if (rom()->is_loaded()) { + DrawDungeonMapsEditor(); + } + ImGui::EndTabItem(); + } + DrawInventoryMenuEditor(); + DrawOverworldMapEditor(); + DrawTitleScreenEditor(); + DrawNamingScreenEditor(); + ImGui::EndTabBar(); + } + return status_; } void ScreenEditor::DrawInventoryMenuEditor() { @@ -121,16 +122,16 @@ absl::Status ScreenEditor::LoadDungeonMaps() { int ptr, rom()->ReadWord(zelda3::screen::kDungeonMapRoomsPtr + (d * 2))); ASSIGN_OR_RETURN( - int ptrGFX, - rom()->ReadWord(zelda3::screen::kDungeonMapRoomsPtr + (d * 2))); - ptr |= 0x0A0000; // Add bank to the short ptr - ptrGFX |= 0x0A0000; // Add bank to the short ptr - int pcPtr = core::SnesToPc(ptr); // Contains data for the next 25 rooms - int pcPtrGFX = - core::SnesToPc(ptrGFX); // Contains data for the next 25 rooms + int ptr_gfx, + rom()->ReadWord(zelda3::screen::kDungeonMapGfxPtr + (d * 2))); + ptr |= 0x0A0000; // Add bank to the short ptr + ptr_gfx |= 0x0A0000; // Add bank to the short ptr + int pc_ptr = core::SnesToPc(ptr); // Contains data for the next 25 rooms + int pc_ptr_gfx = + core::SnesToPc(ptr_gfx); // Contains data for the next 25 rooms ASSIGN_OR_RETURN( - ushort bossRoomD, + ushort boss_room_d, rom()->ReadWord(zelda3::screen::kDungeonMapBossRooms + (d * 2))); ASSIGN_OR_RETURN( @@ -157,14 +158,13 @@ absl::Status ScreenEditor::LoadDungeonMaps() { // for each room on the floor for (int j = 0; j < 25; j++) { - // rdata[j] = 0x0F; gdata[j] = 0xFF; - rdata[j] = rom()->data()[pcPtr + j + (i * 25)]; // Set the rooms + rdata[j] = rom()->data()[pc_ptr + j + (i * 25)]; // Set the rooms if (rdata[j] == 0x0F) { gdata[j] = 0xFF; } else { - gdata[j] = rom()->data()[pcPtrGFX++]; + gdata[j] = rom()->data()[pc_ptr_gfx++]; } std::string label = core::UppercaseHexByte(rdata[j]); @@ -175,7 +175,7 @@ absl::Status ScreenEditor::LoadDungeonMaps() { current_floor_rooms_d.push_back(rdata); // Add new floor data } - dungeon_maps_.emplace_back(bossRoomD, nbr_floor_d, nbr_basement_d, + dungeon_maps_.emplace_back(boss_room_d, nbr_floor_d, nbr_basement_d, current_floor_rooms_d, current_floor_gfx_d); } @@ -185,23 +185,19 @@ absl::Status ScreenEditor::LoadDungeonMaps() { absl::Status ScreenEditor::SaveDungeonMaps() { for (int d = 0; d < 14; d++) { int ptr = zelda3::screen::kDungeonMapRoomsPtr + (d * 2); - int ptrGFX = zelda3::screen::kDungeonMapGfxPtr + (d * 2); - int pcPtr = core::SnesToPc(ptr); - int pcPtrGFX = core::SnesToPc(ptrGFX); + int ptr_gfx = zelda3::screen::kDungeonMapGfxPtr + (d * 2); + int pc_ptr = core::SnesToPc(ptr); + int pc_ptr_gfx = core::SnesToPc(ptr_gfx); const int nbr_floors = dungeon_maps_[d].nbr_of_floor; const int nbr_basements = dungeon_maps_[d].nbr_of_basement; for (int i = 0; i < nbr_floors + nbr_basements; i++) { for (int j = 0; j < 25; j++) { - // rom()->data()[pcPtr + j + (i * 25)] = - // dungeon_maps_[d].floor_rooms[i][j]; - // rom()->data()[pcPtrGFX++] = dungeon_maps_[d].floor_gfx[i][j]; - - RETURN_IF_ERROR(rom()->WriteByte(ptr + j + (i * 25), + RETURN_IF_ERROR(rom()->WriteByte(pc_ptr + j + (i * 25), dungeon_maps_[d].floor_rooms[i][j])); - RETURN_IF_ERROR(rom()->WriteByte(ptrGFX + j + (i * 25), + RETURN_IF_ERROR(rom()->WriteByte(pc_ptr_gfx + j + (i * 25), dungeon_maps_[d].floor_gfx[i][j])); - pcPtrGFX++; + pc_ptr_gfx++; } } } @@ -209,7 +205,8 @@ absl::Status ScreenEditor::SaveDungeonMaps() { return absl::OkStatus(); } -absl::Status ScreenEditor::LoadDungeonMapTile16() { +absl::Status ScreenEditor::LoadDungeonMapTile16( + const std::vector& gfx_data, bool bin_mode) { tile16_sheet_.Init(256, 192, gfx::TileType::Tile16); for (int i = 0; i < 186; i++) { @@ -230,69 +227,99 @@ absl::Status ScreenEditor::LoadDungeonMapTile16() { ASSIGN_OR_RETURN(auto br, rom()->ReadWord(addr + 6 + (i * 8))); gfx::TileInfo t4 = gfx::WordToTileInfo(br); // Bottom right - tile16_sheet_.ComposeTile16(rom()->graphics_buffer(), t1, t2, t3, t4); + int sheet_offset = 212; + if (bin_mode) { + sheet_offset = 0; + } + tile16_sheet_.ComposeTile16(gfx_data, t1, t2, t3, t4, sheet_offset); } RETURN_IF_ERROR(tile16_sheet_.mutable_bitmap()->ApplyPalette( *rom()->mutable_dungeon_palette(3))); - rom()->RenderBitmap(&*tile16_sheet_.mutable_bitmap().get()); + Renderer::GetInstance().RenderBitmap(&*tile16_sheet_.mutable_bitmap().get()); for (int i = 0; i < tile16_sheet_.num_tiles(); ++i) { - if (tile16_individual_.count(i) == 0) { - auto tile = tile16_sheet_.GetTile16(i); - tile16_individual_[i] = tile; - rom()->RenderBitmap(&tile16_individual_[i]); - } + auto tile = tile16_sheet_.GetTile16(i); + tile16_individual_[i] = tile; + RETURN_IF_ERROR( + tile16_individual_[i].ApplyPalette(*rom()->mutable_dungeon_palette(3))); + Renderer::GetInstance().RenderBitmap(&tile16_individual_[i]); } return absl::OkStatus(); } +absl::Status ScreenEditor::SaveDungeonMapTile16() { + for (int i = 0; i < 186; i++) { + int addr = zelda3::screen::kDungeonMapTile16; + if (rom()->data()[zelda3::screen::kDungeonMapExpCheck] != 0xB9) { + addr = zelda3::screen::kDungeonMapTile16Expanded; + } + + gfx::TileInfo t1 = tile16_sheet_.tile_info()[i].tiles[0]; + gfx::TileInfo t2 = tile16_sheet_.tile_info()[i].tiles[1]; + gfx::TileInfo t3 = tile16_sheet_.tile_info()[i].tiles[2]; + gfx::TileInfo t4 = tile16_sheet_.tile_info()[i].tiles[3]; + + auto tl = gfx::TileInfoToWord(t1); + RETURN_IF_ERROR(rom()->WriteWord(addr + (i * 8), tl)); + + auto tr = gfx::TileInfoToWord(t2); + RETURN_IF_ERROR(rom()->WriteWord(addr + 2 + (i * 8), tr)); + + auto bl = gfx::TileInfoToWord(t3); + RETURN_IF_ERROR(rom()->WriteWord(addr + 4 + (i * 8), bl)); + + auto br = gfx::TileInfoToWord(t4); + RETURN_IF_ERROR(rom()->WriteWord(addr + 6 + (i * 8), br)); + } + return absl::OkStatus(); +} + void ScreenEditor::DrawDungeonMapsTabs() { - auto current_dungeon = dungeon_maps_[selected_dungeon]; + auto& current_dungeon = dungeon_maps_[selected_dungeon]; if (ImGui::BeginTabBar("##DungeonMapTabs")) { auto nbr_floors = current_dungeon.nbr_of_floor + current_dungeon.nbr_of_basement; for (int i = 0; i < nbr_floors; i++) { - std::string tab_name = absl::StrFormat("Floor %d", i + 1); - if (i >= current_dungeon.nbr_of_floor) { - tab_name = absl::StrFormat("Basement %d", - i - current_dungeon.nbr_of_floor + 1); + int basement_num = current_dungeon.nbr_of_basement - i; + std::string tab_name = absl::StrFormat("Basement %d", basement_num); + if (i >= current_dungeon.nbr_of_basement) { + tab_name = absl::StrFormat("Floor %d", + i - current_dungeon.nbr_of_basement + 1); } if (ImGui::BeginTabItem(tab_name.c_str())) { floor_number = i; - // screen_canvas_.LoadCustomLabels(dungeon_map_labels_[selected_dungeon]); - // screen_canvas_.set_current_labels(floor_number); screen_canvas_.DrawBackground(ImVec2(325, 325)); screen_canvas_.DrawTileSelector(64.f); auto boss_room = current_dungeon.boss_room; for (int j = 0; j < 25; j++) { if (current_dungeon.floor_rooms[floor_number][j] != 0x0F) { - int tile16_id = current_dungeon.floor_rooms[floor_number][j]; - int tile_x = (tile16_id % 16) * 16; - int tile_y = (tile16_id / 16) * 16; + int tile16_id = current_dungeon.floor_gfx[floor_number][j]; int posX = ((j % 5) * 32); int posY = ((j / 5) * 32); if (tile16_individual_.count(tile16_id) == 0) { - auto tile = tile16_sheet_.GetTile16(tile16_id); - std::cout << "Tile16: " << tile16_id << std::endl; - rom()->RenderBitmap(&tile); - tile16_individual_[tile16_id] = tile; + tile16_individual_[tile16_id] = + tile16_sheet_.GetTile16(tile16_id); + Renderer::GetInstance().RenderBitmap( + &tile16_individual_[tile16_id]); } screen_canvas_.DrawBitmap(tile16_individual_[tile16_id], (posX * 2), (posY * 2), 4.0f); if (current_dungeon.floor_rooms[floor_number][j] == boss_room) { screen_canvas_.DrawOutlineWithColor((posX * 2), (posY * 2), 64, - 64, core::kRedPen); + 64, kRedPen); } std::string label = dungeon_map_labels_[selected_dungeon][floor_number][j]; screen_canvas_.DrawText(label, (posX * 2), (posY * 2)); + std::string gfx_id = core::UppercaseHexByte(tile16_id); + screen_canvas_.DrawText(gfx_id, (posX * 2), (posY * 2) + 16); } } @@ -316,31 +343,76 @@ void ScreenEditor::DrawDungeonMapsTabs() { gui::InputHexWord("Boss Room", ¤t_dungeon.boss_room); - if (ImGui::Button("Copy Floor", ImVec2(100, 0))) { + const ImVec2 button_size = ImVec2(130, 0); + + // Add Floor Button + if (ImGui::Button("Add Floor", button_size) && + current_dungeon.nbr_of_floor < 8) { + current_dungeon.nbr_of_floor++; + dungeon_map_labels_[selected_dungeon].emplace_back(); + } + ImGui::SameLine(); + if (ImGui::Button("Remove Floor", button_size) && + current_dungeon.nbr_of_floor > 0) { + current_dungeon.nbr_of_floor--; + dungeon_map_labels_[selected_dungeon].pop_back(); + } + + // Add Basement Button + if (ImGui::Button("Add Basement", button_size) && + current_dungeon.nbr_of_basement < 8) { + current_dungeon.nbr_of_basement++; + dungeon_map_labels_[selected_dungeon].emplace_back(); + } + ImGui::SameLine(); + if (ImGui::Button("Remove Basement", button_size) && + current_dungeon.nbr_of_basement > 0) { + current_dungeon.nbr_of_basement--; + dungeon_map_labels_[selected_dungeon].pop_back(); + } + + if (ImGui::Button("Copy Floor", button_size)) { copy_button_pressed = true; } ImGui::SameLine(); - if (ImGui::Button("Paste Floor", ImVec2(100, 0))) { + if (ImGui::Button("Paste Floor", button_size)) { paste_button_pressed = true; } } void ScreenEditor::DrawDungeonMapsEditor() { if (!dungeon_maps_loaded_) { - if (LoadDungeonMaps().ok()) { - if (LoadDungeonMapTile16().ok()) { - auto bitmap_manager = rom()->mutable_bitmap_manager(); - sheets_.emplace(0, *bitmap_manager->mutable_bitmap(212)); - sheets_.emplace(1, *bitmap_manager->mutable_bitmap(213)); - sheets_.emplace(2, *bitmap_manager->mutable_bitmap(214)); - sheets_.emplace(3, *bitmap_manager->mutable_bitmap(215)); - dungeon_maps_loaded_ = true; - } else { - ImGui::Text("Failed to load dungeon map tile16"); - } - } else { + if (!LoadDungeonMaps().ok()) { ImGui::Text("Failed to load dungeon maps"); } + + if (LoadDungeonMapTile16(rom()->graphics_buffer()).ok()) { + // TODO: Load roomset gfx based on dungeon ID + sheets_.emplace(0, rom()->gfx_sheets()[212]); + sheets_.emplace(1, rom()->gfx_sheets()[213]); + sheets_.emplace(2, rom()->gfx_sheets()[214]); + sheets_.emplace(3, rom()->gfx_sheets()[215]); + dungeon_maps_loaded_ = true; + } else { + ImGui::Text("Failed to load dungeon map tile16"); + } + } + + if (ImGui::BeginTable("##DungeonMapToolset", 2, ImGuiTableFlags_SizingFixedFit)) { + ImGui::TableSetupColumn("Draw Mode"); + ImGui::TableSetupColumn("Edit Mode"); + + ImGui::TableNextColumn(); + if (ImGui::Button(ICON_MD_DRAW)) { + current_mode_ = EditingMode::DRAW; + } + + ImGui::TableNextColumn(); + if (ImGui::Button(ICON_MD_EDIT)) { + current_mode_ = EditingMode::EDIT; + } + + ImGui::EndTable(); } static std::vector dungeon_names = { @@ -350,7 +422,10 @@ void ScreenEditor::DrawDungeonMapsEditor() { "Thieves' Town", "Ice Palace", "Misery Mire", "Turtle Rock", "Ganon's Tower"}; - if (ImGui::BeginTable("DungeonMapsTable", 4, ImGuiTableFlags_Resizable)) { + if (ImGui::BeginTable("DungeonMapsTable", 4, + ImGuiTableFlags_Resizable | + ImGuiTableFlags_Reorderable | + ImGuiTableFlags_Hideable)) { ImGui::TableSetupColumn("Dungeon"); ImGui::TableSetupColumn("Map"); ImGui::TableSetupColumn("Rooms Gfx"); @@ -384,32 +459,113 @@ void ScreenEditor::DrawDungeonMapsEditor() { if (!tilesheet_canvas_.points().empty()) { selected_tile16_ = tilesheet_canvas_.points().front().x / 32 + (tilesheet_canvas_.points().front().y / 32) * 16; + current_tile16_info = tile16_sheet_.tile_info().at(selected_tile16_); + + // Draw the selected tile + if (!screen_canvas_.points().empty()) { + dungeon_maps_[selected_dungeon] + .floor_gfx[floor_number][selected_room] = selected_tile16_; + tilesheet_canvas_.mutable_points()->clear(); + } + } + + ImGui::Separator(); + current_tile_canvas_.DrawBackground(ImVec2(64 * 2 + 2, 64 * 2 + 4)); + current_tile_canvas_.DrawContextMenu(); + current_tile_canvas_.DrawBitmap(tile16_individual_[selected_tile16_], 2, + 4.0f); + current_tile_canvas_.DrawGrid(16.f); + current_tile_canvas_.DrawOverlay(); + + gui::InputTileInfo("TL", ¤t_tile16_info.tiles[0]); + ImGui::SameLine(); + gui::InputTileInfo("TR", ¤t_tile16_info.tiles[1]); + gui::InputTileInfo("BL", ¤t_tile16_info.tiles[2]); + ImGui::SameLine(); + gui::InputTileInfo("BR", ¤t_tile16_info.tiles[3]); + + if (ImGui::Button("Modify Tile16")) { + tile16_sheet_.ModifyTile16( + rom()->graphics_buffer(), current_tile16_info.tiles[0], + current_tile16_info.tiles[1], current_tile16_info.tiles[2], + current_tile16_info.tiles[3], selected_tile16_, 212); + tile16_individual_[selected_tile16_] = + tile16_sheet_.GetTile16(selected_tile16_); + RETURN_VOID_IF_ERROR(tile16_individual_[selected_tile16_].ApplyPalette( + *rom()->mutable_dungeon_palette(3))); + Renderer::GetInstance().RenderBitmap( + &tile16_individual_[selected_tile16_]); } } ImGui::EndChild(); ImGui::TableNextColumn(); - tilemap_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4)); + tilemap_canvas_.DrawBackground(); tilemap_canvas_.DrawContextMenu(); + if (tilemap_canvas_.DrawTileSelector(16.f)) { + // Get the tile8 ID to use for the tile16 drawing above + selected_tile8_ = tilemap_canvas_.GetTileIdFromMousePos(); + } tilemap_canvas_.DrawBitmapTable(sheets_); tilemap_canvas_.DrawGrid(); tilemap_canvas_.DrawOverlay(); + ImGui::Text("Selected tile8: %d", selected_tile8_); + + ImGui::Separator(); + ImGui::Text("For use with custom inserted graphics assembly patches."); + if (ImGui::Button("Load GFX from BIN file")) LoadBinaryGfx(); + ImGui::EndTable(); } } +void ScreenEditor::LoadBinaryGfx() { + std::string bin_file = core::FileDialogWrapper::ShowOpenFileDialog(); + if (!bin_file.empty()) { + std::ifstream file(bin_file, std::ios::binary); + if (file.is_open()) { + // Read the gfx data into a buffer + std::vector bin_data((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + auto converted_bin = gfx::SnesTo8bppSheet(bin_data, 4, 4); + gfx_bin_data_ = converted_bin; + tile16_sheet_.clear(); + if (LoadDungeonMapTile16(converted_bin, true).ok()) { + sheets_.clear(); + std::vector> gfx_sheets; + for (int i = 0; i < 4; i++) { + gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000), + converted_bin.begin() + ((i + 1) * 0x1000)); + sheets_.emplace(i, gfx::Bitmap(128, 32, 8, gfx_sheets[i])); + sheets_[i].ApplyPalette(*rom()->mutable_dungeon_palette(3)); + Renderer::GetInstance().RenderBitmap(&sheets_[i]); + } + binary_gfx_loaded_ = true; + } else { + status_ = absl::InternalError("Failed to load dungeon map tile16"); + } + file.close(); + } + } +} + void ScreenEditor::DrawTitleScreenEditor() { - TAB_ITEM("Title Screen") - END_TAB_ITEM() + if (ImGui::BeginTabItem("Title Screen")) { + ImGui::EndTabItem(); + } } + void ScreenEditor::DrawNamingScreenEditor() { - TAB_ITEM("Naming Screen") - END_TAB_ITEM() + if (ImGui::BeginTabItem("Naming Screen")) { + ImGui::EndTabItem(); + } } + void ScreenEditor::DrawOverworldMapEditor() { - TAB_ITEM("Overworld Map") - END_TAB_ITEM() + if (ImGui::BeginTabItem("Overworld Map")) { + ImGui::EndTabItem(); + } } void ScreenEditor::DrawToolset() { diff --git a/src/app/editor/graphics/screen_editor.h b/src/app/editor/graphics/screen_editor.h index 9faddd0c..324c9a6b 100644 --- a/src/app/editor/graphics/screen_editor.h +++ b/src/app/editor/graphics/screen_editor.h @@ -1,23 +1,18 @@ #ifndef YAZE_APP_EDITOR_SCREEN_EDITOR_H #define YAZE_APP_EDITOR_SCREEN_EDITOR_H -#include "imgui/imgui.h" - #include #include "absl/status/status.h" -#include "app/core/constants.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" #include "app/gfx/tilesheet.h" #include "app/gui/canvas.h" -#include "app/gui/color.h" -#include "app/gui/icons.h" #include "app/rom.h" #include "app/zelda3/screen/dungeon_map.h" #include "app/zelda3/screen/inventory.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -38,7 +33,7 @@ namespace editor { * The class inherits from the SharedRom class. */ class ScreenEditor : public SharedRom, public Editor { - public: +public: ScreenEditor() { screen_canvas_.SetCanvasSize(ImVec2(512, 512)); type_ = EditorType::kScreen; @@ -55,7 +50,7 @@ class ScreenEditor : public SharedRom, public Editor { absl::Status SaveDungeonMaps(); - private: +private: void DrawTitleScreenEditor(); void DrawNamingScreenEditor(); void DrawOverworldMapEditor(); @@ -65,42 +60,58 @@ class ScreenEditor : public SharedRom, public Editor { void DrawInventoryToolset(); absl::Status LoadDungeonMaps(); - absl::Status LoadDungeonMapTile16(); + absl::Status LoadDungeonMapTile16(const std::vector &gfx_data, + bool bin_mode = false); + absl::Status SaveDungeonMapTile16(); void DrawDungeonMapsTabs(); void DrawDungeonMapsEditor(); - std::vector dungeon_maps_; - std::vector>> dungeon_map_labels_; + void LoadBinaryGfx(); - std::unordered_map tile16_individual_; + enum class EditingMode { DRAW, EDIT }; + + EditingMode current_mode_ = EditingMode::DRAW; bool dungeon_maps_loaded_ = false; + bool binary_gfx_loaded_ = false; - int selected_tile16_ = 0; - int selected_dungeon = 0; uint8_t selected_room = 0; uint8_t boss_room = 0; + + int selected_tile16_ = 0; + int selected_tile8_ = 0; + int selected_dungeon = 0; int floor_number = 1; bool copy_button_pressed = false; bool paste_button_pressed = false; - Bytes all_gfx_; - zelda3::screen::Inventory inventory_; - gfx::SnesPalette palette_; - gui::Canvas screen_canvas_; - gui::Canvas tilesheet_canvas_; - gui::Canvas tilemap_canvas_; - - gfx::BitmapTable sheets_; - - gfx::Tilesheet tile16_sheet_; + std::vector all_gfx_; + std::unordered_map tile16_individual_; + std::vector dungeon_maps_; + std::vector>> dungeon_map_labels_; + std::array current_tile16_data_; + std::vector gfx_bin_data_; absl::Status status_; + + gfx::SnesPalette palette_; + gfx::BitmapTable sheets_; + gfx::Tilesheet tile16_sheet_; + gfx::InternalTile16 current_tile16_info; + + gui::Canvas current_tile_canvas_{"##CurrentTileCanvas"}; + gui::Canvas screen_canvas_; + gui::Canvas tilesheet_canvas_; + gui::Canvas tilemap_canvas_{"##TilemapCanvas", + ImVec2(128 + 2, (192) + 4), + gui::CanvasGridSize::k8x8, 2.f}; + + zelda3::screen::Inventory inventory_; }; -} // namespace editor -} // namespace app -} // namespace yaze +} // namespace editor +} // namespace app +} // namespace yaze #endif diff --git a/src/app/editor/graphics/tile16_editor.cc b/src/app/editor/graphics/tile16_editor.cc index dc52f8ac..4b25faf0 100644 --- a/src/app/editor/graphics/tile16_editor.cc +++ b/src/app/editor/graphics/tile16_editor.cc @@ -1,14 +1,13 @@ #include "tile16_editor.h" -#include "ImGuiFileDialog/ImGuiFileDialog.h" -#include "imgui/imgui.h" - #include +#include "ImGuiFileDialog/ImGuiFileDialog.h" #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "app/core/platform/renderer.h" #include "app/editor/graphics/palette_editor.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" @@ -19,11 +18,14 @@ #include "app/gui/style.h" #include "app/rom.h" #include "app/zelda3/overworld/overworld.h" +#include "imgui/imgui.h" namespace yaze { namespace app { namespace editor { +using core::Renderer; + using ImGui::BeginChild; using ImGui::BeginMenu; using ImGui::BeginMenuBar; @@ -48,14 +50,13 @@ using ImGui::TableSetupColumn; using ImGui::Text; absl::Status Tile16Editor::InitBlockset( - gfx::Bitmap* tile16_blockset_bmp, gfx::Bitmap current_gfx_bmp, + const gfx::Bitmap& tile16_blockset_bmp, const gfx::Bitmap& current_gfx_bmp, const std::vector& tile16_individual, uint8_t all_tiles_types[0x200]) { all_tiles_types_ = all_tiles_types; tile16_blockset_bmp_ = tile16_blockset_bmp; tile16_individual_ = tile16_individual; current_gfx_bmp_ = current_gfx_bmp; - tile8_gfx_data_ = current_gfx_bmp_.vector(); RETURN_IF_ERROR(LoadTile8()); ImVector tile16_names; for (int i = 0; i < 0x200; ++i) { @@ -75,7 +76,7 @@ absl::Status Tile16Editor::Update() { RETURN_IF_ERROR(DrawMenu()); if (BeginTabBar("Tile16 Editor Tabs")) { - RETURN_IF_ERROR(DrawTile16Editor()); + DrawTile16Editor(); RETURN_IF_ERROR(UpdateTile16Transfer()); EndTabBar(); } @@ -97,7 +98,7 @@ absl::Status Tile16Editor::DrawMenu() { return absl::OkStatus(); } -absl::Status Tile16Editor::DrawTile16Editor() { +void Tile16Editor::DrawTile16Editor() { if (BeginTabItem("Tile16 Editing")) { if (BeginTable("#Tile16EditorTable", 2, TABLE_BORDERS_RESIZABLE, ImVec2(0, 0))) { @@ -108,18 +109,23 @@ absl::Status Tile16Editor::DrawTile16Editor() { TableHeadersRow(); TableNextRow(); TableNextColumn(); - RETURN_IF_ERROR(UpdateBlockset()); + status_ = UpdateBlockset(); + if (!status_.ok()) { + EndTable(); + } TableNextColumn(); - RETURN_IF_ERROR(UpdateTile16Edit()); - RETURN_IF_ERROR(DrawTileEditControls()); + status_ = UpdateTile16Edit(); + if (status_ != absl::OkStatus()) { + EndTable(); + } + status_ = DrawTileEditControls(); EndTable(); } EndTabItem(); } - return absl::OkStatus(); } absl::Status Tile16Editor::UpdateBlockset() { @@ -127,14 +133,12 @@ absl::Status Tile16Editor::UpdateBlockset() { gui::BeginChildWithScrollbar("##Tile16EditorBlocksetScrollRegion"); blockset_canvas_.DrawBackground(); gui::EndPadding(); - { - blockset_canvas_.DrawContextMenu(); - blockset_canvas_.DrawTileSelector(32); - blockset_canvas_.DrawBitmap(*tile16_blockset_bmp_, 0, map_blockset_loaded_); - blockset_canvas_.DrawGrid(); - blockset_canvas_.DrawOverlay(); - EndChild(); - } + blockset_canvas_.DrawContextMenu(); + blockset_canvas_.DrawTileSelector(32); + blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 0, map_blockset_loaded_); + blockset_canvas_.DrawGrid(); + blockset_canvas_.DrawOverlay(); + EndChild(); if (!blockset_canvas_.points().empty()) { notify_tile16.mutable_get() = blockset_canvas_.GetTileIdFromMousePos(); @@ -142,11 +146,11 @@ absl::Status Tile16Editor::UpdateBlockset() { if (notify_tile16.modified()) { current_tile16_ = notify_tile16.get(); - current_tile16_bmp_ = &tile16_individual_[notify_tile16]; + current_tile16_bmp_ = tile16_individual_[notify_tile16]; auto ow_main_pal_group = rom()->palette_group().overworld_main; - RETURN_IF_ERROR(current_tile16_bmp_->ApplyPalette( + RETURN_IF_ERROR(current_tile16_bmp_.ApplyPalette( ow_main_pal_group[current_palette_])); - rom()->RenderBitmap(current_tile16_bmp_); + Renderer::GetInstance().RenderBitmap(¤t_tile16_bmp_); } } @@ -166,8 +170,8 @@ absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) { // Calculate the pixel start position within the Tile16 ImVec2 start_position; - start_position.x = ((tile_index_x) / 4) * 0x40; - start_position.y = ((tile_index_y) / 4) * 0x40; + start_position.x = tile_index_x * 0x40; + start_position.y = tile_index_y * 0x40; std::cout << "Start Position X: " << start_position.x << std::endl; std::cout << "Start Position Y: " << start_position.y << std::endl; @@ -177,7 +181,7 @@ absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) { int pixel_index = (start_position.y + y) * tile16_size + ((start_position.x) + x); int gfx_pixel_index = y * tile8_size + x; - current_tile16_bmp_->WriteToPixel( + current_tile16_bmp_.WriteToPixel( pixel_index, current_gfx_individual_[current_tile8_].data()[gfx_pixel_index]); } @@ -197,7 +201,8 @@ absl::Status Tile16Editor::UpdateTile16Edit() { RETURN_IF_ERROR( current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent( ow_main_pal_group[0], current_palette_)); - rom()->UpdateBitmap(¤t_gfx_individual_[current_tile8_]); + Renderer::GetInstance().UpdateBitmap( + ¤t_gfx_individual_[current_tile8_]); } tile8_source_canvas_.DrawBitmap(current_gfx_bmp_, 0, 0, 4.0f); tile8_source_canvas_.DrawGrid(); @@ -214,20 +219,21 @@ absl::Status Tile16Editor::UpdateTile16Edit() { RETURN_IF_ERROR( current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent( ow_main_pal_group[0], current_palette_)); - rom()->UpdateBitmap(¤t_gfx_individual_[current_tile8_]); + Renderer::GetInstance().UpdateBitmap( + ¤t_gfx_individual_[current_tile8_]); } if (BeginChild("Tile16 Editor Options", ImVec2(GetContentRegionAvail().x, 0x50), true)) { tile16_edit_canvas_.DrawBackground(); - tile16_edit_canvas_.DrawContextMenu(current_tile16_bmp_); - tile16_edit_canvas_.DrawBitmap(*current_tile16_bmp_, 0, 0, 4.0f); + tile16_edit_canvas_.DrawContextMenu(¤t_tile16_bmp_); + tile16_edit_canvas_.DrawBitmap(current_tile16_bmp_, 0, 0, 4.0f); if (!tile8_source_canvas_.points().empty()) { if (tile16_edit_canvas_.DrawTilePainter( current_gfx_individual_[current_tile8_], 16, 2.0f)) { RETURN_IF_ERROR( DrawToCurrentTile16(tile16_edit_canvas_.drawn_tile_position())); - rom()->UpdateBitmap(current_tile16_bmp_); + Renderer::GetInstance().UpdateBitmap(¤t_tile16_bmp_); } } tile16_edit_canvas_.DrawGrid(); @@ -258,10 +264,11 @@ absl::Status Tile16Editor::DrawTileEditControls() { if (value > 0x00) { RETURN_IF_ERROR( current_gfx_bmp_.ApplyPaletteWithTransparent(palette, value)); + Renderer::GetInstance().UpdateBitmap(¤t_gfx_bmp_); + RETURN_IF_ERROR( - current_tile16_bmp_->ApplyPaletteWithTransparent(palette, value)); - rom()->UpdateBitmap(¤t_gfx_bmp_); - rom()->UpdateBitmap(current_tile16_bmp_); + current_tile16_bmp_.ApplyPaletteWithTransparent(palette, value)); + Renderer::GetInstance().UpdateBitmap(¤t_tile16_bmp_); } } @@ -290,7 +297,6 @@ absl::Status Tile16Editor::LoadTile8() { // Calculate the position in the current gfx data int num_columns = current_gfx_bmp_.width() / 8; - int num_rows = current_gfx_bmp_.height() / 8; int x = (index % num_columns) * 8 + tx; int y = (index / num_columns) * 8 + ty; int gfx_position = x + (y * 0x100); @@ -310,7 +316,7 @@ absl::Status Tile16Editor::LoadTile8() { current_gfx_individual_[index].Create(0x08, 0x08, 0x08, tile_data); RETURN_IF_ERROR(current_gfx_individual_[index].ApplyPaletteWithTransparent( ow_main_pal_group[0], current_palette_)); - rom()->RenderBitmap(¤t_gfx_individual_[index]); + Renderer::GetInstance().RenderBitmap(¤t_gfx_individual_[index]); } map_blockset_loaded_ = true; @@ -318,8 +324,17 @@ absl::Status Tile16Editor::LoadTile8() { return absl::OkStatus(); } -// ============================================================================ -// Tile16 Transfer +absl::Status Tile16Editor::SetCurrentTile(int id) { + current_tile16_ = id; + current_tile16_bmp_ = tile16_individual_[id]; + auto ow_main_pal_group = rom()->palette_group().overworld_main; + RETURN_IF_ERROR( + current_tile16_bmp_.ApplyPalette(ow_main_pal_group[current_palette_])); + Renderer::GetInstance().RenderBitmap(¤t_tile16_bmp_); + return absl::OkStatus(); +} + +#pragma mark - Tile16Transfer absl::Status Tile16Editor::UpdateTile16Transfer() { if (BeginTabItem("Tile16 Transfer")) { @@ -363,16 +378,15 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() { // TODO: Implement tile16 transfer if (transfer_started_ && !transfer_blockset_loaded_) { PRINT_IF_ERROR(transfer_rom_.LoadAllGraphicsData()) - graphics_bin_ = transfer_rom_.graphics_bin(); // Load the Link to the Past overworld. PRINT_IF_ERROR(transfer_overworld_.Load(transfer_rom_)) transfer_overworld_.set_current_map(0); - palette_ = transfer_overworld_.AreaPalette(); + palette_ = transfer_overworld_.current_area_palette(); // Create the tile16 blockset image - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap( - 0x80, 0x2000, 0x80, transfer_overworld_.Tile16Blockset(), + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + 0x80, 0x2000, 0x80, transfer_overworld_.tile16_blockset_data(), transfer_blockset_bmp_, palette_)); transfer_blockset_loaded_ = true; } @@ -385,16 +399,6 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() { return absl::OkStatus(); } -absl::Status Tile16Editor::SetCurrentTile(int id) { - current_tile16_ = id; - current_tile16_bmp_ = &tile16_individual_[id]; - auto ow_main_pal_group = rom()->palette_group().overworld_main; - RETURN_IF_ERROR( - current_tile16_bmp_->ApplyPalette(ow_main_pal_group[current_palette_])); - rom()->RenderBitmap(current_tile16_bmp_); - return absl::OkStatus(); -} - } // namespace editor } // namespace app } // namespace yaze diff --git a/src/app/editor/graphics/tile16_editor.h b/src/app/editor/graphics/tile16_editor.h index d3eaaec3..9889ec61 100644 --- a/src/app/editor/graphics/tile16_editor.h +++ b/src/app/editor/graphics/tile16_editor.h @@ -1,23 +1,16 @@ #ifndef YAZE_APP_EDITOR_TILE16EDITOR_H #define YAZE_APP_EDITOR_TILE16EDITOR_H -#include "imgui/imgui.h" - -#include - #include "absl/status/status.h" -#include "absl/status/statusor.h" +#include "app/core/common.h" #include "app/editor/graphics/palette_editor.h" -#include "app/editor/utils/editor.h" -#include "app/editor/utils/gfx_context.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" -#include "app/gfx/tilesheet.h" #include "app/gui/canvas.h" -#include "app/gui/icons.h" #include "app/rom.h" #include "app/zelda3/overworld/overworld.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -26,17 +19,17 @@ namespace editor { /** * @brief Popup window to edit Tile16 data */ -class Tile16Editor : public context::GfxContext, public SharedRom { +class Tile16Editor : public GfxContext, public SharedRom { public: - absl::Status InitBlockset(gfx::Bitmap* tile16_blockset_bmp, - gfx::Bitmap current_gfx_bmp, + absl::Status InitBlockset(const gfx::Bitmap& tile16_blockset_bmp, + const gfx::Bitmap& current_gfx_bmp, const std::vector& tile16_individual, uint8_t all_tiles_types[0x200]); absl::Status Update(); absl::Status DrawMenu(); - absl::Status DrawTile16Editor(); + void DrawTile16Editor(); absl::Status UpdateTile16Transfer(); absl::Status UpdateBlockset(); @@ -75,38 +68,32 @@ class Tile16Editor : public context::GfxContext, public SharedRom { // Tile16 blockset for selecting the tile to edit gui::Canvas blockset_canvas_{"blocksetCanvas", ImVec2(0x100, 0x4000), gui::CanvasGridSize::k32x32}; - gfx::Bitmap* tile16_blockset_bmp_; + gfx::Bitmap tile16_blockset_bmp_; // Canvas for editing the selected tile gui::Canvas tile16_edit_canvas_{"Tile16EditCanvas", ImVec2(0x40, 0x40), gui::CanvasGridSize::k64x64}; - gfx::Bitmap* current_tile16_bmp_; + gfx::Bitmap current_tile16_bmp_; // Tile8 canvas to get the tile to drawing in the tile16_edit_canvas_ gui::Canvas tile8_source_canvas_{ "Tile8SourceCanvas", - ImVec2(core::kTilesheetWidth * 4, core::kTilesheetHeight * 0x10 * 4), + ImVec2(gfx::kTilesheetWidth * 4, gfx::kTilesheetHeight * 0x10 * 4), gui::CanvasGridSize::k32x32}; gfx::Bitmap current_gfx_bmp_; gui::Canvas transfer_canvas_; gfx::Bitmap transfer_blockset_bmp_; - std::vector tile16_individual_data_; std::vector tile16_individual_; - std::vector current_gfx_individual_; - std::vector current_tile16_data_; - - std::vector tile8_gfx_data_; - PaletteEditor palette_editor_; gfx::SnesPalette palette_; zelda3::overworld::Overworld transfer_overworld_; - gfx::BitmapTable graphics_bin_; + absl::Status status_; Rom transfer_rom_; absl::Status transfer_status_; @@ -115,4 +102,4 @@ class Tile16Editor : public context::GfxContext, public SharedRom { } // namespace editor } // namespace app } // namespace yaze -#endif // YAZE_APP_EDITOR_TILE16EDITOR_H \ No newline at end of file +#endif // YAZE_APP_EDITOR_TILE16EDITOR_H diff --git a/src/app/editor/master_editor_test.cc b/src/app/editor/master_editor_test.cc deleted file mode 100644 index 69cd54b5..00000000 --- a/src/app/editor/master_editor_test.cc +++ /dev/null @@ -1,10 +0,0 @@ -#include "master_editor.h" - -namespace yaze { -namespace app { -namespace editor { - - -} // namespace editor -} // namespace app -} // namespace yaze \ No newline at end of file diff --git a/src/app/editor/message/message_data.cc b/src/app/editor/message/message_data.cc new file mode 100644 index 00000000..4e00286d --- /dev/null +++ b/src/app/editor/message/message_data.cc @@ -0,0 +1,182 @@ +#include "message_data.h" + +#include "app/core/common.h" + +namespace yaze { +namespace app { +namespace editor { + +uint8_t FindMatchingCharacter(char value) { + for (const auto [key, char_value] : CharEncoder) { + if (value == char_value) { + return key; + } + } + return 0xFF; +} + +uint8_t FindDictionaryEntry(uint8_t value) { + if (value < DICTOFF || value == 0xFF) { + return -1; + } + return value - DICTOFF; +} + +TextElement FindMatchingCommand(uint8_t b) { + TextElement empty_element; + for (const auto& text_element : TextCommands) { + if (text_element.ID == b) { + return text_element; + } + } + return empty_element; +} + +TextElement FindMatchingSpecial(uint8_t value) { + auto it = std::find_if(SpecialChars.begin(), SpecialChars.end(), + [value](const TextElement& text_element) { + return text_element.ID == value; + }); + if (it != SpecialChars.end()) { + return *it; + } + + return TextElement(); +} + +ParsedElement FindMatchingElement(const std::string& str) { + std::smatch match; + for (auto& textElement : TextCommands) { + match = textElement.MatchMe(str); + if (match.size() > 0) { + if (textElement.HasArgument) { + return ParsedElement(textElement, + std::stoi(match[1].str(), nullptr, 16)); + } else { + return ParsedElement(textElement, 0); + } + } + } + + const auto dictionary_element = + TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary"); + + match = dictionary_element.MatchMe(str); + if (match.size() > 0) { + return ParsedElement(dictionary_element, + DICTOFF + std::stoi(match[1].str(), nullptr, 16)); + } + return ParsedElement(); +} + +std::string ParseTextDataByte(uint8_t value) { + if (CharEncoder.contains(value)) { + char c = CharEncoder.at(value); + std::string str = ""; + str.push_back(c); + return str; + } + + // Check for command. + TextElement textElement = FindMatchingCommand(value); + if (!textElement.Empty()) { + return textElement.GenericToken; + } + + // Check for special characters. + textElement = FindMatchingSpecial(value); + if (!textElement.Empty()) { + return textElement.GenericToken; + } + + // Check for dictionary. + int dictionary = FindDictionaryEntry(value); + if (dictionary >= 0) { + return absl::StrFormat("[%s:%X]", DICTIONARYTOKEN, dictionary); + } + + return ""; +} + +std::vector ParseMessageToData(std::string str) { + std::vector bytes; + std::string temp_string = str; + int pos = 0; + + while (pos < temp_string.size()) { + // Get next text fragment. + if (temp_string[pos] == '[') { + int next = temp_string.find(']', pos); + if (next == -1) { + break; + } + + ParsedElement parsedElement = + FindMatchingElement(temp_string.substr(pos, next - pos + 1)); + + const auto dictionary_element = + TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary"); + + if (!parsedElement.Active) { + core::logf("Error parsing message: %s", temp_string); + break; + } else if (parsedElement.Parent == dictionary_element) { + bytes.push_back(parsedElement.Value); + } else { + bytes.push_back(parsedElement.Parent.ID); + + if (parsedElement.Parent.HasArgument) { + bytes.push_back(parsedElement.Value); + } + } + + pos = next + 1; + continue; + } else { + uint8_t bb = FindMatchingCharacter(temp_string[pos++]); + + if (bb != 0xFF) { + core::logf("Error parsing message: %s", temp_string); + bytes.push_back(bb); + } + } + } + + return bytes; +} + +std::vector BuildDictionaryEntries(app::Rom* rom) { + std::vector AllDictionaries; + for (int i = 0; i < kNumDictionaryEntries; i++) { + std::vector bytes; + std::stringstream stringBuilder; + + int address = core::SnesToPc( + kTextData + (rom->data()[kPointersDictionaries + (i * 2) + 1] << 8) + + rom->data()[kPointersDictionaries + (i * 2)]); + + int temppush_backress = core::SnesToPc( + kTextData + + (rom->data()[kPointersDictionaries + ((i + 1) * 2) + 1] << 8) + + rom->data()[kPointersDictionaries + ((i + 1) * 2)]); + + while (address < temppush_backress) { + uint8_t uint8_tDictionary = rom->data()[address++]; + bytes.push_back(uint8_tDictionary); + stringBuilder << ParseTextDataByte(uint8_tDictionary); + } + + AllDictionaries.push_back(DictionaryEntry{(uint8_t)i, stringBuilder.str()}); + } + + std::sort(AllDictionaries.begin(), AllDictionaries.end(), + [](const DictionaryEntry& a, const DictionaryEntry& b) { + return a.Contents.size() > b.Contents.size(); + }); + + return AllDictionaries; +} + +} // namespace editor +} // namespace app +} // namespace yaze \ No newline at end of file diff --git a/src/app/editor/message/message_data.h b/src/app/editor/message/message_data.h index 1f67134b..4934d057 100644 --- a/src/app/editor/message/message_data.h +++ b/src/app/editor/message/message_data.h @@ -1,23 +1,90 @@ #ifndef YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H #define YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H +#include #include #include #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/str_replace.h" +#include "app/rom.h" namespace yaze { namespace app { namespace editor { -const uint8_t MESSAGETERMINATOR = 0x7F; +const uint8_t kMessageTerminator = 0x7F; +const std::string BANKToken = "BANK"; +const std::string DICTIONARYTOKEN = "D"; +constexpr uint8_t DICTOFF = 0x88; -static std::string AddNewLinesToCommands(std::string str); -static std::string ReplaceAllDictionaryWords(std::string str); -static std::vector ParseMessageToData(std::string str); +static const std::unordered_map CharEncoder = { + {0x00, 'A'}, {0x01, 'B'}, {0x02, 'C'}, {0x03, 'D'}, {0x04, 'E'}, + {0x05, 'F'}, {0x06, 'G'}, {0x07, 'H'}, {0x08, 'I'}, {0x09, 'J'}, + {0x0A, 'K'}, {0x0B, 'L'}, {0x0C, 'M'}, {0x0D, 'N'}, {0x0E, 'O'}, + {0x0F, 'P'}, {0x10, 'Q'}, {0x11, 'R'}, {0x12, 'S'}, {0x13, 'T'}, + {0x14, 'U'}, {0x15, 'V'}, {0x16, 'W'}, {0x17, 'X'}, {0x18, 'Y'}, + {0x19, 'Z'}, {0x1A, 'a'}, {0x1B, 'b'}, {0x1C, 'c'}, {0x1D, 'd'}, + {0x1E, 'e'}, {0x1F, 'f'}, {0x20, 'g'}, {0x21, 'h'}, {0x22, 'i'}, + {0x23, 'j'}, {0x24, 'k'}, {0x25, 'l'}, {0x26, 'm'}, {0x27, 'n'}, + {0x28, 'o'}, {0x29, 'p'}, {0x2A, 'q'}, {0x2B, 'r'}, {0x2C, 's'}, + {0x2D, 't'}, {0x2E, 'u'}, {0x2F, 'v'}, {0x30, 'w'}, {0x31, 'x'}, + {0x32, 'y'}, {0x33, 'z'}, {0x34, '0'}, {0x35, '1'}, {0x36, '2'}, + {0x37, '3'}, {0x38, '4'}, {0x39, '5'}, {0x3A, '6'}, {0x3B, '7'}, + {0x3C, '8'}, {0x3D, '9'}, {0x3E, '!'}, {0x3F, '?'}, {0x40, '-'}, + {0x41, '.'}, {0x42, ','}, {0x44, '>'}, {0x45, '('}, {0x46, ')'}, + {0x4C, '"'}, {0x51, '\''}, {0x59, ' '}, {0x5A, '<'}, {0x5F, L'¡'}, + {0x60, L'¡'}, {0x61, L'¡'}, {0x62, L' '}, {0x63, L' '}, {0x64, L' '}, + {0x65, ' '}, {0x66, '_'}, +}; -const std::string CHEESE = "\uBEBE"; // Inserted into commands to protect - // them from dictionary replacements. +uint8_t FindMatchingCharacter(char value); +uint8_t FindDictionaryEntry(uint8_t value); + +std::vector ParseMessageToData(std::string str); + +struct DictionaryEntry { + uint8_t ID; + std::string Contents; + std::vector Data; + int Length; + std::string Token; + + DictionaryEntry() = default; + DictionaryEntry(uint8_t i, std::string s) + : Contents(s), ID(i), Length(s.length()) { + Token = absl::StrFormat("[%s:%00X]", DICTIONARYTOKEN, ID); + Data = ParseMessageToData(Contents); + } + + bool ContainedInString(std::string s) { + return s.find(Contents) != std::string::npos; + } + + std::string ReplaceInstancesOfIn(std::string s) { + std::string replacedString = s; + size_t pos = replacedString.find(Contents); + while (pos != std::string::npos) { + replacedString.replace(pos, Contents.length(), Token); + pos = replacedString.find(Contents, pos + Token.length()); + } + return replacedString; + } +}; + +constexpr int kTextData = 0xE0000; +constexpr int kTextDataEnd = 0xE7FFF; +constexpr int kNumDictionaryEntries = 97; +constexpr int kPointersDictionaries = 0x74703; + +std::vector BuildDictionaryEntries(app::Rom* rom); + +std::string ReplaceAllDictionaryWords(std::string str, + std::vector dictionary); + +// Inserted into commands to protect them from dictionary replacements. +const std::string CHEESE = "\uBEBE"; struct MessageData { int ID; @@ -49,35 +116,13 @@ struct MessageData { ContentsParsed = other.ContentsParsed; } - void SetMessage(std::string messageString) { - ContentsParsed = messageString; - RawString = OptimizeMessageForDictionary(messageString); - RecalculateData(); - } - std::string ToString() { return absl::StrFormat("%0X - %s", ID, ContentsParsed); } - std::string GetReadableDumpedContents() { - std::stringstream stringBuilder; - for (const auto& b : Data) { - stringBuilder << absl::StrFormat("%0X ", b); - } - stringBuilder << absl::StrFormat("%00X", MESSAGETERMINATOR); - - return absl::StrFormat( - "[[[[\r\nMessage " - "%000X]]]]\r\n[Contents]\r\n%s\r\n\r\n[Data]\r\n%s" - "\r\n\r\n\r\n\r\n", - ID, AddNewLinesToCommands(ContentsParsed), stringBuilder.str()); - } - - std::string GetDumpedContents() { - return absl::StrFormat("%000X : %s\r\n\r\n", ID, ContentsParsed); - } - - std::string OptimizeMessageForDictionary(std::string messageString) { + std::string OptimizeMessageForDictionary( + std::string messageString, + const std::vector& dictionary) { std::stringstream protons; bool command = false; for (const auto& c : messageString) { @@ -94,16 +139,18 @@ struct MessageData { } std::string protonsString = protons.str(); - std::string replacedString = ReplaceAllDictionaryWords(protonsString); + std::string replacedString = + ReplaceAllDictionaryWords(protonsString, dictionary); std::string finalString = absl::StrReplaceAll(replacedString, {{CHEESE, ""}}); return finalString; } - void RecalculateData() { - Data = ParseMessageToData(RawString); - DataParsed = ParseMessageToData(ContentsParsed); + void SetMessage(const std::string& message, + const std::vector& dictionary) { + RawString = message; + ContentsParsed = OptimizeMessageForDictionary(message, dictionary); } }; @@ -155,8 +202,64 @@ struct TextElement { } bool Empty() { return ID == 0; } + + // Comparison operator + bool operator==(const TextElement& other) const { return ID == other.ID; } }; +static const std::vector TextCommands = { + TextElement(0x6B, "W", true, "Window border"), + TextElement(0x6D, "P", true, "Window position"), + TextElement(0x6E, "SPD", true, "Scroll speed"), + TextElement(0x7A, "S", true, "Text draw speed"), + TextElement(0x77, "C", true, "Text color"), + TextElement(0x6A, "L", false, "Player name"), + TextElement(0x74, "1", false, "Line 1"), + TextElement(0x75, "2", false, "Line 2"), + TextElement(0x76, "3", false, "Line 3"), + TextElement(0x7E, "K", false, "Wait for key"), + TextElement(0x73, "V", false, "Scroll text"), + TextElement(0x78, "WT", true, "Delay X"), + TextElement(0x6C, "N", true, "BCD number"), + TextElement(0x79, "SFX", true, "Sound effect"), + TextElement(0x71, "CH3", false, "Choose 3"), + TextElement(0x72, "CH2", false, "Choose 2 high"), + TextElement(0x6F, "CH2L", false, "Choose 2 low"), + TextElement(0x68, "CH2I", false, "Choose 2 indented"), + TextElement(0x69, "CHI", false, "Choose item"), + TextElement(0x67, "IMG", false, "Next attract image"), + TextElement(0x80, BANKToken, false, "Bank marker (automatic)"), + TextElement(0x70, "NONO", false, "Crash"), +}; + +TextElement FindMatchingCommand(uint8_t b); + +static const std::vector SpecialChars = { + TextElement(0x43, "...", false, "Ellipsis …"), + TextElement(0x4D, "UP", false, "Arrow ↑"), + TextElement(0x4E, "DOWN", false, "Arrow ↓"), + TextElement(0x4F, "LEFT", false, "Arrow ←"), + TextElement(0x50, "RIGHT", false, "Arrow →"), + TextElement(0x5B, "A", false, "Button Ⓐ"), + TextElement(0x5C, "B", false, "Button Ⓑ"), + TextElement(0x5D, "X", false, "Button ⓧ"), + TextElement(0x5E, "Y", false, "Button ⓨ"), + TextElement(0x52, "HP1L", false, "1 HP left"), + TextElement(0x53, "HP1R", false, "1 HP right"), + TextElement(0x54, "HP2L", false, "2 HP left"), + TextElement(0x55, "HP3L", false, "3 HP left"), + TextElement(0x56, "HP3R", false, "3 HP right"), + TextElement(0x57, "HP4L", false, "4 HP left"), + TextElement(0x58, "HP4R", false, "4 HP right"), + TextElement(0x47, "HY0", false, "Hieroglyph ☥"), + TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"), + TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"), + TextElement(0x4A, "LFL", false, "Link face left"), + TextElement(0x4B, "LFR", false, "Link face right"), +}; + +TextElement FindMatchingSpecial(uint8_t b); + struct ParsedElement { TextElement Parent; uint8_t Value; @@ -170,8 +273,12 @@ struct ParsedElement { } }; +ParsedElement FindMatchingElement(const std::string& str); + +std::string ParseTextDataByte(uint8_t value); + } // namespace editor } // namespace app } // namespace yaze -#endif // YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H \ No newline at end of file +#endif // YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H diff --git a/src/app/editor/message/message_editor.cc b/src/app/editor/message/message_editor.cc index fb3691a8..31cee107 100644 --- a/src/app/editor/message/message_editor.cc +++ b/src/app/editor/message/message_editor.cc @@ -1,7 +1,5 @@ #include "message_editor.h" -#include -#include #include #include #include @@ -9,26 +7,24 @@ #include "absl/status/status.h" #include "absl/strings/str_format.h" #include "absl/strings/str_replace.h" -#include "absl/strings/str_split.h" -#include "app/core/common.h" -#include "app/editor/utils/editor.h" +#include "app/core/platform/renderer.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" -#include "app/gui/icons.h" #include "app/gui/style.h" #include "app/rom.h" +#include "imgui.h" namespace yaze { namespace app { namespace editor { -using ImGui::Begin; +using core::Renderer; + using ImGui::BeginChild; using ImGui::BeginTable; using ImGui::Button; -using ImGui::End; using ImGui::EndChild; using ImGui::EndTable; using ImGui::InputText; @@ -37,216 +33,24 @@ using ImGui::SameLine; using ImGui::Separator; using ImGui::TableHeadersRow; using ImGui::TableNextColumn; -using ImGui::TableNextRow; using ImGui::TableSetupColumn; using ImGui::Text; using ImGui::TextWrapped; -using ImGui::TreeNode; -static ParsedElement FindMatchingElement(string str) { - std::smatch match; - for (auto& textElement : TextCommands) { - match = textElement.MatchMe(str); - if (match.size() > 0) { - if (textElement.HasArgument) { - return ParsedElement(textElement, - std::stoi(match[1].str(), nullptr, 16)); - } else { - return ParsedElement(textElement, 0); - } - } - } +constexpr ImGuiTableFlags kMessageTableFlags = ImGuiTableFlags_Hideable | + ImGuiTableFlags_Borders | + ImGuiTableFlags_Resizable; - match = DictionaryElement.MatchMe(str); - if (match.size() > 0) { - return ParsedElement(DictionaryElement, - DICTOFF + std::stoi(match[1].str(), nullptr, 16)); - } - return ParsedElement(); -} - -static string ReplaceAllDictionaryWords(string str) { - string temp = str; - for (const auto& entry : AllDictionaries) { - if (absl::StrContains(temp, entry.Contents)) { - temp = absl::StrReplaceAll(temp, {{entry.Contents, entry.Contents}}); - } - } - - return temp; -} - -static std::vector ParseMessageToData(string str) { - std::vector bytes; - string tempString = str; - int pos = 0; - - while (pos < tempString.size()) { - // Get next text fragment. - if (tempString[pos] == '[') { - int next = tempString.find(']', pos); - if (next == -1) { - break; - } - - ParsedElement parsedElement = - FindMatchingElement(tempString.substr(pos, next - pos + 1)); - if (!parsedElement.Active) { - break; // TODO: handle badness. - // } else if (parsedElement.Parent == DictionaryElement) { - // bytes.push_back(parsedElement.Value); - } else { - bytes.push_back(parsedElement.Parent.ID); - - if (parsedElement.Parent.HasArgument) { - bytes.push_back(parsedElement.Value); - } - } - - pos = next + 1; - continue; - } else { - uint8_t bb = MessageEditor::FindMatchingCharacter(tempString[pos++]); - - if (bb != 0xFF) { - // TODO: handle badness. - bytes.push_back(bb); - } - } - } - - return bytes; -} - -absl::Status MessageEditor::Update() { - if (rom()->is_loaded() && !data_loaded_) { - RETURN_IF_ERROR(Initialize()); - CurrentMessage = ListOfTexts[1]; - data_loaded_ = true; - } - - if (BeginTable("##MessageEditor", 3, - ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) { - TableSetupColumn("List"); - TableSetupColumn("Contents"); - TableSetupColumn("Commands"); - - TableHeadersRow(); - - TableNextColumn(); - DrawMessageList(); - - TableNextColumn(); - DrawCurrentMessage(); - - TableNextColumn(); - DrawTextCommands(); - - EndTable(); - } - - return absl::OkStatus(); -} - -void MessageEditor::DrawMessageList() { - if (InputText("Search", &search_text_)) { - DisplayedMessages.clear(); - for (const auto& message : ListOfTexts) { - if (absl::StrContains(message.ContentsParsed, search_text_)) { - DisplayedMessages.push_back(message); - } - } - } - - if (BeginChild("##MessagesList", ImVec2(0, 0), true, - ImGuiWindowFlags_AlwaysVerticalScrollbar)) { - if (BeginTable("##MessagesTable", 3, - ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | - ImGuiTableFlags_Resizable)) { - TableSetupColumn("ID"); - TableSetupColumn("Contents"); - TableSetupColumn("Data"); - - TableHeadersRow(); - - for (const auto& message : ListOfTexts) { - TableNextColumn(); - if (Button(core::UppercaseHexWord(message.ID).c_str())) { - CurrentMessage = message; - DrawMessagePreview(); - } - TableNextColumn(); - TextWrapped("%s", ParsedMessages[message.ID].c_str()); - TableNextColumn(); - TextWrapped( - "%s", - core::UppercaseHexLong(ListOfTexts[message.ID].Address).c_str()); - } - - EndTable(); - } - EndChild(); - } -} - -void MessageEditor::DrawCurrentMessage() { - Button(absl::StrCat("Message ", CurrentMessage.ID).c_str()); - if (InputTextMultiline("##MessageEditor", &ParsedMessages[CurrentMessage.ID], - ImVec2(ImGui::GetContentRegionAvail().x, 0))) { - CurrentMessage.Data = ParseMessageToData(message_text_box_.text); - DrawMessagePreview(); - } - Separator(); - - Text("Font Graphics"); - gui::BeginPadding(1); - BeginChild("MessageEditorCanvas", ImVec2(0, 130)); - font_gfx_canvas_.DrawBackground(); - font_gfx_canvas_.DrawContextMenu(); - font_gfx_canvas_.DrawBitmap(font_gfx_bitmap_, 0, 0); - font_gfx_canvas_.DrawGrid(); - font_gfx_canvas_.DrawOverlay(); - EndChild(); - gui::EndPadding(); - Separator(); - - Text("Message Preview"); - if (Button("Refresh Bitmap")) { - rom()->UpdateBitmap(¤t_font_gfx16_bitmap_); - } - gui::BeginPadding(1); - BeginChild("CurrentGfxFont", ImVec2(0, 0), true, - ImGuiWindowFlags_AlwaysVerticalScrollbar); - current_font_gfx16_canvas_.DrawBackground(); - gui::EndPadding(); - current_font_gfx16_canvas_.DrawContextMenu(); - current_font_gfx16_canvas_.DrawBitmap(current_font_gfx16_bitmap_, 0, 0); - current_font_gfx16_canvas_.DrawGrid(); - current_font_gfx16_canvas_.DrawOverlay(); - EndChild(); -} - -void MessageEditor::DrawTextCommands() { - if (BeginChild("##TextCommands", ImVec2(0, 0), true, - ImGuiWindowFlags_AlwaysVerticalScrollbar)) { - for (const auto& text_element : TextCommands) { - if (Button(text_element.GenericToken.c_str())) { - } - SameLine(); - TextWrapped("%s", text_element.Description.c_str()); - Separator(); - } - EndChild(); - } -} +constexpr ImGuiTableFlags kDictTableFlags = + ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable; absl::Status MessageEditor::Initialize() { - for (int i = 0; i < 100; i++) { + for (int i = 0; i < kWidthArraySize; i++) { width_array[i] = rom()->data()[kCharactersWidth + i]; } - BuildDictionaryEntries(); - ReadAllTextData(); + all_dictionaries_ = BuildDictionaryEntries(rom()); + ReadAllTextDataV2(); font_preview_colors_.AddColor(0x7FFF); // White font_preview_colors_.AddColor(0x7C00); // Red @@ -257,21 +61,23 @@ absl::Status MessageEditor::Initialize() { for (int i = 0; i < 0x4000; i++) { data[i] = rom()->data()[kGfxFont + i]; } - font_gfx16_data = gfx::SnesTo8bppSheet(data, /*bpp=*/2); + font_gfx16_data_ = gfx::SnesTo8bppSheet(data, /*bpp=*/2, /*num_sheets=*/2); // 4bpp - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap( - 128, 128, 8, font_gfx16_data, font_gfx_bitmap_, font_preview_colors_)) + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + kFontGfxMessageSize, kFontGfxMessageSize, kFontGfxMessageDepth, + font_gfx16_data_, font_gfx_bitmap_, font_preview_colors_)) - current_font_gfx16_data_.reserve(172 * 4096); - for (int i = 0; i < 172 * 4096; i++) { + current_font_gfx16_data_.reserve(kCurrentMessageWidth * + kCurrentMessageHeight); + for (int i = 0; i < kCurrentMessageWidth * kCurrentMessageHeight; i++) { current_font_gfx16_data_.push_back(0); } // 8bpp - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap( - 172, 4096, 64, current_font_gfx16_data_, current_font_gfx16_bitmap_, - font_preview_colors_)) + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + kCurrentMessageWidth, kCurrentMessageHeight, 64, current_font_gfx16_data_, + current_font_gfx16_bitmap_, font_preview_colors_)) gfx::SnesPalette color_palette = font_gfx_bitmap_.palette(); for (int i = 0; i < font_preview_colors_.size(); i++) { @@ -280,11 +86,11 @@ absl::Status MessageEditor::Initialize() { *font_gfx_bitmap_.mutable_palette() = color_palette; - for (const auto& message : ListOfTexts) { - DisplayedMessages.push_back(message); - } + for (const auto& each_message : list_of_texts_) { + std::cout << "Message #" << each_message.ID << " at address " + << core::UppercaseHexLong(each_message.Address) << std::endl; + std::cout << " " << each_message.RawString << std::endl; - for (const auto& each_message : ListOfTexts) { // Each string has a [:XX] char encoded // The corresponding character is found in CharEncoder unordered_map std::string parsed_message = ""; @@ -313,7 +119,8 @@ absl::Status MessageEditor::Initialize() { } } } - ParsedMessages.push_back(parsed_message); + std::cout << " > " << parsed_message << std::endl; + parsed_messages_.push_back(parsed_message); } DrawMessagePreview(); @@ -321,38 +128,245 @@ absl::Status MessageEditor::Initialize() { return absl::OkStatus(); } -void MessageEditor::BuildDictionaryEntries() { - for (int i = 0; i < 97; i++) { - std::vector bytes; - std::stringstream stringBuilder; - - int address = core::SnesToPc( - 0x0E0000 + (rom()->data()[kPointersDictionaries + (i * 2) + 1] << 8) + - rom()->data()[kPointersDictionaries + (i * 2)]); - - int temppush_backress = core::SnesToPc( - 0x0E0000 + - (rom()->data()[kPointersDictionaries + ((i + 1) * 2) + 1] << 8) + - rom()->data()[kPointersDictionaries + ((i + 1) * 2)]); - - while (address < temppush_backress) { - uint8_t uint8_tDictionary = rom()->data()[address++]; - bytes.push_back(uint8_tDictionary); - stringBuilder << ParseTextDataByte(uint8_tDictionary); - } - - // AllDictionaries[i] = DictionaryEntry{(uint8_t)i, stringBuilder.str()}; - AllDictionaries.push_back(DictionaryEntry{(uint8_t)i, stringBuilder.str()}); +absl::Status MessageEditor::Update() { + if (rom()->is_loaded() && !data_loaded_) { + RETURN_IF_ERROR(Initialize()); + current_message_ = list_of_texts_[1]; + data_loaded_ = true; } - // AllDictionaries.OrderByDescending(dictionary = > dictionary.Length); - AllDictionaries[0].Length = 0; + if (BeginTable("##MessageEditor", 4, kDictTableFlags)) { + TableSetupColumn("List"); + TableSetupColumn("Contents"); + TableSetupColumn("Commands"); + TableSetupColumn("Dictionary"); + + TableHeadersRow(); + + TableNextColumn(); + DrawMessageList(); + + TableNextColumn(); + DrawCurrentMessage(); + + TableNextColumn(); + DrawTextCommands(); + + TableNextColumn(); + DrawDictionary(); + + EndTable(); + } + + return absl::OkStatus(); +} + +void MessageEditor::DrawMessageList() { + if (InputText("Search", &search_text_)) { + // TODO: ImGui style text filtering + } + + if (BeginChild("##MessagesList", ImVec2(0, 0), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + if (BeginTable("##MessagesTable", 3, kMessageTableFlags)) { + TableSetupColumn("ID"); + TableSetupColumn("Contents"); + TableSetupColumn("Data"); + + TableHeadersRow(); + + for (const auto& message : list_of_texts_) { + TableNextColumn(); + if (Button(core::UppercaseHexWord(message.ID).c_str())) { + current_message_ = message; + DrawMessagePreview(); + } + TableNextColumn(); + TextWrapped("%s", parsed_messages_[message.ID].c_str()); + TableNextColumn(); + TextWrapped( + "%s", + core::UppercaseHexLong(list_of_texts_[message.ID].Address).c_str()); + } + + EndTable(); + } + EndChild(); + } +} + +void MessageEditor::DrawCurrentMessage() { + Button(absl::StrCat("Message ", current_message_.ID).c_str()); + if (InputTextMultiline("##MessageEditor", + &parsed_messages_[current_message_.ID], + ImVec2(ImGui::GetContentRegionAvail().x, 0))) { + current_message_.Data = ParseMessageToData(message_text_box_.text); + DrawMessagePreview(); + } + Separator(); + + Text("Font Graphics"); + gui::BeginPadding(1); + BeginChild("MessageEditorCanvas", ImVec2(0, 130)); + font_gfx_canvas_.DrawBackground(); + font_gfx_canvas_.DrawContextMenu(); + font_gfx_canvas_.DrawBitmap(font_gfx_bitmap_, 0, 0); + font_gfx_canvas_.DrawGrid(); + font_gfx_canvas_.DrawOverlay(); + EndChild(); + gui::EndPadding(); + Separator(); + + Text("Message Preview"); + if (Button("Refresh Bitmap")) { + Renderer::GetInstance().UpdateBitmap(¤t_font_gfx16_bitmap_); + } + gui::BeginPadding(1); + BeginChild("CurrentGfxFont", ImVec2(0, 0), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar); + current_font_gfx16_canvas_.DrawBackground(); + gui::EndPadding(); + current_font_gfx16_canvas_.DrawContextMenu(); + current_font_gfx16_canvas_.DrawBitmap(current_font_gfx16_bitmap_, 0, 0); + current_font_gfx16_canvas_.DrawGrid(); + current_font_gfx16_canvas_.DrawOverlay(); + EndChild(); +} + +void MessageEditor::DrawTextCommands() { + if (BeginChild("##TextCommands", ImVec2(0, 0), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + for (const auto& text_element : TextCommands) { + if (Button(text_element.GenericToken.c_str())) { + } + SameLine(); + TextWrapped("%s", text_element.Description.c_str()); + Separator(); + } + EndChild(); + } +} + +void MessageEditor::DrawDictionary() { + if (ImGui::BeginChild("##DictionaryChild", ImVec2(0, 0), true, + ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + if (BeginTable("##Dictionary", 2, kDictTableFlags)) { + TableSetupColumn("ID"); + TableSetupColumn("Contents"); + + for (const auto& dictionary : all_dictionaries_) { + TableNextColumn(); + Text("%s", core::UppercaseHexWord(dictionary.ID).c_str()); + TableNextColumn(); + Text("%s", dictionary.Contents.c_str()); + } + EndTable(); + } + + EndChild(); + } +} + +// TODO: Fix the command parsing. +void MessageEditor::ReadAllTextDataV2() { + // Read all text data from the ROM. + int pos = kTextData; + int message_id = 0; + + std::vector raw_message; + std::vector parsed_message; + + std::string current_raw_message; + std::string current_parsed_message; + + uint8_t current_byte = 0; + while (current_byte != 0xFF) { + current_byte = rom()->data()[pos++]; + if (current_byte == kMessageTerminator) { + auto message = + MessageData(message_id++, pos, current_raw_message, raw_message, + current_parsed_message, parsed_message); + + list_of_texts_.push_back(message); + + raw_message.clear(); + parsed_message.clear(); + current_raw_message.clear(); + current_parsed_message.clear(); + + continue; + } + + raw_message.push_back(current_byte); + + // Check for command. + TextElement text_element = FindMatchingCommand(current_byte); + if (!text_element.Empty()) { + parsed_message.push_back(current_byte); + if (text_element.HasArgument) { + current_byte = rom()->data()[pos++]; + raw_message.push_back(current_byte); + parsed_message.push_back(current_byte); + } + + current_raw_message.append( + text_element.GetParameterizedToken(current_byte)); + current_parsed_message.append( + text_element.GetParameterizedToken(current_byte)); + + if (text_element.Token == BANKToken) { + pos = kTextData2; + } + + continue; + } + + // Check for special characters. + text_element = FindMatchingSpecial(current_byte); + if (!text_element.Empty()) { + current_raw_message.append(text_element.GetParameterizedToken()); + current_parsed_message.append(text_element.GetParameterizedToken()); + parsed_message.push_back(current_byte); + continue; + } + + // Check for dictionary. + int dictionary = FindDictionaryEntry(current_byte); + if (dictionary >= 0) { + current_raw_message.append("["); + current_raw_message.append(DICTIONARYTOKEN); + current_raw_message.append(":"); + current_raw_message.append(core::UppercaseHexWord(dictionary)); + current_raw_message.append("]"); + + uint32_t address = core::Get24LocalFromPC( + rom()->data(), kPointersDictionaries + (dictionary * 2)); + uint32_t address_end = core::Get24LocalFromPC( + rom()->data(), kPointersDictionaries + ((dictionary + 1) * 2)); + + for (uint32_t i = address; i < address_end; i++) { + parsed_message.push_back(rom()->data()[i]); + current_parsed_message.append(ParseTextDataByte(rom()->data()[i])); + } + + continue; + } + + // Everything else. + if (CharEncoder.contains(current_byte)) { + std::string str = ""; + str.push_back(CharEncoder.at(current_byte)); + current_raw_message.append(str); + current_parsed_message.append(str); + parsed_message.push_back(current_byte); + } + } } void MessageEditor::ReadAllTextData() { - int messageID = 0; - uint8_t current_byte; int pos = kTextData; + int message_id = 0; + uint8_t current_byte; std::vector temp_bytes_raw; std::vector temp_bytes_parsed; @@ -363,12 +377,12 @@ void MessageEditor::ReadAllTextData() { while (true) { current_byte = rom()->data()[pos++]; - if (current_byte == MESSAGETERMINATOR) { + if (current_byte == kMessageTerminator) { auto message = - MessageData(messageID++, pos, current_message_raw, temp_bytes_raw, + MessageData(message_id++, pos, current_message_raw, temp_bytes_raw, current_message_parsed, temp_bytes_parsed); - ListOfTexts.push_back(message); + list_of_texts_.push_back(message); temp_bytes_raw.clear(); temp_bytes_parsed.clear(); @@ -407,7 +421,6 @@ void MessageEditor::ReadAllTextData() { // Check for special characters. text_element = FindMatchingSpecial(current_byte); - if (!text_element.Empty()) { current_message_raw.append(text_element.GetParameterizedToken()); current_message_parsed.append(text_element.GetParameterizedToken()); @@ -449,83 +462,29 @@ void MessageEditor::ReadAllTextData() { } } -TextElement MessageEditor::FindMatchingCommand(uint8_t b) { - TextElement empty_element; - for (const auto text_element : TextCommands) { - if (text_element.ID == b) { - return text_element; +std::string ReplaceAllDictionaryWords(std::string str, + std::vector dictionary) { + std::string temp = str; + for (const auto& entry : dictionary) { + if (absl::StrContains(temp, entry.Contents)) { + temp = absl::StrReplaceAll(temp, {{entry.Contents, entry.Contents}}); } } - return empty_element; + return temp; } -TextElement MessageEditor::FindMatchingSpecial(uint8_t value) { - TextElement empty_element; - for (const auto text_element : SpecialChars) { - if (text_element.ID == value) { - return text_element; - } - } - return empty_element; -} - -MessageEditor::DictionaryEntry MessageEditor::GetDictionaryFromID( - uint8_t value) { - if (value < 0 || value >= AllDictionaries.size()) { +DictionaryEntry MessageEditor::GetDictionaryFromID(uint8_t value) { + if (value < 0 || value >= all_dictionaries_.size()) { return DictionaryEntry(); } - return AllDictionaries[value]; -} - -uint8_t MessageEditor::FindDictionaryEntry(uint8_t value) { - if (value < DICTOFF || value == 0xFF) { - return -1; - } - - return value - DICTOFF; -} - -uint8_t MessageEditor::FindMatchingCharacter(char value) { - for (const auto [key, char_value] : CharEncoder) { - if (value == char_value) { - return key; - } - } - return 0xFF; -} - -string MessageEditor::ParseTextDataByte(uint8_t value) { - if (CharEncoder.contains(value)) { - char c = CharEncoder.at(value); - string str = ""; - str.push_back(c); - return str; - } - - // Check for command. - TextElement textElement = FindMatchingCommand(value); - if (!textElement.Empty()) { - return textElement.GenericToken; - } - - // Check for special characters. - textElement = FindMatchingSpecial(value); - if (!textElement.Empty()) { - return textElement.GenericToken; - } - - // Check for dictionary. - int dictionary = FindDictionaryEntry(value); - if (dictionary >= 0) { - return absl::StrFormat("[%s:%X]", DICTIONARYTOKEN, dictionary); - } - - return ""; + return all_dictionaries_[value]; } void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal, int sizex, int sizey) { - int drawid = srcx + (srcy * 32); + const int num_x_tiles = 16; + const int img_width = 512; // (imgwidth/2) + int draw_id = srcx + (srcy * 32); for (int yl = 0; yl < sizey * 8; yl++) { for (int xl = 0; xl < 4; xl++) { int mx = xl; @@ -533,8 +492,9 @@ void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal, // Formula information to get tile index position in the array. // ((ID / nbrofXtiles) * (imgwidth/2) + (ID - ((ID/16)*16) )) - int tx = ((drawid / 16) * 512) + ((drawid - ((drawid / 16) * 16)) * 4); - uint8_t pixel = font_gfx16_data[tx + (yl * 64) + xl]; + int tx = ((draw_id / num_x_tiles) * img_width) + + ((draw_id - ((draw_id / 16) * 16)) * 4); + uint8_t pixel = font_gfx16_data_[tx + (yl * 64) + xl]; // nx,ny = object position, xx,yy = tile position, xl,yl = pixel // position @@ -552,7 +512,7 @@ void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal, } } -void MessageEditor::DrawStringToPreview(string str) { +void MessageEditor::DrawStringToPreview(std::string str) { for (const auto c : str) { DrawCharacterToPreview(c); } @@ -573,25 +533,25 @@ void MessageEditor::DrawCharacterToPreview(const std::vector& text) { int srcy = value / 16; int srcx = value - (value & (~0xF)); - if (text_pos >= 170) { - text_pos = 0; - text_line++; + if (text_position_ >= 170) { + text_position_ = 0; + text_line_++; } - DrawTileToPreview(text_pos, text_line * 16, srcx, srcy, 0, 1, 2); - text_pos += width_array[value]; + DrawTileToPreview(text_position_, text_line_ * 16, srcx, srcy, 0, 1, 2); + text_position_ += width_array[value]; } else if (value == kLine1) { - text_pos = 0; - text_line = 0; + text_position_ = 0; + text_line_ = 0; } else if (value == kScrollVertical) { - text_pos = 0; - text_line += 1; + text_position_ = 0; + text_line_ += 1; } else if (value == kLine2) { - text_pos = 0; - text_line = 1; + text_position_ = 0; + text_line_ = 1; } else if (value == kLine3) { - text_pos = 0; - text_line = 2; + text_position_ = 0; + text_line_ = 2; } else if (value == 0x6B || value == 0x6D || value == 0x6E || value == 0x77 || value == 0x78 || value == 0x79 || value == 0x7A) { @@ -615,15 +575,15 @@ void MessageEditor::DrawCharacterToPreview(const std::vector& text) { } } -void MessageEditor::DrawMessagePreview() // From Parsing. -{ - text_line = 0; +void MessageEditor::DrawMessagePreview() { + // From Parsing. + text_line_ = 0; for (int i = 0; i < (172 * 4096); i++) { current_font_gfx16_data_[i] = 0; } - text_pos = 0; - DrawCharacterToPreview(CurrentMessage.Data); - shown_lines = 0; + text_position_ = 0; + DrawCharacterToPreview(current_message_.Data); + shown_lines_ = 0; } absl::Status MessageEditor::Cut() { @@ -675,7 +635,7 @@ absl::Status MessageEditor::Save() { int pos = kTextData; bool in_second_bank = false; - for (const auto& message : ListOfTexts) { + for (const auto& message : list_of_texts_) { for (const auto value : message.Data) { RETURN_IF_ERROR(rom()->Write(pos, value)); @@ -695,7 +655,7 @@ absl::Status MessageEditor::Save() { } RETURN_IF_ERROR( - rom()->Write(pos++, MESSAGETERMINATOR)); // , true, "Terminator text" + rom()->Write(pos++, kMessageTerminator)); // , true, "Terminator text" } // Verify that we didn't go over the space available for the second block. @@ -712,9 +672,10 @@ absl::Status MessageEditor::Save() { std::string MessageEditor::DisplayTextOverflowError(int pos, bool bank) { int space = bank ? kTextDataEnd - kTextData : kTextData2End - kTextData2; - string bankSTR = bank ? "1st" : "2nd"; - string posSTR = bank ? absl::StrFormat("%X4", pos & 0xFFFF) - : absl::StrFormat("%X4", (pos - kTextData2) & 0xFFFF); + std::string bankSTR = bank ? "1st" : "2nd"; + std::string posSTR = + bank ? absl::StrFormat("%X4", pos & 0xFFFF) + : absl::StrFormat("%X4", (pos - kTextData2) & 0xFFFF); std::string message = absl::StrFormat( "There is too much text data in the %s block to save.\n" "Available: %X4 | Used: %s", @@ -722,30 +683,6 @@ std::string MessageEditor::DisplayTextOverflowError(int pos, bool bank) { return message; } -// push_backs a command to the text field when the push_back command button is -// pressed or the command is double clicked in the list. -void MessageEditor::InsertCommandButton_Click_1() { - // InsertSelectedText( - // TextCommands[TextCommandList.SelectedIndex].GetParameterizedToken( - // (uint8_t)ParamsBox.HexValue)); -} - -// push_backs a special character to the text field when the push_back command -// button is pressed or the character is double clicked in the list. -void MessageEditor::InsertSpecialButton_Click() { - // InsertSelectedText( - // SpecialChars[SpecialsList.SelectedIndex].GetParameterizedToken()); -} - -void MessageEditor::InsertSelectedText(string str) { - int textboxPos = message_text_box_.selection_start; - from_form = true; - // message_text_box_.Text = message_text_box_.Text.Insert(textboxPos, str); - from_form = false; - message_text_box_.selection_start = textboxPos + str.size(); - message_text_box_.Focus(); -} - void MessageEditor::Delete() { // Determine if any text is selected in the TextBox control. if (message_text_box_.selection_length == 0) { diff --git a/src/app/editor/message/message_editor.h b/src/app/editor/message/message_editor.h index 9d1f5842..b75e471b 100644 --- a/src/app/editor/message/message_editor.h +++ b/src/app/editor/message/message_editor.h @@ -1,229 +1,54 @@ #ifndef YAZE_APP_EDITOR_MESSAGE_EDITOR_H #define YAZE_APP_EDITOR_MESSAGE_EDITOR_H -#include -#include -#include #include -#include #include #include "absl/status/status.h" -#include "absl/strings/str_format.h" -#include "absl/strings/str_replace.h" -#include "absl/strings/str_split.h" #include "app/editor/message/message_data.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gfx/bitmap.h" #include "app/gui/canvas.h" -#include "app/gui/icons.h" #include "app/rom.h" namespace yaze { namespace app { namespace editor { -using std::string; - -// TEXT EDITOR RELATED CONSTANTS -const int kGfxFont = 0x70000; // 2bpp format -const int kTextData = 0xE0000; -const int kTextDataEnd = 0xE7FFF; -const int kTextData2 = 0x75F40; -const int kTextData2End = 0x773FF; -const int kPointersDictionaries = 0x74703; -const int kCharactersWidth = 0x74ADF; - -const string DICTIONARYTOKEN = "D"; -const uint8_t DICTOFF = 0x88; -const string BANKToken = "BANK"; -const uint8_t BANKID = 0x80; +constexpr int kGfxFont = 0x70000; // 2bpp format +constexpr int kTextData2 = 0x75F40; +constexpr int kTextData2End = 0x773FF; +constexpr int kCharactersWidth = 0x74ADF; +constexpr int kNumMessages = 396; +constexpr int kCurrentMessageWidth = 172; +constexpr int kCurrentMessageHeight = 4096; +constexpr int kFontGfxMessageSize = 128; +constexpr int kFontGfxMessageDepth = 8; +constexpr uint8_t kWidthArraySize = 100; constexpr uint8_t kBlockTerminator = 0x80; - -static std::vector ParseMessageToData(string str); - -static ParsedElement FindMatchingElement(string str); - +constexpr uint8_t kMessageBankChangeId = 0x80; constexpr uint8_t kScrollVertical = 0x73; constexpr uint8_t kLine1 = 0x74; constexpr uint8_t kLine2 = 0x75; constexpr uint8_t kLine3 = 0x76; -static const TextElement TextCommands[] = { - TextElement(0x6B, "W", true, "Window border"), - TextElement(0x6D, "P", true, "Window position"), - TextElement(0x6E, "SPD", true, "Scroll speed"), - TextElement(0x7A, "S", true, "Text draw speed"), - TextElement(0x77, "C", true, "Text color"), - TextElement(0x6A, "L", false, "Player name"), - TextElement(0x74, "1", false, "Line 1"), - TextElement(0x75, "2", false, "Line 2"), - TextElement(0x76, "3", false, "Line 3"), - TextElement(0x7E, "K", false, "Wait for key"), - TextElement(0x73, "V", false, "Scroll text"), - TextElement(0x78, "WT", true, "Delay X"), - TextElement(0x6C, "N", true, "BCD number"), - TextElement(0x79, "SFX", true, "Sound effect"), - TextElement(0x71, "CH3", false, "Choose 3"), - TextElement(0x72, "CH2", false, "Choose 2 high"), - TextElement(0x6F, "CH2L", false, "Choose 2 low"), - TextElement(0x68, "CH2I", false, "Choose 2 indented"), - TextElement(0x69, "CHI", false, "Choose item"), - TextElement(0x67, "IMG", false, "Next attract image"), - TextElement(0x80, BANKToken, false, "Bank marker (automatic)"), - TextElement(0x70, "NONO", false, "Crash"), -}; - -static std::vector SpecialChars = { - TextElement(0x43, "...", false, "Ellipsis …"), - TextElement(0x4D, "UP", false, "Arrow ↑"), - TextElement(0x4E, "DOWN", false, "Arrow ↓"), - TextElement(0x4F, "LEFT", false, "Arrow ←"), - TextElement(0x50, "RIGHT", false, "Arrow →"), - TextElement(0x5B, "A", false, "Button Ⓐ"), - TextElement(0x5C, "B", false, "Button Ⓑ"), - TextElement(0x5D, "X", false, "Button ⓧ"), - TextElement(0x5E, "Y", false, "Button ⓨ"), - TextElement(0x52, "HP1L", false, "1 HP left"), - TextElement(0x53, "HP1R", false, "1 HP right"), - TextElement(0x54, "HP2L", false, "2 HP left"), - TextElement(0x55, "HP3L", false, "3 HP left"), - TextElement(0x56, "HP3R", false, "3 HP right"), - TextElement(0x57, "HP4L", false, "4 HP left"), - TextElement(0x58, "HP4R", false, "4 HP right"), - TextElement(0x47, "HY0", false, "Hieroglyph ☥"), - TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"), - TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"), - TextElement(0x4A, "LFL", false, "Link face left"), - TextElement(0x4B, "LFR", false, "Link face right"), -}; - -static const std::unordered_map CharEncoder = { - {0x00, 'A'}, - {0x01, 'B'}, - {0x02, 'C'}, - {0x03, 'D'}, - {0x04, 'E'}, - {0x05, 'F'}, - {0x06, 'G'}, - {0x07, 'H'}, - {0x08, 'I'}, - {0x09, 'J'}, - {0x0A, 'K'}, - {0x0B, 'L'}, - {0x0C, 'M'}, - {0x0D, 'N'}, - {0x0E, 'O'}, - {0x0F, 'P'}, - {0x10, 'Q'}, - {0x11, 'R'}, - {0x12, 'S'}, - {0x13, 'T'}, - {0x14, 'U'}, - {0x15, 'V'}, - {0x16, 'W'}, - {0x17, 'X'}, - {0x18, 'Y'}, - {0x19, 'Z'}, - {0x1A, 'a'}, - {0x1B, 'b'}, - {0x1C, 'c'}, - {0x1D, 'd'}, - {0x1E, 'e'}, - {0x1F, 'f'}, - {0x20, 'g'}, - {0x21, 'h'}, - {0x22, 'i'}, - {0x23, 'j'}, - {0x24, 'k'}, - {0x25, 'l'}, - {0x26, 'm'}, - {0x27, 'n'}, - {0x28, 'o'}, - {0x29, 'p'}, - {0x2A, 'q'}, - {0x2B, 'r'}, - {0x2C, 's'}, - {0x2D, 't'}, - {0x2E, 'u'}, - {0x2F, 'v'}, - {0x30, 'w'}, - {0x31, 'x'}, - {0x32, 'y'}, - {0x33, 'z'}, - {0x34, '0'}, - {0x35, '1'}, - {0x36, '2'}, - {0x37, '3'}, - {0x38, '4'}, - {0x39, '5'}, - {0x3A, '6'}, - {0x3B, '7'}, - {0x3C, '8'}, - {0x3D, '9'}, - {0x3E, '!'}, - {0x3F, '?'}, - {0x40, '-'}, - {0x41, '.'}, - {0x42, ','}, - {0x44, '>'}, - {0x45, '('}, - {0x46, ')'}, - {0x4C, '"'}, - {0x51, '\''}, - {0x59, ' '}, - {0x5A, '<'}, - // {0x5F, '¡'}, {0x60, '¡'}, {0x61, '¡'}, {0x62, ' '}, {0x63, ' '}, {0x64, - // ' '}, - {0x65, ' '}, - {0x66, '_'}, -}; - static TextElement DictionaryElement = TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary"); class MessageEditor : public Editor, public SharedRom { public: - struct DictionaryEntry { - uint8_t ID; - std::string Contents; - std::vector Data; - int Length; - std::string Token; - - DictionaryEntry() = default; - DictionaryEntry(uint8_t i, std::string s) - : Contents(s), ID(i), Length(s.length()) { - Token = absl::StrFormat("[%s:%00X]", DICTIONARYTOKEN, ID); - Data = ParseMessageToData(Contents); - } - - bool ContainedInString(std::string s) { - return s.find(Contents) != std::string::npos; - } - - std::string ReplaceInstancesOfIn(std::string s) { - std::string replacedString = s; - size_t pos = replacedString.find(Contents); - while (pos != std::string::npos) { - replacedString.replace(pos, Contents.length(), Token); - pos = replacedString.find(Contents, pos + Token.length()); - } - return replacedString; - } - }; - MessageEditor() { type_ = EditorType::kMessage; } + absl::Status Initialize(); absl::Status Update() override; void DrawMessageList(); void DrawCurrentMessage(); void DrawTextCommands(); + void DrawDictionary(); - absl::Status Initialize(); - void ReadAllTextData(); - void BuildDictionaryEntries(); + void ReadAllTextDataV2(); + [[deprecated]] void ReadAllTextData(); absl::Status Cut() override; absl::Status Copy() override; @@ -238,67 +63,47 @@ class MessageEditor : public Editor, public SharedRom { absl::Status Save(); void Delete(); void SelectAll(); - // void RegisterTests(ImGuiTestEngine* e) override; - TextElement FindMatchingCommand(uint8_t byte); - TextElement FindMatchingSpecial(uint8_t value); - string ParseTextDataByte(uint8_t value); DictionaryEntry GetDictionaryFromID(uint8_t value); - - static uint8_t FindDictionaryEntry(uint8_t value); - static uint8_t FindMatchingCharacter(char value); void DrawTileToPreview(int x, int y, int srcx, int srcy, int pal, int sizex = 1, int sizey = 1); void DrawCharacterToPreview(char c); void DrawCharacterToPreview(const std::vector& text); - void DrawStringToPreview(string str); + void DrawStringToPreview(std::string str); void DrawMessagePreview(); std::string DisplayTextOverflowError(int pos, bool bank); - void InsertCommandButton_Click_1(); - void InsertSpecialButton_Click(); - void InsertSelectedText(string str); - - static const std::vector AllDicts; - - uint8_t width_array[100]; - string romname = ""; - - int text_line = 0; - int text_pos = 0; - int shown_lines = 0; - int selected_tile = 0; - - bool skip_next = false; - bool from_form = false; - - std::vector ListOfTexts; - std::vector DisplayedMessages; - std::vector ParsedMessages; - - MessageData CurrentMessage; - private: - static const TextElement DictionaryElement; - + bool skip_next = false; bool data_loaded_ = false; - int current_message_id_ = 0; + + int text_line_ = 0; + int text_position_ = 0; + int shown_lines_ = 0; + + uint8_t width_array[kWidthArraySize]; std::string search_text_ = ""; + std::vector font_gfx16_data_; + std::vector current_font_gfx16_data_; + std::vector parsed_messages_; + + std::vector list_of_texts_; + + std::vector all_dictionaries_; + + MessageData current_message_; + + gfx::Bitmap font_gfx_bitmap_; + gfx::Bitmap current_font_gfx16_bitmap_; + gfx::SnesPalette font_preview_colors_; + gui::Canvas font_gfx_canvas_{"##FontGfxCanvas", ImVec2(128, 128)}; gui::Canvas current_font_gfx16_canvas_{"##CurrentMessageGfx", ImVec2(172, 4096)}; - gfx::Bitmap font_gfx_bitmap_; - gfx::Bitmap current_font_gfx16_bitmap_; - - Bytes font_gfx16_data; - Bytes current_font_gfx16_data_; - - gfx::SnesPalette font_preview_colors_; - struct TextBox { std::string text; std::string buffer; @@ -357,8 +162,6 @@ class MessageEditor : public Editor, public SharedRom { TextBox message_text_box_; }; -static std::vector AllDictionaries; - } // namespace editor } // namespace app } // namespace yaze diff --git a/src/app/editor/message/message_editor_test.cc b/src/app/editor/message/message_editor_test.cc deleted file mode 100644 index 67c52ae9..00000000 --- a/src/app/editor/message/message_editor_test.cc +++ /dev/null @@ -1,7 +0,0 @@ -#include "message_editor.h" - -namespace yaze { -namespace app { -namespace editor {} // namespace editor -} // namespace app -} // namespace yaze diff --git a/src/app/editor/music/music_editor.h b/src/app/editor/music/music_editor.h index 64cf360a..b82af24a 100644 --- a/src/app/editor/music/music_editor.h +++ b/src/app/editor/music/music_editor.h @@ -1,19 +1,15 @@ #ifndef YAZE_APP_EDITOR_MUSIC_EDITOR_H #define YAZE_APP_EDITOR_MUSIC_EDITOR_H -#include "imgui/imgui.h" - #include "absl/strings/str_format.h" #include "app/editor/code/assembly_editor.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gui/canvas.h" #include "app/gui/icons.h" #include "app/gui/input.h" #include "app/rom.h" #include "app/zelda3/music/tracker.h" -// #include "snes_spc/demo/demo_util.h" -// #include "snes_spc/demo/wave_writer.h" -// #include "snes_spc/snes_spc/spc.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -81,20 +77,11 @@ class MusicEditor : public SharedRom, public Editor { zelda3::music::Tracker music_tracker_; - // Mix_Music* current_song_ = NULL; - AssemblyEditor assembly_editor_; ImGuiTableFlags toolset_table_flags_ = ImGuiTableFlags_SizingFixedFit; ImGuiTableFlags music_editor_flags_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable; - - ImGuiTableFlags channel_table_flags_ = - ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | - ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | - ImGuiTableFlags_SortMulti | ImGuiTableFlags_RowBg | - ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | - ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollY; }; } // namespace editor diff --git a/src/app/editor/overworld/entity.cc b/src/app/editor/overworld/entity.cc index 3d5227fd..785a9012 100644 --- a/src/app/editor/overworld/entity.cc +++ b/src/app/editor/overworld/entity.cc @@ -1,5 +1,6 @@ #include "app/editor/overworld/entity.h" +#include "app/gui/icons.h" #include "app/gui/input.h" #include "app/gui/style.h" @@ -8,7 +9,6 @@ namespace app { namespace editor { using ImGui::BeginChild; -using ImGui::BeginGroup; using ImGui::Button; using ImGui::Checkbox; using ImGui::EndChild; @@ -16,7 +16,9 @@ using ImGui::SameLine; using ImGui::Selectable; using ImGui::Text; -bool IsMouseHoveringOverEntity(const zelda3::OverworldEntity &entity, +constexpr float kInputFieldSize = 30.f; + +bool IsMouseHoveringOverEntity(const zelda3::GameEntity &entity, ImVec2 canvas_p0, ImVec2 scrolling) { // Get the mouse position relative to the canvas const ImGuiIO &io = ImGui::GetIO(); @@ -31,7 +33,7 @@ bool IsMouseHoveringOverEntity(const zelda3::OverworldEntity &entity, return false; } -void MoveEntityOnGrid(zelda3::OverworldEntity *entity, ImVec2 canvas_p0, +void MoveEntityOnGrid(zelda3::GameEntity *entity, ImVec2 canvas_p0, ImVec2 scrolling, bool free_movement) { // Get the mouse position relative to the canvas const ImGuiIO &io = ImGui::GetIO(); @@ -51,19 +53,20 @@ void MoveEntityOnGrid(zelda3::OverworldEntity *entity, ImVec2 canvas_p0, entity->set_y(new_y); } -void HandleEntityDragging(zelda3::OverworldEntity *entity, ImVec2 canvas_p0, +void HandleEntityDragging(zelda3::GameEntity *entity, ImVec2 canvas_p0, ImVec2 scrolling, bool &is_dragging_entity, - zelda3::OverworldEntity *&dragged_entity, - zelda3::OverworldEntity *¤t_entity, + zelda3::GameEntity *&dragged_entity, + zelda3::GameEntity *¤t_entity, bool free_movement) { std::string entity_type = "Entity"; - if (entity->type_ == zelda3::OverworldEntity::EntityType::kExit) { + if (entity->entity_type_ == zelda3::GameEntity::EntityType::kExit) { entity_type = "Exit"; - } else if (entity->type_ == zelda3::OverworldEntity::EntityType::kEntrance) { + } else if (entity->entity_type_ == + zelda3::GameEntity::EntityType::kEntrance) { entity_type = "Entrance"; - } else if (entity->type_ == zelda3::OverworldEntity::EntityType::kSprite) { + } else if (entity->entity_type_ == zelda3::GameEntity::EntityType::kSprite) { entity_type = "Sprite"; - } else if (entity->type_ == zelda3::OverworldEntity::EntityType::kItem) { + } else if (entity->entity_type_ == zelda3::GameEntity::EntityType::kItem) { entity_type = "Item"; } const auto is_hovering = @@ -87,7 +90,7 @@ void HandleEntityDragging(zelda3::OverworldEntity *entity, ImVec2 canvas_p0, } else if (is_dragging_entity && dragged_entity == entity) { if (ImGui::BeginDragDropSource()) { ImGui::SetDragDropPayload("ENTITY_PAYLOAD", &entity, - sizeof(zelda3::OverworldEntity)); + sizeof(zelda3::GameEntity)); Text("Moving %s ID: %s", entity_type.c_str(), core::UppercaseHexByte(entity->entity_id_).c_str()); ImGui::EndDragDropSource(); @@ -132,7 +135,7 @@ bool DrawOverworldEntrancePopup( } if (ImGui::BeginPopupModal("Entrance editor", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { - gui::InputHex("Map ID", &entrance.map_id_); + gui::InputHexWord("Map ID", &entrance.map_id_); gui::InputHexByte("Entrance ID", &entrance.entrance_id_, kInputFieldSize + 20); gui::InputHex("X", &entrance.x_); @@ -209,7 +212,7 @@ bool DrawExitEditorPopup(zelda3::overworld::OverworldExit &exit) { gui::InputHexWord("Room", &exit.room_id_); SameLine(); gui::InputHex("Entity ID", &exit.entity_id_, 4); - gui::InputHex("Map", &exit.map_id_); + gui::InputHexWord("Map", &exit.map_id_); SameLine(); Checkbox("Automatic", &exit.is_automatic_); @@ -310,11 +313,11 @@ bool DrawExitEditorPopup(zelda3::overworld::OverworldExit &exit) { void DrawItemInsertPopup() { // Contents of the Context Menu if (ImGui::BeginPopup("Item Inserter")) { - static int new_item_id = 0; + static size_t new_item_id = 0; Text("Add Item"); BeginChild("ScrollRegion", ImVec2(150, 150), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); - for (int i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) { + for (size_t i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) { if (Selectable(zelda3::overworld::kSecretItemNames[i].c_str(), i == new_item_id)) { new_item_id = i; @@ -348,10 +351,10 @@ bool DrawItemEditorPopup(zelda3::overworld::OverworldItem &item) { BeginChild("ScrollRegion", ImVec2(150, 150), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); ImGui::BeginGroup(); - for (int i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) { + for (size_t i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) { if (Selectable(zelda3::overworld::kSecretItemNames[i].c_str(), - item.id == i)) { - item.id = i; + item.id_ == i)) { + item.id_ = i; } } ImGui::EndGroup(); @@ -384,7 +387,7 @@ void DrawSpriteTable(std::function onSpriteSelect) { // Initialize items if empty if (items.empty()) { for (int i = 0; i < 256; ++i) { - items.push_back(SpriteItem{i, core::kSpriteDefaultNames[i].data()}); + items.push_back(SpriteItem{i, zelda3::kSpriteDefaultNames[i].data()}); } } diff --git a/src/app/editor/overworld/entity.h b/src/app/editor/overworld/entity.h index 3697972a..7a2904a3 100644 --- a/src/app/editor/overworld/entity.h +++ b/src/app/editor/overworld/entity.h @@ -3,7 +3,6 @@ #include "imgui/imgui.h" -#include "app/editor/overworld_editor.h" #include "app/zelda3/common.h" #include "app/zelda3/overworld/overworld.h" @@ -11,16 +10,16 @@ namespace yaze { namespace app { namespace editor { -bool IsMouseHoveringOverEntity(const zelda3::OverworldEntity &entity, +bool IsMouseHoveringOverEntity(const zelda3::GameEntity &entity, ImVec2 canvas_p0, ImVec2 scrolling); -void MoveEntityOnGrid(zelda3::OverworldEntity *entity, ImVec2 canvas_p0, +void MoveEntityOnGrid(zelda3::GameEntity *entity, ImVec2 canvas_p0, ImVec2 scrolling, bool free_movement = false); -void HandleEntityDragging(zelda3::OverworldEntity *entity, ImVec2 canvas_p0, +void HandleEntityDragging(zelda3::GameEntity *entity, ImVec2 canvas_p0, ImVec2 scrolling, bool &is_dragging_entity, - zelda3::OverworldEntity *&dragged_entity, - zelda3::OverworldEntity *¤t_entity, + zelda3::GameEntity *&dragged_entity, + zelda3::GameEntity *¤t_entity, bool free_movement = false); bool DrawEntranceInserterPopup(); @@ -85,4 +84,4 @@ bool DrawSpriteEditorPopup(zelda3::Sprite &sprite); } // namespace app } // namespace yaze -#endif // YAZE_APP_EDITOR_OVERWORLD_ENTITY_H \ No newline at end of file +#endif // YAZE_APP_EDITOR_OVERWORLD_ENTITY_H diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc similarity index 60% rename from src/app/editor/overworld_editor.cc rename to src/app/editor/overworld/overworld_editor.cc index 64871849..fdc7a64e 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -1,23 +1,19 @@ #include "overworld_editor.h" -#include "ImGuiFileDialog/ImGuiFileDialog.h" -#include "imgui/imgui.h" - #include +#include #include +#include -#include "absl/container/flat_hash_map.h" #include "absl/status/status.h" -#include "absl/status/statusor.h" #include "absl/strings/str_format.h" -#include "app/core/common.h" #include "app/core/constants.h" #include "app/core/platform/clipboard.h" +#include "app/core/platform/renderer.h" #include "app/editor/graphics/palette_editor.h" #include "app/editor/overworld/entity.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" #include "app/gui/icons.h" #include "app/gui/input.h" @@ -25,11 +21,14 @@ #include "app/gui/zeml.h" #include "app/rom.h" #include "app/zelda3/overworld/overworld.h" +#include "imgui/imgui.h" namespace yaze { namespace app { namespace editor { +using core::Renderer; + using ImGui::BeginChild; using ImGui::BeginTabBar; using ImGui::BeginTabItem; @@ -56,81 +55,48 @@ using ImGui::TableSetupColumn; using ImGui::Text; constexpr int kTile16Size = 0x10; -constexpr int kOverworldMapSize = 0x200; - -void OverworldEditor::InitializeZeml() { - // Load zeml string from layouts/overworld.zeml - std::string layout = gui::zeml::LoadFile("overworld.zeml"); - // Parse the zeml string into a Node object - layout_node_ = gui::zeml::Parse(layout); - - gui::zeml::Bind(&*layout_node_.GetNode("OverworldCanvas"), - [this]() { DrawOverworldCanvas(); }); - gui::zeml::Bind(&*layout_node_.GetNode("OverworldTileSelector"), - [this]() { status_ = DrawTileSelector(); }); - gui::zeml::Bind(&*layout_node_.GetNode("OwUsageStats"), [this]() { - if (rom()->is_loaded()) { - status_ = UpdateUsageStats(); - } - }); - gui::zeml::Bind(&*layout_node_.GetNode("owToolset"), - [this]() { status_ = DrawToolset(); }); - gui::zeml::Bind(&*layout_node_.GetNode("OwTile16Editor"), [this]() { - if (rom()->is_loaded()) { - status_ = tile16_editor_.Update(); - } - }); - gui::zeml::Bind(&*layout_node_.GetNode("OwGfxGroupEditor"), [this]() { - if (rom()->is_loaded()) { - status_ = gfx_group_editor_.Update(); - } - }); -} absl::Status OverworldEditor::Update() { status_ = absl::OkStatus(); if (rom()->is_loaded() && !all_gfx_loaded_) { RETURN_IF_ERROR(tile16_editor_.InitBlockset( - &tile16_blockset_bmp_, current_gfx_bmp_, tile16_individual_, + tile16_blockset_bmp_, current_gfx_bmp_, tile16_individual_, *overworld_.mutable_all_tiles_types())); - gfx_group_editor_.InitBlockset(&tile16_blockset_bmp_); RETURN_IF_ERROR(LoadEntranceTileTypes(*rom())); all_gfx_loaded_ = true; } - RETURN_IF_ERROR(UpdateFullscreenCanvas()); + if (overworld_canvas_fullscreen_) { + DrawFullscreenCanvas(); + } + // Draw the overworld editor layout from the ZEML file gui::zeml::Render(layout_node_); return status_; } -absl::Status OverworldEditor::UpdateFullscreenCanvas() { - if (overworld_canvas_fullscreen_) { - static bool use_work_area = true; - static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | - ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoSavedSettings; - const ImGuiViewport *viewport = ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); - ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize - : viewport->Size); - - if (ImGui::Begin("Fullscreen Overworld Editor", - &overworld_canvas_fullscreen_, flags)) { - // Draws the toolset for editing the Overworld. - RETURN_IF_ERROR(DrawToolset()) - DrawOverworldCanvas(); - } - ImGui::End(); +void OverworldEditor::DrawFullscreenCanvas() { + static bool use_work_area = true; + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoSavedSettings; + const ImGuiViewport *viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); + ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); + if (ImGui::Begin("Fullscreen Overworld Editor", &overworld_canvas_fullscreen_, + flags)) { + // Draws the toolset for editing the Overworld. + DrawToolset(); + DrawOverworldCanvas(); } - return absl::OkStatus(); + ImGui::End(); } -absl::Status OverworldEditor::DrawToolset() { +void OverworldEditor::DrawToolset() { static bool show_gfx_group = false; static bool show_properties = false; - if (BeginTable("OWToolset", 23, kToolsetTableFlags, ImVec2(0, 0))) { + if (BeginTable("OWToolset", 22, kToolsetTableFlags, ImVec2(0, 0))) { for (const auto &name : kToolsetColumnNames) ImGui::TableSetupColumn(name.data()); @@ -228,7 +194,7 @@ absl::Status OverworldEditor::DrawToolset() { std::vector png_data; if (gfx::ConvertSurfaceToPNG(maps_bmp_[current_map_].surface(), png_data)) { - CopyImageToClipboard(png_data); + core::CopyImageToClipboard(png_data); } else { status_ = absl::InternalError( "Failed to convert overworld map surface to PNG"); @@ -237,34 +203,27 @@ absl::Status OverworldEditor::DrawToolset() { HOVER_HINT("Copy Map to Clipboard"); TableNextColumn(); // Palette - palette_editor_.DisplayPalette(palette_, overworld_.is_loaded()); + status_ = DisplayPalette(palette_, overworld_.is_loaded()); TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator - TableNextColumn(); // Experimental - Checkbox("Experimental", &show_experimental); - TableNextColumn(); Checkbox("Properties", &show_properties); ImGui::EndTable(); } - if (show_experimental) { - RETURN_IF_ERROR(DrawExperimentalModal()) - } - if (show_tile16_editor_) { // Create a table in ImGui for the Tile16 Editor ImGui::Begin("Tile16 Editor", &show_tile16_editor_, ImGuiWindowFlags_MenuBar); - RETURN_IF_ERROR(tile16_editor_.Update()) + status_ = tile16_editor_.Update(); ImGui::End(); } if (show_gfx_group) { gui::BeginWindowWithDisplaySettings("Gfx Group Editor", &show_gfx_group); - RETURN_IF_ERROR(gfx_group_editor_.Update()) + status_ = gfx_group_editor_.Update(); gui::EndWindowWithDisplaySettings(); } @@ -274,6 +233,7 @@ absl::Status OverworldEditor::DrawToolset() { ImGui::End(); } + // TODO: Customizable shortcuts for the Overworld Editor if (!ImGui::IsAnyItemActive()) { if (ImGui::IsKeyDown(ImGuiKey_1)) { current_mode = EditingMode::PAN; @@ -293,15 +253,15 @@ absl::Status OverworldEditor::DrawToolset() { current_mode = EditingMode::MUSIC; } } - - return absl::OkStatus(); } +constexpr std::array kMapSettingsColumnNames = { + "##WorldId", "##GfxId", "##PalId", "##SprGfxId", + "##5thCol", "##6thCol", "##7thCol", "##8thCol"}; + void OverworldEditor::DrawOverworldMapSettings() { if (BeginTable(kOWMapTable.data(), 8, kOWMapFlags, ImVec2(0, 0), -1)) { - for (const auto &name : - {"##1stCol", "##gfxCol", "##palCol", "##sprgfxCol", "##sprpalCol", - "##msgidCol", "##2ndCol", "##mosaic"}) + for (const auto &name : kMapSettingsColumnNames) ImGui::TableSetupColumn(name); TableNextColumn(); @@ -369,6 +329,81 @@ void OverworldEditor::DrawOverworldMapSettings() { } } +void OverworldEditor::DrawCustomOverworldMapSettings() { + if (BeginTable(kOWMapTable.data(), 15, kOWMapFlags, ImVec2(0, 0), -1)) { + for (const auto &name : kMapSettingsColumnNames) + ImGui::TableSetupColumn(name); + + TableNextColumn(); + ImGui::SetNextItemWidth(120.f); + ImGui::Combo("##world", ¤t_world_, kWorldList.data(), 3); + + static const std::array kCustomMapSettingsColumnNames = { + "TileGfx0", "TileGfx1", "TileGfx2", "TileGfx3", + "TileGfx4", "TileGfx5", "TileGfx6", "TileGfx7"}; + for (int i = 0; i < 8; ++i) { + TableNextColumn(); + ImGui::BeginGroup(); + if (gui::InputHexByte(kCustomMapSettingsColumnNames[i].data(), + overworld_.mutable_overworld_map(current_map_) + ->mutable_custom_tileset(i), + kInputFieldSize)) { + RefreshMapProperties(); + RefreshOverworldMap(); + } + ImGui::EndGroup(); + } + + TableNextColumn(); + ImGui::BeginGroup(); + if (gui::InputHexByte("Palette", + overworld_.mutable_overworld_map(current_map_) + ->mutable_area_palette(), + kInputFieldSize)) { + RefreshMapProperties(); + status_ = RefreshMapPalette(); + RefreshOverworldMap(); + } + ImGui::EndGroup(); + + TableNextColumn(); + ImGui::BeginGroup(); + gui::InputHexByte("Spr Gfx", + overworld_.mutable_overworld_map(current_map_) + ->mutable_sprite_graphics(game_state_), + kInputFieldSize); + ImGui::EndGroup(); + + TableNextColumn(); + ImGui::BeginGroup(); + gui::InputHexByte("Spr Palette", + overworld_.mutable_overworld_map(current_map_) + ->mutable_sprite_palette(game_state_), + kInputFieldSize); + ImGui::EndGroup(); + + TableNextColumn(); + ImGui::BeginGroup(); + gui::InputHexWord( + "Msg Id", + overworld_.mutable_overworld_map(current_map_)->mutable_message_id(), + kInputFieldSize + 20); + ImGui::EndGroup(); + + TableNextColumn(); + ImGui::SetNextItemWidth(100.f); + ImGui::Combo("##World", &game_state_, kGamePartComboString.data(), 3); + + TableNextColumn(); + ImGui::Checkbox( + "##mosaic", + overworld_.mutable_overworld_map(current_map_)->mutable_mosaic()); + HOVER_HINT("Enable Mosaic effect for the current map"); + + ImGui::EndTable(); + } +} + void OverworldEditor::DrawOverworldMaps() { int xx = 0; int yy = 0; @@ -423,31 +458,26 @@ void OverworldEditor::DrawOverworldEdits() { selected_world[index_x][index_y] = current_tile16_; } -void OverworldEditor::RenderUpdatedMapBitmap(const ImVec2 &click_position, - const Bytes &tile_data) { - // Calculate the tile position relative to the current active map - constexpr int tile_size = 16; // Tile size is 16x16 pixels - +void OverworldEditor::RenderUpdatedMapBitmap( + const ImVec2 &click_position, const std::vector &tile_data) { // Calculate the tile index for x and y based on the click_position int tile_index_x = - (static_cast(click_position.x) % kOverworldMapSize) / tile_size; + (static_cast(click_position.x) % kOverworldMapSize) / kTile16Size; int tile_index_y = - (static_cast(click_position.y) % kOverworldMapSize) / tile_size; + (static_cast(click_position.y) % kOverworldMapSize) / kTile16Size; // Calculate the pixel start position based on tile index and tile size ImVec2 start_position; - start_position.x = tile_index_x * tile_size; - start_position.y = tile_index_y * tile_size; - - // Get the current map's bitmap from the BitmapTable - gfx::Bitmap ¤t_bitmap = maps_bmp_[current_map_]; + start_position.x = tile_index_x * kTile16Size; + start_position.y = tile_index_y * kTile16Size; // Update the bitmap's pixel data based on the start_position and tile_data - for (int y = 0; y < tile_size; ++y) { - for (int x = 0; x < tile_size; ++x) { + gfx::Bitmap ¤t_bitmap = maps_bmp_[current_map_]; + for (int y = 0; y < kTile16Size; ++y) { + for (int x = 0; x < kTile16Size; ++x) { int pixel_index = (start_position.y + y) * kOverworldMapSize + (start_position.x + x); - current_bitmap.WriteToPixel(pixel_index, tile_data[y * tile_size + x]); + current_bitmap.WriteToPixel(pixel_index, tile_data[y * kTile16Size + x]); } } @@ -455,66 +485,63 @@ void OverworldEditor::RenderUpdatedMapBitmap(const ImVec2 &click_position, } void OverworldEditor::CheckForOverworldEdits() { - if (current_mode == EditingMode::DRAW_TILE) { - CheckForSelectRectangle(); + CheckForSelectRectangle(); - // User has selected a tile they want to draw from the blockset. - if (!blockset_canvas_.points().empty() && - !ow_map_canvas_.select_rect_active()) { - // Left click is pressed - if (ow_map_canvas_.DrawTilePainter(tile16_individual_[current_tile16_], - 16)) { - DrawOverworldEdits(); - } + // User has selected a tile they want to draw from the blockset. + if (!blockset_canvas_.points().empty() && + !ow_map_canvas_.select_rect_active()) { + // Left click is pressed + if (ow_map_canvas_.DrawTilePainter(tile16_individual_[current_tile16_], + kTile16Size)) { + DrawOverworldEdits(); } + } - if (ow_map_canvas_.select_rect_active()) { - if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) || - ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { - auto &selected_world = - (current_world_ == 0) ? overworld_.mutable_map_tiles()->light_world - : (current_world_ == 1) - ? overworld_.mutable_map_tiles()->dark_world - : overworld_.mutable_map_tiles()->special_world; - // new_start_pos and new_end_pos - auto start = ow_map_canvas_.selected_points()[0]; - auto end = ow_map_canvas_.selected_points()[1]; + if (ow_map_canvas_.select_rect_active()) { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) || + ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + auto &selected_world = + (current_world_ == 0) ? overworld_.mutable_map_tiles()->light_world + : (current_world_ == 1) + ? overworld_.mutable_map_tiles()->dark_world + : overworld_.mutable_map_tiles()->special_world; + // new_start_pos and new_end_pos + auto start = ow_map_canvas_.selected_points()[0]; + auto end = ow_map_canvas_.selected_points()[1]; - // Calculate the bounds of the rectangle in terms of 16x16 tile indices - constexpr int tile16_size = 16; - int start_x = std::floor(start.x / tile16_size) * tile16_size; - int start_y = std::floor(start.y / tile16_size) * tile16_size; - int end_x = std::floor(end.x / tile16_size) * tile16_size; - int end_y = std::floor(end.y / tile16_size) * tile16_size; + // Calculate the bounds of the rectangle in terms of 16x16 tile indices + int start_x = std::floor(start.x / kTile16Size) * kTile16Size; + int start_y = std::floor(start.y / kTile16Size) * kTile16Size; + int end_x = std::floor(end.x / kTile16Size) * kTile16Size; + int end_y = std::floor(end.y / kTile16Size) * kTile16Size; - if (start_x > end_x) std::swap(start_x, end_x); - if (start_y > end_y) std::swap(start_y, end_y); + if (start_x > end_x) std::swap(start_x, end_x); + if (start_y > end_y) std::swap(start_y, end_y); - constexpr int local_map_size = 512; // Size of each local map - // Number of tiles per local map (since each tile is 16x16) - constexpr int tiles_per_local_map = local_map_size / 16; + constexpr int local_map_size = 512; // Size of each local map + // Number of tiles per local map (since each tile is 16x16) + constexpr int tiles_per_local_map = local_map_size / kTile16Size; - for (int y = start_y, i = 0; y <= end_y; y += tile16_size) { - for (int x = start_x; x <= end_x; x += tile16_size, ++i) { - // Determine which local map (512x512) the tile is in - int local_map_x = x / local_map_size; - int local_map_y = y / local_map_size; + for (int y = start_y, i = 0; y <= end_y; y += kTile16Size) { + for (int x = start_x; x <= end_x; x += kTile16Size, ++i) { + // Determine which local map (512x512) the tile is in + int local_map_x = x / local_map_size; + int local_map_y = y / local_map_size; - // Calculate the tile's position within its local map - int tile16_x = (x % local_map_size) / tile16_size; - int tile16_y = (y % local_map_size) / tile16_size; + // Calculate the tile's position within its local map + int tile16_x = (x % local_map_size) / kTile16Size; + int tile16_y = (y % local_map_size) / kTile16Size; - // Calculate the index within the overall map structure - int index_x = local_map_x * tiles_per_local_map + tile16_x; - int index_y = local_map_y * tiles_per_local_map + tile16_y; - int tile16_id = overworld_.GetTileFromPosition( - ow_map_canvas_.selected_tiles()[i]); - selected_world[index_x][index_y] = tile16_id; - } + // Calculate the index within the overall map structure + int index_x = local_map_x * tiles_per_local_map + tile16_x; + int index_y = local_map_y * tiles_per_local_map + tile16_y; + int tile16_id = overworld_.GetTileFromPosition( + ow_map_canvas_.selected_tiles()[i]); + selected_world[index_x][index_y] = tile16_id; } - - RefreshOverworldMap(); } + + RefreshOverworldMap(); } } } @@ -541,7 +568,6 @@ void OverworldEditor::CheckForSelectRectangle() { tile16_ids.push_back(overworld_.GetTileFromPosition(each)); } } - // ow_map_canvas_.mutable_selected_tiles()->clear(); } // Create a composite image of all the tile16s selected ow_map_canvas_.DrawBitmapGroup(tile16_ids, tile16_individual_, 0x10); @@ -549,8 +575,8 @@ void OverworldEditor::CheckForSelectRectangle() { absl::Status OverworldEditor::CheckForCurrentMap() { // 4096x4096, 512x512 maps and some are larges maps 1024x1024 - auto mouse_position = ImGui::GetIO().MousePos; - const auto large_map_size = 1024; + const auto mouse_position = ImGui::GetIO().MousePos; + const int large_map_size = 1024; const auto canvas_zero_point = ow_map_canvas_.zero_point(); // Calculate which small map the mouse is currently over @@ -559,7 +585,7 @@ absl::Status OverworldEditor::CheckForCurrentMap() { // Calculate the index of the map in the `maps_bmp_` vector current_map_ = map_x + map_y * 8; - int current_highlighted_map = current_map_; + const int current_highlighted_map = current_map_; if (current_world_ == 1) { current_map_ += 0x40; } else if (current_world_ == 2) { @@ -568,19 +594,18 @@ absl::Status OverworldEditor::CheckForCurrentMap() { current_parent_ = overworld_.overworld_map(current_map_)->parent(); - auto current_map_x = current_highlighted_map % 8; - auto current_map_y = current_highlighted_map / 8; - if (overworld_.overworld_map(current_map_)->is_large_map() || overworld_.overworld_map(current_map_)->large_index() != 0) { - auto highlight_parent = + const int highlight_parent = overworld_.overworld_map(current_highlighted_map)->parent(); - auto parent_map_x = highlight_parent % 8; - auto parent_map_y = highlight_parent / 8; + const int parent_map_x = highlight_parent % 8; + const int parent_map_y = highlight_parent / 8; ow_map_canvas_.DrawOutline(parent_map_x * kOverworldMapSize, parent_map_y * kOverworldMapSize, large_map_size, large_map_size); } else { + const int current_map_x = current_highlighted_map % 8; + const int current_map_y = current_highlighted_map / 8; ow_map_canvas_.DrawOutline(current_map_x * kOverworldMapSize, current_map_y * kOverworldMapSize, kOverworldMapSize, kOverworldMapSize); @@ -590,7 +615,7 @@ absl::Status OverworldEditor::CheckForCurrentMap() { ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { RefreshOverworldMap(); RETURN_IF_ERROR(RefreshTile16Blockset()); - rom()->UpdateBitmap(&maps_bmp_[current_map_]); + Renderer::GetInstance().UpdateBitmap(&maps_bmp_[current_map_]); maps_bmp_[current_map_].set_modified(false); } @@ -612,10 +637,13 @@ void OverworldEditor::CheckForMousePan() { } } -// TODO: Add @JaredBrian ZSCustomOverworld features to OverworldEditor void OverworldEditor::DrawOverworldCanvas() { if (all_gfx_loaded_) { - DrawOverworldMapSettings(); + if (flags()->overworld.kLoadCustomOverworld) { + DrawCustomOverworldMapSettings(); + } else { + DrawOverworldMapSettings(); + } Separator(); } @@ -638,13 +666,22 @@ void OverworldEditor::DrawOverworldCanvas() { ow_map_canvas_.scrolling()); DrawOverworldItems(); DrawOverworldSprites(); - CheckForOverworldEdits(); + if (current_mode == EditingMode::DRAW_TILE) { + CheckForOverworldEdits(); + } if (IsItemHovered()) status_ = CheckForCurrentMap(); } ow_map_canvas_.DrawGrid(); ow_map_canvas_.DrawOverlay(); EndChild(); + + // Handle mouse wheel activity + if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && + ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) { + ImGui::SetScrollX(ImGui::GetScrollX() + ImGui::GetIO().MouseWheelH * 16.0f); + ImGui::SetScrollY(ImGui::GetScrollY() + ImGui::GetIO().MouseWheel * 16.0f); + } } absl::Status OverworldEditor::DrawTile16Selector() { @@ -686,7 +723,8 @@ void OverworldEditor::DrawTile8Selector() { graphics_bin_canvas_.DrawBackground(); graphics_bin_canvas_.DrawContextMenu(); if (all_gfx_loaded_) { - for (auto &[key, value] : rom()->bitmap_manager()) { + int key = 0; + for (auto &value : rom()->gfx_sheets()) { int offset = 0x40 * (key + 1); int top_left_y = graphics_bin_canvas_.zero_point().y + 2; if (key >= 1) { @@ -694,10 +732,11 @@ void OverworldEditor::DrawTile8Selector() { } auto texture = value.texture(); graphics_bin_canvas_.draw_list()->AddImage( - (void *)texture, + (ImTextureID)(intptr_t)texture, ImVec2(graphics_bin_canvas_.zero_point().x + 2, top_left_y), ImVec2(graphics_bin_canvas_.zero_point().x + 0x100, graphics_bin_canvas_.zero_point().y + offset)); + key++; } } graphics_bin_canvas_.DrawGrid(); @@ -705,16 +744,15 @@ void OverworldEditor::DrawTile8Selector() { } absl::Status OverworldEditor::DrawAreaGraphics() { - if (overworld_.is_loaded()) { - if (current_graphics_set_.count(current_map_) == 0) { - overworld_.set_current_map(current_map_); - palette_ = overworld_.AreaPalette(); - gfx::Bitmap bmp; - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap( - 0x80, kOverworldMapSize, 0x08, overworld_.current_graphics(), bmp, - palette_)); - current_graphics_set_[current_map_] = bmp; - } + if (overworld_.is_loaded() && + current_graphics_set_.count(current_map_) == 0) { + overworld_.set_current_map(current_map_); + palette_ = overworld_.current_area_palette(); + gfx::Bitmap bmp; + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + 0x80, kOverworldMapSize, 0x08, overworld_.current_graphics(), bmp, + palette_)); + current_graphics_set_[current_map_] = bmp; } gui::BeginPadding(3); @@ -765,7 +803,6 @@ void OverworldEditor::DrawOverworldEntrances(ImVec2 canvas_p0, ImVec2 scrolling, for (auto &each : overworld_.entrances()) { if (each.map_id_ < 0x40 + (current_world_ * 0x40) && each.map_id_ >= (current_world_ * 0x40) && !each.deleted) { - // Make this yellow auto color = ImVec4(255, 255, 0, 100); if (each.is_hole_) { color = ImVec4(255, 255, 255, 200); @@ -881,10 +918,8 @@ void OverworldEditor::DrawOverworldItems() { int i = 0; for (auto &item : *overworld_.mutable_all_items()) { // Get the item's bitmap and real X and Y positions - if (item.room_map_id < 0x40 + (current_world_ * 0x40) && - item.room_map_id >= (current_world_ * 0x40) && !item.deleted) { - std::string item_name = zelda3::overworld::kSecretItemNames[item.id]; - + if (item.room_map_id_ < 0x40 + (current_world_ * 0x40) && + item.room_map_id_ >= (current_world_ * 0x40) && !item.deleted) { ow_map_canvas_.DrawRect(item.x_, item.y_, 16, 16, ImVec4(255, 0, 0, 150)); if (current_mode == EditingMode::ITEMS) { @@ -901,6 +936,12 @@ void OverworldEditor::DrawOverworldItems() { current_entity_ = &item; } } + std::string item_name = ""; + if (item.id_ < zelda3::overworld::kSecretItemNames.size()) { + item_name = zelda3::overworld::kSecretItemNames[item.id_]; + } else { + item_name = absl::StrFormat("0x%02X", item.id_); + } ow_map_canvas_.DrawText(item_name, item.x_, item.y_); } i++; @@ -926,13 +967,24 @@ void OverworldEditor::DrawOverworldItems() { void OverworldEditor::DrawOverworldSprites() { int i = 0; for (auto &sprite : *overworld_.mutable_sprites(game_state_)) { - int map_id = sprite.map_id(); - int map_x = sprite.map_x(); - int map_y = sprite.map_y(); + if (!sprite.deleted()) { + // int map_id = sprite.map_id(); + // map x and map y are relative to the map + // So we need to check if the map is large or small then add the offset - if (map_id < 0x40 + (current_world_ * 0x40) && - map_id >= (current_world_ * 0x40) && !sprite.deleted()) { - ow_map_canvas_.DrawRect(map_x, map_y, 16, 16, + // Calculate the superX and superY values + // int superY = map_id / 8; + // int superX = map_id % 8; + + // Calculate the map_x and map_y values + int map_x = sprite.map_x(); + int map_y = sprite.map_y(); + + // Calculate the actual map_x and map_y values + // map_x += superX * 512; + // map_y += superY * 512; + + ow_map_canvas_.DrawRect(map_x, map_y, kTile16Size, kTile16Size, /*magenta*/ ImVec4(255, 0, 255, 150)); if (current_mode == EditingMode::SPRITES) { HandleEntityDragging(&sprite, ow_map_canvas_.zero_point(), @@ -945,6 +997,10 @@ void OverworldEditor::DrawOverworldSprites() { current_sprite_ = sprite; } } + if (sprite_previews_[sprite.id()].is_active()) { + ow_map_canvas_.DrawBitmap(sprite_previews_[sprite.id()], map_x, map_y, + 2.0f); + } ow_map_canvas_.DrawText(absl::StrFormat("%s", sprite.name()), map_x, map_y); @@ -970,61 +1026,78 @@ void OverworldEditor::DrawOverworldSprites() { } } -// ---------------------------------------------------------------------------- +absl::Status OverworldEditor::Save() { + if (flags()->overworld.kSaveOverworldMaps) { + RETURN_IF_ERROR(overworld_.CreateTile32Tilemap()); + RETURN_IF_ERROR(overworld_.SaveMap32Tiles()); + RETURN_IF_ERROR(overworld_.SaveMap16Tiles()); + RETURN_IF_ERROR(overworld_.SaveOverworldMaps()); + } + if (flags()->overworld.kSaveOverworldEntrances) { + RETURN_IF_ERROR(overworld_.SaveEntrances()); + } + if (flags()->overworld.kSaveOverworldExits) { + RETURN_IF_ERROR(overworld_.SaveExits()); + } + if (flags()->overworld.kSaveOverworldItems) { + RETURN_IF_ERROR(overworld_.SaveItems()); + } + if (flags()->overworld.kSaveOverworldProperties) { + RETURN_IF_ERROR(overworld_.SaveMapProperties()); + } + return absl::OkStatus(); +} absl::Status OverworldEditor::LoadGraphics() { // Load the Link to the Past overworld. RETURN_IF_ERROR(overworld_.Load(*rom())) - palette_ = overworld_.AreaPalette(); + palette_ = overworld_.current_area_palette(); // Create the area graphics image - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(0x80, kOverworldMapSize, 0x40, - overworld_.current_graphics(), - current_gfx_bmp_, palette_)); + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + 0x80, kOverworldMapSize, 0x40, overworld_.current_graphics(), + current_gfx_bmp_, palette_)); // Create the tile16 blockset image - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(0x80, 0x2000, 0x08, - overworld_.Tile16Blockset(), - tile16_blockset_bmp_, palette_)); + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + 0x80, 0x2000, 0x08, overworld_.tile16_blockset_data(), + tile16_blockset_bmp_, palette_)); map_blockset_loaded_ = true; // Copy the tile16 data into individual tiles. - auto tile16_data = overworld_.Tile16Blockset(); + auto tile16_data = overworld_.tile16_blockset_data(); + tile16_individual_.reserve(zelda3::overworld::kNumTile16Individual); // Loop through the tiles and copy their pixel data into separate vectors - for (int i = 0; i < 4096; i++) { - // Create a new vector for the pixel data of the current tile - Bytes tile_data(16 * 16, 0x00); // More efficient initialization + for (uint i = 0; i < zelda3::overworld::kNumTile16Individual; i++) { + std::vector tile_data(kTile16Size * kTile16Size, 0x00); // Copy the pixel data for the current tile into the vector - for (int ty = 0; ty < 16; ty++) { - for (int tx = 0; tx < 16; tx++) { - int position = tx + (ty * 0x10); + for (int ty = 0; ty < kTile16Size; ty++) { + for (int tx = 0; tx < kTile16Size; tx++) { + int position = tx + (ty * kTile16Size); uint8_t value = - tile16_data[(i % 8 * 16) + (i / 8 * 16 * 0x80) + (ty * 0x80) + tx]; + tile16_data[(i % 8 * kTile16Size) + (i / 8 * kTile16Size * 0x80) + + (ty * 0x80) + tx]; tile_data[position] = value; } } // Add the vector for the current tile to the vector of tile pixel data tile16_individual_data_.push_back(tile_data); - } - - // Render the bitmaps of each tile. - for (int id = 0; id < 4096; id++) { tile16_individual_.emplace_back(); - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap( - 0x10, 0x10, 0x80, tile16_individual_data_[id], tile16_individual_[id], - palette_)); + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + kTile16Size, kTile16Size, 0x80, tile16_individual_data_[i], + tile16_individual_[i], palette_)); } // Render the overworld maps loaded from the ROM. for (int i = 0; i < zelda3::overworld::kNumOverworldMaps; ++i) { overworld_.set_current_map(i); - auto palette = overworld_.AreaPalette(); - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap( - kOverworldMapSize, kOverworldMapSize, 0x200, overworld_.BitmapData(), - maps_bmp_[i], palette)); + auto palette = overworld_.current_area_palette(); + RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( + kOverworldMapSize, kOverworldMapSize, 0x200, + overworld_.current_map_bitmap_data(), maps_bmp_[i], palette)); } if (flags()->overworld.kDrawOverworldSprites) { @@ -1037,18 +1110,163 @@ absl::Status OverworldEditor::LoadGraphics() { absl::Status OverworldEditor::LoadSpriteGraphics() { // Render the sprites for each Overworld map for (int i = 0; i < 3; i++) - for (auto const &sprite : overworld_.Sprites(i)) { - int width = sprite.Width(); - int height = sprite.Height(); - int depth = 0x40; + for (auto const &sprite : overworld_.sprites(i)) { + int width = sprite.width(); + int height = sprite.height(); + int depth = 0x10; auto spr_gfx = sprite.PreviewGraphics(); + if (spr_gfx.empty() || width == 0 || height == 0) { + continue; + } sprite_previews_[sprite.id()].Create(width, height, depth, spr_gfx); RETURN_IF_ERROR(sprite_previews_[sprite.id()].ApplyPalette(palette_)); - rom()->RenderBitmap(&(sprite_previews_[sprite.id()])); + Renderer::GetInstance().RenderBitmap(&(sprite_previews_[sprite.id()])); } return absl::OkStatus(); } +void OverworldEditor::RefreshChildMap(int map_index) { + overworld_.mutable_overworld_map(map_index)->LoadAreaGraphics(); + status_ = overworld_.mutable_overworld_map(map_index)->BuildTileset(); + PRINT_IF_ERROR(status_); + status_ = overworld_.mutable_overworld_map(map_index)->BuildTiles16Gfx( + *overworld_.mutable_tiles16(), overworld_.tiles16().size()); + PRINT_IF_ERROR(status_); + status_ = overworld_.mutable_overworld_map(map_index)->BuildBitmap( + overworld_.GetMapTiles(current_world_)); + maps_bmp_[map_index].set_data( + overworld_.mutable_overworld_map(map_index)->bitmap_data()); + maps_bmp_[map_index].set_modified(true); + PRINT_IF_ERROR(status_); +} + +void OverworldEditor::RefreshOverworldMap() { + std::vector> futures; + int indices[4]; + + auto refresh_map_async = [this](int map_index) { + RefreshChildMap(map_index); + }; + + int source_map_id = current_map_; + bool is_large = overworld_.overworld_map(current_map_)->is_large_map(); + if (is_large) { + source_map_id = current_parent_; + // We need to update the map and its siblings if it's a large map + for (int i = 1; i < 4; i++) { + int sibling_index = overworld_.overworld_map(source_map_id)->parent() + i; + if (i >= 2) sibling_index += 6; + futures.push_back( + std::async(std::launch::async, refresh_map_async, sibling_index)); + indices[i] = sibling_index; + } + } + indices[0] = source_map_id; + futures.push_back( + std::async(std::launch::async, refresh_map_async, source_map_id)); + + for (auto &each : futures) { + each.get(); + } + int n = is_large ? 4 : 1; + // We do texture updating on the main thread + for (int i = 0; i < n; ++i) { + Renderer::GetInstance().UpdateBitmap(&maps_bmp_[indices[i]]); + } +} + +absl::Status OverworldEditor::RefreshMapPalette() { + RETURN_IF_ERROR( + overworld_.mutable_overworld_map(current_map_)->LoadPalette()); + const auto current_map_palette = overworld_.current_area_palette(); + + if (overworld_.overworld_map(current_map_)->is_large_map()) { + // We need to update the map and its siblings if it's a large map + for (int i = 1; i < 4; i++) { + int sibling_index = overworld_.overworld_map(current_map_)->parent() + i; + if (i >= 2) sibling_index += 6; + RETURN_IF_ERROR( + overworld_.mutable_overworld_map(sibling_index)->LoadPalette()); + RETURN_IF_ERROR( + maps_bmp_[sibling_index].ApplyPalette(current_map_palette)); + } + } + + RETURN_IF_ERROR(maps_bmp_[current_map_].ApplyPalette(current_map_palette)); + return absl::OkStatus(); +} + +void OverworldEditor::RefreshMapProperties() { + auto ¤t_ow_map = *overworld_.mutable_overworld_map(current_map_); + if (current_ow_map.is_large_map()) { + // We need to copy the properties from the parent map to the children + for (int i = 1; i < 4; i++) { + int sibling_index = current_ow_map.parent() + i; + if (i >= 2) { + sibling_index += 6; + } + auto &map = *overworld_.mutable_overworld_map(sibling_index); + map.set_area_graphics(current_ow_map.area_graphics()); + map.set_area_palette(current_ow_map.area_palette()); + map.set_sprite_graphics(game_state_, + current_ow_map.sprite_graphics(game_state_)); + map.set_sprite_palette(game_state_, + current_ow_map.sprite_palette(game_state_)); + map.set_message_id(current_ow_map.message_id()); + } + } +} + +absl::Status OverworldEditor::RefreshTile16Blockset() { + if (current_blockset_ == + overworld_.overworld_map(current_map_)->area_graphics()) { + return absl::OkStatus(); + } + current_blockset_ = overworld_.overworld_map(current_map_)->area_graphics(); + + overworld_.set_current_map(current_map_); + palette_ = overworld_.current_area_palette(); + // Create the tile16 blockset image + Renderer::GetInstance().UpdateBitmap(&tile16_blockset_bmp_); + RETURN_IF_ERROR(tile16_blockset_bmp_.ApplyPalette(palette_)); + + // Copy the tile16 data into individual tiles. + const auto tile16_data = overworld_.tile16_blockset_data(); + + std::vector> futures; + // Loop through the tiles and copy their pixel data into separate vectors + for (uint i = 0; i < zelda3::overworld::kNumTile16Individual; i++) { + futures.push_back(std::async( + std::launch::async, + [&](int index) { + std::vector tile_data(16 * 16, 0x00); + for (int ty = 0; ty < 16; ty++) { + for (int tx = 0; tx < 16; tx++) { + int position = tx + (ty * 0x10); + uint8_t value = + tile16_data[(index % 8 * 16) + (index / 8 * 16 * 0x80) + + (ty * 0x80) + tx]; + tile_data[position] = value; + } + } + tile16_individual_[index].set_data(tile_data); + }, + i)); + } + + for (auto &future : futures) { + future.get(); + } + + // Render the bitmaps of each tile. + for (uint id = 0; id < zelda3::overworld::kNumTile16Individual; id++) { + RETURN_IF_ERROR(tile16_individual_[id].ApplyPalette(palette_)); + Renderer::GetInstance().UpdateBitmap(&tile16_individual_[id]); + } + + return absl::OkStatus(); +} + void OverworldEditor::DrawOverworldProperties() { static bool init_properties = false; @@ -1056,87 +1274,97 @@ void OverworldEditor::DrawOverworldProperties() { for (int i = 0; i < 0x40; i++) { std::string area_graphics_str = absl::StrFormat( "%02hX", overworld_.overworld_map(i)->area_graphics()); - properties_canvas_.mutable_labels(0)->push_back(area_graphics_str); + properties_canvas_.mutable_labels(OverworldProperty::LW_AREA_GFX) + ->push_back(area_graphics_str); + area_graphics_str = absl::StrFormat( "%02hX", overworld_.overworld_map(i + 0x40)->area_graphics()); - properties_canvas_.mutable_labels(3)->push_back(area_graphics_str); - } - for (int i = 0; i < 0x40; i++) { + properties_canvas_.mutable_labels(OverworldProperty::DW_AREA_GFX) + ->push_back(area_graphics_str); + std::string area_palette_str = absl::StrFormat("%02hX", overworld_.overworld_map(i)->area_palette()); - properties_canvas_.mutable_labels(1)->push_back(area_palette_str); + properties_canvas_.mutable_labels(OverworldProperty::LW_AREA_PAL) + ->push_back(area_palette_str); + area_palette_str = absl::StrFormat( "%02hX", overworld_.overworld_map(i + 0x40)->area_palette()); - properties_canvas_.mutable_labels(4)->push_back(area_palette_str); - } - for (int i = 0; i < 0x40; i++) { + properties_canvas_.mutable_labels(OverworldProperty::DW_AREA_PAL) + ->push_back(area_palette_str); std::string sprite_gfx_str = absl::StrFormat( "%02hX", overworld_.overworld_map(i)->sprite_graphics(1)); - properties_canvas_.mutable_labels(6)->push_back(sprite_gfx_str); + properties_canvas_.mutable_labels(OverworldProperty::LW_SPR_GFX_PART1) + ->push_back(sprite_gfx_str); + + sprite_gfx_str = absl::StrFormat( + "%02hX", overworld_.overworld_map(i)->sprite_graphics(2)); + properties_canvas_.mutable_labels(OverworldProperty::LW_SPR_GFX_PART2) + ->push_back(sprite_gfx_str); + sprite_gfx_str = absl::StrFormat( "%02hX", overworld_.overworld_map(i + 0x40)->sprite_graphics(1)); - properties_canvas_.mutable_labels(7)->push_back(sprite_gfx_str); - } - for (int i = 0; i < 0x40; i++) { + properties_canvas_.mutable_labels(OverworldProperty::DW_SPR_GFX_PART1) + ->push_back(sprite_gfx_str); + + sprite_gfx_str = absl::StrFormat( + "%02hX", overworld_.overworld_map(i + 0x40)->sprite_graphics(2)); + properties_canvas_.mutable_labels(OverworldProperty::DW_SPR_GFX_PART2) + ->push_back(sprite_gfx_str); + std::string sprite_palette_str = absl::StrFormat( "%02hX", overworld_.overworld_map(i)->sprite_palette(1)); - properties_canvas_.mutable_labels(2)->push_back(sprite_palette_str); + properties_canvas_.mutable_labels(OverworldProperty::LW_SPR_PAL_PART1) + ->push_back(sprite_palette_str); + + sprite_palette_str = absl::StrFormat( + "%02hX", overworld_.overworld_map(i)->sprite_palette(2)); + properties_canvas_.mutable_labels(OverworldProperty::LW_SPR_PAL_PART2) + ->push_back(sprite_palette_str); + sprite_palette_str = absl::StrFormat( "%02hX", overworld_.overworld_map(i + 0x40)->sprite_palette(1)); - properties_canvas_.mutable_labels(5)->push_back(sprite_palette_str); + properties_canvas_.mutable_labels(OverworldProperty::DW_SPR_PAL_PART1) + ->push_back(sprite_palette_str); + + sprite_palette_str = absl::StrFormat( + "%02hX", overworld_.overworld_map(i + 0x40)->sprite_palette(2)); + properties_canvas_.mutable_labels(OverworldProperty::DW_SPR_PAL_PART2) + ->push_back(sprite_palette_str); } init_properties = true; } Text("Area Gfx LW/DW"); - properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 1.0f, 32, 0); + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::LW_AREA_GFX); SameLine(); - properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 1.0f, 32, 1); + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::DW_AREA_GFX); ImGui::Separator(); Text("Sprite Gfx LW/DW"); - properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 1.0f, 32, 6); + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::LW_SPR_GFX_PART1); SameLine(); - properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 1.0f, 32, 7); + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::DW_SPR_GFX_PART1); + SameLine(); + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::LW_SPR_GFX_PART2); + SameLine(); + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::DW_SPR_GFX_PART2); ImGui::Separator(); Text("Area Pal LW/DW"); - properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 1.0f, 32, 2); + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::LW_AREA_PAL); SameLine(); - properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 1.0f, 32, 3); - - static bool dark_world = false; - int world = dark_world ? 3 : 0; - static int current = 0; + properties_canvas_.UpdateInfoGrid(ImVec2(256, 256), 8, 2.0f, 32, + OverworldProperty::DW_AREA_PAL); static bool show_gfx_group = false; Checkbox("Show Gfx Group Editor", &show_gfx_group); - if (Checkbox("Dark World", &dark_world)) { - properties_canvas_.set_current_labels(current + world); - } - SameLine(); - if (Button("Area Graphics")) { - current = 0; - properties_canvas_.set_current_labels(current + world); - } - SameLine(); - if (Button("Area Palette")) { - current = 1; - properties_canvas_.set_current_labels(current + world); - } - if (Button("Sprite Graphics")) { - if (dark_world) { - properties_canvas_.set_current_labels(7); - } else { - properties_canvas_.set_current_labels(6); - } - } - SameLine(); - if (Button("Sprite Palette")) { - current = 2; - properties_canvas_.set_current_labels(current + world); - } - if (show_gfx_group) { gui::BeginWindowWithDisplaySettings("Gfx Group Editor", &show_gfx_group); status_ = gfx_group_editor_.Update(); @@ -1144,55 +1372,6 @@ void OverworldEditor::DrawOverworldProperties() { } } -absl::Status OverworldEditor::DrawExperimentalModal() { - ImGui::Begin("Experimental", &show_experimental); - - DrawDebugWindow(); - - gui::TextWithSeparators("PROTOTYPE OVERWORLD TILEMAP LOADER"); - Text("Please provide two files:"); - Text("One based on MAPn.DAT, which represents the overworld tilemap"); - Text("One based on MAPDATn.DAT, which is the tile32 configurations."); - Text("Currently, loading CGX for this component is NOT supported. "); - Text("Please load a US ROM of LTTP (JP ROM support coming soon)."); - Text( - "Once you've loaded the files, you can click the button below to load " - "the tilemap into the editor"); - - ImGui::InputText("##TilemapFile", &ow_tilemap_filename_); - SameLine(); - gui::FileDialogPipeline( - "ImportTilemapsKey", ".DAT,.dat\0", "Tilemap Hex File", [this]() { - ow_tilemap_filename_ = ImGuiFileDialog::Instance()->GetFilePathName(); - }); - - ImGui::InputText("##Tile32ConfigurationFile", - &tile32_configuration_filename_); - SameLine(); - gui::FileDialogPipeline("ImportTile32Key", ".DAT,.dat\0", "Tile32 Hex File", - [this]() { - tile32_configuration_filename_ = - ImGuiFileDialog::Instance()->GetFilePathName(); - }); - - if (Button("Load Prototype Overworld with ROM graphics")) { - RETURN_IF_ERROR(LoadGraphics()) - all_gfx_loaded_ = true; - } - - gui::TextWithSeparators("Configuration"); - - gui::InputHexShort("Tilemap File Offset (High)", &tilemap_file_offset_high_); - gui::InputHexShort("Tilemap File Offset (Low)", &tilemap_file_offset_low_); - - gui::InputHexShort("LW Maps to Load", &light_maps_to_load_); - gui::InputHexShort("DW Maps to Load", &dark_maps_to_load_); - gui::InputHexShort("SP Maps to Load", &sp_maps_to_load_); - - ImGui::End(); - return absl::OkStatus(); -} - absl::Status OverworldEditor::UpdateUsageStats() { if (BeginTable("UsageStatsTable", 3, kOWEditFlags, ImVec2(0, 0))) { TableSetupColumn("Entrances"); @@ -1206,7 +1385,9 @@ absl::Status OverworldEditor::UpdateUsageStats() { if (BeginChild("UnusedSpritesetScroll", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar)) { for (int i = 0; i < 0x81; i++) { - std::string str = absl::StrFormat("%#x", i); + auto entrance_name = rom()->resource_label()->GetLabel( + "Dungeon Entrance Names", core::UppercaseHexByte(i)); + std::string str = absl::StrFormat("%#x - %s", i, entrance_name); if (Selectable(str.c_str(), selected_entrance_ == i, overworld_.entrances().at(i).deleted ? ImGuiSelectableFlags_Disabled @@ -1241,16 +1422,6 @@ absl::Status OverworldEditor::UpdateUsageStats() { return absl::OkStatus(); } -void OverworldEditor::CalculateUsageStats() { - absl::flat_hash_map entrance_usage; - for (auto each_entrance : overworld_.entrances()) { - if (each_entrance.map_id_ < 0x40 + (current_world_ * 0x40) && - each_entrance.map_id_ >= (current_world_ * 0x40)) { - entrance_usage[each_entrance.entrance_id_]++; - } - } -} - void OverworldEditor::DrawUsageGrid() { // Create a grid of 8x8 squares int totalSquares = 128; @@ -1271,9 +1442,9 @@ void OverworldEditor::DrawUsageGrid() { // Set highlight color if needed if (highlight) { - PushStyleColor( - ImGuiCol_Button, - ImVec4(1.0f, 0.5f, 0.0f, 1.0f)); // Or any highlight color + PushStyleColor(ImGuiCol_Button, + ImVec4(1.0f, 0.5f, 0.0f, + 1.0f)); // Or any highlight color } // Create a button or selectable for each square @@ -1299,37 +1470,6 @@ void OverworldEditor::DrawUsageGrid() { } } -absl::Status OverworldEditor::LoadAnimatedMaps() { - int world_index = 0; - static std::vector animated_built(0x40, false); - if (!animated_built[world_index]) { - animated_maps_[world_index] = maps_bmp_[world_index]; - auto &map = *overworld_.mutable_overworld_map(world_index); - map.DrawAnimatedTiles(); - RETURN_IF_ERROR(map.BuildTileset()); - RETURN_IF_ERROR(map.BuildTiles16Gfx(overworld_.tiles16().size())); - OWBlockset blockset; - if (current_world_ == 0) { - blockset = overworld_.map_tiles().light_world; - } else if (current_world_ == 1) { - blockset = overworld_.map_tiles().dark_world; - } else { - blockset = overworld_.map_tiles().special_world; - } - RETURN_IF_ERROR(map.BuildBitmap(blockset)); - - RETURN_IF_ERROR(rom()->CreateAndRenderBitmap( - kOverworldMapSize, kOverworldMapSize, 0x200, map.bitmap_data(), - animated_maps_[world_index], *map.mutable_current_palette())); - - animated_built[world_index] = true; - } - - return absl::OkStatus(); -} - -// ---------------------------------------------------------------------------- - void OverworldEditor::DrawDebugWindow() { Text("Current Map: %d", current_map_); Text("Current Tile16: %d", current_tile16_); @@ -1360,6 +1500,35 @@ void OverworldEditor::DrawDebugWindow() { } } +void OverworldEditor::InitializeZeml() { + // Load zeml string from layouts/overworld.zeml + std::string layout = gui::zeml::LoadFile("overworld.zeml"); + // Parse the zeml string into a Node object + layout_node_ = gui::zeml::Parse(layout); + + gui::zeml::Bind(&*layout_node_.GetNode("OverworldCanvas"), + [this]() { DrawOverworldCanvas(); }); + gui::zeml::Bind(&*layout_node_.GetNode("OverworldTileSelector"), + [this]() { status_ = DrawTileSelector(); }); + gui::zeml::Bind(&*layout_node_.GetNode("OwUsageStats"), [this]() { + if (rom()->is_loaded()) { + status_ = UpdateUsageStats(); + } + }); + gui::zeml::Bind(&*layout_node_.GetNode("owToolset"), + [this]() { DrawToolset(); }); + gui::zeml::Bind(&*layout_node_.GetNode("OwTile16Editor"), [this]() { + if (rom()->is_loaded()) { + status_ = tile16_editor_.Update(); + } + }); + gui::zeml::Bind(&*layout_node_.GetNode("OwGfxGroupEditor"), [this]() { + if (rom()->is_loaded()) { + status_ = gfx_group_editor_.Update(); + } + }); +} + } // namespace editor } // namespace app } // namespace yaze diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld/overworld_editor.h similarity index 60% rename from src/app/editor/overworld_editor.h rename to src/app/editor/overworld/overworld_editor.h index bd45c76e..dbbacd76 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld/overworld_editor.h @@ -1,8 +1,6 @@ #ifndef YAZE_APP_EDITOR_OVERWORLDEDITOR_H #define YAZE_APP_EDITOR_OVERWORLDEDITOR_H -#include "imgui/imgui.h" - #include #include @@ -10,13 +8,11 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_format.h" -#include "app/core/common.h" +#include "app/editor/editor.h" #include "app/editor/graphics/gfx_group_editor.h" #include "app/editor/graphics/palette_editor.h" #include "app/editor/graphics/tile16_editor.h" #include "app/editor/overworld/entity.h" -#include "app/editor/utils/editor.h" -#include "app/editor/utils/gfx_context.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" @@ -25,24 +21,24 @@ #include "app/gui/zeml.h" #include "app/rom.h" #include "app/zelda3/overworld/overworld.h" +#include "imgui/imgui.h" namespace yaze { namespace app { namespace editor { -static constexpr uint k4BPP = 4; -static constexpr uint kByteSize = 3; -static constexpr uint kMessageIdSize = 5; -static constexpr uint kNumSheetsToLoad = 223; -static constexpr uint kTile8DisplayHeight = 64; -static constexpr float kInputFieldSize = 30.f; - -static constexpr absl::string_view kToolsetColumnNames[] = { - "#undoTool", "#redoTool", "#separator2", "#zoomOutTool", - "#zoomInTool", "#separator", "#drawTool", "#history", - "#entranceTool", "#exitTool", "#itemTool", "#spriteTool", - "#transportTool", "#musicTool", "#separator3", "#tilemapTool", - "propertiesTool"}; +constexpr uint k4BPP = 4; +constexpr uint kByteSize = 3; +constexpr uint kMessageIdSize = 5; +constexpr uint kNumSheetsToLoad = 223; +constexpr uint kTile8DisplayHeight = 64; +constexpr uint kOverworldMapSize = 0x200; +constexpr float kInputFieldSize = 30.f; +constexpr ImVec2 kOverworldCanvasSize(kOverworldMapSize * 8, + kOverworldMapSize * 8); +constexpr ImVec2 kCurrentGfxCanvasSize(0x100 + 1, 0x10 * 0x40 + 1); +constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1); +constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1); constexpr ImGuiTableFlags kOWMapFlags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable; @@ -52,6 +48,14 @@ constexpr ImGuiTableFlags kOWEditFlags = ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; +static constexpr absl::string_view kToolsetColumnNames[] = { + "#undoTool", "#redoTool", "#separator2", "#zoomOutTool", + "#zoomInTool", "#separator", "#drawTool", "#history", + "#entranceTool", "#exitTool", "#itemTool", "#spriteTool", + "#transportTool", "#musicTool", "#separator3", "#tilemapTool", + "propertiesTool", "#separator4", "#experimentalTool", "#properties", + "#separator5"}; + constexpr absl::string_view kWorldList = "Light World\0Dark World\0Extra World\0"; @@ -61,13 +65,17 @@ constexpr absl::string_view kTileSelectorTab = "##TileSelectorTabBar"; constexpr absl::string_view kOWEditTable = "##OWEditTable"; constexpr absl::string_view kOWMapTable = "#MapSettingsTable"; +constexpr int kEntranceTileTypePtrLow = 0xDB8BF; +constexpr int kEntranceTileTypePtrHigh = 0xDB917; +constexpr int kNumEntranceTileTypes = 0x2C; + class EntranceContext { public: absl::Status LoadEntranceTileTypes(Rom& rom) { - int offset_low = 0xDB8BF; - int offset_high = 0xDB917; + int offset_low = kEntranceTileTypePtrLow; + int offset_high = kEntranceTileTypePtrHigh; - for (int i = 0; i < 0x2C; i++) { + for (int i = 0; i < kNumEntranceTileTypes; i++) { // Load entrance tile types ASSIGN_OR_RETURN(auto value_low, rom.ReadWord(offset_low + i)); entrance_tile_types_low_.push_back(value_low); @@ -101,8 +109,8 @@ class EntranceContext { */ class OverworldEditor : public Editor, public SharedRom, - public context::GfxContext, public EntranceContext, + public GfxContext, public core::ExperimentFlags { public: OverworldEditor() { type_ = EditorType::kOverworld; } @@ -110,12 +118,15 @@ class OverworldEditor : public Editor, void InitializeZeml(); absl::Status Update() final; - absl::Status Undo() { return absl::UnimplementedError("Undo"); } - absl::Status Redo() { return absl::UnimplementedError("Redo"); } - absl::Status Cut() { return absl::UnimplementedError("Cut"); } - absl::Status Copy() { return absl::UnimplementedError("Copy"); } - absl::Status Paste() { return absl::UnimplementedError("Paste"); } - absl::Status Find() { return absl::UnimplementedError("Find Unused Tiles"); } + absl::Status Undo() override { return absl::UnimplementedError("Undo"); } + absl::Status Redo() override { return absl::UnimplementedError("Redo"); } + absl::Status Cut() override { return absl::UnimplementedError("Cut"); } + absl::Status Copy() override { return absl::UnimplementedError("Copy"); } + absl::Status Paste() override { return absl::UnimplementedError("Paste"); } + absl::Status Find() override { + return absl::UnimplementedError("Find Unused Tiles"); + } + absl::Status Save(); auto overworld() { return &overworld_; } @@ -135,11 +146,26 @@ class OverworldEditor : public Editor, absl::Status LoadGraphics(); private: - absl::Status UpdateFullscreenCanvas(); + /** + * @brief Draws the canvas, tile16 selector, and toolset in fullscreen + */ + void DrawFullscreenCanvas(); - absl::Status DrawToolset(); + /** + * @brief Toolset for entrances, exits, items, sprites, and transports. + */ + void DrawToolset(); + + /** + * @brief Draws the overworld map settings. Graphics, palettes, etc. + */ void DrawOverworldMapSettings(); + /** + * @brief Draw the overworld settings for ZSCustomOverworld. + */ + void DrawCustomOverworldMapSettings(); + void RefreshChildMap(int i); void RefreshOverworldMap(); absl::Status RefreshMapPalette(); @@ -155,9 +181,28 @@ class OverworldEditor : public Editor, void DrawOverworldMaps(); void DrawOverworldEdits(); void RenderUpdatedMapBitmap(const ImVec2& click_position, - const Bytes& tile_data); + const std::vector& tile_data); + + /** + * @brief Check for changes to the overworld map. + * + * This function either draws the tile painter with the current tile16 or + * group of tile16 data with ow_map_canvas_ and DrawOverworldEdits or it + * checks for left mouse button click/drag to select a tile16 or group of + * tile16 data from the overworld map canvas. Similar to ZScream selection. + */ void CheckForOverworldEdits(); + + /** + * @brief Draw and create the tile16 IDs that are currently selected. + */ void CheckForSelectRectangle(); + + /** + * @brief Check for changes to the overworld map. Calls RefreshOverworldMap + * and RefreshTile16Blockset on the current map if it is modified and is + * actively being edited. + */ absl::Status CheckForCurrentMap(); void CheckForMousePan(); @@ -175,17 +220,10 @@ class OverworldEditor : public Editor, void DrawOverworldProperties(); - absl::Status DrawExperimentalModal(); - absl::Status UpdateUsageStats(); void DrawUsageGrid(); - void CalculateUsageStats(); - - absl::Status LoadAnimatedMaps(); void DrawDebugWindow(); - auto gfx_group_editor() const { return gfx_group_editor_; } - enum class EditingMode { DRAW_TILE, ENTRANCES, @@ -200,84 +238,55 @@ class OverworldEditor : public Editor, EditingMode current_mode = EditingMode::DRAW_TILE; EditingMode previous_mode = EditingMode::DRAW_TILE; + enum OverworldProperty { + LW_AREA_GFX, + DW_AREA_GFX, + LW_AREA_PAL, + DW_AREA_PAL, + LW_SPR_GFX_PART1, + LW_SPR_GFX_PART2, + DW_SPR_GFX_PART1, + DW_SPR_GFX_PART2, + LW_SPR_PAL_PART1, + LW_SPR_PAL_PART2, + DW_SPR_PAL_PART1, + DW_SPR_PAL_PART2, + }; + int current_world_ = 0; int current_map_ = 0; int current_parent_ = 0; + int current_entrance_id_ = 0; + int current_exit_id_ = 0; + int current_item_id_ = 0; + int current_sprite_id_ = 0; + int current_blockset_ = 0; int game_state_ = 1; int current_tile16_ = 0; - int selected_tile_ = 0; - - int current_blockset_ = 0; - int selected_entrance_ = 0; int selected_usage_map_ = 0xFFFF; - char map_gfx_[3] = ""; - char map_palette_[3] = ""; - char spr_gfx_[3] = ""; - char spr_palette_[3] = ""; - char message_id_[5] = ""; - char staticgfx[16]; - - uint32_t tilemap_file_offset_high_ = 0; - uint32_t tilemap_file_offset_low_ = 0; - uint32_t light_maps_to_load_ = 0x51; - uint32_t dark_maps_to_load_ = 0x2A; - uint32_t sp_maps_to_load_ = 0x07; - - bool opt_enable_grid = true; bool all_gfx_loaded_ = false; bool map_blockset_loaded_ = false; bool selected_tile_loaded_ = false; - bool update_selected_tile_ = true; - bool is_dragging_entrance_ = false; bool show_tile16_editor_ = false; - bool show_gfx_group_editor_ = false; bool overworld_canvas_fullscreen_ = false; bool middle_mouse_dragging_ = false; - bool is_dragging_entity_ = false; - zelda3::OverworldEntity* dragged_entity_; - zelda3::OverworldEntity* current_entity_; - int current_entrance_id_ = 0; - zelda3::overworld::OverworldEntrance current_entrance_; - int current_exit_id_ = 0; - zelda3::overworld::OverworldExit current_exit_; - int current_item_id_ = 0; - zelda3::overworld::OverworldItem current_item_; - int current_sprite_id_ = 0; - zelda3::Sprite current_sprite_; - - bool show_experimental = false; - std::string ow_tilemap_filename_ = ""; - std::string tile32_configuration_filename_ = ""; - - Bytes selected_tile_data_; - std::vector tile16_individual_data_; + std::vector selected_tile_data_; + std::vector> tile16_individual_data_; std::vector tile16_individual_; - std::vector tile8_individual_data_; + std::vector> tile8_individual_data_; std::vector tile8_individual_; Tile16Editor tile16_editor_; GfxGroupEditor gfx_group_editor_; PaletteEditor palette_editor_; - zelda3::overworld::Overworld overworld_; - - gui::Canvas ow_map_canvas_{"owMapCanvas", ImVec2(0x200 * 8, 0x200 * 8), - gui::CanvasGridSize::k64x64}; - gui::Canvas current_gfx_canvas_{"customGfxCanvas", - ImVec2(0x100 + 1, 0x10 * 0x40 + 1), - gui::CanvasGridSize::k32x32}; - gui::Canvas blockset_canvas_{"blocksetCanvas", ImVec2(0x100 + 1, 0x2000 + 1), - gui::CanvasGridSize::k32x32}; - gui::Canvas graphics_bin_canvas_{ - "graphicsBinCanvas", ImVec2(0x100 + 1, kNumSheetsToLoad * 0x40 + 1), - gui::CanvasGridSize::k16x16}; - gui::Canvas properties_canvas_; gfx::SnesPalette palette_; + gfx::Bitmap selected_tile_bmp_; gfx::Bitmap tile16_blockset_bmp_; gfx::Bitmap current_gfx_bmp_; @@ -286,10 +295,28 @@ class OverworldEditor : public Editor, gfx::BitmapTable maps_bmp_; gfx::BitmapTable current_graphics_set_; gfx::BitmapTable sprite_previews_; - gfx::BitmapTable animated_maps_; - OWBlockset refresh_blockset_; + zelda3::overworld::Overworld overworld_; + zelda3::OWBlockset refresh_blockset_; + zelda3::Sprite current_sprite_; + + zelda3::overworld::OverworldEntrance current_entrance_; + zelda3::overworld::OverworldExit current_exit_; + zelda3::overworld::OverworldItem current_item_; + + zelda3::GameEntity* current_entity_; + zelda3::GameEntity* dragged_entity_; + + gui::Canvas ow_map_canvas_{"OwMap", kOverworldCanvasSize, + gui::CanvasGridSize::k64x64}; + gui::Canvas current_gfx_canvas_{"CurrentGfx", kCurrentGfxCanvasSize, + gui::CanvasGridSize::k32x32}; + gui::Canvas blockset_canvas_{"OwBlockset", kBlocksetCanvasSize, + gui::CanvasGridSize::k32x32}; + gui::Canvas graphics_bin_canvas_{"GraphicsBin", kGraphicsBinCanvasSize, + gui::CanvasGridSize::k16x16}; + gui::Canvas properties_canvas_; gui::zeml::Node layout_node_; absl::Status status_; }; @@ -297,4 +324,4 @@ class OverworldEditor : public Editor, } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/editor/overworld/refresh.cc b/src/app/editor/overworld/refresh.cc deleted file mode 100644 index bdfaa566..00000000 --- a/src/app/editor/overworld/refresh.cc +++ /dev/null @@ -1,157 +0,0 @@ -#include "app/editor/overworld_editor.h" - -namespace yaze { -namespace app { -namespace editor { - -void OverworldEditor::RefreshChildMap(int map_index) { - overworld_.mutable_overworld_map(map_index)->LoadAreaGraphics(); - status_ = overworld_.mutable_overworld_map(map_index)->BuildTileset(); - PRINT_IF_ERROR(status_); - status_ = overworld_.mutable_overworld_map(map_index)->BuildTiles16Gfx( - overworld_.tiles16().size()); - PRINT_IF_ERROR(status_); - status_ = overworld_.mutable_overworld_map(map_index)->BuildBitmap( - overworld_.GetMapTiles(current_world_)); - maps_bmp_[map_index].set_data( - overworld_.mutable_overworld_map(map_index)->bitmap_data()); - maps_bmp_[map_index].set_modified(true); - PRINT_IF_ERROR(status_); -} - -void OverworldEditor::RefreshOverworldMap() { - std::vector> futures; - int indices[4]; - - auto refresh_map_async = [this](int map_index) { - RefreshChildMap(map_index); - }; - - int source_map_id = current_map_; - bool is_large = overworld_.overworld_map(current_map_)->is_large_map(); - if (is_large) { - source_map_id = current_parent_; - // We need to update the map and its siblings if it's a large map - for (int i = 1; i < 4; i++) { - int sibling_index = overworld_.overworld_map(source_map_id)->parent() + i; - if (i >= 2) sibling_index += 6; - futures.push_back( - std::async(std::launch::async, refresh_map_async, sibling_index)); - indices[i] = sibling_index; - } - } - indices[0] = source_map_id; - futures.push_back( - std::async(std::launch::async, refresh_map_async, source_map_id)); - - for (auto &each : futures) { - each.get(); - } - int n = is_large ? 4 : 1; - // We do texture updating on the main thread - for (int i = 0; i < n; ++i) { - rom()->UpdateBitmap(&maps_bmp_[indices[i]]); - } -} - -absl::Status OverworldEditor::RefreshMapPalette() { - RETURN_IF_ERROR( - overworld_.mutable_overworld_map(current_map_)->LoadPalette()); - const auto current_map_palette = overworld_.AreaPalette(); - - if (overworld_.overworld_map(current_map_)->is_large_map()) { - // We need to update the map and its siblings if it's a large map - for (int i = 1; i < 4; i++) { - int sibling_index = overworld_.overworld_map(current_map_)->parent() + i; - if (i >= 2) sibling_index += 6; - RETURN_IF_ERROR( - overworld_.mutable_overworld_map(sibling_index)->LoadPalette()); - RETURN_IF_ERROR( - maps_bmp_[sibling_index].ApplyPalette(current_map_palette)); - } - } - - RETURN_IF_ERROR(maps_bmp_[current_map_].ApplyPalette(current_map_palette)); - return absl::OkStatus(); -} - -void OverworldEditor::RefreshMapProperties() { - auto ¤t_ow_map = *overworld_.mutable_overworld_map(current_map_); - if (current_ow_map.is_large_map()) { - // We need to copy the properties from the parent map to the children - for (int i = 1; i < 4; i++) { - int sibling_index = current_ow_map.parent() + i; - if (i >= 2) { - sibling_index += 6; - } - auto &map = *overworld_.mutable_overworld_map(sibling_index); - map.set_area_graphics(current_ow_map.area_graphics()); - map.set_area_palette(current_ow_map.area_palette()); - map.set_sprite_graphics(game_state_, - current_ow_map.sprite_graphics(game_state_)); - map.set_sprite_palette(game_state_, - current_ow_map.sprite_palette(game_state_)); - map.set_message_id(current_ow_map.message_id()); - } - } -} - -absl::Status OverworldEditor::RefreshTile16Blockset() { - if (current_blockset_ == - overworld_.overworld_map(current_map_)->area_graphics()) { - return absl::OkStatus(); - } - current_blockset_ = overworld_.overworld_map(current_map_)->area_graphics(); - - overworld_.set_current_map(current_map_); - palette_ = overworld_.AreaPalette(); - // Create the tile16 blockset image - rom()->UpdateBitmap(&tile16_blockset_bmp_); - RETURN_IF_ERROR(tile16_blockset_bmp_.ApplyPalette(palette_)); - - // Copy the tile16 data into individual tiles. - auto tile16_data = overworld_.Tile16Blockset(); - - std::vector> futures; - // Loop through the tiles and copy their pixel data into separate vectors - for (int i = 0; i < 4096; i++) { - futures.push_back(std::async( - std::launch::async, - [&](int index) { - // Create a new vector for the pixel data of the current tile - Bytes tile_data(16 * 16, 0x00); // More efficient initialization - - // Copy the pixel data for the current tile into the vector - for (int ty = 0; ty < 16; ty++) { - for (int tx = 0; tx < 16; tx++) { - int position = tx + (ty * 0x10); - uint8_t value = - tile16_data[(index % 8 * 16) + (index / 8 * 16 * 0x80) + - (ty * 0x80) + tx]; - tile_data[position] = value; - } - } - - // Add the vector for the current tile to the vector of tile pixel - // data - tile16_individual_[index].set_data(tile_data); - }, - i)); - } - - for (auto &future : futures) { - future.get(); - } - - // Render the bitmaps of each tile. - for (int id = 0; id < 4096; id++) { - RETURN_IF_ERROR(tile16_individual_[id].ApplyPalette(palette_)); - rom()->UpdateBitmap(&tile16_individual_[id]); - } - - return absl::OkStatus(); -} - -} // namespace editor -} // namespace app -} // namespace yaze \ No newline at end of file diff --git a/src/app/editor/sprite/sprite_editor.cc b/src/app/editor/sprite/sprite_editor.cc index bd03da0f..5c0cd211 100644 --- a/src/app/editor/sprite/sprite_editor.cc +++ b/src/app/editor/sprite/sprite_editor.cc @@ -4,6 +4,7 @@ #include "app/editor/sprite/zsprite.h" #include "app/gui/icons.h" #include "app/gui/input.h" +#include "app/zelda3/sprite/sprite.h" namespace yaze { namespace app { @@ -71,13 +72,13 @@ void SpriteEditor::DrawVanillaSpriteEditor() { for (int n = 0; n < active_sprites_.Size;) { bool open = true; - if (active_sprites_[n] > sizeof(core::kSpriteDefaultNames) / 4) { + if (active_sprites_[n] > sizeof(zelda3::kSpriteDefaultNames) / 4) { active_sprites_.erase(active_sprites_.Data + n); continue; } if (ImGui::BeginTabItem( - core::kSpriteDefaultNames[active_sprites_[n]].data(), &open, + zelda3::kSpriteDefaultNames[active_sprites_[n]].data(), &open, ImGuiTabItemFlags_None)) { DrawSpriteCanvas(); ImGui::EndTabItem(); @@ -175,7 +176,7 @@ void SpriteEditor::DrawCurrentSheets() { graphics_sheet_canvas_.DrawTileSelector(32); for (int i = 0; i < 8; i++) { graphics_sheet_canvas_.DrawBitmap( - rom()->bitmap_manager()[current_sheets_[i]], 1, (i * 0x40) + 1, 2); + rom()->gfx_sheets().at(current_sheets_[i]), 1, (i * 0x40) + 1, 2); } graphics_sheet_canvas_.DrawGrid(); graphics_sheet_canvas_.DrawOverlay(); @@ -188,10 +189,10 @@ void SpriteEditor::DrawSpritesList() { ImVec2(ImGui::GetContentRegionAvail().x, 0), true, ImGuiWindowFlags_NoDecoration)) { int i = 0; - for (const auto each_sprite_name : core::kSpriteDefaultNames) { + for (const auto each_sprite_name : zelda3::kSpriteDefaultNames) { rom()->resource_label()->SelectableLabelWithNameEdit( current_sprite_id_ == i, "Sprite Names", core::UppercaseHexByte(i), - core::kSpriteDefaultNames[i].data()); + zelda3::kSpriteDefaultNames[i].data()); if (ImGui::IsItemClicked()) { current_sprite_id_ = i; if (!active_sprites_.contains(i)) { @@ -243,7 +244,7 @@ void SpriteEditor::DrawCustomSpritesMetadata() { // ZSprite Maker format open file dialog if (ImGui::Button("Open ZSprite")) { // Open ZSprite file - std::string file_path = FileDialogWrapper::ShowOpenFileDialog(); + std::string file_path = core::FileDialogWrapper::ShowOpenFileDialog(); if (!file_path.empty()) { zsprite::ZSprite zsprite; status_ = zsprite.Load(file_path); diff --git a/src/app/editor/sprite/sprite_editor.h b/src/app/editor/sprite/sprite_editor.h index 0cc6e019..2504a62f 100644 --- a/src/app/editor/sprite/sprite_editor.h +++ b/src/app/editor/sprite/sprite_editor.h @@ -3,7 +3,7 @@ #include "absl/status/status.h" #include "app/editor/sprite/zsprite.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" #include "app/gui/canvas.h" #include "app/rom.h" diff --git a/src/app/editor/sprite/zsprite.h b/src/app/editor/sprite/zsprite.h index 19717403..5cedb73a 100644 --- a/src/app/editor/sprite/zsprite.h +++ b/src/app/editor/sprite/zsprite.h @@ -1,16 +1,16 @@ #ifndef YAZE_APP_EDITOR_SPRITE_ZSPRITE_H #define YAZE_APP_EDITOR_SPRITE_ZSPRITE_H -#include "imgui/imgui.h" - #include #include #include #include #include +#include "app/core/constants.h" #include "absl/status/status.h" #include "app/gfx/snes_tile.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -46,7 +46,7 @@ struct OamTile { struct AnimationGroup { AnimationGroup() = default; AnimationGroup(uint8_t fs, uint8_t fe, uint8_t fsp, std::string fn) - : frame_start(fs), frame_end(fe), frame_speed(fsp), frame_name(fn) {} + : frame_name(fn), frame_start(fs), frame_end(fe), frame_speed(fsp) {} std::string frame_name; uint8_t frame_start; diff --git a/src/app/editor/system/command_manager.cc b/src/app/editor/system/command_manager.cc new file mode 100644 index 00000000..bcb3995c --- /dev/null +++ b/src/app/editor/system/command_manager.cc @@ -0,0 +1,143 @@ +#include "command_manager.h" + +#include + +#include "imgui/imgui.h" + +namespace yaze { +namespace app { +namespace editor { + +ImGuiKey MapKeyToImGuiKey(char key) { + switch (key) { + case 'A': + return ImGuiKey_A; + case 'B': + return ImGuiKey_B; + case 'C': + return ImGuiKey_C; + case 'D': + return ImGuiKey_D; + case 'E': + return ImGuiKey_E; + case 'F': + return ImGuiKey_F; + case 'G': + return ImGuiKey_G; + case 'H': + return ImGuiKey_H; + case 'I': + return ImGuiKey_I; + case 'J': + return ImGuiKey_J; + case 'K': + return ImGuiKey_K; + case 'L': + return ImGuiKey_L; + case 'M': + return ImGuiKey_M; + case 'N': + return ImGuiKey_N; + case 'O': + return ImGuiKey_O; + case 'P': + return ImGuiKey_P; + case 'Q': + return ImGuiKey_Q; + case 'R': + return ImGuiKey_R; + case 'S': + return ImGuiKey_S; + case 'T': + return ImGuiKey_T; + case 'U': + return ImGuiKey_U; + case 'V': + return ImGuiKey_V; + case 'W': + return ImGuiKey_W; + case 'X': + return ImGuiKey_X; + case 'Y': + return ImGuiKey_Y; + case 'Z': + return ImGuiKey_Z; + case '/': + return ImGuiKey_Slash; + case '-': + return ImGuiKey_Minus; + default: + return ImGuiKey_COUNT; + } +} + +// When the player presses Space, a popup will appear fixed to the bottom of the +// ImGui window with a list of the available key commands which can be used. +void CommandManager::ShowWhichKey() { + if (ImGui::IsKeyPressed(ImGuiKey_Space)) { + ImGui::OpenPopup("WhichKey"); + } + + ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - 100), + ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, 100), + ImGuiCond_Always); + if (ImGui::BeginPopup("WhichKey")) { + // ESC to close the popup + if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { + ImGui::CloseCurrentPopup(); + } + + const ImVec4 colors[] = { + ImVec4(0.8f, 0.2f, 0.2f, 1.0f), // Soft Red + ImVec4(0.2f, 0.8f, 0.2f, 1.0f), // Soft Green + ImVec4(0.2f, 0.2f, 0.8f, 1.0f), // Soft Blue + ImVec4(0.8f, 0.8f, 0.2f, 1.0f), // Soft Yellow + ImVec4(0.8f, 0.2f, 0.8f, 1.0f), // Soft Magenta + ImVec4(0.2f, 0.8f, 0.8f, 1.0f) // Soft Cyan + }; + const int numColors = sizeof(colors) / sizeof(colors[0]); + int colorIndex = 0; + + if (ImGui::BeginTable("CommandsTable", commands_.size(), + ImGuiTableFlags_SizingStretchProp)) { + for (const auto &[shortcut, info] : commands_) { + ImGui::TableNextColumn(); + ImGui::TextColored(colors[colorIndex], "%c: %s", + info.command_info.mnemonic, + info.command_info.name.c_str()); + colorIndex = (colorIndex + 1) % numColors; + } + ImGui::EndTable(); + } + ImGui::EndPopup(); + } +} + +void CommandManager::SaveKeybindings(const std::string &filepath) { + std::ofstream out(filepath); + if (out.is_open()) { + for (const auto &[shortcut, info] : commands_) { + out << shortcut << " " << info.command_info.mnemonic << " " + << info.command_info.name << " " << info.command_info.desc << "\n"; + } + out.close(); + } +} + +void CommandManager::LoadKeybindings(const std::string &filepath) { + std::ifstream in(filepath); + if (in.is_open()) { + commands_.clear(); + std::string shortcut, name, desc; + char mnemonic; + while (in >> shortcut >> mnemonic >> name >> desc) { + commands_[shortcut].command_info = {nullptr, mnemonic, name, desc}; + } + in.close(); + } +} + +} // namespace editor +} // namespace app +} // namespace yaze diff --git a/src/app/editor/system/command_manager.h b/src/app/editor/system/command_manager.h new file mode 100644 index 00000000..c6dd7036 --- /dev/null +++ b/src/app/editor/system/command_manager.h @@ -0,0 +1,83 @@ +#ifndef YAZE_APP_EDITOR_SYSTEM_COMMAND_MANAGER_H +#define YAZE_APP_EDITOR_SYSTEM_COMMAND_MANAGER_H + +#include +#include +#include + +#include "imgui/imgui.h" + +namespace yaze { +namespace app { +namespace editor { + +ImGuiKey MapKeyToImGuiKey(char key); + +class CommandManager { +public: + CommandManager() = default; + ~CommandManager() = default; + + using Command = std::function; + + struct CommandInfo { + Command command; + char mnemonic; + std::string name; + std::string desc; + CommandInfo(Command command, char mnemonic, const std::string &name, + const std::string &desc) + : command(std::move(command)), mnemonic(mnemonic), name(name), + desc(desc) {} + CommandInfo() = default; + }; + + // New command info which supports subsections of commands + struct CommandInfoOrPrefix { + CommandInfo command_info; + std::unordered_map subcommands; + CommandInfoOrPrefix(CommandInfo command_info) + : command_info(std::move(command_info)) {} + CommandInfoOrPrefix() = default; + }; + + void RegisterPrefix(const std::string &group_name, const char prefix, + const std::string &name, const std::string &desc) { + commands_[group_name].command_info = {nullptr, prefix, name, desc}; + } + + void RegisterSubcommand(const std::string &group_name, + const std::string &shortcut, const char mnemonic, + const std::string &name, const std::string &desc, + Command command) { + commands_[group_name].subcommands[shortcut].command_info = { + command, mnemonic, name, desc}; + } + + void RegisterCommand(const std::string &shortcut, Command command, + char mnemonic, const std::string &name, + const std::string &desc) { + commands_[shortcut].command_info = {std::move(command), mnemonic, name, + desc}; + } + + void ExecuteCommand(const std::string &shortcut) { + if (commands_.find(shortcut) != commands_.end()) { + commands_[shortcut].command_info.command(); + } + } + + void ShowWhichKey(); + + void SaveKeybindings(const std::string &filepath); + void LoadKeybindings(const std::string &filepath); + +private: + std::unordered_map commands_; +}; + +} // namespace editor +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_EDITOR_SYSTEM_COMMAND_MANAGER_H diff --git a/src/app/editor/system/constant_manager.h b/src/app/editor/system/constant_manager.h new file mode 100644 index 00000000..4909e4a7 --- /dev/null +++ b/src/app/editor/system/constant_manager.h @@ -0,0 +1,77 @@ +#ifndef YAZE_APP_EDITOR_SYSTEM_CONSTANT_MANAGER_H +#define YAZE_APP_EDITOR_SYSTEM_CONSTANT_MANAGER_H + +#include + +#include "app/zelda3/overworld/overworld_map.h" +#include "imgui/imgui.h" + +namespace yaze { +namespace app { +namespace editor { + +class ConstantManager { + public: + void ShowConstantManager() { + ImGui::Begin("Constant Manager"); + + // Tab bar for the different types of constants + // Overworld, dungeon, graphics, expanded + ImGui::TextWrapped( + "This is the constant manager. It allows you to view and edit " + "constants in the ROM. You should only edit these if you know what " + "you're doing."); + + if (ImGui::BeginTabBar("Constant Manager Tabs")) { + if (ImGui::BeginTabItem("Overworld")) { + ImGui::Text("Overworld constants"); + ImGui::Separator(); + ImGui::Text("OverworldCustomASMHasBeenApplied: %d", + zelda3::overworld::OverworldCustomASMHasBeenApplied); + ImGui::Text("OverworldCustomAreaSpecificBGPalette: %d", + zelda3::overworld::OverworldCustomAreaSpecificBGPalette); + ImGui::Text("OverworldCustomAreaSpecificBGEnabled: %d", + zelda3::overworld::OverworldCustomAreaSpecificBGEnabled); + ImGui::Text("OverworldCustomMainPaletteArray: %d", + zelda3::overworld::OverworldCustomMainPaletteArray); + ImGui::Text("OverworldCustomMainPaletteEnabled: %d", + zelda3::overworld::OverworldCustomMainPaletteEnabled); + ImGui::Text("OverworldCustomMosaicArray: %d", + zelda3::overworld::OverworldCustomMosaicArray); + ImGui::Text("OverworldCustomMosaicEnabled: %d", + zelda3::overworld::OverworldCustomMosaicEnabled); + ImGui::Text("OverworldCustomAnimatedGFXArray: %d", + zelda3::overworld::OverworldCustomAnimatedGFXArray); + ImGui::Text("OverworldCustomAnimatedGFXEnabled: %d", + zelda3::overworld::OverworldCustomAnimatedGFXEnabled); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Dungeon")) { + ImGui::Text("Dungeon constants"); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Graphics")) { + ImGui::Text("Graphics constants"); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Expanded")) { + ImGui::Text("Expanded constants"); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + ImGui::End(); + } +}; + +} // namespace editor +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_EDITOR_SYSTEM_CONSTANT_MANAGER_H diff --git a/src/app/editor/system/extension_manager.cc b/src/app/editor/system/extension_manager.cc new file mode 100644 index 00000000..12e8bc67 --- /dev/null +++ b/src/app/editor/system/extension_manager.cc @@ -0,0 +1,85 @@ +#include "extension_manager.h" + +#if defined(__unix__) || defined(__unix) || defined(unix) || \ + defined(__APPLE__) && defined(__MACH__) +#include +#endif + +#include + +#include +#include + +namespace yaze { +namespace app { +namespace editor { + +void ExtensionManager::LoadExtension(const std::string& filename, + yaze_editor_context* context) { +#if defined(__unix__) || defined(__unix) || defined(unix) || \ + defined(__APPLE__) && defined(__MACH__) + auto extension_path = filename.c_str(); + void* handle = dlopen(extension_path, RTLD_LAZY); + if (!handle) { + std::cerr << "Cannot open extension: " << dlerror() << std::endl; + return; + } + dlerror(); // Clear any existing error + + // Load the symbol to retrieve the extension + auto get_extension = reinterpret_cast( + dlsym(handle, "get_yaze_extension")); + const char* dlsym_error = dlerror(); + if (dlsym_error) { + std::cerr << "Cannot load symbol 'get_yaze_extension': " << dlsym_error + << std::endl; + dlclose(handle); + return; + } + + yaze_extension* extension = get_extension(); + if (extension && extension->initialize) { + extension->initialize(context); + } else { + std::cerr << "Failed to initialize the extension." << std::endl; + dlclose(handle); + return; + } + + extensions_.push_back(extension); +#endif +} + +void ExtensionManager::RegisterExtension(yaze_extension* extension) { + extensions_.push_back(extension); +} + +void ExtensionManager::InitializeExtensions(yaze_editor_context* context) { + for (auto& extension : extensions_) { + extension->initialize(context); + } +} + +void ExtensionManager::ShutdownExtensions() { + for (auto& extension : extensions_) { + extension->cleanup(); + } + + // if (handle) { + // dlclose(handle); + // handle = nullptr; + // extension = nullptr; + // } +} + +void ExtensionManager::ExecuteExtensionUI(yaze_editor_context* context) { + for (auto& extension : extensions_) { + if (extension->extend_ui) { + extension->extend_ui(context); + } + } +} + +} // namespace editor +} // namespace app +} // namespace yaze diff --git a/src/app/editor/system/extension_manager.h b/src/app/editor/system/extension_manager.h new file mode 100644 index 00000000..eb471e92 --- /dev/null +++ b/src/app/editor/system/extension_manager.h @@ -0,0 +1,29 @@ +#ifndef YAZE_APP_EDITOR_SYSTEM_EXTENSION_MANAGER_H +#define YAZE_APP_EDITOR_SYSTEM_EXTENSION_MANAGER_H + +#include + +#include +#include + +namespace yaze { +namespace app { +namespace editor { + +class ExtensionManager { + public: + void LoadExtension(const std::string& filename, yaze_editor_context* context); + void RegisterExtension(yaze_extension* extension); + void InitializeExtensions(yaze_editor_context* context); + void ShutdownExtensions(); + void ExecuteExtensionUI(yaze_editor_context* context); + + private: + std::vector extensions_; +}; + +} // namespace editor +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_EDITOR_SYSTEM_EXTENSION_MANAGER_H diff --git a/src/app/editor/utils/flags.h b/src/app/editor/system/flags.h similarity index 90% rename from src/app/editor/utils/flags.h rename to src/app/editor/system/flags.h index bde5bc19..1b0035d2 100644 --- a/src/app/editor/utils/flags.h +++ b/src/app/editor/system/flags.h @@ -1,9 +1,8 @@ #ifndef YAZE_APP_EDITOR_UTILS_FLAGS_H #define YAZE_APP_EDITOR_UTILS_FLAGS_H -#include "imgui/imgui.h" - #include "core/common.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -31,6 +30,8 @@ struct FlagsMenu : public core::ExperimentFlags { &mutable_flags()->overworld.kSaveOverworldItems); Checkbox("Save Overworld Properties", &mutable_flags()->overworld.kSaveOverworldProperties); + Checkbox("Load Custom Overworld", + &mutable_flags()->overworld.kLoadCustomOverworld); ImGui::EndMenu(); } @@ -42,21 +43,16 @@ struct FlagsMenu : public core::ExperimentFlags { ImGui::EndMenu(); } - if (BeginMenu("Emulator Flags")) { - Checkbox("Load Audio Device", &mutable_flags()->kLoadAudioDevice); - ImGui::EndMenu(); - } - Checkbox("Use built-in file dialog", &mutable_flags()->kNewFileDialogWrapper); Checkbox("Enable Console Logging", &mutable_flags()->kLogToConsole); Checkbox("Enable Texture Streaming", &mutable_flags()->kLoadTexturesAsStreaming); - Checkbox("Use Bitmap Manager", &mutable_flags()->kUseBitmapManager); Checkbox("Log Instructions to Debugger", &mutable_flags()->kLogInstructions); Checkbox("Save All Palettes", &mutable_flags()->kSaveAllPalettes); Checkbox("Save Gfx Groups", &mutable_flags()->kSaveGfxGroups); + Checkbox("Save Graphics Sheets", &mutable_flags()->kSaveGraphicsSheet); Checkbox("Use New ImGui Input", &mutable_flags()->kUseNewImGuiInput); } }; diff --git a/src/app/editor/system/history_manager.h b/src/app/editor/system/history_manager.h new file mode 100644 index 00000000..f059e6e8 --- /dev/null +++ b/src/app/editor/system/history_manager.h @@ -0,0 +1,32 @@ +#ifndef YAZE_APP_EDITOR_SYSTEM_HISTORY_MANAGER_H +#define YAZE_APP_EDITOR_SYSTEM_HISTORY_MANAGER_H + +#include +#include +#include + +namespace yaze { +namespace app { +namespace editor { + +// System history manager, undo and redo. +class HistoryManager { + public: + HistoryManager() = default; + ~HistoryManager() = default; + + void Add(const char* data); + void Undo(); + void Redo(); + + private: + std::vector history_; + std::stack undo_; + std::stack redo_; +}; + +} // namespace editor +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_EDITOR_SYSTEM_HISTORY_MANAGER_H diff --git a/src/app/editor/system/popup_manager.cc b/src/app/editor/system/popup_manager.cc new file mode 100644 index 00000000..fb5b3538 --- /dev/null +++ b/src/app/editor/system/popup_manager.cc @@ -0,0 +1,19 @@ +#include "popup_manager.h" + +#include "imgui/imgui.h" + +namespace yaze { +namespace app { +namespace editor { + +PopupManager::PopupManager() { +} + +PopupManager::~PopupManager() { +} + + + +} // namespace editor +} // namespace app +} // namespace yaze diff --git a/src/app/editor/system/popup_manager.h b/src/app/editor/system/popup_manager.h new file mode 100644 index 00000000..056cc8c7 --- /dev/null +++ b/src/app/editor/system/popup_manager.h @@ -0,0 +1,21 @@ +#ifndef YAZE_APP_EDITOR_POPUP_MANAGER_H +#define YAZE_APP_EDITOR_POPUP_MANAGER_H + +namespace yaze { +namespace app { +namespace editor { + +// ImGui popup manager. +class PopupManager { + public: + PopupManager(); + ~PopupManager(); + + void Show(const char* name); +}; + +} // namespace editor +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_EDITOR_POPUP_MANAGER_H diff --git a/src/app/editor/system/resource_manager.h b/src/app/editor/system/resource_manager.h new file mode 100644 index 00000000..116ef9e4 --- /dev/null +++ b/src/app/editor/system/resource_manager.h @@ -0,0 +1,30 @@ +#ifndef YAZE_APP_EDITOR_SYSTEM_RESOURCE_MANAGER_H +#define YAZE_APP_EDITOR_SYSTEM_RESOURCE_MANAGER_H + +#include + +namespace yaze { +namespace app { +namespace editor { + +// System resource manager. +class ResourceManager { + public: + ResourceManager() : count_(0) {} + ~ResourceManager() = default; + + void Load(const char* path); + void Unload(const char* path); + void UnloadAll(); + + size_t Count() const; + + private: + size_t count_; +}; + +} // namespace editor +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_EDITOR_SYSTEM_RESOURCE_MANAGER_H diff --git a/src/app/editor/settings_editor.cc b/src/app/editor/system/settings_editor.cc similarity index 92% rename from src/app/editor/settings_editor.cc rename to src/app/editor/system/settings_editor.cc index 3539419a..2be90b39 100644 --- a/src/app/editor/settings_editor.cc +++ b/src/app/editor/system/settings_editor.cc @@ -1,11 +1,9 @@ -#include "imgui/imgui.h" +#include "app/editor/system/settings_editor.h" #include "absl/status/status.h" -#include "app/editor/utils/flags.h" -#include "app/editor/utils/keyboard_shortcuts.h" -#include "app/editor/settings_editor.h" -#include "app/editor/utils/flags.h" +#include "app/editor/system/flags.h" +#include "imgui/imgui.h" namespace yaze { namespace app { diff --git a/src/app/editor/settings_editor.h b/src/app/editor/system/settings_editor.h similarity index 99% rename from src/app/editor/settings_editor.h rename to src/app/editor/system/settings_editor.h index 32c6e382..3c2c0a07 100644 --- a/src/app/editor/settings_editor.h +++ b/src/app/editor/system/settings_editor.h @@ -4,7 +4,7 @@ #include "imgui/imgui.h" #include "absl/status/status.h" -#include "app/editor/utils/editor.h" +#include "app/editor/editor.h" namespace yaze { namespace app { diff --git a/src/app/editor/utils/gfx_context.cc b/src/app/editor/utils/gfx_context.cc deleted file mode 100644 index 8d829552..00000000 --- a/src/app/editor/utils/gfx_context.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include "app/editor/utils/gfx_context.h" - -#include "imgui/imgui.h" - -#include - -#include "app/editor/graphics/palette_editor.h" -#include "app/editor/utils/editor.h" -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" -#include "app/gui/canvas.h" -#include "app/gui/icons.h" -#include "app/rom.h" - -namespace yaze { -namespace app { -namespace editor { -namespace context { - -std::unordered_map GfxContext::palettesets_; - -} -} // namespace editor -} // namespace app -} // namespace yaze \ No newline at end of file diff --git a/src/app/editor/utils/gfx_context.h b/src/app/editor/utils/gfx_context.h deleted file mode 100644 index d3f8992e..00000000 --- a/src/app/editor/utils/gfx_context.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef YAZE_APP_EDITOR_VRAM_CONTEXT_H -#define YAZE_APP_EDITOR_VRAM_CONTEXT_H - -#include "imgui/imgui.h" - -#include -#include - -#include "app/editor/utils/editor.h" -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" -#include "app/gui/canvas.h" -#include "app/gui/icons.h" -#include "app/rom.h" - -namespace yaze { -namespace app { -namespace editor { -namespace context { - -/** - * @brief Shared graphical context across editors. - */ -class GfxContext { - protected: - // Palettesets for the tile16 individual tiles - static std::unordered_map palettesets_; -}; - -} // namespace context -} // namespace editor -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_EDITOR_VRAM_CONTEXT_H \ No newline at end of file diff --git a/src/app/editor/utils/keyboard_shortcuts.h b/src/app/editor/utils/keyboard_shortcuts.h deleted file mode 100644 index bb70ccf7..00000000 --- a/src/app/editor/utils/keyboard_shortcuts.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef YAZE_APP_EDITOR_UTILS_KEYBOARD_SHORTCUTS_H -#define YAZE_APP_EDITOR_UTILS_KEYBOARD_SHORTCUTS_H - -#include "imgui/imgui.h" - -namespace yaze { -namespace app { -namespace editor { - -struct KeyboardShortcuts { - enum class ShortcutType { - kCut, - kCopy, - kPaste, - kUndo, - kRedo, - kFind, - }; -}; - -} // namespace editor -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_EDITOR_UTILS_KEYBOARD_SHORTCUTS_H_ diff --git a/src/app/editor/utils/recent_files.h b/src/app/editor/utils/recent_files.h deleted file mode 100644 index 2b0c7f6c..00000000 --- a/src/app/editor/utils/recent_files.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef YAZE_APP_EDITOR_UTILS_RECENT_FILES_H -#define YAZE_APP_EDITOR_UTILS_RECENT_FILES_H - -#include -#include -#include -#include - -namespace yaze { -namespace app { -namespace editor { - -class RecentFilesManager { - public: - RecentFilesManager(const std::string& filename) : filename_(filename) {} - - void AddFile(const std::string& filePath) { - // Add a file to the list, avoiding duplicates - auto it = std::find(recentFiles_.begin(), recentFiles_.end(), filePath); - if (it == recentFiles_.end()) { - recentFiles_.push_back(filePath); - } - } - - void Save() { - std::ofstream file(filename_); - if (!file.is_open()) { - return; // Handle the error appropriately - } - - for (const auto& filePath : recentFiles_) { - file << filePath << std::endl; - } - } - - void Load() { - std::ifstream file(filename_); - if (!file.is_open()) { - return; // Handle the error appropriately - } - - recentFiles_.clear(); - std::string line; - while (std::getline(file, line)) { - if (!line.empty()) { - recentFiles_.push_back(line); - } - } - } - - const std::vector& GetRecentFiles() const { - return recentFiles_; - } - - private: - std::string filename_; - std::vector recentFiles_; -}; - -} // namespace editor -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_EDITOR_UTILS_RECENT_FILES_H \ No newline at end of file diff --git a/src/app/emu/audio/apu.h b/src/app/emu/audio/apu.h index 157b9696..b52c6ada 100644 --- a/src/app/emu/audio/apu.h +++ b/src/app/emu/audio/apu.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "app/emu/audio/dsp.h" #include "app/emu/audio/spc700.h" diff --git a/src/app/emu/audio/spc700.cc b/src/app/emu/audio/spc700.cc index 1c5dee06..c2626305 100644 --- a/src/app/emu/audio/spc700.cc +++ b/src/app/emu/audio/spc700.cc @@ -56,7 +56,6 @@ void Spc700::RunOpcode() { } void Spc700::ExecuteInstructions(uint8_t opcode) { - uint16_t initialPC = PC; switch (opcode) { case 0x00: { // nop imp read(PC); diff --git a/src/app/emu/cpu/cpu.h b/src/app/emu/cpu/cpu.h index a9168a69..7623283b 100644 --- a/src/app/emu/cpu/cpu.h +++ b/src/app/emu/cpu/cpu.h @@ -10,7 +10,6 @@ #include "app/core/common.h" #include "app/emu/cpu/clock.h" #include "app/emu/cpu/internal/opcodes.h" -#include "app/emu/debug/log.h" #include "app/emu/memory/memory.h" namespace yaze { @@ -36,7 +35,7 @@ class InstructionEntry { std::string instruction; // Human-readable instruction text }; -class Cpu : public Loggable, public core::ExperimentFlags { +class Cpu : public core::ExperimentFlags { public: explicit Cpu(memory::Memory& mem, Clock& vclock, memory::CpuCallbacks& callbacks) diff --git a/src/app/emu/debug/debugger.h b/src/app/emu/debug/debugger.h deleted file mode 100644 index 4c5d0e46..00000000 --- a/src/app/emu/debug/debugger.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef YAZE_APP_EMU_DEBUG_DEBUGGER_H_ -#define YAZE_APP_EMU_DEBUG_DEBUGGER_H_ - -#include "app/emu/audio/apu.h" -#include "app/emu/cpu/cpu.h" -#include "app/emu/video/ppu.h" - -namespace yaze { -namespace app { -namespace emu { - -class Debugger { - public: - Debugger() = default; - // Attach the debugger to the emulator - // Debugger(CPU &cpu, PPU &ppu, Apu &apu); - - // Set a breakpoint - void SetBreakpoint(uint16_t address); - - // Remove a breakpoint - void RemoveBreakpoint(uint16_t address); - - // Step through the code - void Step(); - - // Inspect memory - uint8_t InspectMemory(uint16_t address); - - // Modify memory - void ModifyMemory(uint16_t address, uint8_t value); - - // Inspect registers - uint8_t InspectRegister(uint8_t reg); - - // Modify registers - void ModifyRegister(uint8_t reg, uint8_t value); - - // Handle other debugger tasks - // ... - - private: - // References to the emulator's components - // CPU &cpu; - // PPU &ppu; - // Apu &apu; - - // Breakpoints, watchpoints, etc. - // ... -}; - -} // namespace emu -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_EMU_DBG_H_ \ No newline at end of file diff --git a/src/app/emu/debug/log.h b/src/app/emu/debug/log.h deleted file mode 100644 index 92c7649f..00000000 --- a/src/app/emu/debug/log.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef YAZE_APP_EMU_LOG_H_ -#define YAZE_APP_EMU_LOG_H_ - -#include -#include - -namespace yaze { -namespace app { -namespace emu { - -// Logger.h -class Logger { - public: - static Logger& GetInstance() { - static Logger instance; - return instance; - } - - void Log(const std::string& message) const { - // Write log messages to a file or console - std::cout << message << std::endl; - } - - private: - Logger() = default; - Logger(const Logger&) = delete; - Logger& operator=(const Logger&) = delete; -}; - -// Loggable.h -class Loggable { - protected: - Logger& logger_ = Logger::GetInstance(); - - virtual ~Loggable() = default; - virtual void LogMessage(const std::string& message) { logger_.Log(message); } -}; - -} // namespace emu -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_EMU_LOG_H_ \ No newline at end of file diff --git a/src/app/emu/debug/emu.cc b/src/app/emu/emu.cc similarity index 87% rename from src/app/emu/debug/emu.cc rename to src/app/emu/emu.cc index 888ca42d..394dbf7a 100644 --- a/src/app/emu/debug/emu.cc +++ b/src/app/emu/emu.cc @@ -5,10 +5,6 @@ #endif #include -#include "absl/status/status.h" -#include "absl/strings/str_format.h" -#include "imgui/imgui.h" -#include "imgui_memory_editor.h" #include #include @@ -25,24 +21,14 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_format.h" +#include "app/core/utils/sdl_deleter.h" #include "app/emu/snes.h" #include "app/rom.h" +#include "imgui/imgui.h" +#include "imgui_memory_editor.h" using namespace yaze::app; - -struct sdl_deleter { - void operator()(SDL_Window *p) const { - if (p) { - SDL_DestroyWindow(p); - } - } - void operator()(SDL_Renderer *p) const { - if (p) { - SDL_DestroyRenderer(p); - } - } - void operator()(SDL_Texture *p) const { SDL_DestroyTexture(p); } -}; +using yaze::app::core::SDL_Deleter; int main(int argc, char **argv) { absl::InitializeSymbolizer(argv[0]); @@ -52,33 +38,30 @@ int main(int argc, char **argv) { options.alarm_on_failure_secs = true; absl::InstallFailureSignalHandler(options); - std::unique_ptr window_; - std::unique_ptr renderer_; + std::unique_ptr window_; + std::unique_ptr renderer_; if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { return EXIT_FAILURE; } else { SDL_DisplayMode displayMode; SDL_GetCurrentDisplayMode(0, &displayMode); - int screenWidth = displayMode.w * 0.8; - int screenHeight = displayMode.h * 0.8; - - window_ = std::unique_ptr( + window_ = std::unique_ptr( SDL_CreateWindow("Yaze Emulator", // window title SDL_WINDOWPOS_UNDEFINED, // initial x position SDL_WINDOWPOS_UNDEFINED, // initial y position 512, // width, in pixels 480, // height, in pixels SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI), - sdl_deleter()); + SDL_Deleter()); if (window_ == nullptr) { return EXIT_FAILURE; } } - renderer_ = std::unique_ptr( + renderer_ = std::unique_ptr( SDL_CreateRenderer(window_.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), - sdl_deleter()); + SDL_Deleter()); if (renderer_ == nullptr) { return EXIT_FAILURE; } else { @@ -102,7 +85,7 @@ int main(int argc, char **argv) { SDL_PauseAudioDevice(audio_device_, 0); #ifdef __APPLE__ - InitializeCocoa(); + yaze_initialize_cocoa(); #endif auto ppu_texture_ = @@ -115,7 +98,7 @@ int main(int argc, char **argv) { Rom rom_; emu::SNES snes_; - Bytes rom_data_; + std::vector rom_data_; bool running = true; bool loaded = false; @@ -126,7 +109,10 @@ int main(int argc, char **argv) { int wanted_samples_ = 0; SDL_Event event; - rom_.LoadFromFile("inidisp_hammer_0f00.sfc"); + if (!rom_.LoadFromFile("inidisp_hammer_0f00.sfc").ok()) { + return EXIT_FAILURE; + } + if (rom_.is_loaded()) { rom_data_ = rom_.vector(); snes_.Init(rom_data_); diff --git a/src/app/emu/CMakeLists.txt b/src/app/emu/emu.cmake similarity index 53% rename from src/app/emu/CMakeLists.txt rename to src/app/emu/emu.cmake index 844e76f4..c326ff87 100644 --- a/src/app/emu/CMakeLists.txt +++ b/src/app/emu/emu.cmake @@ -1,7 +1,7 @@ add_executable( yaze_emu app/rom.cc - app/emu/debug/emu.cc + app/emu/emu.cc ${YAZE_APP_EMU_SRC} ${YAZE_APP_CORE_SRC} ${YAZE_APP_EDITOR_SRC} @@ -11,13 +11,27 @@ add_executable( ${IMGUI_SRC} ) +if (APPLE) + list(APPEND YAZE_APP_CORE_SRC + app/core/platform/app_delegate.mm) +endif() + target_include_directories( yaze_emu PUBLIC lib/ app/ + ${CMAKE_SOURCE_DIR}/incl/ ${CMAKE_SOURCE_DIR}/src/ ${PNG_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ) -target_link_libraries(yaze_emu PUBLIC ${ABSL_TARGETS} ${SDL_TARGETS} ${PNG_LIBRARIES} ${CMAKE_DL_LIBS} ImGui) \ No newline at end of file +target_link_libraries( + yaze_emu PUBLIC + ${ABSL_TARGETS} + ${SDL_TARGETS} + ${PNG_LIBRARIES} + ${CMAKE_DL_LIBS} + ImGui + ImGuiTestEngine +) \ No newline at end of file diff --git a/src/app/emu/emulator.cc b/src/app/emu/emulator.cc index 4373642b..ac912ac3 100644 --- a/src/app/emu/emulator.cc +++ b/src/app/emu/emulator.cc @@ -1,18 +1,18 @@ #include "app/emu/emulator.h" -#include "imgui/imgui.h" -#include "imgui_memory_editor.h" - #include #include #include "app/core/constants.h" #include "app/core/platform/file_dialog.h" +#include "app/core/platform/renderer.h" #include "app/emu/snes.h" #include "app/gui/icons.h" #include "app/gui/input.h" #include "app/gui/zeml.h" #include "app/rom.h" +#include "imgui/imgui.h" +#include "imgui_memory_editor.h" namespace yaze { namespace app { @@ -52,9 +52,9 @@ using ImGui::Text; void Emulator::Run() { static bool loaded = false; if (!snes_.running() && rom()->is_loaded()) { - ppu_texture_ = - SDL_CreateTexture(rom()->renderer().get(), SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, 512, 480); + ppu_texture_ = SDL_CreateTexture(core::Renderer::GetInstance().renderer(), + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 512, 480); if (ppu_texture_ == NULL) { printf("Failed to create texture: %s\n", SDL_GetError()); return; @@ -118,7 +118,8 @@ void Emulator::RenderSnesPpu() { ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar); ImGui::SetCursorPosX((ImGui::GetWindowSize().x - size.x) * 0.5f); ImGui::SetCursorPosY((ImGui::GetWindowSize().y - size.y) * 0.5f); - ImGui::Image((void*)ppu_texture_, size, ImVec2(0, 0), ImVec2(1, 1)); + ImGui::Image((ImTextureID)(intptr_t)ppu_texture_, size, ImVec2(0, 0), + ImVec2(1, 1)); ImGui::EndChild(); } else { @@ -246,7 +247,7 @@ void Emulator::RenderNavBar() { } if (open_file) { - auto file_name = FileDialogWrapper::ShowOpenFileDialog(); + auto file_name = core::FileDialogWrapper::ShowOpenFileDialog(); if (!file_name.empty()) { std::ifstream file(file_name, std::ios::binary); // Load the data directly into rom_data @@ -260,7 +261,101 @@ void Emulator::RenderNavBar() { void Emulator::HandleEvents() { // Handle user input events - // ... + if (ImGui::IsKeyPressed(keybindings_.a_button)) { + snes_.SetButtonState(1, 0, true); + } + + if (ImGui::IsKeyPressed(keybindings_.b_button)) { + snes_.SetButtonState(1, 1, true); + } + + if (ImGui::IsKeyPressed(keybindings_.select_button)) { + snes_.SetButtonState(1, 2, true); + } + + if (ImGui::IsKeyPressed(keybindings_.start_button)) { + snes_.SetButtonState(1, 3, true); + } + + if (ImGui::IsKeyPressed(keybindings_.up_button)) { + snes_.SetButtonState(1, 4, true); + } + + if (ImGui::IsKeyPressed(keybindings_.down_button)) { + snes_.SetButtonState(1, 5, true); + } + + if (ImGui::IsKeyPressed(keybindings_.left_button)) { + snes_.SetButtonState(1, 6, true); + } + + if (ImGui::IsKeyPressed(keybindings_.right_button)) { + snes_.SetButtonState(1, 7, true); + } + + if (ImGui::IsKeyPressed(keybindings_.x_button)) { + snes_.SetButtonState(1, 8, true); + } + + if (ImGui::IsKeyPressed(keybindings_.y_button)) { + snes_.SetButtonState(1, 9, true); + } + + if (ImGui::IsKeyPressed(keybindings_.l_button)) { + snes_.SetButtonState(1, 10, true); + } + + if (ImGui::IsKeyPressed(keybindings_.r_button)) { + snes_.SetButtonState(1, 11, true); + } + + if (ImGui::IsKeyReleased(keybindings_.a_button)) { + snes_.SetButtonState(1, 0, false); + } + + if (ImGui::IsKeyReleased(keybindings_.b_button)) { + snes_.SetButtonState(1, 1, false); + } + + if (ImGui::IsKeyReleased(keybindings_.select_button)) { + snes_.SetButtonState(1, 2, false); + } + + if (ImGui::IsKeyReleased(keybindings_.start_button)) { + snes_.SetButtonState(1, 3, false); + } + + if (ImGui::IsKeyReleased(keybindings_.up_button)) { + snes_.SetButtonState(1, 4, false); + } + + if (ImGui::IsKeyReleased(keybindings_.down_button)) { + snes_.SetButtonState(1, 5, false); + } + + if (ImGui::IsKeyReleased(keybindings_.left_button)) { + snes_.SetButtonState(1, 6, false); + } + + if (ImGui::IsKeyReleased(keybindings_.right_button)) { + snes_.SetButtonState(1, 7, false); + } + + if (ImGui::IsKeyReleased(keybindings_.x_button)) { + snes_.SetButtonState(1, 8, false); + } + + if (ImGui::IsKeyReleased(keybindings_.y_button)) { + snes_.SetButtonState(1, 9, false); + } + + if (ImGui::IsKeyReleased(keybindings_.l_button)) { + snes_.SetButtonState(1, 10, false); + } + + if (ImGui::IsKeyReleased(keybindings_.r_button)) { + snes_.SetButtonState(1, 11, false); + } } void Emulator::RenderBreakpointList() { diff --git a/src/app/emu/emulator.h b/src/app/emu/emulator.h index 8255109e..2b7d844d 100644 --- a/src/app/emu/emulator.h +++ b/src/app/emu/emulator.h @@ -1,14 +1,13 @@ #ifndef YAZE_APP_CORE_EMULATOR_H #define YAZE_APP_CORE_EMULATOR_H -#include "imgui/imgui.h" - #include #include #include "app/emu/snes.h" #include "app/gui/zeml.h" #include "app/rom.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -19,6 +18,46 @@ namespace app { */ namespace emu { +// case SDLK_z: +// editor.emulator().snes().SetButtonState(1, 0, false); +// case SDLK_a: +// editor.emulator().snes().SetButtonState(1, 1, false); +// case SDLK_RSHIFT: +// editor.emulator().snes().SetButtonState(1, 2, false); +// case SDLK_RETURN: +// editor.emulator().snes().SetButtonState(1, 3, false); +// case SDLK_UP: +// editor.emulator().snes().SetButtonState(1, 4, false); +// case SDLK_DOWN: +// editor.emulator().snes().SetButtonState(1, 5, false); +// case SDLK_LEFT: +// editor.emulator().snes().SetButtonState(1, 6, false); +// case SDLK_RIGHT: +// editor.emulator().snes().SetButtonState(1, 7, false); +// case SDLK_x: +// editor.emulator().snes().SetButtonState(1, 8, false); +// case SDLK_s: +// editor.emulator().snes().SetButtonState(1, 9, false); +// case SDLK_d: +// editor.emulator().snes().SetButtonState(1, 10, false); +// case SDLK_c: +// editor.emulator().snes().SetButtonState(1, 11, false); + +struct EmulatorKeybindings { + ImGuiKey a_button = ImGuiKey_Z; + ImGuiKey b_button = ImGuiKey_A; + ImGuiKey x_button = ImGuiKey_S; + ImGuiKey y_button = ImGuiKey_X; + ImGuiKey l_button = ImGuiKey_Q; + ImGuiKey r_button = ImGuiKey_W; + ImGuiKey start_button = ImGuiKey_Enter; + ImGuiKey select_button = ImGuiKey_Backspace; + ImGuiKey up_button = ImGuiKey_UpArrow; + ImGuiKey down_button = ImGuiKey_DownArrow; + ImGuiKey left_button = ImGuiKey_LeftArrow; + ImGuiKey right_button = ImGuiKey_RightArrow; +}; + /** * @class Emulator * @brief A class for emulating and debugging SNES games. @@ -145,6 +184,8 @@ class Emulator : public SharedRom { std::vector rom_data_; + EmulatorKeybindings keybindings_; + gui::zeml::Node emulator_node_; }; diff --git a/src/app/emu/debug/asm_parser.h b/src/app/emu/memory/asm_parser.h similarity index 100% rename from src/app/emu/debug/asm_parser.h rename to src/app/emu/memory/asm_parser.h diff --git a/src/app/emu/memory/dma.cc b/src/app/emu/memory/dma.cc index 734acaae..935b04c8 100644 --- a/src/app/emu/memory/dma.cc +++ b/src/app/emu/memory/dma.cc @@ -17,23 +17,23 @@ static const int transferLength[8] = {1, 2, 2, 4, 4, 4, 2, 4}; void Reset(MemoryImpl* memory) { auto channel = memory->dma_channels(); for (int i = 0; i < 8; i++) { - channel[i].bAdr = 0xff; - channel[i].aAdr = 0xffff; - channel[i].aBank = 0xff; + channel[i].b_addr = 0xff; + channel[i].a_addr = 0xffff; + channel[i].a_bank = 0xff; channel[i].size = 0xffff; - channel[i].indBank = 0xff; - channel[i].tableAdr = 0xffff; - channel[i].repCount = 0xff; + channel[i].ind_bank = 0xff; + channel[i].table_addr = 0xffff; + channel[i].rep_count = 0xff; channel[i].unusedByte = 0xff; - channel[i].dmaActive = false; - channel[i].hdmaActive = false; + channel[i].dma_active = false; + channel[i].hdma_active = false; channel[i].mode = 7; channel[i].fixed = true; channel[i].decrement = true; channel[i].indirect = true; - channel[i].fromB = true; + channel[i].from_b = true; channel[i].unusedBit = true; - channel[i].doTransfer = false; + channel[i].do_transfer = false; channel[i].terminated = false; } memory->set_dma_state(0); @@ -51,20 +51,20 @@ uint8_t Read(MemoryImpl* memory, uint16_t adr) { val |= channel[c].decrement << 4; val |= channel[c].unusedBit << 5; val |= channel[c].indirect << 6; - val |= channel[c].fromB << 7; + val |= channel[c].from_b << 7; return val; } case 0x1: { - return channel[c].bAdr; + return channel[c].b_addr; } case 0x2: { - return channel[c].aAdr & 0xff; + return channel[c].a_addr & 0xff; } case 0x3: { - return channel[c].aAdr >> 8; + return channel[c].a_addr >> 8; } case 0x4: { - return channel[c].aBank; + return channel[c].a_bank; } case 0x5: { return channel[c].size & 0xff; @@ -73,16 +73,16 @@ uint8_t Read(MemoryImpl* memory, uint16_t adr) { return channel[c].size >> 8; } case 0x7: { - return channel[c].indBank; + return channel[c].ind_bank; } case 0x8: { - return channel[c].tableAdr & 0xff; + return channel[c].table_addr & 0xff; } case 0x9: { - return channel[c].tableAdr >> 8; + return channel[c].table_addr >> 8; } case 0xa: { - return channel[c].repCount; + return channel[c].rep_count; } case 0xb: case 0xf: { @@ -104,23 +104,23 @@ void Write(MemoryImpl* memory, uint16_t adr, uint8_t val) { channel[c].decrement = val & 0x10; channel[c].unusedBit = val & 0x20; channel[c].indirect = val & 0x40; - channel[c].fromB = val & 0x80; + channel[c].from_b = val & 0x80; break; } case 0x1: { - channel[c].bAdr = val; + channel[c].b_addr = val; break; } case 0x2: { - channel[c].aAdr = (channel[c].aAdr & 0xff00) | val; + channel[c].a_addr = (channel[c].a_addr & 0xff00) | val; break; } case 0x3: { - channel[c].aAdr = (channel[c].aAdr & 0xff) | (val << 8); + channel[c].a_addr = (channel[c].a_addr & 0xff) | (val << 8); break; } case 0x4: { - channel[c].aBank = val; + channel[c].a_bank = val; break; } case 0x5: { @@ -132,19 +132,19 @@ void Write(MemoryImpl* memory, uint16_t adr, uint8_t val) { break; } case 0x7: { - channel[c].indBank = val; + channel[c].ind_bank = val; break; } case 0x8: { - channel[c].tableAdr = (channel[c].tableAdr & 0xff00) | val; + channel[c].table_addr = (channel[c].table_addr & 0xff00) | val; break; } case 0x9: { - channel[c].tableAdr = (channel[c].tableAdr & 0xff) | (val << 8); + channel[c].table_addr = (channel[c].table_addr & 0xff) | (val << 8); break; } case 0xa: { - channel[c].repCount = val; + channel[c].rep_count = val; break; } case 0xb: @@ -168,22 +168,22 @@ void DoDma(SNES* snes, MemoryImpl* memory, int cpuCycles) { // full transfer overhead WaitCycle(snes, memory); for (int i = 0; i < 8; i++) { - if (!channel[i].dmaActive) continue; + if (!channel[i].dma_active) continue; // do channel i WaitCycle(snes, memory); // overhead per channel int offIndex = 0; - while (channel[i].dmaActive) { + while (channel[i].dma_active) { WaitCycle(snes, memory); - TransferByte(snes, memory, channel[i].aAdr, channel[i].aBank, - channel[i].bAdr + bAdrOffsets[channel[i].mode][offIndex++], - channel[i].fromB); + TransferByte(snes, memory, channel[i].a_addr, channel[i].a_bank, + channel[i].b_addr + bAdrOffsets[channel[i].mode][offIndex++], + channel[i].from_b); offIndex &= 3; if (!channel[i].fixed) { - channel[i].aAdr += channel[i].decrement ? -1 : 1; + channel[i].a_addr += channel[i].decrement ? -1 : 1; } channel[i].size--; if (channel[i].size == 0) { - channel[i].dmaActive = false; + channel[i].dma_active = false; } } } @@ -224,8 +224,8 @@ void InitHdma(SNES* snes, MemoryImpl* memory, bool do_sync, int cpu_cycles) { bool hdmaEnabled = false; // check if a channel is enabled, and do reset for (int i = 0; i < 8; i++) { - if (channel[i].hdmaActive) hdmaEnabled = true; - channel[i].doTransfer = false; + if (channel[i].hdma_active) hdmaEnabled = true; + channel[i].do_transfer = false; channel[i].terminated = false; } if (!hdmaEnabled) return; @@ -235,24 +235,24 @@ void InitHdma(SNES* snes, MemoryImpl* memory, bool do_sync, int cpu_cycles) { // full transfer overhead snes->RunCycles(8); for (int i = 0; i < 8; i++) { - if (channel[i].hdmaActive) { + if (channel[i].hdma_active) { // terminate any dma - channel[i].dmaActive = false; + channel[i].dma_active = false; // load address, repCount, and indirect address if needed snes->RunCycles(8); - channel[i].tableAdr = channel[i].aAdr; - channel[i].repCount = - snes->Read((channel[i].aBank << 16) | channel[i].tableAdr++); - if (channel[i].repCount == 0) channel[i].terminated = true; + channel[i].table_addr = channel[i].a_addr; + channel[i].rep_count = + snes->Read((channel[i].a_bank << 16) | channel[i].table_addr++); + if (channel[i].rep_count == 0) channel[i].terminated = true; if (channel[i].indirect) { snes->RunCycles(8); channel[i].size = - snes->Read((channel[i].aBank << 16) | channel[i].tableAdr++); + snes->Read((channel[i].a_bank << 16) | channel[i].table_addr++); snes->RunCycles(8); channel[i].size |= - snes->Read((channel[i].aBank << 16) | channel[i].tableAdr++) << 8; + snes->Read((channel[i].a_bank << 16) | channel[i].table_addr++) << 8; } - channel[i].doTransfer = true; + channel[i].do_transfer = true; } } if (do_sync) snes->SyncCycles(false, cpu_cycles); @@ -264,7 +264,7 @@ void DoHdma(SNES* snes, MemoryImpl* memory, bool do_sync, int cycles) { bool hdmaActive = false; int lastActive = 0; for (int i = 0; i < 8; i++) { - if (channel[i].hdmaActive) { + if (channel[i].hdma_active) { hdmaActive = true; if (!channel[i].terminated) lastActive = i; } @@ -280,20 +280,20 @@ void DoHdma(SNES* snes, MemoryImpl* memory, bool do_sync, int cycles) { // do all copies for (int i = 0; i < 8; i++) { // terminate any dma - if (channel[i].hdmaActive) channel[i].dmaActive = false; - if (channel[i].hdmaActive && !channel[i].terminated) { + if (channel[i].hdma_active) channel[i].dma_active = false; + if (channel[i].hdma_active && !channel[i].terminated) { // do the hdma - if (channel[i].doTransfer) { + if (channel[i].do_transfer) { for (int j = 0; j < transferLength[channel[i].mode]; j++) { snes->RunCycles(8); if (channel[i].indirect) { - TransferByte(snes, memory, channel[i].size++, channel[i].indBank, - channel[i].bAdr + bAdrOffsets[channel[i].mode][j], - channel[i].fromB); + TransferByte(snes, memory, channel[i].size++, channel[i].ind_bank, + channel[i].b_addr + bAdrOffsets[channel[i].mode][j], + channel[i].from_b); } else { - TransferByte(snes, memory, channel[i].tableAdr++, channel[i].aBank, - channel[i].bAdr + bAdrOffsets[channel[i].mode][j], - channel[i].fromB); + TransferByte(snes, memory, channel[i].table_addr++, channel[i].a_bank, + channel[i].b_addr + bAdrOffsets[channel[i].mode][j], + channel[i].from_b); } } } @@ -301,31 +301,31 @@ void DoHdma(SNES* snes, MemoryImpl* memory, bool do_sync, int cycles) { } // do all updates for (int i = 0; i < 8; i++) { - if (channel[i].hdmaActive && !channel[i].terminated) { - channel[i].repCount--; - channel[i].doTransfer = channel[i].repCount & 0x80; + if (channel[i].hdma_active && !channel[i].terminated) { + channel[i].rep_count--; + channel[i].do_transfer = channel[i].rep_count & 0x80; snes->RunCycles(8); uint8_t newRepCount = - snes->Read((channel[i].aBank << 16) | channel[i].tableAdr); - if ((channel[i].repCount & 0x7f) == 0) { - channel[i].repCount = newRepCount; - channel[i].tableAdr++; + snes->Read((channel[i].a_bank << 16) | channel[i].table_addr); + if ((channel[i].rep_count & 0x7f) == 0) { + channel[i].rep_count = newRepCount; + channel[i].table_addr++; if (channel[i].indirect) { - if (channel[i].repCount == 0 && i == lastActive) { + if (channel[i].rep_count == 0 && i == lastActive) { // if this is the last active channel, only fetch high, and use 0 // for low channel[i].size = 0; } else { snes->RunCycles(8); channel[i].size = - snes->Read((channel[i].aBank << 16) | channel[i].tableAdr++); + snes->Read((channel[i].a_bank << 16) | channel[i].table_addr++); } snes->RunCycles(8); channel[i].size |= - snes->Read((channel[i].aBank << 16) | channel[i].tableAdr++) << 8; + snes->Read((channel[i].a_bank << 16) | channel[i].table_addr++) << 8; } - if (channel[i].repCount == 0) channel[i].terminated = true; - channel[i].doTransfer = true; + if (channel[i].rep_count == 0) channel[i].terminated = true; + channel[i].do_transfer = true; } } } @@ -359,9 +359,9 @@ void StartDma(MemoryImpl* memory, uint8_t val, bool hdma) { auto channel = memory->dma_channels(); for (int i = 0; i < 8; i++) { if (hdma) { - channel[i].hdmaActive = val & (1 << i); + channel[i].hdma_active = val & (1 << i); } else { - channel[i].dmaActive = val & (1 << i); + channel[i].dma_active = val & (1 << i); } } if (!hdma) { diff --git a/src/app/emu/memory/dma_channel.h b/src/app/emu/memory/dma_channel.h index 028b4fc0..385ab472 100644 --- a/src/app/emu/memory/dma_channel.h +++ b/src/app/emu/memory/dma_channel.h @@ -9,24 +9,24 @@ namespace emu { namespace memory { typedef struct DmaChannel { - uint8_t bAdr; - uint16_t aAdr; - uint8_t aBank; - uint16_t size; // also indirect hdma adr - uint8_t indBank; // hdma - uint16_t tableAdr; // hdma - uint8_t repCount; // hdma + uint8_t b_addr; + uint16_t a_addr; + uint8_t a_bank; + uint16_t size; // also indirect hdma adr + uint8_t ind_bank; // hdma + uint16_t table_addr; // hdma + uint8_t rep_count; // hdma uint8_t unusedByte; - bool dmaActive; - bool hdmaActive; + bool dma_active; + bool hdma_active; uint8_t mode; bool fixed; bool decrement; bool indirect; // hdma - bool fromB; + bool from_b; bool unusedBit; - bool doTransfer; // hdma - bool terminated; // hdma + bool do_transfer; // hdma + bool terminated; // hdma } DmaChannel; } // namespace memory diff --git a/src/app/emu/memory/memory.cc b/src/app/emu/memory/memory.cc index 56c1231f..f890c789 100644 --- a/src/app/emu/memory/memory.cc +++ b/src/app/emu/memory/memory.cc @@ -1,34 +1,33 @@ #include "app/emu/memory/memory.h" -#include "imgui/imgui.h" - #include #include #include #include -#include "app/emu/debug/log.h" +#include "imgui/imgui.h" namespace yaze { namespace app { namespace emu { namespace memory { -void MemoryImpl::Initialize(const std::vector& romData, bool verbose) { +void MemoryImpl::Initialize(const std::vector& rom_data, + bool verbose) { verbose_ = verbose; type_ = 1; auto location = 0x7FC0; // GetHeaderOffset(); - romSize = 0x400 << romData[location + 0x17]; - sramSize = 0x400 << romData[location + 0x18]; - rom_.resize(romSize); + rom_size_ = 0x400 << rom_data[location + 0x17]; + sram_size_ = 0x400 << rom_data[location + 0x18]; + rom_.resize(rom_size_); // Copy memory into rom_ - for (size_t i = 0; i < romSize; i++) { - rom_[i] = romData[i]; + for (size_t i = 0; i < rom_size_; i++) { + rom_[i] = rom_data[i]; } - ram_.resize(sramSize); - for (size_t i = 0; i < sramSize; i++) { + ram_.resize(sram_size_); + for (size_t i = 0; i < sram_size_; i++) { ram_[i] = 0; } @@ -37,71 +36,19 @@ void MemoryImpl::Initialize(const std::vector& romData, bool verbose) { std::fill(memory_.begin(), memory_.end(), 0); // Load ROM data into memory based on LoROM mapping - size_t romSize = romData.size(); - size_t romAddress = 0; + size_t rom_data_size = rom_data.size(); + size_t rom_address = 0; const size_t ROM_CHUNK_SIZE = 0x8000; // 32 KB for (size_t bank = 0x00; bank <= 0x3F; ++bank) { for (size_t offset = 0x8000; offset <= 0xFFFF; offset += ROM_CHUNK_SIZE) { - if (romAddress < romSize) { - std::copy(romData.begin() + romAddress, - romData.begin() + romAddress + ROM_CHUNK_SIZE, + if (rom_address < rom_data_size) { + std::copy(rom_data.begin() + rom_address, + rom_data.begin() + rom_address + ROM_CHUNK_SIZE, memory_.begin() + (bank << 16) + offset); - romAddress += ROM_CHUNK_SIZE; + rom_address += ROM_CHUNK_SIZE; } } } - -} - -memory::RomInfo MemoryImpl::ReadRomHeader() { - memory::RomInfo romInfo; - - uint32_t offset = GetHeaderOffset(); - - // Read cartridge title - char title[22]; - for (int i = 0; i < 21; ++i) { - title[i] = ReadByte(offset + i); - } - title[21] = '\0'; // Null-terminate the string - romInfo.title = std::string(title); - - // Read ROM speed and memory map mode - uint8_t romSpeedAndMapMode = ReadByte(offset + 0x15); - romInfo.romSpeed = (memory::RomSpeed)(romSpeedAndMapMode & 0x07); - romInfo.bankSize = (memory::BankSize)((romSpeedAndMapMode >> 5) & 0x01); - - // Read ROM type - romInfo.romType = (memory::RomType)ReadByte(offset + 0x16); - - // Read ROM size - romInfo.romSize = (memory::RomSize)ReadByte(offset + 0x17); - - // Read RAM size - romInfo.sramSize = (memory::SramSize)ReadByte(offset + 0x18); - - // Read country code - romInfo.countryCode = (memory::CountryCode)ReadByte(offset + 0x19); - - // Read license - romInfo.license = (memory::License)ReadByte(offset + 0x1A); - - // Read ROM version - romInfo.version = ReadByte(offset + 0x1B); - - // Read checksum complement - romInfo.checksumComplement = ReadWord(offset + 0x1E); - - // Read checksum - romInfo.checksum = ReadWord(offset + 0x1C); - - // Read NMI VBL vector - romInfo.nmiVblVector = ReadWord(offset + 0x3E); - - // Read reset vector - romInfo.resetVector = ReadWord(offset + 0x3C); - - return romInfo; } uint8_t MemoryImpl::cart_read(uint8_t bank, uint16_t adr) { @@ -136,59 +83,59 @@ void MemoryImpl::cart_write(uint8_t bank, uint16_t adr, uint8_t val) { uint8_t MemoryImpl::cart_readLorom(uint8_t bank, uint16_t adr) { if (((bank >= 0x70 && bank < 0x7e) || bank >= 0xf0) && adr < 0x8000 && - sramSize > 0) { + sram_size_ > 0) { // banks 70-7e and f0-ff, adr 0000-7fff - return ram_[(((bank & 0xf) << 15) | adr) & (sramSize - 1)]; + return ram_[(((bank & 0xf) << 15) | adr) & (sram_size_ - 1)]; } bank &= 0x7f; if (adr >= 0x8000 || bank >= 0x40) { // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff - return rom_[((bank << 15) | (adr & 0x7fff)) & (romSize - 1)]; + return rom_[((bank << 15) | (adr & 0x7fff)) & (rom_size_ - 1)]; } return open_bus_; } void MemoryImpl::cart_writeLorom(uint8_t bank, uint16_t adr, uint8_t val) { if (((bank >= 0x70 && bank < 0x7e) || bank > 0xf0) && adr < 0x8000 && - sramSize > 0) { + sram_size_ > 0) { // banks 70-7e and f0-ff, adr 0000-7fff - ram_[(((bank & 0xf) << 15) | adr) & (sramSize - 1)] = val; + ram_[(((bank & 0xf) << 15) | adr) & (sram_size_ - 1)] = val; } } uint8_t MemoryImpl::cart_readHirom(uint8_t bank, uint16_t adr) { bank &= 0x7f; - if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) { + if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sram_size_ > 0) { // banks 00-3f and 80-bf, adr 6000-7fff - return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)]; + return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sram_size_ - 1)]; } if (adr >= 0x8000 || bank >= 0x40) { // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff - return rom_[(((bank & 0x3f) << 16) | adr) & (romSize - 1)]; + return rom_[(((bank & 0x3f) << 16) | adr) & (rom_size_ - 1)]; } return open_bus_; } uint8_t MemoryImpl::cart_readExHirom(uint8_t bank, uint16_t adr) { - if ((bank & 0x7f) < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) { + if ((bank & 0x7f) < 0x40 && adr >= 0x6000 && adr < 0x8000 && sram_size_ > 0) { // banks 00-3f and 80-bf, adr 6000-7fff - return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)]; + return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sram_size_ - 1)]; } bool secondHalf = bank < 0x80; bank &= 0x7f; if (adr >= 0x8000 || bank >= 0x40) { // adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff return rom_[(((bank & 0x3f) << 16) | (secondHalf ? 0x400000 : 0) | adr) & - (romSize - 1)]; + (rom_size_ - 1)]; } return open_bus_; } void MemoryImpl::cart_writeHirom(uint8_t bank, uint16_t adr, uint8_t val) { bank &= 0x7f; - if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) { + if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sram_size_ > 0) { // banks 00-3f and 80-bf, adr 6000-7fff - ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)] = val; + ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sram_size_ - 1)] = val; } } @@ -218,70 +165,6 @@ uint32_t MemoryImpl::GetMappedAddress(uint32_t address) const { return address; // Return the original address if no mapping is defined } -void DrawSnesMemoryMapping(const MemoryImpl& memory) { - // Using those as a base value to create width/height that are factor of the - // size of our font - const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x; - const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing(); - const char* column_names[] = { - "Offset", "0x00", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "0x07", - "0x08", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F", "0x10", - "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", - "0x1A", "0x1B", "0x1C", "0x1D", "0x1E", "0x1F"}; - const int columns_count = IM_ARRAYSIZE(column_names); - const int rows_count = 16; - - static ImGuiTableFlags table_flags = - ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | - ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | - ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | - ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | - ImGuiTableFlags_HighlightHoveredColumn; - static bool bools[columns_count * rows_count] = {}; - static int frozen_cols = 1; - static int frozen_rows = 2; - ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX); - ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY); - ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, - ImGuiTableFlags_NoBordersInBody); - ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, - ImGuiTableFlags_HighlightHoveredColumn); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2); - - if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, - ImVec2(0.0f, TEXT_BASE_HEIGHT * 12))) { - ImGui::TableSetupColumn( - column_names[0], - ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder); - for (int n = 1; n < columns_count; n++) - ImGui::TableSetupColumn(column_names[n], - ImGuiTableColumnFlags_AngledHeader | - ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows); - - ImGui::TableAngledHeadersRow(); - ImGui::TableHeadersRow(); - for (int row = 0; row < rows_count; row++) { - ImGui::PushID(row); - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::AlignTextToFramePadding(); - ImGui::Text("Offset 0x%04X", row); - for (int column = 1; column < columns_count; column++) - if (ImGui::TableSetColumnIndex(column)) { - ImGui::PushID(column); - ImGui::Checkbox("", &bools[row * columns_count + column]); - ImGui::PopID(); - } - ImGui::PopID(); - } - ImGui::EndTable(); - } -} - } // namespace memory } // namespace emu } // namespace app diff --git a/src/app/emu/memory/memory.h b/src/app/emu/memory/memory.h index 8564e8c8..6485a147 100644 --- a/src/app/emu/memory/memory.h +++ b/src/app/emu/memory/memory.h @@ -7,7 +7,6 @@ #include #include -#include "app/emu/debug/log.h" #include "app/emu/memory/dma_channel.h" // LoROM (Mode 20): @@ -32,67 +31,6 @@ namespace app { namespace emu { namespace memory { -enum RomSpeed { SLOW_ROM = 0x00, FAST_ROM = 0x07 }; - -enum BankSize { LOW_ROM = 0x00, HI_ROM = 0x01 }; - -enum RomType { - ROM_DEFAULT = 0x00, - ROM_RAM = 0x01, - ROM_SRAM = 0x02, - ROM_DSP1 = 0x03, - ROM_DSP1_RAM = 0x04, - ROM_DSP1_SRAM = 0x05, - FX = 0x06 -}; - -enum RomSize { - SIZE_2_MBIT = 0x08, - SIZE_4_MBIT = 0x09, - SIZE_8_MBIT = 0x0A, - SIZE_16_MBIT = 0x0B, - SIZE_32_MBIT = 0x0C -}; - -enum SramSize { - NO_SRAM = 0x00, - SRAM_16_KBIT = 0x01, - SRAM_32_KBIT = 0x02, - SRAM_64_KBIT = 0x03 -}; - -enum CountryCode { - JAPAN = 0x00, - USA = 0x01, - EUROPE_OCEANIA_ASIA = 0x02, - // ... and other countries -}; - -enum License { - INVALID = 0, - NINTENDO = 1, - ZAMUSE = 5, - CAPCOM = 8, - // ... and other licenses -}; - -class RomInfo { - public: - std::string title; - RomSpeed romSpeed; - BankSize bankSize; - RomType romType; - RomSize romSize; - SramSize sramSize; - CountryCode countryCode; - License license; - uint8_t version; - uint16_t checksumComplement; - uint16_t checksum; - uint16_t nmiVblVector; - uint16_t resetVector; -}; - typedef struct CpuCallbacks { std::function read_byte; std::function write_byte; @@ -161,17 +99,13 @@ class Memory { * system. * */ -class MemoryImpl : public Memory, public Loggable { +class MemoryImpl : public Memory { public: - uint32_t romSize; - uint32_t sramSize; void Initialize(const std::vector& romData, bool verbose = false); uint16_t GetHeaderOffset() { - uint8_t mapMode = memory_[(0x00 << 16) + 0xFFD5]; uint16_t offset; - - switch (mapMode & 0x07) { + switch (memory_[(0x00 << 16) + 0xFFD5] & 0x07) { case 0: // LoROM offset = 0x7FC0; break; @@ -190,8 +124,6 @@ class MemoryImpl : public Memory, public Loggable { return offset; } - memory::RomInfo ReadRomHeader(); - uint8_t cart_read(uint8_t bank, uint16_t adr); void cart_write(uint8_t bank, uint16_t adr, uint8_t val); @@ -348,6 +280,10 @@ class MemoryImpl : public Memory, public Loggable { bool pal_timing_ = false; + // Memory regions + uint32_t rom_size_; + uint32_t sram_size_; + // Frame timing uint16_t h_pos_ = 0; uint16_t v_pos_ = 0; @@ -355,9 +291,6 @@ class MemoryImpl : public Memory, public Loggable { // Dma State uint8_t dma_state_ = 0; - // Dma Channels - DmaChannel channel[8]; - // Open bus uint8_t open_bus_ = 0; @@ -367,12 +300,13 @@ class MemoryImpl : public Memory, public Loggable { // Cart Type uint8_t type_ = 1; + // Dma Channels + DmaChannel channel[8]; + // Memory (64KB) std::vector memory_; }; -void DrawSnesMemoryMapping(const MemoryImpl& memory); - } // namespace memory } // namespace emu } // namespace app diff --git a/src/app/emu/snes.cc b/src/app/emu/snes.cc index 8797e9ce..e152e03b 100644 --- a/src/app/emu/snes.cc +++ b/src/app/emu/snes.cc @@ -9,7 +9,6 @@ #include "app/emu/audio/spc700.h" #include "app/emu/cpu/clock.h" #include "app/emu/cpu/cpu.h" -#include "app/emu/debug/debugger.h" #include "app/emu/memory/dma.h" #include "app/emu/memory/memory.h" #include "app/emu/video/ppu.h" diff --git a/src/app/emu/snes.h b/src/app/emu/snes.h index 2dee6099..6b01c671 100644 --- a/src/app/emu/snes.h +++ b/src/app/emu/snes.h @@ -2,18 +2,12 @@ #define YAZE_APP_EMU_SNES_H #include -#include -#include -#include #include "app/emu/audio/apu.h" -#include "app/emu/audio/spc700.h" #include "app/emu/cpu/clock.h" #include "app/emu/cpu/cpu.h" -#include "app/emu/debug/debugger.h" #include "app/emu/memory/memory.h" #include "app/emu/video/ppu.h" -#include "app/rom.h" namespace yaze { namespace app { @@ -80,7 +74,6 @@ class SNES { private: // Components of the SNES ClockImpl clock_; - Debugger debugger; memory::MemoryImpl memory_; memory::CpuCallbacks cpu_callbacks_ = { @@ -141,4 +134,4 @@ class SNES { } // namespace app } // namespace yaze -#endif // YAZE_APP_EMU_SNES_H \ No newline at end of file +#endif // YAZE_APP_EMU_SNES_H diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index 312e37da..890574a0 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -1,29 +1,32 @@ #include "bitmap.h" #include +#if YAZE_LIB_PNG == 1 #include +#endif #include #include #include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" #include "app/core/constants.h" #include "app/gfx/snes_palette.h" +#define SDL_RETURN_IF_ERROR() \ + if (SDL_GetError() != nullptr) { \ + return absl::InternalError(SDL_GetError()); \ + } + namespace yaze { namespace app { namespace gfx { -namespace { -void GrayscalePalette(SDL_Palette *palette) { - for (int i = 0; i < 8; i++) { - palette->colors[i].r = i * 31; - palette->colors[i].g = i * 31; - palette->colors[i].b = i * 31; - } -} +using core::SDL_Surface_Deleter; +using core::SDL_Texture_Deleter; + +#if YAZE_LIB_PNG == 1 + +namespace png_internal { void PngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) { std::vector *p = (std::vector *)png_get_io_ptr(png_ptr); @@ -47,20 +50,7 @@ void PngReadCallback(png_structp png_ptr, png_bytep outBytes, } } -Uint32 GetSnesPixelFormat(int format) { - switch (format) { - case 0: - return SDL_PIXELFORMAT_INDEX8; - case 1: - return SNES_PIXELFORMAT_2BPP; - case 2: - return SNES_PIXELFORMAT_4BPP; - case 3: - return SNES_PIXELFORMAT_8BPP; - } - return SDL_PIXELFORMAT_INDEX8; -} -} // namespace +} // namespace png_internal bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector &buffer) { png_structp png_ptr = png_create_write_struct("1.6.40", NULL, NULL, NULL); @@ -82,7 +72,7 @@ bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector &buffer) { return false; } - png_set_write_fn(png_ptr, &buffer, PngWriteCallback, NULL); + png_set_write_fn(png_ptr, &buffer, png_internal::PngWriteCallback, NULL); png_colorp pal_ptr; @@ -154,7 +144,7 @@ void ConvertPngToSurface(const std::vector &png_data, } // Set our custom read function - png_set_read_fn(png_ptr, &data, PngReadCallback); + png_set_read_fn(png_ptr, &data, png_internal::PngReadCallback); // Read the PNG info png_read_info(png_ptr, info_ptr); @@ -197,40 +187,78 @@ void ConvertPngToSurface(const std::vector &png_data, SDL_Log("Successfully created SDL_Surface from PNG data"); } -Bitmap::Bitmap(int width, int height, int depth, int data_size) { - Create(width, height, depth, Bytes(data_size, 0)); +std::vector Bitmap::GetPngData() { + ConvertSurfaceToPNG(surface_.get(), png_data_); + return png_data_; } -void Bitmap::Create(int width, int height, int depth, const Bytes &data) { - active_ = true; - width_ = width; - height_ = height; - depth_ = depth; - data_ = data; - data_size_ = data.size(); - pixel_data_ = data_.data(); - surface_ = std::unique_ptr( - SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_, - SDL_PIXELFORMAT_INDEX8), - SDL_Surface_Deleter()); - surface_->pixels = pixel_data_; - GrayscalePalette(surface_->format->palette); - active_ = true; +#endif // YAZE_LIB_PNG + +namespace { + +void GrayscalePalette(SDL_Palette *palette) { + for (int i = 0; i < 8; i++) { + palette->colors[i].r = i * 31; + palette->colors[i].g = i * 31; + palette->colors[i].b = i * 31; + } +} + +Uint32 GetSnesPixelFormat(int format) { + switch (format) { + case 0: + return SDL_PIXELFORMAT_INDEX8; + case 1: + return SNES_PIXELFORMAT_2BPP; + case 2: + return SNES_PIXELFORMAT_4BPP; + case 3: + return SNES_PIXELFORMAT_8BPP; + } + return SDL_PIXELFORMAT_INDEX8; +} +} // namespace + +void Bitmap::SaveSurfaceToFile(std::string_view filename) { + SDL_SaveBMP(surface_.get(), filename.data()); +} + +Bitmap::Bitmap(int width, int height, int depth, int data_size) { + Create(width, height, depth, std::vector(data_size, 0)); +} + +void Bitmap::Create(int width, int height, int depth, + const std::vector &data) { + Create(width, height, depth, kIndexed, data); } void Bitmap::Create(int width, int height, int depth, int format, - const Bytes &data) { + const std::vector &data) { + if (data.empty()) { + SDL_Log("Bitmap data is empty\n"); + active_ = false; + return; + } active_ = true; width_ = width; height_ = height; depth_ = depth; data_ = data; data_size_ = data.size(); + if (data_size_ == 0) { + SDL_Log("Data provided to Bitmap is empty.\n"); + return; + } pixel_data_ = data_.data(); - surface_ = std::unique_ptr( + surface_ = std::shared_ptr{ SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_, GetSnesPixelFormat(format)), - SDL_Surface_Deleter()); + SDL_Surface_Deleter{}}; + if (surface_ == nullptr) { + SDL_Log("SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError()); + active_ = false; + return; + } surface_->pixels = pixel_data_; active_ = true; } @@ -242,6 +270,11 @@ void Bitmap::Reformat(int format) { SDL_Surface_Deleter()); surface_->pixels = pixel_data_; active_ = true; + auto apply_palette = ApplyPalette(palette_); + if (!apply_palette.ok()) { + SDL_Log("Failed to apply palette: %s\n", apply_palette.message().data()); + active_ = false; + } } void Bitmap::CreateTexture(SDL_Renderer *renderer) { @@ -259,6 +292,22 @@ void Bitmap::CreateTexture(SDL_Renderer *renderer) { SDL_Log("SDL_CreateTextureFromSurface failed: %s\n", SDL_GetError()); } + converted_surface_ = std::shared_ptr{ + SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0), + SDL_Surface_Deleter{}}; + if (converted_surface_ == nullptr) { + SDL_Log("SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError()); + return; + } + + SDL_LockTexture(texture_.get(), nullptr, (void **)&texture_pixels, + &converted_surface_->pitch); + memcpy(texture_pixels, converted_surface_->pixels, + converted_surface_->h * converted_surface_->pitch); + SDL_UnlockTexture(texture_.get()); +} + +void Bitmap::UpdateTexture(SDL_Renderer *renderer) { SDL_Surface *converted_surface = SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0); if (converted_surface) { @@ -275,92 +324,32 @@ void Bitmap::CreateTexture(SDL_Renderer *renderer) { SDL_UnlockTexture(texture_.get()); } -void Bitmap::UpdateTexture(SDL_Renderer *renderer, bool use_sdl_update) { - SDL_Surface *converted_surface = - SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0); - if (converted_surface) { - converted_surface_ = std::unique_ptr( - converted_surface, SDL_Surface_Deleter()); - } else { - SDL_Log("SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError()); - } - - SDL_LockTexture(texture_.get(), nullptr, (void **)&texture_pixels, - &converted_surface_->pitch); - if (use_sdl_update) { - SDL_UpdateTexture(texture_.get(), nullptr, converted_surface_->pixels, - converted_surface_->pitch); - } else { - memcpy(texture_pixels, converted_surface_->pixels, - converted_surface_->h * converted_surface_->pitch); - } - SDL_UnlockTexture(texture_.get()); -} - -void Bitmap::CreateTexture(std::shared_ptr renderer) { - texture_ = std::shared_ptr{ - SDL_CreateTextureFromSurface(renderer.get(), surface_.get()), - SDL_Texture_Deleter{}}; -} - -void Bitmap::UpdateTexture(std::shared_ptr renderer) { - texture_ = std::shared_ptr{ - SDL_CreateTextureFromSurface(renderer.get(), surface_.get()), - SDL_Texture_Deleter{}}; -} - -void Bitmap::SaveSurfaceToFile(std::string_view filename) { - SDL_SaveBMP(surface_.get(), filename.data()); -} - -void Bitmap::SetSurface(SDL_Surface *surface) { - surface_ = std::unique_ptr( - surface, SDL_Surface_Deleter()); -} - -std::vector Bitmap::GetPngData() { - ConvertSurfaceToPNG(surface_.get(), png_data_); - return png_data_; -} - -void Bitmap::LoadFromPngData(const std::vector &png_data, int width, - int height) { - width_ = width; - height_ = height; - SDL_Surface *surface = surface_.get(); - ConvertPngToSurface(png_data, &surface); - surface_.reset(surface); -} - -// Convert SNESPalette to SDL_Palette for surface. absl::Status Bitmap::ApplyPalette(const SnesPalette &palette) { if (surface_ == nullptr) { - return absl::FailedPreconditionError("Surface is null"); + return absl::FailedPreconditionError( + "Surface is null. Palette not applied"); } - if (surface_->format == nullptr || surface_->format->palette == nullptr) { - return absl::FailedPreconditionError("Surface format or palette is null"); + return absl::FailedPreconditionError( + "Surface format or palette is null. Palette not applied."); } - palette_ = palette; - SDL_Palette *sdlPalette = surface_->format->palette; - if (sdlPalette == nullptr) { + SDL_Palette *sdl_palette = surface_->format->palette; + if (sdl_palette == nullptr) { return absl::InternalError("Failed to get SDL palette"); } SDL_UnlockSurface(surface_.get()); - - for (int i = 0; i < palette.size(); ++i) { + for (size_t i = 0; i < palette.size(); ++i) { ASSIGN_OR_RETURN(gfx::SnesColor pal_color, palette.GetColor(i)); - sdlPalette->colors[i].r = pal_color.rgb().x; - sdlPalette->colors[i].g = pal_color.rgb().y; - sdlPalette->colors[i].b = pal_color.rgb().z; - sdlPalette->colors[i].a = pal_color.rgb().w; + sdl_palette->colors[i].r = pal_color.rgb().x; + sdl_palette->colors[i].g = pal_color.rgb().y; + sdl_palette->colors[i].b = pal_color.rgb().z; + sdl_palette->colors[i].a = pal_color.rgb().w; } - SDL_LockSurface(surface_.get()); - + // SDL_RETURN_IF_ERROR() return absl::OkStatus(); } @@ -369,7 +358,7 @@ absl::Status Bitmap::ApplyPaletteFromPaletteGroup(const SnesPalette &palette, auto start_index = palette_id * 8; palette_ = palette.sub_palette(start_index, start_index + 8); SDL_UnlockSurface(surface_.get()); - for (int i = 0; i < palette_.size(); ++i) { + for (size_t i = 0; i < palette_.size(); ++i) { ASSIGN_OR_RETURN(auto pal_color, palette_.GetColor(i)); if (pal_color.is_transparent()) { surface_->format->palette->colors[i].r = 0; @@ -384,11 +373,29 @@ absl::Status Bitmap::ApplyPaletteFromPaletteGroup(const SnesPalette &palette, } } SDL_LockSurface(surface_.get()); + // SDL_RETURN_IF_ERROR() return absl::OkStatus(); } absl::Status Bitmap::ApplyPaletteWithTransparent(const SnesPalette &palette, - int index, int length) { + size_t index, int length) { + if (index < 0 || index >= palette.size()) { + return absl::InvalidArgumentError("Invalid palette index"); + } + + if (length < 0 || length > palette.size()) { + return absl::InvalidArgumentError("Invalid palette length"); + } + + if (index + length > palette.size()) { + return absl::InvalidArgumentError("Palette index + length exceeds size"); + } + + if (surface_ == nullptr) { + return absl::FailedPreconditionError( + "Surface is null. Palette not applied"); + } + auto start_index = index * 7; palette_ = palette.sub_palette(start_index, start_index + 7); std::vector colors; @@ -408,12 +415,13 @@ absl::Status Bitmap::ApplyPaletteWithTransparent(const SnesPalette &palette, i++; } SDL_LockSurface(surface_.get()); + // SDL_RETURN_IF_ERROR() return absl::OkStatus(); } void Bitmap::ApplyPalette(const std::vector &palette) { SDL_UnlockSurface(surface_.get()); - for (int i = 0; i < palette.size(); ++i) { + for (size_t i = 0; i < palette.size(); ++i) { surface_->format->palette->colors[i].r = palette[i].r; surface_->format->palette->colors[i].g = palette[i].g; surface_->format->palette->colors[i].b = palette[i].b; @@ -422,6 +430,57 @@ void Bitmap::ApplyPalette(const std::vector &palette) { SDL_LockSurface(surface_.get()); } +void Bitmap::Get8x8Tile(int tile_index, int x, int y, + std::vector &tile_data, + int &tile_data_offset) { + int tile_offset = tile_index * (width_ * height_); + int tile_x = (x * 8) % width_; + int tile_y = (y * 8) % height_; + for (int i = 0; i < 8; i++) { + int row_offset = tile_offset + ((tile_y + i) * width_); + for (int j = 0; j < 8; j++) { + int pixel_offset = row_offset + (tile_x + j); + int pixel_value = data_[pixel_offset]; + tile_data[tile_data_offset] = pixel_value; + tile_data_offset++; + } + } +} + +void Bitmap::Get16x16Tile(int tile_x, int tile_y, + std::vector &tile_data, + int &tile_data_offset) { + for (int ty = 0; ty < 16; ty++) { + for (int tx = 0; tx < 16; tx++) { + // Calculate the pixel position in the bitmap + int pixel_x = tile_x + tx; + int pixel_y = tile_y + ty; + int pixel_offset = (pixel_y * width_) + pixel_x; + int pixel_value = data_[pixel_offset]; + + // Store the pixel value in the tile data + tile_data[tile_data_offset++] = pixel_value; + } + } +} + +void Bitmap::WriteColor(int position, const ImVec4 &color) { + // Convert ImVec4 (RGBA) to SDL_Color (RGBA) + SDL_Color sdl_color; + sdl_color.r = static_cast(color.x * 255); + sdl_color.g = static_cast(color.y * 255); + sdl_color.b = static_cast(color.z * 255); + sdl_color.a = static_cast(color.w * 255); + + // Map SDL_Color to the nearest color index in the surface's palette + Uint8 index = + SDL_MapRGB(surface_->format, sdl_color.r, sdl_color.g, sdl_color.b); + + // Write the color index to the pixel data + pixel_data_[position] = index; + modified_ = true; +} + } // namespace gfx } // namespace app } // namespace yaze diff --git a/src/app/gfx/bitmap.h b/src/app/gfx/bitmap.h index fa8577d7..48a97312 100644 --- a/src/app/gfx/bitmap.h +++ b/src/app/gfx/bitmap.h @@ -6,11 +6,9 @@ #include #include -#include "absl/container/flat_hash_map.h" #include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" #include "app/core/constants.h" +#include "app/core/utils/sdl_deleter.h" #include "app/gfx/snes_palette.h" namespace yaze { @@ -22,6 +20,10 @@ namespace app { */ namespace gfx { +// Same as SDL_PIXELFORMAT_INDEX8 for reference +constexpr Uint32 SNES_PIXELFORMAT_INDEXED = + SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX8, 0, 0, 8, 1); + constexpr Uint32 SNES_PIXELFORMAT_2BPP = SDL_DEFINE_PIXELFORMAT( /*type=*/SDL_PIXELTYPE_INDEX8, /*order=*/0, /*layouts=*/0, /*bits=*/2, /*bytes=*/1); @@ -34,13 +36,14 @@ constexpr Uint32 SNES_PIXELFORMAT_8BPP = SDL_DEFINE_PIXELFORMAT( /*type=*/SDL_PIXELTYPE_INDEX8, /*order=*/0, /*layouts=*/0, /*bits=*/8, /*bytes=*/1); -// SDL_PIXELFORMAT_INDEX8 = -// SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_INDEX8, 0, 0, 8, 1), - -constexpr int kFormat2bppIndexed = 1; -constexpr int kFormat4bppIndexed = 2; -constexpr int kFormat8bppIndexed = 3; +enum BitmapFormat { + kIndexed = 0, + k2bpp = 1, + k4bpp = 2, + k8bpp = 3, +}; +#if YAZE_LIB_PNG == 1 /** * @brief Convert SDL_Surface to PNG image data. */ @@ -51,6 +54,7 @@ bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector &buffer); */ void ConvertPngToSurface(const std::vector &png_data, SDL_Surface **outSurface); +#endif /** * @brief Represents a bitmap image. @@ -65,11 +69,11 @@ class Bitmap { Bitmap() = default; Bitmap(int width, int height, int depth, int data_size); - Bitmap(int width, int height, int depth, const Bytes &data) + Bitmap(int width, int height, int depth, const std::vector &data) : width_(width), height_(height), depth_(depth), data_(data) { Create(width, height, depth, data); } - Bitmap(int width, int height, int depth, const Bytes &data, + Bitmap(int width, int height, int depth, const std::vector &data, const SnesPalette &palette) : width_(width), height_(height), @@ -82,11 +86,19 @@ class Bitmap { } } +#if YAZE_LIB_PNG == 1 + std::vector GetPngData(); +#endif + + void SaveSurfaceToFile(std::string_view filename); + /** * @brief Creates a bitmap object with the provided graphical data. */ - void Create(int width, int height, int depth, const Bytes &data); - void Create(int width, int height, int depth, int format, const Bytes &data); + void Create(int width, int height, int depth, + const std::vector &data); + void Create(int width, int height, int depth, int format, + const std::vector &data); void Reformat(int format); @@ -96,31 +108,29 @@ class Bitmap { * Converts the surface from a RGB to ARGB format. * Uses SDL_TEXTUREACCESS_STREAMING to allow for live updates. */ - void CreateTexture(std::shared_ptr renderer); + void CreateTexture(SDL_Renderer *renderer); /** * @brief Updates the underlying SDL_Texture when it already exists. */ - void UpdateTexture(std::shared_ptr renderer); - void CreateTexture(SDL_Renderer *renderer); - void UpdateTexture(SDL_Renderer *renderer, bool use_sdl_update = false); - - void SaveSurfaceToFile(std::string_view filename); - void SetSurface(SDL_Surface *surface); - std::vector GetPngData(); - void LoadFromPngData(const std::vector &png_data, int width, - int height); + void UpdateTexture(SDL_Renderer *renderer); /** * @brief Copy color data from the SnesPalette into the SDL_Palette */ absl::Status ApplyPalette(const SnesPalette &palette); absl::Status ApplyPaletteWithTransparent(const SnesPalette &palette, - int index, int length = 7); + size_t index, int length = 7); void ApplyPalette(const std::vector &palette); absl::Status ApplyPaletteFromPaletteGroup(const SnesPalette &palette, int palette_id); + void Get8x8Tile(int tile_index, int x, int y, std::vector &tile_data, + int &tile_data_offset); + + void Get16x16Tile(int tile_x, int tile_y, std::vector &tile_data, + int &tile_data_offset); + void WriteToPixel(int position, uchar value) { if (pixel_data_ == nullptr) { pixel_data_ = data_.data(); @@ -138,73 +148,7 @@ class Bitmap { modified_ = true; } - void Get8x8Tile(int tile_index, int x, int y, std::vector &tile_data, - int &tile_data_offset) { - int tile_offset = tile_index * (width_ * height_); - int tile_x = (x * 8) % width_; - int tile_y = (y * 8) % height_; - for (int i = 0; i < 8; i++) { - int row_offset = tile_offset + ((tile_y + i) * width_); - for (int j = 0; j < 8; j++) { - int pixel_offset = row_offset + (tile_x + j); - int pixel_value = data_[pixel_offset]; - tile_data[tile_data_offset] = pixel_value; - tile_data_offset++; - } - } - } - - void Get16x16Tile(int tile_index, int x, int y, - std::vector &tile_data, int &tile_data_offset) { - int tile_offset = tile_index * (width_ * height_); - int tile_x = x * 16; - int tile_y = y * 16; - for (int i = 0; i < 16; i++) { - int row_offset = tile_offset + ((i / 8) * (width_ * 8)); - for (int j = 0; j < 16; j++) { - int pixel_offset = - row_offset + ((j / 8) * 8) + ((i % 8) * width_) + (j % 8); - int pixel_value = data_[pixel_offset]; - tile_data[tile_data_offset] = pixel_value; - tile_data_offset++; - } - } - } - - void Get16x16Tile(int tile_x, int tile_y, std::vector &tile_data, - int &tile_data_offset) { - // Assuming 'width_' and 'height_' are the dimensions of the bitmap - // and 'data_' is the bitmap data. - for (int ty = 0; ty < 16; ty++) { - for (int tx = 0; tx < 16; tx++) { - // Calculate the pixel position in the bitmap - int pixel_x = tile_x + tx; - int pixel_y = tile_y + ty; - int pixel_offset = pixel_y * width_ + pixel_x; - int pixel_value = data_[pixel_offset]; - - // Store the pixel value in the tile data - tile_data[tile_data_offset++] = pixel_value; - } - } - } - - void WriteColor(int position, const ImVec4 &color) { - // Convert ImVec4 (RGBA) to SDL_Color (RGBA) - SDL_Color sdl_color; - sdl_color.r = static_cast(color.x * 255); - sdl_color.g = static_cast(color.y * 255); - sdl_color.b = static_cast(color.z * 255); - sdl_color.a = static_cast(color.w * 255); - - // Map SDL_Color to the nearest color index in the surface's palette - Uint8 index = - SDL_MapRGB(surface_->format, sdl_color.r, sdl_color.g, sdl_color.b); - - // Write the color index to the pixel data - pixel_data_[position] = index; - modified_ = true; - } + void WriteColor(int position, const ImVec4 &color); void Cleanup() { active_ = false; @@ -212,7 +156,7 @@ class Bitmap { height_ = 0; depth_ = 0; data_size_ = 0; - palette_.Clear(); + palette_.clear(); } auto sdl_palette() { @@ -236,45 +180,28 @@ class Bitmap { auto mutable_surface() { return surface_.get(); } auto converted_surface() const { return converted_surface_.get(); } auto mutable_converted_surface() { return converted_surface_.get(); } - void set_data(const Bytes &data) { data_ = data; } auto vector() const { return data_; } auto at(int i) const { return data_[i]; } auto texture() const { return texture_.get(); } auto modified() const { return modified_; } - void set_modified(bool modified) { modified_ = modified; } auto is_active() const { return active_; } - auto set_active(bool active) { active_ = active; } + void set_active(bool active) { active_ = active; } + void set_data(const std::vector &data) { data_ = data; } + void set_modified(bool modified) { modified_ = modified; } private: - struct SDL_Texture_Deleter { - void operator()(SDL_Texture *p) const { - if (p != nullptr) { - SDL_DestroyTexture(p); - } - } - }; - - struct SDL_Surface_Deleter { - void operator()(SDL_Surface *p) const { - if (p != nullptr) { - SDL_FreeSurface(p); - } - } - }; - int width_ = 0; int height_ = 0; int depth_ = 0; int data_size_ = 0; - bool freed_ = false; bool active_ = false; bool modified_ = false; void *texture_pixels = nullptr; - uchar *pixel_data_; - Bytes data_; + uint8_t *pixel_data_ = nullptr; + std::vector data_; std::vector png_data_; @@ -286,52 +213,8 @@ class Bitmap { using BitmapTable = std::unordered_map; -/** - * @brief Hash map container of shared pointers to Bitmaps. - */ -class BitmapManager { - private: - std::unordered_map bitmap_cache_; - - public: - void LoadBitmap(int id, const Bytes &data, int width, int height, int depth) { - bitmap_cache_[id].Create(width, height, depth, data); - } - - gfx::Bitmap &operator[](int id) { - auto it = bitmap_cache_.find(id); - if (it != bitmap_cache_.end()) { - return it->second; - } - return bitmap_cache_.begin()->second; - } - gfx::Bitmap &shared_bitmap(int id) { - auto it = bitmap_cache_.find(id); - if (it != bitmap_cache_.end()) { - return it->second; - } - throw std::runtime_error( - absl::StrCat("Bitmap with id ", id, " not found.")); - } - auto mutable_bitmap(int id) { return &bitmap_cache_[id]; } - void clear_cache() { bitmap_cache_.clear(); } - auto size() const { return bitmap_cache_.size(); } - auto at(int id) const { return bitmap_cache_.at(id); } - - using value_type = std::pair; - using iterator = std::unordered_map::iterator; - using const_iterator = std::unordered_map::const_iterator; - - iterator begin() noexcept { return bitmap_cache_.begin(); } - iterator end() noexcept { return bitmap_cache_.end(); } - const_iterator begin() const noexcept { return bitmap_cache_.begin(); } - const_iterator end() const noexcept { return bitmap_cache_.end(); } - const_iterator cbegin() const noexcept { return bitmap_cache_.cbegin(); } - const_iterator cend() const noexcept { return bitmap_cache_.cend(); } -}; - } // namespace gfx } // namespace app } // namespace yaze -#endif // YAZE_APP_GFX_BITMAP_H \ No newline at end of file +#endif // YAZE_APP_GFX_BITMAP_H diff --git a/src/app/gfx/compression.cc b/src/app/gfx/compression.cc index aaeab86e..fcb5cfab 100644 --- a/src/app/gfx/compression.cc +++ b/src/app/gfx/compression.cc @@ -413,10 +413,11 @@ absl::StatusOr SplitCompressionPiece( return new_piece; } -Bytes CreateCompressionString(CompressionPiecePointer& start, int mode) { +std::vector CreateCompressionString(CompressionPiecePointer& start, + int mode) { uint pos = 0; auto piece = start; - Bytes output; + std::vector output; while (piece != nullptr) { if (piece->length <= kMaxLengthNormalHeader) { // Normal header @@ -515,12 +516,13 @@ CompressionPiecePointer MergeCopy(CompressionPiecePointer& start) { return start; } -// TODO TEST compressed data border for each cmd -absl::StatusOr CompressV2(const uchar* data, const int start, - const int length, int mode, bool check) { +absl::StatusOr> CompressV2(const uchar* data, + const int start, + const int length, int mode, + bool check) { // Surely there's no need to compress zero... if (length == 0) { - return Bytes(); + return std::vector(); } // Worst case should be a copy of the string with extended header @@ -868,18 +870,20 @@ uint8_t* Uncompress(uint8_t const* src, int* const size, return b2; } -absl::StatusOr CompressGraphics(const uchar* data, const int pos, - const int length) { +absl::StatusOr> CompressGraphics(const uchar* data, + const int pos, + const int length) { return CompressV2(data, pos, length, kNintendoMode2); } -absl::StatusOr CompressOverworld(const uchar* data, const int pos, - const int length) { +absl::StatusOr> CompressOverworld(const uchar* data, + const int pos, + const int length) { return CompressV2(data, pos, length, kNintendoMode1); } -absl::StatusOr CompressOverworld(const std::vector data, - const int pos, const int length) { +absl::StatusOr> CompressOverworld( + const std::vector data, const int pos, const int length) { return CompressV3(data, pos, length, kNintendoMode1); } @@ -1304,11 +1308,11 @@ void FinalizeCompression(CompressionContext& context) { << context.compressed_data.size()); } -absl::StatusOr CompressV3(const std::vector& data, - const int start, const int length, int mode, - bool check) { +absl::StatusOr> CompressV3( + const std::vector& data, const int start, const int length, + int mode, bool check) { if (length == 0) { - return Bytes(); + return std::vector(); } CompressionContext context(data, start, length, mode); @@ -1332,7 +1336,8 @@ absl::StatusOr CompressV3(const std::vector& data, } FinalizeCompression(context); - return Bytes(context.compressed_data.begin(), context.compressed_data.end()); + return std::vector(context.compressed_data.begin(), + context.compressed_data.end()); } // Decompression @@ -1354,8 +1359,8 @@ std::string SetBuffer(const std::vector& data, int src_pos, return buffer; } -void memfill(const uchar* data, Bytes& buffer, int buffer_pos, int offset, - int length) { +void memfill(const uchar* data, std::vector& buffer, int buffer_pos, + int offset, int length) { auto a = data[offset]; auto b = data[offset + 1]; for (int i = 0; i < length; i = i + 2) { @@ -1364,13 +1369,13 @@ void memfill(const uchar* data, Bytes& buffer, int buffer_pos, int offset, } } -absl::StatusOr DecompressV2(const uchar* data, int offset, int size, - int mode) { +absl::StatusOr> DecompressV2(const uchar* data, int offset, + int size, int mode) { if (size == 0) { - return Bytes(); + return std::vector(); } - Bytes buffer(size, 0); + std::vector buffer(size, 0); uint length = 0; uint buffer_pos = 0; uchar command = 0; @@ -1451,17 +1456,18 @@ absl::StatusOr DecompressV2(const uchar* data, int offset, int size, return buffer; } -absl::StatusOr DecompressGraphics(const uchar* data, int pos, int size) { +absl::StatusOr> DecompressGraphics(const uchar* data, + int pos, int size) { return DecompressV2(data, pos, size, kNintendoMode2); } -absl::StatusOr DecompressOverworld(const uchar* data, int pos, - int size) { +absl::StatusOr> DecompressOverworld(const uchar* data, + int pos, int size) { return DecompressV2(data, pos, size, kNintendoMode1); } -absl::StatusOr DecompressOverworld(const std::vector data, - int pos, int size) { +absl::StatusOr> DecompressOverworld( + const std::vector data, int pos, int size) { return DecompressV2(data.data(), pos, size, kNintendoMode1); } diff --git a/src/app/gfx/compression.h b/src/app/gfx/compression.h index acca1572..d2a0aa92 100644 --- a/src/app/gfx/compression.h +++ b/src/app/gfx/compression.h @@ -1,7 +1,6 @@ #ifndef YAZE_APP_GFX_COMPRESSION_H #define YAZE_APP_GFX_COMPRESSION_H -#include #include #include @@ -142,21 +141,21 @@ void CompressionCommandAlternativeV2(const uchar* data, * @brief Compresses a buffer of data using the LC_LZ2 algorithm. * \deprecated Use Compress and Uncompress instead. */ -absl::StatusOr CompressV2(const uchar* data, const int start, +absl::StatusOr> CompressV2(const uchar* data, const int start, const int length, int mode = 1, bool check = false); -absl::StatusOr CompressGraphics(const uchar* data, const int pos, +absl::StatusOr> CompressGraphics(const uchar* data, const int pos, const int length); -absl::StatusOr CompressOverworld(const uchar* data, const int pos, +absl::StatusOr> CompressOverworld(const uchar* data, const int pos, const int length); -absl::StatusOr CompressOverworld(const std::vector data, +absl::StatusOr> CompressOverworld(const std::vector data, const int pos, const int length); absl::StatusOr SplitCompressionPiece( CompressionPiecePointer& piece, int mode); -Bytes CreateCompressionString(CompressionPiecePointer& start, int mode); +std::vector CreateCompressionString(CompressionPiecePointer& start, int mode); absl::Status ValidateCompressionResult(CompressionPiecePointer& chain_head, int mode, int start, int src_data_pos); @@ -213,7 +212,7 @@ void FinalizeCompression(CompressionContext& context); * @brief Compresses a buffer of data using the LC_LZ2 algorithm. * \deprecated Use Compress and Uncompress instead. */ -absl::StatusOr CompressV3(const std::vector& data, +absl::StatusOr> CompressV3(const std::vector& data, const int start, const int length, int mode = 1, bool check = false); @@ -229,18 +228,18 @@ uint8_t* Uncompress(uint8_t const* src, int* const size, std::string SetBuffer(const std::vector& data, int src_pos, int comp_accumulator); std::string SetBuffer(const uchar* data, int src_pos, int comp_accumulator); -void memfill(const uchar* data, Bytes& buffer, int buffer_pos, int offset, +void memfill(const uchar* data, std::vector& buffer, int buffer_pos, int offset, int length); /** * @brief Decompresses a buffer of data using the LC_LZ2 algorithm. * \deprecated Use Compress and Uncompress instead. */ -absl::StatusOr DecompressV2(const uchar* data, int offset, +absl::StatusOr> DecompressV2(const uchar* data, int offset, int size = 0x800, int mode = 1); -absl::StatusOr DecompressGraphics(const uchar* data, int pos, int size); -absl::StatusOr DecompressOverworld(const uchar* data, int pos, int size); -absl::StatusOr DecompressOverworld(const std::vector data, +absl::StatusOr> DecompressGraphics(const uchar* data, int pos, int size); +absl::StatusOr> DecompressOverworld(const uchar* data, int pos, int size); +absl::StatusOr> DecompressOverworld(const std::vector data, int pos, int size); } // namespace lc_lz2 @@ -249,4 +248,4 @@ absl::StatusOr DecompressOverworld(const std::vector data, } // namespace app } // namespace yaze -#endif // YAZE_APP_GFX_COMPRESSION_H \ No newline at end of file +#endif // YAZE_APP_GFX_COMPRESSION_H diff --git a/src/app/gfx/gfx.cmake b/src/app/gfx/gfx.cmake new file mode 100644 index 00000000..5ebabdf0 --- /dev/null +++ b/src/app/gfx/gfx.cmake @@ -0,0 +1,10 @@ +set( + YAZE_APP_GFX_SRC + app/gfx/bitmap.cc + app/gfx/compression.cc + app/gfx/scad_format.cc + app/gfx/snes_palette.cc + app/gfx/snes_tile.cc + app/gfx/snes_color.cc + app/gfx/tilesheet.cc +) \ No newline at end of file diff --git a/src/app/gfx/scad_format.cc b/src/app/gfx/scad_format.cc index d16857ba..591c5663 100644 --- a/src/app/gfx/scad_format.cc +++ b/src/app/gfx/scad_format.cc @@ -20,8 +20,8 @@ namespace scad_format { void FindMetastamp() { int matching_position = -1; bool matched = false; - Bytes cgx_rom; - Bytes raw_data_; + std::vector cgx_rom; + std::vector raw_data_; for (int i = 0; i < cgx_rom.size() - sizeof(kMatchedBytes) - kOffsetFromMatchedBytesEnd; i++) { @@ -128,7 +128,7 @@ absl::Status DrawScrWithCgx(uint8_t bpp, std::vector& map_data, p = each_dimension; // for each tile on the tile buffer for (int i = 0; i < 0x400; i++) { - if (map_data[i + p] != 0xFFFF) { + if (map_data[i + p] != 0xFF) { auto t = gfx::GetTilesInfo(map_data[i + p]); for (auto yl = 0; yl < 8; yl++) { diff --git a/src/app/gfx/snes_color.cc b/src/app/gfx/snes_color.cc index f2dfb239..1c74d444 100644 --- a/src/app/gfx/snes_color.cc +++ b/src/app/gfx/snes_color.cc @@ -1,11 +1,11 @@ #include "app/gfx/snes_color.h" -#include "imgui/imgui.h" - #include #include +#include "imgui/imgui.h" + namespace yaze { namespace app { namespace gfx { @@ -17,7 +17,7 @@ constexpr uint16_t SNES_BLUE_MASK = 32; constexpr uint16_t SNES_GREEN_SHIFT = 32; constexpr uint16_t SNES_BLUE_SHIFT = 1024; -snes_color ConvertSNEStoRGB(uint16_t color_snes) { +snes_color ConvertSnesToRgb(uint16_t color_snes) { snes_color result; result.red = (color_snes % SNES_RED_MASK) * 8; @@ -31,19 +31,19 @@ snes_color ConvertSNEStoRGB(uint16_t color_snes) { return result; } -uint16_t ConvertRGBtoSNES(const snes_color& color) { +uint16_t ConvertRgbToSnes(const snes_color& color) { uint16_t red = color.red / 8; uint16_t green = color.green / 8; uint16_t blue = color.blue / 8; return (blue * SNES_BLUE_SHIFT) + (green * SNES_GREEN_SHIFT) + red; } -uint16_t ConvertRGBtoSNES(const ImVec4& color) { +uint16_t ConvertRgbToSnes(const ImVec4& color) { snes_color new_color; - new_color.red = color.x * 255; - new_color.green = color.y * 255; - new_color.blue = color.z * 255; - return ConvertRGBtoSNES(new_color); + new_color.red = color.x * kColorByteMax; + new_color.green = color.y * kColorByteMax; + new_color.blue = color.z * kColorByteMax; + return ConvertRgbToSnes(new_color); } SnesColor ReadColorFromRom(int offset, const uint8_t* rom) { @@ -62,7 +62,7 @@ std::vector Extract(const char* data, unsigned int offset, for (unsigned int i = 0; i < palette_size * 2; i += 2) { uint16_t snes_color = (static_cast(data[offset + i + 1]) << 8) | static_cast(data[offset + i]); - palette[i / 2] = ConvertSNEStoRGB(snes_color); + palette[i / 2] = ConvertSnesToRgb(snes_color); } return palette; } @@ -70,7 +70,7 @@ std::vector Extract(const char* data, unsigned int offset, std::vector Convert(const std::vector& palette) { std::vector data(palette.size() * 2); for (unsigned int i = 0; i < palette.size(); i++) { - uint16_t snes_data = ConvertRGBtoSNES(palette[i]); + uint16_t snes_data = ConvertRgbToSnes(palette[i]); data[i * 2] = snes_data & 0xFF; data[i * 2 + 1] = snes_data >> 8; } diff --git a/src/app/gfx/snes_color.h b/src/app/gfx/snes_color.h index dcaea639..8045c1e8 100644 --- a/src/app/gfx/snes_color.h +++ b/src/app/gfx/snes_color.h @@ -1,34 +1,31 @@ #ifndef YAZE_APP_GFX_SNES_COLOR_H_ #define YAZE_APP_GFX_SNES_COLOR_H_ -#include "imgui/imgui.h" +#include #include #include +#include "imgui/imgui.h" + namespace yaze { namespace app { namespace gfx { -/** - * @brief Primitive of 16-bit RGB SNES color. - */ -struct snes_color { - uint16_t red; /**< Red component of the color. */ - uint16_t blue; /**< Blue component of the color. */ - uint16_t green; /**< Green component of the color. */ -}; -typedef struct snes_color snes_color; +constexpr int NumberOfColors = 3143; -snes_color ConvertSNEStoRGB(uint16_t snes_color); -uint16_t ConvertRGBtoSNES(const snes_color& color); -uint16_t ConvertRGBtoSNES(const ImVec4& color); +snes_color ConvertSnesToRgb(uint16_t snes_color); +uint16_t ConvertRgbToSnes(const snes_color& color); +uint16_t ConvertRgbToSnes(const ImVec4& color); std::vector Extract(const char* data, unsigned int offset, unsigned int palette_size); std::vector Convert(const std::vector& palette); +constexpr uint8_t kColorByteMax = 255; +constexpr float kColorByteMaxF = 255.f; + /** * @brief SNES Color container * @@ -41,51 +38,51 @@ std::vector Convert(const std::vector& palette); */ class SnesColor { public: - SnesColor() : rgb_(0.f, 0.f, 0.f, 0.f), snes_(0) {} + SnesColor() : rgb_(0.f, 0.f, 0.f, 0.f), snes_(0), rom_color_({0, 0, 0}) {} explicit SnesColor(const ImVec4 val) : rgb_(val) { snes_color color; - color.red = val.x / 255; - color.green = val.y / 255; - color.blue = val.z / 255; - snes_ = ConvertRGBtoSNES(color); + color.red = val.x / kColorByteMax; + color.green = val.y / kColorByteMax; + color.blue = val.z / kColorByteMax; + snes_ = ConvertRgbToSnes(color); } explicit SnesColor(const uint16_t val) : snes_(val) { - snes_color color = ConvertSNEStoRGB(val); + snes_color color = ConvertSnesToRgb(val); rgb_ = ImVec4(color.red, color.green, color.blue, 0.f); } explicit SnesColor(const snes_color val) - : rgb_(val.red, val.green, val.blue, 255.f), - snes_(ConvertRGBtoSNES(val)), + : rgb_(val.red, val.green, val.blue, kColorByteMaxF), + snes_(ConvertRgbToSnes(val)), rom_color_(val) {} SnesColor(uint8_t r, uint8_t g, uint8_t b) { - rgb_ = ImVec4(r, g, b, 255.f); + rgb_ = ImVec4(r, g, b, kColorByteMaxF); snes_color color; color.red = r; color.green = g; color.blue = b; - snes_ = ConvertRGBtoSNES(color); + snes_ = ConvertRgbToSnes(color); rom_color_ = color; } ImVec4 rgb() const { return rgb_; } void set_rgb(const ImVec4 val) { - rgb_.x = val.x / 255; - rgb_.y = val.y / 255; - rgb_.z = val.z / 255; + rgb_.x = val.x / kColorByteMax; + rgb_.y = val.y / kColorByteMax; + rgb_.z = val.z / kColorByteMax; snes_color color; color.red = val.x; color.green = val.y; color.blue = val.z; rom_color_ = color; - snes_ = ConvertRGBtoSNES(color); + snes_ = ConvertRgbToSnes(color); modified = true; } void set_snes(uint16_t val) { snes_ = val; - snes_color col = ConvertSNEStoRGB(val); + snes_color col = ConvertSnesToRgb(val); rgb_ = ImVec4(col.red, col.green, col.blue, 0.f); modified = true; } diff --git a/src/app/gfx/snes_palette.cc b/src/app/gfx/snes_palette.cc index b5388c3d..a8005ae7 100644 --- a/src/app/gfx/snes_palette.cc +++ b/src/app/gfx/snes_palette.cc @@ -1,7 +1,6 @@ #include "snes_palette.h" #include -#include "imgui/imgui.h" #include #include @@ -15,6 +14,7 @@ #include "absl/status/statusor.h" #include "app/core/constants.h" #include "app/gfx/snes_color.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -25,157 +25,158 @@ namespace gfx { * @brief Internal functions for loading palettes by group. */ namespace palette_group_internal { -absl::Status LoadOverworldMainPalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadOverworldMainPalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 6; i++) { - RETURN_IF_ERROR(palette_groups.overworld_main.AddPalette( + palette_groups.overworld_main.AddPalette( gfx::ReadPaletteFromRom(kOverworldPaletteMain + (i * (35 * 2)), - /*num_colors*/ 35, data))) + /*num_colors=*/35, data)); } return absl::OkStatus(); } absl::Status LoadOverworldAuxiliaryPalettes( - const Bytes& rom_data, gfx::PaletteGroupMap& palette_groups) { + const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 20; i++) { - RETURN_IF_ERROR(palette_groups.overworld_aux.AddPalette( + palette_groups.overworld_aux.AddPalette( gfx::ReadPaletteFromRom(kOverworldPaletteAux + (i * (21 * 2)), - /*num_colors*/ 21, data))) + /*num_colors=*/21, data)); } return absl::OkStatus(); } absl::Status LoadOverworldAnimatedPalettes( - const Bytes& rom_data, gfx::PaletteGroupMap& palette_groups) { + const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 14; i++) { - RETURN_IF_ERROR( - palette_groups.overworld_animated.AddPalette(gfx::ReadPaletteFromRom( - kOverworldPaletteAnimated + (i * (7 * 2)), 7, data))) + palette_groups.overworld_animated.AddPalette(gfx::ReadPaletteFromRom( + kOverworldPaletteAnimated + (i * (7 * 2)), /*num_colors=*/7, data)); } return absl::OkStatus(); } -absl::Status LoadHUDPalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadHUDPalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 2; i++) { - RETURN_IF_ERROR(palette_groups.hud.AddPalette( - gfx::ReadPaletteFromRom(kHudPalettes + (i * 64), 32, data))) + palette_groups.hud.AddPalette(gfx::ReadPaletteFromRom( + kHudPalettes + (i * 64), /*num_colors=*/32, data)); } return absl::OkStatus(); } -absl::Status LoadGlobalSpritePalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadGlobalSpritePalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); - RETURN_IF_ERROR(palette_groups.global_sprites.AddPalette( - gfx::ReadPaletteFromRom(kGlobalSpritesLW, 60, data))) - RETURN_IF_ERROR(palette_groups.global_sprites.AddPalette( - gfx::ReadPaletteFromRom(globalSpritePalettesDW, 60, data))) + palette_groups.global_sprites.AddPalette( + gfx::ReadPaletteFromRom(kGlobalSpritesLW, /*num_colors=*/60, data)); + palette_groups.global_sprites.AddPalette(gfx::ReadPaletteFromRom( + kGlobalSpritePalettesDW, /*num_colors=*/60, data)); return absl::OkStatus(); } -absl::Status LoadArmorPalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadArmorPalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 5; i++) { - RETURN_IF_ERROR(palette_groups.armors.AddPalette( - gfx::ReadPaletteFromRom(kArmorPalettes + (i * 30), 15, data))) + palette_groups.armors.AddPalette(gfx::ReadPaletteFromRom( + kArmorPalettes + (i * 30), /*num_colors=*/15, data)); } return absl::OkStatus(); } -absl::Status LoadSwordPalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadSwordPalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 4; i++) { - RETURN_IF_ERROR(palette_groups.swords.AddPalette( - gfx::ReadPaletteFromRom(kSwordPalettes + (i * 6), 3, data))) + palette_groups.swords.AddPalette(gfx::ReadPaletteFromRom( + kSwordPalettes + (i * 6), /*num_colors=*/3, data)); } return absl::OkStatus(); } -absl::Status LoadShieldPalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadShieldPalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 3; i++) { - RETURN_IF_ERROR(palette_groups.shields.AddPalette( - gfx::ReadPaletteFromRom(kShieldPalettes + (i * 8), 4, data))) + palette_groups.shields.AddPalette(gfx::ReadPaletteFromRom( + kShieldPalettes + (i * 8), /*num_colors=*/4, data)); } return absl::OkStatus(); } -absl::Status LoadSpriteAux1Palettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadSpriteAux1Palettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 12; i++) { - RETURN_IF_ERROR(palette_groups.sprites_aux1.AddPalette( - gfx::ReadPaletteFromRom(kSpritesPalettesAux1 + (i * 14), 7, data))) + palette_groups.sprites_aux1.AddPalette(gfx::ReadPaletteFromRom( + kSpritesPalettesAux1 + (i * 14), /*num_colors=*/7, data)); } return absl::OkStatus(); } -absl::Status LoadSpriteAux2Palettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadSpriteAux2Palettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 11; i++) { - RETURN_IF_ERROR(palette_groups.sprites_aux2.AddPalette( - gfx::ReadPaletteFromRom(kSpritesPalettesAux2 + (i * 14), 7, data))) + palette_groups.sprites_aux2.AddPalette(gfx::ReadPaletteFromRom( + kSpritesPalettesAux2 + (i * 14), /*num_colors=*/7, data)); } return absl::OkStatus(); } -absl::Status LoadSpriteAux3Palettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadSpriteAux3Palettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 24; i++) { - RETURN_IF_ERROR(palette_groups.sprites_aux3.AddPalette( - gfx::ReadPaletteFromRom(kSpritesPalettesAux3 + (i * 14), 7, data))) + palette_groups.sprites_aux3.AddPalette(gfx::ReadPaletteFromRom( + kSpritesPalettesAux3 + (i * 14), /*num_colors=*/7, data)); } return absl::OkStatus(); } -absl::Status LoadDungeonMainPalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status LoadDungeonMainPalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 20; i++) { - RETURN_IF_ERROR(palette_groups.dungeon_main.AddPalette( - gfx::ReadPaletteFromRom(kDungeonMainPalettes + (i * 180), 90, data))) + palette_groups.dungeon_main.AddPalette(gfx::ReadPaletteFromRom( + kDungeonMainPalettes + (i * 180), /*num_colors=*/90, data)); } return absl::OkStatus(); } -absl::Status LoadGrassColors(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { - RETURN_IF_ERROR(palette_groups.grass.AddColor( - gfx::ReadColorFromRom(kHardcodedGrassLW, rom_data.data()))) - RETURN_IF_ERROR(palette_groups.grass.AddColor( - gfx::ReadColorFromRom(hardcodedGrassDW, rom_data.data()))) - RETURN_IF_ERROR(palette_groups.grass.AddColor( - gfx::ReadColorFromRom(hardcodedGrassSpecial, rom_data.data()))) +absl::Status LoadGrassColors(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { + palette_groups.grass.AddColor( + gfx::ReadColorFromRom(kHardcodedGrassLW, rom_data.data())); + palette_groups.grass.AddColor( + gfx::ReadColorFromRom(kHardcodedGrassDW, rom_data.data())); + palette_groups.grass.AddColor( + gfx::ReadColorFromRom(kHardcodedGrassSpecial, rom_data.data())); return absl::OkStatus(); } -absl::Status Load3DObjectPalettes(const Bytes& rom_data, - gfx::PaletteGroupMap& palette_groups) { +absl::Status Load3DObjectPalettes(const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); - RETURN_IF_ERROR(palette_groups.object_3d.AddPalette( - gfx::ReadPaletteFromRom(kTriforcePalette, 8, data))) - RETURN_IF_ERROR(palette_groups.object_3d.AddPalette( - gfx::ReadPaletteFromRom(crystalPalette, 8, data))) + palette_groups.object_3d.AddPalette( + gfx::ReadPaletteFromRom(kTriforcePalette, 8, data)); + palette_groups.object_3d.AddPalette( + gfx::ReadPaletteFromRom(kCrystalPalette, 8, data)); return absl::OkStatus(); } absl::Status LoadOverworldMiniMapPalettes( - const Bytes& rom_data, gfx::PaletteGroupMap& palette_groups) { + const std::vector &rom_data, + gfx::PaletteGroupMap &palette_groups) { auto data = rom_data.data(); for (int i = 0; i < 2; i++) { - RETURN_IF_ERROR( - palette_groups.overworld_mini_map.AddPalette(gfx::ReadPaletteFromRom( - kOverworldMiniMapPalettes + (i * 256), 128, data))) + palette_groups.overworld_mini_map.AddPalette(gfx::ReadPaletteFromRom( + kOverworldMiniMapPalettes + (i * 256), /*num_colors=*/128, data)); } return absl::OkStatus(); } @@ -207,7 +208,7 @@ const absl::flat_hash_map kPaletteGroupColorCounts = { {"grass", 1}, {"3d_object", 8}, {"ow_mini_map", 128}, }; -uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index, +uint32_t GetPaletteAddress(const std::string &group_name, size_t palette_index, size_t color_index) { // Retrieve the base address for the palette group uint32_t base_address = kPaletteGroupAddressMap.at(group_name); @@ -222,96 +223,63 @@ uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index, return address; } -// ============================================================================ - -SnesPalette::SnesPalette(uint8_t mSize) : size_(mSize) { - for (unsigned int i = 0; i < mSize; i++) { - SnesColor col; - colors.push_back(col); - } - size_ = mSize; -} - -SnesPalette::SnesPalette(char* data) : size_(sizeof(data) / 2) { +SnesPalette::SnesPalette(char *data) { assert((sizeof(data) % 4 == 0) && (sizeof(data) <= 32)); for (unsigned i = 0; i < sizeof(data); i += 2) { SnesColor col; col.set_snes(static_cast(data[i + 1]) << 8); col.set_snes(col.snes() | static_cast(data[i])); - snes_color mColor = ConvertSNEStoRGB(col.snes()); + snes_color mColor = ConvertSnesToRgb(col.snes()); col.set_rgb(ImVec4(mColor.red, mColor.green, mColor.blue, 1.f)); colors.push_back(col); } - size_ = sizeof(data) / 2; } -SnesPalette::SnesPalette(const unsigned char* snes_pal) - : size_(sizeof(snes_pal) / 2) { +SnesPalette::SnesPalette(const unsigned char *snes_pal) { assert((sizeof(snes_pal) % 4 == 0) && (sizeof(snes_pal) <= 32)); for (unsigned i = 0; i < sizeof(snes_pal); i += 2) { SnesColor col; col.set_snes(snes_pal[i + 1] << (uint16_t)8); col.set_snes(col.snes() | snes_pal[i]); - snes_color mColor = ConvertSNEStoRGB(col.snes()); + snes_color mColor = ConvertSnesToRgb(col.snes()); col.set_rgb(ImVec4(mColor.red, mColor.green, mColor.blue, 1.f)); colors.push_back(col); } - size_ = sizeof(snes_pal) / 2; } -SnesPalette::SnesPalette(const std::vector& cols) { - for (const auto& each : cols) { +SnesPalette::SnesPalette(const std::vector &cols) { + for (const auto &each : cols) { SnesColor scol; scol.set_rgb(each); colors.push_back(scol); } - size_ = cols.size(); } -SnesPalette::SnesPalette(const std::vector& cols) { - for (const auto& each : cols) { +SnesPalette::SnesPalette(const std::vector &cols) { + for (const auto &each : cols) { SnesColor scol; - scol.set_snes(ConvertRGBtoSNES(each)); + scol.set_snes(ConvertRgbToSnes(each)); colors.push_back(scol); } - size_ = cols.size(); } -SnesPalette::SnesPalette(const std::vector& cols) { - for (const auto& each : cols) { +SnesPalette::SnesPalette(const std::vector &cols) { + for (const auto &each : cols) { colors.push_back(each); } - size_ = cols.size(); } -SDL_Palette* SnesPalette::GetSDL_Palette() { - auto sdl_palette = std::make_shared(); - sdl_palette->ncolors = size_; - - auto color = std::vector(size_); - for (int i = 0; i < size_; i++) { - color[i].r = (uint8_t)colors[i].rgb().x * 100; - color[i].g = (uint8_t)colors[i].rgb().y * 100; - color[i].b = (uint8_t)colors[i].rgb().z * 100; - color[i].a = 0; - std::cout << "Color " << i << " added (R:" << color[i].r - << " G:" << color[i].g << " B:" << color[i].b << ")" << std::endl; - } - sdl_palette->colors = color.data(); - return sdl_palette.get(); -} - -SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uchar* rom) { +SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t *rom) { int color_offset = 0; std::vector colors(num_colors); while (color_offset < num_colors) { short color = (ushort)((rom[offset + 1]) << 8) | rom[offset]; - gfx::snes_color new_color; + snes_color new_color; new_color.red = (color & 0x1F) * 8; new_color.green = ((color >> 5) & 0x1F) * 8; new_color.blue = ((color >> 10) & 0x1F) * 8; - colors[color_offset].set_snes(ConvertRGBtoSNES(new_color)); + colors[color_offset].set_snes(ConvertRgbToSnes(new_color)); if (color_offset == 0) { colors[color_offset].set_transparent(true); } @@ -322,7 +290,7 @@ SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uchar* rom) { return gfx::SnesPalette(colors); } -std::array ToFloatArray(const SnesColor& color) { +std::array ToFloatArray(const SnesColor &color) { std::array colorArray; colorArray[0] = color.rgb().x / 255.0f; colorArray[1] = color.rgb().y / 255.0f; @@ -331,44 +299,39 @@ std::array ToFloatArray(const SnesColor& color) { return colorArray; } -PaletteGroup::PaletteGroup(uint8_t mSize) : size_(mSize) {} - absl::StatusOr CreatePaletteGroupFromColFile( - std::vector& palette_rows) { - PaletteGroup toret; - + std::vector &palette_rows) { + PaletteGroup palette_group; for (int i = 0; i < palette_rows.size(); i += 8) { SnesPalette palette; for (int j = 0; j < 8; j++) { palette.AddColor(palette_rows[i + j].rom_color()); } - RETURN_IF_ERROR(toret.AddPalette(palette)); + palette_group.AddPalette(palette); } - return toret; + return palette_group; } -// Take a SNESPalette with N many colors and divide it into palettes of 8 colors absl::StatusOr CreatePaletteGroupFromLargePalette( - SnesPalette& palette) { - PaletteGroup toret; - - for (int i = 0; i < palette.size(); i += 8) { + SnesPalette &palette, int num_colors) { + PaletteGroup palette_group; + for (int i = 0; i < palette.size(); i += num_colors) { SnesPalette new_palette; - if (i + 8 < palette.size()) { - // new_palette.AddColor(SnesColor(ImVec4(0,0,0,0))); - for (int j = 0; j < 8; j++) { + if (i + num_colors < palette.size()) { + for (int j = 0; j < num_colors; j++) { new_palette.AddColor(palette[i + j]); } } - - RETURN_IF_ERROR(toret.AddPalette(new_palette)); + palette_group.AddPalette(new_palette); } - return toret; + return palette_group; } using namespace palette_group_internal; -absl::Status LoadAllPalettes(const Bytes& rom_data, PaletteGroupMap& groups) { +// TODO: Refactor LoadAllPalettes to use group names, move to zelda3 namespace +absl::Status LoadAllPalettes(const std::vector &rom_data, + PaletteGroupMap &groups) { RETURN_IF_ERROR(LoadOverworldMainPalettes(rom_data, groups)) RETURN_IF_ERROR(LoadOverworldAuxiliaryPalettes(rom_data, groups)) RETURN_IF_ERROR(LoadOverworldAnimatedPalettes(rom_data, groups)) @@ -388,5 +351,6 @@ absl::Status LoadAllPalettes(const Bytes& rom_data, PaletteGroupMap& groups) { } } // namespace gfx +std::unordered_map GfxContext::palettesets_; } // namespace app } // namespace yaze diff --git a/src/app/gfx/snes_palette.h b/src/app/gfx/snes_palette.h index 9128c2b1..bbe7bf57 100644 --- a/src/app/gfx/snes_palette.h +++ b/src/app/gfx/snes_palette.h @@ -1,21 +1,18 @@ #ifndef YAZE_APP_GFX_PALETTE_H #define YAZE_APP_GFX_PALETTE_H -#include -#include "imgui/imgui.h" - #include #include #include #include -#include #include -#include "absl/base/casts.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "app/core/constants.h" #include "app/gfx/snes_color.h" +#include "imgui/imgui.h" +#include "snes_color.h" namespace yaze { namespace app { @@ -52,7 +49,7 @@ static constexpr absl::string_view kPaletteGroupNames[] = { "sprites_aux3", "dungeon_main", "ow_mini_map", "ow_mini_map", "3d_object", "3d_object"}; -constexpr const char* kPaletteGroupAddressesKeys[] = { +constexpr const char *kPaletteGroupAddressesKeys[] = { "ow_main", "ow_aux", "ow_animated", "hud", "global_sprites", "armors", "swords", "shields", "sprites_aux1", "sprites_aux2", "sprites_aux3", "dungeon_main", @@ -63,42 +60,36 @@ constexpr int kOverworldPaletteMain = 0xDE6C8; constexpr int kOverworldPaletteAux = 0xDE86C; constexpr int kOverworldPaletteAnimated = 0xDE604; constexpr int kGlobalSpritesLW = 0xDD218; -constexpr int globalSpritePalettesDW = 0xDD290; -// Green, Blue, Red, Bunny, Electrocuted (15 colors each) -constexpr int kArmorPalettes = 0xDD308; +constexpr int kGlobalSpritePalettesDW = 0xDD290; +constexpr int kArmorPalettes = + 0xDD308; /** < Green, Blue, Red, Bunny, Electrocuted (15 colors each) */ constexpr int kSpritesPalettesAux1 = 0xDD39E; // 7 colors each constexpr int kSpritesPalettesAux2 = 0xDD446; // 7 colors each constexpr int kSpritesPalettesAux3 = 0xDD4E0; // 7 colors each constexpr int kSwordPalettes = 0xDD630; // 3 colors each - 4 entries constexpr int kShieldPalettes = 0xDD648; // 4 colors each - 3 entries constexpr int kHudPalettes = 0xDD660; -constexpr int dungeonMapPalettes = 0xDD70A; // 21 colors -constexpr int kDungeonMainPalettes = 0xDD734; //(15*6) colors each - 20 entries -constexpr int dungeonMapBgPalettes = 0xDE544; // 16*6 +constexpr int kDungeonMapPalettes = 0xDD70A; // 21 colors +constexpr int kDungeonMainPalettes = + 0xDD734; // (15*6) colors each - 20 entries +constexpr int kDungeonMapBgPalettes = 0xDE544; // 16*6 + // Mirrored Value at 0x75645 : 0x75625 constexpr int kHardcodedGrassLW = 0x5FEA9; -constexpr int hardcodedGrassDW = 0x05FEB3; // 0x7564F -constexpr int hardcodedGrassSpecial = 0x75640; +constexpr int kHardcodedGrassDW = 0x05FEB3; // 0x7564F +constexpr int kHardcodedGrassSpecial = 0x75640; constexpr int kOverworldMiniMapPalettes = 0x55B27; constexpr int kTriforcePalette = 0x64425; -constexpr int crystalPalette = 0xF4CD3; -// 2 bytes for each overworld area (320) -constexpr int customAreaSpecificBGPalette = 0x140000; -constexpr int customAreaSpecificBGASM = 0x140150; +constexpr int kCrystalPalette = 0xF4CD3; +constexpr int CustomAreaSpecificBGPalette = + 0x140000; /** < 2 bytes for each overworld area (320) */ + +constexpr int CustomAreaSpecificBGASM = 0x140150; + // 1 byte, not 0 if enabled -constexpr int customAreaSpecificBGEnabled = 0x140140; +constexpr int kCustomAreaSpecificBGEnabled = 0x140140; -/** - * @brief Primitive of a SNES color palette. - */ -struct snes_palette { - uint id; /**< ID of the palette. */ - uint size; /**< Size of the palette. */ - snes_color* colors; /**< Pointer to the colors in the palette. */ -}; -using snes_palette = struct snes_palette; - -uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index, +uint32_t GetPaletteAddress(const std::string &group_name, size_t palette_index, size_t color_index); /** @@ -116,48 +107,31 @@ uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index, class SnesPalette { public: template - explicit SnesPalette(const std::vector& data) { - for (const auto& item : data) { - colors.push_back(SnesColor(item)); + explicit SnesPalette(const std::vector &data) { + for (const auto &item : data) { + colors.emplace_back(SnesColor(item)); } - size_ = data.size(); } SnesPalette() = default; + explicit SnesPalette(char *snesPal); + explicit SnesPalette(const unsigned char *snes_pal); + explicit SnesPalette(const std::vector &); + explicit SnesPalette(const std::vector &); + explicit SnesPalette(const std::vector &); - explicit SnesPalette(uint8_t mSize); - explicit SnesPalette(char* snesPal); - explicit SnesPalette(const unsigned char* snes_pal); - explicit SnesPalette(const std::vector&); - explicit SnesPalette(const std::vector&); - explicit SnesPalette(const std::vector&); - - SDL_Palette* GetSDL_Palette(); - - void Create(const std::vector& cols) { - for (const auto& each : cols) { - colors.push_back(each); + void Create(const std::vector &cols) { + for (const auto &each : cols) { + colors.emplace_back(each); } - size_ = cols.size(); } - void AddColor(SnesColor color) { - colors.push_back(color); - size_++; - } - - void AddColor(snes_color color) { - colors.emplace_back(color); - size_++; - } - - void AddColor(uint16_t color) { - colors.emplace_back(color); - size_++; - } + void AddColor(const SnesColor &color) { colors.emplace_back(color); } + void AddColor(const snes_color &color) { colors.emplace_back(color); } + void AddColor(uint16_t color) { colors.emplace_back(color); } absl::StatusOr GetColor(int i) const { - if (i > size_) { + if (i > colors.size()) { return absl::InvalidArgumentError("SnesPalette: Index out of bounds"); } return colors[i]; @@ -165,32 +139,29 @@ class SnesPalette { auto mutable_color(int i) { return &colors[i]; } - void Clear() { - colors.clear(); - size_ = 0; - } - + void clear() { colors.clear(); } auto size() const { return colors.size(); } auto empty() const { return colors.empty(); } - SnesColor& operator[](int i) { - if (i > size_) { + SnesColor &operator[](int i) { + if (i > colors.size()) { std::cout << "SNESPalette: Index out of bounds" << std::endl; return colors[0]; } return colors[i]; } - void operator()(int i, const SnesColor& color) { - if (i >= size_) { - throw std::out_of_range("SNESPalette: Index out of bounds"); + void operator()(int i, const SnesColor &color) { + if (i >= colors.size()) { + std::cout << "SNESPalette: Index out of bounds" << std::endl; } colors[i] = color; } - void operator()(int i, const ImVec4& color) { - if (i >= size_) { - throw std::out_of_range("SNESPalette: Index out of bounds"); + void operator()(int i, const ImVec4 &color) { + if (i >= colors.size()) { + std::cout << "SNESPalette: Index out of bounds" << std::endl; + return; } colors[i].set_rgb(color); colors[i].set_modified(true); @@ -205,13 +176,12 @@ class SnesPalette { } private: - int size_ = 0; /**< The size of the palette. */ std::vector colors; /**< The colors in the palette. */ }; -SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t* rom); +SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t *rom); -std::array ToFloatArray(const SnesColor& color); +std::array ToFloatArray(const SnesColor &color); /** * @brief Represents a group of palettes. @@ -222,66 +192,39 @@ std::array ToFloatArray(const SnesColor& color); struct PaletteGroup { PaletteGroup() = default; - explicit PaletteGroup(uint8_t mSize); + void AddPalette(SnesPalette pal) { palettes.emplace_back(pal); } - absl::Status AddPalette(SnesPalette pal) { - palettes.emplace_back(pal); - size_ = palettes.size(); - return absl::OkStatus(); - } - - absl::Status AddColor(SnesColor color) { - if (size_ == 0) { + void AddColor(SnesColor color) { + if (palettes.empty()) { palettes.emplace_back(); } palettes[0].AddColor(color); - return absl::OkStatus(); - } - - void Clear() { - palettes.clear(); - size_ = 0; } + void clear() { palettes.clear(); } + void SetName(const std::string &name) { name_ = name; } auto name() const { return name_; } auto size() const { return palettes.size(); } auto mutable_palette(int i) { return &palettes[i]; } auto palette(int i) const { return palettes[i]; } SnesPalette operator[](int i) { - if (i > size_) { + if (i > palettes.size()) { std::cout << "PaletteGroup: Index out of bounds" << std::endl; return palettes[0]; } return palettes[i]; } - const SnesPalette& operator[](int i) const { - if (i > size_) { + const SnesPalette &operator[](int i) const { + if (i > palettes.size()) { std::cout << "PaletteGroup: Index out of bounds" << std::endl; return palettes[0]; } return palettes[i]; } - absl::Status operator()(int i, const SnesColor& color) { - if (i >= size_) { - return absl::InvalidArgumentError("PaletteGroup: Index out of bounds"); - } - palettes[i](0, color); - return absl::OkStatus(); - } - - absl::Status operator()(int i, const ImVec4& color) { - if (i >= size_) { - return absl::InvalidArgumentError("PaletteGroup: Index out of bounds"); - } - palettes[i](0, color); - return absl::OkStatus(); - } - private: - int size_ = 0; std::string name_; std::vector palettes; }; @@ -310,7 +253,7 @@ struct PaletteGroupMap { PaletteGroup object_3d; PaletteGroup overworld_mini_map; - auto get_group(const std::string& group_name) { + auto get_group(const std::string &group_name) { if (group_name == "ow_main") { return &overworld_main; } else if (group_name == "ow_aux") { @@ -347,7 +290,7 @@ struct PaletteGroupMap { } template - absl::Status for_each(Func&& func) { + absl::Status for_each(Func &&func) { RETURN_IF_ERROR(func(overworld_aux)); RETURN_IF_ERROR(func(overworld_animated)); RETURN_IF_ERROR(func(hud)); @@ -364,13 +307,45 @@ struct PaletteGroupMap { RETURN_IF_ERROR(func(overworld_mini_map)); return absl::OkStatus(); } + + void clear() { + overworld_main.clear(); + overworld_aux.clear(); + overworld_animated.clear(); + hud.clear(); + global_sprites.clear(); + armors.clear(); + swords.clear(); + shields.clear(); + sprites_aux1.clear(); + sprites_aux2.clear(); + sprites_aux3.clear(); + dungeon_main.clear(); + grass.clear(); + object_3d.clear(); + overworld_mini_map.clear(); + } + + bool empty() { + return overworld_main.size() == 0 && overworld_aux.size() == 0 && + overworld_animated.size() == 0 && hud.size() == 0 && + global_sprites.size() == 0 && armors.size() == 0 && + swords.size() == 0 && shields.size() == 0 && + sprites_aux1.size() == 0 && sprites_aux2.size() == 0 && + sprites_aux3.size() == 0 && dungeon_main.size() == 0 && + grass.size() == 0 && object_3d.size() == 0 && + overworld_mini_map.size() == 0; + } }; absl::StatusOr CreatePaletteGroupFromColFile( - std::vector& colors); + std::vector &colors); +/** + * @brief Take a SNESPalette, divide it into palettes of 8 colors + */ absl::StatusOr CreatePaletteGroupFromLargePalette( - SnesPalette& palette); + SnesPalette &palette, int num_colors = 8); /** * @brief Loads all the palettes for the game. @@ -381,7 +356,8 @@ absl::StatusOr CreatePaletteGroupFromLargePalette( * groups. * */ -absl::Status LoadAllPalettes(const Bytes& rom_data, PaletteGroupMap& groups); +absl::Status LoadAllPalettes(const std::vector &rom_data, + PaletteGroupMap &groups); /** * @brief Represents a set of palettes used in a SNES graphics system. @@ -429,7 +405,17 @@ struct Paletteset { gfx::SnesPalette composite; /**< The composite palette. */ }; -} // namespace gfx +} // namespace gfx +/** + * @brief Shared graphical context across editors. + */ +class GfxContext { +protected: + // Palettesets for the tile16 individual tiles + static std::unordered_map palettesets_; +}; + + } // namespace app } // namespace yaze diff --git a/src/app/gfx/snes_tile.cc b/src/app/gfx/snes_tile.cc index 6974134a..940fd6c5 100644 --- a/src/app/gfx/snes_tile.cc +++ b/src/app/gfx/snes_tile.cc @@ -1,6 +1,8 @@ #include "snes_tile.h" +#include #include +#include #include #include "app/core/constants.h" @@ -9,9 +11,21 @@ namespace yaze { namespace app { namespace gfx { -tile8 UnpackBppTile(const Bytes& data, const uint32_t offset, +// Bit set for object priority +constexpr ushort TilePriorityBit = 0x2000; + +// Bit set for object hflip +constexpr ushort TileHFlipBit = 0x4000; + +// Bit set for object vflip +constexpr ushort TileVFlipBit = 0x8000; + +// Bits used for tile name +constexpr ushort TileNameMask = 0x03FF; + +snes_tile8 UnpackBppTile(const std::vector& data, const uint32_t offset, const uint32_t bpp) { - tile8 tile; + snes_tile8 tile; assert(bpp >= 1 && bpp <= 8); unsigned int bpp_pos[8]; // More for conveniance and readibility for (int col = 0; col < 8; col++) { @@ -66,7 +80,7 @@ tile8 UnpackBppTile(const Bytes& data, const uint32_t offset, return tile; } -Bytes PackBppTile(const tile8& tile, const uint32_t bpp) { +std::vector PackBppTile(const snes_tile8& tile, const uint32_t bpp) { // Allocate memory for output data std::vector output(bpp * 8, 0); // initialized with 0 unsigned maxcolor = 2 << bpp; @@ -119,7 +133,7 @@ std::vector ConvertBpp(const std::vector& tiles, std::vector converted(nb_tile * to_bpp * 8); for (unsigned int i = 0; i < nb_tile; i++) { - tile8 tile = UnpackBppTile(tiles, i * from_bpp * 8, from_bpp); + snes_tile8 tile = UnpackBppTile(tiles, i * from_bpp * 8, from_bpp); std::vector packed_tile = PackBppTile(tile, to_bpp); std::memcpy(converted.data() + i * to_bpp * 8, packed_tile.data(), to_bpp * 8); @@ -135,13 +149,15 @@ std::vector Convert4bppTo3bpp(const std::vector& tiles) { return ConvertBpp(tiles, 4, 3); } -Bytes SnesTo8bppSheet(const Bytes& sheet, int bpp) { +std::vector SnesTo8bppSheet(const std::vector& sheet, int bpp, + int num_sheets) { int xx = 0; // positions where we are at on the sheet int yy = 0; int pos = 0; int ypos = 0; int num_tiles = 64; int buffer_size = 0x1000; + if (bpp == 2) { bpp = 16; num_tiles = 128; @@ -154,7 +170,13 @@ Bytes SnesTo8bppSheet(const Bytes& sheet, int bpp) { } else if (bpp == 8) { bpp = 64; } - Bytes sheet_buffer_out(buffer_size); + + if (num_sheets != 1) { + num_tiles *= num_sheets; + buffer_size *= num_sheets; + } + + std::vector sheet_buffer_out(buffer_size); for (int i = 0; i < num_tiles; i++) { // for each tiles, 16 per line for (int y = 0; y < 8; y++) { // for each line @@ -187,7 +209,8 @@ Bytes SnesTo8bppSheet(const Bytes& sheet, int bpp) { return sheet_buffer_out; } -Bytes Bpp8SnesToIndexed(Bytes data, uint64_t bpp) { +std::vector Bpp8SnesToIndexed(std::vector data, + uint64_t bpp) { // 3BPP // [r0,bp1],[r0,bp2],[r1,bp1],[r1,bp2],[r2,bp1],[r2,bp2],[r3,bp1],[r3,bp2] // [r4,bp1],[r4,bp2],[r5,bp1],[r5,bp2],[r6,bp1],[r6,bp2],[r7,bp1],[r7,bp2] @@ -199,7 +222,7 @@ Bytes Bpp8SnesToIndexed(Bytes data, uint64_t bpp) { // [r4,bp7],[r4,bp8],[r5,bp7],[r5,bp8],[r6,bp7],[r6,bp8],[r7,bp7],[r7,bp8] // 16 tiles = 1024 bytes - auto buffer = Bytes(data.size()); + auto buffer = std::vector(data.size()); std::vector> bitmap_data; bitmap_data.resize(0x80); for (auto& each : bitmap_data) { @@ -323,46 +346,59 @@ TileInfo WordToTileInfo(uint16_t word) { uint16_t TileInfoToShort(TileInfo tile_info) { // uint16_t result = 0; - // // Copy the id_ value + // Copy the id_ value // result |= tile_info.id_ & 0x3FF; // ids are 10 bits - // // Set the vertical_mirror_, horizontal_mirror_, and over_ flags + // Set the vertical_mirror_, horizontal_mirror_, and over_ flags // result |= (tile_info.vertical_mirror_ ? 1 : 0) << 10; // result |= (tile_info.horizontal_mirror_ ? 1 : 0) << 11; // result |= (tile_info.over_ ? 1 : 0) << 12; - // // Set the palette_ + // Set the palette_ // result |= (tile_info.palette_ & 0x07) << 13; // palettes are 3 bits uint16_t value = 0; // vhopppcc cccccccc if (tile_info.over_) { - value |= core::TilePriorityBit; + value |= TilePriorityBit; } if (tile_info.horizontal_mirror_) { - value |= core::TileHFlipBit; + value |= TileHFlipBit; } if (tile_info.vertical_mirror_) { - value |= core::TileVFlipBit; + value |= TileVFlipBit; } value |= (uint16_t)((tile_info.palette_ << 10) & 0x1C00); - value |= (uint16_t)(tile_info.id_ & core::TileNameMask); + value |= (uint16_t)(tile_info.id_ & TileNameMask); return value; } TileInfo GetTilesInfo(uint16_t tile) { // vhopppcc cccccccc - uint16_t tid = (uint16_t)(tile & core::TileNameMask); + uint16_t tid = (uint16_t)(tile & TileNameMask); uint8_t p = (uint8_t)((tile >> 10) & 0x07); - bool o = ((tile & core::TilePriorityBit) == core::TilePriorityBit); - bool h = ((tile & core::TileHFlipBit) == core::TileHFlipBit); - bool v = ((tile & core::TileVFlipBit) == core::TileVFlipBit); + bool o = ((tile & TilePriorityBit) == TilePriorityBit); + bool h = ((tile & TileHFlipBit) == TileHFlipBit); + bool v = ((tile & TileVFlipBit) == TileVFlipBit); return TileInfo(tid, p, v, h, o); } +void CopyTile8bpp16(int x, int y, int tile, std::vector& bitmap, + std::vector& blockset) { + int src_pos = + ((tile - ((tile / 0x08) * 0x08)) * 0x10) + ((tile / 0x08) * 2048); + int dest_pos = (x + (y * 0x200)); + for (int yy = 0; yy < 0x10; yy++) { + for (int xx = 0; xx < 0x10; xx++) { + bitmap[dest_pos + xx + (yy * 0x200)] = + blockset[src_pos + xx + (yy * 0x80)]; + } + } +} + } // namespace gfx } // namespace app -} // namespace yaze \ No newline at end of file +} // namespace yaze diff --git a/src/app/gfx/snes_tile.h b/src/app/gfx/snes_tile.h index a19c5718..46ab72b3 100644 --- a/src/app/gfx/snes_tile.h +++ b/src/app/gfx/snes_tile.h @@ -1,33 +1,34 @@ #ifndef YAZE_APP_GFX_SNES_TILE_H #define YAZE_APP_GFX_SNES_TILE_H +#include + +#include #include #include +#include #include -#include "app/core/constants.h" - namespace yaze { namespace app { namespace gfx { +constexpr int kTilesheetWidth = 128; +constexpr int kTilesheetHeight = 32; +constexpr int kTilesheetDepth = 8; + constexpr uint8_t kGraphicsBitmap[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; -Bytes SnesTo8bppSheet(const Bytes& sheet, int bpp); -Bytes Bpp8SnesToIndexed(Bytes data, uint64_t bpp = 0); +std::vector SnesTo8bppSheet(const std::vector& sheet, int bpp, + int num_sheets = 1); +std::vector Bpp8SnesToIndexed(std::vector data, + uint64_t bpp = 0); -struct tile8 { - uint32_t id; - char data[64]; - uint32_t palette_id; -}; -using tile8 = struct tile8; +snes_tile8 UnpackBppTile(const std::vector& data, + const uint32_t offset, const uint32_t bpp); -tile8 UnpackBppTile(const Bytes& data, const uint32_t offset, - const uint32_t bpp); - -Bytes PackBppTile(const tile8& tile, const uint32_t bpp); +std::vector PackBppTile(const snes_tile8& tile, const uint32_t bpp); std::vector ConvertBpp(const std::vector& tiles, uint32_t from_bpp, uint32_t to_bpp); @@ -35,6 +36,9 @@ std::vector ConvertBpp(const std::vector& tiles, std::vector Convert3bppTo4bpp(const std::vector& tiles); std::vector Convert4bppTo3bpp(const std::vector& tiles); +void CopyTile8bpp16(int x, int y, int tile, std::vector& bitmap, + std::vector& blockset); + /** * @brief SNES 16-bit tile metadata container * @@ -69,7 +73,6 @@ class TileInfo { uint16_t TileInfoToWord(TileInfo tile_info); TileInfo WordToTileInfo(uint16_t word); uint16_t TileInfoToShort(TileInfo tile_info); - TileInfo GetTilesInfo(uint16_t tile); /** @@ -130,15 +133,15 @@ class Tile16 { TileInfo tile1_; TileInfo tile2_; TileInfo tile3_; - std::vector tiles_info; + std::array tiles_info; Tile16() = default; Tile16(TileInfo t0, TileInfo t1, TileInfo t2, TileInfo t3) : tile0_(t0), tile1_(t1), tile2_(t2), tile3_(t3) { - tiles_info.push_back(tile0_); - tiles_info.push_back(tile1_); - tiles_info.push_back(tile2_); - tiles_info.push_back(tile3_); + tiles_info[0] = tile0_; + tiles_info[1] = tile1_; + tiles_info[2] = tile2_; + tiles_info[3] = tile3_; } bool operator==(const Tile16& other) const { @@ -151,7 +154,7 @@ class Tile16 { /** * @brief Object Attribute Memory tile abstraction container -*/ + */ class OamTile { public: int x_; @@ -172,6 +175,52 @@ class OamTile { } }; +class GraphicsBuffer { + public: + GraphicsBuffer() = default; + GraphicsBuffer(uint8_t bpp, const std::vector& data) + : bpp_(bpp), data_(data) {} + GraphicsBuffer(uint8_t bpp, std::vector&& data) + : bpp_(bpp), data_(std::move(data)) {} + + uint8_t bpp() const { return bpp_; } + const std::vector& data() const { return data_; } + + void set_bpp(uint8_t bpp) { bpp_ = bpp; } + void set_data(const std::vector& data) { data_ = data; } + void to_bpp(uint8_t bpp) { + if (bpp_ == bpp) { + return; + } + data_ = ConvertBpp(data_, bpp_, bpp); + bpp_ = bpp; + } + + // Array-like access via operator[] + uint8_t& operator[](size_t index) { + if (index >= data_.size()) { + throw std::out_of_range("Index out of range"); + } + return data_[index]; + } + + const uint8_t& operator[](size_t index) const { + if (index >= data_.size()) { + throw std::out_of_range("Index out of range"); + } + return data_[index]; + } + + auto begin() { return data_.begin(); } + auto end() { return data_.end(); } + auto begin() const { return data_.begin(); } + auto end() const { return data_.end(); } + + private: + uint8_t bpp_; + std::vector data_; +}; + } // namespace gfx } // namespace app } // namespace yaze diff --git a/src/app/gfx/tilesheet.cc b/src/app/gfx/tilesheet.cc index 71c8f584..5d4d3527 100644 --- a/src/app/gfx/tilesheet.cc +++ b/src/app/gfx/tilesheet.cc @@ -32,12 +32,12 @@ absl::StatusOr CreateTilesheetFromGraphicsBuffer( // Copy the tile data into the tilesheet for (int y = 0; y < 8; ++y) { for (int x = 0; x < 8; ++x) { - int srcIndex = tile_index + (y * 8 + x); - int destX = col * 8 + x; - int destY = row * 8 + y; - int destIndex = (destY * width * 8) + destX; - tilesheet.mutable_bitmap()->mutable_data()[destIndex] = - graphics_buffer[srcIndex]; + int src_index = tile_index + (y * 8 + x); + int dest_x = col * 8 + x; + int dest_y = row * 8 + y; + int dest_index = (dest_y * width * 8) + dest_x; + tilesheet.mutable_bitmap()->mutable_data()[dest_index] = + graphics_buffer[src_index]; } } } @@ -63,28 +63,54 @@ void Tilesheet::ComposeTile16(const std::vector& graphics_buffer, const TileInfo& top_left, const TileInfo& top_right, const TileInfo& bottom_left, - const TileInfo& bottom_right) { + const TileInfo& bottom_right, int sheet_offset) { + sheet_offset_ = sheet_offset; // Calculate the base position for this Tile16 in the full-size bitmap int tiles_per_row = bitmap_->width() / tile_width_; int tile16_row = num_tiles_ / tiles_per_row; int tile16_column = num_tiles_ % tiles_per_row; - int baseX = tile16_column * tile_width_; - int baseY = tile16_row * tile_height_; + int base_x = tile16_column * tile_width_; + int base_y = tile16_row * tile_height_; // Compose and place each part of the Tile16 - ComposeAndPlaceTilePart(graphics_buffer, top_left, baseX, baseY); - ComposeAndPlaceTilePart(graphics_buffer, top_right, baseX + 8, baseY); - ComposeAndPlaceTilePart(graphics_buffer, bottom_left, baseX, baseY + 8); - ComposeAndPlaceTilePart(graphics_buffer, bottom_right, baseX + 8, baseY + 8); + ComposeAndPlaceTilePart(graphics_buffer, top_left, base_x, base_y); + ComposeAndPlaceTilePart(graphics_buffer, top_right, base_x + 8, base_y); + ComposeAndPlaceTilePart(graphics_buffer, bottom_left, base_x, base_y + 8); + ComposeAndPlaceTilePart(graphics_buffer, bottom_right, base_x + 8, + base_y + 8); tile_info_.push_back({top_left, top_right, bottom_left, bottom_right}); num_tiles_++; } +void Tilesheet::ModifyTile16(const std::vector& graphics_buffer, + const TileInfo& top_left, + const TileInfo& top_right, + const TileInfo& bottom_left, + const TileInfo& bottom_right, int tile_id, + int sheet_offset) { + sheet_offset_ = sheet_offset; + // Calculate the base position for this Tile16 in the full-size bitmap + int tiles_per_row = bitmap_->width() / tile_width_; + int tile16_row = tile_id / tiles_per_row; + int tile16_column = tile_id % tiles_per_row; + int base_x = tile16_column * tile_width_; + int base_y = tile16_row * tile_height_; + + // Compose and place each part of the Tile16 + ComposeAndPlaceTilePart(graphics_buffer, top_left, base_x, base_y); + ComposeAndPlaceTilePart(graphics_buffer, top_right, base_x + 8, base_y); + ComposeAndPlaceTilePart(graphics_buffer, bottom_left, base_x, base_y + 8); + ComposeAndPlaceTilePart(graphics_buffer, bottom_right, base_x + 8, + base_y + 8); + + tile_info_[tile_id] = {top_left, top_right, bottom_left, bottom_right}; +} + void Tilesheet::ComposeAndPlaceTilePart( const std::vector& graphics_buffer, const TileInfo& tile_info, - int baseX, int baseY) { + int base_x, int base_y) { std::vector tile_data = FetchTileDataFromGraphicsBuffer(graphics_buffer, tile_info.id_); @@ -98,17 +124,91 @@ void Tilesheet::ComposeAndPlaceTilePart( // Place the tile data into the full-size bitmap at the calculated position for (int y = 0; y < 8; ++y) { for (int x = 0; x < 8; ++x) { - int srcIndex = y * 8 + x; - int destX = baseX + x; - int destY = baseY + y; - int destIndex = (destY * bitmap_->width()) + destX; - internal_data_[destIndex] = tile_data[srcIndex]; + int src_index = y * 8 + x; + int dest_x = base_x + x; + int dest_y = base_y + y; + int dest_index = (dest_y * bitmap_->width()) + dest_x; + internal_data_[dest_index] = tile_data[src_index]; } } bitmap_->set_data(internal_data_); } +std::vector Tilesheet::FetchTileDataFromGraphicsBuffer( + const std::vector& graphics_buffer, int tile_id) { + const int tile_width = 8; + const int tile_height = 8; + const int buffer_width = 128; + const int sheet_height = 32; + + const int tiles_per_row = buffer_width / tile_width; + const int rows_per_sheet = sheet_height / tile_height; + const int tiles_per_sheet = tiles_per_row * rows_per_sheet; + + // Calculate the position in the graphics_buffer_ based on tile_id + std::vector tile_data(0x40, 0x00); + int sheet = (tile_id / tiles_per_sheet) % 4 + sheet_offset_; + int position_in_sheet = tile_id % tiles_per_sheet; + int row_in_sheet = position_in_sheet / tiles_per_row; + int column_in_sheet = position_in_sheet % tiles_per_row; + + // Ensure that the sheet ID is between 212 and 215 if using full gfx buffer + assert(sheet >= sheet_offset_ && sheet <= sheet_offset_ + 3); + + // Copy the tile data from the graphics_buffer_ to tile_data + for (int y = 0; y < 8; ++y) { + for (int x = 0; x < 8; ++x) { + // Calculate the position in the graphics_buffer_ based on tile_id + int src_x = column_in_sheet * tile_width + x; + int src_y = (sheet * sheet_height) + (row_in_sheet * tile_height) + y; + + int src_index = (src_y * buffer_width) + src_x; + int dest_index = y * tile_width + x; + + tile_data[dest_index] = graphics_buffer[src_index]; + } + } + + return tile_data; +} + +void Tilesheet::MirrorTileDataVertically(std::vector& tile_data) { + std::vector tile_data_copy = tile_data; + for (int i = 0; i < 8; ++i) { // For each row + for (int j = 0; j < 8; ++j) { // For each column + int src_index = i * 8 + j; + int dest_index = (7 - i) * 8 + j; // Calculate the mirrored row + tile_data_copy[dest_index] = tile_data[src_index]; + } + } + tile_data = tile_data_copy; +} + +void Tilesheet::MirrorTileDataHorizontally(std::vector& tile_data) { + std::vector tile_data_copy = tile_data; + for (int i = 0; i < 8; ++i) { // For each row + for (int j = 0; j < 8; ++j) { // For each column + int src_index = i * 8 + j; + int dest_index = i * 8 + (7 - j); // Calculate the mirrored column + tile_data_copy[dest_index] = tile_data[src_index]; + } + } + tile_data = tile_data_copy; +} + +void Tilesheet::MirrorTileData(std::vector& tile_data, bool mirrorX, + bool mirrorY) { + std::vector tile_data_copy = tile_data; + if (mirrorX) { + MirrorTileDataHorizontally(tile_data_copy); + } + if (mirrorY) { + MirrorTileDataVertically(tile_data_copy); + } + tile_data = tile_data_copy; +} + } // namespace gfx } // namespace app } // namespace yaze diff --git a/src/app/gfx/tilesheet.h b/src/app/gfx/tilesheet.h index 5de1e6b4..31639b4d 100644 --- a/src/app/gfx/tilesheet.h +++ b/src/app/gfx/tilesheet.h @@ -15,6 +15,10 @@ namespace gfx { enum class TileType { Tile8, Tile16 }; +struct InternalTile16 { + std::array tiles; +}; + /** * @class Tilesheet * @brief Represents a tilesheet, which is a collection of tiles stored in a @@ -37,7 +41,12 @@ class Tilesheet { void ComposeTile16(const std::vector& graphics_buffer, const TileInfo& top_left, const TileInfo& top_right, - const TileInfo& bottom_left, const TileInfo& bottom_right); + const TileInfo& bottom_left, const TileInfo& bottom_right, + int sheet_offset = 0); + void ModifyTile16(const std::vector& graphics_buffer, + const TileInfo& top_left, const TileInfo& top_right, + const TileInfo& bottom_left, const TileInfo& bottom_right, int tile_id, + int sheet_offset = 0); void ComposeAndPlaceTilePart(const std::vector& graphics_buffer, const TileInfo& tile_info, int baseX, int baseY); @@ -45,36 +54,35 @@ class Tilesheet { // Extracts a tile from the tilesheet Bitmap GetTile(int tileX, int tileY, int bmp_width, int bmp_height) { std::vector tileData(tile_width_ * tile_height_); - int tileDataOffset = 0; + int tile_data_offset = 0; bitmap_->Get8x8Tile(CalculateTileIndex(tileX, tileY), tileX, tileY, - tileData, tileDataOffset); + tileData, tile_data_offset); return Bitmap(bmp_width, bmp_height, bitmap_->depth(), tileData); } - Bitmap GetTile16(int tile_x, int tile_y) { - std::vector tile_data(tile_width_ * tile_height_, 0x00); - int tileDataOffset = 0; - bitmap_->Get16x16Tile(tile_x, tile_y, tile_data, tileDataOffset); - return Bitmap(16, 16, bitmap_->depth(), tile_data); - } - Bitmap GetTile16(int tile_id) { + std::cout << "GetTile16: " << tile_id << std::endl; int tiles_per_row = bitmap_->width() / tile_width_; int tile_x = (tile_id % tiles_per_row) * tile_width_; int tile_y = (tile_id / tiles_per_row) * tile_height_; - return GetTile16(tile_x, tile_y); + std::cout << "Tile X: " << tile_x << " Tile Y: " << tile_y << std::endl; + + std::vector tile_data(tile_width_ * tile_height_, 0x00); + int tile_data_offset = 0; + bitmap_->Get16x16Tile(tile_x, tile_y, tile_data, tile_data_offset); + + return Bitmap(16, 16, bitmap_->depth(), tile_data); } // Copy a tile within the tilesheet - void CopyTile(int srcX, int srcY, int destX, int destY, bool mirrorX = false, - bool mirrorY = false) { - auto srcTile = GetTile(srcX, srcY, tile_width_, tile_height_); - auto destTileData = srcTile.vector(); - MirrorTileData(destTileData, mirrorX, mirrorY); - WriteTile(destX, destY, destTileData); + void CopyTile(int srcX, int srcY, int destX, int destY, bool mirror_x = false, + bool mirror_y = false) { + auto src_tile = GetTile(srcX, srcY, tile_width_, tile_height_); + auto dest_tile_data = src_tile.vector(); + MirrorTileData(dest_tile_data, mirror_x, mirror_y); + WriteTile(destX, destY, dest_tile_data); } - // Other methods and properties auto bitmap() const { return bitmap_; } auto mutable_bitmap() { return bitmap_; } auto num_tiles() const { return num_tiles_; } @@ -85,6 +93,13 @@ class Tilesheet { auto tile_type() const { return tile_type_; } auto tile_info() const { return tile_info_; } auto mutable_tile_info() { return tile_info_; } + void clear() { + palette_.clear(); + internal_data_.clear(); + tile_info_.clear(); + bitmap_.reset(); + num_tiles_ = 0; + } private: int CalculateTileIndex(int x, int y) { @@ -92,80 +107,12 @@ class Tilesheet { } std::vector FetchTileDataFromGraphicsBuffer( - const std::vector& graphics_buffer, int tile_id) { - const int tileWidth = 8; - const int tileHeight = 8; - const int bufferWidth = 128; - const int sheetHeight = 32; + const std::vector& graphics_buffer, int tile_id); - const int tilesPerRow = bufferWidth / tileWidth; - const int rowsPerSheet = sheetHeight / tileHeight; - const int tilesPerSheet = tilesPerRow * rowsPerSheet; - - // Calculate the position in the graphics_buffer_ based on tile_id - std::vector tile_data(0x40, 0x00); - int sheet = (tile_id / tilesPerSheet) % 4 + 212; - int positionInSheet = tile_id % tilesPerSheet; - int rowInSheet = positionInSheet / tilesPerRow; - int columnInSheet = positionInSheet % tilesPerRow; - - // Ensure that the sheet ID is between 212 and 215 - assert(sheet >= 212 && sheet <= 215); - - // Copy the tile data from the graphics_buffer_ to tile_data - for (int y = 0; y < 8; ++y) { - for (int x = 0; x < 8; ++x) { - // Calculate the position in the graphics_buffer_ based on tile_id - - int srcX = columnInSheet * tileWidth + x; - int srcY = (sheet * sheetHeight) + (rowInSheet * tileHeight) + y; - - int src_index = (srcY * bufferWidth) + srcX; - int dest_index = y * tileWidth + x; - - tile_data[dest_index] = graphics_buffer[src_index]; - } - } - - return tile_data; - } - - void MirrorTileDataVertically(std::vector& tileData) { - std::vector tile_data_copy = tileData; - for (int i = 0; i < 8; ++i) { // For each row - for (int j = 0; j < 8; ++j) { // For each column - int src_index = i * 8 + j; - int dest_index = (7 - i) * 8 + j; // Calculate the mirrored row - tile_data_copy[dest_index] = tileData[src_index]; - } - } - tileData = tile_data_copy; - } - - void MirrorTileDataHorizontally(std::vector& tileData) { - std::vector tile_data_copy = tileData; - for (int i = 0; i < 8; ++i) { // For each row - for (int j = 0; j < 8; ++j) { // For each column - int src_index = i * 8 + j; - int dest_index = i * 8 + (7 - j); // Calculate the mirrored column - tile_data_copy[dest_index] = tileData[src_index]; - } - } - tileData = tile_data_copy; - } - - void MirrorTileData(std::vector& tileData, bool mirrorX, - bool mirrorY) { - // Implement logic to mirror tile data horizontally and/or vertically - std::vector tile_data_copy = tileData; - if (mirrorX) { - MirrorTileDataHorizontally(tile_data_copy); - } - if (mirrorY) { - MirrorTileDataVertically(tile_data_copy); - } - tileData = tile_data_copy; - } + void MirrorTileDataVertically(std::vector& tileData); + void MirrorTileDataHorizontally(std::vector& tileData); + void MirrorTileData(std::vector& tileData, bool mirror_x, + bool mirror_y); void WriteTile(int x, int y, const std::vector& tileData) { int tileDataOffset = 0; @@ -174,17 +121,16 @@ class Tilesheet { tileDataOffset); } - gfx::SnesPalette palette_; - std::vector internal_data_; - std::shared_ptr bitmap_; - struct InternalTile16 { - std::array tiles; - }; - std::vector tile_info_; int num_tiles_ = 0; int tile_width_ = 0; int tile_height_ = 0; + int sheet_offset_ = 0; + TileType tile_type_; + SnesPalette palette_; + std::vector internal_data_; + std::vector tile_info_; + std::shared_ptr bitmap_; }; absl::StatusOr CreateTilesheetFromGraphicsBuffer( diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index c874815e..7e0a8a3b 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -1,23 +1,23 @@ #include "canvas.h" -#include "imgui/imgui.h" - #include #include -#include "app/editor/graphics/graphics_editor.h" +#include "app/core/platform/renderer.h" #include "app/gfx/bitmap.h" #include "app/gui/color.h" #include "app/gui/input.h" #include "app/gui/style.h" #include "app/rom.h" +#include "imgui/imgui.h" namespace yaze { namespace app { namespace gui { +using core::Renderer; + using ImGui::BeginMenu; -using ImGui::BeginPopup; using ImGui::EndMenu; using ImGui::GetContentRegionAvail; using ImGui::GetCursorScreenPos; @@ -31,11 +31,13 @@ using ImGui::IsMouseDragging; using ImGui::MenuItem; using ImGui::OpenPopupOnItemClick; using ImGui::Selectable; -using ImGui::Separator; using ImGui::Text; +constexpr uint32_t kBlackColor = IM_COL32(0, 0, 0, 255); constexpr uint32_t kRectangleColor = IM_COL32(32, 32, 32, 255); -constexpr uint32_t kRectangleBorder = IM_COL32(255, 255, 255, 255); +constexpr uint32_t kWhiteColor = IM_COL32(255, 255, 255, 255); +constexpr uint32_t kOutlineRect = IM_COL32(255, 255, 255, 200); + constexpr ImGuiButtonFlags kMouseFlags = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight; @@ -71,7 +73,7 @@ void Canvas::DrawBackground(ImVec2 canvas_size, bool can_drag) { // Draw border and background color draw_list_->AddRectFilled(canvas_p0_, canvas_p1_, kRectangleColor); - draw_list_->AddRect(canvas_p0_, canvas_p1_, kRectangleBorder); + draw_list_->AddRect(canvas_p0_, canvas_p1_, kWhiteColor); ImGui::InvisibleButton( canvas_id_.c_str(), @@ -98,8 +100,8 @@ void Canvas::DrawBackground(ImVec2 canvas_size, bool can_drag) { void Canvas::DrawContextMenu(gfx::Bitmap *bitmap) { const ImGuiIO &io = GetIO(); - auto scaled_sz = - ImVec2(canvas_sz_.x * global_scale_, canvas_sz_.y * global_scale_); + const ImVec2 scaled_sz(canvas_sz_.x * global_scale_, + canvas_sz_.y * global_scale_); const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y); // Lock scrolled origin const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y); @@ -126,32 +128,27 @@ void Canvas::DrawContextMenu(gfx::Bitmap *bitmap) { if (bitmap != nullptr) { if (BeginMenu("Bitmap Properties")) { Text("Size: %.0f x %.0f", scaled_sz.x, scaled_sz.y); - Text("Pitch: %s", - absl::StrFormat("%d", bitmap->surface()->pitch).c_str()); + Text("Pitch: %d", bitmap->surface()->pitch); Text("BitsPerPixel: %d", bitmap->surface()->format->BitsPerPixel); Text("BytesPerPixel: %d", bitmap->surface()->format->BytesPerPixel); EndMenu(); } if (BeginMenu("Bitmap Format")) { if (MenuItem("Indexed")) { - bitmap->Reformat(0); - bitmap->ApplyPalette(bitmap->palette()); - rom()->UpdateBitmap(bitmap); + bitmap->Reformat(gfx::BitmapFormat::kIndexed); + Renderer::GetInstance().UpdateBitmap(bitmap); } if (MenuItem("2BPP")) { - bitmap->Reformat(1); - bitmap->ApplyPalette(bitmap->palette()); - rom()->UpdateBitmap(bitmap); + bitmap->Reformat(gfx::BitmapFormat::k2bpp); + Renderer::GetInstance().UpdateBitmap(bitmap); } if (MenuItem("4BPP")) { - bitmap->Reformat(2); - bitmap->ApplyPalette(bitmap->palette()); - rom()->UpdateBitmap(bitmap); + bitmap->Reformat(gfx::BitmapFormat::k4bpp); + Renderer::GetInstance().UpdateBitmap(bitmap); } if (MenuItem("8BPP")) { - bitmap->Reformat(3); - bitmap->ApplyPalette(bitmap->palette()); - rom()->UpdateBitmap(bitmap); + bitmap->Reformat(gfx::BitmapFormat::k8bpp); + Renderer::GetInstance().UpdateBitmap(bitmap); } EndMenu(); } @@ -176,7 +173,7 @@ void Canvas::DrawContextMenu(gfx::Bitmap *bitmap) { if (refresh_graphics_) { auto status = bitmap->ApplyPaletteWithTransparent( *palette, edit_palette_sub_index_); - rom()->UpdateBitmap(bitmap); + Renderer::GetInstance().UpdateBitmap(bitmap); refresh_graphics_ = false; } ImGui::EndChild(); @@ -236,7 +233,7 @@ bool Canvas::DrawTilePainter(const Bitmap &bitmap, int size, float scale) { if (bitmap.is_active()) { draw_list_->AddImage( - (void *)bitmap.texture(), + (ImTextureID)(intptr_t)bitmap.texture(), ImVec2(origin.x + painter_pos.x, origin.y + painter_pos.y), ImVec2(origin.x + painter_pos.x + (size)*scale, origin.y + painter_pos.y + size * scale)); @@ -410,7 +407,7 @@ void Canvas::DrawSelectRect(int current_map, int tile_size, float scale) { canvas_p0_.y + drag_start_pos.y); auto end = ImVec2(canvas_p0_.x + drag_end_pos.x + tile_size, canvas_p0_.y + drag_end_pos.y + tile_size); - draw_list_->AddRect(start, end, kRectangleBorder); + draw_list_->AddRect(start, end, kWhiteColor); dragging = true; } @@ -464,7 +461,7 @@ void Canvas::DrawSelectRect(int current_map, int tile_size, float scale) { void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, bool ready) { if (ready) { draw_list_->AddImage( - (void *)bitmap.texture(), + (ImTextureID)(intptr_t)bitmap.texture(), ImVec2(canvas_p0_.x + border_offset, canvas_p0_.y + border_offset), ImVec2(canvas_p0_.x + (bitmap.width() * 2), canvas_p0_.y + (bitmap.height() * 2))); @@ -475,11 +472,11 @@ void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, float scale) { if (!bitmap.is_active()) { return; } - draw_list_->AddImage((void *)bitmap.texture(), + draw_list_->AddImage((ImTextureID)(intptr_t)bitmap.texture(), ImVec2(canvas_p0_.x, canvas_p0_.y), ImVec2(canvas_p0_.x + (bitmap.width() * scale), canvas_p0_.y + (bitmap.height() * scale))); - draw_list_->AddRect(canvas_p0_, canvas_p1_, kRectangleBorder); + draw_list_->AddRect(canvas_p0_, canvas_p1_, kWhiteColor); } void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset, @@ -488,7 +485,7 @@ void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset, return; } draw_list_->AddImage( - (void *)bitmap.texture(), + (ImTextureID)(intptr_t)bitmap.texture(), ImVec2(canvas_p0_.x + x_offset + scrolling_.x, canvas_p0_.y + y_offset + scrolling_.y), ImVec2( @@ -505,7 +502,7 @@ void Canvas::DrawBitmapTable(const BitmapTable &gfx_bin) { if (key >= 1) { top_left_y = canvas_p0_.y + 0x40 * key; } - draw_list_->AddImage((void *)value.texture(), + draw_list_->AddImage((ImTextureID)(intptr_t)value.texture(), ImVec2(canvas_p0_.x + 2, top_left_y), ImVec2(canvas_p0_.x + 0x100, canvas_p0_.y + offset)); } @@ -516,7 +513,7 @@ void Canvas::DrawOutline(int x, int y, int w, int h) { canvas_p0_.y + scrolling_.y + y); ImVec2 size(canvas_p0_.x + scrolling_.x + x + w, canvas_p0_.y + scrolling_.y + y + h); - draw_list_->AddRect(origin, size, IM_COL32(255, 255, 255, 200), 0, 0, 1.5f); + draw_list_->AddRect(origin, size, kOutlineRect, 0, 0, 1.5f); } void Canvas::DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color) { @@ -612,29 +609,31 @@ void Canvas::DrawRect(int x, int y, int w, int h, ImVec4 color) { // Add a black outline ImVec2 outline_origin(origin.x - 1, origin.y - 1); ImVec2 outline_size(size.x + 1, size.y + 1); - draw_list_->AddRect(outline_origin, outline_size, IM_COL32(0, 0, 0, 255)); + draw_list_->AddRect(outline_origin, outline_size, kBlackColor); } void Canvas::DrawText(std::string text, int x, int y) { draw_list_->AddText(ImVec2(canvas_p0_.x + scrolling_.x + x + 1, canvas_p0_.y + scrolling_.y + y + 1), - IM_COL32(0, 0, 0, 255), text.data()); + kBlackColor, text.data()); draw_list_->AddText( ImVec2(canvas_p0_.x + scrolling_.x + x, canvas_p0_.y + scrolling_.y + y), - IM_COL32(255, 255, 255, 255), text.data()); + kWhiteColor, text.data()); } void Canvas::DrawGridLines(float grid_step) { + const uint32_t grid_color = IM_COL32(200, 200, 200, 50); + const float grid_thickness = 0.5f; for (float x = fmodf(scrolling_.x, grid_step); x < canvas_sz_.x * global_scale_; x += grid_step) draw_list_->AddLine(ImVec2(canvas_p0_.x + x, canvas_p0_.y), - ImVec2(canvas_p0_.x + x, canvas_p1_.y), - IM_COL32(200, 200, 200, 50), 0.5f); + ImVec2(canvas_p0_.x + x, canvas_p1_.y), grid_color, + grid_thickness); for (float y = fmodf(scrolling_.y, grid_step); y < canvas_sz_.y * global_scale_; y += grid_step) draw_list_->AddLine(ImVec2(canvas_p0_.x, canvas_p0_.y + y), - ImVec2(canvas_p1_.x, canvas_p0_.y + y), - IM_COL32(200, 200, 200, 50), 0.5f); + ImVec2(canvas_p1_.x, canvas_p0_.y + y), grid_color, + grid_thickness); } void Canvas::DrawInfoGrid(float grid_step, int tile_id_offset, int label_id) { @@ -645,6 +644,7 @@ void Canvas::DrawInfoGrid(float grid_step, int tile_id_offset, int label_id) { grid_step *= global_scale_; // Apply global scale to grid step DrawGridLines(grid_step); + DrawCustomHighlight(grid_step); if (enable_custom_labels_) { // Draw the contents of labels on the grid @@ -663,13 +663,26 @@ void Canvas::DrawInfoGrid(float grid_step, int tile_id_offset, int label_id) { draw_list_->AddText( ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset, canvas_p0_.y + y + (grid_step / 2) - tile_id_offset), - IM_COL32(255, 255, 255, 255), label.data()); + kWhiteColor, label.data()); } } } } } +void Canvas::DrawCustomHighlight(float grid_step) { + if (highlight_tile_id != -1) { + int tile_x = highlight_tile_id % 8; + int tile_y = highlight_tile_id / 8; + ImVec2 tile_pos(canvas_p0_.x + scrolling_.x + tile_x * grid_step, + canvas_p0_.y + scrolling_.y + tile_y * grid_step); + ImVec2 tile_pos_end(tile_pos.x + grid_step, tile_pos.y + grid_step); + + draw_list_->AddRectFilled(tile_pos, tile_pos_end, + IM_COL32(255, 0, 255, 255)); + } +} + void Canvas::DrawGrid(float grid_step, int tile_id_offset) { // Draw grid + all lines in the canvas draw_list_->PushClipRect(canvas_p0_, canvas_p1_, true); @@ -678,17 +691,7 @@ void Canvas::DrawGrid(float grid_step, int tile_id_offset) { grid_step *= global_scale_; // Apply global scale to grid step DrawGridLines(grid_step); - - if (highlight_tile_id != -1) { - int tile_x = highlight_tile_id % 8; - int tile_y = highlight_tile_id / 8; - ImVec2 tile_pos(canvas_p0_.x + scrolling_.x + tile_x * grid_step, - canvas_p0_.y + scrolling_.y + tile_y * grid_step); - ImVec2 tile_pos_end(tile_pos.x + grid_step, tile_pos.y + grid_step); - - draw_list_->AddRectFilled(tile_pos, tile_pos_end, - IM_COL32(255, 0, 255, 255)); - } + DrawCustomHighlight(grid_step); if (enable_hex_tile_labels_) { // Draw the hex ID of the tile in the center of the tile square @@ -702,7 +705,7 @@ void Canvas::DrawGrid(float grid_step, int tile_id_offset) { std::string hex_id = absl::StrFormat("%02X", tile_id); draw_list_->AddText(ImVec2(canvas_p0_.x + x + (grid_step / 2) - 4, canvas_p0_.y + y + (grid_step / 2) - 4), - IM_COL32(255, 255, 255, 255), hex_id.data()); + kWhiteColor, hex_id.data()); } } } @@ -724,7 +727,7 @@ void Canvas::DrawGrid(float grid_step, int tile_id_offset) { draw_list_->AddText( ImVec2(canvas_p0_.x + x + (grid_step / 2) - tile_id_offset, canvas_p0_.y + y + (grid_step / 2) - tile_id_offset), - IM_COL32(255, 255, 255, 255), label.data()); + kWhiteColor, label.data()); } } } @@ -738,7 +741,7 @@ void Canvas::DrawOverlay() { draw_list_->AddRect( ImVec2(origin.x + points_[n].x, origin.y + points_[n].y), ImVec2(origin.x + points_[n + 1].x, origin.y + points_[n + 1].y), - IM_COL32(255, 255, 255, 255), 1.0f); + kWhiteColor, 1.0f); } if (!selected_points_.empty()) { @@ -747,7 +750,7 @@ void Canvas::DrawOverlay() { origin.y + selected_points_[n].y), ImVec2(origin.x + selected_points_[n + 1].x + 0x10, origin.y + selected_points_[n + 1].y + 0x10), - IM_COL32(255, 255, 255, 255), 1.0f); + kWhiteColor, 1.0f); } } @@ -799,7 +802,8 @@ void GraphicsBinCanvasPipeline(int width, int height, int tile_size, int num_sheets_to_load, int canvas_id, bool is_loaded, gfx::BitmapTable &graphics_bin) { gui::Canvas canvas; - if (ImGuiID child_id = ImGui::GetID((void *)(intptr_t)canvas_id); + if (ImGuiID child_id = + ImGui::GetID((ImTextureID)(intptr_t)(intptr_t)canvas_id); ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { canvas.DrawBackground(ImVec2(width + 1, num_sheets_to_load * height + 1)); @@ -812,7 +816,7 @@ void GraphicsBinCanvasPipeline(int width, int height, int tile_size, top_left_y = canvas.zero_point().y + height * key; } canvas.draw_list()->AddImage( - (void *)value.texture(), + (ImTextureID)(intptr_t)value.texture(), ImVec2(canvas.zero_point().x + 2, top_left_y), ImVec2(canvas.zero_point().x + 0x100, canvas.zero_point().y + offset)); @@ -839,7 +843,8 @@ void BitmapCanvasPipeline(gui::Canvas &canvas, const gfx::Bitmap &bitmap, }; if (scrollbar) { - if (ImGuiID child_id = ImGui::GetID((void *)(intptr_t)canvas_id); + if (ImGuiID child_id = + ImGui::GetID((ImTextureID)(intptr_t)(intptr_t)canvas_id); ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { draw_canvas(canvas, bitmap, width, height, tile_size, is_loaded); @@ -852,4 +857,4 @@ void BitmapCanvasPipeline(gui::Canvas &canvas, const gfx::Bitmap &bitmap, } // namespace gui } // namespace app -} // namespace yaze \ No newline at end of file +} // namespace yaze diff --git a/src/app/gui/canvas.h b/src/app/gui/canvas.h index 07a5c4f4..5bc77ec5 100644 --- a/src/app/gui/canvas.h +++ b/src/app/gui/canvas.h @@ -1,13 +1,11 @@ #ifndef YAZE_GUI_CANVAS_H #define YAZE_GUI_CANVAS_H -#include "imgui/imgui.h" - -#include #include #include "app/gfx/bitmap.h" #include "app/rom.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -34,34 +32,46 @@ enum class CanvasGridSize { k8x8, k16x16, k32x32, k64x64 }; * handling, tile painting, custom grid, and more. */ class Canvas : public SharedRom { - public: +public: Canvas() = default; - explicit Canvas(const std::string& id, ImVec2 canvas_size) + explicit Canvas(const std::string &id) : canvas_id_(id) { + context_id_ = id + "Context"; + } + explicit Canvas(const std::string &id, ImVec2 canvas_size) : canvas_id_(id), custom_canvas_size_(true), canvas_sz_(canvas_size) { context_id_ = id + "Context"; } - explicit Canvas(const std::string& id, ImVec2 canvas_size, + explicit Canvas(const std::string &id, ImVec2 canvas_size, CanvasGridSize grid_size) : canvas_id_(id), custom_canvas_size_(true), canvas_sz_(canvas_size) { context_id_ = id + "Context"; + SetCanvasGridSize(grid_size); + } + explicit Canvas(const std::string &id, ImVec2 canvas_size, CanvasGridSize grid_size, float global_scale) + : canvas_id_(id), custom_canvas_size_(true), canvas_sz_(canvas_size), global_scale_(global_scale) { + context_id_ = id + "Context"; + SetCanvasGridSize(grid_size); + } + + void SetCanvasGridSize(CanvasGridSize grid_size) { switch (grid_size) { - case CanvasGridSize::k8x8: - custom_step_ = 8.0f; - break; - case CanvasGridSize::k16x16: - custom_step_ = 16.0f; - break; - case CanvasGridSize::k32x32: - custom_step_ = 32.0f; - break; - case CanvasGridSize::k64x64: - custom_step_ = 64.0f; - break; + case CanvasGridSize::k8x8: + custom_step_ = 8.0f; + break; + case CanvasGridSize::k16x16: + custom_step_ = 16.0f; + break; + case CanvasGridSize::k32x32: + custom_step_ = 32.0f; + break; + case CanvasGridSize::k64x64: + custom_step_ = 64.0f; + break; } } - void UpdateColorPainter(gfx::Bitmap& bitmap, const ImVec4& color, - const std::function& event, int tile_size, + void UpdateColorPainter(gfx::Bitmap &bitmap, const ImVec4 &color, + const std::function &event, int tile_size, float scale = 1.0f); void UpdateInfoGrid(ImVec2 bg_size, int tile_size, float scale = 1.0f, @@ -73,16 +83,16 @@ class Canvas : public SharedRom { // Context Menu refers to what happens when the right mouse button is pressed // This routine also handles the scrolling for the canvas. - void DrawContextMenu(gfx::Bitmap* bitmap = nullptr); + void DrawContextMenu(gfx::Bitmap *bitmap = nullptr); // Tile painter shows a preview of the currently selected tile // and allows the user to left click to paint the tile or right // click to select a new tile to paint with. - bool DrawTilePainter(const Bitmap& bitmap, int size, float scale = 1.0f); - bool DrawSolidTilePainter(const ImVec4& color, int size); + bool DrawTilePainter(const Bitmap &bitmap, int size, float scale = 1.0f); + bool DrawSolidTilePainter(const ImVec4 &color, int size); // Draws a tile on the canvas at the specified position - void DrawTileOnBitmap(int tile_size, gfx::Bitmap* bitmap, ImVec4 color); + void DrawTileOnBitmap(int tile_size, gfx::Bitmap *bitmap, ImVec4 color); // Dictates which tile is currently selected based on what the user clicks // in the canvas window. Represented and split apart into a grid of tiles. @@ -93,15 +103,15 @@ class Canvas : public SharedRom { float scale = 1.0f); // Draws the contents of the Bitmap image to the Canvas - void DrawBitmap(const Bitmap& bitmap, int border_offset = 0, + void DrawBitmap(const Bitmap &bitmap, int border_offset = 0, bool ready = true); - void DrawBitmap(const Bitmap& bitmap, int border_offset, float scale); - void DrawBitmap(const Bitmap& bitmap, int x_offset = 0, int y_offset = 0, + void DrawBitmap(const Bitmap &bitmap, int border_offset, float scale); + void DrawBitmap(const Bitmap &bitmap, int x_offset = 0, int y_offset = 0, float scale = 1.0f, int alpha = 255); - void DrawBitmapTable(const BitmapTable& gfx_bin); + void DrawBitmapTable(const BitmapTable &gfx_bin); - void DrawBitmapGroup(std::vector& group, - std::vector& tile16_individual_, + void DrawBitmapGroup(std::vector &group, + std::vector &tile16_individual_, int tile_size, float scale = 1.0f); void DrawOutline(int x, int y, int w, int h); @@ -113,7 +123,7 @@ class Canvas : public SharedRom { void DrawText(std::string text, int x, int y); void DrawGridLines(float grid_step); void DrawGrid(float grid_step = 64.0f, int tile_id_offset = 8); - void DrawOverlay(); // last + void DrawOverlay(); // last void DrawInfoGrid(float grid_step = 64.0f, int tile_id_offset = 8, int label_id = 0); @@ -123,11 +133,12 @@ class Canvas : public SharedRom { int GetTileIdFromMousePos() { int x = mouse_pos_in_canvas_.x; int y = mouse_pos_in_canvas_.y; - int num_columns = canvas_sz_.x / custom_step_; - int num_rows = canvas_sz_.y / custom_step_; + int num_columns = (canvas_sz_.x / global_scale_) / custom_step_; + int num_rows = (canvas_sz_.y / global_scale_) / custom_step_; int tile_id = (x / custom_step_) + (y / custom_step_) * num_columns; + tile_id = tile_id / global_scale_; if (tile_id >= num_columns * num_rows) { - tile_id = -1; // Invalid tile ID + tile_id = -1; // Invalid tile ID } return tile_id; } @@ -135,6 +146,7 @@ class Canvas : public SharedRom { canvas_sz_ = canvas_size; custom_canvas_size_ = true; } + void DrawCustomHighlight(float grid_step); bool IsMouseHovering() const { return is_hovered_; } void ZoomIn() { global_scale_ += 0.25f; } void ZoomOut() { global_scale_ -= 0.25f; } @@ -186,7 +198,7 @@ class Canvas : public SharedRom { auto hover_mouse_pos() const { return mouse_pos_in_canvas_; } - private: +private: bool draggable_ = false; bool is_hovered_ = false; bool enable_grid_ = true; @@ -210,7 +222,7 @@ class Canvas : public SharedRom { std::string canvas_id_ = "Canvas"; std::string context_id_ = "CanvasContext"; - ImDrawList* draw_list_; + ImDrawList *draw_list_; ImVector points_; ImVector> labels_; ImVec2 scrolling_; @@ -226,14 +238,14 @@ class Canvas : public SharedRom { void GraphicsBinCanvasPipeline(int width, int height, int tile_size, int num_sheets_to_load, int canvas_id, - bool is_loaded, BitmapTable& graphics_bin); + bool is_loaded, BitmapTable &graphics_bin); -void BitmapCanvasPipeline(gui::Canvas& canvas, const gfx::Bitmap& bitmap, +void BitmapCanvasPipeline(gui::Canvas &canvas, const gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id); -} // namespace gui -} // namespace app -} // namespace yaze +} // namespace gui +} // namespace app +} // namespace yaze #endif diff --git a/src/app/gui/color.cc b/src/app/gui/color.cc index 55541bed..9e8ea108 100644 --- a/src/app/gui/color.cc +++ b/src/app/gui/color.cc @@ -13,7 +13,7 @@ namespace yaze { namespace app { namespace gui { -ImVec4 ConvertSNESColorToImVec4(const SnesColor& color) { +ImVec4 ConvertSnesColorToImVec4(const SnesColor& color) { return ImVec4(static_cast(color.rgb().x) / 255.0f, static_cast(color.rgb().y) / 255.0f, static_cast(color.rgb().z) / 255.0f, @@ -26,7 +26,7 @@ IMGUI_API bool SnesColorButton(absl::string_view id, SnesColor& color, ImGuiColorEditFlags flags, const ImVec2& size_arg) { // Convert the SNES color values to ImGui color values - ImVec4 displayColor = ConvertSNESColorToImVec4(color); + ImVec4 displayColor = ConvertSnesColorToImVec4(color); // Call the original ImGui::ColorButton with the converted color bool pressed = ImGui::ColorButton(id.data(), displayColor, flags, size_arg); @@ -41,14 +41,14 @@ IMGUI_API bool SnesColorButton(absl::string_view id, SnesColor& color, IMGUI_API bool SnesColorEdit4(absl::string_view label, SnesColor* color, ImGuiColorEditFlags flags) { - ImVec4 displayColor = ConvertSNESColorToImVec4(*color); + ImVec4 displayColor = ConvertSnesColorToImVec4(*color); // Call the original ImGui::ColorEdit4 with the converted color bool pressed = ImGui::ColorEdit4(label.data(), (float*)&displayColor.x, flags); color->set_rgb(displayColor); - color->set_snes(gfx::ConvertRGBtoSNES(displayColor)); + color->set_snes(gfx::ConvertRgbToSnes(displayColor)); return pressed; } diff --git a/src/app/gui/color.h b/src/app/gui/color.h index 6e05a008..8d5134de 100644 --- a/src/app/gui/color.h +++ b/src/app/gui/color.h @@ -18,7 +18,7 @@ using gfx::SnesColor; // A utility function to convert an SnesColor object to an ImVec4 with // normalized color values -ImVec4 ConvertSNESColorToImVec4(const SnesColor& color); +ImVec4 ConvertSnesColorToImVec4(const SnesColor& color); // The wrapper function for ImGui::ColorButton that takes a SnesColor reference IMGUI_API bool SnesColorButton(absl::string_view id, SnesColor& color, diff --git a/src/app/gui/gui.cmake b/src/app/gui/gui.cmake new file mode 100644 index 00000000..60481956 --- /dev/null +++ b/src/app/gui/gui.cmake @@ -0,0 +1,9 @@ +set( + YAZE_GUI_SRC + app/gui/modules/asset_browser.cc + app/gui/canvas.cc + app/gui/input.cc + app/gui/style.cc + app/gui/color.cc + app/gui/zeml.cc +) diff --git a/src/app/gui/input.cc b/src/app/gui/input.cc index 06e39d64..f3e74bce 100644 --- a/src/app/gui/input.cc +++ b/src/app/gui/input.cc @@ -1,20 +1,19 @@ #include "input.h" -#include "ImGuiFileDialog/ImGuiFileDialog.h" -#include "imgui/imgui.h" -#include "imgui/imgui_internal.h" -#include "imgui/misc/cpp/imgui_stdlib.h" - #include #include #include +#include "ImGuiFileDialog/ImGuiFileDialog.h" #include "absl/strings/string_view.h" -#include "app/core/common.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" +#include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" #include "app/gui/color.h" +#include "imgui/imgui.h" +#include "imgui/imgui_internal.h" +#include "imgui/misc/cpp/imgui_stdlib.h" namespace ImGui { @@ -46,7 +45,7 @@ bool InputScalarLeft(const char* label, ImGuiDataType data_type, void* p_data, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) flags |= InputScalar_DefaultCharsFilter(data_type, format); - flags |= ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; + flags |= ImGuiInputTextFlags_AutoSelectAll; bool value_changed = false; // if (p_step == NULL) { @@ -104,8 +103,7 @@ bool InputScalarLeft(const char* label, ImGuiDataType data_type, void* p_data, if (!no_step) { const ImVec2 backup_frame_padding = style.FramePadding; style.FramePadding.x = style.FramePadding.y; - ImGuiButtonFlags button_flags = - ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; + ImGuiButtonFlags button_flags = ImGuiButtonFlags_PressedOnClick; if (flags & ImGuiInputTextFlags_ReadOnly) BeginDisabled(); SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) { @@ -249,6 +247,20 @@ bool ListBox(const char* label, int* current_item, height_in_items); } +bool InputTileInfo(const char* label, gfx::TileInfo* tile_info) { + ImGui::PushID(label); + ImGui::BeginGroup(); + bool changed = false; + changed |= InputHexWord(label, &tile_info->id_); + changed |= InputHexByte("Palette", &tile_info->palette_); + changed |= ImGui::Checkbox("Priority", &tile_info->over_); + changed |= ImGui::Checkbox("Vertical Flip", &tile_info->vertical_mirror_); + changed |= ImGui::Checkbox("Horizontal Flip", &tile_info->horizontal_mirror_); + ImGui::EndGroup(); + ImGui::PopID(); + return changed; +} + ImGuiID GetID(const std::string& id) { return ImGui::GetID(id.c_str()); } void FileDialogPipeline(absl::string_view display_key, diff --git a/src/app/gui/input.h b/src/app/gui/input.h index cd7a024b..caa4d9bb 100644 --- a/src/app/gui/input.h +++ b/src/app/gui/input.h @@ -3,10 +3,6 @@ #define IMGUI_DEFINE_MATH_OPERATORS -#include "imgui/imgui.h" -#include "imgui/misc/cpp/imgui_stdlib.h" -#include "imgui_memory_editor.h" - #include #include #include @@ -15,11 +11,14 @@ #include #include "absl/strings/string_view.h" -#include "app/core/common.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" +#include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" #include "app/gui/color.h" +#include "imgui/imgui.h" +#include "imgui/misc/cpp/imgui_stdlib.h" +#include "imgui_memory_editor.h" namespace yaze { namespace app { @@ -47,6 +46,8 @@ IMGUI_API bool ListBox(const char* label, int* current_item, const std::vector& items, int height_in_items = -1); +bool InputTileInfo(const char* label, gfx::TileInfo* tile_info); + using ItemLabelFlags = enum ItemLabelFlag { Left = 1u << 0u, Right = 1u << 1u, diff --git a/src/app/gui/asset_browser.cc b/src/app/gui/modules/asset_browser.cc similarity index 98% rename from src/app/gui/asset_browser.cc rename to src/app/gui/modules/asset_browser.cc index fe6979e7..a584d648 100644 --- a/src/app/gui/asset_browser.cc +++ b/src/app/gui/modules/asset_browser.cc @@ -10,7 +10,8 @@ using namespace ImGui; const ImGuiTableSortSpecs* AssetObject::s_current_sort_specs = NULL; -void GfxSheetAssetBrowser::Draw(gfx::BitmapManager* bmp_manager) { +void GfxSheetAssetBrowser::Draw( + const std::array& bmp_manager) { PushItemWidth(GetFontSize() * 10); SeparatorText("Contents"); Checkbox("Show Type Overlay", &ShowTypeOverlay); @@ -229,7 +230,7 @@ void GfxSheetAssetBrowser::Draw(gfx::BitmapManager* bmp_manager) { ImU32 label_col = GetColorU32( item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled); draw_list->AddImage( - (void*)bmp_manager->mutable_bitmap(item_data->ID)->texture(), + (ImTextureID)(intptr_t)bmp_manager[item_data->ID].texture(), box_min, box_max, ImVec2(0, 0), ImVec2(1, 1), GetColorU32(ImVec4(1, 1, 1, 1))); draw_list->AddText(ImVec2(box_min.x, box_max.y - GetFontSize()), diff --git a/src/app/gui/asset_browser.h b/src/app/gui/modules/asset_browser.h similarity index 96% rename from src/app/gui/asset_browser.h rename to src/app/gui/modules/asset_browser.h index ac79930a..46f57c58 100644 --- a/src/app/gui/asset_browser.h +++ b/src/app/gui/modules/asset_browser.h @@ -1,11 +1,12 @@ #ifndef YAZE_APP_GUI_ASSET_BROWSER_H #define YAZE_APP_GUI_ASSET_BROWSER_H -#include "imgui/imgui.h" - +#include #include #include "app/gfx/bitmap.h" +#include "app/rom.h" +#include "imgui/imgui.h" #define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) #define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) @@ -112,7 +113,7 @@ struct AssetObject { } // Compare function to be used by qsort() - static int __cdecl CompareWithSortSpecs(const void* lhs, const void* rhs) { + static int CompareWithSortSpecs(const void* lhs, const void* rhs) { const AssetObject* a = (const AssetObject*)lhs; const AssetObject* b = (const AssetObject*)rhs; for (int n = 0; n < s_current_sort_specs->SpecsCount; n++) { @@ -187,9 +188,9 @@ struct GfxSheetAssetBrowser { int LayoutLineCount = 0; bool Initialized = false; - void Initialize(gfx::BitmapManager* bmp_manager) { + void Initialize(const std::array& bmp_manager) { // Load the assets - for (int i = 0; i < bmp_manager->size(); i++) { + for (int i = 0; i < kNumGfxSheets; i++) { Items.push_back(UnsortedAsset(i)); } Initialized = true; @@ -238,7 +239,7 @@ struct GfxSheetAssetBrowser { LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f); } - void Draw(gfx::BitmapManager* bmp_manager); + void Draw(const std::array& bmp_manager); }; } // namespace gui diff --git a/src/app/gui/style.cc b/src/app/gui/style.cc index c9639717..0726dff5 100644 --- a/src/app/gui/style.cc +++ b/src/app/gui/style.cc @@ -7,10 +7,11 @@ namespace yaze { namespace app { namespace gui { -void BeginWindowWithDisplaySettings(const char* id, bool* active, - const ImVec2& size, +// TODO: Add more display settings to popup windows. +void BeginWindowWithDisplaySettings(const char *id, bool *active, + const ImVec2 &size, ImGuiWindowFlags flags) { - ImGuiStyle* ref = &ImGui::GetStyle(); + ImGuiStyle *ref = &ImGui::GetStyle(); static float childBgOpacity = 0.75f; auto color = ref->Colors[ImGuiCol_WindowBg]; @@ -44,42 +45,45 @@ void BeginNoPadding() { } void EndNoPadding() { ImGui::PopStyleVar(2); } -void BeginChildWithScrollbar(const char* str_id) { +void BeginChildWithScrollbar(const char *str_id) { ImGui::BeginChild(str_id, ImGui::GetContentRegionAvail(), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); } void BeginChildBothScrollbars(int id) { - ImGuiID child_id = ImGui::GetID((void*)(intptr_t)id); + ImGuiID child_id = ImGui::GetID((void *)(intptr_t)id); ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); } -void DrawDisplaySettings(ImGuiStyle* ref) { +void DrawDisplaySettings(ImGuiStyle *ref) { // You can pass in a reference ImGuiStyle structure to compare to, revert to // and save to (without a reference style pointer, we will use one compared // locally as a reference) - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle &style = ImGui::GetStyle(); static ImGuiStyle ref_saved_style; // Default to using internal storage as reference static bool init = true; - if (init && ref == NULL) ref_saved_style = style; + if (init && ref == NULL) + ref_saved_style = style; init = false; - if (ref == NULL) ref = &ref_saved_style; + if (ref == NULL) + ref = &ref_saved_style; ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); - if (ImGui::ShowStyleSelector("Colors##Selector")) ref_saved_style = style; + if (ImGui::ShowStyleSelector("Colors##Selector")) + ref_saved_style = style; ImGui::ShowFontSelector("Fonts##Selector"); // Simplified Settings (expose floating-pointer border sizes as boolean // representing 0.0f or 1.0f) if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) - style.GrabRounding = style.FrameRounding; // Make GrabRounding always the - // same value as FrameRounding + style.GrabRounding = style.FrameRounding; // Make GrabRounding always the + // same value as FrameRounding { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { @@ -102,9 +106,11 @@ void DrawDisplaySettings(ImGuiStyle* ref) { } // Save/Revert button - if (ImGui::Button("Save Ref")) *ref = ref_saved_style = style; + if (ImGui::Button("Save Ref")) + *ref = ref_saved_style = style; ImGui::SameLine(); - if (ImGui::Button("Revert Ref")) style = *ref; + if (ImGui::Button("Revert Ref")) + style = *ref; ImGui::SameLine(); ImGui::Separator(); @@ -112,16 +118,17 @@ void DrawDisplaySettings(ImGuiStyle* ref) { if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) { if (ImGui::BeginTabItem("Sizes")) { ImGui::SeparatorText("Main"); - ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, + ImGui::SliderFloat2("WindowPadding", (float *)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, + ImGui::SliderFloat2("FramePadding", (float *)&style.FramePadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, + ImGui::SliderFloat2("ItemSpacing", (float *)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, + ImGui::SliderFloat2("ItemInnerSpacing", (float *)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, - 0.0f, 10.0f, "%.0f"); + ImGui::SliderFloat2("TouchExtraPadding", + (float *)&style.TouchExtraPadding, 0.0f, 10.0f, + "%.0f"); ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, @@ -160,32 +167,32 @@ void DrawDisplaySettings(ImGuiStyle* ref) { "%.0f"); ImGui::SeparatorText("Tables"); - ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, + ImGui::SliderFloat2("CellPadding", (float *)&style.CellPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f); ImGui::SeparatorText("Widgets"); - ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, + ImGui::SliderFloat2("WindowTitleAlign", (float *)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); - ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, + ImGui::Combo("ColorButtonPosition", (int *)&style.ColorButtonPosition, "Left\0Right\0"); - ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, + ImGui::SliderFloat2("ButtonTextAlign", (float *)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ImGui::SliderFloat2("SelectableTextAlign", - (float*)&style.SelectableTextAlign, 0.0f, 1.0f, + (float *)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); ImGui::SliderFloat2("SeparatorTextAlign", - (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, + (float *)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("SeparatorTextPadding", - (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, + (float *)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); @@ -194,7 +201,7 @@ void DrawDisplaySettings(ImGuiStyle* ref) { for (int n = 0; n < 2; n++) if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav")) { - ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse + ImGuiHoveredFlags *p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav; ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone); @@ -211,7 +218,7 @@ void DrawDisplaySettings(ImGuiStyle* ref) { ImGui::SeparatorText("Misc"); ImGui::SliderFloat2("DisplaySafeAreaPadding", - (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, + (float *)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); @@ -228,8 +235,8 @@ void DrawDisplaySettings(ImGuiStyle* ref) { ImGui::LogToTTY(); ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); for (int i = 0; i < ImGuiCol_COUNT; i++) { - const ImVec4& col = style.Colors[i]; - const char* name = ImGui::GetStyleColorName(i); + const ImVec4 &col = style.Colors[i]; + const char *name = ImGui::GetStyleColorName(i); if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) ImGui::LogText( @@ -274,10 +281,11 @@ void DrawDisplaySettings(ImGuiStyle* ref) { ImGuiWindowFlags_NavFlattened); ImGui::PushItemWidth(ImGui::GetFontSize() * -12); for (int i = 0; i < ImGuiCol_COUNT; i++) { - const char* name = ImGui::GetStyleColorName(i); - if (!filter.PassFilter(name)) continue; + const char *name = ImGui::GetStyleColorName(i); + if (!filter.PassFilter(name)) + continue; ImGui::PushID(i); - ImGui::ColorEdit4("##color", (float*)&style.Colors[i], + ImGui::ColorEdit4("##color", (float *)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) { // Tips: in a real user application, you may want to merge and use @@ -304,8 +312,8 @@ void DrawDisplaySettings(ImGuiStyle* ref) { } if (ImGui::BeginTabItem("Fonts")) { - ImGuiIO& io = ImGui::GetIO(); - ImFontAtlas* atlas = io.Fonts; + ImGuiIO &io = ImGui::GetIO(); + ImFontAtlas *atlas = io.Fonts; ImGui::ShowFontAtlas(atlas); // Post-baking font scaling. Note that this is NOT the nice way of @@ -320,11 +328,11 @@ void DrawDisplaySettings(ImGuiStyle* ref) { if (ImGui::DragFloat( "window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", - ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + ImGuiSliderFlags_AlwaysClamp)) // Scale only this window ImGui::SetWindowFontScale(window_scale); ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", - ImGuiSliderFlags_AlwaysClamp); // Scale everything + ImGuiSliderFlags_AlwaysClamp); // Scale everything ImGui::PopItemWidth(); ImGui::EndTabItem(); @@ -352,11 +360,12 @@ void DrawDisplaySettings(ImGuiStyle* ref) { &style.CircleTessellationMaxError, 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); const bool show_samples = ImGui::IsItemActive(); - if (show_samples) ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); + if (show_samples) + ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); if (show_samples && ImGui::BeginTooltip()) { ImGui::TextUnformatted("(R = radius, N = number of segments)"); ImGui::Spacing(); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x; for (int n = 0; n < 8; n++) { const float RAD_MIN = 5.0f; @@ -393,10 +402,10 @@ void DrawDisplaySettings(ImGuiStyle* ref) { ImGui::SameLine(); ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, - "%.2f"); // Not exposing zero here so user doesn't - // "lose" the UI (zero alpha clips all - // widgets). But application code could have a - // toggle to switch between zero and non-zero. + "%.2f"); // Not exposing zero here so user doesn't + // "lose" the UI (zero alpha clips all + // widgets). But application code could have a + // toggle to switch between zero and non-zero. ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); @@ -412,15 +421,16 @@ void DrawDisplaySettings(ImGuiStyle* ref) { ImGui::PopItemWidth(); } -void TextWithSeparators(const absl::string_view& text) { +void TextWithSeparators(const absl::string_view &text) { ImGui::Separator(); ImGui::Text("%s", text.data()); ImGui::Separator(); } +// TODO: Make the ColorsYaze style into a configuration file. void ColorsYaze() { - ImGuiStyle* style = &ImGui::GetStyle(); - ImVec4* colors = style->Colors; + ImGuiStyle *style = &ImGui::GetStyle(); + ImVec4 *colors = style->Colors; style->WindowPadding = ImVec2(10.f, 10.f); style->FramePadding = ImVec2(10.f, 2.f); @@ -506,7 +516,7 @@ void ColorsYaze() { colors[ImGuiCol_TableHeaderBg] = alttpDarkGreen; colors[ImGuiCol_TableBorderStrong] = alttpMidGreen; colors[ImGuiCol_TableBorderLight] = - ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here + ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); @@ -517,11 +527,42 @@ void ColorsYaze() { colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); } -void RenderTabItem(const std::string& title, - const std::function& render_func) { - if (ImGui::BeginTabItem(title.c_str())) { - render_func(); - ImGui::EndTabItem(); +void DrawBitmapViewer(const std::vector &bitmaps, float scale, + int ¤t_bitmap_id) { + if (bitmaps.empty()) { + ImGui::Text("No bitmaps available."); + return; + } + + // Display the current bitmap index and total count. + ImGui::Text("Viewing Bitmap %d / %zu", current_bitmap_id + 1, bitmaps.size()); + + // Buttons to navigate through bitmaps. + if (ImGui::Button("<- Prev")) { + if (current_bitmap_id > 0) { + --current_bitmap_id; + } + } + ImGui::SameLine(); + if (ImGui::Button("Next ->")) { + if (current_bitmap_id < bitmaps.size() - 1) { + ++current_bitmap_id; + } + } + + // Display the current bitmap. + const gfx::Bitmap ¤t_bitmap = bitmaps[current_bitmap_id]; + // Assuming Bitmap has a function to get its texture ID, and width and + // height. + ImTextureID tex_id = (ImTextureID)(intptr_t)current_bitmap.texture(); + ImVec2 size(current_bitmap.width() * scale, current_bitmap.height() * scale); + // ImGui::Image(tex_id, size); + + // Scroll if the image is larger than the display area. + if (ImGui::BeginChild("BitmapScrollArea", ImVec2(0, 0), false, + ImGuiWindowFlags_HorizontalScrollbar)) { + ImGui::Image(tex_id, size); + ImGui::EndChild(); } } @@ -529,7 +570,7 @@ void RenderTabItem(const std::string& title, // 65816 LanguageDefinition // ============================================================================ -static const char* const kKeywords[] = { +static const char *const kKeywords[] = { "ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL", "BRA", "BRL", "BVC", "BVS", "CLC", "CLD", "CLI", "CLV", "CMP", "CPX", "CPY", "DEC", "DEX", "DEY", "EOR", "INC", "INX", @@ -541,7 +582,7 @@ static const char* const kKeywords[] = { "TRB", "TSB", "TSC", "TSX", "TXA", "TXS", "TXY", "TYA", "TYX", "WAI", "WDM", "XBA", "XCE", "ORG", "LOROM", "HIROM", "NAMESPACE", "DB"}; -static const char* const kIdentifiers[] = { +static const char *const kIdentifiers[] = { "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", @@ -554,9 +595,10 @@ static const char* const kIdentifiers[] = { TextEditor::LanguageDefinition GetAssemblyLanguageDef() { TextEditor::LanguageDefinition language_65816; - for (auto& k : kKeywords) language_65816.mKeywords.emplace(k); + for (auto &k : kKeywords) + language_65816.mKeywords.emplace(k); - for (auto& k : kIdentifiers) { + for (auto &k : kIdentifiers) { TextEditor::Identifier id; id.mDeclaration = "Built-in function"; language_65816.mIdentifiers.insert(std::make_pair(std::string(k), id)); @@ -606,6 +648,6 @@ TextEditor::LanguageDefinition GetAssemblyLanguageDef() { return language_65816; } -} // namespace gui -} // namespace app -} // namespace yaze +} // namespace gui +} // namespace app +} // namespace yaze diff --git a/src/app/gui/style.h b/src/app/gui/style.h index 0fed9c1a..051a1f88 100644 --- a/src/app/gui/style.h +++ b/src/app/gui/style.h @@ -1,24 +1,23 @@ #ifndef YAZE_APP_CORE_STYLE_H #define YAZE_APP_CORE_STYLE_H -#include "ImGuiColorTextEdit/TextEditor.h" -#include "imgui/imgui.h" -#include "imgui/misc/cpp/imgui_stdlib.h" - #include #include +#include "ImGuiColorTextEdit/TextEditor.h" #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "app/core/constants.h" #include "app/gfx/bitmap.h" +#include "imgui/imgui.h" +#include "imgui/misc/cpp/imgui_stdlib.h" namespace yaze { namespace app { namespace gui { -void BeginWindowWithDisplaySettings(const char* id, bool* active, - const ImVec2& size = ImVec2(0, 0), +void BeginWindowWithDisplaySettings(const char *id, bool *active, + const ImVec2 &size = ImVec2(0, 0), ImGuiWindowFlags flags = 0); void EndWindowWithDisplaySettings(); @@ -29,72 +28,24 @@ void EndPadding(); void BeginNoPadding(); void EndNoPadding(); -void BeginChildWithScrollbar(const char* str_id); +void BeginChildWithScrollbar(const char *str_id); void BeginChildBothScrollbars(int id); -void DrawDisplaySettings(ImGuiStyle* ref = nullptr); +void DrawDisplaySettings(ImGuiStyle *ref = nullptr); -void TextWithSeparators(const absl::string_view& text); +void TextWithSeparators(const absl::string_view &text); void ColorsYaze(); TextEditor::LanguageDefinition GetAssemblyLanguageDef(); -void RenderTabItem(const std::string& title, - const std::function& render_func); - -class BitmapViewer { - public: - BitmapViewer() : current_bitmap_index_(0) {} - - void Display(const std::vector& bitmaps, float scale = 1.0f) { - if (bitmaps.empty()) { - ImGui::Text("No bitmaps available."); - return; - } - - // Display the current bitmap index and total count. - ImGui::Text("Viewing Bitmap %d / %zu", current_bitmap_index_ + 1, - bitmaps.size()); - - // Buttons to navigate through bitmaps. - if (ImGui::Button("<- Prev")) { - if (current_bitmap_index_ > 0) { - --current_bitmap_index_; - } - } - ImGui::SameLine(); - if (ImGui::Button("Next ->")) { - if (current_bitmap_index_ < bitmaps.size() - 1) { - ++current_bitmap_index_; - } - } - - // Display the current bitmap. - const gfx::Bitmap& current_bitmap = bitmaps[current_bitmap_index_]; - // Assuming Bitmap has a function to get its texture ID, and width and - // height. - ImTextureID tex_id = current_bitmap.texture(); - ImVec2 size(current_bitmap.width() * scale, - current_bitmap.height() * scale); - // ImGui::Image(tex_id, size); - - // Scroll if the image is larger than the display area. - if (ImGui::BeginChild("BitmapScrollArea", ImVec2(0, 0), false, - ImGuiWindowFlags_HorizontalScrollbar)) { - ImGui::Image(tex_id, size); - ImGui::EndChild(); - } - } - - private: - int current_bitmap_index_; -}; +void DrawBitmapViewer(const std::vector &bitmaps, float scale, + int ¤t_bitmap); // ============================================================================ -static const char* ExampleNames[] = { +static const char *ExampleNames[] = { "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", "Bitter Gourd", "Bok Choy", @@ -116,7 +67,7 @@ struct MultiSelectWithClipper { ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; - ImGuiMultiSelectIO* ms_io = + ImGuiMultiSelectIO *ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); selection.ApplyRequests(ms_io); @@ -124,7 +75,7 @@ struct MultiSelectWithClipper { clipper.Begin(ITEMS_COUNT); if (ms_io->RangeSrcItem != -1) clipper.IncludeItemByIndex( - (int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped. + (int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped. while (clipper.Step()) { for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++) { char label[64]; @@ -144,8 +95,8 @@ struct MultiSelectWithClipper { } }; -} // namespace gui -} // namespace app -} // namespace yaze +} // namespace gui +} // namespace app +} // namespace yaze #endif diff --git a/src/app/gui/zeml.cc b/src/app/gui/zeml.cc index f7e3b9ab..5e94e097 100644 --- a/src/app/gui/zeml.cc +++ b/src/app/gui/zeml.cc @@ -1,8 +1,6 @@ #include "app/gui/zeml.h" -#include "imgui/imgui.h" - #include #include #include @@ -11,9 +9,10 @@ #include #include +#include "app/core/platform/file_path.h" #include "app/gui/canvas.h" #include "app/gui/input.h" -#include "app/core/platform/file_path.h" +#include "imgui/imgui.h" namespace yaze { namespace app { @@ -592,16 +591,17 @@ std::string LoadFile(const std::string& filename) { std::string fileContents; const std::string kPath = "assets/layouts/"; - #ifdef __APPLE__ - #if TARGET_OS_IOS == 1 - const std::string kBundlePath = GetBundleResourcePath(); - std::ifstream file(kBundlePath + filename); - #else - std::ifstream file(kPath + filename); - #endif - #else - std::ifstream file(kPath + filename); - #endif +#ifdef __APPLE__ +#if TARGET_OS_IOS == 1 + const std::string kBundlePath = core::GetBundleResourcePath(); + std::ifstream file(kBundlePath + filename); +#else + const std::string kBundlePath = core::GetBundleResourcePath(); + std::ifstream file(kBundlePath + "Contents/Resources/layouts/" + filename); +#endif +#else + std::ifstream file(kPath + filename); +#endif if (file.is_open()) { std::string line; diff --git a/src/app/gui/zeml.h b/src/app/gui/zeml.h index dbb9c396..2ba4f594 100644 --- a/src/app/gui/zeml.h +++ b/src/app/gui/zeml.h @@ -5,10 +5,8 @@ #include #include -#include #include #include -#include #include #include diff --git a/src/app/yaze.cc b/src/app/main.cc similarity index 59% rename from src/app/yaze.cc rename to src/app/main.cc index 6017227e..80f827f5 100644 --- a/src/app/yaze.cc +++ b/src/app/main.cc @@ -32,31 +32,23 @@ int main(int argc, char** argv) { rom_filename = argv[1]; } +#ifdef __APPLE__ + yaze_run_cocoa_app_delegate(rom_filename.c_str()); + return EXIT_SUCCESS; +#endif + core::Controller controller; EXIT_IF_ERROR(controller.OnEntry(rom_filename)) -#ifdef __APPLE__ - InitializeCocoa(); -#endif - try { - while (controller.IsActive()) { - controller.OnInput(); - if (auto status = controller.OnLoad(); !status.ok()) { - std::cerr << status.message() << std::endl; - break; - } - controller.DoRender(); + while (controller.IsActive()) { + controller.OnInput(); + if (auto status = controller.OnLoad(); !status.ok()) { + std::cerr << status.message() << std::endl; + break; } - controller.OnExit(); - } catch (const std::bad_alloc& e) { - std::cerr << "Memory allocation failed: " << e.what() << std::endl; - return EXIT_FAILURE; - } catch (const std::exception& e) { - std::cerr << "Exception: " << e.what() << std::endl; - return EXIT_FAILURE; - } catch (...) { - std::cerr << "Unknown exception" << std::endl; - return EXIT_FAILURE; + controller.DoRender(); } + controller.OnExit(); + return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/src/app/rom.cc b/src/app/rom.cc index b0007665..220b65ce 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -1,44 +1,54 @@ #include "rom.h" -#include // for remove -#include // for system_clock -#include // for size_t -#include // for uint32_t, uint8_t -#include // for memcpy -#include // for ctime -#include // for copy_options, copy_options... -#include // for string, fstream, ifstream -#include // for stack -#include // for hash, operator==, char_traits -#include // for unordered_map, operator!= -#include // for tuple_element<>::type -#include // for vector, vector<>::value_type +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "absl/container/flat_hash_map.h" // for flat_hash_map, BitMask -#include "absl/status/status.h" // for OkStatus, InternalError -#include "absl/status/statusor.h" // for StatusOr -#include "absl/strings/str_cat.h" // for StrCat -#include "absl/strings/string_view.h" // for string_view, operator== -#include "app/core/constants.h" // for Bytes, ASSIGN_OR_RETURN -#include "app/gfx/bitmap.h" // for Bitmap, BitmapTable -#include "app/gfx/compression.h" // for DecompressV2 -#include "app/gfx/snes_color.h" // for SNESColor -#include "app/gfx/snes_palette.h" // for PaletteGroup -#include "app/gfx/snes_tile.h" // for SnesTo8bppSheet +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "app/core/constants.h" +#include "app/core/platform/renderer.h" +#include "app/gfx/compression.h" +#include "app/gfx/snes_color.h" +#include "app/gfx/snes_palette.h" +#include "app/gfx/snes_tile.h" namespace yaze { namespace app { -absl::StatusOr Rom::Load2BppGraphics() { - Bytes sheet; +using core::Renderer; +constexpr int Uncompressed3BPPSize = 0x0600; + +namespace { +int GetGraphicsAddress(const uchar *data, uint8_t addr, uint32_t ptr1, + uint32_t ptr2, uint32_t ptr3) { + return core::SnesToPc(core::AddressFromBytes( + data[ptr1 + addr], data[ptr2 + addr], data[ptr3 + addr])); +} +} // namespace + +absl::StatusOr> Rom::Load2BppGraphics() { + std::vector sheet; const uint8_t sheets[] = {113, 114, 218, 219, 220, 221}; - for (const auto& sheet_id : sheets) { - auto offset = GetGraphicsAddress(data(), sheet_id); + for (const auto &sheet_id : sheets) { + auto offset = GetGraphicsAddress(data(), sheet_id, + version_constants().kOverworldGfxPtr1, + version_constants().kOverworldGfxPtr2, + version_constants().kOverworldGfxPtr3); ASSIGN_OR_RETURN(auto decomp_sheet, gfx::lc_lz2::DecompressV2(data(), offset)) auto converted_sheet = gfx::SnesTo8bppSheet(decomp_sheet, 2); - for (const auto& each_pixel : converted_sheet) { + for (const auto &each_pixel : converted_sheet) { sheet.push_back(each_pixel); } } @@ -46,79 +56,76 @@ absl::StatusOr Rom::Load2BppGraphics() { } absl::Status Rom::LoadLinkGraphics() { - const auto link_gfx_offset = 0x80000; // $10:8000 - const auto link_gfx_length = 0x800; // 0x4000 or 0x7000? - link_palette_ = palette_groups_.armors[0]; + const uint32_t kLinkGfxOffset = 0x80000; // $10:8000 + const uint16_t kLinkGfxLength = 0x800; // 0x4000 or 0x7000? // Load Links graphics from the ROM - for (int i = 0; i < 14; i++) { + for (uint32_t i = 0; i < kNumLinkSheets; i++) { ASSIGN_OR_RETURN( auto link_sheet_data, - ReadByteVector(/*offset=*/link_gfx_offset + (i * link_gfx_length), - /*length=*/link_gfx_length)) - // auto link_sheet_8bpp = gfx::SnesTo8bppSheet(link_sheet_data, /*bpp=*/4); - // Convert to 3bpp, then from 3bpp to 8bpp before creating bitmap. - auto link_sheet_3bpp = gfx::Convert4bppTo3bpp(link_sheet_data); - auto link_sheet_8bpp = gfx::SnesTo8bppSheet(link_sheet_3bpp, /*bpp=*/3); - link_graphics_[i].Create(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, link_sheet_8bpp); - RETURN_IF_ERROR( - link_graphics_[i].ApplyPaletteWithTransparent(link_palette_, 0)); - RenderBitmap(&link_graphics_[i]); + ReadByteVector(/*offset=*/kLinkGfxOffset + (i * kLinkGfxLength), + /*length=*/kLinkGfxLength)) + auto link_sheet_8bpp = gfx::SnesTo8bppSheet(link_sheet_data, /*bpp=*/4); + link_graphics_[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight, + gfx::kTilesheetDepth, link_sheet_8bpp); + RETURN_IF_ERROR(link_graphics_[i].ApplyPalette(palette_groups_.armors[0]);) + Renderer::GetInstance().RenderBitmap(&link_graphics_[i]); } - return absl::OkStatus(); } -absl::Status Rom::LoadAllGraphicsData() { - constexpr uint32_t kNumGfxSheets = 223; - Bytes sheet; +absl::Status Rom::LoadAllGraphicsData(bool defer_render) { + std::vector sheet; bool bpp3 = false; - for (int i = 0; i < kNumGfxSheets; i++) { + for (uint32_t i = 0; i < kNumGfxSheets; i++) { if (i >= 115 && i <= 126) { // uncompressed sheets - sheet.resize(core::Uncompressed3BPPSize); - auto offset = GetGraphicsAddress(data(), i); - for (int j = 0; j < core::Uncompressed3BPPSize; j++) { + sheet.resize(Uncompressed3BPPSize); + auto offset = + GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1, + version_constants().kOverworldGfxPtr2, + version_constants().kOverworldGfxPtr3); + for (int j = 0; j < Uncompressed3BPPSize; j++) { sheet[j] = rom_data_[j + offset]; } bpp3 = true; } else if (i == 113 || i == 114 || i >= 218) { bpp3 = false; } else { - auto offset = GetGraphicsAddress(data(), i); - ASSIGN_OR_RETURN(sheet, gfx::lc_lz2::DecompressV2(data(), offset)) + auto offset = + GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1, + version_constants().kOverworldGfxPtr2, + version_constants().kOverworldGfxPtr3); + ASSIGN_OR_RETURN(sheet, + gfx::lc_lz2::DecompressV2(rom_data_.data(), offset)) bpp3 = true; } if (bpp3) { auto converted_sheet = gfx::SnesTo8bppSheet(sheet, 3); - if (flags()->kUseBitmapManager) { - graphics_manager_.LoadBitmap(i, converted_sheet, core::kTilesheetWidth, - core::kTilesheetHeight, - core::kTilesheetDepth); + graphics_sheets_[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight, + gfx::kTilesheetDepth, converted_sheet); + if (graphics_sheets_[i].is_active()) { if (i > 115) { // Apply sprites palette - RETURN_IF_ERROR(graphics_manager_[i].ApplyPaletteWithTransparent( + RETURN_IF_ERROR(graphics_sheets_[i].ApplyPaletteWithTransparent( palette_groups_.global_sprites[0], 0)); } else { - RETURN_IF_ERROR(graphics_manager_[i].ApplyPaletteWithTransparent( + RETURN_IF_ERROR(graphics_sheets_[i].ApplyPaletteWithTransparent( palette_groups_.dungeon_main[0], 0)); } - graphics_manager_[i].CreateTexture(renderer_); } - graphics_bin_[i] = - gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, converted_sheet); - graphics_bin_.at(i).CreateTexture(renderer_); - if (flags()->kUseBitmapManager) { - for (int j = 0; j < graphics_manager_[i].size(); ++j) { - graphics_buffer_.push_back(graphics_manager_[i].at(j)); - } + if (!defer_render) { + graphics_sheets_[i].CreateTexture(Renderer::GetInstance().renderer()); } + + for (int j = 0; j < graphics_sheets_[i].size(); ++j) { + graphics_buffer_.push_back(graphics_sheets_[i].at(j)); + } + } else { - for (int j = 0; j < graphics_bin_[0].size(); ++j) { + for (int j = 0; j < graphics_sheets_[0].size(); ++j) { graphics_buffer_.push_back(0xFF); } } @@ -126,92 +133,137 @@ absl::Status Rom::LoadAllGraphicsData() { return absl::OkStatus(); } -absl::Status Rom::LoadFromFile(const std::string& filename, bool z3_load) { - std::string full_filename = std::filesystem::absolute(filename).string(); - if (full_filename.empty()) { +absl::Status Rom::SaveAllGraphicsData() { + for (int i = 0; i < kNumGfxSheets; i++) { + if (graphics_sheets_[i].is_active()) { + int from_bpp = 8; + int to_bpp = 3; + std::vector final_data; + bool compressed = true; + if (i >= 115 && i <= 126) { + to_bpp = 3; + compressed = false; + } else if (i == 113 || i == 114 || i >= 218) { + to_bpp = 2; + } + + auto sheet_data = graphics_sheets_[i].vector(); + final_data = gfx::ConvertBpp(sheet_data, from_bpp, to_bpp); + if (compressed) { + ASSIGN_OR_RETURN( + final_data, + gfx::lc_lz2::CompressV2(final_data.data(), 0, final_data.size())); + } + auto offset = + GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1, + version_constants().kOverworldGfxPtr2, + version_constants().kOverworldGfxPtr3); + std::copy(final_data.begin(), final_data.end(), + rom_data_.begin() + offset); + } + } + return absl::OkStatus(); +} + +absl::Status Rom::LoadFromFile(const std::string &filename, bool z3_load) { + if (filename.empty()) { return absl::InvalidArgumentError( "Could not load ROM: parameter `filename` is empty."); } - // Set filename + std::string full_filename = std::filesystem::absolute(filename).string(); filename_ = full_filename; - // Open file std::ifstream file(filename_, std::ios::binary); if (!file.is_open()) { - return absl::InternalError( + return absl::NotFoundError( absl::StrCat("Could not open ROM file: ", filename_)); } // Get file size and resize rom_data_ try { size_ = std::filesystem::file_size(filename_); - } catch (const std::filesystem::filesystem_error& e) { - return absl::InternalError( - absl::StrCat("Could not get file size: ", filename_, " - ", e.what())); + } catch (const std::filesystem::filesystem_error &e) { + // Try to get the file size from the open file stream + file.seekg(0, std::ios::end); + if (!file) { + return absl::InternalError(absl::StrCat( + "Could not get file size: ", filename_, " - ", e.what())); + } + size_ = file.tellg(); } rom_data_.resize(size_); // Read file into rom_data_ - file.read(reinterpret_cast(rom_data_.data()), size_); - - // Check if the sROM has a header - constexpr size_t baseROMSize = 1048576; // 1MB - constexpr size_t headerSize = 0x200; // 512 bytes - if (size_ % baseROMSize == headerSize) { - std::cout << "ROM has a header" << std::endl; - has_header_ = true; - } - - // Remove header if present - if (has_header_) { - auto header = - std::vector(rom_data_.begin(), rom_data_.begin() + 0x200); - rom_data_.erase(rom_data_.begin(), rom_data_.begin() + 0x200); - size_ -= 0x200; - } - - // Close file + file.read(reinterpret_cast(rom_data_.data()), size_); file.close(); - // Load Zelda 3 specific data if requested - if (z3_load) { - // Copy ROM title - constexpr uint32_t kTitleStringOffset = 0x7FC0; - constexpr uint32_t kTitleStringLength = 20; - memcpy(title_, rom_data_.data() + kTitleStringOffset, kTitleStringLength); - if (rom_data_[kTitleStringOffset + 0x19] == 0) { - version_ = Z3_Version::JP; - } else { - version_ = Z3_Version::US; - } - RETURN_IF_ERROR(gfx::LoadAllPalettes(rom_data_, palette_groups_)); - LoadGfxGroups(); - } + // Set is_loaded_ flag and return success + is_loaded_ = true; - // Expand the ROM data to 2MB without changing the data in the first 1MB - rom_data_.resize(baseROMSize * 2); - size_ = baseROMSize * 2; + if (z3_load) { + RETURN_IF_ERROR(LoadZelda3()); + } // Set up the resource labels std::string resource_label_filename = absl::StrFormat("%s.labels", filename); resource_label_manager_.LoadLabels(resource_label_filename); - - // Set is_loaded_ flag and return success - is_loaded_ = true; return absl::OkStatus(); } -absl::Status Rom::LoadFromPointer(uchar* data, size_t length) { - if (!data) +absl::Status Rom::LoadFromPointer(uchar *data, size_t length, bool z3_load) { + if (!data || length == 0) return absl::InvalidArgumentError( "Could not load ROM: parameter `data` is empty."); - for (int i = 0; i < length; ++i) rom_data_.push_back(data[i]); + if (!palette_groups_.empty()) palette_groups_.clear(); + if (rom_data_.size() < length) rom_data_.resize(length); + + std::copy(data, data + length, rom_data_.begin()); + size_ = length; + is_loaded_ = true; + + if (z3_load) { + RETURN_IF_ERROR(LoadZelda3()); + } + return absl::OkStatus(); +} + +absl::Status Rom::LoadZelda3() { + // Check if the ROM has a header + constexpr size_t kBaseRomSize = 1048576; // 1MB + constexpr size_t kHeaderSize = 0x200; // 512 bytes + if (size_ % kBaseRomSize == kHeaderSize) { + auto header = + std::vector(rom_data_.begin(), rom_data_.begin() + kHeaderSize); + rom_data_.erase(rom_data_.begin(), rom_data_.begin() + kHeaderSize); + size_ -= 0x200; + } + + // Copy ROM title + constexpr uint32_t kTitleStringOffset = 0x7FC0; + constexpr uint32_t kTitleStringLength = 20; + std::copy(rom_data_.begin() + kTitleStringOffset, + rom_data_.begin() + kTitleStringOffset + kTitleStringLength, + title_.begin()); + if (rom_data_[kTitleStringOffset + 0x19] == 0) { + version_ = Z3_Version::JP; + } else { + version_ = Z3_Version::US; + } + + // Load additional resources + RETURN_IF_ERROR(gfx::LoadAllPalettes(rom_data_, palette_groups_)); + // TODO Load gfx groups or expanded ZS values + RETURN_IF_ERROR(LoadGfxGroups()); + + // Expand the ROM data to 2MB without changing the data in the first 1MB + rom_data_.resize(kBaseRomSize * 2); + size_ = kBaseRomSize * 2; return absl::OkStatus(); } -absl::Status Rom::LoadFromBytes(const Bytes& data) { +absl::Status Rom::LoadFromBytes(const std::vector &data) { if (data.empty()) { return absl::InvalidArgumentError( "Could not load ROM: parameter `data` is empty."); @@ -253,20 +305,16 @@ absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) { try { std::filesystem::copy(filename_, backup_filename, std::filesystem::copy_options::overwrite_existing); - } catch (const std::filesystem::filesystem_error& e) { + } catch (const std::filesystem::filesystem_error &e) { non_firing_status = absl::InternalError(absl::StrCat( "Could not create backup file: ", backup_filename, " - ", e.what())); } } // Run the other save functions - if (flags()->kSaveAllPalettes) { - RETURN_IF_ERROR(SaveAllPalettes()); - } - - if (flags()->kSaveGfxGroups) { - SaveGroupsToRom(); - } + if (flags()->kSaveAllPalettes) RETURN_IF_ERROR(SaveAllPalettes()); + if (flags()->kSaveGfxGroups) RETURN_IF_ERROR(SaveGroupsToRom()); + if (flags()->kSaveGraphicsSheet) RETURN_IF_ERROR(SaveAllGraphicsData()); if (save_new) { // Create a file of the same name and append the date between the filename @@ -301,9 +349,9 @@ absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) { // Save the data to the file try { file.write( - static_cast(static_cast(rom_data_.data())), + static_cast(static_cast(rom_data_.data())), rom_data_.size()); - } catch (const std::ofstream::failure& e) { + } catch (const std::ofstream::failure &e) { return absl::InternalError(absl::StrCat( "Error while writing to ROM file: ", filename, " - ", e.what())); } @@ -321,9 +369,8 @@ absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) { return absl::OkStatus(); } -absl::Status Rom::SavePalette(int index, const std::string& group_name, - gfx::SnesPalette& palette) { - // Iterate through all colors in the palette +absl::Status Rom::SavePalette(int index, const std::string &group_name, + gfx::SnesPalette &palette) { for (size_t j = 0; j < palette.size(); ++j) { gfx::SnesColor color = palette[j]; // If the color is modified, save the color to the ROM @@ -338,7 +385,7 @@ absl::Status Rom::SavePalette(int index, const std::string& group_name, absl::Status Rom::SaveAllPalettes() { RETURN_IF_ERROR( - palette_groups_.for_each([&](gfx::PaletteGroup& group) -> absl::Status { + palette_groups_.for_each([&](gfx::PaletteGroup &group) -> absl::Status { for (size_t i = 0; i < group.size(); ++i) { RETURN_IF_ERROR( SavePalette(i, group.name(), *group.mutable_palette(i))); @@ -349,78 +396,73 @@ absl::Status Rom::SaveAllPalettes() { return absl::OkStatus(); } -void Rom::LoadGfxGroups() { - main_blockset_ids.resize(37, std::vector(8)); - room_blockset_ids.resize(82, std::vector(4)); - spriteset_ids.resize(144, std::vector(4)); - paletteset_ids.resize(72, std::vector(4)); +absl::Status Rom::LoadGfxGroups() { + ASSIGN_OR_RETURN(auto main_blockset_ptr, ReadWord(kGfxGroupsPointer)); + main_blockset_ptr = core::SnesToPc(main_blockset_ptr); - int gfxPointer = - (rom_data_[kGfxGroupsPointer + 1] << 8) + rom_data_[kGfxGroupsPointer]; - gfxPointer = core::SnesToPc(gfxPointer); - - for (int i = 0; i < 37; i++) { + for (uint32_t i = 0; i < kNumMainBlocksets; i++) { for (int j = 0; j < 8; j++) { - main_blockset_ids[i][j] = rom_data_[gfxPointer + (i * 8) + j]; + main_blockset_ids[i][j] = rom_data_[main_blockset_ptr + (i * 8) + j]; } } - for (int i = 0; i < 82; i++) { + for (uint32_t i = 0; i < kNumRoomBlocksets; i++) { for (int j = 0; j < 4; j++) { - room_blockset_ids[i][j] = - rom_data_[core::entrance_gfx_group + (i * 4) + j]; + room_blockset_ids[i][j] = rom_data_[kEntranceGfxGroup + (i * 4) + j]; } } - for (int i = 0; i < 144; i++) { + for (uint32_t i = 0; i < kNumSpritesets; i++) { for (int j = 0; j < 4; j++) { spriteset_ids[i][j] = rom_data_[version_constants().kSpriteBlocksetPointer + (i * 4) + j]; } } - for (int i = 0; i < 72; i++) { + for (uint32_t i = 0; i < kNumPalettesets; i++) { for (int j = 0; j < 4; j++) { paletteset_ids[i][j] = rom_data_[version_constants().kDungeonPalettesGroups + (i * 4) + j]; } } + + return absl::OkStatus(); } -void Rom::SaveGroupsToRom() { - int gfxPointer = - (rom_data_[kGfxGroupsPointer + 1] << 8) + rom_data_[kGfxGroupsPointer]; - gfxPointer = core::SnesToPc(gfxPointer); +absl::Status Rom::SaveGroupsToRom() { + ASSIGN_OR_RETURN(auto main_blockset_ptr, ReadWord(kGfxGroupsPointer)); + main_blockset_ptr = core::SnesToPc(main_blockset_ptr); - for (int i = 0; i < 37; i++) { + for (uint32_t i = 0; i < kNumMainBlocksets; i++) { for (int j = 0; j < 8; j++) { - rom_data_[gfxPointer + (i * 8) + j] = main_blockset_ids[i][j]; + rom_data_[main_blockset_ptr + (i * 8) + j] = main_blockset_ids[i][j]; } } - for (int i = 0; i < 82; i++) { + for (uint32_t i = 0; i < kNumRoomBlocksets; i++) { for (int j = 0; j < 4; j++) { - rom_data_[core::entrance_gfx_group + (i * 4) + j] = - room_blockset_ids[i][j]; + rom_data_[kEntranceGfxGroup + (i * 4) + j] = room_blockset_ids[i][j]; } } - for (int i = 0; i < 144; i++) { + for (uint32_t i = 0; i < kNumSpritesets; i++) { for (int j = 0; j < 4; j++) { rom_data_[version_constants().kSpriteBlocksetPointer + (i * 4) + j] = spriteset_ids[i][j]; } } - for (int i = 0; i < 72; i++) { + for (uint32_t i = 0; i < kNumPalettesets; i++) { for (int j = 0; j < 4; j++) { rom_data_[version_constants().kDungeonPalettesGroups + (i * 4) + j] = paletteset_ids[i][j]; } } + + return absl::OkStatus(); } std::shared_ptr SharedRom::shared_rom_ = nullptr; } // namespace app -} // namespace yaze \ No newline at end of file +} // namespace yaze diff --git a/src/app/rom.h b/src/app/rom.h index 20341481..c99ebd92 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -3,42 +3,35 @@ #include -#include -#include -#include // for size_t -#include // for uint32_t, uint8_t, uint16_t +#include +#include #include #include -#include -#include -#include // for function -#include // for string, operator<<, basic_... -#include // for map -#include // for shared_ptr, make_shared -#include // for stack -#include // for hash, operator== -#include // for unordered_map +#include +#include +#include +#include #include -#include // for vector +#include -#include "absl/container/flat_hash_map.h" // for flat_hash_map -#include "absl/status/status.h" // for Status -#include "absl/status/statusor.h" // for StatusOr -#include "absl/strings/str_cat.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/match.h" #include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" // for string_view +#include "absl/strings/string_view.h" #include "app/core/common.h" -#include "app/core/constants.h" // for Bytes, uchar, armorPalettes -#include "app/core/labeling.h" -#include "app/gfx/bitmap.h" // for Bitmap, BitmapTable -#include "app/gfx/compression.h" -#include "app/gfx/snes_palette.h" // for PaletteGroup, SNESColor +#include "app/core/constants.h" +#include "app/core/project.h" +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" namespace yaze { namespace app { -// Define an enum class for the different versions of the game +/** + * @brief Different versions of the game supported by the Rom class. + */ enum class Z3_Version { US = 1, // US version JP = 2, // JP version @@ -47,7 +40,7 @@ enum class Z3_Version { }; /** - * @brief A struct to hold version constants for each version of the game. + * @brief Constants for each version of the game. */ struct VersionConstants { uint32_t kGfxAnimatedPointer; @@ -115,12 +108,27 @@ static const std::map kVersionConstantsMap = { 0x233C0, // kMap32TileBR 0x5B97, // kSpriteBlocksetPointer 0x67DD0, // kDungeonPalettesGroups - }}}; + }}, + {Z3_Version::SD, {}}, + {Z3_Version::RANDO, {}}, +}; +constexpr uint32_t kNumGfxSheets = 223; +constexpr uint32_t kNumLinkSheets = 14; +constexpr uint32_t kTile16Ptr = 0x78000; constexpr uint32_t kNormalGfxSpaceStart = 0x87000; constexpr uint32_t kNormalGfxSpaceEnd = 0xC4200; constexpr uint32_t kFontSpriteLocation = 0x70000; constexpr uint32_t kGfxGroupsPointer = 0x6237; +constexpr uint32_t kUncompressedSheetSize = 0x0800; +constexpr uint32_t kNumMainBlocksets = 37; +constexpr uint32_t kNumRoomBlocksets = 82; +constexpr uint32_t kNumSpritesets = 144; +constexpr uint32_t kNumPalettesets = 72; +constexpr uint32_t kEntranceGfxGroup = 0x5D97; + +// TODO: Verify what this was used for in ZS +constexpr uint32_t kMaxGraphics = 0xC3FB5; /** * @brief The Rom class is used to load, save, and modify Rom data. @@ -135,7 +143,7 @@ class Rom : public core::ExperimentFlags { * appending the converted sheet data to a byte vector. * */ - absl::StatusOr Load2BppGraphics(); + absl::StatusOr> Load2BppGraphics(); /** * @brief Loads the players 4bpp graphics sheet from Rom data. @@ -160,7 +168,7 @@ class Rom : public core::ExperimentFlags { * | 218-222 | Compressed 2bpp | 0x800 chars | Decompressed each | * */ - absl::Status LoadAllGraphicsData(); + absl::Status LoadAllGraphicsData(bool defer_render = false); /** * Load Rom data from a file. @@ -170,8 +178,8 @@ class Rom : public core::ExperimentFlags { * */ absl::Status LoadFromFile(const std::string& filename, bool z3_load = true); - absl::Status LoadFromPointer(uchar* data, size_t length); - absl::Status LoadFromBytes(const Bytes& data); + absl::Status LoadFromPointer(uchar* data, size_t length, bool z3_load = true); + absl::Status LoadFromBytes(const std::vector& data); /** * @brief Saves the Rom data to a file @@ -185,6 +193,8 @@ class Rom : public core::ExperimentFlags { absl::Status SaveToFile(bool backup, bool save_new = false, std::string filename = ""); + absl::Status SaveAllGraphicsData(); + /** * Saves the given palette to the Rom if any of its colors have been modified. * @@ -204,37 +214,50 @@ class Rom : public core::ExperimentFlags { absl::Status SaveAllPalettes(); /** - * @brief Updates a color in a specified palette group. - * - * This function updates the color at the specified `colorIndex` in the - * palette at `palette_index` within the palette group with the given - * `group_name`. If the group, palette, or color indices are invalid, an error - * is returned. - * - * @param group_name The name of the palette group to update. - * @param palette_index The index of the palette within the group to update. - * @param colorIndex The index of the color within the palette to update. - * @param newColor The new color value to set. - * - * @return An `absl::Status` indicating whether the update was successful. - * Returns `absl::OkStatus()` if successful, or an error status if the - * group, palette, or color indices are invalid. + * @brief Expand the Rom data to a specified size. */ - absl::Status UpdatePaletteColor(const std::string& group_name, - size_t palette_index, size_t colorIndex, - const gfx::SnesColor& newColor); + void Expand(int size) { + rom_data_.resize(size); + size_ = size; + } + + /** + * @brief Close the Rom file. + */ + absl::Status Close() { + rom_data_.clear(); + size_ = 0; + is_loaded_ = false; + return absl::OkStatus(); + } + + /** + * @brief Precondition check for reading and writing to the Rom. + */ + absl::Status ReadWritePreconditions() { + if (!is_loaded_) { + return absl::FailedPreconditionError("ROM file not loaded"); + } + if (rom_data_.empty() || size_ == 0) { + return absl::FailedPreconditionError( + "File was loaded, but ROM data was empty."); + } + return absl::OkStatus(); + } // Read functions absl::StatusOr ReadByte(int offset) { - if (offset >= rom_data_.size()) { - return absl::InvalidArgumentError("Offset out of range"); + RETURN_IF_ERROR(ReadWritePreconditions()); + if (offset >= static_cast(rom_data_.size())) { + return absl::FailedPreconditionError("Offset out of range"); } return rom_data_[offset]; } absl::StatusOr ReadWord(int offset) { - if (offset + 1 >= rom_data_.size()) { - return absl::InvalidArgumentError("Offset out of range"); + RETURN_IF_ERROR(ReadWritePreconditions()); + if (offset + 1 >= static_cast(rom_data_.size())) { + return absl::FailedPreconditionError("Offset out of range"); } auto result = (uint16_t)(rom_data_[offset] | (rom_data_[offset + 1] << 8)); return result; @@ -245,8 +268,9 @@ class Rom : public core::ExperimentFlags { } absl::StatusOr ReadLong(int offset) { - if (offset + 2 >= rom_data_.size()) { - return absl::InvalidArgumentError("Offset out of range"); + RETURN_IF_ERROR(ReadWritePreconditions()); + if (offset + 2 >= static_cast(rom_data_.size())) { + return absl::OutOfRangeError("Offset out of range"); } auto result = (uint32_t)(rom_data_[offset] | (rom_data_[offset + 1] << 8) | (rom_data_[offset + 2] << 16)); @@ -255,11 +279,12 @@ class Rom : public core::ExperimentFlags { absl::StatusOr> ReadByteVector(uint32_t offset, uint32_t length) { - if (offset + length > rom_data_.size()) { - return absl::InvalidArgumentError("Offset and length out of range"); + RETURN_IF_ERROR(ReadWritePreconditions()); + if (offset + length > static_cast(rom_data_.size())) { + return absl::OutOfRangeError("Offset and length out of range"); } std::vector result; - for (int i = offset; i < offset + length; i++) { + for (uint32_t i = offset; i < offset + length; i++) { result.push_back(rom_data_[i]); } return result; @@ -267,7 +292,7 @@ class Rom : public core::ExperimentFlags { absl::StatusOr ReadTile16(uint32_t tile16_id) { // Skip 8 bytes per tile. - auto tpos = 0x78000 + (tile16_id * 0x08); + auto tpos = kTile16Ptr + (tile16_id * 0x08); gfx::Tile16 tile16; ASSIGN_OR_RETURN(auto new_tile0, ReadWord(tpos)) tile16.tile0_ = gfx::WordToTileInfo(new_tile0); @@ -285,7 +310,7 @@ class Rom : public core::ExperimentFlags { absl::Status WriteTile16(int tile16_id, const gfx::Tile16& tile) { // Skip 8 bytes per tile. - auto tpos = 0x78000 + (tile16_id * 0x08); + auto tpos = kTile16Ptr + (tile16_id * 0x08); RETURN_IF_ERROR(WriteShort(tpos, gfx::TileInfoToWord(tile.tile0_))); tpos += 2; RETURN_IF_ERROR(WriteShort(tpos, gfx::TileInfoToWord(tile.tile1_))); @@ -298,7 +323,7 @@ class Rom : public core::ExperimentFlags { // Write functions absl::Status Write(int addr, int value) { - if (addr >= rom_data_.size()) { + if (addr >= static_cast(rom_data_.size())) { return absl::InvalidArgumentError(absl::StrFormat( "Attempt to write %d value failed, address %d out of range", value, addr)); @@ -308,8 +333,9 @@ class Rom : public core::ExperimentFlags { } absl::Status WriteByte(int addr, uint8_t value) { - if (addr >= rom_data_.size()) { - return absl::InvalidArgumentError(absl::StrFormat( + RETURN_IF_ERROR(ReadWritePreconditions()); + if (addr >= static_cast(rom_data_.size())) { + return absl::OutOfRangeError(absl::StrFormat( "Attempt to write byte %#02x value failed, address %d out of range", value, addr)); } @@ -321,8 +347,9 @@ class Rom : public core::ExperimentFlags { } absl::Status WriteWord(int addr, uint16_t value) { - if (addr + 1 >= rom_data_.size()) { - return absl::InvalidArgumentError(absl::StrFormat( + RETURN_IF_ERROR(ReadWritePreconditions()); + if (addr + 1 >= static_cast(rom_data_.size())) { + return absl::OutOfRangeError(absl::StrFormat( "Attempt to write word %#04x value failed, address %d out of range", value, addr)); } @@ -334,8 +361,9 @@ class Rom : public core::ExperimentFlags { } absl::Status WriteShort(int addr, uint16_t value) { - if (addr + 1 >= rom_data_.size()) { - return absl::InvalidArgumentError(absl::StrFormat( + RETURN_IF_ERROR(ReadWritePreconditions()); + if (addr + 1 >= static_cast(rom_data_.size())) { + return absl::OutOfRangeError(absl::StrFormat( "Attempt to write short %#04x value failed, address %d out of range", value, addr)); } @@ -347,8 +375,9 @@ class Rom : public core::ExperimentFlags { } absl::Status WriteLong(uint32_t addr, uint32_t value) { - if (addr + 2 >= rom_data_.size()) { - return absl::InvalidArgumentError(absl::StrFormat( + RETURN_IF_ERROR(ReadWritePreconditions()); + if (addr + 2 >= static_cast(rom_data_.size())) { + return absl::OutOfRangeError(absl::StrFormat( "Attempt to write long %#06x value failed, address %d out of range", value, addr)); } @@ -361,12 +390,13 @@ class Rom : public core::ExperimentFlags { } absl::Status WriteVector(int addr, std::vector data) { - if (addr + data.size() > rom_data_.size()) { + if (addr + static_cast(data.size()) > + static_cast(rom_data_.size())) { return absl::InvalidArgumentError(absl::StrFormat( "Attempt to write vector value failed, address %d out of range", addr)); } - for (int i = 0; i < data.size(); i++) { + for (int i = 0; i < static_cast(data.size()); i++) { rom_data_[addr + i] = data[i]; } core::Logger::log(absl::StrFormat("WriteVector: %#06X: %s", addr, @@ -406,40 +436,40 @@ class Rom : public core::ExperimentFlags { return status; } - void Expand(int size) { - rom_data_.resize(size); - size_ = size; - } - - absl::Status Reload() { - if (filename_.empty()) { - return absl::InvalidArgumentError("No filename specified"); + uint8_t& operator[](unsigned long i) { + if (i > size_) { + std::cout << "ROM: Index " << i << " out of bounds, size: " << size_ + << std::endl; + return rom_data_[0]; } - return LoadFromFile(filename_); + return rom_data_[i]; } - absl::Status Close() { - rom_data_.clear(); - size_ = 0; - is_loaded_ = false; - return absl::OkStatus(); + bool is_loaded() const { + if (!absl::StrContains(filename_, ".sfc") && + !absl::StrContains(filename_, ".smc")) { + return false; + } + return is_loaded_; } - void QueueChanges(std::function const& function) { - changes_.push(function); - } + // Full graphical data for the game + std::vector graphics_buffer() const { return graphics_buffer_; } - VersionConstants version_constants() const { - return kVersionConstantsMap.at(version_); - } + auto title() const { return title_; } + auto size() const { return size_; } + auto begin() { return rom_data_.begin(); } + auto end() { return rom_data_.end(); } + auto data() { return rom_data_.data(); } + auto vector() const { return rom_data_; } + auto version() const { return version_; } + auto filename() const { return filename_; } + auto set_filename(std::string name) { filename_ = name; } - int GetGraphicsAddress(const uchar* data, uint8_t addr) const { - auto part_one = data[version_constants().kOverworldGfxPtr1 + addr] << 16; - auto part_two = data[version_constants().kOverworldGfxPtr2 + addr] << 8; - auto part_three = data[version_constants().kOverworldGfxPtr3 + addr]; - auto snes_addr = (part_one | part_two | part_three); - return core::SnesToPc(snes_addr); - } + auto link_graphics() { return link_graphics_; } + auto mutable_link_graphics() { return &link_graphics_; } + auto gfx_sheets() { return graphics_sheets_; } + auto mutable_gfx_sheets() { return &graphics_sheets_; } auto palette_group() { return palette_groups_; } auto mutable_palette_group() { return &palette_groups_; } @@ -448,96 +478,16 @@ class Rom : public core::ExperimentFlags { return palette_groups_.dungeon_main.mutable_palette(i); } - // Full graphical data for the game - Bytes graphics_buffer() const { return graphics_buffer_; } - - gfx::BitmapTable graphics_bin() const { return graphics_bin_; } - - gfx::Bitmap* mutable_graphics_sheet(int index) { - return &graphics_bin_.at(index); - } - auto bitmap_manager() { return graphics_manager_; } - auto mutable_bitmap_manager() { return &graphics_manager_; } - auto link_graphics() { return link_graphics_; } - auto mutable_link_graphics() { return &link_graphics_; } - - auto title() const { return title_; } - auto size() const { return size_; } - auto begin() { return rom_data_.begin(); } - auto end() { return rom_data_.end(); } - auto data() { return rom_data_.data(); } - auto push_back(uint8_t byte) { rom_data_.push_back(byte); } - auto vector() const { return rom_data_; } - auto filename() const { return filename_; } - auto is_loaded() const { return is_loaded_; } - auto version() const { return version_; } - auto renderer() const { return renderer_; } - - uint8_t& operator[](int i) { - if (i > size_) { - std::cout << "ROM: Index " << i << " out of bounds, size: " << size_ - << std::endl; - return rom_data_[0]; - } - return rom_data_[i]; - } - uint8_t& operator+(int i) { - if (i > size_) { - std::cout << "ROM: Index " << i << " out of bounds, size: " << size_ - << std::endl; - return rom_data_[0]; - } - return rom_data_[i]; - } - const uint8_t* operator&() { return rom_data_.data(); } - - void SetupRenderer(std::shared_ptr renderer) { - renderer_ = renderer; + ResourceLabelManager* resource_label() { return &resource_label_manager_; } + VersionConstants version_constants() const { + return kVersionConstantsMap.at(version_); } - absl::Status CreateAndRenderBitmap(int width, int height, int depth, - const Bytes& data, gfx::Bitmap& bitmap, - gfx::SnesPalette& palette) { - bitmap.Create(width, height, depth, data); - RETURN_IF_ERROR(bitmap.ApplyPalette(palette)); - RenderBitmap(&bitmap); - return absl::OkStatus(); - } + std::array, kNumMainBlocksets> main_blockset_ids; + std::array, kNumRoomBlocksets> room_blockset_ids; + std::array, kNumSpritesets> spriteset_ids; + std::array, kNumPalettesets> paletteset_ids; - /** - * @brief Used to render a bitmap to the screen. - */ - void RenderBitmap(gfx::Bitmap* bitmap) { - if (flags()->kLoadTexturesAsStreaming) { - bitmap->CreateTexture(renderer_.get()); - } else { - bitmap->CreateTexture(renderer_); - } - } - - /** - * @brief Used to update a bitmap on the screen. - */ - void UpdateBitmap(gfx::Bitmap* bitmap, bool use_sdl_update = false) { - if (flags()->kLoadTexturesAsStreaming) { - bitmap->UpdateTexture(renderer_.get(), use_sdl_update); - } else { - bitmap->UpdateTexture(renderer_); - } - } - - std::vector> main_blockset_ids; - std::vector> room_blockset_ids; - std::vector> spriteset_ids; - std::vector> paletteset_ids; - - void LoadGfxGroups(); - void SaveGroupsToRom(); - - auto resource_label() { return &resource_label_manager_; } - auto font_gfx_data() { return font_gfx_data_; } - - private: struct WriteAction { int address; std::variant, @@ -545,7 +495,8 @@ class Rom : public core::ExperimentFlags { value; }; - absl::Status WriteHelper(const WriteAction& action) { + private: + virtual absl::Status WriteHelper(const WriteAction& action) { if (std::holds_alternative(action.value)) { return Write(action.address, std::get(action.value)); } else if (std::holds_alternative(action.value) || @@ -563,7 +514,6 @@ class Rom : public core::ExperimentFlags { } auto error_message = absl::StrFormat("Invalid write argument type: %s", typeid(action.value).name()); - throw std::runtime_error(error_message); return absl::InvalidArgumentError(error_message); } @@ -582,26 +532,42 @@ class Rom : public core::ExperimentFlags { return absl::OkStatus(); } - long size_ = 0; + absl::Status LoadZelda3(); + absl::Status LoadGfxGroups(); + absl::Status SaveGroupsToRom(); + + // ROM file loaded flag bool is_loaded_ = false; - bool has_header_ = false; - uchar title_[21] = "ROM Not Loaded"; - std::string filename_; - Bytes rom_data_; - Bytes graphics_buffer_; - Bytes font_gfx_data_; + // Size of the ROM data. + unsigned long size_ = 0; - Z3_Version version_ = Z3_Version::US; - gfx::BitmapTable graphics_bin_; - gfx::BitmapManager graphics_manager_; - gfx::BitmapTable link_graphics_; - gfx::SnesPalette link_palette_; + // Title of the ROM loaded from the header + std::string title_ = "ROM not loaded"; + + // Filename of the ROM + std::string filename_ = ""; + + // Full contiguous rom space + std::vector rom_data_; + + // Full contiguous graphics space + std::vector graphics_buffer_; + + // All graphics sheets in the game + std::array graphics_sheets_; + + // All graphics sheets for Link + std::array link_graphics_; + + // Label manager for unique resource names. + ResourceLabelManager resource_label_manager_; + + // All palette groups in the game gfx::PaletteGroupMap palette_groups_; - core::ResourceLabelManager resource_label_manager_; - std::stack> changes_; - std::shared_ptr renderer_; + // Version of the game + Z3_Version version_ = Z3_Version::US; }; /** @@ -634,4 +600,4 @@ class SharedRom { } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/rom_test.cc b/src/app/rom_test.cc deleted file mode 100644 index e2d34360..00000000 --- a/src/app/rom_test.cc +++ /dev/null @@ -1,20 +0,0 @@ -#include "app/rom.h" - -#include -#include - -namespace yaze { -namespace app { - -class RomTest : public ::testing::Test { - protected: - Rom rom_; -}; - -TEST_F(RomTest, RomTest) { - EXPECT_EQ(rom_.size(), 0); - EXPECT_EQ(rom_.data(), nullptr); -} - -} // namespace app -} // namespace yaze \ No newline at end of file diff --git a/src/app/zelda3/common.h b/src/app/zelda3/common.h index 7a680024..152d9369 100644 --- a/src/app/zelda3/common.h +++ b/src/app/zelda3/common.h @@ -1,6 +1,10 @@ #ifndef YAZE_APP_ZELDA3_COMMON_H #define YAZE_APP_ZELDA3_COMMON_H +#include +#include +#include + namespace yaze { namespace app { /** @@ -10,10 +14,25 @@ namespace app { namespace zelda3 { /** - * @class OverworldEntity - * @brief Base class for all overworld entities. + * @brief Represents tile32 data for the overworld. */ -class OverworldEntity { +using OWBlockset = std::vector>; + +/** + * @brief Overworld map tile32 data. + */ +struct OWMapTiles { + OWBlockset light_world; // 64 maps + OWBlockset dark_world; // 64 maps + OWBlockset special_world; // 32 maps +}; +using OWMapTiles = struct OWMapTiles; + +/** + * @class GameEntity + * @brief Base class for all overworld and dungeon entities. + */ +class GameEntity { public: enum EntityType { kEntrance = 0, @@ -23,24 +42,284 @@ class OverworldEntity { kTransport = 4, kMusic = 5, kTilemap = 6, - kProperties = 7 - } type_; + kProperties = 7, + kDungeonSprite = 8, + } entity_type_; int x_; int y_; int game_x_; int game_y_; int entity_id_; - int map_id_; + uint16_t map_id_; auto set_x(int x) { x_ = x; } auto set_y(int y) { y_ = y; } - OverworldEntity() = default; + GameEntity() = default; - virtual void UpdateMapProperties(short map_id) = 0; + virtual void UpdateMapProperties(uint16_t map_id) = 0; }; + +static const std::string TileTypeNames[] = { + "$00 Nothing (standard floor)", + "$01 Collision", + "$02 Collision", + "$03 Collision", + "$04 Collision", + "$05 Nothing (unused?)", + "$06 Nothing (unused?)", + "$07 Nothing (unused?)", + "$08 Deep water", + "$09 Shallow water", + "$0A Unknown? Possibly unused", + "$0B Collision (different in Overworld and unknown)", + "$0C Overlay mask", + "$0D Spike floor", + "$0E GT ice", + "$0F Ice palace ice", + "$10 Slope ◤", + "$11 Slope ◥", + "$12 Slope ◣", + "$13 Slope ◢", + "$14 Nothing (unused?)", + "$15 Nothing (unused?)", + "$16 Nothing (unused?)", + "$17 Nothing (unused?)", + "$18 Slope ◤", + "$19 Slope ◥", + "$1A Slope ◣", + "$1B Slope ◢", + "$1C Layer 2 overlay", + "$1D North single-layer auto stairs", + "$1E North layer-swap auto stairs", + "$1F North layer-swap auto stairs", + "$20 Pit", + "$21 Nothing (unused?)", + "$22 Manual stairs", + "$23 Pot switch", + "$24 Pressure switch", + "$25 Nothing (unused but referenced by somaria blocks)", + "$26 Collision (near stairs?)", + "$27 Brazier/Fence/Statue/Block/General hookable things", + "$28 North ledge", + "$29 South ledge", + "$2A East ledge", + "$2B West ledge", + "$2C ◤ ledge", + "$2D ◣ ledge", + "$2E ◥ ledge", + "$2F ◢ ledge", + "$30 Straight inter-room stairs south/up 0", + "$31 Straight inter-room stairs south/up 1", + "$32 Straight inter-room stairs south/up 2", + "$33 Straight inter-room stairs south/up 3", + "$34 Straight inter-room stairs north/down 0", + "$35 Straight inter-room stairs north/down 1", + "$36 Straight inter-room stairs north/down 2", + "$37 Straight inter-room stairs north/down 3", + "$38 Straight inter-room stairs north/down edge", + "$39 Straight inter-room stairs south/up edge", + "$3A Star tile (inactive on load)", + "$3B Star tile (active on load)", + "$3C Nothing (unused?)", + "$3D South single-layer auto stairs", + "$3E South layer-swap auto stairs", + "$3F South layer-swap auto stairs", + "$40 Thick grass", + "$41 Nothing (unused?)", + "$42 Gravestone / Tower of hera ledge shadows??", + "$43 Skull Woods entrance/Hera columns???", + "$44 Spike", + "$45 Nothing (unused?)", + "$46 Desert Tablet", + "$47 Nothing (unused?)", + "$48 Diggable ground", + "$49 Nothing (unused?)", + "$4A Diggable ground", + "$4B Warp tile", + "$4C Nothing (unused?) | Something unknown in overworld", + "$4D Nothing (unused?) | Something unknown in overworld", + "$4E Square corners in EP overworld", + "$4F Square corners in EP overworld", + "$50 Green bush", + "$51 Dark bush", + "$52 Gray rock", + "$53 Black rock", + "$54 Hint tile/Sign", + "$55 Big gray rock", + "$56 Big black rock", + "$57 Bonk rocks", + "$58 Chest 0", + "$59 Chest 1", + "$5A Chest 2", + "$5B Chest 3", + "$5C Chest 4", + "$5D Chest 5", + "$5E Spiral stairs", + "$5F Spiral stairs", + "$60 Rupee tile", + "$61 Nothing (unused?)", + "$62 Bombable floor", + "$63 Minigame chest", + "$64 Nothing (unused?)", + "$65 Nothing (unused?)", + "$66 Crystal peg down", + "$67 Crystal peg up", + "$68 Upwards conveyor", + "$69 Downwards conveyor", + "$6A Leftwards conveyor", + "$6B Rightwards conveyor", + "$6C North vines", + "$6D South vines", + "$6E West vines", + "$6F East vines", + "$70 Pot/Hammer peg/Push block 00", + "$71 Pot/Hammer peg/Push block 01", + "$72 Pot/Hammer peg/Push block 02", + "$73 Pot/Hammer peg/Push block 03", + "$74 Pot/Hammer peg/Push block 04", + "$75 Pot/Hammer peg/Push block 05", + "$76 Pot/Hammer peg/Push block 06", + "$77 Pot/Hammer peg/Push block 07", + "$78 Pot/Hammer peg/Push block 08", + "$79 Pot/Hammer peg/Push block 09", + "$7A Pot/Hammer peg/Push block 0A", + "$7B Pot/Hammer peg/Push block 0B", + "$7C Pot/Hammer peg/Push block 0C", + "$7D Pot/Hammer peg/Push block 0D", + "$7E Pot/Hammer peg/Push block 0E", + "$7F Pot/Hammer peg/Push block 0F", + "$80 North/South door", + "$81 East/West door", + "$82 North/South shutter door", + "$83 East/West shutter door", + "$84 North/South layer 2 door", + "$85 East/West layer 2 door", + "$86 North/South layer 2 shutter door", + "$87 East/West layer 2 shutter door", + "$88 Some type of door (?)", + "$89 East/West transport door", + "$8A Some type of door (?)", + "$8B Some type of door (?)", + "$8C Some type of door (?)", + "$8D Some type of door (?)", + "$8E Entrance door", + "$8F Entrance door", + "$90 Layer toggle shutter door (?)", + "$91 Layer toggle shutter door (?)", + "$92 Layer toggle shutter door (?)", + "$93 Layer toggle shutter door (?)", + "$94 Layer toggle shutter door (?)", + "$95 Layer toggle shutter door (?)", + "$96 Layer toggle shutter door (?)", + "$97 Layer toggle shutter door (?)", + "$98 Layer+Dungeon toggle shutter door (?)", + "$99 Layer+Dungeon toggle shutter door (?)", + "$9A Layer+Dungeon toggle shutter door (?)", + "$9B Layer+Dungeon toggle shutter door (?)", + "$9C Layer+Dungeon toggle shutter door (?)", + "$9D Layer+Dungeon toggle shutter door (?)", + "$9E Layer+Dungeon toggle shutter door (?)", + "$9F Layer+Dungeon toggle shutter door (?)", + "$A0 North/South Dungeon swap door", + "$A1 Dungeon toggle door (?)", + "$A2 Dungeon toggle door (?)", + "$A3 Dungeon toggle door (?)", + "$A4 Dungeon toggle door (?)", + "$A5 Dungeon toggle door (?)", + "$A6 Nothing (unused?)", + "$A7 Nothing (unused?)", + "$A8 Layer+Dungeon toggle shutter door (?)", + "$A9 Layer+Dungeon toggle shutter door (?)", + "$AA Layer+Dungeon toggle shutter door (?)", + "$AB Layer+Dungeon toggle shutter door (?)", + "$AC Layer+Dungeon toggle shutter door (?)", + "$AD Layer+Dungeon toggle shutter door (?)", + "$AE Layer+Dungeon toggle shutter door (?)", + "$AF Layer+Dungeon toggle shutter door (?)", + "$B0 Somaria ─", + "$B1 Somaria │", + "$B2 Somaria ┌", + "$B3 Somaria └", + "$B4 Somaria ┐", + "$B5 Somaria ┘", + "$B6 Somaria ⍰ 1 way", + "$B7 Somaria ┬", + "$B8 Somaria ┴", + "$B9 Somaria ├", + "$BA Somaria ┤", + "$BB Somaria ┼", + "$BC Somaria ⍰ 2 way", + "$BD Somaria ┼ crossover", + "$BE Pipe entrance", + "$BF Nothing (unused?)", + "$C0 Torch 00", + "$C1 Torch 01", + "$C2 Torch 02", + "$C3 Torch 03", + "$C4 Torch 04", + "$C5 Torch 05", + "$C6 Torch 06", + "$C7 Torch 07", + "$C8 Torch 08", + "$C9 Torch 09", + "$CA Torch 0A", + "$CB Torch 0B", + "$CC Torch 0C", + "$CD Torch 0D", + "$CE Torch 0E", + "$CF Torch 0F", + "$D0 Nothing (unused?)", + "$D1 Nothing (unused?)", + "$D2 Nothing (unused?)", + "$D3 Nothing (unused?)", + "$D4 Nothing (unused?)", + "$D5 Nothing (unused?)", + "$D6 Nothing (unused?)", + "$D7 Nothing (unused?)", + "$D8 Nothing (unused?)", + "$D9 Nothing (unused?)", + "$DA Nothing (unused?)", + "$DB Nothing (unused?)", + "$DC Nothing (unused?)", + "$DD Nothing (unused?)", + "$DE Nothing (unused?)", + "$DF Nothing (unused?)", + "$E0 Nothing (unused?)", + "$E1 Nothing (unused?)", + "$E2 Nothing (unused?)", + "$E3 Nothing (unused?)", + "$E4 Nothing (unused?)", + "$E5 Nothing (unused?)", + "$E6 Nothing (unused?)", + "$E7 Nothing (unused?)", + "$E8 Nothing (unused?)", + "$E9 Nothing (unused?)", + "$EA Nothing (unused?)", + "$EB Nothing (unused?)", + "$EC Nothing (unused?)", + "$ED Nothing (unused?)", + "$EE Nothing (unused?)", + "$EF Nothing (unused?)", + "$F0 Door 0 bottom", + "$F1 Door 1 bottom", + "$F2 Door 2 bottom", + "$F3 Door 3 bottom", + "$F4 Door X bottom? (unused?)", + "$F5 Door X bottom? (unused?)", + "$F6 Door X bottom? (unused?)", + "$F7 Door X bottom? (unused?)", + "$F8 Door 0 top", + "$F9 Door 1 top", + "$FA Door 2 top", + "$FB Door 3 top", + "$FC Door X top? (unused?)", + "$FD Door X top? (unused?)", + "$FE Door X top? (unused?)", + "$FF Door X top? (unused?)"}; + } // namespace zelda3 } // namespace app } // namespace yaze -#endif // YAZE_APP_ZELDA3_COMMON_H \ No newline at end of file +#endif // YAZE_APP_ZELDA3_COMMON_H diff --git a/src/app/zelda3/dungeon/object_renderer.cc b/src/app/zelda3/dungeon/object_renderer.cc index 5e030162..fd88b6af 100644 --- a/src/app/zelda3/dungeon/object_renderer.cc +++ b/src/app/zelda3/dungeon/object_renderer.cc @@ -5,7 +5,7 @@ namespace app { namespace zelda3 { namespace dungeon { -void DungeonObjectRenderer::LoadObject(uint16_t objectId, +void DungeonObjectRenderer::LoadObject(uint32_t routine_ptr, std::array& sheet_ids) { vram_.sheets = sheet_ids; @@ -13,48 +13,14 @@ void DungeonObjectRenderer::LoadObject(uint16_t objectId, // Prepare the CPU and memory environment memory_.Initialize(rom_data_); - // Fetch the subtype pointers for the given object ID - auto subtypeInfo = FetchSubtypeInfo(objectId); - // Configure the object based on the fetched information - ConfigureObject(subtypeInfo); + ConfigureObject(); // Run the CPU emulation for the object's draw routines - RenderObject(subtypeInfo); + RenderObject(routine_ptr); } -SubtypeInfo DungeonObjectRenderer::FetchSubtypeInfo(uint16_t object_id) { - SubtypeInfo info; - - // Determine the subtype based on objectId - uint8_t subtype = 1; - - // Based on the subtype, fetch the correct pointers - switch (subtype) { - case 1: // Subtype 1 - info.subtype_ptr = core::subtype1_tiles + (object_id & 0xFF) * 2; - info.routine_ptr = core::subtype1_tiles + 0x200 + (object_id & 0xFF) * 2; - std::cout << "Subtype 1 " << std::hex << info.subtype_ptr << std::endl; - std::cout << "Subtype 1 " << std::hex << info.routine_ptr << std::endl; - break; - case 2: // Subtype 2 - info.subtype_ptr = core::subtype2_tiles + (object_id & 0x7F) * 2; - info.routine_ptr = core::subtype2_tiles + 0x80 + (object_id & 0x7F) * 2; - break; - case 3: // Subtype 3 - info.subtype_ptr = core::subtype3_tiles + (object_id & 0xFF) * 2; - info.routine_ptr = core::subtype3_tiles + 0x100 + (object_id & 0xFF) * 2; - break; - default: - // Handle unknown subtype - throw std::runtime_error("Unknown subtype for object ID: " + - std::to_string(object_id)); - } - - return info; -} - -void DungeonObjectRenderer::ConfigureObject(const SubtypeInfo& info) { +void DungeonObjectRenderer::ConfigureObject() { cpu.A = 0x03D8; cpu.X = 0x03D8; cpu.DB = 0x7E; @@ -94,19 +60,18 @@ void DungeonObjectRenderer::ConfigureObject(const SubtypeInfo& info) { #_0198A9: INY #4 #_0198AD: RTS */ -void DungeonObjectRenderer::RenderObject(const SubtypeInfo& info) { +void DungeonObjectRenderer::RenderObject(uint32_t routine_ptr) { cpu.PB = 0x01; // Push an initial value to the stack we can read later to confirm we are // done - cpu.PushLong(0x01 << 16 | info.routine_ptr); + cpu.PushLong(0x01 << 16 | routine_ptr); int i = 0; while (true) { uint8_t opcode = cpu.ReadByte(cpu.PB << 16 | cpu.PC); cpu.ExecuteInstruction(opcode); - i++; } @@ -138,10 +103,10 @@ void DungeonObjectRenderer::UpdateObjectBitmap() { int x = column * 8; int y = row * 8; - auto sheet = rom()->mutable_graphics_sheet(vram_.sheets[sheet_number]); + auto sheet = rom()->mutable_gfx_sheets()->at(vram_.sheets[sheet_number]); // Copy the tile from VRAM using the read tile_id - sheet->Get8x8Tile(tile_id, x, y, tilemap_, tilemap_offset); + sheet.Get8x8Tile(tile_id, x, y, tilemap_, tilemap_offset); } bitmap_.Create(256, 256, 8, tilemap_); diff --git a/src/app/zelda3/dungeon/object_renderer.h b/src/app/zelda3/dungeon/object_renderer.h index aa25fa75..ef74c3c5 100644 --- a/src/app/zelda3/dungeon/object_renderer.h +++ b/src/app/zelda3/dungeon/object_renderer.h @@ -23,36 +23,32 @@ struct PseudoVram { std::vector palettes; }; -struct SubtypeInfo { - uint32_t subtype_ptr; - uint32_t routine_ptr; -}; - class DungeonObjectRenderer : public SharedRom { public: DungeonObjectRenderer() = default; - void LoadObject(uint16_t objectId, std::array& sheet_ids); + void LoadObject(uint32_t routine_ptr, std::array& sheet_ids); + void ConfigureObject(); + void RenderObject(uint32_t routine_ptr); + void UpdateObjectBitmap(); + gfx::Bitmap* bitmap() { return &bitmap_; } auto memory() { return memory_; } auto mutable_memory() { return &memory_; } private: - SubtypeInfo FetchSubtypeInfo(uint16_t object_id); - void ConfigureObject(const SubtypeInfo& info); - void RenderObject(const SubtypeInfo& info); - void UpdateObjectBitmap(); - std::vector tilemap_; - uint16_t pc_with_rts_; std::vector rom_data_; - emu::memory::MemoryImpl memory_; - emu::ClockImpl clock_; - emu::memory::CpuCallbacks cpu_callbacks_; - emu::Cpu cpu{memory_, clock_, cpu_callbacks_}; - emu::video::Ppu ppu{memory_, clock_}; - gfx::Bitmap bitmap_; + PseudoVram vram_; + + emu::ClockImpl clock_; + emu::memory::MemoryImpl memory_; + emu::memory::CpuCallbacks cpu_callbacks_; + emu::video::Ppu ppu{memory_, clock_}; + emu::Cpu cpu{memory_, clock_, cpu_callbacks_}; + + gfx::Bitmap bitmap_; }; } // namespace dungeon diff --git a/src/app/zelda3/dungeon/room.cc b/src/app/zelda3/dungeon/room.cc index cba89cf5..71a2f92b 100644 --- a/src/app/zelda3/dungeon/room.cc +++ b/src/app/zelda3/dungeon/room.cc @@ -1,9 +1,11 @@ #include "room.h" +#include + #include #include -#include "app/core/common.h" +#include "absl/strings/str_cat.h" #include "app/core/constants.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" @@ -31,12 +33,12 @@ void Room::LoadHeader() { auto header_location = core::SnesToPc(address); - bg2_ = (Background2)((rom()->data()[header_location] >> 5) & 0x07); + bg2_ = (z3_dungeon_background2)((rom()->data()[header_location] >> 5) & 0x07); // collision = (CollisionKey)((rom()->data()[header_location] >> 2) & 0x07); is_light_ = ((rom()->data()[header_location]) & 0x01) == 1; if (is_light_) { - bg2_ = Background2::DarkRoom; + bg2_ = z3_dungeon_background2::DarkRoom; } palette = ((rom()->data()[header_location + 1] & 0x3F)); @@ -72,9 +74,8 @@ void Room::LoadHeader() { // Existing room size address calculation... auto room_size_address = 0xF8000 + (room_id_ * 3); - if (flags()->kLogToConsole) - std::cout << "Room #" << room_id_ << " Address: " << std::hex - << room_size_address << std::endl; + std::cout << "Room #" << room_id_ << " Address: " << std::hex + << room_size_address << std::endl; // Reading bytes for long address construction uint8_t low = rom()->data()[room_size_address]; @@ -83,15 +84,13 @@ void Room::LoadHeader() { // Constructing the long address int long_address = (bank << 16) | (high << 8) | low; - if (flags()->kLogToConsole) - std::cout << std::hex << std::setfill('0') << std::setw(6) << long_address - << std::endl; + std::cout << std::hex << std::setfill('0') << std::setw(6) << long_address + << std::endl; room_size_pointer_ = long_address; if (long_address == 0x0A8000) { // Blank room disregard in size calculation - if (flags()->kLogToConsole) - std::cout << "Size of Room #" << room_id_ << ": 0 bytes" << std::endl; + std::cout << "Size of Room #" << room_id_ << ": 0 bytes" << std::endl; room_size_ = 0; } else { // use the long address to calculate the size of the room @@ -100,9 +99,8 @@ void Room::LoadHeader() { int next_room_address = 0xF8000 + ((room_id_ + 1) * 3); - if (flags()->kLogToConsole) - std::cout << "Next Room Address: " << std::hex << next_room_address - << std::endl; + std::cout << "Next Room Address: " << std::hex << next_room_address + << std::endl; // Reading bytes for long address construction uint8_t next_low = rom()->data()[next_room_address]; @@ -112,19 +110,17 @@ void Room::LoadHeader() { // Constructing the long address int next_long_address = (next_bank << 16) | (next_high << 8) | next_low; - if (flags()->kLogToConsole) - std::cout << std::hex << std::setfill('0') << std::setw(6) - << next_long_address << std::endl; + std::cout << std::hex << std::setfill('0') << std::setw(6) + << next_long_address << std::endl; // Calculate the size of the room int room_size = next_long_address - long_address; room_size_ = room_size; - if (flags()->kLogToConsole) - std::cout << "Size of Room #" << room_id_ << ": " << std::dec - << room_size << " bytes" << std::endl; + std::cout << "Size of Room #" << room_id_ << ": " << std::dec << room_size + << " bytes" << std::endl; } - } catch (const std::exception& e) { - if (flags()->kLogToConsole) std::cout << "Error: " << e.what() << std::endl; + } catch (const std::exception &e) { + std::cout << "Error: " << e.what() << std::endl; } } @@ -170,28 +166,28 @@ void Room::LoadRoomFromROM() { b = rom_data[hpos]; - pits_.TargetLayer = (uchar)(b & 0x03); - stair1_.TargetLayer = (uchar)((b >> 2) & 0x03); - stair2_.TargetLayer = (uchar)((b >> 4) & 0x03); - stair3_.TargetLayer = (uchar)((b >> 6) & 0x03); + pits_.target_layer = (uchar)(b & 0x03); + stair1_.target_layer = (uchar)((b >> 2) & 0x03); + stair2_.target_layer = (uchar)((b >> 4) & 0x03); + stair3_.target_layer = (uchar)((b >> 6) & 0x03); hpos++; - stair4_.TargetLayer = (uchar)(rom_data[hpos] & 0x03); + stair4_.target_layer = (uchar)(rom_data[hpos] & 0x03); hpos++; - pits_.Target = rom_data[hpos]; + pits_.target = rom_data[hpos]; hpos++; - stair1_.Target = rom_data[hpos]; + stair1_.target = rom_data[hpos]; hpos++; - stair2_.Target = rom_data[hpos]; + stair2_.target = rom_data[hpos]; hpos++; - stair3_.Target = rom_data[hpos]; + stair3_.target = rom_data[hpos]; hpos++; - stair4_.Target = rom_data[hpos]; + stair4_.target = rom_data[hpos]; hpos++; // Load room objects - int objectPointer = core::SnesToPc(room_object_pointer); - int room_address = objectPointer + (room_id_ * 3); + int object_pointer = core::SnesToPc(room_object_pointer); + int room_address = object_pointer + (room_id_ * 3); int objects_location = core::SnesToPc(room_address); // Load sprites @@ -201,18 +197,18 @@ void Room::LoadRoomFromROM() { } void Room::LoadRoomGraphics(uchar entrance_blockset) { - const auto& mainGfx = rom()->main_blockset_ids; - const auto& roomGfx = rom()->room_blockset_ids; - const auto& spriteGfx = rom()->spriteset_ids; + const auto &main_gfx = rom()->main_blockset_ids; + const auto &room_gfx = rom()->room_blockset_ids; + const auto &sprite_gfx = rom()->spriteset_ids; current_gfx16_.reserve(0x4000); for (int i = 0; i < 8; i++) { - blocks_[i] = mainGfx[blockset][i]; + blocks_[i] = main_gfx[blockset][i]; if (i >= 6 && i <= 6) { // 3-6 if (entrance_blockset != 0xFF) { - if (roomGfx[entrance_blockset][i - 3] != 0) { - blocks_[i] = roomGfx[entrance_blockset][i - 3]; + if (room_gfx[entrance_blockset][i - 3] != 0) { + blocks_[i] = room_gfx[entrance_blockset][i - 3]; } } } @@ -223,7 +219,7 @@ void Room::LoadRoomGraphics(uchar entrance_blockset) { blocks_[10] = 115 + 6; blocks_[11] = 115 + 7; for (int i = 0; i < 4; i++) { - blocks_[12 + i] = (uchar)(spriteGfx[spriteset + 64][i] + 115); + blocks_[12 + i] = (uchar)(sprite_gfx[spriteset + 64][i] + 115); } // 12-16 sprites } @@ -282,11 +278,11 @@ void Room::LoadAnimatedGraphics() { void Room::LoadObjects() { auto rom_data = rom()->vector(); - int objectPointer = (rom_data[room_object_pointer + 2] << 16) + - (rom_data[room_object_pointer + 1] << 8) + - (rom_data[room_object_pointer]); - objectPointer = core::SnesToPc(objectPointer); - int room_address = objectPointer + (room_id_ * 3); + int object_pointer = (rom_data[room_object_pointer + 2] << 16) + + (rom_data[room_object_pointer + 1] << 8) + + (rom_data[room_object_pointer]); + object_pointer = core::SnesToPc(object_pointer); + int room_address = object_pointer + (room_id_ * 3); int tile_address = (rom_data[room_address + 2] << 16) + (rom_data[room_address + 1] << 8) + rom_data[room_address]; @@ -307,7 +303,7 @@ void Room::LoadObjects() { LoadChests(); - staircase_rooms_vec_.clear(); + z3_staircases_.clear(); int nbr_of_staircase = 0; int pos = objects_location + 2; @@ -373,50 +369,48 @@ void Room::LoadObjects() { sizeXY = 0; } - RoomObject r = - AddObject(oid, posX, posY, sizeXY, static_cast(layer)); - - /** - if (r != nullptr) { - tilesObjects.push_back(r); - } - + RoomObject r(oid, posX, posY, sizeXY, static_cast(layer)); + tile_objects_.push_back(r); for (short stair : stairsObjects) { if (stair == oid) { if (nbr_of_staircase < 4) { - tilesObjects.back().options |= ObjectOption::Stairs; - staircaseRooms.push_back(StaircaseRoom( - posX, posY, "To " + staircase_rooms_[nbr_of_staircase])); + tile_objects_.back().set_options(ObjectOption::Stairs | + tile_objects_.back().options()); + z3_staircases_.push_back(z3_staircase( + posX, posY, + absl::StrCat("To ", staircase_rooms_[nbr_of_staircase]) + .data())); nbr_of_staircase++; } else { - tilesObjects.back().options |= ObjectOption::Stairs; - staircaseRooms.push_back(StaircaseRoom(posX, posY, "To ???")); + tile_objects_.back().set_options(ObjectOption::Stairs | + tile_objects_.back().options()); + z3_staircases_.push_back(z3_staircase(posX, posY, "To ???")); } } } if (oid == 0xF99) { - if (chests_in_room.size() > 0) { - tilesObjects.back().options |= ObjectOption::Chest; - chest_list.push_back( - Chest(posX, posY, chests_in_room.front().itemIn, false)); - chests_in_room.erase(chests_in_room.begin()); + if (chests_in_room_.size() > 0) { + tile_objects_.back().set_options(ObjectOption::Chest | + tile_objects_.back().options()); + // chest_list_.push_back( + // Chest(posX, posY, chests_in_room_.front().itemIn, false)); + chests_in_room_.erase(chests_in_room_.begin()); } } else if (oid == 0xFB1) { - if (chests_in_room.size() > 0) { - tilesObjects.back().options |= ObjectOption::Chest; - chest_list.push_back( - Chest(posX + 1, posY, chests_in_room.front().itemIn, true)); - chests_in_room.erase(chests_in_room.begin()); + if (chests_in_room_.size() > 0) { + tile_objects_.back().set_options(ObjectOption::Chest | + tile_objects_.back().options()); + // chest_list_.push_back( + // Chest(posX + 1, posY, chests_in_room_.front().item_in, true)); + chests_in_room_.erase(chests_in_room_.begin()); } } } else { - tilesObjects.push_back(object_door(static_cast((b2 << 8) + b1), 0, - 0, 0, static_cast(layer))); - } - - **/ + // tile_objects_.push_back(object_door(static_cast((b2 << 8) + b1), + // 0, + // 0, 0, static_cast(layer))); } } } @@ -443,23 +437,23 @@ void Room::LoadSprites() { break; } - // sprites_.emplace_back(this, b3, (b2 & 0x1F), (b1 & 0x1F), - // ((b2 & 0xE0) >> 5) + ((b1 & 0x60) >> 2), - // (b1 & 0x80) >> 7); + sprites_.emplace_back(b3, (b2 & 0x1F), (b1 & 0x1F), + ((b2 & 0xE0) >> 5) + ((b1 & 0x60) >> 2), + (b1 & 0x80) >> 7); if (sprites_.size() > 1) { - Sprite& spr = sprites_.back(); - Sprite& prevSprite = sprites_[sprites_.size() - 2]; + Sprite &spr = sprites_.back(); + Sprite &prevSprite = sprites_[sprites_.size() - 2]; if (spr.id() == 0xE4 && spr.x() == 0x00 && spr.y() == 0x1E && spr.layer() == 1 && spr.subtype() == 0x18) { - // prevSprite.keyDrop() = 1; + prevSprite.set_key_drop(1); sprites_.pop_back(); } if (spr.id() == 0xE4 && spr.x() == 0x00 && spr.y() == 0x1D && spr.layer() == 1 && spr.subtype() == 0x18) { - // prevSprite.keyDrop() = 2; + prevSprite.set_key_drop(2); sprites_.pop_back(); } } @@ -470,12 +464,11 @@ void Room::LoadSprites() { void Room::LoadChests() { auto rom_data = rom()->vector(); - int cpos = (rom_data[chests_data_pointer1 + 2] << 16) + - (rom_data[chests_data_pointer1 + 1] << 8) + - (rom_data[chests_data_pointer1]); - cpos = core::SnesToPc(cpos); - int clength = (rom_data[chests_length_pointer + 1] << 8) + - (rom_data[chests_length_pointer]); + uint32_t cpos = core::SnesToPc((rom_data[chests_data_pointer1 + 2] << 16) + + (rom_data[chests_data_pointer1 + 1] << 8) + + (rom_data[chests_data_pointer1])); + size_t clength = (rom_data[chests_length_pointer + 1] << 8) + + (rom_data[chests_length_pointer]); for (int i = 0; i < clength; i++) { if ((((rom_data[cpos + (i * 3) + 1] << 8) + (rom_data[cpos + (i * 3)])) & @@ -483,13 +476,12 @@ void Room::LoadChests() { // There's a chest in that room ! bool big = false; if ((((rom_data[cpos + (i * 3) + 1] << 8) + (rom_data[cpos + (i * 3)])) & - 0x8000) == 0x8000) // ????? - { + 0x8000) == 0x8000) { big = true; } chests_in_room_.emplace_back( - ChestData(rom_data[cpos + (i * 3) + 2], big)); + z3_chest_data(rom_data[cpos + (i * 3) + 2], big)); } } } diff --git a/src/app/zelda3/dungeon/room.h b/src/app/zelda3/dungeon/room.h index db970b3f..533aa57d 100644 --- a/src/app/zelda3/dungeon/room.h +++ b/src/app/zelda3/dungeon/room.h @@ -1,17 +1,20 @@ #ifndef YAZE_APP_ZELDA3_DUNGEON_ROOM_H #define YAZE_APP_ZELDA3_DUNGEON_ROOM_H +#include + #include +#include +#include +#include #include -#include "app/core/common.h" #include "app/core/constants.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" #include "app/rom.h" -#include "app/zelda3/dungeon/room_names.h" #include "app/zelda3/dungeon/room_object.h" #include "app/zelda3/sprite/sprite.h" @@ -80,47 +83,16 @@ constexpr int door_pos_right = 0x19C6; constexpr int dungeon_spr_ptrs = 0x090000; +constexpr int NumberOfRooms = 296; + constexpr ushort stairsObjects[] = {0x139, 0x138, 0x13B, 0x12E, 0x12D}; -class DungeonDestination { - public: - DungeonDestination() = default; - ~DungeonDestination() = default; - DungeonDestination(uint8_t i) : Index(i) {} - - uint8_t Index; - uint8_t Target = 0; - uint8_t TargetLayer = 0; -}; - -struct object_door { - object_door() = default; - object_door(short id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer) - : id_(id), x_(x), y_(y), size_(size), layer_(layer) {} - - short id_; - uint8_t x_; - uint8_t y_; - uint8_t size_; - uint8_t type_; - uint8_t layer_; -}; - -struct ChestData { - ChestData() = default; - ChestData(uchar i, bool s) : id_(i), size_(s){}; - - uchar id_; - bool size_; -}; - -struct StaircaseRooms {}; - -class Room : public SharedRom, public core::ExperimentFlags { +class Room : public SharedRom { public: Room() = default; Room(int room_id) : room_id_(room_id) {} ~Room() = default; + void LoadHeader(); void LoadRoomFromROM(); @@ -133,7 +105,7 @@ class Room : public SharedRom, public core::ExperimentFlags { void LoadChests(); auto blocks() const { return blocks_; } - auto& mutable_blocks() { return blocks_; } + auto &mutable_blocks() { return blocks_; } auto layer1() const { return background_bmps_[0]; } auto layer2() const { return background_bmps_[1]; } auto layer3() const { return background_bmps_[2]; } @@ -191,25 +163,457 @@ class Room : public SharedRom, public core::ExperimentFlags { std::array chest_list_; std::array background_bmps_; - std::vector sprites_; - std::vector staircase_rooms_vec_; - - Background2 bg2_; - DungeonDestination pits_; - DungeonDestination stair1_; - DungeonDestination stair2_; - DungeonDestination stair3_; - DungeonDestination stair4_; - - std::vector chests_in_room_; std::vector tile_objects_; + std::vector sprites_; + std::vector z3_staircases_; + std::vector chests_in_room_; - std::vector room_addresses_; + z3_dungeon_background2 bg2_; + z3_dungeon_destination pits_; + z3_dungeon_destination stair1_; + z3_dungeon_destination stair2_; + z3_dungeon_destination stair3_; + z3_dungeon_destination stair4_; }; +constexpr std::string_view kRoomNames[] = { + "Ganon", + "Hyrule Castle (North Corridor)", + "Behind Sanctuary (Switch)", + "Houlihan", + "Turtle Rock (Crysta-Roller)", + "Empty", + "Swamp Palace (Arrghus[Boss])", + "Tower of Hera (Moldorm[Boss])", + "Cave (Healing Fairy)", + "Palace of Darkness", + "Palace of Darkness (Stalfos Trap)", + "Palace of Darkness (Turtle)", + "Ganon's Tower (Entrance)", + "Ganon's Tower (Agahnim2[Boss])", + "Ice Palace (Entrance )", + "Empty Clone ", + "Ganon Evacuation Route", + "Hyrule Castle (Bombable Stock )", + "Sanctuary", + "Turtle Rock (Hokku-Bokku Key 2)", + "Turtle Rock (Big Key )", + "Turtle Rock", + "Swamp Palace (Swimming Treadmill)", + "Tower of Hera (Moldorm Fall )", + "Cave", + "Palace of Darkness (Dark Maze)", + "Palace of Darkness (Big Chest )", + "Palace of Darkness (Mimics / Moving Wall )", + "Ganon's Tower (Ice Armos)", + "Ganon's Tower (Final Hallway)", + "Ice Palace (Bomb Floor / Bari )", + "Ice Palace (Pengator / Big Key )", + "Agahnim's Tower (Agahnim[Boss])", + "Hyrule Castle (Key-rat )", + "Hyrule Castle (Sewer Text Trigger )", + "Turtle Rock (West Exit to Balcony)", + "Turtle Rock (Double Hokku-Bokku / Big chest )", + "Empty Clone ", + "Swamp Palace (Statue )", + "Tower of Hera (Big Chest)", + "Swamp Palace (Entrance )", + "Skull Woods (Mothula[Boss])", + "Palace of Darkness (Big Hub )", + "Palace of Darkness (Map Chest / Fairy )", + "Cave", + "Empty Clone ", + "Ice Palace (Compass )", + "Cave (Kakariko Well HP)", + "Agahnim's Tower (Maiden Sacrifice Chamber)", + "Tower of Hera (Hardhat Beetles )", + "Hyrule Castle (Sewer Key Chest )", + "Desert Palace (Lanmolas[Boss])", + "Swamp Palace (Push Block Puzzle / Pre-Big Key )", + "Swamp Palace (Big Key / BS )", + "Swamp Palace (Big Chest )", + "Swamp Palace (Map Chest / Water Fill )", + "Swamp Palace (Key Pot )", + "Skull Woods (Gibdo Key / Mothula Hole )", + "Palace of Darkness (Bombable Floor )", + "Palace of Darkness (Spike Block / Conveyor )", + "Cave", + "Ganon's Tower (Torch 2)", + "Ice Palace (Stalfos Knights / Conveyor Hellway)", + "Ice Palace (Map Chest )", + "Agahnim's Tower (Final Bridge )", + "Hyrule Castle (First Dark )", + "Hyrule Castle (6 Ropes )", + "Desert Palace (Torch Puzzle / Moving Wall )", + "Thieves Town (Big Chest )", + "Thieves Town (Jail Cells )", + "Swamp Palace (Compass Chest )", + "Empty Clone ", + "Empty Clone ", + "Skull Woods (Gibdo Torch Puzzle )", + "Palace of Darkness (Entrance )", + "Palace of Darkness (Warps / South Mimics )", + "Ganon's Tower (Mini-Helmasaur Conveyor )", + "Ganon's Tower (Moldorm )", + "Ice Palace (Bomb-Jump )", + "Ice Palace Clone (Fairy )", + "Hyrule Castle (West Corridor)", + "Hyrule Castle (Throne )", + "Hyrule Castle (East Corridor)", + "Desert Palace (Popos 2 / Beamos Hellway )", + "Swamp Palace (Upstairs Pits )", + "Castle Secret Entrance / Uncle Death ", + "Skull Woods (Key Pot / Trap )", + "Skull Woods (Big Key )", + "Skull Woods (Big Chest )", + "Skull Woods (Final Section Entrance )", + "Palace of Darkness (Helmasaur King[Boss])", + "Ganon's Tower (Spike Pit )", + "Ganon's Tower (Ganon-Ball Z)", + "Ganon's Tower (Gauntlet 1/2/3)", + "Ice Palace (Lonely Firebar)", + "Ice Palace (Hidden Chest / Spike Floor )", + "Hyrule Castle (West Entrance )", + "Hyrule Castle (Main Entrance )", + "Hyrule Castle (East Entrance )", + "Desert Palace (Final Section Entrance )", + "Thieves Town (West Attic )", + "Thieves Town (East Attic )", + "Swamp Palace (Hidden Chest / Hidden Door )", + "Skull Woods (Compass Chest )", + "Skull Woods (Key Chest / Trap )", + "Empty Clone ", + "Palace of Darkness (Rupee )", + "Ganon's Tower (Mimics s)", + "Ganon's Tower (Lanmolas )", + "Ganon's Tower (Gauntlet 4/5)", + "Ice Palace (Pengators )", + "Empty Clone ", + "Hyrule Castle (Small Corridor to Jail Cells)", + "Hyrule Castle (Boomerang Chest )", + "Hyrule Castle (Map Chest )", + "Desert Palace (Big Chest )", + "Desert Palace (Map Chest )", + "Desert Palace (Big Key Chest )", + "Swamp Palace (Water Drain )", + "Tower of Hera (Entrance )", + "Empty Clone ", + "Empty Clone ", + "Empty Clone ", + "Ganon's Tower", + "Ganon's Tower (East Side Collapsing Bridge / Exploding Wall )", + "Ganon's Tower (Winder / Warp Maze )", + "Ice Palace (Hidden Chest / Bombable Floor )", + "Ice Palace ( Big Spike Traps )", + "Hyrule Castle (Jail Cell )", + "Hyrule Castle", + "Hyrule Castle (Basement Chasm )", + "Desert Palace (West Entrance )", + "Desert Palace (Main Entrance )", + "Desert Palace (East Entrance )", + "Empty Clone ", + "Tower of Hera (Tile )", + "Empty Clone ", + "Eastern Palace (Fairy )", + "Empty Clone ", + "Ganon's Tower (Block Puzzle / Spike Skip / Map Chest )", + "Ganon's Tower (East and West Downstairs / Big Chest )", + "Ganon's Tower (Tile / Torch Puzzle )", + "Ice Palace", + "Empty Clone ", + "Misery Mire (Vitreous[Boss])", + "Misery Mire (Final Switch )", + "Misery Mire (Dark Bomb Wall / Switches )", + "Misery Mire (Dark Cane Floor Switch Puzzle )", + "Empty Clone ", + "Ganon's Tower (Final Collapsing Bridge )", + "Ganon's Tower (Torches 1 )", + "Misery Mire (Torch Puzzle / Moving Wall )", + "Misery Mire (Entrance )", + "Eastern Palace (Eyegore Key )", + "Empty Clone ", + "Ganon's Tower (Many Spikes / Warp Maze )", + "Ganon's Tower (Invisible Floor Maze )", + "Ganon's Tower (Compass Chest / Invisible Floor )", + "Ice Palace (Big Chest )", + "Ice Palace", + "Misery Mire (Pre-Vitreous )", + "Misery Mire (Fish )", + "Misery Mire (Bridge Key Chest )", + "Misery Mire", + "Turtle Rock (Trinexx[Boss])", + "Ganon's Tower (Wizzrobes s)", + "Ganon's Tower (Moldorm Fall )", + "Tower of Hera (Fairy )", + "Eastern Palace (Stalfos Spawn )", + "Eastern Palace (Big Chest )", + "Eastern Palace (Map Chest )", + "Thieves Town (Moving Spikes / Key Pot )", + "Thieves Town (Blind The Thief[Boss])", + "Empty Clone ", + "Ice Palace", + "Ice Palace (Ice Bridge )", + "Agahnim's Tower (Circle of Pots)", + "Misery Mire (Hourglass )", + "Misery Mire (Slug )", + "Misery Mire (Spike Key Chest )", + "Turtle Rock (Pre-Trinexx )", + "Turtle Rock (Dark Maze)", + "Turtle Rock (Chain Chomps )", + "Turtle Rock (Map Chest / Key Chest / Roller )", + "Eastern Palace (Big Key )", + "Eastern Palace (Lobby Cannonballs )", + "Eastern Palace (Dark Antifairy / Key Pot )", + "Thieves Town (Hellway)", + "Thieves Town (Conveyor Toilet)", + "Empty Clone ", + "Ice Palace (Block Puzzle )", + "Ice Palace Clone (Switch )", + "Agahnim's Tower (Dark Bridge )", + "Misery Mire (Compass Chest / Tile )", + "Misery Mire (Big Hub )", + "Misery Mire (Big Chest )", + "Turtle Rock (Final Crystal Switch Puzzle )", + "Turtle Rock (Laser Bridge)", + "Turtle Rock", + "Turtle Rock (Torch Puzzle)", + "Eastern Palace (Armos Knights[Boss])", + "Eastern Palace (Entrance )", + "??", + "Thieves Town (North West Entrance )", + "Thieves Town (North East Entrance )", + "Empty Clone ", + "Ice Palace (Hole to Kholdstare )", + "Empty Clone ", + "Agahnim's Tower (Dark Maze)", + "Misery Mire (Conveyor Slug / Big Key )", + "Misery Mire (Mire02 / Wizzrobes )", + "Empty Clone ", + "Empty Clone ", + "Turtle Rock (Laser Key )", + "Turtle Rock (Entrance )", + "Empty Clone ", + "Eastern Palace (Zeldagamer / Pre-Armos Knights )", + "Eastern Palace (Canonball ", + "Eastern Palace", + "Thieves Town (Main (South West) Entrance )", + "Thieves Town (South East Entrance )", + "Empty Clone ", + "Ice Palace (Kholdstare[Boss])", + "Cave", + "Agahnim's Tower (Entrance )", + "Cave (Lost Woods HP)", + "Cave (Lumberjack's Tree HP)", + "Cave (1/2 Magic)", + "Cave (Lost Old Man Final Cave)", + "Cave (Lost Old Man Final Cave)", + "Cave", + "Cave", + "Cave", + "Empty Clone ", + "Cave (Spectacle Rock HP)", + "Cave", + "Empty Clone ", + "Cave", + "Cave (Spiral Cave)", + "Cave (Crystal Switch / 5 Chests )", + "Cave (Lost Old Man Starting Cave)", + "Cave (Lost Old Man Starting Cave)", + "House", + "House (Old Woman (Sahasrahla's Wife?))", + "House (Angry Brothers)", + "House (Angry Brothers)", + "Empty Clone ", + "Empty Clone ", + "Cave", + "Cave", + "Cave", + "Cave", + "Empty Clone ", + "Cave", + "Cave", + "Cave", + + "Chest Minigame", + "Houses", + "Sick Boy house", + "Tavern", + "Link's House", + "Sarashrala Hut", + "Chest Minigame", + "Library", + "Chicken House", + "Witch Shop", + "A Aginah's Cave", + "Dam", + "Mimic Cave", + "Mire Shed", + "Cave", + "Shop", + "Shop", + "Archery Minigame", + "DW Church/Shop", + "Grave Cave", + "Fairy Fountain", + "Fairy Upgrade", + "Pyramid Fairy", + "Spike Cave", + "Chest Minigame", + "Blind Hut", + "Bonzai Cave", + "Circle of bush Cave", + "Big Bomb Shop, C-House", + "Blind Hut 2", + "Hype Cave", + "Shop", + "Ice Cave", + "Smith", + "Fortune Teller", + "MiniMoldorm Cave", + "Under Rock Caves", + "Smith", + "Cave", + "Mazeblock Cave", + "Smith Peg Cave"}; + +constexpr std::string_view kEntranceNames[] = { + "Link's House Intro", + "Link's House Post-intro", + "Sanctuary", + "Hyrule Castle West", + "Hyrule Castle Central", + "Hyrule Castle East", + "Death Mountain Express (Lower)", + "Death Mountain Express (Upper)", + "Eastern Palace", + "Desert Palace Central", + "Desert Palace East", + "Desert Palace West", + "Desert Palace Boss Lair", + "Kakariko Elder's House West", + "Kakariko Elder's House East", + "Kakariko Angry Bros West", + "Kakariko Angry Bros East", + "Mad Batter Lair", + "Under Lumberjacks' Weird Tree", + "Death Mountain Maze 0000", + "Death Mountain Maze 0001", + "Turtle Rock Mountainface 1", + "Death Mountain Cape Heart Piece Cave (Lower)", + "Death Mountain Cape Heart Piece Cave (Upper)", + "Turtle Rock Mountainface 2", + "Turtle Rock Mountainface 3", + "Death Mountain Maze 0002", + "Death Mountain Maze 0003", + "Death Mountain Maze 0004", + "Death Mountain Maze 0005", + "Death Mountain Maze 0006", + "Death Mountain Maze 0007", + "Death Mountain Maze 0008", + "Spectacle Rock Maze 1", + "Spectacle Rock Maze 2", + "Spectacle Rock Maze 3", + "Hyrule Castle Tower", + "Swamp Palace", + "Palace of Darkness", + "Misery Mire", + "Skull Woods 1", + "Skull Woods 2", + "Skull Woods Big Chest", + "Skull Woods Boss Lair", + "Lost Woods Thieves' Lair", + "Ice Palace", + "Death Mountain Escape West", + "Death Mountain Escape East", + "Death Mountain Elder's Cave (Lower)", + "Death Mountain Elder's Cave (Upper)", + "Hyrule Castle Secret Cellar", + "Tower of Hera", + "Thieves's Town", + "Turtle Rock Main", + "Ganon's Pyramid Sanctum (Lower)", + "Ganon's Tower", + "Fairy Cave 1", + "Kakariko Western Well", + "Death Mountain Maze 0009", + "Death Mountain Maze 0010", + "Treasure Shell Game 1", + "Storyteller Cave 1", + "Snitch House 1", + "Snitch House 2", + "SickBoy House", + "Byrna Gauntlet", + "Kakariko Pub South", + "Kakariko Pub North", + "Kakariko Inn", + "Sahasrahlah's Disco Infernum", + "Kakariko's Lame Shop", + "Village of Outcasts Chest Game", + "Village of Outcasts Orphanage", + "Kakariko Library", + "Kakariko Storage Shed", + "Kakariko Sweeper Lady's House", + "Potion Shop", + "Aginah's Desert Cottage", + "Watergate", + "Death Mountain Maze 0011", + "Fairy Cave 2", + "Refill Cave 0001", + "Refill Cave 0002", + "The Bomb \"Shop\"", + "Village of Outcasts Retirement Center", + "Fairy Cave 3", + "Good Bee Cave", + "General Store 1", + "General Store 2", + "Archery Game", + "Storyteller Cave 2", + "Hall of the Invisibility Cape", + "Pond of Wishing", + "Pond of Happiness", + "Fairy Cave 4", + "Swamp of Evil Heart Piece Hall", + "General Store 3", + "Blind's Old Hideout", + "Storyteller Cave 3", + "Warped Pond of Wishing", + "Chez Smithies", + "Fortune Teller 1", + "Fortune Teller 2", + "Chest Shell Game 2", + "Storyteller Cave 4", + "Storyteller Cave 5", + "Storyteller Cave 6", + "Village House 1", + "Thief Hideout 1", + "Thief Hideout 2", + "Heart Piece Cave 1", + "Thief Hideout 3", + "Refill Cave 3", + "Fairy Cave 5", + "Heart Piece Cave 2", + "Hyrule Castle Prison", + "Hyrule Castle Throne Room", + "Hyrule Tower Agahnim's Sanctum", + "Skull Woods 3 (Drop In)", + "Skull Woods 4 (Drop In)", + "Skull Woods 5 (Drop In)", + "Skull Woods 6 (Drop In)", + "Lost Woods Thieves' Hideout (Drop In)", + "Ganon's Pyramid Sanctum (Upper)", + "Fairy Cave 6 (Drop In)", + "Hyrule Castle Secret Cellar (Drop In)", + "Mad Batter Lair (Drop In)", + "Under Lumberjacks' Weird Tree (Drop In)", + "Kakariko Western Well (Drop In)", + "Hyrule Sewers Goodies Room (Drop In)", + "Chris Houlihan Room (Drop In)", + "Heart Piece Cave 3 (Drop In)", + "Ice Rod Cave"}; + } // namespace dungeon } // namespace zelda3 } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/zelda3/dungeon/room_entrance.h b/src/app/zelda3/dungeon/room_entrance.h index 4e67bed6..074d9c42 100644 --- a/src/app/zelda3/dungeon/room_entrance.h +++ b/src/app/zelda3/dungeon/room_entrance.h @@ -15,55 +15,55 @@ namespace dungeon { // ============================================================================ // 0x14577 word value for each room -constexpr int entrance_room = 0x14813; +constexpr int kEntranceRoom = 0x14813; // 8 bytes per room, HU, FU, HD, FD, HL, FL, HR, FR -constexpr int entrance_scrolledge = 0x1491D; // 0x14681 -constexpr int entrance_yscroll = 0x14D45; // 0x14AA9 2 bytes each room -constexpr int entrance_xscroll = 0x14E4F; // 0x14BB3 2 bytes -constexpr int entrance_yposition = 0x14F59; // 0x14CBD 2bytes -constexpr int entrance_xposition = 0x15063; // 0x14DC7 2bytes -constexpr int entrance_cameraytrigger = 0x1516D; // 0x14ED1 2bytes -constexpr int entrance_cameraxtrigger = 0x15277; // 0x14FDB 2bytes +constexpr int kEntranceScrollEdge = 0x1491D; // 0x14681 +constexpr int kEntranceYScroll = 0x14D45; // 0x14AA9 2 bytes each room +constexpr int kEntranceXScroll = 0x14E4F; // 0x14BB3 2 bytes +constexpr int kEntranceYPosition = 0x14F59; // 0x14CBD 2bytes +constexpr int kEntranceXPosition = 0x15063; // 0x14DC7 2bytes +constexpr int kEntranceCameraYTrigger = 0x1516D; // 0x14ED1 2bytes +constexpr int kEntranceCameraXTrigger = 0x15277; // 0x14FDB 2bytes -constexpr int entrance_blockset = 0x15381; // 0x150E5 1byte -constexpr int entrance_floor = 0x15406; // 0x1516A 1byte -constexpr int entrance_dungeon = 0x1548B; // 0x151EF 1byte (dungeon id) -constexpr int entrance_door = 0x15510; // 0x15274 1byte +constexpr int kEntranceBlockset = 0x15381; // 0x150E5 1byte +constexpr int kEntranceFloor = 0x15406; // 0x1516A 1byte +constexpr int kEntranceDungeon = 0x1548B; // 0x151EF 1byte (dungeon id) +constexpr int kEntranceDoor = 0x15510; // 0x15274 1byte // 1 byte, ---b ---a b = bg2, a = need to check -constexpr int entrance_ladderbg = 0x15595; // 0x152F9 -constexpr int entrance_scrolling = 0x1561A; // 0x1537E 1byte --h- --v- -constexpr int entrance_scrollquadrant = 0x1569F; // 0x15403 1byte -constexpr int entrance_exit = 0x15724; // 0x15488 2byte word -constexpr int entrance_music = 0x1582E; // 0x15592 +constexpr int kEntranceLadderBG = 0x15595; // 0x152F9 +constexpr int kEntrancescrolling = 0x1561A; // 0x1537E 1byte --h- --v- +constexpr int kEntranceScrollQuadrant = 0x1569F; // 0x15403 1byte +constexpr int kEntranceExit = 0x15724; // 0x15488 2byte word +constexpr int kEntranceMusic = 0x1582E; // 0x15592 // word value for each room -constexpr int startingentrance_room = 0x15B6E; // 0x158D2 +constexpr int kStartingEntranceroom = 0x15B6E; // 0x158D2 // 8 bytes per room, HU, FU, HD, FD, HL, FL, HR, FR -constexpr int startingentrance_scrolledge = 0x15B7C; // 0x158E0 -constexpr int startingentrance_yscroll = 0x15BB4; // 0x14AA9 //2bytes each room -constexpr int startingentrance_xscroll = 0x15BC2; // 0x14BB3 //2bytes -constexpr int startingentrance_yposition = 0x15BD0; // 0x14CBD 2bytes -constexpr int startingentrance_xposition = 0x15BDE; // 0x14DC7 2bytes -constexpr int startingentrance_cameraytrigger = 0x15BEC; // 0x14ED1 2bytes -constexpr int startingentrance_cameraxtrigger = 0x15BFA; // 0x14FDB 2bytes +constexpr int kStartingEntranceScrollEdge = 0x15B7C; // 0x158E0 +constexpr int kStartingEntranceYScroll = 0x15BB4; // 0x14AA9 //2bytes each room +constexpr int kStartingEntranceXScroll = 0x15BC2; // 0x14BB3 //2bytes +constexpr int kStartingEntranceYPosition = 0x15BD0; // 0x14CBD 2bytes +constexpr int kStartingEntranceXPosition = 0x15BDE; // 0x14DC7 2bytes +constexpr int kStartingEntranceCameraYTrigger = 0x15BEC; // 0x14ED1 2bytes +constexpr int kStartingEntranceCameraXTrigger = 0x15BFA; // 0x14FDB 2bytes -constexpr int startingentrance_blockset = 0x15C08; // 0x150E5 1byte -constexpr int startingentrance_floor = 0x15C0F; // 0x1516A 1byte -constexpr int startingentrance_dungeon = 0x15C16; // 0x151EF 1byte (dungeon id) +constexpr int kStartingEntranceBlockset = 0x15C08; // 0x150E5 1byte +constexpr int kStartingEntranceFloor = 0x15C0F; // 0x1516A 1byte +constexpr int kStartingEntranceDungeon = 0x15C16; // 0x151EF 1byte (dungeon id) -constexpr int startingentrance_door = 0x15C2B; // 0x15274 1byte +constexpr int kStartingEntranceDoor = 0x15C2B; // 0x15274 1byte // 1 byte, ---b ---a b = bg2, a = need to check -constexpr int startingentrance_ladderbg = 0x15C1D; // 0x152F9 +constexpr int kStartingEntranceLadderBG = 0x15C1D; // 0x152F9 // 1byte --h- --v- -constexpr int startingentrance_scrolling = 0x15C24; // 0x1537E -constexpr int startingentrance_scrollquadrant = 0x15C2B; // 0x15403 1byte -constexpr int startingentrance_exit = 0x15C32; // 0x15488 //2byte word -constexpr int startingentrance_music = 0x15C4E; // 0x15592 -constexpr int startingentrance_entrance = 0x15C40; +constexpr int kStartingEntrancescrolling = 0x15C24; // 0x1537E +constexpr int kStartingEntranceScrollQuadrant = 0x15C2B; // 0x15403 1byte +constexpr int kStartingEntranceexit = 0x15C32; // 0x15488 //2byte word +constexpr int kStartingEntrancemusic = 0x15C4E; // 0x15592 +constexpr int kStartingEntranceentrance = 0x15C40; constexpr int items_data_start = 0xDDE9; // save purpose constexpr int items_data_end = 0xE6B2; // save purpose @@ -99,221 +99,223 @@ constexpr int bedPositionResetYHigh = 0x02DE62; constexpr int bedSheetPositionX = 0x0480BD; // short value constexpr int bedSheetPositionY = 0x0480B8; // short value +/** + * @brief Dungeon Room Entrance or Spawn Point + */ class RoomEntrance { public: RoomEntrance() = default; - - RoomEntrance(Rom& rom, uint8_t entrance_id, bool is_spawn_point = false) + RoomEntrance(Rom &rom, uint8_t entrance_id, bool is_spawn_point = false) : entrance_id_(entrance_id) { room_ = - static_cast((rom[entrance_room + (entrance_id * 2) + 1] << 8) + - rom[entrance_room + (entrance_id * 2)]); + static_cast((rom[kEntranceRoom + (entrance_id * 2) + 1] << 8) + + rom[kEntranceRoom + (entrance_id * 2)]); y_position_ = static_cast( - (rom[entrance_yposition + (entrance_id * 2) + 1] << 8) + - rom[entrance_yposition + (entrance_id * 2)]); + (rom[kEntranceYPosition + (entrance_id * 2) + 1] << 8) + + rom[kEntranceYPosition + (entrance_id * 2)]); x_position_ = static_cast( - (rom[entrance_xposition + (entrance_id * 2) + 1] << 8) + - rom[entrance_xposition + (entrance_id * 2)]); + (rom[kEntranceXPosition + (entrance_id * 2) + 1] << 8) + + rom[kEntranceXPosition + (entrance_id * 2)]); camera_x_ = static_cast( - (rom[entrance_xscroll + (entrance_id * 2) + 1] << 8) + - rom[entrance_xscroll + (entrance_id * 2)]); + (rom[kEntranceXScroll + (entrance_id * 2) + 1] << 8) + + rom[kEntranceXScroll + (entrance_id * 2)]); camera_y_ = static_cast( - (rom[entrance_yscroll + (entrance_id * 2) + 1] << 8) + - rom[entrance_yscroll + (entrance_id * 2)]); + (rom[kEntranceYScroll + (entrance_id * 2) + 1] << 8) + + rom[kEntranceYScroll + (entrance_id * 2)]); camera_trigger_y_ = static_cast( - (rom[(entrance_cameraytrigger + (entrance_id * 2)) + 1] << 8) + - rom[entrance_cameraytrigger + (entrance_id * 2)]); + (rom[(kEntranceCameraYTrigger + (entrance_id * 2)) + 1] << 8) + + rom[kEntranceCameraYTrigger + (entrance_id * 2)]); camera_trigger_x_ = static_cast( - (rom[(entrance_cameraxtrigger + (entrance_id * 2)) + 1] << 8) + - rom[entrance_cameraxtrigger + (entrance_id * 2)]); - blockset_ = rom[entrance_blockset + entrance_id]; - music_ = rom[entrance_music + entrance_id]; - dungeon_id_ = rom[entrance_dungeon + entrance_id]; - floor_ = rom[entrance_floor + entrance_id]; - door_ = rom[entrance_door + entrance_id]; - ladder_bg_ = rom[entrance_ladderbg + entrance_id]; - scrolling_ = rom[entrance_scrolling + entrance_id]; - scroll_quadrant_ = rom[entrance_scrollquadrant + entrance_id]; + (rom[(kEntranceCameraXTrigger + (entrance_id * 2)) + 1] << 8) + + rom[kEntranceCameraXTrigger + (entrance_id * 2)]); + blockset_ = rom[kEntranceBlockset + entrance_id]; + music_ = rom[kEntranceMusic + entrance_id]; + dungeon_id_ = rom[kEntranceDungeon + entrance_id]; + floor_ = rom[kEntranceFloor + entrance_id]; + door_ = rom[kEntranceDoor + entrance_id]; + ladder_bg_ = rom[kEntranceLadderBG + entrance_id]; + scrolling_ = rom[kEntrancescrolling + entrance_id]; + scroll_quadrant_ = rom[kEntranceScrollQuadrant + entrance_id]; exit_ = - static_cast((rom[entrance_exit + (entrance_id * 2) + 1] << 8) + - rom[entrance_exit + (entrance_id * 2)]); + static_cast((rom[kEntranceExit + (entrance_id * 2) + 1] << 8) + + rom[kEntranceExit + (entrance_id * 2)]); - camera_boundary_qn_ = rom[entrance_scrolledge + 0 + (entrance_id * 8)]; - camera_boundary_fn_ = rom[entrance_scrolledge + 1 + (entrance_id * 8)]; - camera_boundary_qs_ = rom[entrance_scrolledge + 2 + (entrance_id * 8)]; - camera_boundary_fs_ = rom[entrance_scrolledge + 3 + (entrance_id * 8)]; - camera_boundary_qw_ = rom[entrance_scrolledge + 4 + (entrance_id * 8)]; - camera_boundary_fw_ = rom[entrance_scrolledge + 5 + (entrance_id * 8)]; - camera_boundary_qe_ = rom[entrance_scrolledge + 6 + (entrance_id * 8)]; - camera_boundary_fe_ = rom[entrance_scrolledge + 7 + (entrance_id * 8)]; + camera_boundary_qn_ = rom[kEntranceScrollEdge + 0 + (entrance_id * 8)]; + camera_boundary_fn_ = rom[kEntranceScrollEdge + 1 + (entrance_id * 8)]; + camera_boundary_qs_ = rom[kEntranceScrollEdge + 2 + (entrance_id * 8)]; + camera_boundary_fs_ = rom[kEntranceScrollEdge + 3 + (entrance_id * 8)]; + camera_boundary_qw_ = rom[kEntranceScrollEdge + 4 + (entrance_id * 8)]; + camera_boundary_fw_ = rom[kEntranceScrollEdge + 5 + (entrance_id * 8)]; + camera_boundary_qe_ = rom[kEntranceScrollEdge + 6 + (entrance_id * 8)]; + camera_boundary_fe_ = rom[kEntranceScrollEdge + 7 + (entrance_id * 8)]; if (is_spawn_point) { room_ = static_cast( - (rom[startingentrance_room + (entrance_id * 2) + 1] << 8) + - rom[startingentrance_room + (entrance_id * 2)]); + (rom[kStartingEntranceroom + (entrance_id * 2) + 1] << 8) + + rom[kStartingEntranceroom + (entrance_id * 2)]); y_position_ = static_cast( - (rom[startingentrance_yposition + (entrance_id * 2) + 1] << 8) + - rom[startingentrance_yposition + (entrance_id * 2)]); + (rom[kStartingEntranceYPosition + (entrance_id * 2) + 1] << 8) + + rom[kStartingEntranceYPosition + (entrance_id * 2)]); x_position_ = static_cast( - (rom[startingentrance_xposition + (entrance_id * 2) + 1] << 8) + - rom[startingentrance_xposition + (entrance_id * 2)]); + (rom[kStartingEntranceXPosition + (entrance_id * 2) + 1] << 8) + + rom[kStartingEntranceXPosition + (entrance_id * 2)]); camera_x_ = static_cast( - (rom[startingentrance_xscroll + (entrance_id * 2) + 1] << 8) + - rom[startingentrance_xscroll + (entrance_id * 2)]); + (rom[kStartingEntranceXScroll + (entrance_id * 2) + 1] << 8) + + rom[kStartingEntranceXScroll + (entrance_id * 2)]); camera_y_ = static_cast( - (rom[startingentrance_yscroll + (entrance_id * 2) + 1] << 8) + - rom[startingentrance_yscroll + (entrance_id * 2)]); + (rom[kStartingEntranceYScroll + (entrance_id * 2) + 1] << 8) + + rom[kStartingEntranceYScroll + (entrance_id * 2)]); camera_trigger_y_ = static_cast( - (rom[startingentrance_cameraytrigger + (entrance_id * 2) + 1] << 8) + - rom[startingentrance_cameraytrigger + (entrance_id * 2)]); + (rom[kStartingEntranceCameraYTrigger + (entrance_id * 2) + 1] << 8) + + rom[kStartingEntranceCameraYTrigger + (entrance_id * 2)]); camera_trigger_x_ = static_cast( - (rom[startingentrance_cameraxtrigger + (entrance_id * 2) + 1] << 8) + - rom[startingentrance_cameraxtrigger + (entrance_id * 2)]); + (rom[kStartingEntranceCameraXTrigger + (entrance_id * 2) + 1] << 8) + + rom[kStartingEntranceCameraXTrigger + (entrance_id * 2)]); - blockset_ = rom[startingentrance_blockset + entrance_id]; - music_ = rom[startingentrance_music + entrance_id]; - dungeon_id_ = rom[startingentrance_dungeon + entrance_id]; - floor_ = rom[startingentrance_floor + entrance_id]; - door_ = rom[startingentrance_door + entrance_id]; + blockset_ = rom[kStartingEntranceBlockset + entrance_id]; + music_ = rom[kStartingEntrancemusic + entrance_id]; + dungeon_id_ = rom[kStartingEntranceDungeon + entrance_id]; + floor_ = rom[kStartingEntranceFloor + entrance_id]; + door_ = rom[kStartingEntranceDoor + entrance_id]; - ladder_bg_ = rom[startingentrance_ladderbg + entrance_id]; - scrolling_ = rom[startingentrance_scrolling + entrance_id]; - scroll_quadrant_ = rom[startingentrance_scrollquadrant + entrance_id]; + ladder_bg_ = rom[kStartingEntranceLadderBG + entrance_id]; + scrolling_ = rom[kStartingEntrancescrolling + entrance_id]; + scroll_quadrant_ = rom[kStartingEntranceScrollQuadrant + entrance_id]; exit_ = static_cast( - ((rom[startingentrance_exit + (entrance_id * 2) + 1] & 0x01) << 8) + - rom[startingentrance_exit + (entrance_id * 2)]); + ((rom[kStartingEntranceexit + (entrance_id * 2) + 1] & 0x01) << 8) + + rom[kStartingEntranceexit + (entrance_id * 2)]); camera_boundary_qn_ = - rom[startingentrance_scrolledge + 0 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 0 + (entrance_id * 8)]; camera_boundary_fn_ = - rom[startingentrance_scrolledge + 1 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 1 + (entrance_id * 8)]; camera_boundary_qs_ = - rom[startingentrance_scrolledge + 2 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 2 + (entrance_id * 8)]; camera_boundary_fs_ = - rom[startingentrance_scrolledge + 3 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 3 + (entrance_id * 8)]; camera_boundary_qw_ = - rom[startingentrance_scrolledge + 4 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 4 + (entrance_id * 8)]; camera_boundary_fw_ = - rom[startingentrance_scrolledge + 5 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 5 + (entrance_id * 8)]; camera_boundary_qe_ = - rom[startingentrance_scrolledge + 6 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 6 + (entrance_id * 8)]; camera_boundary_fe_ = - rom[startingentrance_scrolledge + 7 + (entrance_id * 8)]; + rom[kStartingEntranceScrollEdge + 7 + (entrance_id * 8)]; } } - absl::Status Save(Rom& rom, int entrance_id, bool is_spawn_point = false) { + absl::Status Save(Rom &rom, int entrance_id, bool is_spawn_point = false) { if (!is_spawn_point) { RETURN_IF_ERROR( - rom.WriteShort(entrance_yposition + (entrance_id * 2), y_position_)); + rom.WriteShort(kEntranceYPosition + (entrance_id * 2), y_position_)); RETURN_IF_ERROR( - rom.WriteShort(entrance_xposition + (entrance_id * 2), x_position_)); + rom.WriteShort(kEntranceXPosition + (entrance_id * 2), x_position_)); RETURN_IF_ERROR( - rom.WriteShort(entrance_yscroll + (entrance_id * 2), camera_y_)); + rom.WriteShort(kEntranceYScroll + (entrance_id * 2), camera_y_)); RETURN_IF_ERROR( - rom.WriteShort(entrance_xscroll + (entrance_id * 2), camera_x_)); + rom.WriteShort(kEntranceXScroll + (entrance_id * 2), camera_x_)); RETURN_IF_ERROR(rom.WriteShort( - entrance_cameraxtrigger + (entrance_id * 2), camera_trigger_x_)); + kEntranceCameraXTrigger + (entrance_id * 2), camera_trigger_x_)); RETURN_IF_ERROR(rom.WriteShort( - entrance_cameraytrigger + (entrance_id * 2), camera_trigger_y_)); - RETURN_IF_ERROR(rom.WriteShort(entrance_exit + (entrance_id * 2), exit_)); - RETURN_IF_ERROR(rom.Write(entrance_blockset + entrance_id, + kEntranceCameraYTrigger + (entrance_id * 2), camera_trigger_y_)); + RETURN_IF_ERROR(rom.WriteShort(kEntranceExit + (entrance_id * 2), exit_)); + RETURN_IF_ERROR(rom.Write(kEntranceBlockset + entrance_id, (uint8_t)(blockset_ & 0xFF))); RETURN_IF_ERROR( - rom.Write(entrance_music + entrance_id, (uint8_t)(music_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(entrance_dungeon + entrance_id, + rom.Write(kEntranceMusic + entrance_id, (uint8_t)(music_ & 0xFF))); + RETURN_IF_ERROR(rom.Write(kEntranceDungeon + entrance_id, (uint8_t)(dungeon_id_ & 0xFF))); RETURN_IF_ERROR( - rom.Write(entrance_door + entrance_id, (uint8_t)(door_ & 0xFF))); + rom.Write(kEntranceDoor + entrance_id, (uint8_t)(door_ & 0xFF))); RETURN_IF_ERROR( - rom.Write(entrance_floor + entrance_id, (uint8_t)(floor_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(entrance_ladderbg + entrance_id, + rom.Write(kEntranceFloor + entrance_id, (uint8_t)(floor_ & 0xFF))); + RETURN_IF_ERROR(rom.Write(kEntranceLadderBG + entrance_id, (uint8_t)(ladder_bg_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(entrance_scrolling + entrance_id, + RETURN_IF_ERROR(rom.Write(kEntrancescrolling + entrance_id, (uint8_t)(scrolling_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(entrance_scrollquadrant + entrance_id, + RETURN_IF_ERROR(rom.Write(kEntranceScrollQuadrant + entrance_id, (uint8_t)(scroll_quadrant_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 0 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 0 + (entrance_id * 8), camera_boundary_qn_)); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 1 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 1 + (entrance_id * 8), camera_boundary_fn_)); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 2 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 2 + (entrance_id * 8), camera_boundary_qs_)); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 3 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 3 + (entrance_id * 8), camera_boundary_fs_)); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 4 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 4 + (entrance_id * 8), camera_boundary_qw_)); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 5 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 5 + (entrance_id * 8), camera_boundary_fw_)); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 6 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 6 + (entrance_id * 8), camera_boundary_qe_)); - RETURN_IF_ERROR(rom.Write(entrance_scrolledge + 7 + (entrance_id * 8), + RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 7 + (entrance_id * 8), camera_boundary_fe_)); } else { RETURN_IF_ERROR( - rom.WriteShort(startingentrance_room + (entrance_id * 2), room_)); + rom.WriteShort(kStartingEntranceroom + (entrance_id * 2), room_)); RETURN_IF_ERROR(rom.WriteShort( - startingentrance_yposition + (entrance_id * 2), y_position_)); + kStartingEntranceYPosition + (entrance_id * 2), y_position_)); RETURN_IF_ERROR(rom.WriteShort( - startingentrance_xposition + (entrance_id * 2), x_position_)); + kStartingEntranceXPosition + (entrance_id * 2), x_position_)); RETURN_IF_ERROR(rom.WriteShort( - startingentrance_yscroll + (entrance_id * 2), camera_y_)); + kStartingEntranceYScroll + (entrance_id * 2), camera_y_)); RETURN_IF_ERROR(rom.WriteShort( - startingentrance_xscroll + (entrance_id * 2), camera_x_)); + kStartingEntranceXScroll + (entrance_id * 2), camera_x_)); RETURN_IF_ERROR( - rom.WriteShort(startingentrance_cameraxtrigger + (entrance_id * 2), + rom.WriteShort(kStartingEntranceCameraXTrigger + (entrance_id * 2), camera_trigger_x_)); RETURN_IF_ERROR( - rom.WriteShort(startingentrance_cameraytrigger + (entrance_id * 2), + rom.WriteShort(kStartingEntranceCameraYTrigger + (entrance_id * 2), camera_trigger_y_)); RETURN_IF_ERROR( - rom.WriteShort(startingentrance_exit + (entrance_id * 2), exit_)); - RETURN_IF_ERROR(rom.Write(startingentrance_blockset + entrance_id, + rom.WriteShort(kStartingEntranceexit + (entrance_id * 2), exit_)); + RETURN_IF_ERROR(rom.Write(kStartingEntranceBlockset + entrance_id, (uint8_t)(blockset_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(startingentrance_music + entrance_id, + RETURN_IF_ERROR(rom.Write(kStartingEntrancemusic + entrance_id, (uint8_t)(music_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(startingentrance_dungeon + entrance_id, + RETURN_IF_ERROR(rom.Write(kStartingEntranceDungeon + entrance_id, (uint8_t)(dungeon_id_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(startingentrance_door + entrance_id, + RETURN_IF_ERROR(rom.Write(kStartingEntranceDoor + entrance_id, (uint8_t)(door_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(startingentrance_floor + entrance_id, + RETURN_IF_ERROR(rom.Write(kStartingEntranceFloor + entrance_id, (uint8_t)(floor_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(startingentrance_ladderbg + entrance_id, + RETURN_IF_ERROR(rom.Write(kStartingEntranceLadderBG + entrance_id, (uint8_t)(ladder_bg_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(startingentrance_scrolling + entrance_id, + RETURN_IF_ERROR(rom.Write(kStartingEntrancescrolling + entrance_id, (uint8_t)(scrolling_ & 0xFF))); - RETURN_IF_ERROR(rom.Write(startingentrance_scrollquadrant + entrance_id, + RETURN_IF_ERROR(rom.Write(kStartingEntranceScrollQuadrant + entrance_id, (uint8_t)(scroll_quadrant_ & 0xFF))); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 0 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 0 + (entrance_id * 8), camera_boundary_qn_)); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 1 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 1 + (entrance_id * 8), camera_boundary_fn_)); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 2 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 2 + (entrance_id * 8), camera_boundary_qs_)); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 3 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 3 + (entrance_id * 8), camera_boundary_fs_)); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 4 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 4 + (entrance_id * 8), camera_boundary_qw_)); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 5 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 5 + (entrance_id * 8), camera_boundary_fw_)); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 6 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 6 + (entrance_id * 8), camera_boundary_qe_)); RETURN_IF_ERROR( - rom.Write(startingentrance_scrolledge + 7 + (entrance_id * 8), + rom.Write(kStartingEntranceScrollEdge + 7 + (entrance_id * 8), camera_boundary_fe_)); } return absl::OkStatus(); @@ -353,4 +355,4 @@ class RoomEntrance { } // namespace app } // namespace yaze -#endif // YAZE_APP_ZELDA3_DUNGEON_ROOM_ENTRANCE_H \ No newline at end of file +#endif // YAZE_APP_ZELDA3_DUNGEON_ROOM_ENTRANCE_H diff --git a/src/app/zelda3/dungeon/room_names.h b/src/app/zelda3/dungeon/room_names.h deleted file mode 100644 index 53260020..00000000 --- a/src/app/zelda3/dungeon/room_names.h +++ /dev/null @@ -1,453 +0,0 @@ -#ifndef YAZE_APP_ZELDA3_DUNGEON_ROOM_NAMES_H -#define YAZE_APP_ZELDA3_DUNGEON_ROOM_NAMES_H - -#include -#include -#include - -namespace yaze { -namespace app { -namespace zelda3 { -namespace dungeon { - -constexpr std::string_view kRoomNames[] = { - "Ganon", - "Hyrule Castle (North Corridor)", - "Behind Sanctuary (Switch)", - "Houlihan", - "Turtle Rock (Crysta-Roller)", - "Empty", - "Swamp Palace (Arrghus[Boss])", - "Tower of Hera (Moldorm[Boss])", - "Cave (Healing Fairy)", - "Palace of Darkness", - "Palace of Darkness (Stalfos Trap)", - "Palace of Darkness (Turtle)", - "Ganon's Tower (Entrance)", - "Ganon's Tower (Agahnim2[Boss])", - "Ice Palace (Entrance )", - "Empty Clone ", - "Ganon Evacuation Route", - "Hyrule Castle (Bombable Stock )", - "Sanctuary", - "Turtle Rock (Hokku-Bokku Key 2)", - "Turtle Rock (Big Key )", - "Turtle Rock", - "Swamp Palace (Swimming Treadmill)", - "Tower of Hera (Moldorm Fall )", - "Cave", - "Palace of Darkness (Dark Maze)", - "Palace of Darkness (Big Chest )", - "Palace of Darkness (Mimics / Moving Wall )", - "Ganon's Tower (Ice Armos)", - "Ganon's Tower (Final Hallway)", - "Ice Palace (Bomb Floor / Bari )", - "Ice Palace (Pengator / Big Key )", - "Agahnim's Tower (Agahnim[Boss])", - "Hyrule Castle (Key-rat )", - "Hyrule Castle (Sewer Text Trigger )", - "Turtle Rock (West Exit to Balcony)", - "Turtle Rock (Double Hokku-Bokku / Big chest )", - "Empty Clone ", - "Swamp Palace (Statue )", - "Tower of Hera (Big Chest)", - "Swamp Palace (Entrance )", - "Skull Woods (Mothula[Boss])", - "Palace of Darkness (Big Hub )", - "Palace of Darkness (Map Chest / Fairy )", - "Cave", - "Empty Clone ", - "Ice Palace (Compass )", - "Cave (Kakariko Well HP)", - "Agahnim's Tower (Maiden Sacrifice Chamber)", - "Tower of Hera (Hardhat Beetles )", - "Hyrule Castle (Sewer Key Chest )", - "Desert Palace (Lanmolas[Boss])", - "Swamp Palace (Push Block Puzzle / Pre-Big Key )", - "Swamp Palace (Big Key / BS )", - "Swamp Palace (Big Chest )", - "Swamp Palace (Map Chest / Water Fill )", - "Swamp Palace (Key Pot )", - "Skull Woods (Gibdo Key / Mothula Hole )", - "Palace of Darkness (Bombable Floor )", - "Palace of Darkness (Spike Block / Conveyor )", - "Cave", - "Ganon's Tower (Torch 2)", - "Ice Palace (Stalfos Knights / Conveyor Hellway)", - "Ice Palace (Map Chest )", - "Agahnim's Tower (Final Bridge )", - "Hyrule Castle (First Dark )", - "Hyrule Castle (6 Ropes )", - "Desert Palace (Torch Puzzle / Moving Wall )", - "Thieves Town (Big Chest )", - "Thieves Town (Jail Cells )", - "Swamp Palace (Compass Chest )", - "Empty Clone ", - "Empty Clone ", - "Skull Woods (Gibdo Torch Puzzle )", - "Palace of Darkness (Entrance )", - "Palace of Darkness (Warps / South Mimics )", - "Ganon's Tower (Mini-Helmasaur Conveyor )", - "Ganon's Tower (Moldorm )", - "Ice Palace (Bomb-Jump )", - "Ice Palace Clone (Fairy )", - "Hyrule Castle (West Corridor)", - "Hyrule Castle (Throne )", - "Hyrule Castle (East Corridor)", - "Desert Palace (Popos 2 / Beamos Hellway )", - "Swamp Palace (Upstairs Pits )", - "Castle Secret Entrance / Uncle Death ", - "Skull Woods (Key Pot / Trap )", - "Skull Woods (Big Key )", - "Skull Woods (Big Chest )", - "Skull Woods (Final Section Entrance )", - "Palace of Darkness (Helmasaur King[Boss])", - "Ganon's Tower (Spike Pit )", - "Ganon's Tower (Ganon-Ball Z)", - "Ganon's Tower (Gauntlet 1/2/3)", - "Ice Palace (Lonely Firebar)", - "Ice Palace (Hidden Chest / Spike Floor )", - "Hyrule Castle (West Entrance )", - "Hyrule Castle (Main Entrance )", - "Hyrule Castle (East Entrance )", - "Desert Palace (Final Section Entrance )", - "Thieves Town (West Attic )", - "Thieves Town (East Attic )", - "Swamp Palace (Hidden Chest / Hidden Door )", - "Skull Woods (Compass Chest )", - "Skull Woods (Key Chest / Trap )", - "Empty Clone ", - "Palace of Darkness (Rupee )", - "Ganon's Tower (Mimics s)", - "Ganon's Tower (Lanmolas )", - "Ganon's Tower (Gauntlet 4/5)", - "Ice Palace (Pengators )", - "Empty Clone ", - "Hyrule Castle (Small Corridor to Jail Cells)", - "Hyrule Castle (Boomerang Chest )", - "Hyrule Castle (Map Chest )", - "Desert Palace (Big Chest )", - "Desert Palace (Map Chest )", - "Desert Palace (Big Key Chest )", - "Swamp Palace (Water Drain )", - "Tower of Hera (Entrance )", - "Empty Clone ", - "Empty Clone ", - "Empty Clone ", - "Ganon's Tower", - "Ganon's Tower (East Side Collapsing Bridge / Exploding Wall )", - "Ganon's Tower (Winder / Warp Maze )", - "Ice Palace (Hidden Chest / Bombable Floor )", - "Ice Palace ( Big Spike Traps )", - "Hyrule Castle (Jail Cell )", - "Hyrule Castle", - "Hyrule Castle (Basement Chasm )", - "Desert Palace (West Entrance )", - "Desert Palace (Main Entrance )", - "Desert Palace (East Entrance )", - "Empty Clone ", - "Tower of Hera (Tile )", - "Empty Clone ", - "Eastern Palace (Fairy )", - "Empty Clone ", - "Ganon's Tower (Block Puzzle / Spike Skip / Map Chest )", - "Ganon's Tower (East and West Downstairs / Big Chest )", - "Ganon's Tower (Tile / Torch Puzzle )", - "Ice Palace", - "Empty Clone ", - "Misery Mire (Vitreous[Boss])", - "Misery Mire (Final Switch )", - "Misery Mire (Dark Bomb Wall / Switches )", - "Misery Mire (Dark Cane Floor Switch Puzzle )", - "Empty Clone ", - "Ganon's Tower (Final Collapsing Bridge )", - "Ganon's Tower (Torches 1 )", - "Misery Mire (Torch Puzzle / Moving Wall )", - "Misery Mire (Entrance )", - "Eastern Palace (Eyegore Key )", - "Empty Clone ", - "Ganon's Tower (Many Spikes / Warp Maze )", - "Ganon's Tower (Invisible Floor Maze )", - "Ganon's Tower (Compass Chest / Invisible Floor )", - "Ice Palace (Big Chest )", - "Ice Palace", - "Misery Mire (Pre-Vitreous )", - "Misery Mire (Fish )", - "Misery Mire (Bridge Key Chest )", - "Misery Mire", - "Turtle Rock (Trinexx[Boss])", - "Ganon's Tower (Wizzrobes s)", - "Ganon's Tower (Moldorm Fall )", - "Tower of Hera (Fairy )", - "Eastern Palace (Stalfos Spawn )", - "Eastern Palace (Big Chest )", - "Eastern Palace (Map Chest )", - "Thieves Town (Moving Spikes / Key Pot )", - "Thieves Town (Blind The Thief[Boss])", - "Empty Clone ", - "Ice Palace", - "Ice Palace (Ice Bridge )", - "Agahnim's Tower (Circle of Pots)", - "Misery Mire (Hourglass )", - "Misery Mire (Slug )", - "Misery Mire (Spike Key Chest )", - "Turtle Rock (Pre-Trinexx )", - "Turtle Rock (Dark Maze)", - "Turtle Rock (Chain Chomps )", - "Turtle Rock (Map Chest / Key Chest / Roller )", - "Eastern Palace (Big Key )", - "Eastern Palace (Lobby Cannonballs )", - "Eastern Palace (Dark Antifairy / Key Pot )", - "Thieves Town (Hellway)", - "Thieves Town (Conveyor Toilet)", - "Empty Clone ", - "Ice Palace (Block Puzzle )", - "Ice Palace Clone (Switch )", - "Agahnim's Tower (Dark Bridge )", - "Misery Mire (Compass Chest / Tile )", - "Misery Mire (Big Hub )", - "Misery Mire (Big Chest )", - "Turtle Rock (Final Crystal Switch Puzzle )", - "Turtle Rock (Laser Bridge)", - "Turtle Rock", - "Turtle Rock (Torch Puzzle)", - "Eastern Palace (Armos Knights[Boss])", - "Eastern Palace (Entrance )", - "??", - "Thieves Town (North West Entrance )", - "Thieves Town (North East Entrance )", - "Empty Clone ", - "Ice Palace (Hole to Kholdstare )", - "Empty Clone ", - "Agahnim's Tower (Dark Maze)", - "Misery Mire (Conveyor Slug / Big Key )", - "Misery Mire (Mire02 / Wizzrobes )", - "Empty Clone ", - "Empty Clone ", - "Turtle Rock (Laser Key )", - "Turtle Rock (Entrance )", - "Empty Clone ", - "Eastern Palace (Zeldagamer / Pre-Armos Knights )", - "Eastern Palace (Canonball ", - "Eastern Palace", - "Thieves Town (Main (South West) Entrance )", - "Thieves Town (South East Entrance )", - "Empty Clone ", - "Ice Palace (Kholdstare[Boss])", - "Cave", - "Agahnim's Tower (Entrance )", - "Cave (Lost Woods HP)", - "Cave (Lumberjack's Tree HP)", - "Cave (1/2 Magic)", - "Cave (Lost Old Man Final Cave)", - "Cave (Lost Old Man Final Cave)", - "Cave", - "Cave", - "Cave", - "Empty Clone ", - "Cave (Spectacle Rock HP)", - "Cave", - "Empty Clone ", - "Cave", - "Cave (Spiral Cave)", - "Cave (Crystal Switch / 5 Chests )", - "Cave (Lost Old Man Starting Cave)", - "Cave (Lost Old Man Starting Cave)", - "House", - "House (Old Woman (Sahasrahla's Wife?))", - "House (Angry Brothers)", - "House (Angry Brothers)", - "Empty Clone ", - "Empty Clone ", - "Cave", - "Cave", - "Cave", - "Cave", - "Empty Clone ", - "Cave", - "Cave", - "Cave", - - "Chest Minigame", - "Houses", - "Sick Boy house", - "Tavern", - "Link's House", - "Sarashrala Hut", - "Chest Minigame", - "Library", - "Chicken House", - "Witch Shop", - "A Aginah's Cave", - "Dam", - "Mimic Cave", - "Mire Shed", - "Cave", - "Shop", - "Shop", - "Archery Minigame", - "DW Church/Shop", - "Grave Cave", - "Fairy Fountain", - "Fairy Upgrade", - "Pyramid Fairy", - "Spike Cave", - "Chest Minigame", - "Blind Hut", - "Bonzai Cave", - "Circle of bush Cave", - "Big Bomb Shop, C-House", - "Blind Hut 2", - "Hype Cave", - "Shop", - "Ice Cave", - "Smith", - "Fortune Teller", - "MiniMoldorm Cave", - "Under Rock Caves", - "Smith", - "Cave", - "Mazeblock Cave", - "Smith Peg Cave"}; - -constexpr std::string_view kEntranceNames[] = { - "Link's House Intro", - "Link's House Post-intro", - "Sanctuary", - "Hyrule Castle West", - "Hyrule Castle Central", - "Hyrule Castle East", - "Death Mountain Express (Lower)", - "Death Mountain Express (Upper)", - "Eastern Palace", - "Desert Palace Central", - "Desert Palace East", - "Desert Palace West", - "Desert Palace Boss Lair", - "Kakariko Elder's House West", - "Kakariko Elder's House East", - "Kakariko Angry Bros West", - "Kakariko Angry Bros East", - "Mad Batter Lair", - "Under Lumberjacks' Weird Tree", - "Death Mountain Maze 0000", - "Death Mountain Maze 0001", - "Turtle Rock Mountainface 1", - "Death Mountain Cape Heart Piece Cave (Lower)", - "Death Mountain Cape Heart Piece Cave (Upper)", - "Turtle Rock Mountainface 2", - "Turtle Rock Mountainface 3", - "Death Mountain Maze 0002", - "Death Mountain Maze 0003", - "Death Mountain Maze 0004", - "Death Mountain Maze 0005", - "Death Mountain Maze 0006", - "Death Mountain Maze 0007", - "Death Mountain Maze 0008", - "Spectacle Rock Maze 1", - "Spectacle Rock Maze 2", - "Spectacle Rock Maze 3", - "Hyrule Castle Tower", - "Swamp Palace", - "Palace of Darkness", - "Misery Mire", - "Skull Woods 1", - "Skull Woods 2", - "Skull Woods Big Chest", - "Skull Woods Boss Lair", - "Lost Woods Thieves' Lair", - "Ice Palace", - "Death Mountain Escape West", - "Death Mountain Escape East", - "Death Mountain Elder's Cave (Lower)", - "Death Mountain Elder's Cave (Upper)", - "Hyrule Castle Secret Cellar", - "Tower of Hera", - "Thieves's Town", - "Turtle Rock Main", - "Ganon's Pyramid Sanctum (Lower)", - "Ganon's Tower", - "Fairy Cave 1", - "Kakariko Western Well", - "Death Mountain Maze 0009", - "Death Mountain Maze 0010", - "Treasure Shell Game 1", - "Storyteller Cave 1", - "Snitch House 1", - "Snitch House 2", - "SickBoy House", - "Byrna Gauntlet", - "Kakariko Pub South", - "Kakariko Pub North", - "Kakariko Inn", - "Sahasrahlah's Disco Infernum", - "Kakariko's Lame Shop", - "Village of Outcasts Chest Game", - "Village of Outcasts Orphanage", - "Kakariko Library", - "Kakariko Storage Shed", - "Kakariko Sweeper Lady's House", - "Potion Shop", - "Aginah's Desert Cottage", - "Watergate", - "Death Mountain Maze 0011", - "Fairy Cave 2", - "Refill Cave 0001", - "Refill Cave 0002", - "The Bomb \"Shop\"", - "Village of Outcasts Retirement Center", - "Fairy Cave 3", - "Good Bee Cave", - "General Store 1", - "General Store 2", - "Archery Game", - "Storyteller Cave 2", - "Hall of the Invisibility Cape", - "Pond of Wishing", - "Pond of Happiness", - "Fairy Cave 4", - "Swamp of Evil Heart Piece Hall", - "General Store 3", - "Blind's Old Hideout", - "Storyteller Cave 3", - "Warped Pond of Wishing", - "Chez Smithies", - "Fortune Teller 1", - "Fortune Teller 2", - "Chest Shell Game 2", - "Storyteller Cave 4", - "Storyteller Cave 5", - "Storyteller Cave 6", - "Village House 1", - "Thief Hideout 1", - "Thief Hideout 2", - "Heart Piece Cave 1", - "Thief Hideout 3", - "Refill Cave 3", - "Fairy Cave 5", - "Heart Piece Cave 2", - "Hyrule Castle Prison", - "Hyrule Castle Throne Room", - "Hyrule Tower Agahnim's Sanctum", - "Skull Woods 3 (Drop In)", - "Skull Woods 4 (Drop In)", - "Skull Woods 5 (Drop In)", - "Skull Woods 6 (Drop In)", - "Lost Woods Thieves' Hideout (Drop In)", - "Ganon's Pyramid Sanctum (Upper)", - "Fairy Cave 6 (Drop In)", - "Hyrule Castle Secret Cellar (Drop In)", - "Mad Batter Lair (Drop In)", - "Under Lumberjacks' Weird Tree (Drop In)", - "Kakariko Western Well (Drop In)", - "Hyrule Sewers Goodies Room (Drop In)", - "Chris Houlihan Room (Drop In)", - "Heart Piece Cave 3 (Drop In)", - "Ice Rod Cave"}; - -} // namespace dungeon -} // namespace zelda3 -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_ZELDA3_DUNGEON_ROOM_NAMES_H \ No newline at end of file diff --git a/src/app/zelda3/dungeon/room_object.cc b/src/app/zelda3/dungeon/room_object.cc index ed68a02f..8aeb6e71 100644 --- a/src/app/zelda3/dungeon/room_object.cc +++ b/src/app/zelda3/dungeon/room_object.cc @@ -5,7 +5,52 @@ namespace app { namespace zelda3 { namespace dungeon { -void RoomObject::DrawTile(Tile t, int xx, int yy, +ObjectOption operator|(ObjectOption lhs, ObjectOption rhs) { + return static_cast(static_cast(lhs) | + static_cast(rhs)); +} + +ObjectOption operator&(ObjectOption lhs, ObjectOption rhs) { + return static_cast(static_cast(lhs) & + static_cast(rhs)); +} + +ObjectOption operator^(ObjectOption lhs, ObjectOption rhs) { + return static_cast(static_cast(lhs) ^ + static_cast(rhs)); +} + +ObjectOption operator~(ObjectOption option) { + return static_cast(~static_cast(option)); +} + +SubtypeInfo FetchSubtypeInfo(uint16_t object_id) { + SubtypeInfo info; + + // TODO: Determine the subtype based on object_id + uint8_t subtype = 1; + + switch (subtype) { + case 1: // Subtype 1 + info.subtype_ptr = kRoomObjectSubtype1 + (object_id & 0xFF) * 2; + info.routine_ptr = kRoomObjectSubtype1 + 0x200 + (object_id & 0xFF) * 2; + break; + case 2: // Subtype 2 + info.subtype_ptr = kRoomObjectSubtype2 + (object_id & 0x7F) * 2; + info.routine_ptr = kRoomObjectSubtype2 + 0x80 + (object_id & 0x7F) * 2; + break; + case 3: // Subtype 3 + info.subtype_ptr = kRoomObjectSubtype3 + (object_id & 0xFF) * 2; + info.routine_ptr = kRoomObjectSubtype3 + 0x100 + (object_id & 0xFF) * 2; + break; + default: + throw std::runtime_error("Invalid object subtype"); + } + + return info; +} + +void RoomObject::DrawTile(gfx::Tile16 t, int xx, int yy, std::vector& current_gfx16, std::vector& tiles_bg1_buffer, std::vector& tiles_bg2_buffer, @@ -56,7 +101,7 @@ void RoomObject::DrawTile(Tile t, int xx, int yy, 0x1000 && ((xx / 8) + nx_ + offset_x_) + ((ny_ + offset_y_ + (yy / 8)) * 0x40) >= 0) { - ushort td = 0; // gfx::GetTilesInfo(); // TODO t.GetTileInfo() + ushort td = 0; // gfx::GetTilesInfo(); // collisionPoint.Add( // new Point(xx + ((nx + offsetX) * 8), yy + ((ny + +offsetY) * 8))); diff --git a/src/app/zelda3/dungeon/room_object.h b/src/app/zelda3/dungeon/room_object.h index b32a2cce..497bbe4e 100644 --- a/src/app/zelda3/dungeon/room_object.h +++ b/src/app/zelda3/dungeon/room_object.h @@ -1,9 +1,7 @@ #ifndef YAZE_APP_ZELDA3_DUNGEON_ROOM_OBJECT_H #define YAZE_APP_ZELDA3_DUNGEON_ROOM_OBJECT_H -#include #include -#include #include #include @@ -21,22 +19,15 @@ namespace app { namespace zelda3 { namespace dungeon { -struct Tile {}; +struct SubtypeInfo { + uint32_t subtype_ptr; + uint32_t routine_ptr; +}; + +SubtypeInfo FetchSubtypeInfo(uint16_t object_id); enum class SpecialObjectType { Chest, BigChest, InterroomStairs }; -enum Background2 { - Off, - Parallax, - Dark, - OnTop, - Translucent, - Addition, - Normal, - Transparent, - DarkRoom // TODO: Determine if DarkRoom will stay there or not -}; - enum Sorting { All = 0, Wall = 1, @@ -48,7 +39,7 @@ enum Sorting { SortStairs = 64 }; -enum ObjectOption { +enum class ObjectOption { Nothing = 0, Door = 1, Chest = 2, @@ -58,6 +49,17 @@ enum ObjectOption { Stairs = 32 }; +ObjectOption operator|(ObjectOption lhs, ObjectOption rhs); +ObjectOption operator&(ObjectOption lhs, ObjectOption rhs); +ObjectOption operator^(ObjectOption lhs, ObjectOption rhs); +ObjectOption operator~(ObjectOption option); + +constexpr int kRoomObjectSubtype1 = 0x8000; // JP = Same +constexpr int kRoomObjectSubtype2 = 0x83F0; // JP = Same +constexpr int kRoomObjectSubtype3 = 0x84F0; // JP = Same +constexpr int kRoomObjectTileAddress = 0x1B52; // JP = Same +constexpr int kRoomObjectTileAddressFloor = 0x1B5A; // JP = Same + class RoomObject : public SharedRom { public: enum LayerType { BG1 = 0, BG2 = 1, BG3 = 2 }; @@ -73,55 +75,27 @@ class RoomObject : public SharedRom { ox_(x), oy_(y), width_(16), - height_(16), - unique_id_(0) {} - - void GetObjectSize() { - previous_size_ = size_; - size_ = 1; - GetBaseSize(); - UpdateSize(); - size_ = 2; - GetSizeSized(); - UpdateSize(); - size_ = previous_size_; - } - - void GetBaseSize() { - base_width_ = width_; - base_height_ = height_; - } - - void GetSizeSized() { - size_height_ = height_ - base_height_; - size_width_ = width_ - base_width_; - } - - void UpdateSize() { - width_ = 8; - height_ = 8; - } + height_(16) {} void AddTiles(int nbr, int pos) { - auto rom_data = rom()->data(); for (int i = 0; i < nbr; i++) { ASSIGN_OR_LOG_ERROR(auto tile, rom()->ReadTile16(pos + (i * 2))); tiles_.push_back(tile); } } - void DrawTile(Tile t, int xx, int yy, std::vector& current_gfx16, + void DrawTile(gfx::Tile16 t, int xx, int yy, + std::vector& current_gfx16, std::vector& tiles_bg1_buffer, std::vector& tiles_bg2_buffer, ushort tile_under = 0xFFFF); + auto options() const { return options_; } + void set_options(ObjectOption options) { options_ = options; } + protected: bool all_bgs_ = false; bool lit_ = false; - bool deleted_ = false; - bool show_rectangle_ = false; - bool diagonal_fix_ = false; - bool selected_ = false; int16_t id_; uint8_t x_; @@ -136,49 +110,44 @@ class RoomObject : public SharedRom { int width_; int height_; - int base_width_; - int base_height_; - int size_width_; - int size_height_; - int tile_index_ = 0; int offset_x_ = 0; int offset_y_ = 0; - int preview_id_ = 0; - int unique_id_ = 0; std::string name_; + std::vector preview_object_data_; + std::vector tiles_; + LayerType layer_; ObjectOption options_ = ObjectOption::Nothing; - std::vector tiles_; - std::vector preview_object_data_; }; class Subtype1 : public RoomObject { public: - std::vector tiles; - std::string name; - bool allBgs; - Sorting sort; + bool all_bgs; int tile_count_; + std::string name; + Sorting sort; Subtype1(int16_t id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer, - int tileCount) - : RoomObject(id, x, y, size, layer), tile_count_(tileCount) { + int tile_count) + : RoomObject(id, x, y, size, layer), tile_count_(tile_count) { auto rom_data = rom()->data(); - int pos = - core::tile_address + - static_cast( - (rom_data[core::subtype1_tiles + ((id & 0xFF) * 2) + 1] << 8) + - rom_data[core::subtype1_tiles + ((id & 0xFF) * 2)]); + int pos = kRoomObjectTileAddress + + static_cast( + (rom_data[kRoomObjectSubtype1 + ((id & 0xFF) * 2) + 1] << 8) + + rom_data[kRoomObjectSubtype1 + ((id & 0xFF) * 2)]); AddTiles(tile_count_, pos); sort = (Sorting)(Sorting::Horizontal | Sorting::Wall); } - void Draw() { + void Draw(std::vector& current_gfx16, + std::vector& tiles_bg1_buffer, + std::vector& tiles_bg2_buffer) { for (int s = 0; s < size_ + (tile_count_ == 8 ? 1 : 0); s++) { for (int i = 0; i < tile_count_; i++) { - // DrawTile(tiles[i], ((s * 2)) * 8, (i / 2) * 8); + DrawTile(tiles_[i], ((s * 2)) * 8, (i / 2) * 8, current_gfx16, + tiles_bg1_buffer, tiles_bg2_buffer); } } } @@ -186,52 +155,54 @@ class Subtype1 : public RoomObject { class Subtype2 : public RoomObject { public: - std::vector tiles; std::string name; - bool allBgs; + bool all_bgs; Sorting sort; Subtype2(int16_t id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer) : RoomObject(id, x, y, size, layer) { auto rom_data = rom()->data(); - int pos = - core::tile_address + - static_cast( - (rom_data[core::subtype2_tiles + ((id & 0x7F) * 2) + 1] << 8) + - rom_data[core::subtype2_tiles + ((id & 0x7F) * 2)]); + int pos = kRoomObjectTileAddress + + static_cast( + (rom_data[kRoomObjectSubtype2 + ((id & 0x7F) * 2) + 1] << 8) + + rom_data[kRoomObjectSubtype2 + ((id & 0x7F) * 2)]); AddTiles(8, pos); sort = (Sorting)(Sorting::Horizontal | Sorting::Wall); } - void Draw() { + void Draw(std::vector& current_gfx16, + std::vector& tiles_bg1_buffer, + std::vector& tiles_bg2_buffer) { for (int i = 0; i < 8; i++) { - // DrawTile(tiles[i], x_ * 8, (y_ + i) * 8); + DrawTile(tiles_[i], x_ * 8, (y_ + i) * 8, current_gfx16, tiles_bg1_buffer, + tiles_bg2_buffer); } } }; class Subtype3 : public RoomObject { public: - std::vector tiles; + bool all_bgs; std::string name; - bool allBgs; Sorting sort; Subtype3(int16_t id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer) : RoomObject(id, x, y, size, layer) { auto rom_data = rom()->data(); - int pos = - core::tile_address + - static_cast( - (rom_data[core::subtype3_tiles + ((id & 0xFF) * 2) + 1] << 8) + - rom_data[core::subtype3_tiles + ((id & 0xFF) * 2)]); + int pos = kRoomObjectTileAddress + + static_cast( + (rom_data[kRoomObjectSubtype3 + ((id & 0xFF) * 2) + 1] << 8) + + rom_data[kRoomObjectSubtype3 + ((id & 0xFF) * 2)]); AddTiles(8, pos); sort = (Sorting)(Sorting::Horizontal | Sorting::Wall); } - void Draw() { + void Draw(std::vector& current_gfx16, + std::vector& tiles_bg1_buffer, + std::vector& tiles_bg2_buffer) { for (int i = 0; i < 8; i++) { - // DrawTile(tiles[i], x_ * 8, (y_ + i) * 8); + DrawTile(tiles_[i], x_ * 8, (y_ + i) * 8, current_gfx16, tiles_bg1_buffer, + tiles_bg2_buffer); } } }; @@ -241,4 +212,4 @@ class Subtype3 : public RoomObject { } // namespace app } // namespace yaze -#endif // YAZE_APP_ZELDA3_DUNGEON_ROOM_OBJECT_H \ No newline at end of file +#endif // YAZE_APP_ZELDA3_DUNGEON_ROOM_OBJECT_H diff --git a/src/app/zelda3/dungeon/room_tag.h b/src/app/zelda3/dungeon/room_tag.h new file mode 100644 index 00000000..a6f5a331 --- /dev/null +++ b/src/app/zelda3/dungeon/room_tag.h @@ -0,0 +1,94 @@ +#ifndef YAZE_APP_ZELDA3_DUNGEON_ROOM_TAG_H +#define YAZE_APP_ZELDA3_DUNGEON_ROOM_TAG_H + +#include + +namespace yaze { +namespace app { +namespace zelda3 { +namespace dungeon { + +static const std::string RoomEffect[] = {"Nothing", + "Nothing", + "Moving Floor", + "Moving Water", + "Trinexx Shell", + "Red Flashes", + "Light Torch to See Floor", + "Ganon's Darkness"}; + +static const std::string RoomTag[] = {"Nothing", + "NW Kill Enemy to Open", + "NE Kill Enemy to Open", + "SW Kill Enemy to Open", + "SE Kill Enemy to Open", + "W Kill Enemy to Open", + "E Kill Enemy to Open", + "N Kill Enemy to Open", + "S Kill Enemy to Open", + "Clear Quadrant to Open", + "Clear Full Tile to Open", + + "NW Push Block to Open", + "NE Push Block to Open", + "SW Push Block to Open", + "SE Push Block to Open", + "W Push Block to Open", + "E Push Block to Open", + "N Push Block to Open", + "S Push Block to Open", + "Push Block to Open", + "Pull Lever to Open", + "Collect Prize to Open", + + "Hold Switch Open Door", + "Toggle Switch to Open Door", + "Turn off Water", + "Turn on Water", + "Water Gate", + "Water Twin", + "Moving Wall Right", + "Moving Wall Left", + "Crash", + "Crash", + "Push Switch Exploding Wall", + "Holes 0", + "Open Chest (Holes 0)", + "Holes 1", + "Holes 2", + "Defeat Boss for Dungeon Prize", + + "SE Kill Enemy to Push Block", + "Trigger Switch Chest", + "Pull Lever Exploding Wall", + "NW Kill Enemy for Chest", + "NE Kill Enemy for Chest", + "SW Kill Enemy for Chest", + "SE Kill Enemy for Chest", + "W Kill Enemy for Chest", + "E Kill Enemy for Chest", + "N Kill Enemy for Chest", + "S Kill Enemy for Chest", + "Clear Quadrant for Chest", + "Clear Full Tile for Chest", + + "Light Torches to Open", + "Holes 3", + "Holes 4", + "Holes 5", + "Holes 6", + "Agahnim Room", + "Holes 7", + "Holes 8", + "Open Chest for Holes 8", + "Push Block for Chest", + "Clear Room for Triforce Door", + "Light Torches for Chest", + "Kill Boss Again"}; + +} // namespace dungeon +} // namespace zelda3 +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_ZELDA3_DUNGEON_ROOM_TAG_H \ No newline at end of file diff --git a/src/app/zelda3/music/spc700.def b/src/app/zelda3/music/spc700.def deleted file mode 100644 index 4781c5ef..00000000 --- a/src/app/zelda3/music/spc700.def +++ /dev/null @@ -1,26 +0,0 @@ -LIBRARY snes_spc -DESCRIPTION "snes_spc 0.9.0" -EXPORTS - spc_new @1 - spc_delete @2 - spc_init_rom @3 - spc_set_output @4 - spc_sample_count @5 - spc_reset @6 - spc_soft_reset @7 - spc_read_port @8 - spc_write_port @9 - spc_end_frame @10 - spc_mute_voices @11 - spc_disable_surround @12 - spc_set_tempo @13 - spc_load_spc @14 - spc_clear_echo @15 - spc_play @16 - spc_skip @17 - spc_filter_new @18 - spc_filter_delete @19 - spc_filter_run @20 - spc_filter_clear @21 - spc_filter_set_gain @22 - spc_filter_set_bass @23 \ No newline at end of file diff --git a/src/app/zelda3/music/tracker.cc b/src/app/zelda3/music/tracker.cc index 9de7bedb..5753051f 100644 --- a/src/app/zelda3/music/tracker.cc +++ b/src/app/zelda3/music/tracker.cc @@ -11,14 +11,9 @@ #include #include -#include -#include #include -#include "absl/status/status.h" #include "app/core/constants.h" -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_tile.h" #include "app/rom.h" namespace yaze { @@ -27,7 +22,7 @@ namespace zelda3 { namespace { -void AddSPCReloc(music::SongSPCBlock *sbl, short addr) { +void AddSPCReloc(music::SongSpcBlock *sbl, short addr) { sbl->relocs[sbl->relnum++] = addr; if (sbl->relnum == sbl->relsz) { sbl->relsz += 16; @@ -38,16 +33,16 @@ void AddSPCReloc(music::SongSPCBlock *sbl, short addr) { } // namespace namespace music { -SongSPCBlock *Tracker::AllocSPCBlock(int len, int bank) { - SongSPCBlock *sbl; +SongSpcBlock *Tracker::AllocSpcBlock(int len, int bank) { + SongSpcBlock *sbl; if (!len) { printf("warning zero length block allocated"); } if (ss_num == ss_size) { ss_size += 512; - ssblt = (SongSPCBlock **)realloc(ssblt, ss_size << 2); + ssblt = (SongSpcBlock **)realloc(ssblt, ss_size << 2); } - ssblt[ss_num] = sbl = (SongSPCBlock *)malloc(sizeof(SongSPCBlock)); + ssblt[ss_num] = sbl = (SongSpcBlock *)malloc(sizeof(SongSpcBlock)); ss_num++; sbl->start = ss_next; sbl->len = len; @@ -63,7 +58,7 @@ SongSPCBlock *Tracker::AllocSPCBlock(int len, int bank) { // ============================================================================= -unsigned char *Tracker::GetSPCAddr(Rom &rom, unsigned short addr, short bank) { +unsigned char *Tracker::GetSpcAddr(Rom &rom, unsigned short addr, short bank) { unsigned char *rom_ptr; unsigned short a; unsigned short b; @@ -99,16 +94,16 @@ again: // ============================================================================= -short Tracker::AllocSPCCommand() { +short Tracker::AllocSpcCommand() { int i = m_free; int j; int k; - SPCCommand *spc_command; + SpcCommand *spc_command; if (i == -1) { j = m_size; m_size += 1024; - spc_command = current_spc_command_ = (SPCCommand *)realloc( - current_spc_command_, m_size * sizeof(SPCCommand)); + spc_command = current_spc_command_ = (SpcCommand *)realloc( + current_spc_command_, m_size * sizeof(SpcCommand)); k = 1023; while (k--) spc_command[j].next = j + 1, j++; spc_command[j].next = -1; @@ -126,8 +121,8 @@ short Tracker::AllocSPCCommand() { // ============================================================================= short Tracker::GetBlockTime(Rom &rom, short num, short prevtime) { - SPCCommand *spc_command = current_spc_command_; - SPCCommand *spc_command2; + SpcCommand *spc_command = current_spc_command_; + SpcCommand *spc_command2; int i = -1; int j = 0; @@ -219,7 +214,7 @@ short Tracker::GetBlockTime(Rom &rom, short num, short prevtime) { // ============================================================================= -short Tracker::LoadSPCCommand(Rom &rom, unsigned short addr, short bank, +short Tracker::LoadSpcCommand(Rom &rom, unsigned short addr, short bank, int t) { int b = 0; int c = 0; @@ -240,11 +235,11 @@ short Tracker::LoadSPCCommand(Rom &rom, unsigned short addr, short bank, unsigned char *a = nullptr; SongRange *sr; - SPCCommand *spc_command = current_spc_command_; - SPCCommand *spc_command2; + SpcCommand *spc_command = current_spc_command_; + SpcCommand *spc_command2; if (!addr) return -1; - a = GetSPCAddr(rom, addr, bank); + a = GetSpcAddr(rom, addr, bank); d = spcbank; if (!a) { printf("Address not found when loading track"); @@ -255,7 +250,7 @@ short Tracker::LoadSPCCommand(Rom &rom, unsigned short addr, short bank, f = 0x10000; for (c = 0; c < e; c++) { - if (sr[c].bank == d) + if (sr[c].bank == d) { if (sr[c].start > addr) { if (sr[c].start < f) f = sr[c].start; n = c; @@ -270,15 +265,18 @@ short Tracker::LoadSPCCommand(Rom &rom, unsigned short addr, short bank, return f; } if (spc_command[f].flag & 1) k = spc_command[f].b1; - if (spc_command[f].cmd < 0xca) - if (k) + if (spc_command[f].cmd < 0xca) { + if (k) { m -= k; - else + } else { o--; + } + } } printf("Misaligned music pointer"); return -1; } + } } c = n; @@ -292,8 +290,8 @@ short Tracker::LoadSPCCommand(Rom &rom, unsigned short addr, short bank, spc_command2 = spc_command + i; if (spc_command2->next == -1) { l = m_size; - spc_command = current_spc_command_ = (SPCCommand *)realloc( - spc_command, sizeof(SPCCommand) * (m_size += 1024)); + spc_command = current_spc_command_ = (SpcCommand *)realloc( + spc_command, sizeof(SpcCommand) * (m_size += 1024)); spc_command2 = spc_command + i; n = l + 1023; while (l < n) spc_command[l].next = l + 1, l++; @@ -315,11 +313,13 @@ short Tracker::LoadSPCCommand(Rom &rom, unsigned short addr, short bank, b = a[g++]; if (b < 128) j = 3, spc_command2->b2 = b, b = a[g++]; } - if (b < 0xe0) - if (k) + if (b < 0xe0) { + if (k) { m += k; - else + } else { o++; + } + } spc_command2->cmd = b; spc_command2->flag = j; if (b >= 0xe0) { @@ -330,7 +330,7 @@ short Tracker::LoadSPCCommand(Rom &rom, unsigned short addr, short bank, if (b == 15) { m_free = spc_command2->next; spc_command[spc_command2->next].prev = -1; - l = LoadSPCCommand(rom, *(short *)(&(spc_command2->p1)), bank, t - m); + l = LoadSpcCommand(rom, *(short *)(&(spc_command2->p1)), bank, t - m); spc_command = current_spc_command_; spc_command2 = spc_command + i; *(short *)(&(spc_command2->p1)) = l; @@ -399,7 +399,7 @@ void Tracker::LoadSongs(Rom &rom) { Song song; Song song2; SongPart *sp; - SPCCommand *spc_command; + SpcCommand *spc_command; ZeldaWave *zelda_wave; int i; @@ -418,7 +418,7 @@ void Tracker::LoadSongs(Rom &rom) { int filter; spc_command = current_spc_command_ = - (SPCCommand *)malloc(1024 * sizeof(SPCCommand)); + (SpcCommand *)malloc(1024 * sizeof(SpcCommand)); m_free = 0; m_size = 1024; srnum = 0; @@ -444,7 +444,7 @@ void Tracker::LoadSongs(Rom &rom) { spc_command[1023].next = -1; for (i = 0; i < 3; i++) { // Extract the song banks. - b = GetSPCAddr(rom, 0xd000, i); + b = GetSpcAddr(rom, 0xd000, i); for (j = 0;; j++) { if ((r = ((unsigned short *)b)[j]) >= 0xd000) { r = (r - 0xd000) >> 1; @@ -458,7 +458,7 @@ void Tracker::LoadSongs(Rom &rom) { if (!k) songs[l].in_use = false; else { - c = GetSPCAddr(rom, k, i); + c = GetSpcAddr(rom, k, i); // Init the bank index we are current loading. if (!spcbank) @@ -493,7 +493,7 @@ void Tracker::LoadSongs(Rom &rom) { for (m = 0; m < song.numparts; m++) { k = ((unsigned short *)c)[m]; - d = GetSPCAddr(rom, k, i); + d = GetSpcAddr(rom, k, i); if (!spcbank) n = 0; else @@ -522,7 +522,7 @@ void Tracker::LoadSongs(Rom &rom) { p = 50000; for (o = 0; o < 8; o++) { q = sp->tbl[o] = - LoadSPCCommand(rom, ((unsigned short *)d)[o], i, p); + LoadSpcCommand(rom, ((unsigned short *)d)[o], i, p); spc_command = current_spc_command_ + q; if ((spc_command->flag & 4) && spc_command->tim < p) p = spc_command->tim; @@ -535,28 +535,28 @@ void Tracker::LoadSongs(Rom &rom) { } } - b = GetSPCAddr(rom, 0x800, 0); + b = GetSpcAddr(rom, 0x800, 0); snddat1 = (char *)malloc(spclen); sndlen1 = spclen; memcpy(snddat1, b, spclen); - b = GetSPCAddr(rom, 0x17c0, 0); + b = GetSpcAddr(rom, 0x17c0, 0); snddat2 = (char *)malloc(spclen); sndlen2 = spclen; memcpy(snddat2, b, spclen); - b = GetSPCAddr(rom, 0x3d00, 0); + b = GetSpcAddr(rom, 0x3d00, 0); insts = (ZeldaInstrument *)malloc(spclen); memcpy(insts, b, spclen); numinst = spclen / 6; - b = GetSPCAddr(rom, 0x3e00, 0); + b = GetSpcAddr(rom, 0x3e00, 0); m_ofs = b - rom.data() + spclen; sndinsts = (ZeldaSfxInstrument *)malloc(spclen); memcpy(sndinsts, b, spclen); numsndinst = spclen / 9; - b = GetSPCAddr(rom, 0x3c00, 0); + b = GetSpcAddr(rom, 0x3c00, 0); zelda_wave = waves = (ZeldaWave *)malloc(sizeof(ZeldaWave) * (spclen >> 2)); p = spclen >> 1; @@ -576,7 +576,7 @@ void Tracker::LoadSongs(Rom &rom) { foundwave: - d = GetSPCAddr(rom, j, 0); + d = GetSpcAddr(rom, j, 0); e = (short *)malloc(2048); k = 0; @@ -660,12 +660,12 @@ void Tracker::LoadSongs(Rom &rom) { w_modf = 0; } -short Tracker::SaveSPCCommand(Rom &rom, short num, short songtime, +short Tracker::SaveSpcCommand(Rom &rom, short num, short songtime, short endtr) { - SPCCommand *spc_command = current_spc_command_; - SPCCommand *spc_command2; + SpcCommand *spc_command = current_spc_command_; + SpcCommand *spc_command2; SongRange *sr = song_range_; - SongSPCBlock *sbl; + SongSpcBlock *sbl; text_buf_ty buf; @@ -722,7 +722,7 @@ short Tracker::SaveSPCCommand(Rom &rom, short num, short songtime, k += l; } k++; - sbl = AllocSPCBlock(k, sr[j].bank | ((!endtr) << 3) | 16); + sbl = AllocSpcBlock(k, sr[j].bank | ((!endtr) << 3) | 16); b = sbl->buf; for (;;) { @@ -737,7 +737,7 @@ short Tracker::SaveSPCCommand(Rom &rom, short num, short songtime, o = op_len[spc_command2->cmd - 0xe0]; if (spc_command2->cmd == 0xef) { *(short *)b = - SaveSPCCommand(rom, *(short *)&(spc_command2->p1), 0, 1); + SaveSpcCommand(rom, *(short *)&(spc_command2->p1), 0, 1); if (b) AddSPCReloc(sbl, b - sbl->buf); b[2] = spc_command2->p3; b += 3; @@ -783,7 +783,7 @@ short Tracker::SaveSPCCommand(Rom &rom, short num, short songtime, // ============================================================================= -int Tracker::WriteSPCData(Rom &rom, void *buf, int len, int addr, int spc, +int Tracker::WriteSpcData(Rom &rom, void *buf, int len, int addr, int spc, int limit) { unsigned char *rom_data = rom.data(); @@ -841,14 +841,14 @@ void Tracker::SaveSongs(Rom &rom) { Song song; - SPCCommand *spc_command; + SpcCommand *spc_command; SongPart *sp; - SongSPCBlock *stbl; - SongSPCBlock *sptbl; - SongSPCBlock *trtbl; - SongSPCBlock *pstbl; + SongSpcBlock *stbl; + SongSpcBlock *sptbl; + SongSpcBlock *trtbl; + SongSpcBlock *pstbl; ZeldaWave *zelda_wave; ZeldaWave *zelda_wave2; @@ -869,7 +869,7 @@ void Tracker::SaveSongs(Rom &rom) { // if the music has not been modified, return. if (!(m_modf)) return; - ssblt = (SongSPCBlock **)malloc(512 * sizeof(SongSPCBlock)); + ssblt = (SongSpcBlock **)malloc(512 * sizeof(SongSpcBlock)); // set it so the music has not been modified. (reset the status) m_modf = 0; @@ -906,7 +906,7 @@ void Tracker::SaveSongs(Rom &rom) { for (i = 0; i < 3; i++) { k = numsong[i]; - stbl = AllocSPCBlock(k << 1, i + 1); + stbl = AllocSpcBlock(k << 1, i + 1); for (j = 0; j < k; j++) { song = songs[l++]; @@ -919,7 +919,7 @@ void Tracker::SaveSongs(Rom &rom) { if (song.flag & 4) goto alreadysaved; - sptbl = AllocSPCBlock(((song.numparts + 1) << 1) + (song.flag & 2), + sptbl = AllocSpcBlock(((song.numparts + 1) << 1) + (song.flag & 2), (song.flag & 1) ? 0 : (i + 1)); for (m = 0; m < song.numparts; m++) { @@ -927,7 +927,7 @@ void Tracker::SaveSongs(Rom &rom) { if (sp->flag & 2) goto spsaved; - trtbl = AllocSPCBlock(16, (sp->flag & 1) ? 0 : (i + 1)); + trtbl = AllocSpcBlock(16, (sp->flag & 1) ? 0 : (i + 1)); p = 0; @@ -940,7 +940,7 @@ void Tracker::SaveSongs(Rom &rom) { q = 1; for (n = 0; n < 8; n++) { - core::stle16b_i(trtbl->buf, n, SaveSPCCommand(rom, sp->tbl[n], p, q)); + core::stle16b_i(trtbl->buf, n, SaveSpcCommand(rom, sp->tbl[n], p, q)); if (core::ldle16b_i(trtbl->buf, n)) AddSPCReloc(trtbl, n << 1), q = 0; } @@ -1144,14 +1144,14 @@ void Tracker::SaveSongs(Rom &rom) { } } - m = WriteSPCData(rom, wtbl, numwave << 2, 0xc8000, 0x3c00, 0xd74fc); - m = WriteSPCData(rom, b, j, m, 0x4000, 0xd74fc); + m = WriteSpcData(rom, wtbl, numwave << 2, 0xc8000, 0x3c00, 0xd74fc); + m = WriteSpcData(rom, b, j, m, 0x4000, 0xd74fc); free(b); - m = WriteSPCData(rom, insts, numinst * 6, m, 0x3d00, 0xd74fc); - m = WriteSPCData(rom, snddat1, sndlen1, m, 0x800, 0xd74fc); - m = WriteSPCData(rom, snddat2, sndlen2, m, 0x17c0, 0xd74fc); - m = WriteSPCData(rom, sndinsts, numsndinst * 9, m, 0x3e00, 0xd74fc); + m = WriteSpcData(rom, insts, numinst * 6, m, 0x3d00, 0xd74fc); + m = WriteSpcData(rom, snddat1, sndlen1, m, 0x800, 0xd74fc); + m = WriteSpcData(rom, snddat2, sndlen2, m, 0x17c0, 0xd74fc); + m = WriteSpcData(rom, sndinsts, numsndinst * 9, m, 0x3e00, 0xd74fc); m_ofs = m; } else { m = m_ofs; @@ -1249,13 +1249,13 @@ void Tracker::SaveSongs(Rom &rom) { ssblt[i] = 0; } if (n > l + 4) { - *(short *)(rom + l) = n - l - 4; - *(short *)(rom + l + 2) = o ? bank_lwr[k] : 0xd000; + *(short *)(rom.data() + l) = n - l - 4; + *(short *)(rom.data() + l + 2) = o ? bank_lwr[k] : 0xd000; l = n; } } - *(short *)(rom + l) = 0; - *(short *)(rom + l + 2) = 0x800; + *(short *)(rom.data() + l) = 0; + *(short *)(rom.data() + l + 2) = 0x800; if (k == 1) m = l + 4; } free(ssblt); @@ -1266,7 +1266,7 @@ void Tracker::SaveSongs(Rom &rom) { void Tracker::EditTrack(Rom &rom, short i) { int j, k, l; SongRange *sr = song_range_; - SPCCommand *spc_command; + SpcCommand *spc_command; text_buf_ty buf; @@ -1314,7 +1314,7 @@ void Tracker::EditTrack(Rom &rom, short i) { // ============================================================================= void Tracker::NewSR(Rom &rom, int bank) { - SPCCommand *spc_command; + SpcCommand *spc_command; SongRange *sr; if (srnum == srsize) { @@ -1324,7 +1324,7 @@ void Tracker::NewSR(Rom &rom, int bank) { sr = song_range_ + srnum; srnum++; - sr->first = AllocSPCCommand(); + sr->first = AllocSpcCommand(); sr->bank = bank; sr->editor = 0; spc_command = current_spc_command_ + sr->first; diff --git a/src/app/zelda3/music/tracker.h b/src/app/zelda3/music/tracker.h index f7ebb212..65048b2a 100644 --- a/src/app/zelda3/music/tracker.h +++ b/src/app/zelda3/music/tracker.h @@ -1,16 +1,9 @@ #ifndef YAZE_APP_ZELDA3_TRACKER_H #define YAZE_APP_ZELDA3_TRACKER_H -#include -#include -#include #include -#include "absl/status/status.h" -#include "app/core/common.h" #include "app/core/constants.h" -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_tile.h" #include "app/rom.h" namespace yaze { @@ -45,7 +38,7 @@ constexpr int kDungeonMusicBank = 0x0D8000; using text_buf_ty = char[512]; // ============================================================================ -using SongSPCBlock = struct { +struct SongSpcBlock { unsigned short start; unsigned short len; unsigned short relnum; @@ -59,7 +52,7 @@ using SongSPCBlock = struct { // ============================================================================= -using SongRange = struct { +struct SongRange { unsigned short start; unsigned short end; @@ -75,7 +68,7 @@ using SongRange = struct { // ============================================================================= -using SongPart = struct { +struct SongPart { uchar flag; uchar inst; short tbl[8]; @@ -84,7 +77,7 @@ using SongPart = struct { // ============================================================================= -using Song = struct { +struct Song { unsigned char flag; unsigned char inst; SongPart **tbl; @@ -95,7 +88,7 @@ using Song = struct { }; // ============================================================================= -using ZeldaWave = struct { +struct ZeldaWave { int lopst; int end; short lflag; @@ -105,7 +98,7 @@ using ZeldaWave = struct { // ============================================================================ -using SampleEdit = struct { +struct SampleEdit { unsigned short flag; unsigned short init; unsigned short editsamp; @@ -130,7 +123,7 @@ using SampleEdit = struct { // ============================================================================= -using ZeldaInstrument = struct { +struct ZeldaInstrument { unsigned char samp; unsigned char ad; unsigned char sr; @@ -141,7 +134,7 @@ using ZeldaInstrument = struct { // ============================================================================= -using ZeldaSfxInstrument = struct { +struct ZeldaSfxInstrument { unsigned char voll; unsigned char volr; short freq; @@ -154,7 +147,7 @@ using ZeldaSfxInstrument = struct { // ============================================================================= -using SPCCommand = struct { +struct SpcCommand { unsigned short addr; short next; short prev; @@ -173,22 +166,22 @@ using SPCCommand = struct { class Tracker { public: - SongSPCBlock *AllocSPCBlock(int len, int bank); + SongSpcBlock *AllocSpcBlock(int len, int bank); - unsigned char *GetSPCAddr(Rom &rom, unsigned short addr, short bank); + unsigned char *GetSpcAddr(Rom &rom, unsigned short addr, short bank); - short AllocSPCCommand(); + short AllocSpcCommand(); short GetBlockTime(Rom &rom, short num, short prevtime); - short SaveSPCCommand(Rom &rom, short num, short songtime, short endtr); - short LoadSPCCommand(Rom &rom, unsigned short addr, short bank, int t); + short SaveSpcCommand(Rom &rom, short num, short songtime, short endtr); + short LoadSpcCommand(Rom &rom, unsigned short addr, short bank, int t); void SaveSongs(Rom &rom); void LoadSongs(Rom &rom); - int WriteSPCData(Rom &rom, void *buf, int len, int addr, int spc, int limit); + int WriteSpcData(Rom &rom, void *buf, int len, int addr, int spc, int limit); void EditTrack(Rom &rom, short i); @@ -248,9 +241,9 @@ class Tracker { std::vector songs; SongPart *sp_mark; SongRange *song_range_; - SPCCommand *current_spc_command_; + SpcCommand *current_spc_command_; - SongSPCBlock **ssblt; + SongSpcBlock **ssblt; ZeldaWave *waves; ZeldaInstrument *insts; @@ -264,4 +257,4 @@ class Tracker { } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/zelda3/overworld/overworld.cc b/src/app/zelda3/overworld/overworld.cc index 6bb106f4..aee8dc06 100644 --- a/src/app/zelda3/overworld/overworld.cc +++ b/src/app/zelda3/overworld/overworld.cc @@ -1,7 +1,5 @@ #include "overworld.h" -#include - #include #include #include @@ -9,9 +7,7 @@ #include #include -#include "absl/container/flat_hash_map.h" #include "absl/status/status.h" -#include "app/core/common.h" #include "app/core/constants.h" #include "app/gfx/bitmap.h" #include "app/gfx/compression.h" @@ -25,70 +21,16 @@ namespace app { namespace zelda3 { namespace overworld { -namespace { - -absl::flat_hash_map parseFile(const std::string &filename) { - absl::flat_hash_map resultMap; - - std::ifstream file(filename); - if (!file.is_open()) { - std::cerr << "Failed to open file: " << filename << std::endl; - return resultMap; - } - - std::string line; - int currentKey; - bool isHigh = true; - - while (getline(file, line)) { - // Skip empty or whitespace-only lines - if (line.find_first_not_of(" \t\r\n") == std::string::npos) { - continue; - } - - // If the line starts with "MAPDTH" or "MAPDTL", extract the ID. - if (line.find("MAPDTH") == 0) { - auto num_str = line.substr(6); // Extract ID after "MAPDTH" - currentKey = std::stoi(num_str); - isHigh = true; - } else if (line.find("MAPDTL") == 0) { - auto num_str = line.substr(6); // Extract ID after "MAPDTH" - currentKey = std::stoi(num_str); - isHigh = false; - } else { - // Check if the currentKey is already in the map. If not, initialize it. - if (resultMap.find(currentKey) == resultMap.end()) { - resultMap[currentKey] = MapData(); - } - - // Split the line by commas and convert to uint8_t. - std::stringstream ss(line); - std::string valueStr; - while (getline(ss, valueStr, ',')) { - uint8_t value = std::stoi(valueStr, nullptr, 16); - if (isHigh) { - resultMap[currentKey].highData.emplace_back(value); - } else { - resultMap[currentKey].lowData.emplace_back(value); - } - } - } - } - - return resultMap; -} - -} // namespace - absl::Status Overworld::Load(Rom &rom) { rom_ = rom; - AssembleMap32Tiles(); + RETURN_IF_ERROR(AssembleMap32Tiles()); AssembleMap16Tiles(); RETURN_IF_ERROR(DecompressAllMapTiles()) + const bool load_custom_overworld = flags()->overworld.kLoadCustomOverworld; for (int map_index = 0; map_index < kNumOverworldMaps; ++map_index) - overworld_maps_.emplace_back(map_index, rom_, tiles16_); + overworld_maps_.emplace_back(map_index, rom_, load_custom_overworld); FetchLargeMaps(); LoadEntrances(); @@ -156,30 +98,51 @@ void Overworld::FetchLargeMaps() { } } -void Overworld::AssembleMap32Tiles() { - auto get_tile16_for_tile32 = [this](int index, int quadrant, int dimension) { - const uint32_t map32address[4] = {rom()->version_constants().kMap32TileTL, - rom()->version_constants().kMap32TileTR, - rom()->version_constants().kMap32TileBL, - rom()->version_constants().kMap32TileBR}; - return (uint16_t)(rom_[map32address[dimension] + quadrant + (index)] + - (((rom_[map32address[dimension] + (index) + - (quadrant <= 1 ? 4 : 5)] >> - (quadrant % 2 == 0 ? 4 : 0)) & - 0x0F) * - 256)); - }; +absl::StatusOr Overworld::GetTile16ForTile32( + int index, int quadrant, int dimension, const uint32_t *map32address) { + ASSIGN_OR_RETURN(auto arg1, + rom_.ReadByte(map32address[dimension] + quadrant + (index))); + ASSIGN_OR_RETURN(auto arg2, rom_.ReadWord(map32address[dimension] + (index) + + (quadrant <= 1 ? 4 : 5))); + return (uint16_t)(arg1 + + (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256)); +} - // Loop through each 32x32 pixel tile in the rom()-> - for (int i = 0; i < 0x33F0; i += 6) { +constexpr int kMap32TilesLength = 0x33F0; + +absl::Status Overworld::AssembleMap32Tiles() { + int num_tile32 = kMap32TilesLength; + uint32_t map32address[4] = {rom_.version_constants().kMap32TileTL, + rom_.version_constants().kMap32TileTR, + rom_.version_constants().kMap32TileBL, + rom_.version_constants().kMap32TileBR}; + if (rom()->data()[0x01772E] != 0x04) { + map32address[0] = rom_.version_constants().kMap32TileTL; + map32address[1] = kMap32TileTRExpanded; + map32address[2] = kMap32TileBLExpanded; + map32address[3] = kMap32TileBRExpanded; + num_tile32 = kMap32TileCountExpanded; + expanded_tile32_ = true; + } + + // Loop through each 32x32 pixel tile in the rom + for (int i = 0; i < kMap32TilesLength; i += 6) { // Loop through each quadrant of the 32x32 pixel tile. for (int k = 0; k < 4; k++) { // Generate the 16-bit tile for the current quadrant of the current // 32x32 pixel tile. - uint16_t tl = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesTL); - uint16_t tr = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesTR); - uint16_t bl = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesBL); - uint16_t br = get_tile16_for_tile32(i, k, (int)Dimension::map32TilesBR); + ASSIGN_OR_RETURN(uint16_t tl, + GetTile16ForTile32(i, k, (int)Dimension::map32TilesTL, + map32address)); + ASSIGN_OR_RETURN(uint16_t tr, + GetTile16ForTile32(i, k, (int)Dimension::map32TilesTR, + map32address)); + ASSIGN_OR_RETURN(uint16_t bl, + GetTile16ForTile32(i, k, (int)Dimension::map32TilesBL, + map32address)); + ASSIGN_OR_RETURN(uint16_t br, + GetTile16ForTile32(i, k, (int)Dimension::map32TilesBR, + map32address)); // Add the generated 16-bit tiles to the tiles32 vector. tiles32_unique_.emplace_back(gfx::Tile32(tl, tr, bl, br)); @@ -194,11 +157,20 @@ void Overworld::AssembleMap32Tiles() { map_tiles_.dark_world[i].resize(0x200); map_tiles_.special_world[i].resize(0x200); } + + return absl::OkStatus(); } void Overworld::AssembleMap16Tiles() { int tpos = kMap16Tiles; - for (int i = 0; i < 4096; i += 1) { + int num_tile16 = kNumTile16Individual; + if (rom()->data()[0x02FD28] != 0x0F) { + tpos = kMap16TilesExpanded; + num_tile16 = NumberOfMap16Ex; + expanded_tile16_ = true; + } + + for (int i = 0; i < num_tile16; i += 1) { gfx::TileInfo t0 = gfx::GetTilesInfo(rom()->toint16(tpos)); tpos += 2; gfx::TileInfo t1 = gfx::GetTilesInfo(rom()->toint16(tpos)); @@ -223,7 +195,8 @@ void Overworld::AssignWorldTiles(int x, int y, int sx, int sy, int tpos, world[position_x2][position_y2] = tiles32_unique_[tpos].tile3_; } -void Overworld::OrganizeMapTiles(Bytes &bytes, Bytes &bytes2, int i, int sx, +void Overworld::OrganizeMapTiles(std::vector &bytes, + std::vector &bytes2, int i, int sx, int sy, int &ttpos) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { @@ -250,8 +223,8 @@ absl::Status Overworld::DecompressAllMapTiles() { return core::SnesToPc(p); }; - int lowest = 0x0FFFFF; - int highest = 0x0F8000; + uint32_t lowest = 0x0FFFFF; + uint32_t highest = 0x0F8000; int sx = 0; int sy = 0; int c = 0; @@ -273,14 +246,14 @@ absl::Status Overworld::DecompressAllMapTiles() { int size1, size2; auto decomp = gfx::lc_lz2::Uncompress(rom()->data() + p2, &size1, 1); bytes.resize(size1); - for (int i = 0; i < size1; i++) { - bytes[i] = decomp[i]; + for (int j = 0; j < size1; j++) { + bytes[j] = decomp[j]; } free(decomp); decomp = gfx::lc_lz2::Uncompress(rom()->data() + p1, &size2, 1); bytes2.resize(size2); - for (int i = 0; i < size2; i++) { - bytes2[i] = decomp[i]; + for (int j = 0; j < size2; j++) { + bytes2[j] = decomp[j]; } free(decomp); @@ -314,7 +287,7 @@ absl::Status Overworld::LoadOverworldMaps() { } auto task_function = [this, i, size, world_type]() { return overworld_maps_[i].BuildMap(size, game_state_, world_type, - GetMapTiles(world_type)); + tiles16_, GetMapTiles(world_type)); }; futures.emplace_back(std::async(std::launch::async, task_function)); } @@ -331,15 +304,27 @@ absl::Status Overworld::LoadOverworldMaps() { void Overworld::LoadTileTypes() { for (int i = 0; i < 0x200; i++) { - all_tiles_types_[i] = rom()->data()[overworldTilesType + i]; + all_tiles_types_[i] = + rom()->data()[rom()->version_constants().overworldTilesType + i]; } } void Overworld::LoadEntrances() { - for (int i = 0; i < 129; i++) { - short map_id = rom()->toint16(OWEntranceMap + (i * 2)); - uint16_t map_pos = rom()->toint16(OWEntrancePos + (i * 2)); - uint8_t entrance_id = rom_[OWEntranceEntranceId + i]; + int ow_entrance_map_ptr = OWEntranceMap; + int ow_entrance_pos_ptr = OWEntrancePos; + int ow_entrance_id_ptr = OWEntranceEntranceId; + int num_entrances = 129; + if (rom()->data()[0x0DB895] != 0xB8) { + ow_entrance_map_ptr = 0x0DB55F; + ow_entrance_pos_ptr = 0x0DB35F; + ow_entrance_id_ptr = 0x0DB75F; + expanded_entrances_ = true; + } + + for (int i = 0; i < num_entrances; i++) { + short map_id = rom()->toint16(ow_entrance_map_ptr + (i * 2)); + uint16_t map_pos = rom()->toint16(ow_entrance_pos_ptr + (i * 2)); + uint8_t entrance_id = rom_[ow_entrance_id_ptr + i]; int p = map_pos >> 1; int x = (p % 64); int y = (p >> 6); @@ -468,8 +453,8 @@ absl::Status Overworld::LoadItems() { (y * 16) + (sy * 512), false); auto size = all_items_.size(); - all_items_[size - 1].game_x = (uint8_t)x; - all_items_[size - 1].game_y = (uint8_t)y; + all_items_[size - 1].game_x_ = (uint8_t)x; + all_items_[size - 1].game_y_ = (uint8_t)y; addr += 3; } } @@ -487,13 +472,14 @@ absl::Status Overworld::LoadSprites() { return absl::OkStatus(); } -absl::Status Overworld::LoadSpritesFromMap(int sprite_start, int sprite_count, - int sprite_index) { - for (int i = 0; i < sprite_count; i++) { +absl::Status Overworld::LoadSpritesFromMap(int sprites_per_gamestate_ptr, + int num_maps_per_gamestate, + int game_state) { + for (int i = 0; i < num_maps_per_gamestate; i++) { if (map_parent_[i] != i) continue; - int ptrPos = sprite_start + (i * 2); - ASSIGN_OR_RETURN(auto word_addr, rom()->ReadWord(ptrPos)); + int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2); + ASSIGN_OR_RETURN(auto word_addr, rom()->ReadWord(current_spr_ptr)); int sprite_address = core::SnesToPc((0x09 << 0x10) | word_addr); while (true) { ASSIGN_OR_RETURN(uint8_t b1, rom()->ReadByte(sprite_address)); @@ -502,7 +488,7 @@ absl::Status Overworld::LoadSpritesFromMap(int sprite_start, int sprite_count, if (b1 == 0xFF) break; int editor_map_index = i; - if (sprite_index != 0) { + if (game_state != 0) { if (editor_map_index >= 128) editor_map_index -= 128; else if (editor_map_index >= 64) @@ -513,10 +499,11 @@ absl::Status Overworld::LoadSpritesFromMap(int sprite_start, int sprite_count, int realX = ((b2 & 0x3F) * 16) + mapX * 512; int realY = ((b1 & 0x3F) * 16) + mapY * 512; - all_sprites_[sprite_index].emplace_back( - overworld_maps_[i].current_graphics(), (uint8_t)i, b3, - (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY); - // all_sprites_[sprite_index][i].Draw(); + auto current_gfx = overworld_maps_[i].current_graphics(); + all_sprites_[game_state].emplace_back(current_gfx, (uint8_t)i, b3, + (uint8_t)(b2 & 0x3F), + (uint8_t)(b1 & 0x3F), realX, realY); + all_sprites_[game_state][i].Draw(); sprite_address += 3; } @@ -529,13 +516,13 @@ absl::Status Overworld::LoadSpritesFromMap(int sprite_start, int sprite_count, absl::Status Overworld::Save(Rom &rom) { rom_ = rom; - + if (expanded_tile16_) RETURN_IF_ERROR(SaveMap16Expanded()) RETURN_IF_ERROR(SaveMap16Tiles()) + if (expanded_tile32_) RETURN_IF_ERROR(SaveMap32Expanded()) RETURN_IF_ERROR(SaveMap32Tiles()) RETURN_IF_ERROR(SaveOverworldMaps()) RETURN_IF_ERROR(SaveEntrances()) RETURN_IF_ERROR(SaveExits()) - return absl::OkStatus(); } @@ -632,21 +619,20 @@ absl::Status Overworld::SaveOverworldMaps() { core::Logger::log("Saving map pointers1 and compressed data for map " + core::UppercaseHexByte(i) + " at " + core::UppercaseHexLong(snes_pos)); - RETURN_IF_ERROR( - rom()->WriteLong(kCompressedAllMap32PointersLow + (3 * i), snes_pos)); + RETURN_IF_ERROR(rom()->WriteLong( + rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i), + snes_pos)); RETURN_IF_ERROR(rom()->WriteVector(pos, a)); pos += size_a; } else { // Save pointer for map1 int snes_pos = map_pointers1[map_pointers1_id[i]]; - uint8_t b1 = (uint8_t)(snes_pos & 0xFF); - uint8_t b2 = (uint8_t)((snes_pos >> 8) & 0xFF); - uint8_t b3 = (uint8_t)((snes_pos >> 16) & 0xFF); core::Logger::log("Saving map pointers1 for map " + core::UppercaseHexByte(i) + " at " + core::UppercaseHexLong(snes_pos)); - RETURN_IF_ERROR( - rom()->WriteLong(kCompressedAllMap32PointersLow + (3 * i), snes_pos)); + RETURN_IF_ERROR(rom()->WriteLong( + rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i), + snes_pos)); } if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) { @@ -665,14 +651,12 @@ absl::Status Overworld::SaveOverworldMaps() { std::copy(b.begin(), b.end(), map_data_p2[i].begin()); int snes_pos = core::PcToSnes(pos); map_pointers2[i] = snes_pos; - uint8_t b1 = (uint8_t)(snes_pos & 0xFF); - uint8_t b2 = (uint8_t)((snes_pos >> 8) & 0xFF); - uint8_t b3 = (uint8_t)((snes_pos >> 16) & 0xFF); core::Logger::log("Saving map pointers2 and compressed data for map " + core::UppercaseHexByte(i) + " at " + core::UppercaseHexLong(snes_pos)); RETURN_IF_ERROR(rom()->WriteLong( - kCompressedAllMap32PointersHigh + (3 * i), snes_pos)); + rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i), + snes_pos)); RETURN_IF_ERROR(rom()->WriteVector(pos, b)); pos += size_b; } else { @@ -682,7 +666,8 @@ absl::Status Overworld::SaveOverworldMaps() { core::UppercaseHexByte(i) + " at " + core::UppercaseHexLong(snes_pos)); RETURN_IF_ERROR(rom()->WriteLong( - kCompressedAllMap32PointersHigh + (3 * i), snes_pos)); + rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i), + snes_pos)); } } @@ -1084,8 +1069,7 @@ absl::Status Overworld::CreateTile32Tilemap() { } // Create the unique tiles list - for (int i = 0; i < unique_tiles.size(); ++i) { - // static_cast(tile) + for (size_t i = 0; i < unique_tiles.size(); ++i) { tiles32_unique_.emplace_back(gfx::Tile32(unique_tiles[i])); } @@ -1118,11 +1102,61 @@ absl::Status Overworld::CreateTile32Tilemap() { return absl::OkStatus(); } +absl::Status Overworld::SaveMap32Expanded() { + int bottomLeft = kMap32TileBLExpanded; + int bottomRight = kMap32TileBRExpanded; + int topRight = kMap32TileTRExpanded; + int limit = 0x8A80; + + // Updates the pointers too for the tile32 + // Top Right + RETURN_IF_ERROR( + rom()->WriteLong(0x0176EC, core::PcToSnes(kMap32TileTRExpanded))); + RETURN_IF_ERROR( + rom()->WriteLong(0x0176F3, core::PcToSnes(kMap32TileTRExpanded + 1))); + RETURN_IF_ERROR( + rom()->WriteLong(0x0176FA, core::PcToSnes(kMap32TileTRExpanded + 2))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017701, core::PcToSnes(kMap32TileTRExpanded + 3))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017708, core::PcToSnes(kMap32TileTRExpanded + 4))); + RETURN_IF_ERROR( + rom()->WriteLong(0x01771A, core::PcToSnes(kMap32TileTRExpanded + 5))); + + // BottomLeft + RETURN_IF_ERROR( + rom()->WriteLong(0x01772C, core::PcToSnes(kMap32TileBLExpanded))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017733, core::PcToSnes(kMap32TileBLExpanded + 1))); + RETURN_IF_ERROR( + rom()->WriteLong(0x01773A, core::PcToSnes(kMap32TileBLExpanded + 2))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017741, core::PcToSnes(kMap32TileBLExpanded + 3))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017748, core::PcToSnes(kMap32TileBLExpanded + 4))); + RETURN_IF_ERROR( + rom()->WriteLong(0x01775A, core::PcToSnes(kMap32TileBLExpanded + 5))); + + // BottomRight + RETURN_IF_ERROR( + rom()->WriteLong(0x01776C, core::PcToSnes(kMap32TileBRExpanded))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017773, core::PcToSnes(kMap32TileBRExpanded + 1))); + RETURN_IF_ERROR( + rom()->WriteLong(0x01777A, core::PcToSnes(kMap32TileBRExpanded + 2))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017781, core::PcToSnes(kMap32TileBRExpanded + 3))); + RETURN_IF_ERROR( + rom()->WriteLong(0x017788, core::PcToSnes(kMap32TileBRExpanded + 4))); + RETURN_IF_ERROR( + rom()->WriteLong(0x01779A, core::PcToSnes(kMap32TileBRExpanded + 5))); + return absl::OkStatus(); +} + absl::Status Overworld::SaveMap32Tiles() { core::Logger::log("Saving Map32 Tiles"); constexpr int kMaxUniqueTiles = 0x4540; constexpr int kTilesPer32x32Tile = 6; - constexpr int kQuadrantsPer32x32Tile = 4; int unique_tile_index = 0; int num_unique_tiles = tiles32_unique_.size(); @@ -1248,6 +1282,84 @@ absl::Status Overworld::SaveMap32Tiles() { return absl::OkStatus(); } +absl::Status Overworld::SaveMap16Expanded() { + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x008865), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x0EDE4F), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x0EDEE9), + core::PcToSnes(kMap16TilesExpanded))); + + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BBC2D), + core::PcToSnes(kMap16TilesExpanded + 2))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BBC4C), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BBCC2), + core::PcToSnes(kMap16TilesExpanded + 4))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BBCCB), + core::PcToSnes(kMap16TilesExpanded + 6))); + + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BBEF6), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BBF23), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BC041), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BC9B3), + core::PcToSnes(kMap16TilesExpanded))); + + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BC9BA), + core::PcToSnes(kMap16TilesExpanded + 2))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BC9C1), + core::PcToSnes(kMap16TilesExpanded + 4))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BC9C8), + core::PcToSnes(kMap16TilesExpanded + 6))); + + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BCA40), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BCA47), + core::PcToSnes(kMap16TilesExpanded + 2))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BCA4E), + core::PcToSnes(kMap16TilesExpanded + 4))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x1BCA55), + core::PcToSnes(kMap16TilesExpanded + 6))); + + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F457), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F45E), + core::PcToSnes(kMap16TilesExpanded + 2))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F467), + core::PcToSnes(kMap16TilesExpanded + 4))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F46E), + core::PcToSnes(kMap16TilesExpanded + 6))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F51F), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F526), + core::PcToSnes(kMap16TilesExpanded + 4))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F52F), + core::PcToSnes(kMap16TilesExpanded + 2))); + RETURN_IF_ERROR(rom()->WriteLong(core::SnesToPc(0x02F536), + core::PcToSnes(kMap16TilesExpanded + 6))); + + RETURN_IF_ERROR(rom()->WriteShort(core::SnesToPc(0x02FE1C), + core::PcToSnes(kMap16TilesExpanded))); + RETURN_IF_ERROR(rom()->WriteShort(core::SnesToPc(0x02FE23), + core::PcToSnes(kMap16TilesExpanded + 4))); + RETURN_IF_ERROR(rom()->WriteShort(core::SnesToPc(0x02FE2C), + core::PcToSnes(kMap16TilesExpanded + 2))); + RETURN_IF_ERROR(rom()->WriteShort(core::SnesToPc(0x02FE33), + core::PcToSnes(kMap16TilesExpanded + 6))); + + RETURN_IF_ERROR(rom()->Write( + core::SnesToPc(0x02FD28), + static_cast(core::PcToSnes(kMap16TilesExpanded) >> 16))); + RETURN_IF_ERROR(rom()->Write( + core::SnesToPc(0x02FD39), + static_cast(core::PcToSnes(kMap16TilesExpanded) >> 16))); + + return absl::OkStatus(); +} + absl::Status Overworld::SaveMap16Tiles() { core::Logger::log("Saving Map16 Tiles"); int tpos = kMap16Tiles; @@ -1327,20 +1439,20 @@ absl::Status Overworld::SaveExits() { namespace { -bool compareItemsArrays(std::vector itemArray1, - std::vector itemArray2) { - if (itemArray1.size() != itemArray2.size()) { +bool compareItemsArrays(std::vector item_array1, + std::vector item_array2) { + if (item_array1.size() != item_array2.size()) { return false; } bool match; - for (int i = 0; i < itemArray1.size(); i++) { + for (size_t i = 0; i < item_array1.size(); i++) { match = false; - for (int j = 0; j < itemArray2.size(); j++) { + for (size_t j = 0; j < item_array2.size(); j++) { // Check all sprite in 2nd array if one match - if (itemArray1[i].x_ == itemArray2[j].x_ && - itemArray1[i].y_ == itemArray2[j].y_ && - itemArray1[i].id == itemArray2[j].id) { + if (item_array1[i].x_ == item_array2[j].x_ && + item_array1[i].y_ == item_array2[j].y_ && + item_array1[i].id_ == item_array2[j].id_) { match = true; break; } @@ -1362,11 +1474,11 @@ absl::Status Overworld::SaveItems() { for (int i = 0; i < 128; i++) { room_items[i] = std::vector(); for (const OverworldItem &item : all_items_) { - if (item.room_map_id == i) { + if (item.room_map_id_ == i) { room_items[i].emplace_back(item); - if (item.id == 0x86) { + if (item.id_ == 0x86) { RETURN_IF_ERROR(rom()->WriteWord( - 0x16DC5 + (i * 2), (item.game_x + (item.game_y * 64)) * 2)); + 0x16DC5 + (i * 2), (item.game_x_ + (item.game_y_ * 64)) * 2)); } } } @@ -1403,11 +1515,11 @@ absl::Status Overworld::SaveItems() { item_pointers[i] = data_pos; for (const OverworldItem &item : room_items[i]) { short map_pos = - static_cast(((item.game_y << 6) + item.game_x) << 1); + static_cast(((item.game_y_ << 6) + item.game_x_) << 1); uint32_t data = static_cast(map_pos & 0xFF) | static_cast(map_pos >> 8) | - static_cast(item.id); + static_cast(item.id_); RETURN_IF_ERROR(rom()->WriteLong(data_pos, data)); data_pos += 3; } @@ -1440,9 +1552,9 @@ absl::Status Overworld::SaveItems() { absl::Status Overworld::SaveMapProperties() { core::Logger::log("Saving Map Properties"); for (int i = 0; i < 64; i++) { - RETURN_IF_ERROR( - rom()->WriteByte(mapGfx + i, overworld_maps_[i].area_graphics())); - RETURN_IF_ERROR(rom()->WriteByte(overworldMapPalette + i, + RETURN_IF_ERROR(rom()->WriteByte(kAreaGfxIdPtr + i, + overworld_maps_[i].area_graphics())); + RETURN_IF_ERROR(rom()->WriteByte(kOverworldMapPaletteIds + i, overworld_maps_[i].area_palette())); RETURN_IF_ERROR(rom()->WriteByte(overworldSpriteset + i, overworld_maps_[i].sprite_graphics(0))); @@ -1450,125 +1562,36 @@ absl::Status Overworld::SaveMapProperties() { overworld_maps_[i].sprite_graphics(1))); RETURN_IF_ERROR(rom()->WriteByte(overworldSpriteset + 128 + i, overworld_maps_[i].sprite_graphics(2))); - RETURN_IF_ERROR(rom()->WriteByte(overworldSpritePalette + i, + RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpritePaletteIds + i, overworld_maps_[i].sprite_palette(0))); - RETURN_IF_ERROR(rom()->WriteByte(overworldSpritePalette + 64 + i, + RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpritePaletteIds + 64 + i, overworld_maps_[i].sprite_palette(1))); - RETURN_IF_ERROR(rom()->WriteByte(overworldSpritePalette + 128 + i, + RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpritePaletteIds + 128 + i, overworld_maps_[i].sprite_palette(2))); } for (int i = 64; i < 128; i++) { - RETURN_IF_ERROR( - rom()->WriteByte(mapGfx + i, overworld_maps_[i].area_graphics())); + RETURN_IF_ERROR(rom()->WriteByte(kAreaGfxIdPtr + i, + overworld_maps_[i].area_graphics())); RETURN_IF_ERROR(rom()->WriteByte(overworldSpriteset + i, overworld_maps_[i].sprite_graphics(0))); RETURN_IF_ERROR(rom()->WriteByte(overworldSpriteset + 64 + i, overworld_maps_[i].sprite_graphics(1))); RETURN_IF_ERROR(rom()->WriteByte(overworldSpriteset + 128 + i, overworld_maps_[i].sprite_graphics(2))); - RETURN_IF_ERROR(rom()->WriteByte(overworldMapPalette + i, + RETURN_IF_ERROR(rom()->WriteByte(kOverworldMapPaletteIds + i, overworld_maps_[i].area_palette())); - RETURN_IF_ERROR(rom()->WriteByte(overworldSpritePalette + 64 + i, + RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpritePaletteIds + 64 + i, overworld_maps_[i].sprite_palette(0))); - RETURN_IF_ERROR(rom()->WriteByte(overworldSpritePalette + 128 + i, + RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpritePaletteIds + 128 + i, overworld_maps_[i].sprite_palette(1))); - RETURN_IF_ERROR(rom()->WriteByte(overworldSpritePalette + 192 + i, + RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpritePaletteIds + 192 + i, overworld_maps_[i].sprite_palette(2))); } return absl::OkStatus(); } -absl::Status Overworld::DecompressProtoMapTiles(const std::string &filename) { - proto_map_data_ = parseFile(filename); - int sx = 0; - int sy = 0; - int c = 0; - for (int i = 0; i < proto_map_data_.size(); i++) { - int ttpos = 0; - - ASSIGN_OR_RETURN(auto bytes, gfx::lc_lz2::DecompressOverworld( - proto_map_data_[i].lowData, 0, - proto_map_data_[i].lowData.size())) - ASSIGN_OR_RETURN(auto bytes2, gfx::lc_lz2::DecompressOverworld( - proto_map_data_[i].highData, 0, - proto_map_data_[i].highData.size())) - OrganizeMapTiles(bytes, bytes2, i, sx, sy, ttpos); - - sx++; - if (sx >= 8) { - sy++; - sx = 0; - } - - c++; - if (c >= 64) { - sx = 0; - sy = 0; - c = 0; - } - } - - return absl::OkStatus(); -} - -absl::Status Overworld::LoadPrototype(Rom &rom, - const std::string &tilemap_filename) { - rom_ = rom; - - AssembleMap32Tiles(); - AssembleMap16Tiles(); - RETURN_IF_ERROR(DecompressProtoMapTiles(tilemap_filename)) - - for (int map_index = 0; map_index < kNumOverworldMaps; ++map_index) - overworld_maps_.emplace_back(map_index, rom_, tiles16_); - - FetchLargeMaps(); - LoadEntrances(); - - auto size = tiles16_.size(); - std::vector> futures; - for (int i = 0; i < kNumOverworldMaps; ++i) { - futures.emplace_back(std::async(std::launch::async, [this, i, size]() { - if (i < 64) { - return overworld_maps_[i].BuildMap(size, game_state_, 0, - map_tiles_.light_world); - } else if (i < 0x80 && i >= 0x40) { - return overworld_maps_[i].BuildMap(size, game_state_, 1, - map_tiles_.dark_world); - } else { - return overworld_maps_[i].BuildMap(size, game_state_, 2, - map_tiles_.special_world); - } - })); - } - - // Wait for all tasks to complete and check their results - for (auto &future : futures) { - absl::Status status = future.get(); - if (!status.ok()) { - return status; - } - } - - is_loaded_ = true; - return absl::OkStatus(); -} - -OWBlockset &Overworld::GetMapTiles(int world_type) { - switch (world_type) { - case 0: - return map_tiles_.light_world; - case 1: - return map_tiles_.dark_world; - case 2: - return map_tiles_.special_world; - default: - return map_tiles_.light_world; - } -} - } // namespace overworld } // namespace zelda3 } // namespace app diff --git a/src/app/zelda3/overworld/overworld.h b/src/app/zelda3/overworld/overworld.h index affb48d8..030547ed 100644 --- a/src/app/zelda3/overworld/overworld.h +++ b/src/app/zelda3/overworld/overworld.h @@ -1,17 +1,12 @@ #ifndef YAZE_APP_DATA_OVERWORLD_H #define YAZE_APP_DATA_OVERWORLD_H -#include - -#include -#include #include #include "absl/container/flat_hash_map.h" #include "absl/status/status.h" #include "app/core/common.h" #include "app/core/constants.h" -#include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" #include "app/zelda3/common.h" @@ -28,6 +23,18 @@ namespace zelda3 { */ namespace overworld { +constexpr int GravesYTilePos = 0x49968; // short (0x0F entries) +constexpr int GravesXTilePos = 0x49986; // short (0x0F entries) +constexpr int GravesTilemapPos = 0x499A4; // short (0x0F entries) +constexpr int GravesGFX = 0x499C2; // short (0x0F entries) + +constexpr int GravesXPos = 0x4994A; // short (0x0F entries) +constexpr int GravesYLine = 0x4993A; // short (0x08 entries) +constexpr int GravesCountOnY = 0x499E0; // Byte 0x09 entries + +constexpr int GraveLinkSpecialHole = 0x46DD9; // short +constexpr int GraveLinkSpecialStairs = 0x46DE0; // short + // List of secret item names const std::vector kSecretItemNames = { "Nothing", // 0 @@ -65,56 +72,52 @@ constexpr int kOverworldItemsAddress = 0xDC8B9; // 1BC2F9 constexpr int overworldItemsBank = 0xDC8BF; constexpr int overworldItemsEndData = 0xDC89C; // 0DC89E -class OverworldItem : public OverworldEntity { +class OverworldItem : public GameEntity { public: - bool bg2 = false; - uint8_t game_x; - uint8_t game_y; - uint8_t id; - uint16_t room_map_id; + bool bg2_ = false; + uint8_t id_; + uint8_t game_x_; + uint8_t game_y_; + uint16_t room_map_id_; int unique_id = 0; bool deleted = false; OverworldItem() = default; OverworldItem(uint8_t id, uint16_t room_map_id, int x, int y, bool bg2) { - this->id = id; + this->id_ = id; this->x_ = x; this->y_ = y; - this->bg2 = bg2; - this->room_map_id = room_map_id; + this->bg2_ = bg2; + this->room_map_id_ = room_map_id; this->map_id_ = room_map_id; this->entity_id_ = id; - this->type_ = kItem; + this->entity_type_ = kItem; int map_x = room_map_id - ((room_map_id / 8) * 8); int map_y = room_map_id / 8; - this->game_x = static_cast(std::abs(x - (map_x * 512)) / 16); - this->game_y = static_cast(std::abs(y - (map_y * 512)) / 16); - // this->unique_id = ROM.unique_item_id++; + game_x_ = static_cast(std::abs(x - (map_x * 512)) / 16); + game_y_ = static_cast(std::abs(y - (map_y * 512)) / 16); } - void UpdateMapProperties(int16_t room_map_id) override { - this->room_map_id = static_cast(room_map_id); + void UpdateMapProperties(uint16_t room_map_id) override { + room_map_id_ = room_map_id; - if (room_map_id >= 64) { - room_map_id -= 64; + if (room_map_id_ >= 64) { + room_map_id_ -= 64; } - int map_x = room_map_id - ((room_map_id / 8) * 8); - int map_y = room_map_id / 8; + int map_x = room_map_id_ - ((room_map_id_ / 8) * 8); + int map_y = room_map_id_ / 8; - this->game_x = - static_cast(std::abs(this->x_ - (map_x * 512)) / 16); - this->game_y = - static_cast(std::abs(this->y_ - (map_y * 512)) / 16); + game_x_ = static_cast(std::abs(x_ - (map_x * 512)) / 16); + game_y_ = static_cast(std::abs(y_ - (map_y * 512)) / 16); std::cout << "Item: " << std::hex << std::setw(2) << std::setfill('0') - << static_cast(this->id) << " MapId: " << std::hex - << std::setw(2) << std::setfill('0') - << static_cast(this->room_map_id) - << " X: " << static_cast(this->game_x) - << " Y: " << static_cast(this->game_y) << std::endl; + << static_cast(id_) << " MapId: " << std::hex << std::setw(2) + << std::setfill('0') << static_cast(room_map_id_) + << " X: " << static_cast(game_x_) + << " Y: " << static_cast(game_y_) << std::endl; } }; @@ -147,7 +150,7 @@ constexpr int OWExitUnk1Whirlpool = 0x16BF5; // JP = ;016E91 constexpr int OWExitUnk2Whirlpool = 0x16C17; // JP = ;016EB3 constexpr int OWWhirlpoolPosition = 0x16CF8; // JP = ;016F94 -class OverworldExit : public OverworldEntity { +class OverworldExit : public GameEntity { public: uint16_t y_scroll_; uint16_t x_scroll_; @@ -179,7 +182,6 @@ class OverworldExit : public OverworldEntity { entrance_id_(0), area_x_(0), area_y_(0), - is_hole_(false), room_id_(room_id), y_scroll_(y_scroll), x_scroll_(x_scroll), @@ -191,12 +193,13 @@ class OverworldExit : public OverworldEntity { scroll_mod_x_(scroll_mod_x), door_type_1_(door_type_1), door_type_2_(door_type_2), + is_hole_(false), deleted_(deleted) { // Initialize entity variables - this->x_ = player_x; - this->y_ = player_y; - this->map_id_ = map_id; - this->type_ = kExit; + x_ = player_x; + y_ = player_y; + map_id_ = map_id; + entity_type_ = kExit; int mapX = (map_id_ - ((map_id_ / 8) * 8)); int mapY = (map_id_ / 8); @@ -230,7 +233,7 @@ class OverworldExit : public OverworldEntity { } // Overworld overworld - void UpdateMapProperties(short map_id) override { + void UpdateMapProperties(uint16_t map_id) override { map_id_ = map_id; int large = 256; @@ -323,7 +326,21 @@ constexpr int OWHoleArea = 0xDB826; //(0x13 entries, 1 byte each) corresponding entrance numbers constexpr int OWHoleEntrance = 0xDB84C; -class OverworldEntrance : public OverworldEntity { +// OWEntrances Expansion + +// Instructions for editors +// if byte at (PC) address 0xDB895 == B8 then it is vanilla +// Load normal overworld entrances data +// Otherwise load from the expanded space +// When saving just save in expanded space 256 values for each +// (PC Addresses) - you can find snes address at the orgs below +// 0x0DB35F = (short) Map16 tile address (mapPos in ZS) +// 0x0DB55F = (short) Screen ID (MapID in ZS) +// 0x0DB75F = (byte) Entrance leading to (EntranceID in ZS) + +// *Important* the Screen ID now also require bit 0x8000 (15) being set to tell +// entrance is a hole +class OverworldEntrance : public GameEntity { public: uint16_t map_pos_; uchar entrance_id_; @@ -340,7 +357,7 @@ class OverworldEntrance : public OverworldEntity { y_ = y; map_id_ = map_id; entity_id_ = entrance_id; - type_ = kEntrance; + entity_type_ = kEntrance; int mapX = (map_id_ - ((map_id_ / 8) * 8)); int mapY = (map_id_ / 8); @@ -348,12 +365,7 @@ class OverworldEntrance : public OverworldEntity { area_y_ = (uchar)((std::abs(y - (mapY * 512)) / 16)); } - auto Copy() { - return new OverworldEntrance(x_, y_, entrance_id_, map_id_, map_pos_, - is_hole_); - } - - void UpdateMapProperties(short map_id) override { + void UpdateMapProperties(uint16_t map_id) override { map_id_ = map_id; if (map_id_ >= 64) { @@ -370,13 +382,8 @@ class OverworldEntrance : public OverworldEntity { } }; -constexpr int kCompressedAllMap32PointersHigh = 0x1794D; -constexpr int kCompressedAllMap32PointersLow = 0x17B2D; -constexpr int overworldPalGroup1 = 0xDE6C8; -constexpr int overworldPalGroup2 = 0xDE86C; -constexpr int overworldPalGroup3 = 0xDE604; -constexpr int overworldMapPalette = 0x7D1C; -constexpr int overworldSpritePalette = 0x7B41; +constexpr int kOverworldMapPaletteIds = 0x7D1C; +constexpr int kOverworldSpritePaletteIds = 0x7B41; constexpr int overworldMapPaletteGroup = 0x75504; constexpr int overworldSpritePaletteGroup = 0x75580; constexpr int overworldSpriteset = 0x7A41; @@ -386,12 +393,8 @@ constexpr int overworldSpritesBegining = 0x4C881; constexpr int overworldSpritesAgahnim = 0x4CA21; constexpr int overworldSpritesZelda = 0x4C901; -constexpr int mapGfx = 0x7C9C; -constexpr int overlayPointers = 0x77664; -constexpr int overlayPointersBank = 0x0E; - -constexpr int overworldTilesType = 0x71459; -constexpr int overworldMessages = 0x3F51D; +constexpr int kAreaGfxIdPtr = 0x7C9C; +constexpr int kOverworldMessageIds = 0x3F51D; constexpr int overworldMusicBegining = 0x14303; constexpr int overworldMusicZelda = 0x14303 + 0x40; @@ -432,51 +435,23 @@ constexpr int transition_target_west = 0x13F62; constexpr int overworldCustomMosaicASM = 0x1301D0; constexpr int overworldCustomMosaicArray = 0x1301F0; -// 1 byte, not 0 if enabled -constexpr int OverworldCustomASMHasBeenApplied = 0x140145; - -// 2 bytes for each overworld area (0x140) -constexpr int OverworldCustomAreaSpecificBGPalette = 0x140000; - -// 1 byte, not 0 if enabled -constexpr int OverworldCustomAreaSpecificBGEnabled = 0x140140; - -// 1 byte for each overworld area (0xA0) -constexpr int OverworldCustomMainPaletteArray = 0x140160; -// 1 byte, not 0 if enabled -constexpr int OverworldCustomMainPaletteEnabled = 0x140141; - -// 1 byte for each overworld area (0xA0) -constexpr int OverworldCustomMosaicArray = 0x140200; - -// 1 byte, not 0 if enabled -constexpr int OverworldCustomMosaicEnabled = 0x140142; - -// 1 byte for each overworld area (0xA0) -constexpr int OverworldCustomAnimatedGFXArray = 0x1402A0; - -// 1 byte, not 0 if enabled -constexpr int OverworldCustomAnimatedGFXEnabled = 0x140143; - -// 2 bytes for each overworld area (0x140) -constexpr int OverworldCustomSubscreenOverlayArray = 0x140340; - -// 1 byte, not 0 if enabled -constexpr int OverworldCustomSubscreenOverlayEnabled = 0x140144; +// Expanded tile16 and tile32 +constexpr int kMap16TilesExpanded = 0x1E8000; +constexpr int kMap32TileTRExpanded = 0x020000; +constexpr int kMap32TileBLExpanded = 0x1F0000; +constexpr int kMap32TileBRExpanded = 0x1F8000; +constexpr int kMap32TileCountExpanded = 0x0067E0; constexpr int kMap16Tiles = 0x78000; constexpr int kNumOverworldMaps = 160; +constexpr int kNumTile16Individual = 4096; constexpr int Map32PerScreen = 256; -constexpr int NumberOfMap16 = 3752; // 4096 +constexpr int NumberOfMap16 = 3752; // 4096 +constexpr int NumberOfMap16Ex = 4096; // 4096 constexpr int LimitOfMap32 = 8864; constexpr int NumberOfOWSprites = 352; constexpr int NumberOfMap32 = Map32PerScreen * kNumOverworldMaps; -struct MapData { - std::vector highData; - std::vector lowData; -}; - /** * @brief Represents the full Overworld data, light and dark world. * @@ -485,7 +460,6 @@ struct MapData { */ class Overworld : public SharedRom, public core::ExperimentFlags { public: - OWBlockset &GetMapTiles(int world_type); absl::Status Load(Rom &rom); absl::Status LoadOverworldMaps(); void LoadTileTypes(); @@ -505,11 +479,12 @@ class Overworld : public SharedRom, public core::ExperimentFlags { absl::Status SaveItems(); absl::Status CreateTile32Tilemap(); + absl::Status SaveMap16Expanded(); absl::Status SaveMap16Tiles(); + absl::Status SaveMap32Expanded(); absl::Status SaveMap32Tiles(); absl::Status SaveMapProperties(); - absl::Status LoadPrototype(Rom &rom_, const std::string &tilemap_filename); void Destroy() { for (auto &map : overworld_maps_) { @@ -523,7 +498,6 @@ class Overworld : public SharedRom, public core::ExperimentFlags { is_loaded_ = false; } - int current_world_ = 0; int GetTileFromPosition(ImVec2 position) const { if (current_world_ == 0) { return map_tiles_.light_world[position.x][position.y]; @@ -534,14 +508,27 @@ class Overworld : public SharedRom, public core::ExperimentFlags { } } + OWBlockset &GetMapTiles(int world_type) { + switch (world_type) { + case 0: + return map_tiles_.light_world; + case 1: + return map_tiles_.dark_world; + case 2: + return map_tiles_.special_world; + default: + return map_tiles_.light_world; + } + } + auto overworld_maps() const { return overworld_maps_; } auto overworld_map(int i) const { return &overworld_maps_[i]; } auto mutable_overworld_map(int i) { return &overworld_maps_[i]; } auto exits() const { return &all_exits_; } auto mutable_exits() { return &all_exits_; } std::vector tiles16() const { return tiles16_; } - - auto Sprites(int state) const { return all_sprites_[state]; } + auto mutable_tiles16() { return &tiles16_; } + auto sprites(int state) const { return all_sprites_[state]; } auto mutable_sprites(int state) { return &all_sprites_[state]; } auto current_graphics() const { return overworld_maps_[current_map_].current_graphics(); @@ -552,26 +539,21 @@ class Overworld : public SharedRom, public core::ExperimentFlags { auto mutable_holes() { return &all_holes_; } auto deleted_entrances() const { return deleted_entrances_; } auto mutable_deleted_entrances() { return &deleted_entrances_; } - auto AreaPalette() const { + auto current_area_palette() const { return overworld_maps_[current_map_].current_palette(); } - auto AreaPaletteById(int id) const { - return overworld_maps_[id].current_palette(); - } - auto BitmapData() const { + auto current_map_bitmap_data() const { return overworld_maps_[current_map_].bitmap_data(); } - auto Tile16Blockset() const { + auto tile16_blockset_data() const { return overworld_maps_[current_map_].current_tile16_blockset(); } auto is_loaded() const { return is_loaded_; } void set_current_map(int i) { current_map_ = i; } - auto map_tiles() const { return map_tiles_; } auto mutable_map_tiles() { return &map_tiles_; } auto all_items() const { return all_items_; } auto mutable_all_items() { return &all_items_; } - auto &ref_all_items() { return all_items_; } auto all_tiles_types() const { return all_tiles_types_; } auto mutable_all_tiles_types() { return &all_tiles_types_; } @@ -584,20 +566,26 @@ class Overworld : public SharedRom, public core::ExperimentFlags { }; void FetchLargeMaps(); - void AssembleMap32Tiles(); + absl::StatusOr GetTile16ForTile32(int index, int quadrant, + int dimension, + const uint32_t *map32address); + absl::Status AssembleMap32Tiles(); void AssembleMap16Tiles(); void AssignWorldTiles(int x, int y, int sx, int sy, int tpos, OWBlockset &world); - void OrganizeMapTiles(Bytes &bytes, Bytes &bytes2, int i, int sx, int sy, + void OrganizeMapTiles(std::vector &bytes, + std::vector &bytes2, int i, int sx, int sy, int &ttpos); absl::Status DecompressAllMapTiles(); - absl::Status DecompressProtoMapTiles(const std::string &filename); - bool is_loaded_ = false; + bool expanded_tile16_ = false; + bool expanded_tile32_ = false; + bool expanded_entrances_ = false; int game_state_ = 0; int current_map_ = 0; + int current_world_ = 0; uchar map_parent_[160]; Rom rom_; @@ -630,7 +618,6 @@ class Overworld : public SharedRom, public core::ExperimentFlags { std::vector map_pointers2 = std::vector(kNumOverworldMaps); std::vector> usage_stats_; - absl::flat_hash_map proto_map_data_; }; } // namespace overworld @@ -638,4 +625,4 @@ class Overworld : public SharedRom, public core::ExperimentFlags { } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/zelda3/overworld/overworld_map.cc b/src/app/zelda3/overworld/overworld_map.cc index 47b63070..3ff96b98 100644 --- a/src/app/zelda3/overworld/overworld_map.cc +++ b/src/app/zelda3/overworld/overworld_map.cc @@ -1,16 +1,10 @@ #include "overworld_map.h" -#include "imgui/imgui.h" - #include #include -#include #include #include -#include "app/core/common.h" -#include "app/editor/utils/gfx_context.h" -#include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" #include "app/zelda3/overworld/overworld.h" @@ -20,13 +14,24 @@ namespace app { namespace zelda3 { namespace overworld { -OverworldMap::OverworldMap(int index, Rom& rom, - std::vector& tiles16) - : parent_(index), index_(index), rom_(rom), tiles16_(tiles16) { +OverworldMap::OverworldMap(int index, Rom& rom, bool load_custom_data) + : index_(index), parent_(index), rom_(rom) { LoadAreaInfo(); + + if (load_custom_data) { + // If the custom overworld ASM has NOT already been applied, manually set + // the vanilla values. + uint8_t asm_version = rom_[OverworldCustomASMHasBeenApplied]; + if (asm_version == 0x00) { + LoadCustomOverworldData(); + } else { + SetupCustomTileset(asm_version); + } + } } absl::Status OverworldMap::BuildMap(int count, int game_state, int world, + std::vector& tiles16, OWBlockset& world_blockset) { game_state_ = game_state; world_ = world; @@ -39,8 +44,8 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world, area_graphics_ = 0x51; area_palette_ = 0x00; } else { - area_graphics_ = rom_[mapGfx + parent_]; - area_palette_ = rom_[overworldMapPalette + parent_]; + area_graphics_ = rom_[kAreaGfxIdPtr + parent_]; + area_palette_ = rom_[kOverworldMapPaletteIds + parent_]; } initialized_ = true; @@ -49,7 +54,7 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world, LoadAreaGraphics(); RETURN_IF_ERROR(BuildTileset()) - RETURN_IF_ERROR(BuildTiles16Gfx(count)) + RETURN_IF_ERROR(BuildTiles16Gfx(tiles16, count)) RETURN_IF_ERROR(LoadPalette()); RETURN_IF_ERROR(BuildBitmap(world_blockset)) built_ = true; @@ -66,11 +71,11 @@ void OverworldMap::LoadAreaInfo() { } } - message_id_ = rom_.toint16(overworldMessages + (parent_ * 2)); + message_id_ = rom_.toint16(kOverworldMessageIds + (parent_ * 2)); if (index_ < 0x40) { - area_graphics_ = rom_[mapGfx + parent_]; - area_palette_ = rom_[overworldMapPalette + parent_]; + area_graphics_ = rom_[kAreaGfxIdPtr + parent_]; + area_palette_ = rom_[kOverworldMapPaletteIds + parent_]; area_music_[0] = rom_[overworldMusicBegining + parent_]; area_music_[1] = rom_[overworldMusicZelda + parent_]; @@ -81,21 +86,21 @@ void OverworldMap::LoadAreaInfo() { sprite_graphics_[1] = rom_[overworldSpriteset + parent_ + 0x40]; sprite_graphics_[2] = rom_[overworldSpriteset + parent_ + 0x80]; - sprite_palette_[0] = rom_[overworldSpritePalette + parent_]; - sprite_palette_[1] = rom_[overworldSpritePalette + parent_ + 0x40]; - sprite_palette_[2] = rom_[overworldSpritePalette + parent_ + 0x80]; + sprite_palette_[0] = rom_[kOverworldSpritePaletteIds + parent_]; + sprite_palette_[1] = rom_[kOverworldSpritePaletteIds + parent_ + 0x40]; + sprite_palette_[2] = rom_[kOverworldSpritePaletteIds + parent_ + 0x80]; } else if (index_ < 0x80) { - area_graphics_ = rom_[mapGfx + parent_]; - area_palette_ = rom_[overworldMapPalette + parent_]; + area_graphics_ = rom_[kAreaGfxIdPtr + parent_]; + area_palette_ = rom_[kOverworldMapPaletteIds + parent_]; area_music_[0] = rom_[overworldMusicDW + (parent_ - 64)]; sprite_graphics_[0] = rom_[overworldSpriteset + parent_ + 0x80]; sprite_graphics_[1] = rom_[overworldSpriteset + parent_ + 0x80]; sprite_graphics_[2] = rom_[overworldSpriteset + parent_ + 0x80]; - sprite_palette_[0] = rom_[overworldSpritePalette + parent_ + 0x80]; - sprite_palette_[1] = rom_[overworldSpritePalette + parent_ + 0x80]; - sprite_palette_[2] = rom_[overworldSpritePalette + parent_ + 0x80]; + sprite_palette_[0] = rom_[kOverworldSpritePaletteIds + parent_ + 0x80]; + sprite_palette_[1] = rom_[kOverworldSpritePaletteIds + parent_ + 0x80]; + sprite_palette_[2] = rom_[kOverworldSpritePaletteIds + parent_ + 0x80]; } else { if (index_ == 0x94) { parent_ = 0x80; @@ -130,20 +135,209 @@ void OverworldMap::LoadAreaInfo() { area_palette_ = 0x00; } else { // pyramid bg use 0x5B map - area_graphics_ = rom_[mapGfx + parent_]; - area_palette_ = rom_[overworldMapPalette + parent_]; + area_graphics_ = rom_[kAreaGfxIdPtr + parent_]; + area_palette_ = rom_[kOverworldMapPaletteIds + parent_]; } sprite_graphics_[0] = rom_[overworldSpriteset + parent_ + 0x80]; sprite_graphics_[1] = rom_[overworldSpriteset + parent_ + 0x80]; sprite_graphics_[2] = rom_[overworldSpriteset + parent_ + 0x80]; - sprite_palette_[0] = rom_[overworldSpritePalette + parent_ + 0x80]; - sprite_palette_[1] = rom_[overworldSpritePalette + parent_ + 0x80]; - sprite_palette_[2] = rom_[overworldSpritePalette + parent_ + 0x80]; + sprite_palette_[0] = rom_[kOverworldSpritePaletteIds + parent_ + 0x80]; + sprite_palette_[1] = rom_[kOverworldSpritePaletteIds + parent_ + 0x80]; + sprite_palette_[2] = rom_[kOverworldSpritePaletteIds + parent_ + 0x80]; } } +void OverworldMap::LoadCustomOverworldData() { + // Set the main palette values. + if (index_ < 0x40) { + area_palette_ = 0; + } else if (index_ >= 0x40 && index_ < 0x80) { + area_palette_ = 1; + } else if (index_ >= 0x80 && index_ < 0xA0) { + area_palette_ = 0; + } + + if (index_ == 0x03 || index_ == 0x05 || index_ == 0x07) { + area_palette_ = 2; + } else if (index_ == 0x43 || index_ == 0x45 || index_ == 0x47) { + area_palette_ = 3; + } else if (index_ == 0x88) { + area_palette_ = 4; + } + + // Set the mosaic values. + mosaic_ = index_ == 0x00 || index_ == 0x40 || index_ == 0x80 || + index_ == 0x81 || index_ == 0x88; + + int indexWorld = 0x20; + + if (parent_ >= 0x40 && parent_ < 0x80) // DW + { + indexWorld = 0x21; + } else if (parent_ == 0x88) // Triforce room + { + indexWorld = 0x24; + } + + const auto overworld_gfx_groups2 = + rom_.version_constants().kOverworldGfxGroups2; + + // Main Blocksets + + for (int i = 0; i < 8; i++) { + custom_gfx_ids_[i] = + (uint8_t)rom_[overworld_gfx_groups2 + (indexWorld * 8) + i]; + } + + const auto overworldgfxGroups = rom_.version_constants().kOverworldGfxGroups1; + + // Replace the variable tiles with the variable ones. + uint8_t temp = rom_[overworldgfxGroups + (area_graphics_ * 4)]; + if (temp != 0) { + custom_gfx_ids_[3] = temp; + } else { + custom_gfx_ids_[3] = 0xFF; + } + + temp = rom_[overworldgfxGroups + (area_graphics_ * 4) + 1]; + if (temp != 0) { + custom_gfx_ids_[4] = temp; + } else { + custom_gfx_ids_[4] = 0xFF; + } + + temp = rom_[overworldgfxGroups + (area_graphics_ * 4) + 2]; + if (temp != 0) { + custom_gfx_ids_[5] = temp; + } else { + custom_gfx_ids_[5] = 0xFF; + } + + temp = rom_[overworldgfxGroups + (area_graphics_ * 4) + 3]; + if (temp != 0) { + custom_gfx_ids_[6] = temp; + } else { + custom_gfx_ids_[6] = 0xFF; + } + + // Set the animated GFX values. + if (index_ == 0x03 || index_ == 0x05 || index_ == 0x07 || index_ == 0x43 || + index_ == 0x45 || index_ == 0x47) { + animated_gfx_ = 0x59; + } else { + animated_gfx_ = 0x5B; + } + + // Set the subscreen overlay values. + subscreen_overlay_ = 0x00FF; + + if (index_ == 0x00 || + index_ == 0x40) // Add fog 2 to the lost woods and skull woods. + { + subscreen_overlay_ = 0x009D; + } else if (index_ == 0x03 || index_ == 0x05 || + index_ == 0x07) // Add the sky BG to LW death mountain. + { + subscreen_overlay_ = 0x0095; + } else if (index_ == 0x43 || index_ == 0x45 || + index_ == 0x47) // Add the lava to DW death mountain. + { + subscreen_overlay_ = 0x009C; + } else if (index_ == 0x5B) // TODO: Might need this one too "index == 0x1B" + // but for now I don't think so. + { + subscreen_overlay_ = 0x0096; + } else if (index_ == 0x80) // Add fog 1 to the master sword area. + { + subscreen_overlay_ = 0x0097; + } else if (index_ == + 0x88) // Add the triforce room curtains to the triforce room. + { + subscreen_overlay_ = 0x0093; + } +} + +void OverworldMap::SetupCustomTileset(uint8_t asm_version) { + area_palette_ = rom_[OverworldCustomMainPaletteArray + index_]; + mosaic_ = rom_[OverworldCustomMosaicArray + index_] != 0x00; + + // This is just to load the GFX groups for ROMs that have an older version + // of the Overworld ASM already applied. + if (asm_version >= 0x01 && asm_version != 0xFF) { + for (int i = 0; i < 8; i++) { + custom_gfx_ids_[i] = + rom_[OverworldCustomTileGFXGroupArray + (index_ * 8) + i]; + } + + animated_gfx_ = rom_[OverworldCustomAnimatedGFXArray + index_]; + } else { + int indexWorld = 0x20; + + if (parent_ >= 0x40 && parent_ < 0x80) // DW + { + indexWorld = 0x21; + } else if (parent_ == 0x88) // Triforce room + { + indexWorld = 0x24; + } + + // Main Blocksets + + for (int i = 0; i < 8; i++) { + custom_gfx_ids_[i] = + (uint8_t)rom_[rom_.version_constants().kOverworldGfxGroups2 + + (indexWorld * 8) + i]; + } + + const auto overworldgfxGroups = + rom_.version_constants().kOverworldGfxGroups1; + + // Replace the variable tiles with the variable ones. + // If the variable is 00 set it to 0xFF which is the new "don't load + // anything" value. + uint8_t temp = rom_[overworldgfxGroups + (area_graphics_ * 4)]; + if (temp != 0x00) { + custom_gfx_ids_[3] = temp; + } else { + custom_gfx_ids_[3] = 0xFF; + } + + temp = rom_[overworldgfxGroups + (area_graphics_ * 4) + 1]; + if (temp != 0x00) { + custom_gfx_ids_[4] = temp; + } else { + custom_gfx_ids_[4] = 0xFF; + } + + temp = rom_[overworldgfxGroups + (area_graphics_ * 4) + 2]; + if (temp != 0x00) { + custom_gfx_ids_[5] = temp; + } else { + custom_gfx_ids_[5] = 0xFF; + } + + temp = rom_[overworldgfxGroups + (area_graphics_ * 4) + 3]; + if (temp != 0x00) { + custom_gfx_ids_[6] = temp; + } else { + custom_gfx_ids_[6] = 0xFF; + } + + // Set the animated GFX values. + if (index_ == 0x03 || index_ == 0x05 || index_ == 0x07 || index_ == 0x43 || + index_ == 0x45 || index_ == 0x47) { + animated_gfx_ = 0x59; + } else { + animated_gfx_ = 0x5B; + } + } + + subscreen_overlay_ = + rom_[OverworldCustomSubscreenOverlayArray + (index_ * 2)]; +} + // ============================================================================ void OverworldMap::LoadMainBlocksetId() { @@ -211,6 +405,11 @@ void OverworldMap::LoadAreaGraphicsBlocksets() { } } +// TODO: Change the conditions for death mountain gfx +// JaredBrian: This is how ZS did it, but in 3.0.4 I changed it to just check +// for 03, 05, 07, and the DW ones as that's how it would appear in-game if +// you were to make area 03 not a large area anymore for example, so you might +// want to do the same. void OverworldMap::LoadDeathMountainGFX() { static_graphics_[7] = (((parent_ >= 0x03 && parent_ <= 0x07) || (parent_ >= 0x0B && parent_ <= 0x0E)) || @@ -368,9 +567,10 @@ absl::StatusOr OverworldMap::GetPalette( } absl::Status OverworldMap::LoadPalette() { - int previousPalId = index_ > 0 ? rom_[overworldMapPalette + parent_ - 1] : 0; + int previousPalId = + index_ > 0 ? rom_[kOverworldMapPaletteIds + parent_ - 1] : 0; int previousSprPalId = - index_ > 0 ? rom_[overworldSpritePalette + parent_ - 1] : 0; + index_ > 0 ? rom_[kOverworldSpritePaletteIds + parent_ - 1] : 0; area_palette_ = std::min((int)area_palette_, 0xA3); @@ -474,7 +674,8 @@ absl::Status OverworldMap::BuildTileset() { return absl::OkStatus(); } -absl::Status OverworldMap::BuildTiles16Gfx(int count) { +absl::Status OverworldMap::BuildTiles16Gfx(std::vector& tiles16, + int count) { if (current_blockset_.size() == 0) current_blockset_.resize(0x100000, 0x00); const int offsets[] = {0x00, 0x08, 0x400, 0x408}; @@ -483,7 +684,7 @@ absl::Status OverworldMap::BuildTiles16Gfx(int count) { for (auto i = 0; i < count; i++) { for (auto tile = 0; tile < 0x04; tile++) { - gfx::TileInfo info = tiles16_[i].tiles_info[tile]; + gfx::TileInfo info = tiles16[i].tiles_info[tile]; int offset = offsets[tile]; for (auto y = 0; y < 0x08; ++y) { for (auto x = 0; x < 0x08; ++x) { @@ -519,22 +720,6 @@ absl::Status OverworldMap::BuildTiles16Gfx(int count) { return absl::OkStatus(); } -namespace { - -void CopyTile8bpp16(int x, int y, int tile, Bytes& bitmap, Bytes& blockset) { - int src_pos = - ((tile - ((tile / 0x08) * 0x08)) * 0x10) + ((tile / 0x08) * 2048); - int dest_pos = (x + (y * 0x200)); - for (int yy = 0; yy < 0x10; yy++) { - for (int xx = 0; xx < 0x10; xx++) { - bitmap[dest_pos + xx + (yy * 0x200)] = - blockset[src_pos + xx + (yy * 0x80)]; - } - } -} - -} // namespace - absl::Status OverworldMap::BuildBitmap(OWBlockset& world_blockset) { if (bitmap_data_.size() != 0) { bitmap_data_.clear(); @@ -551,8 +736,8 @@ absl::Status OverworldMap::BuildBitmap(OWBlockset& world_blockset) { for (int x = 0; x < 0x20; x++) { auto xt = x + (superX * 0x20); auto yt = y + (superY * 0x20); - CopyTile8bpp16((x * 0x10), (y * 0x10), world_blockset[xt][yt], - bitmap_data_, current_blockset_); + gfx::CopyTile8bpp16((x * 0x10), (y * 0x10), world_blockset[xt][yt], + bitmap_data_, current_blockset_); } } return absl::OkStatus(); diff --git a/src/app/zelda3/overworld/overworld_map.h b/src/app/zelda3/overworld/overworld_map.h index 881292c5..f4158a04 100644 --- a/src/app/zelda3/overworld/overworld_map.h +++ b/src/app/zelda3/overworld/overworld_map.h @@ -1,21 +1,15 @@ #ifndef YAZE_APP_ZELDA3_OVERWORLD_MAP_H #define YAZE_APP_ZELDA3_OVERWORLD_MAP_H -#include "imgui/imgui.h" - #include #include -#include -#include #include #include "absl/status/status.h" -#include "app/core/common.h" -#include "app/editor/utils/gfx_context.h" -#include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" +#include "app/zelda3/common.h" namespace yaze { namespace app { @@ -24,21 +18,60 @@ namespace overworld { static constexpr int kTileOffsets[] = {0, 8, 4096, 4104}; +// 1 byte, not 0 if enabled +constexpr int OverworldCustomASMHasBeenApplied = 0x140145; + +// 2 bytes for each overworld area (0x140) +constexpr int OverworldCustomAreaSpecificBGPalette = 0x140000; + +// 1 byte, not 0 if enabled +constexpr int OverworldCustomAreaSpecificBGEnabled = 0x140140; + +// 1 byte for each overworld area (0xA0) +constexpr int OverworldCustomMainPaletteArray = 0x140160; +// 1 byte, not 0 if enabled +constexpr int OverworldCustomMainPaletteEnabled = 0x140141; + +// 1 byte for each overworld area (0xA0) +constexpr int OverworldCustomMosaicArray = 0x140200; + +// 1 byte, not 0 if enabled +constexpr int OverworldCustomMosaicEnabled = 0x140142; + +// 1 byte for each overworld area (0xA0) +constexpr int OverworldCustomAnimatedGFXArray = 0x1402A0; + +// 1 byte, not 0 if enabled +constexpr int OverworldCustomAnimatedGFXEnabled = 0x140143; + +// 2 bytes for each overworld area (0x140) +constexpr int OverworldCustomSubscreenOverlayArray = 0x140340; + +// 1 byte, not 0 if enabled +constexpr int OverworldCustomSubscreenOverlayEnabled = 0x140144; + +// 8 bytes for each overworld area (0x500) +constexpr int OverworldCustomTileGFXGroupArray = 0x140480; + +// 1 byte, not 0 if enabled +constexpr int OverworldCustomTileGFXGroupEnabled = 0x140148; + /** * @brief Represents a single Overworld map screen. */ -class OverworldMap : public editor::context::GfxContext { +class OverworldMap : public GfxContext { public: OverworldMap() = default; - OverworldMap(int index, Rom& rom, std::vector& tiles16); + OverworldMap(int index, Rom& rom, bool load_custom_data = false); absl::Status BuildMap(int count, int game_state, int world, + std::vector& tiles16, OWBlockset& world_blockset); void LoadAreaGraphics(); absl::Status LoadPalette(); absl::Status BuildTileset(); - absl::Status BuildTiles16Gfx(int count); + absl::Status BuildTiles16Gfx(std::vector& tiles16, int count); absl::Status BuildBitmap(OWBlockset& world_blockset); void DrawAnimatedTiles(); @@ -50,9 +83,7 @@ class OverworldMap : public editor::context::GfxContext { auto is_large_map() const { return large_map_; } auto is_initialized() const { return initialized_; } auto parent() const { return parent_; } - auto mutable_mosaic() { return &mosaic_; } - auto mutable_current_palette() { return ¤t_palette_; } auto area_graphics() const { return area_graphics_; } @@ -80,6 +111,8 @@ class OverworldMap : public editor::context::GfxContext { auto set_sprite_palette(int i, uint8_t value) { sprite_palette_[i] = value; } auto set_message_id(uint16_t value) { message_id_ = value; } + uint8_t* mutable_custom_tileset(int index) { return &custom_gfx_ids_[index]; } + void SetAsLargeMap(int parent_index, int quadrant) { parent_ = parent_index; large_index_ = quadrant; @@ -99,11 +132,12 @@ class OverworldMap : public editor::context::GfxContext { current_blockset_.clear(); current_gfx_.clear(); bitmap_data_.clear(); - tiles16_.clear(); } private: void LoadAreaInfo(); + void LoadCustomOverworldData(); + void SetupCustomTileset(uint8_t asm_version); void LoadMainBlocksetId(); void LoadSpritesBlocksets(); @@ -132,21 +166,23 @@ class OverworldMap : public editor::context::GfxContext { uint16_t message_id_ = 0; uint8_t area_graphics_ = 0; uint8_t area_palette_ = 0; + uint8_t animated_gfx_ = 0; // Custom Overworld Animated ID + uint16_t subscreen_overlay_ = 0; // Custom Overworld Subscreen Overlay ID + uint8_t custom_gfx_ids_[8]; uchar sprite_graphics_[3]; uchar sprite_palette_[3]; uchar area_music_[4]; uchar static_graphics_[16]; Rom rom_; - Bytes all_gfx_; - Bytes current_blockset_; - Bytes current_gfx_; - Bytes bitmap_data_; + std::vector all_gfx_; + std::vector current_blockset_; + std::vector current_gfx_; + std::vector bitmap_data_; OWMapTiles map_tiles_; gfx::SnesPalette current_palette_; - std::vector tiles16_; }; } // namespace overworld @@ -154,4 +190,4 @@ class OverworldMap : public editor::context::GfxContext { } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/zelda3/screen/dungeon_map.h b/src/app/zelda3/screen/dungeon_map.h index 326c4dbb..eb4f19f8 100644 --- a/src/app/zelda3/screen/dungeon_map.h +++ b/src/app/zelda3/screen/dungeon_map.h @@ -18,19 +18,18 @@ constexpr int kDungeonMapGfxPtr = 0x57BE4; // 14 pointers of gfx data constexpr int kDungeonMapDataStart = 0x57039; // IF Byte = 0xB9 dungeon maps are not expanded -constexpr int kDungeonMapExpCheck = 0x56652; // $0A:E652 -constexpr int kDungeonMapTile16 = 0x57009; // $0A:F009 -constexpr int kDungeonMapTile16Expanded = 0x109010; // $21:9010 +constexpr int kDungeonMapExpCheck = 0x56652; // $0A:E652 +constexpr int kDungeonMapTile16 = 0x57009; // $0A:F009 +constexpr int kDungeonMapTile16Expanded = 0x109010; // $21:9010 // 14 words values 0x000F = no boss constexpr int kDungeonMapBossRooms = 0x56807; constexpr int kTriforceVertices = 0x04FFD2; // group of 3, X, Y ,Z -constexpr int TriforceFaces = 0x04FFE4; // group of 5 +constexpr int kTriforceFaces = 0x04FFE4; // group of 5 -constexpr int crystalVertices = 0x04FF98; +constexpr int kCrystalVertices = 0x04FF98; -class DungeonMap { - public: +struct DungeonMap { unsigned short boss_room = 0xFFFF; unsigned char nbr_of_floor = 0; unsigned char nbr_of_basement = 0; diff --git a/src/app/zelda3/screen/inventory.cc b/src/app/zelda3/screen/inventory.cc index b33d4c77..d494daaa 100644 --- a/src/app/zelda3/screen/inventory.cc +++ b/src/app/zelda3/screen/inventory.cc @@ -1,5 +1,6 @@ #include "inventory.h" +#include "app/core/platform/renderer.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/gui/canvas.h" @@ -10,6 +11,8 @@ namespace app { namespace zelda3 { namespace screen { +using core::Renderer; + absl::Status Inventory::Create() { data_.reserve(256 * 256); for (int i = 0; i < 256 * 256; i++) { @@ -65,7 +68,7 @@ absl::Status Inventory::Create() { bitmap_.Create(256, 256, 8, data_); RETURN_IF_ERROR(bitmap_.ApplyPalette(palette_)); - rom()->RenderBitmap(&bitmap_); + Renderer::GetInstance().RenderBitmap(&bitmap_); return absl::OkStatus(); } @@ -73,7 +76,7 @@ absl::Status Inventory::BuildTileset() { tilesheets_.reserve(6 * 0x2000); for (int i = 0; i < 6 * 0x2000; i++) tilesheets_.push_back(0xFF); ASSIGN_OR_RETURN(tilesheets_, rom()->Load2BppGraphics()) - Bytes test; + std::vector test; for (int i = 0; i < 0x4000; i++) { test_.push_back(tilesheets_[i]); } @@ -84,7 +87,7 @@ absl::Status Inventory::BuildTileset() { auto hud_pal_group = rom()->palette_group().hud; palette_ = hud_pal_group[0]; RETURN_IF_ERROR(tilesheets_bmp_.ApplyPalette(palette_)) - rom()->RenderBitmap(&tilesheets_bmp_); + Renderer::GetInstance().RenderBitmap(&tilesheets_bmp_); return absl::OkStatus(); } diff --git a/src/app/zelda3/screen/inventory.h b/src/app/zelda3/screen/inventory.h index 9f251aac..4cae3a47 100644 --- a/src/app/zelda3/screen/inventory.h +++ b/src/app/zelda3/screen/inventory.h @@ -26,11 +26,11 @@ class Inventory : public SharedRom { private: absl::Status BuildTileset(); - Bytes data_; + std::vector data_; gfx::Bitmap bitmap_; - Bytes tilesheets_; - Bytes test_; + std::vector tilesheets_; + std::vector test_; gfx::Bitmap tilesheets_bmp_; gfx::SnesPalette palette_; diff --git a/src/app/zelda3/screen/title_screen.cc b/src/app/zelda3/screen/title_screen.cc index 075e72f6..db2f4b3c 100644 --- a/src/app/zelda3/screen/title_screen.cc +++ b/src/app/zelda3/screen/title_screen.cc @@ -2,7 +2,6 @@ #include -#include "app/core/common.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" @@ -13,16 +12,16 @@ namespace zelda3 { namespace screen { void TitleScreen::Create() { - tiles8Bitmap.Create(128, 512, 8, Bytes(0, 0x20000)); - tilesBG1Bitmap.Create(256, 256, 8, Bytes(0, 0x80000)); - tilesBG2Bitmap.Create(256, 256, 8, Bytes(0, 0x80000)); - oamBGBitmap.Create(256, 256, 8, Bytes(0, 0x80000)); + tiles8Bitmap.Create(128, 512, 8, std::vector(0x20000)); + tilesBG1Bitmap.Create(256, 256, 8, std::vector(0x80000)); + tilesBG2Bitmap.Create(256, 256, 8, std::vector(0x80000)); + oamBGBitmap.Create(256, 256, 8, std::vector(0x80000)); BuildTileset(); LoadTitleScreen(); } void TitleScreen::BuildTileset() { - uchar staticgfx[16]; + uchar staticgfx[16] = {0}; // Main Blocksets @@ -44,7 +43,7 @@ void TitleScreen::BuildTileset() { uchar* currentmapgfx8Data = tiles8Bitmap.mutable_data().data(); // All gfx of the game pack of 2048 bytes (4bpp) - uchar* allgfxData = nullptr; // rom_.GetMasterGraphicsBin(); + uchar* allgfxData = nullptr; for (int i = 0; i < 16; i++) { for (int j = 0; j < 2048; j++) { uchar mapByte = allgfxData[j + (staticgfx[i] * 2048)]; diff --git a/src/app/zelda3/screen/title_screen.h b/src/app/zelda3/screen/title_screen.h index 17c4f1ae..49befd5f 100644 --- a/src/app/zelda3/screen/title_screen.h +++ b/src/app/zelda3/screen/title_screen.h @@ -3,7 +3,7 @@ #include -#include "app/core/common.h" + #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" diff --git a/src/app/zelda3/sprite/overlord.h b/src/app/zelda3/sprite/overlord.h new file mode 100644 index 00000000..44314104 --- /dev/null +++ b/src/app/zelda3/sprite/overlord.h @@ -0,0 +1,43 @@ +#ifndef YAZE_APP_ZELDA3_SPRITE_OVERLORD_H +#define YAZE_APP_ZELDA3_SPRITE_OVERLORD_H + +#include + +namespace yaze { +namespace app { +namespace zelda3 { + +static const std::string kOverlordNames[] = { + "Overlord_SpritePositionTarget", + "Overlord_AllDirectionMetalBallFactory", + "Overlord_CascadeMetalBallFactory", + "Overlord_StalfosFactory", + "Overlord_StalfosTrap", + "Overlord_SnakeTrap", + "Overlord_MovingFloor", + "Overlord_ZolFactory", + "Overlord_WallMasterFactory", + "Overlord_CrumbleTilePath 1", + "Overlord_CrumbleTilePath 2", + "Overlord_CrumbleTilePath 3", + "Overlord_CrumbleTilePath 4", + "Overlord_CrumbleTilePath 5", + "Overlord_CrumbleTilePath 6", + "Overlord_PirogusuFactory 1", + "Overlord_PirogusuFactory 2", + "Overlord_PirogusuFactory 3", + "Overlord_PirogusuFactory 4", + "Overlord_FlyingTileFactory", + "Overlord_WizzrobeFactory", + "Overlord_ZoroFactory", + "Overlord_StalfosTrapTriggerWindow", + "Overlord_RedStalfosTrap", + "Overlord_ArmosCoordinator", + "Overlord_BombTrap", +}; + +} +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_ZELDA3_SPRITE_OVERLORD_H diff --git a/src/app/zelda3/sprite/sprite.cc b/src/app/zelda3/sprite/sprite.cc index 56263256..a9f1d940 100644 --- a/src/app/zelda3/sprite/sprite.cc +++ b/src/app/zelda3/sprite/sprite.cc @@ -6,71 +6,27 @@ namespace yaze { namespace app { namespace zelda3 { -void Sprite::InitSprite(const Bytes& src, uchar mapid, uchar id, uchar x, - uchar y, int map_x, int map_y) { - current_gfx_ = src; - overworld_ = true; - map_id_ = static_cast(mapid); - id_ = id; - this->type_ = zelda3::OverworldEntity::EntityType::kSprite; - this->entity_id_ = id; - this->x_ = map_x_; - this->y_ = map_y_; - nx_ = x; - ny_ = y; - name_ = core::kSpriteDefaultNames[id]; - map_x_ = map_x; - map_y_ = map_y; - preview_gfx_.reserve(64 * 64); - for (int i = 0; i < 64 * 64; i++) { - preview_gfx_.push_back(0xFF); - } -} - -Sprite::Sprite(Bytes src, uchar mapid, uchar id, uchar x, uchar y, int map_x, - int map_y) - : current_gfx_(src), - map_id_(static_cast(mapid)), - id_(id), - nx_(x), - ny_(y), - map_x_(map_x), - map_y_(map_y) { - this->type_ = zelda3::OverworldEntity::EntityType::kSprite; - this->entity_id_ = id; - this->x_ = map_x_; - this->y_ = map_y_; - current_gfx_ = src; - overworld_ = true; - - name_ = core::kSpriteDefaultNames[id]; - preview_gfx_.reserve(64 * 64); - for (int i = 0; i < 64 * 64; i++) { - preview_gfx_.push_back(0xFF); - } -} - -void Sprite::UpdateMapProperties(short map_id) { +void Sprite::UpdateMapProperties(uint16_t map_id) { map_x_ = x_; map_y_ = y_; - name_ = core::kSpriteDefaultNames[id_]; + name_ = kSpriteDefaultNames[id_]; } -void Sprite::updateCoordinates(int map_x, int map_y) { +void Sprite::UpdateCoordinates(int map_x, int map_y) { map_x_ = map_x; map_y_ = map_y; } -void Sprite::updateBBox() { - lowerX_ = 1; - lowerY_ = 1; - higherX_ = 15; - higherY_ = 15; +void Sprite::UpdateBoundaryBox() { + lower_x_ = 1; + lower_y_ = 1; + higher_x_ = 15; + higher_x_ = 15; } void Sprite::Draw() { - uchar x = nx_; - uchar y = ny_; + uint8_t x = nx_; + uint8_t y = ny_; if (overlord_ == 0x07) { if (id_ == 0x1A) { @@ -101,13 +57,13 @@ void Sprite::Draw() { } if (nx_ != x || ny_ != y) { - bounding_box_.x = (lowerX_ + (nx_ * 16)); - bounding_box_.y = (lowerY_ + (ny_ * 16)); + bounding_box_.x = (lower_x_ + (nx_ * 16)); + bounding_box_.y = (lower_y_ + (ny_ * 16)); bounding_box_.w = width_; bounding_box_.h = height_; } else { - bounding_box_.x = (lowerX_ + (x * 16)); - bounding_box_.y = (lowerY_ + (y * 16)); + bounding_box_.x = (lower_x_ + (x * 16)); + bounding_box_.y = (lower_y_ + (y * 16)); bounding_box_.w = width_; bounding_box_.h = height_; } @@ -123,22 +79,22 @@ void Sprite::Draw() { } else if (id_ == 0x02) { DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); } else if (id_ == 0x04) { - uchar p = 3; + uint8_t p = 3; DrawSpriteTile((x * 16), (y * 16), 14, 28, p); DrawSpriteTile((x * 16), (y * 16), 14, 30, p); } else if (id_ == 0x05) { - uchar p = 3; + uint8_t p = 3; DrawSpriteTile((x * 16), (y * 16), 14, 28, p); DrawSpriteTile((x * 16), (y * 16), 14, 30, p); } else if (id_ == 0x06) { - uchar p = 3; + uint8_t p = 3; DrawSpriteTile((x * 16), (y * 16), 14, 28, p); DrawSpriteTile((x * 16), (y * 16), 14, 30, p); } else if (id_ == 0x07) { - uchar p = 3; + uint8_t p = 3; DrawSpriteTile((x * 16), (y * 16), 14, 28, p); DrawSpriteTile((x * 16), (y * 16), 14, 30, p); @@ -908,8 +864,8 @@ void Sprite::Draw() { DrawSpriteTile((x * 16), (y * 16), 4, 4, 5); } - bounding_box_.x = (lowerX_ + (x * 16)); - bounding_box_.y = (lowerY_ + (y * 16)); + bounding_box_.x = (lower_x_ + (x * 16)); + bounding_box_.y = (lower_y_ + (y * 16)); bounding_box_.w = width_; bounding_box_.h = height_; } @@ -948,7 +904,7 @@ void Sprite::DrawSpriteTile(int x, int y, int srcx, int srcy, int pal, int index = (x) + (y * 64) + (mx + (my * 0x80)); if (index >= 0 && index <= 4096) { - preview_gfx_[index] = (uchar)((pixel & 0x0F) + 112 + (pal * 8)); + preview_gfx_[index] = (uint8_t)((pixel & 0x0F) + 112 + (pal * 8)); } } } diff --git a/src/app/zelda3/sprite/sprite.h b/src/app/zelda3/sprite/sprite.h index f3f824a1..02fcc39b 100644 --- a/src/app/zelda3/sprite/sprite.h +++ b/src/app/zelda3/sprite/sprite.h @@ -4,47 +4,343 @@ #include #include -#include #include #include -#include "absl/status/status.h" -#include "app/core/constants.h" -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_tile.h" -#include "app/rom.h" #include "app/zelda3/common.h" +#include "app/zelda3/sprite/overlord.h" namespace yaze { namespace app { namespace zelda3 { +static const std::string kSpriteDefaultNames[]{ + "00 Raven", + "01 Vulture", + "02 Flying Stalfos Head", + "03 No Pointer (Empty", + "04 Pull Switch (good", + "05 Pull Switch (unused", + "06 Pull Switch (bad", + "07 Pull Switch (unused", + "08 Octorock (one way", + "09 Moldorm (Boss", + "0A Octorock (four way", + "0B Chicken", + "0C Octorock (?", + "0D Buzzblock", + "0E Snapdragon", + "0F Octoballoon", + "10 Octoballon Hatchlings", + "11 Hinox", + "12 Moblin", + "13 Mini Helmasaure", + "14 Gargoyle's Domain Gate", + "15 Antifairy", + "16 Sahasrahla / Aginah", + "17 Bush Hoarder", + "18 Mini Moldorm", + "19 Poe", + "1A Dwarves", + "1B Arrow in wall", + "1C Statue", + "1D Weathervane", + "1E Crystal Switch", + "1F Bug-Catching Kid", + "20 Sluggula", + "21 Push Switch", + "22 Ropa", + "23 Red Bari", + "24 Blue Bari", + "25 Talking Tree", + "26 Hardhat Beetle", + "27 Deadrock", + "28 Storytellers", + "29 Blind Hideout attendant", + "2A Sweeping Lady", + "2B Storytellers", + "2C Lumberjacks", + "2D Telepathic Stones", + "2E Multipurpose Sprite", + "2F Race Npc", + "30 Person?", + "31 Fortune Teller", + "32 Angry Brothers", + "33 Pull for items", + "34 Scared Girl", + "35 Innkeeper", + "36 Witch", + "37 Waterfall", + "38 Arrow Target", + "39 Average Middle", + "3A Half Magic Bat", + "3B Dash Item", + "3C Village Kid", + "3D Signs? Chicken lady also showed up / Scared ladies outside houses.", + "3E Rock Hoarder", + "3F Tutorial Soldier", + "40 Lightning Lock", + "41 Blue Sword Soldier / Used by guards to detect player", + "42 Green Sword Soldier", + "43 Red Spear Soldier", + "44 Assault Sword Soldier", + "45 Green Spear Soldier", + "46 Blue Archer", + "47 Green Archer", + "48 Red Javelin Soldier", + "49 Red Javelin Soldier 2", + "4A Red Bomb Soldiers", + "4B Green Soldier Recruits", + "4C Geldman", + "4D Rabbit", + "4E Popo", + "4F Popo 2", + "50 Cannon Balls", + "51 Armos", + "52 Giant Zora", + "53 Armos Knights (Boss", + "54 Lanmolas (Boss", + "55 Fireball Zora", + "56 Walking Zora", + "57 Desert Palace Barriers", + "58 Crab", + "59 Bird", + "5A Squirrel", + "5B Spark (Left to Right", + "5C Spark (Right to Left", + "5D Roller (vertical moving", + "5E Roller (vertical moving", + "5F Roller", + "60 Roller (horizontal moving", + "61 Beamos", + "62 Master Sword", + "63 Devalant (Non", + "64 Devalant (Shooter", + "65 Shooting Gallery Proprietor", + "66 Moving Cannon Ball Shooters (Right", + "67 Moving Cannon Ball Shooters (Left", + "68 Moving Cannon Ball Shooters (Down", + "69 Moving Cannon Ball Shooters (Up", + "6A Ball N' Chain Trooper", + "6B Cannon Soldier", + "6C Mirror Portal", + "6D Rat", + "6E Rope", + "6F Keese", + "70 Helmasaur King Fireball", + "71 Leever", + "72 Activator for the ponds (where you throw in items", + "73 Uncle / Priest", + "74 Running Man", + "75 Bottle Salesman", + "76 Princess Zelda", + "77 Antifairy (Alternate", + "78 Village Elder", + "79 Bee", + "7A Agahnim", + "7B Agahnim Energy Ball", + "7C Hyu", + "7D Big Spike Trap", + "7E Guruguru Bar (Clockwise", + "7F Guruguru Bar (Counter Clockwise", + "80 Winder", + "81 Water Tektite", + "82 Antifairy Circle", + "83 Green Eyegore", + "84 Red Eyegore", + "85 Yellow Stalfos", + "86 Kodongos", + "87 Flames", + "88 Mothula (Boss", + "89 Mothula's Beam", + "8A Spike Trap", + "8B Gibdo", + "8C Arrghus (Boss", + "8D Arrghus spawn", + "8E Terrorpin", + "8F Slime", + "90 Wallmaster", + "91 Stalfos Knight", + "92 Helmasaur King", + "93 Bumper", + "94 Swimmers", + "95 Eye Laser (Right", + "96 Eye Laser (Left", + "97 Eye Laser (Down", + "98 Eye Laser (Up", + "99 Pengator", + "9A Kyameron", + "9B Wizzrobe", + "9C Tadpoles", + "9D Tadpoles", + "9E Ostrich (Haunted Grove", + "9F Flute", + "A0 Birds (Haunted Grove", + "A1 Freezor", + "A2 Kholdstare (Boss", + "A3 Kholdstare's Shell", + "A4 Falling Ice", + "A5 Zazak Fireball", + "A6 Red Zazak", + "A7 Stalfos", + "A8 Bomber Flying Creatures from Darkworld", + "A9 Bomber Flying Creatures from Darkworld", + "AA Pikit", + "AB Maiden", + "AC Apple", + "AD Lost Old Man", + "AE Down Pipe", + "AF Up Pipe", + "B0 Right Pip", + "B1 Left Pipe", + "B2 Good bee again?", + "B3 Hylian Inscription", + "B4 Thief?s chest (not the one that follows you", + "B5 Bomb Salesman", + "B6 Kiki", + "B7 Maiden following you in Blind Dungeon", + "B8 Monologue Testing Sprite", + "B9 Feuding Friends on Death Mountain", + "BA Whirlpool", + "BB Salesman / chestgame guy / 300 rupee giver guy / Chest game thief", + "BC Drunk in the inn", + "BD Vitreous (Large Eyeball", + "BE Vitreous (Small Eyeball", + "BF Vitreous' Lightning", + "C0 Monster in Lake of Ill Omen / Quake Medallion", + "C1 Agahnim teleporting Zelda to dark world", + "C2 Boulders", + "C3 Gibo", + "C4 Thief", + "C5 Medusa", + "C6 Four Way Fireball Spitters (spit when you use your sword", + "C7 Hokku", + "C8 Big Fairy who heals you", + "C9 Tektite", + "CA Chain Chomp", + "CB Trinexx", + "CC Another part of trinexx", + "CD Yet another part of trinexx", + "CE Blind The Thief (Boss)", + "CF Swamola", + "D0 Lynel", + "D1 Bunny Beam", + "D2 Flopping fish", + "D3 Stal", + "D4 Landmine", + "D5 Digging Game Proprietor", + "D6 Ganon", + "D7 Copy of Ganon", + "D8 Heart", + "D9 Green Rupee", + "DA Blue Rupee", + "DB Red Rupee", + "DC Bomb Refill (1)", + "DD Bomb Refill (4)", + "DE Bomb Refill (8)", + "DF Small Magic Refill", + "E0 Full Magic Refill", + "E1 Arrow Refill (5)", + "E2 Arrow Refill (10)", + "E3 Fairy", + "E4 Key", + "E5 Big Key", + "E6 Shield", + "E7 Mushroom", + "E8 Fake Master Sword", + "E9 Magic Shop dude / His items", + "EA Heart Container", + "EB Heart Piece", + "EC Bushes", + "ED Cane Of Somaria Platform", + "EE Mantle", + "EF Cane of Somaria Platform (Unused)", + "F0 Cane of Somaria Platform (Unused)", + "F1 Cane of Somaria Platform (Unused)", + "F2 Medallion Tablet", + "F3", + "F4 Falling Rocks", + "F5", + "F6", + "F7", + "F8", + "F9", + "FA", + "FB", + "FC", + "FD", + "FE", + "FF", +}; + /** * @class Sprite * @brief A class for managing sprites in the overworld and underworld. */ -class Sprite : public OverworldEntity { +class Sprite : public GameEntity { public: Sprite() = default; - Sprite(Bytes src, uchar mapid, uchar id, uchar x, uchar y, int map_x, - int map_y); - void InitSprite(const Bytes& src, uchar mapid, uchar id, uchar x, uchar y, - int map_x, int map_y); - void updateBBox(); + Sprite(std::vector src, uint8_t overworld_map_id, uint8_t id, + uint8_t x, uint8_t y, int map_x, int map_y) + : map_id_(static_cast(overworld_map_id)), + id_(id), + nx_(x), + ny_(y), + map_x_(map_x), + map_y_(map_y), + current_gfx_(src) { + entity_type_ = zelda3::GameEntity::EntityType::kSprite; + entity_id_ = id; + x_ = map_x_; + y_ = map_y_; + overworld_ = true; + name_ = kSpriteDefaultNames[id]; + preview_gfx_.resize(64 * 64, 0xFF); + } + + Sprite(uint8_t id, uint8_t x, uint8_t y, uint8_t subtype, uint8_t layer) + : id_(id), nx_(x), ny_(y), subtype_(subtype), layer_(layer) { + x_ = x; + y_ = y; + name_ = kSpriteDefaultNames[id]; + if (((subtype & 0x07) == 0x07) && id > 0 && id <= 0x1A) { + name_ = kOverlordNames[id - 1]; + overlord_ = 1; + } + } + + void InitSprite(const std::vector &src, uint8_t overworld_map_id, + uint8_t id, uint8_t x, uint8_t y, int map_x, int map_y) { + current_gfx_ = src; + overworld_ = true; + map_id_ = static_cast(overworld_map_id); + id_ = id; + entity_type_ = zelda3::GameEntity::EntityType::kSprite; + entity_id_ = id; + x_ = map_x_; + y_ = map_y_; + nx_ = x; + ny_ = y; + name_ = kSpriteDefaultNames[id]; + map_x_ = map_x; + map_y_ = map_y; + preview_gfx_.resize(64 * 64, 0xFF); + } + void UpdateBoundaryBox(); void Draw(); void DrawSpriteTile(int x, int y, int srcx, int srcy, int pal, bool mirror_x = false, bool mirror_y = false, int sizex = 2, int sizey = 2); - void UpdateMapProperties(short map_id) override; + void UpdateMapProperties(uint16_t map_id) override; // New methods - void updateCoordinates(int map_x, int map_y); + void UpdateCoordinates(int map_x, int map_y); auto PreviewGraphics() const { return preview_gfx_; } auto id() const { return id_; } - auto set_id(uchar id) { id_ = id; } + auto set_id(uint8_t id) { id_ = id; } auto x() const { return x_; } auto y() const { return y_; } auto nx() const { return nx_; } @@ -52,52 +348,50 @@ class Sprite : public OverworldEntity { auto map_id() const { return map_id_; } auto map_x() const { return map_x_; } auto map_y() const { return map_y_; } + auto game_state() const { return game_state_; } auto layer() const { return layer_; } auto subtype() const { return subtype_; } - auto& keyDrop() const { return key_drop_; } - auto Width() const { return bounding_box_.w; } - auto Height() const { return bounding_box_.h; } + auto width() const { return bounding_box_.w; } + auto height() const { return bounding_box_.h; } auto name() { return name_; } auto deleted() const { return deleted_; } auto set_deleted(bool deleted) { deleted_ = deleted; } + auto set_key_drop(int key) { key_drop_ = key; } private: - Bytes current_gfx_; - bool overworld_; - - uchar map_id_; - uchar id_; - // uchar x_; - // uchar y_; - uchar nx_; - uchar ny_; - uchar overlord_ = 0; - std::string name_; - - int subtype_; - int layer_; - - int map_x_; - int map_y_; - Bytes preview_gfx_; - uchar lowerX_; - uchar lowerY_; - uchar higherX_; - uchar higherY_; - SDL_Rect bounding_box_; + uint8_t map_id_; + uint8_t game_state_; + uint8_t id_; + uint8_t nx_; + uint8_t ny_; + uint8_t overlord_ = 0; + uint8_t lower_x_ = 32; + uint8_t lower_y_ = 32; + uint8_t higher_x_ = 0; + uint8_t higher_y_ = 0; int width_ = 16; int height_ = 16; - - int key_drop_; + int map_x_ = 0; + int map_y_ = 0; + int layer_ = 0; + int subtype_ = 0; + int key_drop_ = 0; bool deleted_ = false; + bool overworld_; + + std::string name_; + std::vector preview_gfx_; + std::vector current_gfx_; + + SDL_Rect bounding_box_; }; } // namespace zelda3 } // namespace app } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/app/zelda3/sprite/sprite_builder.cc b/src/app/zelda3/sprite/sprite_builder.cc new file mode 100644 index 00000000..8b069411 --- /dev/null +++ b/src/app/zelda3/sprite/sprite_builder.cc @@ -0,0 +1,153 @@ +#include "sprite_builder.h" + +#include +#include + +namespace yaze { +namespace app { +namespace zelda3 { + +SpriteBuilder SpriteBuilder::Create(const std::string& spriteName) { + SpriteBuilder builder; + + return builder; +} + +SpriteBuilder& SpriteBuilder::SetProperty(const std::string& propertyName, + const std::string& value) { + return *this; +} + +SpriteBuilder& SpriteBuilder::SetProperty(const std::string& propertyName, + int value) { + return *this; +} + +SpriteBuilder& SpriteBuilder::SetProperty(const std::string& propertyName, + bool value) { + return *this; +} + +SpriteBuilder& SpriteBuilder::AddAction(const SpriteAction& action) { + return *this; +} + +SpriteBuilder& SpriteBuilder::SetGlobalAction(const SpriteAction& action) { + return *this; +} + +SpriteBuilder& SpriteBuilder::AddFunction(const SpriteAction& function) { + return *this; +} + +SpriteBuilder& SpriteBuilder::AddFunction(const std::string& asmCode) { + return *this; +} + +std::string SpriteBuilder::BuildProperties() const { + std::stringstream ss; + // Build the properties + for (int i = 0; i < 27; ++i) { + std::string property = "00"; + if (!properties[i].empty()) property = properties[i]; + ss << kSpriteProperties[i] << " = $" << property << std::endl; + } + return ss.str(); +} + +std::string SpriteBuilder::Build() const { + std::stringstream ss; + ss << BuildProperties(); + return ss.str(); +} + +// ============================================================================ + +SpriteAction SpriteAction::Create(const std::string& actionName) { + SpriteAction action; + + return action; +} + +SpriteAction SpriteAction::Create() { + SpriteAction action; + + return action; +} + +SpriteAction& SpriteAction::AddInstruction( + const SpriteInstruction& instruction) { + return *this; +} + +SpriteAction& SpriteAction::AddCustomInstruction(const std::string& asmCode) { + return *this; +} + +SpriteAction& SpriteAction::SetNextAction(const std::string& nextActionName) { + return *this; +} + +std::string SpriteAction::GetConfiguration() const { return ""; } + +// ============================================================================ + +SpriteInstruction SpriteInstruction::PlayAnimation(int startFrame, int endFrame, + int speed) { + SpriteInstruction instruction; + + return instruction; +} + +SpriteInstruction SpriteInstruction::ApplySpeedTowardsPlayer(int speed) { + SpriteInstruction instruction; + instruction.SetConfiguration("JSL Sprite_ApplySpeedTowardsPlayer"); + return instruction; +} + +SpriteInstruction SpriteInstruction::CheckDamageFromPlayer() { + SpriteInstruction instruction; + + return instruction; +} + +SpriteInstruction SpriteInstruction::MoveXyz() { + SpriteInstruction instruction; + + return instruction; +} + +SpriteInstruction SpriteInstruction::BounceFromTileCollision() { + SpriteInstruction instruction; + + return instruction; +} + +SpriteInstruction SpriteInstruction::SetTimer(int timerId, int value) { + SpriteInstruction instruction; + + return instruction; +} + +SpriteInstruction SpriteInstruction::Custom(const std::string& asmCode) { + SpriteInstruction instruction; + + return instruction; +} + +SpriteInstruction SpriteInstruction::BehaveAsBarrier() { + SpriteInstruction instruction; + + return instruction; +} + +SpriteInstruction SpriteInstruction::JumpToFunction( + const std::string& functionName) { + SpriteInstruction instruction; + + return instruction; +} + +} // namespace zelda3 +} // namespace app +} // namespace yaze diff --git a/src/app/zelda3/sprite/sprite_builder.h b/src/app/zelda3/sprite/sprite_builder.h new file mode 100644 index 00000000..313c2eee --- /dev/null +++ b/src/app/zelda3/sprite/sprite_builder.h @@ -0,0 +1,131 @@ +#ifndef YAZE_APP_ZELDA3_SPRITE_SPRITE_BUILDER_H_ +#define YAZE_APP_ZELDA3_SPRITE_SPRITE_BUILDER_H_ + +#include +#include +#include + +namespace yaze { +namespace app { +namespace zelda3 { + +class SpriteInstruction { + public: + // Predefined instructions + static SpriteInstruction PlayAnimation(int startFrame, int endFrame, + int speed); + static SpriteInstruction ApplySpeedTowardsPlayer(int speed); + static SpriteInstruction CheckDamageFromPlayer(); + static SpriteInstruction MoveXyz(); + static SpriteInstruction BounceFromTileCollision(); + static SpriteInstruction SetTimer(int timerId, int value); + static SpriteInstruction BehaveAsBarrier(); + static SpriteInstruction JumpToFunction(const std::string& functionName); + + // Custom instruction + static SpriteInstruction Custom(const std::string& asmCode); + + // Get the instruction configuration + std::string GetConfiguration() const { return instruction_; } + void SetConfiguration(const std::string& instruction) { + instruction_ = instruction; + } + + private: + std::string instruction_; +}; + +class SpriteAction { + public: + // Factory method to create a new action + static SpriteAction Create(const std::string& actionName); + + // Anonymously create an action + static SpriteAction Create(); + + // Add a predefined instruction to the action + SpriteAction& AddInstruction(const SpriteInstruction& instruction); + + // Add custom raw ASM instruction to the action + SpriteAction& AddCustomInstruction(const std::string& asmCode); + + // Set the next action to jump to + SpriteAction& SetNextAction(const std::string& nextActionName); + + // Get the action configuration + std::string GetConfiguration() const; + + private: + std::string name; + std::vector instructions; + std::string nextAction; +}; + +// Array of sprite property names +constexpr const char* kSpriteProperties[] = {"!SPRID", + "!NbrTiles", + "!Harmless", + "!HVelocity", + "!Health", + "!Damage", + "!DeathAnimation", + "!ImperviousAll", + "!SmallShadow", + "!Shadow", + "!Palette", + "!Hitbox", + "!Persist", + "!Statis", + "!CollisionLayer", + "!CanFall", + "!DeflectArrow", + "!WaterSprite", + "!Blockable", + "!Prize", + "!Sound", + "!Interaction", + "!Statue", + "!DeflectProjectiles", + "!ImperviousArrow", + "!ImpervSwordHammer", + "!Boss"}; + +class SpriteBuilder { + public: + // Factory method to create a new sprite + static SpriteBuilder Create(const std::string& spriteName); + + // Set sprite properties + SpriteBuilder& SetProperty(const std::string& propertyName, + const std::string& value); + SpriteBuilder& SetProperty(const std::string& propertyName, int value); + SpriteBuilder& SetProperty(const std::string& propertyName, bool value); + + // Add an action to the sprite + SpriteBuilder& AddAction(const SpriteAction& action); + + // Set global action to the sprite (always runs) + SpriteBuilder& SetGlobalAction(const SpriteAction& action); + + // Add a function to be called from anywhere in the sprite code + SpriteBuilder& AddFunction(const std::string& asmCode); + SpriteBuilder& AddFunction(const SpriteAction& action); + + std::string BuildProperties() const; + + // Build and get the sprite configuration + std::string Build() const; + + private: + std::string name; + std::array properties; + std::vector actions; + SpriteAction globalAction; + std::vector functions; +}; + +} // namespace zelda3 +} // namespace app +} // namespace yaze + +#endif // YAZE_APP_ZELDA3_SPRITE_SPRITE_BUILDER_H_ \ No newline at end of file diff --git a/src/app/zelda3/CMakeLists.txt b/src/app/zelda3/zelda3.cmake similarity index 89% rename from src/app/zelda3/CMakeLists.txt rename to src/app/zelda3/zelda3.cmake index 3b021326..a59b74d1 100644 --- a/src/app/zelda3/CMakeLists.txt +++ b/src/app/zelda3/zelda3.cmake @@ -5,6 +5,7 @@ set( app/zelda3/screen/inventory.cc app/zelda3/screen/title_screen.cc app/zelda3/sprite/sprite.cc + app/zelda3/sprite/sprite_builder.cc app/zelda3/music/tracker.cc app/zelda3/dungeon/room.cc app/zelda3/dungeon/room_object.cc diff --git a/src/cli/command_handler.h b/src/cli/command.h similarity index 58% rename from src/cli/command_handler.h rename to src/cli/command.h index 13a837ef..941d25f0 100644 --- a/src/cli/command_handler.h +++ b/src/cli/command.h @@ -1,34 +1,24 @@ #ifndef YAZE_CLI_COMMAND_HANDLER_H #define YAZE_CLI_COMMAND_HANDLER_H -#include // for uint8_t, uint32_t -#include // for operator<<, string, ostream, basic_... -#include // for make_shared, shared_ptr +#include +#include +#include #include -#include // for char_traits, basic_string, hash -#include -#include // for unordered_map -#include // for vector, vector<>::value_type +#include +#include +#include -#include "absl/status/status.h" // for OkStatus, Status -#include "absl/strings/str_cat.h" -#include "app/core/common.h" // for PcToSnes, SnesToPc -#include "app/core/constants.h" // for RETURN_IF_ERROR -#include "app/emu/snes.h" -#include "app/gfx/bitmap.h" -#include "app/gfx/compression.h" -#include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" -#include "app/gui/canvas.h" -#include "app/rom.h" // for Rom -#include "app/zelda3/overworld/overworld.h" -#include "cli/patch.h" // for ApplyBpsPatch, CreateBpsPatch +#include "absl/status/status.h" +#include "app/core/common.h" +#include "app/core/constants.h" +#include "app/rom.h" +#include "asar-dll-bindings/c/asar.h" namespace yaze { namespace cli { -namespace Color { -enum Code { +enum ColorCode { FG_RED = 31, FG_GREEN = 32, FG_YELLOW = 33, @@ -42,16 +32,15 @@ enum Code { BG_BLUE = 44, BG_DEFAULT = 49 }; -class Modifier { - Code code; +class ColorModifier { + ColorCode code; public: - explicit Modifier(Code pCode) : code(pCode) {} - friend std::ostream& operator<<(std::ostream& os, const Modifier& mod) { + explicit ColorModifier(ColorCode pCode) : code(pCode) {} + friend std::ostream& operator<<(std::ostream& os, const ColorModifier& mod) { return os << "\033[" << mod.code << "m"; } }; -} // namespace Color class CommandHandler { public: @@ -64,43 +53,17 @@ class CommandHandler { class ApplyPatch : public CommandHandler { public: - absl::Status handle(const std::vector& arg_vec) override { - std::string rom_filename = arg_vec[1]; - std::string patch_filename = arg_vec[2]; - RETURN_IF_ERROR(rom_.LoadFromFile(rom_filename)) - auto source = rom_.vector(); - std::ifstream patch_file(patch_filename, std::ios::binary); - std::vector patch; - patch.resize(rom_.size()); - patch_file.read((char*)patch.data(), patch.size()); + absl::Status handle(const std::vector& arg_vec) override; +}; - // Apply patch - std::vector patched; - ApplyBpsPatch(source, patch, patched); - - // Save patched file - std::ofstream patched_rom("patched.sfc", std::ios::binary); - patched_rom.write((char*)patched.data(), patched.size()); - patched_rom.close(); - return absl::OkStatus(); - } +class AsarPatch : public CommandHandler { + public: + absl::Status handle(const std::vector& arg_vec) override; }; class CreatePatch : public CommandHandler { public: - absl::Status handle(const std::vector& arg_vec) override { - std::vector source; - std::vector target; - std::vector patch; - // Create patch - CreateBpsPatch(source, target, patch); - - // Save patch to file - // std::ofstream patchFile("patch.bps", ios::binary); - // patchFile.write(reinterpret_cast(patch.data()), - // patch.size()); patchFile.close(); - return absl::OkStatus(); - } + absl::Status handle(const std::vector& arg_vec) override; }; /** @@ -109,9 +72,9 @@ class CreatePatch : public CommandHandler { class Open : public CommandHandler { public: absl::Status handle(const std::vector& arg_vec) override { - Color::Modifier green(Color::FG_GREEN); - Color::Modifier blue(Color::FG_BLUE); - Color::Modifier reset(Color::FG_RESET); + ColorModifier green(ColorCode::FG_GREEN); + ColorModifier blue(ColorCode::FG_BLUE); + ColorModifier reset(ColorCode::FG_RESET); auto const& arg = arg_vec[0]; RETURN_IF_ERROR(rom_.LoadFromFile(arg)) std::cout << "Title: " << green << rom_.title() << std::endl; @@ -141,10 +104,7 @@ class Backup : public CommandHandler { // Compress Graphics class Compress : public CommandHandler { public: - absl::Status handle(const std::vector& arg_vec) override { - std::cout << "Compress selected with argument: " << arg_vec[0] << std::endl; - return absl::OkStatus(); - } + absl::Status handle(const std::vector& arg_vec) override; }; // Decompress (Export) Graphics @@ -154,39 +114,7 @@ class Compress : public CommandHandler { // mode: class Decompress : public CommandHandler { public: - absl::Status handle(const std::vector& arg_vec) override { - Color::Modifier underline(Color::FG_UNDERLINE); - Color::Modifier reset(Color::FG_RESET); - std::cout << "Please specify the tilesheets you want to export\n"; - std::cout << "You can input an individual sheet, a range X-Y, or comma " - "separate values.\n\n"; - std::cout << underline << "Tilesheets\n" << reset; - std::cout << "0-112 -> compressed 3bpp bgr \n"; - std::cout << "113-114 -> compressed 2bpp\n"; - std::cout << "115-126 -> uncompressed 3bpp sprites\n"; - std::cout << "127-217 -> compressed 3bpp sprites\n"; - std::cout << "218-222 -> compressed 2bpp\n"; - - std::cout << "Enter tilesheets: "; - std::string sheet_input; - std::cin >> sheet_input; - - // Batch Mode - // if (arg_vec.size() == 1) { - // auto rom_filename = arg_vec[1]; - // RETURN_IF_ERROR(rom_.LoadFromFile(arg, true)) - // RETURN_IF_ERROR(rom_.LoadAllGraphicsData()) - // for (auto& graphic_sheet : rom_.graphics_bin()) { - // const auto filename = - // absl::StrCat(rom_.filename(), graphic_sheet.first); - // graphic_sheet.second.SaveSurfaceToFile(filename); - // } - // } - - std::cout << "Decompress selected with argument: " << arg_vec[0] - << std::endl; - return absl::OkStatus(); - } + absl::Status handle(const std::vector& arg_vec) override; }; /** @@ -222,7 +150,7 @@ class PcToSnes : public CommandHandler { uint32_t pc_address; ss >> std::hex >> pc_address; uint32_t snes_address = app::core::PcToSnes(pc_address); - Color::Modifier blue(Color::FG_BLUE); + ColorModifier blue(ColorCode::FG_BLUE); std::cout << "SNES LoROM Address: "; std::cout << blue << "$" << std::uppercase << std::hex << snes_address << "\n"; @@ -303,31 +231,13 @@ class Expand : public CommandHandler { } }; -/** - * @brief Start the emulator on a SNES Rom file. - - * @param arg_vec `-emu ` - * @return absl::Status -*/ -class Emulator : public CommandHandler { - public: - absl::Status handle(const std::vector& arg_vec) override { - std::string filename = arg_vec[0]; - RETURN_IF_ERROR(rom_.LoadFromFile(filename)) - - return absl::OkStatus(); - } - - app::emu::SNES snes; -}; - /** * @brief Command handler for the CLI. */ struct Commands { std::unordered_map> handlers = { - {"-emu", std::make_shared()}, {"-a", std::make_shared()}, + {"-asar", std::make_shared()}, {"-c", std::make_shared()}, {"-o", std::make_shared()}, {"-b", std::make_shared()}, @@ -344,4 +254,4 @@ struct Commands { } // namespace cli } // namespace yaze -#endif \ No newline at end of file +#endif diff --git a/src/cli/handlers/compress.cc b/src/cli/handlers/compress.cc new file mode 100644 index 00000000..95b014ec --- /dev/null +++ b/src/cli/handlers/compress.cc @@ -0,0 +1,33 @@ +#include "cli/command.h" + +namespace yaze { +namespace cli { + +absl::Status Compress::handle(const std::vector& arg_vec) { + std::cout << "Compress selected with argument: " << arg_vec[0] << std::endl; + return absl::OkStatus(); +} + +absl::Status Decompress::handle(const std::vector& arg_vec) { + ColorModifier underline(ColorCode::FG_UNDERLINE); + ColorModifier reset(ColorCode::FG_RESET); + std::cout << "Please specify the tilesheets you want to export\n"; + std::cout << "You can input an individual sheet, a range X-Y, or comma " + "separate values.\n\n"; + std::cout << underline << "Tilesheets\n" << reset; + std::cout << "0-112 -> compressed 3bpp bgr \n"; + std::cout << "113-114 -> compressed 2bpp\n"; + std::cout << "115-126 -> uncompressed 3bpp sprites\n"; + std::cout << "127-217 -> compressed 3bpp sprites\n"; + std::cout << "218-222 -> compressed 2bpp\n"; + + std::cout << "Enter tilesheets: "; + std::string sheet_input; + std::cin >> sheet_input; + + std::cout << "Decompress selected with argument: " << arg_vec[0] << std::endl; + return absl::UnimplementedError("Decompress not implemented"); +} + +} // namespace cli +} // namespace yaze \ No newline at end of file diff --git a/src/cli/handlers/patch.cc b/src/cli/handlers/patch.cc new file mode 100644 index 00000000..4aedf52e --- /dev/null +++ b/src/cli/handlers/patch.cc @@ -0,0 +1,61 @@ +#include "cli/command.h" + +namespace yaze { +namespace cli { + +absl::Status ApplyPatch::handle(const std::vector& arg_vec) { + std::string rom_filename = arg_vec[1]; + std::string patch_filename = arg_vec[2]; + RETURN_IF_ERROR(rom_.LoadFromFile(rom_filename)) + auto source = rom_.vector(); + std::ifstream patch_file(patch_filename, std::ios::binary); + std::vector patch; + patch.resize(rom_.size()); + patch_file.read((char*)patch.data(), patch.size()); + + // Apply patch + std::vector patched; + app::core::ApplyBpsPatch(source, patch, patched); + + // Save patched file + std::ofstream patched_rom("patched.sfc", std::ios::binary); + patched_rom.write((char*)patched.data(), patched.size()); + patched_rom.close(); + return absl::OkStatus(); +} + +absl::Status AsarPatch::handle(const std::vector& arg_vec) { + std::string patch_filename = arg_vec[1]; + std::string rom_filename = arg_vec[2]; + RETURN_IF_ERROR(rom_.LoadFromFile(rom_filename)) + int buflen = rom_.vector().size(); + int romlen = rom_.vector().size(); + if (!asar_patch(patch_filename.c_str(), rom_filename.data(), buflen, + &romlen)) { + std::string error_message = "Failed to apply patch: "; + int num_errors = 0; + const errordata* errors = asar_geterrors(&num_errors); + for (int i = 0; i < num_errors; i++) { + error_message += absl::StrFormat("%s", errors[i].fullerrdata); + } + return absl::InternalError(error_message); + } + return absl::OkStatus(); +} + +absl::Status CreatePatch::handle(const std::vector& arg_vec) { + std::vector source; + std::vector target; + std::vector patch; + // Create patch + app::core::CreateBpsPatch(source, target, patch); + + // Save patch to file + // std::ofstream patchFile("patch.bps", ios::binary); + // patchFile.write(reinterpret_cast(patch.data()), + // patch.size()); patchFile.close(); + return absl::OkStatus(); +} + +} // namespace cli +} // namespace yaze \ No newline at end of file diff --git a/src/cli/command_handler.cc b/src/cli/handlers/tile16_transfer.cc similarity index 88% rename from src/cli/command_handler.cc rename to src/cli/handlers/tile16_transfer.cc index 3878c8a9..9b874919 100644 --- a/src/cli/command_handler.cc +++ b/src/cli/handlers/tile16_transfer.cc @@ -1,12 +1,11 @@ -#include "cli/command_handler.h" +#include +#include -#include // for basic_string, char_traits, stoi -#include // for vector, vector<>::value_type - -#include "absl/status/status.h" // for OkStatus, Status -#include "app/core/common.h" // for app -#include "app/core/constants.h" // for RETURN_IF_ERROR -#include "app/rom.h" // for ROM +#include "absl/status/status.h" +#include "app/core/common.h" +#include "app/core/constants.h" +#include "app/rom.h" +#include "cli/command.h" namespace yaze { namespace cli { diff --git a/src/cli/patch.cc b/src/cli/patch.cc deleted file mode 100644 index 1b6945c8..00000000 --- a/src/cli/patch.cc +++ /dev/null @@ -1,205 +0,0 @@ -#include "cli/patch.h" - -#include - -#include -#include -#include -#include -#include - -namespace yaze { -namespace cli { - -void encode(uint64_t data, std::vector& output) { - while (true) { - uint8_t x = data & 0x7f; - data >>= 7; - if (data == 0) { - output.push_back(0x80 | x); - break; - } - output.push_back(x); - data--; - } -} - -uint64_t decode(const std::vector& input, size_t& offset) { - uint64_t data = 0; - uint64_t shift = 1; - while (true) { - uint8_t x = input[offset++]; - data += (x & 0x7f) * shift; - if (x & 0x80) break; - shift <<= 7; - data += shift; - } - return data; -} - -uint32_t crc32(const std::vector& data) { - uint32_t crc = ::crc32(0L, Z_NULL, 0); - return ::crc32(crc, data.data(), data.size()); -} - -void CreateBpsPatch(const std::vector& source, - const std::vector& target, - std::vector& patch) { - patch.clear(); - patch.insert(patch.end(), {'B', 'P', 'S', '1'}); - - encode(source.size(), patch); - encode(target.size(), patch); - encode(0, patch); // No metadata - - size_t sourceOffset = 0; - size_t targetOffset = 0; - int64_t sourceRelOffset = 0; - int64_t targetRelOffset = 0; - - while (targetOffset < target.size()) { - if (sourceOffset < source.size() && - source[sourceOffset] == target[targetOffset]) { - size_t length = 0; - while (sourceOffset + length < source.size() && - targetOffset + length < target.size() && - source[sourceOffset + length] == target[targetOffset + length]) { - length++; - } - encode((length - 1) << 2 | 0, patch); // SourceRead - sourceOffset += length; - targetOffset += length; - } else { - size_t length = 0; - while (targetOffset + length < target.size() && - (sourceOffset + length >= source.size() || - source[sourceOffset + length] != target[targetOffset + length])) { - length++; - } - if (length > 0) { - encode((length - 1) << 2 | 1, patch); // TargetRead - for (size_t i = 0; i < length; i++) { - patch.push_back(target[targetOffset + i]); - } - targetOffset += length; - } - } - - // SourceCopy - if (sourceOffset < source.size()) { - size_t length = 0; - int64_t offset = sourceOffset - sourceRelOffset; - while (sourceOffset + length < source.size() && - targetOffset + length < target.size() && - source[sourceOffset + length] == target[targetOffset + length]) { - length++; - } - if (length > 0) { - encode((length - 1) << 2 | 2, patch); - encode((offset < 0 ? 1 : 0) | (abs(offset) << 1), patch); - sourceOffset += length; - targetOffset += length; - sourceRelOffset = sourceOffset; - } - } - - // TargetCopy - if (targetOffset > 0) { - size_t length = 0; - int64_t offset = targetOffset - targetRelOffset; - while (targetOffset + length < target.size() && - target[targetOffset - 1] == target[targetOffset + length]) { - length++; - } - if (length > 0) { - encode((length - 1) << 2 | 3, patch); - encode((offset < 0 ? 1 : 0) | (abs(offset) << 1), patch); - targetOffset += length; - targetRelOffset = targetOffset; - } - } - } - - patch.resize(patch.size() + 12); // Make space for the checksums - uint32_t sourceChecksum = crc32(source); - uint32_t targetChecksum = crc32(target); - uint32_t patchChecksum = crc32(patch); - - memcpy(patch.data() + patch.size() - 12, &sourceChecksum, sizeof(uint32_t)); - memcpy(patch.data() + patch.size() - 8, &targetChecksum, sizeof(uint32_t)); - memcpy(patch.data() + patch.size() - 4, &patchChecksum, sizeof(uint32_t)); -} - -void ApplyBpsPatch(const std::vector& source, - const std::vector& patch, - std::vector& target) { - if (patch.size() < 4 || patch[0] != 'B' || patch[1] != 'P' || - patch[2] != 'S' || patch[3] != '1') { - throw std::runtime_error("Invalid patch format"); - } - - size_t patchOffset = 4; - uint64_t sourceSize = decode(patch, patchOffset); - uint64_t targetSize = decode(patch, patchOffset); - uint64_t metadataSize = decode(patch, patchOffset); - patchOffset += metadataSize; - - target.resize(targetSize); - size_t sourceOffset = 0; - size_t targetOffset = 0; - int64_t sourceRelOffset = 0; - int64_t targetRelOffset = 0; - - while (patchOffset < patch.size() - 12) { - uint64_t data = decode(patch, patchOffset); - uint64_t command = data & 3; - uint64_t length = (data >> 2) + 1; - - switch (command) { - case 0: // SourceRead - while (length--) { - target[targetOffset++] = source[sourceOffset++]; - } - break; - case 1: // TargetRead - while (length--) { - target[targetOffset++] = patch[patchOffset++]; - } - break; - case 2: // SourceCopy - { - int64_t offsetData = decode(patch, patchOffset); - sourceRelOffset += (offsetData & 1 ? -1 : +1) * (offsetData >> 1); - while (length--) { - target[targetOffset++] = source[sourceRelOffset++]; - } - } break; - case 3: // TargetCopy - { - uint64_t offsetData = decode(patch, patchOffset); - targetRelOffset += (offsetData & 1 ? -1 : +1) * (offsetData >> 1); - while (length--) { - target[targetOffset++] = target[targetRelOffset++]; - } - } - default: - throw std::runtime_error("Invalid patch command"); - } - } - - uint32_t sourceChecksum; - uint32_t targetChecksum; - uint32_t patchChecksum; - memcpy(&sourceChecksum, patch.data() + patch.size() - 12, sizeof(uint32_t)); - memcpy(&targetChecksum, patch.data() + patch.size() - 8, sizeof(uint32_t)); - memcpy(&patchChecksum, patch.data() + patch.size() - 4, sizeof(uint32_t)); - - if (sourceChecksum != crc32(source) || targetChecksum != crc32(target) || - patchChecksum != - crc32(std::vector(patch.begin(), patch.end() - 4))) { - throw std::runtime_error("Checksum mismatch"); - } -} - -} // namespace cli -} // namespace yaze \ No newline at end of file diff --git a/src/cli/patch.h b/src/cli/patch.h deleted file mode 100644 index 19892605..00000000 --- a/src/cli/patch.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef YAZE_CLI_PATCH_H -#define YAZE_CLI_PATCH_H - -#include - -#include -#include -#include -#include -#include -namespace yaze { -namespace cli { -void encode(uint64_t data, std::vector& output); - -uint64_t decode(const std::vector& input, size_t& offset); - -uint32_t crc32(const std::vector& data); - -void CreateBpsPatch(const std::vector& source, - const std::vector& target, - std::vector& patch); - -void ApplyBpsPatch(const std::vector& source, - const std::vector& patch, - std::vector& target); - -} // namespace cli -} // namespace yaze -#endif \ No newline at end of file diff --git a/src/cli/python/yaze_py.cc b/src/cli/python/yaze_py.cc new file mode 100644 index 00000000..23e51845 --- /dev/null +++ b/src/cli/python/yaze_py.cc @@ -0,0 +1,60 @@ +#include + +#include "incl/extension.h" +#include "incl/overworld.h" +#include "incl/snes_color.h" +#include "incl/sprite.h" +#include "yaze.h" + +BOOST_PYTHON_MODULE(yaze_py) { + using namespace boost::python; + + class_("z3_rom") + .def_readonly("filename", &z3_rom::filename) + .def_readonly("data", &z3_rom::data) + .def_readonly("size", &z3_rom::size) + .def_readonly("impl", &z3_rom::impl); + + class_("snes_color") + .def_readonly("red", &snes_color::red) + .def_readonly("green", &snes_color::green) + .def_readonly("blue", &snes_color::blue); + + class_("snes_palette") + .def_readonly("id", &snes_palette::id) + .def_readonly("size", &snes_palette::size) + .def_readonly("colors", &snes_palette::colors); + + class_("sprite") + .def_readonly("name", &z3_sprite::name) + .def_readonly("id", &z3_sprite::id); + + class_("yaze_flags") + .def_readwrite("debug", &yaze_flags::debug) + .def_readwrite("rom_filename", &yaze_flags::rom_filename) + .def_readwrite("rom", &yaze_flags::rom); + + class_("yaze_project") + .def_readonly("filename", &yaze_project::filepath); + + class_("yaze_editor_context") + .def_readonly("project", &yaze_editor_context::project); + + enum_("yaze_event_type") + .value("YAZE_EVENT_ROM_LOADED", YAZE_EVENT_ROM_LOADED) + .value("YAZE_EVENT_ROM_SAVED", YAZE_EVENT_ROM_SAVED) + .value("YAZE_EVENT_SPRITE_MODIFIED", YAZE_EVENT_SPRITE_MODIFIED) + .value("YAZE_EVENT_PALETTE_CHANGED", YAZE_EVENT_PALETTE_CHANGED); + + class_("yaze_extension") + .def_readonly("name", &yaze_extension::name) + .def_readonly("version", &yaze_extension::version); + + // Functions that return raw pointers need to be managed by Python's garbage + // collector + def("yaze_load_rom", &yaze_load_rom, + return_value_policy()); + def("yaze_unload_rom", &yaze_unload_rom); // No need to manage memory here + def("yaze_get_color_from_paletteset", &yaze_get_color_from_paletteset); + def("yaze_check_version", &yaze_check_version); +} diff --git a/src/cli/python/yaze_py.cmake b/src/cli/python/yaze_py.cmake new file mode 100644 index 00000000..7275029c --- /dev/null +++ b/src/cli/python/yaze_py.cmake @@ -0,0 +1,50 @@ +find_package(PythonLibs 3.11 REQUIRED) +find_package(Boost COMPONENTS python3 REQUIRED) + +# target x86_64 for module +add_library( + yaze_py MODULE + py/yaze_py.cc + yaze.cc + app/rom.cc + app/core/common.cc + app/core/labeling.cc + app/zelda3/overworld/overworld_map.cc + app/zelda3/overworld/overworld.cc + app/zelda3/sprite/sprite.cc + app/editor/utils/gfx_context.cc + ${YAZE_APP_GFX_SRC} + ${IMGUI_PATH}/imgui.cpp + ${IMGUI_PATH}/imgui_demo.cpp + ${IMGUI_PATH}/imgui_draw.cpp + ${IMGUI_PATH}/imgui_widgets.cpp + ${IMGUI_PATH}/misc/cpp/imgui_stdlib.cpp +) + +if (APPLE) + set(PYTHON_HEADERS /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/Headers) +elseif(LINUX) + set(PYTHON_HEADERS /usr/include/python3.8) +endif() + +target_include_directories( + yaze_py PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/ + lib/ + app/ + ${SDL_INCLUDE_DIR} + ${PYTHON_HEADERS} + ${Boost_INCLUDE_DIRS} + ${PYTHON_INCLUDE_DIRS} +) + +target_link_libraries( + yaze_py PUBLIC + ${SDL_TARGETS} + ${ABSL_TARGETS} + ${PYTHON_LIBRARIES} + ${PNG_LIBRARIES} + Boost::python3 + ImGui + ImGuiTestEngine +) \ No newline at end of file diff --git a/src/cli/z3ed.cc b/src/cli/z3ed.cc index 85cbe86d..1f7319bf 100644 --- a/src/cli/z3ed.cc +++ b/src/cli/z3ed.cc @@ -1,19 +1,16 @@ -#include #include #include #include -#include #include -#include #include #include -#include "absl/status/status.h" -#include "app/core/common.h" +#include "absl/flags/flag.h" #include "app/core/constants.h" -#include "app/rom.h" -#include "cli/command_handler.h" -#include "cli/patch.h" +#include "cli/command.h" + +ABSL_FLAG(bool, verbose, false, "Enable verbose output"); +ABSL_FLAG(bool, debug, false, "Enable debug output"); namespace yaze { @@ -25,11 +22,11 @@ namespace cli { namespace { void HelpCommand() { - Color::Modifier ylw(Color::FG_YELLOW); - Color::Modifier mag(Color::FG_MAGENTA); - Color::Modifier red(Color::FG_RED); - Color::Modifier reset(Color::FG_RESET); - Color::Modifier underline(Color::FG_UNDERLINE); + ColorModifier ylw(ColorCode::FG_YELLOW); + ColorModifier mag(ColorCode::FG_MAGENTA); + ColorModifier red(ColorCode::FG_RED); + ColorModifier reset(ColorCode::FG_RESET); + ColorModifier underline(ColorCode::FG_UNDERLINE); std::cout << "\n"; std::cout << ylw << " ▲ " << reset << " z3ed\n"; std::cout << ylw << "▲ ▲ " << reset << " by " << mag << "scawful\n\n" @@ -61,7 +58,12 @@ void HelpCommand() { } int RunCommandHandler(int argc, char* argv[]) { - if (argv[1] == "-h" || argc == 1) { + if (argc == 1) { + HelpCommand(); + return EXIT_SUCCESS; + } + + if (std::strcmp(argv[1], "-h") == 0 || argc == 1) { HelpCommand(); return EXIT_SUCCESS; } @@ -88,4 +90,4 @@ int RunCommandHandler(int argc, char* argv[]) { int main(int argc, char* argv[]) { return yaze::cli::RunCommandHandler(argc, argv); -} \ No newline at end of file +} diff --git a/src/cli/CMakeLists.txt b/src/cli/z3ed.cmake similarity index 66% rename from src/cli/CMakeLists.txt rename to src/cli/z3ed.cmake index 5bafd437..fd3b7772 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/z3ed.cmake @@ -1,25 +1,27 @@ add_executable( z3ed cli/z3ed.cc - cli/patch.cc - cli/command_handler.cc + cli/handlers/compress.cc + cli/handlers/patch.cc + cli/handlers/tile16_transfer.cc app/rom.cc app/core/common.cc - app/core/labeling.cc - app/gui/pipeline.cc - app/editor/context/gfx_context.cc - app/core/platform/file_dialog.mm + app/core/project.cc + app/core/platform/file_path.mm ${YAZE_APP_EMU_SRC} ${YAZE_APP_GFX_SRC} ${YAZE_APP_ZELDA3_SRC} ${YAZE_GUI_SRC} ${IMGUI_SRC} + ${ASAR_STATIC_SRC} ) target_include_directories( z3ed PUBLIC lib/ app/ + ${ASAR_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/incl/ ${CMAKE_SOURCE_DIR}/src/ ${PNG_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} @@ -28,11 +30,13 @@ target_include_directories( target_link_libraries( z3ed PUBLIC + asar-static ${ABSL_TARGETS} ${SDL_TARGETS} ${PNG_LIBRARIES} ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS} + ImGuiTestEngine ImGui ) \ No newline at end of file diff --git a/src/ios/Media.xcassets/Contents.json b/src/ios/Media.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/src/ios/Media.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/ios/Media.xcassets/yaze.appiconset/Contents.json b/src/ios/Media.xcassets/yaze.appiconset/Contents.json new file mode 100644 index 00000000..3b68d945 --- /dev/null +++ b/src/ios/Media.xcassets/yaze.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "yaze.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/ios/Media.xcassets/yaze.appiconset/yaze.png b/src/ios/Media.xcassets/yaze.appiconset/yaze.png new file mode 100644 index 0000000000000000000000000000000000000000..022145765afc339fd4110c6aa5346aeb3640f263 GIT binary patch literal 6580 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7&zE~RK2WrGXn!-OQy4PfTy#wLP1e}T4qiv z1B1rI+KILvhaF^&#$Wd84w2DW^k~9Dt4IOS!Yf)L3!PSqMwJ@u{K7rUL`74tuPOWB z!TzJGn!7iz<6GCH@PqNun+Ho?D5?I_*WA+a@xc!H_wQ`q-D7lGd?>`&fN#aD)Fr}& zhO?tZo7ZzVI@q%bPMERs{L&!LioW&LKYmn+KaRZj{GW`i*S(Ymf0cQuyAlQS1^n}) zte)3C;?VZw`e^xahNHMj-IHB!K1n}cbeQRUkHpL`Hiaz_I%ON~99)yK;z;n3K-a4p z@h5hzDY*A&O<2~NQvZL43gV(8pIMzvRN2s>xocruu z^=8JT8Wia);1ZqmnEikA{kyYTPjZ@T%CPT>%lVzm!tsvj?5^B;`P*fmSw7e^hezFx z&t)*4zvTMus4pBZ?y~8vyFF_Ud(1lqX8&C&9(_-iYl?6k_$^r*%=cn9>#pl}?nV8! zsAVv^68eeF!h*%Ed&=H-AKwL}=l`FV`Sm+9&#j_5+aU2WV6?C$dAqwXtYC;>P`Ki;O^-g5Z=fq&cGnvZBqSo@J6k71{tFoTPf4};3DR3@O6 z0zeE*Lm+}66O{BA96$s(72;(QXCl~2B27fHokoTe3;=Wm*j>J0{XrIiw_bLCK8D_F zc=CLI^}h*OQEB@b8$9wrLDv8x7&t&g1Bk%KQ~)ag#S;TTCUGV#J4|8FlYI$!_hsWQj6 zAAdUR{+C5BK5wu4S@a(#&p)mSr+7hL9|WFqU@!m$0ZEYua=HSDU?7w-8o;WEGh6|z zmXL`^R$@2YA-$RNQS8Zf`}p*4m+QYXy8J$8_b+mGxx$T&(*>Js?d*F5a%9~1Gj=`& zRbhj}<1;`m!Je?Ni;|FP9YAIiX*enA5v-P0hGX|N9#K+Uj>i}b|Bw*S_=*SYR+3;i zlEWUfOZyb;p2WZ3_WFzV|KBn$K9|4!MBibu*L(4hu48{$=BPHk!QAL!FdF zf+u+|*u0xl;dvC-+oiw;x9k9KYyis;QRaE?1y%M zbx~YpG=Th!Q4=VDMTs++5^Y=fi{{bofz&l{K4+_r;1D(;PN zbA^qg!A;BHj?M=5OzT5k?f<{s`HO?0!&rB-;2*Z8(XJ_j12~Z*RRbgxu=v`ZR??T) zGuFn&F$aZC6=YC&|Ns7%|MhJ7j4MYII?WP#nK|RhRa(FPJg=3Dpk0Fp;i&;aHmc@7U# z0j!od!|@n{)yn_3HztFM{|3i@*EZh>m0*OZ0()BlC=Ly>GfYcOs(#EbXuk{+@^tlc JS?83{1OUa{T2TN1 literal 0 HcmV?d00001 diff --git a/src/ios/iOS/Info-iOS.plist b/src/ios/iOS/Info-iOS.plist new file mode 100644 index 00000000..2d98d3c6 --- /dev/null +++ b/src/ios/iOS/Info-iOS.plist @@ -0,0 +1,120 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDocumentTypes + + + CFBundleTypeName + SFC ROM + LSHandlerRank + Default + LSItemContentTypes + + org.halext.sfc + + + + CFBundleTypeName + SMC ROM + LSHandlerRank + Default + LSItemContentTypes + + halext.sfc + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + yaze-ios + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + metal + + UIRequiresFullScreen + + UIStatusBarHidden + + UIStatusBarStyle + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UTExportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Super Nintendo ROMs + UTTypeIconFiles + + UTTypeIdentifier + org.halext.sfc + UTTypeTagSpecification + + public.filename-extension + + sfc + + + + + UTImportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeDescription + Super Nintendo ROMs + UTTypeIconFiles + + UTTypeIdentifier + org.halext.sfc + UTTypeTagSpecification + + public.filename-extension + + sfc + + public.mime-type + + + + + + diff --git a/src/ios/iOS/LaunchScreen.storyboard b/src/ios/iOS/LaunchScreen.storyboard new file mode 100644 index 00000000..12c52cfb --- /dev/null +++ b/src/ios/iOS/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ios/main.mm b/src/ios/main.mm new file mode 100644 index 00000000..dcf7e85d --- /dev/null +++ b/src/ios/main.mm @@ -0,0 +1,394 @@ +// yaze iOS Application +// Uses SDL2 and ImGui + +#import + +#if TARGET_OS_OSX +#import +#else +#import +#endif + +#import +#import + +#import +#import + +#include "app/core/controller.h" +#include "app/core/platform/app_delegate.h" + +#include + +#ifdef main +#undef main +#endif + +#include "app/core/platform/view_controller.h" +#include "imgui/backends/imgui_impl_metal.h" +#include "imgui/imgui.h" + +// ---------------------------------------------------------------------------- +// AppViewController +// ---------------------------------------------------------------------------- + +@implementation AppViewController + +- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil + bundle:(nullable NSBundle *)nibBundleOrNil { + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + + _device = MTLCreateSystemDefaultDevice(); + _commandQueue = [_device newCommandQueue]; + + if (!self.device) { + NSLog(@"Metal is not supported"); + abort(); + } + + _controller = new yaze::app::core::Controller(); + + SDL_SetMainReady(); + SDL_iOSSetEventPump(SDL_TRUE); + int argc = NSProcessInfo.processInfo.arguments.count; + char **argv = new char *[argc]; + for (int i = 0; i < argc; i++) { + NSString *arg = NSProcessInfo.processInfo.arguments[i]; + const char *cString = [arg UTF8String]; + argv[i] = new char[strlen(cString) + 1]; + strcpy(argv[i], cString); + } + + std::string rom_filename = ""; + if (argc > 1) { + rom_filename = argv[1]; + } + SDL_iOSSetEventPump(SDL_FALSE); + + // Enable native IME. + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); + if (!_controller->CreateWindow().ok()) { + printf("Error creating window: %s\n", SDL_GetError()); + abort(); + } + if (!_controller->CreateRenderer().ok()) { + printf("Error creating renderer: %s\n", SDL_GetError()); + abort(); + } + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO &io = ImGui::GetIO(); + (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + yaze::app::gui::ColorsYaze(); + + ImGui_ImplSDL2_InitForSDLRenderer(_controller->window(), _controller->renderer()); + ImGui_ImplSDLRenderer2_Init(_controller->renderer()); + + if (!_controller->LoadFontFamilies().ok()) { + abort(); + } + _controller->SetupScreen(rom_filename); + _controller->set_active(true); + + _hoverGestureRecognizer = + [[UIHoverGestureRecognizer alloc] initWithTarget:self action:@selector(HoverGesture:)]; + [self.view addGestureRecognizer:_hoverGestureRecognizer]; + + _pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self + action:@selector(HandlePinch:)]; + [self.view addGestureRecognizer:_pinchRecognizer]; + + _longPressRecognizer = + [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; + [self.view addGestureRecognizer:_longPressRecognizer]; + + _swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self + action:@selector(HandleSwipe:)]; + _swipeRecognizer.direction = + UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionLeft; + [self.view addGestureRecognizer:_swipeRecognizer]; + return self; +} + +- (MTKView *)mtkView { + return (MTKView *)self.view; +} + +- (void)loadView { + self.view = [[MTKView alloc] initWithFrame:CGRectMake(0, 0, 1200, 720)]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.mtkView.device = self.device; + self.mtkView.delegate = self; + +#if TARGET_OS_OSX + ImGui_ImplOSX_Init(self.view); + [NSApp activateIgnoringOtherApps:YES]; +#endif +} + +- (void)drawInMTKView:(MTKView *)view { + ImGuiIO &io = ImGui::GetIO(); + io.DisplaySize.x = view.bounds.size.width; + io.DisplaySize.y = view.bounds.size.height; + +#if TARGET_OS_OSX + CGFloat framebufferScale = + view.window.screen.backingScaleFactor ?: NSScreen.mainScreen.backingScaleFactor; +#else + CGFloat framebufferScale = view.window.screen.scale ?: UIScreen.mainScreen.scale; +#endif + io.DisplayFramebufferScale = ImVec2(framebufferScale, framebufferScale); + + ImGui_ImplSDLRenderer2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); +#if TARGET_OS_OSX + ImGui_ImplOSX_NewFrame(view); +#endif + + ImGui::NewFrame(); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImVec2 dimensions(io.DisplaySize.x, io.DisplaySize.y); + ImGui::SetNextWindowSize(dimensions, ImGuiCond_Always); + if (ImGui::Begin("##YazeMain", nullptr, + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | + ImGuiWindowFlags_NoBringToFrontOnFocus)) { + auto controller_status = _controller->OnLoad(); + if (!controller_status.ok()) { + abort(); + } + ImGui::End(); + } + _controller->DoRender(); +} + +- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size { +} + +// ---------------------------------------------------------------------------- +// Input processing +// ---------------------------------------------------------------------------- + +#if TARGET_OS_OSX + +- (void)viewWillAppear { + [super viewWillAppear]; + self.view.window.delegate = self; +} + +- (void)windowWillClose:(NSNotification *)notification { + ImGui_ImplMetal_Shutdown(); + ImGui_ImplOSX_Shutdown(); + ImGui::DestroyContext(); +} + +#else + +// This touch mapping is super cheesy/hacky. We treat any touch on the screen +// as if it were a depressed left mouse button, and we don't bother handling +// multitouch correctly at all. This causes the "cursor" to behave very erratically +// when there are multiple active touches. But for demo purposes, single-touch +// interaction actually works surprisingly well. +- (void)UpdateIOWithTouchEvent:(UIEvent *)event { + UITouch *anyTouch = event.allTouches.anyObject; + CGPoint touchLocation = [anyTouch locationInView:self.view]; + ImGuiIO &io = ImGui::GetIO(); + io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); + io.AddMousePosEvent(touchLocation.x, touchLocation.y); + + BOOL hasActiveTouch = NO; + for (UITouch *touch in event.allTouches) { + if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) { + hasActiveTouch = YES; + break; + } + } + io.AddMouseButtonEvent(0, hasActiveTouch); +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [self UpdateIOWithTouchEvent:event]; +} +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + [self UpdateIOWithTouchEvent:event]; +} +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [self UpdateIOWithTouchEvent:event]; +} +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [self UpdateIOWithTouchEvent:event]; +} + +- (void)HoverGesture:(UIHoverGestureRecognizer *)gesture { + ImGuiIO &io = ImGui::GetIO(); + io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); + // Cast to UIGestureRecognizer to UIGestureRecognizer to get locationInView + UIGestureRecognizer *gestureRecognizer = (UIGestureRecognizer *)gesture; + if (gesture.zOffset < 0.50) { + io.AddMousePosEvent([gestureRecognizer locationInView:self.view].x, + [gestureRecognizer locationInView:self.view].y); + } +} + +- (void)HandlePinch:(UIPinchGestureRecognizer *)gesture { + ImGuiIO &io = ImGui::GetIO(); + io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); + io.AddMouseWheelEvent(0.0f, gesture.scale); +} + +- (void)HandleSwipe:(UISwipeGestureRecognizer *)gesture { + ImGuiIO &io = ImGui::GetIO(); + io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); + if (gesture.direction == UISwipeGestureRecognizerDirectionRight) { + io.AddMouseWheelEvent(1.0f, 0.0f); // Swipe Right + } else if (gesture.direction == UISwipeGestureRecognizerDirectionLeft) { + io.AddMouseWheelEvent(-1.0f, 0.0f); // Swipe Left + } +} + +- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture { + ImGuiIO &io = ImGui::GetIO(); + io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); + io.AddMouseButtonEvent(1, gesture.state == UIGestureRecognizerStateBegan); +} + +#endif + +@end + +// ---------------------------------------------------------------------------- +// AppDelegate +// ---------------------------------------------------------------------------- + +#if TARGET_OS_OSX + +@interface AppDelegate : NSObject +@property(nonatomic, strong) NSWindow *window; +@end + +@implementation AppDelegate + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { + return YES; +} + +- (instancetype)init { + if (self = [super init]) { + NSViewController *rootViewController = [[AppViewController alloc] initWithNibName:nil + bundle:nil]; + self.window = [[NSWindow alloc] + initWithContentRect:NSZeroRect + styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable + backing:NSBackingStoreBuffered + defer:NO]; + self.window.contentViewController = rootViewController; + [self.window center]; + [self.window makeKeyAndOrderFront:self]; + } + return self; +} + +@end + +#else + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + UIViewController *rootViewController = [[AppViewController alloc] init]; + self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; +} + +- (void)applicationWillTerminate:(UIApplication *)application { + ImGui_ImplSDLRenderer2_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + SDL_Quit(); +} + +- (void)PresentDocumentPickerWithCompletionHandler: + (void (^)(NSString *selectedFile))completionHandler { + self.completionHandler = completionHandler; + + NSArray *documentTypes = @[ [UTType typeWithIdentifier:@"org.halext.sfc"] ]; + UIViewController *rootViewController = self.window.rootViewController; + _documentPicker = + [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:documentTypes]; + _documentPicker.delegate = self; + _documentPicker.modalPresentationStyle = UIModalPresentationFormSheet; + + [rootViewController presentViewController:_documentPicker animated:YES completion:nil]; +} + +- (void)documentPicker:(UIDocumentPickerViewController *)controller + didPickDocumentsAtURLs:(NSArray *)urls { + NSURL *selectedFileURL = [urls firstObject]; + + if (self.completionHandler) { + if (selectedFileURL) { + self.completionHandler(selectedFileURL.path); + std::string fileName = std::string([selectedFileURL.path UTF8String]); + + // Extract the data from the file + [selectedFileURL startAccessingSecurityScopedResource]; + + auto data = [NSData dataWithContentsOfURL:selectedFileURL]; + // Cast NSData* to uint8_t* + uchar *bytes = (uchar *)[data bytes]; + // Size of the data + size_t size = [data length]; + + PRINT_IF_ERROR(yaze::app::SharedRom::shared_rom_->LoadFromPointer(bytes, size)); + std::string filename = std::string([selectedFileURL.path UTF8String]); + yaze::app::SharedRom::shared_rom_->set_filename(filename); + [selectedFileURL stopAccessingSecurityScopedResource]; + + } else { + self.completionHandler(@""); + } + } + self.completionHandler = nil; + [controller dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller { + if (self.completionHandler) { + self.completionHandler(@""); + } + self.completionHandler = nil; + [controller dismissViewControllerAnimated:YES completion:nil]; +} + +@end + +#endif + +// ---------------------------------------------------------------------------- +// Application main() function +// ---------------------------------------------------------------------------- + +#if TARGET_OS_OSX +int main(int argc, const char *argv[]) { return NSApplicationMain(argc, argv); } +#else + +int main(int argc, char *argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} + +#endif diff --git a/src/ios/yaze.xcodeproj/project.pbxproj b/src/ios/yaze.xcodeproj/project.pbxproj new file mode 100644 index 00000000..731caab6 --- /dev/null +++ b/src/ios/yaze.xcodeproj/project.pbxproj @@ -0,0 +1,6321 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; }; + 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; + 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; + 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; }; + 8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */; }; + 8309BDA5253CCC070045E2A1 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDA0253CCBC10045E2A1 /* main.mm */; }; + 8309BDA8253CCC080045E2A1 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDA0253CCBC10045E2A1 /* main.mm */; }; + 8309BDBB253CCCAD0045E2A1 /* imgui_impl_metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal.mm */; }; + 8309BDBE253CCCB60045E2A1 /* imgui_impl_metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal.mm */; }; + 8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8309BDC5253CCCFE0045E2A1 /* AppKit.framework */; }; + 8309BE04253CDAB60045E2A1 /* MainMenu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8309BDFA253CDAAE0045E2A1 /* MainMenu.storyboard */; }; + 83BBE9E520EB46B900295997 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9E420EB46B900295997 /* Metal.framework */; }; + 83BBE9E720EB46BD00295997 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9E620EB46BD00295997 /* MetalKit.framework */; }; + 83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9EA20EB471700295997 /* MetalKit.framework */; }; + 83BBE9ED20EB471700295997 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9EB20EB471700295997 /* Metal.framework */; }; + 83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0120EB54E700295997 /* imgui_draw.cpp */; }; + 83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0120EB54E700295997 /* imgui_draw.cpp */; }; + 83BBEA0720EB54E700295997 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0220EB54E700295997 /* imgui_demo.cpp */; }; + 83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0220EB54E700295997 /* imgui_demo.cpp */; }; + 83BBEA0920EB54E700295997 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0320EB54E700295997 /* imgui.cpp */; }; + 83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0320EB54E700295997 /* imgui.cpp */; }; + E318D8FB2C59C08300091322 /* app_delegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D8482C59C08300091322 /* app_delegate.mm */; }; + E318D8FC2C59C08300091322 /* app_delegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D8482C59C08300091322 /* app_delegate.mm */; }; + E318D8FD2C59C08300091322 /* clipboard.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8492C59C08300091322 /* clipboard.cc */; }; + E318D8FE2C59C08300091322 /* clipboard.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8492C59C08300091322 /* clipboard.cc */; }; + E318D8FF2C59C08300091322 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D84B2C59C08300091322 /* clipboard.mm */; }; + E318D9002C59C08300091322 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D84B2C59C08300091322 /* clipboard.mm */; }; + E318D9012C59C08300091322 /* file_dialog.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D84D2C59C08300091322 /* file_dialog.mm */; }; + E318D9022C59C08300091322 /* file_dialog.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D84D2C59C08300091322 /* file_dialog.mm */; }; + E318D9032C59C08300091322 /* font_loader.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D84E2C59C08300091322 /* font_loader.cc */; }; + E318D9042C59C08300091322 /* font_loader.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D84E2C59C08300091322 /* font_loader.cc */; }; + E318D9052C59C08300091322 /* font_loader.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D8502C59C08300091322 /* font_loader.mm */; }; + E318D9062C59C08300091322 /* font_loader.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318D8502C59C08300091322 /* font_loader.mm */; }; + E318D9072C59C08300091322 /* common.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8522C59C08300091322 /* common.cc */; }; + E318D9082C59C08300091322 /* common.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8522C59C08300091322 /* common.cc */; }; + E318D9092C59C08300091322 /* controller.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8552C59C08300091322 /* controller.cc */; }; + E318D90A2C59C08300091322 /* controller.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8552C59C08300091322 /* controller.cc */; }; + E318D90D2C59C08300091322 /* assembly_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D85C2C59C08300091322 /* assembly_editor.cc */; }; + E318D90E2C59C08300091322 /* assembly_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D85C2C59C08300091322 /* assembly_editor.cc */; }; + E318D90F2C59C08300091322 /* dungeon_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8602C59C08300091322 /* dungeon_editor.cc */; }; + E318D9102C59C08300091322 /* dungeon_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8602C59C08300091322 /* dungeon_editor.cc */; }; + E318D9112C59C08300091322 /* gfx_group_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8632C59C08300091322 /* gfx_group_editor.cc */; }; + E318D9122C59C08300091322 /* gfx_group_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8632C59C08300091322 /* gfx_group_editor.cc */; }; + E318D9132C59C08300091322 /* graphics_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8652C59C08300091322 /* graphics_editor.cc */; }; + E318D9142C59C08300091322 /* graphics_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8652C59C08300091322 /* graphics_editor.cc */; }; + E318D9152C59C08300091322 /* palette_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8672C59C08300091322 /* palette_editor.cc */; }; + E318D9162C59C08300091322 /* palette_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8672C59C08300091322 /* palette_editor.cc */; }; + E318D9172C59C08300091322 /* screen_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8692C59C08300091322 /* screen_editor.cc */; }; + E318D9182C59C08300091322 /* screen_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8692C59C08300091322 /* screen_editor.cc */; }; + E318D9192C59C08300091322 /* tile16_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D86B2C59C08300091322 /* tile16_editor.cc */; }; + E318D91A2C59C08300091322 /* tile16_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D86B2C59C08300091322 /* tile16_editor.cc */; }; + E318D91D2C59C08300091322 /* message_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8702C59C08300091322 /* message_editor.cc */; }; + E318D91E2C59C08300091322 /* message_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8702C59C08300091322 /* message_editor.cc */; }; + E318D91F2C59C08300091322 /* music_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8732C59C08300091322 /* music_editor.cc */; }; + E318D9202C59C08300091322 /* music_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8732C59C08300091322 /* music_editor.cc */; }; + E318D9212C59C08300091322 /* entity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8762C59C08300091322 /* entity.cc */; }; + E318D9222C59C08300091322 /* entity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8762C59C08300091322 /* entity.cc */; }; + E318D9252C59C08300091322 /* sprite_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D87A2C59C08300091322 /* sprite_editor.cc */; }; + E318D9262C59C08300091322 /* sprite_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D87A2C59C08300091322 /* sprite_editor.cc */; }; + E318D9272C59C08300091322 /* gfx_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8802C59C08300091322 /* gfx_context.cc */; }; + E318D9282C59C08300091322 /* gfx_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8802C59C08300091322 /* gfx_context.cc */; }; + E318D9332C59C08300091322 /* addressing.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D88E2C59C08300091322 /* addressing.cc */; }; + E318D9342C59C08300091322 /* addressing.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D88E2C59C08300091322 /* addressing.cc */; }; + E318D9352C59C08300091322 /* instructions.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D88F2C59C08300091322 /* instructions.cc */; }; + E318D9362C59C08300091322 /* instructions.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D88F2C59C08300091322 /* instructions.cc */; }; + E318D9372C59C08300091322 /* apu.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8922C59C08300091322 /* apu.cc */; }; + E318D9382C59C08300091322 /* apu.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8922C59C08300091322 /* apu.cc */; }; + E318D9392C59C08300091322 /* dsp.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8942C59C08300091322 /* dsp.cc */; }; + E318D93A2C59C08300091322 /* dsp.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8942C59C08300091322 /* dsp.cc */; }; + E318D93B2C59C08300091322 /* spc700.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8962C59C08300091322 /* spc700.cc */; }; + E318D93C2C59C08300091322 /* spc700.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8962C59C08300091322 /* spc700.cc */; }; + E318D93D2C59C08300091322 /* addressing.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8992C59C08300091322 /* addressing.cc */; }; + E318D93E2C59C08300091322 /* addressing.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8992C59C08300091322 /* addressing.cc */; }; + E318D93F2C59C08300091322 /* instructions.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D89A2C59C08300091322 /* instructions.cc */; }; + E318D9402C59C08300091322 /* instructions.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D89A2C59C08300091322 /* instructions.cc */; }; + E318D9422C59C08300091322 /* old_cpu.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D89B2C59C08300091322 /* old_cpu.cc */; }; + E318D9432C59C08300091322 /* cpu.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D89F2C59C08300091322 /* cpu.cc */; }; + E318D9442C59C08300091322 /* cpu.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D89F2C59C08300091322 /* cpu.cc */; }; + E318D9472C59C08300091322 /* dma.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8A82C59C08300091322 /* dma.cc */; }; + E318D9482C59C08300091322 /* dma.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8A82C59C08300091322 /* dma.cc */; }; + E318D9492C59C08300091322 /* memory.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8AA2C59C08300091322 /* memory.cc */; }; + E318D94A2C59C08300091322 /* memory.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8AA2C59C08300091322 /* memory.cc */; }; + E318D94B2C59C08300091322 /* ppu.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8AF2C59C08300091322 /* ppu.cc */; }; + E318D94C2C59C08300091322 /* ppu.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8AF2C59C08300091322 /* ppu.cc */; }; + E318D94F2C59C08300091322 /* emulator.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8B32C59C08300091322 /* emulator.cc */; }; + E318D9502C59C08300091322 /* emulator.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8B32C59C08300091322 /* emulator.cc */; }; + E318D9512C59C08300091322 /* snes.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8B52C59C08300091322 /* snes.cc */; }; + E318D9522C59C08300091322 /* snes.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8B52C59C08300091322 /* snes.cc */; }; + E318D9532C59C08300091322 /* bitmap.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8B82C59C08300091322 /* bitmap.cc */; }; + E318D9542C59C08300091322 /* bitmap.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8B82C59C08300091322 /* bitmap.cc */; }; + E318D9552C59C08300091322 /* compression.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8BA2C59C08300091322 /* compression.cc */; }; + E318D9562C59C08300091322 /* compression.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8BA2C59C08300091322 /* compression.cc */; }; + E318D9572C59C08300091322 /* scad_format.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8BC2C59C08300091322 /* scad_format.cc */; }; + E318D9582C59C08300091322 /* scad_format.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8BC2C59C08300091322 /* scad_format.cc */; }; + E318D9592C59C08300091322 /* snes_color.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8BE2C59C08300091322 /* snes_color.cc */; }; + E318D95A2C59C08300091322 /* snes_color.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8BE2C59C08300091322 /* snes_color.cc */; }; + E318D95B2C59C08300091322 /* snes_palette.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C02C59C08300091322 /* snes_palette.cc */; }; + E318D95C2C59C08300091322 /* snes_palette.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C02C59C08300091322 /* snes_palette.cc */; }; + E318D95D2C59C08300091322 /* snes_tile.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C22C59C08300091322 /* snes_tile.cc */; }; + E318D95E2C59C08300091322 /* snes_tile.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C22C59C08300091322 /* snes_tile.cc */; }; + E318D95F2C59C08300091322 /* tilesheet.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C42C59C08300091322 /* tilesheet.cc */; }; + E318D9602C59C08300091322 /* tilesheet.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C42C59C08300091322 /* tilesheet.cc */; }; + E318D9632C59C08300091322 /* canvas.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C92C59C08300091322 /* canvas.cc */; }; + E318D9642C59C08300091322 /* canvas.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8C92C59C08300091322 /* canvas.cc */; }; + E318D9652C59C08300091322 /* color.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8CB2C59C08300091322 /* color.cc */; }; + E318D9662C59C08300091322 /* color.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8CB2C59C08300091322 /* color.cc */; }; + E318D9672C59C08300091322 /* input.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8CE2C59C08300091322 /* input.cc */; }; + E318D9682C59C08300091322 /* input.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8CE2C59C08300091322 /* input.cc */; }; + E318D9692C59C08300091322 /* style.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8D02C59C08300091322 /* style.cc */; }; + E318D96A2C59C08300091322 /* style.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8D02C59C08300091322 /* style.cc */; }; + E318D96B2C59C08300091322 /* zeml.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8D22C59C08300091322 /* zeml.cc */; }; + E318D96C2C59C08300091322 /* zeml.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8D22C59C08300091322 /* zeml.cc */; }; + E318D96D2C59C08300091322 /* object_renderer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8D62C59C08300091322 /* object_renderer.cc */; }; + E318D96E2C59C08300091322 /* object_renderer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8D62C59C08300091322 /* object_renderer.cc */; }; + E318D96F2C59C08300091322 /* room_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8DA2C59C08300091322 /* room_object.cc */; }; + E318D9702C59C08300091322 /* room_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8DA2C59C08300091322 /* room_object.cc */; }; + E318D9712C59C08300091322 /* room.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8DC2C59C08300091322 /* room.cc */; }; + E318D9722C59C08300091322 /* room.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8DC2C59C08300091322 /* room.cc */; }; + E318D9752C59C08300091322 /* tracker.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E02C59C08300091322 /* tracker.cc */; }; + E318D9762C59C08300091322 /* tracker.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E02C59C08300091322 /* tracker.cc */; }; + E318D9772C59C08300091322 /* overworld_map.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E32C59C08300091322 /* overworld_map.cc */; }; + E318D9782C59C08300091322 /* overworld_map.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E32C59C08300091322 /* overworld_map.cc */; }; + E318D9792C59C08300091322 /* overworld.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E52C59C08300091322 /* overworld.cc */; }; + E318D97A2C59C08300091322 /* overworld.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E52C59C08300091322 /* overworld.cc */; }; + E318D97B2C59C08300091322 /* inventory.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E92C59C08300091322 /* inventory.cc */; }; + E318D97C2C59C08300091322 /* inventory.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8E92C59C08300091322 /* inventory.cc */; }; + E318D97D2C59C08300091322 /* title_screen.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8EB2C59C08300091322 /* title_screen.cc */; }; + E318D97E2C59C08300091322 /* title_screen.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8EB2C59C08300091322 /* title_screen.cc */; }; + E318D97F2C59C08300091322 /* sprite.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8EE2C59C08300091322 /* sprite.cc */; }; + E318D9802C59C08300091322 /* sprite.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8EE2C59C08300091322 /* sprite.cc */; }; + E318D9872C59C08300091322 /* rom.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8F62C59C08300091322 /* rom.cc */; }; + E318D9882C59C08300091322 /* rom.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8F62C59C08300091322 /* rom.cc */; }; + E318D98A2C59C08300091322 /* yaze.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D8F82C59C08300091322 /* yaze.cc */; }; + E318D98D2C59CBBB00091322 /* TextEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D98B2C59CBBB00091322 /* TextEditor.cpp */; }; + E318D98E2C59CBBB00091322 /* TextEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D98B2C59CBBB00091322 /* TextEditor.cpp */; }; + E318D9952C59CDF800091322 /* imgui_impl_sdl2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D9942C59CDF800091322 /* imgui_impl_sdl2.cpp */; }; + E318D9962C59CDF800091322 /* imgui_impl_sdl2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D9942C59CDF800091322 /* imgui_impl_sdl2.cpp */; }; + E318D9992C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D9972C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp */; }; + E318D99A2C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D9972C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp */; }; + E318D99D2C59D0E600091322 /* imgui_stdlib.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D99B2C59D0E500091322 /* imgui_stdlib.cpp */; }; + E318D99E2C59D0E600091322 /* imgui_stdlib.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318D99B2C59D0E500091322 /* imgui_stdlib.cpp */; }; + E318DF282C5A4FBD00091322 /* algorithm_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9A32C5A4FBD00091322 /* algorithm_test.cc */; }; + E318DF2E2C5A4FBD00091322 /* container_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9A72C5A4FBD00091322 /* container_test.cc */; }; + E318DF302C5A4FBD00091322 /* equal_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9A92C5A4FBD00091322 /* equal_benchmark.cc */; }; + E318DF322C5A4FBD00091322 /* atomic_hook_test_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9AC2C5A4FBD00091322 /* atomic_hook_test_helper.cc */; }; + E318DF342C5A4FBD00091322 /* atomic_hook_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9AE2C5A4FBD00091322 /* atomic_hook_test.cc */; }; + E318DF362C5A4FBE00091322 /* cmake_thread_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9B02C5A4FBD00091322 /* cmake_thread_test.cc */; }; + E318DF372C5A4FBE00091322 /* cycleclock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9B12C5A4FBD00091322 /* cycleclock.cc */; }; + E318DF382C5A4FBE00091322 /* cycleclock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9B12C5A4FBD00091322 /* cycleclock.cc */; }; + E318DF3A2C5A4FBE00091322 /* endian_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9B52C5A4FBD00091322 /* endian_test.cc */; }; + E318DF3C2C5A4FBE00091322 /* errno_saver_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9B72C5A4FBD00091322 /* errno_saver_test.cc */; }; + E318DF3E2C5A4FBE00091322 /* exception_safety_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9B92C5A4FBD00091322 /* exception_safety_testing.cc */; }; + E318DF402C5A4FBE00091322 /* fast_type_id_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9BC2C5A4FBD00091322 /* fast_type_id_test.cc */; }; + E318DF422C5A4FBE00091322 /* low_level_alloc_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9C32C5A4FBD00091322 /* low_level_alloc_test.cc */; }; + E318DF432C5A4FBE00091322 /* low_level_alloc.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9C42C5A4FBD00091322 /* low_level_alloc.cc */; }; + E318DF442C5A4FBE00091322 /* low_level_alloc.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9C42C5A4FBD00091322 /* low_level_alloc.cc */; }; + E318DF462C5A4FBE00091322 /* prefetch_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9C82C5A4FBD00091322 /* prefetch_test.cc */; }; + E318DF472C5A4FBE00091322 /* raw_logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9CB2C5A4FBD00091322 /* raw_logging.cc */; }; + E318DF482C5A4FBE00091322 /* raw_logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9CB2C5A4FBD00091322 /* raw_logging.cc */; }; + E318DF4A2C5A4FBE00091322 /* scoped_set_env_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9CE2C5A4FBD00091322 /* scoped_set_env_test.cc */; }; + E318DF4B2C5A4FBE00091322 /* scoped_set_env.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9CF2C5A4FBD00091322 /* scoped_set_env.cc */; }; + E318DF4C2C5A4FBE00091322 /* scoped_set_env.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9CF2C5A4FBD00091322 /* scoped_set_env.cc */; }; + E318DF4D2C5A4FBE00091322 /* spinlock_akaros.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D12C5A4FBD00091322 /* spinlock_akaros.inc */; }; + E318DF502C5A4FBE00091322 /* spinlock_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D22C5A4FBD00091322 /* spinlock_benchmark.cc */; }; + E318DF512C5A4FBE00091322 /* spinlock_linux.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D32C5A4FBD00091322 /* spinlock_linux.inc */; }; + E318DF532C5A4FBE00091322 /* spinlock_posix.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D42C5A4FBD00091322 /* spinlock_posix.inc */; }; + E318DF552C5A4FBE00091322 /* spinlock_wait.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D52C5A4FBD00091322 /* spinlock_wait.cc */; }; + E318DF562C5A4FBE00091322 /* spinlock_wait.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D52C5A4FBD00091322 /* spinlock_wait.cc */; }; + E318DF572C5A4FBE00091322 /* spinlock_win32.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D72C5A4FBD00091322 /* spinlock_win32.inc */; }; + E318DF592C5A4FBE00091322 /* spinlock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D82C5A4FBD00091322 /* spinlock.cc */; }; + E318DF5A2C5A4FBE00091322 /* spinlock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9D82C5A4FBD00091322 /* spinlock.cc */; }; + E318DF5C2C5A4FBE00091322 /* strerror_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9DA2C5A4FBD00091322 /* strerror_benchmark.cc */; }; + E318DF5E2C5A4FBE00091322 /* strerror_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9DB2C5A4FBD00091322 /* strerror_test.cc */; }; + E318DF5F2C5A4FBE00091322 /* strerror.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9DC2C5A4FBD00091322 /* strerror.cc */; }; + E318DF602C5A4FBE00091322 /* strerror.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9DC2C5A4FBD00091322 /* strerror.cc */; }; + E318DF622C5A4FBE00091322 /* sysinfo_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9DE2C5A4FBD00091322 /* sysinfo_test.cc */; }; + E318DF632C5A4FBE00091322 /* sysinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9DF2C5A4FBD00091322 /* sysinfo.cc */; }; + E318DF642C5A4FBE00091322 /* sysinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9DF2C5A4FBD00091322 /* sysinfo.cc */; }; + E318DF662C5A4FBE00091322 /* thread_identity_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9E22C5A4FBD00091322 /* thread_identity_benchmark.cc */; }; + E318DF682C5A4FBE00091322 /* thread_identity_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9E32C5A4FBD00091322 /* thread_identity_test.cc */; }; + E318DF692C5A4FBE00091322 /* thread_identity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9E42C5A4FBD00091322 /* thread_identity.cc */; }; + E318DF6A2C5A4FBE00091322 /* thread_identity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9E42C5A4FBD00091322 /* thread_identity.cc */; }; + E318DF6B2C5A4FBE00091322 /* throw_delegate.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9E62C5A4FBD00091322 /* throw_delegate.cc */; }; + E318DF6C2C5A4FBE00091322 /* throw_delegate.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9E62C5A4FBD00091322 /* throw_delegate.cc */; }; + E318DF6E2C5A4FBE00091322 /* unique_small_name_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9EA2C5A4FBD00091322 /* unique_small_name_test.cc */; }; + E318DF6F2C5A4FBE00091322 /* unscaledcycleclock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9EB2C5A4FBD00091322 /* unscaledcycleclock.cc */; }; + E318DF702C5A4FBE00091322 /* unscaledcycleclock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9EB2C5A4FBD00091322 /* unscaledcycleclock.cc */; }; + E318DF722C5A4FBE00091322 /* bit_cast_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9EF2C5A4FBD00091322 /* bit_cast_test.cc */; }; + E318DF762C5A4FBE00091322 /* call_once_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9F12C5A4FBD00091322 /* call_once_test.cc */; }; + E318DF7A2C5A4FBE00091322 /* config_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9F52C5A4FBD00091322 /* config_test.cc */; }; + E318DF7C2C5A4FBE00091322 /* exception_safety_testing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9F92C5A4FBD00091322 /* exception_safety_testing_test.cc */; }; + E318DF7E2C5A4FBE00091322 /* inline_variable_test_a.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9FA2C5A4FBD00091322 /* inline_variable_test_a.cc */; }; + E318DF802C5A4FBE00091322 /* inline_variable_test_b.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9FB2C5A4FBD00091322 /* inline_variable_test_b.cc */; }; + E318DF822C5A4FBE00091322 /* inline_variable_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9FC2C5A4FBD00091322 /* inline_variable_test.cc */; }; + E318DF842C5A4FBE00091322 /* invoke_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9FD2C5A4FBD00091322 /* invoke_test.cc */; }; + E318DF862C5A4FBE00091322 /* log_severity_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9FE2C5A4FBD00091322 /* log_severity_test.cc */; }; + E318DF872C5A4FBE00091322 /* log_severity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9FF2C5A4FBD00091322 /* log_severity.cc */; }; + E318DF882C5A4FBE00091322 /* log_severity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318D9FF2C5A4FBD00091322 /* log_severity.cc */; }; + E318DF8A2C5A4FBE00091322 /* optimization_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA022C5A4FBD00091322 /* optimization_test.cc */; }; + E318DF8C2C5A4FBE00091322 /* raw_logging_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA072C5A4FBD00091322 /* raw_logging_test.cc */; }; + E318DF8E2C5A4FBE00091322 /* spinlock_test_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA082C5A4FBD00091322 /* spinlock_test_common.cc */; }; + E318DF902C5A4FBE00091322 /* throw_delegate_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA0A2C5A4FBD00091322 /* throw_delegate_test.cc */; }; + E318DF942C5A4FBE00091322 /* cleanup_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA102C5A4FBD00091322 /* cleanup_test.cc */; }; + E318DF982C5A4FBE00091322 /* compressed_tuple_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA192C5A4FBD00091322 /* compressed_tuple_test.cc */; }; + E318DF9A2C5A4FBE00091322 /* container_memory_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA1B2C5A4FBD00091322 /* container_memory_test.cc */; }; + E318DF9C2C5A4FBE00091322 /* hash_function_defaults_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA1E2C5A4FBD00091322 /* hash_function_defaults_test.cc */; }; + E318DF9E2C5A4FBE00091322 /* hash_generator_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA202C5A4FBD00091322 /* hash_generator_testing.cc */; }; + E318DFA02C5A4FBE00091322 /* hash_policy_testing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA222C5A4FBD00091322 /* hash_policy_testing_test.cc */; }; + E318DFA22C5A4FBE00091322 /* hash_policy_traits_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA242C5A4FBD00091322 /* hash_policy_traits_test.cc */; }; + E318DFA32C5A4FBE00091322 /* hashtablez_sampler_force_weak_definition.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA282C5A4FBD00091322 /* hashtablez_sampler_force_weak_definition.cc */; }; + E318DFA42C5A4FBE00091322 /* hashtablez_sampler_force_weak_definition.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA282C5A4FBD00091322 /* hashtablez_sampler_force_weak_definition.cc */; }; + E318DFA62C5A4FBE00091322 /* hashtablez_sampler_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA292C5A4FBD00091322 /* hashtablez_sampler_test.cc */; }; + E318DFA72C5A4FBE00091322 /* hashtablez_sampler.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA2A2C5A4FBD00091322 /* hashtablez_sampler.cc */; }; + E318DFA82C5A4FBE00091322 /* hashtablez_sampler.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA2A2C5A4FBD00091322 /* hashtablez_sampler.cc */; }; + E318DFAA2C5A4FBE00091322 /* layout_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA2D2C5A4FBD00091322 /* layout_benchmark.cc */; }; + E318DFAC2C5A4FBE00091322 /* layout_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA2E2C5A4FBD00091322 /* layout_test.cc */; }; + E318DFAE2C5A4FBE00091322 /* node_slot_policy_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA302C5A4FBD00091322 /* node_slot_policy_test.cc */; }; + E318DFB02C5A4FBE00091322 /* raw_hash_set_allocator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA332C5A4FBD00091322 /* raw_hash_set_allocator_test.cc */; }; + E318DFB22C5A4FBE00091322 /* raw_hash_set_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA342C5A4FBD00091322 /* raw_hash_set_benchmark.cc */; }; + E318DFB42C5A4FBE00091322 /* raw_hash_set_probe_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA352C5A4FBD00091322 /* raw_hash_set_probe_benchmark.cc */; }; + E318DFB62C5A4FBE00091322 /* raw_hash_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA362C5A4FBD00091322 /* raw_hash_set_test.cc */; }; + E318DFB72C5A4FBE00091322 /* raw_hash_set.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA372C5A4FBD00091322 /* raw_hash_set.cc */; }; + E318DFB82C5A4FBE00091322 /* raw_hash_set.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA372C5A4FBD00091322 /* raw_hash_set.cc */; }; + E318DFBA2C5A4FBE00091322 /* test_instance_tracker_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA392C5A4FBD00091322 /* test_instance_tracker_test.cc */; }; + E318DFBC2C5A4FBE00091322 /* test_instance_tracker.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA3A2C5A4FBD00091322 /* test_instance_tracker.cc */; }; + E318DFBE2C5A4FBE00091322 /* unordered_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA412C5A4FBD00091322 /* unordered_map_test.cc */; }; + E318DFC02C5A4FBE00091322 /* unordered_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA462C5A4FBD00091322 /* unordered_set_test.cc */; }; + E318DFC22C5A4FBE00091322 /* btree_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA482C5A4FBD00091322 /* btree_benchmark.cc */; }; + E318DFC42C5A4FBE00091322 /* btree_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA4B2C5A4FBD00091322 /* btree_test.cc */; }; + E318DFCA2C5A4FBE00091322 /* fixed_array_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA4F2C5A4FBD00091322 /* fixed_array_benchmark.cc */; }; + E318DFCC2C5A4FBE00091322 /* fixed_array_exception_safety_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA502C5A4FBD00091322 /* fixed_array_exception_safety_test.cc */; }; + E318DFCE2C5A4FBF00091322 /* fixed_array_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA512C5A4FBD00091322 /* fixed_array_test.cc */; }; + E318DFD02C5A4FBF00091322 /* flat_hash_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA532C5A4FBD00091322 /* flat_hash_map_test.cc */; }; + E318DFD22C5A4FBF00091322 /* flat_hash_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA552C5A4FBD00091322 /* flat_hash_set_test.cc */; }; + E318DFD42C5A4FBF00091322 /* inlined_vector_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA572C5A4FBD00091322 /* inlined_vector_benchmark.cc */; }; + E318DFD62C5A4FBF00091322 /* inlined_vector_exception_safety_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA582C5A4FBD00091322 /* inlined_vector_exception_safety_test.cc */; }; + E318DFD82C5A4FBF00091322 /* inlined_vector_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA592C5A4FBD00091322 /* inlined_vector_test.cc */; }; + E318DFDA2C5A4FBF00091322 /* node_hash_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA5B2C5A4FBD00091322 /* node_hash_map_test.cc */; }; + E318DFDC2C5A4FBF00091322 /* node_hash_set_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA5D2C5A4FBD00091322 /* node_hash_set_test.cc */; }; + E318DFDE2C5A4FBF00091322 /* sample_element_size_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA5F2C5A4FBD00091322 /* sample_element_size_test.cc */; }; + E318DFEB2C5A4FBF00091322 /* address_is_readable.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA692C5A4FBD00091322 /* address_is_readable.cc */; }; + E318DFEC2C5A4FBF00091322 /* address_is_readable.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA692C5A4FBD00091322 /* address_is_readable.cc */; }; + E318DFEE2C5A4FBF00091322 /* demangle_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA6B2C5A4FBD00091322 /* demangle_test.cc */; }; + E318DFEF2C5A4FBF00091322 /* demangle.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA6C2C5A4FBD00091322 /* demangle.cc */; }; + E318DFF02C5A4FBF00091322 /* demangle.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA6C2C5A4FBD00091322 /* demangle.cc */; }; + E318DFF12C5A4FBF00091322 /* elf_mem_image.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA6E2C5A4FBD00091322 /* elf_mem_image.cc */; }; + E318DFF22C5A4FBF00091322 /* elf_mem_image.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA6E2C5A4FBD00091322 /* elf_mem_image.cc */; }; + E318DFF32C5A4FBF00091322 /* examine_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA702C5A4FBD00091322 /* examine_stack.cc */; }; + E318DFF42C5A4FBF00091322 /* examine_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA702C5A4FBD00091322 /* examine_stack.cc */; }; + E318DFF62C5A4FBF00091322 /* stack_consumption_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA722C5A4FBD00091322 /* stack_consumption_test.cc */; }; + E318DFF72C5A4FBF00091322 /* stack_consumption.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA732C5A4FBD00091322 /* stack_consumption.cc */; }; + E318DFF82C5A4FBF00091322 /* stack_consumption.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA732C5A4FBD00091322 /* stack_consumption.cc */; }; + E318DFF92C5A4FBF00091322 /* stacktrace_aarch64-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA752C5A4FBD00091322 /* stacktrace_aarch64-inl.inc */; }; + E318DFFB2C5A4FBF00091322 /* stacktrace_arm-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA762C5A4FBD00091322 /* stacktrace_arm-inl.inc */; }; + E318DFFD2C5A4FBF00091322 /* stacktrace_emscripten-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA782C5A4FBD00091322 /* stacktrace_emscripten-inl.inc */; }; + E318DFFF2C5A4FBF00091322 /* stacktrace_generic-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA792C5A4FBD00091322 /* stacktrace_generic-inl.inc */; }; + E318E0012C5A4FBF00091322 /* stacktrace_powerpc-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA7A2C5A4FBD00091322 /* stacktrace_powerpc-inl.inc */; }; + E318E0032C5A4FBF00091322 /* stacktrace_riscv-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA7B2C5A4FBD00091322 /* stacktrace_riscv-inl.inc */; }; + E318E0052C5A4FBF00091322 /* stacktrace_unimplemented-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA7C2C5A4FBD00091322 /* stacktrace_unimplemented-inl.inc */; }; + E318E0072C5A4FBF00091322 /* stacktrace_win32-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA7D2C5A4FBD00091322 /* stacktrace_win32-inl.inc */; }; + E318E0092C5A4FBF00091322 /* stacktrace_x86-inl.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA7E2C5A4FBD00091322 /* stacktrace_x86-inl.inc */; }; + E318E00B2C5A4FBF00091322 /* vdso_support.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA802C5A4FBD00091322 /* vdso_support.cc */; }; + E318E00C2C5A4FBF00091322 /* vdso_support.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA802C5A4FBD00091322 /* vdso_support.cc */; }; + E318E0122C5A4FBF00091322 /* failure_signal_handler_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA852C5A4FBD00091322 /* failure_signal_handler_test.cc */; }; + E318E0132C5A4FBF00091322 /* failure_signal_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA862C5A4FBD00091322 /* failure_signal_handler.cc */; }; + E318E0142C5A4FBF00091322 /* failure_signal_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA862C5A4FBD00091322 /* failure_signal_handler.cc */; }; + E318E0162C5A4FBF00091322 /* leak_check_fail_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA882C5A4FBD00091322 /* leak_check_fail_test.cc */; }; + E318E0182C5A4FBF00091322 /* leak_check_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA892C5A4FBD00091322 /* leak_check_test.cc */; }; + E318E0192C5A4FBF00091322 /* leak_check.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA8A2C5A4FBD00091322 /* leak_check.cc */; }; + E318E01A2C5A4FBF00091322 /* leak_check.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA8A2C5A4FBD00091322 /* leak_check.cc */; }; + E318E01C2C5A4FBF00091322 /* stacktrace_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA8C2C5A4FBD00091322 /* stacktrace_benchmark.cc */; }; + E318E01D2C5A4FBF00091322 /* stacktrace.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA8D2C5A4FBD00091322 /* stacktrace.cc */; }; + E318E01E2C5A4FBF00091322 /* stacktrace.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA8D2C5A4FBD00091322 /* stacktrace.cc */; }; + E318E01F2C5A4FBF00091322 /* symbolize_darwin.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA8F2C5A4FBD00091322 /* symbolize_darwin.inc */; }; + E318E0212C5A4FBF00091322 /* symbolize_elf.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA902C5A4FBD00091322 /* symbolize_elf.inc */; }; + E318E0232C5A4FBF00091322 /* symbolize_emscripten.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA912C5A4FBD00091322 /* symbolize_emscripten.inc */; }; + E318E0262C5A4FBF00091322 /* symbolize_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA922C5A4FBD00091322 /* symbolize_test.cc */; }; + E318E0272C5A4FBF00091322 /* symbolize_unimplemented.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA932C5A4FBD00091322 /* symbolize_unimplemented.inc */; }; + E318E0292C5A4FBF00091322 /* symbolize_win32.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA942C5A4FBD00091322 /* symbolize_win32.inc */; }; + E318E02B2C5A4FBF00091322 /* symbolize.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA952C5A4FBD00091322 /* symbolize.cc */; }; + E318E02C2C5A4FBF00091322 /* symbolize.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA952C5A4FBD00091322 /* symbolize.cc */; }; + E318E02D2C5A4FBF00091322 /* commandlineflag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA992C5A4FBD00091322 /* commandlineflag.cc */; }; + E318E02E2C5A4FBF00091322 /* commandlineflag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA992C5A4FBD00091322 /* commandlineflag.cc */; }; + E318E02F2C5A4FBF00091322 /* flag_msvc.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA9B2C5A4FBD00091322 /* flag_msvc.inc */; }; + E318E0312C5A4FBF00091322 /* flag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA9C2C5A4FBD00091322 /* flag.cc */; }; + E318E0322C5A4FBF00091322 /* flag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA9C2C5A4FBD00091322 /* flag.cc */; }; + E318E0342C5A4FBF00091322 /* path_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DA9F2C5A4FBD00091322 /* path_util_test.cc */; }; + E318E0352C5A4FBF00091322 /* private_handle_accessor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAA12C5A4FBD00091322 /* private_handle_accessor.cc */; }; + E318E0362C5A4FBF00091322 /* private_handle_accessor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAA12C5A4FBD00091322 /* private_handle_accessor.cc */; }; + E318E0382C5A4FBF00091322 /* program_name_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAA32C5A4FBD00091322 /* program_name_test.cc */; }; + E318E0392C5A4FBF00091322 /* program_name.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAA42C5A4FBD00091322 /* program_name.cc */; }; + E318E03A2C5A4FBF00091322 /* program_name.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAA42C5A4FBD00091322 /* program_name.cc */; }; + E318E03C2C5A4FBF00091322 /* sequence_lock_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAA72C5A4FBD00091322 /* sequence_lock_test.cc */; }; + E318E03E2C5A4FBF00091322 /* usage_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAA92C5A4FBD00091322 /* usage_test.cc */; }; + E318E03F2C5A4FBF00091322 /* usage.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAAA2C5A4FBD00091322 /* usage.cc */; }; + E318E0402C5A4FBF00091322 /* usage.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAAA2C5A4FBD00091322 /* usage.cc */; }; + E318E0462C5A4FBF00091322 /* commandlineflag_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAAF2C5A4FBD00091322 /* commandlineflag_test.cc */; }; + E318E0472C5A4FBF00091322 /* commandlineflag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB02C5A4FBD00091322 /* commandlineflag.cc */; }; + E318E0482C5A4FBF00091322 /* commandlineflag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB02C5A4FBD00091322 /* commandlineflag.cc */; }; + E318E04A2C5A4FBF00091322 /* config_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB22C5A4FBD00091322 /* config_test.cc */; }; + E318E04C2C5A4FBF00091322 /* flag_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB52C5A4FBD00091322 /* flag_benchmark.cc */; }; + E318E0502C5A4FBF00091322 /* flag_test_defs.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB72C5A4FBD00091322 /* flag_test_defs.cc */; }; + E318E0522C5A4FBF00091322 /* flag_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB82C5A4FBD00091322 /* flag_test.cc */; }; + E318E0532C5A4FBF00091322 /* flag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB92C5A4FBD00091322 /* flag.cc */; }; + E318E0542C5A4FBF00091322 /* flag.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAB92C5A4FBD00091322 /* flag.cc */; }; + E318E0562C5A4FBF00091322 /* marshalling_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DABB2C5A4FBD00091322 /* marshalling_test.cc */; }; + E318E0572C5A4FBF00091322 /* marshalling.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DABC2C5A4FBD00091322 /* marshalling.cc */; }; + E318E0582C5A4FBF00091322 /* marshalling.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DABC2C5A4FBD00091322 /* marshalling.cc */; }; + E318E05A2C5A4FBF00091322 /* parse_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DABE2C5A4FBD00091322 /* parse_test.cc */; }; + E318E05B2C5A4FBF00091322 /* parse.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DABF2C5A4FBD00091322 /* parse.cc */; }; + E318E05C2C5A4FBF00091322 /* parse.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DABF2C5A4FBD00091322 /* parse.cc */; }; + E318E05E2C5A4FBF00091322 /* reflection_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC12C5A4FBD00091322 /* reflection_test.cc */; }; + E318E05F2C5A4FBF00091322 /* reflection.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC22C5A4FBD00091322 /* reflection.cc */; }; + E318E0602C5A4FBF00091322 /* reflection.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC22C5A4FBD00091322 /* reflection.cc */; }; + E318E0622C5A4FBF00091322 /* usage_config_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC42C5A4FBD00091322 /* usage_config_test.cc */; }; + E318E0632C5A4FBF00091322 /* usage_config.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC52C5A4FBD00091322 /* usage_config.cc */; }; + E318E0642C5A4FBF00091322 /* usage_config.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC52C5A4FBD00091322 /* usage_config.cc */; }; + E318E0652C5A4FBF00091322 /* usage.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC72C5A4FBD00091322 /* usage.cc */; }; + E318E0662C5A4FBF00091322 /* usage.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAC72C5A4FBD00091322 /* usage.cc */; }; + E318E0682C5A4FC000091322 /* any_invocable_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DACF2C5A4FBD00091322 /* any_invocable_test.cc */; }; + E318E06A2C5A4FC000091322 /* bind_front_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAD12C5A4FBD00091322 /* bind_front_test.cc */; }; + E318E0702C5A4FC000091322 /* function_ref_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAD52C5A4FBD00091322 /* function_ref_test.cc */; }; + E318E0722C5A4FC000091322 /* function_type_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAD72C5A4FBD00091322 /* function_type_benchmark.cc */; }; + E318E0742C5A4FC000091322 /* city_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DADA2C5A4FBD00091322 /* city_test.cc */; }; + E318E0752C5A4FC000091322 /* city.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DADB2C5A4FBD00091322 /* city.cc */; }; + E318E0762C5A4FC000091322 /* city.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DADB2C5A4FBD00091322 /* city.cc */; }; + E318E0772C5A4FC000091322 /* hash.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DADD2C5A4FBD00091322 /* hash.cc */; }; + E318E0782C5A4FC000091322 /* hash.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DADD2C5A4FBD00091322 /* hash.cc */; }; + E318E07A2C5A4FC000091322 /* low_level_hash_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DADF2C5A4FBD00091322 /* low_level_hash_test.cc */; }; + E318E07B2C5A4FC000091322 /* low_level_hash.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAE02C5A4FBD00091322 /* low_level_hash.cc */; }; + E318E07C2C5A4FC000091322 /* low_level_hash.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAE02C5A4FBD00091322 /* low_level_hash.cc */; }; + E318E07E2C5A4FC000091322 /* print_hash_of.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAE22C5A4FBD00091322 /* print_hash_of.cc */; }; + E318E0842C5A4FC000091322 /* hash_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAE72C5A4FBD00091322 /* hash_benchmark.cc */; }; + E318E0862C5A4FC000091322 /* hash_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAE82C5A4FBD00091322 /* hash_test.cc */; }; + E318E08C2C5A4FC000091322 /* memory_exception_safety_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAEF2C5A4FBD00091322 /* memory_exception_safety_test.cc */; }; + E318E08E2C5A4FC000091322 /* memory_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAF02C5A4FBD00091322 /* memory_test.cc */; }; + E318E0942C5A4FC000091322 /* type_traits_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAF62C5A4FBD00091322 /* type_traits_test.cc */; }; + E318E0962C5A4FC000091322 /* bits_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAFD2C5A4FBD00091322 /* bits_benchmark.cc */; }; + E318E0982C5A4FC000091322 /* bits_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DAFE2C5A4FBD00091322 /* bits_test.cc */; }; + E318E09E2C5A4FC000091322 /* int128_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB022C5A4FBD00091322 /* int128_benchmark.cc */; }; + E318E09F2C5A4FC000091322 /* int128_have_intrinsic.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB032C5A4FBD00091322 /* int128_have_intrinsic.inc */; }; + E318E0A12C5A4FC000091322 /* int128_no_intrinsic.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB042C5A4FBD00091322 /* int128_no_intrinsic.inc */; }; + E318E0A42C5A4FC000091322 /* int128_stream_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB052C5A4FBD00091322 /* int128_stream_test.cc */; }; + E318E0A62C5A4FC000091322 /* int128_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB062C5A4FBD00091322 /* int128_test.cc */; }; + E318E0A72C5A4FC000091322 /* int128.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB072C5A4FBD00091322 /* int128.cc */; }; + E318E0A82C5A4FC000091322 /* int128.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB072C5A4FBD00091322 /* int128.cc */; }; + E318E0AA2C5A4FC000091322 /* exponential_biased_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB0B2C5A4FBD00091322 /* exponential_biased_test.cc */; }; + E318E0AB2C5A4FC000091322 /* exponential_biased.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB0C2C5A4FBD00091322 /* exponential_biased.cc */; }; + E318E0AC2C5A4FC000091322 /* exponential_biased.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB0C2C5A4FBD00091322 /* exponential_biased.cc */; }; + E318E0AE2C5A4FC000091322 /* periodic_sampler_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB0E2C5A4FBD00091322 /* periodic_sampler_benchmark.cc */; }; + E318E0B02C5A4FC000091322 /* periodic_sampler_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB0F2C5A4FBD00091322 /* periodic_sampler_test.cc */; }; + E318E0B12C5A4FC000091322 /* periodic_sampler.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB102C5A4FBD00091322 /* periodic_sampler.cc */; }; + E318E0B22C5A4FC000091322 /* periodic_sampler.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB102C5A4FBD00091322 /* periodic_sampler.cc */; }; + E318E0B42C5A4FC000091322 /* sample_recorder_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB122C5A4FBD00091322 /* sample_recorder_test.cc */; }; + E318E0BC2C5A4FC000091322 /* chi_square_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB1A2C5A4FBD00091322 /* chi_square_test.cc */; }; + E318E0BD2C5A4FC000091322 /* chi_square.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB1B2C5A4FBD00091322 /* chi_square.cc */; }; + E318E0BE2C5A4FC000091322 /* chi_square.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB1B2C5A4FBD00091322 /* chi_square.cc */; }; + E318E0C02C5A4FC000091322 /* distribution_test_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB1E2C5A4FBD00091322 /* distribution_test_util_test.cc */; }; + E318E0C22C5A4FC000091322 /* distribution_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB1F2C5A4FBD00091322 /* distribution_test_util.cc */; }; + E318E0C42C5A4FC000091322 /* explicit_seed_seq_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB212C5A4FBD00091322 /* explicit_seed_seq_test.cc */; }; + E318E0C62C5A4FC000091322 /* fast_uniform_bits_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB232C5A4FBD00091322 /* fast_uniform_bits_test.cc */; }; + E318E0C82C5A4FC000091322 /* fastmath_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB252C5A4FBD00091322 /* fastmath_test.cc */; }; + E318E0CA2C5A4FC000091322 /* gaussian_distribution_gentables.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB272C5A4FBD00091322 /* gaussian_distribution_gentables.cc */; }; + E318E0CC2C5A4FC000091322 /* generate_real_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB282C5A4FBD00091322 /* generate_real_test.cc */; }; + E318E0CE2C5A4FC000091322 /* iostream_state_saver_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB2A2C5A4FBD00091322 /* iostream_state_saver_test.cc */; }; + E318E0D02C5A4FC000091322 /* nanobenchmark_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB2E2C5A4FBD00091322 /* nanobenchmark_test.cc */; }; + E318E0D22C5A4FC000091322 /* nanobenchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB2F2C5A4FBD00091322 /* nanobenchmark.cc */; }; + E318E0D42C5A4FC000091322 /* nonsecure_base_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB312C5A4FBD00091322 /* nonsecure_base_test.cc */; }; + E318E0D62C5A4FC000091322 /* pcg_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB332C5A4FBD00091322 /* pcg_engine_test.cc */; }; + E318E0D82C5A4FC000091322 /* pool_urbg_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB362C5A4FBD00091322 /* pool_urbg_test.cc */; }; + E318E0D92C5A4FC000091322 /* pool_urbg.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB372C5A4FBD00091322 /* pool_urbg.cc */; }; + E318E0DA2C5A4FC000091322 /* pool_urbg.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB372C5A4FBD00091322 /* pool_urbg.cc */; }; + E318E0DC2C5A4FC000091322 /* randen_benchmarks.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB392C5A4FBD00091322 /* randen_benchmarks.cc */; }; + E318E0DD2C5A4FC000091322 /* randen_detect.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB3A2C5A4FBD00091322 /* randen_detect.cc */; }; + E318E0DE2C5A4FC000091322 /* randen_detect.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB3A2C5A4FBD00091322 /* randen_detect.cc */; }; + E318E0E02C5A4FC000091322 /* randen_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB3C2C5A4FBD00091322 /* randen_engine_test.cc */; }; + E318E0E22C5A4FC000091322 /* randen_hwaes_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB3E2C5A4FBD00091322 /* randen_hwaes_test.cc */; }; + E318E0E32C5A4FC000091322 /* randen_hwaes.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB3F2C5A4FBD00091322 /* randen_hwaes.cc */; }; + E318E0E42C5A4FC000091322 /* randen_hwaes.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB3F2C5A4FBD00091322 /* randen_hwaes.cc */; }; + E318E0E52C5A4FC000091322 /* randen_round_keys.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB412C5A4FBD00091322 /* randen_round_keys.cc */; }; + E318E0E62C5A4FC000091322 /* randen_round_keys.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB412C5A4FBD00091322 /* randen_round_keys.cc */; }; + E318E0E82C5A4FC000091322 /* randen_slow_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB422C5A4FBD00091322 /* randen_slow_test.cc */; }; + E318E0E92C5A4FC000091322 /* randen_slow.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB432C5A4FBD00091322 /* randen_slow.cc */; }; + E318E0EA2C5A4FC000091322 /* randen_slow.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB432C5A4FBD00091322 /* randen_slow.cc */; }; + E318E0EC2C5A4FC000091322 /* randen_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB452C5A4FBD00091322 /* randen_test.cc */; }; + E318E0ED2C5A4FC000091322 /* randen.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB472C5A4FBD00091322 /* randen.cc */; }; + E318E0EE2C5A4FC000091322 /* randen.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB472C5A4FBD00091322 /* randen.cc */; }; + E318E0F02C5A4FC000091322 /* salted_seed_seq_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB492C5A4FBD00091322 /* salted_seed_seq_test.cc */; }; + E318E0F22C5A4FC000091322 /* seed_material_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB4B2C5A4FBD00091322 /* seed_material_test.cc */; }; + E318E0F32C5A4FC000091322 /* seed_material.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB4C2C5A4FBD00091322 /* seed_material.cc */; }; + E318E0F42C5A4FC000091322 /* seed_material.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB4C2C5A4FBD00091322 /* seed_material.cc */; }; + E318E0F62C5A4FC000091322 /* traits_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB4F2C5A4FBD00091322 /* traits_test.cc */; }; + E318E0F82C5A4FC000091322 /* uniform_helper_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB512C5A4FBD00091322 /* uniform_helper_test.cc */; }; + E318E0FA2C5A4FC000091322 /* wide_multiply_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB532C5A4FBD00091322 /* wide_multiply_test.cc */; }; + E318E0FC2C5A4FC000091322 /* benchmarks.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB562C5A4FBD00091322 /* benchmarks.cc */; }; + E318E0FE2C5A4FC000091322 /* bernoulli_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB572C5A4FBD00091322 /* bernoulli_distribution_test.cc */; }; + E318E1002C5A4FC000091322 /* beta_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB592C5A4FBD00091322 /* beta_distribution_test.cc */; }; + E318E1022C5A4FC000091322 /* bit_gen_ref_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB5B2C5A4FBD00091322 /* bit_gen_ref_test.cc */; }; + E318E1082C5A4FC100091322 /* discrete_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB5F2C5A4FBD00091322 /* discrete_distribution_test.cc */; }; + E318E1092C5A4FC100091322 /* discrete_distribution.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB602C5A4FBD00091322 /* discrete_distribution.cc */; }; + E318E10A2C5A4FC100091322 /* discrete_distribution.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB602C5A4FBD00091322 /* discrete_distribution.cc */; }; + E318E10C2C5A4FC100091322 /* distributions_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB622C5A4FBD00091322 /* distributions_test.cc */; }; + E318E10E2C5A4FC100091322 /* examples_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB642C5A4FBD00091322 /* examples_test.cc */; }; + E318E1102C5A4FC100091322 /* exponential_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB652C5A4FBD00091322 /* exponential_distribution_test.cc */; }; + E318E1122C5A4FC100091322 /* gaussian_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB672C5A4FBD00091322 /* gaussian_distribution_test.cc */; }; + E318E1132C5A4FC100091322 /* gaussian_distribution.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB682C5A4FBD00091322 /* gaussian_distribution.cc */; }; + E318E1142C5A4FC100091322 /* gaussian_distribution.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB682C5A4FBD00091322 /* gaussian_distribution.cc */; }; + E318E1162C5A4FC100091322 /* generators_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB6A2C5A4FBD00091322 /* generators_test.cc */; }; + E318E1182C5A4FC100091322 /* log_uniform_int_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB6B2C5A4FBD00091322 /* log_uniform_int_distribution_test.cc */; }; + E318E11A2C5A4FC100091322 /* mock_distributions_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB6D2C5A4FBD00091322 /* mock_distributions_test.cc */; }; + E318E11C2C5A4FC100091322 /* mocking_bit_gen_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB6F2C5A4FBD00091322 /* mocking_bit_gen_test.cc */; }; + E318E11E2C5A4FC100091322 /* poisson_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB712C5A4FBD00091322 /* poisson_distribution_test.cc */; }; + E318E11F2C5A4FC100091322 /* seed_gen_exception.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB742C5A4FBD00091322 /* seed_gen_exception.cc */; }; + E318E1202C5A4FC100091322 /* seed_gen_exception.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB742C5A4FBD00091322 /* seed_gen_exception.cc */; }; + E318E1222C5A4FC100091322 /* seed_sequences_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB762C5A4FBD00091322 /* seed_sequences_test.cc */; }; + E318E1232C5A4FC100091322 /* seed_sequences.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB772C5A4FBD00091322 /* seed_sequences.cc */; }; + E318E1242C5A4FC100091322 /* seed_sequences.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB772C5A4FBD00091322 /* seed_sequences.cc */; }; + E318E1262C5A4FC100091322 /* uniform_int_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB792C5A4FBD00091322 /* uniform_int_distribution_test.cc */; }; + E318E1282C5A4FC100091322 /* uniform_real_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB7B2C5A4FBD00091322 /* uniform_real_distribution_test.cc */; }; + E318E12A2C5A4FC100091322 /* zipf_distribution_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB7D2C5A4FBD00091322 /* zipf_distribution_test.cc */; }; + E318E12F2C5A4FC100091322 /* status_payload_printer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB862C5A4FBD00091322 /* status_payload_printer.cc */; }; + E318E1302C5A4FC100091322 /* status_payload_printer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB862C5A4FBD00091322 /* status_payload_printer.cc */; }; + E318E1322C5A4FC100091322 /* status_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB882C5A4FBD00091322 /* status_test.cc */; }; + E318E1332C5A4FC100091322 /* status.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB892C5A4FBD00091322 /* status.cc */; }; + E318E1342C5A4FC100091322 /* status.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB892C5A4FBD00091322 /* status.cc */; }; + E318E1362C5A4FC100091322 /* statusor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB8B2C5A4FBD00091322 /* statusor_test.cc */; }; + E318E1372C5A4FC100091322 /* statusor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB8C2C5A4FBD00091322 /* statusor.cc */; }; + E318E1382C5A4FC100091322 /* statusor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB8C2C5A4FBD00091322 /* statusor.cc */; }; + E318E13A2C5A4FC100091322 /* arg_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB902C5A4FBD00091322 /* arg_test.cc */; }; + E318E13B2C5A4FC100091322 /* arg.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB912C5A4FBD00091322 /* arg.cc */; }; + E318E13C2C5A4FC100091322 /* arg.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB912C5A4FBD00091322 /* arg.cc */; }; + E318E13E2C5A4FC100091322 /* bind_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB932C5A4FBD00091322 /* bind_test.cc */; }; + E318E13F2C5A4FC100091322 /* bind.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB942C5A4FBD00091322 /* bind.cc */; }; + E318E1402C5A4FC100091322 /* bind.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB942C5A4FBD00091322 /* bind.cc */; }; + E318E1422C5A4FC100091322 /* checker_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB962C5A4FBD00091322 /* checker_test.cc */; }; + E318E1442C5A4FC100091322 /* convert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB982C5A4FBD00091322 /* convert_test.cc */; }; + E318E1462C5A4FC100091322 /* extension_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB992C5A4FBD00091322 /* extension_test.cc */; }; + E318E1472C5A4FC100091322 /* extension.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB9A2C5A4FBD00091322 /* extension.cc */; }; + E318E1482C5A4FC100091322 /* extension.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB9A2C5A4FBD00091322 /* extension.cc */; }; + E318E1492C5A4FC100091322 /* float_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB9C2C5A4FBD00091322 /* float_conversion.cc */; }; + E318E14A2C5A4FC100091322 /* float_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB9C2C5A4FBD00091322 /* float_conversion.cc */; }; + E318E14C2C5A4FC100091322 /* output_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB9E2C5A4FBD00091322 /* output_test.cc */; }; + E318E14D2C5A4FC100091322 /* output.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB9F2C5A4FBD00091322 /* output.cc */; }; + E318E14E2C5A4FC100091322 /* output.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB9F2C5A4FBD00091322 /* output.cc */; }; + E318E1502C5A4FC100091322 /* parser_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA12C5A4FBD00091322 /* parser_test.cc */; }; + E318E1512C5A4FC100091322 /* parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA22C5A4FBD00091322 /* parser.cc */; }; + E318E1522C5A4FC100091322 /* parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA22C5A4FBD00091322 /* parser.cc */; }; + E318E1542C5A4FC100091322 /* char_map_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA52C5A4FBD00091322 /* char_map_benchmark.cc */; }; + E318E1562C5A4FC100091322 /* char_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA62C5A4FBD00091322 /* char_map_test.cc */; }; + E318E1582C5A4FC100091322 /* charconv_bigint_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA82C5A4FBD00091322 /* charconv_bigint_test.cc */; }; + E318E1592C5A4FC100091322 /* charconv_bigint.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA92C5A4FBD00091322 /* charconv_bigint.cc */; }; + E318E15A2C5A4FC100091322 /* charconv_bigint.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBA92C5A4FBD00091322 /* charconv_bigint.cc */; }; + E318E15C2C5A4FC100091322 /* charconv_parse_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBAB2C5A4FBD00091322 /* charconv_parse_test.cc */; }; + E318E15D2C5A4FC100091322 /* charconv_parse.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBAC2C5A4FBD00091322 /* charconv_parse.cc */; }; + E318E15E2C5A4FC100091322 /* charconv_parse.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBAC2C5A4FBD00091322 /* charconv_parse.cc */; }; + E318E1602C5A4FC100091322 /* cord_data_edge_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBAE2C5A4FBD00091322 /* cord_data_edge_test.cc */; }; + E318E1612C5A4FC100091322 /* cord_internal.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB02C5A4FBD00091322 /* cord_internal.cc */; }; + E318E1622C5A4FC100091322 /* cord_internal.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB02C5A4FBD00091322 /* cord_internal.cc */; }; + E318E1642C5A4FC100091322 /* cord_rep_btree_navigator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB22C5A4FBD00091322 /* cord_rep_btree_navigator_test.cc */; }; + E318E1652C5A4FC100091322 /* cord_rep_btree_navigator.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB32C5A4FBD00091322 /* cord_rep_btree_navigator.cc */; }; + E318E1662C5A4FC100091322 /* cord_rep_btree_navigator.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB32C5A4FBD00091322 /* cord_rep_btree_navigator.cc */; }; + E318E1682C5A4FC100091322 /* cord_rep_btree_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB52C5A4FBD00091322 /* cord_rep_btree_reader_test.cc */; }; + E318E1692C5A4FC100091322 /* cord_rep_btree_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB62C5A4FBD00091322 /* cord_rep_btree_reader.cc */; }; + E318E16A2C5A4FC100091322 /* cord_rep_btree_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB62C5A4FBD00091322 /* cord_rep_btree_reader.cc */; }; + E318E16C2C5A4FC100091322 /* cord_rep_btree_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB82C5A4FBD00091322 /* cord_rep_btree_test.cc */; }; + E318E16D2C5A4FC100091322 /* cord_rep_btree.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB92C5A4FBD00091322 /* cord_rep_btree.cc */; }; + E318E16E2C5A4FC100091322 /* cord_rep_btree.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBB92C5A4FBD00091322 /* cord_rep_btree.cc */; }; + E318E16F2C5A4FC100091322 /* cord_rep_consume.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBBB2C5A4FBD00091322 /* cord_rep_consume.cc */; }; + E318E1702C5A4FC100091322 /* cord_rep_consume.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBBB2C5A4FBD00091322 /* cord_rep_consume.cc */; }; + E318E1722C5A4FC100091322 /* cord_rep_crc_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBBD2C5A4FBD00091322 /* cord_rep_crc_test.cc */; }; + E318E1732C5A4FC100091322 /* cord_rep_crc.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBBE2C5A4FBD00091322 /* cord_rep_crc.cc */; }; + E318E1742C5A4FC100091322 /* cord_rep_crc.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBBE2C5A4FBD00091322 /* cord_rep_crc.cc */; }; + E318E1752C5A4FC100091322 /* cord_rep_ring.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC22C5A4FBD00091322 /* cord_rep_ring.cc */; }; + E318E1762C5A4FC100091322 /* cord_rep_ring.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC22C5A4FBD00091322 /* cord_rep_ring.cc */; }; + E318E1782C5A4FC100091322 /* cordz_functions_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC52C5A4FBD00091322 /* cordz_functions_test.cc */; }; + E318E1792C5A4FC100091322 /* cordz_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC62C5A4FBD00091322 /* cordz_functions.cc */; }; + E318E17A2C5A4FC100091322 /* cordz_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC62C5A4FBD00091322 /* cordz_functions.cc */; }; + E318E17C2C5A4FC100091322 /* cordz_handle_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC82C5A4FBD00091322 /* cordz_handle_test.cc */; }; + E318E17D2C5A4FC100091322 /* cordz_handle.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC92C5A4FBD00091322 /* cordz_handle.cc */; }; + E318E17E2C5A4FC100091322 /* cordz_handle.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBC92C5A4FBD00091322 /* cordz_handle.cc */; }; + E318E1802C5A4FC100091322 /* cordz_info_statistics_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBCB2C5A4FBD00091322 /* cordz_info_statistics_test.cc */; }; + E318E1822C5A4FC100091322 /* cordz_info_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBCC2C5A4FBD00091322 /* cordz_info_test.cc */; }; + E318E1832C5A4FC100091322 /* cordz_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBCD2C5A4FBD00091322 /* cordz_info.cc */; }; + E318E1842C5A4FC100091322 /* cordz_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBCD2C5A4FBD00091322 /* cordz_info.cc */; }; + E318E1862C5A4FC100091322 /* cordz_sample_token_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBCF2C5A4FBD00091322 /* cordz_sample_token_test.cc */; }; + E318E1872C5A4FC100091322 /* cordz_sample_token.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBD02C5A4FBD00091322 /* cordz_sample_token.cc */; }; + E318E1882C5A4FC100091322 /* cordz_sample_token.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBD02C5A4FBD00091322 /* cordz_sample_token.cc */; }; + E318E18A2C5A4FC100091322 /* cordz_update_scope_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBD32C5A4FBD00091322 /* cordz_update_scope_test.cc */; }; + E318E18C2C5A4FC100091322 /* cordz_update_tracker_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBD52C5A4FBD00091322 /* cordz_update_tracker_test.cc */; }; + E318E18D2C5A4FC100091322 /* escaping.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBD82C5A4FBD00091322 /* escaping.cc */; }; + E318E18E2C5A4FC100091322 /* escaping.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBD82C5A4FBD00091322 /* escaping.cc */; }; + E318E1902C5A4FC100091322 /* memutil_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBDA2C5A4FBD00091322 /* memutil_benchmark.cc */; }; + E318E1922C5A4FC100091322 /* memutil_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBDB2C5A4FBD00091322 /* memutil_test.cc */; }; + E318E1932C5A4FC100091322 /* memutil.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBDC2C5A4FBD00091322 /* memutil.cc */; }; + E318E1942C5A4FC100091322 /* memutil.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBDC2C5A4FBD00091322 /* memutil.cc */; }; + E318E1962C5A4FC100091322 /* ostringstream_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBDF2C5A4FBD00091322 /* ostringstream_benchmark.cc */; }; + E318E1982C5A4FC100091322 /* ostringstream_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBE02C5A4FBD00091322 /* ostringstream_test.cc */; }; + E318E1992C5A4FC200091322 /* ostringstream.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBE12C5A4FBD00091322 /* ostringstream.cc */; }; + E318E19A2C5A4FC200091322 /* ostringstream.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBE12C5A4FBD00091322 /* ostringstream.cc */; }; + E318E19C2C5A4FC200091322 /* pow10_helper_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBE32C5A4FBD00091322 /* pow10_helper_test.cc */; }; + E318E19D2C5A4FC200091322 /* pow10_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBE42C5A4FBD00091322 /* pow10_helper.cc */; }; + E318E19E2C5A4FC200091322 /* pow10_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBE42C5A4FBD00091322 /* pow10_helper.cc */; }; + E318E1A02C5A4FC200091322 /* resize_uninitialized_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBE62C5A4FBD00091322 /* resize_uninitialized_test.cc */; }; + E318E1A22C5A4FC200091322 /* string_constant_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBEB2C5A4FBD00091322 /* string_constant_test.cc */; }; + E318E1A42C5A4FC200091322 /* utf8_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBED2C5A4FBD00091322 /* utf8_test.cc */; }; + E318E1A52C5A4FC200091322 /* utf8.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBEE2C5A4FBD00091322 /* utf8.cc */; }; + E318E1A62C5A4FC200091322 /* utf8.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBEE2C5A4FBD00091322 /* utf8.cc */; }; + E318E1A82C5A4FC200091322 /* ascii_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF12C5A4FBD00091322 /* ascii_benchmark.cc */; }; + E318E1AA2C5A4FC200091322 /* ascii_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF22C5A4FBD00091322 /* ascii_test.cc */; }; + E318E1AB2C5A4FC200091322 /* ascii.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF32C5A4FBD00091322 /* ascii.cc */; }; + E318E1AC2C5A4FC200091322 /* ascii.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF32C5A4FBD00091322 /* ascii.cc */; }; + E318E1B02C5A4FC200091322 /* charconv_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF62C5A4FBD00091322 /* charconv_benchmark.cc */; }; + E318E1B22C5A4FC200091322 /* charconv_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF72C5A4FBD00091322 /* charconv_test.cc */; }; + E318E1B32C5A4FC200091322 /* charconv.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF82C5A4FBD00091322 /* charconv.cc */; }; + E318E1B42C5A4FC200091322 /* charconv.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBF82C5A4FBD00091322 /* charconv.cc */; }; + E318E1B72C5A4FC200091322 /* cord_analysis.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBFB2C5A4FBD00091322 /* cord_analysis.cc */; }; + E318E1B82C5A4FC200091322 /* cord_analysis.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBFB2C5A4FBD00091322 /* cord_analysis.cc */; }; + E318E1BA2C5A4FC200091322 /* cord_buffer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBFD2C5A4FBD00091322 /* cord_buffer_test.cc */; }; + E318E1BB2C5A4FC200091322 /* cord_buffer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBFE2C5A4FBD00091322 /* cord_buffer.cc */; }; + E318E1BC2C5A4FC200091322 /* cord_buffer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DBFE2C5A4FBD00091322 /* cord_buffer.cc */; }; + E318E1BE2C5A4FC200091322 /* cord_ring_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC002C5A4FBD00091322 /* cord_ring_reader_test.cc */; }; + E318E1C02C5A4FC200091322 /* cord_ring_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC012C5A4FBD00091322 /* cord_ring_test.cc */; }; + E318E1C22C5A4FC200091322 /* cord_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC032C5A4FBD00091322 /* cord_test.cc */; }; + E318E1C32C5A4FC200091322 /* cord.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC042C5A4FBD00091322 /* cord.cc */; }; + E318E1C42C5A4FC200091322 /* cord.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC042C5A4FBD00091322 /* cord.cc */; }; + E318E1C62C5A4FC200091322 /* cordz_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC072C5A4FBD00091322 /* cordz_test.cc */; }; + E318E1C82C5A4FC200091322 /* escaping_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC082C5A4FBD00091322 /* escaping_benchmark.cc */; }; + E318E1CA2C5A4FC200091322 /* escaping_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC092C5A4FBD00091322 /* escaping_test.cc */; }; + E318E1CB2C5A4FC200091322 /* escaping.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC0A2C5A4FBD00091322 /* escaping.cc */; }; + E318E1CC2C5A4FC200091322 /* escaping.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC0A2C5A4FBD00091322 /* escaping.cc */; }; + E318E1CE2C5A4FC200091322 /* match_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC0C2C5A4FBD00091322 /* match_test.cc */; }; + E318E1CF2C5A4FC200091322 /* match.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC0D2C5A4FBD00091322 /* match.cc */; }; + E318E1D02C5A4FC200091322 /* match.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC0D2C5A4FBD00091322 /* match.cc */; }; + E318E1D22C5A4FC200091322 /* numbers_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC0F2C5A4FBD00091322 /* numbers_benchmark.cc */; }; + E318E1D42C5A4FC200091322 /* numbers_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC102C5A4FBD00091322 /* numbers_test.cc */; }; + E318E1D52C5A4FC200091322 /* numbers.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC112C5A4FBD00091322 /* numbers.cc */; }; + E318E1D62C5A4FC200091322 /* numbers.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC112C5A4FBD00091322 /* numbers.cc */; }; + E318E1D82C5A4FC200091322 /* str_cat_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC132C5A4FBD00091322 /* str_cat_benchmark.cc */; }; + E318E1DA2C5A4FC200091322 /* str_cat_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC142C5A4FBD00091322 /* str_cat_test.cc */; }; + E318E1DB2C5A4FC200091322 /* str_cat.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC152C5A4FBD00091322 /* str_cat.cc */; }; + E318E1DC2C5A4FC200091322 /* str_cat.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC152C5A4FBD00091322 /* str_cat.cc */; }; + E318E1DE2C5A4FC200091322 /* str_format_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC172C5A4FBD00091322 /* str_format_test.cc */; }; + E318E1E02C5A4FC200091322 /* str_join_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC192C5A4FBD00091322 /* str_join_benchmark.cc */; }; + E318E1E22C5A4FC200091322 /* str_join_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC1A2C5A4FBD00091322 /* str_join_test.cc */; }; + E318E1E42C5A4FC200091322 /* str_replace_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC1C2C5A4FBD00091322 /* str_replace_benchmark.cc */; }; + E318E1E62C5A4FC200091322 /* str_replace_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC1D2C5A4FBD00091322 /* str_replace_test.cc */; }; + E318E1E72C5A4FC200091322 /* str_replace.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC1E2C5A4FBD00091322 /* str_replace.cc */; }; + E318E1E82C5A4FC200091322 /* str_replace.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC1E2C5A4FBD00091322 /* str_replace.cc */; }; + E318E1EA2C5A4FC200091322 /* str_split_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC202C5A4FBD00091322 /* str_split_benchmark.cc */; }; + E318E1EC2C5A4FC200091322 /* str_split_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC212C5A4FBD00091322 /* str_split_test.cc */; }; + E318E1ED2C5A4FC200091322 /* str_split.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC222C5A4FBD00091322 /* str_split.cc */; }; + E318E1EE2C5A4FC200091322 /* str_split.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC222C5A4FBD00091322 /* str_split.cc */; }; + E318E1F02C5A4FC200091322 /* string_view_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC242C5A4FBD00091322 /* string_view_benchmark.cc */; }; + E318E1F22C5A4FC200091322 /* string_view_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC252C5A4FBD00091322 /* string_view_test.cc */; }; + E318E1F32C5A4FC200091322 /* string_view.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC262C5A4FBD00091322 /* string_view.cc */; }; + E318E1F42C5A4FC200091322 /* string_view.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC262C5A4FBD00091322 /* string_view.cc */; }; + E318E1F62C5A4FC200091322 /* strip_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC282C5A4FBD00091322 /* strip_test.cc */; }; + E318E1F82C5A4FC200091322 /* substitute_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC2A2C5A4FBD00091322 /* substitute_test.cc */; }; + E318E1F92C5A4FC200091322 /* substitute.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC2B2C5A4FBD00091322 /* substitute.cc */; }; + E318E1FA2C5A4FC200091322 /* substitute.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC2B2C5A4FBD00091322 /* substitute.cc */; }; + E318E1FB2C5A4FC200091322 /* create_thread_identity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC2F2C5A4FBD00091322 /* create_thread_identity.cc */; }; + E318E1FC2C5A4FC200091322 /* create_thread_identity.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC2F2C5A4FBD00091322 /* create_thread_identity.cc */; }; + E318E1FE2C5A4FC200091322 /* graphcycles_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC322C5A4FBD00091322 /* graphcycles_benchmark.cc */; }; + E318E2002C5A4FC200091322 /* graphcycles_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC332C5A4FBD00091322 /* graphcycles_test.cc */; }; + E318E2012C5A4FC200091322 /* graphcycles.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC342C5A4FBD00091322 /* graphcycles.cc */; }; + E318E2022C5A4FC200091322 /* graphcycles.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC342C5A4FBD00091322 /* graphcycles.cc */; }; + E318E2042C5A4FC200091322 /* per_thread_sem_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC372C5A4FBD00091322 /* per_thread_sem_test.cc */; }; + E318E2052C5A4FC200091322 /* per_thread_sem.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC382C5A4FBD00091322 /* per_thread_sem.cc */; }; + E318E2062C5A4FC200091322 /* per_thread_sem.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC382C5A4FBD00091322 /* per_thread_sem.cc */; }; + E318E2072C5A4FC200091322 /* waiter.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC3B2C5A4FBD00091322 /* waiter.cc */; }; + E318E2082C5A4FC200091322 /* waiter.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC3B2C5A4FBD00091322 /* waiter.cc */; }; + E318E20A2C5A4FC200091322 /* barrier_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC3E2C5A4FBD00091322 /* barrier_test.cc */; }; + E318E20B2C5A4FC200091322 /* barrier.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC3F2C5A4FBD00091322 /* barrier.cc */; }; + E318E20C2C5A4FC200091322 /* barrier.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC3F2C5A4FBD00091322 /* barrier.cc */; }; + E318E20E2C5A4FC200091322 /* blocking_counter_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC412C5A4FBD00091322 /* blocking_counter_benchmark.cc */; }; + E318E2102C5A4FC200091322 /* blocking_counter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC422C5A4FBD00091322 /* blocking_counter_test.cc */; }; + E318E2112C5A4FC200091322 /* blocking_counter.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC432C5A4FBD00091322 /* blocking_counter.cc */; }; + E318E2122C5A4FC200091322 /* blocking_counter.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC432C5A4FBD00091322 /* blocking_counter.cc */; }; + E318E2182C5A4FC200091322 /* lifetime_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC472C5A4FBD00091322 /* lifetime_test.cc */; }; + E318E21A2C5A4FC200091322 /* mutex_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC482C5A4FBD00091322 /* mutex_benchmark.cc */; }; + E318E21C2C5A4FC200091322 /* mutex_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC492C5A4FBD00091322 /* mutex_test.cc */; }; + E318E21D2C5A4FC200091322 /* mutex.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC4A2C5A4FBD00091322 /* mutex.cc */; }; + E318E21E2C5A4FC200091322 /* mutex.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC4A2C5A4FBD00091322 /* mutex.cc */; }; + E318E2202C5A4FC200091322 /* notification_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC4C2C5A4FBD00091322 /* notification_test.cc */; }; + E318E2212C5A4FC200091322 /* notification.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC4D2C5A4FBD00091322 /* notification.cc */; }; + E318E2222C5A4FC200091322 /* notification.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC4D2C5A4FBD00091322 /* notification.cc */; }; + E318E2242C5A4FC200091322 /* cctz_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC572C5A4FBD00091322 /* cctz_benchmark.cc */; }; + E318E2252C5A4FC200091322 /* civil_time_detail.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC582C5A4FBD00091322 /* civil_time_detail.cc */; }; + E318E2262C5A4FC200091322 /* civil_time_detail.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC582C5A4FBD00091322 /* civil_time_detail.cc */; }; + E318E2282C5A4FC200091322 /* civil_time_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC592C5A4FBD00091322 /* civil_time_test.cc */; }; + E318E2292C5A4FC200091322 /* time_zone_fixed.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC5A2C5A4FBD00091322 /* time_zone_fixed.cc */; }; + E318E22A2C5A4FC200091322 /* time_zone_fixed.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC5A2C5A4FBD00091322 /* time_zone_fixed.cc */; }; + E318E22C2C5A4FC300091322 /* time_zone_format_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC5C2C5A4FBD00091322 /* time_zone_format_test.cc */; }; + E318E22D2C5A4FC300091322 /* time_zone_format.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC5D2C5A4FBD00091322 /* time_zone_format.cc */; }; + E318E22E2C5A4FC300091322 /* time_zone_format.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC5D2C5A4FBD00091322 /* time_zone_format.cc */; }; + E318E22F2C5A4FC300091322 /* time_zone_if.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC5E2C5A4FBD00091322 /* time_zone_if.cc */; }; + E318E2302C5A4FC300091322 /* time_zone_if.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC5E2C5A4FBD00091322 /* time_zone_if.cc */; }; + E318E2312C5A4FC300091322 /* time_zone_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC602C5A4FBD00091322 /* time_zone_impl.cc */; }; + E318E2322C5A4FC300091322 /* time_zone_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC602C5A4FBD00091322 /* time_zone_impl.cc */; }; + E318E2332C5A4FC300091322 /* time_zone_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC622C5A4FBD00091322 /* time_zone_info.cc */; }; + E318E2342C5A4FC300091322 /* time_zone_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC622C5A4FBD00091322 /* time_zone_info.cc */; }; + E318E2352C5A4FC300091322 /* time_zone_libc.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC642C5A4FBD00091322 /* time_zone_libc.cc */; }; + E318E2362C5A4FC300091322 /* time_zone_libc.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC642C5A4FBD00091322 /* time_zone_libc.cc */; }; + E318E2382C5A4FC300091322 /* time_zone_lookup_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC662C5A4FBD00091322 /* time_zone_lookup_test.cc */; }; + E318E2392C5A4FC300091322 /* time_zone_lookup.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC672C5A4FBD00091322 /* time_zone_lookup.cc */; }; + E318E23A2C5A4FC300091322 /* time_zone_lookup.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC672C5A4FBD00091322 /* time_zone_lookup.cc */; }; + E318E23B2C5A4FC300091322 /* time_zone_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC682C5A4FBD00091322 /* time_zone_posix.cc */; }; + E318E23C2C5A4FC300091322 /* time_zone_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC682C5A4FBD00091322 /* time_zone_posix.cc */; }; + E318E23D2C5A4FC300091322 /* zone_info_source.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC6B2C5A4FBD00091322 /* zone_info_source.cc */; }; + E318E23E2C5A4FC300091322 /* zone_info_source.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DC6B2C5A4FBD00091322 /* zone_info_source.cc */; }; + E318E6F12C5A4FC900091322 /* get_current_time_chrono.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEDD2C5A4FBD00091322 /* get_current_time_chrono.inc */; }; + E318E6F32C5A4FC900091322 /* get_current_time_posix.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEDE2C5A4FBD00091322 /* get_current_time_posix.inc */; }; + E318E6F62C5A4FC900091322 /* test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEDF2C5A4FBD00091322 /* test_util.cc */; }; + E318E6F72C5A4FC900091322 /* zoneinfo.inc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEE12C5A4FBD00091322 /* zoneinfo.inc */; }; + E318E6FC2C5A4FC900091322 /* civil_time_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEE42C5A4FBD00091322 /* civil_time_benchmark.cc */; }; + E318E6FE2C5A4FC900091322 /* civil_time_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEE52C5A4FBD00091322 /* civil_time_test.cc */; }; + E318E6FF2C5A4FC900091322 /* civil_time.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEE62C5A4FBD00091322 /* civil_time.cc */; }; + E318E7002C5A4FC900091322 /* civil_time.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEE62C5A4FBD00091322 /* civil_time.cc */; }; + E318E7022C5A4FC900091322 /* clock_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEE82C5A4FBD00091322 /* clock_benchmark.cc */; }; + E318E7042C5A4FC900091322 /* clock_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEE92C5A4FBD00091322 /* clock_test.cc */; }; + E318E7052C5A4FC900091322 /* clock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEEA2C5A4FBD00091322 /* clock.cc */; }; + E318E7062C5A4FC900091322 /* clock.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEEA2C5A4FBD00091322 /* clock.cc */; }; + E318E70A2C5A4FC900091322 /* duration_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEED2C5A4FBD00091322 /* duration_benchmark.cc */; }; + E318E70C2C5A4FC900091322 /* duration_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEEE2C5A4FBD00091322 /* duration_test.cc */; }; + E318E70D2C5A4FC900091322 /* duration.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEEF2C5A4FBD00091322 /* duration.cc */; }; + E318E70E2C5A4FC900091322 /* duration.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEEF2C5A4FBD00091322 /* duration.cc */; }; + E318E7102C5A4FC900091322 /* format_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF02C5A4FBD00091322 /* format_benchmark.cc */; }; + E318E7122C5A4FC900091322 /* format_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF12C5A4FBD00091322 /* format_test.cc */; }; + E318E7132C5A4FC900091322 /* format.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF22C5A4FBD00091322 /* format.cc */; }; + E318E7142C5A4FC900091322 /* format.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF22C5A4FBD00091322 /* format.cc */; }; + E318E7162C5A4FC900091322 /* time_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF32C5A4FBD00091322 /* time_benchmark.cc */; }; + E318E7182C5A4FC900091322 /* time_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF42C5A4FBD00091322 /* time_test.cc */; }; + E318E71A2C5A4FC900091322 /* time_zone_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF52C5A4FBD00091322 /* time_zone_test.cc */; }; + E318E71B2C5A4FC900091322 /* time.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF62C5A4FBD00091322 /* time.cc */; }; + E318E71C2C5A4FC900091322 /* time.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEF62C5A4FBD00091322 /* time.cc */; }; + E318E71E2C5A4FC900091322 /* conformance_testing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DEFE2C5A4FBD00091322 /* conformance_testing_test.cc */; }; + E318E7202C5A4FC900091322 /* any_exception_safety_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF062C5A4FBD00091322 /* any_exception_safety_test.cc */; }; + E318E7222C5A4FC900091322 /* any_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF072C5A4FBD00091322 /* any_test.cc */; }; + E318E7232C5A4FC900091322 /* bad_any_cast.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF092C5A4FBD00091322 /* bad_any_cast.cc */; }; + E318E7242C5A4FC900091322 /* bad_any_cast.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF092C5A4FBD00091322 /* bad_any_cast.cc */; }; + E318E7252C5A4FC900091322 /* bad_optional_access.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF0B2C5A4FBD00091322 /* bad_optional_access.cc */; }; + E318E7262C5A4FC900091322 /* bad_optional_access.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF0B2C5A4FBD00091322 /* bad_optional_access.cc */; }; + E318E7272C5A4FC900091322 /* bad_variant_access.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF0D2C5A4FBD00091322 /* bad_variant_access.cc */; }; + E318E7282C5A4FC900091322 /* bad_variant_access.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF0D2C5A4FBD00091322 /* bad_variant_access.cc */; }; + E318E72E2C5A4FC900091322 /* compare_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF112C5A4FBD00091322 /* compare_test.cc */; }; + E318E7302C5A4FC900091322 /* optional_exception_safety_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF132C5A4FBD00091322 /* optional_exception_safety_test.cc */; }; + E318E7322C5A4FC900091322 /* optional_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF142C5A4FBD00091322 /* optional_test.cc */; }; + E318E7342C5A4FC900091322 /* span_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF162C5A4FBD00091322 /* span_test.cc */; }; + E318E7362C5A4FC900091322 /* variant_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF182C5A4FBD00091322 /* variant_benchmark.cc */; }; + E318E7382C5A4FC900091322 /* variant_exception_safety_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF192C5A4FBD00091322 /* variant_exception_safety_test.cc */; }; + E318E73A2C5A4FC900091322 /* variant_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF1A2C5A4FBD00091322 /* variant_test.cc */; }; + E318E7402C5A4FCA00091322 /* utility_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DF202C5A4FBD00091322 /* utility_test.cc */; }; + E318E7422C5A4FCA00091322 /* abseil.podspec.gen.py in Resources */ = {isa = PBXBuildFile; fileRef = E318DF232C5A4FBD00091322 /* abseil.podspec.gen.py */; }; + E318E78A2C5A536400091322 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = E318E7762C5A536400091322 /* README.md */; }; + E318E78D2C5A536400091322 /* ImGuiFileDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318E77B2C5A536400091322 /* ImGuiFileDialog.cpp */; }; + E318E78E2C5A536400091322 /* ImGuiFileDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318E77B2C5A536400091322 /* ImGuiFileDialog.cpp */; }; + E318E7902C5A536400091322 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = E318E77E2C5A536400091322 /* LICENSE */; }; + E318E7932C5A542700091322 /* distribution_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = E318DB1F2C5A4FBD00091322 /* distribution_test_util.cc */; }; + E318E7942C5A542700091322 /* distribution_test_util.h in Sources */ = {isa = PBXBuildFile; fileRef = E318DB202C5A4FBD00091322 /* distribution_test_util.h */; }; + E318E7AD2C5A548C00091322 /* png.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7952C5A548C00091322 /* png.c */; }; + E318E7AE2C5A548C00091322 /* png.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7952C5A548C00091322 /* png.c */; }; + E318E7AF2C5A548C00091322 /* pngerror.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7992C5A548C00091322 /* pngerror.c */; }; + E318E7B02C5A548C00091322 /* pngerror.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7992C5A548C00091322 /* pngerror.c */; }; + E318E7B12C5A548C00091322 /* pngget.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E79A2C5A548C00091322 /* pngget.c */; }; + E318E7B22C5A548C00091322 /* pngget.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E79A2C5A548C00091322 /* pngget.c */; }; + E318E7B32C5A548C00091322 /* pngmem.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E79D2C5A548C00091322 /* pngmem.c */; }; + E318E7B42C5A548C00091322 /* pngmem.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E79D2C5A548C00091322 /* pngmem.c */; }; + E318E7B52C5A548C00091322 /* pngpread.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E79E2C5A548C00091322 /* pngpread.c */; }; + E318E7B62C5A548C00091322 /* pngpread.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E79E2C5A548C00091322 /* pngpread.c */; }; + E318E7B72C5A548C00091322 /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A02C5A548C00091322 /* pngread.c */; }; + E318E7B82C5A548C00091322 /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A02C5A548C00091322 /* pngread.c */; }; + E318E7B92C5A548C00091322 /* pngrio.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A12C5A548C00091322 /* pngrio.c */; }; + E318E7BA2C5A548C00091322 /* pngrio.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A12C5A548C00091322 /* pngrio.c */; }; + E318E7BB2C5A548C00091322 /* pngrtran.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A22C5A548C00091322 /* pngrtran.c */; }; + E318E7BC2C5A548C00091322 /* pngrtran.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A22C5A548C00091322 /* pngrtran.c */; }; + E318E7BD2C5A548C00091322 /* pngrutil.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A32C5A548C00091322 /* pngrutil.c */; }; + E318E7BE2C5A548C00091322 /* pngrutil.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A32C5A548C00091322 /* pngrutil.c */; }; + E318E7BF2C5A548C00091322 /* pngset.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A42C5A548C00091322 /* pngset.c */; }; + E318E7C02C5A548C00091322 /* pngset.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A42C5A548C00091322 /* pngset.c */; }; + E318E7C22C5A548C00091322 /* pngtest.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A62C5A548C00091322 /* pngtest.c */; }; + E318E7C32C5A548C00091322 /* pngtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A72C5A548C00091322 /* pngtrans.c */; }; + E318E7C42C5A548C00091322 /* pngtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A72C5A548C00091322 /* pngtrans.c */; }; + E318E7C52C5A548C00091322 /* pngwio.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A82C5A548C00091322 /* pngwio.c */; }; + E318E7C62C5A548C00091322 /* pngwio.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A82C5A548C00091322 /* pngwio.c */; }; + E318E7C72C5A548C00091322 /* pngwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A92C5A548C00091322 /* pngwrite.c */; }; + E318E7C82C5A548C00091322 /* pngwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7A92C5A548C00091322 /* pngwrite.c */; }; + E318E7C92C5A548C00091322 /* pngwtran.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7AA2C5A548C00091322 /* pngwtran.c */; }; + E318E7CA2C5A548C00091322 /* pngwtran.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7AA2C5A548C00091322 /* pngwtran.c */; }; + E318E7CB2C5A548C00091322 /* pngwutil.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7AB2C5A548C00091322 /* pngwutil.c */; }; + E318E7CC2C5A548C00091322 /* pngwutil.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7AB2C5A548C00091322 /* pngwutil.c */; }; + E318E7D02C5A55AE00091322 /* filter_neon.S in Sources */ = {isa = PBXBuildFile; fileRef = E318E7CD2C5A55AE00091322 /* filter_neon.S */; }; + E318E7D12C5A55AE00091322 /* filter_neon.S in Sources */ = {isa = PBXBuildFile; fileRef = E318E7CD2C5A55AE00091322 /* filter_neon.S */; }; + E318E7D22C5A55AE00091322 /* palette_neon_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7CE2C5A55AE00091322 /* palette_neon_intrinsics.c */; }; + E318E7D32C5A55AE00091322 /* palette_neon_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7CE2C5A55AE00091322 /* palette_neon_intrinsics.c */; }; + E318E7D42C5A55AE00091322 /* filter_neon_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7CF2C5A55AE00091322 /* filter_neon_intrinsics.c */; }; + E318E7D52C5A55AE00091322 /* filter_neon_intrinsics.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7CF2C5A55AE00091322 /* filter_neon_intrinsics.c */; }; + E318E7D72C5A55C300091322 /* arm_init.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7D62C5A55C300091322 /* arm_init.c */; }; + E318E7D82C5A55C300091322 /* arm_init.c in Sources */ = {isa = PBXBuildFile; fileRef = E318E7D62C5A55C300091322 /* arm_init.c */; }; + E318E7E82C5A688A00091322 /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DB2C5A688A00091322 /* DroidSans.ttf */; }; + E318E7EA2C5A688A00091322 /* IBMPlexSansJP-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DC2C5A688A00091322 /* IBMPlexSansJP-Bold.ttf */; }; + E318E7EC2C5A688A00091322 /* Karla-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DD2C5A688A00091322 /* Karla-Regular.ttf */; }; + E318E7EE2C5A688A00091322 /* MaterialIcons-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DE2C5A688A00091322 /* MaterialIcons-Regular.ttf */; }; + E318E7F02C5A688A00091322 /* NotoSansJP.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DF2C5A688A00091322 /* NotoSansJP.ttf */; }; + E318E7F22C5A688A00091322 /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7E02C5A688A00091322 /* Roboto-Medium.ttf */; }; + E318E7F42C5A688A00091322 /* overworld.zeml in Resources */ = {isa = PBXBuildFile; fileRef = E318E7E22C5A688A00091322 /* overworld.zeml */; }; + E318E7F62C5A688A00091322 /* ow_toolset.zeml in Resources */ = {isa = PBXBuildFile; fileRef = E318E7E32C5A688A00091322 /* ow_toolset.zeml */; }; + E318E7F92C5A8DE200091322 /* file_path.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318E7F82C5A8DE200091322 /* file_path.mm */; }; + E318E7FA2C5A8DE200091322 /* file_path.mm in Sources */ = {isa = PBXBuildFile; fileRef = E318E7F82C5A8DE200091322 /* file_path.mm */; }; + E318E8342C5BD8C100091322 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E318E8332C5BD8C000091322 /* UniformTypeIdentifiers.framework */; }; + E318E86A2C5D74C500091322 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E318E8592C5D74B700091322 /* SDL2.framework */; }; + E318E86B2C5D74C500091322 /* SDL2.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E318E8592C5D74B700091322 /* SDL2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E318E86D2C5D757800091322 /* Cousine-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DA2C5A688A00091322 /* Cousine-Regular.ttf */; }; + E318E86E2C5D757800091322 /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DB2C5A688A00091322 /* DroidSans.ttf */; }; + E318E86F2C5D757800091322 /* IBMPlexSansJP-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DC2C5A688A00091322 /* IBMPlexSansJP-Bold.ttf */; }; + E318E8702C5D757800091322 /* Karla-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DD2C5A688A00091322 /* Karla-Regular.ttf */; }; + E318E8712C5D757800091322 /* MaterialIcons-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DE2C5A688A00091322 /* MaterialIcons-Regular.ttf */; }; + E318E8722C5D757800091322 /* NotoSansJP.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7DF2C5A688A00091322 /* NotoSansJP.ttf */; }; + E318E8732C5D757800091322 /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E318E7E02C5A688A00091322 /* Roboto-Medium.ttf */; }; + E318E8742C5D757800091322 /* overworld.zeml in Resources */ = {isa = PBXBuildFile; fileRef = E318E7E22C5A688A00091322 /* overworld.zeml */; }; + E318E8752C5D757800091322 /* ow_toolset.zeml in Resources */ = {isa = PBXBuildFile; fileRef = E318E7E32C5A688A00091322 /* ow_toolset.zeml */; }; + E318E8772C5D949200091322 /* yaze.png in Resources */ = {isa = PBXBuildFile; fileRef = E318E8762C5D949200091322 /* yaze.png */; }; + E318E8792C5D958400091322 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E318E8782C5D958400091322 /* Media.xcassets */; }; + E318E87A2C605D5700091322 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E318E8572C5D74B700091322 /* SDL2.framework */; }; + E318E87B2C605D5700091322 /* SDL2.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E318E8572C5D74B700091322 /* SDL2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E318E87F2C609B3500091322 /* PencilKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E318E87E2C609B3500091322 /* PencilKit.framework */; }; + E32BC4CB2CA4D7D9001F57A8 /* command_manager.cc in Sources */ = {isa = PBXBuildFile; fileRef = E32BC4CA2CA4D7BC001F57A8 /* command_manager.cc */; }; + E34C789C2C5882A100A6C275 /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; }; + E36971DA2CE189EA00DEF2F6 /* project.cc in Sources */ = {isa = PBXBuildFile; fileRef = E36971D92CE189EA00DEF2F6 /* project.cc */; }; + E36971DB2CE189EA00DEF2F6 /* project.cc in Sources */ = {isa = PBXBuildFile; fileRef = E36971D92CE189EA00DEF2F6 /* project.cc */; }; + E36971E42CE18A2A00DEF2F6 /* file_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = E36971E12CE18A2A00DEF2F6 /* file_util.cc */; }; + E36971E52CE18A2A00DEF2F6 /* file_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = E36971E12CE18A2A00DEF2F6 /* file_util.cc */; }; + E384E2D62C76C6E800147029 /* message_data.cc in Sources */ = {isa = PBXBuildFile; fileRef = E384E2D52C76C6C800147029 /* message_data.cc */; }; + E38A97F72C6C4CE3005FB662 /* extension_manager.cc in Sources */ = {isa = PBXBuildFile; fileRef = E38A97F22C6C4CE3005FB662 /* extension_manager.cc */; }; + E38A97F82C6C4CE3005FB662 /* settings_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E38A97F42C6C4CE3005FB662 /* settings_editor.cc */; }; + E3B864952C8214B500122951 /* asset_browser.cc in Sources */ = {isa = PBXBuildFile; fileRef = E3B864902C82144A00122951 /* asset_browser.cc */; }; + E3BE958D2C68379B008DD1E7 /* editor_manager.cc in Sources */ = {isa = PBXBuildFile; fileRef = E3BE958B2C68379B008DD1E7 /* editor_manager.cc */; }; + E3BE95902C6837C8008DD1E7 /* overworld_editor.cc in Sources */ = {isa = PBXBuildFile; fileRef = E3BE958F2C6837C8008DD1E7 /* overworld_editor.cc */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + E318E8562C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = BECDF66C0761BA81005FE872; + remoteInfo = Framework; + }; + E318E8582C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A7D88B5423E2437C00DCD162; + remoteInfo = "Framework-iOS"; + }; + E318E85A2C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A7D88D1523E24BED00DCD162; + remoteInfo = "Framework-tvOS"; + }; + E318E85C2C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = BECDF6B30761BA81005FE872; + remoteInfo = "Static Library"; + }; + E318E85E2C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A7D88E5423E24D3B00DCD162; + remoteInfo = "Static Library-iOS"; + }; + E318E8602C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A769B23D23E259AE00872273; + remoteInfo = "Static Library-tvOS"; + }; + E318E8622C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = DB31407717554B71006C0E22; + remoteInfo = "Shared Library"; + }; + E318E8642C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A75FCEB323E25AB700529352; + remoteInfo = "Shared Library-iOS"; + }; + E318E8662C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A75FD06C23E25AC700529352; + remoteInfo = "Shared Library-tvOS"; + }; + E318E8682C5D74B700091322 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = BECDF6BE0761BA81005FE872; + remoteInfo = "Standard DMG"; + }; + E36971D72CE1898700DEF2F6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = E2D187CF28A5673500D2B4F1; + remoteInfo = "xcFramework-iOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + E318E86C2C5D74C500091322 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + E318E86B2C5D74C500091322 /* SDL2.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + E318E87C2C605D5700091322 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + E318E87B2C605D5700091322 /* SDL2.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; + 07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../yaze/src/lib/imgui/imgui_internal.h; sourceTree = ""; }; + 07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = /Users/scawful/Code/yaze/src/lib/imgui/imgui_widgets.cpp; sourceTree = ""; }; + 5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = /Users/scawful/Code/yaze/src/lib/imgui/imgui_tables.cpp; sourceTree = ""; }; + 8307E7C420E9F9C900473790 /* yaze.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = yaze.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8307E7DA20E9F9C900473790 /* yaze.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = yaze.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + 8309BDA0253CCBC10045E2A1 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; + 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = imgui_impl_metal.mm; path = "/Users/scawful/Code/xcode/metal-ios/imgui_impl_metal.mm"; sourceTree = ""; }; + 8309BDC5253CCCFE0045E2A1 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 8309BDF7253CDAAE0045E2A1 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 8309BDF8253CDAAE0045E2A1 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; + 8309BDFA253CDAAE0045E2A1 /* MainMenu.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainMenu.storyboard; sourceTree = ""; }; + 8309BDFB253CDAAE0045E2A1 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; + 83BBE9E420EB46B900295997 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk/System/Library/Frameworks/Metal.framework; sourceTree = DEVELOPER_DIR; }; + 83BBE9E620EB46BD00295997 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk/System/Library/Frameworks/MetalKit.framework; sourceTree = DEVELOPER_DIR; }; + 83BBE9E820EB46C100295997 /* ModelIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModelIO.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk/System/Library/Frameworks/ModelIO.framework; sourceTree = DEVELOPER_DIR; }; + 83BBE9EA20EB471700295997 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; + 83BBE9EB20EB471700295997 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; + 83BBE9EE20EB471C00295997 /* ModelIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModelIO.framework; path = System/Library/Frameworks/ModelIO.framework; sourceTree = SDKROOT; }; + 83BBEA0120EB54E700295997 /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = /Users/scawful/Code/yaze/src/lib/imgui/imgui_draw.cpp; sourceTree = ""; }; + 83BBEA0220EB54E700295997 /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = /Users/scawful/Code/yaze/src/lib/imgui/imgui_demo.cpp; sourceTree = ""; }; + 83BBEA0320EB54E700295997 /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = /Users/scawful/Code/yaze/src/lib/imgui/imgui.cpp; sourceTree = ""; }; + 83BBEA0420EB54E700295997 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imconfig.h; sourceTree = ""; }; + E318D8472C59C08300091322 /* app_delegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = app_delegate.h; sourceTree = ""; }; + E318D8482C59C08300091322 /* app_delegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = app_delegate.mm; sourceTree = ""; }; + E318D8492C59C08300091322 /* clipboard.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = clipboard.cc; sourceTree = ""; }; + E318D84A2C59C08300091322 /* clipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clipboard.h; sourceTree = ""; }; + E318D84B2C59C08300091322 /* clipboard.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = ""; }; + E318D84C2C59C08300091322 /* file_dialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_dialog.h; sourceTree = ""; }; + E318D84D2C59C08300091322 /* file_dialog.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = file_dialog.mm; sourceTree = ""; }; + E318D84E2C59C08300091322 /* font_loader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = font_loader.cc; sourceTree = ""; }; + E318D84F2C59C08300091322 /* font_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = font_loader.h; sourceTree = ""; }; + E318D8502C59C08300091322 /* font_loader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = font_loader.mm; sourceTree = ""; }; + E318D8522C59C08300091322 /* common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = common.cc; sourceTree = ""; }; + E318D8532C59C08300091322 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; + E318D8542C59C08300091322 /* constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = constants.h; sourceTree = ""; }; + E318D8552C59C08300091322 /* controller.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = controller.cc; sourceTree = ""; }; + E318D8562C59C08300091322 /* controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controller.h; sourceTree = ""; }; + E318D8592C59C08300091322 /* project.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = project.h; sourceTree = ""; }; + E318D85C2C59C08300091322 /* assembly_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assembly_editor.cc; sourceTree = ""; }; + E318D85D2C59C08300091322 /* assembly_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assembly_editor.h; sourceTree = ""; }; + E318D85E2C59C08300091322 /* memory_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory_editor.h; sourceTree = ""; }; + E318D8602C59C08300091322 /* dungeon_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dungeon_editor.cc; sourceTree = ""; }; + E318D8612C59C08300091322 /* dungeon_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dungeon_editor.h; sourceTree = ""; }; + E318D8632C59C08300091322 /* gfx_group_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gfx_group_editor.cc; sourceTree = ""; }; + E318D8642C59C08300091322 /* gfx_group_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gfx_group_editor.h; sourceTree = ""; }; + E318D8652C59C08300091322 /* graphics_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphics_editor.cc; sourceTree = ""; }; + E318D8662C59C08300091322 /* graphics_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphics_editor.h; sourceTree = ""; }; + E318D8672C59C08300091322 /* palette_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = palette_editor.cc; sourceTree = ""; }; + E318D8682C59C08300091322 /* palette_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = palette_editor.h; sourceTree = ""; }; + E318D8692C59C08300091322 /* screen_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = screen_editor.cc; sourceTree = ""; }; + E318D86A2C59C08300091322 /* screen_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = screen_editor.h; sourceTree = ""; }; + E318D86B2C59C08300091322 /* tile16_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tile16_editor.cc; sourceTree = ""; }; + E318D86C2C59C08300091322 /* tile16_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tile16_editor.h; sourceTree = ""; }; + E318D86E2C59C08300091322 /* message_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = message_data.h; sourceTree = ""; }; + E318D8702C59C08300091322 /* message_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = message_editor.cc; sourceTree = ""; }; + E318D8712C59C08300091322 /* message_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = message_editor.h; sourceTree = ""; }; + E318D8732C59C08300091322 /* music_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = music_editor.cc; sourceTree = ""; }; + E318D8742C59C08300091322 /* music_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = music_editor.h; sourceTree = ""; }; + E318D8762C59C08300091322 /* entity.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = entity.cc; sourceTree = ""; }; + E318D8772C59C08300091322 /* entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = entity.h; sourceTree = ""; }; + E318D87A2C59C08300091322 /* sprite_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sprite_editor.cc; sourceTree = ""; }; + E318D87B2C59C08300091322 /* sprite_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sprite_editor.h; sourceTree = ""; }; + E318D87C2C59C08300091322 /* zsprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zsprite.h; sourceTree = ""; }; + E318D87E2C59C08300091322 /* editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = editor.h; sourceTree = ""; }; + E318D87F2C59C08300091322 /* flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flags.h; sourceTree = ""; }; + E318D8802C59C08300091322 /* gfx_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gfx_context.cc; sourceTree = ""; }; + E318D8812C59C08300091322 /* gfx_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gfx_context.h; sourceTree = ""; }; + E318D8832C59C08300091322 /* recent_files.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recent_files.h; sourceTree = ""; }; + E318D88E2C59C08300091322 /* addressing.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = addressing.cc; sourceTree = ""; }; + E318D88F2C59C08300091322 /* instructions.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instructions.cc; sourceTree = ""; }; + E318D8902C59C08300091322 /* opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opcodes.h; sourceTree = ""; }; + E318D8922C59C08300091322 /* apu.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = apu.cc; sourceTree = ""; }; + E318D8932C59C08300091322 /* apu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apu.h; sourceTree = ""; }; + E318D8942C59C08300091322 /* dsp.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsp.cc; sourceTree = ""; }; + E318D8952C59C08300091322 /* dsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsp.h; sourceTree = ""; }; + E318D8962C59C08300091322 /* spc700.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spc700.cc; sourceTree = ""; }; + E318D8972C59C08300091322 /* spc700.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spc700.h; sourceTree = ""; }; + E318D8992C59C08300091322 /* addressing.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = addressing.cc; sourceTree = ""; }; + E318D89A2C59C08300091322 /* instructions.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instructions.cc; sourceTree = ""; }; + E318D89B2C59C08300091322 /* old_cpu.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = old_cpu.cc; sourceTree = ""; }; + E318D89C2C59C08300091322 /* opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opcodes.h; sourceTree = ""; }; + E318D89E2C59C08300091322 /* clock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clock.h; sourceTree = ""; }; + E318D89F2C59C08300091322 /* cpu.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpu.cc; sourceTree = ""; }; + E318D8A02C59C08300091322 /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = ""; }; + E318D8A22C59C08300091322 /* asm_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asm_parser.h; sourceTree = ""; }; + E318D8A32C59C08300091322 /* debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debugger.h; sourceTree = ""; }; + E318D8A52C59C08300091322 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = ""; }; + E318D8A72C59C08300091322 /* dma_channel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dma_channel.h; sourceTree = ""; }; + E318D8A82C59C08300091322 /* dma.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dma.cc; sourceTree = ""; }; + E318D8A92C59C08300091322 /* dma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dma.h; sourceTree = ""; }; + E318D8AA2C59C08300091322 /* memory.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memory.cc; sourceTree = ""; }; + E318D8AB2C59C08300091322 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = ""; }; + E318D8AC2C59C08300091322 /* mock_memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mock_memory.h; sourceTree = ""; }; + E318D8AE2C59C08300091322 /* ppu_registers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ppu_registers.h; sourceTree = ""; }; + E318D8AF2C59C08300091322 /* ppu.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ppu.cc; sourceTree = ""; }; + E318D8B02C59C08300091322 /* ppu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ppu.h; sourceTree = ""; }; + E318D8B32C59C08300091322 /* emulator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emulator.cc; sourceTree = ""; }; + E318D8B42C59C08300091322 /* emulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emulator.h; sourceTree = ""; }; + E318D8B52C59C08300091322 /* snes.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = snes.cc; sourceTree = ""; }; + E318D8B62C59C08300091322 /* snes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = snes.h; sourceTree = ""; }; + E318D8B82C59C08300091322 /* bitmap.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bitmap.cc; sourceTree = ""; }; + E318D8B92C59C08300091322 /* bitmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitmap.h; sourceTree = ""; }; + E318D8BA2C59C08300091322 /* compression.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compression.cc; sourceTree = ""; }; + E318D8BB2C59C08300091322 /* compression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compression.h; sourceTree = ""; }; + E318D8BC2C59C08300091322 /* scad_format.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scad_format.cc; sourceTree = ""; }; + E318D8BD2C59C08300091322 /* scad_format.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scad_format.h; sourceTree = ""; }; + E318D8BE2C59C08300091322 /* snes_color.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = snes_color.cc; sourceTree = ""; }; + E318D8BF2C59C08300091322 /* snes_color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = snes_color.h; sourceTree = ""; }; + E318D8C02C59C08300091322 /* snes_palette.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = snes_palette.cc; sourceTree = ""; }; + E318D8C12C59C08300091322 /* snes_palette.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = snes_palette.h; sourceTree = ""; }; + E318D8C22C59C08300091322 /* snes_tile.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = snes_tile.cc; sourceTree = ""; }; + E318D8C32C59C08300091322 /* snes_tile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = snes_tile.h; sourceTree = ""; }; + E318D8C42C59C08300091322 /* tilesheet.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tilesheet.cc; sourceTree = ""; }; + E318D8C52C59C08300091322 /* tilesheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tilesheet.h; sourceTree = ""; }; + E318D8C92C59C08300091322 /* canvas.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = canvas.cc; sourceTree = ""; }; + E318D8CA2C59C08300091322 /* canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = canvas.h; sourceTree = ""; }; + E318D8CB2C59C08300091322 /* color.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = color.cc; sourceTree = ""; }; + E318D8CC2C59C08300091322 /* color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = color.h; sourceTree = ""; }; + E318D8CD2C59C08300091322 /* icons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = icons.h; sourceTree = ""; }; + E318D8CE2C59C08300091322 /* input.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = input.cc; sourceTree = ""; }; + E318D8CF2C59C08300091322 /* input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input.h; sourceTree = ""; }; + E318D8D02C59C08300091322 /* style.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = style.cc; sourceTree = ""; }; + E318D8D12C59C08300091322 /* style.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = style.h; sourceTree = ""; }; + E318D8D22C59C08300091322 /* zeml.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = zeml.cc; sourceTree = ""; }; + E318D8D32C59C08300091322 /* zeml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zeml.h; sourceTree = ""; }; + E318D8D52C59C08300091322 /* object_names.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = object_names.h; sourceTree = ""; }; + E318D8D62C59C08300091322 /* object_renderer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = object_renderer.cc; sourceTree = ""; }; + E318D8D72C59C08300091322 /* object_renderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = object_renderer.h; sourceTree = ""; }; + E318D8D82C59C08300091322 /* room_entrance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = room_entrance.h; sourceTree = ""; }; + E318D8D92C59C08300091322 /* room_names.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = room_names.h; sourceTree = ""; }; + E318D8DA2C59C08300091322 /* room_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = room_object.cc; sourceTree = ""; }; + E318D8DB2C59C08300091322 /* room_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = room_object.h; sourceTree = ""; }; + E318D8DC2C59C08300091322 /* room.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = room.cc; sourceTree = ""; }; + E318D8DD2C59C08300091322 /* room.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = room.h; sourceTree = ""; }; + E318D8DF2C59C08300091322 /* spc700.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = spc700.def; sourceTree = ""; }; + E318D8E02C59C08300091322 /* tracker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tracker.cc; sourceTree = ""; }; + E318D8E12C59C08300091322 /* tracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tracker.h; sourceTree = ""; }; + E318D8E32C59C08300091322 /* overworld_map.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = overworld_map.cc; sourceTree = ""; }; + E318D8E42C59C08300091322 /* overworld_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = overworld_map.h; sourceTree = ""; }; + E318D8E52C59C08300091322 /* overworld.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = overworld.cc; sourceTree = ""; }; + E318D8E62C59C08300091322 /* overworld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = overworld.h; sourceTree = ""; }; + E318D8E82C59C08300091322 /* dungeon_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dungeon_map.h; sourceTree = ""; }; + E318D8E92C59C08300091322 /* inventory.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inventory.cc; sourceTree = ""; }; + E318D8EA2C59C08300091322 /* inventory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inventory.h; sourceTree = ""; }; + E318D8EB2C59C08300091322 /* title_screen.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = title_screen.cc; sourceTree = ""; }; + E318D8EC2C59C08300091322 /* title_screen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = title_screen.h; sourceTree = ""; }; + E318D8EE2C59C08300091322 /* sprite.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sprite.cc; sourceTree = ""; }; + E318D8EF2C59C08300091322 /* sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sprite.h; sourceTree = ""; }; + E318D8F22C59C08300091322 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; + E318D8F62C59C08300091322 /* rom.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rom.cc; sourceTree = ""; }; + E318D8F72C59C08300091322 /* rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rom.h; sourceTree = ""; }; + E318D8F82C59C08300091322 /* yaze.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = yaze.cc; sourceTree = ""; }; + E318D98B2C59CBBB00091322 /* TextEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextEditor.cpp; path = ../../yaze/src/lib/ImGuiColorTextEdit/TextEditor.cpp; sourceTree = ""; }; + E318D98C2C59CBBB00091322 /* TextEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextEditor.h; path = ../../yaze/src/lib/ImGuiColorTextEdit/TextEditor.h; sourceTree = ""; }; + E318D9942C59CDF800091322 /* imgui_impl_sdl2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_impl_sdl2.cpp; path = ../../yaze/src/lib/imgui/backends/imgui_impl_sdl2.cpp; sourceTree = ""; }; + E318D9972C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_impl_sdlrenderer2.cpp; path = ../../yaze/src/lib/imgui/backends/imgui_impl_sdlrenderer2.cpp; sourceTree = ""; }; + E318D99B2C59D0E500091322 /* imgui_stdlib.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_stdlib.cpp; path = ../../yaze/src/lib/imgui/misc/cpp/imgui_stdlib.cpp; sourceTree = ""; }; + E318D99C2C59D0E500091322 /* imgui_stdlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_stdlib.h; path = ../../yaze/src/lib/imgui/misc/cpp/imgui_stdlib.h; sourceTree = ""; }; + E318D9A02C59DFD200091322 /* libpng16.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng16.a; path = "../../../opt/anaconda3/pkgs/libpng-1.6.37-ha441bb4_0/lib/libpng16.a"; sourceTree = ""; }; + E318D9A32C5A4FBD00091322 /* algorithm_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = algorithm_test.cc; sourceTree = ""; }; + E318D9A42C5A4FBD00091322 /* algorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = algorithm.h; sourceTree = ""; }; + E318D9A52C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318D9A62C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318D9A72C5A4FBD00091322 /* container_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = container_test.cc; sourceTree = ""; }; + E318D9A82C5A4FBD00091322 /* container.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = container.h; sourceTree = ""; }; + E318D9A92C5A4FBD00091322 /* equal_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = equal_benchmark.cc; sourceTree = ""; }; + E318D9AC2C5A4FBD00091322 /* atomic_hook_test_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = atomic_hook_test_helper.cc; sourceTree = ""; }; + E318D9AD2C5A4FBD00091322 /* atomic_hook_test_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = atomic_hook_test_helper.h; sourceTree = ""; }; + E318D9AE2C5A4FBD00091322 /* atomic_hook_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = atomic_hook_test.cc; sourceTree = ""; }; + E318D9AF2C5A4FBD00091322 /* atomic_hook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = atomic_hook.h; sourceTree = ""; }; + E318D9B02C5A4FBD00091322 /* cmake_thread_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cmake_thread_test.cc; sourceTree = ""; }; + E318D9B12C5A4FBD00091322 /* cycleclock.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cycleclock.cc; sourceTree = ""; }; + E318D9B22C5A4FBD00091322 /* cycleclock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cycleclock.h; sourceTree = ""; }; + E318D9B32C5A4FBD00091322 /* direct_mmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = direct_mmap.h; sourceTree = ""; }; + E318D9B42C5A4FBD00091322 /* dynamic_annotations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dynamic_annotations.h; sourceTree = ""; }; + E318D9B52C5A4FBD00091322 /* endian_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = endian_test.cc; sourceTree = ""; }; + E318D9B62C5A4FBD00091322 /* endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endian.h; sourceTree = ""; }; + E318D9B72C5A4FBD00091322 /* errno_saver_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = errno_saver_test.cc; sourceTree = ""; }; + E318D9B82C5A4FBD00091322 /* errno_saver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = errno_saver.h; sourceTree = ""; }; + E318D9B92C5A4FBD00091322 /* exception_safety_testing.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exception_safety_testing.cc; sourceTree = ""; }; + E318D9BA2C5A4FBD00091322 /* exception_safety_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception_safety_testing.h; sourceTree = ""; }; + E318D9BB2C5A4FBD00091322 /* exception_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception_testing.h; sourceTree = ""; }; + E318D9BC2C5A4FBD00091322 /* fast_type_id_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fast_type_id_test.cc; sourceTree = ""; }; + E318D9BD2C5A4FBD00091322 /* fast_type_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fast_type_id.h; sourceTree = ""; }; + E318D9BE2C5A4FBD00091322 /* hide_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hide_ptr.h; sourceTree = ""; }; + E318D9BF2C5A4FBD00091322 /* identity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = identity.h; sourceTree = ""; }; + E318D9C02C5A4FBD00091322 /* inline_variable_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_variable_testing.h; sourceTree = ""; }; + E318D9C12C5A4FBD00091322 /* inline_variable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_variable.h; sourceTree = ""; }; + E318D9C22C5A4FBD00091322 /* invoke.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = invoke.h; sourceTree = ""; }; + E318D9C32C5A4FBD00091322 /* low_level_alloc_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = low_level_alloc_test.cc; sourceTree = ""; }; + E318D9C42C5A4FBD00091322 /* low_level_alloc.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = low_level_alloc.cc; sourceTree = ""; }; + E318D9C52C5A4FBD00091322 /* low_level_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = low_level_alloc.h; sourceTree = ""; }; + E318D9C62C5A4FBD00091322 /* low_level_scheduling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = low_level_scheduling.h; sourceTree = ""; }; + E318D9C72C5A4FBD00091322 /* per_thread_tls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = per_thread_tls.h; sourceTree = ""; }; + E318D9C82C5A4FBD00091322 /* prefetch_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = prefetch_test.cc; sourceTree = ""; }; + E318D9C92C5A4FBD00091322 /* prefetch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = prefetch.h; sourceTree = ""; }; + E318D9CA2C5A4FBD00091322 /* pretty_function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pretty_function.h; sourceTree = ""; }; + E318D9CB2C5A4FBD00091322 /* raw_logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raw_logging.cc; sourceTree = ""; }; + E318D9CC2C5A4FBD00091322 /* raw_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = raw_logging.h; sourceTree = ""; }; + E318D9CD2C5A4FBD00091322 /* scheduling_mode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scheduling_mode.h; sourceTree = ""; }; + E318D9CE2C5A4FBD00091322 /* scoped_set_env_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scoped_set_env_test.cc; sourceTree = ""; }; + E318D9CF2C5A4FBD00091322 /* scoped_set_env.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scoped_set_env.cc; sourceTree = ""; }; + E318D9D02C5A4FBD00091322 /* scoped_set_env.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scoped_set_env.h; sourceTree = ""; }; + E318D9D12C5A4FBD00091322 /* spinlock_akaros.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = spinlock_akaros.inc; sourceTree = ""; }; + E318D9D22C5A4FBD00091322 /* spinlock_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spinlock_benchmark.cc; sourceTree = ""; }; + E318D9D32C5A4FBD00091322 /* spinlock_linux.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = spinlock_linux.inc; sourceTree = ""; }; + E318D9D42C5A4FBD00091322 /* spinlock_posix.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = spinlock_posix.inc; sourceTree = ""; }; + E318D9D52C5A4FBD00091322 /* spinlock_wait.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spinlock_wait.cc; sourceTree = ""; }; + E318D9D62C5A4FBD00091322 /* spinlock_wait.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spinlock_wait.h; sourceTree = ""; }; + E318D9D72C5A4FBD00091322 /* spinlock_win32.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = spinlock_win32.inc; sourceTree = ""; }; + E318D9D82C5A4FBD00091322 /* spinlock.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spinlock.cc; sourceTree = ""; }; + E318D9D92C5A4FBD00091322 /* spinlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spinlock.h; sourceTree = ""; }; + E318D9DA2C5A4FBD00091322 /* strerror_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strerror_benchmark.cc; sourceTree = ""; }; + E318D9DB2C5A4FBD00091322 /* strerror_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strerror_test.cc; sourceTree = ""; }; + E318D9DC2C5A4FBD00091322 /* strerror.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strerror.cc; sourceTree = ""; }; + E318D9DD2C5A4FBD00091322 /* strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strerror.h; sourceTree = ""; }; + E318D9DE2C5A4FBD00091322 /* sysinfo_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sysinfo_test.cc; sourceTree = ""; }; + E318D9DF2C5A4FBD00091322 /* sysinfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sysinfo.cc; sourceTree = ""; }; + E318D9E02C5A4FBD00091322 /* sysinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sysinfo.h; sourceTree = ""; }; + E318D9E12C5A4FBD00091322 /* thread_annotations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread_annotations.h; sourceTree = ""; }; + E318D9E22C5A4FBD00091322 /* thread_identity_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_identity_benchmark.cc; sourceTree = ""; }; + E318D9E32C5A4FBD00091322 /* thread_identity_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_identity_test.cc; sourceTree = ""; }; + E318D9E42C5A4FBD00091322 /* thread_identity.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_identity.cc; sourceTree = ""; }; + E318D9E52C5A4FBD00091322 /* thread_identity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread_identity.h; sourceTree = ""; }; + E318D9E62C5A4FBD00091322 /* throw_delegate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = throw_delegate.cc; sourceTree = ""; }; + E318D9E72C5A4FBD00091322 /* throw_delegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = throw_delegate.h; sourceTree = ""; }; + E318D9E82C5A4FBD00091322 /* tsan_mutex_interface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tsan_mutex_interface.h; sourceTree = ""; }; + E318D9E92C5A4FBD00091322 /* unaligned_access.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unaligned_access.h; sourceTree = ""; }; + E318D9EA2C5A4FBD00091322 /* unique_small_name_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unique_small_name_test.cc; sourceTree = ""; }; + E318D9EB2C5A4FBD00091322 /* unscaledcycleclock.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unscaledcycleclock.cc; sourceTree = ""; }; + E318D9EC2C5A4FBD00091322 /* unscaledcycleclock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unscaledcycleclock.h; sourceTree = ""; }; + E318D9EE2C5A4FBD00091322 /* attributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = attributes.h; sourceTree = ""; }; + E318D9EF2C5A4FBD00091322 /* bit_cast_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bit_cast_test.cc; sourceTree = ""; }; + E318D9F02C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318D9F12C5A4FBD00091322 /* call_once_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = call_once_test.cc; sourceTree = ""; }; + E318D9F22C5A4FBD00091322 /* call_once.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = call_once.h; sourceTree = ""; }; + E318D9F32C5A4FBD00091322 /* casts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = casts.h; sourceTree = ""; }; + E318D9F42C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318D9F52C5A4FBD00091322 /* config_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_test.cc; sourceTree = ""; }; + E318D9F62C5A4FBD00091322 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; + E318D9F72C5A4FBD00091322 /* const_init.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = const_init.h; sourceTree = ""; }; + E318D9F82C5A4FBD00091322 /* dynamic_annotations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dynamic_annotations.h; sourceTree = ""; }; + E318D9F92C5A4FBD00091322 /* exception_safety_testing_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exception_safety_testing_test.cc; sourceTree = ""; }; + E318D9FA2C5A4FBD00091322 /* inline_variable_test_a.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_variable_test_a.cc; sourceTree = ""; }; + E318D9FB2C5A4FBD00091322 /* inline_variable_test_b.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_variable_test_b.cc; sourceTree = ""; }; + E318D9FC2C5A4FBD00091322 /* inline_variable_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_variable_test.cc; sourceTree = ""; }; + E318D9FD2C5A4FBD00091322 /* invoke_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = invoke_test.cc; sourceTree = ""; }; + E318D9FE2C5A4FBD00091322 /* log_severity_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log_severity_test.cc; sourceTree = ""; }; + E318D9FF2C5A4FBD00091322 /* log_severity.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log_severity.cc; sourceTree = ""; }; + E318DA002C5A4FBD00091322 /* log_severity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log_severity.h; sourceTree = ""; }; + E318DA012C5A4FBD00091322 /* macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macros.h; sourceTree = ""; }; + E318DA022C5A4FBD00091322 /* optimization_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = optimization_test.cc; sourceTree = ""; }; + E318DA032C5A4FBD00091322 /* optimization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = optimization.h; sourceTree = ""; }; + E318DA042C5A4FBD00091322 /* options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = options.h; sourceTree = ""; }; + E318DA052C5A4FBD00091322 /* policy_checks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policy_checks.h; sourceTree = ""; }; + E318DA062C5A4FBD00091322 /* port.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = port.h; sourceTree = ""; }; + E318DA072C5A4FBD00091322 /* raw_logging_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raw_logging_test.cc; sourceTree = ""; }; + E318DA082C5A4FBD00091322 /* spinlock_test_common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spinlock_test_common.cc; sourceTree = ""; }; + E318DA092C5A4FBD00091322 /* thread_annotations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread_annotations.h; sourceTree = ""; }; + E318DA0A2C5A4FBD00091322 /* throw_delegate_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = throw_delegate_test.cc; sourceTree = ""; }; + E318DA0D2C5A4FBD00091322 /* cleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cleanup.h; sourceTree = ""; }; + E318DA0F2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DA102C5A4FBD00091322 /* cleanup_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cleanup_test.cc; sourceTree = ""; }; + E318DA112C5A4FBD00091322 /* cleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cleanup.h; sourceTree = ""; }; + E318DA122C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DA162C5A4FBD00091322 /* btree_container.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = btree_container.h; sourceTree = ""; }; + E318DA172C5A4FBD00091322 /* btree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = btree.h; sourceTree = ""; }; + E318DA182C5A4FBD00091322 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; + E318DA192C5A4FBD00091322 /* compressed_tuple_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compressed_tuple_test.cc; sourceTree = ""; }; + E318DA1A2C5A4FBD00091322 /* compressed_tuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compressed_tuple.h; sourceTree = ""; }; + E318DA1B2C5A4FBD00091322 /* container_memory_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = container_memory_test.cc; sourceTree = ""; }; + E318DA1C2C5A4FBD00091322 /* container_memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = container_memory.h; sourceTree = ""; }; + E318DA1D2C5A4FBD00091322 /* counting_allocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = counting_allocator.h; sourceTree = ""; }; + E318DA1E2C5A4FBD00091322 /* hash_function_defaults_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash_function_defaults_test.cc; sourceTree = ""; }; + E318DA1F2C5A4FBD00091322 /* hash_function_defaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash_function_defaults.h; sourceTree = ""; }; + E318DA202C5A4FBD00091322 /* hash_generator_testing.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash_generator_testing.cc; sourceTree = ""; }; + E318DA212C5A4FBD00091322 /* hash_generator_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash_generator_testing.h; sourceTree = ""; }; + E318DA222C5A4FBD00091322 /* hash_policy_testing_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash_policy_testing_test.cc; sourceTree = ""; }; + E318DA232C5A4FBD00091322 /* hash_policy_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash_policy_testing.h; sourceTree = ""; }; + E318DA242C5A4FBD00091322 /* hash_policy_traits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash_policy_traits_test.cc; sourceTree = ""; }; + E318DA252C5A4FBD00091322 /* hash_policy_traits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash_policy_traits.h; sourceTree = ""; }; + E318DA262C5A4FBD00091322 /* hashtable_debug_hooks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hashtable_debug_hooks.h; sourceTree = ""; }; + E318DA272C5A4FBD00091322 /* hashtable_debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hashtable_debug.h; sourceTree = ""; }; + E318DA282C5A4FBD00091322 /* hashtablez_sampler_force_weak_definition.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashtablez_sampler_force_weak_definition.cc; sourceTree = ""; }; + E318DA292C5A4FBD00091322 /* hashtablez_sampler_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashtablez_sampler_test.cc; sourceTree = ""; }; + E318DA2A2C5A4FBD00091322 /* hashtablez_sampler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashtablez_sampler.cc; sourceTree = ""; }; + E318DA2B2C5A4FBD00091322 /* hashtablez_sampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hashtablez_sampler.h; sourceTree = ""; }; + E318DA2C2C5A4FBD00091322 /* inlined_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inlined_vector.h; sourceTree = ""; }; + E318DA2D2C5A4FBD00091322 /* layout_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = layout_benchmark.cc; sourceTree = ""; }; + E318DA2E2C5A4FBD00091322 /* layout_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = layout_test.cc; sourceTree = ""; }; + E318DA2F2C5A4FBD00091322 /* layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = layout.h; sourceTree = ""; }; + E318DA302C5A4FBD00091322 /* node_slot_policy_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_slot_policy_test.cc; sourceTree = ""; }; + E318DA312C5A4FBD00091322 /* node_slot_policy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = node_slot_policy.h; sourceTree = ""; }; + E318DA322C5A4FBD00091322 /* raw_hash_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = raw_hash_map.h; sourceTree = ""; }; + E318DA332C5A4FBD00091322 /* raw_hash_set_allocator_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raw_hash_set_allocator_test.cc; sourceTree = ""; }; + E318DA342C5A4FBD00091322 /* raw_hash_set_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raw_hash_set_benchmark.cc; sourceTree = ""; }; + E318DA352C5A4FBD00091322 /* raw_hash_set_probe_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raw_hash_set_probe_benchmark.cc; sourceTree = ""; }; + E318DA362C5A4FBD00091322 /* raw_hash_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raw_hash_set_test.cc; sourceTree = ""; }; + E318DA372C5A4FBD00091322 /* raw_hash_set.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raw_hash_set.cc; sourceTree = ""; }; + E318DA382C5A4FBD00091322 /* raw_hash_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = raw_hash_set.h; sourceTree = ""; }; + E318DA392C5A4FBD00091322 /* test_instance_tracker_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_instance_tracker_test.cc; sourceTree = ""; }; + E318DA3A2C5A4FBD00091322 /* test_instance_tracker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_instance_tracker.cc; sourceTree = ""; }; + E318DA3B2C5A4FBD00091322 /* test_instance_tracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test_instance_tracker.h; sourceTree = ""; }; + E318DA3C2C5A4FBD00091322 /* tracked.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tracked.h; sourceTree = ""; }; + E318DA3D2C5A4FBD00091322 /* unordered_map_constructor_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_map_constructor_test.h; sourceTree = ""; }; + E318DA3E2C5A4FBD00091322 /* unordered_map_lookup_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_map_lookup_test.h; sourceTree = ""; }; + E318DA3F2C5A4FBD00091322 /* unordered_map_members_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_map_members_test.h; sourceTree = ""; }; + E318DA402C5A4FBD00091322 /* unordered_map_modifiers_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_map_modifiers_test.h; sourceTree = ""; }; + E318DA412C5A4FBD00091322 /* unordered_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unordered_map_test.cc; sourceTree = ""; }; + E318DA422C5A4FBD00091322 /* unordered_set_constructor_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_set_constructor_test.h; sourceTree = ""; }; + E318DA432C5A4FBD00091322 /* unordered_set_lookup_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_set_lookup_test.h; sourceTree = ""; }; + E318DA442C5A4FBD00091322 /* unordered_set_members_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_set_members_test.h; sourceTree = ""; }; + E318DA452C5A4FBD00091322 /* unordered_set_modifiers_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unordered_set_modifiers_test.h; sourceTree = ""; }; + E318DA462C5A4FBD00091322 /* unordered_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unordered_set_test.cc; sourceTree = ""; }; + E318DA482C5A4FBD00091322 /* btree_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = btree_benchmark.cc; sourceTree = ""; }; + E318DA492C5A4FBD00091322 /* btree_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = btree_map.h; sourceTree = ""; }; + E318DA4A2C5A4FBD00091322 /* btree_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = btree_set.h; sourceTree = ""; }; + E318DA4B2C5A4FBD00091322 /* btree_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = btree_test.cc; sourceTree = ""; }; + E318DA4C2C5A4FBD00091322 /* btree_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = btree_test.h; sourceTree = ""; }; + E318DA4D2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DA4E2C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DA4F2C5A4FBD00091322 /* fixed_array_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fixed_array_benchmark.cc; sourceTree = ""; }; + E318DA502C5A4FBD00091322 /* fixed_array_exception_safety_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fixed_array_exception_safety_test.cc; sourceTree = ""; }; + E318DA512C5A4FBD00091322 /* fixed_array_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fixed_array_test.cc; sourceTree = ""; }; + E318DA522C5A4FBD00091322 /* fixed_array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fixed_array.h; sourceTree = ""; }; + E318DA532C5A4FBD00091322 /* flat_hash_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flat_hash_map_test.cc; sourceTree = ""; }; + E318DA542C5A4FBD00091322 /* flat_hash_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flat_hash_map.h; sourceTree = ""; }; + E318DA552C5A4FBD00091322 /* flat_hash_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flat_hash_set_test.cc; sourceTree = ""; }; + E318DA562C5A4FBD00091322 /* flat_hash_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flat_hash_set.h; sourceTree = ""; }; + E318DA572C5A4FBD00091322 /* inlined_vector_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inlined_vector_benchmark.cc; sourceTree = ""; }; + E318DA582C5A4FBD00091322 /* inlined_vector_exception_safety_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inlined_vector_exception_safety_test.cc; sourceTree = ""; }; + E318DA592C5A4FBD00091322 /* inlined_vector_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inlined_vector_test.cc; sourceTree = ""; }; + E318DA5A2C5A4FBD00091322 /* inlined_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inlined_vector.h; sourceTree = ""; }; + E318DA5B2C5A4FBD00091322 /* node_hash_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_hash_map_test.cc; sourceTree = ""; }; + E318DA5C2C5A4FBD00091322 /* node_hash_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = node_hash_map.h; sourceTree = ""; }; + E318DA5D2C5A4FBD00091322 /* node_hash_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_hash_set_test.cc; sourceTree = ""; }; + E318DA5E2C5A4FBD00091322 /* node_hash_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = node_hash_set.h; sourceTree = ""; }; + E318DA5F2C5A4FBD00091322 /* sample_element_size_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample_element_size_test.cc; sourceTree = ""; }; + E318DA612C5A4FBD00091322 /* AbseilConfigureCopts.cmake */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AbseilConfigureCopts.cmake; sourceTree = ""; }; + E318DA622C5A4FBD00091322 /* configure_copts.bzl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = configure_copts.bzl; sourceTree = ""; }; + E318DA632C5A4FBD00091322 /* copts.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = copts.py; sourceTree = ""; }; + E318DA642C5A4FBD00091322 /* generate_copts.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_copts.py; sourceTree = ""; }; + E318DA652C5A4FBD00091322 /* GENERATED_AbseilCopts.cmake */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GENERATED_AbseilCopts.cmake; sourceTree = ""; }; + E318DA662C5A4FBD00091322 /* GENERATED_copts.bzl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GENERATED_copts.bzl; sourceTree = ""; }; + E318DA692C5A4FBD00091322 /* address_is_readable.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = address_is_readable.cc; sourceTree = ""; }; + E318DA6A2C5A4FBD00091322 /* address_is_readable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = address_is_readable.h; sourceTree = ""; }; + E318DA6B2C5A4FBD00091322 /* demangle_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = demangle_test.cc; sourceTree = ""; }; + E318DA6C2C5A4FBD00091322 /* demangle.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = demangle.cc; sourceTree = ""; }; + E318DA6D2C5A4FBD00091322 /* demangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = demangle.h; sourceTree = ""; }; + E318DA6E2C5A4FBD00091322 /* elf_mem_image.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = elf_mem_image.cc; sourceTree = ""; }; + E318DA6F2C5A4FBD00091322 /* elf_mem_image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = elf_mem_image.h; sourceTree = ""; }; + E318DA702C5A4FBD00091322 /* examine_stack.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = examine_stack.cc; sourceTree = ""; }; + E318DA712C5A4FBD00091322 /* examine_stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = examine_stack.h; sourceTree = ""; }; + E318DA722C5A4FBD00091322 /* stack_consumption_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stack_consumption_test.cc; sourceTree = ""; }; + E318DA732C5A4FBD00091322 /* stack_consumption.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stack_consumption.cc; sourceTree = ""; }; + E318DA742C5A4FBD00091322 /* stack_consumption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_consumption.h; sourceTree = ""; }; + E318DA752C5A4FBD00091322 /* stacktrace_aarch64-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_aarch64-inl.inc"; sourceTree = ""; }; + E318DA762C5A4FBD00091322 /* stacktrace_arm-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_arm-inl.inc"; sourceTree = ""; }; + E318DA772C5A4FBD00091322 /* stacktrace_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stacktrace_config.h; sourceTree = ""; }; + E318DA782C5A4FBD00091322 /* stacktrace_emscripten-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_emscripten-inl.inc"; sourceTree = ""; }; + E318DA792C5A4FBD00091322 /* stacktrace_generic-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_generic-inl.inc"; sourceTree = ""; }; + E318DA7A2C5A4FBD00091322 /* stacktrace_powerpc-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_powerpc-inl.inc"; sourceTree = ""; }; + E318DA7B2C5A4FBD00091322 /* stacktrace_riscv-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_riscv-inl.inc"; sourceTree = ""; }; + E318DA7C2C5A4FBD00091322 /* stacktrace_unimplemented-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_unimplemented-inl.inc"; sourceTree = ""; }; + E318DA7D2C5A4FBD00091322 /* stacktrace_win32-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_win32-inl.inc"; sourceTree = ""; }; + E318DA7E2C5A4FBD00091322 /* stacktrace_x86-inl.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = "stacktrace_x86-inl.inc"; sourceTree = ""; }; + E318DA7F2C5A4FBD00091322 /* symbolize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = symbolize.h; sourceTree = ""; }; + E318DA802C5A4FBD00091322 /* vdso_support.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vdso_support.cc; sourceTree = ""; }; + E318DA812C5A4FBD00091322 /* vdso_support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vdso_support.h; sourceTree = ""; }; + E318DA832C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DA842C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DA852C5A4FBD00091322 /* failure_signal_handler_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = failure_signal_handler_test.cc; sourceTree = ""; }; + E318DA862C5A4FBD00091322 /* failure_signal_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = failure_signal_handler.cc; sourceTree = ""; }; + E318DA872C5A4FBD00091322 /* failure_signal_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = failure_signal_handler.h; sourceTree = ""; }; + E318DA882C5A4FBD00091322 /* leak_check_fail_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = leak_check_fail_test.cc; sourceTree = ""; }; + E318DA892C5A4FBD00091322 /* leak_check_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = leak_check_test.cc; sourceTree = ""; }; + E318DA8A2C5A4FBD00091322 /* leak_check.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = leak_check.cc; sourceTree = ""; }; + E318DA8B2C5A4FBD00091322 /* leak_check.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = leak_check.h; sourceTree = ""; }; + E318DA8C2C5A4FBD00091322 /* stacktrace_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stacktrace_benchmark.cc; sourceTree = ""; }; + E318DA8D2C5A4FBD00091322 /* stacktrace.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stacktrace.cc; sourceTree = ""; }; + E318DA8E2C5A4FBD00091322 /* stacktrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stacktrace.h; sourceTree = ""; }; + E318DA8F2C5A4FBD00091322 /* symbolize_darwin.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = symbolize_darwin.inc; sourceTree = ""; }; + E318DA902C5A4FBD00091322 /* symbolize_elf.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = symbolize_elf.inc; sourceTree = ""; }; + E318DA912C5A4FBD00091322 /* symbolize_emscripten.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = symbolize_emscripten.inc; sourceTree = ""; }; + E318DA922C5A4FBD00091322 /* symbolize_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = symbolize_test.cc; sourceTree = ""; }; + E318DA932C5A4FBD00091322 /* symbolize_unimplemented.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = symbolize_unimplemented.inc; sourceTree = ""; }; + E318DA942C5A4FBD00091322 /* symbolize_win32.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = symbolize_win32.inc; sourceTree = ""; }; + E318DA952C5A4FBD00091322 /* symbolize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = symbolize.cc; sourceTree = ""; }; + E318DA962C5A4FBD00091322 /* symbolize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = symbolize.h; sourceTree = ""; }; + E318DA992C5A4FBD00091322 /* commandlineflag.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = commandlineflag.cc; sourceTree = ""; }; + E318DA9A2C5A4FBD00091322 /* commandlineflag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commandlineflag.h; sourceTree = ""; }; + E318DA9B2C5A4FBD00091322 /* flag_msvc.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = flag_msvc.inc; sourceTree = ""; }; + E318DA9C2C5A4FBD00091322 /* flag.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flag.cc; sourceTree = ""; }; + E318DA9D2C5A4FBD00091322 /* flag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flag.h; sourceTree = ""; }; + E318DA9E2C5A4FBD00091322 /* parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parse.h; sourceTree = ""; }; + E318DA9F2C5A4FBD00091322 /* path_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = path_util_test.cc; sourceTree = ""; }; + E318DAA02C5A4FBD00091322 /* path_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = path_util.h; sourceTree = ""; }; + E318DAA12C5A4FBD00091322 /* private_handle_accessor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = private_handle_accessor.cc; sourceTree = ""; }; + E318DAA22C5A4FBD00091322 /* private_handle_accessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = private_handle_accessor.h; sourceTree = ""; }; + E318DAA32C5A4FBD00091322 /* program_name_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = program_name_test.cc; sourceTree = ""; }; + E318DAA42C5A4FBD00091322 /* program_name.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = program_name.cc; sourceTree = ""; }; + E318DAA52C5A4FBD00091322 /* program_name.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = program_name.h; sourceTree = ""; }; + E318DAA62C5A4FBD00091322 /* registry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = registry.h; sourceTree = ""; }; + E318DAA72C5A4FBD00091322 /* sequence_lock_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sequence_lock_test.cc; sourceTree = ""; }; + E318DAA82C5A4FBD00091322 /* sequence_lock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sequence_lock.h; sourceTree = ""; }; + E318DAA92C5A4FBD00091322 /* usage_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usage_test.cc; sourceTree = ""; }; + E318DAAA2C5A4FBD00091322 /* usage.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usage.cc; sourceTree = ""; }; + E318DAAB2C5A4FBD00091322 /* usage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usage.h; sourceTree = ""; }; + E318DAAD2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DAAE2C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DAAF2C5A4FBD00091322 /* commandlineflag_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = commandlineflag_test.cc; sourceTree = ""; }; + E318DAB02C5A4FBD00091322 /* commandlineflag.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = commandlineflag.cc; sourceTree = ""; }; + E318DAB12C5A4FBD00091322 /* commandlineflag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commandlineflag.h; sourceTree = ""; }; + E318DAB22C5A4FBD00091322 /* config_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_test.cc; sourceTree = ""; }; + E318DAB32C5A4FBD00091322 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; + E318DAB42C5A4FBD00091322 /* declare.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = declare.h; sourceTree = ""; }; + E318DAB52C5A4FBD00091322 /* flag_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flag_benchmark.cc; sourceTree = ""; }; + E318DAB62C5A4FBD00091322 /* flag_benchmark.lds */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = flag_benchmark.lds; sourceTree = ""; }; + E318DAB72C5A4FBD00091322 /* flag_test_defs.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flag_test_defs.cc; sourceTree = ""; }; + E318DAB82C5A4FBD00091322 /* flag_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flag_test.cc; sourceTree = ""; }; + E318DAB92C5A4FBD00091322 /* flag.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flag.cc; sourceTree = ""; }; + E318DABA2C5A4FBD00091322 /* flag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flag.h; sourceTree = ""; }; + E318DABB2C5A4FBD00091322 /* marshalling_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = marshalling_test.cc; sourceTree = ""; }; + E318DABC2C5A4FBD00091322 /* marshalling.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = marshalling.cc; sourceTree = ""; }; + E318DABD2C5A4FBD00091322 /* marshalling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = marshalling.h; sourceTree = ""; }; + E318DABE2C5A4FBD00091322 /* parse_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parse_test.cc; sourceTree = ""; }; + E318DABF2C5A4FBD00091322 /* parse.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parse.cc; sourceTree = ""; }; + E318DAC02C5A4FBD00091322 /* parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parse.h; sourceTree = ""; }; + E318DAC12C5A4FBD00091322 /* reflection_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reflection_test.cc; sourceTree = ""; }; + E318DAC22C5A4FBD00091322 /* reflection.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reflection.cc; sourceTree = ""; }; + E318DAC32C5A4FBD00091322 /* reflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reflection.h; sourceTree = ""; }; + E318DAC42C5A4FBD00091322 /* usage_config_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usage_config_test.cc; sourceTree = ""; }; + E318DAC52C5A4FBD00091322 /* usage_config.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usage_config.cc; sourceTree = ""; }; + E318DAC62C5A4FBD00091322 /* usage_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usage_config.h; sourceTree = ""; }; + E318DAC72C5A4FBD00091322 /* usage.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = usage.cc; sourceTree = ""; }; + E318DAC82C5A4FBD00091322 /* usage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usage.h; sourceTree = ""; }; + E318DACB2C5A4FBD00091322 /* any_invocable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = any_invocable.h; sourceTree = ""; }; + E318DACC2C5A4FBD00091322 /* front_binder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = front_binder.h; sourceTree = ""; }; + E318DACD2C5A4FBD00091322 /* function_ref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = function_ref.h; sourceTree = ""; }; + E318DACF2C5A4FBD00091322 /* any_invocable_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = any_invocable_test.cc; sourceTree = ""; }; + E318DAD02C5A4FBD00091322 /* any_invocable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = any_invocable.h; sourceTree = ""; }; + E318DAD12C5A4FBD00091322 /* bind_front_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bind_front_test.cc; sourceTree = ""; }; + E318DAD22C5A4FBD00091322 /* bind_front.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bind_front.h; sourceTree = ""; }; + E318DAD32C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DAD42C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DAD52C5A4FBD00091322 /* function_ref_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = function_ref_test.cc; sourceTree = ""; }; + E318DAD62C5A4FBD00091322 /* function_ref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = function_ref.h; sourceTree = ""; }; + E318DAD72C5A4FBD00091322 /* function_type_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = function_type_benchmark.cc; sourceTree = ""; }; + E318DADA2C5A4FBD00091322 /* city_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = city_test.cc; sourceTree = ""; }; + E318DADB2C5A4FBD00091322 /* city.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = city.cc; sourceTree = ""; }; + E318DADC2C5A4FBD00091322 /* city.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = city.h; sourceTree = ""; }; + E318DADD2C5A4FBD00091322 /* hash.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash.cc; sourceTree = ""; }; + E318DADE2C5A4FBD00091322 /* hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash.h; sourceTree = ""; }; + E318DADF2C5A4FBD00091322 /* low_level_hash_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = low_level_hash_test.cc; sourceTree = ""; }; + E318DAE02C5A4FBD00091322 /* low_level_hash.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = low_level_hash.cc; sourceTree = ""; }; + E318DAE12C5A4FBD00091322 /* low_level_hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = low_level_hash.h; sourceTree = ""; }; + E318DAE22C5A4FBD00091322 /* print_hash_of.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = print_hash_of.cc; sourceTree = ""; }; + E318DAE32C5A4FBD00091322 /* spy_hash_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spy_hash_state.h; sourceTree = ""; }; + E318DAE52C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DAE62C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DAE72C5A4FBD00091322 /* hash_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash_benchmark.cc; sourceTree = ""; }; + E318DAE82C5A4FBD00091322 /* hash_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash_test.cc; sourceTree = ""; }; + E318DAE92C5A4FBD00091322 /* hash_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash_testing.h; sourceTree = ""; }; + E318DAEA2C5A4FBD00091322 /* hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash.h; sourceTree = ""; }; + E318DAED2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DAEE2C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DAEF2C5A4FBD00091322 /* memory_exception_safety_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memory_exception_safety_test.cc; sourceTree = ""; }; + E318DAF02C5A4FBD00091322 /* memory_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memory_test.cc; sourceTree = ""; }; + E318DAF12C5A4FBD00091322 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = ""; }; + E318DAF42C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DAF52C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DAF62C5A4FBD00091322 /* type_traits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = type_traits_test.cc; sourceTree = ""; }; + E318DAF72C5A4FBD00091322 /* type_traits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = type_traits.h; sourceTree = ""; }; + E318DAFA2C5A4FBD00091322 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = ""; }; + E318DAFB2C5A4FBD00091322 /* representation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = representation.h; sourceTree = ""; }; + E318DAFD2C5A4FBD00091322 /* bits_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bits_benchmark.cc; sourceTree = ""; }; + E318DAFE2C5A4FBD00091322 /* bits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bits_test.cc; sourceTree = ""; }; + E318DAFF2C5A4FBD00091322 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = ""; }; + E318DB002C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DB012C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DB022C5A4FBD00091322 /* int128_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = int128_benchmark.cc; sourceTree = ""; }; + E318DB032C5A4FBD00091322 /* int128_have_intrinsic.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = int128_have_intrinsic.inc; sourceTree = ""; }; + E318DB042C5A4FBD00091322 /* int128_no_intrinsic.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = int128_no_intrinsic.inc; sourceTree = ""; }; + E318DB052C5A4FBD00091322 /* int128_stream_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = int128_stream_test.cc; sourceTree = ""; }; + E318DB062C5A4FBD00091322 /* int128_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = int128_test.cc; sourceTree = ""; }; + E318DB072C5A4FBD00091322 /* int128.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = int128.cc; sourceTree = ""; }; + E318DB082C5A4FBD00091322 /* int128.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = int128.h; sourceTree = ""; }; + E318DB0B2C5A4FBD00091322 /* exponential_biased_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exponential_biased_test.cc; sourceTree = ""; }; + E318DB0C2C5A4FBD00091322 /* exponential_biased.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exponential_biased.cc; sourceTree = ""; }; + E318DB0D2C5A4FBD00091322 /* exponential_biased.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exponential_biased.h; sourceTree = ""; }; + E318DB0E2C5A4FBD00091322 /* periodic_sampler_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = periodic_sampler_benchmark.cc; sourceTree = ""; }; + E318DB0F2C5A4FBD00091322 /* periodic_sampler_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = periodic_sampler_test.cc; sourceTree = ""; }; + E318DB102C5A4FBD00091322 /* periodic_sampler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = periodic_sampler.cc; sourceTree = ""; }; + E318DB112C5A4FBD00091322 /* periodic_sampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = periodic_sampler.h; sourceTree = ""; }; + E318DB122C5A4FBD00091322 /* sample_recorder_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample_recorder_test.cc; sourceTree = ""; }; + E318DB132C5A4FBD00091322 /* sample_recorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sample_recorder.h; sourceTree = ""; }; + E318DB152C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DB162C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DB192C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DB1A2C5A4FBD00091322 /* chi_square_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chi_square_test.cc; sourceTree = ""; }; + E318DB1B2C5A4FBD00091322 /* chi_square.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chi_square.cc; sourceTree = ""; }; + E318DB1C2C5A4FBD00091322 /* chi_square.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chi_square.h; sourceTree = ""; }; + E318DB1D2C5A4FBD00091322 /* distribution_caller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = distribution_caller.h; sourceTree = ""; }; + E318DB1E2C5A4FBD00091322 /* distribution_test_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = distribution_test_util_test.cc; sourceTree = ""; }; + E318DB1F2C5A4FBD00091322 /* distribution_test_util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = distribution_test_util.cc; sourceTree = ""; }; + E318DB202C5A4FBD00091322 /* distribution_test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = distribution_test_util.h; sourceTree = ""; }; + E318DB212C5A4FBD00091322 /* explicit_seed_seq_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = explicit_seed_seq_test.cc; sourceTree = ""; }; + E318DB222C5A4FBD00091322 /* explicit_seed_seq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = explicit_seed_seq.h; sourceTree = ""; }; + E318DB232C5A4FBD00091322 /* fast_uniform_bits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fast_uniform_bits_test.cc; sourceTree = ""; }; + E318DB242C5A4FBD00091322 /* fast_uniform_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fast_uniform_bits.h; sourceTree = ""; }; + E318DB252C5A4FBD00091322 /* fastmath_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fastmath_test.cc; sourceTree = ""; }; + E318DB262C5A4FBD00091322 /* fastmath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fastmath.h; sourceTree = ""; }; + E318DB272C5A4FBD00091322 /* gaussian_distribution_gentables.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gaussian_distribution_gentables.cc; sourceTree = ""; }; + E318DB282C5A4FBD00091322 /* generate_real_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = generate_real_test.cc; sourceTree = ""; }; + E318DB292C5A4FBD00091322 /* generate_real.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = generate_real.h; sourceTree = ""; }; + E318DB2A2C5A4FBD00091322 /* iostream_state_saver_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iostream_state_saver_test.cc; sourceTree = ""; }; + E318DB2B2C5A4FBD00091322 /* iostream_state_saver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iostream_state_saver.h; sourceTree = ""; }; + E318DB2C2C5A4FBD00091322 /* mock_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mock_helpers.h; sourceTree = ""; }; + E318DB2D2C5A4FBD00091322 /* mock_overload_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mock_overload_set.h; sourceTree = ""; }; + E318DB2E2C5A4FBD00091322 /* nanobenchmark_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nanobenchmark_test.cc; sourceTree = ""; }; + E318DB2F2C5A4FBD00091322 /* nanobenchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nanobenchmark.cc; sourceTree = ""; }; + E318DB302C5A4FBD00091322 /* nanobenchmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nanobenchmark.h; sourceTree = ""; }; + E318DB312C5A4FBD00091322 /* nonsecure_base_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nonsecure_base_test.cc; sourceTree = ""; }; + E318DB322C5A4FBD00091322 /* nonsecure_base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nonsecure_base.h; sourceTree = ""; }; + E318DB332C5A4FBD00091322 /* pcg_engine_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pcg_engine_test.cc; sourceTree = ""; }; + E318DB342C5A4FBD00091322 /* pcg_engine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pcg_engine.h; sourceTree = ""; }; + E318DB352C5A4FBD00091322 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = platform.h; sourceTree = ""; }; + E318DB362C5A4FBD00091322 /* pool_urbg_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pool_urbg_test.cc; sourceTree = ""; }; + E318DB372C5A4FBD00091322 /* pool_urbg.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pool_urbg.cc; sourceTree = ""; }; + E318DB382C5A4FBD00091322 /* pool_urbg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pool_urbg.h; sourceTree = ""; }; + E318DB392C5A4FBD00091322 /* randen_benchmarks.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_benchmarks.cc; sourceTree = ""; }; + E318DB3A2C5A4FBD00091322 /* randen_detect.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_detect.cc; sourceTree = ""; }; + E318DB3B2C5A4FBD00091322 /* randen_detect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = randen_detect.h; sourceTree = ""; }; + E318DB3C2C5A4FBD00091322 /* randen_engine_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_engine_test.cc; sourceTree = ""; }; + E318DB3D2C5A4FBD00091322 /* randen_engine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = randen_engine.h; sourceTree = ""; }; + E318DB3E2C5A4FBD00091322 /* randen_hwaes_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_hwaes_test.cc; sourceTree = ""; }; + E318DB3F2C5A4FBD00091322 /* randen_hwaes.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_hwaes.cc; sourceTree = ""; }; + E318DB402C5A4FBD00091322 /* randen_hwaes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = randen_hwaes.h; sourceTree = ""; }; + E318DB412C5A4FBD00091322 /* randen_round_keys.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_round_keys.cc; sourceTree = ""; }; + E318DB422C5A4FBD00091322 /* randen_slow_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_slow_test.cc; sourceTree = ""; }; + E318DB432C5A4FBD00091322 /* randen_slow.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_slow.cc; sourceTree = ""; }; + E318DB442C5A4FBD00091322 /* randen_slow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = randen_slow.h; sourceTree = ""; }; + E318DB452C5A4FBD00091322 /* randen_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen_test.cc; sourceTree = ""; }; + E318DB462C5A4FBD00091322 /* randen_traits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = randen_traits.h; sourceTree = ""; }; + E318DB472C5A4FBD00091322 /* randen.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = randen.cc; sourceTree = ""; }; + E318DB482C5A4FBD00091322 /* randen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = randen.h; sourceTree = ""; }; + E318DB492C5A4FBD00091322 /* salted_seed_seq_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = salted_seed_seq_test.cc; sourceTree = ""; }; + E318DB4A2C5A4FBD00091322 /* salted_seed_seq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = salted_seed_seq.h; sourceTree = ""; }; + E318DB4B2C5A4FBD00091322 /* seed_material_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seed_material_test.cc; sourceTree = ""; }; + E318DB4C2C5A4FBD00091322 /* seed_material.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seed_material.cc; sourceTree = ""; }; + E318DB4D2C5A4FBD00091322 /* seed_material.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seed_material.h; sourceTree = ""; }; + E318DB4E2C5A4FBD00091322 /* sequence_urbg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sequence_urbg.h; sourceTree = ""; }; + E318DB4F2C5A4FBD00091322 /* traits_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = traits_test.cc; sourceTree = ""; }; + E318DB502C5A4FBD00091322 /* traits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = traits.h; sourceTree = ""; }; + E318DB512C5A4FBD00091322 /* uniform_helper_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = uniform_helper_test.cc; sourceTree = ""; }; + E318DB522C5A4FBD00091322 /* uniform_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uniform_helper.h; sourceTree = ""; }; + E318DB532C5A4FBD00091322 /* wide_multiply_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wide_multiply_test.cc; sourceTree = ""; }; + E318DB542C5A4FBD00091322 /* wide_multiply.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wide_multiply.h; sourceTree = ""; }; + E318DB562C5A4FBD00091322 /* benchmarks.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = benchmarks.cc; sourceTree = ""; }; + E318DB572C5A4FBD00091322 /* bernoulli_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bernoulli_distribution_test.cc; sourceTree = ""; }; + E318DB582C5A4FBD00091322 /* bernoulli_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bernoulli_distribution.h; sourceTree = ""; }; + E318DB592C5A4FBD00091322 /* beta_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = beta_distribution_test.cc; sourceTree = ""; }; + E318DB5A2C5A4FBD00091322 /* beta_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = beta_distribution.h; sourceTree = ""; }; + E318DB5B2C5A4FBD00091322 /* bit_gen_ref_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bit_gen_ref_test.cc; sourceTree = ""; }; + E318DB5C2C5A4FBD00091322 /* bit_gen_ref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_gen_ref.h; sourceTree = ""; }; + E318DB5D2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DB5E2C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DB5F2C5A4FBD00091322 /* discrete_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = discrete_distribution_test.cc; sourceTree = ""; }; + E318DB602C5A4FBD00091322 /* discrete_distribution.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = discrete_distribution.cc; sourceTree = ""; }; + E318DB612C5A4FBD00091322 /* discrete_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = discrete_distribution.h; sourceTree = ""; }; + E318DB622C5A4FBD00091322 /* distributions_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = distributions_test.cc; sourceTree = ""; }; + E318DB632C5A4FBD00091322 /* distributions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = distributions.h; sourceTree = ""; }; + E318DB642C5A4FBD00091322 /* examples_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = examples_test.cc; sourceTree = ""; }; + E318DB652C5A4FBD00091322 /* exponential_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exponential_distribution_test.cc; sourceTree = ""; }; + E318DB662C5A4FBD00091322 /* exponential_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exponential_distribution.h; sourceTree = ""; }; + E318DB672C5A4FBD00091322 /* gaussian_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gaussian_distribution_test.cc; sourceTree = ""; }; + E318DB682C5A4FBD00091322 /* gaussian_distribution.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gaussian_distribution.cc; sourceTree = ""; }; + E318DB692C5A4FBD00091322 /* gaussian_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gaussian_distribution.h; sourceTree = ""; }; + E318DB6A2C5A4FBD00091322 /* generators_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = generators_test.cc; sourceTree = ""; }; + E318DB6B2C5A4FBD00091322 /* log_uniform_int_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log_uniform_int_distribution_test.cc; sourceTree = ""; }; + E318DB6C2C5A4FBD00091322 /* log_uniform_int_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log_uniform_int_distribution.h; sourceTree = ""; }; + E318DB6D2C5A4FBD00091322 /* mock_distributions_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mock_distributions_test.cc; sourceTree = ""; }; + E318DB6E2C5A4FBD00091322 /* mock_distributions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mock_distributions.h; sourceTree = ""; }; + E318DB6F2C5A4FBD00091322 /* mocking_bit_gen_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mocking_bit_gen_test.cc; sourceTree = ""; }; + E318DB702C5A4FBD00091322 /* mocking_bit_gen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mocking_bit_gen.h; sourceTree = ""; }; + E318DB712C5A4FBD00091322 /* poisson_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = poisson_distribution_test.cc; sourceTree = ""; }; + E318DB722C5A4FBD00091322 /* poisson_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = poisson_distribution.h; sourceTree = ""; }; + E318DB732C5A4FBD00091322 /* random.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = random.h; sourceTree = ""; }; + E318DB742C5A4FBD00091322 /* seed_gen_exception.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seed_gen_exception.cc; sourceTree = ""; }; + E318DB752C5A4FBD00091322 /* seed_gen_exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seed_gen_exception.h; sourceTree = ""; }; + E318DB762C5A4FBD00091322 /* seed_sequences_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seed_sequences_test.cc; sourceTree = ""; }; + E318DB772C5A4FBD00091322 /* seed_sequences.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seed_sequences.cc; sourceTree = ""; }; + E318DB782C5A4FBD00091322 /* seed_sequences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seed_sequences.h; sourceTree = ""; }; + E318DB792C5A4FBD00091322 /* uniform_int_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = uniform_int_distribution_test.cc; sourceTree = ""; }; + E318DB7A2C5A4FBD00091322 /* uniform_int_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uniform_int_distribution.h; sourceTree = ""; }; + E318DB7B2C5A4FBD00091322 /* uniform_real_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = uniform_real_distribution_test.cc; sourceTree = ""; }; + E318DB7C2C5A4FBD00091322 /* uniform_real_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uniform_real_distribution.h; sourceTree = ""; }; + E318DB7D2C5A4FBD00091322 /* zipf_distribution_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = zipf_distribution_test.cc; sourceTree = ""; }; + E318DB7E2C5A4FBD00091322 /* zipf_distribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zipf_distribution.h; sourceTree = ""; }; + E318DB812C5A4FBD00091322 /* status_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status_internal.h; sourceTree = ""; }; + E318DB822C5A4FBD00091322 /* statusor_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = statusor_internal.h; sourceTree = ""; }; + E318DB842C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DB852C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DB862C5A4FBD00091322 /* status_payload_printer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status_payload_printer.cc; sourceTree = ""; }; + E318DB872C5A4FBD00091322 /* status_payload_printer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status_payload_printer.h; sourceTree = ""; }; + E318DB882C5A4FBD00091322 /* status_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status_test.cc; sourceTree = ""; }; + E318DB892C5A4FBD00091322 /* status.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status.cc; sourceTree = ""; }; + E318DB8A2C5A4FBD00091322 /* status.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status.h; sourceTree = ""; }; + E318DB8B2C5A4FBD00091322 /* statusor_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statusor_test.cc; sourceTree = ""; }; + E318DB8C2C5A4FBD00091322 /* statusor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statusor.cc; sourceTree = ""; }; + E318DB8D2C5A4FBD00091322 /* statusor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = statusor.h; sourceTree = ""; }; + E318DB902C5A4FBD00091322 /* arg_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arg_test.cc; sourceTree = ""; }; + E318DB912C5A4FBD00091322 /* arg.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = arg.cc; sourceTree = ""; }; + E318DB922C5A4FBD00091322 /* arg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arg.h; sourceTree = ""; }; + E318DB932C5A4FBD00091322 /* bind_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bind_test.cc; sourceTree = ""; }; + E318DB942C5A4FBD00091322 /* bind.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bind.cc; sourceTree = ""; }; + E318DB952C5A4FBD00091322 /* bind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bind.h; sourceTree = ""; }; + E318DB962C5A4FBD00091322 /* checker_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = checker_test.cc; sourceTree = ""; }; + E318DB972C5A4FBD00091322 /* checker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = checker.h; sourceTree = ""; }; + E318DB982C5A4FBD00091322 /* convert_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = convert_test.cc; sourceTree = ""; }; + E318DB992C5A4FBD00091322 /* extension_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extension_test.cc; sourceTree = ""; }; + E318DB9A2C5A4FBD00091322 /* extension.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extension.cc; sourceTree = ""; }; + E318DB9B2C5A4FBD00091322 /* extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extension.h; sourceTree = ""; }; + E318DB9C2C5A4FBD00091322 /* float_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = float_conversion.cc; sourceTree = ""; }; + E318DB9D2C5A4FBD00091322 /* float_conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = float_conversion.h; sourceTree = ""; }; + E318DB9E2C5A4FBD00091322 /* output_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = output_test.cc; sourceTree = ""; }; + E318DB9F2C5A4FBD00091322 /* output.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = output.cc; sourceTree = ""; }; + E318DBA02C5A4FBD00091322 /* output.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = output.h; sourceTree = ""; }; + E318DBA12C5A4FBD00091322 /* parser_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parser_test.cc; sourceTree = ""; }; + E318DBA22C5A4FBD00091322 /* parser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parser.cc; sourceTree = ""; }; + E318DBA32C5A4FBD00091322 /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = ""; }; + E318DBA52C5A4FBD00091322 /* char_map_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = char_map_benchmark.cc; sourceTree = ""; }; + E318DBA62C5A4FBD00091322 /* char_map_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = char_map_test.cc; sourceTree = ""; }; + E318DBA72C5A4FBD00091322 /* char_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = char_map.h; sourceTree = ""; }; + E318DBA82C5A4FBD00091322 /* charconv_bigint_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charconv_bigint_test.cc; sourceTree = ""; }; + E318DBA92C5A4FBD00091322 /* charconv_bigint.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charconv_bigint.cc; sourceTree = ""; }; + E318DBAA2C5A4FBD00091322 /* charconv_bigint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = charconv_bigint.h; sourceTree = ""; }; + E318DBAB2C5A4FBD00091322 /* charconv_parse_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charconv_parse_test.cc; sourceTree = ""; }; + E318DBAC2C5A4FBD00091322 /* charconv_parse.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charconv_parse.cc; sourceTree = ""; }; + E318DBAD2C5A4FBD00091322 /* charconv_parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = charconv_parse.h; sourceTree = ""; }; + E318DBAE2C5A4FBD00091322 /* cord_data_edge_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_data_edge_test.cc; sourceTree = ""; }; + E318DBAF2C5A4FBD00091322 /* cord_data_edge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_data_edge.h; sourceTree = ""; }; + E318DBB02C5A4FBD00091322 /* cord_internal.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_internal.cc; sourceTree = ""; }; + E318DBB12C5A4FBD00091322 /* cord_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_internal.h; sourceTree = ""; }; + E318DBB22C5A4FBD00091322 /* cord_rep_btree_navigator_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_btree_navigator_test.cc; sourceTree = ""; }; + E318DBB32C5A4FBD00091322 /* cord_rep_btree_navigator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_btree_navigator.cc; sourceTree = ""; }; + E318DBB42C5A4FBD00091322 /* cord_rep_btree_navigator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_btree_navigator.h; sourceTree = ""; }; + E318DBB52C5A4FBD00091322 /* cord_rep_btree_reader_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_btree_reader_test.cc; sourceTree = ""; }; + E318DBB62C5A4FBD00091322 /* cord_rep_btree_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_btree_reader.cc; sourceTree = ""; }; + E318DBB72C5A4FBD00091322 /* cord_rep_btree_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_btree_reader.h; sourceTree = ""; }; + E318DBB82C5A4FBD00091322 /* cord_rep_btree_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_btree_test.cc; sourceTree = ""; }; + E318DBB92C5A4FBD00091322 /* cord_rep_btree.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_btree.cc; sourceTree = ""; }; + E318DBBA2C5A4FBD00091322 /* cord_rep_btree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_btree.h; sourceTree = ""; }; + E318DBBB2C5A4FBD00091322 /* cord_rep_consume.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_consume.cc; sourceTree = ""; }; + E318DBBC2C5A4FBD00091322 /* cord_rep_consume.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_consume.h; sourceTree = ""; }; + E318DBBD2C5A4FBD00091322 /* cord_rep_crc_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_crc_test.cc; sourceTree = ""; }; + E318DBBE2C5A4FBD00091322 /* cord_rep_crc.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_crc.cc; sourceTree = ""; }; + E318DBBF2C5A4FBD00091322 /* cord_rep_crc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_crc.h; sourceTree = ""; }; + E318DBC02C5A4FBD00091322 /* cord_rep_flat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_flat.h; sourceTree = ""; }; + E318DBC12C5A4FBD00091322 /* cord_rep_ring_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_ring_reader.h; sourceTree = ""; }; + E318DBC22C5A4FBD00091322 /* cord_rep_ring.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_rep_ring.cc; sourceTree = ""; }; + E318DBC32C5A4FBD00091322 /* cord_rep_ring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_ring.h; sourceTree = ""; }; + E318DBC42C5A4FBD00091322 /* cord_rep_test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_rep_test_util.h; sourceTree = ""; }; + E318DBC52C5A4FBD00091322 /* cordz_functions_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_functions_test.cc; sourceTree = ""; }; + E318DBC62C5A4FBD00091322 /* cordz_functions.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_functions.cc; sourceTree = ""; }; + E318DBC72C5A4FBD00091322 /* cordz_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_functions.h; sourceTree = ""; }; + E318DBC82C5A4FBD00091322 /* cordz_handle_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_handle_test.cc; sourceTree = ""; }; + E318DBC92C5A4FBD00091322 /* cordz_handle.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_handle.cc; sourceTree = ""; }; + E318DBCA2C5A4FBD00091322 /* cordz_handle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_handle.h; sourceTree = ""; }; + E318DBCB2C5A4FBD00091322 /* cordz_info_statistics_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_info_statistics_test.cc; sourceTree = ""; }; + E318DBCC2C5A4FBD00091322 /* cordz_info_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_info_test.cc; sourceTree = ""; }; + E318DBCD2C5A4FBD00091322 /* cordz_info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_info.cc; sourceTree = ""; }; + E318DBCE2C5A4FBD00091322 /* cordz_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_info.h; sourceTree = ""; }; + E318DBCF2C5A4FBD00091322 /* cordz_sample_token_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_sample_token_test.cc; sourceTree = ""; }; + E318DBD02C5A4FBD00091322 /* cordz_sample_token.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_sample_token.cc; sourceTree = ""; }; + E318DBD12C5A4FBD00091322 /* cordz_sample_token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_sample_token.h; sourceTree = ""; }; + E318DBD22C5A4FBD00091322 /* cordz_statistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_statistics.h; sourceTree = ""; }; + E318DBD32C5A4FBD00091322 /* cordz_update_scope_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_update_scope_test.cc; sourceTree = ""; }; + E318DBD42C5A4FBD00091322 /* cordz_update_scope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_update_scope.h; sourceTree = ""; }; + E318DBD52C5A4FBD00091322 /* cordz_update_tracker_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_update_tracker_test.cc; sourceTree = ""; }; + E318DBD62C5A4FBD00091322 /* cordz_update_tracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_update_tracker.h; sourceTree = ""; }; + E318DBD72C5A4FBD00091322 /* escaping_test_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = escaping_test_common.h; sourceTree = ""; }; + E318DBD82C5A4FBD00091322 /* escaping.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = escaping.cc; sourceTree = ""; }; + E318DBD92C5A4FBD00091322 /* escaping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = escaping.h; sourceTree = ""; }; + E318DBDA2C5A4FBD00091322 /* memutil_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memutil_benchmark.cc; sourceTree = ""; }; + E318DBDB2C5A4FBD00091322 /* memutil_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memutil_test.cc; sourceTree = ""; }; + E318DBDC2C5A4FBD00091322 /* memutil.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memutil.cc; sourceTree = ""; }; + E318DBDD2C5A4FBD00091322 /* memutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memutil.h; sourceTree = ""; }; + E318DBDE2C5A4FBD00091322 /* numbers_test_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = numbers_test_common.h; sourceTree = ""; }; + E318DBDF2C5A4FBD00091322 /* ostringstream_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ostringstream_benchmark.cc; sourceTree = ""; }; + E318DBE02C5A4FBD00091322 /* ostringstream_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ostringstream_test.cc; sourceTree = ""; }; + E318DBE12C5A4FBD00091322 /* ostringstream.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ostringstream.cc; sourceTree = ""; }; + E318DBE22C5A4FBD00091322 /* ostringstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ostringstream.h; sourceTree = ""; }; + E318DBE32C5A4FBD00091322 /* pow10_helper_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pow10_helper_test.cc; sourceTree = ""; }; + E318DBE42C5A4FBD00091322 /* pow10_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pow10_helper.cc; sourceTree = ""; }; + E318DBE52C5A4FBD00091322 /* pow10_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pow10_helper.h; sourceTree = ""; }; + E318DBE62C5A4FBD00091322 /* resize_uninitialized_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resize_uninitialized_test.cc; sourceTree = ""; }; + E318DBE72C5A4FBD00091322 /* resize_uninitialized.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resize_uninitialized.h; sourceTree = ""; }; + E318DBE82C5A4FBD00091322 /* stl_type_traits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stl_type_traits.h; sourceTree = ""; }; + E318DBE92C5A4FBD00091322 /* str_join_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = str_join_internal.h; sourceTree = ""; }; + E318DBEA2C5A4FBD00091322 /* str_split_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = str_split_internal.h; sourceTree = ""; }; + E318DBEB2C5A4FBD00091322 /* string_constant_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_constant_test.cc; sourceTree = ""; }; + E318DBEC2C5A4FBD00091322 /* string_constant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_constant.h; sourceTree = ""; }; + E318DBED2C5A4FBD00091322 /* utf8_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utf8_test.cc; sourceTree = ""; }; + E318DBEE2C5A4FBD00091322 /* utf8.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utf8.cc; sourceTree = ""; }; + E318DBEF2C5A4FBD00091322 /* utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utf8.h; sourceTree = ""; }; + E318DBF12C5A4FBD00091322 /* ascii_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ascii_benchmark.cc; sourceTree = ""; }; + E318DBF22C5A4FBD00091322 /* ascii_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ascii_test.cc; sourceTree = ""; }; + E318DBF32C5A4FBD00091322 /* ascii.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ascii.cc; sourceTree = ""; }; + E318DBF42C5A4FBD00091322 /* ascii.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ascii.h; sourceTree = ""; }; + E318DBF52C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DBF62C5A4FBD00091322 /* charconv_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charconv_benchmark.cc; sourceTree = ""; }; + E318DBF72C5A4FBD00091322 /* charconv_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charconv_test.cc; sourceTree = ""; }; + E318DBF82C5A4FBD00091322 /* charconv.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charconv.cc; sourceTree = ""; }; + E318DBF92C5A4FBD00091322 /* charconv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = charconv.h; sourceTree = ""; }; + E318DBFA2C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DBFB2C5A4FBD00091322 /* cord_analysis.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_analysis.cc; sourceTree = ""; }; + E318DBFC2C5A4FBD00091322 /* cord_analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_analysis.h; sourceTree = ""; }; + E318DBFD2C5A4FBD00091322 /* cord_buffer_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_buffer_test.cc; sourceTree = ""; }; + E318DBFE2C5A4FBD00091322 /* cord_buffer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_buffer.cc; sourceTree = ""; }; + E318DBFF2C5A4FBD00091322 /* cord_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_buffer.h; sourceTree = ""; }; + E318DC002C5A4FBD00091322 /* cord_ring_reader_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_ring_reader_test.cc; sourceTree = ""; }; + E318DC012C5A4FBD00091322 /* cord_ring_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_ring_test.cc; sourceTree = ""; }; + E318DC022C5A4FBD00091322 /* cord_test_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord_test_helpers.h; sourceTree = ""; }; + E318DC032C5A4FBD00091322 /* cord_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord_test.cc; sourceTree = ""; }; + E318DC042C5A4FBD00091322 /* cord.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cord.cc; sourceTree = ""; }; + E318DC052C5A4FBD00091322 /* cord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cord.h; sourceTree = ""; }; + E318DC062C5A4FBD00091322 /* cordz_test_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cordz_test_helpers.h; sourceTree = ""; }; + E318DC072C5A4FBD00091322 /* cordz_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cordz_test.cc; sourceTree = ""; }; + E318DC082C5A4FBD00091322 /* escaping_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = escaping_benchmark.cc; sourceTree = ""; }; + E318DC092C5A4FBD00091322 /* escaping_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = escaping_test.cc; sourceTree = ""; }; + E318DC0A2C5A4FBD00091322 /* escaping.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = escaping.cc; sourceTree = ""; }; + E318DC0B2C5A4FBD00091322 /* escaping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = escaping.h; sourceTree = ""; }; + E318DC0C2C5A4FBD00091322 /* match_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = match_test.cc; sourceTree = ""; }; + E318DC0D2C5A4FBD00091322 /* match.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = match.cc; sourceTree = ""; }; + E318DC0E2C5A4FBD00091322 /* match.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = match.h; sourceTree = ""; }; + E318DC0F2C5A4FBD00091322 /* numbers_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = numbers_benchmark.cc; sourceTree = ""; }; + E318DC102C5A4FBD00091322 /* numbers_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = numbers_test.cc; sourceTree = ""; }; + E318DC112C5A4FBD00091322 /* numbers.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = numbers.cc; sourceTree = ""; }; + E318DC122C5A4FBD00091322 /* numbers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = numbers.h; sourceTree = ""; }; + E318DC132C5A4FBD00091322 /* str_cat_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_cat_benchmark.cc; sourceTree = ""; }; + E318DC142C5A4FBD00091322 /* str_cat_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_cat_test.cc; sourceTree = ""; }; + E318DC152C5A4FBD00091322 /* str_cat.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_cat.cc; sourceTree = ""; }; + E318DC162C5A4FBD00091322 /* str_cat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = str_cat.h; sourceTree = ""; }; + E318DC172C5A4FBD00091322 /* str_format_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_format_test.cc; sourceTree = ""; }; + E318DC182C5A4FBD00091322 /* str_format.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = str_format.h; sourceTree = ""; }; + E318DC192C5A4FBD00091322 /* str_join_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_join_benchmark.cc; sourceTree = ""; }; + E318DC1A2C5A4FBD00091322 /* str_join_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_join_test.cc; sourceTree = ""; }; + E318DC1B2C5A4FBD00091322 /* str_join.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = str_join.h; sourceTree = ""; }; + E318DC1C2C5A4FBD00091322 /* str_replace_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_replace_benchmark.cc; sourceTree = ""; }; + E318DC1D2C5A4FBD00091322 /* str_replace_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_replace_test.cc; sourceTree = ""; }; + E318DC1E2C5A4FBD00091322 /* str_replace.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_replace.cc; sourceTree = ""; }; + E318DC1F2C5A4FBD00091322 /* str_replace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = str_replace.h; sourceTree = ""; }; + E318DC202C5A4FBD00091322 /* str_split_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_split_benchmark.cc; sourceTree = ""; }; + E318DC212C5A4FBD00091322 /* str_split_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_split_test.cc; sourceTree = ""; }; + E318DC222C5A4FBD00091322 /* str_split.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = str_split.cc; sourceTree = ""; }; + E318DC232C5A4FBD00091322 /* str_split.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = str_split.h; sourceTree = ""; }; + E318DC242C5A4FBD00091322 /* string_view_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_view_benchmark.cc; sourceTree = ""; }; + E318DC252C5A4FBD00091322 /* string_view_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_view_test.cc; sourceTree = ""; }; + E318DC262C5A4FBD00091322 /* string_view.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_view.cc; sourceTree = ""; }; + E318DC272C5A4FBD00091322 /* string_view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_view.h; sourceTree = ""; }; + E318DC282C5A4FBD00091322 /* strip_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strip_test.cc; sourceTree = ""; }; + E318DC292C5A4FBD00091322 /* strip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strip.h; sourceTree = ""; }; + E318DC2A2C5A4FBD00091322 /* substitute_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = substitute_test.cc; sourceTree = ""; }; + E318DC2B2C5A4FBD00091322 /* substitute.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = substitute.cc; sourceTree = ""; }; + E318DC2C2C5A4FBD00091322 /* substitute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = substitute.h; sourceTree = ""; }; + E318DC2F2C5A4FBD00091322 /* create_thread_identity.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = create_thread_identity.cc; sourceTree = ""; }; + E318DC302C5A4FBD00091322 /* create_thread_identity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = create_thread_identity.h; sourceTree = ""; }; + E318DC312C5A4FBD00091322 /* futex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = futex.h; sourceTree = ""; }; + E318DC322C5A4FBD00091322 /* graphcycles_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphcycles_benchmark.cc; sourceTree = ""; }; + E318DC332C5A4FBD00091322 /* graphcycles_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphcycles_test.cc; sourceTree = ""; }; + E318DC342C5A4FBD00091322 /* graphcycles.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphcycles.cc; sourceTree = ""; }; + E318DC352C5A4FBD00091322 /* graphcycles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphcycles.h; sourceTree = ""; }; + E318DC362C5A4FBD00091322 /* kernel_timeout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_timeout.h; sourceTree = ""; }; + E318DC372C5A4FBD00091322 /* per_thread_sem_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = per_thread_sem_test.cc; sourceTree = ""; }; + E318DC382C5A4FBD00091322 /* per_thread_sem.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = per_thread_sem.cc; sourceTree = ""; }; + E318DC392C5A4FBD00091322 /* per_thread_sem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = per_thread_sem.h; sourceTree = ""; }; + E318DC3A2C5A4FBD00091322 /* thread_pool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread_pool.h; sourceTree = ""; }; + E318DC3B2C5A4FBD00091322 /* waiter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = waiter.cc; sourceTree = ""; }; + E318DC3C2C5A4FBD00091322 /* waiter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = waiter.h; sourceTree = ""; }; + E318DC3E2C5A4FBD00091322 /* barrier_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = barrier_test.cc; sourceTree = ""; }; + E318DC3F2C5A4FBD00091322 /* barrier.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = barrier.cc; sourceTree = ""; }; + E318DC402C5A4FBD00091322 /* barrier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = barrier.h; sourceTree = ""; }; + E318DC412C5A4FBD00091322 /* blocking_counter_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blocking_counter_benchmark.cc; sourceTree = ""; }; + E318DC422C5A4FBD00091322 /* blocking_counter_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blocking_counter_test.cc; sourceTree = ""; }; + E318DC432C5A4FBD00091322 /* blocking_counter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blocking_counter.cc; sourceTree = ""; }; + E318DC442C5A4FBD00091322 /* blocking_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blocking_counter.h; sourceTree = ""; }; + E318DC452C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DC462C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DC472C5A4FBD00091322 /* lifetime_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lifetime_test.cc; sourceTree = ""; }; + E318DC482C5A4FBD00091322 /* mutex_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutex_benchmark.cc; sourceTree = ""; }; + E318DC492C5A4FBD00091322 /* mutex_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutex_test.cc; sourceTree = ""; }; + E318DC4A2C5A4FBD00091322 /* mutex.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutex.cc; sourceTree = ""; }; + E318DC4B2C5A4FBD00091322 /* mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mutex.h; sourceTree = ""; }; + E318DC4C2C5A4FBD00091322 /* notification_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = notification_test.cc; sourceTree = ""; }; + E318DC4D2C5A4FBD00091322 /* notification.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = notification.cc; sourceTree = ""; }; + E318DC4E2C5A4FBD00091322 /* notification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notification.h; sourceTree = ""; }; + E318DC512C5A4FBD00091322 /* civil_time_detail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = civil_time_detail.h; sourceTree = ""; }; + E318DC522C5A4FBD00091322 /* civil_time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = civil_time.h; sourceTree = ""; }; + E318DC532C5A4FBD00091322 /* time_zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_zone.h; sourceTree = ""; }; + E318DC542C5A4FBD00091322 /* zone_info_source.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zone_info_source.h; sourceTree = ""; }; + E318DC572C5A4FBD00091322 /* cctz_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cctz_benchmark.cc; sourceTree = ""; }; + E318DC582C5A4FBD00091322 /* civil_time_detail.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = civil_time_detail.cc; sourceTree = ""; }; + E318DC592C5A4FBD00091322 /* civil_time_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = civil_time_test.cc; sourceTree = ""; }; + E318DC5A2C5A4FBD00091322 /* time_zone_fixed.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_fixed.cc; sourceTree = ""; }; + E318DC5B2C5A4FBD00091322 /* time_zone_fixed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_zone_fixed.h; sourceTree = ""; }; + E318DC5C2C5A4FBD00091322 /* time_zone_format_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_format_test.cc; sourceTree = ""; }; + E318DC5D2C5A4FBD00091322 /* time_zone_format.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_format.cc; sourceTree = ""; }; + E318DC5E2C5A4FBD00091322 /* time_zone_if.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_if.cc; sourceTree = ""; }; + E318DC5F2C5A4FBD00091322 /* time_zone_if.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_zone_if.h; sourceTree = ""; }; + E318DC602C5A4FBD00091322 /* time_zone_impl.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_impl.cc; sourceTree = ""; }; + E318DC612C5A4FBD00091322 /* time_zone_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_zone_impl.h; sourceTree = ""; }; + E318DC622C5A4FBD00091322 /* time_zone_info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_info.cc; sourceTree = ""; }; + E318DC632C5A4FBD00091322 /* time_zone_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_zone_info.h; sourceTree = ""; }; + E318DC642C5A4FBD00091322 /* time_zone_libc.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_libc.cc; sourceTree = ""; }; + E318DC652C5A4FBD00091322 /* time_zone_libc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_zone_libc.h; sourceTree = ""; }; + E318DC662C5A4FBD00091322 /* time_zone_lookup_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_lookup_test.cc; sourceTree = ""; }; + E318DC672C5A4FBD00091322 /* time_zone_lookup.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_lookup.cc; sourceTree = ""; }; + E318DC682C5A4FBD00091322 /* time_zone_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_posix.cc; sourceTree = ""; }; + E318DC692C5A4FBD00091322 /* time_zone_posix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_zone_posix.h; sourceTree = ""; }; + E318DC6A2C5A4FBD00091322 /* tzfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tzfile.h; sourceTree = ""; }; + E318DC6B2C5A4FBD00091322 /* zone_info_source.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = zone_info_source.cc; sourceTree = ""; }; + E318DC6D2C5A4FBD00091322 /* Abidjan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Abidjan; sourceTree = ""; }; + E318DC6E2C5A4FBD00091322 /* Accra */ = {isa = PBXFileReference; lastKnownFileType = text; path = Accra; sourceTree = ""; }; + E318DC6F2C5A4FBD00091322 /* Addis_Ababa */ = {isa = PBXFileReference; lastKnownFileType = text; path = Addis_Ababa; sourceTree = ""; }; + E318DC702C5A4FBD00091322 /* Algiers */ = {isa = PBXFileReference; lastKnownFileType = text; path = Algiers; sourceTree = ""; }; + E318DC712C5A4FBD00091322 /* Asmara */ = {isa = PBXFileReference; lastKnownFileType = text; path = Asmara; sourceTree = ""; }; + E318DC722C5A4FBD00091322 /* Asmera */ = {isa = PBXFileReference; lastKnownFileType = text; path = Asmera; sourceTree = ""; }; + E318DC732C5A4FBD00091322 /* Bamako */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bamako; sourceTree = ""; }; + E318DC742C5A4FBD00091322 /* Bangui */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bangui; sourceTree = ""; }; + E318DC752C5A4FBD00091322 /* Banjul */ = {isa = PBXFileReference; lastKnownFileType = text; path = Banjul; sourceTree = ""; }; + E318DC762C5A4FBD00091322 /* Bissau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bissau; sourceTree = ""; }; + E318DC772C5A4FBD00091322 /* Blantyre */ = {isa = PBXFileReference; lastKnownFileType = text; path = Blantyre; sourceTree = ""; }; + E318DC782C5A4FBD00091322 /* Brazzaville */ = {isa = PBXFileReference; lastKnownFileType = text; path = Brazzaville; sourceTree = ""; }; + E318DC792C5A4FBD00091322 /* Bujumbura */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bujumbura; sourceTree = ""; }; + E318DC7A2C5A4FBD00091322 /* Cairo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cairo; sourceTree = ""; }; + E318DC7B2C5A4FBD00091322 /* Casablanca */ = {isa = PBXFileReference; lastKnownFileType = text; path = Casablanca; sourceTree = ""; }; + E318DC7C2C5A4FBD00091322 /* Ceuta */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ceuta; sourceTree = ""; }; + E318DC7D2C5A4FBD00091322 /* Conakry */ = {isa = PBXFileReference; lastKnownFileType = text; path = Conakry; sourceTree = ""; }; + E318DC7E2C5A4FBD00091322 /* Dakar */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dakar; sourceTree = ""; }; + E318DC7F2C5A4FBD00091322 /* Dar_es_Salaam */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dar_es_Salaam; sourceTree = ""; }; + E318DC802C5A4FBD00091322 /* Djibouti */ = {isa = PBXFileReference; lastKnownFileType = text; path = Djibouti; sourceTree = ""; }; + E318DC812C5A4FBD00091322 /* Douala */ = {isa = PBXFileReference; lastKnownFileType = text; path = Douala; sourceTree = ""; }; + E318DC822C5A4FBD00091322 /* El_Aaiun */ = {isa = PBXFileReference; lastKnownFileType = text; path = El_Aaiun; sourceTree = ""; }; + E318DC832C5A4FBD00091322 /* Freetown */ = {isa = PBXFileReference; lastKnownFileType = text; path = Freetown; sourceTree = ""; }; + E318DC842C5A4FBD00091322 /* Gaborone */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gaborone; sourceTree = ""; }; + E318DC852C5A4FBD00091322 /* Harare */ = {isa = PBXFileReference; lastKnownFileType = text; path = Harare; sourceTree = ""; }; + E318DC862C5A4FBD00091322 /* Johannesburg */ = {isa = PBXFileReference; lastKnownFileType = text; path = Johannesburg; sourceTree = ""; }; + E318DC872C5A4FBD00091322 /* Juba */ = {isa = PBXFileReference; lastKnownFileType = text; path = Juba; sourceTree = ""; }; + E318DC882C5A4FBD00091322 /* Kampala */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kampala; sourceTree = ""; }; + E318DC892C5A4FBD00091322 /* Khartoum */ = {isa = PBXFileReference; lastKnownFileType = text; path = Khartoum; sourceTree = ""; }; + E318DC8A2C5A4FBD00091322 /* Kigali */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kigali; sourceTree = ""; }; + E318DC8B2C5A4FBD00091322 /* Kinshasa */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kinshasa; sourceTree = ""; }; + E318DC8C2C5A4FBD00091322 /* Lagos */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lagos; sourceTree = ""; }; + E318DC8D2C5A4FBD00091322 /* Libreville */ = {isa = PBXFileReference; lastKnownFileType = text; path = Libreville; sourceTree = ""; }; + E318DC8E2C5A4FBD00091322 /* Lome */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lome; sourceTree = ""; }; + E318DC8F2C5A4FBD00091322 /* Luanda */ = {isa = PBXFileReference; lastKnownFileType = text; path = Luanda; sourceTree = ""; }; + E318DC902C5A4FBD00091322 /* Lubumbashi */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lubumbashi; sourceTree = ""; }; + E318DC912C5A4FBD00091322 /* Lusaka */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lusaka; sourceTree = ""; }; + E318DC922C5A4FBD00091322 /* Malabo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Malabo; sourceTree = ""; }; + E318DC932C5A4FBD00091322 /* Maputo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Maputo; sourceTree = ""; }; + E318DC942C5A4FBD00091322 /* Maseru */ = {isa = PBXFileReference; lastKnownFileType = text; path = Maseru; sourceTree = ""; }; + E318DC952C5A4FBD00091322 /* Mbabane */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mbabane; sourceTree = ""; }; + E318DC962C5A4FBD00091322 /* Mogadishu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mogadishu; sourceTree = ""; }; + E318DC972C5A4FBD00091322 /* Monrovia */ = {isa = PBXFileReference; lastKnownFileType = text; path = Monrovia; sourceTree = ""; }; + E318DC982C5A4FBD00091322 /* Nairobi */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nairobi; sourceTree = ""; }; + E318DC992C5A4FBD00091322 /* Ndjamena */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ndjamena; sourceTree = ""; }; + E318DC9A2C5A4FBD00091322 /* Niamey */ = {isa = PBXFileReference; lastKnownFileType = text; path = Niamey; sourceTree = ""; }; + E318DC9B2C5A4FBD00091322 /* Nouakchott */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nouakchott; sourceTree = ""; }; + E318DC9C2C5A4FBD00091322 /* Ouagadougou */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ouagadougou; sourceTree = ""; }; + E318DC9D2C5A4FBD00091322 /* Porto-Novo */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Porto-Novo"; sourceTree = ""; }; + E318DC9E2C5A4FBD00091322 /* Sao_Tome */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sao_Tome; sourceTree = ""; }; + E318DC9F2C5A4FBD00091322 /* Timbuktu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Timbuktu; sourceTree = ""; }; + E318DCA02C5A4FBD00091322 /* Tripoli */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tripoli; sourceTree = ""; }; + E318DCA12C5A4FBD00091322 /* Tunis */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tunis; sourceTree = ""; }; + E318DCA22C5A4FBD00091322 /* Windhoek */ = {isa = PBXFileReference; lastKnownFileType = text; path = Windhoek; sourceTree = ""; }; + E318DCA42C5A4FBD00091322 /* Buenos_Aires */ = {isa = PBXFileReference; lastKnownFileType = text; path = Buenos_Aires; sourceTree = ""; }; + E318DCA52C5A4FBD00091322 /* Catamarca */ = {isa = PBXFileReference; lastKnownFileType = text; path = Catamarca; sourceTree = ""; }; + E318DCA62C5A4FBD00091322 /* ComodRivadavia */ = {isa = PBXFileReference; lastKnownFileType = text; path = ComodRivadavia; sourceTree = ""; }; + E318DCA72C5A4FBD00091322 /* Cordoba */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cordoba; sourceTree = ""; }; + E318DCA82C5A4FBD00091322 /* Jujuy */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jujuy; sourceTree = ""; }; + E318DCA92C5A4FBD00091322 /* La_Rioja */ = {isa = PBXFileReference; lastKnownFileType = text; path = La_Rioja; sourceTree = ""; }; + E318DCAA2C5A4FBD00091322 /* Mendoza */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mendoza; sourceTree = ""; }; + E318DCAB2C5A4FBD00091322 /* Rio_Gallegos */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rio_Gallegos; sourceTree = ""; }; + E318DCAC2C5A4FBD00091322 /* Salta */ = {isa = PBXFileReference; lastKnownFileType = text; path = Salta; sourceTree = ""; }; + E318DCAD2C5A4FBD00091322 /* San_Juan */ = {isa = PBXFileReference; lastKnownFileType = text; path = San_Juan; sourceTree = ""; }; + E318DCAE2C5A4FBD00091322 /* San_Luis */ = {isa = PBXFileReference; lastKnownFileType = text; path = San_Luis; sourceTree = ""; }; + E318DCAF2C5A4FBD00091322 /* Tucuman */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tucuman; sourceTree = ""; }; + E318DCB02C5A4FBD00091322 /* Ushuaia */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ushuaia; sourceTree = ""; }; + E318DCB22C5A4FBD00091322 /* Indianapolis */ = {isa = PBXFileReference; lastKnownFileType = text; path = Indianapolis; sourceTree = ""; }; + E318DCB32C5A4FBD00091322 /* Knox */ = {isa = PBXFileReference; lastKnownFileType = text; path = Knox; sourceTree = ""; }; + E318DCB42C5A4FBD00091322 /* Marengo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Marengo; sourceTree = ""; }; + E318DCB52C5A4FBD00091322 /* Petersburg */ = {isa = PBXFileReference; lastKnownFileType = text; path = Petersburg; sourceTree = ""; }; + E318DCB62C5A4FBD00091322 /* Tell_City */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tell_City; sourceTree = ""; }; + E318DCB72C5A4FBD00091322 /* Vevay */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vevay; sourceTree = ""; }; + E318DCB82C5A4FBD00091322 /* Vincennes */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vincennes; sourceTree = ""; }; + E318DCB92C5A4FBD00091322 /* Winamac */ = {isa = PBXFileReference; lastKnownFileType = text; path = Winamac; sourceTree = ""; }; + E318DCBB2C5A4FBD00091322 /* Louisville */ = {isa = PBXFileReference; lastKnownFileType = text; path = Louisville; sourceTree = ""; }; + E318DCBC2C5A4FBD00091322 /* Monticello */ = {isa = PBXFileReference; lastKnownFileType = text; path = Monticello; sourceTree = ""; }; + E318DCBE2C5A4FBD00091322 /* Beulah */ = {isa = PBXFileReference; lastKnownFileType = text; path = Beulah; sourceTree = ""; }; + E318DCBF2C5A4FBD00091322 /* Center */ = {isa = PBXFileReference; lastKnownFileType = text; path = Center; sourceTree = ""; }; + E318DCC02C5A4FBD00091322 /* New_Salem */ = {isa = PBXFileReference; lastKnownFileType = text; path = New_Salem; sourceTree = ""; }; + E318DCC22C5A4FBD00091322 /* Adak */ = {isa = PBXFileReference; lastKnownFileType = text; path = Adak; sourceTree = ""; }; + E318DCC32C5A4FBD00091322 /* Anchorage */ = {isa = PBXFileReference; lastKnownFileType = text; path = Anchorage; sourceTree = ""; }; + E318DCC42C5A4FBD00091322 /* Anguilla */ = {isa = PBXFileReference; lastKnownFileType = text; path = Anguilla; sourceTree = ""; }; + E318DCC52C5A4FBD00091322 /* Antigua */ = {isa = PBXFileReference; lastKnownFileType = text; path = Antigua; sourceTree = ""; }; + E318DCC62C5A4FBD00091322 /* Araguaina */ = {isa = PBXFileReference; lastKnownFileType = text; path = Araguaina; sourceTree = ""; }; + E318DCC72C5A4FBD00091322 /* Aruba */ = {isa = PBXFileReference; lastKnownFileType = text; path = Aruba; sourceTree = ""; }; + E318DCC82C5A4FBD00091322 /* Asuncion */ = {isa = PBXFileReference; lastKnownFileType = text; path = Asuncion; sourceTree = ""; }; + E318DCC92C5A4FBD00091322 /* Atikokan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Atikokan; sourceTree = ""; }; + E318DCCA2C5A4FBD00091322 /* Atka */ = {isa = PBXFileReference; lastKnownFileType = text; path = Atka; sourceTree = ""; }; + E318DCCB2C5A4FBD00091322 /* Bahia */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bahia; sourceTree = ""; }; + E318DCCC2C5A4FBD00091322 /* Bahia_Banderas */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bahia_Banderas; sourceTree = ""; }; + E318DCCD2C5A4FBD00091322 /* Barbados */ = {isa = PBXFileReference; lastKnownFileType = text; path = Barbados; sourceTree = ""; }; + E318DCCE2C5A4FBD00091322 /* Belem */ = {isa = PBXFileReference; lastKnownFileType = text; path = Belem; sourceTree = ""; }; + E318DCCF2C5A4FBD00091322 /* Belize */ = {isa = PBXFileReference; lastKnownFileType = text; path = Belize; sourceTree = ""; }; + E318DCD02C5A4FBD00091322 /* Blanc-Sablon */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Blanc-Sablon"; sourceTree = ""; }; + E318DCD12C5A4FBD00091322 /* Boa_Vista */ = {isa = PBXFileReference; lastKnownFileType = text; path = Boa_Vista; sourceTree = ""; }; + E318DCD22C5A4FBD00091322 /* Bogota */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bogota; sourceTree = ""; }; + E318DCD32C5A4FBD00091322 /* Boise */ = {isa = PBXFileReference; lastKnownFileType = text; path = Boise; sourceTree = ""; }; + E318DCD42C5A4FBD00091322 /* Buenos_Aires */ = {isa = PBXFileReference; lastKnownFileType = text; path = Buenos_Aires; sourceTree = ""; }; + E318DCD52C5A4FBD00091322 /* Cambridge_Bay */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cambridge_Bay; sourceTree = ""; }; + E318DCD62C5A4FBD00091322 /* Campo_Grande */ = {isa = PBXFileReference; lastKnownFileType = text; path = Campo_Grande; sourceTree = ""; }; + E318DCD72C5A4FBD00091322 /* Cancun */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cancun; sourceTree = ""; }; + E318DCD82C5A4FBD00091322 /* Caracas */ = {isa = PBXFileReference; lastKnownFileType = text; path = Caracas; sourceTree = ""; }; + E318DCD92C5A4FBD00091322 /* Catamarca */ = {isa = PBXFileReference; lastKnownFileType = text; path = Catamarca; sourceTree = ""; }; + E318DCDA2C5A4FBD00091322 /* Cayenne */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cayenne; sourceTree = ""; }; + E318DCDB2C5A4FBD00091322 /* Cayman */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cayman; sourceTree = ""; }; + E318DCDC2C5A4FBD00091322 /* Chicago */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chicago; sourceTree = ""; }; + E318DCDD2C5A4FBD00091322 /* Chihuahua */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chihuahua; sourceTree = ""; }; + E318DCDE2C5A4FBD00091322 /* Coral_Harbour */ = {isa = PBXFileReference; lastKnownFileType = text; path = Coral_Harbour; sourceTree = ""; }; + E318DCDF2C5A4FBD00091322 /* Cordoba */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cordoba; sourceTree = ""; }; + E318DCE02C5A4FBD00091322 /* Costa_Rica */ = {isa = PBXFileReference; lastKnownFileType = text; path = Costa_Rica; sourceTree = ""; }; + E318DCE12C5A4FBD00091322 /* Creston */ = {isa = PBXFileReference; lastKnownFileType = text; path = Creston; sourceTree = ""; }; + E318DCE22C5A4FBD00091322 /* Cuiaba */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cuiaba; sourceTree = ""; }; + E318DCE32C5A4FBD00091322 /* Curacao */ = {isa = PBXFileReference; lastKnownFileType = text; path = Curacao; sourceTree = ""; }; + E318DCE42C5A4FBD00091322 /* Danmarkshavn */ = {isa = PBXFileReference; lastKnownFileType = text; path = Danmarkshavn; sourceTree = ""; }; + E318DCE52C5A4FBD00091322 /* Dawson */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dawson; sourceTree = ""; }; + E318DCE62C5A4FBD00091322 /* Dawson_Creek */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dawson_Creek; sourceTree = ""; }; + E318DCE72C5A4FBD00091322 /* Denver */ = {isa = PBXFileReference; lastKnownFileType = text; path = Denver; sourceTree = ""; }; + E318DCE82C5A4FBD00091322 /* Detroit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Detroit; sourceTree = ""; }; + E318DCE92C5A4FBD00091322 /* Dominica */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dominica; sourceTree = ""; }; + E318DCEA2C5A4FBD00091322 /* Edmonton */ = {isa = PBXFileReference; lastKnownFileType = text; path = Edmonton; sourceTree = ""; }; + E318DCEB2C5A4FBD00091322 /* Eirunepe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Eirunepe; sourceTree = ""; }; + E318DCEC2C5A4FBD00091322 /* El_Salvador */ = {isa = PBXFileReference; lastKnownFileType = text; path = El_Salvador; sourceTree = ""; }; + E318DCED2C5A4FBD00091322 /* Ensenada */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ensenada; sourceTree = ""; }; + E318DCEE2C5A4FBD00091322 /* Fort_Nelson */ = {isa = PBXFileReference; lastKnownFileType = text; path = Fort_Nelson; sourceTree = ""; }; + E318DCEF2C5A4FBD00091322 /* Fort_Wayne */ = {isa = PBXFileReference; lastKnownFileType = text; path = Fort_Wayne; sourceTree = ""; }; + E318DCF02C5A4FBD00091322 /* Fortaleza */ = {isa = PBXFileReference; lastKnownFileType = text; path = Fortaleza; sourceTree = ""; }; + E318DCF12C5A4FBD00091322 /* Glace_Bay */ = {isa = PBXFileReference; lastKnownFileType = text; path = Glace_Bay; sourceTree = ""; }; + E318DCF22C5A4FBD00091322 /* Godthab */ = {isa = PBXFileReference; lastKnownFileType = text; path = Godthab; sourceTree = ""; }; + E318DCF32C5A4FBD00091322 /* Goose_Bay */ = {isa = PBXFileReference; lastKnownFileType = text; path = Goose_Bay; sourceTree = ""; }; + E318DCF42C5A4FBD00091322 /* Grand_Turk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Grand_Turk; sourceTree = ""; }; + E318DCF52C5A4FBD00091322 /* Grenada */ = {isa = PBXFileReference; lastKnownFileType = text; path = Grenada; sourceTree = ""; }; + E318DCF62C5A4FBD00091322 /* Guadeloupe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Guadeloupe; sourceTree = ""; }; + E318DCF72C5A4FBD00091322 /* Guatemala */ = {isa = PBXFileReference; lastKnownFileType = text; path = Guatemala; sourceTree = ""; }; + E318DCF82C5A4FBD00091322 /* Guayaquil */ = {isa = PBXFileReference; lastKnownFileType = text; path = Guayaquil; sourceTree = ""; }; + E318DCF92C5A4FBD00091322 /* Guyana */ = {isa = PBXFileReference; lastKnownFileType = text; path = Guyana; sourceTree = ""; }; + E318DCFA2C5A4FBD00091322 /* Halifax */ = {isa = PBXFileReference; lastKnownFileType = text; path = Halifax; sourceTree = ""; }; + E318DCFB2C5A4FBD00091322 /* Havana */ = {isa = PBXFileReference; lastKnownFileType = text; path = Havana; sourceTree = ""; }; + E318DCFC2C5A4FBD00091322 /* Hermosillo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hermosillo; sourceTree = ""; }; + E318DCFD2C5A4FBD00091322 /* Indianapolis */ = {isa = PBXFileReference; lastKnownFileType = text; path = Indianapolis; sourceTree = ""; }; + E318DCFE2C5A4FBD00091322 /* Inuvik */ = {isa = PBXFileReference; lastKnownFileType = text; path = Inuvik; sourceTree = ""; }; + E318DCFF2C5A4FBD00091322 /* Iqaluit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Iqaluit; sourceTree = ""; }; + E318DD002C5A4FBD00091322 /* Jamaica */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jamaica; sourceTree = ""; }; + E318DD012C5A4FBD00091322 /* Jujuy */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jujuy; sourceTree = ""; }; + E318DD022C5A4FBD00091322 /* Juneau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Juneau; sourceTree = ""; }; + E318DD032C5A4FBD00091322 /* Knox_IN */ = {isa = PBXFileReference; lastKnownFileType = text; path = Knox_IN; sourceTree = ""; }; + E318DD042C5A4FBD00091322 /* Kralendijk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kralendijk; sourceTree = ""; }; + E318DD052C5A4FBD00091322 /* La_Paz */ = {isa = PBXFileReference; lastKnownFileType = text; path = La_Paz; sourceTree = ""; }; + E318DD062C5A4FBD00091322 /* Lima */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lima; sourceTree = ""; }; + E318DD072C5A4FBD00091322 /* Los_Angeles */ = {isa = PBXFileReference; lastKnownFileType = text; path = Los_Angeles; sourceTree = ""; }; + E318DD082C5A4FBD00091322 /* Louisville */ = {isa = PBXFileReference; lastKnownFileType = text; path = Louisville; sourceTree = ""; }; + E318DD092C5A4FBD00091322 /* Lower_Princes */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lower_Princes; sourceTree = ""; }; + E318DD0A2C5A4FBD00091322 /* Maceio */ = {isa = PBXFileReference; lastKnownFileType = text; path = Maceio; sourceTree = ""; }; + E318DD0B2C5A4FBD00091322 /* Managua */ = {isa = PBXFileReference; lastKnownFileType = text; path = Managua; sourceTree = ""; }; + E318DD0C2C5A4FBD00091322 /* Manaus */ = {isa = PBXFileReference; lastKnownFileType = text; path = Manaus; sourceTree = ""; }; + E318DD0D2C5A4FBD00091322 /* Marigot */ = {isa = PBXFileReference; lastKnownFileType = text; path = Marigot; sourceTree = ""; }; + E318DD0E2C5A4FBD00091322 /* Martinique */ = {isa = PBXFileReference; lastKnownFileType = text; path = Martinique; sourceTree = ""; }; + E318DD0F2C5A4FBD00091322 /* Matamoros */ = {isa = PBXFileReference; lastKnownFileType = text; path = Matamoros; sourceTree = ""; }; + E318DD102C5A4FBD00091322 /* Mazatlan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mazatlan; sourceTree = ""; }; + E318DD112C5A4FBD00091322 /* Mendoza */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mendoza; sourceTree = ""; }; + E318DD122C5A4FBD00091322 /* Menominee */ = {isa = PBXFileReference; lastKnownFileType = text; path = Menominee; sourceTree = ""; }; + E318DD132C5A4FBD00091322 /* Merida */ = {isa = PBXFileReference; lastKnownFileType = text; path = Merida; sourceTree = ""; }; + E318DD142C5A4FBD00091322 /* Metlakatla */ = {isa = PBXFileReference; lastKnownFileType = text; path = Metlakatla; sourceTree = ""; }; + E318DD152C5A4FBD00091322 /* Mexico_City */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mexico_City; sourceTree = ""; }; + E318DD162C5A4FBD00091322 /* Miquelon */ = {isa = PBXFileReference; lastKnownFileType = text; path = Miquelon; sourceTree = ""; }; + E318DD172C5A4FBD00091322 /* Moncton */ = {isa = PBXFileReference; lastKnownFileType = text; path = Moncton; sourceTree = ""; }; + E318DD182C5A4FBD00091322 /* Monterrey */ = {isa = PBXFileReference; lastKnownFileType = text; path = Monterrey; sourceTree = ""; }; + E318DD192C5A4FBD00091322 /* Montevideo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Montevideo; sourceTree = ""; }; + E318DD1A2C5A4FBD00091322 /* Montreal */ = {isa = PBXFileReference; lastKnownFileType = text; path = Montreal; sourceTree = ""; }; + E318DD1B2C5A4FBD00091322 /* Montserrat */ = {isa = PBXFileReference; lastKnownFileType = text; path = Montserrat; sourceTree = ""; }; + E318DD1C2C5A4FBD00091322 /* Nassau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nassau; sourceTree = ""; }; + E318DD1D2C5A4FBD00091322 /* New_York */ = {isa = PBXFileReference; lastKnownFileType = text; path = New_York; sourceTree = ""; }; + E318DD1E2C5A4FBD00091322 /* Nipigon */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nipigon; sourceTree = ""; }; + E318DD1F2C5A4FBD00091322 /* Nome */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nome; sourceTree = ""; }; + E318DD202C5A4FBD00091322 /* Noronha */ = {isa = PBXFileReference; lastKnownFileType = text; path = Noronha; sourceTree = ""; }; + E318DD212C5A4FBD00091322 /* Nuuk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nuuk; sourceTree = ""; }; + E318DD222C5A4FBD00091322 /* Ojinaga */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ojinaga; sourceTree = ""; }; + E318DD232C5A4FBD00091322 /* Panama */ = {isa = PBXFileReference; lastKnownFileType = text; path = Panama; sourceTree = ""; }; + E318DD242C5A4FBD00091322 /* Pangnirtung */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pangnirtung; sourceTree = ""; }; + E318DD252C5A4FBD00091322 /* Paramaribo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Paramaribo; sourceTree = ""; }; + E318DD262C5A4FBD00091322 /* Phoenix */ = {isa = PBXFileReference; lastKnownFileType = text; path = Phoenix; sourceTree = ""; }; + E318DD272C5A4FBD00091322 /* Port_of_Spain */ = {isa = PBXFileReference; lastKnownFileType = text; path = Port_of_Spain; sourceTree = ""; }; + E318DD282C5A4FBD00091322 /* Port-au-Prince */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Port-au-Prince"; sourceTree = ""; }; + E318DD292C5A4FBD00091322 /* Porto_Acre */ = {isa = PBXFileReference; lastKnownFileType = text; path = Porto_Acre; sourceTree = ""; }; + E318DD2A2C5A4FBD00091322 /* Porto_Velho */ = {isa = PBXFileReference; lastKnownFileType = text; path = Porto_Velho; sourceTree = ""; }; + E318DD2B2C5A4FBD00091322 /* Puerto_Rico */ = {isa = PBXFileReference; lastKnownFileType = text; path = Puerto_Rico; sourceTree = ""; }; + E318DD2C2C5A4FBD00091322 /* Punta_Arenas */ = {isa = PBXFileReference; lastKnownFileType = text; path = Punta_Arenas; sourceTree = ""; }; + E318DD2D2C5A4FBD00091322 /* Rainy_River */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rainy_River; sourceTree = ""; }; + E318DD2E2C5A4FBD00091322 /* Rankin_Inlet */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rankin_Inlet; sourceTree = ""; }; + E318DD2F2C5A4FBD00091322 /* Recife */ = {isa = PBXFileReference; lastKnownFileType = text; path = Recife; sourceTree = ""; }; + E318DD302C5A4FBD00091322 /* Regina */ = {isa = PBXFileReference; lastKnownFileType = text; path = Regina; sourceTree = ""; }; + E318DD312C5A4FBD00091322 /* Resolute */ = {isa = PBXFileReference; lastKnownFileType = text; path = Resolute; sourceTree = ""; }; + E318DD322C5A4FBD00091322 /* Rio_Branco */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rio_Branco; sourceTree = ""; }; + E318DD332C5A4FBD00091322 /* Rosario */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rosario; sourceTree = ""; }; + E318DD342C5A4FBD00091322 /* Santa_Isabel */ = {isa = PBXFileReference; lastKnownFileType = text; path = Santa_Isabel; sourceTree = ""; }; + E318DD352C5A4FBD00091322 /* Santarem */ = {isa = PBXFileReference; lastKnownFileType = text; path = Santarem; sourceTree = ""; }; + E318DD362C5A4FBD00091322 /* Santiago */ = {isa = PBXFileReference; lastKnownFileType = text; path = Santiago; sourceTree = ""; }; + E318DD372C5A4FBD00091322 /* Santo_Domingo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Santo_Domingo; sourceTree = ""; }; + E318DD382C5A4FBD00091322 /* Sao_Paulo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sao_Paulo; sourceTree = ""; }; + E318DD392C5A4FBD00091322 /* Scoresbysund */ = {isa = PBXFileReference; lastKnownFileType = text; path = Scoresbysund; sourceTree = ""; }; + E318DD3A2C5A4FBD00091322 /* Shiprock */ = {isa = PBXFileReference; lastKnownFileType = text; path = Shiprock; sourceTree = ""; }; + E318DD3B2C5A4FBD00091322 /* Sitka */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sitka; sourceTree = ""; }; + E318DD3C2C5A4FBD00091322 /* St_Barthelemy */ = {isa = PBXFileReference; lastKnownFileType = text; path = St_Barthelemy; sourceTree = ""; }; + E318DD3D2C5A4FBD00091322 /* St_Johns */ = {isa = PBXFileReference; lastKnownFileType = text; path = St_Johns; sourceTree = ""; }; + E318DD3E2C5A4FBD00091322 /* St_Kitts */ = {isa = PBXFileReference; lastKnownFileType = text; path = St_Kitts; sourceTree = ""; }; + E318DD3F2C5A4FBD00091322 /* St_Lucia */ = {isa = PBXFileReference; lastKnownFileType = text; path = St_Lucia; sourceTree = ""; }; + E318DD402C5A4FBD00091322 /* St_Thomas */ = {isa = PBXFileReference; lastKnownFileType = text; path = St_Thomas; sourceTree = ""; }; + E318DD412C5A4FBD00091322 /* St_Vincent */ = {isa = PBXFileReference; lastKnownFileType = text; path = St_Vincent; sourceTree = ""; }; + E318DD422C5A4FBD00091322 /* Swift_Current */ = {isa = PBXFileReference; lastKnownFileType = text; path = Swift_Current; sourceTree = ""; }; + E318DD432C5A4FBD00091322 /* Tegucigalpa */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tegucigalpa; sourceTree = ""; }; + E318DD442C5A4FBD00091322 /* Thule */ = {isa = PBXFileReference; lastKnownFileType = text; path = Thule; sourceTree = ""; }; + E318DD452C5A4FBD00091322 /* Thunder_Bay */ = {isa = PBXFileReference; lastKnownFileType = text; path = Thunder_Bay; sourceTree = ""; }; + E318DD462C5A4FBD00091322 /* Tijuana */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tijuana; sourceTree = ""; }; + E318DD472C5A4FBD00091322 /* Toronto */ = {isa = PBXFileReference; lastKnownFileType = text; path = Toronto; sourceTree = ""; }; + E318DD482C5A4FBD00091322 /* Tortola */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tortola; sourceTree = ""; }; + E318DD492C5A4FBD00091322 /* Vancouver */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vancouver; sourceTree = ""; }; + E318DD4A2C5A4FBD00091322 /* Virgin */ = {isa = PBXFileReference; lastKnownFileType = text; path = Virgin; sourceTree = ""; }; + E318DD4B2C5A4FBD00091322 /* Whitehorse */ = {isa = PBXFileReference; lastKnownFileType = text; path = Whitehorse; sourceTree = ""; }; + E318DD4C2C5A4FBD00091322 /* Winnipeg */ = {isa = PBXFileReference; lastKnownFileType = text; path = Winnipeg; sourceTree = ""; }; + E318DD4D2C5A4FBD00091322 /* Yakutat */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yakutat; sourceTree = ""; }; + E318DD4E2C5A4FBD00091322 /* Yellowknife */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yellowknife; sourceTree = ""; }; + E318DD502C5A4FBD00091322 /* Casey */ = {isa = PBXFileReference; lastKnownFileType = text; path = Casey; sourceTree = ""; }; + E318DD512C5A4FBD00091322 /* Davis */ = {isa = PBXFileReference; lastKnownFileType = text; path = Davis; sourceTree = ""; }; + E318DD522C5A4FBD00091322 /* DumontDUrville */ = {isa = PBXFileReference; lastKnownFileType = text; path = DumontDUrville; sourceTree = ""; }; + E318DD532C5A4FBD00091322 /* Macquarie */ = {isa = PBXFileReference; lastKnownFileType = text; path = Macquarie; sourceTree = ""; }; + E318DD542C5A4FBD00091322 /* Mawson */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mawson; sourceTree = ""; }; + E318DD552C5A4FBD00091322 /* McMurdo */ = {isa = PBXFileReference; lastKnownFileType = text; path = McMurdo; sourceTree = ""; }; + E318DD562C5A4FBD00091322 /* Palmer */ = {isa = PBXFileReference; lastKnownFileType = text; path = Palmer; sourceTree = ""; }; + E318DD572C5A4FBD00091322 /* Rothera */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rothera; sourceTree = ""; }; + E318DD582C5A4FBD00091322 /* South_Pole */ = {isa = PBXFileReference; lastKnownFileType = text; path = South_Pole; sourceTree = ""; }; + E318DD592C5A4FBD00091322 /* Syowa */ = {isa = PBXFileReference; lastKnownFileType = text; path = Syowa; sourceTree = ""; }; + E318DD5A2C5A4FBD00091322 /* Troll */ = {isa = PBXFileReference; lastKnownFileType = text; path = Troll; sourceTree = ""; }; + E318DD5B2C5A4FBD00091322 /* Vostok */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vostok; sourceTree = ""; }; + E318DD5D2C5A4FBD00091322 /* Longyearbyen */ = {isa = PBXFileReference; lastKnownFileType = text; path = Longyearbyen; sourceTree = ""; }; + E318DD5F2C5A4FBD00091322 /* Aden */ = {isa = PBXFileReference; lastKnownFileType = text; path = Aden; sourceTree = ""; }; + E318DD602C5A4FBD00091322 /* Almaty */ = {isa = PBXFileReference; lastKnownFileType = text; path = Almaty; sourceTree = ""; }; + E318DD612C5A4FBD00091322 /* Amman */ = {isa = PBXFileReference; lastKnownFileType = text; path = Amman; sourceTree = ""; }; + E318DD622C5A4FBD00091322 /* Anadyr */ = {isa = PBXFileReference; lastKnownFileType = text; path = Anadyr; sourceTree = ""; }; + E318DD632C5A4FBD00091322 /* Aqtau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Aqtau; sourceTree = ""; }; + E318DD642C5A4FBD00091322 /* Aqtobe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Aqtobe; sourceTree = ""; }; + E318DD652C5A4FBD00091322 /* Ashgabat */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ashgabat; sourceTree = ""; }; + E318DD662C5A4FBD00091322 /* Ashkhabad */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ashkhabad; sourceTree = ""; }; + E318DD672C5A4FBD00091322 /* Atyrau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Atyrau; sourceTree = ""; }; + E318DD682C5A4FBD00091322 /* Baghdad */ = {isa = PBXFileReference; lastKnownFileType = text; path = Baghdad; sourceTree = ""; }; + E318DD692C5A4FBD00091322 /* Bahrain */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bahrain; sourceTree = ""; }; + E318DD6A2C5A4FBD00091322 /* Baku */ = {isa = PBXFileReference; lastKnownFileType = text; path = Baku; sourceTree = ""; }; + E318DD6B2C5A4FBD00091322 /* Bangkok */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bangkok; sourceTree = ""; }; + E318DD6C2C5A4FBD00091322 /* Barnaul */ = {isa = PBXFileReference; lastKnownFileType = text; path = Barnaul; sourceTree = ""; }; + E318DD6D2C5A4FBD00091322 /* Beirut */ = {isa = PBXFileReference; lastKnownFileType = text; path = Beirut; sourceTree = ""; }; + E318DD6E2C5A4FBD00091322 /* Bishkek */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bishkek; sourceTree = ""; }; + E318DD6F2C5A4FBD00091322 /* Brunei */ = {isa = PBXFileReference; lastKnownFileType = text; path = Brunei; sourceTree = ""; }; + E318DD702C5A4FBD00091322 /* Calcutta */ = {isa = PBXFileReference; lastKnownFileType = text; path = Calcutta; sourceTree = ""; }; + E318DD712C5A4FBD00091322 /* Chita */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chita; sourceTree = ""; }; + E318DD722C5A4FBD00091322 /* Choibalsan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Choibalsan; sourceTree = ""; }; + E318DD732C5A4FBD00091322 /* Chongqing */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chongqing; sourceTree = ""; }; + E318DD742C5A4FBD00091322 /* Chungking */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chungking; sourceTree = ""; }; + E318DD752C5A4FBD00091322 /* Colombo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Colombo; sourceTree = ""; }; + E318DD762C5A4FBD00091322 /* Dacca */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dacca; sourceTree = ""; }; + E318DD772C5A4FBD00091322 /* Damascus */ = {isa = PBXFileReference; lastKnownFileType = text; path = Damascus; sourceTree = ""; }; + E318DD782C5A4FBD00091322 /* Dhaka */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dhaka; sourceTree = ""; }; + E318DD792C5A4FBD00091322 /* Dili */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dili; sourceTree = ""; }; + E318DD7A2C5A4FBD00091322 /* Dubai */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dubai; sourceTree = ""; }; + E318DD7B2C5A4FBD00091322 /* Dushanbe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dushanbe; sourceTree = ""; }; + E318DD7C2C5A4FBD00091322 /* Famagusta */ = {isa = PBXFileReference; lastKnownFileType = text; path = Famagusta; sourceTree = ""; }; + E318DD7D2C5A4FBD00091322 /* Gaza */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gaza; sourceTree = ""; }; + E318DD7E2C5A4FBD00091322 /* Harbin */ = {isa = PBXFileReference; lastKnownFileType = text; path = Harbin; sourceTree = ""; }; + E318DD7F2C5A4FBD00091322 /* Hebron */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hebron; sourceTree = ""; }; + E318DD802C5A4FBD00091322 /* Ho_Chi_Minh */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ho_Chi_Minh; sourceTree = ""; }; + E318DD812C5A4FBD00091322 /* Hong_Kong */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hong_Kong; sourceTree = ""; }; + E318DD822C5A4FBD00091322 /* Hovd */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hovd; sourceTree = ""; }; + E318DD832C5A4FBD00091322 /* Irkutsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Irkutsk; sourceTree = ""; }; + E318DD842C5A4FBD00091322 /* Istanbul */ = {isa = PBXFileReference; lastKnownFileType = text; path = Istanbul; sourceTree = ""; }; + E318DD852C5A4FBD00091322 /* Jakarta */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jakarta; sourceTree = ""; }; + E318DD862C5A4FBD00091322 /* Jayapura */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jayapura; sourceTree = ""; }; + E318DD872C5A4FBD00091322 /* Jerusalem */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jerusalem; sourceTree = ""; }; + E318DD882C5A4FBD00091322 /* Kabul */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kabul; sourceTree = ""; }; + E318DD892C5A4FBD00091322 /* Kamchatka */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kamchatka; sourceTree = ""; }; + E318DD8A2C5A4FBD00091322 /* Karachi */ = {isa = PBXFileReference; lastKnownFileType = text; path = Karachi; sourceTree = ""; }; + E318DD8B2C5A4FBD00091322 /* Kashgar */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kashgar; sourceTree = ""; }; + E318DD8C2C5A4FBD00091322 /* Kathmandu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kathmandu; sourceTree = ""; }; + E318DD8D2C5A4FBD00091322 /* Katmandu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Katmandu; sourceTree = ""; }; + E318DD8E2C5A4FBD00091322 /* Khandyga */ = {isa = PBXFileReference; lastKnownFileType = text; path = Khandyga; sourceTree = ""; }; + E318DD8F2C5A4FBD00091322 /* Kolkata */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kolkata; sourceTree = ""; }; + E318DD902C5A4FBD00091322 /* Krasnoyarsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Krasnoyarsk; sourceTree = ""; }; + E318DD912C5A4FBD00091322 /* Kuala_Lumpur */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kuala_Lumpur; sourceTree = ""; }; + E318DD922C5A4FBD00091322 /* Kuching */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kuching; sourceTree = ""; }; + E318DD932C5A4FBD00091322 /* Kuwait */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kuwait; sourceTree = ""; }; + E318DD942C5A4FBD00091322 /* Macao */ = {isa = PBXFileReference; lastKnownFileType = text; path = Macao; sourceTree = ""; }; + E318DD952C5A4FBD00091322 /* Macau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Macau; sourceTree = ""; }; + E318DD962C5A4FBD00091322 /* Magadan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Magadan; sourceTree = ""; }; + E318DD972C5A4FBD00091322 /* Makassar */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makassar; sourceTree = ""; }; + E318DD982C5A4FBD00091322 /* Manila */ = {isa = PBXFileReference; lastKnownFileType = text; path = Manila; sourceTree = ""; }; + E318DD992C5A4FBD00091322 /* Muscat */ = {isa = PBXFileReference; lastKnownFileType = text; path = Muscat; sourceTree = ""; }; + E318DD9A2C5A4FBD00091322 /* Nicosia */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nicosia; sourceTree = ""; }; + E318DD9B2C5A4FBD00091322 /* Novokuznetsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Novokuznetsk; sourceTree = ""; }; + E318DD9C2C5A4FBD00091322 /* Novosibirsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Novosibirsk; sourceTree = ""; }; + E318DD9D2C5A4FBD00091322 /* Omsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Omsk; sourceTree = ""; }; + E318DD9E2C5A4FBD00091322 /* Oral */ = {isa = PBXFileReference; lastKnownFileType = text; path = Oral; sourceTree = ""; }; + E318DD9F2C5A4FBD00091322 /* Phnom_Penh */ = {isa = PBXFileReference; lastKnownFileType = text; path = Phnom_Penh; sourceTree = ""; }; + E318DDA02C5A4FBD00091322 /* Pontianak */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pontianak; sourceTree = ""; }; + E318DDA12C5A4FBD00091322 /* Pyongyang */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pyongyang; sourceTree = ""; }; + E318DDA22C5A4FBD00091322 /* Qatar */ = {isa = PBXFileReference; lastKnownFileType = text; path = Qatar; sourceTree = ""; }; + E318DDA32C5A4FBD00091322 /* Qostanay */ = {isa = PBXFileReference; lastKnownFileType = text; path = Qostanay; sourceTree = ""; }; + E318DDA42C5A4FBD00091322 /* Qyzylorda */ = {isa = PBXFileReference; lastKnownFileType = text; path = Qyzylorda; sourceTree = ""; }; + E318DDA52C5A4FBD00091322 /* Rangoon */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rangoon; sourceTree = ""; }; + E318DDA62C5A4FBD00091322 /* Riyadh */ = {isa = PBXFileReference; lastKnownFileType = text; path = Riyadh; sourceTree = ""; }; + E318DDA72C5A4FBD00091322 /* Saigon */ = {isa = PBXFileReference; lastKnownFileType = text; path = Saigon; sourceTree = ""; }; + E318DDA82C5A4FBD00091322 /* Sakhalin */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sakhalin; sourceTree = ""; }; + E318DDA92C5A4FBD00091322 /* Samarkand */ = {isa = PBXFileReference; lastKnownFileType = text; path = Samarkand; sourceTree = ""; }; + E318DDAA2C5A4FBD00091322 /* Seoul */ = {isa = PBXFileReference; lastKnownFileType = text; path = Seoul; sourceTree = ""; }; + E318DDAB2C5A4FBD00091322 /* Shanghai */ = {isa = PBXFileReference; lastKnownFileType = text; path = Shanghai; sourceTree = ""; }; + E318DDAC2C5A4FBD00091322 /* Singapore */ = {isa = PBXFileReference; lastKnownFileType = text; path = Singapore; sourceTree = ""; }; + E318DDAD2C5A4FBD00091322 /* Srednekolymsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Srednekolymsk; sourceTree = ""; }; + E318DDAE2C5A4FBD00091322 /* Taipei */ = {isa = PBXFileReference; lastKnownFileType = text; path = Taipei; sourceTree = ""; }; + E318DDAF2C5A4FBD00091322 /* Tashkent */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tashkent; sourceTree = ""; }; + E318DDB02C5A4FBD00091322 /* Tbilisi */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tbilisi; sourceTree = ""; }; + E318DDB12C5A4FBD00091322 /* Tehran */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tehran; sourceTree = ""; }; + E318DDB22C5A4FBD00091322 /* Tel_Aviv */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tel_Aviv; sourceTree = ""; }; + E318DDB32C5A4FBD00091322 /* Thimbu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Thimbu; sourceTree = ""; }; + E318DDB42C5A4FBD00091322 /* Thimphu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Thimphu; sourceTree = ""; }; + E318DDB52C5A4FBD00091322 /* Tokyo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tokyo; sourceTree = ""; }; + E318DDB62C5A4FBD00091322 /* Tomsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tomsk; sourceTree = ""; }; + E318DDB72C5A4FBD00091322 /* Ujung_Pandang */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ujung_Pandang; sourceTree = ""; }; + E318DDB82C5A4FBD00091322 /* Ulaanbaatar */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ulaanbaatar; sourceTree = ""; }; + E318DDB92C5A4FBD00091322 /* Ulan_Bator */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ulan_Bator; sourceTree = ""; }; + E318DDBA2C5A4FBD00091322 /* Urumqi */ = {isa = PBXFileReference; lastKnownFileType = text; path = Urumqi; sourceTree = ""; }; + E318DDBB2C5A4FBD00091322 /* Ust-Nera */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Ust-Nera"; sourceTree = ""; }; + E318DDBC2C5A4FBD00091322 /* Vientiane */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vientiane; sourceTree = ""; }; + E318DDBD2C5A4FBD00091322 /* Vladivostok */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vladivostok; sourceTree = ""; }; + E318DDBE2C5A4FBD00091322 /* Yakutsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yakutsk; sourceTree = ""; }; + E318DDBF2C5A4FBD00091322 /* Yangon */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yangon; sourceTree = ""; }; + E318DDC02C5A4FBD00091322 /* Yekaterinburg */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yekaterinburg; sourceTree = ""; }; + E318DDC12C5A4FBD00091322 /* Yerevan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yerevan; sourceTree = ""; }; + E318DDC32C5A4FBD00091322 /* Azores */ = {isa = PBXFileReference; lastKnownFileType = text; path = Azores; sourceTree = ""; }; + E318DDC42C5A4FBD00091322 /* Bermuda */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bermuda; sourceTree = ""; }; + E318DDC52C5A4FBD00091322 /* Canary */ = {isa = PBXFileReference; lastKnownFileType = text; path = Canary; sourceTree = ""; }; + E318DDC62C5A4FBD00091322 /* Cape_Verde */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cape_Verde; sourceTree = ""; }; + E318DDC72C5A4FBD00091322 /* Faeroe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Faeroe; sourceTree = ""; }; + E318DDC82C5A4FBD00091322 /* Faroe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Faroe; sourceTree = ""; }; + E318DDC92C5A4FBD00091322 /* Jan_Mayen */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jan_Mayen; sourceTree = ""; }; + E318DDCA2C5A4FBD00091322 /* Madeira */ = {isa = PBXFileReference; lastKnownFileType = text; path = Madeira; sourceTree = ""; }; + E318DDCB2C5A4FBD00091322 /* Reykjavik */ = {isa = PBXFileReference; lastKnownFileType = text; path = Reykjavik; sourceTree = ""; }; + E318DDCC2C5A4FBD00091322 /* South_Georgia */ = {isa = PBXFileReference; lastKnownFileType = text; path = South_Georgia; sourceTree = ""; }; + E318DDCD2C5A4FBD00091322 /* St_Helena */ = {isa = PBXFileReference; lastKnownFileType = text; path = St_Helena; sourceTree = ""; }; + E318DDCE2C5A4FBD00091322 /* Stanley */ = {isa = PBXFileReference; lastKnownFileType = text; path = Stanley; sourceTree = ""; }; + E318DDD02C5A4FBD00091322 /* ACT */ = {isa = PBXFileReference; lastKnownFileType = text; path = ACT; sourceTree = ""; }; + E318DDD12C5A4FBD00091322 /* Adelaide */ = {isa = PBXFileReference; lastKnownFileType = text; path = Adelaide; sourceTree = ""; }; + E318DDD22C5A4FBD00091322 /* Brisbane */ = {isa = PBXFileReference; lastKnownFileType = text; path = Brisbane; sourceTree = ""; }; + E318DDD32C5A4FBD00091322 /* Broken_Hill */ = {isa = PBXFileReference; lastKnownFileType = text; path = Broken_Hill; sourceTree = ""; }; + E318DDD42C5A4FBD00091322 /* Canberra */ = {isa = PBXFileReference; lastKnownFileType = text; path = Canberra; sourceTree = ""; }; + E318DDD52C5A4FBD00091322 /* Currie */ = {isa = PBXFileReference; lastKnownFileType = text; path = Currie; sourceTree = ""; }; + E318DDD62C5A4FBD00091322 /* Darwin */ = {isa = PBXFileReference; lastKnownFileType = text; path = Darwin; sourceTree = ""; }; + E318DDD72C5A4FBD00091322 /* Eucla */ = {isa = PBXFileReference; lastKnownFileType = text; path = Eucla; sourceTree = ""; }; + E318DDD82C5A4FBD00091322 /* Hobart */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hobart; sourceTree = ""; }; + E318DDD92C5A4FBD00091322 /* LHI */ = {isa = PBXFileReference; lastKnownFileType = text; path = LHI; sourceTree = ""; }; + E318DDDA2C5A4FBD00091322 /* Lindeman */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lindeman; sourceTree = ""; }; + E318DDDB2C5A4FBD00091322 /* Lord_Howe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lord_Howe; sourceTree = ""; }; + E318DDDC2C5A4FBD00091322 /* Melbourne */ = {isa = PBXFileReference; lastKnownFileType = text; path = Melbourne; sourceTree = ""; }; + E318DDDD2C5A4FBD00091322 /* North */ = {isa = PBXFileReference; lastKnownFileType = text; path = North; sourceTree = ""; }; + E318DDDE2C5A4FBD00091322 /* NSW */ = {isa = PBXFileReference; lastKnownFileType = text; path = NSW; sourceTree = ""; }; + E318DDDF2C5A4FBD00091322 /* Perth */ = {isa = PBXFileReference; lastKnownFileType = text; path = Perth; sourceTree = ""; }; + E318DDE02C5A4FBD00091322 /* Queensland */ = {isa = PBXFileReference; lastKnownFileType = text; path = Queensland; sourceTree = ""; }; + E318DDE12C5A4FBD00091322 /* South */ = {isa = PBXFileReference; lastKnownFileType = text; path = South; sourceTree = ""; }; + E318DDE22C5A4FBD00091322 /* Sydney */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sydney; sourceTree = ""; }; + E318DDE32C5A4FBD00091322 /* Tasmania */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tasmania; sourceTree = ""; }; + E318DDE42C5A4FBD00091322 /* Victoria */ = {isa = PBXFileReference; lastKnownFileType = text; path = Victoria; sourceTree = ""; }; + E318DDE52C5A4FBD00091322 /* West */ = {isa = PBXFileReference; lastKnownFileType = text; path = West; sourceTree = ""; }; + E318DDE62C5A4FBD00091322 /* Yancowinna */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yancowinna; sourceTree = ""; }; + E318DDE82C5A4FBD00091322 /* Acre */ = {isa = PBXFileReference; lastKnownFileType = text; path = Acre; sourceTree = ""; }; + E318DDE92C5A4FBD00091322 /* DeNoronha */ = {isa = PBXFileReference; lastKnownFileType = text; path = DeNoronha; sourceTree = ""; }; + E318DDEA2C5A4FBD00091322 /* East */ = {isa = PBXFileReference; lastKnownFileType = text; path = East; sourceTree = ""; }; + E318DDEB2C5A4FBD00091322 /* West */ = {isa = PBXFileReference; lastKnownFileType = text; path = West; sourceTree = ""; }; + E318DDED2C5A4FBD00091322 /* Atlantic */ = {isa = PBXFileReference; lastKnownFileType = text; path = Atlantic; sourceTree = ""; }; + E318DDEE2C5A4FBD00091322 /* Central */ = {isa = PBXFileReference; lastKnownFileType = text; path = Central; sourceTree = ""; }; + E318DDEF2C5A4FBD00091322 /* Eastern */ = {isa = PBXFileReference; lastKnownFileType = text; path = Eastern; sourceTree = ""; }; + E318DDF02C5A4FBD00091322 /* Mountain */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mountain; sourceTree = ""; }; + E318DDF12C5A4FBD00091322 /* Newfoundland */ = {isa = PBXFileReference; lastKnownFileType = text; path = Newfoundland; sourceTree = ""; }; + E318DDF22C5A4FBD00091322 /* Pacific */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pacific; sourceTree = ""; }; + E318DDF32C5A4FBD00091322 /* Saskatchewan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Saskatchewan; sourceTree = ""; }; + E318DDF42C5A4FBD00091322 /* Yukon */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yukon; sourceTree = ""; }; + E318DDF62C5A4FBD00091322 /* Continental */ = {isa = PBXFileReference; lastKnownFileType = text; path = Continental; sourceTree = ""; }; + E318DDF72C5A4FBD00091322 /* EasterIsland */ = {isa = PBXFileReference; lastKnownFileType = text; path = EasterIsland; sourceTree = ""; }; + E318DDF92C5A4FBD00091322 /* GMT */ = {isa = PBXFileReference; lastKnownFileType = text; path = GMT; sourceTree = ""; }; + E318DDFA2C5A4FBD00091322 /* GMT-0 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-0"; sourceTree = ""; }; + E318DDFB2C5A4FBD00091322 /* GMT-1 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-1"; sourceTree = ""; }; + E318DDFC2C5A4FBD00091322 /* GMT-2 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-2"; sourceTree = ""; }; + E318DDFD2C5A4FBD00091322 /* GMT-3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-3"; sourceTree = ""; }; + E318DDFE2C5A4FBD00091322 /* GMT-4 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-4"; sourceTree = ""; }; + E318DDFF2C5A4FBD00091322 /* GMT-5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-5"; sourceTree = ""; }; + E318DE002C5A4FBD00091322 /* GMT-6 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-6"; sourceTree = ""; }; + E318DE012C5A4FBD00091322 /* GMT-7 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-7"; sourceTree = ""; }; + E318DE022C5A4FBD00091322 /* GMT-8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-8"; sourceTree = ""; }; + E318DE032C5A4FBD00091322 /* GMT-9 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-9"; sourceTree = ""; }; + E318DE042C5A4FBD00091322 /* GMT-10 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-10"; sourceTree = ""; }; + E318DE052C5A4FBD00091322 /* GMT-11 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-11"; sourceTree = ""; }; + E318DE062C5A4FBD00091322 /* GMT-12 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-12"; sourceTree = ""; }; + E318DE072C5A4FBD00091322 /* GMT-13 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-13"; sourceTree = ""; }; + E318DE082C5A4FBD00091322 /* GMT-14 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-14"; sourceTree = ""; }; + E318DE092C5A4FBD00091322 /* GMT+0 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+0"; sourceTree = ""; }; + E318DE0A2C5A4FBD00091322 /* GMT+1 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+1"; sourceTree = ""; }; + E318DE0B2C5A4FBD00091322 /* GMT+2 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+2"; sourceTree = ""; }; + E318DE0C2C5A4FBD00091322 /* GMT+3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+3"; sourceTree = ""; }; + E318DE0D2C5A4FBD00091322 /* GMT+4 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+4"; sourceTree = ""; }; + E318DE0E2C5A4FBD00091322 /* GMT+5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+5"; sourceTree = ""; }; + E318DE0F2C5A4FBD00091322 /* GMT+6 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+6"; sourceTree = ""; }; + E318DE102C5A4FBD00091322 /* GMT+7 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+7"; sourceTree = ""; }; + E318DE112C5A4FBD00091322 /* GMT+8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+8"; sourceTree = ""; }; + E318DE122C5A4FBD00091322 /* GMT+9 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+9"; sourceTree = ""; }; + E318DE132C5A4FBD00091322 /* GMT+10 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+10"; sourceTree = ""; }; + E318DE142C5A4FBD00091322 /* GMT+11 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+11"; sourceTree = ""; }; + E318DE152C5A4FBD00091322 /* GMT+12 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+12"; sourceTree = ""; }; + E318DE162C5A4FBD00091322 /* GMT0 */ = {isa = PBXFileReference; lastKnownFileType = text; path = GMT0; sourceTree = ""; }; + E318DE172C5A4FBD00091322 /* Greenwich */ = {isa = PBXFileReference; lastKnownFileType = text; path = Greenwich; sourceTree = ""; }; + E318DE182C5A4FBD00091322 /* UCT */ = {isa = PBXFileReference; lastKnownFileType = text; path = UCT; sourceTree = ""; }; + E318DE192C5A4FBD00091322 /* Universal */ = {isa = PBXFileReference; lastKnownFileType = text; path = Universal; sourceTree = ""; }; + E318DE1A2C5A4FBD00091322 /* UTC */ = {isa = PBXFileReference; lastKnownFileType = text; path = UTC; sourceTree = ""; }; + E318DE1B2C5A4FBD00091322 /* Zulu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Zulu; sourceTree = ""; }; + E318DE1D2C5A4FBD00091322 /* Amsterdam */ = {isa = PBXFileReference; lastKnownFileType = text; path = Amsterdam; sourceTree = ""; }; + E318DE1E2C5A4FBD00091322 /* Andorra */ = {isa = PBXFileReference; lastKnownFileType = text; path = Andorra; sourceTree = ""; }; + E318DE1F2C5A4FBD00091322 /* Astrakhan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Astrakhan; sourceTree = ""; }; + E318DE202C5A4FBD00091322 /* Athens */ = {isa = PBXFileReference; lastKnownFileType = text; path = Athens; sourceTree = ""; }; + E318DE212C5A4FBD00091322 /* Belfast */ = {isa = PBXFileReference; lastKnownFileType = text; path = Belfast; sourceTree = ""; }; + E318DE222C5A4FBD00091322 /* Belgrade */ = {isa = PBXFileReference; lastKnownFileType = text; path = Belgrade; sourceTree = ""; }; + E318DE232C5A4FBD00091322 /* Berlin */ = {isa = PBXFileReference; lastKnownFileType = text; path = Berlin; sourceTree = ""; }; + E318DE242C5A4FBD00091322 /* Bratislava */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bratislava; sourceTree = ""; }; + E318DE252C5A4FBD00091322 /* Brussels */ = {isa = PBXFileReference; lastKnownFileType = text; path = Brussels; sourceTree = ""; }; + E318DE262C5A4FBD00091322 /* Bucharest */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bucharest; sourceTree = ""; }; + E318DE272C5A4FBD00091322 /* Budapest */ = {isa = PBXFileReference; lastKnownFileType = text; path = Budapest; sourceTree = ""; }; + E318DE282C5A4FBD00091322 /* Busingen */ = {isa = PBXFileReference; lastKnownFileType = text; path = Busingen; sourceTree = ""; }; + E318DE292C5A4FBD00091322 /* Chisinau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chisinau; sourceTree = ""; }; + E318DE2A2C5A4FBD00091322 /* Copenhagen */ = {isa = PBXFileReference; lastKnownFileType = text; path = Copenhagen; sourceTree = ""; }; + E318DE2B2C5A4FBD00091322 /* Dublin */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dublin; sourceTree = ""; }; + E318DE2C2C5A4FBD00091322 /* Gibraltar */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gibraltar; sourceTree = ""; }; + E318DE2D2C5A4FBD00091322 /* Guernsey */ = {isa = PBXFileReference; lastKnownFileType = text; path = Guernsey; sourceTree = ""; }; + E318DE2E2C5A4FBD00091322 /* Helsinki */ = {isa = PBXFileReference; lastKnownFileType = text; path = Helsinki; sourceTree = ""; }; + E318DE2F2C5A4FBD00091322 /* Isle_of_Man */ = {isa = PBXFileReference; lastKnownFileType = text; path = Isle_of_Man; sourceTree = ""; }; + E318DE302C5A4FBD00091322 /* Istanbul */ = {isa = PBXFileReference; lastKnownFileType = text; path = Istanbul; sourceTree = ""; }; + E318DE312C5A4FBD00091322 /* Jersey */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jersey; sourceTree = ""; }; + E318DE322C5A4FBD00091322 /* Kaliningrad */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kaliningrad; sourceTree = ""; }; + E318DE332C5A4FBD00091322 /* Kiev */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kiev; sourceTree = ""; }; + E318DE342C5A4FBD00091322 /* Kirov */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kirov; sourceTree = ""; }; + E318DE352C5A4FBD00091322 /* Lisbon */ = {isa = PBXFileReference; lastKnownFileType = text; path = Lisbon; sourceTree = ""; }; + E318DE362C5A4FBD00091322 /* Ljubljana */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ljubljana; sourceTree = ""; }; + E318DE372C5A4FBD00091322 /* London */ = {isa = PBXFileReference; lastKnownFileType = text; path = London; sourceTree = ""; }; + E318DE382C5A4FBD00091322 /* Luxembourg */ = {isa = PBXFileReference; lastKnownFileType = text; path = Luxembourg; sourceTree = ""; }; + E318DE392C5A4FBD00091322 /* Madrid */ = {isa = PBXFileReference; lastKnownFileType = text; path = Madrid; sourceTree = ""; }; + E318DE3A2C5A4FBD00091322 /* Malta */ = {isa = PBXFileReference; lastKnownFileType = text; path = Malta; sourceTree = ""; }; + E318DE3B2C5A4FBD00091322 /* Mariehamn */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mariehamn; sourceTree = ""; }; + E318DE3C2C5A4FBD00091322 /* Minsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Minsk; sourceTree = ""; }; + E318DE3D2C5A4FBD00091322 /* Monaco */ = {isa = PBXFileReference; lastKnownFileType = text; path = Monaco; sourceTree = ""; }; + E318DE3E2C5A4FBD00091322 /* Moscow */ = {isa = PBXFileReference; lastKnownFileType = text; path = Moscow; sourceTree = ""; }; + E318DE3F2C5A4FBD00091322 /* Nicosia */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nicosia; sourceTree = ""; }; + E318DE402C5A4FBD00091322 /* Oslo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Oslo; sourceTree = ""; }; + E318DE412C5A4FBD00091322 /* Paris */ = {isa = PBXFileReference; lastKnownFileType = text; path = Paris; sourceTree = ""; }; + E318DE422C5A4FBD00091322 /* Podgorica */ = {isa = PBXFileReference; lastKnownFileType = text; path = Podgorica; sourceTree = ""; }; + E318DE432C5A4FBD00091322 /* Prague */ = {isa = PBXFileReference; lastKnownFileType = text; path = Prague; sourceTree = ""; }; + E318DE442C5A4FBD00091322 /* Riga */ = {isa = PBXFileReference; lastKnownFileType = text; path = Riga; sourceTree = ""; }; + E318DE452C5A4FBD00091322 /* Rome */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rome; sourceTree = ""; }; + E318DE462C5A4FBD00091322 /* Samara */ = {isa = PBXFileReference; lastKnownFileType = text; path = Samara; sourceTree = ""; }; + E318DE472C5A4FBD00091322 /* San_Marino */ = {isa = PBXFileReference; lastKnownFileType = text; path = San_Marino; sourceTree = ""; }; + E318DE482C5A4FBD00091322 /* Sarajevo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sarajevo; sourceTree = ""; }; + E318DE492C5A4FBD00091322 /* Saratov */ = {isa = PBXFileReference; lastKnownFileType = text; path = Saratov; sourceTree = ""; }; + E318DE4A2C5A4FBD00091322 /* Simferopol */ = {isa = PBXFileReference; lastKnownFileType = text; path = Simferopol; sourceTree = ""; }; + E318DE4B2C5A4FBD00091322 /* Skopje */ = {isa = PBXFileReference; lastKnownFileType = text; path = Skopje; sourceTree = ""; }; + E318DE4C2C5A4FBD00091322 /* Sofia */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sofia; sourceTree = ""; }; + E318DE4D2C5A4FBD00091322 /* Stockholm */ = {isa = PBXFileReference; lastKnownFileType = text; path = Stockholm; sourceTree = ""; }; + E318DE4E2C5A4FBD00091322 /* Tallinn */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tallinn; sourceTree = ""; }; + E318DE4F2C5A4FBD00091322 /* Tirane */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tirane; sourceTree = ""; }; + E318DE502C5A4FBD00091322 /* Tiraspol */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tiraspol; sourceTree = ""; }; + E318DE512C5A4FBD00091322 /* Ulyanovsk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ulyanovsk; sourceTree = ""; }; + E318DE522C5A4FBD00091322 /* Uzhgorod */ = {isa = PBXFileReference; lastKnownFileType = text; path = Uzhgorod; sourceTree = ""; }; + E318DE532C5A4FBD00091322 /* Vaduz */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vaduz; sourceTree = ""; }; + E318DE542C5A4FBD00091322 /* Vatican */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vatican; sourceTree = ""; }; + E318DE552C5A4FBD00091322 /* Vienna */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vienna; sourceTree = ""; }; + E318DE562C5A4FBD00091322 /* Vilnius */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vilnius; sourceTree = ""; }; + E318DE572C5A4FBD00091322 /* Volgograd */ = {isa = PBXFileReference; lastKnownFileType = text; path = Volgograd; sourceTree = ""; }; + E318DE582C5A4FBD00091322 /* Warsaw */ = {isa = PBXFileReference; lastKnownFileType = text; path = Warsaw; sourceTree = ""; }; + E318DE592C5A4FBD00091322 /* Zagreb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Zagreb; sourceTree = ""; }; + E318DE5A2C5A4FBD00091322 /* Zaporozhye */ = {isa = PBXFileReference; lastKnownFileType = text; path = Zaporozhye; sourceTree = ""; }; + E318DE5B2C5A4FBD00091322 /* Zurich */ = {isa = PBXFileReference; lastKnownFileType = text; path = Zurich; sourceTree = ""; }; + E318DE5D2C5A4FBD00091322 /* Antananarivo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Antananarivo; sourceTree = ""; }; + E318DE5E2C5A4FBD00091322 /* Chagos */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chagos; sourceTree = ""; }; + E318DE5F2C5A4FBD00091322 /* Christmas */ = {isa = PBXFileReference; lastKnownFileType = text; path = Christmas; sourceTree = ""; }; + E318DE602C5A4FBD00091322 /* Cocos */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cocos; sourceTree = ""; }; + E318DE612C5A4FBD00091322 /* Comoro */ = {isa = PBXFileReference; lastKnownFileType = text; path = Comoro; sourceTree = ""; }; + E318DE622C5A4FBD00091322 /* Kerguelen */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kerguelen; sourceTree = ""; }; + E318DE632C5A4FBD00091322 /* Mahe */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mahe; sourceTree = ""; }; + E318DE642C5A4FBD00091322 /* Maldives */ = {isa = PBXFileReference; lastKnownFileType = text; path = Maldives; sourceTree = ""; }; + E318DE652C5A4FBD00091322 /* Mauritius */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mauritius; sourceTree = ""; }; + E318DE662C5A4FBD00091322 /* Mayotte */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mayotte; sourceTree = ""; }; + E318DE672C5A4FBD00091322 /* Reunion */ = {isa = PBXFileReference; lastKnownFileType = text; path = Reunion; sourceTree = ""; }; + E318DE692C5A4FBD00091322 /* BajaNorte */ = {isa = PBXFileReference; lastKnownFileType = text; path = BajaNorte; sourceTree = ""; }; + E318DE6A2C5A4FBD00091322 /* BajaSur */ = {isa = PBXFileReference; lastKnownFileType = text; path = BajaSur; sourceTree = ""; }; + E318DE6B2C5A4FBD00091322 /* General */ = {isa = PBXFileReference; lastKnownFileType = text; path = General; sourceTree = ""; }; + E318DE6D2C5A4FBD00091322 /* Apia */ = {isa = PBXFileReference; lastKnownFileType = text; path = Apia; sourceTree = ""; }; + E318DE6E2C5A4FBD00091322 /* Auckland */ = {isa = PBXFileReference; lastKnownFileType = text; path = Auckland; sourceTree = ""; }; + E318DE6F2C5A4FBD00091322 /* Bougainville */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bougainville; sourceTree = ""; }; + E318DE702C5A4FBD00091322 /* Chatham */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chatham; sourceTree = ""; }; + E318DE712C5A4FBD00091322 /* Chuuk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Chuuk; sourceTree = ""; }; + E318DE722C5A4FBD00091322 /* Easter */ = {isa = PBXFileReference; lastKnownFileType = text; path = Easter; sourceTree = ""; }; + E318DE732C5A4FBD00091322 /* Efate */ = {isa = PBXFileReference; lastKnownFileType = text; path = Efate; sourceTree = ""; }; + E318DE742C5A4FBD00091322 /* Enderbury */ = {isa = PBXFileReference; lastKnownFileType = text; path = Enderbury; sourceTree = ""; }; + E318DE752C5A4FBD00091322 /* Fakaofo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Fakaofo; sourceTree = ""; }; + E318DE762C5A4FBD00091322 /* Fiji */ = {isa = PBXFileReference; lastKnownFileType = text; path = Fiji; sourceTree = ""; }; + E318DE772C5A4FBD00091322 /* Funafuti */ = {isa = PBXFileReference; lastKnownFileType = text; path = Funafuti; sourceTree = ""; }; + E318DE782C5A4FBD00091322 /* Galapagos */ = {isa = PBXFileReference; lastKnownFileType = text; path = Galapagos; sourceTree = ""; }; + E318DE792C5A4FBD00091322 /* Gambier */ = {isa = PBXFileReference; lastKnownFileType = text; path = Gambier; sourceTree = ""; }; + E318DE7A2C5A4FBD00091322 /* Guadalcanal */ = {isa = PBXFileReference; lastKnownFileType = text; path = Guadalcanal; sourceTree = ""; }; + E318DE7B2C5A4FBD00091322 /* Guam */ = {isa = PBXFileReference; lastKnownFileType = text; path = Guam; sourceTree = ""; }; + E318DE7C2C5A4FBD00091322 /* Honolulu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Honolulu; sourceTree = ""; }; + E318DE7D2C5A4FBD00091322 /* Johnston */ = {isa = PBXFileReference; lastKnownFileType = text; path = Johnston; sourceTree = ""; }; + E318DE7E2C5A4FBD00091322 /* Kanton */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kanton; sourceTree = ""; }; + E318DE7F2C5A4FBD00091322 /* Kiritimati */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kiritimati; sourceTree = ""; }; + E318DE802C5A4FBD00091322 /* Kosrae */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kosrae; sourceTree = ""; }; + E318DE812C5A4FBD00091322 /* Kwajalein */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kwajalein; sourceTree = ""; }; + E318DE822C5A4FBD00091322 /* Majuro */ = {isa = PBXFileReference; lastKnownFileType = text; path = Majuro; sourceTree = ""; }; + E318DE832C5A4FBD00091322 /* Marquesas */ = {isa = PBXFileReference; lastKnownFileType = text; path = Marquesas; sourceTree = ""; }; + E318DE842C5A4FBD00091322 /* Midway */ = {isa = PBXFileReference; lastKnownFileType = text; path = Midway; sourceTree = ""; }; + E318DE852C5A4FBD00091322 /* Nauru */ = {isa = PBXFileReference; lastKnownFileType = text; path = Nauru; sourceTree = ""; }; + E318DE862C5A4FBD00091322 /* Niue */ = {isa = PBXFileReference; lastKnownFileType = text; path = Niue; sourceTree = ""; }; + E318DE872C5A4FBD00091322 /* Norfolk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Norfolk; sourceTree = ""; }; + E318DE882C5A4FBD00091322 /* Noumea */ = {isa = PBXFileReference; lastKnownFileType = text; path = Noumea; sourceTree = ""; }; + E318DE892C5A4FBD00091322 /* Pago_Pago */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pago_Pago; sourceTree = ""; }; + E318DE8A2C5A4FBD00091322 /* Palau */ = {isa = PBXFileReference; lastKnownFileType = text; path = Palau; sourceTree = ""; }; + E318DE8B2C5A4FBD00091322 /* Pitcairn */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pitcairn; sourceTree = ""; }; + E318DE8C2C5A4FBD00091322 /* Pohnpei */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pohnpei; sourceTree = ""; }; + E318DE8D2C5A4FBD00091322 /* Ponape */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ponape; sourceTree = ""; }; + E318DE8E2C5A4FBD00091322 /* Port_Moresby */ = {isa = PBXFileReference; lastKnownFileType = text; path = Port_Moresby; sourceTree = ""; }; + E318DE8F2C5A4FBD00091322 /* Rarotonga */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rarotonga; sourceTree = ""; }; + E318DE902C5A4FBD00091322 /* Saipan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Saipan; sourceTree = ""; }; + E318DE912C5A4FBD00091322 /* Samoa */ = {isa = PBXFileReference; lastKnownFileType = text; path = Samoa; sourceTree = ""; }; + E318DE922C5A4FBD00091322 /* Tahiti */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tahiti; sourceTree = ""; }; + E318DE932C5A4FBD00091322 /* Tarawa */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tarawa; sourceTree = ""; }; + E318DE942C5A4FBD00091322 /* Tongatapu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tongatapu; sourceTree = ""; }; + E318DE952C5A4FBD00091322 /* Truk */ = {isa = PBXFileReference; lastKnownFileType = text; path = Truk; sourceTree = ""; }; + E318DE962C5A4FBD00091322 /* Wake */ = {isa = PBXFileReference; lastKnownFileType = text; path = Wake; sourceTree = ""; }; + E318DE972C5A4FBD00091322 /* Wallis */ = {isa = PBXFileReference; lastKnownFileType = text; path = Wallis; sourceTree = ""; }; + E318DE982C5A4FBD00091322 /* Yap */ = {isa = PBXFileReference; lastKnownFileType = text; path = Yap; sourceTree = ""; }; + E318DE9A2C5A4FBD00091322 /* Alaska */ = {isa = PBXFileReference; lastKnownFileType = text; path = Alaska; sourceTree = ""; }; + E318DE9B2C5A4FBD00091322 /* Aleutian */ = {isa = PBXFileReference; lastKnownFileType = text; path = Aleutian; sourceTree = ""; }; + E318DE9C2C5A4FBD00091322 /* Arizona */ = {isa = PBXFileReference; lastKnownFileType = text; path = Arizona; sourceTree = ""; }; + E318DE9D2C5A4FBD00091322 /* Central */ = {isa = PBXFileReference; lastKnownFileType = text; path = Central; sourceTree = ""; }; + E318DE9E2C5A4FBD00091322 /* East-Indiana */ = {isa = PBXFileReference; lastKnownFileType = text; path = "East-Indiana"; sourceTree = ""; }; + E318DE9F2C5A4FBD00091322 /* Eastern */ = {isa = PBXFileReference; lastKnownFileType = text; path = Eastern; sourceTree = ""; }; + E318DEA02C5A4FBD00091322 /* Hawaii */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hawaii; sourceTree = ""; }; + E318DEA12C5A4FBD00091322 /* Indiana-Starke */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Indiana-Starke"; sourceTree = ""; }; + E318DEA22C5A4FBD00091322 /* Michigan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Michigan; sourceTree = ""; }; + E318DEA32C5A4FBD00091322 /* Mountain */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mountain; sourceTree = ""; }; + E318DEA42C5A4FBD00091322 /* Pacific */ = {isa = PBXFileReference; lastKnownFileType = text; path = Pacific; sourceTree = ""; }; + E318DEA52C5A4FBD00091322 /* Samoa */ = {isa = PBXFileReference; lastKnownFileType = text; path = Samoa; sourceTree = ""; }; + E318DEA72C5A4FBD00091322 /* CET */ = {isa = PBXFileReference; lastKnownFileType = text; path = CET; sourceTree = ""; }; + E318DEA82C5A4FBD00091322 /* CST6CDT */ = {isa = PBXFileReference; lastKnownFileType = text; path = CST6CDT; sourceTree = ""; }; + E318DEA92C5A4FBD00091322 /* Cuba */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cuba; sourceTree = ""; }; + E318DEAA2C5A4FBD00091322 /* EET */ = {isa = PBXFileReference; lastKnownFileType = text; path = EET; sourceTree = ""; }; + E318DEAB2C5A4FBD00091322 /* Egypt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Egypt; sourceTree = ""; }; + E318DEAC2C5A4FBD00091322 /* Eire */ = {isa = PBXFileReference; lastKnownFileType = text; path = Eire; sourceTree = ""; }; + E318DEAD2C5A4FBD00091322 /* EST */ = {isa = PBXFileReference; lastKnownFileType = text; path = EST; sourceTree = ""; }; + E318DEAE2C5A4FBD00091322 /* EST5EDT */ = {isa = PBXFileReference; lastKnownFileType = text; path = EST5EDT; sourceTree = ""; }; + E318DEAF2C5A4FBD00091322 /* Factory */ = {isa = PBXFileReference; lastKnownFileType = text; path = Factory; sourceTree = ""; }; + E318DEB02C5A4FBD00091322 /* GB */ = {isa = PBXFileReference; lastKnownFileType = text; path = GB; sourceTree = ""; }; + E318DEB12C5A4FBD00091322 /* GB-Eire */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GB-Eire"; sourceTree = ""; }; + E318DEB22C5A4FBD00091322 /* GMT */ = {isa = PBXFileReference; lastKnownFileType = text; path = GMT; sourceTree = ""; }; + E318DEB32C5A4FBD00091322 /* GMT-0 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT-0"; sourceTree = ""; }; + E318DEB42C5A4FBD00091322 /* GMT+0 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "GMT+0"; sourceTree = ""; }; + E318DEB52C5A4FBD00091322 /* GMT0 */ = {isa = PBXFileReference; lastKnownFileType = text; path = GMT0; sourceTree = ""; }; + E318DEB62C5A4FBD00091322 /* Greenwich */ = {isa = PBXFileReference; lastKnownFileType = text; path = Greenwich; sourceTree = ""; }; + E318DEB72C5A4FBD00091322 /* Hongkong */ = {isa = PBXFileReference; lastKnownFileType = text; path = Hongkong; sourceTree = ""; }; + E318DEB82C5A4FBD00091322 /* HST */ = {isa = PBXFileReference; lastKnownFileType = text; path = HST; sourceTree = ""; }; + E318DEB92C5A4FBD00091322 /* Iceland */ = {isa = PBXFileReference; lastKnownFileType = text; path = Iceland; sourceTree = ""; }; + E318DEBA2C5A4FBD00091322 /* Iran */ = {isa = PBXFileReference; lastKnownFileType = text; path = Iran; sourceTree = ""; }; + E318DEBB2C5A4FBD00091322 /* iso3166.tab */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = iso3166.tab; sourceTree = ""; }; + E318DEBC2C5A4FBD00091322 /* Israel */ = {isa = PBXFileReference; lastKnownFileType = text; path = Israel; sourceTree = ""; }; + E318DEBD2C5A4FBD00091322 /* Jamaica */ = {isa = PBXFileReference; lastKnownFileType = text; path = Jamaica; sourceTree = ""; }; + E318DEBE2C5A4FBD00091322 /* Japan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Japan; sourceTree = ""; }; + E318DEBF2C5A4FBD00091322 /* Kwajalein */ = {isa = PBXFileReference; lastKnownFileType = text; path = Kwajalein; sourceTree = ""; }; + E318DEC02C5A4FBD00091322 /* Libya */ = {isa = PBXFileReference; lastKnownFileType = text; path = Libya; sourceTree = ""; }; + E318DEC12C5A4FBD00091322 /* localtime */ = {isa = PBXFileReference; lastKnownFileType = text; path = localtime; sourceTree = ""; }; + E318DEC22C5A4FBD00091322 /* MET */ = {isa = PBXFileReference; lastKnownFileType = text; path = MET; sourceTree = ""; }; + E318DEC32C5A4FBD00091322 /* MST */ = {isa = PBXFileReference; lastKnownFileType = text; path = MST; sourceTree = ""; }; + E318DEC42C5A4FBD00091322 /* MST7MDT */ = {isa = PBXFileReference; lastKnownFileType = text; path = MST7MDT; sourceTree = ""; }; + E318DEC52C5A4FBD00091322 /* Navajo */ = {isa = PBXFileReference; lastKnownFileType = text; path = Navajo; sourceTree = ""; }; + E318DEC62C5A4FBD00091322 /* NZ */ = {isa = PBXFileReference; lastKnownFileType = text; path = NZ; sourceTree = ""; }; + E318DEC72C5A4FBD00091322 /* NZ-CHAT */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NZ-CHAT"; sourceTree = ""; }; + E318DEC82C5A4FBD00091322 /* Poland */ = {isa = PBXFileReference; lastKnownFileType = text; path = Poland; sourceTree = ""; }; + E318DEC92C5A4FBD00091322 /* Portugal */ = {isa = PBXFileReference; lastKnownFileType = text; path = Portugal; sourceTree = ""; }; + E318DECA2C5A4FBD00091322 /* PRC */ = {isa = PBXFileReference; lastKnownFileType = text; path = PRC; sourceTree = ""; }; + E318DECB2C5A4FBD00091322 /* PST8PDT */ = {isa = PBXFileReference; lastKnownFileType = text; path = PST8PDT; sourceTree = ""; }; + E318DECC2C5A4FBD00091322 /* ROC */ = {isa = PBXFileReference; lastKnownFileType = text; path = ROC; sourceTree = ""; }; + E318DECD2C5A4FBD00091322 /* ROK */ = {isa = PBXFileReference; lastKnownFileType = text; path = ROK; sourceTree = ""; }; + E318DECE2C5A4FBD00091322 /* Singapore */ = {isa = PBXFileReference; lastKnownFileType = text; path = Singapore; sourceTree = ""; }; + E318DECF2C5A4FBD00091322 /* Turkey */ = {isa = PBXFileReference; lastKnownFileType = text; path = Turkey; sourceTree = ""; }; + E318DED02C5A4FBD00091322 /* UCT */ = {isa = PBXFileReference; lastKnownFileType = text; path = UCT; sourceTree = ""; }; + E318DED12C5A4FBD00091322 /* Universal */ = {isa = PBXFileReference; lastKnownFileType = text; path = Universal; sourceTree = ""; }; + E318DED22C5A4FBD00091322 /* UTC */ = {isa = PBXFileReference; lastKnownFileType = text; path = UTC; sourceTree = ""; }; + E318DED32C5A4FBD00091322 /* W-SU */ = {isa = PBXFileReference; lastKnownFileType = text; path = "W-SU"; sourceTree = ""; }; + E318DED42C5A4FBD00091322 /* WET */ = {isa = PBXFileReference; lastKnownFileType = text; path = WET; sourceTree = ""; }; + E318DED52C5A4FBD00091322 /* zone1970.tab */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = zone1970.tab; sourceTree = ""; }; + E318DED62C5A4FBD00091322 /* Zulu */ = {isa = PBXFileReference; lastKnownFileType = text; path = Zulu; sourceTree = ""; }; + E318DED82C5A4FBD00091322 /* README.zoneinfo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.zoneinfo; sourceTree = ""; }; + E318DED92C5A4FBD00091322 /* version */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = version; sourceTree = ""; }; + E318DEDB2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DEDD2C5A4FBD00091322 /* get_current_time_chrono.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = get_current_time_chrono.inc; sourceTree = ""; }; + E318DEDE2C5A4FBD00091322 /* get_current_time_posix.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = get_current_time_posix.inc; sourceTree = ""; }; + E318DEDF2C5A4FBD00091322 /* test_util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_util.cc; sourceTree = ""; }; + E318DEE02C5A4FBD00091322 /* test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = test_util.h; sourceTree = ""; }; + E318DEE12C5A4FBD00091322 /* zoneinfo.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = zoneinfo.inc; sourceTree = ""; }; + E318DEE32C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DEE42C5A4FBD00091322 /* civil_time_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = civil_time_benchmark.cc; sourceTree = ""; }; + E318DEE52C5A4FBD00091322 /* civil_time_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = civil_time_test.cc; sourceTree = ""; }; + E318DEE62C5A4FBD00091322 /* civil_time.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = civil_time.cc; sourceTree = ""; }; + E318DEE72C5A4FBD00091322 /* civil_time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = civil_time.h; sourceTree = ""; }; + E318DEE82C5A4FBD00091322 /* clock_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = clock_benchmark.cc; sourceTree = ""; }; + E318DEE92C5A4FBD00091322 /* clock_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = clock_test.cc; sourceTree = ""; }; + E318DEEA2C5A4FBD00091322 /* clock.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = clock.cc; sourceTree = ""; }; + E318DEEB2C5A4FBD00091322 /* clock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clock.h; sourceTree = ""; }; + E318DEEC2C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DEED2C5A4FBD00091322 /* duration_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = duration_benchmark.cc; sourceTree = ""; }; + E318DEEE2C5A4FBD00091322 /* duration_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = duration_test.cc; sourceTree = ""; }; + E318DEEF2C5A4FBD00091322 /* duration.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = duration.cc; sourceTree = ""; }; + E318DEF02C5A4FBD00091322 /* format_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = format_benchmark.cc; sourceTree = ""; }; + E318DEF12C5A4FBD00091322 /* format_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = format_test.cc; sourceTree = ""; }; + E318DEF22C5A4FBD00091322 /* format.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = format.cc; sourceTree = ""; }; + E318DEF32C5A4FBD00091322 /* time_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_benchmark.cc; sourceTree = ""; }; + E318DEF42C5A4FBD00091322 /* time_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_test.cc; sourceTree = ""; }; + E318DEF52C5A4FBD00091322 /* time_zone_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_zone_test.cc; sourceTree = ""; }; + E318DEF62C5A4FBD00091322 /* time.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time.cc; sourceTree = ""; }; + E318DEF72C5A4FBD00091322 /* time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time.h; sourceTree = ""; }; + E318DEFA2C5A4FBD00091322 /* conformance_aliases.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conformance_aliases.h; sourceTree = ""; }; + E318DEFB2C5A4FBD00091322 /* conformance_archetype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conformance_archetype.h; sourceTree = ""; }; + E318DEFC2C5A4FBD00091322 /* conformance_profile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conformance_profile.h; sourceTree = ""; }; + E318DEFD2C5A4FBD00091322 /* conformance_testing_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conformance_testing_helpers.h; sourceTree = ""; }; + E318DEFE2C5A4FBD00091322 /* conformance_testing_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = conformance_testing_test.cc; sourceTree = ""; }; + E318DEFF2C5A4FBD00091322 /* conformance_testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conformance_testing.h; sourceTree = ""; }; + E318DF002C5A4FBD00091322 /* optional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = optional.h; sourceTree = ""; }; + E318DF012C5A4FBD00091322 /* parentheses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parentheses.h; sourceTree = ""; }; + E318DF022C5A4FBD00091322 /* span.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = span.h; sourceTree = ""; }; + E318DF032C5A4FBD00091322 /* transform_args.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = transform_args.h; sourceTree = ""; }; + E318DF042C5A4FBD00091322 /* variant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = variant.h; sourceTree = ""; }; + E318DF062C5A4FBD00091322 /* any_exception_safety_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = any_exception_safety_test.cc; sourceTree = ""; }; + E318DF072C5A4FBD00091322 /* any_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = any_test.cc; sourceTree = ""; }; + E318DF082C5A4FBD00091322 /* any.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = any.h; sourceTree = ""; }; + E318DF092C5A4FBD00091322 /* bad_any_cast.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bad_any_cast.cc; sourceTree = ""; }; + E318DF0A2C5A4FBD00091322 /* bad_any_cast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bad_any_cast.h; sourceTree = ""; }; + E318DF0B2C5A4FBD00091322 /* bad_optional_access.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bad_optional_access.cc; sourceTree = ""; }; + E318DF0C2C5A4FBD00091322 /* bad_optional_access.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bad_optional_access.h; sourceTree = ""; }; + E318DF0D2C5A4FBD00091322 /* bad_variant_access.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bad_variant_access.cc; sourceTree = ""; }; + E318DF0E2C5A4FBD00091322 /* bad_variant_access.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bad_variant_access.h; sourceTree = ""; }; + E318DF0F2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DF102C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DF112C5A4FBD00091322 /* compare_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compare_test.cc; sourceTree = ""; }; + E318DF122C5A4FBD00091322 /* compare.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compare.h; sourceTree = ""; }; + E318DF132C5A4FBD00091322 /* optional_exception_safety_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = optional_exception_safety_test.cc; sourceTree = ""; }; + E318DF142C5A4FBD00091322 /* optional_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = optional_test.cc; sourceTree = ""; }; + E318DF152C5A4FBD00091322 /* optional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = optional.h; sourceTree = ""; }; + E318DF162C5A4FBD00091322 /* span_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = span_test.cc; sourceTree = ""; }; + E318DF172C5A4FBD00091322 /* span.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = span.h; sourceTree = ""; }; + E318DF182C5A4FBD00091322 /* variant_benchmark.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = variant_benchmark.cc; sourceTree = ""; }; + E318DF192C5A4FBD00091322 /* variant_exception_safety_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = variant_exception_safety_test.cc; sourceTree = ""; }; + E318DF1A2C5A4FBD00091322 /* variant_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = variant_test.cc; sourceTree = ""; }; + E318DF1B2C5A4FBD00091322 /* variant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = variant.h; sourceTree = ""; }; + E318DF1E2C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DF1F2C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318DF202C5A4FBD00091322 /* utility_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utility_test.cc; sourceTree = ""; }; + E318DF212C5A4FBD00091322 /* utility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utility.h; sourceTree = ""; }; + E318DF232C5A4FBD00091322 /* abseil.podspec.gen.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = abseil.podspec.gen.py; sourceTree = ""; }; + E318DF242C5A4FBD00091322 /* BUILD.bazel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BUILD.bazel; sourceTree = ""; }; + E318DF252C5A4FBD00091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318E7702C5A536400091322 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; + E318E7712C5A536400091322 /* dirent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirent.h; sourceTree = ""; }; + E318E7722C5A536400091322 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + E318E7732C5A536400091322 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + E318E7752C5A536400091322 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + E318E7762C5A536400091322 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + E318E7772C5A536400091322 /* stb_image_resize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stb_image_resize.h; sourceTree = ""; }; + E318E7782C5A536400091322 /* stb_image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stb_image.h; sourceTree = ""; }; + E318E77A2C5A536400091322 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + E318E77B2C5A536400091322 /* ImGuiFileDialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImGuiFileDialog.cpp; sourceTree = ""; }; + E318E77C2C5A536400091322 /* ImGuiFileDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImGuiFileDialog.h; sourceTree = ""; }; + E318E77D2C5A536400091322 /* ImGuiFileDialogConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImGuiFileDialogConfig.h; sourceTree = ""; }; + E318E77E2C5A536400091322 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + E318E77F2C5A536400091322 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + E318E7952C5A548C00091322 /* png.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = png.c; sourceTree = ""; }; + E318E7962C5A548C00091322 /* png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = png.h; sourceTree = ""; }; + E318E7972C5A548C00091322 /* pngconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngconf.h; sourceTree = ""; }; + E318E7982C5A548C00091322 /* pngdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngdebug.h; sourceTree = ""; }; + E318E7992C5A548C00091322 /* pngerror.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngerror.c; sourceTree = ""; }; + E318E79A2C5A548C00091322 /* pngget.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngget.c; sourceTree = ""; }; + E318E79B2C5A548C00091322 /* pnginfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pnginfo.h; sourceTree = ""; }; + E318E79C2C5A548C00091322 /* pnglibconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pnglibconf.h; sourceTree = ""; }; + E318E79D2C5A548C00091322 /* pngmem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngmem.c; sourceTree = ""; }; + E318E79E2C5A548C00091322 /* pngpread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngpread.c; sourceTree = ""; }; + E318E79F2C5A548C00091322 /* pngpriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngpriv.h; sourceTree = ""; }; + E318E7A02C5A548C00091322 /* pngread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngread.c; sourceTree = ""; }; + E318E7A12C5A548C00091322 /* pngrio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngrio.c; sourceTree = ""; }; + E318E7A22C5A548C00091322 /* pngrtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngrtran.c; sourceTree = ""; }; + E318E7A32C5A548C00091322 /* pngrutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngrutil.c; sourceTree = ""; }; + E318E7A42C5A548C00091322 /* pngset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngset.c; sourceTree = ""; }; + E318E7A52C5A548C00091322 /* pngstruct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngstruct.h; sourceTree = ""; }; + E318E7A62C5A548C00091322 /* pngtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngtest.c; sourceTree = ""; }; + E318E7A72C5A548C00091322 /* pngtrans.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngtrans.c; sourceTree = ""; }; + E318E7A82C5A548C00091322 /* pngwio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwio.c; sourceTree = ""; }; + E318E7A92C5A548C00091322 /* pngwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwrite.c; sourceTree = ""; }; + E318E7AA2C5A548C00091322 /* pngwtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwtran.c; sourceTree = ""; }; + E318E7AB2C5A548C00091322 /* pngwutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwutil.c; sourceTree = ""; }; + E318E7CD2C5A55AE00091322 /* filter_neon.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = filter_neon.S; path = ../arm/filter_neon.S; sourceTree = ""; }; + E318E7CE2C5A55AE00091322 /* palette_neon_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = palette_neon_intrinsics.c; path = ../arm/palette_neon_intrinsics.c; sourceTree = ""; }; + E318E7CF2C5A55AE00091322 /* filter_neon_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = filter_neon_intrinsics.c; path = ../arm/filter_neon_intrinsics.c; sourceTree = ""; }; + E318E7D62C5A55C300091322 /* arm_init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arm_init.c; sourceTree = ""; }; + E318E7DA2C5A688A00091322 /* Cousine-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Cousine-Regular.ttf"; sourceTree = ""; }; + E318E7DB2C5A688A00091322 /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = ""; }; + E318E7DC2C5A688A00091322 /* IBMPlexSansJP-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IBMPlexSansJP-Bold.ttf"; sourceTree = ""; }; + E318E7DD2C5A688A00091322 /* Karla-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Karla-Regular.ttf"; sourceTree = ""; }; + E318E7DE2C5A688A00091322 /* MaterialIcons-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "MaterialIcons-Regular.ttf"; sourceTree = ""; }; + E318E7DF2C5A688A00091322 /* NotoSansJP.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = NotoSansJP.ttf; sourceTree = ""; }; + E318E7E02C5A688A00091322 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = ""; }; + E318E7E22C5A688A00091322 /* overworld.zeml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = overworld.zeml; sourceTree = ""; }; + E318E7E32C5A688A00091322 /* ow_toolset.zeml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ow_toolset.zeml; sourceTree = ""; }; + E318E7F72C5A8DE200091322 /* file_path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_path.h; sourceTree = ""; }; + E318E7F82C5A8DE200091322 /* file_path.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = file_path.mm; sourceTree = ""; }; + E318E8092C5B24CD00091322 /* ow_toolset.zeml */ = {isa = PBXFileReference; lastKnownFileType = text; path = ow_toolset.zeml; sourceTree = ""; }; + E318E80A2C5B24CD00091322 /* overworld.zeml */ = {isa = PBXFileReference; lastKnownFileType = text; path = overworld.zeml; sourceTree = ""; }; + E318E80C2C5B24CD00091322 /* Cousine-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Cousine-Regular.ttf"; sourceTree = ""; }; + E318E80D2C5B24CD00091322 /* Karla-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Karla-Regular.ttf"; sourceTree = ""; }; + E318E80E2C5B24CD00091322 /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = ""; }; + E318E80F2C5B24CD00091322 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = ""; }; + E318E8102C5B24CD00091322 /* IBMPlexSansJP-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IBMPlexSansJP-Bold.ttf"; sourceTree = ""; }; + E318E8112C5B24CD00091322 /* MaterialIcons-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "MaterialIcons-Regular.ttf"; sourceTree = ""; }; + E318E8122C5B24CD00091322 /* NotoSansJP.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = NotoSansJP.ttf; sourceTree = ""; }; + E318E8332C5BD8C000091322 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.5.sdk/System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = DEVELOPER_DIR; }; + E318E8492C5D74B700091322 /* SDL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL.xcodeproj; path = ../lib/SDL/Xcode/SDL/SDL.xcodeproj; sourceTree = ""; }; + E318E8762C5D949200091322 /* yaze.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = yaze.png; sourceTree = ""; }; + E318E8782C5D958400091322 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = ""; }; + E318E87E2C609B3500091322 /* PencilKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PencilKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.5.sdk/System/Library/Frameworks/PencilKit.framework; sourceTree = DEVELOPER_DIR; }; + E32BC4CA2CA4D7BC001F57A8 /* command_manager.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = command_manager.cc; sourceTree = ""; }; + E36971D92CE189EA00DEF2F6 /* project.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = project.cc; sourceTree = ""; }; + E36971E02CE18A2A00DEF2F6 /* file_util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = file_util.h; sourceTree = ""; }; + E36971E12CE18A2A00DEF2F6 /* file_util.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = file_util.cc; sourceTree = ""; }; + E36971E22CE18A2A00DEF2F6 /* sdl_deleter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sdl_deleter.h; sourceTree = ""; }; + E384E2D52C76C6C800147029 /* message_data.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = message_data.cc; sourceTree = ""; }; + E38985002C67082800D4CF13 /* renderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderer.h; sourceTree = ""; }; + E38985012C67CDDB00D4CF13 /* view_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = view_controller.h; sourceTree = ""; }; + E38A97F12C6C4CE3005FB662 /* command_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = command_manager.h; sourceTree = ""; }; + E38A97F22C6C4CE3005FB662 /* extension_manager.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extension_manager.cc; sourceTree = ""; }; + E38A97F32C6C4CE3005FB662 /* extension_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extension_manager.h; sourceTree = ""; }; + E38A97F42C6C4CE3005FB662 /* settings_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = settings_editor.cc; sourceTree = ""; }; + E38A97F52C6C4CE3005FB662 /* settings_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = settings_editor.h; sourceTree = ""; }; + E3B8648F2C82144A00122951 /* asset_browser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = asset_browser.h; sourceTree = ""; }; + E3B864902C82144A00122951 /* asset_browser.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = asset_browser.cc; sourceTree = ""; }; + E3BE958B2C68379B008DD1E7 /* editor_manager.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = editor_manager.cc; sourceTree = ""; }; + E3BE958C2C68379B008DD1E7 /* editor_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = editor_manager.h; sourceTree = ""; }; + E3BE958E2C6837C8008DD1E7 /* overworld_editor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = overworld_editor.h; sourceTree = ""; }; + E3BE958F2C6837C8008DD1E7 /* overworld_editor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = overworld_editor.cc; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8307E7C120E9F9C900473790 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E318E86A2C5D74C500091322 /* SDL2.framework in Frameworks */, + 8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */, + E318E87F2C609B3500091322 /* PencilKit.framework in Frameworks */, + 83BBE9E720EB46BD00295997 /* MetalKit.framework in Frameworks */, + 83BBE9E520EB46B900295997 /* Metal.framework in Frameworks */, + E318E8342C5BD8C100091322 /* UniformTypeIdentifiers.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8307E7D720E9F9C900473790 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E318E87A2C605D5700091322 /* SDL2.framework in Frameworks */, + 8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */, + 83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */, + 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */, + 83BBE9ED20EB471700295997 /* Metal.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8307E7B520E9F9C700473790 = { + isa = PBXGroup; + children = ( + E318E8492C5D74B700091322 /* SDL.xcodeproj */, + E318E7D92C5A687600091322 /* assets */, + E318E7AC2C5A548C00091322 /* png */, + E318DF262C5A4FBD00091322 /* absl */, + E318D8FA2C59C08300091322 /* app */, + 83BBE9F020EB544400295997 /* imgui */, + 8309BD9E253CCBA70045E2A1 /* yaze-ios */, + 8307E7C520E9F9C900473790 /* Products */, + 83BBE9E320EB46B800295997 /* Frameworks */, + ); + sourceTree = ""; + }; + 8307E7C520E9F9C900473790 /* Products */ = { + isa = PBXGroup; + children = ( + 8307E7C420E9F9C900473790 /* yaze.app */, + 8307E7DA20E9F9C900473790 /* yaze.app */, + ); + name = Products; + sourceTree = ""; + }; + 8309BD9E253CCBA70045E2A1 /* yaze-ios */ = { + isa = PBXGroup; + children = ( + 8309BDF6253CDAAE0045E2A1 /* iOS */, + 8309BDF9253CDAAE0045E2A1 /* macOS */, + 8309BDA0253CCBC10045E2A1 /* main.mm */, + E318E8782C5D958400091322 /* Media.xcassets */, + ); + name = "yaze-ios"; + sourceTree = ""; + }; + 8309BDF6253CDAAE0045E2A1 /* iOS */ = { + isa = PBXGroup; + children = ( + 8309BDF7253CDAAE0045E2A1 /* LaunchScreen.storyboard */, + 8309BDF8253CDAAE0045E2A1 /* Info-iOS.plist */, + ); + path = iOS; + sourceTree = ""; + }; + 8309BDF9253CDAAE0045E2A1 /* macOS */ = { + isa = PBXGroup; + children = ( + 8309BDFA253CDAAE0045E2A1 /* MainMenu.storyboard */, + 8309BDFB253CDAAE0045E2A1 /* Info-macOS.plist */, + ); + path = macOS; + sourceTree = ""; + }; + 83BBE9E320EB46B800295997 /* Frameworks */ = { + isa = PBXGroup; + children = ( + E318E87E2C609B3500091322 /* PencilKit.framework */, + E318E8332C5BD8C000091322 /* UniformTypeIdentifiers.framework */, + E318D9A02C59DFD200091322 /* libpng16.a */, + 05318E0E274C397200A8DE2E /* GameController.framework */, + 8309BDC5253CCCFE0045E2A1 /* AppKit.framework */, + 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */, + 83BBE9EE20EB471C00295997 /* ModelIO.framework */, + 83BBE9EB20EB471700295997 /* Metal.framework */, + 83BBE9EA20EB471700295997 /* MetalKit.framework */, + 83BBE9E820EB46C100295997 /* ModelIO.framework */, + 83BBE9E620EB46BD00295997 /* MetalKit.framework */, + 83BBE9E420EB46B900295997 /* Metal.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 83BBE9F020EB544400295997 /* imgui */ = { + isa = PBXGroup; + children = ( + E318E7802C5A536400091322 /* ImGuiFileDialog */, + E318D99B2C59D0E500091322 /* imgui_stdlib.cpp */, + E318D99C2C59D0E500091322 /* imgui_stdlib.h */, + E318D9972C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp */, + E318D9942C59CDF800091322 /* imgui_impl_sdl2.cpp */, + E318D98B2C59CBBB00091322 /* TextEditor.cpp */, + E318D98C2C59CBBB00091322 /* TextEditor.h */, + 5079822D257677DB0038A28D /* imgui_tables.cpp */, + 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal.mm */, + 83BBEA0420EB54E700295997 /* imconfig.h */, + 83BBEA0320EB54E700295997 /* imgui.cpp */, + 83BBEA0220EB54E700295997 /* imgui_demo.cpp */, + 83BBEA0120EB54E700295997 /* imgui_draw.cpp */, + 07A82ED62139413C0078D120 /* imgui_internal.h */, + 07A82ED72139413C0078D120 /* imgui_widgets.cpp */, + ); + name = imgui; + path = "/Users/scawful/Code/xcode/metal-ios"; + sourceTree = ""; + }; + E318D8512C59C08300091322 /* platform */ = { + isa = PBXGroup; + children = ( + E38985012C67CDDB00D4CF13 /* view_controller.h */, + E38985002C67082800D4CF13 /* renderer.h */, + E318E7F72C5A8DE200091322 /* file_path.h */, + E318E7F82C5A8DE200091322 /* file_path.mm */, + E318D8472C59C08300091322 /* app_delegate.h */, + E318D8482C59C08300091322 /* app_delegate.mm */, + E318D8492C59C08300091322 /* clipboard.cc */, + E318D84A2C59C08300091322 /* clipboard.h */, + E318D84B2C59C08300091322 /* clipboard.mm */, + E318D84C2C59C08300091322 /* file_dialog.h */, + E318D84D2C59C08300091322 /* file_dialog.mm */, + E318D84E2C59C08300091322 /* font_loader.cc */, + E318D84F2C59C08300091322 /* font_loader.h */, + E318D8502C59C08300091322 /* font_loader.mm */, + ); + path = platform; + sourceTree = ""; + }; + E318D85B2C59C08300091322 /* core */ = { + isa = PBXGroup; + children = ( + E36971E32CE18A2A00DEF2F6 /* utils */, + E318D8512C59C08300091322 /* platform */, + E318D8522C59C08300091322 /* common.cc */, + E318D8532C59C08300091322 /* common.h */, + E318D8542C59C08300091322 /* constants.h */, + E318D8552C59C08300091322 /* controller.cc */, + E318D8562C59C08300091322 /* controller.h */, + E36971D92CE189EA00DEF2F6 /* project.cc */, + E318D8592C59C08300091322 /* project.h */, + ); + path = core; + sourceTree = ""; + }; + E318D85F2C59C08300091322 /* code */ = { + isa = PBXGroup; + children = ( + E318D85C2C59C08300091322 /* assembly_editor.cc */, + E318D85D2C59C08300091322 /* assembly_editor.h */, + E318D85E2C59C08300091322 /* memory_editor.h */, + ); + path = code; + sourceTree = ""; + }; + E318D8622C59C08300091322 /* dungeon */ = { + isa = PBXGroup; + children = ( + E318D8602C59C08300091322 /* dungeon_editor.cc */, + E318D8612C59C08300091322 /* dungeon_editor.h */, + ); + path = dungeon; + sourceTree = ""; + }; + E318D86D2C59C08300091322 /* graphics */ = { + isa = PBXGroup; + children = ( + E318D8632C59C08300091322 /* gfx_group_editor.cc */, + E318D8642C59C08300091322 /* gfx_group_editor.h */, + E318D8652C59C08300091322 /* graphics_editor.cc */, + E318D8662C59C08300091322 /* graphics_editor.h */, + E318D8672C59C08300091322 /* palette_editor.cc */, + E318D8682C59C08300091322 /* palette_editor.h */, + E318D8692C59C08300091322 /* screen_editor.cc */, + E318D86A2C59C08300091322 /* screen_editor.h */, + E318D86B2C59C08300091322 /* tile16_editor.cc */, + E318D86C2C59C08300091322 /* tile16_editor.h */, + ); + path = graphics; + sourceTree = ""; + }; + E318D8722C59C08300091322 /* message */ = { + isa = PBXGroup; + children = ( + E384E2D52C76C6C800147029 /* message_data.cc */, + E318D86E2C59C08300091322 /* message_data.h */, + E318D8702C59C08300091322 /* message_editor.cc */, + E318D8712C59C08300091322 /* message_editor.h */, + ); + path = message; + sourceTree = ""; + }; + E318D8752C59C08300091322 /* music */ = { + isa = PBXGroup; + children = ( + E318D8732C59C08300091322 /* music_editor.cc */, + E318D8742C59C08300091322 /* music_editor.h */, + ); + path = music; + sourceTree = ""; + }; + E318D8792C59C08300091322 /* overworld */ = { + isa = PBXGroup; + children = ( + E3BE958F2C6837C8008DD1E7 /* overworld_editor.cc */, + E3BE958E2C6837C8008DD1E7 /* overworld_editor.h */, + E318D8762C59C08300091322 /* entity.cc */, + E318D8772C59C08300091322 /* entity.h */, + ); + path = overworld; + sourceTree = ""; + }; + E318D87D2C59C08300091322 /* sprite */ = { + isa = PBXGroup; + children = ( + E318D87A2C59C08300091322 /* sprite_editor.cc */, + E318D87B2C59C08300091322 /* sprite_editor.h */, + E318D87C2C59C08300091322 /* zsprite.h */, + ); + path = sprite; + sourceTree = ""; + }; + E318D8842C59C08300091322 /* utils */ = { + isa = PBXGroup; + children = ( + E318D87E2C59C08300091322 /* editor.h */, + E318D87F2C59C08300091322 /* flags.h */, + E318D8802C59C08300091322 /* gfx_context.cc */, + E318D8812C59C08300091322 /* gfx_context.h */, + E318D8832C59C08300091322 /* recent_files.h */, + ); + path = utils; + sourceTree = ""; + }; + E318D88D2C59C08300091322 /* editor */ = { + isa = PBXGroup; + children = ( + E318D85F2C59C08300091322 /* code */, + E318D8622C59C08300091322 /* dungeon */, + E318D86D2C59C08300091322 /* graphics */, + E318D8722C59C08300091322 /* message */, + E318D8752C59C08300091322 /* music */, + E318D8792C59C08300091322 /* overworld */, + E318D87D2C59C08300091322 /* sprite */, + E318D8842C59C08300091322 /* utils */, + E38A97F62C6C4CE3005FB662 /* system */, + E3BE958B2C68379B008DD1E7 /* editor_manager.cc */, + E3BE958C2C68379B008DD1E7 /* editor_manager.h */, + ); + path = editor; + sourceTree = ""; + }; + E318D8912C59C08300091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318D88E2C59C08300091322 /* addressing.cc */, + E318D88F2C59C08300091322 /* instructions.cc */, + E318D8902C59C08300091322 /* opcodes.h */, + ); + path = internal; + sourceTree = ""; + }; + E318D8982C59C08300091322 /* audio */ = { + isa = PBXGroup; + children = ( + E318D8912C59C08300091322 /* internal */, + E318D8922C59C08300091322 /* apu.cc */, + E318D8932C59C08300091322 /* apu.h */, + E318D8942C59C08300091322 /* dsp.cc */, + E318D8952C59C08300091322 /* dsp.h */, + E318D8962C59C08300091322 /* spc700.cc */, + E318D8972C59C08300091322 /* spc700.h */, + ); + path = audio; + sourceTree = ""; + }; + E318D89D2C59C08300091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318D8992C59C08300091322 /* addressing.cc */, + E318D89A2C59C08300091322 /* instructions.cc */, + E318D89B2C59C08300091322 /* old_cpu.cc */, + E318D89C2C59C08300091322 /* opcodes.h */, + ); + path = internal; + sourceTree = ""; + }; + E318D8A12C59C08300091322 /* cpu */ = { + isa = PBXGroup; + children = ( + E318D89D2C59C08300091322 /* internal */, + E318D89E2C59C08300091322 /* clock.h */, + E318D89F2C59C08300091322 /* cpu.cc */, + E318D8A02C59C08300091322 /* cpu.h */, + ); + path = cpu; + sourceTree = ""; + }; + E318D8A62C59C08300091322 /* debug */ = { + isa = PBXGroup; + children = ( + E318D8A22C59C08300091322 /* asm_parser.h */, + E318D8A32C59C08300091322 /* debugger.h */, + E318D8A52C59C08300091322 /* log.h */, + ); + path = debug; + sourceTree = ""; + }; + E318D8AD2C59C08300091322 /* memory */ = { + isa = PBXGroup; + children = ( + E318D8A72C59C08300091322 /* dma_channel.h */, + E318D8A82C59C08300091322 /* dma.cc */, + E318D8A92C59C08300091322 /* dma.h */, + E318D8AA2C59C08300091322 /* memory.cc */, + E318D8AB2C59C08300091322 /* memory.h */, + E318D8AC2C59C08300091322 /* mock_memory.h */, + ); + path = memory; + sourceTree = ""; + }; + E318D8B12C59C08300091322 /* video */ = { + isa = PBXGroup; + children = ( + E318D8AE2C59C08300091322 /* ppu_registers.h */, + E318D8AF2C59C08300091322 /* ppu.cc */, + E318D8B02C59C08300091322 /* ppu.h */, + ); + path = video; + sourceTree = ""; + }; + E318D8B72C59C08300091322 /* emu */ = { + isa = PBXGroup; + children = ( + E318D8982C59C08300091322 /* audio */, + E318D8A12C59C08300091322 /* cpu */, + E318D8A62C59C08300091322 /* debug */, + E318D8AD2C59C08300091322 /* memory */, + E318D8B12C59C08300091322 /* video */, + E318D8B32C59C08300091322 /* emulator.cc */, + E318D8B42C59C08300091322 /* emulator.h */, + E318D8B52C59C08300091322 /* snes.cc */, + E318D8B62C59C08300091322 /* snes.h */, + ); + path = emu; + sourceTree = ""; + }; + E318D8C62C59C08300091322 /* gfx */ = { + isa = PBXGroup; + children = ( + E318D8B82C59C08300091322 /* bitmap.cc */, + E318D8B92C59C08300091322 /* bitmap.h */, + E318D8BA2C59C08300091322 /* compression.cc */, + E318D8BB2C59C08300091322 /* compression.h */, + E318D8BC2C59C08300091322 /* scad_format.cc */, + E318D8BD2C59C08300091322 /* scad_format.h */, + E318D8BE2C59C08300091322 /* snes_color.cc */, + E318D8BF2C59C08300091322 /* snes_color.h */, + E318D8C02C59C08300091322 /* snes_palette.cc */, + E318D8C12C59C08300091322 /* snes_palette.h */, + E318D8C22C59C08300091322 /* snes_tile.cc */, + E318D8C32C59C08300091322 /* snes_tile.h */, + E318D8C42C59C08300091322 /* tilesheet.cc */, + E318D8C52C59C08300091322 /* tilesheet.h */, + ); + path = gfx; + sourceTree = ""; + }; + E318D8D42C59C08300091322 /* gui */ = { + isa = PBXGroup; + children = ( + E3B864942C82146700122951 /* modules */, + E318D8C92C59C08300091322 /* canvas.cc */, + E318D8CA2C59C08300091322 /* canvas.h */, + E318D8CB2C59C08300091322 /* color.cc */, + E318D8CC2C59C08300091322 /* color.h */, + E318D8CD2C59C08300091322 /* icons.h */, + E318D8CE2C59C08300091322 /* input.cc */, + E318D8CF2C59C08300091322 /* input.h */, + E318D8D02C59C08300091322 /* style.cc */, + E318D8D12C59C08300091322 /* style.h */, + E318D8D22C59C08300091322 /* zeml.cc */, + E318D8D32C59C08300091322 /* zeml.h */, + ); + path = gui; + sourceTree = ""; + }; + E318D8DE2C59C08300091322 /* dungeon */ = { + isa = PBXGroup; + children = ( + E318D8D52C59C08300091322 /* object_names.h */, + E318D8D62C59C08300091322 /* object_renderer.cc */, + E318D8D72C59C08300091322 /* object_renderer.h */, + E318D8D82C59C08300091322 /* room_entrance.h */, + E318D8D92C59C08300091322 /* room_names.h */, + E318D8DA2C59C08300091322 /* room_object.cc */, + E318D8DB2C59C08300091322 /* room_object.h */, + E318D8DC2C59C08300091322 /* room.cc */, + E318D8DD2C59C08300091322 /* room.h */, + ); + path = dungeon; + sourceTree = ""; + }; + E318D8E22C59C08300091322 /* music */ = { + isa = PBXGroup; + children = ( + E318D8DF2C59C08300091322 /* spc700.def */, + E318D8E02C59C08300091322 /* tracker.cc */, + E318D8E12C59C08300091322 /* tracker.h */, + ); + path = music; + sourceTree = ""; + }; + E318D8E72C59C08300091322 /* overworld */ = { + isa = PBXGroup; + children = ( + E318D8E32C59C08300091322 /* overworld_map.cc */, + E318D8E42C59C08300091322 /* overworld_map.h */, + E318D8E52C59C08300091322 /* overworld.cc */, + E318D8E62C59C08300091322 /* overworld.h */, + ); + path = overworld; + sourceTree = ""; + }; + E318D8ED2C59C08300091322 /* screen */ = { + isa = PBXGroup; + children = ( + E318D8E82C59C08300091322 /* dungeon_map.h */, + E318D8E92C59C08300091322 /* inventory.cc */, + E318D8EA2C59C08300091322 /* inventory.h */, + E318D8EB2C59C08300091322 /* title_screen.cc */, + E318D8EC2C59C08300091322 /* title_screen.h */, + ); + path = screen; + sourceTree = ""; + }; + E318D8F02C59C08300091322 /* sprite */ = { + isa = PBXGroup; + children = ( + E318D8EE2C59C08300091322 /* sprite.cc */, + E318D8EF2C59C08300091322 /* sprite.h */, + ); + path = sprite; + sourceTree = ""; + }; + E318D8F32C59C08300091322 /* zelda3 */ = { + isa = PBXGroup; + children = ( + E318D8DE2C59C08300091322 /* dungeon */, + E318D8E22C59C08300091322 /* music */, + E318D8E72C59C08300091322 /* overworld */, + E318D8ED2C59C08300091322 /* screen */, + E318D8F02C59C08300091322 /* sprite */, + E318D8F22C59C08300091322 /* common.h */, + ); + path = zelda3; + sourceTree = ""; + }; + E318D8FA2C59C08300091322 /* app */ = { + isa = PBXGroup; + children = ( + E318D85B2C59C08300091322 /* core */, + E318D88D2C59C08300091322 /* editor */, + E318D8B72C59C08300091322 /* emu */, + E318D8C62C59C08300091322 /* gfx */, + E318D8D42C59C08300091322 /* gui */, + E318D8F32C59C08300091322 /* zelda3 */, + E318D8F62C59C08300091322 /* rom.cc */, + E318D8F72C59C08300091322 /* rom.h */, + E318D8F82C59C08300091322 /* yaze.cc */, + ); + name = app; + path = ../app; + sourceTree = ""; + }; + E318D9A22C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318D9AA2C5A4FBD00091322 /* algorithm */ = { + isa = PBXGroup; + children = ( + E318D9A22C5A4FBD00091322 /* CMakeFiles */, + E318D9A32C5A4FBD00091322 /* algorithm_test.cc */, + E318D9A42C5A4FBD00091322 /* algorithm.h */, + E318D9A52C5A4FBD00091322 /* BUILD.bazel */, + E318D9A62C5A4FBD00091322 /* CMakeLists.txt */, + E318D9A72C5A4FBD00091322 /* container_test.cc */, + E318D9A82C5A4FBD00091322 /* container.h */, + E318D9A92C5A4FBD00091322 /* equal_benchmark.cc */, + ); + path = algorithm; + sourceTree = ""; + }; + E318D9AB2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318D9ED2C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318D9AC2C5A4FBD00091322 /* atomic_hook_test_helper.cc */, + E318D9AD2C5A4FBD00091322 /* atomic_hook_test_helper.h */, + E318D9AE2C5A4FBD00091322 /* atomic_hook_test.cc */, + E318D9AF2C5A4FBD00091322 /* atomic_hook.h */, + E318D9B02C5A4FBD00091322 /* cmake_thread_test.cc */, + E318D9B12C5A4FBD00091322 /* cycleclock.cc */, + E318D9B22C5A4FBD00091322 /* cycleclock.h */, + E318D9B32C5A4FBD00091322 /* direct_mmap.h */, + E318D9B42C5A4FBD00091322 /* dynamic_annotations.h */, + E318D9B52C5A4FBD00091322 /* endian_test.cc */, + E318D9B62C5A4FBD00091322 /* endian.h */, + E318D9B72C5A4FBD00091322 /* errno_saver_test.cc */, + E318D9B82C5A4FBD00091322 /* errno_saver.h */, + E318D9B92C5A4FBD00091322 /* exception_safety_testing.cc */, + E318D9BA2C5A4FBD00091322 /* exception_safety_testing.h */, + E318D9BB2C5A4FBD00091322 /* exception_testing.h */, + E318D9BC2C5A4FBD00091322 /* fast_type_id_test.cc */, + E318D9BD2C5A4FBD00091322 /* fast_type_id.h */, + E318D9BE2C5A4FBD00091322 /* hide_ptr.h */, + E318D9BF2C5A4FBD00091322 /* identity.h */, + E318D9C02C5A4FBD00091322 /* inline_variable_testing.h */, + E318D9C12C5A4FBD00091322 /* inline_variable.h */, + E318D9C22C5A4FBD00091322 /* invoke.h */, + E318D9C32C5A4FBD00091322 /* low_level_alloc_test.cc */, + E318D9C42C5A4FBD00091322 /* low_level_alloc.cc */, + E318D9C52C5A4FBD00091322 /* low_level_alloc.h */, + E318D9C62C5A4FBD00091322 /* low_level_scheduling.h */, + E318D9C72C5A4FBD00091322 /* per_thread_tls.h */, + E318D9C82C5A4FBD00091322 /* prefetch_test.cc */, + E318D9C92C5A4FBD00091322 /* prefetch.h */, + E318D9CA2C5A4FBD00091322 /* pretty_function.h */, + E318D9CB2C5A4FBD00091322 /* raw_logging.cc */, + E318D9CC2C5A4FBD00091322 /* raw_logging.h */, + E318D9CD2C5A4FBD00091322 /* scheduling_mode.h */, + E318D9CE2C5A4FBD00091322 /* scoped_set_env_test.cc */, + E318D9CF2C5A4FBD00091322 /* scoped_set_env.cc */, + E318D9D02C5A4FBD00091322 /* scoped_set_env.h */, + E318D9D12C5A4FBD00091322 /* spinlock_akaros.inc */, + E318D9D22C5A4FBD00091322 /* spinlock_benchmark.cc */, + E318D9D32C5A4FBD00091322 /* spinlock_linux.inc */, + E318D9D42C5A4FBD00091322 /* spinlock_posix.inc */, + E318D9D52C5A4FBD00091322 /* spinlock_wait.cc */, + E318D9D62C5A4FBD00091322 /* spinlock_wait.h */, + E318D9D72C5A4FBD00091322 /* spinlock_win32.inc */, + E318D9D82C5A4FBD00091322 /* spinlock.cc */, + E318D9D92C5A4FBD00091322 /* spinlock.h */, + E318D9DA2C5A4FBD00091322 /* strerror_benchmark.cc */, + E318D9DB2C5A4FBD00091322 /* strerror_test.cc */, + E318D9DC2C5A4FBD00091322 /* strerror.cc */, + E318D9DD2C5A4FBD00091322 /* strerror.h */, + E318D9DE2C5A4FBD00091322 /* sysinfo_test.cc */, + E318D9DF2C5A4FBD00091322 /* sysinfo.cc */, + E318D9E02C5A4FBD00091322 /* sysinfo.h */, + E318D9E12C5A4FBD00091322 /* thread_annotations.h */, + E318D9E22C5A4FBD00091322 /* thread_identity_benchmark.cc */, + E318D9E32C5A4FBD00091322 /* thread_identity_test.cc */, + E318D9E42C5A4FBD00091322 /* thread_identity.cc */, + E318D9E52C5A4FBD00091322 /* thread_identity.h */, + E318D9E62C5A4FBD00091322 /* throw_delegate.cc */, + E318D9E72C5A4FBD00091322 /* throw_delegate.h */, + E318D9E82C5A4FBD00091322 /* tsan_mutex_interface.h */, + E318D9E92C5A4FBD00091322 /* unaligned_access.h */, + E318D9EA2C5A4FBD00091322 /* unique_small_name_test.cc */, + E318D9EB2C5A4FBD00091322 /* unscaledcycleclock.cc */, + E318D9EC2C5A4FBD00091322 /* unscaledcycleclock.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DA0B2C5A4FBD00091322 /* base */ = { + isa = PBXGroup; + children = ( + E318D9AB2C5A4FBD00091322 /* CMakeFiles */, + E318D9ED2C5A4FBD00091322 /* internal */, + E318D9EE2C5A4FBD00091322 /* attributes.h */, + E318D9EF2C5A4FBD00091322 /* bit_cast_test.cc */, + E318D9F02C5A4FBD00091322 /* BUILD.bazel */, + E318D9F12C5A4FBD00091322 /* call_once_test.cc */, + E318D9F22C5A4FBD00091322 /* call_once.h */, + E318D9F32C5A4FBD00091322 /* casts.h */, + E318D9F42C5A4FBD00091322 /* CMakeLists.txt */, + E318D9F52C5A4FBD00091322 /* config_test.cc */, + E318D9F62C5A4FBD00091322 /* config.h */, + E318D9F72C5A4FBD00091322 /* const_init.h */, + E318D9F82C5A4FBD00091322 /* dynamic_annotations.h */, + E318D9F92C5A4FBD00091322 /* exception_safety_testing_test.cc */, + E318D9FA2C5A4FBD00091322 /* inline_variable_test_a.cc */, + E318D9FB2C5A4FBD00091322 /* inline_variable_test_b.cc */, + E318D9FC2C5A4FBD00091322 /* inline_variable_test.cc */, + E318D9FD2C5A4FBD00091322 /* invoke_test.cc */, + E318D9FE2C5A4FBD00091322 /* log_severity_test.cc */, + E318D9FF2C5A4FBD00091322 /* log_severity.cc */, + E318DA002C5A4FBD00091322 /* log_severity.h */, + E318DA012C5A4FBD00091322 /* macros.h */, + E318DA022C5A4FBD00091322 /* optimization_test.cc */, + E318DA032C5A4FBD00091322 /* optimization.h */, + E318DA042C5A4FBD00091322 /* options.h */, + E318DA052C5A4FBD00091322 /* policy_checks.h */, + E318DA062C5A4FBD00091322 /* port.h */, + E318DA072C5A4FBD00091322 /* raw_logging_test.cc */, + E318DA082C5A4FBD00091322 /* spinlock_test_common.cc */, + E318DA092C5A4FBD00091322 /* thread_annotations.h */, + E318DA0A2C5A4FBD00091322 /* throw_delegate_test.cc */, + ); + path = base; + sourceTree = ""; + }; + E318DA0C2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DA0E2C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DA0D2C5A4FBD00091322 /* cleanup.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DA132C5A4FBD00091322 /* cleanup */ = { + isa = PBXGroup; + children = ( + E318DA0C2C5A4FBD00091322 /* CMakeFiles */, + E318DA0E2C5A4FBD00091322 /* internal */, + E318DA0F2C5A4FBD00091322 /* BUILD.bazel */, + E318DA102C5A4FBD00091322 /* cleanup_test.cc */, + E318DA112C5A4FBD00091322 /* cleanup.h */, + E318DA122C5A4FBD00091322 /* CMakeLists.txt */, + ); + path = cleanup; + sourceTree = ""; + }; + E318DA142C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DA152C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DA472C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DA162C5A4FBD00091322 /* btree_container.h */, + E318DA172C5A4FBD00091322 /* btree.h */, + E318DA182C5A4FBD00091322 /* common.h */, + E318DA192C5A4FBD00091322 /* compressed_tuple_test.cc */, + E318DA1A2C5A4FBD00091322 /* compressed_tuple.h */, + E318DA1B2C5A4FBD00091322 /* container_memory_test.cc */, + E318DA1C2C5A4FBD00091322 /* container_memory.h */, + E318DA1D2C5A4FBD00091322 /* counting_allocator.h */, + E318DA1E2C5A4FBD00091322 /* hash_function_defaults_test.cc */, + E318DA1F2C5A4FBD00091322 /* hash_function_defaults.h */, + E318DA202C5A4FBD00091322 /* hash_generator_testing.cc */, + E318DA212C5A4FBD00091322 /* hash_generator_testing.h */, + E318DA222C5A4FBD00091322 /* hash_policy_testing_test.cc */, + E318DA232C5A4FBD00091322 /* hash_policy_testing.h */, + E318DA242C5A4FBD00091322 /* hash_policy_traits_test.cc */, + E318DA252C5A4FBD00091322 /* hash_policy_traits.h */, + E318DA262C5A4FBD00091322 /* hashtable_debug_hooks.h */, + E318DA272C5A4FBD00091322 /* hashtable_debug.h */, + E318DA282C5A4FBD00091322 /* hashtablez_sampler_force_weak_definition.cc */, + E318DA292C5A4FBD00091322 /* hashtablez_sampler_test.cc */, + E318DA2A2C5A4FBD00091322 /* hashtablez_sampler.cc */, + E318DA2B2C5A4FBD00091322 /* hashtablez_sampler.h */, + E318DA2C2C5A4FBD00091322 /* inlined_vector.h */, + E318DA2D2C5A4FBD00091322 /* layout_benchmark.cc */, + E318DA2E2C5A4FBD00091322 /* layout_test.cc */, + E318DA2F2C5A4FBD00091322 /* layout.h */, + E318DA302C5A4FBD00091322 /* node_slot_policy_test.cc */, + E318DA312C5A4FBD00091322 /* node_slot_policy.h */, + E318DA322C5A4FBD00091322 /* raw_hash_map.h */, + E318DA332C5A4FBD00091322 /* raw_hash_set_allocator_test.cc */, + E318DA342C5A4FBD00091322 /* raw_hash_set_benchmark.cc */, + E318DA352C5A4FBD00091322 /* raw_hash_set_probe_benchmark.cc */, + E318DA362C5A4FBD00091322 /* raw_hash_set_test.cc */, + E318DA372C5A4FBD00091322 /* raw_hash_set.cc */, + E318DA382C5A4FBD00091322 /* raw_hash_set.h */, + E318DA392C5A4FBD00091322 /* test_instance_tracker_test.cc */, + E318DA3A2C5A4FBD00091322 /* test_instance_tracker.cc */, + E318DA3B2C5A4FBD00091322 /* test_instance_tracker.h */, + E318DA3C2C5A4FBD00091322 /* tracked.h */, + E318DA3D2C5A4FBD00091322 /* unordered_map_constructor_test.h */, + E318DA3E2C5A4FBD00091322 /* unordered_map_lookup_test.h */, + E318DA3F2C5A4FBD00091322 /* unordered_map_members_test.h */, + E318DA402C5A4FBD00091322 /* unordered_map_modifiers_test.h */, + E318DA412C5A4FBD00091322 /* unordered_map_test.cc */, + E318DA422C5A4FBD00091322 /* unordered_set_constructor_test.h */, + E318DA432C5A4FBD00091322 /* unordered_set_lookup_test.h */, + E318DA442C5A4FBD00091322 /* unordered_set_members_test.h */, + E318DA452C5A4FBD00091322 /* unordered_set_modifiers_test.h */, + E318DA462C5A4FBD00091322 /* unordered_set_test.cc */, + ); + path = internal; + sourceTree = ""; + }; + E318DA602C5A4FBD00091322 /* container */ = { + isa = PBXGroup; + children = ( + E318DA152C5A4FBD00091322 /* CMakeFiles */, + E318DA472C5A4FBD00091322 /* internal */, + E318DA482C5A4FBD00091322 /* btree_benchmark.cc */, + E318DA492C5A4FBD00091322 /* btree_map.h */, + E318DA4A2C5A4FBD00091322 /* btree_set.h */, + E318DA4B2C5A4FBD00091322 /* btree_test.cc */, + E318DA4C2C5A4FBD00091322 /* btree_test.h */, + E318DA4D2C5A4FBD00091322 /* BUILD.bazel */, + E318DA4E2C5A4FBD00091322 /* CMakeLists.txt */, + E318DA4F2C5A4FBD00091322 /* fixed_array_benchmark.cc */, + E318DA502C5A4FBD00091322 /* fixed_array_exception_safety_test.cc */, + E318DA512C5A4FBD00091322 /* fixed_array_test.cc */, + E318DA522C5A4FBD00091322 /* fixed_array.h */, + E318DA532C5A4FBD00091322 /* flat_hash_map_test.cc */, + E318DA542C5A4FBD00091322 /* flat_hash_map.h */, + E318DA552C5A4FBD00091322 /* flat_hash_set_test.cc */, + E318DA562C5A4FBD00091322 /* flat_hash_set.h */, + E318DA572C5A4FBD00091322 /* inlined_vector_benchmark.cc */, + E318DA582C5A4FBD00091322 /* inlined_vector_exception_safety_test.cc */, + E318DA592C5A4FBD00091322 /* inlined_vector_test.cc */, + E318DA5A2C5A4FBD00091322 /* inlined_vector.h */, + E318DA5B2C5A4FBD00091322 /* node_hash_map_test.cc */, + E318DA5C2C5A4FBD00091322 /* node_hash_map.h */, + E318DA5D2C5A4FBD00091322 /* node_hash_set_test.cc */, + E318DA5E2C5A4FBD00091322 /* node_hash_set.h */, + E318DA5F2C5A4FBD00091322 /* sample_element_size_test.cc */, + ); + path = container; + sourceTree = ""; + }; + E318DA672C5A4FBD00091322 /* copts */ = { + isa = PBXGroup; + children = ( + E318DA612C5A4FBD00091322 /* AbseilConfigureCopts.cmake */, + E318DA622C5A4FBD00091322 /* configure_copts.bzl */, + E318DA632C5A4FBD00091322 /* copts.py */, + E318DA642C5A4FBD00091322 /* generate_copts.py */, + E318DA652C5A4FBD00091322 /* GENERATED_AbseilCopts.cmake */, + E318DA662C5A4FBD00091322 /* GENERATED_copts.bzl */, + ); + path = copts; + sourceTree = ""; + }; + E318DA682C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DA822C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DA692C5A4FBD00091322 /* address_is_readable.cc */, + E318DA6A2C5A4FBD00091322 /* address_is_readable.h */, + E318DA6B2C5A4FBD00091322 /* demangle_test.cc */, + E318DA6C2C5A4FBD00091322 /* demangle.cc */, + E318DA6D2C5A4FBD00091322 /* demangle.h */, + E318DA6E2C5A4FBD00091322 /* elf_mem_image.cc */, + E318DA6F2C5A4FBD00091322 /* elf_mem_image.h */, + E318DA702C5A4FBD00091322 /* examine_stack.cc */, + E318DA712C5A4FBD00091322 /* examine_stack.h */, + E318DA722C5A4FBD00091322 /* stack_consumption_test.cc */, + E318DA732C5A4FBD00091322 /* stack_consumption.cc */, + E318DA742C5A4FBD00091322 /* stack_consumption.h */, + E318DA752C5A4FBD00091322 /* stacktrace_aarch64-inl.inc */, + E318DA762C5A4FBD00091322 /* stacktrace_arm-inl.inc */, + E318DA772C5A4FBD00091322 /* stacktrace_config.h */, + E318DA782C5A4FBD00091322 /* stacktrace_emscripten-inl.inc */, + E318DA792C5A4FBD00091322 /* stacktrace_generic-inl.inc */, + E318DA7A2C5A4FBD00091322 /* stacktrace_powerpc-inl.inc */, + E318DA7B2C5A4FBD00091322 /* stacktrace_riscv-inl.inc */, + E318DA7C2C5A4FBD00091322 /* stacktrace_unimplemented-inl.inc */, + E318DA7D2C5A4FBD00091322 /* stacktrace_win32-inl.inc */, + E318DA7E2C5A4FBD00091322 /* stacktrace_x86-inl.inc */, + E318DA7F2C5A4FBD00091322 /* symbolize.h */, + E318DA802C5A4FBD00091322 /* vdso_support.cc */, + E318DA812C5A4FBD00091322 /* vdso_support.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DA972C5A4FBD00091322 /* debugging */ = { + isa = PBXGroup; + children = ( + E318DA682C5A4FBD00091322 /* CMakeFiles */, + E318DA822C5A4FBD00091322 /* internal */, + E318DA832C5A4FBD00091322 /* BUILD.bazel */, + E318DA842C5A4FBD00091322 /* CMakeLists.txt */, + E318DA852C5A4FBD00091322 /* failure_signal_handler_test.cc */, + E318DA862C5A4FBD00091322 /* failure_signal_handler.cc */, + E318DA872C5A4FBD00091322 /* failure_signal_handler.h */, + E318DA882C5A4FBD00091322 /* leak_check_fail_test.cc */, + E318DA892C5A4FBD00091322 /* leak_check_test.cc */, + E318DA8A2C5A4FBD00091322 /* leak_check.cc */, + E318DA8B2C5A4FBD00091322 /* leak_check.h */, + E318DA8C2C5A4FBD00091322 /* stacktrace_benchmark.cc */, + E318DA8D2C5A4FBD00091322 /* stacktrace.cc */, + E318DA8E2C5A4FBD00091322 /* stacktrace.h */, + E318DA8F2C5A4FBD00091322 /* symbolize_darwin.inc */, + E318DA902C5A4FBD00091322 /* symbolize_elf.inc */, + E318DA912C5A4FBD00091322 /* symbolize_emscripten.inc */, + E318DA922C5A4FBD00091322 /* symbolize_test.cc */, + E318DA932C5A4FBD00091322 /* symbolize_unimplemented.inc */, + E318DA942C5A4FBD00091322 /* symbolize_win32.inc */, + E318DA952C5A4FBD00091322 /* symbolize.cc */, + E318DA962C5A4FBD00091322 /* symbolize.h */, + ); + path = debugging; + sourceTree = ""; + }; + E318DA982C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DAAC2C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DA992C5A4FBD00091322 /* commandlineflag.cc */, + E318DA9A2C5A4FBD00091322 /* commandlineflag.h */, + E318DA9B2C5A4FBD00091322 /* flag_msvc.inc */, + E318DA9C2C5A4FBD00091322 /* flag.cc */, + E318DA9D2C5A4FBD00091322 /* flag.h */, + E318DA9E2C5A4FBD00091322 /* parse.h */, + E318DA9F2C5A4FBD00091322 /* path_util_test.cc */, + E318DAA02C5A4FBD00091322 /* path_util.h */, + E318DAA12C5A4FBD00091322 /* private_handle_accessor.cc */, + E318DAA22C5A4FBD00091322 /* private_handle_accessor.h */, + E318DAA32C5A4FBD00091322 /* program_name_test.cc */, + E318DAA42C5A4FBD00091322 /* program_name.cc */, + E318DAA52C5A4FBD00091322 /* program_name.h */, + E318DAA62C5A4FBD00091322 /* registry.h */, + E318DAA72C5A4FBD00091322 /* sequence_lock_test.cc */, + E318DAA82C5A4FBD00091322 /* sequence_lock.h */, + E318DAA92C5A4FBD00091322 /* usage_test.cc */, + E318DAAA2C5A4FBD00091322 /* usage.cc */, + E318DAAB2C5A4FBD00091322 /* usage.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DAC92C5A4FBD00091322 /* flags */ = { + isa = PBXGroup; + children = ( + E318DA982C5A4FBD00091322 /* CMakeFiles */, + E318DAAC2C5A4FBD00091322 /* internal */, + E318DAAD2C5A4FBD00091322 /* BUILD.bazel */, + E318DAAE2C5A4FBD00091322 /* CMakeLists.txt */, + E318DAAF2C5A4FBD00091322 /* commandlineflag_test.cc */, + E318DAB02C5A4FBD00091322 /* commandlineflag.cc */, + E318DAB12C5A4FBD00091322 /* commandlineflag.h */, + E318DAB22C5A4FBD00091322 /* config_test.cc */, + E318DAB32C5A4FBD00091322 /* config.h */, + E318DAB42C5A4FBD00091322 /* declare.h */, + E318DAB52C5A4FBD00091322 /* flag_benchmark.cc */, + E318DAB62C5A4FBD00091322 /* flag_benchmark.lds */, + E318DAB72C5A4FBD00091322 /* flag_test_defs.cc */, + E318DAB82C5A4FBD00091322 /* flag_test.cc */, + E318DAB92C5A4FBD00091322 /* flag.cc */, + E318DABA2C5A4FBD00091322 /* flag.h */, + E318DABB2C5A4FBD00091322 /* marshalling_test.cc */, + E318DABC2C5A4FBD00091322 /* marshalling.cc */, + E318DABD2C5A4FBD00091322 /* marshalling.h */, + E318DABE2C5A4FBD00091322 /* parse_test.cc */, + E318DABF2C5A4FBD00091322 /* parse.cc */, + E318DAC02C5A4FBD00091322 /* parse.h */, + E318DAC12C5A4FBD00091322 /* reflection_test.cc */, + E318DAC22C5A4FBD00091322 /* reflection.cc */, + E318DAC32C5A4FBD00091322 /* reflection.h */, + E318DAC42C5A4FBD00091322 /* usage_config_test.cc */, + E318DAC52C5A4FBD00091322 /* usage_config.cc */, + E318DAC62C5A4FBD00091322 /* usage_config.h */, + E318DAC72C5A4FBD00091322 /* usage.cc */, + E318DAC82C5A4FBD00091322 /* usage.h */, + ); + path = flags; + sourceTree = ""; + }; + E318DACA2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DACE2C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DACB2C5A4FBD00091322 /* any_invocable.h */, + E318DACC2C5A4FBD00091322 /* front_binder.h */, + E318DACD2C5A4FBD00091322 /* function_ref.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DAD82C5A4FBD00091322 /* functional */ = { + isa = PBXGroup; + children = ( + E318DACA2C5A4FBD00091322 /* CMakeFiles */, + E318DACE2C5A4FBD00091322 /* internal */, + E318DACF2C5A4FBD00091322 /* any_invocable_test.cc */, + E318DAD02C5A4FBD00091322 /* any_invocable.h */, + E318DAD12C5A4FBD00091322 /* bind_front_test.cc */, + E318DAD22C5A4FBD00091322 /* bind_front.h */, + E318DAD32C5A4FBD00091322 /* BUILD.bazel */, + E318DAD42C5A4FBD00091322 /* CMakeLists.txt */, + E318DAD52C5A4FBD00091322 /* function_ref_test.cc */, + E318DAD62C5A4FBD00091322 /* function_ref.h */, + E318DAD72C5A4FBD00091322 /* function_type_benchmark.cc */, + ); + path = functional; + sourceTree = ""; + }; + E318DAD92C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DAE42C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DADA2C5A4FBD00091322 /* city_test.cc */, + E318DADB2C5A4FBD00091322 /* city.cc */, + E318DADC2C5A4FBD00091322 /* city.h */, + E318DADD2C5A4FBD00091322 /* hash.cc */, + E318DADE2C5A4FBD00091322 /* hash.h */, + E318DADF2C5A4FBD00091322 /* low_level_hash_test.cc */, + E318DAE02C5A4FBD00091322 /* low_level_hash.cc */, + E318DAE12C5A4FBD00091322 /* low_level_hash.h */, + E318DAE22C5A4FBD00091322 /* print_hash_of.cc */, + E318DAE32C5A4FBD00091322 /* spy_hash_state.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DAEB2C5A4FBD00091322 /* hash */ = { + isa = PBXGroup; + children = ( + E318DAD92C5A4FBD00091322 /* CMakeFiles */, + E318DAE42C5A4FBD00091322 /* internal */, + E318DAE52C5A4FBD00091322 /* BUILD.bazel */, + E318DAE62C5A4FBD00091322 /* CMakeLists.txt */, + E318DAE72C5A4FBD00091322 /* hash_benchmark.cc */, + E318DAE82C5A4FBD00091322 /* hash_test.cc */, + E318DAE92C5A4FBD00091322 /* hash_testing.h */, + E318DAEA2C5A4FBD00091322 /* hash.h */, + ); + path = hash; + sourceTree = ""; + }; + E318DAEC2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DAF22C5A4FBD00091322 /* memory */ = { + isa = PBXGroup; + children = ( + E318DAEC2C5A4FBD00091322 /* CMakeFiles */, + E318DAED2C5A4FBD00091322 /* BUILD.bazel */, + E318DAEE2C5A4FBD00091322 /* CMakeLists.txt */, + E318DAEF2C5A4FBD00091322 /* memory_exception_safety_test.cc */, + E318DAF02C5A4FBD00091322 /* memory_test.cc */, + E318DAF12C5A4FBD00091322 /* memory.h */, + ); + path = memory; + sourceTree = ""; + }; + E318DAF32C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DAF82C5A4FBD00091322 /* meta */ = { + isa = PBXGroup; + children = ( + E318DAF32C5A4FBD00091322 /* CMakeFiles */, + E318DAF42C5A4FBD00091322 /* BUILD.bazel */, + E318DAF52C5A4FBD00091322 /* CMakeLists.txt */, + E318DAF62C5A4FBD00091322 /* type_traits_test.cc */, + E318DAF72C5A4FBD00091322 /* type_traits.h */, + ); + path = meta; + sourceTree = ""; + }; + E318DAF92C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DAFC2C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DAFA2C5A4FBD00091322 /* bits.h */, + E318DAFB2C5A4FBD00091322 /* representation.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DB092C5A4FBD00091322 /* numeric */ = { + isa = PBXGroup; + children = ( + E318DAF92C5A4FBD00091322 /* CMakeFiles */, + E318DAFC2C5A4FBD00091322 /* internal */, + E318DAFD2C5A4FBD00091322 /* bits_benchmark.cc */, + E318DAFE2C5A4FBD00091322 /* bits_test.cc */, + E318DAFF2C5A4FBD00091322 /* bits.h */, + E318DB002C5A4FBD00091322 /* BUILD.bazel */, + E318DB012C5A4FBD00091322 /* CMakeLists.txt */, + E318DB022C5A4FBD00091322 /* int128_benchmark.cc */, + E318DB032C5A4FBD00091322 /* int128_have_intrinsic.inc */, + E318DB042C5A4FBD00091322 /* int128_no_intrinsic.inc */, + E318DB052C5A4FBD00091322 /* int128_stream_test.cc */, + E318DB062C5A4FBD00091322 /* int128_test.cc */, + E318DB072C5A4FBD00091322 /* int128.cc */, + E318DB082C5A4FBD00091322 /* int128.h */, + ); + path = numeric; + sourceTree = ""; + }; + E318DB0A2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DB142C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DB0B2C5A4FBD00091322 /* exponential_biased_test.cc */, + E318DB0C2C5A4FBD00091322 /* exponential_biased.cc */, + E318DB0D2C5A4FBD00091322 /* exponential_biased.h */, + E318DB0E2C5A4FBD00091322 /* periodic_sampler_benchmark.cc */, + E318DB0F2C5A4FBD00091322 /* periodic_sampler_test.cc */, + E318DB102C5A4FBD00091322 /* periodic_sampler.cc */, + E318DB112C5A4FBD00091322 /* periodic_sampler.h */, + E318DB122C5A4FBD00091322 /* sample_recorder_test.cc */, + E318DB132C5A4FBD00091322 /* sample_recorder.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DB172C5A4FBD00091322 /* profiling */ = { + isa = PBXGroup; + children = ( + E318DB0A2C5A4FBD00091322 /* CMakeFiles */, + E318DB142C5A4FBD00091322 /* internal */, + E318DB152C5A4FBD00091322 /* BUILD.bazel */, + E318DB162C5A4FBD00091322 /* CMakeLists.txt */, + ); + path = profiling; + sourceTree = ""; + }; + E318DB182C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DB552C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DB192C5A4FBD00091322 /* BUILD.bazel */, + E318DB1A2C5A4FBD00091322 /* chi_square_test.cc */, + E318DB1B2C5A4FBD00091322 /* chi_square.cc */, + E318DB1C2C5A4FBD00091322 /* chi_square.h */, + E318DB1D2C5A4FBD00091322 /* distribution_caller.h */, + E318DB1E2C5A4FBD00091322 /* distribution_test_util_test.cc */, + E318DB1F2C5A4FBD00091322 /* distribution_test_util.cc */, + E318DB202C5A4FBD00091322 /* distribution_test_util.h */, + E318DB212C5A4FBD00091322 /* explicit_seed_seq_test.cc */, + E318DB222C5A4FBD00091322 /* explicit_seed_seq.h */, + E318DB232C5A4FBD00091322 /* fast_uniform_bits_test.cc */, + E318DB242C5A4FBD00091322 /* fast_uniform_bits.h */, + E318DB252C5A4FBD00091322 /* fastmath_test.cc */, + E318DB262C5A4FBD00091322 /* fastmath.h */, + E318DB272C5A4FBD00091322 /* gaussian_distribution_gentables.cc */, + E318DB282C5A4FBD00091322 /* generate_real_test.cc */, + E318DB292C5A4FBD00091322 /* generate_real.h */, + E318DB2A2C5A4FBD00091322 /* iostream_state_saver_test.cc */, + E318DB2B2C5A4FBD00091322 /* iostream_state_saver.h */, + E318DB2C2C5A4FBD00091322 /* mock_helpers.h */, + E318DB2D2C5A4FBD00091322 /* mock_overload_set.h */, + E318DB2E2C5A4FBD00091322 /* nanobenchmark_test.cc */, + E318DB2F2C5A4FBD00091322 /* nanobenchmark.cc */, + E318DB302C5A4FBD00091322 /* nanobenchmark.h */, + E318DB312C5A4FBD00091322 /* nonsecure_base_test.cc */, + E318DB322C5A4FBD00091322 /* nonsecure_base.h */, + E318DB332C5A4FBD00091322 /* pcg_engine_test.cc */, + E318DB342C5A4FBD00091322 /* pcg_engine.h */, + E318DB352C5A4FBD00091322 /* platform.h */, + E318DB362C5A4FBD00091322 /* pool_urbg_test.cc */, + E318DB372C5A4FBD00091322 /* pool_urbg.cc */, + E318DB382C5A4FBD00091322 /* pool_urbg.h */, + E318DB392C5A4FBD00091322 /* randen_benchmarks.cc */, + E318DB3A2C5A4FBD00091322 /* randen_detect.cc */, + E318DB3B2C5A4FBD00091322 /* randen_detect.h */, + E318DB3C2C5A4FBD00091322 /* randen_engine_test.cc */, + E318DB3D2C5A4FBD00091322 /* randen_engine.h */, + E318DB3E2C5A4FBD00091322 /* randen_hwaes_test.cc */, + E318DB3F2C5A4FBD00091322 /* randen_hwaes.cc */, + E318DB402C5A4FBD00091322 /* randen_hwaes.h */, + E318DB412C5A4FBD00091322 /* randen_round_keys.cc */, + E318DB422C5A4FBD00091322 /* randen_slow_test.cc */, + E318DB432C5A4FBD00091322 /* randen_slow.cc */, + E318DB442C5A4FBD00091322 /* randen_slow.h */, + E318DB452C5A4FBD00091322 /* randen_test.cc */, + E318DB462C5A4FBD00091322 /* randen_traits.h */, + E318DB472C5A4FBD00091322 /* randen.cc */, + E318DB482C5A4FBD00091322 /* randen.h */, + E318DB492C5A4FBD00091322 /* salted_seed_seq_test.cc */, + E318DB4A2C5A4FBD00091322 /* salted_seed_seq.h */, + E318DB4B2C5A4FBD00091322 /* seed_material_test.cc */, + E318DB4C2C5A4FBD00091322 /* seed_material.cc */, + E318DB4D2C5A4FBD00091322 /* seed_material.h */, + E318DB4E2C5A4FBD00091322 /* sequence_urbg.h */, + E318DB4F2C5A4FBD00091322 /* traits_test.cc */, + E318DB502C5A4FBD00091322 /* traits.h */, + E318DB512C5A4FBD00091322 /* uniform_helper_test.cc */, + E318DB522C5A4FBD00091322 /* uniform_helper.h */, + E318DB532C5A4FBD00091322 /* wide_multiply_test.cc */, + E318DB542C5A4FBD00091322 /* wide_multiply.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DB7F2C5A4FBD00091322 /* random */ = { + isa = PBXGroup; + children = ( + E318DB182C5A4FBD00091322 /* CMakeFiles */, + E318DB552C5A4FBD00091322 /* internal */, + E318DB562C5A4FBD00091322 /* benchmarks.cc */, + E318DB572C5A4FBD00091322 /* bernoulli_distribution_test.cc */, + E318DB582C5A4FBD00091322 /* bernoulli_distribution.h */, + E318DB592C5A4FBD00091322 /* beta_distribution_test.cc */, + E318DB5A2C5A4FBD00091322 /* beta_distribution.h */, + E318DB5B2C5A4FBD00091322 /* bit_gen_ref_test.cc */, + E318DB5C2C5A4FBD00091322 /* bit_gen_ref.h */, + E318DB5D2C5A4FBD00091322 /* BUILD.bazel */, + E318DB5E2C5A4FBD00091322 /* CMakeLists.txt */, + E318DB5F2C5A4FBD00091322 /* discrete_distribution_test.cc */, + E318DB602C5A4FBD00091322 /* discrete_distribution.cc */, + E318DB612C5A4FBD00091322 /* discrete_distribution.h */, + E318DB622C5A4FBD00091322 /* distributions_test.cc */, + E318DB632C5A4FBD00091322 /* distributions.h */, + E318DB642C5A4FBD00091322 /* examples_test.cc */, + E318DB652C5A4FBD00091322 /* exponential_distribution_test.cc */, + E318DB662C5A4FBD00091322 /* exponential_distribution.h */, + E318DB672C5A4FBD00091322 /* gaussian_distribution_test.cc */, + E318DB682C5A4FBD00091322 /* gaussian_distribution.cc */, + E318DB692C5A4FBD00091322 /* gaussian_distribution.h */, + E318DB6A2C5A4FBD00091322 /* generators_test.cc */, + E318DB6B2C5A4FBD00091322 /* log_uniform_int_distribution_test.cc */, + E318DB6C2C5A4FBD00091322 /* log_uniform_int_distribution.h */, + E318DB6D2C5A4FBD00091322 /* mock_distributions_test.cc */, + E318DB6E2C5A4FBD00091322 /* mock_distributions.h */, + E318DB6F2C5A4FBD00091322 /* mocking_bit_gen_test.cc */, + E318DB702C5A4FBD00091322 /* mocking_bit_gen.h */, + E318DB712C5A4FBD00091322 /* poisson_distribution_test.cc */, + E318DB722C5A4FBD00091322 /* poisson_distribution.h */, + E318DB732C5A4FBD00091322 /* random.h */, + E318DB742C5A4FBD00091322 /* seed_gen_exception.cc */, + E318DB752C5A4FBD00091322 /* seed_gen_exception.h */, + E318DB762C5A4FBD00091322 /* seed_sequences_test.cc */, + E318DB772C5A4FBD00091322 /* seed_sequences.cc */, + E318DB782C5A4FBD00091322 /* seed_sequences.h */, + E318DB792C5A4FBD00091322 /* uniform_int_distribution_test.cc */, + E318DB7A2C5A4FBD00091322 /* uniform_int_distribution.h */, + E318DB7B2C5A4FBD00091322 /* uniform_real_distribution_test.cc */, + E318DB7C2C5A4FBD00091322 /* uniform_real_distribution.h */, + E318DB7D2C5A4FBD00091322 /* zipf_distribution_test.cc */, + E318DB7E2C5A4FBD00091322 /* zipf_distribution.h */, + ); + path = random; + sourceTree = ""; + }; + E318DB802C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DB832C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DB812C5A4FBD00091322 /* status_internal.h */, + E318DB822C5A4FBD00091322 /* statusor_internal.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DB8E2C5A4FBD00091322 /* status */ = { + isa = PBXGroup; + children = ( + E318DB802C5A4FBD00091322 /* CMakeFiles */, + E318DB832C5A4FBD00091322 /* internal */, + E318DB842C5A4FBD00091322 /* BUILD.bazel */, + E318DB852C5A4FBD00091322 /* CMakeLists.txt */, + E318DB862C5A4FBD00091322 /* status_payload_printer.cc */, + E318DB872C5A4FBD00091322 /* status_payload_printer.h */, + E318DB882C5A4FBD00091322 /* status_test.cc */, + E318DB892C5A4FBD00091322 /* status.cc */, + E318DB8A2C5A4FBD00091322 /* status.h */, + E318DB8B2C5A4FBD00091322 /* statusor_test.cc */, + E318DB8C2C5A4FBD00091322 /* statusor.cc */, + E318DB8D2C5A4FBD00091322 /* statusor.h */, + ); + path = status; + sourceTree = ""; + }; + E318DB8F2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DBA42C5A4FBD00091322 /* str_format */ = { + isa = PBXGroup; + children = ( + E318DB902C5A4FBD00091322 /* arg_test.cc */, + E318DB912C5A4FBD00091322 /* arg.cc */, + E318DB922C5A4FBD00091322 /* arg.h */, + E318DB932C5A4FBD00091322 /* bind_test.cc */, + E318DB942C5A4FBD00091322 /* bind.cc */, + E318DB952C5A4FBD00091322 /* bind.h */, + E318DB962C5A4FBD00091322 /* checker_test.cc */, + E318DB972C5A4FBD00091322 /* checker.h */, + E318DB982C5A4FBD00091322 /* convert_test.cc */, + E318DB992C5A4FBD00091322 /* extension_test.cc */, + E318DB9A2C5A4FBD00091322 /* extension.cc */, + E318DB9B2C5A4FBD00091322 /* extension.h */, + E318DB9C2C5A4FBD00091322 /* float_conversion.cc */, + E318DB9D2C5A4FBD00091322 /* float_conversion.h */, + E318DB9E2C5A4FBD00091322 /* output_test.cc */, + E318DB9F2C5A4FBD00091322 /* output.cc */, + E318DBA02C5A4FBD00091322 /* output.h */, + E318DBA12C5A4FBD00091322 /* parser_test.cc */, + E318DBA22C5A4FBD00091322 /* parser.cc */, + E318DBA32C5A4FBD00091322 /* parser.h */, + ); + path = str_format; + sourceTree = ""; + }; + E318DBF02C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DBA42C5A4FBD00091322 /* str_format */, + E318DBA52C5A4FBD00091322 /* char_map_benchmark.cc */, + E318DBA62C5A4FBD00091322 /* char_map_test.cc */, + E318DBA72C5A4FBD00091322 /* char_map.h */, + E318DBA82C5A4FBD00091322 /* charconv_bigint_test.cc */, + E318DBA92C5A4FBD00091322 /* charconv_bigint.cc */, + E318DBAA2C5A4FBD00091322 /* charconv_bigint.h */, + E318DBAB2C5A4FBD00091322 /* charconv_parse_test.cc */, + E318DBAC2C5A4FBD00091322 /* charconv_parse.cc */, + E318DBAD2C5A4FBD00091322 /* charconv_parse.h */, + E318DBAE2C5A4FBD00091322 /* cord_data_edge_test.cc */, + E318DBAF2C5A4FBD00091322 /* cord_data_edge.h */, + E318DBB02C5A4FBD00091322 /* cord_internal.cc */, + E318DBB12C5A4FBD00091322 /* cord_internal.h */, + E318DBB22C5A4FBD00091322 /* cord_rep_btree_navigator_test.cc */, + E318DBB32C5A4FBD00091322 /* cord_rep_btree_navigator.cc */, + E318DBB42C5A4FBD00091322 /* cord_rep_btree_navigator.h */, + E318DBB52C5A4FBD00091322 /* cord_rep_btree_reader_test.cc */, + E318DBB62C5A4FBD00091322 /* cord_rep_btree_reader.cc */, + E318DBB72C5A4FBD00091322 /* cord_rep_btree_reader.h */, + E318DBB82C5A4FBD00091322 /* cord_rep_btree_test.cc */, + E318DBB92C5A4FBD00091322 /* cord_rep_btree.cc */, + E318DBBA2C5A4FBD00091322 /* cord_rep_btree.h */, + E318DBBB2C5A4FBD00091322 /* cord_rep_consume.cc */, + E318DBBC2C5A4FBD00091322 /* cord_rep_consume.h */, + E318DBBD2C5A4FBD00091322 /* cord_rep_crc_test.cc */, + E318DBBE2C5A4FBD00091322 /* cord_rep_crc.cc */, + E318DBBF2C5A4FBD00091322 /* cord_rep_crc.h */, + E318DBC02C5A4FBD00091322 /* cord_rep_flat.h */, + E318DBC12C5A4FBD00091322 /* cord_rep_ring_reader.h */, + E318DBC22C5A4FBD00091322 /* cord_rep_ring.cc */, + E318DBC32C5A4FBD00091322 /* cord_rep_ring.h */, + E318DBC42C5A4FBD00091322 /* cord_rep_test_util.h */, + E318DBC52C5A4FBD00091322 /* cordz_functions_test.cc */, + E318DBC62C5A4FBD00091322 /* cordz_functions.cc */, + E318DBC72C5A4FBD00091322 /* cordz_functions.h */, + E318DBC82C5A4FBD00091322 /* cordz_handle_test.cc */, + E318DBC92C5A4FBD00091322 /* cordz_handle.cc */, + E318DBCA2C5A4FBD00091322 /* cordz_handle.h */, + E318DBCB2C5A4FBD00091322 /* cordz_info_statistics_test.cc */, + E318DBCC2C5A4FBD00091322 /* cordz_info_test.cc */, + E318DBCD2C5A4FBD00091322 /* cordz_info.cc */, + E318DBCE2C5A4FBD00091322 /* cordz_info.h */, + E318DBCF2C5A4FBD00091322 /* cordz_sample_token_test.cc */, + E318DBD02C5A4FBD00091322 /* cordz_sample_token.cc */, + E318DBD12C5A4FBD00091322 /* cordz_sample_token.h */, + E318DBD22C5A4FBD00091322 /* cordz_statistics.h */, + E318DBD32C5A4FBD00091322 /* cordz_update_scope_test.cc */, + E318DBD42C5A4FBD00091322 /* cordz_update_scope.h */, + E318DBD52C5A4FBD00091322 /* cordz_update_tracker_test.cc */, + E318DBD62C5A4FBD00091322 /* cordz_update_tracker.h */, + E318DBD72C5A4FBD00091322 /* escaping_test_common.h */, + E318DBD82C5A4FBD00091322 /* escaping.cc */, + E318DBD92C5A4FBD00091322 /* escaping.h */, + E318DBDA2C5A4FBD00091322 /* memutil_benchmark.cc */, + E318DBDB2C5A4FBD00091322 /* memutil_test.cc */, + E318DBDC2C5A4FBD00091322 /* memutil.cc */, + E318DBDD2C5A4FBD00091322 /* memutil.h */, + E318DBDE2C5A4FBD00091322 /* numbers_test_common.h */, + E318DBDF2C5A4FBD00091322 /* ostringstream_benchmark.cc */, + E318DBE02C5A4FBD00091322 /* ostringstream_test.cc */, + E318DBE12C5A4FBD00091322 /* ostringstream.cc */, + E318DBE22C5A4FBD00091322 /* ostringstream.h */, + E318DBE32C5A4FBD00091322 /* pow10_helper_test.cc */, + E318DBE42C5A4FBD00091322 /* pow10_helper.cc */, + E318DBE52C5A4FBD00091322 /* pow10_helper.h */, + E318DBE62C5A4FBD00091322 /* resize_uninitialized_test.cc */, + E318DBE72C5A4FBD00091322 /* resize_uninitialized.h */, + E318DBE82C5A4FBD00091322 /* stl_type_traits.h */, + E318DBE92C5A4FBD00091322 /* str_join_internal.h */, + E318DBEA2C5A4FBD00091322 /* str_split_internal.h */, + E318DBEB2C5A4FBD00091322 /* string_constant_test.cc */, + E318DBEC2C5A4FBD00091322 /* string_constant.h */, + E318DBED2C5A4FBD00091322 /* utf8_test.cc */, + E318DBEE2C5A4FBD00091322 /* utf8.cc */, + E318DBEF2C5A4FBD00091322 /* utf8.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DC2D2C5A4FBD00091322 /* strings */ = { + isa = PBXGroup; + children = ( + E318DB8F2C5A4FBD00091322 /* CMakeFiles */, + E318DBF02C5A4FBD00091322 /* internal */, + E318DBF12C5A4FBD00091322 /* ascii_benchmark.cc */, + E318DBF22C5A4FBD00091322 /* ascii_test.cc */, + E318DBF32C5A4FBD00091322 /* ascii.cc */, + E318DBF42C5A4FBD00091322 /* ascii.h */, + E318DBF52C5A4FBD00091322 /* BUILD.bazel */, + E318DBF62C5A4FBD00091322 /* charconv_benchmark.cc */, + E318DBF72C5A4FBD00091322 /* charconv_test.cc */, + E318DBF82C5A4FBD00091322 /* charconv.cc */, + E318DBF92C5A4FBD00091322 /* charconv.h */, + E318DBFA2C5A4FBD00091322 /* CMakeLists.txt */, + E318DBFB2C5A4FBD00091322 /* cord_analysis.cc */, + E318DBFC2C5A4FBD00091322 /* cord_analysis.h */, + E318DBFD2C5A4FBD00091322 /* cord_buffer_test.cc */, + E318DBFE2C5A4FBD00091322 /* cord_buffer.cc */, + E318DBFF2C5A4FBD00091322 /* cord_buffer.h */, + E318DC002C5A4FBD00091322 /* cord_ring_reader_test.cc */, + E318DC012C5A4FBD00091322 /* cord_ring_test.cc */, + E318DC022C5A4FBD00091322 /* cord_test_helpers.h */, + E318DC032C5A4FBD00091322 /* cord_test.cc */, + E318DC042C5A4FBD00091322 /* cord.cc */, + E318DC052C5A4FBD00091322 /* cord.h */, + E318DC062C5A4FBD00091322 /* cordz_test_helpers.h */, + E318DC072C5A4FBD00091322 /* cordz_test.cc */, + E318DC082C5A4FBD00091322 /* escaping_benchmark.cc */, + E318DC092C5A4FBD00091322 /* escaping_test.cc */, + E318DC0A2C5A4FBD00091322 /* escaping.cc */, + E318DC0B2C5A4FBD00091322 /* escaping.h */, + E318DC0C2C5A4FBD00091322 /* match_test.cc */, + E318DC0D2C5A4FBD00091322 /* match.cc */, + E318DC0E2C5A4FBD00091322 /* match.h */, + E318DC0F2C5A4FBD00091322 /* numbers_benchmark.cc */, + E318DC102C5A4FBD00091322 /* numbers_test.cc */, + E318DC112C5A4FBD00091322 /* numbers.cc */, + E318DC122C5A4FBD00091322 /* numbers.h */, + E318DC132C5A4FBD00091322 /* str_cat_benchmark.cc */, + E318DC142C5A4FBD00091322 /* str_cat_test.cc */, + E318DC152C5A4FBD00091322 /* str_cat.cc */, + E318DC162C5A4FBD00091322 /* str_cat.h */, + E318DC172C5A4FBD00091322 /* str_format_test.cc */, + E318DC182C5A4FBD00091322 /* str_format.h */, + E318DC192C5A4FBD00091322 /* str_join_benchmark.cc */, + E318DC1A2C5A4FBD00091322 /* str_join_test.cc */, + E318DC1B2C5A4FBD00091322 /* str_join.h */, + E318DC1C2C5A4FBD00091322 /* str_replace_benchmark.cc */, + E318DC1D2C5A4FBD00091322 /* str_replace_test.cc */, + E318DC1E2C5A4FBD00091322 /* str_replace.cc */, + E318DC1F2C5A4FBD00091322 /* str_replace.h */, + E318DC202C5A4FBD00091322 /* str_split_benchmark.cc */, + E318DC212C5A4FBD00091322 /* str_split_test.cc */, + E318DC222C5A4FBD00091322 /* str_split.cc */, + E318DC232C5A4FBD00091322 /* str_split.h */, + E318DC242C5A4FBD00091322 /* string_view_benchmark.cc */, + E318DC252C5A4FBD00091322 /* string_view_test.cc */, + E318DC262C5A4FBD00091322 /* string_view.cc */, + E318DC272C5A4FBD00091322 /* string_view.h */, + E318DC282C5A4FBD00091322 /* strip_test.cc */, + E318DC292C5A4FBD00091322 /* strip.h */, + E318DC2A2C5A4FBD00091322 /* substitute_test.cc */, + E318DC2B2C5A4FBD00091322 /* substitute.cc */, + E318DC2C2C5A4FBD00091322 /* substitute.h */, + ); + path = strings; + sourceTree = ""; + }; + E318DC2E2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DC3D2C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DC2F2C5A4FBD00091322 /* create_thread_identity.cc */, + E318DC302C5A4FBD00091322 /* create_thread_identity.h */, + E318DC312C5A4FBD00091322 /* futex.h */, + E318DC322C5A4FBD00091322 /* graphcycles_benchmark.cc */, + E318DC332C5A4FBD00091322 /* graphcycles_test.cc */, + E318DC342C5A4FBD00091322 /* graphcycles.cc */, + E318DC352C5A4FBD00091322 /* graphcycles.h */, + E318DC362C5A4FBD00091322 /* kernel_timeout.h */, + E318DC372C5A4FBD00091322 /* per_thread_sem_test.cc */, + E318DC382C5A4FBD00091322 /* per_thread_sem.cc */, + E318DC392C5A4FBD00091322 /* per_thread_sem.h */, + E318DC3A2C5A4FBD00091322 /* thread_pool.h */, + E318DC3B2C5A4FBD00091322 /* waiter.cc */, + E318DC3C2C5A4FBD00091322 /* waiter.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DC4F2C5A4FBD00091322 /* synchronization */ = { + isa = PBXGroup; + children = ( + E318DC2E2C5A4FBD00091322 /* CMakeFiles */, + E318DC3D2C5A4FBD00091322 /* internal */, + E318DC3E2C5A4FBD00091322 /* barrier_test.cc */, + E318DC3F2C5A4FBD00091322 /* barrier.cc */, + E318DC402C5A4FBD00091322 /* barrier.h */, + E318DC412C5A4FBD00091322 /* blocking_counter_benchmark.cc */, + E318DC422C5A4FBD00091322 /* blocking_counter_test.cc */, + E318DC432C5A4FBD00091322 /* blocking_counter.cc */, + E318DC442C5A4FBD00091322 /* blocking_counter.h */, + E318DC452C5A4FBD00091322 /* BUILD.bazel */, + E318DC462C5A4FBD00091322 /* CMakeLists.txt */, + E318DC472C5A4FBD00091322 /* lifetime_test.cc */, + E318DC482C5A4FBD00091322 /* mutex_benchmark.cc */, + E318DC492C5A4FBD00091322 /* mutex_test.cc */, + E318DC4A2C5A4FBD00091322 /* mutex.cc */, + E318DC4B2C5A4FBD00091322 /* mutex.h */, + E318DC4C2C5A4FBD00091322 /* notification_test.cc */, + E318DC4D2C5A4FBD00091322 /* notification.cc */, + E318DC4E2C5A4FBD00091322 /* notification.h */, + ); + path = synchronization; + sourceTree = ""; + }; + E318DC502C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DC552C5A4FBD00091322 /* cctz */ = { + isa = PBXGroup; + children = ( + E318DC512C5A4FBD00091322 /* civil_time_detail.h */, + E318DC522C5A4FBD00091322 /* civil_time.h */, + E318DC532C5A4FBD00091322 /* time_zone.h */, + E318DC542C5A4FBD00091322 /* zone_info_source.h */, + ); + path = cctz; + sourceTree = ""; + }; + E318DC562C5A4FBD00091322 /* include */ = { + isa = PBXGroup; + children = ( + E318DC552C5A4FBD00091322 /* cctz */, + ); + path = include; + sourceTree = ""; + }; + E318DC6C2C5A4FBD00091322 /* src */ = { + isa = PBXGroup; + children = ( + E318DC572C5A4FBD00091322 /* cctz_benchmark.cc */, + E318DC582C5A4FBD00091322 /* civil_time_detail.cc */, + E318DC592C5A4FBD00091322 /* civil_time_test.cc */, + E318DC5A2C5A4FBD00091322 /* time_zone_fixed.cc */, + E318DC5B2C5A4FBD00091322 /* time_zone_fixed.h */, + E318DC5C2C5A4FBD00091322 /* time_zone_format_test.cc */, + E318DC5D2C5A4FBD00091322 /* time_zone_format.cc */, + E318DC5E2C5A4FBD00091322 /* time_zone_if.cc */, + E318DC5F2C5A4FBD00091322 /* time_zone_if.h */, + E318DC602C5A4FBD00091322 /* time_zone_impl.cc */, + E318DC612C5A4FBD00091322 /* time_zone_impl.h */, + E318DC622C5A4FBD00091322 /* time_zone_info.cc */, + E318DC632C5A4FBD00091322 /* time_zone_info.h */, + E318DC642C5A4FBD00091322 /* time_zone_libc.cc */, + E318DC652C5A4FBD00091322 /* time_zone_libc.h */, + E318DC662C5A4FBD00091322 /* time_zone_lookup_test.cc */, + E318DC672C5A4FBD00091322 /* time_zone_lookup.cc */, + E318DC682C5A4FBD00091322 /* time_zone_posix.cc */, + E318DC692C5A4FBD00091322 /* time_zone_posix.h */, + E318DC6A2C5A4FBD00091322 /* tzfile.h */, + E318DC6B2C5A4FBD00091322 /* zone_info_source.cc */, + ); + path = src; + sourceTree = ""; + }; + E318DCA32C5A4FBD00091322 /* Africa */ = { + isa = PBXGroup; + children = ( + E318DC6D2C5A4FBD00091322 /* Abidjan */, + E318DC6E2C5A4FBD00091322 /* Accra */, + E318DC6F2C5A4FBD00091322 /* Addis_Ababa */, + E318DC702C5A4FBD00091322 /* Algiers */, + E318DC712C5A4FBD00091322 /* Asmara */, + E318DC722C5A4FBD00091322 /* Asmera */, + E318DC732C5A4FBD00091322 /* Bamako */, + E318DC742C5A4FBD00091322 /* Bangui */, + E318DC752C5A4FBD00091322 /* Banjul */, + E318DC762C5A4FBD00091322 /* Bissau */, + E318DC772C5A4FBD00091322 /* Blantyre */, + E318DC782C5A4FBD00091322 /* Brazzaville */, + E318DC792C5A4FBD00091322 /* Bujumbura */, + E318DC7A2C5A4FBD00091322 /* Cairo */, + E318DC7B2C5A4FBD00091322 /* Casablanca */, + E318DC7C2C5A4FBD00091322 /* Ceuta */, + E318DC7D2C5A4FBD00091322 /* Conakry */, + E318DC7E2C5A4FBD00091322 /* Dakar */, + E318DC7F2C5A4FBD00091322 /* Dar_es_Salaam */, + E318DC802C5A4FBD00091322 /* Djibouti */, + E318DC812C5A4FBD00091322 /* Douala */, + E318DC822C5A4FBD00091322 /* El_Aaiun */, + E318DC832C5A4FBD00091322 /* Freetown */, + E318DC842C5A4FBD00091322 /* Gaborone */, + E318DC852C5A4FBD00091322 /* Harare */, + E318DC862C5A4FBD00091322 /* Johannesburg */, + E318DC872C5A4FBD00091322 /* Juba */, + E318DC882C5A4FBD00091322 /* Kampala */, + E318DC892C5A4FBD00091322 /* Khartoum */, + E318DC8A2C5A4FBD00091322 /* Kigali */, + E318DC8B2C5A4FBD00091322 /* Kinshasa */, + E318DC8C2C5A4FBD00091322 /* Lagos */, + E318DC8D2C5A4FBD00091322 /* Libreville */, + E318DC8E2C5A4FBD00091322 /* Lome */, + E318DC8F2C5A4FBD00091322 /* Luanda */, + E318DC902C5A4FBD00091322 /* Lubumbashi */, + E318DC912C5A4FBD00091322 /* Lusaka */, + E318DC922C5A4FBD00091322 /* Malabo */, + E318DC932C5A4FBD00091322 /* Maputo */, + E318DC942C5A4FBD00091322 /* Maseru */, + E318DC952C5A4FBD00091322 /* Mbabane */, + E318DC962C5A4FBD00091322 /* Mogadishu */, + E318DC972C5A4FBD00091322 /* Monrovia */, + E318DC982C5A4FBD00091322 /* Nairobi */, + E318DC992C5A4FBD00091322 /* Ndjamena */, + E318DC9A2C5A4FBD00091322 /* Niamey */, + E318DC9B2C5A4FBD00091322 /* Nouakchott */, + E318DC9C2C5A4FBD00091322 /* Ouagadougou */, + E318DC9D2C5A4FBD00091322 /* Porto-Novo */, + E318DC9E2C5A4FBD00091322 /* Sao_Tome */, + E318DC9F2C5A4FBD00091322 /* Timbuktu */, + E318DCA02C5A4FBD00091322 /* Tripoli */, + E318DCA12C5A4FBD00091322 /* Tunis */, + E318DCA22C5A4FBD00091322 /* Windhoek */, + ); + path = Africa; + sourceTree = ""; + }; + E318DCB12C5A4FBD00091322 /* Argentina */ = { + isa = PBXGroup; + children = ( + E318DCA42C5A4FBD00091322 /* Buenos_Aires */, + E318DCA52C5A4FBD00091322 /* Catamarca */, + E318DCA62C5A4FBD00091322 /* ComodRivadavia */, + E318DCA72C5A4FBD00091322 /* Cordoba */, + E318DCA82C5A4FBD00091322 /* Jujuy */, + E318DCA92C5A4FBD00091322 /* La_Rioja */, + E318DCAA2C5A4FBD00091322 /* Mendoza */, + E318DCAB2C5A4FBD00091322 /* Rio_Gallegos */, + E318DCAC2C5A4FBD00091322 /* Salta */, + E318DCAD2C5A4FBD00091322 /* San_Juan */, + E318DCAE2C5A4FBD00091322 /* San_Luis */, + E318DCAF2C5A4FBD00091322 /* Tucuman */, + E318DCB02C5A4FBD00091322 /* Ushuaia */, + ); + path = Argentina; + sourceTree = ""; + }; + E318DCBA2C5A4FBD00091322 /* Indiana */ = { + isa = PBXGroup; + children = ( + E318DCB22C5A4FBD00091322 /* Indianapolis */, + E318DCB32C5A4FBD00091322 /* Knox */, + E318DCB42C5A4FBD00091322 /* Marengo */, + E318DCB52C5A4FBD00091322 /* Petersburg */, + E318DCB62C5A4FBD00091322 /* Tell_City */, + E318DCB72C5A4FBD00091322 /* Vevay */, + E318DCB82C5A4FBD00091322 /* Vincennes */, + E318DCB92C5A4FBD00091322 /* Winamac */, + ); + path = Indiana; + sourceTree = ""; + }; + E318DCBD2C5A4FBD00091322 /* Kentucky */ = { + isa = PBXGroup; + children = ( + E318DCBB2C5A4FBD00091322 /* Louisville */, + E318DCBC2C5A4FBD00091322 /* Monticello */, + ); + path = Kentucky; + sourceTree = ""; + }; + E318DCC12C5A4FBD00091322 /* North_Dakota */ = { + isa = PBXGroup; + children = ( + E318DCBE2C5A4FBD00091322 /* Beulah */, + E318DCBF2C5A4FBD00091322 /* Center */, + E318DCC02C5A4FBD00091322 /* New_Salem */, + ); + path = North_Dakota; + sourceTree = ""; + }; + E318DD4F2C5A4FBD00091322 /* America */ = { + isa = PBXGroup; + children = ( + E318DCB12C5A4FBD00091322 /* Argentina */, + E318DCBA2C5A4FBD00091322 /* Indiana */, + E318DCBD2C5A4FBD00091322 /* Kentucky */, + E318DCC12C5A4FBD00091322 /* North_Dakota */, + E318DCC22C5A4FBD00091322 /* Adak */, + E318DCC32C5A4FBD00091322 /* Anchorage */, + E318DCC42C5A4FBD00091322 /* Anguilla */, + E318DCC52C5A4FBD00091322 /* Antigua */, + E318DCC62C5A4FBD00091322 /* Araguaina */, + E318DCC72C5A4FBD00091322 /* Aruba */, + E318DCC82C5A4FBD00091322 /* Asuncion */, + E318DCC92C5A4FBD00091322 /* Atikokan */, + E318DCCA2C5A4FBD00091322 /* Atka */, + E318DCCB2C5A4FBD00091322 /* Bahia */, + E318DCCC2C5A4FBD00091322 /* Bahia_Banderas */, + E318DCCD2C5A4FBD00091322 /* Barbados */, + E318DCCE2C5A4FBD00091322 /* Belem */, + E318DCCF2C5A4FBD00091322 /* Belize */, + E318DCD02C5A4FBD00091322 /* Blanc-Sablon */, + E318DCD12C5A4FBD00091322 /* Boa_Vista */, + E318DCD22C5A4FBD00091322 /* Bogota */, + E318DCD32C5A4FBD00091322 /* Boise */, + E318DCD42C5A4FBD00091322 /* Buenos_Aires */, + E318DCD52C5A4FBD00091322 /* Cambridge_Bay */, + E318DCD62C5A4FBD00091322 /* Campo_Grande */, + E318DCD72C5A4FBD00091322 /* Cancun */, + E318DCD82C5A4FBD00091322 /* Caracas */, + E318DCD92C5A4FBD00091322 /* Catamarca */, + E318DCDA2C5A4FBD00091322 /* Cayenne */, + E318DCDB2C5A4FBD00091322 /* Cayman */, + E318DCDC2C5A4FBD00091322 /* Chicago */, + E318DCDD2C5A4FBD00091322 /* Chihuahua */, + E318DCDE2C5A4FBD00091322 /* Coral_Harbour */, + E318DCDF2C5A4FBD00091322 /* Cordoba */, + E318DCE02C5A4FBD00091322 /* Costa_Rica */, + E318DCE12C5A4FBD00091322 /* Creston */, + E318DCE22C5A4FBD00091322 /* Cuiaba */, + E318DCE32C5A4FBD00091322 /* Curacao */, + E318DCE42C5A4FBD00091322 /* Danmarkshavn */, + E318DCE52C5A4FBD00091322 /* Dawson */, + E318DCE62C5A4FBD00091322 /* Dawson_Creek */, + E318DCE72C5A4FBD00091322 /* Denver */, + E318DCE82C5A4FBD00091322 /* Detroit */, + E318DCE92C5A4FBD00091322 /* Dominica */, + E318DCEA2C5A4FBD00091322 /* Edmonton */, + E318DCEB2C5A4FBD00091322 /* Eirunepe */, + E318DCEC2C5A4FBD00091322 /* El_Salvador */, + E318DCED2C5A4FBD00091322 /* Ensenada */, + E318DCEE2C5A4FBD00091322 /* Fort_Nelson */, + E318DCEF2C5A4FBD00091322 /* Fort_Wayne */, + E318DCF02C5A4FBD00091322 /* Fortaleza */, + E318DCF12C5A4FBD00091322 /* Glace_Bay */, + E318DCF22C5A4FBD00091322 /* Godthab */, + E318DCF32C5A4FBD00091322 /* Goose_Bay */, + E318DCF42C5A4FBD00091322 /* Grand_Turk */, + E318DCF52C5A4FBD00091322 /* Grenada */, + E318DCF62C5A4FBD00091322 /* Guadeloupe */, + E318DCF72C5A4FBD00091322 /* Guatemala */, + E318DCF82C5A4FBD00091322 /* Guayaquil */, + E318DCF92C5A4FBD00091322 /* Guyana */, + E318DCFA2C5A4FBD00091322 /* Halifax */, + E318DCFB2C5A4FBD00091322 /* Havana */, + E318DCFC2C5A4FBD00091322 /* Hermosillo */, + E318DCFD2C5A4FBD00091322 /* Indianapolis */, + E318DCFE2C5A4FBD00091322 /* Inuvik */, + E318DCFF2C5A4FBD00091322 /* Iqaluit */, + E318DD002C5A4FBD00091322 /* Jamaica */, + E318DD012C5A4FBD00091322 /* Jujuy */, + E318DD022C5A4FBD00091322 /* Juneau */, + E318DD032C5A4FBD00091322 /* Knox_IN */, + E318DD042C5A4FBD00091322 /* Kralendijk */, + E318DD052C5A4FBD00091322 /* La_Paz */, + E318DD062C5A4FBD00091322 /* Lima */, + E318DD072C5A4FBD00091322 /* Los_Angeles */, + E318DD082C5A4FBD00091322 /* Louisville */, + E318DD092C5A4FBD00091322 /* Lower_Princes */, + E318DD0A2C5A4FBD00091322 /* Maceio */, + E318DD0B2C5A4FBD00091322 /* Managua */, + E318DD0C2C5A4FBD00091322 /* Manaus */, + E318DD0D2C5A4FBD00091322 /* Marigot */, + E318DD0E2C5A4FBD00091322 /* Martinique */, + E318DD0F2C5A4FBD00091322 /* Matamoros */, + E318DD102C5A4FBD00091322 /* Mazatlan */, + E318DD112C5A4FBD00091322 /* Mendoza */, + E318DD122C5A4FBD00091322 /* Menominee */, + E318DD132C5A4FBD00091322 /* Merida */, + E318DD142C5A4FBD00091322 /* Metlakatla */, + E318DD152C5A4FBD00091322 /* Mexico_City */, + E318DD162C5A4FBD00091322 /* Miquelon */, + E318DD172C5A4FBD00091322 /* Moncton */, + E318DD182C5A4FBD00091322 /* Monterrey */, + E318DD192C5A4FBD00091322 /* Montevideo */, + E318DD1A2C5A4FBD00091322 /* Montreal */, + E318DD1B2C5A4FBD00091322 /* Montserrat */, + E318DD1C2C5A4FBD00091322 /* Nassau */, + E318DD1D2C5A4FBD00091322 /* New_York */, + E318DD1E2C5A4FBD00091322 /* Nipigon */, + E318DD1F2C5A4FBD00091322 /* Nome */, + E318DD202C5A4FBD00091322 /* Noronha */, + E318DD212C5A4FBD00091322 /* Nuuk */, + E318DD222C5A4FBD00091322 /* Ojinaga */, + E318DD232C5A4FBD00091322 /* Panama */, + E318DD242C5A4FBD00091322 /* Pangnirtung */, + E318DD252C5A4FBD00091322 /* Paramaribo */, + E318DD262C5A4FBD00091322 /* Phoenix */, + E318DD272C5A4FBD00091322 /* Port_of_Spain */, + E318DD282C5A4FBD00091322 /* Port-au-Prince */, + E318DD292C5A4FBD00091322 /* Porto_Acre */, + E318DD2A2C5A4FBD00091322 /* Porto_Velho */, + E318DD2B2C5A4FBD00091322 /* Puerto_Rico */, + E318DD2C2C5A4FBD00091322 /* Punta_Arenas */, + E318DD2D2C5A4FBD00091322 /* Rainy_River */, + E318DD2E2C5A4FBD00091322 /* Rankin_Inlet */, + E318DD2F2C5A4FBD00091322 /* Recife */, + E318DD302C5A4FBD00091322 /* Regina */, + E318DD312C5A4FBD00091322 /* Resolute */, + E318DD322C5A4FBD00091322 /* Rio_Branco */, + E318DD332C5A4FBD00091322 /* Rosario */, + E318DD342C5A4FBD00091322 /* Santa_Isabel */, + E318DD352C5A4FBD00091322 /* Santarem */, + E318DD362C5A4FBD00091322 /* Santiago */, + E318DD372C5A4FBD00091322 /* Santo_Domingo */, + E318DD382C5A4FBD00091322 /* Sao_Paulo */, + E318DD392C5A4FBD00091322 /* Scoresbysund */, + E318DD3A2C5A4FBD00091322 /* Shiprock */, + E318DD3B2C5A4FBD00091322 /* Sitka */, + E318DD3C2C5A4FBD00091322 /* St_Barthelemy */, + E318DD3D2C5A4FBD00091322 /* St_Johns */, + E318DD3E2C5A4FBD00091322 /* St_Kitts */, + E318DD3F2C5A4FBD00091322 /* St_Lucia */, + E318DD402C5A4FBD00091322 /* St_Thomas */, + E318DD412C5A4FBD00091322 /* St_Vincent */, + E318DD422C5A4FBD00091322 /* Swift_Current */, + E318DD432C5A4FBD00091322 /* Tegucigalpa */, + E318DD442C5A4FBD00091322 /* Thule */, + E318DD452C5A4FBD00091322 /* Thunder_Bay */, + E318DD462C5A4FBD00091322 /* Tijuana */, + E318DD472C5A4FBD00091322 /* Toronto */, + E318DD482C5A4FBD00091322 /* Tortola */, + E318DD492C5A4FBD00091322 /* Vancouver */, + E318DD4A2C5A4FBD00091322 /* Virgin */, + E318DD4B2C5A4FBD00091322 /* Whitehorse */, + E318DD4C2C5A4FBD00091322 /* Winnipeg */, + E318DD4D2C5A4FBD00091322 /* Yakutat */, + E318DD4E2C5A4FBD00091322 /* Yellowknife */, + ); + path = America; + sourceTree = ""; + }; + E318DD5C2C5A4FBD00091322 /* Antarctica */ = { + isa = PBXGroup; + children = ( + E318DD502C5A4FBD00091322 /* Casey */, + E318DD512C5A4FBD00091322 /* Davis */, + E318DD522C5A4FBD00091322 /* DumontDUrville */, + E318DD532C5A4FBD00091322 /* Macquarie */, + E318DD542C5A4FBD00091322 /* Mawson */, + E318DD552C5A4FBD00091322 /* McMurdo */, + E318DD562C5A4FBD00091322 /* Palmer */, + E318DD572C5A4FBD00091322 /* Rothera */, + E318DD582C5A4FBD00091322 /* South_Pole */, + E318DD592C5A4FBD00091322 /* Syowa */, + E318DD5A2C5A4FBD00091322 /* Troll */, + E318DD5B2C5A4FBD00091322 /* Vostok */, + ); + path = Antarctica; + sourceTree = ""; + }; + E318DD5E2C5A4FBD00091322 /* Arctic */ = { + isa = PBXGroup; + children = ( + E318DD5D2C5A4FBD00091322 /* Longyearbyen */, + ); + path = Arctic; + sourceTree = ""; + }; + E318DDC22C5A4FBD00091322 /* Asia */ = { + isa = PBXGroup; + children = ( + E318DD5F2C5A4FBD00091322 /* Aden */, + E318DD602C5A4FBD00091322 /* Almaty */, + E318DD612C5A4FBD00091322 /* Amman */, + E318DD622C5A4FBD00091322 /* Anadyr */, + E318DD632C5A4FBD00091322 /* Aqtau */, + E318DD642C5A4FBD00091322 /* Aqtobe */, + E318DD652C5A4FBD00091322 /* Ashgabat */, + E318DD662C5A4FBD00091322 /* Ashkhabad */, + E318DD672C5A4FBD00091322 /* Atyrau */, + E318DD682C5A4FBD00091322 /* Baghdad */, + E318DD692C5A4FBD00091322 /* Bahrain */, + E318DD6A2C5A4FBD00091322 /* Baku */, + E318DD6B2C5A4FBD00091322 /* Bangkok */, + E318DD6C2C5A4FBD00091322 /* Barnaul */, + E318DD6D2C5A4FBD00091322 /* Beirut */, + E318DD6E2C5A4FBD00091322 /* Bishkek */, + E318DD6F2C5A4FBD00091322 /* Brunei */, + E318DD702C5A4FBD00091322 /* Calcutta */, + E318DD712C5A4FBD00091322 /* Chita */, + E318DD722C5A4FBD00091322 /* Choibalsan */, + E318DD732C5A4FBD00091322 /* Chongqing */, + E318DD742C5A4FBD00091322 /* Chungking */, + E318DD752C5A4FBD00091322 /* Colombo */, + E318DD762C5A4FBD00091322 /* Dacca */, + E318DD772C5A4FBD00091322 /* Damascus */, + E318DD782C5A4FBD00091322 /* Dhaka */, + E318DD792C5A4FBD00091322 /* Dili */, + E318DD7A2C5A4FBD00091322 /* Dubai */, + E318DD7B2C5A4FBD00091322 /* Dushanbe */, + E318DD7C2C5A4FBD00091322 /* Famagusta */, + E318DD7D2C5A4FBD00091322 /* Gaza */, + E318DD7E2C5A4FBD00091322 /* Harbin */, + E318DD7F2C5A4FBD00091322 /* Hebron */, + E318DD802C5A4FBD00091322 /* Ho_Chi_Minh */, + E318DD812C5A4FBD00091322 /* Hong_Kong */, + E318DD822C5A4FBD00091322 /* Hovd */, + E318DD832C5A4FBD00091322 /* Irkutsk */, + E318DD842C5A4FBD00091322 /* Istanbul */, + E318DD852C5A4FBD00091322 /* Jakarta */, + E318DD862C5A4FBD00091322 /* Jayapura */, + E318DD872C5A4FBD00091322 /* Jerusalem */, + E318DD882C5A4FBD00091322 /* Kabul */, + E318DD892C5A4FBD00091322 /* Kamchatka */, + E318DD8A2C5A4FBD00091322 /* Karachi */, + E318DD8B2C5A4FBD00091322 /* Kashgar */, + E318DD8C2C5A4FBD00091322 /* Kathmandu */, + E318DD8D2C5A4FBD00091322 /* Katmandu */, + E318DD8E2C5A4FBD00091322 /* Khandyga */, + E318DD8F2C5A4FBD00091322 /* Kolkata */, + E318DD902C5A4FBD00091322 /* Krasnoyarsk */, + E318DD912C5A4FBD00091322 /* Kuala_Lumpur */, + E318DD922C5A4FBD00091322 /* Kuching */, + E318DD932C5A4FBD00091322 /* Kuwait */, + E318DD942C5A4FBD00091322 /* Macao */, + E318DD952C5A4FBD00091322 /* Macau */, + E318DD962C5A4FBD00091322 /* Magadan */, + E318DD972C5A4FBD00091322 /* Makassar */, + E318DD982C5A4FBD00091322 /* Manila */, + E318DD992C5A4FBD00091322 /* Muscat */, + E318DD9A2C5A4FBD00091322 /* Nicosia */, + E318DD9B2C5A4FBD00091322 /* Novokuznetsk */, + E318DD9C2C5A4FBD00091322 /* Novosibirsk */, + E318DD9D2C5A4FBD00091322 /* Omsk */, + E318DD9E2C5A4FBD00091322 /* Oral */, + E318DD9F2C5A4FBD00091322 /* Phnom_Penh */, + E318DDA02C5A4FBD00091322 /* Pontianak */, + E318DDA12C5A4FBD00091322 /* Pyongyang */, + E318DDA22C5A4FBD00091322 /* Qatar */, + E318DDA32C5A4FBD00091322 /* Qostanay */, + E318DDA42C5A4FBD00091322 /* Qyzylorda */, + E318DDA52C5A4FBD00091322 /* Rangoon */, + E318DDA62C5A4FBD00091322 /* Riyadh */, + E318DDA72C5A4FBD00091322 /* Saigon */, + E318DDA82C5A4FBD00091322 /* Sakhalin */, + E318DDA92C5A4FBD00091322 /* Samarkand */, + E318DDAA2C5A4FBD00091322 /* Seoul */, + E318DDAB2C5A4FBD00091322 /* Shanghai */, + E318DDAC2C5A4FBD00091322 /* Singapore */, + E318DDAD2C5A4FBD00091322 /* Srednekolymsk */, + E318DDAE2C5A4FBD00091322 /* Taipei */, + E318DDAF2C5A4FBD00091322 /* Tashkent */, + E318DDB02C5A4FBD00091322 /* Tbilisi */, + E318DDB12C5A4FBD00091322 /* Tehran */, + E318DDB22C5A4FBD00091322 /* Tel_Aviv */, + E318DDB32C5A4FBD00091322 /* Thimbu */, + E318DDB42C5A4FBD00091322 /* Thimphu */, + E318DDB52C5A4FBD00091322 /* Tokyo */, + E318DDB62C5A4FBD00091322 /* Tomsk */, + E318DDB72C5A4FBD00091322 /* Ujung_Pandang */, + E318DDB82C5A4FBD00091322 /* Ulaanbaatar */, + E318DDB92C5A4FBD00091322 /* Ulan_Bator */, + E318DDBA2C5A4FBD00091322 /* Urumqi */, + E318DDBB2C5A4FBD00091322 /* Ust-Nera */, + E318DDBC2C5A4FBD00091322 /* Vientiane */, + E318DDBD2C5A4FBD00091322 /* Vladivostok */, + E318DDBE2C5A4FBD00091322 /* Yakutsk */, + E318DDBF2C5A4FBD00091322 /* Yangon */, + E318DDC02C5A4FBD00091322 /* Yekaterinburg */, + E318DDC12C5A4FBD00091322 /* Yerevan */, + ); + path = Asia; + sourceTree = ""; + }; + E318DDCF2C5A4FBD00091322 /* Atlantic */ = { + isa = PBXGroup; + children = ( + E318DDC32C5A4FBD00091322 /* Azores */, + E318DDC42C5A4FBD00091322 /* Bermuda */, + E318DDC52C5A4FBD00091322 /* Canary */, + E318DDC62C5A4FBD00091322 /* Cape_Verde */, + E318DDC72C5A4FBD00091322 /* Faeroe */, + E318DDC82C5A4FBD00091322 /* Faroe */, + E318DDC92C5A4FBD00091322 /* Jan_Mayen */, + E318DDCA2C5A4FBD00091322 /* Madeira */, + E318DDCB2C5A4FBD00091322 /* Reykjavik */, + E318DDCC2C5A4FBD00091322 /* South_Georgia */, + E318DDCD2C5A4FBD00091322 /* St_Helena */, + E318DDCE2C5A4FBD00091322 /* Stanley */, + ); + path = Atlantic; + sourceTree = ""; + }; + E318DDE72C5A4FBD00091322 /* Australia */ = { + isa = PBXGroup; + children = ( + E318DDD02C5A4FBD00091322 /* ACT */, + E318DDD12C5A4FBD00091322 /* Adelaide */, + E318DDD22C5A4FBD00091322 /* Brisbane */, + E318DDD32C5A4FBD00091322 /* Broken_Hill */, + E318DDD42C5A4FBD00091322 /* Canberra */, + E318DDD52C5A4FBD00091322 /* Currie */, + E318DDD62C5A4FBD00091322 /* Darwin */, + E318DDD72C5A4FBD00091322 /* Eucla */, + E318DDD82C5A4FBD00091322 /* Hobart */, + E318DDD92C5A4FBD00091322 /* LHI */, + E318DDDA2C5A4FBD00091322 /* Lindeman */, + E318DDDB2C5A4FBD00091322 /* Lord_Howe */, + E318DDDC2C5A4FBD00091322 /* Melbourne */, + E318DDDD2C5A4FBD00091322 /* North */, + E318DDDE2C5A4FBD00091322 /* NSW */, + E318DDDF2C5A4FBD00091322 /* Perth */, + E318DDE02C5A4FBD00091322 /* Queensland */, + E318DDE12C5A4FBD00091322 /* South */, + E318DDE22C5A4FBD00091322 /* Sydney */, + E318DDE32C5A4FBD00091322 /* Tasmania */, + E318DDE42C5A4FBD00091322 /* Victoria */, + E318DDE52C5A4FBD00091322 /* West */, + E318DDE62C5A4FBD00091322 /* Yancowinna */, + ); + path = Australia; + sourceTree = ""; + }; + E318DDEC2C5A4FBD00091322 /* Brazil */ = { + isa = PBXGroup; + children = ( + E318DDE82C5A4FBD00091322 /* Acre */, + E318DDE92C5A4FBD00091322 /* DeNoronha */, + E318DDEA2C5A4FBD00091322 /* East */, + E318DDEB2C5A4FBD00091322 /* West */, + ); + path = Brazil; + sourceTree = ""; + }; + E318DDF52C5A4FBD00091322 /* Canada */ = { + isa = PBXGroup; + children = ( + E318DDED2C5A4FBD00091322 /* Atlantic */, + E318DDEE2C5A4FBD00091322 /* Central */, + E318DDEF2C5A4FBD00091322 /* Eastern */, + E318DDF02C5A4FBD00091322 /* Mountain */, + E318DDF12C5A4FBD00091322 /* Newfoundland */, + E318DDF22C5A4FBD00091322 /* Pacific */, + E318DDF32C5A4FBD00091322 /* Saskatchewan */, + E318DDF42C5A4FBD00091322 /* Yukon */, + ); + path = Canada; + sourceTree = ""; + }; + E318DDF82C5A4FBD00091322 /* Chile */ = { + isa = PBXGroup; + children = ( + E318DDF62C5A4FBD00091322 /* Continental */, + E318DDF72C5A4FBD00091322 /* EasterIsland */, + ); + path = Chile; + sourceTree = ""; + }; + E318DE1C2C5A4FBD00091322 /* Etc */ = { + isa = PBXGroup; + children = ( + E318DDF92C5A4FBD00091322 /* GMT */, + E318DDFA2C5A4FBD00091322 /* GMT-0 */, + E318DDFB2C5A4FBD00091322 /* GMT-1 */, + E318DDFC2C5A4FBD00091322 /* GMT-2 */, + E318DDFD2C5A4FBD00091322 /* GMT-3 */, + E318DDFE2C5A4FBD00091322 /* GMT-4 */, + E318DDFF2C5A4FBD00091322 /* GMT-5 */, + E318DE002C5A4FBD00091322 /* GMT-6 */, + E318DE012C5A4FBD00091322 /* GMT-7 */, + E318DE022C5A4FBD00091322 /* GMT-8 */, + E318DE032C5A4FBD00091322 /* GMT-9 */, + E318DE042C5A4FBD00091322 /* GMT-10 */, + E318DE052C5A4FBD00091322 /* GMT-11 */, + E318DE062C5A4FBD00091322 /* GMT-12 */, + E318DE072C5A4FBD00091322 /* GMT-13 */, + E318DE082C5A4FBD00091322 /* GMT-14 */, + E318DE092C5A4FBD00091322 /* GMT+0 */, + E318DE0A2C5A4FBD00091322 /* GMT+1 */, + E318DE0B2C5A4FBD00091322 /* GMT+2 */, + E318DE0C2C5A4FBD00091322 /* GMT+3 */, + E318DE0D2C5A4FBD00091322 /* GMT+4 */, + E318DE0E2C5A4FBD00091322 /* GMT+5 */, + E318DE0F2C5A4FBD00091322 /* GMT+6 */, + E318DE102C5A4FBD00091322 /* GMT+7 */, + E318DE112C5A4FBD00091322 /* GMT+8 */, + E318DE122C5A4FBD00091322 /* GMT+9 */, + E318DE132C5A4FBD00091322 /* GMT+10 */, + E318DE142C5A4FBD00091322 /* GMT+11 */, + E318DE152C5A4FBD00091322 /* GMT+12 */, + E318DE162C5A4FBD00091322 /* GMT0 */, + E318DE172C5A4FBD00091322 /* Greenwich */, + E318DE182C5A4FBD00091322 /* UCT */, + E318DE192C5A4FBD00091322 /* Universal */, + E318DE1A2C5A4FBD00091322 /* UTC */, + E318DE1B2C5A4FBD00091322 /* Zulu */, + ); + path = Etc; + sourceTree = ""; + }; + E318DE5C2C5A4FBD00091322 /* Europe */ = { + isa = PBXGroup; + children = ( + E318DE1D2C5A4FBD00091322 /* Amsterdam */, + E318DE1E2C5A4FBD00091322 /* Andorra */, + E318DE1F2C5A4FBD00091322 /* Astrakhan */, + E318DE202C5A4FBD00091322 /* Athens */, + E318DE212C5A4FBD00091322 /* Belfast */, + E318DE222C5A4FBD00091322 /* Belgrade */, + E318DE232C5A4FBD00091322 /* Berlin */, + E318DE242C5A4FBD00091322 /* Bratislava */, + E318DE252C5A4FBD00091322 /* Brussels */, + E318DE262C5A4FBD00091322 /* Bucharest */, + E318DE272C5A4FBD00091322 /* Budapest */, + E318DE282C5A4FBD00091322 /* Busingen */, + E318DE292C5A4FBD00091322 /* Chisinau */, + E318DE2A2C5A4FBD00091322 /* Copenhagen */, + E318DE2B2C5A4FBD00091322 /* Dublin */, + E318DE2C2C5A4FBD00091322 /* Gibraltar */, + E318DE2D2C5A4FBD00091322 /* Guernsey */, + E318DE2E2C5A4FBD00091322 /* Helsinki */, + E318DE2F2C5A4FBD00091322 /* Isle_of_Man */, + E318DE302C5A4FBD00091322 /* Istanbul */, + E318DE312C5A4FBD00091322 /* Jersey */, + E318DE322C5A4FBD00091322 /* Kaliningrad */, + E318DE332C5A4FBD00091322 /* Kiev */, + E318DE342C5A4FBD00091322 /* Kirov */, + E318DE352C5A4FBD00091322 /* Lisbon */, + E318DE362C5A4FBD00091322 /* Ljubljana */, + E318DE372C5A4FBD00091322 /* London */, + E318DE382C5A4FBD00091322 /* Luxembourg */, + E318DE392C5A4FBD00091322 /* Madrid */, + E318DE3A2C5A4FBD00091322 /* Malta */, + E318DE3B2C5A4FBD00091322 /* Mariehamn */, + E318DE3C2C5A4FBD00091322 /* Minsk */, + E318DE3D2C5A4FBD00091322 /* Monaco */, + E318DE3E2C5A4FBD00091322 /* Moscow */, + E318DE3F2C5A4FBD00091322 /* Nicosia */, + E318DE402C5A4FBD00091322 /* Oslo */, + E318DE412C5A4FBD00091322 /* Paris */, + E318DE422C5A4FBD00091322 /* Podgorica */, + E318DE432C5A4FBD00091322 /* Prague */, + E318DE442C5A4FBD00091322 /* Riga */, + E318DE452C5A4FBD00091322 /* Rome */, + E318DE462C5A4FBD00091322 /* Samara */, + E318DE472C5A4FBD00091322 /* San_Marino */, + E318DE482C5A4FBD00091322 /* Sarajevo */, + E318DE492C5A4FBD00091322 /* Saratov */, + E318DE4A2C5A4FBD00091322 /* Simferopol */, + E318DE4B2C5A4FBD00091322 /* Skopje */, + E318DE4C2C5A4FBD00091322 /* Sofia */, + E318DE4D2C5A4FBD00091322 /* Stockholm */, + E318DE4E2C5A4FBD00091322 /* Tallinn */, + E318DE4F2C5A4FBD00091322 /* Tirane */, + E318DE502C5A4FBD00091322 /* Tiraspol */, + E318DE512C5A4FBD00091322 /* Ulyanovsk */, + E318DE522C5A4FBD00091322 /* Uzhgorod */, + E318DE532C5A4FBD00091322 /* Vaduz */, + E318DE542C5A4FBD00091322 /* Vatican */, + E318DE552C5A4FBD00091322 /* Vienna */, + E318DE562C5A4FBD00091322 /* Vilnius */, + E318DE572C5A4FBD00091322 /* Volgograd */, + E318DE582C5A4FBD00091322 /* Warsaw */, + E318DE592C5A4FBD00091322 /* Zagreb */, + E318DE5A2C5A4FBD00091322 /* Zaporozhye */, + E318DE5B2C5A4FBD00091322 /* Zurich */, + ); + path = Europe; + sourceTree = ""; + }; + E318DE682C5A4FBD00091322 /* Indian */ = { + isa = PBXGroup; + children = ( + E318DE5D2C5A4FBD00091322 /* Antananarivo */, + E318DE5E2C5A4FBD00091322 /* Chagos */, + E318DE5F2C5A4FBD00091322 /* Christmas */, + E318DE602C5A4FBD00091322 /* Cocos */, + E318DE612C5A4FBD00091322 /* Comoro */, + E318DE622C5A4FBD00091322 /* Kerguelen */, + E318DE632C5A4FBD00091322 /* Mahe */, + E318DE642C5A4FBD00091322 /* Maldives */, + E318DE652C5A4FBD00091322 /* Mauritius */, + E318DE662C5A4FBD00091322 /* Mayotte */, + E318DE672C5A4FBD00091322 /* Reunion */, + ); + path = Indian; + sourceTree = ""; + }; + E318DE6C2C5A4FBD00091322 /* Mexico */ = { + isa = PBXGroup; + children = ( + E318DE692C5A4FBD00091322 /* BajaNorte */, + E318DE6A2C5A4FBD00091322 /* BajaSur */, + E318DE6B2C5A4FBD00091322 /* General */, + ); + path = Mexico; + sourceTree = ""; + }; + E318DE992C5A4FBD00091322 /* Pacific */ = { + isa = PBXGroup; + children = ( + E318DE6D2C5A4FBD00091322 /* Apia */, + E318DE6E2C5A4FBD00091322 /* Auckland */, + E318DE6F2C5A4FBD00091322 /* Bougainville */, + E318DE702C5A4FBD00091322 /* Chatham */, + E318DE712C5A4FBD00091322 /* Chuuk */, + E318DE722C5A4FBD00091322 /* Easter */, + E318DE732C5A4FBD00091322 /* Efate */, + E318DE742C5A4FBD00091322 /* Enderbury */, + E318DE752C5A4FBD00091322 /* Fakaofo */, + E318DE762C5A4FBD00091322 /* Fiji */, + E318DE772C5A4FBD00091322 /* Funafuti */, + E318DE782C5A4FBD00091322 /* Galapagos */, + E318DE792C5A4FBD00091322 /* Gambier */, + E318DE7A2C5A4FBD00091322 /* Guadalcanal */, + E318DE7B2C5A4FBD00091322 /* Guam */, + E318DE7C2C5A4FBD00091322 /* Honolulu */, + E318DE7D2C5A4FBD00091322 /* Johnston */, + E318DE7E2C5A4FBD00091322 /* Kanton */, + E318DE7F2C5A4FBD00091322 /* Kiritimati */, + E318DE802C5A4FBD00091322 /* Kosrae */, + E318DE812C5A4FBD00091322 /* Kwajalein */, + E318DE822C5A4FBD00091322 /* Majuro */, + E318DE832C5A4FBD00091322 /* Marquesas */, + E318DE842C5A4FBD00091322 /* Midway */, + E318DE852C5A4FBD00091322 /* Nauru */, + E318DE862C5A4FBD00091322 /* Niue */, + E318DE872C5A4FBD00091322 /* Norfolk */, + E318DE882C5A4FBD00091322 /* Noumea */, + E318DE892C5A4FBD00091322 /* Pago_Pago */, + E318DE8A2C5A4FBD00091322 /* Palau */, + E318DE8B2C5A4FBD00091322 /* Pitcairn */, + E318DE8C2C5A4FBD00091322 /* Pohnpei */, + E318DE8D2C5A4FBD00091322 /* Ponape */, + E318DE8E2C5A4FBD00091322 /* Port_Moresby */, + E318DE8F2C5A4FBD00091322 /* Rarotonga */, + E318DE902C5A4FBD00091322 /* Saipan */, + E318DE912C5A4FBD00091322 /* Samoa */, + E318DE922C5A4FBD00091322 /* Tahiti */, + E318DE932C5A4FBD00091322 /* Tarawa */, + E318DE942C5A4FBD00091322 /* Tongatapu */, + E318DE952C5A4FBD00091322 /* Truk */, + E318DE962C5A4FBD00091322 /* Wake */, + E318DE972C5A4FBD00091322 /* Wallis */, + E318DE982C5A4FBD00091322 /* Yap */, + ); + path = Pacific; + sourceTree = ""; + }; + E318DEA62C5A4FBD00091322 /* US */ = { + isa = PBXGroup; + children = ( + E318DE9A2C5A4FBD00091322 /* Alaska */, + E318DE9B2C5A4FBD00091322 /* Aleutian */, + E318DE9C2C5A4FBD00091322 /* Arizona */, + E318DE9D2C5A4FBD00091322 /* Central */, + E318DE9E2C5A4FBD00091322 /* East-Indiana */, + E318DE9F2C5A4FBD00091322 /* Eastern */, + E318DEA02C5A4FBD00091322 /* Hawaii */, + E318DEA12C5A4FBD00091322 /* Indiana-Starke */, + E318DEA22C5A4FBD00091322 /* Michigan */, + E318DEA32C5A4FBD00091322 /* Mountain */, + E318DEA42C5A4FBD00091322 /* Pacific */, + E318DEA52C5A4FBD00091322 /* Samoa */, + ); + path = US; + sourceTree = ""; + }; + E318DED72C5A4FBD00091322 /* zoneinfo */ = { + isa = PBXGroup; + children = ( + E318DCA32C5A4FBD00091322 /* Africa */, + E318DD4F2C5A4FBD00091322 /* America */, + E318DD5C2C5A4FBD00091322 /* Antarctica */, + E318DD5E2C5A4FBD00091322 /* Arctic */, + E318DDC22C5A4FBD00091322 /* Asia */, + E318DDCF2C5A4FBD00091322 /* Atlantic */, + E318DDE72C5A4FBD00091322 /* Australia */, + E318DDEC2C5A4FBD00091322 /* Brazil */, + E318DDF52C5A4FBD00091322 /* Canada */, + E318DDF82C5A4FBD00091322 /* Chile */, + E318DE1C2C5A4FBD00091322 /* Etc */, + E318DE5C2C5A4FBD00091322 /* Europe */, + E318DE682C5A4FBD00091322 /* Indian */, + E318DE6C2C5A4FBD00091322 /* Mexico */, + E318DE992C5A4FBD00091322 /* Pacific */, + E318DEA62C5A4FBD00091322 /* US */, + E318DEA72C5A4FBD00091322 /* CET */, + E318DEA82C5A4FBD00091322 /* CST6CDT */, + E318DEA92C5A4FBD00091322 /* Cuba */, + E318DEAA2C5A4FBD00091322 /* EET */, + E318DEAB2C5A4FBD00091322 /* Egypt */, + E318DEAC2C5A4FBD00091322 /* Eire */, + E318DEAD2C5A4FBD00091322 /* EST */, + E318DEAE2C5A4FBD00091322 /* EST5EDT */, + E318DEAF2C5A4FBD00091322 /* Factory */, + E318DEB02C5A4FBD00091322 /* GB */, + E318DEB12C5A4FBD00091322 /* GB-Eire */, + E318DEB22C5A4FBD00091322 /* GMT */, + E318DEB32C5A4FBD00091322 /* GMT-0 */, + E318DEB42C5A4FBD00091322 /* GMT+0 */, + E318DEB52C5A4FBD00091322 /* GMT0 */, + E318DEB62C5A4FBD00091322 /* Greenwich */, + E318DEB72C5A4FBD00091322 /* Hongkong */, + E318DEB82C5A4FBD00091322 /* HST */, + E318DEB92C5A4FBD00091322 /* Iceland */, + E318DEBA2C5A4FBD00091322 /* Iran */, + E318DEBB2C5A4FBD00091322 /* iso3166.tab */, + E318DEBC2C5A4FBD00091322 /* Israel */, + E318DEBD2C5A4FBD00091322 /* Jamaica */, + E318DEBE2C5A4FBD00091322 /* Japan */, + E318DEBF2C5A4FBD00091322 /* Kwajalein */, + E318DEC02C5A4FBD00091322 /* Libya */, + E318DEC12C5A4FBD00091322 /* localtime */, + E318DEC22C5A4FBD00091322 /* MET */, + E318DEC32C5A4FBD00091322 /* MST */, + E318DEC42C5A4FBD00091322 /* MST7MDT */, + E318DEC52C5A4FBD00091322 /* Navajo */, + E318DEC62C5A4FBD00091322 /* NZ */, + E318DEC72C5A4FBD00091322 /* NZ-CHAT */, + E318DEC82C5A4FBD00091322 /* Poland */, + E318DEC92C5A4FBD00091322 /* Portugal */, + E318DECA2C5A4FBD00091322 /* PRC */, + E318DECB2C5A4FBD00091322 /* PST8PDT */, + E318DECC2C5A4FBD00091322 /* ROC */, + E318DECD2C5A4FBD00091322 /* ROK */, + E318DECE2C5A4FBD00091322 /* Singapore */, + E318DECF2C5A4FBD00091322 /* Turkey */, + E318DED02C5A4FBD00091322 /* UCT */, + E318DED12C5A4FBD00091322 /* Universal */, + E318DED22C5A4FBD00091322 /* UTC */, + E318DED32C5A4FBD00091322 /* W-SU */, + E318DED42C5A4FBD00091322 /* WET */, + E318DED52C5A4FBD00091322 /* zone1970.tab */, + E318DED62C5A4FBD00091322 /* Zulu */, + ); + path = zoneinfo; + sourceTree = ""; + }; + E318DEDA2C5A4FBD00091322 /* testdata */ = { + isa = PBXGroup; + children = ( + E318DED72C5A4FBD00091322 /* zoneinfo */, + E318DED82C5A4FBD00091322 /* README.zoneinfo */, + E318DED92C5A4FBD00091322 /* version */, + ); + path = testdata; + sourceTree = ""; + }; + E318DEDC2C5A4FBD00091322 /* cctz */ = { + isa = PBXGroup; + children = ( + E318DC562C5A4FBD00091322 /* include */, + E318DC6C2C5A4FBD00091322 /* src */, + E318DEDA2C5A4FBD00091322 /* testdata */, + E318DEDB2C5A4FBD00091322 /* BUILD.bazel */, + ); + path = cctz; + sourceTree = ""; + }; + E318DEE22C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DEDC2C5A4FBD00091322 /* cctz */, + E318DEDD2C5A4FBD00091322 /* get_current_time_chrono.inc */, + E318DEDE2C5A4FBD00091322 /* get_current_time_posix.inc */, + E318DEDF2C5A4FBD00091322 /* test_util.cc */, + E318DEE02C5A4FBD00091322 /* test_util.h */, + E318DEE12C5A4FBD00091322 /* zoneinfo.inc */, + ); + path = internal; + sourceTree = ""; + }; + E318DEF82C5A4FBD00091322 /* time */ = { + isa = PBXGroup; + children = ( + E318DC502C5A4FBD00091322 /* CMakeFiles */, + E318DEE22C5A4FBD00091322 /* internal */, + E318DEE32C5A4FBD00091322 /* BUILD.bazel */, + E318DEE42C5A4FBD00091322 /* civil_time_benchmark.cc */, + E318DEE52C5A4FBD00091322 /* civil_time_test.cc */, + E318DEE62C5A4FBD00091322 /* civil_time.cc */, + E318DEE72C5A4FBD00091322 /* civil_time.h */, + E318DEE82C5A4FBD00091322 /* clock_benchmark.cc */, + E318DEE92C5A4FBD00091322 /* clock_test.cc */, + E318DEEA2C5A4FBD00091322 /* clock.cc */, + E318DEEB2C5A4FBD00091322 /* clock.h */, + E318DEEC2C5A4FBD00091322 /* CMakeLists.txt */, + E318DEED2C5A4FBD00091322 /* duration_benchmark.cc */, + E318DEEE2C5A4FBD00091322 /* duration_test.cc */, + E318DEEF2C5A4FBD00091322 /* duration.cc */, + E318DEF02C5A4FBD00091322 /* format_benchmark.cc */, + E318DEF12C5A4FBD00091322 /* format_test.cc */, + E318DEF22C5A4FBD00091322 /* format.cc */, + E318DEF32C5A4FBD00091322 /* time_benchmark.cc */, + E318DEF42C5A4FBD00091322 /* time_test.cc */, + E318DEF52C5A4FBD00091322 /* time_zone_test.cc */, + E318DEF62C5A4FBD00091322 /* time.cc */, + E318DEF72C5A4FBD00091322 /* time.h */, + ); + path = time; + sourceTree = ""; + }; + E318DEF92C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DF052C5A4FBD00091322 /* internal */ = { + isa = PBXGroup; + children = ( + E318DEFA2C5A4FBD00091322 /* conformance_aliases.h */, + E318DEFB2C5A4FBD00091322 /* conformance_archetype.h */, + E318DEFC2C5A4FBD00091322 /* conformance_profile.h */, + E318DEFD2C5A4FBD00091322 /* conformance_testing_helpers.h */, + E318DEFE2C5A4FBD00091322 /* conformance_testing_test.cc */, + E318DEFF2C5A4FBD00091322 /* conformance_testing.h */, + E318DF002C5A4FBD00091322 /* optional.h */, + E318DF012C5A4FBD00091322 /* parentheses.h */, + E318DF022C5A4FBD00091322 /* span.h */, + E318DF032C5A4FBD00091322 /* transform_args.h */, + E318DF042C5A4FBD00091322 /* variant.h */, + ); + path = internal; + sourceTree = ""; + }; + E318DF1C2C5A4FBD00091322 /* types */ = { + isa = PBXGroup; + children = ( + E318DEF92C5A4FBD00091322 /* CMakeFiles */, + E318DF052C5A4FBD00091322 /* internal */, + E318DF062C5A4FBD00091322 /* any_exception_safety_test.cc */, + E318DF072C5A4FBD00091322 /* any_test.cc */, + E318DF082C5A4FBD00091322 /* any.h */, + E318DF092C5A4FBD00091322 /* bad_any_cast.cc */, + E318DF0A2C5A4FBD00091322 /* bad_any_cast.h */, + E318DF0B2C5A4FBD00091322 /* bad_optional_access.cc */, + E318DF0C2C5A4FBD00091322 /* bad_optional_access.h */, + E318DF0D2C5A4FBD00091322 /* bad_variant_access.cc */, + E318DF0E2C5A4FBD00091322 /* bad_variant_access.h */, + E318DF0F2C5A4FBD00091322 /* BUILD.bazel */, + E318DF102C5A4FBD00091322 /* CMakeLists.txt */, + E318DF112C5A4FBD00091322 /* compare_test.cc */, + E318DF122C5A4FBD00091322 /* compare.h */, + E318DF132C5A4FBD00091322 /* optional_exception_safety_test.cc */, + E318DF142C5A4FBD00091322 /* optional_test.cc */, + E318DF152C5A4FBD00091322 /* optional.h */, + E318DF162C5A4FBD00091322 /* span_test.cc */, + E318DF172C5A4FBD00091322 /* span.h */, + E318DF182C5A4FBD00091322 /* variant_benchmark.cc */, + E318DF192C5A4FBD00091322 /* variant_exception_safety_test.cc */, + E318DF1A2C5A4FBD00091322 /* variant_test.cc */, + E318DF1B2C5A4FBD00091322 /* variant.h */, + ); + path = types; + sourceTree = ""; + }; + E318DF1D2C5A4FBD00091322 /* CMakeFiles */ = { + isa = PBXGroup; + children = ( + ); + path = CMakeFiles; + sourceTree = ""; + }; + E318DF222C5A4FBD00091322 /* utility */ = { + isa = PBXGroup; + children = ( + E318DF1D2C5A4FBD00091322 /* CMakeFiles */, + E318DF1E2C5A4FBD00091322 /* BUILD.bazel */, + E318DF1F2C5A4FBD00091322 /* CMakeLists.txt */, + E318DF202C5A4FBD00091322 /* utility_test.cc */, + E318DF212C5A4FBD00091322 /* utility.h */, + ); + path = utility; + sourceTree = ""; + }; + E318DF262C5A4FBD00091322 /* absl */ = { + isa = PBXGroup; + children = ( + E318D9AA2C5A4FBD00091322 /* algorithm */, + E318DA0B2C5A4FBD00091322 /* base */, + E318DA132C5A4FBD00091322 /* cleanup */, + E318DA142C5A4FBD00091322 /* CMakeFiles */, + E318DA602C5A4FBD00091322 /* container */, + E318DA672C5A4FBD00091322 /* copts */, + E318DA972C5A4FBD00091322 /* debugging */, + E318DAC92C5A4FBD00091322 /* flags */, + E318DAD82C5A4FBD00091322 /* functional */, + E318DAEB2C5A4FBD00091322 /* hash */, + E318DAF22C5A4FBD00091322 /* memory */, + E318DAF82C5A4FBD00091322 /* meta */, + E318DB092C5A4FBD00091322 /* numeric */, + E318DB172C5A4FBD00091322 /* profiling */, + E318DB7F2C5A4FBD00091322 /* random */, + E318DB8E2C5A4FBD00091322 /* status */, + E318DC2D2C5A4FBD00091322 /* strings */, + E318DC4F2C5A4FBD00091322 /* synchronization */, + E318DEF82C5A4FBD00091322 /* time */, + E318DF1C2C5A4FBD00091322 /* types */, + E318DF222C5A4FBD00091322 /* utility */, + E318DF232C5A4FBD00091322 /* abseil.podspec.gen.py */, + E318DF242C5A4FBD00091322 /* BUILD.bazel */, + E318DF252C5A4FBD00091322 /* CMakeLists.txt */, + ); + name = absl; + path = "../lib/abseil-cpp/absl"; + sourceTree = ""; + }; + E318E7742C5A536400091322 /* dirent */ = { + isa = PBXGroup; + children = ( + E318E7702C5A536400091322 /* ChangeLog */, + E318E7712C5A536400091322 /* dirent.h */, + E318E7722C5A536400091322 /* LICENSE */, + E318E7732C5A536400091322 /* README.md */, + ); + path = dirent; + sourceTree = ""; + }; + E318E7792C5A536400091322 /* stb */ = { + isa = PBXGroup; + children = ( + E318E7752C5A536400091322 /* LICENSE */, + E318E7762C5A536400091322 /* README.md */, + E318E7772C5A536400091322 /* stb_image_resize.h */, + E318E7782C5A536400091322 /* stb_image.h */, + ); + path = stb; + sourceTree = ""; + }; + E318E7802C5A536400091322 /* ImGuiFileDialog */ = { + isa = PBXGroup; + children = ( + E318E7742C5A536400091322 /* dirent */, + E318E7792C5A536400091322 /* stb */, + E318E77A2C5A536400091322 /* CMakeLists.txt */, + E318E77B2C5A536400091322 /* ImGuiFileDialog.cpp */, + E318E77C2C5A536400091322 /* ImGuiFileDialog.h */, + E318E77D2C5A536400091322 /* ImGuiFileDialogConfig.h */, + E318E77E2C5A536400091322 /* LICENSE */, + E318E77F2C5A536400091322 /* README.md */, + ); + name = ImGuiFileDialog; + path = ../../yaze/src/lib/ImGuiFileDialog; + sourceTree = ""; + }; + E318E7AC2C5A548C00091322 /* png */ = { + isa = PBXGroup; + children = ( + E318E8072C5B24CC00091322 /* assets */, + E318E7D62C5A55C300091322 /* arm_init.c */, + E318E7CF2C5A55AE00091322 /* filter_neon_intrinsics.c */, + E318E7CD2C5A55AE00091322 /* filter_neon.S */, + E318E7CE2C5A55AE00091322 /* palette_neon_intrinsics.c */, + E318E7952C5A548C00091322 /* png.c */, + E318E7962C5A548C00091322 /* png.h */, + E318E7972C5A548C00091322 /* pngconf.h */, + E318E7982C5A548C00091322 /* pngdebug.h */, + E318E7992C5A548C00091322 /* pngerror.c */, + E318E79A2C5A548C00091322 /* pngget.c */, + E318E79B2C5A548C00091322 /* pnginfo.h */, + E318E79C2C5A548C00091322 /* pnglibconf.h */, + E318E79D2C5A548C00091322 /* pngmem.c */, + E318E79E2C5A548C00091322 /* pngpread.c */, + E318E79F2C5A548C00091322 /* pngpriv.h */, + E318E7A02C5A548C00091322 /* pngread.c */, + E318E7A12C5A548C00091322 /* pngrio.c */, + E318E7A22C5A548C00091322 /* pngrtran.c */, + E318E7A32C5A548C00091322 /* pngrutil.c */, + E318E7A42C5A548C00091322 /* pngset.c */, + E318E7A52C5A548C00091322 /* pngstruct.h */, + E318E7A62C5A548C00091322 /* pngtest.c */, + E318E7A72C5A548C00091322 /* pngtrans.c */, + E318E7A82C5A548C00091322 /* pngwio.c */, + E318E7A92C5A548C00091322 /* pngwrite.c */, + E318E7AA2C5A548C00091322 /* pngwtran.c */, + E318E7AB2C5A548C00091322 /* pngwutil.c */, + ); + name = png; + path = ../../../lpng1643/png; + sourceTree = ""; + }; + E318E7D92C5A687600091322 /* assets */ = { + isa = PBXGroup; + children = ( + E318E8762C5D949200091322 /* yaze.png */, + E318E7E12C5A688A00091322 /* font */, + E318E7E42C5A688A00091322 /* layouts */, + ); + name = assets; + path = ../../assets; + sourceTree = ""; + }; + E318E7E12C5A688A00091322 /* font */ = { + isa = PBXGroup; + children = ( + E318E7DA2C5A688A00091322 /* Cousine-Regular.ttf */, + E318E7DB2C5A688A00091322 /* DroidSans.ttf */, + E318E7DC2C5A688A00091322 /* IBMPlexSansJP-Bold.ttf */, + E318E7DD2C5A688A00091322 /* Karla-Regular.ttf */, + E318E7DE2C5A688A00091322 /* MaterialIcons-Regular.ttf */, + E318E7DF2C5A688A00091322 /* NotoSansJP.ttf */, + E318E7E02C5A688A00091322 /* Roboto-Medium.ttf */, + ); + path = font; + sourceTree = ""; + }; + E318E7E42C5A688A00091322 /* layouts */ = { + isa = PBXGroup; + children = ( + E318E7E22C5A688A00091322 /* overworld.zeml */, + E318E7E32C5A688A00091322 /* ow_toolset.zeml */, + ); + path = layouts; + sourceTree = ""; + }; + E318E8072C5B24CC00091322 /* assets */ = { + isa = PBXGroup; + children = ( + E318E80B2C5B24CD00091322 /* font */, + E318E8082C5B24CD00091322 /* layouts */, + ); + path = assets; + sourceTree = ""; + }; + E318E8082C5B24CD00091322 /* layouts */ = { + isa = PBXGroup; + children = ( + E318E80A2C5B24CD00091322 /* overworld.zeml */, + E318E8092C5B24CD00091322 /* ow_toolset.zeml */, + ); + path = layouts; + sourceTree = ""; + }; + E318E80B2C5B24CD00091322 /* font */ = { + isa = PBXGroup; + children = ( + E318E80C2C5B24CD00091322 /* Cousine-Regular.ttf */, + E318E80E2C5B24CD00091322 /* DroidSans.ttf */, + E318E8102C5B24CD00091322 /* IBMPlexSansJP-Bold.ttf */, + E318E80D2C5B24CD00091322 /* Karla-Regular.ttf */, + E318E8112C5B24CD00091322 /* MaterialIcons-Regular.ttf */, + E318E8122C5B24CD00091322 /* NotoSansJP.ttf */, + E318E80F2C5B24CD00091322 /* Roboto-Medium.ttf */, + ); + path = font; + sourceTree = ""; + }; + E318E84A2C5D74B700091322 /* Products */ = { + isa = PBXGroup; + children = ( + E318E8572C5D74B700091322 /* SDL2.framework */, + E318E8592C5D74B700091322 /* SDL2.framework */, + E318E85B2C5D74B700091322 /* SDL2.framework */, + E36971D82CE1898700DEF2F6 /* SDL2.framework */, + E318E85D2C5D74B700091322 /* libSDL2.a */, + E318E85F2C5D74B700091322 /* libSDL2.a */, + E318E8612C5D74B700091322 /* libSDL2.a */, + E318E8632C5D74B700091322 /* libSDL2.dylib */, + E318E8652C5D74B700091322 /* libSDL2.dylib */, + E318E8672C5D74B700091322 /* libSDL2.dylib */, + E318E8692C5D74B700091322 /* SDL2 */, + ); + name = Products; + sourceTree = ""; + }; + E36971E32CE18A2A00DEF2F6 /* utils */ = { + isa = PBXGroup; + children = ( + E36971E02CE18A2A00DEF2F6 /* file_util.h */, + E36971E12CE18A2A00DEF2F6 /* file_util.cc */, + E36971E22CE18A2A00DEF2F6 /* sdl_deleter.h */, + ); + path = utils; + sourceTree = ""; + }; + E38A97F62C6C4CE3005FB662 /* system */ = { + isa = PBXGroup; + children = ( + E32BC4CA2CA4D7BC001F57A8 /* command_manager.cc */, + E38A97F12C6C4CE3005FB662 /* command_manager.h */, + E38A97F22C6C4CE3005FB662 /* extension_manager.cc */, + E38A97F32C6C4CE3005FB662 /* extension_manager.h */, + E38A97F42C6C4CE3005FB662 /* settings_editor.cc */, + E38A97F52C6C4CE3005FB662 /* settings_editor.h */, + ); + path = system; + sourceTree = ""; + }; + E3B864942C82146700122951 /* modules */ = { + isa = PBXGroup; + children = ( + E3B864902C82144A00122951 /* asset_browser.cc */, + E3B8648F2C82144A00122951 /* asset_browser.h */, + ); + path = modules; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8307E7C320E9F9C900473790 /* yaze_ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8307E7F020E9F9C900473790 /* Build configuration list for PBXNativeTarget "yaze_ios" */; + buildPhases = ( + 8307E7C020E9F9C900473790 /* Sources */, + 8307E7C120E9F9C900473790 /* Frameworks */, + 8307E7C220E9F9C900473790 /* Resources */, + E318E86C2C5D74C500091322 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = yaze_ios; + productName = "imguiex iOS"; + productReference = 8307E7C420E9F9C900473790 /* yaze.app */; + productType = "com.apple.product-type.application"; + }; + 8307E7D920E9F9C900473790 /* yaze_macos */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8307E7F320E9F9C900473790 /* Build configuration list for PBXNativeTarget "yaze_macos" */; + buildPhases = ( + 8307E7D620E9F9C900473790 /* Sources */, + 8307E7D720E9F9C900473790 /* Frameworks */, + 8307E7D820E9F9C900473790 /* Resources */, + E318E87C2C605D5700091322 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = yaze_macos; + productName = "imguiex macOS"; + productReference = 8307E7DA20E9F9C900473790 /* yaze.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8307E7B620E9F9C700473790 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1540; + ORGANIZATIONNAME = "Warren Moore"; + TargetAttributes = { + 8307E7C320E9F9C900473790 = { + CreatedOnToolsVersion = 9.4.1; + LastSwiftMigration = 1540; + ProvisioningStyle = Automatic; + }; + 8307E7D920E9F9C900473790 = { + CreatedOnToolsVersion = 9.4.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 8307E7B920E9F9C700473790 /* Build configuration list for PBXProject "yaze" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8307E7B520E9F9C700473790; + productRefGroup = 8307E7C520E9F9C900473790 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = E318E84A2C5D74B700091322 /* Products */; + ProjectRef = E318E8492C5D74B700091322 /* SDL.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 8307E7C320E9F9C900473790 /* yaze_ios */, + 8307E7D920E9F9C900473790 /* yaze_macos */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + E318E8572C5D74B700091322 /* SDL2.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = SDL2.framework; + remoteRef = E318E8562C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E8592C5D74B700091322 /* SDL2.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = SDL2.framework; + remoteRef = E318E8582C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E85B2C5D74B700091322 /* SDL2.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = SDL2.framework; + remoteRef = E318E85A2C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E85D2C5D74B700091322 /* libSDL2.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libSDL2.a; + remoteRef = E318E85C2C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E85F2C5D74B700091322 /* libSDL2.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libSDL2.a; + remoteRef = E318E85E2C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E8612C5D74B700091322 /* libSDL2.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libSDL2.a; + remoteRef = E318E8602C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E8632C5D74B700091322 /* libSDL2.dylib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = libSDL2.dylib; + remoteRef = E318E8622C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E8652C5D74B700091322 /* libSDL2.dylib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = libSDL2.dylib; + remoteRef = E318E8642C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E8672C5D74B700091322 /* libSDL2.dylib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = libSDL2.dylib; + remoteRef = E318E8662C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E318E8692C5D74B700091322 /* SDL2 */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = SDL2; + remoteRef = E318E8682C5D74B700091322 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E36971D82CE1898700DEF2F6 /* SDL2.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = SDL2.framework; + remoteRef = E36971D72CE1898700DEF2F6 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 8307E7C220E9F9C900473790 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E318E86D2C5D757800091322 /* Cousine-Regular.ttf in Resources */, + E318E86E2C5D757800091322 /* DroidSans.ttf in Resources */, + E318E86F2C5D757800091322 /* IBMPlexSansJP-Bold.ttf in Resources */, + E318E8702C5D757800091322 /* Karla-Regular.ttf in Resources */, + E318E8712C5D757800091322 /* MaterialIcons-Regular.ttf in Resources */, + E318E8792C5D958400091322 /* Media.xcassets in Resources */, + E318E8722C5D757800091322 /* NotoSansJP.ttf in Resources */, + E318E8772C5D949200091322 /* yaze.png in Resources */, + E318E8732C5D757800091322 /* Roboto-Medium.ttf in Resources */, + E318E8742C5D757800091322 /* overworld.zeml in Resources */, + E318E8752C5D757800091322 /* ow_toolset.zeml in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8307E7D820E9F9C900473790 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E318E7F02C5A688A00091322 /* NotoSansJP.ttf in Resources */, + E318E7E82C5A688A00091322 /* DroidSans.ttf in Resources */, + E318E7EA2C5A688A00091322 /* IBMPlexSansJP-Bold.ttf in Resources */, + 8309BE04253CDAB60045E2A1 /* MainMenu.storyboard in Resources */, + E318E7422C5A4FCA00091322 /* abseil.podspec.gen.py in Resources */, + E318E7EE2C5A688A00091322 /* MaterialIcons-Regular.ttf in Resources */, + E318E7F22C5A688A00091322 /* Roboto-Medium.ttf in Resources */, + E318E78A2C5A536400091322 /* README.md in Resources */, + E318E7EC2C5A688A00091322 /* Karla-Regular.ttf in Resources */, + E318E7F42C5A688A00091322 /* overworld.zeml in Resources */, + E318E7902C5A536400091322 /* LICENSE in Resources */, + E318E7F62C5A688A00091322 /* ow_toolset.zeml in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8307E7C020E9F9C900473790 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E32BC4CB2CA4D7D9001F57A8 /* command_manager.cc in Sources */, + E3B864952C8214B500122951 /* asset_browser.cc in Sources */, + E384E2D62C76C6E800147029 /* message_data.cc in Sources */, + E318E7932C5A542700091322 /* distribution_test_util.cc in Sources */, + E318E7942C5A542700091322 /* distribution_test_util.h in Sources */, + E318D9692C59C08300091322 /* style.cc in Sources */, + E318E1492C5A4FC100091322 /* float_conversion.cc in Sources */, + E318E2012C5A4FC200091322 /* graphcycles.cc in Sources */, + E318D9012C59C08300091322 /* file_dialog.mm in Sources */, + E318D9752C59C08300091322 /* tracker.cc in Sources */, + 8309BDBB253CCCAD0045E2A1 /* imgui_impl_metal.mm in Sources */, + E318E0012C5A4FBF00091322 /* stacktrace_powerpc-inl.inc in Sources */, + E318D9792C59C08300091322 /* overworld.cc in Sources */, + E318E2312C5A4FC300091322 /* time_zone_impl.cc in Sources */, + E318E1132C5A4FC100091322 /* gaussian_distribution.cc in Sources */, + E318D97B2C59C08300091322 /* inventory.cc in Sources */, + E318E0092C5A4FBF00091322 /* stacktrace_x86-inl.inc in Sources */, + E318D9252C59C08300091322 /* sprite_editor.cc in Sources */, + E318D9052C59C08300091322 /* font_loader.mm in Sources */, + E318E0532C5A4FBF00091322 /* flag.cc in Sources */, + E318DFF72C5A4FBF00091322 /* stack_consumption.cc in Sources */, + E318E16D2C5A4FC100091322 /* cord_rep_btree.cc in Sources */, + 83BBEA0920EB54E700295997 /* imgui.cpp in Sources */, + E318D93D2C59C08300091322 /* addressing.cc in Sources */, + E318E0312C5A4FBF00091322 /* flag.cc in Sources */, + E318DF6B2C5A4FBE00091322 /* throw_delegate.cc in Sources */, + E318D95F2C59C08300091322 /* tilesheet.cc in Sources */, + E318D9652C59C08300091322 /* color.cc in Sources */, + E318E0F32C5A4FC000091322 /* seed_material.cc in Sources */, + E318D98D2C59CBBB00091322 /* TextEditor.cpp in Sources */, + E318D9992C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp in Sources */, + E318E00B2C5A4FBF00091322 /* vdso_support.cc in Sources */, + E318E7B12C5A548C00091322 /* pngget.c in Sources */, + E318E0A72C5A4FC000091322 /* int128.cc in Sources */, + E318DFEF2C5A4FBF00091322 /* demangle.cc in Sources */, + E318E0032C5A4FBF00091322 /* stacktrace_riscv-inl.inc in Sources */, + E318E1932C5A4FC100091322 /* memutil.cc in Sources */, + E318DF432C5A4FBE00091322 /* low_level_alloc.cc in Sources */, + E318D93F2C59C08300091322 /* instructions.cc in Sources */, + E318E0052C5A4FBF00091322 /* stacktrace_unimplemented-inl.inc in Sources */, + E318E1DB2C5A4FC200091322 /* str_cat.cc in Sources */, + E318E15D2C5A4FC100091322 /* charconv_parse.cc in Sources */, + E318E1C32C5A4FC200091322 /* cord.cc in Sources */, + E318D9532C59C08300091322 /* bitmap.cc in Sources */, + E318E13B2C5A4FC100091322 /* arg.cc in Sources */, + E318DF532C5A4FBE00091322 /* spinlock_posix.inc in Sources */, + E318E2112C5A4FC200091322 /* blocking_counter.cc in Sources */, + E318E0272C5A4FBF00091322 /* symbolize_unimplemented.inc in Sources */, + E318E0A12C5A4FC000091322 /* int128_no_intrinsic.inc in Sources */, + E318E7BD2C5A548C00091322 /* pngrutil.c in Sources */, + E318E0BD2C5A4FC000091322 /* chi_square.cc in Sources */, + E318E7AD2C5A548C00091322 /* png.c in Sources */, + E318E0472C5A4FBF00091322 /* commandlineflag.cc in Sources */, + E318D94F2C59C08300091322 /* emulator.cc in Sources */, + E318E03F2C5A4FBF00091322 /* usage.cc in Sources */, + E318E1D52C5A4FC200091322 /* numbers.cc in Sources */, + E318E1752C5A4FC100091322 /* cord_rep_ring.cc in Sources */, + E318DF692C5A4FBE00091322 /* thread_identity.cc in Sources */, + E318E1332C5A4FC100091322 /* status.cc in Sources */, + E318E1652C5A4FC100091322 /* cord_rep_btree_navigator.cc in Sources */, + E318E1472C5A4FC100091322 /* extension.cc in Sources */, + E318DF572C5A4FBE00091322 /* spinlock_win32.inc in Sources */, + E318D9772C59C08300091322 /* overworld_map.cc in Sources */, + E318E7B52C5A548C00091322 /* pngpread.c in Sources */, + E318D9712C59C08300091322 /* room.cc in Sources */, + E318E6F12C5A4FC900091322 /* get_current_time_chrono.inc in Sources */, + E318E0772C5A4FC000091322 /* hash.cc in Sources */, + E318E2052C5A4FC200091322 /* per_thread_sem.cc in Sources */, + E318E0E52C5A4FC000091322 /* randen_round_keys.cc in Sources */, + E318D9212C59C08300091322 /* entity.cc in Sources */, + E318D9512C59C08300091322 /* snes.cc in Sources */, + E318DF472C5A4FBE00091322 /* raw_logging.cc in Sources */, + E318E2392C5A4FC300091322 /* time_zone_lookup.cc in Sources */, + E318E23B2C5A4FC300091322 /* time_zone_posix.cc in Sources */, + E318E7C32C5A548C00091322 /* pngtrans.c in Sources */, + E318E7B32C5A548C00091322 /* pngmem.c in Sources */, + E318E02D2C5A4FBF00091322 /* commandlineflag.cc in Sources */, + E318D97D2C59C08300091322 /* title_screen.cc in Sources */, + E318DF512C5A4FBE00091322 /* spinlock_linux.inc in Sources */, + E318E7D22C5A55AE00091322 /* palette_neon_intrinsics.c in Sources */, + E318E0192C5A4FBF00091322 /* leak_check.cc in Sources */, + E318E23D2C5A4FC300091322 /* zone_info_source.cc in Sources */, + E318DFF32C5A4FBF00091322 /* examine_stack.cc in Sources */, + E318E1BB2C5A4FC200091322 /* cord_buffer.cc in Sources */, + E318D8FB2C59C08300091322 /* app_delegate.mm in Sources */, + E318D9192C59C08300091322 /* tile16_editor.cc in Sources */, + 83BBEA0720EB54E700295997 /* imgui_demo.cpp in Sources */, + E318E1992C5A4FC200091322 /* ostringstream.cc in Sources */, + E318E2072C5A4FC200091322 /* waiter.cc in Sources */, + E318E09F2C5A4FC000091322 /* int128_have_intrinsic.inc in Sources */, + E318DF5F2C5A4FBE00091322 /* strerror.cc in Sources */, + E318E1592C5A4FC100091322 /* charconv_bigint.cc in Sources */, + E318DFF12C5A4FBF00091322 /* elf_mem_image.cc in Sources */, + E318E7132C5A4FC900091322 /* format.cc in Sources */, + E318D9492C59C08300091322 /* memory.cc in Sources */, + E318E7C52C5A548C00091322 /* pngwio.c in Sources */, + E318E7C92C5A548C00091322 /* pngwtran.c in Sources */, + E318E17D2C5A4FC100091322 /* cordz_handle.cc in Sources */, + E318E1CB2C5A4FC200091322 /* escaping.cc in Sources */, + E318E1232C5A4FC100091322 /* seed_sequences.cc in Sources */, + E318DFEB2C5A4FBF00091322 /* address_is_readable.cc in Sources */, + E318E1FB2C5A4FC200091322 /* create_thread_identity.cc in Sources */, + E318E7252C5A4FC900091322 /* bad_optional_access.cc in Sources */, + E318D9432C59C08300091322 /* cpu.cc in Sources */, + E318E2212C5A4FC200091322 /* notification.cc in Sources */, + E318DF872C5A4FBE00091322 /* log_severity.cc in Sources */, + E318D9872C59C08300091322 /* rom.cc in Sources */, + E318E0D92C5A4FC000091322 /* pool_urbg.cc in Sources */, + E318D96F2C59C08300091322 /* room_object.cc in Sources */, + E318D96B2C59C08300091322 /* zeml.cc in Sources */, + E318E70D2C5A4FC900091322 /* duration.cc in Sources */, + E318E1372C5A4FC100091322 /* statusor.cc in Sources */, + E318D95D2C59C08300091322 /* snes_tile.cc in Sources */, + E318E0632C5A4FBF00091322 /* usage_config.cc in Sources */, + E318D8FF2C59C08300091322 /* clipboard.mm in Sources */, + E318DFB72C5A4FBE00091322 /* raw_hash_set.cc in Sources */, + E318D9592C59C08300091322 /* snes_color.cc in Sources */, + E318E11F2C5A4FC100091322 /* seed_gen_exception.cc in Sources */, + E318D9952C59CDF800091322 /* imgui_impl_sdl2.cpp in Sources */, + E318E22F2C5A4FC300091322 /* time_zone_if.cc in Sources */, + E318DFFB2C5A4FBF00091322 /* stacktrace_arm-inl.inc in Sources */, + E318E2292C5A4FC200091322 /* time_zone_fixed.cc in Sources */, + E318E12F2C5A4FC100091322 /* status_payload_printer.cc in Sources */, + E36971DB2CE189EA00DEF2F6 /* project.cc in Sources */, + E318E78D2C5A536400091322 /* ImGuiFileDialog.cpp in Sources */, + E318E1792C5A4FC100091322 /* cordz_functions.cc in Sources */, + E318E0212C5A4FBF00091322 /* symbolize_elf.inc in Sources */, + E318D94B2C59C08300091322 /* ppu.cc in Sources */, + E318E7BF2C5A548C00091322 /* pngset.c in Sources */, + E318E2252C5A4FC200091322 /* civil_time_detail.cc in Sources */, + E318D9552C59C08300091322 /* compression.cc in Sources */, + E318E2352C5A4FC300091322 /* time_zone_libc.cc in Sources */, + E318E1B72C5A4FC200091322 /* cord_analysis.cc in Sources */, + E318D8FD2C59C08300091322 /* clipboard.cc in Sources */, + E3BE958D2C68379B008DD1E7 /* editor_manager.cc in Sources */, + E318D9072C59C08300091322 /* common.cc in Sources */, + E318D96D2C59C08300091322 /* object_renderer.cc in Sources */, + E318DFFD2C5A4FBF00091322 /* stacktrace_emscripten-inl.inc in Sources */, + E318E0072C5A4FBF00091322 /* stacktrace_win32-inl.inc in Sources */, + E318D93B2C59C08300091322 /* spc700.cc in Sources */, + E318D9132C59C08300091322 /* graphics_editor.cc in Sources */, + E318DF632C5A4FBE00091322 /* sysinfo.cc in Sources */, + E318D90F2C59C08300091322 /* dungeon_editor.cc in Sources */, + E318D9032C59C08300091322 /* font_loader.cc in Sources */, + E318DF552C5A4FBE00091322 /* spinlock_wait.cc in Sources */, + E318D90D2C59C08300091322 /* assembly_editor.cc in Sources */, + E38A97F72C6C4CE3005FB662 /* extension_manager.cc in Sources */, + E318D9152C59C08300091322 /* palette_editor.cc in Sources */, + E3BE95902C6837C8008DD1E7 /* overworld_editor.cc in Sources */, + E318E0AB2C5A4FC000091322 /* exponential_biased.cc in Sources */, + E318D9332C59C08300091322 /* addressing.cc in Sources */, + E318E0B12C5A4FC000091322 /* periodic_sampler.cc in Sources */, + E318DF6F2C5A4FBE00091322 /* unscaledcycleclock.cc in Sources */, + E318E1E72C5A4FC200091322 /* str_replace.cc in Sources */, + E318D99D2C59D0E600091322 /* imgui_stdlib.cpp in Sources */, + E318E07B2C5A4FC000091322 /* low_level_hash.cc in Sources */, + E318E19D2C5A4FC200091322 /* pow10_helper.cc in Sources */, + E318E1692C5A4FC100091322 /* cord_rep_btree_reader.cc in Sources */, + E318E0232C5A4FBF00091322 /* symbolize_emscripten.inc in Sources */, + E318D97F2C59C08300091322 /* sprite.cc in Sources */, + E318E1832C5A4FC100091322 /* cordz_info.cc in Sources */, + E318E7D02C5A55AE00091322 /* filter_neon.S in Sources */, + E318D9392C59C08300091322 /* dsp.cc in Sources */, + E318D9632C59C08300091322 /* canvas.cc in Sources */, + E318D95B2C59C08300091322 /* snes_palette.cc in Sources */, + E318E1092C5A4FC100091322 /* discrete_distribution.cc in Sources */, + E318D9572C59C08300091322 /* scad_format.cc in Sources */, + E318E0E32C5A4FC000091322 /* randen_hwaes.cc in Sources */, + E318D9092C59C08300091322 /* controller.cc in Sources */, + E318D9372C59C08300091322 /* apu.cc in Sources */, + E318E22D2C5A4FC300091322 /* time_zone_format.cc in Sources */, + E318E6FF2C5A4FC900091322 /* civil_time.cc in Sources */, + 83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */, + E318E1732C5A4FC100091322 /* cord_rep_crc.cc in Sources */, + E318E2332C5A4FC300091322 /* time_zone_info.cc in Sources */, + E318E16F2C5A4FC100091322 /* cord_rep_consume.cc in Sources */, + E36971E52CE18A2A00DEF2F6 /* file_util.cc in Sources */, + E318E1CF2C5A4FC200091322 /* match.cc in Sources */, + E318E02F2C5A4FBF00091322 /* flag_msvc.inc in Sources */, + E318DFFF2C5A4FBF00091322 /* stacktrace_generic-inl.inc in Sources */, + E318E1AB2C5A4FC200091322 /* ascii.cc in Sources */, + E318E7F92C5A8DE200091322 /* file_path.mm in Sources */, + E318E0E92C5A4FC000091322 /* randen_slow.cc in Sources */, + E318D9472C59C08300091322 /* dma.cc in Sources */, + E318E02B2C5A4FBF00091322 /* symbolize.cc in Sources */, + E318E7AF2C5A548C00091322 /* pngerror.c in Sources */, + E318E0132C5A4FBF00091322 /* failure_signal_handler.cc in Sources */, + E318E0752C5A4FC000091322 /* city.cc in Sources */, + E318E05B2C5A4FBF00091322 /* parse.cc in Sources */, + E318E6F72C5A4FC900091322 /* zoneinfo.inc in Sources */, + E318DFF92C5A4FBF00091322 /* stacktrace_aarch64-inl.inc in Sources */, + E318DF372C5A4FBE00091322 /* cycleclock.cc in Sources */, + 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, + E318E1512C5A4FC100091322 /* parser.cc in Sources */, + E318E1ED2C5A4FC200091322 /* str_split.cc in Sources */, + E318E7BB2C5A548C00091322 /* pngrtran.c in Sources */, + E318D9352C59C08300091322 /* instructions.cc in Sources */, + E318E0ED2C5A4FC000091322 /* randen.cc in Sources */, + E38A97F82C6C4CE3005FB662 /* settings_editor.cc in Sources */, + E318E7052C5A4FC900091322 /* clock.cc in Sources */, + E318DFA72C5A4FBE00091322 /* hashtablez_sampler.cc in Sources */, + E318E1F92C5A4FC200091322 /* substitute.cc in Sources */, + E318E05F2C5A4FBF00091322 /* reflection.cc in Sources */, + E318E7272C5A4FC900091322 /* bad_variant_access.cc in Sources */, + E318DFA32C5A4FBE00091322 /* hashtablez_sampler_force_weak_definition.cc in Sources */, + E318E18D2C5A4FC100091322 /* escaping.cc in Sources */, + E318E01D2C5A4FBF00091322 /* stacktrace.cc in Sources */, + E318E0DD2C5A4FC000091322 /* randen_detect.cc in Sources */, + E318E7B92C5A548C00091322 /* pngrio.c in Sources */, + E318E14D2C5A4FC100091322 /* output.cc in Sources */, + E318E0352C5A4FBF00091322 /* private_handle_accessor.cc in Sources */, + E318E0292C5A4FBF00091322 /* symbolize_win32.inc in Sources */, + E318E0392C5A4FBF00091322 /* program_name.cc in Sources */, + E318E0572C5A4FBF00091322 /* marshalling.cc in Sources */, + E318E7D72C5A55C300091322 /* arm_init.c in Sources */, + E318E21D2C5A4FC200091322 /* mutex.cc in Sources */, + E318E7B72C5A548C00091322 /* pngread.c in Sources */, + E318D91D2C59C08300091322 /* message_editor.cc in Sources */, + E318E7CB2C5A548C00091322 /* pngwutil.c in Sources */, + E318E1872C5A4FC100091322 /* cordz_sample_token.cc in Sources */, + E318DF4D2C5A4FBE00091322 /* spinlock_akaros.inc in Sources */, + E318E1B32C5A4FC200091322 /* charconv.cc in Sources */, + E318E1612C5A4FC100091322 /* cord_internal.cc in Sources */, + E318DF4B2C5A4FBE00091322 /* scoped_set_env.cc in Sources */, + E318E7232C5A4FC900091322 /* bad_any_cast.cc in Sources */, + E318E20B2C5A4FC200091322 /* barrier.cc in Sources */, + E318DF592C5A4FBE00091322 /* spinlock.cc in Sources */, + E318E7D42C5A55AE00091322 /* filter_neon_intrinsics.c in Sources */, + E318E1F32C5A4FC200091322 /* string_view.cc in Sources */, + 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */, + E318E1A52C5A4FC200091322 /* utf8.cc in Sources */, + E318D9272C59C08300091322 /* gfx_context.cc in Sources */, + E318D91F2C59C08300091322 /* music_editor.cc in Sources */, + E318D9672C59C08300091322 /* input.cc in Sources */, + 8309BDA5253CCC070045E2A1 /* main.mm in Sources */, + E318E6F32C5A4FC900091322 /* get_current_time_posix.inc in Sources */, + E318E71B2C5A4FC900091322 /* time.cc in Sources */, + E318D9172C59C08300091322 /* screen_editor.cc in Sources */, + E318E0652C5A4FBF00091322 /* usage.cc in Sources */, + E318E01F2C5A4FBF00091322 /* symbolize_darwin.inc in Sources */, + E318D9112C59C08300091322 /* gfx_group_editor.cc in Sources */, + E318E13F2C5A4FC100091322 /* bind.cc in Sources */, + E318E7C72C5A548C00091322 /* pngwrite.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8307E7D620E9F9C900473790 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E318E0E22C5A4FC000091322 /* randen_hwaes_test.cc in Sources */, + E318E7D52C5A55AE00091322 /* filter_neon_intrinsics.c in Sources */, + E318D9402C59C08300091322 /* instructions.cc in Sources */, + E318E1C22C5A4FC200091322 /* cord_test.cc in Sources */, + E318D9682C59C08300091322 /* input.cc in Sources */, + E318DF602C5A4FBE00091322 /* strerror.cc in Sources */, + E318E7C22C5A548C00091322 /* pngtest.c in Sources */, + E318D93A2C59C08300091322 /* dsp.cc in Sources */, + E318D9762C59C08300091322 /* tracker.cc in Sources */, + E318E23A2C5A4FC300091322 /* time_zone_lookup.cc in Sources */, + E318DF5C2C5A4FBE00091322 /* strerror_benchmark.cc in Sources */, + E318E0F42C5A4FC000091322 /* seed_material.cc in Sources */, + E318E2062C5A4FC200091322 /* per_thread_sem.cc in Sources */, + E318DFA62C5A4FBE00091322 /* hashtablez_sampler_test.cc in Sources */, + E318DFA02C5A4FBE00091322 /* hash_policy_testing_test.cc in Sources */, + E318E7102C5A4FC900091322 /* format_benchmark.cc in Sources */, + E318E1A22C5A4FC200091322 /* string_constant_test.cc in Sources */, + E318E1482C5A4FC100091322 /* extension.cc in Sources */, + E318E72E2C5A4FC900091322 /* compare_test.cc in Sources */, + E318E1AA2C5A4FC200091322 /* ascii_test.cc in Sources */, + E318E1E02C5A4FC200091322 /* str_join_benchmark.cc in Sources */, + E318E7182C5A4FC900091322 /* time_test.cc in Sources */, + E318E2082C5A4FC200091322 /* waiter.cc in Sources */, + E318E15E2C5A4FC100091322 /* charconv_parse.cc in Sources */, + E318E04C2C5A4FBF00091322 /* flag_benchmark.cc in Sources */, + E318E1A62C5A4FC200091322 /* utf8.cc in Sources */, + E318D94A2C59C08300091322 /* memory.cc in Sources */, + E318DF462C5A4FBE00091322 /* prefetch_test.cc in Sources */, + E318E0722C5A4FC000091322 /* function_type_benchmark.cc in Sources */, + E318E03E2C5A4FBF00091322 /* usage_test.cc in Sources */, + E318E0122C5A4FBF00091322 /* failure_signal_handler_test.cc in Sources */, + E318D9382C59C08300091322 /* apu.cc in Sources */, + E318E0B22C5A4FC000091322 /* periodic_sampler.cc in Sources */, + E318D96A2C59C08300091322 /* style.cc in Sources */, + E318DFAC2C5A4FBE00091322 /* layout_test.cc in Sources */, + E318E0BE2C5A4FC000091322 /* chi_square.cc in Sources */, + E318E0DC2C5A4FC000091322 /* randen_benchmarks.cc in Sources */, + E318E08C2C5A4FC000091322 /* memory_exception_safety_test.cc in Sources */, + E318E1CC2C5A4FC200091322 /* escaping.cc in Sources */, + E318E7222C5A4FC900091322 /* any_test.cc in Sources */, + E318E1FC2C5A4FC200091322 /* create_thread_identity.cc in Sources */, + 8309BDBE253CCCB60045E2A1 /* imgui_impl_metal.mm in Sources */, + E318DF3A2C5A4FBE00091322 /* endian_test.cc in Sources */, + E318D91E2C59C08300091322 /* message_editor.cc in Sources */, + E318E7042C5A4FC900091322 /* clock_test.cc in Sources */, + E318E0D02C5A4FC000091322 /* nanobenchmark_test.cc in Sources */, + E318E0FE2C5A4FC000091322 /* bernoulli_distribution_test.cc in Sources */, + E318E2262C5A4FC200091322 /* civil_time_detail.cc in Sources */, + E318E1F02C5A4FC200091322 /* string_view_benchmark.cc in Sources */, + E318DFB02C5A4FBE00091322 /* raw_hash_set_allocator_test.cc in Sources */, + E318D9442C59C08300091322 /* cpu.cc in Sources */, + E318E0682C5A4FC000091322 /* any_invocable_test.cc in Sources */, + E318E15C2C5A4FC100091322 /* charconv_parse_test.cc in Sources */, + E318E0342C5A4FBF00091322 /* path_util_test.cc in Sources */, + E318E0C62C5A4FC000091322 /* fast_uniform_bits_test.cc in Sources */, + E318DFC02C5A4FBE00091322 /* unordered_set_test.cc in Sources */, + E318E0D22C5A4FC000091322 /* nanobenchmark.cc in Sources */, + E318DFF82C5A4FBF00091322 /* stack_consumption.cc in Sources */, + E318DF622C5A4FBE00091322 /* sysinfo_test.cc in Sources */, + E318E19A2C5A4FC200091322 /* ostringstream.cc in Sources */, + E318D98E2C59CBBB00091322 /* TextEditor.cpp in Sources */, + E318D9522C59C08300091322 /* snes.cc in Sources */, + E318E0EC2C5A4FC000091322 /* randen_test.cc in Sources */, + E318E7C82C5A548C00091322 /* pngwrite.c in Sources */, + E318E7D32C5A55AE00091322 /* palette_neon_intrinsics.c in Sources */, + E318DFBE2C5A4FBE00091322 /* unordered_map_test.cc in Sources */, + E318E0F82C5A4FC000091322 /* uniform_helper_test.cc in Sources */, + E318E1DA2C5A4FC200091322 /* str_cat_test.cc in Sources */, + E318DFBA2C5A4FBE00091322 /* test_instance_tracker_test.cc in Sources */, + 83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */, + E318E1722C5A4FC100091322 /* cord_rep_crc_test.cc in Sources */, + E318E1362C5A4FC100091322 /* statusor_test.cc in Sources */, + E318E0382C5A4FBF00091322 /* program_name_test.cc in Sources */, + E318E0942C5A4FC000091322 /* type_traits_test.cc in Sources */, + E318DF382C5A4FBE00091322 /* cycleclock.cc in Sources */, + E318E7342C5A4FC900091322 /* span_test.cc in Sources */, + E318DF702C5A4FBE00091322 /* unscaledcycleclock.cc in Sources */, + E318D9282C59C08300091322 /* gfx_context.cc in Sources */, + E318E0962C5A4FC000091322 /* bits_benchmark.cc in Sources */, + E318D9342C59C08300091322 /* addressing.cc in Sources */, + E318DF2E2C5A4FBD00091322 /* container_test.cc in Sources */, + E318E1E42C5A4FC200091322 /* str_replace_benchmark.cc in Sources */, + E318E14A2C5A4FC100091322 /* float_conversion.cc in Sources */, + E318D9422C59C08300091322 /* old_cpu.cc in Sources */, + E318E0A42C5A4FC000091322 /* int128_stream_test.cc in Sources */, + E318DF5E2C5A4FBE00091322 /* strerror_test.cc in Sources */, + E318DFF62C5A4FBF00091322 /* stack_consumption_test.cc in Sources */, + E318E23C2C5A4FC300091322 /* time_zone_posix.cc in Sources */, + E318DF4A2C5A4FBE00091322 /* scoped_set_env_test.cc in Sources */, + E318E1682C5A4FC100091322 /* cord_rep_btree_reader_test.cc in Sources */, + E318E0C02C5A4FC000091322 /* distribution_test_util_test.cc in Sources */, + E318E7FA2C5A8DE200091322 /* file_path.mm in Sources */, + E318DF942C5A4FBE00091322 /* cleanup_test.cc in Sources */, + E318D95C2C59C08300091322 /* snes_palette.cc in Sources */, + E318DFD82C5A4FBF00091322 /* inlined_vector_test.cc in Sources */, + 83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */, + E318D9142C59C08300091322 /* graphics_editor.cc in Sources */, + E318E0762C5A4FC000091322 /* city.cc in Sources */, + E318E1982C5A4FC100091322 /* ostringstream_test.cc in Sources */, + E318E1162C5A4FC100091322 /* generators_test.cc in Sources */, + E318E0162C5A4FBF00091322 /* leak_check_fail_test.cc in Sources */, + E318E7D12C5A55AE00091322 /* filter_neon.S in Sources */, + E318E05A2C5A4FBF00091322 /* parse_test.cc in Sources */, + E318D9222C59C08300091322 /* entity.cc in Sources */, + E318E7362C5A4FC900091322 /* variant_benchmark.cc in Sources */, + E318DFB62C5A4FBE00091322 /* raw_hash_set_test.cc in Sources */, + E318DFCA2C5A4FBE00091322 /* fixed_array_benchmark.cc in Sources */, + E318E10A2C5A4FC100091322 /* discrete_distribution.cc in Sources */, + E318E2342C5A4FC300091322 /* time_zone_info.cc in Sources */, + E318DFF42C5A4FBF00091322 /* examine_stack.cc in Sources */, + E318E21A2C5A4FC200091322 /* mutex_benchmark.cc in Sources */, + E318D8FE2C59C08300091322 /* clipboard.cc in Sources */, + E318E1D42C5A4FC200091322 /* numbers_test.cc in Sources */, + E318E07C2C5A4FC000091322 /* low_level_hash.cc in Sources */, + E318E21E2C5A4FC200091322 /* mutex.cc in Sources */, + E318DF822C5A4FBE00091322 /* inline_variable_test.cc in Sources */, + E318D98A2C59C08300091322 /* yaze.cc in Sources */, + E318D99E2C59D0E600091322 /* imgui_stdlib.cpp in Sources */, + E318DF4C2C5A4FBE00091322 /* scoped_set_env.cc in Sources */, + E318E0562C5A4FBF00091322 /* marshalling_test.cc in Sources */, + E318E1B02C5A4FC200091322 /* charconv_benchmark.cc in Sources */, + E318E1082C5A4FC100091322 /* discrete_distribution_test.cc in Sources */, + E318E2202C5A4FC200091322 /* notification_test.cc in Sources */, + E318DF402C5A4FBE00091322 /* fast_type_id_test.cc in Sources */, + E318E16A2C5A4FC100091322 /* cord_rep_btree_reader.cc in Sources */, + E318E11A2C5A4FC100091322 /* mock_distributions_test.cc in Sources */, + E36971DA2CE189EA00DEF2F6 /* project.cc in Sources */, + E318E0602C5A4FBF00091322 /* reflection.cc in Sources */, + E318DF882C5A4FBE00091322 /* log_severity.cc in Sources */, + E318DF302C5A4FBD00091322 /* equal_benchmark.cc in Sources */, + E318DF722C5A4FBE00091322 /* bit_cast_test.cc in Sources */, + E318E0702C5A4FC000091322 /* function_ref_test.cc in Sources */, + E318E09E2C5A4FC000091322 /* int128_benchmark.cc in Sources */, + E318E7B62C5A548C00091322 /* pngpread.c in Sources */, + E318D9582C59C08300091322 /* scad_format.cc in Sources */, + E318DFF02C5A4FBF00091322 /* demangle.cc in Sources */, + E318D90A2C59C08300091322 /* controller.cc in Sources */, + E318E1B82C5A4FC200091322 /* cord_analysis.cc in Sources */, + E318E1BA2C5A4FC200091322 /* cord_buffer_test.cc in Sources */, + E318DFEE2C5A4FBF00091322 /* demangle_test.cc in Sources */, + E318E1882C5A4FC100091322 /* cordz_sample_token.cc in Sources */, + E318DFDE2C5A4FBF00091322 /* sample_element_size_test.cc in Sources */, + E318E0622C5A4FBF00091322 /* usage_config_test.cc in Sources */, + E318E6FE2C5A4FC900091322 /* civil_time_test.cc in Sources */, + E318E1EC2C5A4FC200091322 /* str_split_test.cc in Sources */, + E318E70C2C5A4FC900091322 /* duration_test.cc in Sources */, + E318E7AE2C5A548C00091322 /* png.c in Sources */, + E318E7382C5A4FC900091322 /* variant_exception_safety_test.cc in Sources */, + E318E0A62C5A4FC000091322 /* int128_test.cc in Sources */, + E318DFCC2C5A4FBE00091322 /* fixed_array_exception_safety_test.cc in Sources */, + E318DF762C5A4FBE00091322 /* call_once_test.cc in Sources */, + E318D90E2C59C08300091322 /* assembly_editor.cc in Sources */, + E318DF8C2C5A4FBE00091322 /* raw_logging_test.cc in Sources */, + E318DFC42C5A4FBE00091322 /* btree_test.cc in Sources */, + E318DFDC2C5A4FBF00091322 /* node_hash_set_test.cc in Sources */, + E318E1D82C5A4FC200091322 /* str_cat_benchmark.cc in Sources */, + E318D9062C59C08300091322 /* font_loader.mm in Sources */, + E318E1702C5A4FC100091322 /* cord_rep_consume.cc in Sources */, + E318E0FA2C5A4FC000091322 /* wide_multiply_test.cc in Sources */, + E318E0AA2C5A4FC000091322 /* exponential_biased_test.cc in Sources */, + E318E1202C5A4FC100091322 /* seed_gen_exception.cc in Sources */, + E318E10E2C5A4FC100091322 /* examples_test.cc in Sources */, + E318E1CA2C5A4FC200091322 /* escaping_test.cc in Sources */, + E318E1642C5A4FC100091322 /* cord_rep_btree_navigator_test.cc in Sources */, + 83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */, + E318D9802C59C08300091322 /* sprite.cc in Sources */, + E318E1C42C5A4FC200091322 /* cord.cc in Sources */, + E318D9542C59C08300091322 /* bitmap.cc in Sources */, + E318DFA42C5A4FBE00091322 /* hashtablez_sampler_force_weak_definition.cc in Sources */, + E318E05C2C5A4FBF00091322 /* parse.cc in Sources */, + E318E7C62C5A548C00091322 /* pngwio.c in Sources */, + E318E1022C5A4FC000091322 /* bit_gen_ref_test.cc in Sources */, + E318E0B02C5A4FC000091322 /* periodic_sampler_test.cc in Sources */, + E318E7B22C5A548C00091322 /* pngget.c in Sources */, + E318E0862C5A4FC000091322 /* hash_test.cc in Sources */, + E318E19C2C5A4FC200091322 /* pow10_helper_test.cc in Sources */, + E318E7B42C5A548C00091322 /* pngmem.c in Sources */, + E318DF562C5A4FBE00091322 /* spinlock_wait.cc in Sources */, + E318E7122C5A4FC900091322 /* format_test.cc in Sources */, + E318E2242C5A4FC200091322 /* cctz_benchmark.cc in Sources */, + E318E0362C5A4FBF00091322 /* private_handle_accessor.cc in Sources */, + E318D9202C59C08300091322 /* music_editor.cc in Sources */, + E318D97A2C59C08300091322 /* overworld.cc in Sources */, + E318E1F62C5A4FC200091322 /* strip_test.cc in Sources */, + E318E0A82C5A4FC000091322 /* int128.cc in Sources */, + E318E1002C5A4FC000091322 /* beta_distribution_test.cc in Sources */, + E318E1962C5A4FC100091322 /* ostringstream_benchmark.cc in Sources */, + E318D9482C59C08300091322 /* dma.cc in Sources */, + E318E16E2C5A4FC100091322 /* cord_rep_btree.cc in Sources */, + E318E0D82C5A4FC000091322 /* pool_urbg_test.cc in Sources */, + E318E7D82C5A55C300091322 /* arm_init.c in Sources */, + E318E0782C5A4FC000091322 /* hash.cc in Sources */, + E318E11C2C5A4FC100091322 /* mocking_bit_gen_test.cc in Sources */, + E318E18E2C5A4FC100091322 /* escaping.cc in Sources */, + E318E0CC2C5A4FC000091322 /* generate_real_test.cc in Sources */, + E318E1A02C5A4FC200091322 /* resize_uninitialized_test.cc in Sources */, + E318DF322C5A4FBD00091322 /* atomic_hook_test_helper.cc in Sources */, + E318E1C82C5A4FC200091322 /* escaping_benchmark.cc in Sources */, + E318E1A42C5A4FC200091322 /* utf8_test.cc in Sources */, + E318E1542C5A4FC100091322 /* char_map_benchmark.cc in Sources */, + E318E0982C5A4FC000091322 /* bits_test.cc in Sources */, + E318E1E22C5A4FC200091322 /* str_join_test.cc in Sources */, + E318E0F62C5A4FC000091322 /* traits_test.cc in Sources */, + E318E05E2C5A4FBF00091322 /* reflection_test.cc in Sources */, + E318E1222C5A4FC100091322 /* seed_sequences_test.cc in Sources */, + E318D9642C59C08300091322 /* canvas.cc in Sources */, + E318DFB42C5A4FBE00091322 /* raw_hash_set_probe_benchmark.cc in Sources */, + E318E00C2C5A4FBF00091322 /* vdso_support.cc in Sources */, + E318E01E2C5A4FBF00091322 /* stacktrace.cc in Sources */, + E318E2382C5A4FC300091322 /* time_zone_lookup_test.cc in Sources */, + E318DFAE2C5A4FBE00091322 /* node_slot_policy_test.cc in Sources */, + E318E02C2C5A4FBF00091322 /* symbolize.cc in Sources */, + E318E7242C5A4FC900091322 /* bad_any_cast.cc in Sources */, + E318DFCE2C5A4FBF00091322 /* fixed_array_test.cc in Sources */, + E318E0742C5A4FC000091322 /* city_test.cc in Sources */, + E318E2182C5A4FC200091322 /* lifetime_test.cc in Sources */, + E318E01C2C5A4FBF00091322 /* stacktrace_benchmark.cc in Sources */, + E318E7262C5A4FC900091322 /* bad_optional_access.cc in Sources */, + E318E0642C5A4FBF00091322 /* usage_config.cc in Sources */, + E318E2102C5A4FC200091322 /* blocking_counter_test.cc in Sources */, + E318E0322C5A4FBF00091322 /* flag.cc in Sources */, + E318E0522C5A4FBF00091322 /* flag_test.cc in Sources */, + E318E1BE2C5A4FC200091322 /* cord_ring_reader_test.cc in Sources */, + E318D9962C59CDF800091322 /* imgui_impl_sdl2.cpp in Sources */, + E318DF642C5A4FBE00091322 /* sysinfo.cc in Sources */, + E318DF862C5A4FBE00091322 /* log_severity_test.cc in Sources */, + E318E1442C5A4FC100091322 /* convert_test.cc in Sources */, + E318DF8E2C5A4FBE00091322 /* spinlock_test_common.cc in Sources */, + E318E17A2C5A4FC100091322 /* cordz_functions.cc in Sources */, + E318E7CC2C5A548C00091322 /* pngwutil.c in Sources */, + E318E2282C5A4FC200091322 /* civil_time_test.cc in Sources */, + E318D9502C59C08300091322 /* emulator.cc in Sources */, + E318DFB82C5A4FBE00091322 /* raw_hash_set.cc in Sources */, + E318D96C2C59C08300091322 /* zeml.cc in Sources */, + E318D97C2C59C08300091322 /* inventory.cc in Sources */, + E318D9162C59C08300091322 /* palette_editor.cc in Sources */, + E318DF342C5A4FBD00091322 /* atomic_hook_test.cc in Sources */, + E318D97E2C59C08300091322 /* title_screen.cc in Sources */, + E318E7202C5A4FC900091322 /* any_exception_safety_test.cc in Sources */, + E318E01A2C5A4FBF00091322 /* leak_check.cc in Sources */, + E318D99A2C59D0C400091322 /* imgui_impl_sdlrenderer2.cpp in Sources */, + E318E0AE2C5A4FC000091322 /* periodic_sampler_benchmark.cc in Sources */, + E318DF442C5A4FBE00091322 /* low_level_alloc.cc in Sources */, + E318E0EE2C5A4FC000091322 /* randen.cc in Sources */, + E318E1EA2C5A4FC200091322 /* str_split_benchmark.cc in Sources */, + E318E11E2C5A4FC100091322 /* poisson_distribution_test.cc in Sources */, + E318E1342C5A4FC100091322 /* status.cc in Sources */, + E318DFD22C5A4FBF00091322 /* flat_hash_set_test.cc in Sources */, + E318DF7E2C5A4FBE00091322 /* inline_variable_test_a.cc in Sources */, + E318E2042C5A4FC200091322 /* per_thread_sem_test.cc in Sources */, + E318E1302C5A4FC100091322 /* status_payload_printer.cc in Sources */, + E318E71E2C5A4FC900091322 /* conformance_testing_test.cc in Sources */, + E318D95E2C59C08300091322 /* snes_tile.cc in Sources */, + E318E7162C5A4FC900091322 /* time_benchmark.cc in Sources */, + E318D93E2C59C08300091322 /* addressing.cc in Sources */, + E318D9002C59C08300091322 /* clipboard.mm in Sources */, + E318E7C42C5A548C00091322 /* pngtrans.c in Sources */, + E318E1EE2C5A4FC200091322 /* str_split.cc in Sources */, + E318E0C22C5A4FC000091322 /* distribution_test_util.cc in Sources */, + E318E7142C5A4FC900091322 /* format.cc in Sources */, + E318E14C2C5A4FC100091322 /* output_test.cc in Sources */, + E318E1862C5A4FC100091322 /* cordz_sample_token_test.cc in Sources */, + E318E1822C5A4FC100091322 /* cordz_info_test.cc in Sources */, + E318E2002C5A4FC200091322 /* graphcycles_test.cc in Sources */, + E318E0E42C5A4FC000091322 /* randen_hwaes.cc in Sources */, + E318E1502C5A4FC100091322 /* parser_test.cc in Sources */, + E318D9182C59C08300091322 /* screen_editor.cc in Sources */, + E318E0CA2C5A4FC000091322 /* gaussian_distribution_gentables.cc in Sources */, + E318E20C2C5A4FC200091322 /* barrier.cc in Sources */, + E318E1E62C5A4FC200091322 /* str_replace_test.cc in Sources */, + E318E0D42C5A4FC000091322 /* nonsecure_base_test.cc in Sources */, + E318E1522C5A4FC100091322 /* parser.cc in Sources */, + E318E1902C5A4FC100091322 /* memutil_benchmark.cc in Sources */, + E318D95A2C59C08300091322 /* snes_color.cc in Sources */, + E318DF3E2C5A4FBE00091322 /* exception_safety_testing.cc in Sources */, + E318E1C02C5A4FC200091322 /* cord_ring_test.cc in Sources */, + E318DF362C5A4FBE00091322 /* cmake_thread_test.cc in Sources */, + E318E2022C5A4FC200091322 /* graphcycles.cc in Sources */, + E318E22C2C5A4FC300091322 /* time_zone_format_test.cc in Sources */, + E318E0F02C5A4FC000091322 /* salted_seed_seq_test.cc in Sources */, + E318E0662C5A4FBF00091322 /* usage.cc in Sources */, + E318E0142C5A4FBF00091322 /* failure_signal_handler.cc in Sources */, + E318E1182C5A4FC100091322 /* log_uniform_int_distribution_test.cc in Sources */, + E318E1942C5A4FC100091322 /* memutil.cc in Sources */, + E318E13A2C5A4FC100091322 /* arg_test.cc in Sources */, + E318E2222C5A4FC200091322 /* notification.cc in Sources */, + E318E02E2C5A4FBF00091322 /* commandlineflag.cc in Sources */, + E318DF3C2C5A4FBE00091322 /* errno_saver_test.cc in Sources */, + E318E18A2C5A4FC100091322 /* cordz_update_scope_test.cc in Sources */, + E318E7302C5A4FC900091322 /* optional_exception_safety_test.cc in Sources */, + E318D9882C59C08300091322 /* rom.cc in Sources */, + E318E1282C5A4FC100091322 /* uniform_real_distribution_test.cc in Sources */, + E318E19E2C5A4FC200091322 /* pow10_helper.cc in Sources */, + E318E0462C5A4FBF00091322 /* commandlineflag_test.cc in Sources */, + E318E0AC2C5A4FC000091322 /* exponential_biased.cc in Sources */, + E318DF9E2C5A4FBE00091322 /* hash_generator_testing.cc in Sources */, + E318E7B02C5A548C00091322 /* pngerror.c in Sources */, + E318E20A2C5A4FC200091322 /* barrier_test.cc in Sources */, + E318DF6A2C5A4FBE00091322 /* thread_identity.cc in Sources */, + E318DF802C5A4FBE00091322 /* inline_variable_test_b.cc in Sources */, + E318E7322C5A4FC900091322 /* optional_test.cc in Sources */, + E318E1782C5A4FC100091322 /* cordz_functions_test.cc in Sources */, + E318DF682C5A4FBE00091322 /* thread_identity_test.cc in Sources */, + E318E1922C5A4FC100091322 /* memutil_test.cc in Sources */, + E318DF8A2C5A4FBE00091322 /* optimization_test.cc in Sources */, + E318DFD62C5A4FBF00091322 /* inlined_vector_exception_safety_test.cc in Sources */, + E318E22A2C5A4FC200091322 /* time_zone_fixed.cc in Sources */, + E318E70E2C5A4FC900091322 /* duration.cc in Sources */, + E34C789C2C5882A100A6C275 /* imgui_tables.cpp in Sources */, + E318E0E82C5A4FC000091322 /* randen_slow_test.cc in Sources */, + E318E08E2C5A4FC000091322 /* memory_test.cc in Sources */, + E318E0F22C5A4FC000091322 /* seed_material_test.cc in Sources */, + E318E1F82C5A4FC200091322 /* substitute_test.cc in Sources */, + E318D9662C59C08300091322 /* color.cc in Sources */, + E318E0FC2C5A4FC000091322 /* benchmarks.cc in Sources */, + E318E7002C5A4FC900091322 /* civil_time.cc in Sources */, + E318E17E2C5A4FC100091322 /* cordz_handle.cc in Sources */, + E318DF842C5A4FBE00091322 /* invoke_test.cc in Sources */, + E318E1422C5A4FC100091322 /* checker_test.cc in Sources */, + E318E1B22C5A4FC200091322 /* charconv_test.cc in Sources */, + E318E1BC2C5A4FC200091322 /* cord_buffer.cc in Sources */, + E318D9082C59C08300091322 /* common.cc in Sources */, + E318E1DE2C5A4FC200091322 /* str_format_test.cc in Sources */, + E318E71C2C5A4FC900091322 /* time.cc in Sources */, + E318DFA82C5A4FBE00091322 /* hashtablez_sampler.cc in Sources */, + E318E1122C5A4FC100091322 /* gaussian_distribution_test.cc in Sources */, + E318D93C2C59C08300091322 /* spc700.cc in Sources */, + E318E2322C5A4FC300091322 /* time_zone_impl.cc in Sources */, + E318E0B42C5A4FC000091322 /* sample_recorder_test.cc in Sources */, + E318D9702C59C08300091322 /* room_object.cc in Sources */, + E318E0E62C5A4FC000091322 /* randen_round_keys.cc in Sources */, + E318E0482C5A4FBF00091322 /* commandlineflag.cc in Sources */, + E318E0DA2C5A4FC000091322 /* pool_urbg.cc in Sources */, + E318E1A82C5A4FC200091322 /* ascii_benchmark.cc in Sources */, + 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */, + E318E7062C5A4FC900091322 /* clock.cc in Sources */, + E318DFF22C5A4FBF00091322 /* elf_mem_image.cc in Sources */, + E318E0E02C5A4FC000091322 /* randen_engine_test.cc in Sources */, + E318DFDA2C5A4FBF00091322 /* node_hash_map_test.cc in Sources */, + E318D9022C59C08300091322 /* file_dialog.mm in Sources */, + E318E73A2C5A4FC900091322 /* variant_test.cc in Sources */, + E318D96E2C59C08300091322 /* object_renderer.cc in Sources */, + E318E1142C5A4FC100091322 /* gaussian_distribution.cc in Sources */, + E318E1F22C5A4FC200091322 /* string_view_test.cc in Sources */, + E318E0182C5A4FBF00091322 /* leak_check_test.cc in Sources */, + E318D9102C59C08300091322 /* dungeon_editor.cc in Sources */, + 8309BDA8253CCC080045E2A1 /* main.mm in Sources */, + E318E1242C5A4FC100091322 /* seed_sequences.cc in Sources */, + E318D9562C59C08300091322 /* compression.cc in Sources */, + E318E7BA2C5A548C00091322 /* pngrio.c in Sources */, + E318DFD02C5A4FBF00091322 /* flat_hash_map_test.cc in Sources */, + E318E1322C5A4FC100091322 /* status_test.cc in Sources */, + E318DFEC2C5A4FBF00091322 /* address_is_readable.cc in Sources */, + E318E07E2C5A4FC000091322 /* print_hash_of.cc in Sources */, + E318E06A2C5A4FC000091322 /* bind_front_test.cc in Sources */, + E318DFAA2C5A4FBE00091322 /* layout_benchmark.cc in Sources */, + E318DFD42C5A4FBF00091322 /* inlined_vector_benchmark.cc in Sources */, + E318E17C2C5A4FC100091322 /* cordz_handle_test.cc in Sources */, + E318E2122C5A4FC200091322 /* blocking_counter.cc in Sources */, + E318DF982C5A4FBE00091322 /* compressed_tuple_test.cc in Sources */, + E318E20E2C5A4FC200091322 /* blocking_counter_benchmark.cc in Sources */, + E318E7282C5A4FC900091322 /* bad_variant_access.cc in Sources */, + E318D9042C59C08300091322 /* font_loader.cc in Sources */, + E318D9602C59C08300091322 /* tilesheet.cc in Sources */, + E318E12A2C5A4FC100091322 /* zipf_distribution_test.cc in Sources */, + E318E1D02C5A4FC200091322 /* match.cc in Sources */, + E318E1602C5A4FC100091322 /* cord_data_edge_test.cc in Sources */, + E318E21C2C5A4FC200091322 /* mutex_test.cc in Sources */, + E318E1FA2C5A4FC200091322 /* substitute.cc in Sources */, + E318DF662C5A4FBE00091322 /* thread_identity_benchmark.cc in Sources */, + E318DFBC2C5A4FBE00091322 /* test_instance_tracker.cc in Sources */, + E318E1C62C5A4FC200091322 /* cordz_test.cc in Sources */, + E318E04A2C5A4FBF00091322 /* config_test.cc in Sources */, + E318E0402C5A4FBF00091322 /* usage.cc in Sources */, + E318D9362C59C08300091322 /* instructions.cc in Sources */, + E318E6FC2C5A4FC900091322 /* civil_time_benchmark.cc in Sources */, + E318DFA22C5A4FBE00091322 /* hash_policy_traits_test.cc in Sources */, + E318E7BE2C5A548C00091322 /* pngrutil.c in Sources */, + E318E0262C5A4FBF00091322 /* symbolize_test.cc in Sources */, + E318E16C2C5A4FC100091322 /* cord_rep_btree_test.cc in Sources */, + E318DF6E2C5A4FBE00091322 /* unique_small_name_test.cc in Sources */, + E318E7402C5A4FCA00091322 /* utility_test.cc in Sources */, + E318E1462C5A4FC100091322 /* extension_test.cc in Sources */, + E318E7B82C5A548C00091322 /* pngread.c in Sources */, + E318E03C2C5A4FBF00091322 /* sequence_lock_test.cc in Sources */, + E318D9782C59C08300091322 /* overworld_map.cc in Sources */, + E318E22E2C5A4FC300091322 /* time_zone_format.cc in Sources */, + E318E7C02C5A548C00091322 /* pngset.c in Sources */, + E318E07A2C5A4FC000091322 /* low_level_hash_test.cc in Sources */, + E318E1DC2C5A4FC200091322 /* str_cat.cc in Sources */, + E318E1D62C5A4FC200091322 /* numbers.cc in Sources */, + E318E1B42C5A4FC200091322 /* charconv.cc in Sources */, + E318E13E2C5A4FC100091322 /* bind_test.cc in Sources */, + E318DF902C5A4FBE00091322 /* throw_delegate_test.cc in Sources */, + E318E78E2C5A536400091322 /* ImGuiFileDialog.cpp in Sources */, + E318DF502C5A4FBE00091322 /* spinlock_benchmark.cc in Sources */, + E318E1382C5A4FC100091322 /* statusor.cc in Sources */, + E318E1AC2C5A4FC200091322 /* ascii.cc in Sources */, + E318E2362C5A4FC300091322 /* time_zone_libc.cc in Sources */, + E318E0DE2C5A4FC000091322 /* randen_detect.cc in Sources */, + E318DF9C2C5A4FBE00091322 /* hash_function_defaults_test.cc in Sources */, + E318E1582C5A4FC100091322 /* charconv_bigint_test.cc in Sources */, + E318E71A2C5A4FC900091322 /* time_zone_test.cc in Sources */, + E318E1D22C5A4FC200091322 /* numbers_benchmark.cc in Sources */, + E36971E42CE18A2A00DEF2F6 /* file_util.cc in Sources */, + E318E1FE2C5A4FC200091322 /* graphcycles_benchmark.cc in Sources */, + E318DF282C5A4FBD00091322 /* algorithm_test.cc in Sources */, + E318E0EA2C5A4FC000091322 /* randen_slow.cc in Sources */, + E318D9722C59C08300091322 /* room.cc in Sources */, + E318E1E82C5A4FC200091322 /* str_replace.cc in Sources */, + E318D9122C59C08300091322 /* gfx_group_editor.cc in Sources */, + E318E1F42C5A4FC200091322 /* string_view.cc in Sources */, + E318D9262C59C08300091322 /* sprite_editor.cc in Sources */, + E318E18C2C5A4FC100091322 /* cordz_update_tracker_test.cc in Sources */, + E318E0842C5A4FC000091322 /* hash_benchmark.cc in Sources */, + E318E1762C5A4FC100091322 /* cord_rep_ring.cc in Sources */, + E318E14E2C5A4FC100091322 /* output.cc in Sources */, + E318E0542C5A4FBF00091322 /* flag.cc in Sources */, + E318E15A2C5A4FC100091322 /* charconv_bigint.cc in Sources */, + E318DFC22C5A4FBE00091322 /* btree_benchmark.cc in Sources */, + E318E0BC2C5A4FC000091322 /* chi_square_test.cc in Sources */, + E318E1262C5A4FC100091322 /* uniform_int_distribution_test.cc in Sources */, + E318E1562C5A4FC100091322 /* char_map_test.cc in Sources */, + E318E03A2C5A4FBF00091322 /* program_name.cc in Sources */, + E318E1842C5A4FC100091322 /* cordz_info.cc in Sources */, + E318E7BC2C5A548C00091322 /* pngrtran.c in Sources */, + E318E1802C5A4FC100091322 /* cordz_info_statistics_test.cc in Sources */, + E318E0CE2C5A4FC000091322 /* iostream_state_saver_test.cc in Sources */, + E318E6F62C5A4FC900091322 /* test_util.cc in Sources */, + E318DF422C5A4FBE00091322 /* low_level_alloc_test.cc in Sources */, + E318D8FC2C59C08300091322 /* app_delegate.mm in Sources */, + E318E1402C5A4FC100091322 /* bind.cc in Sources */, + E318E1622C5A4FC100091322 /* cord_internal.cc in Sources */, + E318E0D62C5A4FC000091322 /* pcg_engine_test.cc in Sources */, + E318E23E2C5A4FC300091322 /* zone_info_source.cc in Sources */, + E318E0502C5A4FBF00091322 /* flag_test_defs.cc in Sources */, + E318E1CE2C5A4FC200091322 /* match_test.cc in Sources */, + E318E1102C5A4FC100091322 /* exponential_distribution_test.cc in Sources */, + E318E0582C5A4FBF00091322 /* marshalling.cc in Sources */, + E318DF6C2C5A4FBE00091322 /* throw_delegate.cc in Sources */, + E318DF7A2C5A4FBE00091322 /* config_test.cc in Sources */, + E318E7022C5A4FC900091322 /* clock_benchmark.cc in Sources */, + E318D91A2C59C08300091322 /* tile16_editor.cc in Sources */, + E318DF7C2C5A4FBE00091322 /* exception_safety_testing_test.cc in Sources */, + E318E0C82C5A4FC000091322 /* fastmath_test.cc in Sources */, + E318E10C2C5A4FC100091322 /* distributions_test.cc in Sources */, + E318DF482C5A4FBE00091322 /* raw_logging.cc in Sources */, + E318E1742C5A4FC100091322 /* cord_rep_crc.cc in Sources */, + E318E7CA2C5A548C00091322 /* pngwtran.c in Sources */, + E318DF9A2C5A4FBE00091322 /* container_memory_test.cc in Sources */, + E318DF5A2C5A4FBE00091322 /* spinlock.cc in Sources */, + E318E1662C5A4FC100091322 /* cord_rep_btree_navigator.cc in Sources */, + E318E13C2C5A4FC100091322 /* arg.cc in Sources */, + E318DFB22C5A4FBE00091322 /* raw_hash_set_benchmark.cc in Sources */, + E318E0C42C5A4FC000091322 /* explicit_seed_seq_test.cc in Sources */, + E318E70A2C5A4FC900091322 /* duration_benchmark.cc in Sources */, + E318D94C2C59C08300091322 /* ppu.cc in Sources */, + E318E2302C5A4FC300091322 /* time_zone_if.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8307E7EE20E9F9C900473790 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 8307E7EF20E9F9C900473790 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + }; + name = Release; + }; + 8307E7F120E9F9C900473790 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = yaze; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = SN8Z922TT6; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = c17; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + "YAZE_LIB_PNG=1", + ); + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( + "DEBUG=1", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "Yet Another Zelda3 Editor"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; + INFOPLIST_KEY_UISupportsDocumentBrowser = YES; + INFOPLIST_PREPROCESSOR_DEFINITIONS = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 0.2.0; + OTHER_LDFLAGS = ""; + PRODUCT_BUNDLE_IDENTIFIER = "org.halext.yaze-ios"; + PRODUCT_NAME = yaze; + SDKROOT = iphoneos; + SWIFT_OBJC_BRIDGING_HEADER = "iOS/yaze_ios-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYSTEM_HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../lib/SDL/include\"", + /Users/scawful/Code/lpng1643, + ); + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../app\"", + "\"$(SRCROOT)/../lib/abseil-cpp\"", + "\"$(SRCROOT)/../\"", + "\"$(SRCROOT)/../lib\"", + "\"$(SRCROOT)/../lib/abseil-cpp\"", + "\"$(SRCROOT)/../lib/imgui\"", + ); + }; + name = Debug; + }; + 8307E7F220E9F9C900473790 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = yaze; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = SN8Z922TT6; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = c17; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "Yet Another Zelda3 Editor"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; + INFOPLIST_KEY_UISupportsDocumentBrowser = YES; + INFOPLIST_PREPROCESSOR_DEFINITIONS = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 0.2.0; + OTHER_LDFLAGS = ""; + PRODUCT_BUNDLE_IDENTIFIER = "org.halext.yaze-ios"; + PRODUCT_NAME = yaze; + SDKROOT = iphoneos; + SWIFT_OBJC_BRIDGING_HEADER = "iOS/yaze_ios-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + SYSTEM_HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../lib/SDL/include\"", + /Users/scawful/Code/lpng1643, + ); + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../app\"", + "\"$(SRCROOT)/../lib/abseil-cpp\"", + "\"$(SRCROOT)/../\"", + "\"$(SRCROOT)/../lib\"", + "\"$(SRCROOT)/../lib/abseil-cpp\"", + "\"$(SRCROOT)/../lib/imgui\"", + ); + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8307E7F420E9F9C900473790 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = yaze; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = SN8Z922TT6; + INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.halext.yaze-macos"; + PRODUCT_NAME = yaze; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../**"; + }; + name = Debug; + }; + 8307E7F520E9F9C900473790 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = yaze; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = SN8Z922TT6; + INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.halext.yaze-macos"; + PRODUCT_NAME = yaze; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../**"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8307E7B920E9F9C700473790 /* Build configuration list for PBXProject "yaze" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8307E7EE20E9F9C900473790 /* Debug */, + 8307E7EF20E9F9C900473790 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8307E7F020E9F9C900473790 /* Build configuration list for PBXNativeTarget "yaze_ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8307E7F120E9F9C900473790 /* Debug */, + 8307E7F220E9F9C900473790 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8307E7F320E9F9C900473790 /* Build configuration list for PBXNativeTarget "yaze_macos" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8307E7F420E9F9C900473790 /* Debug */, + 8307E7F520E9F9C900473790 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8307E7B620E9F9C700473790 /* Project object */; +} diff --git a/src/ios/yaze.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/ios/yaze.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..a929b724 --- /dev/null +++ b/src/ios/yaze.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..0c67376e --- /dev/null +++ b/src/ios/yaze.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/Bookmarks/bookmarks.plist b/src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/Bookmarks/bookmarks.plist new file mode 100644 index 00000000..d359a542 --- /dev/null +++ b/src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/Bookmarks/bookmarks.plist @@ -0,0 +1,131 @@ + + + + + top-level-items + + + children + + + children + + + destination + + rebasable-url + + base + workspace + payload + + relative-path + iOS/LaunchScreen.storyboard + + + type + DVTDocumentLocation + + type + bookmark + + + destination + + rebasable-url + + base + workspace + payload + + relative-path + iOS/Info-iOS.plist + + + type + DVTDocumentLocation + + type + bookmark + + + title + iOS + type + group + + + children + + + destination + + rebasable-url + + base + workspace + payload + + relative-path + macOS/MainMenu.storyboard + + + type + DVTDocumentLocation + + type + bookmark + + + destination + + rebasable-url + + base + workspace + payload + + relative-path + macOS/Info-macOS.plist + + + type + DVTDocumentLocation + + type + bookmark + + + title + macOS + type + group + + + destination + + rebasable-url + + base + workspace + payload + + relative-path + main.mm + + + type + DVTDocumentLocation + + type + bookmark + + + title + yaze-ios + type + group + + + + diff --git a/src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/UserInterfaceState.xcuserstate b/src/ios/yaze.xcodeproj/project.xcworkspace/xcuserdata/scawful.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..80bffebbf79f10b674e4c2ebb2c8a195c8e38e97 GIT binary patch literal 407072 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ⅅophfpf>x>!zXfErDpRz^d) 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

!3cU(~?Y#w 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 + + + + BuildLocationStyle + UseAppPreferences + CustomBuildLocationType + RelativeToDerivedData + DerivedDataLocationStyle + Default + ShowSharedSchemesAutomaticallyEnabled + + + diff --git a/src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..bd645f3f --- /dev/null +++ b/src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcschemes/xcschememanagement.plist b/src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..77af7aad --- /dev/null +++ b/src/ios/yaze.xcodeproj/xcuserdata/scawful.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,39 @@ + + + + + SchemeUserState + + example_apple_metal_ios.xcscheme_^#shared#^_ + + orderHint + 2 + + example_apple_metal_macos.xcscheme_^#shared#^_ + + orderHint + 0 + + imgui_apple_metal_ios.xcscheme_^#shared#^_ + + orderHint + 2 + + imgui_apple_metal_macos.xcscheme_^#shared#^_ + + orderHint + 0 + + yaze_ios.xcscheme_^#shared#^_ + + orderHint + 4 + + yaze_macos.xcscheme_^#shared#^_ + + orderHint + 7 + + + + diff --git a/src/lib/abseil-cpp b/src/lib/abseil-cpp index 8c0b94e7..053d842f 160000 --- a/src/lib/abseil-cpp +++ b/src/lib/abseil-cpp @@ -1 +1 @@ -Subproject commit 8c0b94e793a66495e0b1f34a5eb26bd7dc672db0 +Subproject commit 053d842fa6c55ee103057b3c325b1923fd5d67d2 diff --git a/src/lib/asar b/src/lib/asar index 5edd93ce..5e0cdba7 160000 --- a/src/lib/asar +++ b/src/lib/asar @@ -1 +1 @@ -Subproject commit 5edd93ce9de723d3bfc21dc41a921f5ec33b71da +Subproject commit 5e0cdba7566438be20abf4591633c01d83750dd9 diff --git a/src/lib/imgui b/src/lib/imgui index 1f634f1d..08400f5b 160000 --- a/src/lib/imgui +++ b/src/lib/imgui @@ -1 +1 @@ -Subproject commit 1f634f1d94e16feb3d0b15ad79e8bc44cccc184d +Subproject commit 08400f5be7fa8a83682b99d611ab7cdc66258425 diff --git a/src/lib/imgui_memory_editor.h b/src/lib/imgui_memory_editor.h index 205e6be7..00946246 100644 --- a/src/lib/imgui_memory_editor.h +++ b/src/lib/imgui_memory_editor.h @@ -253,13 +253,23 @@ struct MemoryEditor size_t preview_data_type_size = OptShowDataPreview ? DataTypeGetSize(PreviewDataType) : 0; size_t data_editing_addr_next = (size_t)-1; - if (DataEditingAddr != (size_t)-1) - { - // Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered) - if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && (ptrdiff_t)DataEditingAddr >= (ptrdiff_t)Cols) { data_editing_addr_next = DataEditingAddr - Cols; } - else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; } - else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && (ptrdiff_t)DataEditingAddr > (ptrdiff_t)0) { data_editing_addr_next = DataEditingAddr - 1; } - else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - 1) { data_editing_addr_next = DataEditingAddr + 1; } + if (DataEditingAddr != (size_t)-1) { + // Move cursor but only apply on next frame so scrolling with be + // synchronized (because currently we can't change the scrolling while the + // window is being rendered) + if (ImGui::IsKeyPressed(ImGuiKey_UpArrow) && + (ptrdiff_t)DataEditingAddr >= (ptrdiff_t)Cols) { + data_editing_addr_next = DataEditingAddr - Cols; + } else if (ImGui::IsKeyPressed(ImGuiKey_DownArrow) && + (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - Cols) { + data_editing_addr_next = DataEditingAddr + Cols; + } else if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow) && + (ptrdiff_t)DataEditingAddr > (ptrdiff_t)0) { + data_editing_addr_next = DataEditingAddr - 1; + } else if (ImGui::IsKeyPressed(ImGuiKey_RightArrow) && + (ptrdiff_t)DataEditingAddr < (ptrdiff_t)mem_size - 1) { + data_editing_addr_next = DataEditingAddr + 1; + } } // Draw vertical separator diff --git a/src/lib/imgui_test_engine b/src/lib/imgui_test_engine index 82714610..a6b76971 160000 --- a/src/lib/imgui_test_engine +++ b/src/lib/imgui_test_engine @@ -1 +1 @@ -Subproject commit 8271461028664d67ae633712b1e0805ace73fe47 +Subproject commit a6b76971146d0cd148860156a8382497982943aa diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index cfbb66fe..d2601731 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,50 +1,35 @@ -# GoogleTest ------------------------------------------------------------------ -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip -) - -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) -enable_testing() - -# Append the ../ prefix to the include directories -list(TRANSFORM YAZE_APP_GFX_SRC PREPEND "../") -list(TRANSFORM YAZE_APP_EMU_SRC PREPEND "../") -list(TRANSFORM YAZE_APP_CORE_SRC PREPEND "../") -list(TRANSFORM YAZE_GUI_SRC PREPEND "../") +include(../cmake/gtest.cmake) add_executable( yaze_test - yaze_test.cc - emu/cpu_test.cc - # emu/spc700_test.cc - # emu/ppu_test.cc - gfx/compression_test.cc - gfx/snes_palette_test.cc - zelda3/room_object_test.cc - ../cli/patch.cc - ../cli/command_handler.cc - ../app/rom.cc - ../app/rom_test.cc - ../app/core/common.cc - ../app/core/labeling.cc - ../app/editor/utils/gfx_context.cc + test/yaze_test.cc + test/rom_test.cc + test/gfx/compression_test.cc + test/gfx/snes_palette_test.cc + test/integration/test_editor.cc + test/zelda3/overworld_test.cc + test/zelda3/sprite_builder_test.cc + app/rom.cc + app/core/common.cc + ${ASAR_STATIC_SRC} + ${YAZE_APP_CORE_SRC} ${YAZE_APP_EMU_SRC} ${YAZE_APP_GFX_SRC} + ${YAZE_APP_ZELDA3_SRC} + ${YAZE_APP_EDITOR_SRC} ${YAZE_GUI_SRC} - ${IMGUI_FILE_DLG_PATH}/ImGuiFileDialog.cpp - ../lib/imgui/misc/cpp/imgui_stdlib.cpp - # ${ASAR_STATIC_SRC} + ${IMGUI_SRC} + ${IMGUI_TEST_ENGINE_SOURCES} ) target_include_directories( yaze_test PUBLIC - ../ - ../app/ - ../lib/ + app/ + lib/ + ${CMAKE_SOURCE_DIR}/incl/ + ${CMAKE_SOURCE_DIR}/src/ + ${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine + ${ASAR_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} ${PNG_INCLUDE_DIRS} ) @@ -52,11 +37,12 @@ target_include_directories( target_link_libraries( yaze_test SDL2::SDL2 + asar-static ${ABSL_TARGETS} ${PNG_LIBRARIES} - ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS} + yaze_c ImGuiTestEngine ImGui gmock_main @@ -66,6 +52,7 @@ target_link_libraries( ) target_compile_definitions(yaze_test PRIVATE "linux") target_compile_definitions(yaze_test PRIVATE "stricmp=strcasecmp") +target_compile_definitions(yaze_test PRIVATE "IMGUI_ENABLE_TEST_ENGINE") include(GoogleTest) gtest_discover_tests(yaze_test) \ No newline at end of file diff --git a/src/test/core/testing.h b/src/test/core/testing.h new file mode 100644 index 00000000..a8e68178 --- /dev/null +++ b/src/test/core/testing.h @@ -0,0 +1,48 @@ +#ifndef YAZE_TEST_CORE_TESTING_H +#define YAZE_TEST_CORE_TESTING_H + +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" + +#define EXPECT_OK(expr) EXPECT_EQ((expr), absl::OkStatus()) + +#define ASSERT_OK(expr) ASSERT_EQ((expr), absl::OkStatus()) + +#define ASSERT_OK_AND_ASSIGN(lhs, rexpr) \ + if (auto rexpr_value = (rexpr); rexpr_value.ok()) { \ + lhs = std::move(rexpr_value).value(); \ + } else { \ + FAIL() << "error: " << rexpr_value.status(); \ + } + +namespace yaze { +namespace test { + +// StatusIs is a matcher that matches a status that has the same code and +// message as the expected status. +MATCHER_P(StatusIs, status, "") { return arg.code() == status; } + +// Support for testing absl::StatusOr. +template +::testing::AssertionResult IsOkAndHolds(const absl::StatusOr& status_or, + const T& value) { + if (!status_or.ok()) { + return ::testing::AssertionFailure() + << "Expected status to be OK, but got: " << status_or.status(); + } + if (status_or.value() != value) { + return ::testing::AssertionFailure() << "Expected value to be " << value + << ", but got: " << status_or.value(); + } + return ::testing::AssertionSuccess(); +} + +MATCHER_P(IsOkAndHolds, value, "") { return IsOkAndHolds(arg, value); } + +} // namespace test +} // namespace yaze + +#endif // YAZE_TEST_CORE_TESTING_H \ No newline at end of file diff --git a/src/test/emu/cpu_test.cc b/src/test/emu/cpu_test.cc index 13b85ab5..296443bc 100644 --- a/src/test/emu/cpu_test.cc +++ b/src/test/emu/cpu_test.cc @@ -5,12 +5,13 @@ #include "app/emu/cpu/clock.h" #include "app/emu/cpu/internal/opcodes.h" -#include "app/emu/debug/asm_parser.h" +#include "app/emu/memory/asm_parser.h" #include "app/emu/memory/memory.h" -#include "app/emu/memory/mock_memory.h" +#include "test/mocks/mock_memory.h" -namespace yaze_test { -namespace emu_test { +namespace yaze { +namespace test { +namespace emu { using yaze::app::emu::AsmParser; using yaze::app::emu::Cpu; @@ -4197,5 +4198,6 @@ TEST_F(CpuTest, XCESwitchBackAndForth) { EXPECT_FALSE(cpu.E); // Emulation mode flag should be cleared } -} // namespace emu_test -} // namespace yaze_test +} // namespace emu +} // namespace test +} // namespace yaze diff --git a/src/test/emu/ppu_test.cc b/src/test/emu/ppu_test.cc index 637aebec..3099f801 100644 --- a/src/test/emu/ppu_test.cc +++ b/src/test/emu/ppu_test.cc @@ -4,10 +4,11 @@ #include "app/emu/cpu/clock.h" #include "app/emu/memory/memory.h" -#include "app/emu/memory/mock_memory.h" +#include "test/mocks/mock_memory.h" -namespace yaze_test { -namespace emu_test { +namespace yaze { +namespace test { +namespace emu { using yaze::app::emu::Clock; using yaze::app::emu::memory::MockClock; @@ -26,32 +27,6 @@ class MockPpu : public PpuInterface { MOCK_METHOD(void, Write, (uint16_t address, uint8_t data), (override)); MOCK_METHOD(uint8_t, Read, (uint16_t address), (const, override)); - MOCK_METHOD(void, RenderFrame, (), (override)); - MOCK_METHOD(void, RenderScanline, (), (override)); - MOCK_METHOD(void, RenderBackground, (int layer), (override)); - MOCK_METHOD(void, RenderSprites, (), (override)); - - MOCK_METHOD(void, Init, (), (override)); - MOCK_METHOD(void, Reset, (), (override)); - MOCK_METHOD(void, Update, (double deltaTime), (override)); - MOCK_METHOD(void, UpdateClock, (double deltaTime), (override)); - MOCK_METHOD(void, UpdateInternalState, (int cycles), (override)); - - MOCK_METHOD(const std::vector&, GetFrameBuffer, (), - (const, override)); - MOCK_METHOD(std::shared_ptr, GetScreen, (), (const, override)); - - MOCK_METHOD(void, UpdateModeSettings, (), (override)); - MOCK_METHOD(void, UpdateTileData, (), (override)); - MOCK_METHOD(void, UpdateTileMapData, (), (override)); - MOCK_METHOD(void, UpdatePaletteData, (), (override)); - - MOCK_METHOD(void, ApplyEffects, (), (override)); - MOCK_METHOD(void, ComposeLayers, (), (override)); - - MOCK_METHOD(void, DisplayFrameBuffer, (), (override)); - MOCK_METHOD(void, Notify, (uint32_t address, uint8_t data), (override)); - std::vector internalFrameBuffer; std::vector vram; std::vector sprites; @@ -71,11 +46,6 @@ class PpuTest : public ::testing::Test { PpuTest() {} void SetUp() override { - ON_CALL(mock_ppu, Init()).WillByDefault([this]() { - mock_ppu.internalFrameBuffer.resize(256 * 240); - mock_ppu.vram.resize(0x10000); - }); - ON_CALL(mock_ppu, Write(::testing::_, ::testing::_)) .WillByDefault([this](uint16_t address, uint8_t data) { mock_ppu.vram[address] = data; @@ -84,76 +54,9 @@ class PpuTest : public ::testing::Test { ON_CALL(mock_ppu, Read(::testing::_)) .WillByDefault( [this](uint16_t address) { return mock_ppu.vram[address]; }); - - ON_CALL(mock_ppu, RenderScanline()).WillByDefault([this]() { - // Simulate scanline rendering logic... - }); - - ON_CALL(mock_ppu, GetFrameBuffer()).WillByDefault([this]() { - return mock_ppu.internalFrameBuffer; - }); - - // Additional ON_CALL setups as needed... } - - void TearDown() override { - // Common cleanup (if necessary) - } - - const uint8_t testVRAMValue = 0xAB; - const uint16_t testVRAMAddress = 0x2000; - const std::vector spriteData = {/* ... */}; - const std::vector bgData = {/* ... */}; - const uint8_t testPaletteIndex = 3; - const uint16_t testTileIndex = 42; }; -// Test Initialization -TEST_F(PpuTest, InitializationSetsCorrectFrameBufferSize) { - EXPECT_CALL(mock_ppu, Init()).Times(1); - mock_ppu.Init(); - EXPECT_EQ(mock_ppu.GetFrameBuffer().size(), 256 * 240); -} - -// Test State Reset -TEST_F(PpuTest, ResetClearsFrameBuffer) { - EXPECT_CALL(mock_ppu, Reset()).Times(1); - mock_ppu.Reset(); - auto frameBuffer = mock_ppu.GetFrameBuffer(); - EXPECT_TRUE(std::all_of(frameBuffer.begin(), frameBuffer.end(), - [](uint8_t val) { return val == 0; })); -} - -// Test Memory Interaction -TEST_F(PpuTest, ReadWriteVRAM) { - uint16_t address = testVRAMAddress; - uint8_t value = testVRAMValue; - EXPECT_CALL(mock_ppu, Write(address, value)).Times(1); - mock_ppu.Write(address, value); - EXPECT_EQ(mock_ppu.Read(address), value); -} - -// Test Rendering Mechanics -TEST_F(PpuTest, RenderScanlineUpdatesFrameBuffer) { - // Setup PPU with necessary background and sprite data - // Call RenderScanline and check if the framebuffer is updated correctly -} - -// Test Mode and Register Handling -TEST_F(PpuTest, Mode0Rendering) { - // Set PPU to Mode0 and verify correct rendering behavior -} - -// Test Interrupts and Counters -TEST_F(PpuTest, VBlankInterruptTriggered) { - // Simulate conditions for V-Blank and test if the interrupt is triggered -} - -// Test Composite Rendering and Output -TEST_F(PpuTest, FrameComposition) { - // Setup various layers and sprites, call ComposeLayers, and verify the frame - // buffer -} - -} // namespace emu_test -} // namespace yaze_test \ No newline at end of file +} // namespace emu +} // namespace test +} // namespace yaze \ No newline at end of file diff --git a/src/test/emu/spc700_test.cc b/src/test/emu/spc700_test.cc index 7ecb9628..16625fae 100644 --- a/src/test/emu/spc700_test.cc +++ b/src/test/emu/spc700_test.cc @@ -4,8 +4,9 @@ #include #include -namespace yaze_test { -namespace emu_test { +namespace yaze { +namespace test { +namespace emu { using testing::_; using testing::Return; @@ -72,7 +73,7 @@ class Spc700Test : public ::testing::Test { testing::StrictMock audioRAM; ApuCallbacks callbacks_; - Spc700 spc700{audioRAM, callbacks_}; + Spc700 spc700{callbacks_}; }; // ======================================================== @@ -470,5 +471,6 @@ TEST_F(Spc700Test, BootIplRomOk) { // EXPECT_EQ(spc700.PC, 0xFFC1 + 0x3F); } -} // namespace emu_test -} // namespace yaze_test +} // namespace emu +} // namespace test +} // namespace yaze diff --git a/src/test/gfx/compression_test.cc b/src/test/gfx/compression_test.cc index 2056cd65..f7875f1d 100644 --- a/src/test/gfx/compression_test.cc +++ b/src/test/gfx/compression_test.cc @@ -10,8 +10,9 @@ #define BUILD_HEADER(command, length) (command << 5) + (length - 1) -namespace yaze_test { -namespace gfx_test { +namespace yaze { +namespace test { +namespace gfx { using yaze::app::Rom; using yaze::app::gfx::lc_lz2::CompressionContext; @@ -32,8 +33,8 @@ using ::testing::TypedEq; namespace { -Bytes ExpectCompressOk(Rom& rom, uchar* in, int in_size) { - auto load_status = rom.LoadFromPointer(in, in_size); +std::vector ExpectCompressOk(Rom& rom, uchar* in, int in_size) { + auto load_status = rom.LoadFromPointer(in, in_size, false); EXPECT_TRUE(load_status.ok()); auto compression_status = CompressV3(rom.vector(), 0, in_size); EXPECT_TRUE(compression_status.ok()); @@ -41,7 +42,8 @@ Bytes ExpectCompressOk(Rom& rom, uchar* in, int in_size) { return compressed_bytes; } -Bytes ExpectDecompressBytesOk(Rom& rom, Bytes& in) { +std::vector ExpectDecompressBytesOk(Rom& rom, + std::vector& in) { auto load_status = rom.LoadFromBytes(in); EXPECT_TRUE(load_status.ok()); auto decompression_status = DecompressV2(rom.data(), 0, in.size()); @@ -50,8 +52,8 @@ Bytes ExpectDecompressBytesOk(Rom& rom, Bytes& in) { return decompressed_bytes; } -Bytes ExpectDecompressOk(Rom& rom, uchar* in, int in_size) { - auto load_status = rom.LoadFromPointer(in, in_size); +std::vector ExpectDecompressOk(Rom& rom, uchar* in, int in_size) { + auto load_status = rom.LoadFromPointer(in, in_size, false); EXPECT_TRUE(load_status.ok()); auto decompression_status = DecompressV2(rom.data(), 0, in_size); EXPECT_TRUE(decompression_status.ok()); @@ -72,16 +74,16 @@ std::shared_ptr ExpectNewCompressionPieceOk( void AssertCompressionQuality( const std::vector& uncompressed_data, const std::vector& expected_compressed_data) { - absl::StatusOr result = + absl::StatusOr> result = CompressV3(uncompressed_data, 0, uncompressed_data.size(), 0, false); ASSERT_TRUE(result.ok()); auto compressed_data = std::move(*result); EXPECT_THAT(compressed_data, ElementsAreArray(expected_compressed_data)); } -Bytes ExpectCompressV3Ok(const std::vector& uncompressed_data, +std::vector ExpectCompressV3Ok(const std::vector& uncompressed_data, const std::vector& expected_compressed_data) { - absl::StatusOr result = + absl::StatusOr> result = CompressV3(uncompressed_data, 0, uncompressed_data.size(), 0, false); EXPECT_TRUE(result.ok()); auto compressed_data = std::move(*result); @@ -129,16 +131,6 @@ TEST(LC_LZ2_CompressionTest, RepeatedBytesBeforeUncompressableRepeated) { {0x04, 0x01, 0x00, 0x00, 0x00, 0x02, 0x22, 0x00, 0xFF}); } -TEST(LC_LZ2_CompressionTest, CompressionDecompressionEmptyData) { - Rom rom; - uchar empty_input[0] = {}; - auto comp_result = ExpectCompressOk(rom, empty_input, 0); - EXPECT_EQ(0, comp_result.size()); - - auto decomp_result = ExpectDecompressOk(rom, empty_input, 0); - EXPECT_EQ(0, decomp_result.size()); -} - TEST(LC_LZ2_CompressionTest, NewDecompressionPieceOk) { char command = 1; int length = 1; @@ -405,7 +397,7 @@ TEST(CheckIncByteV3Test, NotAnIncreasingSequence) { TEST(LC_LZ2_CompressionTest, DecompressionValidCommand) { Rom rom; - Bytes simple_copy_input = {BUILD_HEADER(0x00, 0x02), 0x2A, 0x45, 0xFF}; + std::vector simple_copy_input = {BUILD_HEADER(0x00, 0x02), 0x2A, 0x45, 0xFF}; uchar simple_copy_output[2] = {0x2A, 0x45}; auto decomp_result = ExpectDecompressBytesOk(rom, simple_copy_input); EXPECT_THAT(simple_copy_output, ElementsAreArray(decomp_result.data(), 2)); @@ -429,5 +421,6 @@ TEST(LC_LZ2_CompressionTest, DecompressionMixingCommand) { EXPECT_THAT(random1_o, ElementsAreArray(decomp_result.data(), 9)); } -} // namespace gfx_test -} // namespace yaze_test \ No newline at end of file +} // namespace gfx +} // namespace test +} // namespace yaze \ No newline at end of file diff --git a/src/test/gfx/snes_palette_test.cc b/src/test/gfx/snes_palette_test.cc index fca0672f..2e962290 100644 --- a/src/test/gfx/snes_palette_test.cc +++ b/src/test/gfx/snes_palette_test.cc @@ -5,19 +5,18 @@ #include "app/gfx/snes_color.h" -namespace yaze_test { -namespace gfx_test { +namespace yaze { +namespace test { +namespace gfx { using ::testing::ElementsAreArray; -using yaze::app::gfx::ConvertRGBtoSNES; -using yaze::app::gfx::ConvertSNEStoRGB; +using yaze::app::gfx::ConvertRgbToSnes; +using yaze::app::gfx::ConvertSnestoRGB; using yaze::app::gfx::Extract; -using yaze::app::gfx::snes_color; -using yaze::app::gfx::snes_palette; using yaze::app::gfx::SnesPalette; namespace { -unsigned int test_convert(yaze::app::gfx::snes_color col) { +unsigned int test_convert(snes_color col) { unsigned int toret; toret = col.red << 16; toret += col.green << 8; @@ -26,55 +25,45 @@ unsigned int test_convert(yaze::app::gfx::snes_color col) { } } // namespace -TEST(SNESPaletteTest, AddColor) { +TEST(SnesPaletteTest, AddColor) { yaze::app::gfx::SnesPalette palette; yaze::app::gfx::SnesColor color; palette.AddColor(color); ASSERT_EQ(palette.size(), 1); } -TEST(SNESPaletteTest, GetColorOutOfBounds) { - yaze::app::gfx::SnesPalette palette; - std::vector colors(5); - palette.Create(colors); - - // TODO: Fix this test, behavior has changed since the original - // ASSERT_THROW(palette.GetColor(10), std::exception); - // ASSERT_THROW(palette[10], std::exception); -} - -TEST(SNESColorTest, ConvertRGBtoSNES) { +TEST(SnesColorTest, ConvertRgbToSnes) { snes_color color = {132, 132, 132}; - uint16_t snes = ConvertRGBtoSNES(color); + uint16_t snes = ConvertRgbToSnes(color); ASSERT_EQ(snes, 0x4210); } -TEST(SNESColorTest, ConvertSNEStoRGB) { +TEST(SnesColorTest, ConvertSnestoRGB) { uint16_t snes = 0x4210; - snes_color color = ConvertSNEStoRGB(snes); + snes_color color = ConvertSnestoRGB(snes); ASSERT_EQ(color.red, 132); ASSERT_EQ(color.green, 132); ASSERT_EQ(color.blue, 132); } -TEST(SNESColorTest, ConvertSNESToRGB_Binary) { +TEST(SnesColorTest, ConvertSnesToRGB_Binary) { uint16_t red = 0b0000000000011111; uint16_t blue = 0b0111110000000000; uint16_t green = 0b0000001111100000; uint16_t purple = 0b0111110000011111; snes_color testcolor; - testcolor = ConvertSNEStoRGB(red); + testcolor = ConvertSnestoRGB(red); ASSERT_EQ(0xFF0000, test_convert(testcolor)); - testcolor = ConvertSNEStoRGB(green); + testcolor = ConvertSnestoRGB(green); ASSERT_EQ(0x00FF00, test_convert(testcolor)); - testcolor = ConvertSNEStoRGB(blue); + testcolor = ConvertSnestoRGB(blue); ASSERT_EQ(0x0000FF, test_convert(testcolor)); - testcolor = ConvertSNEStoRGB(purple); + testcolor = ConvertSnestoRGB(purple); ASSERT_EQ(0xFF00FF, test_convert(testcolor)); } -TEST(SNESColorTest, Extraction) { +TEST(SnesColorTest, Extraction) { // red, blue, green, purple char data[8] = {0x1F, 0x00, 0x00, 0x7C, static_cast(0xE0), 0x03, 0x1F, 0x7C}; @@ -86,7 +75,7 @@ TEST(SNESColorTest, Extraction) { ASSERT_EQ(0xFF00FF, test_convert(pal[3])); } -TEST(SNESColorTest, Convert) { +TEST(SnesColorTest, Convert) { // red, blue, green, purple white char data[10] = {0x1F, 0x00, @@ -99,10 +88,11 @@ TEST(SNESColorTest, Convert) { static_cast(0xFF), 0x1F}; auto pal = Extract(data, 0, 5); - auto snes_string = Convert(pal); + auto snes_string = yaze::app::gfx::Convert(pal); EXPECT_EQ(10, snes_string.size()); EXPECT_THAT(data, ElementsAreArray(snes_string.data(), 10)); } -} // namespace gfx_test -} // namespace yaze_test \ No newline at end of file +} // namespace gfx +} // namespace test +} // namespace yaze \ No newline at end of file diff --git a/src/test/integration/test_editor.cc b/src/test/integration/test_editor.cc new file mode 100644 index 00000000..53411800 --- /dev/null +++ b/src/test/integration/test_editor.cc @@ -0,0 +1,101 @@ +#include "test/integration/test_editor.h" + +#include + +#include "app/core/controller.h" +#include "app/core/platform/renderer.h" +#include "app/gui/style.h" +#include "imgui/backends/imgui_impl_sdl2.h" +#include "imgui/backends/imgui_impl_sdlrenderer2.h" +#include "imgui/imgui.h" +#include "imgui_test_engine/imgui_te_context.h" +#include "imgui_test_engine/imgui_te_engine.h" +#include "imgui_test_engine/imgui_te_imconfig.h" +#include "imgui_test_engine/imgui_te_ui.h" + +namespace yaze { +namespace test { +namespace integration { + +absl::Status TestEditor::Update() { + ImGui::NewFrame(); + if (ImGui::Begin("My Window")) { + ImGui::Text("Hello, world!"); + ImGui::Button("My Button"); + } + + static bool show_demo_window = true; + + ImGuiTestEngine_ShowTestEngineWindows(engine_, &show_demo_window); + + ImGui::End(); + + return absl::OkStatus(); +} + +void TestEditor::RegisterTests(ImGuiTestEngine* engine) { + engine_ = engine; + ImGuiTest* test = IM_REGISTER_TEST(engine, "demo_test", "test1"); + test->TestFunc = [](ImGuiTestContext* ctx) { + ctx->SetRef("My Window"); + ctx->ItemClick("My Button"); + ctx->ItemCheck("Node/Checkbox"); + }; +} + +int RunIntegrationTest() { + yaze::test::integration::TestEditor test_editor; + yaze::app::core::Controller controller; + controller.init_test_editor(&test_editor); + + if (!controller.CreateWindow().ok()) { + return EXIT_FAILURE; + } + if (!controller.CreateRenderer().ok()) { + return EXIT_FAILURE; + } + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + // Initialize Test Engine + ImGuiTestEngine* engine = ImGuiTestEngine_CreateContext(); + ImGuiTestEngineIO& test_io = ImGuiTestEngine_GetIO(engine); + test_io.ConfigVerboseLevel = ImGuiTestVerboseLevel_Info; + test_io.ConfigVerboseLevelOnError = ImGuiTestVerboseLevel_Debug; + + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + + // Initialize ImGui for SDL + ImGui_ImplSDL2_InitForSDLRenderer( + controller.window(), yaze::app::core::Renderer::GetInstance().renderer()); + ImGui_ImplSDLRenderer2_Init( + yaze::app::core::Renderer::GetInstance().renderer()); + + test_editor.RegisterTests(engine); + ImGuiTestEngine_Start(engine, ImGui::GetCurrentContext()); + controller.set_active(true); + + // Set the default style + yaze::app::gui::ColorsYaze(); + + // Build a new ImGui frame + ImGui_ImplSDLRenderer2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + + while (controller.IsActive()) { + controller.OnInput(); + if (const auto status = controller.OnTestLoad(); !status.ok()) { + return EXIT_FAILURE; + } + controller.DoRender(); + } + + ImGuiTestEngine_Stop(engine); + controller.OnExit(); + return EXIT_SUCCESS; +} + +} // namespace integration +} // namespace test +} // namespace yaze diff --git a/src/test/integration/test_editor.h b/src/test/integration/test_editor.h new file mode 100644 index 00000000..c555bd32 --- /dev/null +++ b/src/test/integration/test_editor.h @@ -0,0 +1,53 @@ +#ifndef YAZE_TEST_INTEGRATION_TEST_EDITOR_H +#define YAZE_TEST_INTEGRATION_TEST_EDITOR_H + +#include "app/editor/editor.h" +#include "imgui/imgui.h" +#include "imgui_test_engine/imgui_te_context.h" +#include "imgui_test_engine/imgui_te_engine.h" + +namespace yaze { +namespace test { +namespace integration { + +class TestEditor : public yaze::app::editor::Editor { + public: + TestEditor() = default; + ~TestEditor() = default; + + absl::Status Cut() override { + return absl::UnimplementedError("Not implemented"); + } + absl::Status Copy() override { + return absl::UnimplementedError("Not implemented"); + } + absl::Status Paste() override { + return absl::UnimplementedError("Not implemented"); + } + + absl::Status Undo() override { + return absl::UnimplementedError("Not implemented"); + } + absl::Status Redo() override { + return absl::UnimplementedError("Not implemented"); + } + + absl::Status Find() override { + return absl::UnimplementedError("Not implemented"); + } + + absl::Status Update() override; + + void RegisterTests(ImGuiTestEngine* engine); + + private: + ImGuiTestEngine* engine_; +}; + +int RunIntegrationTest(); + +} // namespace integration +} // namespace test +} // namespace yaze + +#endif // YAZE_TEST_INTEGRATION_TEST_EDITOR_H \ No newline at end of file diff --git a/src/app/emu/memory/mock_memory.h b/src/test/mocks/mock_memory.h similarity index 100% rename from src/app/emu/memory/mock_memory.h rename to src/test/mocks/mock_memory.h diff --git a/src/test/rom_test.cc b/src/test/rom_test.cc new file mode 100644 index 00000000..99de8782 --- /dev/null +++ b/src/test/rom_test.cc @@ -0,0 +1,246 @@ +#include "app/rom.h" + +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "test/core/testing.h" +#include "app/gfx/snes_color.h" + +namespace yaze { +namespace test { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Return; + +const static std::vector kMockRomData = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, +}; + +class MockRom : public app::Rom { + public: + MOCK_METHOD(absl::Status, WriteHelper, (const WriteAction&), (override)); + + MOCK_METHOD2(ReadHelper, absl::Status(uint8_t&, int)); + MOCK_METHOD2(ReadHelper, absl::Status(uint16_t&, int)); + MOCK_METHOD2(ReadHelper, absl::Status(std::vector&, int)); + + MOCK_METHOD(absl::StatusOr, ReadByte, (int)); + MOCK_METHOD(absl::StatusOr, ReadWord, (int)); + MOCK_METHOD(absl::StatusOr, ReadLong, (int)); +}; + +class RomTest : public ::testing::Test { + protected: + app::Rom rom_; +}; + +TEST_F(RomTest, Uninitialized) { + EXPECT_EQ(rom_.size(), 0); + EXPECT_EQ(rom_.data(), nullptr); +} + +TEST_F(RomTest, LoadFromFile) { +#if defined(__linux__) + GTEST_SKIP(); +#endif + EXPECT_OK(rom_.LoadFromFile("test.sfc")); + EXPECT_EQ(rom_.size(), 0x200000); + EXPECT_NE(rom_.data(), nullptr); +} + +TEST_F(RomTest, LoadFromFileInvalid) { + EXPECT_THAT(rom_.LoadFromFile("invalid.sfc"), + StatusIs(absl::StatusCode::kNotFound)); + EXPECT_EQ(rom_.size(), 0); + EXPECT_EQ(rom_.data(), nullptr); +} + +TEST_F(RomTest, LoadFromFileEmpty) { + EXPECT_THAT(rom_.LoadFromFile(""), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(RomTest, ReadByteOk) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + for (size_t i = 0; i < kMockRomData.size(); ++i) { + uint8_t byte; + ASSERT_OK_AND_ASSIGN(byte, rom_.ReadByte(i)); + EXPECT_EQ(byte, kMockRomData[i]); + } +} + +TEST_F(RomTest, ReadByteInvalid) { + EXPECT_THAT(rom_.ReadByte(0).status(), + StatusIs(absl::StatusCode::kFailedPrecondition)); +} + +TEST_F(RomTest, ReadWordOk) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + for (size_t i = 0; i < kMockRomData.size(); i += 2) { + // Little endian + EXPECT_THAT( + rom_.ReadWord(i), + IsOkAndHolds((kMockRomData[i]) | kMockRomData[i + 1] << 8)); + } +} + +TEST_F(RomTest, ReadWordInvalid) { + EXPECT_THAT(rom_.ReadWord(0).status(), + StatusIs(absl::StatusCode::kFailedPrecondition)); +} + +TEST_F(RomTest, ReadLongOk) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + for (size_t i = 0; i < kMockRomData.size(); i += 4) { + // Little endian + EXPECT_THAT(rom_.ReadLong(i), + IsOkAndHolds((kMockRomData[i]) | kMockRomData[i] | + kMockRomData[i + 1] << 8 | + kMockRomData[i + 2] << 16)); + } +} + +TEST_F(RomTest, ReadLongInvalid) { + EXPECT_THAT(rom_.ReadLong(0).status(), + StatusIs(absl::StatusCode::kFailedPrecondition)); +} + +TEST_F(RomTest, ReadBytesOk) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + std::vector bytes; + ASSERT_OK_AND_ASSIGN(bytes, rom_.ReadByteVector(0, kMockRomData.size())); + EXPECT_THAT(bytes, ::testing::ContainerEq(kMockRomData)); +} + +TEST_F(RomTest, ReadBytesInvalid) { + EXPECT_THAT(rom_.ReadByteVector(0, 1).status(), + StatusIs(absl::StatusCode::kFailedPrecondition)); +} + +TEST_F(RomTest, ReadBytesOutOfRange) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + std::vector bytes; + EXPECT_THAT(rom_.ReadByteVector(kMockRomData.size() + 1, 1).status(), + StatusIs(absl::StatusCode::kOutOfRange)); +} + +TEST_F(RomTest, WriteByteOk) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + for (size_t i = 0; i < kMockRomData.size(); ++i) { + EXPECT_OK(rom_.WriteByte(i, 0xFF)); + uint8_t byte; + ASSERT_OK_AND_ASSIGN(byte, rom_.ReadByte(i)); + EXPECT_EQ(byte, 0xFF); + } +} + +TEST_F(RomTest, WriteByteInvalid) { + EXPECT_THAT(rom_.WriteByte(0, 0xFF), + StatusIs(absl::StatusCode::kFailedPrecondition)); + + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + EXPECT_THAT(rom_.WriteByte(kMockRomData.size(), 0xFF), + StatusIs(absl::StatusCode::kOutOfRange)); +} + +TEST_F(RomTest, WriteWordOk) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + for (size_t i = 0; i < kMockRomData.size(); i += 2) { + EXPECT_OK(rom_.WriteWord(i, 0xFFFF)); + uint16_t word; + ASSERT_OK_AND_ASSIGN(word, rom_.ReadWord(i)); + EXPECT_EQ(word, 0xFFFF); + } +} + +TEST_F(RomTest, WriteWordInvalid) { + EXPECT_THAT(rom_.WriteWord(0, 0xFFFF), + StatusIs(absl::StatusCode::kFailedPrecondition)); + + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + EXPECT_THAT(rom_.WriteWord(kMockRomData.size(), 0xFFFF), + StatusIs(absl::StatusCode::kOutOfRange)); +} + +TEST_F(RomTest, WriteLongOk) { + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + + for (size_t i = 0; i < kMockRomData.size(); i += 4) { + EXPECT_OK(rom_.WriteLong(i, 0xFFFFFF)); + uint32_t word; + ASSERT_OK_AND_ASSIGN(word, rom_.ReadLong(i)); + EXPECT_EQ(word, 0xFFFFFF); + } +} + +TEST_F(RomTest, WriteLongInvalid) { + EXPECT_THAT(rom_.WriteLong(0, 0xFFFFFF), + StatusIs(absl::StatusCode::kFailedPrecondition)); + + EXPECT_OK(rom_.LoadFromBytes(kMockRomData)); + EXPECT_THAT(rom_.WriteLong(kMockRomData.size(), 0xFFFFFFFF), + StatusIs(absl::StatusCode::kOutOfRange)); +} + +TEST_F(RomTest, WriteTransactionSuccess) { + MockRom mock_rom; + EXPECT_OK(mock_rom.LoadFromBytes(kMockRomData)); + + EXPECT_CALL(mock_rom, WriteHelper(_)) + .WillRepeatedly(Return(absl::OkStatus())); + + EXPECT_OK(mock_rom.WriteTransaction( + app::Rom::WriteAction{0x1000, uint8_t{0xFF}}, + app::Rom::WriteAction{0x1001, uint16_t{0xABCD}}, + app::Rom::WriteAction{0x1002, std::vector{0x12, 0x34}})); +} + +TEST_F(RomTest, WriteTransactionFailure) { + MockRom mock_rom; + EXPECT_OK(mock_rom.LoadFromBytes(kMockRomData)); + + EXPECT_CALL(mock_rom, WriteHelper(_)) + .WillOnce(Return(absl::OkStatus())) + .WillOnce(Return(absl::InternalError("Write failed"))); + + EXPECT_EQ(mock_rom.WriteTransaction( + app::Rom::WriteAction{0x1000, uint8_t{0xFF}}, + app::Rom::WriteAction{0x1001, uint16_t{0xABCD}}), + absl::InternalError("Write failed")); +} + +TEST_F(RomTest, ReadTransactionSuccess) { + MockRom mock_rom; + EXPECT_OK(mock_rom.LoadFromBytes(kMockRomData)); + uint8_t byte_val; + uint16_t word_val; + + EXPECT_OK(mock_rom.ReadTransaction(byte_val, 0x0000, word_val, 0x0001)); + + EXPECT_EQ(byte_val, 0x00); + EXPECT_EQ(word_val, 0x0201); +} + +TEST_F(RomTest, ReadTransactionFailure) { + MockRom mock_rom; + EXPECT_OK(mock_rom.LoadFromBytes(kMockRomData)); + uint8_t byte_val; + + EXPECT_EQ(mock_rom.ReadTransaction(byte_val, 0x1000), + absl::FailedPreconditionError("Offset out of range")); +} + +} // namespace test +} // namespace yaze diff --git a/src/test/yaze_test.cc b/src/test/yaze_test.cc index b972ad10..f80414ac 100644 --- a/src/test/yaze_test.cc +++ b/src/test/yaze_test.cc @@ -1,14 +1,34 @@ #define SDL_MAIN_HANDLED + +#include "yaze.h" + #include #include "absl/debugging/failure_signal_handler.h" #include "absl/debugging/symbolize.h" +#include "test/integration/test_editor.h" + +namespace yaze { +namespace test { + +} // namespace test +} // namespace yaze int main(int argc, char* argv[]) { absl::InitializeSymbolizer(argv[0]); absl::FailureSignalHandlerOptions options; absl::InstallFailureSignalHandler(options); + + if (argc > 1 && std::string(argv[1]) == "integration") { + return yaze::test::integration::RunIntegrationTest(); + } else if (argc > 1 && std::string(argv[1]) == "room_object") { + ::testing::InitGoogleTest(&argc, argv); + if (!RUN_ALL_TESTS()) { + return yaze::test::integration::RunIntegrationTest(); + } + } + ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/src/test/zelda3/dungeon_room_test.cc b/src/test/zelda3/dungeon_room_test.cc new file mode 100644 index 00000000..c2211997 --- /dev/null +++ b/src/test/zelda3/dungeon_room_test.cc @@ -0,0 +1,37 @@ +#include "app/zelda3/dungeon/room.h" + +#include "gtest/gtest.h" +#include +#include + +#include "app/rom.h" + +namespace yaze { +namespace test { +namespace zelda3 { + +class DungeonRoomTest : public ::testing::Test, public app::SharedRom { +protected: + void SetUp() override { + // Skip tests on Linux for automated github builds +#if defined(__linux__) + GTEST_SKIP(); +#else + if (!rom()->LoadFromFile("./zelda3.sfc").ok()) { + GTEST_SKIP_("Failed to load test ROM"); + } +#endif + } + void TearDown() override {} +}; + +TEST_F(DungeonRoomTest, SingleRoomLoadOk) { + app::zelda3::dungeon::Room test_room(/*room_id=*/0); + test_room.LoadHeader(); + // Do some assertions based on the output in ZS + test_room.LoadRoomFromROM(); +} + +} // namespace zelda3 +} // namespace test +} // namespace yaze diff --git a/src/test/zelda3/message_test.cc b/src/test/zelda3/message_test.cc new file mode 100644 index 00000000..c593d187 --- /dev/null +++ b/src/test/zelda3/message_test.cc @@ -0,0 +1,49 @@ +#include + +#include "app/editor/message/message_data.h" +#include "app/editor/message/message_editor.h" +#include "test/core/testing.h" + +namespace yaze { +namespace test { +namespace zelda3 { + +class MessageTest : public ::testing::Test, public app::SharedRom { + protected: + void SetUp() override { +#if defined(__linux__) + GTEST_SKIP(); +#endif + } + void TearDown() override {} + + app::editor::MessageEditor message_editor_; + std::vector dictionary_; +}; + +TEST_F(MessageTest, LoadMessagesFromRomOk) { + EXPECT_OK(rom()->LoadFromFile("zelda3.sfc")); + EXPECT_OK(message_editor_.Initialize()); +} + +/** + * @test Verify that a single message can be loaded from the ROM. + * + * @details The message is loaded from the ROM and the message is parsed. + * + * Message #1 at address 0x0E000B + RawString: + [S:00][3][][:75][:44][CH2I] + + Parsed: + [S:##]A + [3]give + [2]give >[CH2I] + */ +TEST_F(MessageTest, VerifySingleMessageFromRomOk) { + // TODO - Implement this test +} + +} // namespace zelda3 +} // namespace test +} // namespace yaze diff --git a/src/test/zelda3/overworld_test.cc b/src/test/zelda3/overworld_test.cc new file mode 100644 index 00000000..fac567c2 --- /dev/null +++ b/src/test/zelda3/overworld_test.cc @@ -0,0 +1,58 @@ +#include "app/zelda3/overworld/overworld.h" + +#include +#include + +#include "app/rom.h" +#include "app/zelda3/overworld/overworld.h" +#include "app/zelda3/overworld/overworld_map.h" +#include "test/core/testing.h" + +namespace yaze { +namespace test { +namespace zelda3 { + +class OverworldTest : public ::testing::Test, public app::SharedRom { + protected: + void SetUp() override { + // Skip tests on Linux for automated github builds +#if defined(__linux__) + GTEST_SKIP(); +#endif + } + void TearDown() override {} + + app::zelda3::overworld::Overworld overworld_; +}; + +TEST_F(OverworldTest, OverworldLoadNoRomDataError) { + // Arrange + app::Rom rom; + + // Act + auto status = overworld_.Load(rom); + + // Assert + EXPECT_FALSE(status.ok()); + EXPECT_THAT(status.message(), testing::HasSubstr("ROM file not loaded")); +} + +TEST_F(OverworldTest, OverworldLoadRomDataOk) { + // Arrange + EXPECT_OK(rom()->LoadFromFile("zelda3.sfc")); + EXPECT_OK(rom()->LoadAllGraphicsData(/*defer_render=*/true)); + + // Act + auto status = overworld_.Load(*rom()); + + // Assert + EXPECT_TRUE(status.ok()); + EXPECT_EQ(overworld_.overworld_maps().size(), + app::zelda3::overworld::kNumOverworldMaps); + EXPECT_EQ(overworld_.tiles16().size(), + app::zelda3::overworld::kNumTile16Individual); +} + +} // namespace zelda3 +} // namespace test +} // namespace yaze diff --git a/src/test/zelda3/room_object_test.cc b/src/test/zelda3/room_object_test.cc deleted file mode 100644 index b63aefd1..00000000 --- a/src/test/zelda3/room_object_test.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include "app/zelda3/dungeon/room_object.h" - -#include -#include - -#include "app/emu/cpu/cpu.h" -#include "app/emu/memory/memory.h" -#include "app/emu/memory/mock_memory.h" -#include "app/emu/video/ppu.h" -#include "app/gfx/bitmap.h" -#include "app/rom.h" - -namespace yaze_test { -namespace zelda3_test { - -using yaze::app::Rom; -using yaze::app::zelda3::dungeon::DungeonObjectRenderer; - -TEST(DungeonObjectTest, RenderObjectsAsBitmaps) { - Rom rom; - // rom.LoadFromFile("/Users/scawful/Code/yaze/build/bin/zelda3.sfc")); - // EXPECT_EQ(rom_status, absl::Status::ok()); - - DungeonObjectRenderer renderer; -} - -} // namespace zelda3_test -} // namespace yaze_test \ No newline at end of file diff --git a/src/test/zelda3/sprite_builder_test.cc b/src/test/zelda3/sprite_builder_test.cc new file mode 100644 index 00000000..f97ad8c2 --- /dev/null +++ b/src/test/zelda3/sprite_builder_test.cc @@ -0,0 +1,66 @@ +#include "app/zelda3/sprite/sprite_builder.h" + +#include +#include + +namespace yaze { +namespace test { +namespace zelda3 { + +using namespace yaze::app::zelda3; + +class SpriteBuilderTest : public ::testing::Test { + protected: + void SetUp() override { + // Create a new sprite + SpriteBuilder sprite = SpriteBuilder::Create("Puffstool") + .SetProperty("NbrTiles", 2) + .SetProperty("Health", 10) + .SetProperty("Harmless", false); + // Create an anonymous global action for the sprite to run before each + // action + SpriteAction globalAction = SpriteAction::Create().AddInstruction( + SpriteInstruction::BehaveAsBarrier()); + // Create an action for the SprAction::LocalJumpTable + SpriteAction walkAction = + SpriteAction::Create("Walk") + .AddInstruction(SpriteInstruction::PlayAnimation(0, 6, 10)) + .AddInstruction(SpriteInstruction::ApplySpeedTowardsPlayer(2)) + .AddInstruction(SpriteInstruction::MoveXyz()) + .AddInstruction(SpriteInstruction::BounceFromTileCollision()) + .AddCustomInstruction("JSL $0DBB7C"); // Custom ASM + // Link to the idle action. If the action does not exist, build will fail + walkAction.SetNextAction("IdleAction"); + + // Idle action which jumps to a fn. If the fn does not exist, build will + // fail + SpriteAction idleAction = + SpriteAction::Create("IdleAction") + .AddInstruction(SpriteInstruction::JumpToFunction("IdleFn")); + idleAction.SetNextAction("Walk"); + + // Build the function that the idle action jumps to + SpriteAction idleFunction = SpriteAction::Create("IdleFn").AddInstruction( + SpriteInstruction::MoveXyz()); + + // Add actions and functions to sprite + sprite.SetGlobalAction(globalAction); + sprite.AddAction(idleAction); // 0x00 + sprite.AddAction(walkAction); // 0x01 + sprite.AddFunction(idleFunction); // Local + } + void TearDown() override {} + + SpriteBuilder sprite; +}; + +TEST_F(SpriteBuilderTest, BuildSpritePropertiesOk) { + EXPECT_THAT(sprite.BuildProperties(), testing::HasSubstr(R"(!SPRID = $00 +!NbrTiles = $00 +!Harmless = $00 +)")); +} + +} // namespace zelda3_test +} // namespace test +} // namespace yaze \ No newline at end of file diff --git a/src/yaze.ico b/src/win32/yaze.ico similarity index 100% rename from src/yaze.ico rename to src/win32/yaze.ico diff --git a/src/yaze.rc b/src/win32/yaze.rc similarity index 100% rename from src/yaze.rc rename to src/win32/yaze.rc diff --git a/src/yaze.res b/src/win32/yaze.res similarity index 100% rename from src/yaze.res rename to src/win32/yaze.res diff --git a/src/yaze.cc b/src/yaze.cc new file mode 100644 index 00000000..5af7e32a --- /dev/null +++ b/src/yaze.cc @@ -0,0 +1,123 @@ +#include "yaze.h" + +#include + +#include "app/rom.h" +#include "app/zelda3/overworld/overworld.h" + +void yaze_check_version(const char* version) { + printf("Yaze version: %s\n", version); + auto version_check = yaze::app::core::CheckVersion(version); + if (!version_check.ok()) { + printf("%s\n", version_check.status().message().data()); + exit(1); + } + return; +} + +int yaze_init(yaze_editor_context* yaze_ctx) { + if (yaze_ctx->project->rom_filename == nullptr) { + return -1; + } + + yaze_ctx->rom = yaze_load_rom(yaze_ctx->project->rom_filename); + if (yaze_ctx->rom == nullptr) { + return -1; + } + + return 0; +} + +void yaze_cleanup(yaze_editor_context* yaze_ctx) { + if (yaze_ctx->rom) { + yaze_unload_rom(yaze_ctx->rom); + } +} + +yaze_project yaze_load_project(const char* filename) { + yaze_project project; + project.filepath = filename; + return project; +} + +z3_rom* yaze_load_rom(const char* filename) { + yaze::app::Rom* internal_rom; + internal_rom = new yaze::app::Rom(); + if (!internal_rom->LoadFromFile(filename).ok()) { + delete internal_rom; + return nullptr; + } + + z3_rom* rom = new z3_rom(); + rom->filename = filename; + rom->impl = internal_rom; + rom->data = internal_rom->data(); + rom->size = internal_rom->size(); + return rom; +} + +void yaze_unload_rom(z3_rom* rom) { + if (rom->impl) { + delete static_cast(rom->impl); + } + + if (rom) { + delete rom; + } +} + +yaze_bitmap yaze_load_bitmap(const char* filename) { + yaze_bitmap bitmap; + bitmap.width = 0; + bitmap.height = 0; + bitmap.bpp = 0; + bitmap.data = nullptr; + return bitmap; +} + +snes_color yaze_get_color_from_paletteset(const z3_rom* rom, int palette_set, + int palette, int color) { + snes_color color_struct; + color_struct.red = 0; + color_struct.green = 0; + color_struct.blue = 0; + + if (rom->impl) { + yaze::app::Rom* internal_rom = static_cast(rom->impl); + auto get_color = + internal_rom->palette_group() + .get_group(yaze::app::gfx::kPaletteGroupAddressesKeys[palette_set]) + ->palette(palette) + .GetColor(color); + if (!get_color.ok()) { + return color_struct; + } + color_struct = get_color.value().rom_color(); + + return color_struct; + } + + return color_struct; +} + +z3_overworld* yaze_load_overworld(const z3_rom* rom) { + if (rom->impl == nullptr) { + return nullptr; + } + + yaze::app::Rom* internal_rom = static_cast(rom->impl); + auto internal_overworld = new yaze::app::zelda3::overworld::Overworld(); + if (!internal_overworld->Load(*internal_rom).ok()) { + return nullptr; + } + + z3_overworld* overworld = new z3_overworld(); + overworld->impl = internal_overworld; + int map_id = 0; + for (const auto& ow_map : internal_overworld->overworld_maps()) { + overworld->maps[map_id] = new z3_overworld_map(); + overworld->maps[map_id]->id = map_id; + map_id++; + } + return overworld; +}