Trying to make a Dreamcast Mappy playback library

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
BlackAura
DC Developer
DC Developer
Posts: 9951
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Re: Trying to make a Dreamcast Mappy playback library

Post by BlackAura »

BB Hood wrote:How can the PVR handle clipping in hardware if I don't tell it where to clip? My drawing block function will only draw the whole tile.
If you're drawing full-screen, the hardware will clip everything to the screen coordinates. It's a side-effect of the tile-based rendering approach the PVR uses - for each tile (32x32 pixel block) on-screen, it finds all the polygons that intersect the tile, clips them to the tile, and then renders them.

If you're not drawing full-screen, you can set the clipping region. However, since the clipping is based on tiles, you can only clip to tile boundaries. You send a PVR_CMD_USERCLIP primitive to the PVR to set the clipping region. Then, for polygons you want to be affected by clipping, you need to set gen.clip_mode in the polygon context to PVR_USERCLIP_INSIDE. You could also use PVR_USERCLIP_OUTSIDE to exclude polygons from that area.

At least, that's the theory - I've never been able to get it to work - it works on half the screen only, with a flickery mess at the borders. In theory, this should set the clipping region:

Code: Select all

#define CLAMP( X, MIN, MAX )  ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
void set_clip(int x, int y, int width, int height)
{
	int min_x, min_y, max_x, max_y;
	int screen_width, screen_height;

	// Empty userclip polygon header
	// KOS has no code to support this - we have to build the header ourselves
	pvr_poly_hdr_t user_clip = {
		PVR_CMD_USERCLIP, 0x00000000, 0x00000000, 0x00000000,
		0x00000000, 0x00000000, 0x00000000, 0x00000000
	};

	// Get the screen size (in tiles)
	screen_width = vid_mode->width / 32;
	screen_height = vid_mode->height / 32;

	// Calculate the minimum and maximum tile to render
	min_x = x / 32;
	min_y = y / 32;
	max_x = ((x + width) - 1) / 32;
	max_y = ((y + height) - 1) / 32;

	// Copy into the header, clamping to the acceptable range as we go
	user_clip.d1 = CLAMP(min_x, 0, screen_width);
	user_clip.d2 = CLAMP(min_y, 0, screen_height);
	user_clip.d3 = CLAMP(max_x, 0, screen_width);
	user_clip.d4 = CLAMP(max_y, 0, screen_height);

	// Send the clipping rectangle command
	pvr_prim(&user_clip, sizeof(user_clip));
}
The KGL library that comes with KOS has an implementation of this (it's used to implement GL_SCISSOR), although I've never used it. It's pretty much the only source for documentation on how this thing's supposed to work.

If you need finer clipping than that, there's no hardware mechanism to help you. You'll have to clip the tiles manually against the viewing area.
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: Trying to make a Dreamcast Mappy playback library

Post by BB Hood »

If you can't get it to work properly there is not way I could. Thanks for going through the trouble of digging up that above code. I implemented your previous method for the drawing loop and will add(already written the code but don't have DCMappy in front of me right now) untextured borders to the map. Thanks for your help OneThirty8 and BlackAura.

EDIT: Tada
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: Trying to make a Dreamcast Mappy playback library

Post by BB Hood »

Sorry for the double post :oops: . Anyways I decided not to use untextured border because it would get in the way if someone lets say draws two maps(the same) on the screen. They would have to be a minimum of block width apart because the untextured black rectangle would overlap on the other map if they get too close. Here is my working (clipping) drawing function:

Code: Select all

