tile engine help

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

tile engine help

Post by JJPeerless »

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;
}


}
inomine
Posts: 53
Joined: Thu May 05, 2005 7:26 pm

Re: tile engine help

Post by inomine »

JJPeerless wrote:
however, on the psp..if you bitblt anything off the x/y of the screen..it freezes up...
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 :P
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

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:

Code: Select all

void pgRangeBitBlt&#40;unsigned long x,unsigned long y,unsigned long w,unsigned long h,unsigned long mag,const unsigned short *d&#41;
&#123;

unsigned long xloop,yloop,ymag,xmag;
const unsigned short *dd;
unsigned char *vptr0; //vram pointer

for &#40;yloop=y; yloop<y+h; y++&#41;
&#123;
  for &#40;ymag=0; ymag<mag; ymag++&#41;
  &#123;
    dd=d;
    for &#40;xloop=x; xloop<x+h; x++&#41;
    &#123;
      for &#40;xmag=0; xmag<mag; xmag++&#41;
      &#123;
        if &#40;&#40;xloop >=0&#41; && &#40;x < SCREEN_WIDTH&#41; && &#40;y>= 0&#41; && &#40;y < SCREEN_HEIGHT&#41;&#41;
         &#123; 
           vptr0=pgGetVramAddr&#40;xloop+xmag,yloop+ymag&#41;;
           *&#40;unsigned short *&#41;vptr0=*dd;
         &#125;
      &#125;
       dd++;
    &#125; 
  &#125;
   d+=w;
&#125;
&#125;
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
Last edited by wulf on Thu Jun 23, 2005 9:18 am, edited 1 time in total.
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

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?
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

what about..drawing the image thats bigger than the screen to a bufffer..then clipping it to the correct size and then flip that to the screen.. would that be any more efficient?
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

well, I don't know, but I don't think so, because in the end, you have to write the data twice..
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

note that mag's lowest value is 0, so if you call it with mag=1, your tiles will be twice their orig size.. (just noticed that bug)
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

i think my confusion is actually going back to plain old C...

i dont understand unsigned char...doesnt it only hold a byte from 0-255...

how can an unsigned char be the "vram" or whatever..i dont understand

char *pg_vramtop=(char *)0x04000000;

like that..
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

because it is the color information...
the address is held in the pointer, but the pointer points to an unsigned char, which is the color..
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

yea..but its ONE char... isnt the screen made up of like hmm.. 480 x 272 pixels..
shouldnt it be a 2d array of chars?
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

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
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

ok well, thats what i figured..

so say the screen looks like this:

011100
111111
111000
111111

then in memory it would be

011100111111111000111111

and the char points to the first 0..and you just increase your position to go through the bytes?
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

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.
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

ok, that's just too funny! you totally got it, though..:)
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

vptr0=pgGetVramAddr(x,y);

what is that doing..before all the loops

the loop makes no sense to me..it doesnt "save" anything anywhere..it just adds stuff to those vptr and vptr0..which i dont understand either..
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

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.
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

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..
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

or do you mean the original bitblit from pg.c?

cause i thought you were talking about my code..
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

im still talking about the original..
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

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)

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 &#40;master x loop&#41;
                              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&#40;x&#41;
                     end of master x loop
                     go to the next line in vram
           end of magy loop
           go to the next line in picture&#40;y&#41;
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&#40;unsigned long x,unsigned long y,unsigned long w,unsigned long h,unsigned long mag,const unsigned short *d&#41;
&#123;
	unsigned char *vptr0;		//pointer to vram
	unsigned char *vptr;		//pointer to vram
	unsigned long xx,yy,mx,my;
	const unsigned short *dd;

	vptr0=pgGetVramAddr&#40;x,y&#41;;
	for &#40;yy=0; yy<h; yy++&#41; &#123;
		for &#40;my=0; my<mag; my++&#41; &#123;
			vptr=vptr0;
			dd=d;
			for &#40;xx=0; xx<w; xx++&#41; &#123;
				for &#40;mx=0; mx<mag; mx++&#41; &#123;
					*&#40;unsigned short *&#41;vptr=*dd;
					vptr+=PIXELSIZE*2;
				&#125;
				dd++;
			&#125;
			vptr0+=LINESIZE*2;
		&#125;
		d+=w;
	&#125;

&#125;
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

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
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

i just want to thank you wulf..for your time..

i actually understand what nem's graphics library does now..and i was able to rewrite the functions i need..and i got my tile problem working!

thanks alot!
wulf
Posts: 81
Joined: Wed Apr 13, 2005 6:56 pm

Post by wulf »

Sweet! I'm glad I could help.. to be honest, I learned a lot too... before seeing nem's code, I had no idea how to implement a magnification for sprites.. :P but anyway, you're welcome.
Post Reply