Merge pull request #28 from scawful/delta

Delta, Inventory Menu
This commit is contained in:
Justin Scofield
2022-09-17 10:38:37 -05:00
committed by GitHub
45 changed files with 2992 additions and 567 deletions

View File

@@ -42,6 +42,10 @@ set(
find_package(PNG REQUIRED) find_package(PNG REQUIRED)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED) find_package(GLEW REQUIRED)
find_package(gRPC REQUIRED)
set(PROTOBUF_INCLUDE_PATH ${CMAKE_CURRENT_BINARY_DIR}
CACHE INTERNAL "Path to generated protobuf files.")
include_directories(${PROTOBUF_INCLUDE_PATH})
# Project Files # Project Files
add_subdirectory(src/lib/abseil-cpp) add_subdirectory(src/lib/abseil-cpp)

View File

@@ -36,12 +36,35 @@ set(
# Asar Assembly --------------------------------------------------------------- # Asar Assembly ---------------------------------------------------------------
add_subdirectory(lib/asar/src) add_subdirectory(lib/asar/src)
set(ASAR_GEN_EXE OFF) get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES)
set(ASAR_GEN_DLL ON) target_include_directories(asar-static PRIVATE ${ASAR_INCLUDE_DIR})
set(ASAR_GEN_LIB OFF) set(ASAR_GEN_EXE OFF)
set(ASAR_GEN_DLL ON)
set(ASAR_GEN_LIB ON)
set(ASAR_GEN_EXE_TEST OFF) set(ASAR_GEN_EXE_TEST OFF)
set(ASAR_GEN_DLL_TEST OFF) set(ASAR_GEN_DLL_TEST OFF)
set(ASAR_STATIC_SRC
"lib/asar/src/asar/interface-lib.cpp"
"lib/asar/src/asar/addr2line.cpp"
"lib/asar/src/asar/arch-65816.cpp"
"lib/asar/src/asar/arch-spc700.cpp"
"lib/asar/src/asar/arch-superfx.cpp"
"lib/asar/src/asar/assembleblock.cpp"
"lib/asar/src/asar/crc32.cpp"
"lib/asar/src/asar/libcon.cpp"
"lib/asar/src/asar/libsmw.cpp"
"lib/asar/src/asar/libstr.cpp"
"lib/asar/src/asar/macro.cpp"
"lib/asar/src/asar/main.cpp"
"lib/asar/src/asar/asar_math.cpp"
"lib/asar/src/asar/virtualfile.cpp"
"lib/asar/src/asar/warnings.cpp"
"lib/asar/src/asar/errors.cpp"
"lib/asar/src/asar/platform/file-helpers.cpp"
"lib/asar/src/asar/platform/linux/file-helpers-linux.cpp"
)
# yaze source files ----------------------------------------------------------- # yaze source files -----------------------------------------------------------
set( set(
YAZE_APP_CORE_SRC YAZE_APP_CORE_SRC
@@ -62,16 +85,17 @@ set(
set( set(
YAZE_APP_GFX_SRC YAZE_APP_GFX_SRC
app/gfx/bitmap.cc app/gfx/bitmap.cc
app/gfx/pseudo_vram.cc
app/gfx/snes_palette.cc app/gfx/snes_palette.cc
app/gfx/snes_tile.cc app/gfx/snes_tile.cc
) )
set( set(
YAZE_APP_ZELDA3_SRC YAZE_APP_ZELDA3_SRC
app/zelda3/inventory.cc
app/zelda3/overworld_map.cc app/zelda3/overworld_map.cc
app/zelda3/overworld.cc app/zelda3/overworld.cc
app/zelda3/screen.cc app/zelda3/title_screen.cc
app/zelda3/sprite.cc
) )
set( set(
@@ -85,6 +109,7 @@ set(
gui/input.cc gui/input.cc
gui/style.cc gui/style.cc
gui/widgets.cc gui/widgets.cc
gui/color.cc
) )
add_executable( add_executable(
@@ -98,7 +123,7 @@ add_executable(
${YAZE_APP_ZELDA3_SRC} ${YAZE_APP_ZELDA3_SRC}
${YAZE_GUI_SRC} ${YAZE_GUI_SRC}
${IMGUI_SRC} ${IMGUI_SRC}
lib/asar/src/asar-dll-bindings/c/asardll.c ${ASAR_STATIC_SRC}
) )
target_include_directories( target_include_directories(
@@ -110,7 +135,7 @@ target_include_directories(
${PNG_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS}
${SDL2_INCLUDE_DIR} ${SDL2_INCLUDE_DIR}
${GLEW_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS}
lib/asar/src/asar-dll-bindings/c lib/asar/src/
) )
set(SDL_TARGETS SDL2::SDL2) set(SDL_TARGETS SDL2::SDL2)
@@ -129,7 +154,10 @@ target_link_libraries(
${OPENGL_LIBRARIES} ${OPENGL_LIBRARIES}
${CMAKE_DL_LIBS} ${CMAKE_DL_LIBS}
ImGui ImGui
asar-static
) )
target_compile_definitions(yaze PRIVATE "linux")
target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp")
set_target_properties(yaze set_target_properties(yaze
PROPERTIES PROPERTIES
@@ -139,6 +167,48 @@ set_target_properties(yaze
LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/yaze.res" LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/yaze.res"
) )
add_subdirectory(app/delta)
add_executable(
yaze_delta
app/delta/delta.cc
app/delta/viewer.cc
app/delta/client.cc
app/rom.cc
${YAZE_APP_ASM_SRC}
${YAZE_APP_CORE_SRC}
${YAZE_APP_EDITOR_SRC}
${YAZE_APP_GFX_SRC}
${YAZE_APP_ZELDA3_SRC}
${YAZE_GUI_SRC}
${IMGUI_SRC}
)
target_include_directories(
yaze_delta PUBLIC
lib/
app/
${ASAR_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/src/
${PNG_INCLUDE_DIRS}
${SDL2_INCLUDE_DIR}
${GLEW_INCLUDE_DIRS}
${ASAR_STATIC_SRC}
)
target_link_libraries(
yaze_delta PUBLIC
${ABSL_TARGETS}
${SDL_TARGETS}
${PNG_LIBRARIES}
${GLEW_LIBRARIES}
${OPENGL_LIBRARIES}
${CMAKE_DL_LIBS}
delta-service
asar-static
ImGui
)
set (source "${CMAKE_SOURCE_DIR}/assets") set (source "${CMAKE_SOURCE_DIR}/assets")
set (destination "${CMAKE_CURRENT_BINARY_DIR}/assets") set (destination "${CMAKE_CURRENT_BINARY_DIR}/assets")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD

View File

@@ -1,6 +1,6 @@
#include "script.h" #include "script.h"
#include <asardll.h> #include <asar/interface-lib.h>
#include <array> #include <array>
#include <cstdint> #include <cstdint>
@@ -20,49 +20,13 @@ namespace yaze {
namespace app { namespace app {
namespace snes_asm { namespace snes_asm {
std::string GenerateBytePool(char mosaic_tiles[core::kNumOverworldMaps]) {
std::string to_return = "";
int column = 0;
for (int i = 0; i < core::kNumOverworldMaps; ++i) {
std::string to_add = "";
// if start of line, define byte
if (i == 0 || i % 8 == 0) {
to_add += " db ";
}
// set byte
to_add += "$00";
if (mosaic_tiles[i] > 0) {
if (i == 0 || i % 8 == 0) {
to_add = " db $01";
} else {
to_add = "$01";
}
}
// newline or comma separated
if (column == 7) {
column = 0;
to_add += " \n";
} else {
column++;
to_add += ", ";
}
to_return += to_add;
}
return to_return;
}
absl::Status Script::ApplyPatchToROM(ROM &rom) { absl::Status Script::ApplyPatchToROM(ROM &rom) {
if (patch_contents_.empty() || patch_filename_.empty()) { if (patch_contents_.empty() || patch_filename_.empty()) {
return absl::InvalidArgumentError("No patch loaded!"); return absl::InvalidArgumentError("No patch loaded!");
} }
char *data = (char *)rom.data();
int size = rom.GetSize();
int count = 0; int count = 0;
auto data = (char *)rom.data();
int size = rom.size();
if (!asar_patch(patch_filename_.c_str(), data, patch_size_, &size)) { if (!asar_patch(patch_filename_.c_str(), data, patch_size_, &size)) {
auto asar_error = asar_geterrors(&count); auto asar_error = asar_geterrors(&count);
auto full_error = asar_error->fullerrdata; auto full_error = asar_error->fullerrdata;
@@ -71,43 +35,37 @@ absl::Status Script::ApplyPatchToROM(ROM &rom) {
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status Script::GenerateMosaicChangeAssembly( absl::Status Script::PatchOverworldMosaic(
ROM &rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, ROM &rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset,
int hook_offset) { int hook_offset) {
for (int i = 0; i < core::kNumOverworldMaps; i++) {
if (mosaic_tiles[i]) {
rom[core::overworldCustomMosaicArray + i] = 0x01;
} else {
rom[core::overworldCustomMosaicArray + i] = 0x00;
}
}
std::fstream file("assets/asm/mosaic_change.asm", std::fstream file("assets/asm/mosaic_change.asm",
std::ios::out | std::ios::in); std::ios::out | std::ios::in);
if (!file.is_open()) { if (!file.is_open()) {
return absl::InvalidArgumentError( return absl::InvalidArgumentError(
"Couldn't open mosaic change template file"); "Unable to open mosaic change assembly source");
} }
std::stringstream assembly; std::stringstream assembly;
assembly << file.rdbuf(); assembly << file.rdbuf();
file.close(); file.close();
auto assembly_string = assembly.str(); auto assembly_string = assembly.str();
if (!core::StringReplace(assembly_string, "<HOOK>", kMosaicChangeOffset)) { if (!core::StringReplace(assembly_string, "<HOOK>", kMosaicChangeOffset)) {
return absl::InternalError( return absl::InternalError(
"Mosaic template did not have proper `<HOOK>` to replace."); "Mosaic template did not have proper `<HOOK>` to replace.");
} }
if (!core::StringReplace( if (!core::StringReplace(
assembly_string, "<EXPANDED_SPACE>", assembly_string, "<EXPANDED_SPACE>",
absl::StrFormat("$%x", routine_offset + kSNESToPCOffset))) { absl::StrFormat("$%x", routine_offset + kSNESToPCOffset))) {
return absl::InternalError( return absl::InternalError(
"Mosaic template did not have proper `<EXPANDED_SPACE>` to replace."); "Mosaic template did not have proper `<EXPANDED_SPACE>` to replace.");
} }
assembly_string += GenerateBytePool(mosaic_tiles);
patch_contents_ = assembly_string; patch_contents_ = assembly_string;
patch_filename_ = "assets/asm/mosaic_change_generated.asm";
std::ofstream new_file(patch_filename_, std::ios::out);
if (new_file.is_open()) {
new_file.write(assembly_string.c_str(), assembly_string.size());
new_file.close();
}
return ApplyPatchToROM(rom); return ApplyPatchToROM(rom);
} }

View File

@@ -1,7 +1,7 @@
#ifndef YAZE_APP_ASM_SCRIPT_H #ifndef YAZE_APP_ASM_SCRIPT_H
#define YAZE_APP_ASM_SCRIPT_H #define YAZE_APP_ASM_SCRIPT_H
#include <asardll.h> #include <asar/interface-lib.h>
#include <array> #include <array>
#include <cstdint> #include <cstdint>
@@ -27,17 +27,15 @@ class ScriptTemplate {
public: public:
virtual ~ScriptTemplate() = default; virtual ~ScriptTemplate() = default;
virtual absl::Status ApplyPatchToROM(ROM& rom) = 0; virtual absl::Status ApplyPatchToROM(ROM& rom) = 0;
virtual absl::Status GenerateMosaicChangeAssembly( virtual absl::Status PatchOverworldMosaic(
ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset,
int hook_offset = 0) = 0; int hook_offset = 0) = 0;
}; };
class Script : public ScriptTemplate { class Script : public ScriptTemplate {
public: public:
Script() { asar_init_with_dll_path("assets/libasar.dll"); }
absl::Status ApplyPatchToROM(ROM& rom) override; absl::Status ApplyPatchToROM(ROM& rom) override;
absl::Status GenerateMosaicChangeAssembly( absl::Status PatchOverworldMosaic(
ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset,
int hook_offset = 0) override; int hook_offset = 0) override;

View File

@@ -25,6 +25,14 @@
#define MENU_ITEM(w) if (ImGui::MenuItem(w)) #define MENU_ITEM(w) if (ImGui::MenuItem(w))
#define MENU_ITEM2(w, v) if (ImGui::MenuItem(w, v)) #define MENU_ITEM2(w, v) if (ImGui::MenuItem(w, v))
#define BUTTON_COLUMN(w) \
ImGui::TableNextColumn(); \
ImGui::Button(w);
#define TEXT_COLUMN(w) \
ImGui::TableNextColumn(); \
ImGui::Text(w);
#define PRINT_IF_ERROR(expression) \ #define PRINT_IF_ERROR(expression) \
{ \ { \
auto error = expression; \ auto error = expression; \
@@ -474,7 +482,7 @@ constexpr int customAreaSpecificBGPalette =
constexpr int customAreaSpecificBGASM = 0x140150; constexpr int customAreaSpecificBGASM = 0x140150;
constexpr int customAreaSpecificBGEnabled = constexpr int customAreaSpecificBGEnabled =
0x140140; // 1 byte, not 0 if enabled 0x140140; // 1 byte, not 0 if enabled
constexpr int overworldCustomMosaicArray = 0x1301F0;
// ============================================================================ // ============================================================================
// Dungeon Map Related Variables // Dungeon Map Related Variables
// ============================================================================ // ============================================================================
@@ -1301,6 +1309,294 @@ static const absl::string_view TileTypeNames[] = {
"$FE Door X top? (unused?)", "$FE Door X top? (unused?)",
"$FF Door X top? (unused?)"}; "$FF Door X top? (unused?)"};
static const absl::string_view 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 absl::string_view 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 core
} // namespace app } // namespace app
} // namespace yaze } // namespace yaze

View File

@@ -26,6 +26,7 @@ class Controller {
absl::Status onEntry(); absl::Status onEntry();
void onInput(); void onInput();
void onLoad(); void onLoad();
void onLoadDelta();
void doRender() const; void doRender() const;
void onExit() const; void onExit() const;

View File

@@ -0,0 +1,32 @@
add_library(delta-service delta.proto)
target_link_libraries(delta-service
PUBLIC
protobuf::libprotobuf
gRPC::grpc
gRPC::grpc++
)
target_include_directories(delta-service
PUBLIC
${CMAKE_CURRENT_BINARY_DIR}
${PROTOBUF_INCLUDE_PATH}
)
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
# compile the message types
protobuf_generate(TARGET delta-service LANGUAGE cpp)
# compile the GRPC services
protobuf_generate(
TARGET
delta-service
LANGUAGE
grpc
GENERATE_EXTENSIONS
.grpc.pb.h
.grpc.pb.cc
PLUGIN
"protoc-gen-grpc=${grpc_cpp_plugin_location}"
)

53
src/app/delta/client.cc Normal file
View File

@@ -0,0 +1,53 @@
#include "client.h"
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#include "absl/status/status.h"
#include "src/app/delta/delta.grpc.pb.h"
#include "src/app/delta/delta.pb.h"
namespace yaze {
namespace app {
namespace delta {
using grpc::Channel;
using grpc::ClientAsyncResponseReader;
using grpc::ClientContext;
using grpc::CompletionQueue;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::Status;
void Client::CreateChannel() {
auto channel = grpc::CreateChannel("localhost:50051",
grpc::InsecureChannelCredentials());
stub_ = ::YazeDelta::NewStub(channel);
}
absl::Status Client::InitRepo(std::string author_name,
std::string project_name) {
Repository new_repo;
new_repo.set_author_name(author_name);
new_repo.set_project_name(project_name);
InitRequest request;
request.set_allocated_repo(&new_repo);
InitResponse response;
Status status = stub_->Init(&rpc_context, request, &response);
if (!status.ok()) {
std::cerr << status.error_code() << ": " << status.error_message()
<< std::endl;
return absl::InternalError(status.error_message());
}
return absl::OkStatus();
}
} // namespace delta
} // namespace app
} // namespace yaze

44
src/app/delta/client.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef YAZE_APP_DELTA_CLIENT_H
#define YAZE_APP_DELTA_CLIENT_H
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#include <vector>
#include "absl/status/status.h"
#include "src/app/delta/delta.grpc.pb.h"
#include "src/app/delta/delta.pb.h"
namespace yaze {
namespace app {
namespace delta {
using grpc::Channel;
using grpc::ClientAsyncResponseReader;
using grpc::ClientContext;
using grpc::CompletionQueue;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::Status;
class Client {
public:
Client() = default;
void CreateChannel();
absl::Status InitRepo(std::string author_name, std::string project_name);
private:
ClientContext rpc_context;
std::vector<Repository> repos_;
std::unique_ptr<YazeDelta::Stub> stub_;
};
} // namespace delta
} // namespace app
} // namespace yaze
#endif

32
src/app/delta/delta.cc Normal file
View File

@@ -0,0 +1,32 @@
#if defined(_WIN32)
#define main SDL_main
#endif
#include "absl/debugging/failure_signal_handler.h"
#include "absl/debugging/symbolize.h"
#include "app/core/controller.h"
#include "app/delta/viewer.h"
int main(int argc, char** argv) {
absl::InitializeSymbolizer(argv[0]);
absl::FailureSignalHandlerOptions options;
absl::InstallFailureSignalHandler(options);
yaze::app::core::Controller controller;
yaze::app::delta::Viewer viewer;
auto entry_status = controller.onEntry();
if (!entry_status.ok()) {
return EXIT_FAILURE;
}
while (controller.isActive()) {
controller.onInput();
viewer.Update();
controller.doRender();
}
controller.onExit();
return EXIT_SUCCESS;
}

80
src/app/delta/delta.proto Normal file
View File

@@ -0,0 +1,80 @@
syntax = "proto3";
option cc_enable_arenas = true;
service YazeDelta {
rpc Init(InitRequest) returns (InitResponse) {}
rpc Clone(CloneRequest) returns (CloneResponse) {}
rpc Push(PushRequest) returns (PushResponse) {}
rpc Pull(PullRequest) returns (PullResponse) {}
rpc Sync(stream SyncRequest) returns (stream SyncResponse) {}
rpc CreateBranch(CreateBranchRequest) returns (CreateBranchResponse) {}
rpc DeleteBranch(DeleteBranchRequest) returns (DeleteBranchResponse) {}
rpc Merge(MergeRequest) returns (MergeResponse) {}
rpc UndoMerge(UndoMergeRequest) returns (UndoMergeResponse) {}
}
message Commit {
int64 commit_id = 1;
int64 parent_commit_id = 2;
string author_name = 3;
string message_header = 4;
optional string message_body = 5;
bytes data = 6;
int64 signature = 7;
}
message Branch {
string branch_name = 1;
optional string parent_name = 2;
repeated Commit commits = 3;
}
message Repository {
string project_name = 1;
string author_name = 2;
int64 signature = 3;
optional bool locked = 4;
optional string password = 5;
repeated Branch tree = 6;
}
message InitRequest {
Repository repo = 1;
}
message InitResponse {
int32 response = 1;
}
message CloneRequest {}
message CloneResponse {}
message PushRequest {
string author_name = 1;
}
message PushResponse {}
message PullRequest {}
message PullResponse {}
message SyncRequest {}
message SyncResponse {}
message CreateBranchRequest {}
message CreateBranchResponse {}
message DeleteBranchRequest {}
message DeleteBranchResponse {}
message MergeRequest {}
message MergeResponse {}
message UndoMergeRequest {}
message UndoMergeResponse {}

42
src/app/delta/service.cc Normal file
View File

@@ -0,0 +1,42 @@
#include "service.h"
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#include "absl/status/status.h"
#include "src/app/delta/delta.grpc.pb.h"
#include "src/app/delta/delta.pb.h"
namespace yaze {
namespace app {
namespace delta {
using grpc::Channel;
using grpc::ClientAsyncResponseReader;
using grpc::ClientContext;
using grpc::CompletionQueue;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::Status;
Status DeltaService::Init(grpc::ServerContext* context,
const InitRequest* request, InitResponse* reply) {
return Status::OK;
}
Status DeltaService::Push(grpc::ServerContext* context,
const PushRequest* request, PushResponse* reply) {
return Status::OK;
}
Status DeltaService::Pull(grpc::ServerContext* context,
const PullRequest* request, PullResponse* reply) {
return Status::OK;
}
} // namespace delta
} // namespace app
} // namespace yaze

37
src/app/delta/service.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef YAZE_APP_DELTA_SERVICE_H
#define YAZE_APP_DELTA_SERVICE_H
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#include <vector>
#include "absl/status/status.h"
#include "src/app/delta/delta.grpc.pb.h"
#include "src/app/delta/delta.pb.h"
namespace yaze {
namespace app {
namespace delta {
class DeltaService final : public ::YazeDelta::Service {
public:
Status Init(grpc::ServerContext* context, const InitRequest* request,
InitResponse* reply) override;
Status Push(grpc::ServerContext* context, const PushRequest* request,
PushResponse* reply) override;
Status Pull(grpc::ServerContext* context, const PullRequest* request,
PullResponse* reply) override;
private:
std::vector<Repository> repos_;
};
} // namespace delta
} // namespace app
} // namespace yaze

229
src/app/delta/viewer.cc Normal file
View File

@@ -0,0 +1,229 @@
#include "viewer.h"
#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/constants.h"
#include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h"
#include "app/rom.h"
#include "gui/canvas.h"
#include "gui/icons.h"
#include "gui/input.h"
namespace yaze {
namespace app {
namespace delta {
namespace {
constexpr ImGuiWindowFlags kMainEditorFlags =
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar;
void NewMasterFrame() {
const ImGuiIO& io = ImGui::GetIO();
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, kMainEditorFlags)) {
ImGui::End();
return;
}
}
} // namespace
void Viewer::Update() {
NewMasterFrame();
DrawYazeMenu();
DrawFileDialog();
ImGui::Text(ICON_MD_CHANGE_HISTORY);
ImGui::SameLine();
ImGui::Text("%s", rom_.GetTitle());
ImGui::Separator();
ImGui::Button(ICON_MD_SYNC);
ImGui::SameLine();
ImGui::Button(ICON_MD_ARROW_UPWARD);
ImGui::SameLine();
ImGui::Button(ICON_MD_ARROW_DOWNWARD);
ImGui::SameLine();
ImGui::Button(ICON_MD_MERGE);
ImGui::SameLine();
ImGui::Button(ICON_MD_MANAGE_HISTORY);
ImGui::SameLine();
ImGui::Button(ICON_MD_LAN);
ImGui::SameLine();
ImGui::Button(ICON_MD_COMMIT);
ImGui::SameLine();
ImGui::Button(ICON_MD_DIFFERENCE);
ImGui::Separator();
ImGui::SetNextItemWidth(75.f);
ImGui::Button(ICON_MD_SEND);
ImGui::SameLine();
ImGui::InputText("Server Address", &client_address_);
ImGui::SetNextItemWidth(75.f);
ImGui::Button(ICON_MD_DOWNLOAD);
ImGui::SameLine();
ImGui::InputText("Repository Source", &client_address_);
ImGui::Separator();
DrawBranchTree();
ImGui::End();
}
void Viewer::DrawFileDialog() {
if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey")) {
if (ImGuiFileDialog::Instance()->IsOk()) {
std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
rom_.LoadFromFile(filePathName);
}
ImGuiFileDialog::Instance()->Close();
}
}
void Viewer::DrawYazeMenu() {
MENU_BAR()
DrawFileMenu();
DrawViewMenu();
END_MENU_BAR()
}
void Viewer::DrawFileMenu() const {
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open", "Ctrl+O")) {
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open ROM",
".sfc,.smc", ".");
}
MENU_ITEM2("Save", "Ctrl+S") {}
ImGui::EndMenu();
}
}
void Viewer::DrawViewMenu() {
static bool show_imgui_metrics = false;
static bool show_imgui_style_editor = false;
static bool show_memory_editor = false;
static bool show_imgui_demo = false;
if (show_imgui_metrics) {
ImGui::ShowMetricsWindow(&show_imgui_metrics);
}
if (show_memory_editor) {
static MemoryEditor mem_edit;
mem_edit.DrawWindow("Memory Editor", (void*)&rom_, rom_.size());
}
if (show_imgui_demo) {
ImGui::ShowDemoWindow();
}
if (show_imgui_style_editor) {
ImGui::Begin("Style Editor (ImGui)", &show_imgui_style_editor);
ImGui::ShowStyleEditor();
ImGui::End();
}
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("HEX Editor", nullptr, &show_memory_editor);
ImGui::MenuItem("ImGui Demo", nullptr, &show_imgui_demo);
ImGui::Separator();
if (ImGui::BeginMenu("GUI Tools")) {
ImGui::MenuItem("Metrics (ImGui)", nullptr, &show_imgui_metrics);
ImGui::MenuItem("Style Editor (ImGui)", nullptr,
&show_imgui_style_editor);
ImGui::EndMenu();
}
ImGui::EndMenu();
}
}
void Viewer::DrawBranchTree() {
static ImGuiTableFlags flags =
ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH |
ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg |
ImGuiTableFlags_NoBordersInBody;
if (ImGui::BeginTable("3ways", 3, flags)) {
// The first column will use the default _WidthStretch when ScrollX is Off
// and _WidthFixed when ScrollX is On
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed,
10 * 12.0f);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed,
10 * 18.0f);
ImGui::TableHeadersRow();
// Simple storage to output a dummy file-system.
struct MyTreeNode {
const char* Name;
const char* Type;
int Size;
int ChildIdx;
int ChildCount;
static void DisplayNode(const MyTreeNode* node,
const MyTreeNode* all_nodes) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
const bool is_folder = (node->ChildCount > 0);
if (is_folder) {
bool open =
ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::TextDisabled("--");
ImGui::TableNextColumn();
ImGui::TextUnformatted(node->Type);
if (open) {
for (int child_n = 0; child_n < node->ChildCount; child_n++)
DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
ImGui::TreePop();
}
} else {
ImGui::TreeNodeEx(
node->Name, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet |
ImGuiTreeNodeFlags_NoTreePushOnOpen |
ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::Text("%d", node->Size);
ImGui::TableNextColumn();
ImGui::TextUnformatted(node->Type);
}
}
};
static const MyTreeNode nodes[] = {
{"lttp-redux", "Repository", -1, 1, 3},
{"main", "Branch", -1, 4, 2},
{"hyrule-castle", "Branch", -1, 4, 2},
{"lost-woods", "Branch", -1, 6, 3},
{"Added some bushes", "Commit", 1024, -1, -1},
{"Constructed a new house", "Commit", 123000, -1, -1},
{"File1_b.wav", "Commit", 456000, -1, -1},
{"Image001.png", "Commit", 203128, -1, -1},
{"Copy of Image001.png", "Commit", 203256, -1, -1},
{"Copy of Image001 (Final2).png", "Commit", 203512, -1, -1},
};
MyTreeNode::DisplayNode(&nodes[0], nodes);
ImGui::EndTable();
}
}
} // namespace delta
} // namespace app
} // namespace yaze

45
src/app/delta/viewer.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef YAZE_APP_DELTA_VIEWER_H
#define YAZE_APP_DELTA_VIEWER_H
#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/constants.h"
#include "app/delta/client.h"
#include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h"
#include "app/rom.h"
#include "gui/canvas.h"
#include "gui/icons.h"
#include "gui/input.h"
namespace yaze {
namespace app {
namespace delta {
class Viewer {
public:
void Update();
private:
void DrawFileDialog();
void DrawYazeMenu();
void DrawFileMenu() const;
void DrawViewMenu();
void DrawBranchTree();
std::string client_address_;
ROM rom_;
Client client_;
};
} // namespace delta
} // namespace app
} // namespace yaze
#endif

View File

@@ -103,6 +103,7 @@ void MasterEditor::DrawFileDialog() {
status_ = rom_.LoadFromFile(filePathName); status_ = rom_.LoadFromFile(filePathName);
overworld_editor_.SetupROM(rom_); overworld_editor_.SetupROM(rom_);
screen_editor_.SetupROM(rom_); screen_editor_.SetupROM(rom_);
palette_editor_.SetupROM(rom_);
} }
ImGuiFileDialog::Instance()->Close(); ImGuiFileDialog::Instance()->Close();
} }
@@ -118,10 +119,10 @@ void MasterEditor::DrawAboutPopup() {
if (about_) ImGui::OpenPopup("About"); if (about_) ImGui::OpenPopup("About");
if (ImGui::BeginPopupModal("About", nullptr, if (ImGui::BeginPopupModal("About", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) { ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Yet Another Zelda3 Editor - v0.01"); ImGui::Text("Yet Another Zelda3 Editor - v0.02");
ImGui::Text("Written by: scawful"); ImGui::Text("Written by: scawful");
ImGui::Spacing(); ImGui::Spacing();
ImGui::Text("Special Thanks: Zarby89"); ImGui::Text("Special Thanks: Zarby89, JaredBrian");
ImGui::Separator(); ImGui::Separator();
if (ImGui::Button("Close", ImVec2(200, 0))) { if (ImGui::Button("Close", ImVec2(200, 0))) {
@@ -137,7 +138,7 @@ void MasterEditor::DrawInfoPopup() {
if (ImGui::BeginPopupModal("ROM Information", nullptr, if (ImGui::BeginPopupModal("ROM Information", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) { ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Title: %s", rom_.GetTitle()); ImGui::Text("Title: %s", rom_.GetTitle());
ImGui::Text("ROM Size: %ld", rom_.GetSize()); ImGui::Text("ROM Size: %ld", rom_.size());
if (ImGui::Button("Close", ImVec2(200, 0))) { if (ImGui::Button("Close", ImVec2(200, 0))) {
rom_info_ = false; rom_info_ = false;
@@ -215,7 +216,7 @@ void MasterEditor::DrawViewMenu() {
if (show_memory_editor) { if (show_memory_editor) {
static MemoryEditor mem_edit; static MemoryEditor mem_edit;
mem_edit.DrawWindow("Memory Editor", (void *)&rom_, rom_.GetSize()); mem_edit.DrawWindow("Memory Editor", (void *)&rom_, rom_.size());
} }
if (show_imgui_demo) { if (show_imgui_demo) {

View File

@@ -8,6 +8,8 @@
#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_map.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "app/editor/palette_editor.h"
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h" #include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h" #include "app/gfx/snes_tile.h"
@@ -22,15 +24,15 @@ namespace editor {
namespace { namespace {
void UpdateSelectedTile16(int selected, gfx::Bitmap &tile16_blockset, void UpdateSelectedTile16(int selected, gfx::Bitmap &tile16_blockset,
gfx::Bitmap &selected_tile) { Bytes &selected_tile) {
selected_tile.reserve(256);
auto blockset = tile16_blockset.GetData(); auto blockset = tile16_blockset.GetData();
auto bitmap = selected_tile.GetData();
int src_pos = ((selected - ((selected / 0x08) * 0x08)) * 0x10) + int src_pos = ((selected - ((selected / 0x08) * 0x08)) * 0x10) +
((selected / 0x08) * 2048); ((selected / 0x08) * 2048);
for (int yy = 0; yy < 0x10; yy++) { for (int yy = 0; yy < 0x10; yy++) {
for (int xx = 0; xx < 0x10; xx++) { for (int xx = 0; xx < 0x10; xx++) {
bitmap[xx + (yy * 0x10)] = blockset[src_pos + xx + (yy * 0x80)]; selected_tile[xx + (yy * 0x10)] = blockset[src_pos + xx + (yy * 0x80)];
} }
} }
} }
@@ -44,25 +46,21 @@ absl::Status OverworldEditor::Update() {
all_gfx_loaded_ = true; all_gfx_loaded_ = true;
RETURN_IF_ERROR(overworld_.Load(rom_)) RETURN_IF_ERROR(overworld_.Load(rom_))
current_gfx_bmp_.Create(128, 512, 64, overworld_.GetCurrentGraphics()); palette_ = overworld_.AreaPalette();
current_gfx_bmp_.Create(128, 512, 64, overworld_.AreaGraphics());
current_gfx_bmp_.ApplyPalette(palette_);
rom_.RenderBitmap(&current_gfx_bmp_); rom_.RenderBitmap(&current_gfx_bmp_);
auto tile16_palette = overworld_.GetCurrentPalette(); tile16_blockset_bmp_.Create(128, 8192, 128, overworld_.Tile16Blockset());
tile16_blockset_bmp_.Create(128, 8192, 128, tile16_blockset_bmp_.ApplyPalette(palette_);
overworld_.GetCurrentBlockset());
for (int j = 0; j < tile16_palette.colors.size(); j++) {
tile16_blockset_bmp_.SetPaletteColor(j, tile16_palette.GetColor(j));
}
rom_.RenderBitmap(&tile16_blockset_bmp_); rom_.RenderBitmap(&tile16_blockset_bmp_);
map_blockset_loaded_ = true; map_blockset_loaded_ = true;
for (int i = 0; i < core::kNumOverworldMaps; ++i) { for (int i = 0; i < core::kNumOverworldMaps; ++i) {
overworld_.SetCurrentMap(i); overworld_.SetCurrentMap(i);
auto palette = overworld_.GetCurrentPalette(); auto palette = overworld_.AreaPalette();
maps_bmp_[i].Create(512, 512, 512, overworld_.GetCurrentBitmapData()); maps_bmp_[i].Create(512, 512, 512, overworld_.BitmapData());
for (int j = 0; j < palette.colors.size(); j++) { maps_bmp_[i].ApplyPalette(palette);
maps_bmp_[i].SetPaletteColor(j, palette.GetColor(j));
}
rom_.RenderBitmap(&(maps_bmp_[i])); rom_.RenderBitmap(&(maps_bmp_[i]));
} }
} }
@@ -72,11 +70,8 @@ absl::Status OverworldEditor::Update() {
selected_tile_bmp_.Create(16, 16, 64, 256); selected_tile_bmp_.Create(16, 16, 64, 256);
} }
UpdateSelectedTile16(selected_tile_, tile16_blockset_bmp_, UpdateSelectedTile16(selected_tile_, tile16_blockset_bmp_,
selected_tile_bmp_); selected_tile_data_);
auto palette = overworld_.GetCurrentPalette(); selected_tile_bmp_.ApplyPalette(palette_);
for (int j = 0; j < palette.colors.size(); j++) {
selected_tile_bmp_.SetPaletteColor(j, palette.GetColor(j));
}
rom_.RenderBitmap(&selected_tile_bmp_); rom_.RenderBitmap(&selected_tile_bmp_);
update_selected_tile_ = false; update_selected_tile_ = false;
} }
@@ -102,44 +97,26 @@ absl::Status OverworldEditor::Update() {
} }
absl::Status OverworldEditor::DrawToolset() { absl::Status OverworldEditor::DrawToolset() {
if (ImGui::BeginTable("OWToolset", 15, toolset_table_flags, ImVec2(0, 0))) { if (ImGui::BeginTable("OWToolset", 17, toolset_table_flags, ImVec2(0, 0))) {
for (const auto &name : kToolsetColumnNames) for (const auto &name : kToolsetColumnNames)
ImGui::TableSetupColumn(name.data()); ImGui::TableSetupColumn(name.data());
ImGui::TableNextColumn(); BUTTON_COLUMN(ICON_MD_UNDO) // Undo
ImGui::Button(ICON_MD_UNDO); BUTTON_COLUMN(ICON_MD_REDO) // Redo
ImGui::TableNextColumn(); TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator
ImGui::Button(ICON_MD_REDO); BUTTON_COLUMN(ICON_MD_ZOOM_OUT) // Zoom Out
ImGui::TableNextColumn(); BUTTON_COLUMN(ICON_MD_ZOOM_IN) // Zoom In
ImGui::Text(ICON_MD_MORE_VERT); TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator
BUTTON_COLUMN(ICON_MD_DRAW) // Draw Tile
ImGui::TableNextColumn(); BUTTON_COLUMN(ICON_MD_DOOR_FRONT) // Entrances
ImGui::Button(ICON_MD_ZOOM_OUT); BUTTON_COLUMN(ICON_MD_DOOR_BACK) // Exits
ImGui::TableNextColumn(); BUTTON_COLUMN(ICON_MD_GRASS) // Items
ImGui::Button(ICON_MD_ZOOM_IN); BUTTON_COLUMN(ICON_MD_PEST_CONTROL_RODENT) // Sprites
ImGui::TableNextColumn(); BUTTON_COLUMN(ICON_MD_ADD_LOCATION) // Transports
ImGui::Text(ICON_MD_MORE_VERT); BUTTON_COLUMN(ICON_MD_MUSIC_NOTE) // Music
TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator
ImGui::TableNextColumn(); ImGui::TableNextColumn(); // Palette
ImGui::Button(ICON_MD_DRAW); palette_editor_.DisplayPalette(palette_, overworld_.isLoaded());
// Entrances
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_DOOR_FRONT);
// Exits
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_DOOR_BACK);
// Items
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_GRASS);
// Sprites
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_PEST_CONTROL_RODENT);
// Transports
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_ADD_LOCATION);
// Music
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_MUSIC_NOTE);
ImGui::EndTable(); ImGui::EndTable();
} }
@@ -218,6 +195,15 @@ void OverworldEditor::DrawOverworldCanvas() {
xx = 0; xx = 0;
} }
} }
for (const auto &each : overworld_.Entrances()) {
if (each.mapId_ < 64 + (current_world_ * 0x40) &&
each.mapId_ >= (current_world_ * 0x40)) {
overworld_map_canvas_.DrawRect(each.x_, each.y_, 16, 16,
ImVec4(210, 24, 210, 150));
std::string str = absl::StrFormat("%#x", each.entranceId_);
overworld_map_canvas_.DrawText(str, each.x_ - 4, each.y_ - 2);
}
}
} }
overworld_map_canvas_.DrawGrid(64.f); overworld_map_canvas_.DrawGrid(64.f);
overworld_map_canvas_.DrawOverlay(); overworld_map_canvas_.DrawOverlay();
@@ -261,9 +247,7 @@ void OverworldEditor::DrawTileSelector() {
void OverworldEditor::DrawTile16Selector() { void OverworldEditor::DrawTile16Selector() {
blockset_canvas_.DrawBackground(ImVec2(0x100 + 1, (8192 * 2) + 1)); blockset_canvas_.DrawBackground(ImVec2(0x100 + 1, (8192 * 2) + 1));
blockset_canvas_.DrawContextMenu(); blockset_canvas_.DrawContextMenu();
if (map_blockset_loaded_) { blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 2, map_blockset_loaded_);
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 2);
}
blockset_canvas_.DrawGrid(32.0f); blockset_canvas_.DrawGrid(32.0f);
blockset_canvas_.DrawOverlay(); blockset_canvas_.DrawOverlay();
} }
@@ -291,13 +275,11 @@ void OverworldEditor::DrawTile8Selector() {
} }
void OverworldEditor::DrawAreaGraphics() { void OverworldEditor::DrawAreaGraphics() {
if (overworld_.isLoaded()) { current_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 16 * 64 + 1));
current_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 16 * 64 + 1)); current_gfx_canvas_.DrawContextMenu();
current_gfx_canvas_.DrawContextMenu(); current_gfx_canvas_.DrawBitmap(current_gfx_bmp_, 2, overworld_.isLoaded());
current_gfx_canvas_.DrawBitmap(current_gfx_bmp_); current_gfx_canvas_.DrawGrid(32.0f);
current_gfx_canvas_.DrawGrid(32.0f); current_gfx_canvas_.DrawOverlay();
current_gfx_canvas_.DrawOverlay();
}
} }
void OverworldEditor::LoadGraphics() { void OverworldEditor::LoadGraphics() {

View File

@@ -9,6 +9,8 @@
#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_map.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "app/editor/palette_editor.h"
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h" #include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h" #include "app/gfx/snes_tile.h"
@@ -29,10 +31,10 @@ static constexpr uint kTile8DisplayHeight = 64;
static constexpr float kInputFieldSize = 30.f; static constexpr float kInputFieldSize = 30.f;
static constexpr absl::string_view kToolsetColumnNames[] = { static constexpr absl::string_view kToolsetColumnNames[] = {
"#undoTool", "#redoTool", "#drawTool", "#separator2", "#undoTool", "#redoTool", "#drawTool", "#separator2",
"#zoomOutTool", "#zoomInTool", "#separator", "#history", "#zoomOutTool", "#zoomInTool", "#separator", "#history",
"#entranceTool", "#exitTool", "#itemTool", "#spriteTool", "#entranceTool", "#exitTool", "#itemTool", "#spriteTool",
"#transportTool", "#musicTool" }; "#transportTool", "#musicTool"};
static constexpr absl::string_view kOverworldSettingsColumnNames[] = { static constexpr absl::string_view kOverworldSettingsColumnNames[] = {
"##1stCol", "##gfxCol", "##palCol", "##sprgfxCol", "##1stCol", "##gfxCol", "##palCol", "##sprgfxCol",
@@ -82,17 +84,20 @@ class OverworldEditor {
ImGuiTableFlags_Resizable | ImGuiTableFlags_Resizable |
ImGuiTableFlags_SizingStretchSame; ImGuiTableFlags_SizingStretchSame;
Bytes selected_tile_data_;
std::unordered_map<int, gfx::Bitmap> graphics_bin_; std::unordered_map<int, gfx::Bitmap> graphics_bin_;
std::unordered_map<int, gfx::Bitmap> current_graphics_set_; std::unordered_map<int, gfx::Bitmap> current_graphics_set_;
std::unordered_map<int, gfx::Bitmap> maps_bmp_; std::unordered_map<int, gfx::Bitmap> maps_bmp_;
std::unordered_map<int, gfx::Bitmap> sprite_previews_;
ROM rom_; ROM rom_;
PaletteEditor palette_editor_;
zelda3::Overworld overworld_; zelda3::Overworld overworld_;
gfx::SNESPalette palette_; gfx::SNESPalette palette_;
gfx::Bitmap tile16_blockset_bmp_; // pointer size 1048576 gfx::Bitmap tile16_blockset_bmp_;
gfx::Bitmap current_gfx_bmp_; // pointer size 32768 gfx::Bitmap current_gfx_bmp_;
gfx::Bitmap all_gfx_bmp; // pointer size 456704 gfx::Bitmap all_gfx_bmp;
gfx::Bitmap selected_tile_bmp_; gfx::Bitmap selected_tile_bmp_;
gui::Canvas overworld_map_canvas_; gui::Canvas overworld_map_canvas_;

View File

@@ -12,10 +12,28 @@ namespace app {
namespace editor { namespace editor {
absl::Status PaletteEditor::Update() { absl::Status PaletteEditor::Update() {
for (const auto &name : kPaletteCategoryNames) { for (int i = 0; i < 11; ++i) {
if (ImGui::TreeNode(name.data())) { if (ImGui::TreeNode(kPaletteCategoryNames[i].data())) {
ImGui::SameLine(); auto size = rom_.GetPaletteGroup(kPaletteGroupNames[i].data()).size;
if (ImGui::SmallButton("button")) { auto palettes = rom_.GetPaletteGroup(kPaletteGroupNames[i].data());
for (int j = 0; j < size; j++) {
ImGui::Text("%d", j);
auto palette = palettes[j];
for (int n = 0; n < size; n++) {
ImGui::PushID(n);
if ((n % 8) != 0)
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
ImGuiColorEditFlags palette_button_flags =
ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker;
if (ImGui::ColorButton("##palette", palette[n].RGB(),
palette_button_flags, ImVec2(20, 20)))
current_color_ =
ImVec4(palette[n].rgb.x, palette[n].rgb.y, palette[n].rgb.z,
current_color_.w); // Preserve alpha!
ImGui::PopID();
}
} }
ImGui::TreePop(); ImGui::TreePop();
} }
@@ -23,6 +41,88 @@ absl::Status PaletteEditor::Update() {
return absl::OkStatus(); 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;
static ImVec4 saved_palette[256] = {};
if (loaded && !init) {
for (int n = 0; n < palette.size_; n++) {
saved_palette[n].x = palette.GetColor(n).rgb.x / 255;
saved_palette[n].y = palette.GetColor(n).rgb.y / 255;
saved_palette[n].z = palette.GetColor(n).rgb.z / 255;
saved_palette[n].w = 255; // Alpha
}
init = true;
}
static ImVec4 backup_color;
bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
open_popup |= ImGui::Button("Palette");
if (open_popup) {
ImGui::OpenPopup("mypicker");
backup_color = color;
}
if (ImGui::BeginPopup("mypicker")) {
ImGui::Text("Current Overworld Palette");
ImGui::Separator();
ImGui::ColorPicker4("##picker", (float*)&color,
misc_flags | ImGuiColorEditFlags_NoSidePreview |
ImGuiColorEditFlags_NoSmallPreview);
ImGui::SameLine();
ImGui::BeginGroup(); // Lock X position
ImGui::Text("Current ==>");
ImGui::SameLine();
ImGui::Text("Previous");
ImGui::ColorButton(
"##current", color,
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
ImVec2(60, 40));
ImGui::SameLine();
if (ImGui::ColorButton(
"##previous", backup_color,
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
ImVec2(60, 40)))
color = backup_color;
ImGui::Separator();
ImGui::Text("Palette");
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) {
ImGui::PushID(n);
if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha |
ImGuiColorEditFlags_NoPicker |
ImGuiColorEditFlags_NoTooltip;
if (ImGui::ColorButton("##palette", saved_palette[n],
palette_button_flags, ImVec2(20, 20)))
color = ImVec4(saved_palette[n].x, saved_palette[n].y,
saved_palette[n].z, color.w); // Preserve alpha!
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
ImGui::EndDragDropTarget();
}
ImGui::PopID();
}
ImGui::EndGroup();
ImGui::EndPopup();
}
}
} // namespace editor } // namespace editor
} // namespace app } // namespace app
} // namespace yaze } // namespace yaze

View File

@@ -5,6 +5,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "app/gfx/snes_palette.h" #include "app/gfx/snes_palette.h"
#include "app/rom.h"
#include "gui/canvas.h" #include "gui/canvas.h"
#include "gui/icons.h" #include "gui/icons.h"
@@ -17,11 +18,21 @@ static constexpr absl::string_view kPaletteCategoryNames[] = {
"Area Colors", "Enemies", "Dungeons", "World Map", "Area Colors", "Enemies", "Dungeons", "World Map",
"Dungeon Map", "Triforce", "Crystal"}; "Dungeon Map", "Triforce", "Crystal"};
static constexpr absl::string_view kPaletteGroupNames[] = {
"swords", "shields", "armors", "ow_main",
"ow_aux", "global_sprites", "dungeon_main", "ow_mini_map",
"ow_mini_map", "3d_object", "3d_object"};
class PaletteEditor { class PaletteEditor {
public: public:
absl::Status Update(); absl::Status Update();
void DisplayPalette(gfx::SNESPalette& palette, bool loaded);
auto SetupROM(ROM& rom) { rom_ = rom; }
private: private:
ImVec4 current_color_;
ROM rom_;
}; };
} // namespace editor } // namespace editor

View File

@@ -17,6 +17,7 @@
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#include "app/gfx/snes_tile.h" #include "app/gfx/snes_tile.h"
#include "gui/canvas.h" #include "gui/canvas.h"
#include "gui/icons.h"
#include "gui/input.h" #include "gui/input.h"
namespace yaze { namespace yaze {
@@ -27,13 +28,12 @@ ScreenEditor::ScreenEditor() { screen_canvas_.SetCanvasSize(ImVec2(512, 512)); }
void ScreenEditor::Update() { void ScreenEditor::Update() {
TAB_BAR("##TabBar") TAB_BAR("##TabBar")
DrawMosaicEditor(); DrawInventoryMenuEditor();
DrawTitleScreenEditor(); DrawTitleScreenEditor();
DrawNamingScreenEditor(); DrawNamingScreenEditor();
DrawOverworldMapEditor(); DrawOverworldMapEditor();
DrawDungeonMapsEditor(); DrawDungeonMapsEditor();
DrawGameMenuEditor(); DrawMosaicEditor();
DrawHUDEditor();
END_TAB_BAR() END_TAB_BAR()
} }
@@ -60,6 +60,64 @@ void ScreenEditor::DrawWorldGrid(int world, int h, int w) {
} }
} }
void ScreenEditor::DrawInventoryMenuEditor() {
TAB_ITEM("Inventory Menu")
static bool create = false;
if (!create && rom_.isLoaded()) {
inventory_.Create();
palette_ =inventory_.Palette();
create = true;
}
DrawInventoryToolset();
if (ImGui::BeginTable("InventoryScreen", 3, ImGuiTableFlags_Resizable)) {
ImGui::TableSetupColumn("Canvas");
ImGui::TableSetupColumn("Tiles");
ImGui::TableSetupColumn("Palette");
ImGui::TableHeadersRow();
ImGui::TableNextColumn();
screen_canvas_.DrawBackground();
screen_canvas_.DrawContextMenu();
screen_canvas_.DrawBitmap(inventory_.Bitmap(), 2, create);
screen_canvas_.DrawGrid(32.0f);
screen_canvas_.DrawOverlay();
ImGui::TableNextColumn();
tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4));
tilesheet_canvas_.DrawContextMenu();
tilesheet_canvas_.DrawBitmap(inventory_.Tilesheet(), 2, create);
tilesheet_canvas_.DrawGrid(16.0f);
tilesheet_canvas_.DrawOverlay();
ImGui::TableNextColumn();
gui::DisplayPalette(palette_, create);
ImGui::EndTable();
}
ImGui::Separator();
END_TAB_ITEM()
}
void ScreenEditor::DrawTitleScreenEditor() {
TAB_ITEM("Title Screen")
END_TAB_ITEM()
}
void ScreenEditor::DrawNamingScreenEditor() {
TAB_ITEM("Naming Screen")
END_TAB_ITEM()
}
void ScreenEditor::DrawOverworldMapEditor() {
TAB_ITEM("Overworld Map")
END_TAB_ITEM()
}
void ScreenEditor::DrawDungeonMapsEditor() {
TAB_ITEM("Dungeon Maps")
END_TAB_ITEM()
}
void ScreenEditor::DrawMosaicEditor() { void ScreenEditor::DrawMosaicEditor() {
TAB_ITEM("Mosaic Transitions") TAB_ITEM("Mosaic Transitions")
@@ -84,7 +142,7 @@ void ScreenEditor::DrawMosaicEditor() {
gui::InputHex("Routine Location", &overworldCustomMosaicASM); gui::InputHex("Routine Location", &overworldCustomMosaicASM);
if (ImGui::Button("Generate Mosaic Assembly")) { if (ImGui::Button("Generate Mosaic Assembly")) {
auto mosaic = mosaic_script_.GenerateMosaicChangeAssembly( auto mosaic = mosaic_script_.PatchOverworldMosaic(
rom_, mosaic_tiles_, overworldCustomMosaicASM); rom_, mosaic_tiles_, overworldCustomMosaicASM);
if (!mosaic.ok()) { if (!mosaic.ok()) {
std::cout << mosaic; std::cout << mosaic;
@@ -94,39 +152,6 @@ void ScreenEditor::DrawMosaicEditor() {
END_TAB_ITEM() END_TAB_ITEM()
} }
void ScreenEditor::DrawTitleScreenEditor() {
TAB_ITEM("Title Screen")
END_TAB_ITEM()
}
void ScreenEditor::DrawNamingScreenEditor() {
TAB_ITEM("Naming Screen")
END_TAB_ITEM()
}
void ScreenEditor::DrawOverworldMapEditor() {
TAB_ITEM("Overworld Map")
END_TAB_ITEM()
}
void ScreenEditor::DrawDungeonMapsEditor() {
TAB_ITEM("Dungeon Maps")
END_TAB_ITEM()
}
void ScreenEditor::DrawGameMenuEditor() {
TAB_ITEM("Game Menu")
END_TAB_ITEM()
}
void ScreenEditor::DrawHUDEditor() {
TAB_ITEM("Heads-up Display")
END_TAB_ITEM()
}
void ScreenEditor::DrawCanvas() {
screen_canvas_.DrawBackground();
screen_canvas_.DrawContextMenu();
screen_canvas_.DrawGrid();
screen_canvas_.DrawOverlay();
}
void ScreenEditor::DrawToolset() { void ScreenEditor::DrawToolset() {
static bool show_bg1 = true; static bool show_bg1 = true;
static bool show_bg2 = true; static bool show_bg2 = true;
@@ -147,6 +172,30 @@ void ScreenEditor::DrawToolset() {
ImGui::Checkbox("Draw BG3", &drawing_bg3); ImGui::Checkbox("Draw BG3", &drawing_bg3);
} }
void ScreenEditor::DrawInventoryToolset() {
if (ImGui::BeginTable("InventoryToolset", 8, ImGuiTableFlags_SizingFixedFit, ImVec2(0, 0))) {
ImGui::TableSetupColumn("#drawTool");
ImGui::TableSetupColumn("#sep1");
ImGui::TableSetupColumn("#zoomOut");
ImGui::TableSetupColumn("#zoomIN");
ImGui::TableSetupColumn("#sep2");
ImGui::TableSetupColumn("#bg2Tool");
ImGui::TableSetupColumn("#bg3Tool");
ImGui::TableSetupColumn("#itemTool");
BUTTON_COLUMN(ICON_MD_UNDO)
BUTTON_COLUMN(ICON_MD_REDO)
TEXT_COLUMN(ICON_MD_MORE_VERT)
BUTTON_COLUMN(ICON_MD_ZOOM_OUT)
BUTTON_COLUMN(ICON_MD_ZOOM_IN)
TEXT_COLUMN(ICON_MD_MORE_VERT)
BUTTON_COLUMN(ICON_MD_DRAW)
BUTTON_COLUMN(ICON_MD_BUILD)
ImGui::EndTable();
}
}
} // namespace editor } // namespace editor
} // namespace app } // namespace app
} // namespace yaze } // namespace yaze

View File

@@ -9,9 +9,12 @@
#include "app/core/constants.h" #include "app/core/constants.h"
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#include "app/gfx/snes_tile.h" #include "app/gfx/snes_tile.h"
#include "app/gfx/snes_palette.h"
#include "app/rom.h" #include "app/rom.h"
#include "app/zelda3/screen.h" #include "app/zelda3/inventory.h"
#include "gui/canvas.h" #include "gui/canvas.h"
#include "gui/icons.h"
#include "gui/color.h"
namespace yaze { namespace yaze {
namespace app { namespace app {
@@ -19,12 +22,14 @@ namespace editor {
using MosaicArray = std::array<int, core::kNumOverworldMaps>; using MosaicArray = std::array<int, core::kNumOverworldMaps>;
static int overworldCustomMosaicASM = 0x1301D0; static int overworldCustomMosaicASM = 0x1301D0;
static int overworldCustomMosaicArray = 0x1301F0;
class ScreenEditor { class ScreenEditor {
public: public:
ScreenEditor(); ScreenEditor();
void SetupROM(ROM &rom) { rom_ = rom; } void SetupROM(ROM &rom) {
rom_ = rom;
inventory_.SetupROM(rom_);
}
void Update(); void Update();
private: private:
@@ -33,19 +38,21 @@ class ScreenEditor {
void DrawNamingScreenEditor(); void DrawNamingScreenEditor();
void DrawOverworldMapEditor(); void DrawOverworldMapEditor();
void DrawDungeonMapsEditor(); void DrawDungeonMapsEditor();
void DrawGameMenuEditor(); void DrawInventoryMenuEditor();
void DrawHUDEditor();
void DrawCanvas();
void DrawToolset(); void DrawToolset();
void DrawInventoryToolset();
void DrawWorldGrid(int world, int h = 8, int w = 8); void DrawWorldGrid(int world, int h = 8, int w = 8);
char mosaic_tiles_[core::kNumOverworldMaps]; char mosaic_tiles_[core::kNumOverworldMaps];
ROM rom_; ROM rom_;
Bytes all_gfx_;
zelda3::Inventory inventory_;
gfx::SNESPalette palette_;
snes_asm::Script mosaic_script_; snes_asm::Script mosaic_script_;
zelda3::Screen current_screen_;
gui::Canvas screen_canvas_; gui::Canvas screen_canvas_;
gui::Canvas tilesheet_canvas_;
}; };
} // namespace editor } // namespace editor

View File

@@ -47,8 +47,8 @@ void Bitmap::Create(int width, int height, int depth, uchar *data) {
SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_, SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_,
SDL_PIXELFORMAT_INDEX8), SDL_PIXELFORMAT_INDEX8),
SDL_Surface_Deleter()); SDL_Surface_Deleter());
GrayscalePalette(surface_->format->palette);
surface_->pixels = pixel_data_; surface_->pixels = pixel_data_;
GrayscalePalette(surface_->format->palette);
} }
// Reserves data to later draw to surface via pointer // Reserves data to later draw to surface via pointer
@@ -57,13 +57,14 @@ void Bitmap::Create(int width, int height, int depth, int size) {
height_ = height; height_ = height;
depth_ = depth; depth_ = depth;
data_size_ = size; data_size_ = size;
data_.reserve(size);
pixel_data_ = data_.data();
surface_ = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>( surface_ = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
SDL_CreateRGBSurfaceWithFormat(0, width, height, depth, SDL_CreateRGBSurfaceWithFormat(0, width, height, depth,
SDL_PIXELFORMAT_INDEX8), SDL_PIXELFORMAT_INDEX8),
SDL_Surface_Deleter()); SDL_Surface_Deleter());
GrayscalePalette(surface_->format->palette);
pixel_data_ = (uchar *)SDL_malloc(size);
surface_->pixels = pixel_data_; surface_->pixels = pixel_data_;
GrayscalePalette(surface_->format->palette);
} }
// Pass raw pixel data directly to the surface // Pass raw pixel data directly to the surface
@@ -103,68 +104,21 @@ void Bitmap::CreateTexture(std::shared_ptr<SDL_Renderer> renderer) {
} }
// Convert SNESPalette to SDL_Palette for surface. // Convert SNESPalette to SDL_Palette for surface.
void Bitmap::ApplyPalette(const SNESPalette & palette) { void Bitmap::ApplyPalette(const SNESPalette &palette) {
palette_ = palette; palette_ = palette;
SDL_SetPaletteColors(surface_->format->palette, for (int i = 0; i < palette.size_; ++i) {
palette_.GetSDL_Palette()->colors, if (palette.GetColor(i).transparent) {
0, 256); surface_->format->palette->colors[i].r = 0;
} surface_->format->palette->colors[i].g = 0;
surface_->format->palette->colors[i].b = 0;
void Bitmap::SetPaletteColor(int id, gfx::SNESColor color) { surface_->format->palette->colors[i].a = 0;
surface_->format->palette->colors[id].r = color.rgb.x; } else {
surface_->format->palette->colors[id].g = color.rgb.y; surface_->format->palette->colors[i].r = palette.GetColor(i).rgb.x;
surface_->format->palette->colors[id].b = color.rgb.z; surface_->format->palette->colors[i].g = palette.GetColor(i).rgb.y;
} surface_->format->palette->colors[i].b = palette.GetColor(i).rgb.z;
surface_->format->palette->colors[i].a = palette.GetColor(i).rgb.w;
// Creates a vector of bitmaps which are individual 8x8 tiles.
absl::StatusOr<std::vector<Bitmap>> Bitmap::CreateTiles() {
std::vector<Bitmap> tiles;
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 4; ++j) {
Bitmap bmp;
bmp.Create(8, 8, 8, 32);
auto surface = bmp.GetSurface();
SDL_Rect src_rect = {i, j, 8, 8};
if (SDL_BlitSurface(surface_.get(), &src_rect, surface, nullptr) != 0)
return absl::InternalError(
absl::StrCat("Failed to blit surface: ", SDL_GetError()));
tiles.push_back(bmp);
} }
} }
return tiles;
}
// Converts a vector of 8x8 tiles into a tilesheet.
absl::Status Bitmap::CreateFromTiles(const std::vector<Bitmap> &tiles) {
if (tiles.empty())
return absl::InvalidArgumentError(
"Failed to create bitmap: `tiles` is empty.");
SDL_Rect tile_rect = {0, 0, 8, 8};
SDL_Rect dest_rect = {0, 0, 8, 8};
for (const auto &tile : tiles) {
auto src = tile.GetSurface();
if (SDL_BlitSurface(src, &tile_rect, surface_.get(), &dest_rect) != 0)
return absl::InternalError(
absl::StrCat("Failed to blit surface: ", SDL_GetError()));
dest_rect.x++;
if (dest_rect.x == 15) {
dest_rect.x = 0;
dest_rect.y++;
}
}
return absl::OkStatus();
}
absl::Status Bitmap::WritePixel(int pos, uchar pixel) {
if (!surface_) {
return absl::InternalError("Surface not loaded");
}
auto pixels = (char *)surface_->pixels;
pixels[pos] = pixel;
return absl::OkStatus();
} }
} // namespace gfx } // namespace gfx

View File

@@ -31,12 +31,6 @@ class Bitmap {
void CreateTexture(std::shared_ptr<SDL_Renderer> renderer); void CreateTexture(std::shared_ptr<SDL_Renderer> renderer);
void ApplyPalette(const SNESPalette &palette); void ApplyPalette(const SNESPalette &palette);
void SetPaletteColor(int id, gfx::SNESColor color);
absl::StatusOr<std::vector<Bitmap>> CreateTiles();
absl::Status CreateFromTiles(const std::vector<Bitmap> &tiles);
absl::Status WritePixel(int pos, uchar pixel);
int GetWidth() const { return width_; } int GetWidth() const { return width_; }
int GetHeight() const { return height_; } int GetHeight() const { return height_; }
@@ -59,6 +53,7 @@ class Bitmap {
struct SDL_Surface_Deleter { struct SDL_Surface_Deleter {
void operator()(SDL_Surface *p) const { void operator()(SDL_Surface *p) const {
if (p != nullptr) { if (p != nullptr) {
p->pixels = nullptr;
SDL_FreeSurface(p); SDL_FreeSurface(p);
p = nullptr; p = nullptr;
} }

View File

@@ -1,30 +0,0 @@
#include "pseudo_vram.h"
namespace yaze {
namespace app {
namespace gfx {
void pseudo_vram::ChangeGraphicsTileset(
const std::vector<Bitmap>& graphics_set) {}
void pseudo_vram::ChangeGraphicsPalette(const SNESPalette& graphics_pal) {}
void pseudo_vram::ChangeSpriteTileset(const std::vector<Bitmap>& sprite_set) {}
void pseudo_vram::ChangeSpritePalette(const SNESPalette& sprite_pal) {}
std::vector<Bitmap> CreateGraphicsSet(
int id, const std::unordered_map<int, Bitmap>& all_graphics) {
std::vector<Bitmap> graphics_set;
return graphics_set;
}
std::vector<Bitmap> CreateSpriteSet(
int id, const std::unordered_map<int, Bitmap>& all_graphics) {
std::vector<Bitmap> graphics_set;
return graphics_set;
}
} // namespace gfx
} // namespace app
} // namespace yaze

View File

@@ -1,47 +0,0 @@
#ifndef YAZE_APP_GFX_PSEUDO_VRAM_H
#define YAZE_APP_GFX_PSEUDO_VRAM_H
#include <SDL.h>
#include <cstdint>
#include <unordered_map>
#include <vector>
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h"
namespace yaze {
namespace app {
namespace gfx {
// VRAM: 64 KB of VRAM for screen maps and tile sets (backgrounds and objects)
// OAM: 512 + 32 bytes for objects (Object Attribute Memory)
// CGRAM: 512 bytes for palette data
// Palette: 256 entries; 15-Bit color (BGR555) for a total of 32,768 colors.
// Resolution: between 256x224 and 512x448.
class pseudo_vram {
public:
void ChangeGraphicsTileset(const std::vector<Bitmap>& graphics_set);
void ChangeGraphicsPalette(const SNESPalette& graphics_pal);
void ChangeSpriteTileset(const std::vector<Bitmap>& sprite_set);
void ChangeSpritePalette(const SNESPalette& sprite_pal);
auto GetTileset(int index) const { return m_vram.at(index); }
private:
static const uint32_t REAL_VRAM_SIZE = 0x8000;
std::unordered_map<int, Bitmap> m_vram;
};
std::vector<Bitmap> CreateGraphicsSet(
int id, const std::unordered_map<int, Bitmap>& all_graphics);
std::vector<Bitmap> CreateSpriteSet(
int id, const std::unordered_map<int, Bitmap>& all_graphics);
} // namespace gfx
} // namespace app
} // namespace yaze
#endif // YAZE_APP_GFX_PSEUDO_VRAM_H

View File

@@ -66,8 +66,8 @@ SNESColor::SNESColor() : rgb(ImVec4(0.f, 0.f, 0.f, 0.f)) {}
SNESColor::SNESColor(snes_color val) { SNESColor::SNESColor(snes_color val) {
rgb.x = val.red; rgb.x = val.red;
rgb.y = val.blue; rgb.y = val.green;
rgb.z = val.green; rgb.z = val.blue;
} }
SNESColor::SNESColor(ImVec4 val) : rgb(val) { SNESColor::SNESColor(ImVec4 val) : rgb(val) {
@@ -88,13 +88,13 @@ void SNESColor::setRgb(ImVec4 val) {
} }
void SNESColor::setSNES(snes_color val) { void SNESColor::setSNES(snes_color val) {
rgb = ImVec4(val.red, val.green, val.blue, 1.f); rgb = ImVec4(val.red, val.green, val.blue, 255.f);
} }
void SNESColor::setSNES(uint16_t val) { void SNESColor::setSNES(uint16_t val) {
snes = val; snes = val;
snes_color col = ConvertSNEStoRGB(val); snes_color col = ConvertSNEStoRGB(val);
rgb = ImVec4(col.red, col.green, col.blue, 1.f); rgb = ImVec4(col.red, col.green, col.blue, 0.f);
} }
// ============================================================================ // ============================================================================

View File

@@ -45,7 +45,13 @@ struct SNESColor {
void setRgb(ImVec4); void setRgb(ImVec4);
void setSNES(snes_color); void setSNES(snes_color);
void setSNES(uint16_t); void setSNES(uint16_t);
void setTransparent(bool t) { transparent = t; }
auto RGB() {
return ImVec4(rgb.x / 255, rgb.y / 255, rgb.z / 255, rgb.w);
}
bool transparent = false;
uint16_t snes = 0; uint16_t snes = 0;
ImVec4 rgb; ImVec4 rgb;
}; };

View File

@@ -20,61 +20,10 @@
#include "app/core/constants.h" #include "app/core/constants.h"
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#define COMPRESSION_STRING_MOD 7 << 5
namespace yaze { namespace yaze {
namespace app { namespace app {
namespace { namespace lc_lz2 {
int GetGraphicsAddress(const uchar* data, uint8_t offset) {
auto part_one = data[kOverworldGraphicsPos1 + offset] << 16;
auto part_two = data[kOverworldGraphicsPos2 + offset] << 8;
auto part_three = data[kOverworldGraphicsPos3 + offset];
auto snes_addr = (part_one | part_two | part_three);
return core::SnesToPc(snes_addr);
}
Bytes SNES3bppTo8bppSheet(Bytes sheet) {
Bytes sheet_buffer_out(0x1000);
int xx = 0; // positions where we are at on the sheet
int yy = 0;
int pos = 0;
int ypos = 0;
// for each tiles, 16 per line
for (int i = 0; i < 64; i++) {
// for each line
for (int y = 0; y < 8; y++) {
//[0] + [1] + [16]
for (int x = 0; x < 8; x++) {
auto b1 = ((sheet[(y * 2) + (24 * pos)] & (kGraphicsBitmap[x])));
auto b2 = (sheet[((y * 2) + (24 * pos)) + 1] & (kGraphicsBitmap[x]));
auto b3 = (sheet[(16 + y) + (24 * pos)] & (kGraphicsBitmap[x]));
unsigned char b = 0;
if (b1 != 0) {
b |= 1;
}
if (b2 != 0) {
b |= 2;
}
if (b3 != 0) {
b |= 4;
}
sheet_buffer_out[x + (xx) + (y * 128) + (yy * 1024)] = b;
}
}
pos++;
ypos++;
xx += 8;
if (ypos >= 16) {
yy++;
xx = 0;
ypos = 0;
}
}
return sheet_buffer_out;
}
void PrintCompressionPiece(const std::shared_ptr<CompressionPiece>& piece) { void PrintCompressionPiece(const std::shared_ptr<CompressionPiece>& piece) {
printf("Command: %d\n", piece->command); printf("Command: %d\n", piece->command);
@@ -298,8 +247,7 @@ Bytes CreateCompressionString(std::shared_ptr<CompressionPiece>& start,
pos++; pos++;
} else { } else {
if (piece->length <= kMaxLengthCompression) { if (piece->length <= kMaxLengthCompression) {
output.push_back((COMPRESSION_STRING_MOD) | output.push_back(kCompressionStringMod | ((uchar)piece->command << 2) |
((uchar)piece->command << 2) |
(((piece->length - 1) & 0xFF00) >> 8)); (((piece->length - 1) & 0xFF00) >> 8));
pos++; pos++;
printf("Building extended header : cmd: %d, length: %d - %02X\n", printf("Building extended header : cmd: %d, length: %d - %02X\n",
@@ -354,7 +302,7 @@ absl::Status ValidateCompressionResult(
RETURN_IF_ERROR(temp_rom.LoadFromBytes( RETURN_IF_ERROR(temp_rom.LoadFromBytes(
CreateCompressionString(compressed_chain_start->next, mode))) CreateCompressionString(compressed_chain_start->next, mode)))
ASSIGN_OR_RETURN(auto decomp_data, ASSIGN_OR_RETURN(auto decomp_data,
temp_rom.Decompress(0, temp_rom.GetSize())) temp_rom.Decompress(0, temp_rom.size()))
if (!std::equal(decomp_data.begin() + start, decomp_data.end(), if (!std::equal(decomp_data.begin() + start, decomp_data.end(),
temp_rom.begin())) { temp_rom.begin())) {
return absl::InternalError(absl::StrFormat( return absl::InternalError(absl::StrFormat(
@@ -392,6 +340,65 @@ std::shared_ptr<CompressionPiece> MergeCopy(
return start; return start;
} }
} // namespace lc_lz2
namespace {
int GetGraphicsAddress(const uchar* data, uint8_t offset) {
auto part_one = data[kOverworldGraphicsPos1 + offset] << 16;
auto part_two = data[kOverworldGraphicsPos2 + offset] << 8;
auto part_three = data[kOverworldGraphicsPos3 + offset];
auto snes_addr = (part_one | part_two | part_three);
return core::SnesToPc(snes_addr);
}
Bytes SnesTo8bppSheet(Bytes sheet, int bpp) {
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;
buffer_size = 0x2000;
} else if (bpp == 3) {
bpp = 24;
}
Bytes 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
for (int x = 0; x < 8; x++) { //[0] + [1] + [16]
auto b1 = ((sheet[(y * 2) + (bpp * pos)] & (kGraphicsBitmap[x])));
auto b2 = (sheet[((y * 2) + (bpp * pos)) + 1] & (kGraphicsBitmap[x]));
auto b3 = (sheet[(16 + y) + (bpp * pos)] & (kGraphicsBitmap[x]));
unsigned char b = 0;
if (b1 != 0) {
b |= 1;
}
if (b2 != 0) {
b |= 2;
}
if (b3 != 0 && bpp != 16) {
b |= 4;
}
sheet_buffer_out[x + (xx) + (y * 128) + (yy * 1024)] = b;
}
}
pos++;
ypos++;
xx += 8;
if (ypos >= 16) {
yy++;
xx = 0;
ypos = 0;
}
}
return sheet_buffer_out;
}
} // namespace } // namespace
// TODO TEST compressed data border for each cmd // TODO TEST compressed data border for each cmd
@@ -413,18 +420,19 @@ absl::StatusOr<Bytes> ROM::Compress(const int start, const int length, int mode,
data_size_taken.fill({}); data_size_taken.fill({});
cmd_args.fill({{}}); cmd_args.fill({{}});
CheckByteRepeat(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, lc_lz2::CheckByteRepeat(rom_data_.data(), data_size_taken, cmd_args,
last_pos); src_data_pos, last_pos);
CheckWordRepeat(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, lc_lz2::CheckWordRepeat(rom_data_.data(), data_size_taken, cmd_args,
last_pos); src_data_pos, last_pos);
CheckIncByte(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, lc_lz2::CheckIncByte(rom_data_.data(), data_size_taken, cmd_args,
last_pos); src_data_pos, last_pos);
CheckIntraCopy(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, lc_lz2::CheckIntraCopy(rom_data_.data(), data_size_taken, cmd_args,
last_pos, start); src_data_pos, last_pos, start);
uint max_win = 2; uint max_win = 2;
uint cmd_with_max = kCommandDirectCopy; uint cmd_with_max = kCommandDirectCopy;
ValidateForByteGain(data_size_taken, cmd_size, max_win, cmd_with_max); lc_lz2::ValidateForByteGain(data_size_taken, cmd_size, max_win,
cmd_with_max);
if (cmd_with_max == kCommandDirectCopy) { if (cmd_with_max == kCommandDirectCopy) {
// This is the worst case scenario // This is the worst case scenario
@@ -446,10 +454,9 @@ absl::StatusOr<Bytes> ROM::Compress(const int start, const int length, int mode,
comp_accumulator = 0; comp_accumulator = 0;
} }
} else { } else {
// Anything is better than directly copying bytes... lc_lz2::CompressionCommandAlternative(
CompressionCommandAlternative(rom_data_.data(), compressed_chain, rom_data_.data(), compressed_chain, cmd_size, cmd_args, src_data_pos,
cmd_size, cmd_args, src_data_pos, comp_accumulator, cmd_with_max, max_win);
comp_accumulator, cmd_with_max, max_win);
} }
if (src_data_pos > last_pos) { if (src_data_pos > last_pos) {
@@ -458,14 +465,15 @@ absl::StatusOr<Bytes> ROM::Compress(const int start, const int length, int mode,
} }
if (check) { if (check) {
RETURN_IF_ERROR(ValidateCompressionResult(compressed_chain_start, mode, RETURN_IF_ERROR(lc_lz2::ValidateCompressionResult(
start, src_data_pos)) compressed_chain_start, mode, start, src_data_pos))
} }
} }
MergeCopy(compressed_chain_start->next); // Skipping compression chain header // Skipping compression chain header
PrintCompressionChain(compressed_chain_start); lc_lz2::MergeCopy(compressed_chain_start->next);
return CreateCompressionString(compressed_chain_start->next, mode); lc_lz2::PrintCompressionChain(compressed_chain_start);
return lc_lz2::CreateCompressionString(compressed_chain_start->next, mode);
} }
absl::StatusOr<Bytes> ROM::CompressGraphics(const int pos, const int length) { absl::StatusOr<Bytes> ROM::CompressGraphics(const int pos, const int length) {
@@ -503,10 +511,8 @@ absl::StatusOr<Bytes> ROM::Decompress(int offset, int size, int mode) {
offset += length; offset += length;
break; break;
case kCommandByteFill: case kCommandByteFill:
for (int i = 0; i < length; i++) { memset(buffer.data() + buffer_pos, (int)(rom_data_[offset]), length);
buffer[buffer_pos] = rom_data_[offset]; buffer_pos += length;
buffer_pos++;
}
offset += 1; // Advances 1 byte in the ROM offset += 1; // Advances 1 byte in the ROM
break; break;
case kCommandWordFill: { case kCommandWordFill: {
@@ -531,39 +537,27 @@ absl::StatusOr<Bytes> ROM::Decompress(int offset, int size, int mode) {
ushort s1 = ((rom_data_[offset + 1] & kSnesByteMax) << 8); ushort s1 = ((rom_data_[offset + 1] & kSnesByteMax) << 8);
ushort s2 = ((rom_data_[offset] & kSnesByteMax)); ushort s2 = ((rom_data_[offset] & kSnesByteMax));
int addr = (s1 | s2); int addr = (s1 | s2);
if (mode == kNintendoMode1) { // Reversed byte order for overworld maps if (mode == kNintendoMode1) { // Reversed byte order for overworld maps
// addr = (s2 | s1); addr = (rom_data_[offset + 1] & kSnesByteMax) |
addr = (rom_data_[offset + 1]) | ((rom_data_[offset]) << 8); ((rom_data_[offset] & kSnesByteMax) << 8);
memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length);
buffer_pos += length;
offset += 2;
break;
} }
if (addr > offset) { if (addr > offset) {
return absl::InternalError(absl::StrFormat( return absl::InternalError(absl::StrFormat(
"DecompressOverworld: Offset for command copy exceeds " "Decompress: Offset for command copy exceeds current position "
"current position (Offset : %#04x | Pos : %#06x)\n", "(Offset : %#04x | Pos : %#06x)\n",
addr, offset)); addr, offset));
} }
if (buffer_pos + length >= size) { if (buffer_pos + length >= size) {
size *= 2; size *= 2;
buffer.resize(size); buffer.resize(size);
} }
memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length);
for (int i = 0; i < length; i++) { buffer_pos += length;
buffer[buffer_pos] = buffer[addr + i]; offset += 2;
buffer_pos++;
}
offset += 2; // Advance 2 bytes in the ROM
} break; } break;
default: { default: {
std::cout << absl::StrFormat( std::cout << absl::StrFormat(
"DecompressGraphics: Invalid command in header (Offset : %#06x, " "Decompress: Invalid header (Offset : %#06x, Command: %#04x)\n",
"Command: %#04x)\n",
offset, command); offset, command);
} break; } break;
} }
@@ -582,6 +576,21 @@ absl::StatusOr<Bytes> ROM::DecompressOverworld(int pos, int size) {
return Decompress(pos, size, kNintendoMode1); return Decompress(pos, size, kNintendoMode1);
} }
absl::StatusOr<Bytes> ROM::Load2bppGraphics() {
Bytes sheet;
const uint8_t sheets[] = {113, 114, 218, 219, 220, 221};
for (const auto& sheet_id : sheets) {
auto offset = GetGraphicsAddress(rom_data_.data(), sheet_id);
ASSIGN_OR_RETURN(auto decomp_sheet, Decompress(offset))
auto converted_sheet = SnesTo8bppSheet(decomp_sheet, 2);
for (const auto& each_pixel : converted_sheet) {
sheet.push_back(each_pixel);
}
}
return sheet;
}
// 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 chars // 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 chars
// 113-114 -> compressed 2bpp -> (decompressed each) 0x800 chars // 113-114 -> compressed 2bpp -> (decompressed each) 0x800 chars
// 115-126 -> uncompressed 3bpp sprites -> (each) 0x600 chars // 115-126 -> uncompressed 3bpp sprites -> (each) 0x600 chars
@@ -589,7 +598,7 @@ absl::StatusOr<Bytes> ROM::DecompressOverworld(int pos, int size) {
// 218-222 -> compressed 2bpp -> (decompressed each) 0x800 chars // 218-222 -> compressed 2bpp -> (decompressed each) 0x800 chars
absl::Status ROM::LoadAllGraphicsData() { absl::Status ROM::LoadAllGraphicsData() {
Bytes sheet; Bytes sheet;
bool convert = false; bool bpp3 = false;
for (int i = 0; i < core::NumberOfSheets; i++) { for (int i = 0; i < core::NumberOfSheets; i++) {
if (i >= 115 && i <= 126) { // uncompressed sheets if (i >= 115 && i <= 126) { // uncompressed sheets
@@ -598,17 +607,17 @@ absl::Status ROM::LoadAllGraphicsData() {
for (int j = 0; j < core::Uncompressed3BPPSize; j++) { for (int j = 0; j < core::Uncompressed3BPPSize; j++) {
sheet[j] = rom_data_[j + offset]; sheet[j] = rom_data_[j + offset];
} }
convert = true; bpp3 = true;
} else if (i == 113 || i == 114 || i >= 218) { } else if (i == 113 || i == 114 || i >= 218) {
convert = false; bpp3 = false;
} else { } else {
auto offset = GetGraphicsAddress(rom_data_.data(), i); auto offset = GetGraphicsAddress(rom_data_.data(), i);
ASSIGN_OR_RETURN(sheet, Decompress(offset)) ASSIGN_OR_RETURN(sheet, Decompress(offset))
convert = true; bpp3 = true;
} }
if (convert) { if (bpp3) {
auto converted_sheet = SNES3bppTo8bppSheet(sheet); auto converted_sheet = SnesTo8bppSheet(sheet, 3);
graphics_bin_[i] = graphics_bin_[i] =
gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight,
core::kTilesheetDepth, converted_sheet.data(), 0x1000); core::kTilesheetDepth, converted_sheet.data(), 0x1000);
@@ -618,7 +627,7 @@ absl::Status ROM::LoadAllGraphicsData() {
graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j));
} }
} else { } else {
for (int j = 0; j < 0x1000; ++j) { for (int j = 0; j < graphics_bin_.at(0).GetSize(); ++j) {
graphics_buffer_.push_back(0xFF); graphics_buffer_.push_back(0xFF);
} }
} }
@@ -687,7 +696,7 @@ void ROM::RenderBitmap(gfx::Bitmap* bitmap) const {
} }
gfx::SNESColor ROM::ReadColor(int offset) { gfx::SNESColor ROM::ReadColor(int offset) {
short color = (short)((rom_data_[offset + 1] << 8) + rom_data_[offset]); short color = toint16(offset);
gfx::snes_color new_color; gfx::snes_color new_color;
new_color.red = (color & 0x1F) * 8; new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8; new_color.green = ((color >> 5) & 0x1F) * 8;
@@ -701,7 +710,7 @@ gfx::SNESPalette ROM::ReadPalette(int offset, int num_colors) {
std::vector<gfx::SNESColor> colors(num_colors); std::vector<gfx::SNESColor> colors(num_colors);
while (color_offset < num_colors) { while (color_offset < num_colors) {
short color = (short)((rom_data_[offset + 1] << 8) + rom_data_[offset]); short color = toint16(offset);
gfx::snes_color new_color; gfx::snes_color new_color;
new_color.red = (color & 0x1F) * 8; new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8; new_color.green = ((color >> 5) & 0x1F) * 8;
@@ -783,31 +792,6 @@ void ROM::LoadAllPalettes() {
palette_groups_["ow_mini_map"].AddPalette( palette_groups_["ow_mini_map"].AddPalette(
ReadPalette(core::overworldMiniMapPalettes + (i * 256), 128)); ReadPalette(core::overworldMiniMapPalettes + (i * 256), 128));
} }
// TODO: check for the paletts in the empty bank space that kan will allocate
// and read them in here
// TODO magic colors
// LW
// int j = 0;
// while (j < 64) {
// zelda3::overworld_BackgroundPalette[j++] =
// Color.FromArgb(0xFF, 0x48, 0x98, 0x48);
// }
// // DW
// while (j < 128) {
// zelda3::overworld_BackgroundPalette[j++] =
// Color.FromArgb(0xFF, 0x90, 0x88, 0x50);
// }
// // SP
// while (j < core::kNumOverworldMaps) {
// zelda3::overworld_BackgroundPalette[j++] =
// Color.FromArgb(0xFF, 0x48, 0x98, 0x48);
// }
// zelda3::overworld_BackgroundPalette =
// ReadPalette(core::customAreaSpecificBGPalette, 160);
} }
} // namespace app } // namespace app

View File

@@ -17,6 +17,7 @@
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "app/core/common.h" #include "app/core/common.h"
#include "app/core/constants.h" #include "app/core/constants.h"
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
@@ -47,6 +48,7 @@ constexpr int kCommandMod = 0x07;
constexpr int kExpandedMod = 0xE0; constexpr int kExpandedMod = 0xE0;
constexpr int kExpandedLengthMod = 0x3FF; constexpr int kExpandedLengthMod = 0x3FF;
constexpr int kNormalLengthMod = 0x1F; constexpr int kNormalLengthMod = 0x1F;
constexpr int kCompressionStringMod = 7 << 5;
constexpr uchar kGraphicsBitmap[8] = {0x80, 0x40, 0x20, 0x10, constexpr uchar kGraphicsBitmap[8] = {0x80, 0x40, 0x20, 0x10,
0x08, 0x04, 0x02, 0x01}; 0x08, 0x04, 0x02, 0x01};
@@ -76,6 +78,8 @@ class ROM {
absl::StatusOr<Bytes> DecompressGraphics(int pos, int size); absl::StatusOr<Bytes> DecompressGraphics(int pos, int size);
absl::StatusOr<Bytes> DecompressOverworld(int pos, int size); absl::StatusOr<Bytes> DecompressOverworld(int pos, int size);
absl::StatusOr<Bytes> Load2bppGraphics();
absl::Status LoadAllGraphicsData(); absl::Status LoadAllGraphicsData();
absl::Status LoadFromFile(const absl::string_view& filename); absl::Status LoadFromFile(const absl::string_view& filename);
absl::Status LoadFromPointer(uchar* data, size_t length); absl::Status LoadFromPointer(uchar* data, size_t length);
@@ -89,7 +93,6 @@ class ROM {
void RenderBitmap(gfx::Bitmap* bitmap) const; void RenderBitmap(gfx::Bitmap* bitmap) const;
auto GetSize() const { return size_; }
auto GetTitle() const { return title; } auto GetTitle() const { return title; }
auto GetGraphicsBin() const { return graphics_bin_; } auto GetGraphicsBin() const { return graphics_bin_; }
auto GetGraphicsBuffer() const { return graphics_buffer_; } auto GetGraphicsBuffer() const { return graphics_buffer_; }
@@ -101,6 +104,7 @@ class ROM {
auto begin() { return rom_data_.begin(); } auto begin() { return rom_data_.begin(); }
auto end() { return rom_data_.end(); } auto end() { return rom_data_.end(); }
auto data() { return rom_data_.data(); } auto data() { return rom_data_.data(); }
auto size() const { return size_; }
uchar& operator[](int i) { uchar& operator[](int i) {
if (i > size_) { if (i > size_) {

View File

@@ -0,0 +1,88 @@
#include "inventory.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_tile.h"
#include "app/rom.h"
#include "gui/canvas.h"
namespace yaze {
namespace app {
namespace zelda3 {
void Inventory::Create() {
data_.reserve(256 * 256);
for (int i = 0; i < 256 * 256; i++) {
data_.push_back(0xFF);
}
PRINT_IF_ERROR(BuildTileset())
for (int i = 0; i < 0x400; i += 0x08) {
tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos)));
tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x02)));
tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x04)));
tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x08)));
}
const int offsets[] = {0x00, 0x08, 0x800, 0x808};
auto xx = 0;
auto yy = 0;
int i = 0;
for (const auto& tile : tiles_) {
int offset = offsets[i];
for (auto y = 0; y < 0x08; ++y) {
for (auto x = 0; x < 0x08; ++x) {
int mx = x;
int my = y;
if (tile.horizontal_mirror_ != 0) {
mx = 0x07 - x;
}
if (tile.vertical_mirror_ != 0) {
my = 0x07 - y;
}
int xpos = ((tile.id_ % 0x10) * 0x08);
int ypos = (((tile.id_ / 0x10)) * 0x400);
int source = ypos + xpos + (x + (y * 0x80));
auto destination = xx + yy + offset + (mx + (my * 0x100));
data_[destination] = (test_[source] & 0x0F) + tile.palette_ * 0x08;
}
}
if (i == 4) {
i = 0;
xx += 0x10;
if (xx >= 0x100) {
yy += 0x1000;
xx = 0;
}
} else {
i++;
}
}
bitmap_.Create(256, 256, 128, data_);
bitmap_.ApplyPalette(palette_);
rom_.RenderBitmap(&bitmap_);
}
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;
for (int i = 0; i < 0x4000; i++) {
test_.push_back(tilesheets_[i]);
}
for (int i = 0x8000; i < + 0x8000 + 0x2000; i++) {
test_.push_back(tilesheets_[i]);
}
tilesheets_bmp_.Create(128, 0x130, 64, test_);
palette_ = rom_.GetPaletteGroup("hud")[0];
tilesheets_bmp_.ApplyPalette(palette_);
rom_.RenderBitmap(&tilesheets_bmp_);
return absl::OkStatus();
}
} // namespace zelda3
} // namespace app
} // namespace yaze

View File

@@ -0,0 +1,47 @@
#ifndef YAZE_APP_ZELDA3_INVENTORY_H
#define YAZE_APP_ZELDA3_INVENTORY_H
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_tile.h"
#include "app/gfx/snes_palette.h"
#include "app/rom.h"
#include "gui/canvas.h"
namespace yaze {
namespace app {
namespace zelda3 {
constexpr int kInventoryStart = 0x6564A;
constexpr int kBowItemPos = 0x6F631;
class Inventory {
public:
void SetupROM(ROM& rom) { rom_ = rom; }
auto Bitmap() const { return bitmap_; }
auto Tilesheet() const { return tilesheets_bmp_; }
auto Palette() const { return palette_; }
void Create();
private:
absl::Status BuildTileset();
ROM rom_;
Bytes data_;
gfx::Bitmap bitmap_;
Bytes tilesheets_;
Bytes test_;
gfx::Bitmap tilesheets_bmp_;
gfx::SNESPalette palette_;
gui::Canvas canvas_;
std::vector<gfx::TileInfo> tiles_;
};
} // namespace zelda3
} // namespace app
} // namespace yaze
#endif

View File

@@ -38,6 +38,8 @@ absl::Status Overworld::Load(ROM &rom) {
overworld_maps_.emplace_back(map_index, rom_, tiles16); overworld_maps_.emplace_back(map_index, rom_, tiles16);
FetchLargeMaps(); FetchLargeMaps();
LoadEntrances();
LoadSprites();
auto size = tiles16.size(); auto size = tiles16.size();
for (int i = 0; i < core::kNumOverworldMaps; ++i) { for (int i = 0; i < core::kNumOverworldMaps; ++i) {
@@ -194,8 +196,8 @@ void Overworld::FetchLargeMaps() {
overworld_maps_[136].SetLargeMap(false); overworld_maps_[136].SetLargeMap(false);
bool mapChecked[64]; bool mapChecked[64];
for (auto &each : mapChecked) { for (int i = 0; i < 64; i++) {
each = false; mapChecked[i] = false;
} }
int xx = 0; int xx = 0;
int yy = 0; int yy = 0;
@@ -237,6 +239,148 @@ void Overworld::FetchLargeMaps() {
} }
} }
void Overworld::LoadEntrances() {
for (int i = 0; i < 129; i++) {
short mapId = rom_.toint16(core::OWEntranceMap + (i * 2));
ushort mapPos = rom_.toint16(core::OWEntrancePos + (i * 2));
uchar entranceId = (rom_[core::OWEntranceEntranceId + i]);
int p = mapPos >> 1;
int x = (p % 64);
int y = (p >> 6);
bool deleted = false;
if (mapPos == 0xFFFF) {
deleted = true;
}
all_entrances_.emplace_back(
(x * 16) + (((mapId % 64) - (((mapId % 64) / 8) * 8)) * 512),
(y * 16) + (((mapId % 64) / 8) * 512), entranceId, mapId, mapPos,
deleted);
}
for (int i = 0; i < 0x13; i++) {
short mapId = (short)((rom_[core::OWHoleArea + (i * 2) + 1] << 8) +
(rom_[core::OWHoleArea + (i * 2)]));
short mapPos = (short)((rom_[core::OWHolePos + (i * 2) + 1] << 8) +
(rom_[core::OWHolePos + (i * 2)]));
uchar entranceId = (rom_[core::OWHoleEntrance + i]);
int p = (mapPos + 0x400) >> 1;
int x = (p % 64);
int y = (p >> 6);
all_holes_.emplace_back(
(x * 16) + (((mapId % 64) - (((mapId % 64) / 8) * 8)) * 512),
(y * 16) + (((mapId % 64) / 8) * 512), entranceId, mapId,
(ushort)(mapPos + 0x400), true);
}
}
void Overworld::LoadSprites() {
// LW[0] = RainState 0 to 63 there's no data for DW
// LW[1] = ZeldaState 0 to 128 ; Contains LW and DW <128 or 144 wtf
// LW[2] = AgahState 0 to ?? ;Contains data for LW and DW
for (int i = 0; i < 3; i++) {
all_sprites_.emplace_back(std::vector<Sprite>());
}
// Console.WriteLine(((core::overworldSpritesBegining & 0xFFFF) + (09 <<
// 16)).ToString("X6"));
for (int i = 0; i < 64; i++) {
if (map_parent_[i] == i) {
// Beginning Sprites
int ptrPos = core::overworldSpritesBegining + (i * 2);
int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos));
while (true) {
uchar b1 = rom_[spriteAddress];
uchar b2 = rom_[spriteAddress + 1];
uchar b3 = rom_[spriteAddress + 2];
if (b1 == 0xFF) {
break;
}
int mapY = (i / 8);
int mapX = (i % 8);
int realX = ((b2 & 0x3F) * 16) + mapX * 512;
int realY = ((b1 & 0x3F) * 16) + mapY * 512;
all_sprites_[0].emplace_back(overworld_maps_[i].AreaGraphics(),
(uchar)i, b3, (uchar)(b2 & 0x3F),
(uchar)(b1 & 0x3F), realX, realY);
spriteAddress += 3;
}
}
}
for (int i = 0; i < 144; i++) {
if (map_parent_[i] == i) {
// Zelda Saved Sprites
int ptrPos = core::overworldSpritesZelda + (i * 2);
int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos));
while (true) {
uchar b1 = rom_[spriteAddress];
uchar b2 = rom_[spriteAddress + 1];
uchar b3 = rom_[spriteAddress + 2];
if (b1 == 0xFF) {
break;
}
int editorMapIndex = i;
if (editorMapIndex >= 128) {
editorMapIndex = i - 128;
} else if (editorMapIndex >= 64) {
editorMapIndex = i - 64;
}
int mapY = (editorMapIndex / 8);
int mapX = (editorMapIndex % 8);
int realX = ((b2 & 0x3F) * 16) + mapX * 512;
int realY = ((b1 & 0x3F) * 16) + mapY * 512;
all_sprites_[1].emplace_back(overworld_maps_[i].AreaGraphics(),
(uchar)i, b3, (uchar)(b2 & 0x3F),
(uchar)(b1 & 0x3F), realX, realY);
spriteAddress += 3;
}
}
// Agahnim Dead Sprites
if (map_parent_[i] == i) {
int ptrPos = core::overworldSpritesAgahnim + (i * 2);
int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos));
while (true) {
uchar b1 = rom_[spriteAddress];
uchar b2 = rom_[spriteAddress + 1];
uchar b3 = rom_[spriteAddress + 2];
if (b1 == 0xFF) {
break;
}
int editorMapIndex = i;
if (editorMapIndex >= 128) {
editorMapIndex = i - 128;
} else if (editorMapIndex >= 64) {
editorMapIndex = i - 64;
}
int mapY = (editorMapIndex / 8);
int mapX = (editorMapIndex % 8);
int realX = ((b2 & 0x3F) * 16) + mapX * 512;
int realY = ((b1 & 0x3F) * 16) + mapY * 512;
all_sprites_[2].emplace_back(overworld_maps_[i].AreaGraphics(),
(uchar)i, b3, (uchar)(b2 & 0x3F),
(uchar)(b1 & 0x3F), realX, realY);
spriteAddress += 3;
}
}
}
}
} // namespace zelda3 } // namespace zelda3
} // namespace app } // namespace app
} // namespace yaze } // namespace yaze

View File

@@ -9,33 +9,88 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "app/core/constants.h" #include "app/core/constants.h"
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#include "app/gfx/pseudo_vram.h"
#include "app/gfx/snes_tile.h" #include "app/gfx/snes_tile.h"
#include "app/rom.h" #include "app/rom.h"
#include "app/zelda3/overworld_map.h" #include "app/zelda3/overworld_map.h"
#include "app/zelda3/sprite.h"
namespace yaze { namespace yaze {
namespace app { namespace app {
namespace zelda3 { namespace zelda3 {
class OverworldEntrance {
public:
int x_;
int y_;
ushort mapPos;
uchar entranceId_, AreaX, AreaY;
short mapId_;
bool isHole = false;
bool deleted = false;
OverworldEntrance(int x, int y, uchar entranceId, short mapId, ushort mapPos,
bool hole) {
x_ = x;
y_ = y;
entranceId_ = entranceId;
mapId_ = mapId;
mapPos = mapPos;
int mapX = (mapId_ - ((mapId / 8) * 8));
int mapY = (mapId_ / 8);
AreaX = (uchar)((std::abs(x - (mapX * 512)) / 16));
AreaY = (uchar)((std::abs(y - (mapY * 512)) / 16));
isHole = hole;
}
auto Copy() {
return new OverworldEntrance(x_, y_, entranceId_, mapId_, mapPos, isHole);
}
void updateMapStuff(short mapId) {
mapId_ = mapId;
if (mapId_ >= 64) {
mapId_ -= 64;
}
int mapX = (mapId_ - ((mapId_ / 8) * 8));
int mapY = (mapId_ / 8);
AreaX = (uchar)((std::abs(x_ - (mapX * 512)) / 16));
AreaY = (uchar)((std::abs(y_ - (mapY * 512)) / 16));
int mx = (mapId_ - ((mapId_ / 8) * 8));
int my = (mapId_ / 8);
uchar xx = (uchar)((x_ - (mx * 512)) / 16);
uchar yy = (uchar)((y_ - (my * 512)) / 16);
mapPos = (ushort)((((AreaY) << 6) | (AreaX & 0x3F)) << 1);
}
};
class Overworld { class Overworld {
public: public:
absl::Status Load(ROM &rom); absl::Status Load(ROM &rom);
auto GetTiles16() const { return tiles16; } auto GetTiles16() const { return tiles16; }
auto GetOverworldMap(uint index) { return overworld_maps_[index]; } auto GetOverworldMap(uint index) { return overworld_maps_[index]; }
auto GetOverworldMaps() const { return overworld_maps_; } auto GetOverworldMaps() const { return overworld_maps_; }
auto GetCurrentBlockset() const { auto Sprites() const { return all_sprites_[game_state_]; }
return overworld_maps_[current_map_].GetCurrentBlockset(); auto AreaGraphics() const {
return overworld_maps_[current_map_].AreaGraphics();
} }
auto GetCurrentGraphics() const { auto Entrances() const { return all_entrances_; }
return overworld_maps_[current_map_].GetCurrentGraphics(); auto AreaPalette() const {
return overworld_maps_[current_map_].AreaPalette();
} }
auto GetCurrentBitmapData() const { auto BitmapData() const { return overworld_maps_[current_map_].BitmapData(); }
return overworld_maps_[current_map_].GetBitmapData(); auto Tile16Blockset() const {
} return overworld_maps_[current_map_].Tile16Blockset();
auto GetCurrentPalette() const {
return overworld_maps_[current_map_].GetCurrentPalette();
} }
auto GameState() const { return game_state_; }
auto isLoaded() const { return is_loaded_; } auto isLoaded() const { return is_loaded_; }
void SetCurrentMap(int i) { current_map_ = i; } void SetCurrentMap(int i) { current_map_ = i; }
@@ -58,9 +113,12 @@ class Overworld {
int &ttpos); int &ttpos);
absl::Status DecompressAllMapTiles(); absl::Status DecompressAllMapTiles();
void FetchLargeMaps(); void FetchLargeMaps();
void LoadEntrances();
void LoadSprites();
void LoadOverworldMap(); void LoadOverworldMap();
int game_state_ = 1; int game_state_ = 0;
int current_map_ = 0; int current_map_ = 0;
uchar map_parent_[160]; uchar map_parent_[160];
bool is_loaded_ = false; bool is_loaded_ = false;
@@ -71,6 +129,9 @@ class Overworld {
std::vector<gfx::Tile16> tiles16; std::vector<gfx::Tile16> tiles16;
std::vector<gfx::Tile32> tiles32; std::vector<gfx::Tile32> tiles32;
std::vector<OverworldMap> overworld_maps_; std::vector<OverworldMap> overworld_maps_;
std::vector<OverworldEntrance> all_entrances_;
std::vector<OverworldEntrance> all_holes_;
std::vector<std::vector<Sprite>> all_sprites_;
}; };
} // namespace zelda3 } // namespace zelda3

View File

@@ -46,7 +46,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
int k = 0; int k = 0;
for (int y = 2; y < 7; y++) { for (int y = 2; y < 7; y++) {
for (int x = 1; x < 8; x++) { for (int x = 1; x < 8; x++) {
new_palette[x + (16 * y)] = main[k++]; new_palette[x + (16 * y)] = main[k];
k++;
} }
} }
@@ -61,7 +62,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 2; y < 5; y++) { for (int y = 2; y < 5; y++) {
for (int x = 9; x < 16; x++) { for (int x = 9; x < 16; x++) {
new_palette[x + (16 * y)] = aux1[k++]; new_palette[x + (16 * y)] = aux1[k];
k++;
} }
} }
@@ -69,7 +71,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 5; y < 8; y++) { for (int y = 5; y < 8; y++) {
for (int x = 9; x < 16; x++) { for (int x = 9; x < 16; x++) {
new_palette[x + (16 * y)] = aux2[k++]; new_palette[x + (16 * y)] = aux2[k];
k++;
} }
} }
@@ -88,7 +91,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 8; y < 9; y++) { for (int y = 8; y < 9; y++) {
for (int x = 1; x < 8; x++) { for (int x = 1; x < 8; x++) {
new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux1")[1][k++]; new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux1")[1][k];
k++;
} }
} }
@@ -96,7 +100,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 8; y < 9; y++) { for (int y = 8; y < 9; y++) {
for (int x = 9; x < 16; x++) { for (int x = 9; x < 16; x++) {
new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux3")[0][k++]; new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux3")[0][k];
k++;
} }
} }
@@ -104,7 +109,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 9; y < 13; y++) { for (int y = 9; y < 13; y++) {
for (int x = 1; x < 16; x++) { for (int x = 1; x < 16; x++) {
new_palette[x + (16 * y)] = rom.GetPaletteGroup("global_sprites")[0][k++]; new_palette[x + (16 * y)] = rom.GetPaletteGroup("global_sprites")[0][k];
k++;
} }
} }
@@ -112,7 +118,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 13; y < 14; y++) { for (int y = 13; y < 14; y++) {
for (int x = 1; x < 8; x++) { for (int x = 1; x < 8; x++) {
new_palette[x + (16 * y)] = spr[k++]; new_palette[x + (16 * y)] = spr[k];
k++;
} }
} }
@@ -120,7 +127,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 14; y < 15; y++) { for (int y = 14; y < 15; y++) {
for (int x = 1; x < 8; x++) { for (int x = 1; x < 8; x++) {
new_palette[x + (16 * y)] = spr2[k++]; new_palette[x + (16 * y)] = spr2[k];
k++;
} }
} }
@@ -128,21 +136,15 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
k = 0; k = 0;
for (int y = 15; y < 16; y++) { for (int y = 15; y < 16; y++) {
for (int x = 1; x < 16; x++) { for (int x = 1; x < 16; x++) {
new_palette[x + (16 * y)] = rom.GetPaletteGroup("armors")[0][k++]; new_palette[x + (16 * y)] = rom.GetPaletteGroup("armors")[0][k];
k++;
} }
} }
current.Create(new_palette); current.Create(new_palette);
// ColorPalette pal = GFX.editort16Bitmap.Palette; for (int i = 0; i < 256; i++) {
// for (int i = 0; i < 256; i++) { current[(i / 16) * 16].setTransparent(true);
// pal.Entries[i] = new_palette[i]; }
// pal.Entries[(i / 16) * 16] = Color.Transparent;
// }
// GFX.mapgfx16Bitmap.Palette = pal;
// GFX.mapblockset16Bitmap.Palette = pal;
// gfxBitmap.Palette = pal;
} }
} // namespace } // namespace
@@ -156,6 +158,7 @@ OverworldMap::OverworldMap(int index, ROM& rom,
absl::Status OverworldMap::BuildMap(int count, int game_state, int world, absl::Status OverworldMap::BuildMap(int count, int game_state, int world,
uchar* map_parent, uchar* map_parent,
OWBlockset& world_blockset) { OWBlockset& world_blockset) {
game_state_ = game_state;
world_ = world; world_ = world;
if (large_map_) { if (large_map_) {
parent_ = map_parent[index_]; parent_ = map_parent[index_];
@@ -176,16 +179,7 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world,
} }
} }
int world_index = 0x20; LoadAreaGraphics();
if (parent_ < 0x40) {
world_index = 0x20;
} else if (parent_ >= 0x40 && parent_ < 0x80) {
world_index = 0x21;
} else if (parent_ == 0x88) {
world_index = 0x24;
}
LoadAreaGraphics(game_state, world_index);
RETURN_IF_ERROR(BuildTileset()) RETURN_IF_ERROR(BuildTileset())
RETURN_IF_ERROR(BuildTiles16Gfx(count)) RETURN_IF_ERROR(BuildTiles16Gfx(count))
LoadPalette(); LoadPalette();
@@ -273,7 +267,16 @@ void OverworldMap::LoadAreaInfo() {
} }
} }
void OverworldMap::LoadAreaGraphics(int game_state, int world_index) { void OverworldMap::LoadAreaGraphics() {
int world_index = 0x20;
if (parent_ < 0x40) {
world_index = 0x20;
} else if (parent_ >= 0x40 && parent_ < 0x80) {
world_index = 0x21;
} else if (parent_ == 0x88) {
world_index = 0x24;
}
// Sprites Blocksets // Sprites Blocksets
static_graphics_[8] = 0x73 + 0x00; static_graphics_[8] = 0x73 + 0x00;
static_graphics_[9] = 0x73 + 0x01; static_graphics_[9] = 0x73 + 0x01;
@@ -281,7 +284,7 @@ void OverworldMap::LoadAreaGraphics(int game_state, int world_index) {
static_graphics_[11] = 0x73 + 0x07; static_graphics_[11] = 0x73 + 0x07;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
static_graphics_[12 + i] = (rom_[core::kSpriteBlocksetPointer + static_graphics_[12 + i] = (rom_[core::kSpriteBlocksetPointer +
(sprite_graphics_[game_state] * 4) + i] + (sprite_graphics_[game_state_] * 4) + i] +
0x73); 0x73);
} }
@@ -333,8 +336,7 @@ void OverworldMap::LoadPalette() {
uchar pal0 = 0; uchar pal0 = 0;
uchar pal1 = uchar pal1 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4)];
rom_[core::overworldMapPaletteGroup + (area_palette_ * 4)]; // aux1
uchar pal2 = uchar pal2 =
rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + 1]; // aux2 rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + 1]; // aux2
uchar pal3 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + uchar pal3 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) +
@@ -387,7 +389,7 @@ void OverworldMap::LoadPalette() {
if (parent_ < 0x40) { if (parent_ < 0x40) {
// Default LW Palette // Default LW Palette
pal0 = 0; pal0 = 0;
bgr = rom_.GetPaletteGroup("grass")[0].GetColor(0);
if (parent_ == 0x03 || parent_ == 0x05 || parent_ == 0x07) { if (parent_ == 0x03 || parent_ == 0x05 || parent_ == 0x07) {
pal0 = 2; pal0 = 2;
} }
@@ -457,8 +459,16 @@ absl::Status OverworldMap::BuildTileset() {
for (int i = 0; i < 0x10; i++) { for (int i = 0; i < 0x10; i++) {
for (int j = 0; j < 0x1000; j++) { for (int j = 0; j < 0x1000; j++) {
current_gfx_[(i * 0x1000) + j] = auto byte = all_gfx_[j + (static_graphics_[i] * 0x1000)];
all_gfx_[j + (static_graphics_[i] * 0x1000)]; switch (i) {
case 0:
case 3:
case 4:
case 5:
byte += 0x88;
break;
}
current_gfx_[(i * 0x1000) + j] = byte;
} }
} }
return absl::OkStatus(); return absl::OkStatus();
@@ -496,7 +506,7 @@ absl::Status OverworldMap::BuildTiles16Gfx(int count) {
auto destination = xx + yy + offset + (mx + (my * 0x80)); auto destination = xx + yy + offset + (mx + (my * 0x80));
current_blockset_[destination] = current_blockset_[destination] =
current_gfx_[source] + (info.palette_ * 0x10); (current_gfx_[source] & 0x0F) + (info.palette_ * 0x10);
} }
} }
} }