int DCMappy::MapDrawBG (void) {
    #ifdef DEBUG_MAP
    if(pvr_state.list_reg_open != PVR_LIST_OP_POLY) {
         
        printf("MapDrawBG() can only be called after pvr_list_begin(PVR_LIST_OP_POLY) and NOT after pvr_list_begin(PVR_LIST_TR_POLY).\n"); 
        return 0;
    }
    #endif

    int			i, j, mapvclip, maphclip;
    int         x_max, y_max, x_min, y_min;
    int 		numtile, numanim;
    float       temp;
    ANISTR		* anim;
	Block_Rect  TileDestRect;
	
	x_min = XPosition/mapblockwidth;
    y_min = YPosition/mapblockheight;
    x_max = x_min+(Screen_w/mapblockwidth)+1;
    y_max = y_min+(Screen_h/mapblockheight)+1;
    
	maphclip=XPosition%mapblockwidth;
	mapvclip=YPosition%mapblockheight;	
	
	for(i = 0; i <= y_max; i++) {
		for(j = 0; j < x_max; j++)
		{	
            TileDestRect.x	= j*mapblockwidth-maphclip + MMOX;
			TileDestRect.y	= i*mapblockheight-mapvclip + MMOY;
			TileDestRect.h	= mapblockheight; 
            TileDestRect.w	= mapblockwidth;  
            
			// Clip Left
			if(TileDestRect.x < MMOX) {                            
                TileDestRect.w = mapblockwidth - (MMOX - TileDestRect.x);            
                if(TileDestRect.w <= 0) continue;  // Out of bounds.. Dont draw it
                TileDestRect.x	= MMOX;
                temp = mapblockwidth - TileDestRect.w;
                temp = temp / mapblockwidth;
                TileDestRect.u1 = temp;
                
                // Handle Corners(Top Left then Bottom Left)
                if(TileDestRect.y < MMOY){
                    TileDestRect.h = mapblockheight - (MMOY - TileDestRect.y);
                    TileDestRect.y	= MMOY;
                    temp = mapblockheight - TileDestRect.h;
                    temp = temp / mapblockheight;
                    TileDestRect.v1 = temp;
                } else TileDestRect.v1 = 0.0f;
                
                if((TileDestRect.y+mapblockheight) > (MMOY+Screen_h)) {
                        TileDestRect.h = (MMOY+Screen_h) - TileDestRect.y;
                        if(TileDestRect.h > mapblockheight) continue; // Out of bounds.. Dont draw it
                        temp = TileDestRect.h;
			            temp = temp/mapblockheight;
                        TileDestRect.v2 = temp;
                } else TileDestRect.v2 = 1.0f;
			    TileDestRect.u2 = 1.0f; 
			    
			    // Clip Right
            } else if((TileDestRect.x+mapblockwidth) > (MMOX+Screen_w)) {
                TileDestRect.w = (MMOX+Screen_w) - TileDestRect.x;
                if(TileDestRect.w > mapblockwidth) continue; // Out of bounds.. Dont draw it
                TileDestRect.u1 = 0.0f;
                
                // Handle Corners(Top Right then Bottom Right)
                if(TileDestRect.y < MMOY){
                    TileDestRect.h = mapblockheight - (MMOY - TileDestRect.y);
                    TileDestRect.y	= MMOY;
                    temp = mapblockheight - TileDestRect.h;
                    temp = temp / mapblockheight;
                    TileDestRect.v1 = temp;
                } else TileDestRect.v1 = 0.0f;
                
                if((TileDestRect.y+mapblockheight) > (MMOY+Screen_h)) {
                        TileDestRect.h = (MMOY+Screen_h) - TileDestRect.y;
                        if(TileDestRect.h > mapblockheight) continue; // Out of bounds.. Dont draw it
                        temp = TileDestRect.h;
			            temp = temp/mapblockheight;
                        TileDestRect.v2 = temp;
                } else TileDestRect.v2 = 1.0f;
                temp = TileDestRect.w;
                temp = temp / mapblockwidth;
			    TileDestRect.u2 = temp;
                
                // Clip Top
            } else if(TileDestRect.y < MMOY) {
                TileDestRect.h = mapblockheight - (MMOY - TileDestRect.y);
                if( TileDestRect.h <= 0) continue;  // Out of bounds.. Dont draw it
                TileDestRect.y	= MMOY;
                temp = mapblockheight - TileDestRect.h;
                temp = temp / mapblockheight;
                TileDestRect.u1 = 0.0f;
                TileDestRect.v1 = temp;
			    TileDestRect.u2 = TileDestRect.v2 = 1.0f;
			    
			    // Clip Bottom
            } else if((TileDestRect.y+mapblockheight) > (MMOY+Screen_h)) {
                TileDestRect.h = (MMOY+Screen_h) - TileDestRect.y;
                if(TileDestRect.h > mapblockheight) continue;   // Out of bounds.. Dont draw it
                TileDestRect.u1 = TileDestRect.v1 = 0.0f;
			    TileDestRect.u2 = 1.0f;
			    temp = TileDestRect.h;
			    temp = temp/mapblockheight;
                TileDestRect.v2 = temp;
                
                // Default
            } else {			
			    TileDestRect.u1 = TileDestRect.v1 = 0.0f;
			    TileDestRect.u2 = TileDestRect.v2 = 1.0f;
            } 
			
			numtile = mappt[x_min+j+((y_min+i)*mapwidth)];
			
			if (((x_min+j)<mapwidth) && ((y_min+i)<mapheight))
			    if (numtile>=0)
					MapDrawBlock(&maplpDDSTiles_OP[((BLKSTR *) (mapblockstrpt+numtile))->bgoff], &TileDestRect); 
			else {
			    anim = (ANISTR *) (mapanimstrendpt + numtile);
			    numanim = mapanimstrpt[ANDTSize+anim->ancuroff+1]&0XFF;
			    numanim <<= 8;
			    numanim |= mapanimstrpt[ANDTSize+anim->ancuroff]&0XFF;
			    MapDrawBlock(&maplpDDSTiles_OP[((BLKSTR *) (mapblockstrpt+numanim))->bgoff], &TileDestRect); 
			}
		}
    }
	
	return 0;
}
and it WORKS! but I was wondering if anybody can see any optimizations I can make. Don't trace the code but if there is anything that I can change to help it run faster let me know. I am not having any lag or anything but I want to optimize it if possible.

