mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-07-31 15:17:20 -05:00
468 lines
13 KiB
C
468 lines
13 KiB
C
#include "software_sprite.h"
|
|
|
|
#include <nitro/gx/g3imm.h>
|
|
#include <nnsys/g2d/g2d_Image.h>
|
|
#include <nnsys/g2d/g2d_Softsprite.h>
|
|
#include <nnsys/gfd/VramManager/gfd_PlttVramMan_Types.h>
|
|
#include <nnsys/gfd/VramManager/gfd_TexVramMan_Types.h>
|
|
|
|
#include "constants/colors.h"
|
|
#include "constants/graphics.h"
|
|
#include "constants/heap.h"
|
|
|
|
#include "heap.h"
|
|
|
|
struct SoftwareSpriteChars {
|
|
NNSGfdTexKey vramKey;
|
|
NNSG2dImageProxy proxy;
|
|
};
|
|
|
|
struct SoftwareSpritePalette {
|
|
NNSGfdPlttKey vramKey;
|
|
NNSG2dImagePaletteProxy proxy;
|
|
};
|
|
|
|
struct SoftwareSprite {
|
|
NNSG2dSVec2 position;
|
|
NNSG2dSVec2 center;
|
|
NNSG2dSVec2 dimensions;
|
|
fx32 scaleX;
|
|
fx32 scaleY;
|
|
int priority;
|
|
int rotation;
|
|
BOOL inUse;
|
|
BOOL visible;
|
|
NNSG2dImageAttr *attributes;
|
|
u32 vramAddressChars;
|
|
u32 vramAddressPalette;
|
|
u32 paletteSlot;
|
|
BOOL flipH;
|
|
BOOL flipV;
|
|
GXRgb diffuse;
|
|
u8 alpha;
|
|
};
|
|
|
|
struct SoftwareSpriteManager {
|
|
SoftwareSprite *sprites;
|
|
int numSprites;
|
|
SoftwareSpriteChars *chars;
|
|
int numChars;
|
|
SoftwareSpritePalette *palettes;
|
|
int numPalettes;
|
|
};
|
|
|
|
static SoftwareSprite *NewSprites(int count, enum HeapID heapID);
|
|
static SoftwareSpriteChars *NewSpriteChars(int count, enum HeapID heapID);
|
|
static SoftwareSpritePalette *NewSpritePalettes(int count, enum HeapID heapID);
|
|
|
|
static void ZeroSprite(SoftwareSprite *sprite);
|
|
static void ZeroChars(SoftwareSpriteChars *chars);
|
|
static void ZeroPalette(SoftwareSpritePalette *palette);
|
|
|
|
static SoftwareSprite *FindAvailableSprite(SoftwareSpriteManager *softSpriteMan);
|
|
static SoftwareSpriteChars *FindAvailableChars(SoftwareSpriteManager *softSpriteMan);
|
|
static SoftwareSpritePalette *FindAvailablePalette(SoftwareSpriteManager *softSpriteMan);
|
|
|
|
static NNSGfdTexKey AllocateVRAM_Chars(NNSG2dCharacterData *charsData);
|
|
static NNSGfdPlttKey AllocateVRAM_Palette(int paletteSlot);
|
|
static void LoadProxy_Chars(NNSG2dCharacterData *charsData, NNSGfdTexKey vramKey, NNSG2dImageProxy *proxy);
|
|
static void LoadProxy_Palette(NNSG2dPaletteData *paletteData, NNSGfdPlttKey vramKey, NNSG2dImagePaletteProxy *proxy);
|
|
|
|
static void DrawSprite(SoftwareSprite *sprite);
|
|
static void LoadSprite(SoftwareSprite *sprite, const SoftwareSpriteTemplate *template);
|
|
|
|
SoftwareSpriteManager *SoftwareSpriteManager_New(const SoftwareSpriteManagerTemplate *template)
|
|
{
|
|
SoftwareSpriteManager *softSpriteMan = Heap_Alloc(template->heapID, sizeof(SoftwareSpriteManager));
|
|
GF_ASSERT(softSpriteMan);
|
|
|
|
softSpriteMan->sprites = NewSprites(template->numSprites, template->heapID);
|
|
softSpriteMan->numSprites = template->numSprites;
|
|
softSpriteMan->chars = NewSpriteChars(template->numChars, template->heapID);
|
|
softSpriteMan->numChars = template->numChars;
|
|
softSpriteMan->palettes = NewSpritePalettes(template->numPalettes, template->heapID);
|
|
softSpriteMan->numPalettes = template->numPalettes;
|
|
|
|
return softSpriteMan;
|
|
}
|
|
|
|
void SoftwareSpriteManager_Free(SoftwareSpriteManager *softSpriteMan)
|
|
{
|
|
GF_ASSERT(softSpriteMan);
|
|
GF_ASSERT(softSpriteMan->sprites);
|
|
GF_ASSERT(softSpriteMan->chars);
|
|
GF_ASSERT(softSpriteMan->palettes);
|
|
|
|
Heap_Free(softSpriteMan->sprites);
|
|
Heap_Free(softSpriteMan->chars);
|
|
Heap_Free(softSpriteMan->palettes);
|
|
Heap_Free(softSpriteMan);
|
|
|
|
softSpriteMan = NULL;
|
|
}
|
|
|
|
void SoftwareSpriteManager_DrawVisible(SoftwareSpriteManager *manager)
|
|
{
|
|
G3_PushMtx();
|
|
|
|
for (int i = 0; i < manager->numSprites; i++) {
|
|
if (manager->sprites[i].visible) {
|
|
DrawSprite(manager->sprites + i);
|
|
}
|
|
}
|
|
|
|
G3_PopMtx(1);
|
|
}
|
|
|
|
SoftwareSpriteChars *SoftwareSprite_LoadChars(const SoftwareSpriteCharsTemplate *template)
|
|
{
|
|
SoftwareSpriteChars *chars = FindAvailableChars(template->softSpriteMan);
|
|
GF_ASSERT(chars);
|
|
GF_ASSERT(template->charsData->mapingType == GX_OBJVRAMMODE_CHAR_2D);
|
|
|
|
chars->vramKey = AllocateVRAM_Chars(template->charsData);
|
|
GF_ASSERT(chars->vramKey);
|
|
|
|
LoadProxy_Chars(template->charsData, chars->vramKey, &chars->proxy);
|
|
return chars;
|
|
}
|
|
|
|
void SoftwareSprite_FreeChars(SoftwareSpriteChars *chars)
|
|
{
|
|
NNS_GfdFreeTexVram(chars->vramKey);
|
|
ZeroChars(chars);
|
|
}
|
|
|
|
void SoftwareSpriteManager_FreeAllChars(SoftwareSpriteManager *softSpriteMan)
|
|
{
|
|
for (int i = 0; i < softSpriteMan->numChars; i++) {
|
|
if (softSpriteMan->chars[i].vramKey) {
|
|
SoftwareSprite_FreeChars(softSpriteMan->chars + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
SoftwareSpritePalette *SoftwareSprite_LoadPalette(const SoftwareSpritePaletteTemplate *template)
|
|
{
|
|
SoftwareSpritePalette *palette = FindAvailablePalette(template->softSpriteMan);
|
|
GF_ASSERT(palette);
|
|
|
|
palette->vramKey = AllocateVRAM_Palette(template->paletteSlot);
|
|
GF_ASSERT(palette->vramKey);
|
|
|
|
LoadProxy_Palette(template->paletteData, palette->vramKey, &palette->proxy);
|
|
return palette;
|
|
}
|
|
|
|
void SoftwareSprite_FreePalette(SoftwareSpritePalette *palette)
|
|
{
|
|
NNS_GfdFreePlttVram(palette->vramKey);
|
|
ZeroPalette(palette);
|
|
}
|
|
|
|
void SoftwareSpriteManager_FreeAllPalettes(SoftwareSpriteManager *softSpriteMan)
|
|
{
|
|
for (int i = 0; i < softSpriteMan->numPalettes; i++) {
|
|
if (softSpriteMan->palettes[i].vramKey) {
|
|
SoftwareSprite_FreePalette(softSpriteMan->palettes + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
SoftwareSprite *SoftwareSprite_Load(const SoftwareSpriteTemplate *template)
|
|
{
|
|
SoftwareSprite *sprite = FindAvailableSprite(template->softSpriteMan);
|
|
GF_ASSERT(sprite);
|
|
|
|
LoadSprite(sprite, template);
|
|
sprite->inUse = TRUE;
|
|
sprite->visible = TRUE;
|
|
return sprite;
|
|
}
|
|
|
|
void SoftwareSprite_Reset(SoftwareSprite *sprite)
|
|
{
|
|
ZeroSprite(sprite);
|
|
}
|
|
|
|
void SoftwareSprite_SetVisible(SoftwareSprite *sprite, BOOL visible)
|
|
{
|
|
GF_ASSERT(sprite);
|
|
sprite->visible = visible;
|
|
}
|
|
|
|
void SoftwareSprite_SetPosition(SoftwareSprite *sprite, s16 x, s16 y)
|
|
{
|
|
sprite->position.x = x;
|
|
sprite->position.y = y;
|
|
}
|
|
|
|
NNSG2dSVec2 SoftwareSprite_GetPosition(SoftwareSprite *sprite)
|
|
{
|
|
return sprite->position;
|
|
}
|
|
|
|
void SoftwareSprite_SetCenter(SoftwareSprite *sprite, s16 x, s16 y)
|
|
{
|
|
sprite->center.x = x;
|
|
sprite->center.y = y;
|
|
}
|
|
|
|
void SoftwareSprite_SetScalingFactors(SoftwareSprite *sprite, fx32 scaleX, fx32 scaleY)
|
|
{
|
|
sprite->scaleX = scaleX;
|
|
sprite->scaleY = scaleY;
|
|
}
|
|
|
|
void SoftwareSprite_SetDimensions(SoftwareSprite *sprite, int x, int y)
|
|
{
|
|
sprite->dimensions.x = x;
|
|
sprite->dimensions.y = y;
|
|
}
|
|
|
|
NNSG2dSVec2 SoftwareSprite_GetDimensions(SoftwareSprite *sprite)
|
|
{
|
|
return sprite->dimensions;
|
|
}
|
|
|
|
void SoftwareSprite_SetPriority(SoftwareSprite *sprite, int priority)
|
|
{
|
|
sprite->priority = priority;
|
|
}
|
|
|
|
int SoftwareSprite_GetPriority(SoftwareSprite *sprite)
|
|
{
|
|
return sprite->priority;
|
|
}
|
|
|
|
void SoftwareSprite_SetAlpha(SoftwareSprite *sprite, u8 alpha)
|
|
{
|
|
sprite->alpha = alpha;
|
|
}
|
|
|
|
void SoftwareSprite_SetDiffuse(SoftwareSprite *sprite, GXRgb diffuse)
|
|
{
|
|
sprite->diffuse = diffuse;
|
|
}
|
|
|
|
void SoftwareSprite_SetAttributes(SoftwareSprite *sprite, NNSG2dImageAttr *attributes)
|
|
{
|
|
sprite->attributes = attributes;
|
|
}
|
|
|
|
void SoftwareSprite_SetVRAMAddress_Chars(SoftwareSprite *sprite, u32 address)
|
|
{
|
|
sprite->vramAddressChars = address;
|
|
}
|
|
|
|
void SoftwareSprite_SetVRAMAddress_Palette(SoftwareSprite *sprite, u32 address)
|
|
{
|
|
sprite->vramAddressPalette = address;
|
|
}
|
|
|
|
void SoftwareSprite_SetPaletteSlot(SoftwareSprite *sprite, u32 offset)
|
|
{
|
|
sprite->paletteSlot = offset;
|
|
}
|
|
|
|
void SoftwareSprite_SetFlip(SoftwareSprite *sprite, int direction, BOOL flip)
|
|
{
|
|
if (direction == SPRITE_FLIP_H) {
|
|
sprite->flipH = flip;
|
|
} else {
|
|
sprite->flipV = flip;
|
|
}
|
|
}
|
|
|
|
void SoftwareSprite_SetRotation(SoftwareSprite *sprite, u16 rotation)
|
|
{
|
|
sprite->rotation = rotation;
|
|
}
|
|
|
|
static void ZeroSprite(SoftwareSprite *sprite)
|
|
{
|
|
memset(sprite, 0, sizeof(SoftwareSprite));
|
|
sprite->alpha = 31;
|
|
sprite->diffuse = COLOR_WHITE;
|
|
}
|
|
|
|
static void ZeroChars(SoftwareSpriteChars *chars)
|
|
{
|
|
chars->vramKey = 0;
|
|
NNS_G2dInitImageProxy(&chars->proxy);
|
|
}
|
|
|
|
static void ZeroPalette(SoftwareSpritePalette *palette)
|
|
{
|
|
palette->vramKey = 0;
|
|
NNS_G2dInitImagePaletteProxy(&palette->proxy);
|
|
}
|
|
|
|
static SoftwareSprite *NewSprites(int count, enum HeapID heapID)
|
|
{
|
|
SoftwareSprite *sprites = Heap_Alloc(heapID, sizeof(SoftwareSprite) * count);
|
|
GF_ASSERT(sprites);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
ZeroSprite(sprites + i);
|
|
}
|
|
|
|
return sprites;
|
|
}
|
|
|
|
static SoftwareSpriteChars *NewSpriteChars(int count, enum HeapID heapID)
|
|
{
|
|
SoftwareSpriteChars *chars = Heap_Alloc(heapID, sizeof(SoftwareSpriteChars) * count);
|
|
GF_ASSERT(chars);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
ZeroChars(chars + i);
|
|
}
|
|
|
|
return chars;
|
|
}
|
|
|
|
static SoftwareSpritePalette *NewSpritePalettes(int count, enum HeapID heapID)
|
|
{
|
|
SoftwareSpritePalette *palettes = Heap_Alloc(heapID, sizeof(SoftwareSpritePalette) * count);
|
|
GF_ASSERT(palettes);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
ZeroPalette(palettes + i);
|
|
}
|
|
|
|
return palettes;
|
|
}
|
|
|
|
static SoftwareSprite *FindAvailableSprite(SoftwareSpriteManager *softSpriteMan)
|
|
{
|
|
for (int i = 0; i < softSpriteMan->numSprites; i++) {
|
|
if (softSpriteMan->sprites[i].inUse == FALSE) {
|
|
return softSpriteMan->sprites + i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static SoftwareSpriteChars *FindAvailableChars(SoftwareSpriteManager *softSpriteMan)
|
|
{
|
|
for (int i = 0; i < softSpriteMan->numSprites; i++) {
|
|
if (softSpriteMan->chars[i].vramKey == 0) {
|
|
return softSpriteMan->chars + i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static SoftwareSpritePalette *FindAvailablePalette(SoftwareSpriteManager *softSpriteMan)
|
|
{
|
|
for (int i = 0; i < softSpriteMan->numSprites; i++) {
|
|
if (softSpriteMan->palettes[i].vramKey == 0) {
|
|
return softSpriteMan->palettes + i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static NNSGfdTexKey AllocateVRAM_Chars(NNSG2dCharacterData *charsData)
|
|
{
|
|
return NNS_GfdAllocTexVram(charsData->szByte, FALSE, 0);
|
|
}
|
|
|
|
static NNSGfdPlttKey AllocateVRAM_Palette(int paletteSlot)
|
|
{
|
|
return NNS_GfdAllocPlttVram(PLTT_OFFSET(paletteSlot), FALSE, 0);
|
|
}
|
|
|
|
static void LoadProxy_Chars(NNSG2dCharacterData *charsData, NNSGfdTexKey vramKey, NNSG2dImageProxy *proxy)
|
|
{
|
|
NNS_G2dLoadImage2DMapping(charsData, NNS_GfdGetTexKeyAddr(vramKey), NNS_G2D_VRAM_TYPE_3DMAIN, proxy);
|
|
}
|
|
|
|
static void LoadProxy_Palette(NNSG2dPaletteData *paletteData, NNSGfdPlttKey vramKey, NNSG2dImagePaletteProxy *proxy)
|
|
{
|
|
int size = paletteData->szByte;
|
|
paletteData->szByte = NNS_GfdGetPlttKeySize(vramKey);
|
|
|
|
NNS_G2dLoadPalette(paletteData, NNS_GfdGetPlttKeyAddr(vramKey), NNS_G2D_VRAM_TYPE_3DMAIN, proxy);
|
|
paletteData->szByte = size;
|
|
}
|
|
|
|
static void DrawSprite(SoftwareSprite *sprite)
|
|
{
|
|
G3_PushMtx();
|
|
G3_MaterialColorDiffAmb(sprite->diffuse, COLOR_WHITE, TRUE);
|
|
G3_MaterialColorSpecEmi(COLOR_GRAY, COLOR_BLACK, FALSE);
|
|
G3_TexImageParam(
|
|
sprite->attributes->fmt,
|
|
GX_TEXGEN_TEXCOORD,
|
|
sprite->attributes->sizeS,
|
|
sprite->attributes->sizeT,
|
|
GX_TEXREPEAT_NONE,
|
|
GX_TEXFLIP_NONE,
|
|
sprite->attributes->plttUse,
|
|
sprite->vramAddressChars);
|
|
G3_TexPlttBase(sprite->vramAddressPalette + PLTT_OFFSET(sprite->paletteSlot), sprite->attributes->fmt);
|
|
G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, sprite->alpha, 0);
|
|
|
|
NNSG2dSVec2 uv0, uv1;
|
|
if (sprite->flipH) {
|
|
uv0.x = sprite->dimensions.x;
|
|
uv1.x = 0;
|
|
} else {
|
|
uv1.x = sprite->dimensions.x;
|
|
uv0.x = 0;
|
|
}
|
|
|
|
if (sprite->flipV) {
|
|
uv0.y = sprite->dimensions.y;
|
|
uv1.y = 0;
|
|
} else {
|
|
uv1.y = sprite->dimensions.y;
|
|
uv0.y = 0;
|
|
}
|
|
|
|
G3_Translate(
|
|
(sprite->position.x + sprite->center.x) * FX32_ONE,
|
|
(sprite->position.y + sprite->center.y) * FX32_ONE,
|
|
sprite->priority * FX32_ONE);
|
|
G3_RotZ(FX_SinIdx(sprite->rotation), FX_CosIdx(sprite->rotation));
|
|
G3_Scale(sprite->scaleX, sprite->scaleY, FX32_ONE);
|
|
G3_Translate(-sprite->center.x * FX32_ONE, -sprite->center.y * FX32_ONE, 0);
|
|
NNS_G2dDrawSpriteFast(0, 0, 0, sprite->dimensions.x, sprite->dimensions.y, uv0.x, uv0.y, uv1.x, uv1.y);
|
|
G3_PopMtx(1);
|
|
}
|
|
|
|
static void LoadSprite(SoftwareSprite *sprite, const SoftwareSpriteTemplate *template)
|
|
{
|
|
int dimenX = 8;
|
|
for (int i = 0; i < template->chars->proxy.attr.sizeS; i++) {
|
|
dimenX *= 2;
|
|
}
|
|
|
|
int dimenY = 8;
|
|
for (int i = 0; i < template->chars->proxy.attr.sizeT; i++) {
|
|
dimenY *= 2;
|
|
}
|
|
|
|
SoftwareSprite_SetPosition(sprite, template->xPos, template->yPos);
|
|
SoftwareSprite_SetCenter(sprite, dimenX / 2, dimenY / 2);
|
|
|
|
sprite->scaleX = FX32_ONE;
|
|
sprite->scaleY = FX32_ONE;
|
|
|
|
SoftwareSprite_SetDimensions(sprite, dimenX, dimenY);
|
|
SoftwareSprite_SetPriority(sprite, template->priority);
|
|
SoftwareSprite_SetAlpha(sprite, template->alpha);
|
|
SoftwareSprite_SetAttributes(sprite, &template->chars->proxy.attr);
|
|
SoftwareSprite_SetVRAMAddress_Chars(sprite, NNS_G2dGetImageLocation(&template->chars->proxy, NNS_G2D_VRAM_TYPE_3DMAIN));
|
|
SoftwareSprite_SetVRAMAddress_Palette(sprite, NNS_G2dGetImagePaletteLocation(&template->palette->proxy, NNS_G2D_VRAM_TYPE_3DMAIN));
|
|
SoftwareSprite_SetPaletteSlot(sprite, template->paletteSlot);
|
|
SoftwareSprite_SetFlip(sprite, SPRITE_FLIP_H, FALSE);
|
|
SoftwareSprite_SetFlip(sprite, SPRITE_FLIP_V, FALSE);
|
|
SoftwareSprite_SetRotation(sprite, template->rotation);
|
|
}
|