Files
pico-launcher/arm9/source/gui/OamBuilder.h
2025-11-25 17:41:31 +01:00

220 lines
6.9 KiB
C++

#pragma once
#include "common.h"
#include "core/math/Point.h"
#include <libtwl/gfx/gfxOam.h>
/// @brief Helper class for building oams.
class OamBuilder
{
u16 _attr0;
u16 _attr1;
u16 _attr2;
OamBuilder()
: _attr0(0), _attr1(0), _attr2(0) { }
public:
template <int width, int height>
static constexpr OamBuilder OamWithSize(const Point& position, u32 vramOffset)
{
return OamWithSize<width, height>(position.x, position.y, vramOffset);
}
template <int width, int height>
static constexpr OamBuilder OamWithSize(int x, int y, u32 vramOffset)
{
OamBuilder builder;
switch (width)
{
case 8:
{
switch (height)
{
case 8:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_8_8;
builder._attr1 = GFX_OAM_ATTR1_SIZE_8_8;
break;
case 16:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_8_16;
builder._attr1 = GFX_OAM_ATTR1_SIZE_8_16;
break;
case 32:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_8_32;
builder._attr1 = GFX_OAM_ATTR1_SIZE_8_32;
break;
default:
static_assert(width != 8 || (height == 8 || height == 16 || height == 32), "Invalid oam height for width 8");
break;
}
break;
}
case 16:
{
switch (height)
{
case 8:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_16_8;
builder._attr1 = GFX_OAM_ATTR1_SIZE_16_8;
break;
case 16:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_16_16;
builder._attr1 = GFX_OAM_ATTR1_SIZE_16_16;
break;
case 32:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_16_32;
builder._attr1 = GFX_OAM_ATTR1_SIZE_16_32;
break;
default:
static_assert(width != 16 || (height == 8 || height == 16 || height == 32), "Invalid oam height for width 16");
break;
}
break;
}
case 32:
{
switch (height)
{
case 8:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_32_8;
builder._attr1 = GFX_OAM_ATTR1_SIZE_32_8;
break;
case 16:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_32_16;
builder._attr1 = GFX_OAM_ATTR1_SIZE_32_16;
break;
case 32:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_32_32;
builder._attr1 = GFX_OAM_ATTR1_SIZE_32_32;
break;
case 64:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_32_64;
builder._attr1 = GFX_OAM_ATTR1_SIZE_32_64;
break;
default:
static_assert(width != 32 || (height == 8 || height == 16 || height == 32 || height == 64), "Invalid oam height for width 32");
break;
}
break;
}
case 64:
{
switch (height)
{
case 32:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_64_32;
builder._attr1 = GFX_OAM_ATTR1_SIZE_64_32;
break;
case 64:
builder._attr0 = GFX_OAM_ATTR0_SHAPE_64_64;
builder._attr1 = GFX_OAM_ATTR1_SIZE_64_64;
break;
default:
static_assert(width != 64 || (height == 32 || height == 64), "Invalid oam height for width 64");
break;
}
break;
}
default:
static_assert(width == 8 || width == 16 || width == 32 || width == 64, "Invalid oam width");
break;
}
builder._attr0 |= GFX_OAM_ATTR0_Y(y);
builder._attr1 |= GFX_OAM_ATTR1_X(x);
builder._attr2 = GFX_OAM_ATTR2_VRAM_OFFS(vramOffset);
return builder;
}
constexpr OamBuilder& Hidden()
{
_attr0 &= ~GFX_OAM_ATTR0_DOUBLE_AFFINE;
_attr0 |= GFX_OAM_ATTR0_HIDDEN;
return *this;
}
constexpr OamBuilder& AsWindow()
{
_attr0 &= ~GFX_OAM_ATTR0_MODE_BITMAP;
_attr0 |= GFX_OAM_ATTR0_MODE_WINDOW;
return *this;
}
constexpr OamBuilder& AsTranslucent()
{
_attr0 &= ~GFX_OAM_ATTR0_MODE_BITMAP;
_attr0 |= GFX_OAM_ATTR0_MODE_TRANSLUCENT;
return *this;
}
constexpr OamBuilder& AsBitmap(int alpha = 16)
{
_attr0 &= ~GFX_OAM_ATTR0_PLTT256;
_attr0 |= GFX_OAM_ATTR0_MODE_BITMAP;
if (alpha == 0)
return Hidden();
_attr2 &= ~GFX_OAM_ATTR2_BMP_ALPHA(0xF);
_attr2 |= GFX_OAM_ATTR2_BMP_ALPHA(alpha - 1);
return *this;
}
constexpr OamBuilder& WithAffineMtx(int mtx, bool doubleSize = false)
{
_attr0 &= ~GFX_OAM_ATTR0_DOUBLE_AFFINE;
if (doubleSize)
_attr0 |= GFX_OAM_ATTR0_DOUBLE_AFFINE;
else
_attr0 |= GFX_OAM_ATTR0_AFFINE;
_attr1 &= ~GFX_OAM_ATTR1_MTX(0x1F);
_attr1 |= GFX_OAM_ATTR1_MTX(mtx);
return *this;
}
constexpr OamBuilder& WithHFlip(bool hFlip = true)
{
if (hFlip)
_attr1 |= GFX_OAM_ATTR1_HFLIP;
else
_attr1 &= ~GFX_OAM_ATTR1_HFLIP;
return *this;
}
constexpr OamBuilder& WithVFlip(bool vFlip = true)
{
if (vFlip)
_attr1 |= GFX_OAM_ATTR1_VFLIP;
else
_attr1 &= ~GFX_OAM_ATTR1_VFLIP;
return *this;
}
constexpr OamBuilder& WithPriority(int priority)
{
_attr2 &= ~GFX_OAM_ATTR2_PRIORITY(3);
_attr2 |= GFX_OAM_ATTR2_PRIORITY(priority);
return *this;
}
constexpr OamBuilder& WithPalette16(int palette)
{
_attr0 &= ~GFX_OAM_ATTR0_PLTT256;
_attr2 &= ~GFX_OAM_ATTR2_PLTT(0xF);
_attr2 |= GFX_OAM_ATTR2_PLTT(palette);
return *this;
}
constexpr OamBuilder& WithPalette256(int palette = 0)
{
_attr0 |= GFX_OAM_ATTR0_PLTT256;
_attr2 &= ~GFX_OAM_ATTR2_PLTT(0xF);
_attr2 |= GFX_OAM_ATTR2_PLTT(palette);
return *this;
}
constexpr void Build(gfx_oam_entry_t& oamEntry) const
{
oamEntry.attr0 = _attr0;
oamEntry.attr1 = _attr1;
oamEntry.attr2 = _attr2;
}
};