Re: 2d Blitting using SDL
For a start, you need to convert the images you're blitting to the same format as the surface you're blitting them to. Second, you should be using RLE acceleration for sprites. Third, you're updating parts of the screen twice (using SDL_UpdateRects and SDL_Flip).
If you want to change only the parts of the background that need to be changed, you need to copy what was on the screen to a temporary surface, then restore it when you're done instead of re-blitting the entire background.
Re: 2d Blitting using SDL
[quote author=BlackAura link=board=pdev;num=1096339360;start=0#1 date=09/27/04 at 22:46:33]
If you want to change only the parts of the background that need to be changed, you need to copy what was on the screen to a temporary surface, then restore it when you're done instead of re-blitting the entire background.[/quote]
How would i go about it? Â*this Â*is a problem that is also in lot of sdl examples i find they Â*just blit the whole Â*background screen.. Also done in a lot of sdl games ive looked at most are simple and from people starting out so on a 2,4ghz pc it works fine. Or they fill the screen with a colour to clear it.
Thanks ive fixed the other to parts you noted. It's a simple game it's more like freeway just with a frog nothing much just the speed is a major problem. Since i dont do many games it's just a problem ive run into a lot i would like to learn how to fix this. Holds my self back from doing more homebrew games.
Thanks for your insight thus far. :)
Re: 2d Blitting using SDL
Basically, for each sprite you're going to draw, you need a temporary surface to hold whatever is underneath that sprite. When you draw a sprite, you:
1 - If there's something in the temporary surface, blit it back to the screen over the top of the old sprite image
2 - Do a blit from the screen to the temporary surface. The source should be the entire area that's going to be covered by your sprite
3 - Blit the sprite
Assuming your sprites will never overlap, this will work fine. If they do overlap, you'll need to make a lot of adjustments, and it might turn out to be less efficient than redrawing the whole screen if you're using a lot of sprites.
Also, you might want to consider using UpdateRect instead of Flip. Since we know which areas of the screen have been updated, we can get SDL to copy over only those areas. Either way, without 2D acceleration of any kind, it's going to be slow.
You could also abstract the drawing code out a little, and use 3D acceleration to draw things on the Dreamcast.
Re: 2d Blitting using SDL
Hi Ian & BA
For fun, I tried to convert your code to a simple PVR render.
Here is the result :
Code:
#include <kos.h>
#include <png/png.h>
/* romdisk */
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
//---------------------------------------------------------------------- -------
// GLOBALS
//---------------------------------------------------------------------- -------
/* //JMD Remove
SDL_Surface *g_screenSurface = NULL;
SDL_Surface *g_donutSurface = NULL;
SDL_Surface *Back_Surface = NULL;
*/
// texture structure + declarations
typedef struct {
pvr_ptr_t texture;
int text_h;
int text_w;
} DC_Texture;
typedef struct {
int h;
int w;
int x;
int y;
} DC_Rect;
DC_Texture g_donutSurface;
DC_Texture Back_Surface;
const int UPDATE_INTERVAL = 20;
// JMD change
// definitions for pad test
#define CTRL_BUTTON_NOTHING 0
#define CTRL_BUTTON_A 1
#define CTRL_BUTTON_B 2
#define CTRL_BUTTON_Y 3
#define CTRL_BUTTON_X 4
#define CTRL_BUTTON_START 5
#define CTRL_BUTTON_UP 6
#define CTRL_BUTTON_DOWN 7
#define CTRL_BUTTON_LEFT 8
#define CTRL_BUTTON_RIGHT 9
#define CTRL_BUTTON_LTRIG 10
#define CTRL_BUTTON_RTRIG 11
#define CTRL_BUTTON_BTRIG 12
#define CTRL_BUTTON_XBYLT 13
#define CTRL_TYPE_NOTHING 0
#define CTRL_TYPE_PAD 1
#define CTRL_TYPE_KEYBOARD 2
#define CTRL_TYPE_MOUSE 3
typedef struct {
int Port;
int Type;
int Action;
float ValueX;
float ValueY;
} Ctrl_Action_Return;
//---------------------------------------------------------------------- -------
// PROTOTYPES
//---------------------------------------------------------------------- -------
int main(int argc, char *argv[]);
void init(void);
void shutDown(void);
//void loadBMP(void); // JMD Remove
//Uint32 timeLeft(void); // JMD Remove
void render(void);
// JMD change
void Dc_TestPad (Ctrl_Action_Return *Return, int Port);
void loadPVR(void);
void Dc_ClearScreen();
void DC_BlitScreen (DC_Texture IN_Texture , DC_Rect RectSource , DC_Rect RectDest, int IN_layer) ;
void DC_Scene_Begin ();
void DC_Scene_End ();
//---------------------------------------------------------------------- -------
// Name: main()
// Desc:
//---------------------------------------------------------------------- -------
int main(int argc, char *argv[])
{
// JMD ADD : return structure of the pad test
Ctrl_Action_Return Test_Ctrl;
int Done = 0;
init();
// loadBMP(); // JMD REMOVE
loadPVR();
while( Done==0 )
{
Dc_TestPad(&Test_Ctrl,0); // JMD change --> test the pad
if(Test_Ctrl.Action==CTRL_BUTTON_START){ // QUIT
Done = 1;}
render();
}
// SDL Remove
/*
SDL_Event event;
while( SDL_PollEvent( &event ) )
{
if( event.type == SDL_QUIT )
Done = 1;
if( event.type == SDL_KEYDOWN )
{
if( event.key.keysym.sym == SDLK_ESCAPE )
Done = 1;
}
}
*/
shutDown();
return 0;
}
//---------------------------------------------------------------------- -------
// Name: init()
// Desc:
//---------------------------------------------------------------------- -------
void init( void )
{
pvr_init_defaults();
/* //JMD : SDL Remove
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "Unable to init SDL: %s\n", SDL_GetError() );
exit(1);
}
atexit( SDL_Quit );
g_screenSurface = SDL_SetVideoMode( 640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );
if( g_screenSurface == NULL )
{
printf( "Unable to set 640x480 video: %s\n", SDL_GetError() );
exit(1);
}
*/
}
//---------------------------------------------------------------------- -------
// Name: shutDown()
// Desc:
//---------------------------------------------------------------------- -------
void shutDown( void )
{
pvr_mem_free(g_donutSurface.texture);
pvr_mem_free(Back_Surface.texture);
/* JMD Remove
SDL_FreeSurface( g_donutSurface );
SDL_FreeSurface( g_screenSurface );
*/
}
//---------------------------------------------------------------------- -------
// Name: loadBMP()
// Desc:
//---------------------------------------------------------------------- -------
/*
void loadBMP( void )
{
// Load the BMP file into a surface
g_donutSurface = SDL_LoadBMP( "/rd/donut.bmp" );
Back_Surface = SDL_LoadBMP( "/rd/back.bmp" );
if( g_donutSurface == NULL )
{
//fprintf(stderr, "Couldn't load \"donut.bmp\"", SDL_GetError());
return;
}
SDL_SetColorKey( g_donutSurface, SDL_SRCCOLORKEY,
SDL_MapRGB( g_donutSurface->format, 0, 0, 0) );
}
*/
//---------------------------------------------------------------------- -------
// Name: loadPVR()
// Desc:
//---------------------------------------------------------------------- -------
void loadPVR( void )
{
// size of the structures
g_donutSurface.text_h = 512;
g_donutSurface.text_w = 512;
Back_Surface.text_h = 512;
Back_Surface.text_w = 512;
g_donutSurface.texture = (int *)(pvr_mem_malloc(g_donutSurface.text_h*g_donutSurface.text_w*2));
Back_Surface.texture = (int *)(pvr_mem_malloc(Back_Surface.text_h*Back_Surface.text_w*2));
png_to_texture("/rd/Gfx/donut.png", g_donutSurface.texture, PNG_FULL_ALPHA);
png_to_texture("/rd/Gfx/donut.png", Back_Surface.texture, PNG_FULL_ALPHA);
}
//---------------------------------------------------------------------- -------
// Name: timeLeft()
// Desc:
//---------------------------------------------------------------------- -------
/* JMD Remove : Not used
Uint32 timeLeft( void )
{
static Uint32 timeToNextUpdate = 0;
Uint32 currentTime;
currentTime = SDL_GetTicks();
if( timeToNextUpdate <= currentTime )
{
timeToNextUpdate = currentTime + UPDATE_INTERVAL;
return 0;
}
return( timeToNextUpdate - currentTime );
}
*/
//---------------------------------------------------------------------- -------
// Name: render()
// Desc:
//---------------------------------------------------------------------- -------
void render( void )
{
// JMD Remove
// SDL_Rect srcRect;
// SDL_Rect destRect;
DC_Rect srcRect;
DC_Rect destRect;
// JMD Remove
// SDL_Delay( timeLeft() );
// JMD Remove
// SDL_BlitSurface( Back_Surface, NULL,g_screenSurface,NULL);
//Dc_ClearScreen();
// begin scene
DC_Scene_Begin ();
// blit background
destRect.x = 0;
destRect.y = 0;
destRect.w = 640;
destRect.h = 480;
srcRect.x = 0;
srcRect.y = 0;
srcRect.w = 512;
srcRect.h = 512;
DC_BlitScreen (g_donutSurface , srcRect , destRect, 1);
//
// Blit the bitmap surface to the main surface
//
static int nPosition = 0;
static int nFrame = 0;
// Build a source SDL_Rect which will copy only a small portion of the texture.
srcRect.x = (( nFrame % 5 ) * 64);
srcRect.y = (( nFrame / 5 ) * 64);
srcRect.w = 64;
srcRect.h = 64;
destRect.x = nPosition;
destRect.y = 200;
destRect.w = 64;
destRect.h = 64;
// JMD Remove
// SDL_BlitSurface( g_donutSurface, &srcRect, g_screenSurface, &destRect );
DC_BlitScreen (g_donutSurface , srcRect , destRect, 2);
DC_Scene_End ();
// JMD Remove
// Update the changed portion of the screen
//SDL_UpdateRects( g_screenSurface, 1, &destRect );
//
// Increment the sprite's frame number. Our sprite's animation sequence
// consists of 30 frames (0-29).
//
++nFrame;
if( nFrame > 29 )
{nFrame = 0;}
//
// Slowly move our sprite across the screen. This demonstrates how to use
// a SDL_Rect destination rect with the SDL_BlitSurface method to place a
// sprite on the main screen surface.
//
++nPosition;
if( nPosition > 640 )
{ nPosition = 0;}
// JMD Remove
// SDL_Flip( g_screenSurface );
}
//---------------------------------------------------------------------- -------
// Name: Dc_TestPad()
// Desc: Test the pad for the port passed in parameters
//---------------------------------------------------------------------- -------
void Dc_TestPad (Ctrl_Action_Return *Return, int Port){
// rien
cont_state_t * state;
maple_device_t * addr;
int ctrl=Port;
// init return value
Return->Action=CTRL_BUTTON_NOTHING;
Return->Port=Port;
Return->Type=CTRL_TYPE_NOTHING;
Return->ValueX=0;
Return->ValueY=0;
if(Return->Action==CTRL_BUTTON_NOTHING){
// MAP PAD
addr = maple_enum_type(ctrl, MAPLE_FUNC_CONTROLLER);
if(addr!=NULL){
state = maple_dev_status(addr);
Return->Type=CTRL_TYPE_PAD;
if(state->buttons & CONT_DPAD_DOWN)
{Return->Action=CTRL_BUTTON_DOWN;
Return->ValueY=1; }
if(state->buttons & CONT_DPAD_UP)
{Return->Action=CTRL_BUTTON_UP;
Return->ValueY=-1; }
if(state->buttons & CONT_DPAD_LEFT)
{Return->Action=CTRL_BUTTON_LEFT;
Return->ValueX=-1; }
if(state->buttons & CONT_DPAD_RIGHT)
{Return->Action=CTRL_BUTTON_RIGHT;
Return->ValueX=1; }
if(state->rtrig){Return->Action=CTRL_BUTTON_RTRIG; }
if(state->ltrig){Return->Action=CTRL_BUTTON_LTRIG; }
if((state->ltrig)&&(state->rtrig)){Return->Action=CTRL_BUTTON_BTRIG; }
if(state->buttons & CONT_B) {Return->Action=CTRL_BUTTON_B; }
if(state->buttons & CONT_X) {Return->Action=CTRL_BUTTON_X; }
if(state->buttons & CONT_Y) {Return->Action=CTRL_BUTTON_Y; }
if(state->buttons & CONT_A) {Return->Action=CTRL_BUTTON_A; }
if(state->buttons & CONT_START) {Return->Action=CTRL_BUTTON_START; }
if(state->joyx>0){
Return->Action=CTRL_BUTTON_RIGHT;
Return->ValueX=state->joyx/127.f; }
if(state->joyx<0){
Return->Action=CTRL_BUTTON_LEFT;
Return->ValueX=state->joyx/127.f; }
if(state->joyy>0){
Return->Action=CTRL_BUTTON_DOWN;
Return->ValueY=state->joyy/127.f; }
if(state->joyy<0){
Return->Action=CTRL_BUTTON_UP;
Return->ValueY=state->joyy/127.f; }
}else{
// MAP KEYBOARD
addr = maple_enum_type(ctrl, MAPLE_FUNC_KEYBOARD);
Return->Type=CTRL_TYPE_KEYBOARD;
if(addr!=NULL){
// don"t know how to test keyboard :(
}else{
// MAP MOUSE
addr = maple_enum_type(ctrl, MAPLE_FUNC_MOUSE);
Return->Type=CTRL_TYPE_MOUSE;
if(addr!=NULL){
// don"t know how to test mouse :(
}
}
}}
}
//---------------------------------------------------------------------- -------
// Name: Dc_ClearScreen()
// Desc: Blit a black rectangle on the screen
//---------------------------------------------------------------------- -------
void Dc_ClearScreen()
{
int i=0;
int int_Value = 0;
for(i=0;i<30;i++){
vid_border_color(0,0,0);
pvr_wait_ready();
pvr_scene_begin();
pvr_list_begin(PVR_LIST_TR_POLY);
// int col;
pvr_poly_cxt_t cxt;
pvr_poly_hdr_t hdr;
pvr_vertex_t vert;
pvr_poly_cxt_col(&cxt, PVR_LIST_TR_POLY);
cxt.gen.culling = PVR_CULLING_NONE;
pvr_poly_compile(&hdr, &cxt);
pvr_prim(&hdr, sizeof(hdr));
vert.flags = PVR_CMD_VERTEX;
vert.argb = PVR_PACK_COLOR(int_Value, 0, 0, 0);
vert.oargb = 0;
vert.x = 0;
vert.y = 0;
vert.z = 100;
pvr_prim(&vert, sizeof(vert));
vert.x = 640 ;
vert.y = 0;
vert.z = 100;
pvr_prim(&vert, sizeof(vert));
vert.x = 0;
vert.y = 480;
vert.z = 100;
pvr_prim(&vert, sizeof(vert));
vert.x = 640;
vert.y = 480;
vert.z = 100;
vert.flags = PVR_CMD_VERTEX_EOL;
pvr_prim(&vert, sizeof(vert));
pvr_list_finish();
pvr_scene_finish();
}
}
//---------------------------------------------------------------------- -------
// Name: Dc_ClearScreen()
// Desc: Blit a black rectangle on the screen
//---------------------------------------------------------------------- -------
void DC_BlitScreen (DC_Texture IN_Texture , DC_Rect RectSource , DC_Rect RectDest, int IN_layer)
{
pvr_poly_cxt_t cxt;
pvr_poly_hdr_t hdr;
pvr_vertex_t vert;
pvr_poly_cxt_txr(&cxt, PVR_LIST_TR_POLY, PVR_TXRFMT_ARGB4444, IN_Texture.text_w , IN_Texture.text_h , IN_Texture.texture, PVR_FILTER_BILINEAR);
cxt.gen.culling = PVR_CULLING_NONE;
pvr_poly_compile(&hdr, &cxt);
pvr_prim(&hdr, sizeof(hdr));
vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
vert.oargb = 0;
vert.flags = PVR_CMD_VERTEX;
vert.x = RectDest.x;
vert.y = RectDest.y;
vert.z = IN_layer;
vert.u = ((float)(RectSource.x)/(float)(IN_Texture.text_w));
vert.v = ((float)(RectSource.y)/(float)(IN_Texture.text_h));
pvr_prim(&vert, sizeof(vert));
vert.x = RectDest.x + RectDest.w;
vert.y = RectDest.y;
vert.z = IN_layer;
vert.u = ( (float)(RectSource.x + RectSource.w)/ (float)(IN_Texture.text_w));
vert.v = ((float)(RectSource.y)/(float)(IN_Texture.text_h));
pvr_prim(&vert, sizeof(vert));
vert.x = RectDest.x;
vert.y = RectDest.y + RectDest.h;
vert.z = IN_layer;
vert.u = ((float)(RectSource.x)/(float)(IN_Texture.text_w));
vert.v = ( (float)(RectSource.y + RectSource.h)/ (float)(IN_Texture.text_h));
pvr_prim(&vert, sizeof(vert));
vert.x = RectDest.x + RectDest.w;
vert.y = RectDest.y + RectDest.h;
vert.z = IN_layer;
vert.u = ( (float)(RectSource.x + RectSource.w)/ (float)(IN_Texture.text_w));
vert.v = ( (float)(RectSource.y + RectSource.h)/ (float)(IN_Texture.text_h));
vert.flags = PVR_CMD_VERTEX_EOL;
pvr_prim(&vert, sizeof(vert));
}
//---------------------------------------------------------------------- -------
// Name: DC_Scene_Begin() et DC_Scene_End()
// Desc: begin and end scene
//---------------------------------------------------------------------- -------
void DC_Scene_Begin ()
{
pvr_wait_ready();
pvr_scene_begin();
pvr_list_begin(PVR_LIST_TR_POLY);
}
void DC_Scene_End ()
{
pvr_list_finish();
pvr_scene_finish();
}
My coding conventions not necessary the best so I'm open to any constructive comment :).
To work, I changed the bmp files 'back.bmp' and 'donuts.bmp' in 512*512 PNG files (support transparancies).
You can change the size in function loadPVR() but need to be multiple of 2.
For the render, I tried to create a blit function as soon as possible than SDL.
The PAD test function is the one I use. I'm sure we can do better :/.
Hope this bit of code will help you. Of course it's not as portable as SDL and will only compile for DC.
Re: 2d Blitting using SDL
Fantastic JMD cant wait to play around with this. :) Thanks a lot JMD Really good work...
:)
Re: 2d Blitting using SDL
|Reporting back after trying it well wow speed is now the same as my 2.4ghz pc much better then sdl thats for sure. Having a problem with the sprite flickering not sure about that yet. Other then that speed is normal and it works great JMD. thanks again.. :)