PDA

View Full Version : 2d Blitting using SDL



Ian_micheal
September 27th, 2004, 21:42
Im writing a frogger type clone game called froggway every thing is fine game-play-wize but the speed... it's some what based on *some of the sprite loading routine *on this example. The problem is the game runs at 5FPS *but fullspeed on my pc but on the dreamcast using SDL it's super slow totaly unplay-able and im left with having no background image if i want the game playable.

Here's the code example of the way im blitting the sprite and back ground. The main problem is the back ground... with out it the sprite runs the, correct speed. I would like any help , on optmizing this for dreamcast. Or some logic on a better way. I did want to use sdl for this but im thinking I might have to use some other lib that would set my game back a long way.

Example code i use the same way for blitting my sprites so ive included this it will compile on dreamcast if you need the grafix to test pm me.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL/SDL.h>

#include <kos.h>

/* romdisk */
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);


//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
SDL_Surface *g_screenSurface = NULL;
SDL_Surface *g_donutSurface *= NULL;
SDL_Surface *Back_Surface *= NULL;

const int UPDATE_INTERVAL = 20;

//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
int main(int argc, char *argv[]);

void init(void);
void shutDown(void);
void loadBMP(void);
Uint32 timeLeft(void);
void render(void);

//-----------------------------------------------------------------------------
// Name: main()
// Desc:
//-----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
* *init();

* *loadBMP();
int Done; *
*

* Done = 0;

* *while( 1 )
* *{
* * * *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;
* * * * * *}
* * * *}

* * * *render();
* *}

* *shutDown();

* *return 0;
}

//-----------------------------------------------------------------------------
// Name: init()
// Desc:
//-----------------------------------------------------------------------------
void init( void )
{
* *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 )
{
* *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: timeLeft()
// Desc:
//-----------------------------------------------------------------------------
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 )
{
* *SDL_Delay( timeLeft() );

* *SDL_BlitSurface( Back_Surface, NULL,g_screenSurface,NULL);
* *
* *//
* *// Blit the bitmap surface to the main surface
* *//

* *static int nPosition = 0;
* * *static int nFrame * *= 0;

* *SDL_Rect srcRect;
* *SDL_Rect destRect;

* *// 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;

* *SDL_BlitSurface( g_donutSurface, &srcRect, g_screenSurface, &destRect );
*

* *// 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;

* *SDL_Flip( g_screenSurface );
}



Thanks for reading. Im looking at geting the speed up this affects most sdl ports as well. Back ground image blits every frame to clear the trail left by the sprite. There must be a way using sdl to auto clear behine the sprite as it moves and not the whole screen. Ive just not found any example out there i could understand.

BlackAura
September 27th, 2004, 22:46
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.

Ian_micheal
September 28th, 2004, 01:40
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.

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. :)

BlackAura
September 28th, 2004, 02:16
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.

JMD
September 28th, 2004, 17:17
Hi Ian & BA

For fun, I tried to convert your code to a simple PVR render.

Here is the result :




#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_donutSur face.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.

Ian_micheal
September 28th, 2004, 19:28
Fantastic JMD cant wait to play around with this. :) Thanks a lot JMD Really good work...

:)

Ian_micheal
September 29th, 2004, 01:58
|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.. :)