namespace housekeeping continued again
This commit is contained in:
1232
src/app/core/constants.h
Normal file
1232
src/app/core/constants.h
Normal file
File diff suppressed because it is too large
Load Diff
185
src/app/core/controller.cc
Normal file
185
src/app/core/controller.cc
Normal file
@@ -0,0 +1,185 @@
|
||||
#include "controller.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <imgui/backends/imgui_impl_sdl.h>
|
||||
#include <imgui/backends/imgui_impl_sdlrenderer.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "gui/editor/editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace core {
|
||||
|
||||
bool Controller::isActive() const { return active_; }
|
||||
|
||||
void Controller::onEntry() {
|
||||
CreateWindow();
|
||||
CreateRenderer();
|
||||
CreateGuiContext();
|
||||
editor_.SetupScreen(sdl_renderer_);
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
io.KeyMap[ImGuiKey_Backspace] = SDL_GetScancodeFromKey(SDLK_BACKSPACE);
|
||||
io.KeyMap[ImGuiKey_Enter] = SDL_GetScancodeFromKey(SDLK_RETURN);
|
||||
io.KeyMap[ImGuiKey_UpArrow] = SDL_GetScancodeFromKey(SDLK_UP);
|
||||
io.KeyMap[ImGuiKey_DownArrow] = SDL_GetScancodeFromKey(SDLK_DOWN);
|
||||
io.KeyMap[ImGuiKey_Tab] = SDL_GetScancodeFromKey(SDLK_TAB);
|
||||
io.KeyMap[ImGuiKey_LeftCtrl] = SDL_GetScancodeFromKey(SDLK_LCTRL);
|
||||
active_ = true;
|
||||
}
|
||||
|
||||
void Controller::onInput() {
|
||||
int wheel = 0;
|
||||
int mouseX;
|
||||
int mouseY;
|
||||
SDL_Event event;
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
const int buttons = SDL_GetMouseState(&mouseX, &mouseY);
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_UP:
|
||||
case SDLK_DOWN:
|
||||
case SDLK_RETURN:
|
||||
case SDLK_BACKSPACE:
|
||||
case SDLK_TAB:
|
||||
io.KeysDown[event.key.keysym.scancode] =
|
||||
(event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_KEYUP: {
|
||||
int key = event.key.keysym.scancode;
|
||||
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
|
||||
io.KeysDown[key] = (event.type == SDL_KEYDOWN);
|
||||
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
|
||||
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
|
||||
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
|
||||
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
|
||||
break;
|
||||
}
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (event.window.event) {
|
||||
case SDL_WINDOWEVENT_CLOSE:
|
||||
quit();
|
||||
break;
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
io.DisplaySize.x = static_cast<float>(event.window.data1);
|
||||
io.DisplaySize.y = static_cast<float>(event.window.data2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
io.AddInputCharactersUTF8(event.text.text);
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
wheel = event.wheel.y;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
io.DeltaTime = 1.0f / 60.0f;
|
||||
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
|
||||
io.MouseDown[0] = buttons & SDL_BUTTON(SDL_BUTTON_LEFT);
|
||||
io.MouseDown[1] = buttons & SDL_BUTTON(SDL_BUTTON_RIGHT);
|
||||
io.MouseWheel = static_cast<float>(wheel);
|
||||
}
|
||||
|
||||
void Controller::onLoad() { editor_.UpdateScreen(); }
|
||||
|
||||
void Controller::doRender() {
|
||||
SDL_RenderClear(sdl_renderer_.get());
|
||||
ImGui::Render();
|
||||
ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_RenderPresent(sdl_renderer_.get());
|
||||
}
|
||||
|
||||
void Controller::onExit() {
|
||||
ImGui_ImplSDLRenderer_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void Controller::CreateWindow() {
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING)) {
|
||||
SDL_Log("SDL_Init: %s\n", SDL_GetError());
|
||||
} else {
|
||||
sdl_window_ = std::unique_ptr<SDL_Window, sdl_deleter>(
|
||||
SDL_CreateWindow("Yet Another Zelda3 Editor", // window title
|
||||
SDL_WINDOWPOS_UNDEFINED, // initial x position
|
||||
SDL_WINDOWPOS_UNDEFINED, // initial y position
|
||||
1200, // width, in pixels
|
||||
800, // height, in pixels
|
||||
SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL),
|
||||
sdl_deleter());
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::CreateRenderer() {
|
||||
if (sdl_window_ == nullptr) {
|
||||
SDL_Log("SDL_CreateWindow: %s\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
} else {
|
||||
sdl_renderer_ = std::unique_ptr<SDL_Renderer, sdl_deleter>(
|
||||
SDL_CreateRenderer(
|
||||
sdl_window_.get(), -1,
|
||||
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
|
||||
sdl_deleter());
|
||||
if (sdl_renderer_ == nullptr) {
|
||||
SDL_Log("SDL_CreateRenderer: %s\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
} else {
|
||||
SDL_SetRenderDrawBlendMode(sdl_renderer_.get(), SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(sdl_renderer_.get(), 0x00, 0x00, 0x00, 0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::CreateGuiContext() {
|
||||
// Create the ImGui and ImPlot contexts
|
||||
ImGui::CreateContext();
|
||||
|
||||
// Initialize ImGui for SDL
|
||||
ImGui_ImplSDL2_InitForSDLRenderer(sdl_window_.get(), sdl_renderer_.get());
|
||||
ImGui_ImplSDLRenderer_Init(sdl_renderer_.get());
|
||||
|
||||
// Load available fonts
|
||||
const ImGuiIO &io = ImGui::GetIO();
|
||||
io.Fonts->AddFontFromFileTTF("assets/font/Karla-Regular.ttf", 14.0f);
|
||||
|
||||
// merge in icons from Google Material Design
|
||||
static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0};
|
||||
ImFontConfig icons_config;
|
||||
icons_config.MergeMode = true;
|
||||
icons_config.GlyphOffset.y = 5.0f;
|
||||
icons_config.GlyphMinAdvanceX = 13.0f;
|
||||
icons_config.PixelSnapH = true;
|
||||
io.Fonts->AddFontFromFileTTF(FONT_ICON_FILE_NAME_MD, 18.0f, &icons_config,
|
||||
icons_ranges);
|
||||
io.Fonts->AddFontFromFileTTF("assets/font/Roboto-Medium.ttf", 14.0f);
|
||||
io.Fonts->AddFontFromFileTTF("assets/font/Cousine-Regular.ttf", 14.0f);
|
||||
io.Fonts->AddFontFromFileTTF("assets/font/DroidSans.ttf", 16.0f);
|
||||
|
||||
// Set the default style
|
||||
gui::ColorsYaze();
|
||||
|
||||
// Build a new ImGui frame
|
||||
ImGui_ImplSDLRenderer_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(sdl_window_.get());
|
||||
}
|
||||
|
||||
} // namespace core
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
55
src/app/core/controller.h
Normal file
55
src/app/core/controller.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef YAZE_APP_CORE_CONTROLLER_H
|
||||
#define YAZE_APP_CORE_CONTROLLER_H
|
||||
#define SDL_MAIN_HANDLED
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <imgui/backends/imgui_impl_sdl.h>
|
||||
#include <imgui/backends/imgui_impl_sdlrenderer.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include "gui/editor/editor.h"
|
||||
#include "gui/icons.h"
|
||||
#include "gui/style.h"
|
||||
|
||||
int main(int argc, char **argv);
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace core {
|
||||
|
||||
class Controller {
|
||||
public:
|
||||
Controller() = default;
|
||||
|
||||
bool isActive() const;
|
||||
void onEntry();
|
||||
void onInput();
|
||||
void onLoad();
|
||||
void doRender();
|
||||
void onExit();
|
||||
|
||||
private:
|
||||
void CreateWindow();
|
||||
void CreateRenderer();
|
||||
void CreateGuiContext();
|
||||
inline void quit() { active_ = false; }
|
||||
friend int ::main(int argc, char **argv);
|
||||
|
||||
struct sdl_deleter {
|
||||
void operator()(SDL_Window *p) const { SDL_DestroyWindow(p); }
|
||||
void operator()(SDL_Renderer *p) const { SDL_DestroyRenderer(p); }
|
||||
void operator()(SDL_Texture *p) const { SDL_DestroyTexture(p); }
|
||||
};
|
||||
|
||||
bool active_;
|
||||
Editor::Editor editor_;
|
||||
std::shared_ptr<SDL_Window> sdl_window_;
|
||||
std::shared_ptr<SDL_Renderer> sdl_renderer_;
|
||||
};
|
||||
|
||||
} // namespace core
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_CORE_CONTROLLER_H
|
||||
18
src/app/core/entry_point.h
Normal file
18
src/app/core/entry_point.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef YAZE_APP_CONTROLLER_ENTRYPOINT_H
|
||||
#define YAZE_APP_CONTROLLER_ENTRYPOINT_H
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
yaze::app::core::Controller controller;
|
||||
controller.onEntry();
|
||||
while (controller.isActive()) {
|
||||
controller.onInput();
|
||||
controller.onLoad();
|
||||
controller.doRender();
|
||||
}
|
||||
controller.onExit();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // YAZE_APP_CONTROLLER_ENTRYPOINT_H
|
||||
178
src/app/gfx/bitmap.cc
Normal file
178
src/app/gfx/bitmap.cc
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "bitmap.h"
|
||||
|
||||
#include <rommapping.h>
|
||||
|
||||
#include "rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gfx {
|
||||
|
||||
int GetPCGfxAddress(char *romData, char id) {
|
||||
char **info1 = new char *[255];
|
||||
int gfxPointer1 =
|
||||
lorom_snes_to_pc((romData[core::Constants::gfx_1_pointer + 1] << 8) +
|
||||
(romData[core::Constants::gfx_1_pointer]),
|
||||
info1);
|
||||
int gfxPointer2 =
|
||||
lorom_snes_to_pc((romData[core::Constants::gfx_2_pointer + 1] << 8) +
|
||||
(romData[core::Constants::gfx_2_pointer]),
|
||||
info1);
|
||||
int gfxPointer3 =
|
||||
lorom_snes_to_pc((romData[core::Constants::gfx_3_pointer + 1] << 8) +
|
||||
(romData[core::Constants::gfx_3_pointer]),
|
||||
info1);
|
||||
|
||||
char gfxGamePointer1 = romData[gfxPointer1 + id];
|
||||
char gfxGamePointer2 = romData[gfxPointer2 + id];
|
||||
char gfxGamePointer3 = romData[gfxPointer3 + id];
|
||||
|
||||
return lorom_snes_to_pc(
|
||||
Data::AddressFromBytes(gfxGamePointer1, gfxGamePointer2, gfxGamePointer3),
|
||||
info1);
|
||||
}
|
||||
|
||||
char *CreateAllGfxDataRaw(char *romData) {
|
||||
// 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
|
||||
// 127-217 -> compressed 3bpp sprites -> (decompressed each) 0x600 chars
|
||||
// 218-222 -> compressed 2bpp -> (decompressed each) 0x800 chars
|
||||
|
||||
char *buffer = new char[346624];
|
||||
int bufferPos = 0;
|
||||
char *data = new char[2048];
|
||||
unsigned int uncompressedSize = 0;
|
||||
unsigned int compressedSize = 0;
|
||||
|
||||
for (int i = 0; i < core::Constants::NumberOfSheets; i++) {
|
||||
isbpp3[i] = ((i >= 0 && i <= 112) || // Compressed 3bpp bg
|
||||
(i >= 115 && i <= 126) || // Uncompressed 3bpp sprites
|
||||
(i >= 127 && i <= 217) // Compressed 3bpp sprites
|
||||
);
|
||||
|
||||
// uncompressed sheets
|
||||
if (i >= 115 && i <= 126) {
|
||||
data = new char[core::Constants::Uncompressed3BPPSize];
|
||||
int startAddress = GetPCGfxAddress(romData, (char)i);
|
||||
for (int j = 0; j < core::Constants::Uncompressed3BPPSize; j++) {
|
||||
data[j] = romData[j + startAddress];
|
||||
}
|
||||
} else {
|
||||
data = alttp_decompress_gfx((char *)romData,
|
||||
GetPCGfxAddress(romData, (char)i),
|
||||
core::Constants::UncompressedSheetSize,
|
||||
&uncompressedSize, &compressedSize);
|
||||
}
|
||||
|
||||
for (int j = 0; j < sizeof(data); j++) {
|
||||
buffer[j + bufferPos] = data[j];
|
||||
}
|
||||
|
||||
bufferPos += sizeof(data);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void CreateAllGfxData(char *romData, char *allgfx16Ptr) {
|
||||
char *data = CreateAllGfxDataRaw(romData);
|
||||
char *newData = new char[0x6F800];
|
||||
uchar *mask = new uchar[]{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||
int sheetPosition = 0;
|
||||
|
||||
// 8x8 tile
|
||||
for (int s = 0; s < core::Constants::NumberOfSheets; s++) // Per Sheet
|
||||
{
|
||||
for (int j = 0; j < 4; j++) // Per Tile Line Y
|
||||
{
|
||||
for (int i = 0; i < 16; i++) // Per Tile Line X
|
||||
{
|
||||
for (int y = 0; y < 8; y++) // Per Pixel Line
|
||||
{
|
||||
if (isbpp3[s]) {
|
||||
char lineBits0 =
|
||||
data[(y * 2) + (i * 24) + (j * 384) + sheetPosition];
|
||||
char lineBits1 =
|
||||
data[(y * 2) + (i * 24) + (j * 384) + 1 + sheetPosition];
|
||||
char lineBits2 =
|
||||
data[(y) + (i * 24) + (j * 384) + 16 + sheetPosition];
|
||||
|
||||
for (int x = 0; x < 4; x++) // Per Pixel X
|
||||
{
|
||||
char pixdata = 0;
|
||||
char pixdata2 = 0;
|
||||
|
||||
if ((lineBits0 & mask[(x * 2)]) == mask[(x * 2)]) {
|
||||
pixdata += 1;
|
||||
}
|
||||
if ((lineBits1 & mask[(x * 2)]) == mask[(x * 2)]) {
|
||||
pixdata += 2;
|
||||
}
|
||||
if ((lineBits2 & mask[(x * 2)]) == mask[(x * 2)]) {
|
||||
pixdata += 4;
|
||||
}
|
||||
|
||||
if ((lineBits0 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) {
|
||||
pixdata2 += 1;
|
||||
}
|
||||
if ((lineBits1 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) {
|
||||
pixdata2 += 2;
|
||||
}
|
||||
if ((lineBits2 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) {
|
||||
pixdata2 += 4;
|
||||
}
|
||||
|
||||
newData[(y * 64) + (x) + (i * 4) + (j * 512) + (s * 2048)] =
|
||||
(char)((pixdata << 4) | pixdata2);
|
||||
}
|
||||
} else {
|
||||
char lineBits0 =
|
||||
data[(y * 2) + (i * 16) + (j * 256) + sheetPosition];
|
||||
char lineBits1 =
|
||||
data[(y * 2) + (i * 16) + (j * 256) + 1 + sheetPosition];
|
||||
|
||||
for (int x = 0; x < 4; x++) // Per Pixel X
|
||||
{
|
||||
char pixdata = 0;
|
||||
char pixdata2 = 0;
|
||||
|
||||
if ((lineBits0 & mask[(x * 2)]) == mask[(x * 2)]) {
|
||||
pixdata += 1;
|
||||
}
|
||||
if ((lineBits1 & mask[(x * 2)]) == mask[(x * 2)]) {
|
||||
pixdata += 2;
|
||||
}
|
||||
|
||||
if ((lineBits0 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) {
|
||||
pixdata2 += 1;
|
||||
}
|
||||
if ((lineBits1 & mask[(x * 2) + 1]) == mask[(x * 2) + 1]) {
|
||||
pixdata2 += 2;
|
||||
}
|
||||
|
||||
newData[(y * 64) + (x) + (i * 4) + (j * 512) + (s * 2048)] =
|
||||
(char)((pixdata << 4) | pixdata2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isbpp3[s]) {
|
||||
sheetPosition += core::Constants::Uncompressed3BPPSize;
|
||||
} else {
|
||||
sheetPosition += core::Constants::UncompressedSheetSize;
|
||||
}
|
||||
}
|
||||
|
||||
char *allgfx16Data = (char *)allgfx16Ptr;
|
||||
|
||||
for (int i = 0; i < 0x6F800; i++) {
|
||||
allgfx16Data[i] = newData[i];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
37
src/app/gfx/bitmap.h
Normal file
37
src/app/gfx/bitmap.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef YAZE_APP_UTILS_BITMAP_H
|
||||
#define YAZE_APP_UTILS_BITMAP_H
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "Core/constants.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gfx {
|
||||
|
||||
class Bitmap {
|
||||
public:
|
||||
Bitmap() = default;
|
||||
Bitmap(int width, int height, char *data)
|
||||
: width_(width), height_(height), pixel_data_(data) {}
|
||||
|
||||
int GetWidth() const { return width_; }
|
||||
int GetHeight() const { return height_; }
|
||||
|
||||
private:
|
||||
int width_;
|
||||
int height_;
|
||||
char *pixel_data_;
|
||||
};
|
||||
|
||||
static bool isbpp3[core::Constants::NumberOfSheets];
|
||||
|
||||
int GetPCGfxAddress(char *romData, char id);
|
||||
char *CreateAllGfxDataRaw(char *romData);
|
||||
void CreateAllGfxData(char *romData, char *allgfx16Ptr);
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
113
src/app/gfx/palette.cc
Normal file
113
src/app/gfx/palette.cc
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "palette.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gfx {
|
||||
|
||||
SNESColor::SNESColor() : rgb(ImVec4(0.f, 0.f, 0.f, 0.f)) {}
|
||||
|
||||
SNESColor::SNESColor(ImVec4 val) : rgb(val) {
|
||||
m_color col;
|
||||
col.red = (uchar)val.x;
|
||||
col.blue = (uchar)val.y;
|
||||
col.green = (uchar)val.z;
|
||||
snes = convertcolor_rgb_to_snes(col);
|
||||
}
|
||||
|
||||
void SNESColor::setRgb(ImVec4 val) {
|
||||
rgb = val;
|
||||
m_color col;
|
||||
col.red = val.x;
|
||||
col.blue = val.y;
|
||||
col.green = val.z;
|
||||
snes = convertcolor_rgb_to_snes(col);
|
||||
}
|
||||
|
||||
void SNESColor::setSNES(uint16_t val) {
|
||||
snes = val;
|
||||
m_color col = convertcolor_snes_to_rgb(val);
|
||||
rgb = ImVec4(col.red, col.green, col.blue, 1.f);
|
||||
}
|
||||
|
||||
SNESPalette::SNESPalette(uint8_t mSize) : size_(mSize) {
|
||||
for (unsigned int i = 0; i < mSize; i++) {
|
||||
SNESColor col;
|
||||
colors.push_back(col);
|
||||
}
|
||||
}
|
||||
|
||||
SNESPalette::SNESPalette(char* data) {
|
||||
assert((sizeof(data) % 4 == 0) && (sizeof(data) <= 32));
|
||||
size_ = sizeof(data) / 2;
|
||||
for (unsigned i = 0; i < sizeof(data); i += 2) {
|
||||
SNESColor col;
|
||||
col.snes = static_cast<uchar>(data[i + 1]) << 8;
|
||||
col.snes = col.snes | static_cast<uchar>(data[i]);
|
||||
m_color mColor = convertcolor_snes_to_rgb(col.snes);
|
||||
col.rgb = ImVec4(mColor.red, mColor.green, mColor.blue, 1.f);
|
||||
colors.push_back(col);
|
||||
}
|
||||
}
|
||||
|
||||
SNESPalette::SNESPalette(const unsigned char* snes_pal) {
|
||||
assert((sizeof(snes_pal) % 4 == 0) && (sizeof(snes_pal) <= 32));
|
||||
size_ = sizeof(snes_pal) / 2;
|
||||
for (unsigned i = 0; i < sizeof(snes_pal); i += 2) {
|
||||
SNESColor col;
|
||||
col.snes = snes_pal[i + 1] << (uint16_t) 8;
|
||||
col.snes = col.snes | snes_pal[i];
|
||||
m_color mColor = convertcolor_snes_to_rgb(col.snes);
|
||||
col.rgb = ImVec4(mColor.red, mColor.green, mColor.blue, 1.f);
|
||||
colors.push_back(col);
|
||||
}
|
||||
}
|
||||
|
||||
SNESPalette::SNESPalette(std::vector<ImVec4> cols) {
|
||||
for (const auto& each : cols) {
|
||||
SNESColor scol;
|
||||
scol.setRgb(each);
|
||||
colors.push_back(scol);
|
||||
}
|
||||
size_ = cols.size();
|
||||
}
|
||||
|
||||
char* SNESPalette::encode() {
|
||||
// char* data(size * 2, 0);
|
||||
char* data = new char[size_ * 2];
|
||||
for (unsigned int i = 0; i < size_; i++) {
|
||||
// std::cout << QString::number(colors[i].snes, 16);
|
||||
data[i * 2] = (char)(colors[i].snes & 0xFF);
|
||||
data[i * 2 + 1] = (char)(colors[i].snes >> 8);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
SDL_Palette* SNESPalette::GetSDL_Palette() {
|
||||
std::cout << "Converting SNESPalette to SDL_Palette" << std::endl;
|
||||
auto sdl_palette = std::make_shared<SDL_Palette>();
|
||||
sdl_palette->ncolors = size_;
|
||||
|
||||
auto* sdl_colors = new SDL_Color[size_];
|
||||
for (int i = 0; i < size_; i++) {
|
||||
sdl_colors[i].r = (uint8_t)colors[i].rgb.x * 100;
|
||||
sdl_colors[i].g = (uint8_t)colors[i].rgb.y * 100;
|
||||
sdl_colors[i].b = (uint8_t)colors[i].rgb.z * 100;
|
||||
std::cout << "Color " << i << " added (R:" << sdl_colors[i].r
|
||||
<< " G:" << sdl_colors[i].g << " B:" << sdl_colors[i].b << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
sdl_palette->colors = sdl_colors;
|
||||
|
||||
// store the pointers to free them later
|
||||
sdl_palettes_.push_back(sdl_palette);
|
||||
colors_arrays_.push_back(sdl_colors);
|
||||
|
||||
return sdl_palette.get();
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
50
src/app/gfx/palette.h
Normal file
50
src/app/gfx/palette.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef YAZE_APP_gfx_PALETTE_H
|
||||
#define YAZE_APP_gfx_PALETTE_H
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <palette.h>
|
||||
#include <tile.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gfx {
|
||||
|
||||
struct SNESColor {
|
||||
SNESColor();
|
||||
explicit SNESColor(ImVec4);
|
||||
uint16_t snes = 0;
|
||||
ImVec4 rgb;
|
||||
void setRgb(ImVec4);
|
||||
void setSNES(uint16_t);
|
||||
uint8_t approxSNES();
|
||||
ImVec4 approxRGB();
|
||||
};
|
||||
|
||||
class SNESPalette {
|
||||
public:
|
||||
SNESPalette() = default;
|
||||
explicit SNESPalette(uint8_t mSize);
|
||||
explicit SNESPalette(char* snesPal);
|
||||
explicit SNESPalette(const unsigned char* snes_pal);
|
||||
explicit SNESPalette(std::vector<ImVec4>);
|
||||
|
||||
char* encode();
|
||||
SDL_Palette* GetSDL_Palette();
|
||||
|
||||
int size_ = 0;
|
||||
std::vector<SNESColor> colors;
|
||||
std::vector<std::shared_ptr<SDL_Palette>> sdl_palettes_;
|
||||
std::vector<SDL_Color*> colors_arrays_;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_gfx_PALETTE_H
|
||||
113
src/app/gfx/tile.cc
Normal file
113
src/app/gfx/tile.cc
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "tile.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gfx {
|
||||
|
||||
TilesPattern::TilesPattern() {
|
||||
tiles_per_row_ = 16;
|
||||
number_of_tiles_ = 16;
|
||||
// transform_vector_.push_back(std::vector<int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
// 8,
|
||||
// 9, 10, 11, 12, 13, 14, 15});
|
||||
// transform_vector_.push_back(std::vector<int>{});
|
||||
// transform_vector_.push_back(std::vector<int>{});
|
||||
// transform_vector_.push_back(std::vector<int>{});
|
||||
|
||||
transform_vector_.push_back(std::vector<int>{0, 1, 2, 3});
|
||||
transform_vector_.push_back(std::vector<int>{4, 5, 6, 7});
|
||||
transform_vector_.push_back(std::vector<int>{8, 9, 10, 11});
|
||||
transform_vector_.push_back(std::vector<int>{12, 13, 14, 15});
|
||||
}
|
||||
|
||||
std::vector<std::vector<tile8> > TilesPattern::transform(
|
||||
const std::vector<tile8> &tiles) const {
|
||||
uint repeatOffsetY = 0;
|
||||
uint repeatOffsetX = 0;
|
||||
uint tVectHeight = transform_vector_.size();
|
||||
uint tVectWidth = transform_vector_[0].size();
|
||||
uint repeat = 0;
|
||||
std::vector<std::vector<tile8> > toret;
|
||||
uint transPerRow = tiles_per_row_ / tVectWidth;
|
||||
uint nbTransform = tiles.size() / number_of_tiles_;
|
||||
printf("Tiles size : %d\nnbtransform : %d\npattern number of tiles : %d\n",
|
||||
tiles.size(), nbTransform, number_of_tiles_);
|
||||
|
||||
if (transPerRow > nbTransform)
|
||||
toret.resize(tVectHeight);
|
||||
else
|
||||
toret.resize(((uint)(((double)nbTransform / (double)transPerRow) + 0.5)) *
|
||||
tVectHeight);
|
||||
|
||||
for (auto &each : toret) {
|
||||
each.resize(tiles_per_row_);
|
||||
}
|
||||
|
||||
std::cout << toret[0].size() << " x " << toret.size();
|
||||
while (repeat != nbTransform) {
|
||||
std::cout << "repeat" << repeat;
|
||||
for (uint j = 0; j < tVectHeight; j++) {
|
||||
for (uint i = 0; i < tVectWidth; i++) {
|
||||
uint posTile = transform_vector_[j][i] + number_of_tiles_ * repeat;
|
||||
uint posX = i + repeatOffsetX;
|
||||
uint posY = j + repeatOffsetY;
|
||||
printf("X: %d - Y: %d - posTile : %d \n", posX, posY, posTile);
|
||||
toret.at(posY).at(posX) = tiles[posTile];
|
||||
}
|
||||
}
|
||||
if (repeatOffsetX + tVectWidth == tiles_per_row_) {
|
||||
repeatOffsetX = 0;
|
||||
repeatOffsetY += tVectHeight;
|
||||
} else
|
||||
repeatOffsetX += tVectWidth;
|
||||
repeat++;
|
||||
}
|
||||
std::cout << "End of transform" << std::endl;
|
||||
return toret;
|
||||
}
|
||||
|
||||
std::vector<tile8> TilesPattern::reverse(
|
||||
const std::vector<tile8> &tiles) const {
|
||||
uint repeatOffsetY = 0;
|
||||
uint repeatOffsetX = 0;
|
||||
uint tVectHeight = transform_vector_.size();
|
||||
uint tVectWidth = transform_vector_[0].size();
|
||||
uint repeat = 0;
|
||||
uint nbTransPerRow = tiles_per_row_ / tVectWidth;
|
||||
uint nbTiles = tiles.size();
|
||||
std::vector<tile8> toretVec(tiles.size());
|
||||
|
||||
for (uint i = 0; i < nbTiles; i++) {
|
||||
uint lineNb = i / tiles_per_row_;
|
||||
uint lineInTab = lineNb % tVectHeight;
|
||||
uint colInTab = i % tVectWidth;
|
||||
uint tileNb = transform_vector_[lineInTab][colInTab];
|
||||
|
||||
uint lineBlock = i / (nbTransPerRow * number_of_tiles_);
|
||||
uint blockNB =
|
||||
(i % (nbTransPerRow * number_of_tiles_) % tiles_per_row_) / tVectWidth;
|
||||
|
||||
std::cout << colInTab << lineInTab << " = " << tileNb;
|
||||
uint pos = tileNb + (lineBlock + blockNB) * number_of_tiles_;
|
||||
std::cout << i << "Goes to : " << pos;
|
||||
toretVec[pos] = tiles[i];
|
||||
}
|
||||
return toretVec;
|
||||
}
|
||||
|
||||
std::vector<std::vector<tile8> > TilesPattern::transform(
|
||||
const TilesPattern &pattern, const std::vector<tile8> &tiles) {
|
||||
return pattern.transform(tiles);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
103
src/app/gfx/tile.h
Normal file
103
src/app/gfx/tile.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef YAZE_APP_DATA_TILE_H
|
||||
#define YAZE_APP_DATA_TILE_H
|
||||
|
||||
#include <tile.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Core/constants.h"
|
||||
#include "gfx/palette.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gfx {
|
||||
|
||||
// vhopppcc cccccccc
|
||||
// [0, 1]
|
||||
// [2, 3]
|
||||
class TileInfo {
|
||||
public:
|
||||
ushort id_;
|
||||
ushort over_;
|
||||
ushort vertical_mirror_;
|
||||
ushort horizontal_mirror_;
|
||||
uchar palette_;
|
||||
TileInfo() = default;
|
||||
TileInfo(ushort id, uchar palette, ushort v, ushort h, ushort o)
|
||||
: id_(id),
|
||||
over_(o),
|
||||
vertical_mirror_(v),
|
||||
horizontal_mirror_(h),
|
||||
palette_(palette) {}
|
||||
};
|
||||
|
||||
class Tile32 {
|
||||
public:
|
||||
ushort tile0_;
|
||||
ushort tile1_;
|
||||
ushort tile2_;
|
||||
ushort tile3_;
|
||||
|
||||
Tile32(ushort t0, ushort t1, ushort t2, ushort t3)
|
||||
: tile0_(t0), tile1_(t1), tile2_(t2), tile3_(t3) {}
|
||||
};
|
||||
|
||||
class Tile16 {
|
||||
public:
|
||||
TileInfo tile0_;
|
||||
TileInfo tile1_;
|
||||
TileInfo tile2_;
|
||||
TileInfo tile3_;
|
||||
std::vector<TileInfo> tiles_info;
|
||||
|
||||
Tile16(TileInfo t0, TileInfo t1, TileInfo t2, TileInfo t3)
|
||||
: tile0_(t0), tile1_(t1), tile2_(t2), tile3_(t3) {
|
||||
tiles_info.push_back(tile0_);
|
||||
tiles_info.push_back(tile1_);
|
||||
tiles_info.push_back(tile2_);
|
||||
tiles_info.push_back(tile3_);
|
||||
}
|
||||
};
|
||||
|
||||
class TilesPattern {
|
||||
public:
|
||||
TilesPattern();
|
||||
std::string name;
|
||||
std::string description;
|
||||
unsigned int tiles_per_row_;
|
||||
unsigned int number_of_tiles_;
|
||||
|
||||
static TilesPattern pattern(std::string name);
|
||||
static std::vector<std::vector<tile8>> transform(
|
||||
const TilesPattern& pattern, const std::vector<tile8>& tiles);
|
||||
|
||||
protected:
|
||||
std::vector<std::vector<tile8>> transform(
|
||||
const std::vector<tile8>& tiles) const;
|
||||
std::vector<tile8> reverse(const std::vector<tile8>& tiles) const;
|
||||
|
||||
private:
|
||||
std::vector<std::vector<int>> transform_vector_;
|
||||
};
|
||||
|
||||
class TilePreset {
|
||||
public:
|
||||
TilePreset() = default;
|
||||
TilesPattern tilesPattern;
|
||||
bool no_zero_color_ = false;
|
||||
int pc_tiles_location_ = 0;
|
||||
int pc_palette_location_ = 0;
|
||||
int bits_per_pixel_ = 0;
|
||||
int length_ = 0;
|
||||
int SNESTilesLocation = 0;
|
||||
int SNESPaletteLocation = 0;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
296
src/app/rom.cc
Normal file
296
src/app/rom.cc
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "rom.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "Core/constants.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace Data {
|
||||
|
||||
ROM::~ROM() {
|
||||
if (loaded) {
|
||||
delete[] current_rom_;
|
||||
for (auto &each : decompressed_graphic_sheets_) {
|
||||
free(each);
|
||||
}
|
||||
for (auto &each : converted_graphic_sheets_) {
|
||||
free(each);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ROM::SetupRenderer(std::shared_ptr<SDL_Renderer> renderer) {
|
||||
sdl_renderer_ = renderer;
|
||||
}
|
||||
|
||||
// TODO: check if the rom has a header on load
|
||||
void ROM::LoadFromFile(const std::string &path) {
|
||||
size_ = std::filesystem::file_size(path.c_str());
|
||||
std::ifstream file(path.c_str(), std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
std::cout << "Error: Could not open ROM file " << path << std::endl;
|
||||
return;
|
||||
}
|
||||
current_rom_ = new unsigned char[size_];
|
||||
for (unsigned int i = 0; i < size_; i++) {
|
||||
char byte_read_ = ' ';
|
||||
file.read(&byte_read_, sizeof(char));
|
||||
current_rom_[i] = byte_read_;
|
||||
}
|
||||
file.close();
|
||||
memcpy(title, current_rom_ + 32704, 21);
|
||||
version_ = current_rom_[27];
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
std::vector<tile8> ROM::ExtractTiles(gfx::TilePreset &preset) {
|
||||
std::cout << "Extracting tiles..." << std::endl;
|
||||
uint filePos = 0;
|
||||
uint size_out = 0;
|
||||
uint size = preset.length_;
|
||||
int tilePos = preset.pc_tiles_location_;
|
||||
std::vector<tile8> rawTiles;
|
||||
filePos = GetRomPosition(tilePos, preset.SNESTilesLocation);
|
||||
std::cout << "ROM Position: " << filePos << " from "
|
||||
<< preset.SNESTilesLocation << std::endl;
|
||||
|
||||
// decompress the gfx
|
||||
auto data = (char *)malloc(sizeof(char) * size);
|
||||
memcpy(data, (current_rom_ + filePos), size);
|
||||
data = alttp_decompress_gfx(data, 0, size, &size_out, &compressed_size_);
|
||||
std::cout << "size: " << size << std::endl;
|
||||
std::cout << "lastCompressedSize: " << compressed_size_ << std::endl;
|
||||
if (data == nullptr) {
|
||||
std::cout << alttp_decompression_error << std::endl;
|
||||
return rawTiles;
|
||||
}
|
||||
|
||||
// unpack the tiles based on their depth
|
||||
unsigned tileCpt = 0;
|
||||
std::cout << "Unpacking tiles..." << std::endl;
|
||||
for (unsigned int tilePos = 0; tilePos < size;
|
||||
tilePos += preset.bits_per_pixel_ * 8) {
|
||||
tile8 newTile = unpack_bpp_tile(data, tilePos, preset.bits_per_pixel_);
|
||||
newTile.id = tileCpt;
|
||||
rawTiles.push_back(newTile);
|
||||
tileCpt++;
|
||||
}
|
||||
std::cout << "Done unpacking tiles" << std::endl;
|
||||
free(data);
|
||||
std::cout << "Done extracting tiles." << std::endl;
|
||||
return rawTiles;
|
||||
}
|
||||
|
||||
gfx::SNESPalette ROM::ExtractPalette(gfx::TilePreset &preset) {
|
||||
uint filePos =
|
||||
GetRomPosition(preset.pc_palette_location_, preset.SNESPaletteLocation);
|
||||
std::cout << "Palette pos : " << filePos << std::endl; // TODO: make this hex
|
||||
uint palette_size = pow(2, preset.bits_per_pixel_); // - 1;
|
||||
|
||||
auto palette_data = std::make_unique<unsigned char[]>(palette_size * 2);
|
||||
memcpy(palette_data.get(), current_rom_ + filePos, palette_size * 2);
|
||||
|
||||
// char *ab = (char *)malloc(sizeof(char) * (palette_size * 2));
|
||||
// memcpy(ab, current_rom_ + filePos, palette_size * 2);
|
||||
|
||||
for (int i = 0; i < palette_size; i++) {
|
||||
std::cout << palette_data[i];
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
const unsigned char *data = palette_data.get();
|
||||
gfx::SNESPalette pal(data);
|
||||
if (preset.no_zero_color_) {
|
||||
gfx::SNESColor col;
|
||||
|
||||
col.setRgb(ImVec4(153, 153, 153, 255));
|
||||
pal.colors.push_back(col);
|
||||
pal.colors.erase(pal.colors.begin(),
|
||||
pal.colors.begin() + pal.colors.size() - 1);
|
||||
}
|
||||
return pal;
|
||||
}
|
||||
|
||||
uint32_t ROM::GetRomPosition(int direct_addr, uint snes_addr) const {
|
||||
unsigned int filePos = -1;
|
||||
std::cout << "directAddr:" << direct_addr << std::endl;
|
||||
if (direct_addr == -1) {
|
||||
filePos = rommapping_snes_to_pc(snes_addr, type_, has_header_);
|
||||
} else {
|
||||
filePos = direct_addr;
|
||||
if (has_header_) filePos += 0x200;
|
||||
}
|
||||
std::cout << "filePos:" << filePos << std::endl;
|
||||
return filePos;
|
||||
}
|
||||
|
||||
char *ROM::Decompress(int pos, int size, bool reversed) {
|
||||
char *buffer = new char[size];
|
||||
decompressed_graphic_sheets_.push_back(buffer);
|
||||
for (int i = 0; i < size; i++) {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
unsigned int bufferPos = 0;
|
||||
unsigned char cmd = 0;
|
||||
unsigned int length = 0;
|
||||
|
||||
uchar databyte = current_rom_[pos];
|
||||
while (true) {
|
||||
databyte = (unsigned char)current_rom_[pos];
|
||||
if (databyte == 0xFF) // End of decompression
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((databyte & 0xE0) == 0xE0) // Expanded Command
|
||||
{
|
||||
cmd = (unsigned char)((databyte >> 2) & 0x07);
|
||||
length =
|
||||
(unsigned short)(((current_rom_[pos] << 8) | current_rom_[pos + 1]) &
|
||||
0x3FF);
|
||||
pos += 2; // Advance 2 bytes in ROM
|
||||
} else // Normal Command
|
||||
{
|
||||
cmd = (unsigned char)((databyte >> 5) & 0x07);
|
||||
length = (unsigned char)(databyte & 0x1F);
|
||||
pos += 1; // Advance 1 byte in ROM
|
||||
}
|
||||
length += 1; // Every commands are at least 1 size even if 00
|
||||
switch (cmd) {
|
||||
case 00: // Direct Copy (Could be replaced with a MEMCPY)
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos++];
|
||||
}
|
||||
// Do not advance in the ROM
|
||||
break;
|
||||
case 01: // Byte Fill
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos];
|
||||
}
|
||||
pos += 1; // Advance 1 byte in the ROM
|
||||
break;
|
||||
case 02: // Word Fill
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos];
|
||||
buffer[bufferPos++] = (unsigned char)current_rom_[pos + 1];
|
||||
}
|
||||
pos += 2; // Advance 2 byte in the ROM
|
||||
break;
|
||||
case 03: // Increasing Fill
|
||||
{
|
||||
unsigned char incByte = (unsigned char)current_rom_[pos];
|
||||
for (int i = 0; i < (unsigned int)length; i++) {
|
||||
buffer[bufferPos++] = (unsigned char)incByte++;
|
||||
}
|
||||
pos += 1; // Advance 1 byte in the ROM
|
||||
} break;
|
||||
case 04: // Repeat (Reversed byte order for maps)
|
||||
{
|
||||
unsigned short s1 = ((current_rom_[pos + 1] & 0xFF) << 8);
|
||||
unsigned short s2 = ((current_rom_[pos] & 0xFF));
|
||||
unsigned short Addr = (unsigned short)(s1 | s2);
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer[bufferPos] = (unsigned char)buffer[Addr + i];
|
||||
bufferPos++;
|
||||
}
|
||||
pos += 2; // Advance 2 bytes in the ROM
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uchar *ROM::SNES3bppTo8bppSheet(uchar *buffer_in,
|
||||
int sheet_id) // 128x32
|
||||
{
|
||||
// 8bpp sheet out
|
||||
const uchar bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||
uchar *sheet_buffer_out = (uchar *)malloc(0x1000);
|
||||
converted_graphic_sheets_.push_back(sheet_buffer_out);
|
||||
int xx = 0; // positions where we are at on the sheet
|
||||
int yy = 0;
|
||||
int pos = 0;
|
||||
int ypos = 0;
|
||||
|
||||
if (sheet_id != 0) {
|
||||
yy = sheet_id;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++) // for each tiles //16 per lines
|
||||
{
|
||||
for (int y = 0; y < 8; y++) // for each lines
|
||||
{
|
||||
//[0] + [1] + [16]
|
||||
for (int x = 0; x < 8; x++) {
|
||||
unsigned char b1 =
|
||||
(unsigned char)((buffer_in[(y * 2) + (24 * pos)] & (bitmask[x])));
|
||||
unsigned char b2 =
|
||||
(unsigned char)(buffer_in[((y * 2) + (24 * pos)) + 1] &
|
||||
(bitmask[x]));
|
||||
unsigned char b3 =
|
||||
(unsigned char)(buffer_in[(16 + y) + (24 * pos)] & (bitmask[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;
|
||||
}
|
||||
|
||||
SDL_Texture *ROM::DrawgfxSheet(int offset) {
|
||||
SDL_Surface *surface =
|
||||
SDL_CreateRGBSurfaceWithFormat(0, 128, 32, 8, SDL_PIXELFORMAT_INDEX8);
|
||||
std::cout << "Drawing surface #" << offset << std::endl;
|
||||
uchar *sheet_buffer = nullptr;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
surface->format->palette->colors[i].r = i * 31;
|
||||
surface->format->palette->colors[i].g = i * 31;
|
||||
surface->format->palette->colors[i].b = i * 31;
|
||||
}
|
||||
|
||||
unsigned int snesAddr = 0;
|
||||
unsigned int pcAddr = 0;
|
||||
snesAddr = (unsigned int)((((uchar)(current_rom_[0x4F80 + offset]) << 16) |
|
||||
((uchar)(current_rom_[0x505F + offset]) << 8) |
|
||||
((uchar)(current_rom_[0x513E + offset]))));
|
||||
pcAddr = SnesToPc(snesAddr);
|
||||
std::cout << "Decompressing..." << std::endl;
|
||||
char *decomp = Decompress(pcAddr);
|
||||
std::cout << "Converting to 8bpp sheet..." << std::endl;
|
||||
sheet_buffer = SNES3bppTo8bppSheet((uchar *)decomp);
|
||||
std::cout << "Assigning pixel data..." << std::endl;
|
||||
surface->pixels = sheet_buffer;
|
||||
std::cout << "Creating texture from surface..." << std::endl;
|
||||
SDL_Texture *sheet_texture = nullptr;
|
||||
sheet_texture = SDL_CreateTextureFromSurface(sdl_renderer_.get(), surface);
|
||||
if (sheet_texture == nullptr) {
|
||||
std::cout << "Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
return sheet_texture;
|
||||
}
|
||||
|
||||
int AddressFromBytes(uchar addr1, uchar addr2, uchar addr3) {
|
||||
return (addr1 << 16) | (addr2 << 8) | addr3;
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
75
src/app/rom.h
Normal file
75
src/app/rom.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef YAZE_APP_UTILS_ROM_H
|
||||
#define YAZE_APP_UTILS_ROM_H
|
||||
|
||||
#include <compressions/alttpcompression.h>
|
||||
#include <rommapping.h>
|
||||
#include <tile.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Core/constants.h"
|
||||
#include "gfx/tile.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace Data {
|
||||
|
||||
int AddressFromBytes(uchar addr1, uchar addr2, uchar addr3);
|
||||
|
||||
class ROM {
|
||||
public:
|
||||
~ROM();
|
||||
|
||||
void SetupRenderer(std::shared_ptr<SDL_Renderer> renderer);
|
||||
void LoadFromFile(const std::string& path);
|
||||
std::vector<tile8> ExtractTiles(gfx::TilePreset& preset);
|
||||
gfx::SNESPalette ExtractPalette(gfx::TilePreset& preset);
|
||||
uint32_t GetRomPosition(int direct_addr, uint snes_addr) const;
|
||||
char* Decompress(int pos, int size = 0x800, bool reversed = false);
|
||||
uchar* SNES3bppTo8bppSheet(uchar* buffer_in, int sheet_id = 0);
|
||||
SDL_Texture* DrawgfxSheet(int offset);
|
||||
|
||||
inline uchar* GetRawData() { return current_rom_; }
|
||||
const uchar* getTitle() const { return title; }
|
||||
long int getSize() const { return size_; }
|
||||
char getVersion() const { return version_; }
|
||||
bool isLoaded() const { return loaded; }
|
||||
|
||||
unsigned int SnesToPc(unsigned int addr) {
|
||||
if (addr >= 0x808000) {
|
||||
addr -= 0x808000;
|
||||
}
|
||||
unsigned int temp = (addr & 0x7FFF) + ((addr / 2) & 0xFF8000);
|
||||
return (temp + 0x0);
|
||||
}
|
||||
|
||||
private:
|
||||
bool loaded = false;
|
||||
bool has_header_ = false;
|
||||
uchar* current_rom_;
|
||||
uchar version_;
|
||||
uchar title[21] = "ROM Not Loaded";
|
||||
uint uncompressed_size_;
|
||||
uint compressed_size_;
|
||||
uint compress_size_;
|
||||
long int size_;
|
||||
enum rom_type type_ = LoROM;
|
||||
|
||||
std::shared_ptr<uchar> rom_ptr_;
|
||||
std::vector<char*> decompressed_graphic_sheets_;
|
||||
std::vector<uchar*> converted_graphic_sheets_;
|
||||
std::vector<SDL_Surface> surfaces_;
|
||||
std::shared_ptr<SDL_Renderer> sdl_renderer_;
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
348
src/app/zelda3/overworld.cc
Normal file
348
src/app/zelda3/overworld.cc
Normal file
@@ -0,0 +1,348 @@
|
||||
#include "overworld.h"
|
||||
|
||||
#include "gfx/tile.h"
|
||||
#include "rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace Data {
|
||||
|
||||
using namespace core;
|
||||
using namespace gfx;
|
||||
|
||||
Overworld::~Overworld() {
|
||||
if (isLoaded) {
|
||||
for (int i = 0; i < (int)tiles32.size(); i++) {
|
||||
free(allmapsTilesLW[i]);
|
||||
free(allmapsTilesDW[i]);
|
||||
free(allmapsTilesSP[i]);
|
||||
}
|
||||
free(allmapsTilesLW);
|
||||
free(allmapsTilesDW);
|
||||
free(allmapsTilesSP);
|
||||
|
||||
delete[] overworldMapPointer;
|
||||
delete[] owactualMapPointer;
|
||||
}
|
||||
}
|
||||
|
||||
static TileInfo GetTilesInfo(ushort tile) {
|
||||
// vhopppcc cccccccc
|
||||
ushort o = 0;
|
||||
ushort v = 0;
|
||||
ushort h = 0;
|
||||
ushort tid = (ushort)(tile & 0x3FF);
|
||||
uchar p = (uchar)((tile >> 10) & 0x07);
|
||||
|
||||
o = (ushort)((tile & 0x2000) >> 13);
|
||||
h = (ushort)((tile & 0x4000) >> 14);
|
||||
v = (ushort)((tile & 0x8000) >> 15);
|
||||
|
||||
return TileInfo(tid, p, v, h, o);
|
||||
}
|
||||
|
||||
void Overworld::Load(Data::ROM& rom) {
|
||||
rom_ = rom;
|
||||
for (int i = 0; i < 0x2B; i++) {
|
||||
tileLeftEntrance.push_back(Constants::overworldEntranceAllowedTilesLeft +
|
||||
(i * 2));
|
||||
tileRightEntrance.push_back(Constants::overworldEntranceAllowedTilesRight +
|
||||
(i * 2));
|
||||
}
|
||||
|
||||
AssembleMap32Tiles();
|
||||
AssembleMap16Tiles();
|
||||
DecompressAllMapTiles();
|
||||
|
||||
// Map Initialization :
|
||||
for (int i = 0; i < 160; i++) {
|
||||
allmaps.push_back(OverworldMap(rom_, tiles16, (uchar)i));
|
||||
}
|
||||
FetchLargeMaps();
|
||||
LoadOverworldMap();
|
||||
|
||||
auto size = tiles16.size();
|
||||
for (int i = 0; i < 160; i++) {
|
||||
allmaps[i].BuildMap(mapParent, size, gameState, allmapsTilesLW,
|
||||
allmapsTilesDW, allmapsTilesSP);
|
||||
}
|
||||
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
ushort Overworld::GenerateTile32(int i, int k, int dimension) {
|
||||
return (ushort)(rom_.GetRawData()[map32address[dimension] + k + (i)] +
|
||||
(((rom_.GetRawData()[map32address[dimension] + (i) +
|
||||
(k <= 1 ? 4 : 5)] >>
|
||||
(k % 2 == 0 ? 4 : 0)) &
|
||||
0x0F) *
|
||||
256));
|
||||
}
|
||||
|
||||
void Overworld::AssembleMap32Tiles() {
|
||||
for (int i = 0; i < 0x33F0; i += 6) {
|
||||
ushort tl, tr, bl, br;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
tl = GenerateTile32(i, k, (int)Dimension::map32TilesTL);
|
||||
tr = GenerateTile32(i, k, (int)Dimension::map32TilesTR);
|
||||
bl = GenerateTile32(i, k, (int)Dimension::map32TilesBL);
|
||||
br = GenerateTile32(i, k, (int)Dimension::map32TilesBR);
|
||||
tiles32.push_back(Tile32(tl, tr, bl, br));
|
||||
}
|
||||
}
|
||||
|
||||
allmapsTilesLW = (ushort**)malloc(tiles32.size() * sizeof(ushort*));
|
||||
for (int i = 0; i < tiles32.size(); i++)
|
||||
allmapsTilesLW[i] = (ushort*)malloc(tiles32.size() * sizeof(ushort));
|
||||
|
||||
allmapsTilesDW = (ushort**)malloc(tiles32.size() * sizeof(ushort*));
|
||||
for (int i = 0; i < tiles32.size(); i++)
|
||||
allmapsTilesDW[i] = (ushort*)malloc(tiles32.size() * sizeof(ushort));
|
||||
|
||||
allmapsTilesSP = (ushort**)malloc(tiles32.size() * sizeof(ushort*));
|
||||
for (int i = 0; i < tiles32.size(); i++)
|
||||
allmapsTilesSP[i] = (ushort*)malloc(tiles32.size() * sizeof(ushort));
|
||||
}
|
||||
|
||||
void Overworld::AssembleMap16Tiles() {
|
||||
int tpos = core::Constants::map16Tiles;
|
||||
for (int i = 0; i < 4096; i += 1) // 3760
|
||||
{
|
||||
TileInfo t0 = GetTilesInfo((uintptr_t)rom_.GetRawData() + tpos);
|
||||
tpos += 2;
|
||||
TileInfo t1 = GetTilesInfo((uintptr_t)rom_.GetRawData() + tpos);
|
||||
tpos += 2;
|
||||
TileInfo t2 = GetTilesInfo((uintptr_t)rom_.GetRawData() + tpos);
|
||||
tpos += 2;
|
||||
TileInfo t3 = GetTilesInfo((uintptr_t)rom_.GetRawData() + tpos);
|
||||
tpos += 2;
|
||||
tiles16.push_back(Tile16(t0, t1, t2, t3));
|
||||
}
|
||||
}
|
||||
|
||||
void Overworld::DecompressAllMapTiles() {
|
||||
int lowest = 0x0FFFFF;
|
||||
int highest = 0x0F8000;
|
||||
int sx = 0;
|
||||
int sy = 0;
|
||||
int c = 0;
|
||||
for (int i = 0; i < 160; i++) {
|
||||
int p1 = (rom_.GetRawData()[(Constants::compressedAllMap32PointersHigh) +
|
||||
2 + (int)(3 * i)]
|
||||
<< 16) +
|
||||
(rom_.GetRawData()[(Constants::compressedAllMap32PointersHigh) +
|
||||
1 + (int)(3 * i)]
|
||||
<< 8) +
|
||||
(rom_.GetRawData()[(Constants::compressedAllMap32PointersHigh +
|
||||
(int)(3 * i))]);
|
||||
|
||||
char* tmp = new char[256];
|
||||
p1 = lorom_snes_to_pc(p1, &tmp);
|
||||
std::cout << tmp << std::endl;
|
||||
int p2 = (rom_.GetRawData()[(Constants::compressedAllMap32PointersLow) + 2 +
|
||||
(int)(3 * i)]
|
||||
<< 16) +
|
||||
(rom_.GetRawData()[(Constants::compressedAllMap32PointersLow) + 1 +
|
||||
(int)(3 * i)]
|
||||
<< 8) +
|
||||
(rom_.GetRawData()[(Constants::compressedAllMap32PointersLow +
|
||||
(int)(3 * i))]);
|
||||
p2 = lorom_snes_to_pc(p2, &tmp);
|
||||
std::cout << tmp << std::endl;
|
||||
delete[] tmp;
|
||||
|
||||
int ttpos = 0;
|
||||
unsigned int compressedSize1 = 0;
|
||||
unsigned int compressedSize2 = 0;
|
||||
unsigned int compressedLength1 = 0;
|
||||
unsigned int compressedLength2 = 0;
|
||||
|
||||
if (p1 >= highest) {
|
||||
highest = p1;
|
||||
}
|
||||
if (p2 >= highest) {
|
||||
highest = p2;
|
||||
}
|
||||
|
||||
if (p1 <= lowest) {
|
||||
if (p1 > 0x0F8000) {
|
||||
lowest = p1;
|
||||
}
|
||||
}
|
||||
if (p2 <= lowest) {
|
||||
if (p2 > 0x0F8000) {
|
||||
lowest = p2;
|
||||
}
|
||||
}
|
||||
|
||||
auto bytes =
|
||||
alttp_decompress_overworld((char*)rom_.GetRawData(), p2, 1000,
|
||||
&compressedSize1, &compressedLength1);
|
||||
auto bytes2 =
|
||||
alttp_decompress_overworld((char*)rom_.GetRawData(), p1, 1000,
|
||||
&compressedSize2, &compressedLength2);
|
||||
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
ushort tidD = (ushort)((bytes2[ttpos] << 8) + bytes[ttpos]);
|
||||
|
||||
int tpos = tidD;
|
||||
if (tpos < tiles32.size()) {
|
||||
if (i < 64) {
|
||||
allmapsTilesLW[(x * 2) + (sx * 32)][(y * 2) + (sy * 32)] =
|
||||
tiles32[tpos].tile0_;
|
||||
allmapsTilesLW[(x * 2) + 1 + (sx * 32)][(y * 2) + (sy * 32)] =
|
||||
tiles32[tpos].tile1_;
|
||||
allmapsTilesLW[(x * 2) + (sx * 32)][(y * 2) + 1 + (sy * 32)] =
|
||||
tiles32[tpos].tile2_;
|
||||
allmapsTilesLW[(x * 2) + 1 + (sx * 32)][(y * 2) + 1 + (sy * 32)] =
|
||||
tiles32[tpos].tile3_;
|
||||
} else if (i < 128 && i >= 64) {
|
||||
allmapsTilesDW[(x * 2) + (sx * 32)][(y * 2) + (sy * 32)] =
|
||||
tiles32[tpos].tile0_;
|
||||
allmapsTilesDW[(x * 2) + 1 + (sx * 32)][(y * 2) + (sy * 32)] =
|
||||
tiles32[tpos].tile1_;
|
||||
allmapsTilesDW[(x * 2) + (sx * 32)][(y * 2) + 1 + (sy * 32)] =
|
||||
tiles32[tpos].tile2_;
|
||||
allmapsTilesDW[(x * 2) + 1 + (sx * 32)][(y * 2) + 1 + (sy * 32)] =
|
||||
tiles32[tpos].tile3_;
|
||||
} else {
|
||||
allmapsTilesSP[(x * 2) + (sx * 32)][(y * 2) + (sy * 32)] =
|
||||
tiles32[tpos].tile0_;
|
||||
allmapsTilesSP[(x * 2) + 1 + (sx * 32)][(y * 2) + (sy * 32)] =
|
||||
tiles32[tpos].tile1_;
|
||||
allmapsTilesSP[(x * 2) + (sx * 32)][(y * 2) + 1 + (sy * 32)] =
|
||||
tiles32[tpos].tile2_;
|
||||
allmapsTilesSP[(x * 2) + 1 + (sx * 32)][(y * 2) + 1 + (sy * 32)] =
|
||||
tiles32[tpos].tile3_;
|
||||
}
|
||||
}
|
||||
|
||||
ttpos += 1;
|
||||
}
|
||||
}
|
||||
|
||||
sx++;
|
||||
if (sx >= 8) {
|
||||
sy++;
|
||||
sx = 0;
|
||||
}
|
||||
|
||||
c++;
|
||||
if (c >= 64) {
|
||||
sx = 0;
|
||||
sy = 0;
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "MapPointers(lowest) : " << lowest << std::endl;
|
||||
std::cout << "MapPointers(highest) : " << highest << std::endl;
|
||||
}
|
||||
|
||||
void Overworld::FetchLargeMaps() {
|
||||
for (int i = 128; i < 145; i++) {
|
||||
mapParent[i] = 0;
|
||||
}
|
||||
|
||||
mapParent[128] = 128;
|
||||
mapParent[129] = 129;
|
||||
mapParent[130] = 129;
|
||||
mapParent[137] = 129;
|
||||
mapParent[138] = 129;
|
||||
mapParent[136] = 136;
|
||||
allmaps[136].largeMap = false;
|
||||
|
||||
bool mapChecked[64];
|
||||
for (int i = 0; i < 64; i++) {
|
||||
mapChecked[i] = false;
|
||||
}
|
||||
int xx = 0;
|
||||
int yy = 0;
|
||||
while (true) {
|
||||
int i = xx + (yy * 8);
|
||||
if (mapChecked[i] == false) {
|
||||
if (allmaps[i].largeMap == true) {
|
||||
mapChecked[i] = true;
|
||||
mapParent[i] = (uchar)i;
|
||||
mapParent[i + 64] = (uchar)(i + 64);
|
||||
|
||||
mapChecked[i + 1] = true;
|
||||
mapParent[i + 1] = (uchar)i;
|
||||
mapParent[i + 65] = (uchar)(i + 64);
|
||||
|
||||
mapChecked[i + 8] = true;
|
||||
mapParent[i + 8] = (uchar)i;
|
||||
mapParent[i + 72] = (uchar)(i + 64);
|
||||
|
||||
mapChecked[i + 9] = true;
|
||||
mapParent[i + 9] = (uchar)i;
|
||||
mapParent[i + 73] = (uchar)(i + 64);
|
||||
xx++;
|
||||
} else {
|
||||
mapParent[i] = (uchar)i;
|
||||
mapParent[i + 64] = (uchar)(i + 64);
|
||||
mapChecked[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
xx++;
|
||||
if (xx >= 8) {
|
||||
xx = 0;
|
||||
yy += 1;
|
||||
if (yy >= 8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Overworld::LoadOverworldMap() {
|
||||
overworldMapBitmap = new Bitmap(128, 128, overworldMapPointer);
|
||||
owactualMapBitmap = new Bitmap(512, 512, owactualMapPointer);
|
||||
|
||||
// Mode 7
|
||||
char* ptr = overworldMapPointer;
|
||||
|
||||
int pos = 0;
|
||||
for (int sy = 0; sy < 16; sy++) {
|
||||
for (int sx = 0; sx < 16; sx++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
ptr[x + (sx * 8) + (y * 128) + (sy * 1024)] =
|
||||
rom_.GetRawData()[0x0C4000 + pos];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ColorPalette cp = overworldMapBitmap.Palette;
|
||||
// for (int i = 0; i < 256; i += 2)
|
||||
// {
|
||||
// //55B27 = US LW
|
||||
// //55C27 = US DW
|
||||
// cp.Entries[i / 2] = getColor((short)((ROM.DATA[0x55B27 + i + 1] << 8) +
|
||||
// ROM.DATA[0x55B27 + i]));
|
||||
|
||||
// int k = 0;
|
||||
// int j = 0;
|
||||
// for (int y = 10; y < 14; y++)
|
||||
// {
|
||||
// for (int x = 0; x < 15; x++)
|
||||
// {
|
||||
// cp.Entries[145 + k] = Palettes.globalSprite_Palettes[0][j];
|
||||
// k++;
|
||||
// j++;
|
||||
// }
|
||||
// k++;
|
||||
// }
|
||||
// }
|
||||
|
||||
// overworldMapBitmap.Palette = cp;
|
||||
// owactualMapBitmap.Palette = cp;
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
74
src/app/zelda3/overworld.h
Normal file
74
src/app/zelda3/overworld.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef YAZE_APP_DATA_OVERWORLD_H
|
||||
#define YAZE_APP_DATA_OVERWORLD_H
|
||||
|
||||
#include <rommapping.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Core/constants.h"
|
||||
#include "gfx/bitmap.h"
|
||||
#include "gfx/tile.h"
|
||||
#include "overworld_map.h"
|
||||
#include "rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace Data {
|
||||
|
||||
class Overworld {
|
||||
public:
|
||||
Overworld() = default;
|
||||
~Overworld();
|
||||
|
||||
void Load(Data::ROM& rom);
|
||||
|
||||
char* overworldMapPointer = new char[0x40000];
|
||||
gfx::Bitmap* overworldMapBitmap;
|
||||
|
||||
char* owactualMapPointer = new char[0x40000];
|
||||
gfx::Bitmap* owactualMapBitmap;
|
||||
|
||||
private:
|
||||
Data::ROM rom_;
|
||||
int gameState = 1;
|
||||
bool isLoaded = false;
|
||||
uchar mapParent[160];
|
||||
|
||||
ushort** allmapsTilesLW; // 64 maps * (32*32 tiles)
|
||||
ushort** allmapsTilesDW; // 64 maps * (32*32 tiles)
|
||||
ushort** allmapsTilesSP; // 32 maps * (32*32 tiles)
|
||||
|
||||
std::vector<gfx::Tile16> tiles16;
|
||||
std::vector<gfx::Tile32> tiles32;
|
||||
std::vector<gfx::Tile32> map16tiles;
|
||||
|
||||
std::vector<OverworldMap> allmaps;
|
||||
|
||||
std::vector<ushort> tileLeftEntrance;
|
||||
std::vector<ushort> tileRightEntrance;
|
||||
|
||||
int map32address[4] = {
|
||||
core::Constants::map32TilesTL, core::Constants::map32TilesTR,
|
||||
core::Constants::map32TilesBL, core::Constants::map32TilesBR};
|
||||
|
||||
enum Dimension {
|
||||
map32TilesTL = 0,
|
||||
map32TilesTR = 1,
|
||||
map32TilesBL = 2,
|
||||
map32TilesBR = 3
|
||||
};
|
||||
|
||||
ushort GenerateTile32(int i, int k, int dimension);
|
||||
void AssembleMap32Tiles();
|
||||
void AssembleMap16Tiles();
|
||||
void DecompressAllMapTiles();
|
||||
void FetchLargeMaps();
|
||||
void LoadOverworldMap();
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
359
src/app/zelda3/overworld_map.cc
Normal file
359
src/app/zelda3/overworld_map.cc
Normal file
@@ -0,0 +1,359 @@
|
||||
#include "overworld_map.h"
|
||||
|
||||
#include "rom.h"
|
||||
#include "gfx/tile.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace Data {
|
||||
|
||||
using namespace core;
|
||||
using namespace gfx;
|
||||
|
||||
OverworldMap::OverworldMap(Data::ROM & rom,
|
||||
const std::vector<gfx::Tile16> tiles16,
|
||||
uchar index)
|
||||
: rom_(rom), index(index), tiles16_(tiles16), parent(index) {
|
||||
if (index != 0x80) {
|
||||
if (index <= 150) {
|
||||
if (rom_.GetRawData()[Constants::overworldMapSize + (index & 0x3F)] !=
|
||||
0) {
|
||||
largeMap = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 64) {
|
||||
sprgfx[0] = rom_.GetRawData()[Constants::overworldSpriteset + parent];
|
||||
sprgfx[1] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 64];
|
||||
sprgfx[2] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 128];
|
||||
gfx = rom_.GetRawData()[Constants::mapGfx + parent];
|
||||
palette = rom_.GetRawData()[Constants::overworldMapPalette + parent];
|
||||
sprpalette[0] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent];
|
||||
sprpalette[1] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 64];
|
||||
sprpalette[2] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 128];
|
||||
musics[0] = rom_.GetRawData()[Constants::overworldMusicBegining + parent];
|
||||
musics[1] = rom_.GetRawData()[Constants::overworldMusicZelda + parent];
|
||||
musics[2] =
|
||||
rom_.GetRawData()[Constants::overworldMusicMasterSword + parent];
|
||||
musics[3] = rom_.GetRawData()[Constants::overworldMusicAgahim + parent];
|
||||
} else if (index < 128) {
|
||||
sprgfx[0] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 128];
|
||||
sprgfx[1] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 128];
|
||||
sprgfx[2] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 128];
|
||||
gfx = rom_.GetRawData()[Constants::mapGfx + parent];
|
||||
palette = rom_.GetRawData()[Constants::overworldMapPalette + parent];
|
||||
sprpalette[0] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 128];
|
||||
sprpalette[1] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 128];
|
||||
sprpalette[2] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 128];
|
||||
|
||||
musics[0] = rom_.GetRawData()[Constants::overworldMusicDW + (parent - 64)];
|
||||
} else {
|
||||
if (index == 0x94) {
|
||||
parent = 128;
|
||||
} else if (index == 0x95) {
|
||||
parent = 03;
|
||||
} else if (index == 0x96) // pyramid bg use 0x5B map
|
||||
{
|
||||
parent = 0x5B;
|
||||
} else if (index == 0x97) // pyramid bg use 0x5B map
|
||||
{
|
||||
parent = 0x00;
|
||||
} else if (index == 156) {
|
||||
parent = 67;
|
||||
} else if (index == 157) {
|
||||
parent = 0;
|
||||
} else if (index == 158) {
|
||||
parent = 0;
|
||||
} else if (index == 159) {
|
||||
parent = 44;
|
||||
} else if (index == 136) {
|
||||
parent = 136;
|
||||
}
|
||||
|
||||
messageID = rom_.GetRawData()[Constants::overworldMessages + parent];
|
||||
|
||||
sprgfx[0] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 128];
|
||||
sprgfx[1] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 128];
|
||||
sprgfx[2] = rom_.GetRawData()[Constants::overworldSpriteset + parent + 128];
|
||||
sprpalette[0] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 128];
|
||||
sprpalette[1] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 128];
|
||||
sprpalette[2] =
|
||||
rom_.GetRawData()[Constants::overworldSpritePalette + parent + 128];
|
||||
|
||||
palette =
|
||||
rom_.GetRawData()[Constants::overworldSpecialPALGroup + parent - 128];
|
||||
if (index >= 0x80 && index <= 0x8A && index != 0x88) {
|
||||
gfx = rom_.GetRawData()[Constants::overworldSpecialGFXGroup +
|
||||
(parent - 128)];
|
||||
palette = rom_.GetRawData()[Constants::overworldSpecialPALGroup + 1];
|
||||
} else if (index == 0x88) {
|
||||
gfx = 81;
|
||||
palette = 0;
|
||||
} else // pyramid bg use 0x5B map
|
||||
{
|
||||
gfx = rom_.GetRawData()[Constants::mapGfx + parent];
|
||||
palette = rom_.GetRawData()[Constants::overworldMapPalette + parent];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::BuildMap(uchar* mapParent, int count, int gameState,
|
||||
ushort** allmapsTilesLW, ushort** allmapsTilesDW,
|
||||
ushort** allmapsTilesSP) {
|
||||
tilesUsed = new ushort*[32];
|
||||
for (int i = 0; i < 32; i++) tilesUsed[i] = new ushort;
|
||||
|
||||
if (largeMap) {
|
||||
this->parent = mapParent[index];
|
||||
|
||||
if (parent != index) {
|
||||
if (!firstLoad) {
|
||||
gfx = rom_.GetRawData()[Constants::mapGfx + parent];
|
||||
palette = rom_.GetRawData()[Constants::overworldMapPalette + parent];
|
||||
firstLoad = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BuildTileset(gameState);
|
||||
BuildTiles16Gfx(count); // build on GFX.mapgfx16Ptr
|
||||
|
||||
int world = 0;
|
||||
|
||||
if (index < 64) {
|
||||
tilesUsed = allmapsTilesLW;
|
||||
} else if (index < 128 && index >= 64) {
|
||||
tilesUsed = allmapsTilesDW;
|
||||
world = 1;
|
||||
} else {
|
||||
tilesUsed = allmapsTilesSP;
|
||||
world = 2;
|
||||
}
|
||||
|
||||
int superY = ((index - (world * 64)) / 8);
|
||||
int superX = index - (world * 64) - (superY * 8);
|
||||
|
||||
for (int y = 0; y < 32; y++) {
|
||||
for (int x = 0; x < 32; x++) {
|
||||
CopyTile8bpp16((x * 16), (y * 16),
|
||||
tilesUsed[x + (superX * 32)][y + (superY * 32)], gfxPtr,
|
||||
mapblockset16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::CopyTile8bpp16(int x, int y, int tile, int* destbmpPtr,
|
||||
int* sourcebmpPtr) {
|
||||
int sourceY = (tile / 8);
|
||||
int sourceX = (tile) - ((sourceY)*8);
|
||||
int sourcePtrPos = ((tile - ((tile / 8) * 8)) * 16) +
|
||||
((tile / 8) * 2048); //(sourceX * 16) + (sourceY * 128);
|
||||
uchar* sourcePtr = (uchar*)sourcebmpPtr;
|
||||
|
||||
int destPtrPos = (x + (y * 512));
|
||||
uchar* destPtr = (uchar*)destbmpPtr;
|
||||
|
||||
for (int ystrip = 0; ystrip < 16; ystrip++) {
|
||||
for (int xstrip = 0; xstrip < 16; xstrip++) {
|
||||
destPtr[destPtrPos + xstrip + (ystrip * 512)] =
|
||||
sourcePtr[sourcePtrPos + xstrip + (ystrip * 128)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::CopyTile8bpp16From8(int xP, int yP, int tileID,
|
||||
int* destbmpPtr, int* sourcebmpPtr) {
|
||||
auto gfx16Data = (uchar*)destbmpPtr;
|
||||
|
||||
auto gfx8Data = currentOWgfx16Ptr;
|
||||
|
||||
int offsets[] = {0, 8, 4096, 4104};
|
||||
|
||||
auto tiles = tiles16_[tileID];
|
||||
|
||||
for (auto tile = 0; tile < 4; tile++) {
|
||||
TileInfo info = tiles.tiles_info[tile];
|
||||
int offset = offsets[tile];
|
||||
|
||||
for (auto y = 0; y < 8; y++) {
|
||||
for (auto x = 0; x < 4; x++) {
|
||||
CopyTileToMap(x, y, xP, yP, offset, info, gfx16Data, gfx8Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::BuildTiles16Gfx(int count) {
|
||||
uchar* gfx16Data = (uchar*)mapblockset16;
|
||||
uchar* gfx8Data = currentOWgfx16Ptr;
|
||||
|
||||
int offsets[] = {0, 8, 1024, 1032};
|
||||
auto yy = 0;
|
||||
auto xx = 0;
|
||||
|
||||
for (auto i = 0; i < count; i++) // number of tiles16 3748?
|
||||
{
|
||||
// 8x8 tile draw
|
||||
// gfx8 = 4bpp so everyting is /2F
|
||||
auto tiles = tiles16_[i];
|
||||
|
||||
for (auto tile = 0; tile < 4; tile++) {
|
||||
TileInfo info = tiles16_[i].tiles_info[tile];
|
||||
int offset = offsets[tile];
|
||||
|
||||
for (auto y = 0; y < 8; y++) {
|
||||
for (auto x = 0; x < 4; x++) {
|
||||
CopyTile(x, y, xx, yy, offset, info, gfx16Data, gfx8Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xx += 16;
|
||||
if (xx >= 128) {
|
||||
yy += 2048;
|
||||
xx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::CopyTile(int x, int y, int xx, int yy, int offset,
|
||||
TileInfo tile, uchar* gfx16Pointer,
|
||||
uchar* gfx8Pointer) // map,current
|
||||
{
|
||||
int mx = x;
|
||||
int my = y;
|
||||
uchar r = 0;
|
||||
|
||||
if (tile.horizontal_mirror_ != 0) {
|
||||
mx = 3 - x;
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (tile.vertical_mirror_ != 0) {
|
||||
my = 7 - y;
|
||||
}
|
||||
|
||||
int tx = ((tile.id_ / 16) * 512) + ((tile.id_ - ((tile.id_ / 16) * 16)) * 4);
|
||||
auto index = xx + yy + offset + (mx * 2) + (my * 128);
|
||||
auto pixel = gfx8Pointer[tx + (y * 64) + x];
|
||||
|
||||
gfx16Pointer[index + r ^ 1] = (uchar)((pixel & 0x0F) + tile.palette_ * 16);
|
||||
gfx16Pointer[index + r] = (uchar)(((pixel >> 4) & 0x0F) + tile.palette_ * 16);
|
||||
}
|
||||
|
||||
void OverworldMap::CopyTileToMap(int x, int y, int xx, int yy, int offset,
|
||||
TileInfo tile, uchar* gfx16Pointer,
|
||||
uchar* gfx8Pointer) // map,current
|
||||
{
|
||||
int mx = x;
|
||||
int my = y;
|
||||
uchar r = 0;
|
||||
|
||||
if (tile.horizontal_mirror_ != 0) {
|
||||
mx = 3 - x;
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (tile.vertical_mirror_ != 0) {
|
||||
my = 7 - y;
|
||||
}
|
||||
|
||||
int tx = ((tile.id_ / 16) * 512) + ((tile.id_ - ((tile.id_ / 16) * 16)) * 4);
|
||||
auto index = xx + (yy * 512) + offset + (mx * 2) + (my * 512);
|
||||
auto pixel = gfx8Pointer[tx + (y * 64) + x];
|
||||
|
||||
gfx16Pointer[index + r ^ 1] = (uchar)((pixel & 0x0F) + tile.palette_ * 16);
|
||||
gfx16Pointer[index + r] = (uchar)(((pixel >> 4) & 0x0F) + tile.palette_ * 16);
|
||||
}
|
||||
|
||||
void OverworldMap::BuildTileset(int gameState) {
|
||||
int indexWorld = 0x20;
|
||||
if (parent < 0x40) {
|
||||
indexWorld = 0x20;
|
||||
} else if (parent >= 0x40 && parent < 0x80) {
|
||||
indexWorld = 0x21;
|
||||
} else if (parent == 0x88) {
|
||||
indexWorld = 36;
|
||||
}
|
||||
|
||||
// Sprites Blocksets
|
||||
staticgfx[8] = 115 + 0;
|
||||
staticgfx[9] = 115 + 1;
|
||||
staticgfx[10] = 115 + 6;
|
||||
staticgfx[11] = 115 + 7;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
staticgfx[12 + i] =
|
||||
(uchar)(rom_.GetRawData()[Constants::sprite_blockset_pointer +
|
||||
(sprgfx[gameState] * 4) + i] +
|
||||
115);
|
||||
}
|
||||
|
||||
// Main Blocksets
|
||||
for (int i = 0; i < 8; i++) {
|
||||
staticgfx[i] = rom_.GetRawData()[Constants::overworldgfxGroups2 +
|
||||
(indexWorld * 8) + i];
|
||||
}
|
||||
|
||||
if (rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4)] != 0) {
|
||||
staticgfx[3] = rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4)];
|
||||
}
|
||||
if (rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4) + 1] != 0) {
|
||||
staticgfx[4] =
|
||||
rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4) + 1];
|
||||
}
|
||||
if (rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4) + 2] != 0) {
|
||||
staticgfx[5] =
|
||||
rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4) + 2];
|
||||
}
|
||||
if (rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4) + 3] != 0) {
|
||||
staticgfx[6] =
|
||||
rom_.GetRawData()[Constants::overworldgfxGroups + (gfx * 4) + 3];
|
||||
}
|
||||
|
||||
// Hardcoded overworld GFX Values, for death mountain
|
||||
if ((parent >= 0x03 && parent <= 0x07) ||
|
||||
(parent >= 0x0B && parent <= 0x0E)) {
|
||||
staticgfx[7] = 89;
|
||||
} else if ((parent >= 0x43 && parent <= 0x47) ||
|
||||
(parent >= 0x4B && parent <= 0x4E)) {
|
||||
staticgfx[7] = 89;
|
||||
} else {
|
||||
staticgfx[7] = 91;
|
||||
}
|
||||
|
||||
uchar* currentmapgfx8Data = new uchar[(128 * 512) / 2];
|
||||
// (uchar*)GFX.currentOWgfx16Ptr.ToPointer(); // loaded gfx for the current
|
||||
// // map (empty at this point)
|
||||
uchar* allgfxData = new uchar[(128 * 7136) / 2];
|
||||
// (uchar*)GFX.allgfx16Ptr
|
||||
// .ToPointer(); // all gfx of the game pack of 2048 uchars (4bpp)
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 2048; j++) {
|
||||
uchar mapByte = allgfxData[j + (staticgfx[i] * 2048)];
|
||||
switch (i) {
|
||||
case 0:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
mapByte += 0x88;
|
||||
break;
|
||||
}
|
||||
|
||||
currentmapgfx8Data[(i * 2048) + j] = mapByte; // Upload used gfx data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
77
src/app/zelda3/overworld_map.h
Normal file
77
src/app/zelda3/overworld_map.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
#include "rom.h"
|
||||
#include "gfx/bitmap.h"
|
||||
#include "gfx/tile.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace Data {
|
||||
|
||||
using ushort = unsigned short;
|
||||
|
||||
class OverworldMap {
|
||||
public:
|
||||
uchar parent = 0;
|
||||
uchar index = 0;
|
||||
uchar gfx = 0;
|
||||
uchar palette = 0;
|
||||
bool firstLoad = false;
|
||||
short messageID = 0;
|
||||
bool largeMap = false;
|
||||
|
||||
uchar sprgfx[3];
|
||||
uchar sprpalette[3];
|
||||
uchar musics[4];
|
||||
|
||||
int* gfxPtr = new int[512 * 512];
|
||||
int* mapblockset16 = new int[1048576];
|
||||
gfx::Bitmap mapblockset16Bitmap;
|
||||
gfx::Bitmap gfxBitmap;
|
||||
|
||||
uchar* staticgfx =
|
||||
new uchar[16]; // Need to be used to display map and not pre render it!
|
||||
ushort** tilesUsed;
|
||||
|
||||
bool needRefresh = false;
|
||||
Data::ROM rom_;
|
||||
|
||||
uchar* currentOWgfx16Ptr = new uchar[(128 * 512) / 2];
|
||||
std::vector<gfx::Tile16> tiles16_;
|
||||
|
||||
OverworldMap(Data::ROM & rom, const std::vector<gfx::Tile16> tiles16,
|
||||
uchar index);
|
||||
void BuildMap(uchar* mapParent, int count, int gameState,
|
||||
ushort** allmapsTilesLW, ushort** allmapsTilesDW,
|
||||
ushort** allmapsTilesSP);
|
||||
void CopyTile8bpp16(int x, int y, int tile, int* destbmpPtr,
|
||||
int* sourcebmpPtr);
|
||||
void CopyTile8bpp16From8(int xP, int yP, int tileID, int* destbmpPtr,
|
||||
int* sourcebmpPtr);
|
||||
|
||||
private:
|
||||
void BuildTiles16Gfx(int count);
|
||||
// void ReloadPalettes() { LoadPalette(); }
|
||||
|
||||
void CopyTile(int x, int y, int xx, int yy, int offset,
|
||||
gfx::TileInfo tile, uchar* gfx16Pointer,
|
||||
uchar* gfx8Pointer);
|
||||
void CopyTileToMap(int x, int y, int xx, int yy, int offset,
|
||||
gfx::TileInfo tile, uchar* gfx16Pointer,
|
||||
uchar* gfx8Pointer);
|
||||
|
||||
void LoadPalette();
|
||||
|
||||
void SetColorsPalette(int index, ImVec4 main, ImVec4 animated, ImVec4 aux1,
|
||||
ImVec4 aux2, ImVec4 hud, ImVec4 bgrcolor, ImVec4 spr,
|
||||
ImVec4 spr2);
|
||||
|
||||
void BuildTileset(int gameState);
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
Reference in New Issue
Block a user