Skip to content

Commit

Permalink
feat: gifscript backend
Browse files Browse the repository at this point in the history
  • Loading branch information
F0bes committed Apr 2, 2024
1 parent 4625f91 commit e0cf3fb
Show file tree
Hide file tree
Showing 6 changed files with 461 additions and 21 deletions.
1 change: 1 addition & 0 deletions .github/workflows/master-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ jobs:
generate_release_notes: true
files: |
${{github.workspace}}/build/gifscript
${{github.workspace}}/build/tpircsfig
tag_name: ${{ steps.tag_version.outputs.new_tag }}
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ set(GENERATED_SOURCES
set(BACKEND_SOURCES
${BACKEND_INCLUDE}/backend.hpp
${BACKEND_INCLUDE}/c_code.hpp
${BACKEND_INCLUDE}/gifscript_backend.hpp
${BACKEND_SRC}/c_code.cpp
${BACKEND_SRC}/gifscript_backend.cpp
)

set(CORE_SOURCES
Expand Down Expand Up @@ -105,6 +107,7 @@ else()
message("git version: ${GIT_VERSION}")
target_compile_options(gifscript_core PRIVATE -Wall -Werror -Wno-unused-const-variable ${CPP_23_ARG})
target_compile_options(gifscript PRIVATE -DGIT_VERSION=${GIT_VERSION} -Wall -Werror -Wno-unused-const-variable ${CPP_23_ARG})
target_compile_options(tpircsfig PRIVATE -DGIT_VERSION=${GIT_VERSION} -Wall -Werror -Wno-unused-const-variable ${CPP_23_ARG})
endif()

target_include_directories(gifscript PUBLIC ${fmt_SOURCE_DIR}/include)
Expand Down
57 changes: 57 additions & 0 deletions backends/include/gifscript_backend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#pragma once

#include "backend.hpp"

#include <functional>
#include <unordered_map>

class gifscript_backend : public Backend
{

public:
gifscript_backend() = default;
~gifscript_backend();

bool arg_parse(int argc, char** argv) override;

void set_output(const std::string_view& output) override
{
this->output = output;
};

void print_help() const override;

void emit(GIFBlock& block) override;

// Primitive dispatching
static std::string emit_primitive(gifscript_backend*, const GifRegister&);
static std::string emit_rgbaq(gifscript_backend*, const GifRegister&);
static std::string emit_uv(gifscript_backend*, const GifRegister&);
static std::string emit_xyz2(gifscript_backend*, const GifRegister&);
static std::string emit_tex0(gifscript_backend*, const GifRegister&);
static std::string emit_fog(gifscript_backend*, const GifRegister&);
static std::string emit_fogcol(gifscript_backend*, const GifRegister&);
static std::string emit_scissor(gifscript_backend*, const GifRegister&);
static std::string emit_signal(gifscript_backend*, const GifRegister&);
static std::string emit_finish(gifscript_backend*, const GifRegister&);
static std::string emit_label(gifscript_backend*, const GifRegister&);

std::unordered_map<uint32_t, std::function<std::string(gifscript_backend*, const GifRegister&)>> dispatch_table =
{
{0x00, gifscript_backend::emit_primitive},
{0x01, gifscript_backend::emit_rgbaq},
{0x03, gifscript_backend::emit_uv},
{0x05, gifscript_backend::emit_xyz2},
{0x06, gifscript_backend::emit_tex0},
{0x0A, gifscript_backend::emit_fog},
{0x3D, gifscript_backend::emit_fogcol},
{0x40, gifscript_backend::emit_scissor},
{0x60, gifscript_backend::emit_signal},
{0x61, gifscript_backend::emit_finish},
{0x62, gifscript_backend::emit_label}};

private:
std::string output = "";
FILE* file = nullptr;
bool first_emit = true;
};
240 changes: 240 additions & 0 deletions backends/src/gifscript_backend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
#include "gifscript_backend.hpp"
#include "registers.hpp"
#include "logger.hpp"
#include "version.hpp"

#include <fmt/core.h>
#include <functional>

auto gifscript_backend::arg_parse(int argc, char** argv) -> bool
{
return true;
}

void gifscript_backend::print_help() const
{
fmt::print(
"gifscript backend options: none\n");
}

gifscript_backend::~gifscript_backend()
{
if(file != nullptr && file != stdout)
{
fclose(file);
}
}

void gifscript_backend::emit(GIFBlock& block)
{
std::string buffer = fmt::format("{} {{\n\t", block.name);
fmt::print("Emitting block: {}\n", block.name);
for(const auto& reg : block.registers)
{
buffer += dispatch_table[static_cast<uint32_t>(reg->GetID())](this, *reg);
buffer += "\n\t";
}

buffer.pop_back();
buffer.pop_back();
buffer += "\n}\n";

if(first_emit)
{
if(output.empty())
{
file = stdout;
}
else
{
file = fopen(output.c_str(), "w");
}

if(file == nullptr)
{
logger::error("Failed to open file: %s\n", output.cbegin());
return;
}
const std::string prologue = fmt::format("// Generated with GIFScript version {}\n", GIT_VERSION);
fwrite(prologue.c_str(), 1, prologue.size(), file);
}

fwrite(buffer.c_str(), 1, buffer.size(), file);
}

auto gifscript_backend::emit_primitive(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& prim = dynamic_cast<const PRIM&>(reg);

std::string line = "prim ";
switch(prim.GetType())
{
case PrimType::Point:
line += "point";
break;
case PrimType::Line:
line += "line";
break;
case PrimType::LineStrip:
line += "linestrip";
break;
case PrimType::Triangle:
line += "triangle";
break;
case PrimType::TriangleStrip:
line += "trianglestrip";
break;
case PrimType::TriangleFan:
line += "trianglefan";
break;
case PrimType::Sprite:
line += "sprite";
break;
default:
logger::error("Unknown primitive type: %d\n", static_cast<int>(prim.GetType()));
}

if(prim.IsGouraud())
{
line += " gouraud";
}

if(prim.IsTextured())
{
line += " textured";
}

if(prim.IsFogging())
{
line += " fogging";
}

if(prim.IsAA1())
{
line += " aa1";
}

line += ";";
return line;
}

auto gifscript_backend::emit_rgbaq(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& rgbaq = dynamic_cast<const RGBAQ&>(reg);

auto val = rgbaq.GetValue();
return fmt::format("rgbaq 0x{:x},0x{:x},0x{:x},0x{:x};",
val.x, val.y, val.z, val.w);
}

auto gifscript_backend::emit_uv(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& uv_reg = dynamic_cast<const UV&>(reg);

auto val = uv_reg.GetValue();
return fmt::format("uv 0x{:x},0x{:x};",
val.x, val.y);
}

auto gifscript_backend::emit_xyz2(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& xyz2 = dynamic_cast<const XYZ2&>(reg);

auto val = xyz2.GetValue();
return fmt::format("xyz2 0x{:x},0x{:x},0x{:x};",
val.x, val.y, val.z);
}

auto gifscript_backend::emit_tex0(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& tex0 = dynamic_cast<const TEX0&>(reg);

std::string line = fmt::format("tex0 0x{:x} 0x{:x} 0x{:x},0x{:x}",
tex0.GetTBP(), tex0.GetTBW(), tex0.GetTW(), tex0.GetTH());

switch(tex0.GetPSM())
{
case PSM::CT32:
line += " CT32";
break;
case PSM::CT24:
line += " CT24";
break;
case PSM::CT16:
line += " CT16";
break;
}

switch(tex0.GetTFX())
{
case TFX::Modulate:
line += " modulate";
break;
case TFX::Decal:
line += " decal";
break;
case TFX::Highlight:
line += " highlight";
break;
case TFX::Highlight2:
line += " highlight2";
break;
}

line += ";";
return line;
}

auto gifscript_backend::emit_fog(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& fog = dynamic_cast<const FOG&>(reg);

auto val = fog.GetValue();
return fmt::format("fog 0x{:x};",
val);
}

auto gifscript_backend::emit_fogcol(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& fogcol = dynamic_cast<const FOGCOL&>(reg);

auto val = fogcol.GetValue();
return fmt::format("fogcol 0x{:x},0x{:x},0x{:x};",
val.x, val.y, val.z);
}

auto gifscript_backend::emit_scissor(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& scissor = dynamic_cast<const SCISSOR&>(reg);

auto val = scissor.GetValue();
return fmt::format("scissor 0x{:x},0x{:x},0x{:x},0x{:x};",
val.x, val.y, val.z, val.w);
}

auto gifscript_backend::emit_signal(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& signal = dynamic_cast<const SIGNAL&>(reg);

auto val = signal.GetValue();
return fmt::format("signal 0x{:x},0x{:x};",
val.x, val.y);
}

auto gifscript_backend::emit_finish(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& finish = dynamic_cast<const FINISH&>(reg);

auto val = finish.GetValue();
return fmt::format("finish 0x{:x};",
val);
}

auto gifscript_backend::emit_label(gifscript_backend* inst, const GifRegister& reg) -> std::string
{
const auto& label = dynamic_cast<const LABEL&>(reg);

auto val = label.GetValue();
return fmt::format("label 0x{:x},0x{:x};",
val.x, val.y);
}
17 changes: 17 additions & 0 deletions frontends/gifscript.rl
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
#include <fmt/format.h>

#include "c_code.hpp"
#include "gifscript_backend.hpp"

#include "logger.hpp"
#ifndef WIN32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif

#include "parser.c"

#ifndef WIN32
#pragma GCC diagnostic pop
#endif
#include "registers.hpp"
Expand Down Expand Up @@ -553,6 +558,8 @@ void print_help(char* argv0)
"Valid backends are:\n\t"
" c_code(default)\n\t"
" Generates a c file with an array for each gif block\n"
" gifscript\n\t"
" Generates a gifscript file. Mostly used for debugging or tpircsfig\n"
"For backend specific help, please pass --bhelp to your backend\n" , argv0);
};

Expand Down Expand Up @@ -581,6 +588,16 @@ int main(int argc, char **argv)
return 1;
}
}
else if (backend_str == "gifscript")
{
fmt::print("Using gifscript backend\n");
backend = new gifscript_backend();
if(!backend->arg_parse(argc, argv))
{
fmt::print("Use --bhelp for valid backend configuration arguments\n");
return 1;
}
}
else
{
fmt::print("Unknown backend: {}\n", backend_str);
Expand Down
Loading

0 comments on commit e0cf3fb

Please sign in to comment.