View File

@@ -28,18 +28,17 @@ class OverworldMap {
absl::Status BuildMap(int count, int game_state, int world, uchar* map_parent, absl::Status BuildMap(int count, int game_state, int world, uchar* map_parent,
OWBlockset& world_blockset); OWBlockset& world_blockset);
auto GetCurrentBlockset() const { return current_blockset_; } auto Tile16Blockset() const { return current_blockset_; }
auto GetCurrentGraphics() const { return current_gfx_; } auto AreaGraphics() const { return current_gfx_; }
auto GetCurrentPalette() const { return current_palette_; } auto AreaPalette() const { return current_palette_; }
auto GetBitmapData() const { return bitmap_data_; } auto BitmapData() const { return bitmap_data_; }
auto SetLargeMap(bool is_set) { large_map_ = is_set; } auto SetLargeMap(bool is_set) { large_map_ = is_set; }
auto IsLargeMap() const { return large_map_; } auto IsLargeMap() const { return large_map_; }
auto IsInitialized() const { return initialized_; } auto IsInitialized() const { return initialized_; }
auto IsBuilt() const { return built_; }
private: private:
void LoadAreaInfo(); void LoadAreaInfo();
void LoadAreaGraphics(int game_state, int world_index); void LoadAreaGraphics();
void LoadPalette(); void LoadPalette();
absl::Status BuildTileset(); absl::Status BuildTileset();
@@ -52,8 +51,6 @@ class OverworldMap {
int message_id_ = 0; int message_id_ = 0;
int area_graphics_ = 0; int area_graphics_ = 0;
int area_palette_ = 0; int area_palette_ = 0;
// TODO SET ME
int game_state_ = 0; int game_state_ = 0;
uchar sprite_graphics_[3]; uchar sprite_graphics_[3];

921
src/app/zelda3/sprite.cc Normal file
View File

@@ -0,0 +1,921 @@
#include "sprite.h"
namespace yaze {
namespace app {
namespace zelda3 {
Sprite::Sprite(Bytes src, uchar mapid, uchar id, uchar x, uchar y, int map_x,
int map_y) {
current_gfx_ = src;
overworld_ = true;
map_id_ = mapid;
id_ = id;
x_ = x;
y_ = 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);
}
}
void Sprite::updateBBox() {
lowerX_ = 1;
lowerY_ = 1;
higherX_ = 15;
higherY_ = 15;
}
void Sprite::Draw(bool picker) {
uchar x = nx_;
uchar y = ny_;
picker_ = picker;
if (overlord_ == 0x07) {
if (id_ == 0x1A) {
DrawSpriteTile((x * 16), (y * 16), 14, 6, 11); // bomb
} else if (id_ == 0x05) {
DrawSpriteTile((x * 16), (y * 16) - 12, 12, 16, 12, false, true);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 12, false, true);
} else if (id_ == 0x06) {
DrawSpriteTile((x * 16), (y * 16), 10, 26, 14, true, true, 2,
2); // snek
} else if (id_ == 0x09) {
DrawSpriteTile((x * 16), (y * 16), 6, 26, 14);
DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 8, 26, 14);
DrawSpriteTile((x * 16), (y * 16) + 16, 10, 27, 14, false, false, 1, 1);
} else if (id_ == 0x14) {
DrawSpriteTile((x * 16), (y * 16) + 8, 12, 06, 12, false, false, 2,
1); // shadow tile
DrawSpriteTile((x * 16), (y * 16) - 8, 3, 29, 8, false, false, 1,
1); // tile
DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 3, 29, 8, true, false, 1,
1); // tile
DrawSpriteTile((x * 16), (y * 16), 3, 29, 8, false, true, 1,
1); // tile
DrawSpriteTile((x * 16) + 8, (y * 16), 3, 29, 8, true, true, 1,
1); // tile
} else {
DrawSpriteTile((x * 16), (y * 16), 4, 4, 5);
}
if (nx_ != x || ny_ != y) {
bounding_box_.x = (lowerX_ + (nx_ * 16));
bounding_box_.y = (lowerY_ + (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_.w = width_;
bounding_box_.h = height_;
}
return;
}
if (id_ == 0x00) {
DrawSpriteTile((x * 16), (y * 16), 4, 28, 10);
} else if (id_ == 0x01) {
DrawSpriteTile((x * 16) - 8, (y * 16), 6, 24, 12, false, false, 2, 2);
DrawSpriteTile((x * 16) + 8, (y * 16), 6, 24, 12, true, false, 2, 2);
} else if (id_ == 0x02) {
DrawSpriteTile((x * 16), (y * 16), 0, 16, 10);
} else if (id_ == 0x04) {
uchar 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;
DrawSpriteTile((x * 16), (y * 16), 14, 28, p);
DrawSpriteTile((x * 16), (y * 16), 14, 30, p);
} else if (id_ == 0x06) {
uchar 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;
DrawSpriteTile((x * 16), (y * 16), 14, 28, p);
DrawSpriteTile((x * 16), (y * 16), 14, 30, p);
} else if (id_ == 0x08) {
DrawSpriteTile((x * 16), (y * 16), 0, 24, 6);
DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 6, false, false, 1, 1);
} else if (id_ == 0x09) {
DrawSpriteTile((x * 16) - 22, (y * 16) - 24, 12, 24, 12, false, false, 2,
2); // Moldorm tail
DrawSpriteTile((x * 16) - 16, (y * 16) - 20, 8, 24, 12, false, false, 2,
2); // Moldorm b2
DrawSpriteTile((x * 16) - 12, (y * 16) - 16, 4, 24, 12, false, false, 4,
4); // Moldorm b
DrawSpriteTile((x * 16), (y * 16), 0, 24, 12, false, false, 4,
4); // Moldorm head
DrawSpriteTile((x * 16) + 20, (y * 16) + 12, 8, 26, 14, false, false, 2,
2); // Moldorm eye
DrawSpriteTile((x * 16) + 12, (y * 16) + 20, 8, 26, 14, false, false, 2,
2); // Moldorm eye
} else if (id_ == 0x0A) {
DrawSpriteTile((x * 16), (y * 16), 0, 24, 8);
DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 8, false, false, 1, 1);
} else if (id_ == 0x0B) {
DrawSpriteTile((x * 16), (y * 16), 10, 30, 10);
} else if (id_ == 0x0C) {
DrawSpriteTile((x * 16), (y * 16), 0, 24, 8);
DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 8, false, false, 1, 1);
} else if (id_ == 0x0D) {
DrawSpriteTile((x * 16), (y * 16), 14, 28, 12);
} else if (id_ == 0x0E) {
DrawSpriteTile((x * 16), (y * 16), 8, 18, 10, false, false, 3, 2);
} else if (id_ == 0x0F) {
DrawSpriteTile((x * 16), (y * 16), 14, 24, 8, false, false, 2, 3);
DrawSpriteTile((x * 16) + 16, (y * 16), 30, 8, 8, true, false, 1, 3);
} else if (id_ == 0x10) {
DrawSpriteTile((x * 16), (y * 16), 12, 31, 8, false, false, 1, 1);
} else if (id_ == 0x11) {
DrawSpriteTile((x * 16), (y * 16) + 16, 6, 16, 8, false, false, 2,
2); // Feet
DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 4, 18, 8, false, false, 2,
2); // Body1
DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 4, 18, 8, true, false, 2,
2); // Body2
DrawSpriteTile((x * 16), (y * 16), 0, 16, 8, false, false, 2,
2); // Head
} else if (id_ == 0x12) {
DrawSpriteTile((x * 16), (y * 16) + 8, 8, 26, 8);
DrawSpriteTile((x * 16), (y * 16), 6, 24, 8);
} else if (id_ == 0x13) {
DrawSpriteTile((x * 16), (y * 16), 4, 22, 2);
} else if (id_ == 0x15) {
// Antifairy
DrawSpriteTile((x * 16) + 2, (y * 16) + 8, 3, 30, 5, false, false, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16) + 2, 3, 30, 5, false, false, 1, 1);
DrawSpriteTile((x * 16) + 14, (y * 16) + 8, 3, 30, 5, false, false, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16) + 14, 3, 30, 5, false, false, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 1, 30, 5, false, false, 1,
1); // Middle
} else if (id_ == 0x16) {
DrawSpriteTile((x * 16), (y * 16) + 8, 2, 26, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 26, 2);
} else if (id_ == 0x17) // Bush hoarder
{
DrawSpriteTile((x * 16), (y * 16), 8, 30, 10);
} else if (id_ == 0x18) // Mini moldorm
{
DrawSpriteTile((x * 16) + 13, (y * 16) + 17, 13, 21, 8, false, false, 1,
1); // Tail
DrawSpriteTile((x * 16) + 5, (y * 16) + 8, 2, 22, 8); // Body
DrawSpriteTile((x * 16), (y * 16), 0, 22, 8); // Head
DrawSpriteTile((x * 16), (y * 16) - 4, 13, 20, 8, false, false, 1,
1); // Eyes
DrawSpriteTile((x * 16) - 4, (y * 16), 13, 20, 8, false, false, 1,
1); // Eyes
} else if (id_ == 0x19) // Poe - ghost
{
DrawSpriteTile((x * 16), (y * 16), 6, 31, 2); //
} else if (id_ == 0x1A) // Smith
{
// DrawSpriteTile((x*16), (y *16), 2, 4, 10,true); // Smitty
// DrawSpriteTile((x*16)+12, (y *16) - 7, 0, 6, 10); // Hammer
DrawSpriteTile((x * 16), (y * 16), 4, 22, 10);
} else if (id_ == 0x1C) // Statue
{
DrawSpriteTile((x * 16), (y * 16) + 8, 0, 28, 15);
DrawSpriteTile((x * 16), (y * 16), 2, 28, 15, false, false, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16), 2, 28, 15, true, false, 1, 1);
} else if (id_ == 0x1E) // Crystal switch
{
DrawSpriteTile((x * 16), (y * 16), 4, 30, 5);
} else if (id_ == 0x1F) // Sick kid
{
DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 10, 16, 14);
DrawSpriteTile((x * 16) + 16 - 8, (y * 16) + 8, 10, 16, 14, true);
DrawSpriteTile((x * 16) - 8, (y * 16) + 16, 10, 16, 14, false, true, 2, 2);
DrawSpriteTile((x * 16) + 16 - 8, (y * 16) + 16, 10, 16, 14, true, true, 2,
2);
DrawSpriteTile((x * 16), (y * 16) - 4, 14, 16, 10);
} else if (id_ == 0x20) {
DrawSpriteTile((x * 16), (y * 16), 2, 24, 7);
} else if (id_ == 0x21) // Push switch
{
DrawSpriteTile((x * 16) + 4, (y * 16) + 20, 13, 29, 3, false, false, 1, 1);
DrawSpriteTile((x * 16) + 4, (y * 16) + 28, 12, 29, 3, false, false, 1, 1);
DrawSpriteTile((x * 16), (y * 16) + 8, 10, 28, 3);
} else if (id_ == 0x22) // Rope
{
DrawSpriteTile((x * 16), (y * 16), 8, 26, 5);
} else if (id_ == 0x23) // Red bari
{
DrawSpriteTile((x * 16), (y * 16), 2, 18, 4, false, false, 1, 2);
DrawSpriteTile((x * 16) + 8, (y * 16), 2, 18, 4, true, false, 1, 2);
} else if (id_ == 0x24) // Blue bari
{
DrawSpriteTile((x * 16), (y * 16), 2, 18, 6, false, false, 1, 2);
DrawSpriteTile((x * 16) + 8, (y * 16), 2, 18, 6, true, false, 1, 2);
} else if (id_ == 0x25) // Talking tree?
{
// TODO: Add something here?
} else if (id_ == 0x26) // Hardhat beetle
{
if ((x & 0x01) == 0x00) {
DrawSpriteTile((x * 16), (y * 16), 4, 20, 8);
DrawSpriteTile((x * 16), (y * 16) - 6, 0, 20, 8);
} else {
DrawSpriteTile((x * 16), (y * 16), 4, 20, 10);
DrawSpriteTile((x * 16), (y * 16) - 6, 0, 20, 10);
}
} else if (id_ == 0x27) // Deadrock
{
DrawSpriteTile((x * 16), (y * 16), 2, 30, 10);
} else if (id_ == 0x28) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x29) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x2A) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x2B) // ???
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x2C) // Lumberjack
{
DrawSpriteTile((x * 16) - 24, (y * 16) + 12, 6, 26, 12, true); // Body
DrawSpriteTile((x * 16) - 24, (y * 16), 8, 26, 12, true); // Head
DrawSpriteTile((x * 16) - 14, (y * 16) + 12, 14, 27, 10, false, false, 1,
1); // Saw left edge
DrawSpriteTile((x * 16) - 6, (y * 16) + 12, 15, 27, 10, false, false, 1,
1); // Saw left edge
DrawSpriteTile((x * 16) + 2, (y * 16) + 12, 15, 27, 10, false, false, 1,
1); // Saw left edge
DrawSpriteTile((x * 16) + 10, (y * 16) + 12, 15, 27, 10, false, false, 1,
1); // Saw left edge
DrawSpriteTile((x * 16) + 18, (y * 16) + 12, 15, 27, 10, false, false, 1,
1); // Saw left edge
DrawSpriteTile((x * 16) + 26, (y * 16) + 12, 15, 27, 10, false, false, 1,
1); // Saw left edge
DrawSpriteTile((x * 16) + 34, (y * 16) + 12, 14, 27, 10, true, false, 1,
1); // Saw left edge
DrawSpriteTile((x * 16) + 40, (y * 16) + 12, 4, 26, 12); // Body
DrawSpriteTile((x * 16) + 40, (y * 16), 8, 26, 12); // Head
} else if (id_ == 0x2D) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x2E) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x2F) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x30) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x31) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x32) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
}
/*
else if (id_== 0x33) // Pull for rupees
{
}
*/
else if (id_ == 0x34) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x35) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x36) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
}
/*
else if (id_== 0x37) // Waterfall
{
DrawSpriteTile((x*16), (y *16), 14, 6, 10);
}
*/
else if (id_ == 0x38) // Arrowtarget
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x39) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x3A) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x3B) // Dash item
{
} else if (id_ == 0x3C) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x3D) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x3E) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x3F) // Npcs
{
DrawSpriteTile((x * 16), (y * 16), 14, 22, 10);
} else if (id_ == 0x40) // Lightning lock (agah tower)
{
DrawSpriteTile((x * 16) - 24, (y * 16), 10, 28, 2, false, false, 1, 2);
DrawSpriteTile((x * 16) - 16, (y * 16), 6, 30, 2);
DrawSpriteTile((x * 16), (y * 16), 8, 30, 2);
DrawSpriteTile((x * 16) + 16, (y * 16), 6, 30, 2);
DrawSpriteTile((x * 16) + 24, (y * 16), 10, 28, 2, false, false, 1, 2);
} else if (id_ == 0x41) // Blue soldier
{
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 10, true, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 20, 10);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 10, false, false, 1,
2); // Shield
DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 14, 22, 10, false, true, 1,
2); // Sword
} else if (id_ == 0x42) // Green soldier
{
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 12);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 12, true, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 12, false, false, 1,
2); // Shield
DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 14, 22, 12, false, true, 1,
2); // Sword
} else if (id_ == 0x43) // Red spear soldier
{
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 8, true, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 20, 8);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 8, false, false, 1,
2); // Shield
DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 11, 22, 8, false, true, 1,
2); // Spear
} else if (id_ == 0x44) // Sword blue holding up
{
DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 10);
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); // Head
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 14, 22, 10, false, true, 1,
2); // Sword
} else if (id_ == 0x45) // Green spear soldier
{
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 12);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 12, true, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 12, false, false, 1,
2); // Shield
DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 11, 22, 12, false, true, 1,
2); // Spear
} else if (id_ == 0x46) // Blue archer
{
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 10, true, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 20, 10); // Head
DrawSpriteTile((x * 16), (y * 16) + 16, 10, 16, 10, false, false, 1,
1); // Bow1
DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 10, 16, 10, true, false, 1,
1); // Bow2
} else if (id_ == 0x47) // Green archer
{
DrawSpriteTile((x * 16), (y * 16) + 8, 14, 16, 12);
DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
DrawSpriteTile((x * 16), (y * 16) + 16, 10, 16, 12, false, false, 1,
1); // Bow1
DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 10, 16, 12, true, false, 1,
1); // Bow2
} else if (id_ == 0x48) // Javelin soldier red
{
DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8);
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 8); // Head
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 11, 22, 8, false, true, 1,
2); // Sword
} else if (id_ == 0x49) // Javelin soldier red from bush
{
DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8);
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 18, 8); // Head
DrawSpriteTile((x * 16), (y * 16) + 24, 0, 20, 2);
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 11, 22, 8, false, true, 1,
2); // Sword
} else if (id_ == 0x4A) // Red bomb soldier
{
DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8);
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 8); // Head
DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 14, 22, 11); // Bomb
} else if (id_ == 0x4B) // Green soldier recruit
{
// 0,4
DrawSpriteTile((x * 16), (y * 16), 6, 24, 12);
DrawSpriteTile((x * 16), (y * 16) - 10, 0, 20, 12);
} else if (id_ == 0x4C) // Jazzhand
{
DrawSpriteTile((x * 16), (y * 16), 0, 26, 14, false, false, 6, 2);
} else if (id_ == 0x4D) // Rabit??
{
DrawSpriteTile((x * 16), (y * 16), 0, 26, 12, false, false, 6, 2);
} else if (id_ == 0x4E) // Popo1
{
DrawSpriteTile((x * 16), (y * 16), 0, 20, 10);
} else if (id_ == 0x4F) // Popo2
{
DrawSpriteTile((x * 16), (y * 16), 2, 20, 10);
} else if (id_ == 0x50) // Canon ball
{
DrawSpriteTile((x * 16), (y * 16), 0, 24, 10);
} else if (id_ == 0x51) // Armos
{
DrawSpriteTile((x * 16), (y * 16), 0, 28, 11, false, false, 2, 4);
} else if (id_ == 0x53) // Armos Knight
{
DrawSpriteTile((x * 16), (y * 16), 0, 28, 10, false, false, 4, 4);
} else if (id_ == 0x54) {
DrawSpriteTile((x * 16), (y * 16), 2, 28, 12);
DrawSpriteTile((x * 16) + 8, (y * 16) + 10, 6, 28, 12);
DrawSpriteTile((x * 16) + 16, (y * 16) + 18, 10, 28, 12);
} else if (id_ == 0x55) // Fireball Zora
{
DrawSpriteTile((x * 16), (y * 16), 4, 26, 11);
} else if (id_ == 0x56) // Zora
{
DrawSpriteTile((x * 16), (y * 16), 10, 20, 2);
DrawSpriteTile((x * 16), (y * 16) + 8, 8, 30, 2);
} else if (id_ == 0x57) // Desert Rocks
{
DrawSpriteTile((x * 16), (y * 16), 14, 24, 2, false, false, 2, 4);
DrawSpriteTile((x * 16) + 16, (y * 16), 14, 24, 2, true, false, 2, 4);
} else if (id_ == 0x58) // Crab
{
DrawSpriteTile((x * 16), (y * 16), 14, 24, 12);
DrawSpriteTile((x * 16) + 16, (y * 16), 14, 24, 12, true);
} else if (id_ == 0x5B) // Spark
{
DrawSpriteTile((x * 16), (y * 16), 8, 18, 4);
} else if (id_ == 0x5C) // Spark
{
DrawSpriteTile((x * 16), (y * 16), 8, 18, 4, true);
} else if (id_ == 0x5D) // Roller vertical1
{
// Subset3
if (((y * 16) & 0x10) == 0x10) {
DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
for (int i = 0; i < 7; i++) {
DrawSpriteTile((x * 16) + 8 + (i * 16), (y * 16), 9, 24, 11);
}
DrawSpriteTile((x * 16) + (16 * 7), (y * 16), 8, 24, 11, true);
} else {
DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
DrawSpriteTile((x * 16) + 16, (y * 16), 9, 24, 11);
DrawSpriteTile((x * 16) + 32, (y * 16), 9, 24, 11);
DrawSpriteTile((x * 16) + 48, (y * 16), 8, 24, 11, true);
}
} else if (id_ == 0x5E) // Roller vertical2
{
// Subset3
if (((y * 16) & 0x10) == 0x10) {
DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
for (int i = 0; i < 7; i++) {
DrawSpriteTile((x * 16) + 8 + (i * 16), (y * 16), 9, 24, 11);
}
DrawSpriteTile((x * 16) + (16 * 7), (y * 16), 8, 24, 11, true);
} else {
DrawSpriteTile((x * 16), (y * 16), 8, 24, 11);
DrawSpriteTile((x * 16) + 16, (y * 16), 9, 24, 11);
DrawSpriteTile((x * 16) + 32, (y * 16), 9, 24, 11);
DrawSpriteTile((x * 16) + 48, (y * 16), 8, 24, 11, true);
}
} else if (id_ == 0x5F) // Roller horizontal
{
if (((x * 16) & 0x10) == 0x10) {
DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
DrawSpriteTile((x * 16), (y * 16) + 16, 14, 25, 11);
DrawSpriteTile((x * 16), (y * 16) + 32, 14, 25, 11);
DrawSpriteTile((x * 16), (y * 16) + 48, 14, 24, 11, false, true);
} else {
for (int i = 0; i < 7; i++) {
DrawSpriteTile((x * 16), (y * 16) + i * 16, 14, 25, 11);
}
DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
DrawSpriteTile((x * 16), (y * 16) + (7 * 16), 14, 24, 11, false, true);
}
} else if (id_ == 0x60) // Roller horizontal2 (right to left)
{
// Subset3
if (((x * 16) & 0x10) == 0x10) {
DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
DrawSpriteTile((x * 16), (y * 16) + 16, 14, 25, 11);
DrawSpriteTile((x * 16), (y * 16) + 32, 14, 25, 11);
DrawSpriteTile((x * 16), (y * 16) + 48, 14, 24, 11, false, true);
} else {
for (int i = 0; i < 7; i++) {
DrawSpriteTile((x * 16), (y * 16) + i * 16, 14, 25, 11);
}
DrawSpriteTile((x * 16), (y * 16), 14, 24, 11);
DrawSpriteTile((x * 16), (y * 16) + (7 * 16), 14, 24, 11, false, true);
}
} else if (id_ == 0x61) // Beamos
{
DrawSpriteTile((x * 16), (y * 16) - 16, 8, 20, 14, false, false, 2, 4);
DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 10, 20, 14, false, false, 1, 1);
} else if (id_ == 0x63) // Devalant non-shooter
{
DrawSpriteTile((x * 16) - 8, (y * 16) - 8, 2, 16, 2);
DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 2, 16, 2, true);
DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 2, 16, 2, false, true);
DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 2, 16, 2, true, true);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 10);
} else if (id_ == 0x64) // Devalant non-shooter
{
DrawSpriteTile((x * 16) - 8, (y * 16) - 8, 2, 16, 2);
DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 2, 16, 2, true);
DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 2, 16, 2, false, true);
DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 2, 16, 2, true, true);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 8);
} else if (id_ == 0x66) // Moving wall canon right
{
DrawSpriteTile((x * 16), (y * 16), 14, 16, 14, true);
} else if (id_ == 0x67) // Moving wall canon right
{
DrawSpriteTile((x * 16), (y * 16), 14, 16, 14);
} else if (id_ == 0x68) // Moving wall canon right
{
DrawSpriteTile((x * 16), (y * 16), 12, 16, 14);
} else if (id_ == 0x69) // Moving wall canon right
{
DrawSpriteTile((x * 16), (y * 16), 12, 16, 14, false, true);
} else if (id_ == 0x6A) // Chainball soldier
{
DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 14);
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 14, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 14); // Head
DrawSpriteTile((x * 16) + 12, (y * 16) - 16, 10, 18, 14); // Ball
} else if (id_ == 0x6B) // Cannon soldier
{
DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 14);
DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 14, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 14); // Head
DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 4, 18, 14); // Cannon
} else if (id_ == 0x6C) // Mirror portal
{
// Useless
} else if (id_ == 0x6D) // Rat
{
DrawSpriteTile((x * 16), (y * 16), 14, 24, 5);
} else if (id_ == 0x6E) // Rope
{
DrawSpriteTile((x * 16), (y * 16), 10, 26, 5);
} else if (id_ == 0x6F) {
DrawSpriteTile((x * 16), (y * 16), 4, 24, 10);
} else if (id_ == 0x70) // Helma fireball
{
DrawSpriteTile((x * 16), (y * 16), 10, 28, 4);
} else if (id_ == 0x71) // Leever
{
DrawSpriteTile((x * 16), (y * 16), 6, 16, 4);
} else if (id_ == 0x73) // Uncle priest
{
} else if (id_ == 0x79) // Bee
{
DrawSpriteTile((x * 16), (y * 16), 4, 14, 11, false, false, 1, 1);
} else if (id_ == 0x7A) {
DrawSpriteTile((x * 16), (y * 16) - 16, 2, 24, 12, false, false, 2, 4);
DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 2, 24, 12, true, false, 2, 4);
} else if (id_ == 0x7C) // Skull head
{
DrawSpriteTile((x * 16), (y * 16), 0, 16, 10);
} else if (id_ == 0x7D) // Big spike
{
DrawSpriteTile((x * 16), (y * 16), 4, 28, 11);
DrawSpriteTile((x * 16) + 16, (y * 16), 4, 28, 11, true);
DrawSpriteTile((x * 16), (y * 16) + 16, 4, 28, 11, false, true);
DrawSpriteTile((x * 16) + 16, (y * 16) + 16, 4, 28, 11, true, true);
} else if (id_ == 0x7E) // Guruguru clockwise
{
DrawSpriteTile((x * 16), (y * 16) - 14, 8, 18, 4);
DrawSpriteTile((x * 16), (y * 16) - 28, 8, 18, 4);
DrawSpriteTile((x * 16), (y * 16) - 42, 8, 18, 4);
DrawSpriteTile((x * 16), (y * 16) - 56, 8, 18, 4);
} else if (id_ == 0x7F) // Guruguru Counterclockwise
{
DrawSpriteTile((x * 16), (y * 16) - 14, 8, 18, 4);
DrawSpriteTile((x * 16), (y * 16) - 28, 8, 18, 4);
DrawSpriteTile((x * 16), (y * 16) - 42, 8, 18, 4);
DrawSpriteTile((x * 16), (y * 16) - 56, 8, 18, 4);
} else if (id_ == 0x80) // Winder (moving firebar)
{
DrawSpriteTile((x * 16), (y * 16), 8, 18, 4);
DrawSpriteTile((x * 16) - 14, (y * 16), 8, 18, 4);
DrawSpriteTile((x * 16) - 28, (y * 16), 8, 18, 4);
DrawSpriteTile((x * 16) - 42, (y * 16), 8, 18, 4);
DrawSpriteTile((x * 16) - 56, (y * 16), 8, 18, 4);
} else if (id_ == 0x81) // Water tektite
{
DrawSpriteTile((x * 16), (y * 16), 0, 24, 11);
} else if (id_ == 0x82) // circle antifairy
{
// Antifairy top
DrawSpriteTile((x * 16 + 2) - 4, (y * 16 + 8) - 16, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 2) - 16, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 14) - 4, (y * 16 + 8) - 16, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 14) - 16, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 8) - 16, 1, 30, 5, false, false,
1, 1); // Middle
// Left
DrawSpriteTile((x * 16 + 2) - 16, (y * 16 + 8) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 2) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 14) - 16, (y * 16 + 8) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 14) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 8) - 4, 1, 30, 5, false, false,
1, 1); // Middle
DrawSpriteTile((x * 16 + 2) - 4, (y * 16 + 8) + 8, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 2) + 8, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 14) - 4, (y * 16 + 8) + 8, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 14) + 8, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 8) + 8, 1, 30, 5, false, false,
1, 1); // Middle
// Left
DrawSpriteTile((x * 16 + 2) + 8, (y * 16 + 8) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 2) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 14) + 8, (y * 16 + 8) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 14) - 4, 3, 30, 5, false, false,
1, 1);
DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 8) - 4, 1, 30, 5, false, false,
1, 1); // Middle
} else if (id_ == 0x83) // Green eyegore
{
DrawSpriteTile((x * 16), (y * 16), 12, 24, 14, false, false, 2, 3);
DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 14, true, false, 1, 3);
} else if (id_ == 0x84) // Red eyegore
{
DrawSpriteTile((x * 16), (y * 16), 12, 24, 8, false, false, 2, 3);
DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 8, true, false, 1, 3);
} else if (id_ == 0x85) // Yellow stalfos
{
DrawSpriteTile((x * 16), (y * 16), 10, 16, 11);
DrawSpriteTile((x * 16), (y * 16) - 12, 0, 16, 11); // Head
} else if (id_ == 0x86) // Kodongo
{
DrawSpriteTile((x * 16), (y * 16), 4, 26, 14);
} else if (id_ == 0x88) // Mothula
{
DrawSpriteTile((x * 16), (y * 16), 8, 24, 14, false, false, 2, 4);
DrawSpriteTile((x * 16) + 16, (y * 16), 8, 24, 14, true, false, 2, 4);
} else if (id_ == 0x8A) // Spike
{
DrawSpriteTile((x * 16), (y * 16), 6, 30, 15);
} else if (id_ == 0x8B) // Gibdo
{
DrawSpriteTile((x * 16), (y * 16), 10, 24, 14);
DrawSpriteTile((x * 16), (y * 16) - 8, 0, 24, 14);
} else if (id_ == 0x8C) // Arrghus
{
DrawSpriteTile((x * 16), (y * 16), 0, 24, 14, false, false, 2, 4);
DrawSpriteTile((x * 16) + 16, (y * 16), 0, 24, 14, true, false, 2, 4);
} else if (id_ == 0x8D) // Arrghus spawn
{
DrawSpriteTile((x * 16), (y * 16), 6, 24, 14);
} else if (id_ == 0x8E) // Terrorpin
{
DrawSpriteTile((x * 16), (y * 16), 14, 24, 12);
} else if (id_ == 0x8F) // Slime
{
DrawSpriteTile((x * 16), (y * 16), 0, 20, 12);
} else if (id_ == 0x90) // Wall master
{
DrawSpriteTile((x * 16), (y * 16), 6, 26, 12);
DrawSpriteTile((x * 16) + 16, (y * 16), 15, 26, 12, false, false, 1, 1);
DrawSpriteTile((x * 16) + 16, (y * 16) + 8, 9, 26, 12, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16) + 16, 10, 27, 12, false, false, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 8, 27, 12, false, false, 1, 1);
} else if (id_ == 0x91) // Stalfos knight
{
DrawSpriteTile((x * 16) - 2, (y * 16) + 12, 4, 22, 12, false, false, 1, 2);
DrawSpriteTile((x * 16) + 10, (y * 16) + 12, 4, 22, 12, true, false, 1, 2);
DrawSpriteTile((x * 16) - 4, (y * 16) + 4, 1, 22, 12);
DrawSpriteTile((x * 16) + 12, (y * 16) + 4, 3, 22, 12, false, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16) - 8, 6, 20, 12);
} else if (id_ == 0x92) // Helmaking
{
DrawSpriteTile((x * 16), (y * 16) + 32, 14, 26, 14);
DrawSpriteTile((x * 16) + 16, (y * 16) + 32, 0, 28, 14);
DrawSpriteTile((x * 16) + 32, (y * 16) + 32, 14, 26, 14, true);
DrawSpriteTile((x * 16), (y * 16) + 16 + 32, 2, 28, 14);
DrawSpriteTile((x * 16) + 16, (y * 16) + 16 + 32, 4, 28, 14);
DrawSpriteTile((x * 16) + 32, (y * 16) + 16 + 32, 2, 28, 14, true);
DrawSpriteTile((x * 16) + 8, (y * 16) + 32 + 32, 6, 28, 14);
DrawSpriteTile((x * 16) + 24, (y * 16) + 32 + 32, 6, 28, 14, true);
} else if (id_ == 0x93) // Bumper
{
DrawSpriteTile((x * 16), (y * 16), 12, 30, 7);
DrawSpriteTile((x * 16) + 16, (y * 16), 12, 30, 7, true);
DrawSpriteTile((x * 16) + 16, (y * 16) + 16, 12, 30, 7, true, true);
DrawSpriteTile((x * 16), (y * 16) + 16, 12, 30, 7, false, true);
} else if (id_ == 0x95) // Right laser eye
{
DrawSpriteTile((x * 16), (y * 16), 9, 28, 3, true, false, 1, 2);
DrawSpriteTile((x * 16), (y * 16) + 16, 9, 28, 3, true, true, 1, 1);
} else if (id_ == 0x96) // Left laser eye
{
DrawSpriteTile((x * 16) + 8, (y * 16) - 4, 9, 28, 3, false, false, 1, 2);
DrawSpriteTile((x * 16) + 8, (y * 16) + 12, 9, 28, 3, false, true, 1, 1);
} else if (id_ == 0x97) // Right laser eye
{
DrawSpriteTile((x * 16), (y * 16), 6, 28, 3, false, false, 2, 1);
DrawSpriteTile((x * 16) + 16, (y * 16), 6, 28, 3, true, false, 1, 1);
} else if (id_ == 0x98) // Right laser eye
{
DrawSpriteTile((x * 16), (y * 16), 6, 28, 3, false, true, 2, 1);
DrawSpriteTile((x * 16) + 16, (y * 16), 6, 28, 3, true, true, 1, 1);
} else if (id_ == 0x99) {
DrawSpriteTile((x * 16), (y * 16), 6, 24, 12);
DrawSpriteTile((x * 16), (y * 16) - 8, 0, 24, 12);
} else if (id_ == 0x9A) // Water bubble kyameron
{
DrawSpriteTile((x * 16), (y * 16), 10, 24, 6);
} else if (id_ == 0x9B) // Water bubble kyameron
{
DrawSpriteTile((x * 16), (y * 16), 6, 24, 11);
DrawSpriteTile((x * 16), (y * 16) - 8, 2, 27, 11, false, false, 2, 1);
} else if (id_ == 0x9C) // Water bubble kyameron
{
DrawSpriteTile((x * 16), (y * 16), 12, 22, 11);
DrawSpriteTile((x * 16) + 16, (y * 16), 13, 22, 11, false, false, 1, 2);
} else if (id_ == 0x9D) // Water bubble kyameron
{
DrawSpriteTile((x * 16), (y * 16), 14, 21, 11);
DrawSpriteTile((x * 16), (y * 16) - 16, 14, 20, 11, false, false, 2, 1);
} else if (id_ == 0xA1) {
DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 6, 26, 14);
DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 6, 26, 14, true);
} else if (id_ == 0xA2) {
DrawSpriteTile((x * 16), (y * 16) + 8, 0, 24, 14, false, false, 4, 4);
} else if (id_ == 0xA5) {
DrawSpriteTile((x * 16), (y * 16), 0, 26, 10, false, false, 3, 2);
DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 0, 24, 10);
} else if (id_ == 0xA6) {
DrawSpriteTile((x * 16), (y * 16), 0, 26, 8, false, false, 3, 2);
DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 0, 24, 8);
} else if (id_ == 0xA7) {
DrawSpriteTile((x * 16), (y * 16) + 12, 12, 16, 10);
DrawSpriteTile((x * 16), (y * 16), 0, 16, 10);
} else if (id_ == 0xAC) {
DrawSpriteTile((x * 16), (y * 16), 5, 14, 4);
} else if (id_ == 0xAD) {
DrawSpriteTile((x * 16), (y * 16) + 8, 14, 10, 10);
DrawSpriteTile((x * 16), (y * 16), 12, 10, 10);
} else if (id_ == 0xBA) {
DrawSpriteTile((x * 16), (y * 16), 14, 14, 6);
} else if (id_ == 0xC1) {
DrawSpriteTile((x * 16), (y * 16) - 16, 2, 24, 12, false, false, 2, 4);
DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 2, 24, 12, true, false, 2, 4);
} else if (id_ == 0xC3) {
DrawSpriteTile((x * 16), (y * 16), 10, 14, 12);
} else if (id_ == 0xC4) {
DrawSpriteTile((x * 16), (y * 16), 0, 18, 14);
DrawSpriteTile((x * 16), (y * 16) - 8, 0, 16, 14);
} else if (id_ == 0xC5) {
} else if (id_ == 0xC6) {
DrawSpriteTile((x * 16) + 4, (y * 16) + 14, 3, 30, 14, false, false, 1, 1);
DrawSpriteTile((x * 16) + 14, (y * 16) + 4, 3, 30, 14, false, false, 1, 1);
DrawSpriteTile((x * 16) + 4, (y * 16) + 2, 1, 31, 14, false, false, 1, 1);
DrawSpriteTile((x * 16) - 6, (y * 16) + 4, 3, 30, 14, false, false, 1, 1);
DrawSpriteTile((x * 16) + 4, (y * 16) - 6, 3, 30, 14, false, false, 1, 1);
} else if (id_ == 0xC7) {
DrawSpriteTile((x * 16), (y * 16), 0, 26, 4);
DrawSpriteTile((x * 16), (y * 16) - 10, 0, 26, 4);
DrawSpriteTile((x * 16), (y * 16) - 20, 0, 26, 4);
DrawSpriteTile((x * 16), (y * 16) - 30, 2, 26, 4);
} else if (id_ == 0xC8) {
DrawSpriteTile((x * 16), (y * 16), 12, 24, 12, false, false, 2, 3);
DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 12, true, false, 1, 3);
} else if (id_ == 0xC9) {
DrawSpriteTile((x * 16), (y * 16), 8, 28, 8, false);
DrawSpriteTile((x * 16) + 16, (y * 16), 8, 28, 8, true);
} else if (id_ == 0xCA) {
DrawSpriteTile((x * 16), (y * 16), 8, 10, 10);
} else if (id_ == 0xD0) {
DrawSpriteTile((x * 16), (y * 16), 7, 14, 11, false, false, 3, 2);
DrawSpriteTile((x * 16), (y * 16) - 10, 8, 12, 11);
} else if (id_ == 0xD1) {
DrawSpriteTile((x * 16) + 2, (y * 16) + 8, 7, 13, 11, true, true, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16) + 2, 7, 13, 11, true, false, 1, 1);
DrawSpriteTile((x * 16) + 14, (y * 16) + 8, 7, 13, 11, true, true, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16) + 14, 7, 13, 11, false, true, 1, 1);
DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 7, 13, 11, false, false, 1,
1); // Middle
// 6,7 / 13
} else if (id_ == 0xD4) {
DrawSpriteTile((x * 16) - 4, (y * 16), 0, 7, 7, false, false, 1, 1);
DrawSpriteTile((x * 16) + 4, (y * 16), 0, 7, 7, true, false, 1, 1);
} else if (id_ == 0xE3) // Fairy
{
DrawSpriteTile((x * 16), (y * 16), 10, 14, 10);
} else if (id_ == 0xE4) // Key
{
DrawSpriteTile((x * 16), (y * 16), 11, 06, 11, false, false, 1, 2);
} else if (id_ == 0xE7) // Mushroom
{
DrawSpriteTile((x * 16), (y * 16), 14, 30, 16);
} else if (id_ == 0xE8) // Fake ms
{
DrawSpriteTile((x * 16) + 4, (y * 16), 4, 31, 10, false, false, 1, 1);
DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 5, 31, 10, false, false, 1, 1);
} else if (id_ == 0xEB) {
DrawSpriteTile((x * 16), (y * 16), 0, 14, 5);
} else if (id_ == 0xF2) {
DrawSpriteTile((x * 16), (y * 16) - 16, 12, 24, 2, false, false, 2, 4);
DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 12, 24, 2, true, false, 2, 4);
} else if (id_ == 0xF4) {
DrawSpriteTile((x * 16), (y * 16), 12, 28, 5, false, false, 4, 4);
} else {
// stringtodraw.Add(new SpriteName(x, (y *16), sprites_name.name[id]));
DrawSpriteTile((x * 16), (y * 16), 4, 4, 5);
}
bounding_box_.x = (lowerX_ + (x * 16));
bounding_box_.y = (lowerY_ + (y * 16));
bounding_box_.w = width_;
bounding_box_.h = height_;
}
void Sprite::DrawSpriteTile(int x, int y, int srcx, int srcy, int pal,
bool mirror_x, bool mirror_y, int sizex, int sizey,
bool iskey) {
x += 16;
y += 16;
int drawid_ = (srcx + (srcy * 16)) + 512;
for (auto yl = 0; yl < sizey * 8; yl++) {
for (auto xl = 0; xl < (sizex * 8) / 2; xl++) {
int mx = xl;
int my = yl;
if (mirror_x) {
mx = (((sizex * 8) / 2) - 1) - xl;
}
if (mirror_y) {
my = (((sizey * 8)) - 1) - yl;
}
// Formula information to get tile index position in the array
//((ID / nbrofXtiles) * (imgwidth/2) + (ID - ((ID/16)*16) ))
int tx = ((drawid_ / 0x10) * 0x400) +
((drawid_ - ((drawid_ / 0x10) * 0x10)) * 8);
auto pixel = current_gfx_[tx + (yl * 0x80) + xl];
// nx,ny = object position, xx,yy = tile position, xl,yl = pixel
// position
int index = (x) + (y * 64) + (mx + (my * 0x80));
if (index >= 0 && index <= 4096) {
preview_gfx_[index] = (uchar)((pixel & 0x0F) + 112 + (pal * 8));
}
}
}
}
} // namespace zelda3
} // namespace app
} // namespace yaze

