tile engine help
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
tile engine help
hey..im starting a psp tile 2d scroller..and well i have my "map" as a 2d array
60x30 integers.. where each tile is 16x16 pixels.
so the map is 960x 480 pixels (bigger than the psp screen..which is what i want)
so i have this big map, and then i have a viewable area (the psp screen) which will be 29 x 17 tiles, where each tile is 16x 16
so i have a global int mapX and mapY, which increment the top-left of where i should start drawing from on the BIG map..
so i have the D-Pad changing the mapX and mapY values..
then in my drawMap function..
i find out which tile based on mapX and mapY will be the top left on the psp screen
tileX=mapX /16
tileY=mapY/16
pretty straight foward so far..
so then i pgBitBlt the tiles that are visible on the screen...and when i press the D-Pad i scroll through my map just fine..
however, i have my mapX and mapY being incremented by 16.. the size of a tile.. so that works out just fine..
but if I want to have smooth scrolling..i need to increment by less than the size of a tile...this is where my problem comes into play..
so say i increment by 5..that means ill have to draw only part of a tile on the right side of the screen..not a full tile..
however, on the psp..if you bitblt anything off the x/y of the screen..it freezes up...
i probably lost you by now..so ill paste some of my code..so you can see it..
//This is how i change the mapX and mapY values with the DPAD
case 5: //UP ARROW
if(mapY-16 > MAP_MIN_Y)
{
mapY-=16;
}
break;
case 6://DOWN ARROW
if(mapY+16 < MAP_MAX_Y)
{
mapY+=16;
}
break;
case 7://LEFT ARROW
if(mapX-16 > MAP_MIN_X)
{
mapX-=16;
}
break;
case 8://RIGHT ARROW
if(mapX+16 < MAP_MAX_X)
{
mapX+=16;
}
//
void drawMap(int drawX,int drawY)
{
int tileX = drawX/16;
int tileY = drawY/16;
int x,y;
for(x=0;x<29;x++)
{
for(y=0;y<17;y++)
{
drawTile(map[tileY+y][tileX+x].tile_number,x*16,y*16);
}
}
}
void drawTile(int tileNum,int X,int Y)
{
switch(tileNum)
{
case 0:
pgBitBlt(X,Y,TILE_WIDTH,TILE_HEIGHT,1,image_grass);
break;
case 1:
pgBitBlt(X,Y,TILE_WIDTH,TILE_HEIGHT,1,image_dirt);
break;
case 2:
pgBitBlt(X,Y,TILE_WIDTH,TILE_HEIGHT,1,image_water);
break;
}
}
60x30 integers.. where each tile is 16x16 pixels.
so the map is 960x 480 pixels (bigger than the psp screen..which is what i want)
so i have this big map, and then i have a viewable area (the psp screen) which will be 29 x 17 tiles, where each tile is 16x 16
so i have a global int mapX and mapY, which increment the top-left of where i should start drawing from on the BIG map..
so i have the D-Pad changing the mapX and mapY values..
then in my drawMap function..
i find out which tile based on mapX and mapY will be the top left on the psp screen
tileX=mapX /16
tileY=mapY/16
pretty straight foward so far..
so then i pgBitBlt the tiles that are visible on the screen...and when i press the D-Pad i scroll through my map just fine..
however, i have my mapX and mapY being incremented by 16.. the size of a tile.. so that works out just fine..
but if I want to have smooth scrolling..i need to increment by less than the size of a tile...this is where my problem comes into play..
so say i increment by 5..that means ill have to draw only part of a tile on the right side of the screen..not a full tile..
however, on the psp..if you bitblt anything off the x/y of the screen..it freezes up...
i probably lost you by now..so ill paste some of my code..so you can see it..
//This is how i change the mapX and mapY values with the DPAD
case 5: //UP ARROW
if(mapY-16 > MAP_MIN_Y)
{
mapY-=16;
}
break;
case 6://DOWN ARROW
if(mapY+16 < MAP_MAX_Y)
{
mapY+=16;
}
break;
case 7://LEFT ARROW
if(mapX-16 > MAP_MIN_X)
{
mapX-=16;
}
break;
case 8://RIGHT ARROW
if(mapX+16 < MAP_MAX_X)
{
mapX+=16;
}
//
void drawMap(int drawX,int drawY)
{
int tileX = drawX/16;
int tileY = drawY/16;
int x,y;
for(x=0;x<29;x++)
{
for(y=0;y<17;y++)
{
drawTile(map[tileY+y][tileX+x].tile_number,x*16,y*16);
}
}
}
void drawTile(int tileNum,int X,int Y)
{
switch(tileNum)
{
case 0:
pgBitBlt(X,Y,TILE_WIDTH,TILE_HEIGHT,1,image_grass);
break;
case 1:
pgBitBlt(X,Y,TILE_WIDTH,TILE_HEIGHT,1,image_dirt);
break;
case 2:
pgBitBlt(X,Y,TILE_WIDTH,TILE_HEIGHT,1,image_water);
break;
}
}
Re: tile engine help
Well, depending on where exactly, but yes it will if you try to write to some place that you shouldn't. So what you need to do is write some code to make sure that you don't :PJJPeerless wrote:
however, on the psp..if you bitblt anything off the x/y of the screen..it freezes up...
if you provide a range check in bitblit to see if the x,y values of the pixel to be written are valid, you can make it work.. it might make it slower, and there is almost certainly a way to optimise(sp?) this, but it will work. ie:
note.. this may not work.. i have not tested it yet, but even if it doesn't, it will give you a platform to start from.. happy coding!
[EDIT] I forgot a semicolon after vptr0's declaration.. whoops..
seems it will compile now, but the logic might be a bit flawed, so use with care
Code: Select all
void pgRangeBitBlt(unsigned long x,unsigned long y,unsigned long w,unsigned long h,unsigned long mag,const unsigned short *d)
{
unsigned long xloop,yloop,ymag,xmag;
const unsigned short *dd;
unsigned char *vptr0; //vram pointer
for (yloop=y; yloop<y+h; y++)
{
for (ymag=0; ymag<mag; ymag++)
{
dd=d;
for (xloop=x; xloop<x+h; x++)
{
for (xmag=0; xmag<mag; xmag++)
{
if ((xloop >=0) && (x < SCREEN_WIDTH) && (y>= 0) && (y < SCREEN_HEIGHT))
{
vptr0=pgGetVramAddr(xloop+xmag,yloop+ymag);
*(unsigned short *)vptr0=*dd;
}
}
dd++;
}
}
d+=w;
}
}
[EDIT] I forgot a semicolon after vptr0's declaration.. whoops..
seems it will compile now, but the logic might be a bit flawed, so use with care
Last edited by wulf on Thu Jun 23, 2005 9:18 am, edited 1 time in total.
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
the main problem is i dont understand how nem's pg libary actually works..i only know how to USE it..
i dont understand any of the primitive functions of the psp that he is using in his functions..
but all your doing is..as it loops through each pixel of the picture..if the coords of it are not within the screen bounds..your just not drawing it..right?
i dont understand any of the primitive functions of the psp that he is using in his functions..
but all your doing is..as it loops through each pixel of the picture..if the coords of it are not within the screen bounds..your just not drawing it..right?
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
ahh, see, that's the trick... you only need access to the first char, then you offset the pointer by the size of exactly one char for each pixel into the picture you want.. note that to move down a y value, you have to offset by y*SCREEN_WIDTH because you are "skipping" those pixels.
and that makes me think that I have another bug in my function.. hold on
... no not the one I thoght... nm
and that makes me think that I have another bug in my function.. hold on
... no not the one I thoght... nm
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
maybe I should have said :
althogh your picture is 2d, all memory (on your hdd, the psp, everything) is 1d
that means that your pic must be chopped up and arranged in mem as 1d, then when the psp puts it on screen, it reads out the 1d memory in chunks of SCREEN_WIDTH, for each line.
so like this for a 4x3 "pic" alternating blue and red stripes:
blue blue blue blue
red red red red
blue blue blue blue
/\ this is how you see it when you edit it in image editor..
\/ but this is how it's saved:
blue blue blue blue red red red red blue blue blue blue
AND, that's how the psp's memory needs to look when you put the pic on the screen..
that's what the loops do.. they shuffle through the picture aligning the psp's memory and the stored pic, and then copying over the pic, one pixel at a time.
althogh your picture is 2d, all memory (on your hdd, the psp, everything) is 1d
that means that your pic must be chopped up and arranged in mem as 1d, then when the psp puts it on screen, it reads out the 1d memory in chunks of SCREEN_WIDTH, for each line.
so like this for a 4x3 "pic" alternating blue and red stripes:
blue blue blue blue
red red red red
blue blue blue blue
/\ this is how you see it when you edit it in image editor..
\/ but this is how it's saved:
blue blue blue blue red red red red blue blue blue blue
AND, that's how the psp's memory needs to look when you put the pic on the screen..
that's what the loops do.. they shuffle through the picture aligning the psp's memory and the stored pic, and then copying over the pic, one pixel at a time.
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
vptr0 is just a pointer to the vram of the psp..
pgGetVramAddr supplies the correct address for a given pixel for each iteration.
the next line puts the pixel data from the picture into the ram, effectively drawing one pixel..
jeach time the for loops are incremented, the yloop and xloop values change.
that means that as the loop progresses, the place in ram, and the place in the image are being
changed. that way, the line
*(unsigned short *)vptr0=*dd; (which is the pixel writing line)
is always writing to a different place, from a different place.
pgGetVramAddr supplies the correct address for a given pixel for each iteration.
the next line puts the pixel data from the picture into the ram, effectively drawing one pixel..
jeach time the for loops are incremented, the yloop and xloop values change.
that means that as the loop progresses, the place in ram, and the place in the image are being
changed. that way, the line
*(unsigned short *)vptr0=*dd; (which is the pixel writing line)
is always writing to a different place, from a different place.
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am
how can i go about having another buffer, that is slightly wider than the actual psp screen..then use a function almost identical to bitblt to write this "bigger buffer"..like at top will i need to do something like
char *pg_vramtop2=(char *)0x04000000; and change the offset?
and then write to that using the new bitblt..
and then i want to be able to take that new buffer..and not start from 0,0 and go to 480x 272..but go from some xOff,yOff to xOff+482, yOff+272..
but i dont know how to create such a buffer..or copy a 480x272 portion of the new buffer to the main buffer..
char *pg_vramtop2=(char *)0x04000000; and change the offset?
and then write to that using the new bitblt..
and then i want to be able to take that new buffer..and not start from 0,0 and go to 480x 272..but go from some xOff,yOff to xOff+482, yOff+272..
but i dont know how to create such a buffer..or copy a 480x272 portion of the new buffer to the main buffer..
oh, I see.
well, his style is a bit different than mine, but i wrote mine based on his...
his variable naming is a bit hard to understand at first, that's why I changed the names of mine..
but the basic premise is this..
he gets the place of the first pixel in the psp's ram with the vptr0=... line
he increments the place in memory with the vptr+=PIXELSIZE*2; command
and the vptr0+=LINESIZE*2; command, instead of using vptr0=pgGetVramAddr(x,y);
for every pixel, like I do..
his way is faster, but it means that since you are blindly incrementuing the position in memory,
you can easily run out of the valid memory..
he needs two of each variable (xx,yy,vptr0,vptr,etc) because of the built in magnification he wrote. that's because of the way the magnification works: it simply moves the ram address without moving the part of the picture it's drawing, so each pixel gets doubled up,(or tripled, or whatever)
the reason for the doubling up of the variables is because there needs to be a way to "uncouple" the picture incrementing while the magnification code is being implemented.
here is some pseudocode for what is basically happening:
the doubling of variables basically allows us to "remember" where we were before the magnification part took place (rewind to before it)
you can also use the above for comments on each line below.
btw, understanding exactly how it works isn't ultra-mega-super important, as long as you get the gist..
you just have to be able to implement it in your code..
and you will understand it, if you keep trying.
another place that will help you with game drawing stuff is www.gamedev.org (or is it .com?)
you will find that pretty much all pixel/picture drawing routines similar, regardless of the platform..
the only code here that is psp specific is the function that determines the correct address in ram, getVramAddr..
well, his style is a bit different than mine, but i wrote mine based on his...
his variable naming is a bit hard to understand at first, that's why I changed the names of mine..
but the basic premise is this..
he gets the place of the first pixel in the psp's ram with the vptr0=... line
he increments the place in memory with the vptr+=PIXELSIZE*2; command
and the vptr0+=LINESIZE*2; command, instead of using vptr0=pgGetVramAddr(x,y);
for every pixel, like I do..
his way is faster, but it means that since you are blindly incrementuing the position in memory,
you can easily run out of the valid memory..
he needs two of each variable (xx,yy,vptr0,vptr,etc) because of the built in magnification he wrote. that's because of the way the magnification works: it simply moves the ram address without moving the part of the picture it's drawing, so each pixel gets doubled up,(or tripled, or whatever)
the reason for the doubling up of the variables is because there needs to be a way to "uncouple" the picture incrementing while the magnification code is being implemented.
here is some pseudocode for what is basically happening:
the doubling of variables basically allows us to "remember" where we were before the magnification part took place (rewind to before it)
Code: Select all
loop through y values of picture
loop through the magnification of y
make a copy of the vram position so the mag doesn't screw us up
make a copy of the picture pos for the same reason
loop through the x values of the picture (master x loop)
loop through the mag of x
draw the pixel
go to the next place in vram
end of magx loop
go to the next pixel(x)
end of master x loop
go to the next line in vram
end of magy loop
go to the next line in picture(y)
end of master y loop
you can also use the above for comments on each line below.
btw, understanding exactly how it works isn't ultra-mega-super important, as long as you get the gist..
you just have to be able to implement it in your code..
and you will understand it, if you keep trying.
another place that will help you with game drawing stuff is www.gamedev.org (or is it .com?)
you will find that pretty much all pixel/picture drawing routines similar, regardless of the platform..
the only code here that is psp specific is the function that determines the correct address in ram, getVramAddr..
Code: Select all
void pgBitBlt(unsigned long x,unsigned long y,unsigned long w,unsigned long h,unsigned long mag,const unsigned short *d)
{
unsigned char *vptr0; //pointer to vram
unsigned char *vptr; //pointer to vram
unsigned long xx,yy,mx,my;
const unsigned short *dd;
vptr0=pgGetVramAddr(x,y);
for (yy=0; yy<h; yy++) {
for (my=0; my<mag; my++) {
vptr=vptr0;
dd=d;
for (xx=0; xx<w; xx++) {
for (mx=0; mx<mag; mx++) {
*(unsigned short *)vptr=*dd;
vptr+=PIXELSIZE*2;
}
dd++;
}
vptr0+=LINESIZE*2;
}
d+=w;
}
}
to be honest, I'm not exactly sure about your "bigger buffer" question.. I assume you want to keep it in Vram?
if you don't, then you could make an array with the same number of elements as pixels for your buffer,
copy the image data into this array, then use a modified bitblt to only capture the data you want.
you would need to add some paramaters to the bitblt function, like xoffset, yoffset, and possibly xlength and ylength values if you wanted to have a variable "window"
you would also need code to set the position in bigbuffer to the right place at the start, and then
set it again to the proper offset inside your bigbuffer every new line..
you would then repeat this until your psp-screen-sized window is copied into vram.
sorry if this isn't making any sense, but It's late here, and I'm pretty tired..
hope this helps,
wulf
if you don't, then you could make an array with the same number of elements as pixels for your buffer,
copy the image data into this array, then use a modified bitblt to only capture the data you want.
you would need to add some paramaters to the bitblt function, like xoffset, yoffset, and possibly xlength and ylength values if you wanted to have a variable "window"
you would also need code to set the position in bigbuffer to the right place at the start, and then
set it again to the proper offset inside your bigbuffer every new line..
you would then repeat this until your psp-screen-sized window is copied into vram.
sorry if this isn't making any sense, but It's late here, and I'm pretty tired..
hope this helps,
wulf
-
- Posts: 82
- Joined: Mon Jun 20, 2005 3:32 am