diff --git a/backend/c_code.cpp b/backend/c_code.cpp index 29c647c..a072593 100644 --- a/backend/c_code.cpp +++ b/backend/c_code.cpp @@ -51,7 +51,7 @@ void c_code_backend::print_help() const c_code_backend::~c_code_backend() { - if(file != nullptr && file != stdout) + if (file != nullptr && file != stdout) { fclose(file); } @@ -60,9 +60,9 @@ c_code_backend::~c_code_backend() void c_code_backend::emit(GIFBlock* block) { std::string prim_str; - if(block->prim) + if (block->prim) { - if(emit_mode == EmitMode::USE_DEFS) + if (emit_mode == EmitMode::USE_DEFS) { prim_str = fmt::format("GS_SET_PRIM({},{},{},{},0,{},GS_ENABLE,0,0)", PrimTypeStrings[block->prim->GetType()], block->prim->IsGouraud() ? "GS_ENABLE" : "GS_DISABLE", @@ -83,8 +83,7 @@ void c_code_backend::emit(GIFBlock* block) std::string buffer = fmt::format("u64 {1}_data_size = {0};\n" "u64 {1}_data[] __attribute__((aligned(16))) = {{\n\t" "GIF_SET_TAG({2},1,{3},{4},0,1),GIF_REG_AD,\n\t", - (block->registers.size() + 1) * 16, block->name, block->registers.size() - , block->prim ? 1 : 0, block->prim ? prim_str : "0"); + (block->registers.size() + 1) * 16, block->name, block->registers.size(), block->prim ? 1 : 0, block->prim ? prim_str : "0"); fmt::print("Emitting block: {}\n", block->name); for (auto& reg : block->registers) { @@ -152,6 +151,16 @@ std::string c_code_backend::emit_rgbaq(c_code_backend* inst, std::shared_ptremit_mode == EmitMode::USE_DEFS ? "GS_REG_RGBAQ" : "0x01"); } +std::string c_code_backend::emit_uv(c_code_backend* inst, std::shared_ptr reg) +{ + UV uv = dynamic_cast(*reg); + + auto val = uv.GetValue(); + + return fmt::format("GS_SET_UV({}<<4,{}<<4),{},", + val.x, val.y, inst->emit_mode == EmitMode::USE_DEFS ? "GS_REG_UV" : "0x03"); +} + std::string c_code_backend::emit_xyz2(c_code_backend* inst, std::shared_ptr reg) { XYZ2 xyz2 = dynamic_cast(*reg); @@ -162,6 +171,39 @@ std::string c_code_backend::emit_xyz2(c_code_backend* inst, std::shared_ptremit_mode == EmitMode::USE_DEFS ? "GS_REG_XYZ2" : "0x05"); } +std::string c_code_backend::emit_tex0(c_code_backend* inst, std::shared_ptr reg) +{ + TEX0 tex0 = dynamic_cast(*reg); + + if (inst->emit_mode == EmitMode::USE_DEFS) + { + std::string PSM_STR; + switch (tex0.GetPSM()) + { + case PSM::CT32: + PSM_STR = "GS_PSM_32"; + break; + case PSM::CT24: + PSM_STR = "GS_PSM_24"; + break; + case PSM::CT16: + PSM_STR = "GS_PSM_16"; + break; + } + + // Todo: Support gs_psm defines + return fmt::format("GS_SET_TEX0(0x{:x},0x{:x},{},{:x},{:x},{:d},{},0,0,0,0,0),GS_REG_TEX0,", + tex0.GetTBP(), tex0.GetTBW(), PSM_STR, + tex0.GetTW(), tex0.GetTH(), tex0.GetTCC(), static_cast(tex0.GetTFX())); + } + else + { + return fmt::format("GS_SET_TEX0(0x{:02x},0x{:02x},{},{:02x},{:02x},{:d},{},0,0,0,0,0),0x06,", + tex0.GetTBP(), tex0.GetTBW(), static_cast(tex0.GetPSM()), + tex0.GetTW(), tex0.GetTH(), tex0.GetTCC(), static_cast(tex0.GetTFX())); + } +} + std::string c_code_backend::emit_fog(c_code_backend* inst, std::shared_ptr reg) { FOG fog = dynamic_cast(*reg); @@ -199,7 +241,7 @@ std::string c_code_backend::emit_signal(c_code_backend* inst, std::shared_ptremit_mode == EmitMode::USE_DEFS ? "GS_REG_SIGNAL" : "0x60"); + val.x, val.y, inst->emit_mode == EmitMode::USE_DEFS ? "GS_REG_SIGNAL" : "0x60"); } std::string c_code_backend::emit_finish(c_code_backend* inst, std::shared_ptr reg) @@ -207,13 +249,13 @@ std::string c_code_backend::emit_finish(c_code_backend* inst, std::shared_ptr(*reg); auto val = finish.GetValue(); - if(inst->emit_mode == EmitMode::USE_DEFS) + if (inst->emit_mode == EmitMode::USE_DEFS) { - return fmt::format("GS_SET_FINISH({}),GS_REG_FINISH,",val); + return fmt::format("GS_SET_FINISH({}),GS_REG_FINISH,", val); } else { - return fmt::format("0x{:x},{},",val, "0x61"); + return fmt::format("0x{:x},{},", val, "0x61"); } } @@ -224,5 +266,5 @@ std::string c_code_backend::emit_label(c_code_backend* inst, std::shared_ptremit_mode == EmitMode::USE_DEFS ? "GS_REG_LABEL" : "0x62"); + val.x, val.y, inst->emit_mode == EmitMode::USE_DEFS ? "GS_REG_LABEL" : "0x62"); } diff --git a/backend/c_code.h b/backend/c_code.h index e42bc2e..e3f888a 100644 --- a/backend/c_code.h +++ b/backend/c_code.h @@ -36,7 +36,9 @@ class c_code_backend : public Backend // Primitive dispatching static std::string emit_primitive(c_code_backend*, std::shared_ptr reg); static std::string emit_rgbaq(c_code_backend*, std::shared_ptr reg); + static std::string emit_uv(c_code_backend*, std::shared_ptr reg); static std::string emit_xyz2(c_code_backend*, std::shared_ptr reg); + static std::string emit_tex0(c_code_backend*, std::shared_ptr reg); static std::string emit_fog(c_code_backend*, std::shared_ptr reg); static std::string emit_fogcol(c_code_backend*, std::shared_ptr reg); static std::string emit_scissor(c_code_backend*, std::shared_ptr reg); @@ -48,7 +50,9 @@ class c_code_backend : public Backend { {0x00, c_code_backend::emit_primitive}, {0x01, c_code_backend::emit_rgbaq}, + {0x03, c_code_backend::emit_uv}, {0x05, c_code_backend::emit_xyz2}, + {0x06, c_code_backend::emit_tex0}, {0x0A, c_code_backend::emit_fog}, {0x3D, c_code_backend::emit_fogcol}, {0x40, c_code_backend::emit_scissor}, diff --git a/examples/textured.gs b/examples/textured.gs new file mode 100644 index 0000000..75611ac --- /dev/null +++ b/examples/textured.gs @@ -0,0 +1,38 @@ +/* + This expects a 128x128 CT23 texture to be placed at vram location 0x2300 + The vram address is not divided by 64 by gifscript, you must do that before + In other words, the actual vram address is 0x2300 * 64 + + UV (and XY coords) are automatically shifted, there is no way to do half + pixel offsets at this moment +*/ + +textured_tri { + rgbaq 0x80,0,0,127; + prim tri textured; + + // By default DECAL is used + + // This draws half of the texture as-is + tex0 0x2300 2 ct24 7,7; + uv 0,0; + xyz2 100,100,0; + uv 0,128; + xyz2 100,228,0; + uv 128,128; + xyz2 228,228,0; + + // This draws the other half of the texture, modulated by vertex colours + // with gouraud shading to make it a bit more interesting + prim tri textured gouraud; + tex0 0x2300 2 ct24 7,7 modulate; + rgbaq 0x00,0x80,0x00,127; + uv 0,0; + xyz2 100,100,0; + rgbaq 0x00,0x00,0x80,127; + uv 128,0; + xyz2 228,100,0; + rgbaq 0x80,0x00,0x00,127; + uv 128,128; + xyz2 228,228,0; +} diff --git a/gifscript.rl b/gifscript.rl index 5e9fe08..d075d6d 100644 --- a/gifscript.rl +++ b/gifscript.rl @@ -35,6 +35,13 @@ void FailError(const char* ts, const char* te); } # Registers + action prim_tok { + Parse(lparser, REG, new std::any(GifRegisters::PRIM), &valid); + if(!valid) { + FailError(ts, te); + } + } + action rgbaq_tok { Parse(lparser, REG, new std::any(GifRegisters::RGBAQ), &valid); if(!valid) { @@ -42,6 +49,13 @@ void FailError(const char* ts, const char* te); } } + action uv_tok { + Parse(lparser, REG, new std::any(GifRegisters::UV), &valid); + if(!valid) { + FailError(ts, te); + } + } + action xyz2_tok { Parse(lparser, REG, new std::any(GifRegisters::XYZ2), &valid); if(!valid) { @@ -49,8 +63,8 @@ void FailError(const char* ts, const char* te); } } - action prim_tok { - Parse(lparser, REG, new std::any(GifRegisters::PRIM), &valid); + action tex0_tok { + Parse(lparser, REG, new std::any(GifRegisters::TEX0), &valid); if(!valid) { FailError(ts, te); } @@ -178,6 +192,56 @@ void FailError(const char* ts, const char* te); } } + # TEX0 Modifiers + action mod_ct32_tok { + Parse(lparser, MOD, new std::any(RegModifier::CT32), &valid); + if(!valid) { + FailError(ts, te); + } + } + + action mod_ct24_tok { + Parse(lparser, MOD, new std::any(RegModifier::CT24), &valid); + if(!valid) { + FailError(ts, te); + } + } + + action mod_ct16_tok { + Parse(lparser, MOD, new std::any(RegModifier::CT16), &valid); + if(!valid) { + FailError(ts, te); + } + } + + action mod_modulate_tok { + Parse(lparser, MOD, new std::any(RegModifier::Modulate), &valid); + if(!valid) { + FailError(ts, te); + } + } + + action mod_decal_tok { + Parse(lparser, MOD, new std::any(RegModifier::Decal), &valid); + if(!valid) { + FailError(ts, te); + } + } + + action mod_highlight_tok { + Parse(lparser, MOD, new std::any(RegModifier::Highlight), &valid); + if(!valid) { + FailError(ts, te); + } + } + + action mod_highlight2_tok { + Parse(lparser, MOD, new std::any(RegModifier::Highlight2), &valid); + if(!valid) { + FailError(ts, te); + } + } + # Vectors action vec4_tok { std::string s(ts, te - ts); @@ -276,9 +340,11 @@ void FailError(const char* ts, const char* te); semi = ';'; # Registers + prim = /prim/i; rgbaq = (/rgbaq/i|/rgba/i); + uv = /uv/i; xyz2 = /xyz2/i; - prim = /prim/i; + tex0 = /tex0/i; fog = /fog/i; fogcol = /fogcol/i; scissor = /scissor/i; @@ -300,6 +366,14 @@ void FailError(const char* ts, const char* te); mod_fogging = (/fogging/i|/fog/i); mod_aa1 = /aa1/i; mod_texture = (/texture/i|/textured/i); + # TEX0 Modifiers + mod_ct32 = (/ct32/i|/psmct32/i); + mod_ct24 = (/ct24/i|/psmct24/i); + mod_ct16 = (/ct16/i|/psmct16/i); + mod_modulate = (/modulate/i); + mod_decal = (/decal/i); + mod_highlight = (/highlight/i); + mod_highlight2 = (/highlight2/i); # Constants int_const = digit+; @@ -326,9 +400,11 @@ void FailError(const char* ts, const char* te); semi => semi_tok; # Registers + prim => prim_tok; rgbaq => rgbaq_tok; + uv => uv_tok; xyz2 => xyz2_tok; - prim => prim_tok; + tex0 => tex0_tok; fog => fog_tok; fogcol => fogcol_tok; scissor => scissor_tok; @@ -350,6 +426,14 @@ void FailError(const char* ts, const char* te); mod_fogging => mod_fogging_tok; mod_aa1 => mod_aa1_tok; mod_texture => mod_texture_tok; + # TEX0 Modifiers + mod_ct32 => mod_ct32_tok; + mod_ct24 => mod_ct24_tok; + mod_ct16 => mod_ct16_tok; + mod_modulate => mod_modulate_tok; + mod_decal => mod_decal_tok; + mod_highlight => mod_highlight_tok; + mod_highlight2 => mod_highlight2_tok; # Vectors vec4 => vec4_tok; diff --git a/registers.cpp b/registers.cpp index 048238a..a0bdcb7 100644 --- a/registers.cpp +++ b/registers.cpp @@ -8,8 +8,12 @@ std::shared_ptr GenReg(GifRegisters reg) return std::make_shared(); case GifRegisters::RGBAQ: return std::make_shared(); + case GifRegisters::UV: + return std::make_shared(); case GifRegisters::XYZ2: return std::make_shared(); + case GifRegisters::TEX0: + return std::make_shared(); case GifRegisters::FOG: return std::make_shared(); case GifRegisters::FOGCOL: diff --git a/registers.h b/registers.h index e5b021c..e01d405 100644 --- a/registers.h +++ b/registers.h @@ -14,7 +14,9 @@ enum class GifRegisters { PRIM, RGBAQ, + UV, XYZ2, + TEX0, FOG, FOGCOL, SCISSOR, @@ -26,7 +28,9 @@ enum class GifRegisters constexpr const char* const GifRegisterStrings[] = { "PRIM", "RGBAQ", + "UV", "XYZ2", + "TEX0", "FOG", "FOGCOL", "SCISSOR", @@ -49,6 +53,15 @@ enum RegModifier : uint32_t Fogging, AA1, Texture, + + // TEX0 + CT32, + CT24, + CT16, + Modulate, + Decal, + Highlight, + Highlight2 }; const std::string RegModifierStrings[] = { @@ -60,7 +73,13 @@ const std::string RegModifierStrings[] = { "Fogging", "AA1", "Texture", -}; + "CT32", + "CT24", + "CT16" + "Modulate", + "Decal", + "Highlight", + "Highlight2"}; // Register Access Type // Used to determine if the gif block can use packed or reglist modes @@ -100,6 +119,7 @@ class GifRegister { return rat == RAT::AD; } + constexpr bool HasSideEffects() { return sideEffects; @@ -253,7 +273,6 @@ struct PRIM : public GifRegister struct RGBAQ : public GifRegister { - std::optional value; public: @@ -299,6 +318,52 @@ struct RGBAQ : public GifRegister } }; +struct UV : public GifRegister +{ + std::optional value; + +public: + UV() + : GifRegister(0x03, "UV", RAT::ADP) + { + } + + bool Ready() override + { + return value.has_value(); + } + + void Push(uint32_t) override + { + logger::error("Not supported!"); + } + + void Push(Vec2 v2) override + { + value = v2; + } + + void Push(Vec3 v3) override + { + logger::error("Not supported!"); + } + + void Push(Vec4 v4) override + { + logger::error("Not supported!"); + } + + bool ApplyModifier(RegModifier) override + { + return false; + } + + Vec2 GetValue() + { + return value.value(); + } +}; + struct XYZ2 : public GifRegister { std::optional value; @@ -344,6 +409,147 @@ struct XYZ2 : public GifRegister } }; +enum class PSM +{ + CT32, + CT24, + CT16 +}; + +enum class TFX +{ + Modulate, + Decal, + Highlight, + Highlight2 +}; + +struct TEX0 : public GifRegister +{ + std::optional tbp; + std::optional tbw; + std::optional psm; + std::optional tw; + std::optional th; + TFX tfx = TFX::Decal; + bool tcc = 0; + + TEX0() + : GifRegister(0x06, "TEX0", RAT::ADP) + { + } + + bool Ready() override + { + return tbp.has_value() && tbw.has_value() && psm.has_value() && tw.has_value() && th.has_value(); + } + + void Push(uint32_t i) override + { + if (!tbp.has_value()) + tbp = i; + else if (!tbw.has_value()) + tbw = i; + else if (!tw.has_value()) + tw = i; + else if (!th.has_value()) + th = i; + else + logger::error("Unsure what you're trying to push to TEX0 (%d)", i); + } + + void Push(Vec2 v2) override + { + if (!tw.has_value() && !th.has_value()) + { + tw = v2.x; + th = v2.y; + } + else + { + logger::error("Unsure what you're trying to push to TEX0 (%d, %d)", v2.x, v2.y); + } + } + + void Push(Vec3 v3) override + { + logger::error("Not supported!"); + } + + void Push(Vec4) override + { + logger::error("Not supported!"); + } + + bool ApplyModifier(RegModifier mod) override + { + switch (mod) + { + case CT32: + psm = PSM::CT32; + break; + case CT24: + psm = PSM::CT24; + break; + case CT16: + psm = PSM::CT16; + break; + case Modulate: + tfx = TFX::Modulate; + break; + case Decal: + tfx = TFX::Decal; + break; + case Highlight: + tfx = TFX::Highlight; + break; + case Highlight2: + tfx = TFX::Highlight2; + break; + default: + logger::error("Unknown modifier: %d", mod); + return false; + } + + return true; + } + + uint32_t GetTBP() + { + return tbp.value(); + } + + uint32_t GetTBW() + { + return tbw.value(); + } + + PSM GetPSM() + { + return psm.value(); + } + + uint32_t GetTW() + { + return tw.value(); + } + + uint32_t GetTH() + { + return th.value(); + } + + bool GetTCC() + { + return tcc; + } + + TFX GetTFX() + { + return tfx; + } +}; + class FOG : public GifRegister { std::optional value;