68
src/app/zelda3/sprite.h Normal file
View File

@@ -0,0 +1,68 @@
#ifndef YAZE_APP_ZELDA3_SPRITE_H
#define YAZE_APP_ZELDA3_SPRITE_H
#include <SDL.h>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#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 {
namespace app {
namespace zelda3 {
class Sprite {
public:
uchar x_, y_, id_;
uchar nx_, ny_;
uchar layer_ = 0;
uchar subtype_ = 0;
uchar overlord_ = 0;
std::string name_;
uchar keyDrop_ = 0;
int sizeMap_ = 512;
bool overworld_ = false;
bool preview_ = false;
uchar map_id_ = 0;
int map_x_ = 0;
int map_y_ = 0;
short room_id_ = 0;
bool picker_ = false;
bool selected_ = false;
SDL_Rect bounding_box_;
Bytes current_gfx_;
Bytes preview_gfx_;
int lowerX_ = 32;
int lowerY_ = 32;
int higherX_ = 0;
int higherY_ = 0;
int width_ = 16;
int height_ = 16;
Sprite(Bytes src, uchar mapid, uchar id, uchar x, uchar y, int map_x,
int map_y);
void updateBBox();
void Draw(bool picker = false);
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, bool iskey = false);
auto PreviewGraphics() { return preview_gfx_; }
};
} // namespace zelda3
} // namespace app
} // namespace yaze
#endif

