Merge branch 'master' of https://github.com/scawful/yaze
This commit is contained in:
@@ -171,8 +171,6 @@ bool StringReplace(std::string &str, const std::string &from,
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<ExperimentFlags::Flags> ExperimentFlags::flags_;
|
||||
|
||||
uint32_t Get24LocalFromPC(uint8_t *data, int addr, bool pc) {
|
||||
uint32_t ret =
|
||||
(PcToSnes(addr) & 0xFF0000) | (data[addr + 1] << 8) | data[addr];
|
||||
|
||||
@@ -96,57 +96,44 @@ class ExperimentFlags {
|
||||
} overworld;
|
||||
};
|
||||
|
||||
ExperimentFlags() = default;
|
||||
virtual ~ExperimentFlags() = default;
|
||||
auto flags() const {
|
||||
if (!flags_) {
|
||||
flags_ = std::make_shared<Flags>();
|
||||
}
|
||||
Flags *flags = flags_.get();
|
||||
return flags;
|
||||
}
|
||||
Flags *mutable_flags() {
|
||||
if (!flags_) {
|
||||
flags_ = std::make_shared<Flags>();
|
||||
}
|
||||
return flags_.get();
|
||||
static Flags &get() {
|
||||
static Flags instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::string Serialize() const {
|
||||
std::string result;
|
||||
result +=
|
||||
"kLogInstructions: " + std::to_string(flags_->kLogInstructions) + "\n";
|
||||
"kLogInstructions: " + std::to_string(get().kLogInstructions) + "\n";
|
||||
result +=
|
||||
"kSaveAllPalettes: " + std::to_string(flags_->kSaveAllPalettes) + "\n";
|
||||
"kSaveAllPalettes: " + std::to_string(get().kSaveAllPalettes) + "\n";
|
||||
result += "kSaveGfxGroups: " + std::to_string(get().kSaveGfxGroups) + "\n";
|
||||
result +=
|
||||
"kSaveGfxGroups: " + std::to_string(flags_->kSaveGfxGroups) + "\n";
|
||||
result += "kSaveWithChangeQueue: " +
|
||||
std::to_string(flags_->kSaveWithChangeQueue) + "\n";
|
||||
"kSaveWithChangeQueue: " + std::to_string(get().kSaveWithChangeQueue) +
|
||||
"\n";
|
||||
result += "kDrawDungeonRoomGraphics: " +
|
||||
std::to_string(flags_->kDrawDungeonRoomGraphics) + "\n";
|
||||
std::to_string(get().kDrawDungeonRoomGraphics) + "\n";
|
||||
result += "kNewFileDialogWrapper: " +
|
||||
std::to_string(flags_->kNewFileDialogWrapper) + "\n";
|
||||
std::to_string(get().kNewFileDialogWrapper) + "\n";
|
||||
result += "kLoadTexturesAsStreaming: " +
|
||||
std::to_string(flags_->kLoadTexturesAsStreaming) + "\n";
|
||||
std::to_string(get().kLoadTexturesAsStreaming) + "\n";
|
||||
result +=
|
||||
"kSaveDungeonMaps: " + std::to_string(flags_->kSaveDungeonMaps) + "\n";
|
||||
result += "kLogToConsole: " + std::to_string(flags_->kLogToConsole) + "\n";
|
||||
"kSaveDungeonMaps: " + std::to_string(get().kSaveDungeonMaps) + "\n";
|
||||
result += "kLogToConsole: " + std::to_string(get().kLogToConsole) + "\n";
|
||||
result += "kDrawOverworldSprites: " +
|
||||
std::to_string(flags_->overworld.kDrawOverworldSprites) + "\n";
|
||||
std::to_string(get().overworld.kDrawOverworldSprites) + "\n";
|
||||
result += "kSaveOverworldMaps: " +
|
||||
std::to_string(flags_->overworld.kSaveOverworldMaps) + "\n";
|
||||
std::to_string(get().overworld.kSaveOverworldMaps) + "\n";
|
||||
result += "kSaveOverworldEntrances: " +
|
||||
std::to_string(flags_->overworld.kSaveOverworldEntrances) + "\n";
|
||||
std::to_string(get().overworld.kSaveOverworldEntrances) + "\n";
|
||||
result += "kSaveOverworldExits: " +
|
||||
std::to_string(flags_->overworld.kSaveOverworldExits) + "\n";
|
||||
std::to_string(get().overworld.kSaveOverworldExits) + "\n";
|
||||
result += "kSaveOverworldItems: " +
|
||||
std::to_string(flags_->overworld.kSaveOverworldItems) + "\n";
|
||||
std::to_string(get().overworld.kSaveOverworldItems) + "\n";
|
||||
result += "kSaveOverworldProperties: " +
|
||||
std::to_string(flags_->overworld.kSaveOverworldProperties) + "\n";
|
||||
std::to_string(get().overworld.kSaveOverworldProperties) + "\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::shared_ptr<Flags> flags_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ constexpr char kEndOfProjectFile[] = "EndOfProjectFile";
|
||||
* user can have different rom file names for a single project and keep track of
|
||||
* backups.
|
||||
*/
|
||||
struct Project : public core::ExperimentFlags {
|
||||
struct Project {
|
||||
absl::Status Create(const std::string& project_name) {
|
||||
name = project_name;
|
||||
project_opened_ = true;
|
||||
|
||||
@@ -77,7 +77,7 @@ absl::Status DungeonEditor::Initialize() {
|
||||
rooms_.emplace_back(zelda3::Room(/*room_id=*/i));
|
||||
rooms_[i].LoadHeader();
|
||||
rooms_[i].LoadRoomFromROM();
|
||||
if (flags()->kDrawDungeonRoomGraphics) {
|
||||
if (core::ExperimentFlags::get().kDrawDungeonRoomGraphics) {
|
||||
rooms_[i].LoadRoomGraphics();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef YAZE_APP_EDITOR_DUNGEONEDITOR_H
|
||||
#define YAZE_APP_EDITOR_DUNGEONEDITOR_H
|
||||
|
||||
#include "app/core/common.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/editor/graphics/gfx_group_editor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/rom.h"
|
||||
#include "imgui/imgui.h"
|
||||
@@ -39,9 +39,7 @@ constexpr ImGuiTableFlags kDungeonTableFlags =
|
||||
* tile selector, and object renderer. Additionally, it handles loading room
|
||||
* entrances, calculating usage statistics, and rendering set usage.
|
||||
*/
|
||||
class DungeonEditor : public Editor,
|
||||
public SharedRom,
|
||||
public core::ExperimentFlags {
|
||||
class DungeonEditor : public Editor, public SharedRom {
|
||||
public:
|
||||
DungeonEditor() { type_ = EditorType::kDungeon; }
|
||||
|
||||
|
||||
@@ -683,7 +683,7 @@ void EditorManager::LoadRom() {
|
||||
}
|
||||
|
||||
void EditorManager::SaveRom() {
|
||||
if (flags()->kSaveDungeonMaps) {
|
||||
if (core::ExperimentFlags::get().kSaveDungeonMaps) {
|
||||
status_ = screen_editor_.SaveDungeonMaps();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace editor {
|
||||
* variable points to the currently active editor in the tab view.
|
||||
*
|
||||
*/
|
||||
class EditorManager : public SharedRom, public core::ExperimentFlags {
|
||||
class EditorManager : public SharedRom {
|
||||
public:
|
||||
EditorManager() {
|
||||
current_editor_ = &overworld_editor_;
|
||||
|
||||
@@ -621,7 +621,7 @@ void OverworldEditor::CheckForMousePan() {
|
||||
|
||||
void OverworldEditor::DrawOverworldCanvas() {
|
||||
if (all_gfx_loaded_) {
|
||||
if (flags()->overworld.kLoadCustomOverworld) {
|
||||
if (core::ExperimentFlags::get().overworld.kLoadCustomOverworld) {
|
||||
DrawCustomOverworldMapSettings();
|
||||
} else {
|
||||
DrawOverworldMapSettings();
|
||||
@@ -1009,22 +1009,22 @@ void OverworldEditor::DrawOverworldSprites() {
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::Save() {
|
||||
if (flags()->overworld.kSaveOverworldMaps) {
|
||||
if (core::ExperimentFlags::get().overworld.kSaveOverworldMaps) {
|
||||
RETURN_IF_ERROR(overworld_.CreateTile32Tilemap());
|
||||
RETURN_IF_ERROR(overworld_.SaveMap32Tiles());
|
||||
RETURN_IF_ERROR(overworld_.SaveMap16Tiles());
|
||||
RETURN_IF_ERROR(overworld_.SaveOverworldMaps());
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldEntrances) {
|
||||
if (core::ExperimentFlags::get().overworld.kSaveOverworldEntrances) {
|
||||
RETURN_IF_ERROR(overworld_.SaveEntrances());
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldExits) {
|
||||
if (core::ExperimentFlags::get().overworld.kSaveOverworldExits) {
|
||||
RETURN_IF_ERROR(overworld_.SaveExits());
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldItems) {
|
||||
if (core::ExperimentFlags::get().overworld.kSaveOverworldItems) {
|
||||
RETURN_IF_ERROR(overworld_.SaveItems());
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldProperties) {
|
||||
if (core::ExperimentFlags::get().overworld.kSaveOverworldProperties) {
|
||||
RETURN_IF_ERROR(overworld_.SaveMapProperties());
|
||||
}
|
||||
return absl::OkStatus();
|
||||
@@ -1082,7 +1082,7 @@ absl::Status OverworldEditor::LoadGraphics() {
|
||||
overworld_.current_map_bitmap_data(), maps_bmp_[i], palette));
|
||||
}
|
||||
|
||||
if (flags()->overworld.kDrawOverworldSprites) {
|
||||
if (core::ExperimentFlags::get().overworld.kDrawOverworldSprites) {
|
||||
RETURN_IF_ERROR(LoadSpriteGraphics());
|
||||
}
|
||||
|
||||
|
||||
@@ -72,9 +72,7 @@ constexpr absl::string_view kOWMapTable = "#MapSettingsTable";
|
||||
* Provides access to the GfxGroupEditor and Tile16Editor through popup windows.
|
||||
*
|
||||
*/
|
||||
class OverworldEditor : public Editor,
|
||||
public gfx::GfxContext,
|
||||
public core::ExperimentFlags {
|
||||
class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
public:
|
||||
OverworldEditor(Rom& rom) : rom_(rom) { type_ = EditorType::kOverworld; }
|
||||
|
||||
|
||||
@@ -7,51 +7,53 @@
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
using core::ExperimentFlags;
|
||||
using ImGui::BeginMenu;
|
||||
using ImGui::Checkbox;
|
||||
using ImGui::EndMenu;
|
||||
using ImGui::MenuItem;
|
||||
using ImGui::Separator;
|
||||
|
||||
struct FlagsMenu : public core::ExperimentFlags {
|
||||
struct FlagsMenu {
|
||||
void Draw() {
|
||||
if (BeginMenu("Overworld Flags")) {
|
||||
Checkbox("Enable Overworld Sprites",
|
||||
&mutable_flags()->overworld.kDrawOverworldSprites);
|
||||
&ExperimentFlags::get().overworld.kDrawOverworldSprites);
|
||||
Separator();
|
||||
Checkbox("Save Overworld Maps",
|
||||
&mutable_flags()->overworld.kSaveOverworldMaps);
|
||||
&ExperimentFlags::get().overworld.kSaveOverworldMaps);
|
||||
Checkbox("Save Overworld Entrances",
|
||||
&mutable_flags()->overworld.kSaveOverworldEntrances);
|
||||
&ExperimentFlags::get().overworld.kSaveOverworldEntrances);
|
||||
Checkbox("Save Overworld Exits",
|
||||
&mutable_flags()->overworld.kSaveOverworldExits);
|
||||
&ExperimentFlags::get().overworld.kSaveOverworldExits);
|
||||
Checkbox("Save Overworld Items",
|
||||
&mutable_flags()->overworld.kSaveOverworldItems);
|
||||
&ExperimentFlags::get().overworld.kSaveOverworldItems);
|
||||
Checkbox("Save Overworld Properties",
|
||||
&mutable_flags()->overworld.kSaveOverworldProperties);
|
||||
&ExperimentFlags::get().overworld.kSaveOverworldProperties);
|
||||
Checkbox("Load Custom Overworld",
|
||||
&mutable_flags()->overworld.kLoadCustomOverworld);
|
||||
&ExperimentFlags::get().overworld.kLoadCustomOverworld);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (BeginMenu("Dungeon Flags")) {
|
||||
Checkbox("Draw Dungeon Room Graphics",
|
||||
&mutable_flags()->kDrawDungeonRoomGraphics);
|
||||
&ExperimentFlags::get().kDrawDungeonRoomGraphics);
|
||||
Separator();
|
||||
Checkbox("Save Dungeon Maps", &mutable_flags()->kSaveDungeonMaps);
|
||||
Checkbox("Save Dungeon Maps", &ExperimentFlags::get().kSaveDungeonMaps);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
Checkbox("Use built-in file dialog",
|
||||
&mutable_flags()->kNewFileDialogWrapper);
|
||||
Checkbox("Enable Console Logging", &mutable_flags()->kLogToConsole);
|
||||
&ExperimentFlags::get().kNewFileDialogWrapper);
|
||||
Checkbox("Enable Console Logging", &ExperimentFlags::get().kLogToConsole);
|
||||
Checkbox("Enable Texture Streaming",
|
||||
&mutable_flags()->kLoadTexturesAsStreaming);
|
||||
&ExperimentFlags::get().kLoadTexturesAsStreaming);
|
||||
Checkbox("Log Instructions to Debugger",
|
||||
&mutable_flags()->kLogInstructions);
|
||||
Checkbox("Save All Palettes", &mutable_flags()->kSaveAllPalettes);
|
||||
Checkbox("Save Gfx Groups", &mutable_flags()->kSaveGfxGroups);
|
||||
Checkbox("Save Graphics Sheets", &mutable_flags()->kSaveGraphicsSheet);
|
||||
&ExperimentFlags::get().kLogInstructions);
|
||||
Checkbox("Save All Palettes", &ExperimentFlags::get().kSaveAllPalettes);
|
||||
Checkbox("Save Gfx Groups", &ExperimentFlags::get().kSaveGfxGroups);
|
||||
Checkbox("Save Graphics Sheets",
|
||||
&ExperimentFlags::get().kSaveGraphicsSheet);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1803,7 +1803,7 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
|
||||
|
||||
void Cpu::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
|
||||
bool immediate, bool accumulator_mode) {
|
||||
if (flags()->kLogInstructions) {
|
||||
if (core::ExperimentFlags::get().kLogInstructions) {
|
||||
std::ostringstream oss;
|
||||
oss << "$" << std::uppercase << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(PB) << ":" << std::hex << PC << ": 0x"
|
||||
|
||||
@@ -34,7 +34,7 @@ class InstructionEntry {
|
||||
std::string instruction; // Human-readable instruction text
|
||||
};
|
||||
|
||||
class Cpu : public core::ExperimentFlags {
|
||||
class Cpu {
|
||||
public:
|
||||
explicit Cpu(Memory& mem, Clock& vclock, CpuCallbacks& callbacks)
|
||||
: memory(mem), clock(vclock), callbacks_(callbacks) {}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
@@ -15,9 +14,291 @@
|
||||
namespace yaze {
|
||||
namespace gfx {
|
||||
|
||||
namespace lc_lz2 {
|
||||
std::vector<uint8_t> HyruleMagicCompress(uint8_t const* const src,
|
||||
int const oldsize, int* const size,
|
||||
int const flag) {
|
||||
unsigned char* b2 =
|
||||
(unsigned char*)malloc(0x1000); // allocate a 2^12 sized buffer
|
||||
|
||||
// Compression commands
|
||||
int i, j, k, l, m = 0, n, o = 0, bd = 0, p, q = 0, r;
|
||||
|
||||
for (i = 0; i < oldsize;) {
|
||||
l = src[i]; // grab a char from the buffer.
|
||||
|
||||
k = 0;
|
||||
|
||||
r = !!q; // r = the same logical value (0 or 1) as q, but not the same
|
||||
// value necesarily.
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
if (src[j] == l) {
|
||||
m = oldsize - j;
|
||||
|
||||
for (n = 0; n < m; n++)
|
||||
if (src[n + j] != src[n + i]) break;
|
||||
|
||||
if (n > k) k = n, o = j;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = i + 1; n < oldsize; n++) {
|
||||
if (src[n] != l) {
|
||||
// look for chars identical to the first one.
|
||||
// stop if we can't find one.
|
||||
// n will reach i+k+1 for some k >= 0.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n -= i; // offset back by i. i.e. n = k+1 as above.
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 1;
|
||||
else {
|
||||
m = src[i + 1];
|
||||
|
||||
for (n = i + 2; n < oldsize; n++) {
|
||||
if (src[n] != l) break;
|
||||
|
||||
n++;
|
||||
|
||||
if (src[n] != m) break;
|
||||
}
|
||||
|
||||
n -= i;
|
||||
|
||||
if (n > 2 + r)
|
||||
p = 2;
|
||||
else {
|
||||
m = oldsize - i;
|
||||
|
||||
for (n = 1; n < m; n++)
|
||||
if (src[i + n] != l + n) break;
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 3;
|
||||
else
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (k > 3 + r && k > n + (p & 1)) p = 4, n = k;
|
||||
|
||||
if (!p)
|
||||
q++, i++;
|
||||
else {
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
q = 0;
|
||||
}
|
||||
|
||||
i += n;
|
||||
n--;
|
||||
|
||||
if (n > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (n >> 8) + (p << 2));
|
||||
b2[bd++] = (unsigned char)n;
|
||||
} else
|
||||
b2[bd++] = (unsigned char)((p << 5) + n);
|
||||
|
||||
switch (p) {
|
||||
case 1:
|
||||
case 3:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
b2[bd++] = (unsigned char)m;
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (flag) {
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
b2[bd++] = (unsigned char)o;
|
||||
} else {
|
||||
b2[bd++] = (unsigned char)o;
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
}
|
||||
|
||||
b2[bd++] = 255;
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
*size = bd;
|
||||
|
||||
std::vector<uint8_t> compressed_data(b2, b2 + bd);
|
||||
free(b2);
|
||||
return compressed_data;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> HyruleMagicDecompress(uint8_t const* src, int* const size,
|
||||
int const p_big_endian) {
|
||||
unsigned char* b2 = (unsigned char*)malloc(1024);
|
||||
|
||||
int bd = 0, bs = 1024;
|
||||
|
||||
unsigned char a;
|
||||
unsigned char b;
|
||||
unsigned short c, d;
|
||||
|
||||
for (;;) {
|
||||
// retrieve a uchar from the buffer.
|
||||
a = *(src++);
|
||||
|
||||
// end the decompression routine if we encounter 0xff.
|
||||
if (a == 0xff) break;
|
||||
|
||||
// examine the top 3 bits of a.
|
||||
b = (a >> 5);
|
||||
|
||||
if (b == 7) // i.e. 0b 111
|
||||
{
|
||||
// get bits 0b 0001 1100
|
||||
b = ((a >> 2) & 7);
|
||||
|
||||
// get bits 0b 0000 0011, multiply by 256, OR with the next byte.
|
||||
c = ((a & 0x0003) << 8);
|
||||
c |= *(src++);
|
||||
} else
|
||||
// or get bits 0b 0001 1111
|
||||
c = (uint16_t)(a & 31);
|
||||
|
||||
c++;
|
||||
|
||||
if ((bd + c) > (bs - 512)) {
|
||||
// need to increase the buffer size.
|
||||
bs += 1024;
|
||||
b2 = (uint8_t*)realloc(b2, bs);
|
||||
}
|
||||
|
||||
// 7 was handled, here we handle other decompression codes.
|
||||
|
||||
switch (b) {
|
||||
case 0: // 0b 000
|
||||
|
||||
// raw copy
|
||||
|
||||
// copy info from the src buffer to our new buffer,
|
||||
// at offset bd (which we'll be increasing;
|
||||
memcpy(b2 + bd, src, c);
|
||||
|
||||
// increment the src pointer accordingly.
|
||||
src += c;
|
||||
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 1: // 0b 001
|
||||
|
||||
// rle copy
|
||||
|
||||
// make c duplicates of one byte, inc the src pointer.
|
||||
memset(b2 + bd, *(src++), c);
|
||||
|
||||
// increase the b2 offset.
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 2: // 0b 010
|
||||
|
||||
// rle 16-bit alternating copy
|
||||
|
||||
d = core::ldle16b(src);
|
||||
|
||||
src += 2;
|
||||
|
||||
while (c > 1) {
|
||||
// copy that 16-bit number c/2 times into the b2 buffer.
|
||||
core::stle16b(b2 + bd, d);
|
||||
|
||||
bd += 2;
|
||||
c -= 2; // hence c/2
|
||||
}
|
||||
|
||||
if (c) // if there's a remainder of c/2, this handles it.
|
||||
b2[bd++] = (char)d;
|
||||
|
||||
break;
|
||||
|
||||
case 3: // 0b 011
|
||||
|
||||
// incrementing copy
|
||||
|
||||
// get the current src byte.
|
||||
a = *(src++);
|
||||
|
||||
while (c--) {
|
||||
// increment that byte and copy to b2 in c iterations.
|
||||
// e.g. a = 4, b2 will have 4,5,6,7,8... written to it.
|
||||
b2[bd++] = a++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: // 0b 100, 101, 110
|
||||
|
||||
// lz copy
|
||||
|
||||
if (p_big_endian) {
|
||||
d = (*src << 8) + src[1];
|
||||
} else {
|
||||
d = core::ldle16b(src);
|
||||
}
|
||||
|
||||
while (c--) {
|
||||
// copy from a different location in the buffer.
|
||||
b2[bd++] = b2[d++];
|
||||
}
|
||||
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
|
||||
if (size) (*size) = bd;
|
||||
|
||||
// return the unsigned char* buffer b2, which contains the uncompressed data.
|
||||
std::vector<uint8_t> decompressed_data(b2, b2 + bd);
|
||||
free(b2);
|
||||
return decompressed_data;
|
||||
}
|
||||
|
||||
namespace lc_lz2 {
|
||||
|
||||
void PrintCompressionPiece(const CompressionPiecePointer& piece) {
|
||||
std::cout << "Command: " << std::to_string(piece->command) << "\n";
|
||||
@@ -178,9 +459,6 @@ void CompressionCommandAlternative(const uchar* rom_data,
|
||||
comp_accumulator = 0;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Compression V2
|
||||
|
||||
void CheckByteRepeatV2(const uchar* data, uint& src_pos, const uint last_pos,
|
||||
CompressionCommand& cmd) {
|
||||
uint i = 0;
|
||||
@@ -379,15 +657,17 @@ absl::StatusOr<CompressionPiecePointer> SplitCompressionPiece(
|
||||
new_piece->argument[0] =
|
||||
(char)(piece->argument[0] + kMaxLengthCompression);
|
||||
break;
|
||||
case kCommandDirectCopy:
|
||||
case kCommandDirectCopy: {
|
||||
std::string empty;
|
||||
piece->argument_length = kMaxLengthCompression;
|
||||
new_piece = std::make_shared<CompressionPiece>(
|
||||
piece->command, length_left, nullptr, length_left);
|
||||
piece->command, length_left, empty, length_left);
|
||||
// MEMCPY
|
||||
for (int i = 0; i < length_left; ++i) {
|
||||
new_piece->argument[i] = piece->argument[i + kMaxLengthCompression];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kCommandRepeatingBytes: {
|
||||
piece->argument_length = kMaxLengthCompression;
|
||||
uint offset = piece->argument[0] + (piece->argument[1] << 8);
|
||||
@@ -525,7 +805,9 @@ absl::StatusOr<std::vector<uint8_t>> CompressV2(const uchar* data,
|
||||
}
|
||||
|
||||
// Worst case should be a copy of the string with extended header
|
||||
auto compressed_chain = std::make_shared<CompressionPiece>(1, 1, "aaa", 2);
|
||||
std::string worst_case = "aaa";
|
||||
auto compressed_chain =
|
||||
std::make_shared<CompressionPiece>(1, 1, worst_case, 2);
|
||||
auto compressed_chain_start = compressed_chain;
|
||||
|
||||
CompressionCommand current_cmd = {/*argument*/ {{}},
|
||||
@@ -589,286 +871,6 @@ absl::StatusOr<std::vector<uint8_t>> CompressV2(const uchar* data,
|
||||
return CreateCompressionString(compressed_chain_start->next, mode);
|
||||
}
|
||||
|
||||
// Hyrule Magic
|
||||
uint8_t* Compress(uint8_t const* const src, int const oldsize, int* const size,
|
||||
int const flag) {
|
||||
unsigned char* b2 =
|
||||
(unsigned char*)malloc(0x1000); // allocate a 2^12 sized buffer
|
||||
|
||||
int i, j, k, l, m = 0, n, o = 0, bd = 0, p, q = 0, r;
|
||||
|
||||
for (i = 0; i < oldsize;) {
|
||||
l = src[i]; // grab a char from the buffer.
|
||||
|
||||
k = 0;
|
||||
|
||||
r = !!q; // r = the same logical value (0 or 1) as q, but not the same
|
||||
// value necesarily.
|
||||
|
||||
for (j = 0; j < i - 1; j++) {
|
||||
if (src[j] == l) {
|
||||
m = oldsize - j;
|
||||
|
||||
for (n = 0; n < m; n++)
|
||||
if (src[n + j] != src[n + i]) break;
|
||||
|
||||
if (n > k) k = n, o = j;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = i + 1; n < oldsize; n++) {
|
||||
if (src[n] != l) {
|
||||
// look for chars identical to the first one.
|
||||
// stop if we can't find one.
|
||||
// n will reach i+k+1 for some k >= 0.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n -= i; // offset back by i. i.e. n = k+1 as above.
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 1;
|
||||
else {
|
||||
m = src[i + 1];
|
||||
|
||||
for (n = i + 2; n < oldsize; n++) {
|
||||
if (src[n] != l) break;
|
||||
|
||||
n++;
|
||||
|
||||
if (src[n] != m) break;
|
||||
}
|
||||
|
||||
n -= i;
|
||||
|
||||
if (n > 2 + r)
|
||||
p = 2;
|
||||
else {
|
||||
m = oldsize - i;
|
||||
|
||||
for (n = 1; n < m; n++)
|
||||
if (src[i + n] != l + n) break;
|
||||
|
||||
if (n > 1 + r)
|
||||
p = 3;
|
||||
else
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (k > 3 + r && k > n + (p & 1)) p = 4, n = k;
|
||||
|
||||
if (!p)
|
||||
q++, i++;
|
||||
else {
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
q = 0;
|
||||
}
|
||||
|
||||
i += n;
|
||||
n--;
|
||||
|
||||
if (n > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (n >> 8) + (p << 2));
|
||||
b2[bd++] = (unsigned char)n;
|
||||
} else
|
||||
b2[bd++] = (unsigned char)((p << 5) + n);
|
||||
|
||||
switch (p) {
|
||||
case 1:
|
||||
case 3:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
b2[bd++] = (unsigned char)l;
|
||||
b2[bd++] = (unsigned char)m;
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (flag) {
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
b2[bd++] = (unsigned char)o;
|
||||
} else {
|
||||
b2[bd++] = (unsigned char)o;
|
||||
b2[bd++] = (unsigned char)(o >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (q) {
|
||||
q--;
|
||||
|
||||
if (q > 31) {
|
||||
b2[bd++] = (unsigned char)(224 + (q >> 8));
|
||||
}
|
||||
|
||||
b2[bd++] = (unsigned char)q;
|
||||
q++;
|
||||
|
||||
memcpy(b2 + bd, src + i - q, q);
|
||||
|
||||
bd += q;
|
||||
}
|
||||
|
||||
b2[bd++] = 255;
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
*size = bd;
|
||||
|
||||
return b2;
|
||||
}
|
||||
|
||||
uint8_t* Uncompress(uint8_t const* src, int* const size,
|
||||
int const p_big_endian) {
|
||||
unsigned char* b2 = (unsigned char*)malloc(1024);
|
||||
|
||||
int bd = 0, bs = 1024;
|
||||
|
||||
unsigned char a;
|
||||
unsigned char b;
|
||||
unsigned short c, d;
|
||||
|
||||
for (;;) {
|
||||
// retrieve a uchar from the buffer.
|
||||
a = *(src++);
|
||||
|
||||
// end the decompression routine if we encounter 0xff.
|
||||
if (a == 0xff) break;
|
||||
|
||||
// examine the top 3 bits of a.
|
||||
b = (a >> 5);
|
||||
|
||||
if (b == 7) // i.e. 0b 111
|
||||
{
|
||||
// get bits 0b 0001 1100
|
||||
b = ((a >> 2) & 7);
|
||||
|
||||
// get bits 0b 0000 0011, multiply by 256, OR with the next byte.
|
||||
c = ((a & 0x0003) << 8);
|
||||
c |= *(src++);
|
||||
} else
|
||||
// or get bits 0b 0001 1111
|
||||
c = (uint16_t)(a & 31);
|
||||
|
||||
c++;
|
||||
|
||||
if ((bd + c) > (bs - 512)) {
|
||||
// need to increase the buffer size.
|
||||
bs += 1024;
|
||||
b2 = (uint8_t*)realloc(b2, bs);
|
||||
}
|
||||
|
||||
// 7 was handled, here we handle other decompression codes.
|
||||
|
||||
switch (b) {
|
||||
case 0: // 0b 000
|
||||
|
||||
// raw copy
|
||||
|
||||
// copy info from the src buffer to our new buffer,
|
||||
// at offset bd (which we'll be increasing;
|
||||
memcpy(b2 + bd, src, c);
|
||||
|
||||
// increment the src pointer accordingly.
|
||||
src += c;
|
||||
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 1: // 0b 001
|
||||
|
||||
// rle copy
|
||||
|
||||
// make c duplicates of one byte, inc the src pointer.
|
||||
memset(b2 + bd, *(src++), c);
|
||||
|
||||
// increase the b2 offset.
|
||||
bd += c;
|
||||
|
||||
break;
|
||||
|
||||
case 2: // 0b 010
|
||||
|
||||
// rle 16-bit alternating copy
|
||||
|
||||
d = core::ldle16b(src);
|
||||
|
||||
src += 2;
|
||||
|
||||
while (c > 1) {
|
||||
// copy that 16-bit number c/2 times into the b2 buffer.
|
||||
core::stle16b(b2 + bd, d);
|
||||
|
||||
bd += 2;
|
||||
c -= 2; // hence c/2
|
||||
}
|
||||
|
||||
if (c) // if there's a remainder of c/2, this handles it.
|
||||
b2[bd++] = (char)d;
|
||||
|
||||
break;
|
||||
|
||||
case 3: // 0b 011
|
||||
|
||||
// incrementing copy
|
||||
|
||||
// get the current src byte.
|
||||
a = *(src++);
|
||||
|
||||
while (c--) {
|
||||
// increment that byte and copy to b2 in c iterations.
|
||||
// e.g. a = 4, b2 will have 4,5,6,7,8... written to it.
|
||||
b2[bd++] = a++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: // 0b 100, 101, 110
|
||||
|
||||
// lz copy
|
||||
|
||||
if (p_big_endian) {
|
||||
d = (*src << 8) + src[1];
|
||||
} else {
|
||||
d = core::ldle16b(src);
|
||||
}
|
||||
|
||||
while (c--) {
|
||||
// copy from a different location in the buffer.
|
||||
b2[bd++] = b2[d++];
|
||||
}
|
||||
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
b2 = (unsigned char*)realloc(b2, bd);
|
||||
|
||||
if (size) (*size) = bd;
|
||||
|
||||
// return the unsigned char* buffer b2, which contains the uncompressed data.
|
||||
return b2;
|
||||
}
|
||||
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressGraphics(const uchar* data,
|
||||
const int pos,
|
||||
const int length) {
|
||||
@@ -886,9 +888,6 @@ absl::StatusOr<std::vector<uint8_t>> CompressOverworld(
|
||||
return CompressV3(data, pos, length, kNintendoMode1);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Compression V3
|
||||
|
||||
void CheckByteRepeatV3(CompressionContext& context) {
|
||||
uint pos = context.src_pos;
|
||||
|
||||
@@ -1208,15 +1207,17 @@ absl::StatusOr<CompressionPiece> SplitCompressionPieceV3(
|
||||
piece.argument_length);
|
||||
new_piece.argument[0] = (char)(piece.argument[0] + kMaxLengthCompression);
|
||||
break;
|
||||
case kCommandDirectCopy:
|
||||
case kCommandDirectCopy: {
|
||||
piece.argument_length = kMaxLengthCompression;
|
||||
new_piece =
|
||||
CompressionPiece(piece.command, length_left, nullptr, length_left);
|
||||
std::string empty_string = "";
|
||||
new_piece = CompressionPiece(piece.command, length_left, empty_string,
|
||||
length_left);
|
||||
// MEMCPY
|
||||
for (int i = 0; i < length_left; ++i) {
|
||||
new_piece.argument[i] = piece.argument[i + kMaxLengthCompression];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kCommandRepeatingBytes: {
|
||||
piece.argument_length = kMaxLengthCompression;
|
||||
uint offset = piece.argument[0] + (piece.argument[1] << 8);
|
||||
@@ -1339,8 +1340,6 @@ absl::StatusOr<std::vector<uint8_t>> CompressV3(
|
||||
context.compressed_data.end());
|
||||
}
|
||||
|
||||
// Decompression
|
||||
|
||||
std::string SetBuffer(const uchar* data, int src_pos, int comp_accumulator) {
|
||||
std::string buffer;
|
||||
for (int i = 0; i < comp_accumulator; ++i) {
|
||||
@@ -1472,5 +1471,4 @@ absl::StatusOr<std::vector<uint8_t>> DecompressOverworld(
|
||||
|
||||
} // namespace lc_lz2
|
||||
} // namespace gfx
|
||||
|
||||
} // namespace yaze
|
||||
} // namespace yaze
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
@@ -13,6 +14,13 @@
|
||||
namespace yaze {
|
||||
namespace gfx {
|
||||
|
||||
std::vector<uint8_t> HyruleMagicCompress(uint8_t const* const src,
|
||||
int const oldsize, int* const size,
|
||||
int const flag);
|
||||
|
||||
std::vector<uint8_t> HyruleMagicDecompress(uint8_t const* src, int* const size,
|
||||
int const p_big_endian);
|
||||
|
||||
/**
|
||||
* @namespace yaze::gfx::lc_lz2
|
||||
* @brief Contains the LC_LZ2 compression algorithm.
|
||||
@@ -74,7 +82,7 @@ struct CompressionPiece {
|
||||
std::string argument;
|
||||
std::shared_ptr<CompressionPiece> next = nullptr;
|
||||
CompressionPiece() = default;
|
||||
CompressionPiece(int cmd, int len, std::string args, int arg_len)
|
||||
CompressionPiece(int cmd, int len, std::string& args, int arg_len)
|
||||
: command(cmd), length(len), argument_length(arg_len), argument(args) {}
|
||||
};
|
||||
using CompressionPiece = struct CompressionPiece;
|
||||
@@ -138,31 +146,33 @@ void CompressionCommandAlternativeV2(const uchar* data,
|
||||
|
||||
/**
|
||||
* @brief Compresses a buffer of data using the LC_LZ2 algorithm.
|
||||
* \deprecated Use Compress and Uncompress instead.
|
||||
* \deprecated Use HyruleMagicDecompress instead.
|
||||
*/
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressV2(const uchar* data, const int start,
|
||||
const int length, int mode = 1,
|
||||
bool check = false);
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressV2(const uchar* data,
|
||||
const int start,
|
||||
const int length, int mode = 1,
|
||||
bool check = false);
|
||||
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressGraphics(const uchar* data, const int pos,
|
||||
const int length);
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressOverworld(const uchar* data, const int pos,
|
||||
const int length);
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressOverworld(const std::vector<uint8_t> data,
|
||||
const int pos, const int length);
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressGraphics(const uchar* data,
|
||||
const int pos,
|
||||
const int length);
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressOverworld(const uchar* data,
|
||||
const int pos,
|
||||
const int length);
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressOverworld(
|
||||
const std::vector<uint8_t> data, const int pos, const int length);
|
||||
|
||||
absl::StatusOr<CompressionPiecePointer> SplitCompressionPiece(
|
||||
CompressionPiecePointer& piece, int mode);
|
||||
|
||||
std::vector<uint8_t> CreateCompressionString(CompressionPiecePointer& start, int mode);
|
||||
std::vector<uint8_t> CreateCompressionString(CompressionPiecePointer& start,
|
||||
int mode);
|
||||
|
||||
absl::Status ValidateCompressionResult(CompressionPiecePointer& chain_head,
|
||||
int mode, int start, int src_data_pos);
|
||||
|
||||
CompressionPiecePointer MergeCopy(CompressionPiecePointer& start);
|
||||
|
||||
// Compression V3
|
||||
|
||||
struct CompressionContext {
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<uint8_t> compressed_data;
|
||||
@@ -209,42 +219,35 @@ void FinalizeCompression(CompressionContext& context);
|
||||
|
||||
/**
|
||||
* @brief Compresses a buffer of data using the LC_LZ2 algorithm.
|
||||
* \deprecated Use Compress and Uncompress instead.
|
||||
* \deprecated Use HyruleMagicCompress
|
||||
*/
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressV3(const std::vector<uint8_t>& data,
|
||||
const int start, const int length,
|
||||
int mode = 1, bool check = false);
|
||||
|
||||
// Hyrule Magic
|
||||
uint8_t* Compress(uint8_t const* const src, int const oldsize, int* const size,
|
||||
int const flag);
|
||||
|
||||
uint8_t* Uncompress(uint8_t const* src, int* const size,
|
||||
int const p_big_endian);
|
||||
|
||||
// Decompression
|
||||
absl::StatusOr<std::vector<uint8_t>> CompressV3(
|
||||
const std::vector<uint8_t>& data, const int start, const int length,
|
||||
int mode = 1, bool check = false);
|
||||
|
||||
std::string SetBuffer(const std::vector<uint8_t>& data, int src_pos,
|
||||
int comp_accumulator);
|
||||
std::string SetBuffer(const uchar* data, int src_pos, int comp_accumulator);
|
||||
void memfill(const uchar* data, std::vector<uint8_t>& buffer, int buffer_pos, int offset,
|
||||
int length);
|
||||
void memfill(const uchar* data, std::vector<uint8_t>& buffer, int buffer_pos,
|
||||
int offset, int length);
|
||||
|
||||
/**
|
||||
* @brief Decompresses a buffer of data using the LC_LZ2 algorithm.
|
||||
* \deprecated Use Compress and Uncompress instead.
|
||||
* @note Works well for graphics but not overworld data. Prefer Hyrule Magic
|
||||
* routines for overworld data.
|
||||
*/
|
||||
absl::StatusOr<std::vector<uint8_t>> DecompressV2(const uchar* data, int offset,
|
||||
int size = 0x800, int mode = 1);
|
||||
absl::StatusOr<std::vector<uint8_t>> DecompressGraphics(const uchar* data, int pos, int size);
|
||||
absl::StatusOr<std::vector<uint8_t>> DecompressOverworld(const uchar* data, int pos, int size);
|
||||
absl::StatusOr<std::vector<uint8_t>> DecompressOverworld(const std::vector<uint8_t> data,
|
||||
int pos, int size);
|
||||
int size = 0x800,
|
||||
int mode = 1);
|
||||
absl::StatusOr<std::vector<uint8_t>> DecompressGraphics(const uchar* data,
|
||||
int pos, int size);
|
||||
absl::StatusOr<std::vector<uint8_t>> DecompressOverworld(const uchar* data,
|
||||
int pos, int size);
|
||||
absl::StatusOr<std::vector<uint8_t>> DecompressOverworld(
|
||||
const std::vector<uint8_t> data, int pos, int size);
|
||||
|
||||
} // namespace lc_lz2
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_GFX_COMPRESSION_H
|
||||
|
||||
@@ -150,7 +150,7 @@ absl::Status Rom::SaveAllGraphicsData() {
|
||||
final_data = gfx::Bpp8SnesToIndexed(sheet_data, 8);
|
||||
int size = 0;
|
||||
if (compressed) {
|
||||
auto compressed_data = gfx::lc_lz2::Compress(
|
||||
auto compressed_data = gfx::HyruleMagicCompress(
|
||||
final_data.data(), final_data.size(), &size, 1);
|
||||
for (int j = 0; j < size; j++) {
|
||||
sheet_data[j] = compressed_data[j];
|
||||
@@ -315,9 +315,12 @@ absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) {
|
||||
}
|
||||
|
||||
// Run the other save functions
|
||||
if (flags()->kSaveAllPalettes) RETURN_IF_ERROR(SaveAllPalettes());
|
||||
if (flags()->kSaveGfxGroups) RETURN_IF_ERROR(SaveGroupsToRom());
|
||||
if (flags()->kSaveGraphicsSheet) RETURN_IF_ERROR(SaveAllGraphicsData());
|
||||
if (core::ExperimentFlags::get().kSaveAllPalettes)
|
||||
RETURN_IF_ERROR(SaveAllPalettes());
|
||||
if (core::ExperimentFlags::get().kSaveGfxGroups)
|
||||
RETURN_IF_ERROR(SaveGroupsToRom());
|
||||
if (core::ExperimentFlags::get().kSaveGraphicsSheet)
|
||||
RETURN_IF_ERROR(SaveAllGraphicsData());
|
||||
|
||||
if (save_new) {
|
||||
// Create a file of the same name and append the date between the filename
|
||||
|
||||
@@ -131,7 +131,7 @@ constexpr uint32_t kMaxGraphics = 0xC3FB5;
|
||||
/**
|
||||
* @brief The Rom class is used to load, save, and modify Rom data.
|
||||
*/
|
||||
class Rom : public core::ExperimentFlags {
|
||||
class Rom {
|
||||
public:
|
||||
/**
|
||||
* @brief Loads the players 4bpp graphics sheet from Rom data.
|
||||
|
||||
@@ -21,7 +21,8 @@ absl::Status Overworld::Load(Rom &rom) {
|
||||
AssembleMap16Tiles();
|
||||
RETURN_IF_ERROR(DecompressAllMapTiles())
|
||||
|
||||
const bool load_custom_overworld = flags()->overworld.kLoadCustomOverworld;
|
||||
const bool load_custom_overworld =
|
||||
core::ExperimentFlags::get().overworld.kLoadCustomOverworld;
|
||||
for (int map_index = 0; map_index < kNumOverworldMaps; ++map_index)
|
||||
overworld_maps_.emplace_back(map_index, rom_, load_custom_overworld);
|
||||
|
||||
@@ -107,7 +108,8 @@ absl::Status Overworld::AssembleMap32Tiles() {
|
||||
rom_.version_constants().kMap32TileTR,
|
||||
rom_.version_constants().kMap32TileBL,
|
||||
rom_.version_constants().kMap32TileBR};
|
||||
if (rom()->data()[kMap32ExpandedFlagPos] != 0x04) {
|
||||
if (rom()->data()[kMap32ExpandedFlagPos] != 0x04 &&
|
||||
core::ExperimentFlags::get().overworld.kLoadCustomOverworld) {
|
||||
map32address[0] = rom_.version_constants().kMap32TileTL;
|
||||
map32address[1] = kMap32TileTRExpanded;
|
||||
map32address[2] = kMap32TileBLExpanded;
|
||||
@@ -155,7 +157,8 @@ absl::Status Overworld::AssembleMap32Tiles() {
|
||||
void Overworld::AssembleMap16Tiles() {
|
||||
int tpos = kMap16Tiles;
|
||||
int num_tile16 = kNumTile16Individual;
|
||||
if (rom()->data()[kMap16ExpandedFlagPos] != 0x0F) {
|
||||
if (rom()->data()[kMap16ExpandedFlagPos] != 0x0F &&
|
||||
core::ExperimentFlags::get().overworld.kLoadCustomOverworld) {
|
||||
tpos = kMap16TilesExpanded;
|
||||
num_tile16 = NumberOfMap16Ex;
|
||||
expanded_tile16_ = true;
|
||||
@@ -214,8 +217,11 @@ absl::Status Overworld::DecompressAllMapTiles() {
|
||||
return core::SnesToPc(p);
|
||||
};
|
||||
|
||||
uint32_t lowest = 0x0FFFFF;
|
||||
uint32_t highest = 0x0F8000;
|
||||
constexpr uint32_t kBaseLowest = 0x0FFFFF;
|
||||
constexpr uint32_t kBaseHighest = 0x0F8000;
|
||||
|
||||
uint32_t lowest = kBaseLowest;
|
||||
uint32_t highest = kBaseHighest;
|
||||
int sx = 0;
|
||||
int sy = 0;
|
||||
int c = 0;
|
||||
@@ -230,24 +236,12 @@ absl::Status Overworld::DecompressAllMapTiles() {
|
||||
if (p1 >= highest) highest = p1;
|
||||
if (p2 >= highest) highest = p2;
|
||||
|
||||
if (p1 <= lowest && p1 > 0x0F8000) lowest = p1;
|
||||
if (p2 <= lowest && p2 > 0x0F8000) lowest = p2;
|
||||
if (p1 <= lowest && p1 > kBaseHighest) lowest = p1;
|
||||
if (p2 <= lowest && p2 > kBaseHighest) lowest = p2;
|
||||
|
||||
std::vector<uint8_t> bytes, bytes2;
|
||||
int size1, size2;
|
||||
auto decomp = gfx::lc_lz2::Uncompress(rom()->data() + p2, &size1, 1);
|
||||
bytes.resize(size1);
|
||||
for (int j = 0; j < size1; j++) {
|
||||
bytes[j] = decomp[j];
|
||||
}
|
||||
free(decomp);
|
||||
decomp = gfx::lc_lz2::Uncompress(rom()->data() + p1, &size2, 1);
|
||||
bytes2.resize(size2);
|
||||
for (int j = 0; j < size2; j++) {
|
||||
bytes2[j] = decomp[j];
|
||||
}
|
||||
free(decomp);
|
||||
|
||||
auto bytes = gfx::HyruleMagicDecompress(rom()->data() + p2, &size1, 1);
|
||||
auto bytes2 = gfx::HyruleMagicDecompress(rom()->data() + p1, &size2, 1);
|
||||
OrganizeMapTiles(bytes, bytes2, i, sx, sy, ttpos);
|
||||
|
||||
sx++;
|
||||
@@ -302,7 +296,8 @@ void Overworld::LoadEntrances() {
|
||||
int ow_entrance_pos_ptr = kOverworldEntrancePos;
|
||||
int ow_entrance_id_ptr = kOverworldEntranceEntranceId;
|
||||
int num_entrances = 129;
|
||||
if (rom()->data()[kOverworldEntranceExpandedFlagPos] != 0xB8) {
|
||||
if (rom()->data()[kOverworldEntranceExpandedFlagPos] != 0xB8 &&
|
||||
core::ExperimentFlags::get().overworld.kLoadCustomOverworld) {
|
||||
ow_entrance_map_ptr = kOverworldEntranceMapExpanded;
|
||||
ow_entrance_pos_ptr = kOverworldEntrancePosExpanded;
|
||||
ow_entrance_id_ptr = kOverworldEntranceEntranceIdExpanded;
|
||||
@@ -377,7 +372,7 @@ absl::Status Overworld::LoadExits() {
|
||||
uint16_t px = (uint16_t)((rom_data[OWExitXPlayer + (i * 2) + 1] << 8) +
|
||||
rom_data[OWExitXPlayer + (i * 2)]);
|
||||
|
||||
if (rom()->flags()->kLogToConsole) {
|
||||
if (core::ExperimentFlags::get().kLogToConsole) {
|
||||
std::cout << "Exit: " << i << " RoomID: " << exit_room_id
|
||||
<< " MapID: " << exit_map_id << " VRAM: " << exit_vram
|
||||
<< " YScroll: " << exit_y_scroll
|
||||
@@ -538,24 +533,13 @@ absl::Status Overworld::SaveOverworldMaps() {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> a, b;
|
||||
int size_a, size_b;
|
||||
// Compress single_map_1 and single_map_2
|
||||
auto a_char = gfx::lc_lz2::Compress(single_map_1.data(), 256, &size_a, 1);
|
||||
auto b_char = gfx::lc_lz2::Compress(single_map_2.data(), 256, &size_b, 1);
|
||||
if (a_char == nullptr || b_char == nullptr) {
|
||||
auto a = gfx::HyruleMagicCompress(single_map_1.data(), 256, &size_a, 1);
|
||||
auto b = gfx::HyruleMagicCompress(single_map_2.data(), 256, &size_b, 1);
|
||||
if (a.empty() || b.empty()) {
|
||||
return absl::AbortedError("Error compressing map gfx.");
|
||||
}
|
||||
// Copy the compressed data to a and b
|
||||
a.resize(size_a);
|
||||
b.resize(size_b);
|
||||
// Copy the arrays manually
|
||||
for (int k = 0; k < size_a; k++) {
|
||||
a[k] = a_char[k];
|
||||
}
|
||||
for (int k = 0; k < size_b; k++) {
|
||||
b[k] = b_char[k];
|
||||
}
|
||||
|
||||
// Save compressed data and pointers
|
||||
map_data_p1[i] = std::vector<uint8_t>(size_a);
|
||||
@@ -571,8 +555,8 @@ absl::Status Overworld::SaveOverworldMaps() {
|
||||
pos = kOverworldMapDataOverflow; // 0x0F8780;
|
||||
}
|
||||
|
||||
auto compare_array = [](const std::vector<uint8_t> &array1,
|
||||
const std::vector<uint8_t> &array2) -> bool {
|
||||
const auto compare_array = [](const std::vector<uint8_t> &array1,
|
||||
const std::vector<uint8_t> &array2) -> bool {
|
||||
if (array1.size() != array2.size()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1075,7 +1059,7 @@ absl::Status Overworld::CreateTile32Tilemap() {
|
||||
unique_tiles.size(), LimitOfMap32));
|
||||
}
|
||||
|
||||
if (flags()->kLogToConsole) {
|
||||
if (core::ExperimentFlags::get().kLogToConsole) {
|
||||
std::cout << "Number of unique Tiles32: " << tiles32_unique_.size()
|
||||
<< " Saved:" << tiles32_unique_.size()
|
||||
<< " Out of: " << LimitOfMap32 << std::endl;
|
||||
@@ -1528,7 +1512,7 @@ absl::Status Overworld::SaveItems() {
|
||||
return absl::AbortedError("Too many items");
|
||||
}
|
||||
|
||||
if (flags()->kLogToConsole) {
|
||||
if (core::ExperimentFlags::get().kLogToConsole) {
|
||||
std::cout << "End of Items : " << data_pos << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ constexpr int NumberOfMap32 = Map32PerScreen * kNumOverworldMaps;
|
||||
* This class is responsible for loading and saving the overworld data,
|
||||
* as well as creating the tilesets and tilemaps for the overworld.
|
||||
*/
|
||||
class Overworld : public SharedRom, public core::ExperimentFlags {
|
||||
class Overworld : public SharedRom {
|
||||
public:
|
||||
absl::Status Load(Rom &rom);
|
||||
absl::Status LoadOverworldMaps();
|
||||
|
||||
Reference in New Issue
Block a user