Palettes
Posted: Sat Jul 04, 2009 6:30 pm
Hi,
I am very new to programming on the DS, although I would classify my C++ knowledge as decent.
I have been working off of Patater's tutorial and found it very instructive. But when I try to put my own sprites in and display more than one of each, I begin to encounter problems with the palettes. I've got a gameboard made up of an array of columns, with each column's constructor displaying several of my square sprite. Then I have a set of pieces, with the constructor displaying several piece sprites. (Simplifying to one of each appears to make no difference in my problems). I've moved the initialization and display into these objects, and had to attempt to extrapolate what I should be doing for multiple sprites, with moderate success.
I am having two problems, both palette related, the first the more bothersome:
1) If I display only the board or only the pieces, everything is fine. But if I try to do both, the pieces (the second to initialize) come up strangely. I keep trying different things and I get different weird problems, but never quite right. Most recently, the first piece looks great but the rest all use the square's palette.
2) I've been having trouble trying to use multiple palettes, and although I just got it working, I'm not quite sure why. I figured with 16 palettes in 256 colours, I could just set up each palette to use 16 colours. The usenti program encourages this belief with the ability to choose which row of 16 colours it's displaying with. But if I have a transparent on each line, my results seem to be that it's being ignored. I would have thought with my palette set up as such:
Black, transparent, red, junk x 13
Black, transparent, green, junk x 13
Then I could just add 16 to get to the second palette. But they seem to be capped at 16, as after that point it isn't following my palette at all. OK, so maybe:
Black, transparent, red, black, transparent, green
and add 3.
But here's what's working:
Black, transparent, red, black, green
and adding 2. This pattern continues; if I keep alternating black and another colour then my 3-colour palette replaces the black with black and the red with the other colour, and I just add 4, 6, etc. It's ignoring the transparent altogether. So... what's up with that?
I suspect you'll want to see some code. Well, I suspect you want it all, but for now I'm going to try to avoid that because I'm not sure if I can attach it, and it'll look ugly in text since it's spread across many files. Maybe somebody will know immediately with only what I suspect are the pertinent lines:
Stuff in main:
Column * colArray[boardSize];
int main() {
powerOn(POWER_ALL_2D);
lcdMainOnBottom();
initVideo();
initBackgrounds();
displayBackgrounds();
// Set up a few sprites.
OAMTable *oam = new OAMTable();
initOAM(oam);
int numSprites = 0;
int nextID = 0;
for (int col = 0; col < boardSize + 2; col++)
{
colArray[col] = new Column(oam,numSprites,nextID);
numSprites += boardSize;
nextID = (*colArray[col]).getNextID();
for (int row = 0; row < boardSize; row++)
{
colArray[col]->squareInfo[row]->entry->x = startX + col * squareSize;
}
}
ObjPiece *p = new ObjPiece(oam, numSprites,nextID);
touchPosition touch;
for (;;) {
updateInput(&touch);
handleInput(&touch);
swiWaitForVBlank();
updateOAM(oam);
}
return 0;
}
In obj_piece:
ObjPiece::ObjPiece(OAMTable * oam, int c, int nextID) {
SpriteInfo spriteInfo[boardSize * 2];
int nextAvailableTileIdx = nextID;
// Construct the pieces
for (int player = 0; player < 2; player++)
{
for (int i = 0; i < boardSize; i++)
{
pieceInfo[player] = &spriteInfo[player*boardSize+i];
SpriteEntry * pieceEntry = &oam->oamBuffer[c+player*boardSize+i];
pieceInfo[player]->oamId = c+player*boardSize+i;
pieceInfo[player]->width = 32;
pieceInfo[player]->height = 32;
pieceInfo[player]->angle = 0;
pieceInfo[player]->entry = pieceEntry;
pieceEntry->isRotateScale = true;
pieceEntry->isSizeDouble = false;
pieceEntry->blendMode = OBJMODE_NORMAL;
pieceEntry->isMosaic = false;
pieceEntry->colorMode = OBJCOLOR_16;
pieceEntry->shape = OBJSHAPE_SQUARE;
pieceEntry->x = startX + player * (squareSize * (boardSize + 1));
pieceEntry->y = startY + (i-1) * squareSize;
pieceEntry->rotationIndex = pieceInfo[player]->oamId;
pieceEntry->size = OBJSIZE_32;
pieceEntry->gfxIndex = nextAvailableTileIdx;
nextAvailableTileIdx += pieceTilesLen / BYTES_PER_16_COLOR_TILE;
pieceEntry->priority = OBJPRIORITY_1;
pieceEntry->palette = pieceInfo[player]->oamId;
}
}
drawPieces(oam);
next_id = nextAvailableTileIdx;
}
int ObjPiece::getNextID()
{
return next_id;
}
void ObjPiece::drawPieces(OAMTable * oam) {
for (int player = 0; player < 2; player++)
{
for (int i = 0; i < boardSize; i++)
{
rotateSprite(&oam->matrixBuffer[pieceInfo[player]->oamId],
pieceInfo[player]->angle);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, piecePal+2,&SPRITE_PALETTE[
pieceInfo[player][i]->oamId * COLORS_PER_PALETTE], piecePalLen);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, pieceTiles, &SPRITE_GFX[(pieceInfo[
player][i]->entry->gfxIndex) * OFFSET_MULTIPLIER], pieceTilesLen);
SpriteEntry * e = pieceInfo[player][i]->entry;
}
}
}
And column:
Column::Column(OAMTable * oam, int c, int nextID) {
SpriteInfo spriteInfo[boardSize];
int nextAvailableTileIdx = nextID;
// Construct the row of squares
for (int i = 0; i < boardSize; i++)
{
squareInfo[i] = &spriteInfo[i];//c+i];
SpriteEntry * squareEntry = &oam->oamBuffer[c+i];
squareInfo[i]->oamId = c+i;
squareInfo[i]->width = 32;
squareInfo[i]->height = 32;
squareInfo[i]->angle = 0;
squareInfo[i]->entry = squareEntry;
squareEntry->isRotateScale = false;
squareEntry->isSizeDouble = false;
squareEntry->blendMode = OBJMODE_NORMAL;
squareEntry->isMosaic = false;
squareEntry->colorMode = OBJCOLOR_16;
squareEntry->shape = OBJSHAPE_SQUARE;
squareEntry->y = startY + i * squareSize;
squareEntry->rotationIndex = squareInfo[i]->oamId;
squareEntry->size = OBJSIZE_32;
squareEntry->gfxIndex = nextAvailableTileIdx;
nextAvailableTileIdx += squareTilesLen / BYTES_PER_16_COLOR_TILE;
squareEntry->priority = OBJPRIORITY_2;
squareEntry->palette = squareInfo[i]->oamId;
}
drawBoard(oam);
next_id = nextAvailableTileIdx;
}
int Column::getNextID()
{
return next_id;
}
void Column::drawBoard(OAMTable * oam)
{
for (int i = 0; i < boardSize; i++) {
rotateSprite(&oam->matrixBuffer[squareInfo[i]->oamId],
squareInfo[i]->angle);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, &squarePal[0], &SPRITE_PALETTE[
squareInfo[i]->oamId * COLORS_PER_PALETTE], squarePalLen);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, squareTiles, &SPRITE_GFX[
squareInfo[i]->entry->gfxIndex * OFFSET_MULTIPLIER], squareTilesLen);
}
}
Column has a public array (yeah, I know it shouldn't be public):
SpriteInfo * squareInfo[boardSize];
And Piece has this (although protected, here):
SpriteInfo * pieceInfo[2][boardSize];
Oh, and the constants:
const int squareSprite = 32;
const int spaceBetween = -1;
const int squareSize = squareSprite + spaceBetween;
const int boardSize = 3;
const int numRows = boardSize;
const int numCols = boardSize + 2;
const int startX = (256 - squareSprite * numCols - spaceBetween * (numCols - 1)) / 2;
const int startY = (192 - squareSprite * numRows - spaceBetween * (numRows - 1)) / 2;
static const int COLORS_PER_PALETTE = 16;
static const int BOUNDARY_VALUE = 32; // This is the default boundary value
// (can be set in REG_DISPCNT)
static const int OFFSET_MULTIPLIER = BOUNDARY_VALUE / sizeof(SPRITE_GFX[0]);
static const int BYTES_PER_16_COLOR_TILE = 16;
Thanks for any help you can give me, even if it's just to direct me elsewhere. As I said, I'm pretty new to this community. Thanks!
I am very new to programming on the DS, although I would classify my C++ knowledge as decent.
I have been working off of Patater's tutorial and found it very instructive. But when I try to put my own sprites in and display more than one of each, I begin to encounter problems with the palettes. I've got a gameboard made up of an array of columns, with each column's constructor displaying several of my square sprite. Then I have a set of pieces, with the constructor displaying several piece sprites. (Simplifying to one of each appears to make no difference in my problems). I've moved the initialization and display into these objects, and had to attempt to extrapolate what I should be doing for multiple sprites, with moderate success.
I am having two problems, both palette related, the first the more bothersome:
1) If I display only the board or only the pieces, everything is fine. But if I try to do both, the pieces (the second to initialize) come up strangely. I keep trying different things and I get different weird problems, but never quite right. Most recently, the first piece looks great but the rest all use the square's palette.
2) I've been having trouble trying to use multiple palettes, and although I just got it working, I'm not quite sure why. I figured with 16 palettes in 256 colours, I could just set up each palette to use 16 colours. The usenti program encourages this belief with the ability to choose which row of 16 colours it's displaying with. But if I have a transparent on each line, my results seem to be that it's being ignored. I would have thought with my palette set up as such:
Black, transparent, red, junk x 13
Black, transparent, green, junk x 13
Then I could just add 16 to get to the second palette. But they seem to be capped at 16, as after that point it isn't following my palette at all. OK, so maybe:
Black, transparent, red, black, transparent, green
and add 3.
But here's what's working:
Black, transparent, red, black, green
and adding 2. This pattern continues; if I keep alternating black and another colour then my 3-colour palette replaces the black with black and the red with the other colour, and I just add 4, 6, etc. It's ignoring the transparent altogether. So... what's up with that?
I suspect you'll want to see some code. Well, I suspect you want it all, but for now I'm going to try to avoid that because I'm not sure if I can attach it, and it'll look ugly in text since it's spread across many files. Maybe somebody will know immediately with only what I suspect are the pertinent lines:
Stuff in main:
Column * colArray[boardSize];
int main() {
powerOn(POWER_ALL_2D);
lcdMainOnBottom();
initVideo();
initBackgrounds();
displayBackgrounds();
// Set up a few sprites.
OAMTable *oam = new OAMTable();
initOAM(oam);
int numSprites = 0;
int nextID = 0;
for (int col = 0; col < boardSize + 2; col++)
{
colArray[col] = new Column(oam,numSprites,nextID);
numSprites += boardSize;
nextID = (*colArray[col]).getNextID();
for (int row = 0; row < boardSize; row++)
{
colArray[col]->squareInfo[row]->entry->x = startX + col * squareSize;
}
}
ObjPiece *p = new ObjPiece(oam, numSprites,nextID);
touchPosition touch;
for (;;) {
updateInput(&touch);
handleInput(&touch);
swiWaitForVBlank();
updateOAM(oam);
}
return 0;
}
In obj_piece:
ObjPiece::ObjPiece(OAMTable * oam, int c, int nextID) {
SpriteInfo spriteInfo[boardSize * 2];
int nextAvailableTileIdx = nextID;
// Construct the pieces
for (int player = 0; player < 2; player++)
{
for (int i = 0; i < boardSize; i++)
{
pieceInfo[player] = &spriteInfo[player*boardSize+i];
SpriteEntry * pieceEntry = &oam->oamBuffer[c+player*boardSize+i];
pieceInfo[player]->oamId = c+player*boardSize+i;
pieceInfo[player]->width = 32;
pieceInfo[player]->height = 32;
pieceInfo[player]->angle = 0;
pieceInfo[player]->entry = pieceEntry;
pieceEntry->isRotateScale = true;
pieceEntry->isSizeDouble = false;
pieceEntry->blendMode = OBJMODE_NORMAL;
pieceEntry->isMosaic = false;
pieceEntry->colorMode = OBJCOLOR_16;
pieceEntry->shape = OBJSHAPE_SQUARE;
pieceEntry->x = startX + player * (squareSize * (boardSize + 1));
pieceEntry->y = startY + (i-1) * squareSize;
pieceEntry->rotationIndex = pieceInfo[player]->oamId;
pieceEntry->size = OBJSIZE_32;
pieceEntry->gfxIndex = nextAvailableTileIdx;
nextAvailableTileIdx += pieceTilesLen / BYTES_PER_16_COLOR_TILE;
pieceEntry->priority = OBJPRIORITY_1;
pieceEntry->palette = pieceInfo[player]->oamId;
}
}
drawPieces(oam);
next_id = nextAvailableTileIdx;
}
int ObjPiece::getNextID()
{
return next_id;
}
void ObjPiece::drawPieces(OAMTable * oam) {
for (int player = 0; player < 2; player++)
{
for (int i = 0; i < boardSize; i++)
{
rotateSprite(&oam->matrixBuffer[pieceInfo[player]->oamId],
pieceInfo[player]->angle);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, piecePal+2,&SPRITE_PALETTE[
pieceInfo[player][i]->oamId * COLORS_PER_PALETTE], piecePalLen);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, pieceTiles, &SPRITE_GFX[(pieceInfo[
player][i]->entry->gfxIndex) * OFFSET_MULTIPLIER], pieceTilesLen);
SpriteEntry * e = pieceInfo[player][i]->entry;
}
}
}
And column:
Column::Column(OAMTable * oam, int c, int nextID) {
SpriteInfo spriteInfo[boardSize];
int nextAvailableTileIdx = nextID;
// Construct the row of squares
for (int i = 0; i < boardSize; i++)
{
squareInfo[i] = &spriteInfo[i];//c+i];
SpriteEntry * squareEntry = &oam->oamBuffer[c+i];
squareInfo[i]->oamId = c+i;
squareInfo[i]->width = 32;
squareInfo[i]->height = 32;
squareInfo[i]->angle = 0;
squareInfo[i]->entry = squareEntry;
squareEntry->isRotateScale = false;
squareEntry->isSizeDouble = false;
squareEntry->blendMode = OBJMODE_NORMAL;
squareEntry->isMosaic = false;
squareEntry->colorMode = OBJCOLOR_16;
squareEntry->shape = OBJSHAPE_SQUARE;
squareEntry->y = startY + i * squareSize;
squareEntry->rotationIndex = squareInfo[i]->oamId;
squareEntry->size = OBJSIZE_32;
squareEntry->gfxIndex = nextAvailableTileIdx;
nextAvailableTileIdx += squareTilesLen / BYTES_PER_16_COLOR_TILE;
squareEntry->priority = OBJPRIORITY_2;
squareEntry->palette = squareInfo[i]->oamId;
}
drawBoard(oam);
next_id = nextAvailableTileIdx;
}
int Column::getNextID()
{
return next_id;
}
void Column::drawBoard(OAMTable * oam)
{
for (int i = 0; i < boardSize; i++) {
rotateSprite(&oam->matrixBuffer[squareInfo[i]->oamId],
squareInfo[i]->angle);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, &squarePal[0], &SPRITE_PALETTE[
squareInfo[i]->oamId * COLORS_PER_PALETTE], squarePalLen);
dmaCopyHalfWords(SPRITE_DMA_CHANNEL, squareTiles, &SPRITE_GFX[
squareInfo[i]->entry->gfxIndex * OFFSET_MULTIPLIER], squareTilesLen);
}
}
Column has a public array (yeah, I know it shouldn't be public):
SpriteInfo * squareInfo[boardSize];
And Piece has this (although protected, here):
SpriteInfo * pieceInfo[2][boardSize];
Oh, and the constants:
const int squareSprite = 32;
const int spaceBetween = -1;
const int squareSize = squareSprite + spaceBetween;
const int boardSize = 3;
const int numRows = boardSize;
const int numCols = boardSize + 2;
const int startX = (256 - squareSprite * numCols - spaceBetween * (numCols - 1)) / 2;
const int startY = (192 - squareSprite * numRows - spaceBetween * (numRows - 1)) / 2;
static const int COLORS_PER_PALETTE = 16;
static const int BOUNDARY_VALUE = 32; // This is the default boundary value
// (can be set in REG_DISPCNT)
static const int OFFSET_MULTIPLIER = BOUNDARY_VALUE / sizeof(SPRITE_GFX[0]);
static const int BYTES_PER_16_COLOR_TILE = 16;
Thanks for any help you can give me, even if it's just to direct me elsewhere. As I said, I'm pretty new to this community. Thanks!