#19239 - Darmstadium - Thu Apr 15, 2004 3:36 am
I'm making this text demo. I drew all ascii character numbers 32-125 for it to use. I load up the bitmap containing the character set, the palette for the bg I put the chars on, and the map data, all with no problems. The problem is that my demo doesn't display the right tiles. It displays seemingly random tiles, ignoring which tiles I specified in the map data. I checked the map data and it is excactly what I expected. I ask you to help me figure out how to make this behave how I want.
In case you're curious, to get the number of the character you want in my set from an ASCII character number, you subtract 32 from the ASCII number and multiply that by two.
Here is my code so far:
Code: |
#include <math.h>
#include "gba.h"
#include "dispcnt.h"
#include "bg.h"
#include "dma.h"
#include "alphabet.pal.c"
#include "alphabet.raw.c"
FIXED angle = 0;
FIXED zoom = 1 << 8;
FIXED SIN[360];
FIXED COS[360];
char RotIndexCounter = 0;
background bg2;
u16 * ascii_to_mine(char * str, u16 len)
{
u16 * mine = new u16[len];
u16 loop;
for (loop = 0; loop < len; loop++)
mine[loop] = (str[loop] - 32) * 2;
return mine;
}
int main()
{
REG_DISPCNT = 1 | OBJ_ENABLE | OBJ_MAP_1D | BG2_ENABLE;
u16 loop;
for(loop = 0; loop < 360; loop++)
{
SIN[loop] = (FIXED)(sin(RADIAN(loop)) * 256);
COS[loop] = (FIXED)(cos(RADIAN(loop)) * 256);
}
REG_BG2CNT = ROTBG_SIZE_128x128 | (0 << CHAR_SHIFT) | (28 << SCREEN_SHIFT) | BG_COLOR_256;
bg2.x_scroll = 120;
bg2.y_scroll = 80;
REG_DM3SAD = (u32)alphabet_Bitmap;
REG_DM3DAD = (u32)CharBaseBlock(0);
REG_DM3CNT = 8192 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_32;
REG_DM3SAD = (u32)alphabet_Palette;
REG_DM3DAD = (u32)BGPaletteMem;
REG_DM3CNT = 128 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_32;
u16 * mapdat = (u16 *)ScreenBaseBlock(28);
for (loop = 0; loop < 256; loop++)
mapdat[loop] = 0;
mapdat[0] = 84;
mapdat[1] = 130;
mapdat[2] = 134;
mapdat[3] = 150;
//mapdat = ascii_to_mine("test", 4);
while (1)
{
RotateBg(&bg2,angle,0,0,zoom);
WaitForVBlank();
}
return 0;
}
|
I realize that I'm being a bit wasteful with the tiles; I really, really don't need 256 colors, but I couldn't find a tutorial that told you how to use 16 color tiles. I'm also probably not going to need a rot bg and also can't find a tut on text bgs, so if anybody knows of a tut that teaches you these things, please let me know. Thanks a lot for your help.
#19240 - niltsair - Thu Apr 15, 2004 4:00 am
Quote: |
u16 * mapdat = (u16 *)ScreenBaseBlock(28);
for (loop = 0; loop < 256; loop++)
mapdat[loop] = 0;
mapdat[0] = 84;
mapdat[1] = 130;
mapdat[2] = 134;
mapdat[3] = 150; |
Since you're using a rotation bg, each entry in the Map data takes 8bits (the tile number). You're using a 16bits pointer, which means it end up writing 2 entries in the map, 0 and the number(84,130,134,150) for each one.
Problem is, the Video memory can only be written with 16/32bits values. So try this :
Code: |
for (loop = 0; loop < (16*16)/2; loop++)
mapdat[loop] = 0;
mapdat[0] = 84 | 130;
mapdat[1] = 134 | 150; |
http://www.gbadev.org/docs.php?section=tutorials for tutorials. I recommand The pern project tutorial
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)
#19245 - tepples - Thu Apr 15, 2004 5:56 am
niltsair wrote: |
Since you're using a rotation bg, each entry in the Map data takes 8bits (the tile number). You're using a 16bits pointer, which means it end up writing 2 entries in the map, 0 and the number(84,130,134,150) for each one.
Problem is, the Video memory can only be written with 16/32bits values. So try this :
Code: | for (loop = 0; loop < (16*16)/2; loop++)
mapdat[loop] = 0;
mapdat[0] = 84 | 130;
mapdat[1] = 134 | 150; |
|
Nit: Shouldn't the right-side of each pair be shifted << 8 like this?
Code: |
for (loop = 0; loop < (16*16)/2; loop++)
mapdat[loop] = 0;
mapdat[0] = 84 | (130 << 8);
mapdat[1] = 134 | (150 << 8); |
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#19251 - LOst? - Thu Apr 15, 2004 9:22 am
tepples wrote: |
niltsair wrote: | Since you're using a rotation bg, each entry in the Map data takes 8bits (the tile number). You're using a 16bits pointer, which means it end up writing 2 entries in the map, 0 and the number(84,130,134,150) for each one.
Problem is, the Video memory can only be written with 16/32bits values. So try this :
Code: | for (loop = 0; loop < (16*16)/2; loop++)
mapdat[loop] = 0;
mapdat[0] = 84 | 130;
mapdat[1] = 134 | 150; |
|
Nit: Shouldn't the right-side of each pair be shifted << 8 like this?
Code: | for (loop = 0; loop < (16*16)/2; loop++)
mapdat[loop] = 0;
mapdat[0] = 84 | (130 << 8);
mapdat[1] = 134 | (150 << 8); |
|
Yes it must be shifted with 8. Else you will OR it in the same byte.
#19256 - niltsair - Thu Apr 15, 2004 2:03 pm
Errr yes, was rather late :P
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)
#19276 - Darmstadium - Thu Apr 15, 2004 9:39 pm
Well, I tried doing it nilsair's way but that didn't really change anything. I'll try to describe my problem better. Two characters appear: what should be char number 68 and a small dot. The character that has number 68 apears at tile 0,0 and the dot that is not one of the character that should be there appears at 3,0. All of the other tiles seem to display the space character. Also, once I tried it niltsair's way, the horizontal flip was set for tile 1,0. Anway, the map data is precisely what it should be, but the tiles it displays are completely wrong. Thanks for helping
#19279 - niltsair - Thu Apr 15, 2004 10:04 pm
Are your Tiles Data and Palette valid? Check inside your emulator to know if they are. If they're not, make sure that your data in #include "alphabet.pal.c" and #include "alphabet.raw.c" are valid.
Const u16 for palette.
Const u8 for Tiles or Const u16 for Tiles or Const u32 for Tiles. (Depends on how they stored the pixels values in it)
This is not the cause of your problem but you shouldn't include .c in another source file that what Header are for.
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)
#19299 - Cearn - Fri Apr 16, 2004 2:57 pm
Darmstadium wrote: |
Well, I tried doing it nilsair's way but that didn't really change anything. I'll try to describe my problem better. Two characters appear: what should be char number 68 and a small dot. The character that has number 68 apears at tile 0,0 and the dot that is not one of the character that should be there appears at 3,0. All of the other tiles seem to display the space character. Also, once I tried it niltsair's way, the horizontal flip was set for tile 1,0. Anway, the map data is precisely what it should be, but the tiles it displays are completely wrong. Thanks for helping |
Uhm, did you check the tile numbers and flags with the VBA map viewer? If so, you may like to know that this information is wrong for rotational backgrounds (it still thinks it's on a text background). Check out the bug report
on the vba sourceproject site for a more complete story and a fixed version.
Also, why are you multiplying the tile-number by 2? Is it because they're 256 color tiles, which take twice the amount of memory that 16 color tiles do? If so, don't. Unlike for sprites, the tile-numbering for backgrounds is always by the tile. See http://forum.gbadev.org/viewtopic.php?t=2891 or here for some details on tile-counting.
In other words, "Jack" would be simply be tiles 42, 65, 67, 75. (Btw, you were planning on cleaning up after that new in ascii_to_mine, right? Just checking.)
niltsair wrote: |
Const u16 for palette.
Const u8 for Tiles or Const u16 for tiles or Const u32 for Tiles. (Depends on how they stored the pixels values in it) |
u8 for Tiles is probably a bad idea since, as you said,
niltsair wrote: |
... the Video memory can only be written with 16/32bits values.
|
which would put use back were we started, right? :P
#19303 - niltsair - Fri Apr 16, 2004 4:10 pm
Quote: |
Quote: | niltsair wrote:
... the Video memory can only be written with 16/32bits values. | which would put use back were we started, right? :P |
It doesn't matter really, as long as you tell the linker to align it on a 32bits bondaries (ALIGN4) and just cast the pointer to whatever you want when transfering the tiles (by dma or inside a loop). The only different would be seing your values listed as : Code: |
const u8 myTiles[] ALIGN4 = { 0x01, 0x02, 0x03, 0x01F, ...}; or
const u16 myTiles[] ALIGN4 = { 0x0102, 0x0301F, ...}; or
const u32 myTiles[] = { 0x01020301F, ...};
REG_DM3SAD = (u32)myTiles;
REG_DM3DAD = (u32)CharBaseBlock(0);
REG_DM3CNT = 8192 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE | MA_32;
|
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)
#19308 - Darmstadium - Fri Apr 16, 2004 9:15 pm
Thanks for your help guys.
Good news = everything works fantasticaly well AND i learned to use 16 color text bgs
Bad news = my ascii_to_mine() function somehow destroys all of my tile data
First:
I've made a lot of changes so here is my new code:
Code: |
#include <math.h>
#include "gba.h"
#include "dispcnt.h"
#include "bg.h"
#include "dma.h"
#include "alphabet.pal.c"
#include "alphabet.raw.c"
background bg2;
u16 strlen(char * str)
{
u16 len = 0;
while (str[len] != '\0')
len++;
return len;
}
//somehow directly destroys my tile data
u16 * ascii_to_mine(const char * str, const u8 len)
{
u16 * mstr = new u16[len];
u16 loop;
for (loop = 0; loop < len; loop++)
mstr[loop] = (u16)(str[loop] - 32);
return mstr;
}
void copy_mstr(const u16 * mstr, const u16 mstr_len, const u16 tile_n)
{
REG_DM3SAD = (u32)mstr;
REG_DM3DAD = (u32)(ScreenBaseBlock(28) + tile_n * 0x20);
REG_DM3CNT = mstr_len | DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_16;
}
int main()
{
REG_DISPCNT = MODE_0 | OBJ_ENABLE | OBJ_MAP_1D | BG2_ENABLE;
REG_BG2CNT = TEXTBG_SIZE_256x256 | (0 << CHAR_SHIFT) | (28 << SCREEN_SHIFT) | BG_COLOR_16;
bg2.x_scroll = 120;
bg2.y_scroll = 80;
REG_DM3SAD = (u32)alphabet_Bitmap;
REG_DM3DAD = (u32)CharBaseBlock(0);
REG_DM3CNT = 8192 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_32;
REG_DM3SAD = (u32)alphabet_Palette;
REG_DM3DAD = (u32)0x05000000;
REG_DM3CNT = 64 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_32;
u16 * mapdat = (u16 *)ScreenBaseBlock(28);
u16 * mstr_test = new u16[4];
mstr_test = ascii_to_mine("Jack", 4);
/////Convert the string "Jack" manually\\\\\
//mstr_test[0] = 42;
//mstr_test[1] = 65;
//mstr_test[2] = 67;
//mstr_test[3] = 75;
copy_mstr(mstr_test, 4, 0);
//main loop not needed at this point
//while (1)
//{
// WaitForVBlank();
//}
return 0;
}
|
Next:
Cearn - how come I shouldn't be using new? What are the alternatives?
Last:
Like I said, ascii_to_mine() is going on a rampage. It's not a problem with the data it returns a pointer to that is copied using the copy_mstr() function, but the actual code in that function somehow does this... I'm stumped. Anybody got any ideas?
Thanks for your help guys
#19309 - sajiimori - Fri Apr 16, 2004 10:02 pm
You do know that with common linkscripts, the GBA resets when main() returns...? You might want to put that while(1) back in.
Your copy_mstr() is weird. Why are you multiplying tile_n by 0x20? Map cells are only 2 bytes long on text BGs -- perhaps you were thinking of character offsets.
You've enabled sprites without moving them off the screen (or doing that double-size deal), so you might get garbage on the top left corner.
Why are you scrolling half a screen to the right and downward? Scroll coordinates represent the top left corner of the screen, not the center.
Don't use 'new' unless you're going to do real memory management. Stick to static arrays until then -- you have memory leaks all over.
#19409 - Cearn - Mon Apr 19, 2004 8:57 am
@ niltsair
OK if you pay attention it doesn't matter, but if you would simply use a copy-loop, you might have problems
Code: |
const u8 map[128]= { ... };
u16 *sb= ScreenBlock(0); // or u8 *sb
for(ii=0; ii<128; ii++)
sb[ii] = map[ii];
|
That would be bad (so would using memcpy, at least the last time I checked). DMA would be OK, of course.
@ Darmstadium
What sajimori said should help you out.
About the "new" thing, when you use new (or malloc in C) you basically put a fence around a portion of the memory which won't be messed with without your permission until you delete (or free) it, even when the function goes out of scope. This is in contrast to local variables, which memory's free when the function ends. When you use new to allocate memory, but never release it again with delete, it leaves you with less and less memory everytime you allocate more. That's the memory leak that sajimori is talking about. In your code you have
Code: |
//somehow directly destroys my tile data
u16 * ascii_to_mine(const char * str, const u8 len)
{
u16 * mstr = new u16[len];
u16 loop;
for (loop = 0; loop < len; loop++)
mstr[loop] = (u16)(str[loop] - 32);
return mstr;
}
int main()
{
// blah
u16 * mstr_test = new u16[4];
mstr_test = ascii_to_mine("Jack", 4);
// blah
|
What this does is first allocate some memory to mstr_test, and then in ascii_to_mine it allocates some more, neither of which are ever released. Even worse, when you assign the result of ascii_to_mine to mstr_test, the old pointer is lost so you won't be able to release it at all. EVER. OK, so it's only 16 bytes now, but it'll get worse and worse with bigger projects. Check your C/C++ book for more on memory allocation.
What you may want to do is model your ascii_to_mine function to the standard C routine of strcpy. Something like
Code: |
u16 * ascii_to_mine(u16 *dest, const char *src, int len)
{
int loop;
for (loop = 0; loop < len; loop++)
dest[loop] = (u16)(src[loop] - 32);
// dest[len]='\0';
return dest;
}
|
Whether the line "dest[len]='\0';" should be in there is more of a personal choice; It's standard for C-strings to have a '\0' delimiter, but if you don't want that, just leave it out. Note also that I use standard ints instead of u16 and u8 for counters and lengths. It may use a little more memory, but it makes the GBA happier as it's a 32bit machine.
Anyway, using such a function will let you use either static arrays for the destination (like sajimori advised), or you could allocate it dynamically. The point is, you won't have nasty side effects like memory leaks stemming from that function alone.