View File

@@ -1,4 +1,4 @@
#include "screen.h" #include "title_screen.h"
#include <cstdint> #include <cstdint>
@@ -11,7 +11,7 @@ namespace yaze {
namespace app { namespace app {
namespace zelda3 { namespace zelda3 {
void Screen::Create() { void TitleScreen::Create() {
tiles8Bitmap.Create(128, 512, 8, 0x20000); tiles8Bitmap.Create(128, 512, 8, 0x20000);
tilesBG1Bitmap.Create(256, 256, 8, 0x80000); tilesBG1Bitmap.Create(256, 256, 8, 0x80000);
tilesBG2Bitmap.Create(256, 256, 8, 0x80000); tilesBG2Bitmap.Create(256, 256, 8, 0x80000);
@@ -20,12 +20,9 @@ void Screen::Create() {
BuildTileset(); BuildTileset();
LoadTitleScreen(); LoadTitleScreen();
LoadOverworldMap();
LoadDungeonMaps();
LoadAllMapIcons();
} }
void Screen::BuildTileset() { void TitleScreen::BuildTileset() {
uchar staticgfx[16]; uchar staticgfx[16];
// Main Blocksets // Main Blocksets
@@ -66,7 +63,7 @@ void Screen::BuildTileset() {
} }
} }
void Screen::LoadTitleScreen() { void TitleScreen::LoadTitleScreen() {
int pos = int pos =
(rom_[0x138C + 3] << 16) + (rom_[0x1383 + 3] << 8) + rom_[0x137A + 3]; (rom_[0x138C + 3] << 16) + (rom_[0x1383 + 3] << 8) + rom_[0x137A + 3];
@@ -127,14 +124,6 @@ void Screen::LoadTitleScreen() {
pal_selected_ = 2; pal_selected_ = 2;
} }
void Screen::LoadNamingScreen() {}
void Screen::LoadOverworldMap() {}
void Screen::LoadDungeonMaps() {}
void Screen::LoadAllMapIcons() {}
} // namespace zelda3 } // namespace zelda3
} // namespace app } // namespace app
} // namespace yaze } // namespace yaze

View File

@@ -12,17 +12,13 @@ namespace yaze {
namespace app { namespace app {
namespace zelda3 { namespace zelda3 {
class Screen { class TitleScreen {
public: public:
void Create(); void Create();
private: private:
void BuildTileset(); void BuildTileset();
void LoadTitleScreen(); void LoadTitleScreen();
void LoadNamingScreen();
void LoadOverworldMap();
void LoadDungeonMaps();
void LoadAllMapIcons();
int sword_x_ = 0; int sword_x_ = 0;
int mx_click_ = 0; int mx_click_ = 0;

View File

@@ -6,6 +6,7 @@
#include <string> #include <string>
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#include "app/rom.h"
namespace yaze { namespace yaze {
namespace gui { namespace gui {
@@ -39,8 +40,10 @@ void Canvas::DrawContextMenu() {
// Add first and second point // Add first and second point
if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
ImVec2 draw_tile_outline_pos; ImVec2 draw_tile_outline_pos;
draw_tile_outline_pos.x = std::round((double)mouse_pos_in_canvas.x / 32) * 32; draw_tile_outline_pos.x =
draw_tile_outline_pos.y = std::round((double)mouse_pos_in_canvas.y / 32) * 32; std::round((double)mouse_pos_in_canvas.x / 32) * 32;
draw_tile_outline_pos.y =
std::round((double)mouse_pos_in_canvas.y / 32) * 32;
points_.push_back(draw_tile_outline_pos); points_.push_back(draw_tile_outline_pos);
points_.push_back( points_.push_back(
@@ -61,6 +64,11 @@ void Canvas::DrawContextMenu() {
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
if (ImGui::BeginPopup("context")) { if (ImGui::BeginPopup("context")) {
ImGui::MenuItem("Show Grid", nullptr, &enable_grid_);
if (ImGui::MenuItem("Reset Position", nullptr, false)) {
scrolling_.x = 0;
scrolling_.y = 0;
}
if (ImGui::MenuItem("Remove all", nullptr, false, points_.Size > 0)) { if (ImGui::MenuItem("Remove all", nullptr, false, points_.Size > 0)) {
points_.clear(); points_.clear();
} }
@@ -68,12 +76,35 @@ void Canvas::DrawContextMenu() {
} }
} }
void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset) { void Canvas::DrawTilesFromUser(app::ROM &rom, Bytes &tile,
draw_list_->AddImage( app::gfx::SNESPalette &pal) {
(void *)bitmap.GetTexture(), ImVec2 draw_tile_outline_pos;
ImVec2(canvas_p0_.x + border_offset, canvas_p0_.y + border_offset),
ImVec2(canvas_p0_.x + (bitmap.GetWidth() * 2), // Add rectangle
canvas_p0_.y + (bitmap.GetHeight() * 2))); if (is_hovered_ && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
draw_tile_outline_pos.x =
std::round((double)mouse_pos_in_canvas_.x / 16) * 16;
draw_tile_outline_pos.y =
std::round((double)mouse_pos_in_canvas_.y / 16) * 16;
points_.push_back(draw_tile_outline_pos);
points_.push_back(
ImVec2(draw_tile_outline_pos.x + 16, draw_tile_outline_pos.y + 16));
changed_tiles_.emplace_back(app::gfx::Bitmap(16, 16, 64, tile.data()));
changed_tiles_.back().ApplyPalette(pal);
rom.RenderBitmap(&(changed_tiles_.back()));
}
}
void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, bool ready) {
if (ready) {
draw_list_->AddImage(
(void *)bitmap.GetTexture(),
ImVec2(canvas_p0_.x + border_offset, canvas_p0_.y + border_offset),
ImVec2(canvas_p0_.x + (bitmap.GetWidth() * 2),
canvas_p0_.y + (bitmap.GetHeight() * 2)));
}
} }
void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset) { void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset) {
@@ -86,11 +117,28 @@ void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset) {
} }
void Canvas::DrawOutline(int x, int y, int w, int h) { void Canvas::DrawOutline(int x, int y, int w, int h) {
ImVec2 origin(x, y); ImVec2 origin(canvas_p0_.x + scrolling_.x + x,
ImVec2 size(x + w, y + 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, 255)); draw_list_->AddRect(origin, size, IM_COL32(255, 255, 255, 255));
} }
void Canvas::DrawRect(int x, int y, int w, int h, ImVec4 color) {
ImVec2 origin(canvas_p0_.x + scrolling_.x + x,
canvas_p0_.y + scrolling_.y + y);
ImVec2 size(canvas_p0_.x + scrolling_.x + x + w,
canvas_p0_.y + scrolling_.y + y + h);
draw_list_->AddRectFilled(origin, size,
IM_COL32(color.x, color.y, color.z, color.w));
}
void Canvas::DrawText(std::string text, int x, int y) {
draw_list_->AddText(
ImVec2(canvas_p0_.x + scrolling_.x + x, canvas_p0_.y + scrolling_.y + y),
IM_COL32(255, 255, 255, 255), text.data());
}
void Canvas::DrawGrid(float grid_step) { void Canvas::DrawGrid(float grid_step) {
// Draw grid + all lines in the canvas // Draw grid + all lines in the canvas
draw_list_->PushClipRect(canvas_p0_, canvas_p1_, true); draw_list_->PushClipRect(canvas_p0_, canvas_p1_, true);

View File

@@ -7,6 +7,7 @@
#include <string> #include <string>
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
#include "app/rom.h"
namespace yaze { namespace yaze {
namespace gui { namespace gui {
@@ -21,9 +22,14 @@ class Canvas {
void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0)); void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0));
void DrawContextMenu(); void DrawContextMenu();
void DrawBitmap(const Bitmap& bitmap, int border_offset = 0); void DrawTilesFromUser(app::ROM& rom, Bytes& tile,
app::gfx::SNESPalette& pal);
void DrawBitmap(const Bitmap& bitmap, int border_offset = 0,
bool ready = true);
void DrawBitmap(const Bitmap& bitmap, int x_offset, int y_offset); void DrawBitmap(const Bitmap& bitmap, int x_offset, int y_offset);
void DrawOutline(int x, int y, int w, int h); void DrawOutline(int x, int y, int w, int h);
void DrawRect(int x, int y, int w, int h, ImVec4 color);
void DrawText(std::string text, int x, int y);
void DrawGrid(float grid_step = 64.0f); void DrawGrid(float grid_step = 64.0f);
void DrawOverlay(); // last void DrawOverlay(); // last
@@ -38,6 +44,7 @@ class Canvas {
bool enable_grid_ = true; bool enable_grid_ = true;
bool enable_context_menu_ = true; bool enable_context_menu_ = true;
bool custom_canvas_size_ = false; bool custom_canvas_size_ = false;
bool is_hovered_ = false;
ImDrawList* draw_list_; ImDrawList* draw_list_;
ImVector<ImVec2> points_; ImVector<ImVec2> points_;
@@ -45,6 +52,9 @@ class Canvas {
ImVec2 canvas_sz_; ImVec2 canvas_sz_;
ImVec2 canvas_p0_; ImVec2 canvas_p0_;
ImVec2 canvas_p1_; ImVec2 canvas_p1_;
ImVec2 mouse_pos_in_canvas_;
std::vector<app::gfx::Bitmap> changed_tiles_;
std::string title_; std::string title_;
}; };

84
src/gui/color.cc Normal file
View File

@@ -0,0 +1,84 @@
#include "color.h"
#include <imgui/imgui.h>
#include <cmath>
#include <string>
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
namespace yaze {
namespace gui {
void DisplayPalette(app::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;
static ImVec4 saved_palette[32] = {};
if (loaded && !init) {
for (int n = 0; n < palette.size_; n++) {
saved_palette[n].x = palette.GetColor(n).rgb.x / 255;
saved_palette[n].y = palette.GetColor(n).rgb.y / 255;
saved_palette[n].z = palette.GetColor(n).rgb.z / 255;
saved_palette[n].w = 255; // Alpha
}
init = true;
}
static ImVec4 backup_color;
ImGui::Text("Current ==>");
ImGui::SameLine();
ImGui::Text("Previous");
ImGui::ColorButton(
"##current", color,
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
ImVec2(60, 40));
ImGui::SameLine();
if (ImGui::ColorButton(
"##previous", backup_color,
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
ImVec2(60, 40)))
color = backup_color;
ImGui::Separator();
ImGui::BeginGroup(); // Lock X position
ImGui::Text("Palette");
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) {
ImGui::PushID(n);
if ((n % 4) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha |
ImGuiColorEditFlags_NoPicker |
ImGuiColorEditFlags_NoTooltip;
if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags,
ImVec2(20, 20)))
color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z,
color.w); // Preserve alpha!
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
ImGui::EndDragDropTarget();
}
ImGui::PopID();
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::ColorPicker4("##picker", (float*)&color,
misc_flags | ImGuiColorEditFlags_NoSidePreview |
ImGuiColorEditFlags_NoSmallPreview);
}
} // namespace gui
} // namespace yaze

20
src/gui/color.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef YAZE_GUI_COLOR_H
#define YAZE_GUI_COLOR_H
#include <imgui/imgui.h>
#include <cmath>
#include <string>
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
namespace yaze {
namespace gui {
void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded);
} // namespace gui
} // namespace yaze
#endif

View File

@@ -30,7 +30,7 @@ using ::testing::Return;
class MockScript : public Script { class MockScript : public Script {
public: public:
MOCK_METHOD(absl::Status, ApplyPatchToROM, (ROM & rom)); MOCK_METHOD(absl::Status, ApplyPatchToROM, (ROM & rom));
MOCK_METHOD(absl::Status, GenerateMosaicChangeAssembly, MOCK_METHOD(absl::Status, PatchOverworldMosaic,
(ROM & rom, char mosaic_tiles[yaze::app::core::kNumOverworldMaps], (ROM & rom, char mosaic_tiles[yaze::app::core::kNumOverworldMaps],
int routine_offset, int hook_offset)); int routine_offset, int hook_offset));
}; };
@@ -40,15 +40,15 @@ TEST(ASMTest, ApplyMosaicChangePatchOk) {
MockScript script; MockScript script;
char mosaic_tiles[yaze::app::core::kNumOverworldMaps]; char mosaic_tiles[yaze::app::core::kNumOverworldMaps];
EXPECT_CALL(script, GenerateMosaicChangeAssembly(_, Eq(mosaic_tiles), EXPECT_CALL(script, PatchOverworldMosaic(_, Eq(mosaic_tiles),
Eq(0x1301D0 + 0x138000), 0)) Eq(0x1301D0 + 0x138000), 0))
.WillOnce(Return(absl::OkStatus())); .WillOnce(Return(absl::OkStatus()));
EXPECT_CALL(script, ApplyPatchToROM(_)).WillOnce(Return(absl::OkStatus())); EXPECT_CALL(script, ApplyPatchToROM(_)).WillOnce(Return(absl::OkStatus()));
EXPECT_THAT(script.GenerateMosaicChangeAssembly(rom, mosaic_tiles, EXPECT_THAT(
0x1301D0 + 0x138000, 0), script.PatchOverworldMosaic(rom, mosaic_tiles, 0x1301D0 + 0x138000, 0),
absl::OkStatus()); absl::OkStatus());
EXPECT_THAT(script.ApplyPatchToROM(rom), absl::OkStatus()); EXPECT_THAT(script.ApplyPatchToROM(rom), absl::OkStatus());
} }