EDIT: Here is a link to show it in action.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Re: Trying to make a Dreamcast Mappy playback library

Post by BlackAura »

There are probably a few things you could do to make the code shorter (the clipping code in particular), but nothing immediately jumps out as being a performance problem. If you want to optimize it anyway, I suggest trying to come up with a situation in which your code isn't fast enough anyway. Drawing lots of layers at once, for example. Then you'd actually have something you could improve upon.

My suspicion is that this rendering code is never going to be CPU-limited. Instead, it's likely to end up being limited by the speed of the PVR. Unless you have five or six full-screen layers, all blended with those beneath, I doubt you'd even hit that. This is the kind of thing the Dreamcast should be able to do without even breaking a sweat.

Since you have CPU time to burn, you might as well try to add features. The most obvious thing I could suggest is rotation and scaling support. The catch with that - it'd require being able to clip arbitrary polygons against the window. Which is kind of tricky, even in 2D.
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: Trying to make a Dreamcast Mappy playback library

Post by BB Hood »

I was thinking of adding scaling but dont know what anybody might use rotation for.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5663
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: Trying to make a Dreamcast Mappy playback library

Post by BlueCrab »

BB Hood wrote:I was thinking of adding scaling but dont know what anybody might use rotation for.
You could use rotation for a cheap isometric effect.
OneThirty8
Damn Dirty Ape
Damn Dirty Ape
Posts: 5031
Joined: Thu Nov 07, 2002 11:11 pm
Location: Saugerties, NY
Has thanked: 0
Been thanked: 0

Re: Trying to make a Dreamcast Mappy playback library

Post by OneThirty8 »

BlueCrab wrote:
BB Hood wrote:I was thinking of adding scaling but dont know what anybody might use rotation for.
You could use rotation for a cheap isometric effect.
I thought Mappy already gave you the ability to load an isometric map. Am I thinking of something else?
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5663
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: Trying to make a Dreamcast Mappy playback library

Post by BlueCrab »

OneThirty8 wrote:
BlueCrab wrote:
BB Hood wrote:I was thinking of adding scaling but dont know what anybody might use rotation for.
You could use rotation for a cheap isometric effect.
I thought Mappy already gave you the ability to load an isometric map. Am I thinking of something else?
It does, but I'm pretty sure that the code that BB Hood is working on probably doesn't support it yet, so this would be a way to simulate it with a square grid.
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: Trying to make a Dreamcast Mappy playback library

Post by BB Hood »

^ He is probably right because I haven't tested it. I figured out [today] that the code in SDLMappy doesn't decode everything like collision which I have to find a way to decode by looking at other playback libraries. SDLMappy sucks pretty bad. Right now im basically trying to test all the functions of this library by writing demos. I am already done with a vertical scrolling demo which I ported from a video game programming book(Game Programming All-in-one). All I have left to demo is two more examples, one a horizontal scroller and the other (I'm guessing) is platform(Think old tile games like pokemon, zelda etc.). I will probably find a way to support isometric maps as well by looking at other playback libraries. It'll take me a while to get it all done.
User avatar
BB Hood
DC Developer
DC Developer
Posts: 189
Joined: Fri Mar 30, 2007 12:09 am
Has thanked: 41 times
Been thanked: 10 times

Re: Trying to make a Dreamcast Mappy playback library

Post by BB Hood »

Done> viewtopic.php?f=40&t=99270 . I did what I wanted to do with it. No isometric or hexagonal map support. I learned a lot...thanks guys.
Post Reply