#include <nds.h>
#include <stdio.h>
#define SPRITE_MAX 128
SpriteSize sizes[] = {
SpriteSize_8x8,
SpriteSize_8x16,
SpriteSize_16x8,
SpriteSize_8x32,
SpriteSize_16x16,
SpriteSize_32x8,
SpriteSize_16x32,
SpriteSize_32x16,
SpriteSize_32x32,
SpriteSize_32x64,
SpriteSize_64x32,
SpriteSize_64x64,
};
typedef struct {
int x,y,z;
int dx, dy;
bool alive;
u16* gfx;
SpriteColorFormat format;
SpriteSize size;
}mySprite;
mySprite sprites[SPRITE_MAX];
u32 spriteMemoryUsage = 0;
u32 oomCount = 0;
u32 allocationCount = 0;
u32 spriteMemSize = 128 * 1024;
bool oom = false;
OamState *oam = &oamMain;
void createSprite(mySprite* s, int x, int y, int z, SpriteSize size, SpriteColorFormat format, int dx, int dy) {
s->alive = true;
s->x = x;
s->y = y;
s->z = z;
s->dx = dx;
s->dy = dy;
s->size = size;
s->format = format;
s->gfx = oamAllocateGfx(oam, size, format);
allocationCount++;
if(s->gfx) {
spriteMemoryUsage += (size & 0xFFF) << 5;
oom = false;
} else {
oom = true;
if(spriteMemoryUsage + ((size & 0xFFF) << 5) < spriteMemSize)
oomCount++;
}
}
void killSprite(mySprite *s) {
s->alive = false;
if(s->gfx) {
oamFreeGfx(oam, s->gfx);
spriteMemoryUsage -= (s->size & 0xFFF) << 5;
}
s->gfx = 0;
}
int zsort(const void* a, const void* b) {
mySprite *first = (mySprite*)a;
mySprite *second = (mySprite*)b;
if(first == second) return 0;
if(!first && second) return -1;
if(first && !second) return 1;
if(!first->alive && second->alive) return -1;
if(first->alive && !second->alive) return 1;
if(!first->alive && !second->alive) return 0;
if(first->z == second->z) return 0;
if(first->z < second->z ) return -1;
if(first->z > second->z) return 1;
return 0;
}
void updateSprites(void) {
int i;
qsort(sprites, SPRITE_MAX, sizeof(mySprite), zsort);
for(i = 0; i < SPRITE_MAX; i++) {
oamSet(oam,
i,
sprites[i].x, sprites[i].y,
0,
0,
sprites[i].size,
sprites[i].format,
sprites[i].gfx,
-1,
false,
!sprites[i].alive,
false,
false,
false);
}
}
void randomSprite(mySprite* s) {
u8 c = rand() % 256;
u16 color = c | (c << 8);
createSprite(s, rand() % 256, rand() % 192, 0, sizes[(rand() % 12)], SpriteColorFormat_256Color, rand() % 4 - 2, rand() % 4 - 2);
if(s->dx == 0 && s->dy == 0) {
s->dx = rand() % 3 + 1;
s->dy = rand() % 3 + 1;
}
if(s->gfx) {
swiCopy(&color, s->gfx, ((s->size & 0xFFF) << 4) | COPY_MODE_FILL);
} else {
s->alive = false;
}
}
void moveSprites(void) {
int i;
for(i = 0; i < SPRITE_MAX; i++) {
sprites[i].x += sprites[i].dx;
sprites[i].y += sprites[i].dy;
if(sprites[i].x >= 256 || sprites[i].x < 0 || sprites[i].y >= 192 || sprites[i].y < 0) {
killSprite(&sprites[i]);
randomSprite(&sprites[i]);
}
}
}
int main(void) {
int i;
int memUsageTemp = 0xFFFFFFFF;
videoSetMode(MODE_0_2D);
videoSetModeSub(MODE_0_2D);
vramSetBankA(VRAM_A_MAIN_SPRITE);
vramSetBankB(VRAM_B_MAIN_SPRITE);
vramSetBankD(VRAM_D_SUB_SPRITE);
consoleDemoInit();
oamInit(oam, SpriteMapping_1D_128, false);
for(i = 0; i < SPRITE_MAX; i++)
randomSprite(&sprites[i]);
for(i = 0; i < 256; i++) {
SPRITE_PALETTE[i] = rand();
SPRITE_PALETTE_SUB[i] = rand();
}
while(1) {
moveSprites();
updateSprites();
swiWaitForVBlank();
oamUpdate(oam);
if(oom) {
memUsageTemp = memUsageTemp > spriteMemoryUsage ? spriteMemoryUsage : memUsageTemp;
}
consoleClear();
printf("Memory usage: %i %i%% \n", spriteMemoryUsage, 100 * spriteMemoryUsage / (spriteMemSize));
printf("Percentage fail: %i%% \n", oomCount * 100 / allocationCount);
printf("Lowest Usage at fail %i %i%% \n", memUsageTemp, 100 * memUsageTemp / (spriteMemSize));
}
return 0;
}