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(OpenGL 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
add_subdirectory(src/lib/abseil-cpp)

View File

@@ -36,12 +36,35 @@ set(
# Asar Assembly ---------------------------------------------------------------
add_subdirectory(lib/asar/src)
set(ASAR_GEN_EXE OFF)
set(ASAR_GEN_DLL ON)
set(ASAR_GEN_LIB OFF)
get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES)
target_include_directories(asar-static PRIVATE ${ASAR_INCLUDE_DIR})
set(ASAR_GEN_EXE OFF)
set(ASAR_GEN_DLL ON)
set(ASAR_GEN_LIB ON)
set(ASAR_GEN_EXE_TEST OFF)
set(ASAR_GEN_DLL_TEST OFF)
set(ASAR_STATIC_SRC
"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 -----------------------------------------------------------
set(
YAZE_APP_CORE_SRC
@@ -62,16 +85,17 @@ set(
set(
YAZE_APP_GFX_SRC
app/gfx/bitmap.cc
app/gfx/pseudo_vram.cc
app/gfx/snes_palette.cc
app/gfx/snes_tile.cc
)
set(
YAZE_APP_ZELDA3_SRC
app/zelda3/inventory.cc
app/zelda3/overworld_map.cc
app/zelda3/overworld.cc
app/zelda3/screen.cc
app/zelda3/title_screen.cc
app/zelda3/sprite.cc
)
set(
@@ -85,6 +109,7 @@ set(
gui/input.cc
gui/style.cc
gui/widgets.cc
gui/color.cc
)
add_executable(
@@ -98,7 +123,7 @@ add_executable(
${YAZE_APP_ZELDA3_SRC}
${YAZE_GUI_SRC}
${IMGUI_SRC}
lib/asar/src/asar-dll-bindings/c/asardll.c
${ASAR_STATIC_SRC}
)
target_include_directories(
@@ -110,7 +135,7 @@ target_include_directories(
${PNG_INCLUDE_DIRS}
${SDL2_INCLUDE_DIR}
${GLEW_INCLUDE_DIRS}
lib/asar/src/asar-dll-bindings/c
lib/asar/src/
)
set(SDL_TARGETS SDL2::SDL2)
@@ -129,7 +154,10 @@ target_link_libraries(
${OPENGL_LIBRARIES}
${CMAKE_DL_LIBS}
ImGui
asar-static
)
target_compile_definitions(yaze PRIVATE "linux")
target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp")
set_target_properties(yaze
PROPERTIES
@@ -139,6 +167,48 @@ set_target_properties(yaze
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 (destination "${CMAKE_CURRENT_BINARY_DIR}/assets")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD

View File

@@ -1,6 +1,6 @@
#include "script.h"
#include <asardll.h>
#include <asar/interface-lib.h>
#include <array>
#include <cstdint>
@@ -20,49 +20,13 @@ namespace yaze {
namespace app {
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) {
if (patch_contents_.empty() || patch_filename_.empty()) {
return absl::InvalidArgumentError("No patch loaded!");
}
char *data = (char *)rom.data();
int size = rom.GetSize();
int count = 0;
auto data = (char *)rom.data();
int size = rom.size();
if (!asar_patch(patch_filename_.c_str(), data, patch_size_, &size)) {
auto asar_error = asar_geterrors(&count);
auto full_error = asar_error->fullerrdata;
@@ -71,43 +35,37 @@ absl::Status Script::ApplyPatchToROM(ROM &rom) {
return absl::OkStatus();
}
absl::Status Script::GenerateMosaicChangeAssembly(
absl::Status Script::PatchOverworldMosaic(
ROM &rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_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::ios::out | std::ios::in);
if (!file.is_open()) {
return absl::InvalidArgumentError(
"Couldn't open mosaic change template file");
"Unable to open mosaic change assembly source");
}
std::stringstream assembly;
assembly << file.rdbuf();
file.close();
auto assembly_string = assembly.str();
if (!core::StringReplace(assembly_string, "<HOOK>", kMosaicChangeOffset)) {
return absl::InternalError(
"Mosaic template did not have proper `<HOOK>` to replace.");
}
if (!core::StringReplace(
assembly_string, "<EXPANDED_SPACE>",
absl::StrFormat("$%x", routine_offset + kSNESToPCOffset))) {
return absl::InternalError(
"Mosaic template did not have proper `<EXPANDED_SPACE>` to replace.");
}
assembly_string += GenerateBytePool(mosaic_tiles);
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);
}

View File

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

View File

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

View File

@@ -26,6 +26,7 @@ class Controller {
absl::Status onEntry();
void onInput();
void onLoad();
void onLoadDelta();
void doRender() 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);
overworld_editor_.SetupROM(rom_);
screen_editor_.SetupROM(rom_);
palette_editor_.SetupROM(rom_);
}
ImGuiFileDialog::Instance()->Close();
}
@@ -118,10 +119,10 @@ void MasterEditor::DrawAboutPopup() {
if (about_) ImGui::OpenPopup("About");
if (ImGui::BeginPopupModal("About", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Yet Another Zelda3 Editor - v0.01");
ImGui::Text("Yet Another Zelda3 Editor - v0.02");
ImGui::Text("Written by: scawful");
ImGui::Spacing();
ImGui::Text("Special Thanks: Zarby89");
ImGui::Text("Special Thanks: Zarby89, JaredBrian");
ImGui::Separator();
if (ImGui::Button("Close", ImVec2(200, 0))) {
@@ -137,7 +138,7 @@ void MasterEditor::DrawInfoPopup() {
if (ImGui::BeginPopupModal("ROM Information", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
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))) {
rom_info_ = false;
@@ -215,7 +216,7 @@ void MasterEditor::DrawViewMenu() {
if (show_memory_editor) {
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) {

View File

@@ -8,6 +8,8 @@
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "app/editor/palette_editor.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h"
@@ -22,15 +24,15 @@ namespace editor {
namespace {
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 bitmap = selected_tile.GetData();
int src_pos = ((selected - ((selected / 0x08) * 0x08)) * 0x10) +
((selected / 0x08) * 2048);
for (int yy = 0; yy < 0x10; yy++) {
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;
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_);
auto tile16_palette = overworld_.GetCurrentPalette();
tile16_blockset_bmp_.Create(128, 8192, 128,
overworld_.GetCurrentBlockset());
for (int j = 0; j < tile16_palette.colors.size(); j++) {
tile16_blockset_bmp_.SetPaletteColor(j, tile16_palette.GetColor(j));
}
tile16_blockset_bmp_.Create(128, 8192, 128, overworld_.Tile16Blockset());
tile16_blockset_bmp_.ApplyPalette(palette_);
rom_.RenderBitmap(&tile16_blockset_bmp_);
map_blockset_loaded_ = true;
for (int i = 0; i < core::kNumOverworldMaps; ++i) {
overworld_.SetCurrentMap(i);
auto palette = overworld_.GetCurrentPalette();
maps_bmp_[i].Create(512, 512, 512, overworld_.GetCurrentBitmapData());
for (int j = 0; j < palette.colors.size(); j++) {
maps_bmp_[i].SetPaletteColor(j, palette.GetColor(j));
}
auto palette = overworld_.AreaPalette();
maps_bmp_[i].Create(512, 512, 512, overworld_.BitmapData());
maps_bmp_[i].ApplyPalette(palette);
rom_.RenderBitmap(&(maps_bmp_[i]));
}
}
@@ -72,11 +70,8 @@ absl::Status OverworldEditor::Update() {
selected_tile_bmp_.Create(16, 16, 64, 256);
}
UpdateSelectedTile16(selected_tile_, tile16_blockset_bmp_,
selected_tile_bmp_);
auto palette = overworld_.GetCurrentPalette();
for (int j = 0; j < palette.colors.size(); j++) {
selected_tile_bmp_.SetPaletteColor(j, palette.GetColor(j));
}
selected_tile_data_);
selected_tile_bmp_.ApplyPalette(palette_);
rom_.RenderBitmap(&selected_tile_bmp_);
update_selected_tile_ = false;
}
@@ -102,44 +97,26 @@ absl::Status OverworldEditor::Update() {
}
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)
ImGui::TableSetupColumn(name.data());
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_UNDO);
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_REDO);
ImGui::TableNextColumn();
ImGui::Text(ICON_MD_MORE_VERT);
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_ZOOM_OUT);
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_ZOOM_IN);
ImGui::TableNextColumn();
ImGui::Text(ICON_MD_MORE_VERT);
ImGui::TableNextColumn();
ImGui::Button(ICON_MD_DRAW);
// 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);
BUTTON_COLUMN(ICON_MD_UNDO) // Undo
BUTTON_COLUMN(ICON_MD_REDO) // Redo
TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator
BUTTON_COLUMN(ICON_MD_ZOOM_OUT) // Zoom Out
BUTTON_COLUMN(ICON_MD_ZOOM_IN) // Zoom In
TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator
BUTTON_COLUMN(ICON_MD_DRAW) // Draw Tile
BUTTON_COLUMN(ICON_MD_DOOR_FRONT) // Entrances
BUTTON_COLUMN(ICON_MD_DOOR_BACK) // Exits
BUTTON_COLUMN(ICON_MD_GRASS) // Items
BUTTON_COLUMN(ICON_MD_PEST_CONTROL_RODENT) // Sprites
BUTTON_COLUMN(ICON_MD_ADD_LOCATION) // Transports
BUTTON_COLUMN(ICON_MD_MUSIC_NOTE) // Music
TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator
ImGui::TableNextColumn(); // Palette
palette_editor_.DisplayPalette(palette_, overworld_.isLoaded());
ImGui::EndTable();
}
@@ -218,6 +195,15 @@ void OverworldEditor::DrawOverworldCanvas() {
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_.DrawOverlay();
@@ -261,9 +247,7 @@ void OverworldEditor::DrawTileSelector() {
void OverworldEditor::DrawTile16Selector() {
blockset_canvas_.DrawBackground(ImVec2(0x100 + 1, (8192 * 2) + 1));
blockset_canvas_.DrawContextMenu();
if (map_blockset_loaded_) {
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 2);
}
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 2, map_blockset_loaded_);
blockset_canvas_.DrawGrid(32.0f);
blockset_canvas_.DrawOverlay();
}
@@ -291,13 +275,11 @@ void OverworldEditor::DrawTile8Selector() {
}
void OverworldEditor::DrawAreaGraphics() {
if (overworld_.isLoaded()) {
current_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 16 * 64 + 1));
current_gfx_canvas_.DrawContextMenu();
current_gfx_canvas_.DrawBitmap(current_gfx_bmp_);
current_gfx_canvas_.DrawGrid(32.0f);
current_gfx_canvas_.DrawOverlay();
}
current_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 16 * 64 + 1));
current_gfx_canvas_.DrawContextMenu();
current_gfx_canvas_.DrawBitmap(current_gfx_bmp_, 2, overworld_.isLoaded());
current_gfx_canvas_.DrawGrid(32.0f);
current_gfx_canvas_.DrawOverlay();
}
void OverworldEditor::LoadGraphics() {

View File

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

View File

@@ -12,10 +12,28 @@ namespace app {
namespace editor {
absl::Status PaletteEditor::Update() {
for (const auto &name : kPaletteCategoryNames) {
if (ImGui::TreeNode(name.data())) {
ImGui::SameLine();
if (ImGui::SmallButton("button")) {
for (int i = 0; i < 11; ++i) {
if (ImGui::TreeNode(kPaletteCategoryNames[i].data())) {
auto size = rom_.GetPaletteGroup(kPaletteGroupNames[i].data()).size;
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();
}
@@ -23,6 +41,88 @@ absl::Status PaletteEditor::Update() {
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 app
} // namespace yaze

View File

@@ -5,6 +5,7 @@
#include "absl/status/status.h"
#include "app/gfx/snes_palette.h"
#include "app/rom.h"
#include "gui/canvas.h"
#include "gui/icons.h"
@@ -17,11 +18,21 @@ static constexpr absl::string_view kPaletteCategoryNames[] = {
"Area Colors", "Enemies", "Dungeons", "World Map",
"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 {
public:
absl::Status Update();
void DisplayPalette(gfx::SNESPalette& palette, bool loaded);
auto SetupROM(ROM& rom) { rom_ = rom; }
private:
ImVec4 current_color_;
ROM rom_;
};
} // namespace editor

View File

@@ -17,6 +17,7 @@
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_tile.h"
#include "gui/canvas.h"
#include "gui/icons.h"
#include "gui/input.h"
namespace yaze {
@@ -27,13 +28,12 @@ ScreenEditor::ScreenEditor() { screen_canvas_.SetCanvasSize(ImVec2(512, 512)); }
void ScreenEditor::Update() {
TAB_BAR("##TabBar")
DrawMosaicEditor();
DrawInventoryMenuEditor();
DrawTitleScreenEditor();
DrawNamingScreenEditor();
DrawOverworldMapEditor();
DrawDungeonMapsEditor();
DrawGameMenuEditor();
DrawHUDEditor();
DrawMosaicEditor();
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() {
TAB_ITEM("Mosaic Transitions")
@@ -84,7 +142,7 @@ void ScreenEditor::DrawMosaicEditor() {
gui::InputHex("Routine Location", &overworldCustomMosaicASM);
if (ImGui::Button("Generate Mosaic Assembly")) {
auto mosaic = mosaic_script_.GenerateMosaicChangeAssembly(
auto mosaic = mosaic_script_.PatchOverworldMosaic(
rom_, mosaic_tiles_, overworldCustomMosaicASM);
if (!mosaic.ok()) {
std::cout << mosaic;
@@ -94,39 +152,6 @@ void ScreenEditor::DrawMosaicEditor() {
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() {
static bool show_bg1 = true;
static bool show_bg2 = true;
@@ -147,6 +172,30 @@ void ScreenEditor::DrawToolset() {
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 app
} // namespace yaze

View File

@@ -9,9 +9,12 @@
#include "app/core/constants.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_tile.h"
#include "app/gfx/snes_palette.h"
#include "app/rom.h"
#include "app/zelda3/screen.h"
#include "app/zelda3/inventory.h"
#include "gui/canvas.h"
#include "gui/icons.h"
#include "gui/color.h"
namespace yaze {
namespace app {
@@ -19,12 +22,14 @@ namespace editor {
using MosaicArray = std::array<int, core::kNumOverworldMaps>;
static int overworldCustomMosaicASM = 0x1301D0;
static int overworldCustomMosaicArray = 0x1301F0;
class ScreenEditor {
public:
ScreenEditor();
void SetupROM(ROM &rom) { rom_ = rom; }
void SetupROM(ROM &rom) {
rom_ = rom;
inventory_.SetupROM(rom_);
}
void Update();
private:
@@ -33,19 +38,21 @@ class ScreenEditor {
void DrawNamingScreenEditor();
void DrawOverworldMapEditor();
void DrawDungeonMapsEditor();
void DrawGameMenuEditor();
void DrawHUDEditor();
void DrawInventoryMenuEditor();
void DrawCanvas();
void DrawToolset();
void DrawInventoryToolset();
void DrawWorldGrid(int world, int h = 8, int w = 8);
char mosaic_tiles_[core::kNumOverworldMaps];
ROM rom_;
Bytes all_gfx_;
zelda3::Inventory inventory_;
gfx::SNESPalette palette_;
snes_asm::Script mosaic_script_;
zelda3::Screen current_screen_;
gui::Canvas screen_canvas_;
gui::Canvas tilesheet_canvas_;
};
} // 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_PIXELFORMAT_INDEX8),
SDL_Surface_Deleter());
GrayscalePalette(surface_->format->palette);
surface_->pixels = pixel_data_;
GrayscalePalette(surface_->format->palette);
}
// 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;
depth_ = depth;
data_size_ = size;
data_.reserve(size);
pixel_data_ = data_.data();
surface_ = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(
SDL_CreateRGBSurfaceWithFormat(0, width, height, depth,
SDL_PIXELFORMAT_INDEX8),
SDL_Surface_Deleter());
GrayscalePalette(surface_->format->palette);
pixel_data_ = (uchar *)SDL_malloc(size);
surface_->pixels = pixel_data_;
GrayscalePalette(surface_->format->palette);
}
// 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.
void Bitmap::ApplyPalette(const SNESPalette & palette) {
void Bitmap::ApplyPalette(const SNESPalette &palette) {
palette_ = palette;
SDL_SetPaletteColors(surface_->format->palette,
palette_.GetSDL_Palette()->colors,
0, 256);
}
void Bitmap::SetPaletteColor(int id, gfx::SNESColor color) {
surface_->format->palette->colors[id].r = color.rgb.x;
surface_->format->palette->colors[id].g = color.rgb.y;
surface_->format->palette->colors[id].b = color.rgb.z;
}
// 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);
for (int i = 0; i < palette.size_; ++i) {
if (palette.GetColor(i).transparent) {
surface_->format->palette->colors[i].r = 0;
surface_->format->palette->colors[i].g = 0;
surface_->format->palette->colors[i].b = 0;
surface_->format->palette->colors[i].a = 0;
} else {
surface_->format->palette->colors[i].r = palette.GetColor(i).rgb.x;
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;
}
}
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

View File

@@ -31,12 +31,6 @@ class Bitmap {
void CreateTexture(std::shared_ptr<SDL_Renderer> renderer);
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 GetHeight() const { return height_; }
@@ -59,6 +53,7 @@ class Bitmap {
struct SDL_Surface_Deleter {
void operator()(SDL_Surface *p) const {
if (p != nullptr) {
p->pixels = nullptr;
SDL_FreeSurface(p);
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) {
rgb.x = val.red;
rgb.y = val.blue;
rgb.z = val.green;
rgb.y = val.green;
rgb.z = val.blue;
}
SNESColor::SNESColor(ImVec4 val) : rgb(val) {
@@ -88,13 +88,13 @@ void SNESColor::setRgb(ImVec4 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) {
snes = 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 setSNES(snes_color);
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;
ImVec4 rgb;
};

View File

@@ -20,61 +20,10 @@
#include "app/core/constants.h"
#include "app/gfx/bitmap.h"
#define COMPRESSION_STRING_MOD 7 << 5
namespace yaze {
namespace app {
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 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;
}
namespace lc_lz2 {
void PrintCompressionPiece(const std::shared_ptr<CompressionPiece>& piece) {
printf("Command: %d\n", piece->command);
@@ -298,8 +247,7 @@ Bytes CreateCompressionString(std::shared_ptr<CompressionPiece>& start,
pos++;
} else {
if (piece->length <= kMaxLengthCompression) {
output.push_back((COMPRESSION_STRING_MOD) |
((uchar)piece->command << 2) |
output.push_back(kCompressionStringMod | ((uchar)piece->command << 2) |
(((piece->length - 1) & 0xFF00) >> 8));
pos++;
printf("Building extended header : cmd: %d, length: %d - %02X\n",
@@ -354,7 +302,7 @@ absl::Status ValidateCompressionResult(
RETURN_IF_ERROR(temp_rom.LoadFromBytes(
CreateCompressionString(compressed_chain_start->next, mode)))
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(),
temp_rom.begin())) {
return absl::InternalError(absl::StrFormat(
@@ -392,6 +340,65 @@ std::shared_ptr<CompressionPiece> MergeCopy(
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
// 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({});
cmd_args.fill({{}});
CheckByteRepeat(rom_data_.data(), data_size_taken, cmd_args, src_data_pos,
last_pos);
CheckWordRepeat(rom_data_.data(), data_size_taken, cmd_args, src_data_pos,
last_pos);
CheckIncByte(rom_data_.data(), data_size_taken, cmd_args, src_data_pos,
last_pos);
CheckIntraCopy(rom_data_.data(), data_size_taken, cmd_args, src_data_pos,
last_pos, start);
lc_lz2::CheckByteRepeat(rom_data_.data(), data_size_taken, cmd_args,
src_data_pos, last_pos);
lc_lz2::CheckWordRepeat(rom_data_.data(), data_size_taken, cmd_args,
src_data_pos, last_pos);
lc_lz2::CheckIncByte(rom_data_.data(), data_size_taken, cmd_args,
src_data_pos, last_pos);
lc_lz2::CheckIntraCopy(rom_data_.data(), data_size_taken, cmd_args,
src_data_pos, last_pos, start);
uint max_win = 2;
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) {
// 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;
}
} else {
// Anything is better than directly copying bytes...
CompressionCommandAlternative(rom_data_.data(), compressed_chain,
cmd_size, cmd_args, src_data_pos,
comp_accumulator, cmd_with_max, max_win);
lc_lz2::CompressionCommandAlternative(
rom_data_.data(), compressed_chain, cmd_size, cmd_args, src_data_pos,
comp_accumulator, cmd_with_max, max_win);
}
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) {
RETURN_IF_ERROR(ValidateCompressionResult(compressed_chain_start, mode,
start, src_data_pos))
RETURN_IF_ERROR(lc_lz2::ValidateCompressionResult(
compressed_chain_start, mode, start, src_data_pos))
}
}
MergeCopy(compressed_chain_start->next); // Skipping compression chain header
PrintCompressionChain(compressed_chain_start);
return CreateCompressionString(compressed_chain_start->next, mode);
// Skipping compression chain header
lc_lz2::MergeCopy(compressed_chain_start->next);
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) {
@@ -503,10 +511,8 @@ absl::StatusOr<Bytes> ROM::Decompress(int offset, int size, int mode) {
offset += length;
break;
case kCommandByteFill:
for (int i = 0; i < length; i++) {
buffer[buffer_pos] = rom_data_[offset];
buffer_pos++;
}
memset(buffer.data() + buffer_pos, (int)(rom_data_[offset]), length);
buffer_pos += length;
offset += 1; // Advances 1 byte in the ROM
break;
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 s2 = ((rom_data_[offset] & kSnesByteMax));
int addr = (s1 | s2);
if (mode == kNintendoMode1) { // Reversed byte order for overworld maps
// addr = (s2 | s1);
addr = (rom_data_[offset + 1]) | ((rom_data_[offset]) << 8);
memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length);
buffer_pos += length;
offset += 2;
break;
addr = (rom_data_[offset + 1] & kSnesByteMax) |
((rom_data_[offset] & kSnesByteMax) << 8);
}
if (addr > offset) {
return absl::InternalError(absl::StrFormat(
"DecompressOverworld: Offset for command copy exceeds "
"current position (Offset : %#04x | Pos : %#06x)\n",
"Decompress: Offset for command copy exceeds current position "
"(Offset : %#04x | Pos : %#06x)\n",
addr, offset));
}
if (buffer_pos + length >= size) {
size *= 2;
buffer.resize(size);
}
for (int i = 0; i < length; i++) {
buffer[buffer_pos] = buffer[addr + i];
buffer_pos++;
}
offset += 2; // Advance 2 bytes in the ROM
memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length);
buffer_pos += length;
offset += 2;
} break;
default: {
std::cout << absl::StrFormat(
"DecompressGraphics: Invalid command in header (Offset : %#06x, "
"Command: %#04x)\n",
"Decompress: Invalid header (Offset : %#06x, Command: %#04x)\n",
offset, command);
} break;
}
@@ -582,6 +576,21 @@ absl::StatusOr<Bytes> ROM::DecompressOverworld(int pos, int size) {
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
// 113-114 -> compressed 2bpp -> (decompressed each) 0x800 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
absl::Status ROM::LoadAllGraphicsData() {
Bytes sheet;
bool convert = false;
bool bpp3 = false;
for (int i = 0; i < core::NumberOfSheets; i++) {
if (i >= 115 && i <= 126) { // uncompressed sheets
@@ -598,17 +607,17 @@ absl::Status ROM::LoadAllGraphicsData() {
for (int j = 0; j < core::Uncompressed3BPPSize; j++) {
sheet[j] = rom_data_[j + offset];
}
convert = true;
bpp3 = true;
} else if (i == 113 || i == 114 || i >= 218) {
convert = false;
bpp3 = false;
} else {
auto offset = GetGraphicsAddress(rom_data_.data(), i);
ASSIGN_OR_RETURN(sheet, Decompress(offset))
convert = true;
bpp3 = true;
}
if (convert) {
auto converted_sheet = SNES3bppTo8bppSheet(sheet);
if (bpp3) {
auto converted_sheet = SnesTo8bppSheet(sheet, 3);
graphics_bin_[i] =
gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight,
core::kTilesheetDepth, converted_sheet.data(), 0x1000);
@@ -618,7 +627,7 @@ absl::Status ROM::LoadAllGraphicsData() {
graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j));
}
} else {
for (int j = 0; j < 0x1000; ++j) {
for (int j = 0; j < graphics_bin_.at(0).GetSize(); ++j) {
graphics_buffer_.push_back(0xFF);
}
}
@@ -687,7 +696,7 @@ void ROM::RenderBitmap(gfx::Bitmap* bitmap) const {
}
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;
new_color.red = (color & 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);
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;
new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8;
@@ -783,31 +792,6 @@ void ROM::LoadAllPalettes() {
palette_groups_["ow_mini_map"].AddPalette(
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

View File

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

View File

@@ -9,33 +9,88 @@
#include "absl/status/status.h"
#include "app/core/constants.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/pseudo_vram.h"
#include "app/gfx/snes_tile.h"
#include "app/rom.h"
#include "app/zelda3/overworld_map.h"
#include "app/zelda3/sprite.h"
namespace yaze {
namespace app {
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 {
public:
absl::Status Load(ROM &rom);
auto GetTiles16() const { return tiles16; }
auto GetOverworldMap(uint index) { return overworld_maps_[index]; }
auto GetOverworldMaps() const { return overworld_maps_; }
auto GetCurrentBlockset() const {
return overworld_maps_[current_map_].GetCurrentBlockset();
auto Sprites() const { return all_sprites_[game_state_]; }
auto AreaGraphics() const {
return overworld_maps_[current_map_].AreaGraphics();
}
auto GetCurrentGraphics() const {
return overworld_maps_[current_map_].GetCurrentGraphics();
auto Entrances() const { return all_entrances_; }
auto AreaPalette() const {
return overworld_maps_[current_map_].AreaPalette();
}
auto GetCurrentBitmapData() const {
return overworld_maps_[current_map_].GetBitmapData();
}
auto GetCurrentPalette() const {
return overworld_maps_[current_map_].GetCurrentPalette();
auto BitmapData() const { return overworld_maps_[current_map_].BitmapData(); }
auto Tile16Blockset() const {
return overworld_maps_[current_map_].Tile16Blockset();
}
auto GameState() const { return game_state_; }
auto isLoaded() const { return is_loaded_; }
void SetCurrentMap(int i) { current_map_ = i; }
@@ -58,9 +113,12 @@ class Overworld {
int &ttpos);
absl::Status DecompressAllMapTiles();
void FetchLargeMaps();
void LoadEntrances();
void LoadSprites();
void LoadOverworldMap();
int game_state_ = 1;
int game_state_ = 0;
int current_map_ = 0;
uchar map_parent_[160];
bool is_loaded_ = false;
@@ -71,6 +129,9 @@ class Overworld {
std::vector<gfx::Tile16> tiles16;
std::vector<gfx::Tile32> tiles32;
std::vector<OverworldMap> overworld_maps_;
std::vector<OverworldEntrance> all_entrances_;
std::vector<OverworldEntrance> all_holes_;
std::vector<std::vector<Sprite>> all_sprites_;
};
} // namespace zelda3

View File

@@ -46,7 +46,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current,
int k = 0;
for (int y = 2; y < 7; y++) {
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;
for (int y = 2; y < 5; y++) {
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;
for (int y = 5; y < 8; y++) {
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;
for (int y = 8; y < 9; y++) {
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;
for (int y = 8; y < 9; y++) {
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;
for (int y = 9; y < 13; y++) {
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;
for (int y = 13; y < 14; y++) {
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;
for (int y = 14; y < 15; y++) {
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;
for (int y = 15; y < 16; y++) {
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);
// ColorPalette pal = GFX.editort16Bitmap.Palette;
// for (int i = 0; i < 256; i++) {
// pal.Entries[i] = new_palette[i];
// pal.Entries[(i / 16) * 16] = Color.Transparent;
// }
// GFX.mapgfx16Bitmap.Palette = pal;
// GFX.mapblockset16Bitmap.Palette = pal;
// gfxBitmap.Palette = pal;
for (int i = 0; i < 256; i++) {
current[(i / 16) * 16].setTransparent(true);
}
}
} // namespace
@@ -156,6 +158,7 @@ OverworldMap::OverworldMap(int index, ROM& rom,
absl::Status OverworldMap::BuildMap(int count, int game_state, int world,
uchar* map_parent,
OWBlockset& world_blockset) {
game_state_ = game_state;
world_ = world;
if (large_map_) {
parent_ = map_parent[index_];
@@ -176,16 +179,7 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world,
}
}
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;
}
LoadAreaGraphics(game_state, world_index);
LoadAreaGraphics();
RETURN_IF_ERROR(BuildTileset())
RETURN_IF_ERROR(BuildTiles16Gfx(count))
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
static_graphics_[8] = 0x73 + 0x00;
static_graphics_[9] = 0x73 + 0x01;
@@ -281,7 +284,7 @@ void OverworldMap::LoadAreaGraphics(int game_state, int world_index) {
static_graphics_[11] = 0x73 + 0x07;
for (int i = 0; i < 4; i++) {
static_graphics_[12 + i] = (rom_[core::kSpriteBlocksetPointer +
(sprite_graphics_[game_state] * 4) + i] +
(sprite_graphics_[game_state_] * 4) + i] +
0x73);
}
@@ -333,8 +336,7 @@ void OverworldMap::LoadPalette() {
uchar pal0 = 0;
uchar pal1 =
rom_[core::overworldMapPaletteGroup + (area_palette_ * 4)]; // aux1
uchar pal1 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4)];
uchar pal2 =
rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + 1]; // aux2
uchar pal3 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) +
@@ -387,7 +389,7 @@ void OverworldMap::LoadPalette() {
if (parent_ < 0x40) {
// Default LW Palette
pal0 = 0;
bgr = rom_.GetPaletteGroup("grass")[0].GetColor(0);
if (parent_ == 0x03 || parent_ == 0x05 || parent_ == 0x07) {
pal0 = 2;
}
@@ -457,8 +459,16 @@ absl::Status OverworldMap::BuildTileset() {
for (int i = 0; i < 0x10; i++) {
for (int j = 0; j < 0x1000; j++) {
current_gfx_[(i * 0x1000) + j] =
all_gfx_[j + (static_graphics_[i] * 0x1000)];
auto byte = 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();
@@ -496,7 +506,7 @@ absl::Status OverworldMap::BuildTiles16Gfx(int count) {
auto destination = xx + yy + offset + (mx + (my * 0x80));
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,
OWBlockset& world_blockset);
auto GetCurrentBlockset() const { return current_blockset_; }
auto GetCurrentGraphics() const { return current_gfx_; }
auto GetCurrentPalette() const { return current_palette_; }
auto GetBitmapData() const { return bitmap_data_; }
auto Tile16Blockset() const { return current_blockset_; }
auto AreaGraphics() const { return current_gfx_; }
auto AreaPalette() const { return current_palette_; }
auto BitmapData() const { return bitmap_data_; }
auto SetLargeMap(bool is_set) { large_map_ = is_set; }
auto IsLargeMap() const { return large_map_; }
auto IsInitialized() const { return initialized_; }
auto IsBuilt() const { return built_; }
private:
void LoadAreaInfo();
void LoadAreaGraphics(int game_state, int world_index);
void LoadAreaGraphics();
void LoadPalette();
absl::Status BuildTileset();
@@ -52,8 +51,6 @@ class OverworldMap {
int message_id_ = 0;
int area_graphics_ = 0;
int area_palette_ = 0;
// TODO SET ME
int game_state_ = 0;
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>
@@ -11,7 +11,7 @@ namespace yaze {
namespace app {
namespace zelda3 {
void Screen::Create() {
void TitleScreen::Create() {
tiles8Bitmap.Create(128, 512, 8, 0x20000);
tilesBG1Bitmap.Create(256, 256, 8, 0x80000);
tilesBG2Bitmap.Create(256, 256, 8, 0x80000);
@@ -20,12 +20,9 @@ void Screen::Create() {
BuildTileset();
LoadTitleScreen();
LoadOverworldMap();
LoadDungeonMaps();
LoadAllMapIcons();
}
void Screen::BuildTileset() {
void TitleScreen::BuildTileset() {
uchar staticgfx[16];
// Main Blocksets
@@ -66,7 +63,7 @@ void Screen::BuildTileset() {
}
}
void Screen::LoadTitleScreen() {
void TitleScreen::LoadTitleScreen() {
int pos =
(rom_[0x138C + 3] << 16) + (rom_[0x1383 + 3] << 8) + rom_[0x137A + 3];
@@ -127,14 +124,6 @@ void Screen::LoadTitleScreen() {
pal_selected_ = 2;
}
void Screen::LoadNamingScreen() {}
void Screen::LoadOverworldMap() {}
void Screen::LoadDungeonMaps() {}
void Screen::LoadAllMapIcons() {}
} // namespace zelda3
} // namespace app
} // namespace yaze

View File

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

View File

@@ -6,6 +6,7 @@
#include <string>
#include "app/gfx/bitmap.h"
#include "app/rom.h"
namespace yaze {
namespace gui {
@@ -39,8 +40,10 @@ void Canvas::DrawContextMenu() {
// Add first and second point
if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
ImVec2 draw_tile_outline_pos;
draw_tile_outline_pos.x = 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;
draw_tile_outline_pos.x =
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(
@@ -61,6 +64,11 @@ void Canvas::DrawContextMenu() {
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
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)) {
points_.clear();
}
@@ -68,12 +76,35 @@ void Canvas::DrawContextMenu() {
}
}
void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset) {
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::DrawTilesFromUser(app::ROM &rom, Bytes &tile,
app::gfx::SNESPalette &pal) {
ImVec2 draw_tile_outline_pos;
// Add rectangle
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) {
@@ -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) {
ImVec2 origin(x, y);
ImVec2 size(x + w, y + h);
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_->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) {
// Draw grid + all lines in the canvas
draw_list_->PushClipRect(canvas_p0_, canvas_p1_, true);

View File

@@ -7,6 +7,7 @@
#include <string>
#include "app/gfx/bitmap.h"
#include "app/rom.h"
namespace yaze {
namespace gui {
@@ -21,9 +22,14 @@ class Canvas {
void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0));
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 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 DrawOverlay(); // last
@@ -38,6 +44,7 @@ class Canvas {
bool enable_grid_ = true;
bool enable_context_menu_ = true;
bool custom_canvas_size_ = false;
bool is_hovered_ = false;
ImDrawList* draw_list_;
ImVector<ImVec2> points_;
@@ -45,6 +52,9 @@ class Canvas {
ImVec2 canvas_sz_;
ImVec2 canvas_p0_;
ImVec2 canvas_p1_;
ImVec2 mouse_pos_in_canvas_;
std::vector<app::gfx::Bitmap> changed_tiles_;
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 {
public:
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],
int routine_offset, int hook_offset));
};
@@ -40,15 +40,15 @@ TEST(ASMTest, ApplyMosaicChangePatchOk) {
MockScript script;
char mosaic_tiles[yaze::app::core::kNumOverworldMaps];
EXPECT_CALL(script, GenerateMosaicChangeAssembly(_, Eq(mosaic_tiles),
Eq(0x1301D0 + 0x138000), 0))
EXPECT_CALL(script, PatchOverworldMosaic(_, Eq(mosaic_tiles),
Eq(0x1301D0 + 0x138000), 0))
.WillOnce(Return(absl::OkStatus()));
EXPECT_CALL(script, ApplyPatchToROM(_)).WillOnce(Return(absl::OkStatus()));
EXPECT_THAT(script.GenerateMosaicChangeAssembly(rom, mosaic_tiles,
0x1301D0 + 0x138000, 0),
absl::OkStatus());
EXPECT_THAT(
script.PatchOverworldMosaic(rom, mosaic_tiles, 0x1301D0 + 0x138000, 0),
absl::OkStatus());
EXPECT_THAT(script.ApplyPatchToROM(rom), absl::OkStatus());
}