Archived

This topic is now archived and is closed to further replies.

Zanthos

SDL Phantom Blitting

Recommended Posts

I''ve never had much luck with API''s, and SDL is my new venture.. And I''ve hit some problem I don''t seem to think I can solve. Basically, I have a program which works in either windowed or fullscreen mode, and displays a bitmap at the position of the cursor. I''ve disabled the cursor using SDL_ShowCursor(0), and am using: SDL_HWSURFACE|SDL_DOUBLEBUFFER as my primary surface flags. The problem.. Whilst the program is running, I get strange "phantom blits" which flick around on the screen in a seemingly random fashion whilst I move the mouse cursor. These "phantom blits" are also seemingly random chunks of the screen, both in size and position. I''ve completely ruled out any tearing due to buffer flipping, and anything due to the mouse cursor(whether visible or not). Additionally, this problem is apparent whether in fullscreen or windowed mode. I did, however, find a bodge to the problem, and that is to use SDL_Delay(10) after the SDL_Flip(screen) call, but I can''t live with myself to use that as a fix Any help would be much appreciated. Additionally.. My system configuration: Windows 2000 Professional SP 4 DirectX 9.0b SDL 1.2.6 P4 Non-HT @ 2.4Ghz Creative nVidia GeForce3 Ti200 64MB via Detonator XP 40.72 512MB DDR333 RAM

Share this post


Link to post
Share on other sites
I''ve read in several places that SDL locks to the refresh rate of my video adaptor, which is currently @ 75Hz(unless you can override it somehow). Unfortunately, I''ve just tried my test app again, which has the 10ms delay, and my kludgy fix has broken..

Share this post


Link to post
Share on other sites
If you could post some of your code it would be easier to see what is going on. I have been using SDL for a while and haven''t had that problem yet. Oh, and is it happening in both full screen and windowed?

"If you are not willing to try, you will never succeed! If you never succeed, are you really trying?"

Grellin

Share this post


Link to post
Share on other sites
Here it is...



/*
lesson5.cpp
Cone3D GFX with SDL lesson 5.
Made by Marius Andra 2002
http://cone3d.gamedev.net

You can use the code for anything you like.
Even in a commercial project.
But please let me know where it ends up.
I''m just curious. That''s all.
*/


#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>

#include "SDL.h"

#include "font.h"

// These two variables contain the dimensions of the playfield

int rows;
int cols;

SDL_Surface *screen; // The screen surface

SDL_Surface *balls[10];// The ball images

SDLFont *font1; // 2 fonts

SDLFont *font2;

char *playf; // The playfield itself


// The default width and height of the screen

int scrwidth=640, scrheight=480;
int centx=0,centy=0; // Used to center the grid nicely onto the screen


int bls=4; // Number of differently colored balls


int bla=0; // Used with the mouse...


int score=0; // The current score


// This function draws a surface onto the screen

void DrawIMG(SDL_Surface *img, int x, int y)
{
SDL_Rect dest;
dest.x = x;
dest.y = y;
SDL_BlitSurface(img, NULL, screen, &dest);
}

// This swaps two type char variables

void swap(char &r1, char &r2)
{
char temp=r1;
r1=r2;
r2=temp;
}

// Returns the color of a ball in the playfield.

inline char &grid(int a, int b)
{
return playf[a*cols+b];
}

// This function makes balls fall down and rows move left.

void collapse()
{
// Make balls fall down

int to=-1;
for(int j=0;j<cols;j++)
{
to=-1;
for(int i=rows-1;i>=0;i--)
{
if(to==-1 && grid(i,j)==-1) {to=i;}
else if(to!=-1 && grid(i,j)!=-1) {swap(grid(i,j),grid(to,j)); to--;}
}
}

// Move rows to the left

to=-1;
{
for(int j=0;j<cols;j++)
{
if(to==-1 && grid(rows-1,j)==-1)
{
to=j;
} else if(to!=-1 && grid(rows-1,j)!=-1) {
for(int i=0;i<rows;i++)
{
grid(i,to) = grid(i,j);
}
to++;
}
}

{
if(to!=-1)
{
for(int j=to;j<cols;j++)
{
for(int i=0;i<rows;i++)
{
grid(i,j)=-1;
}
}
}
}
}
}

// This is a recursive function that clears a bunch of balls.

// It uses the flood fill algorithm

int pick(int i, int j, int a)
{
int sum=1;
grid(i,j)=-1;
if(i != 0 && grid(i-1,j)==a) sum+=pick(i-1,j,a);
if(j != 0 && grid(i,j-1)==a) sum+=pick(i,j-1,a);
if(i<rows-1 && grid(i+1,j) == a) sum+=pick(i+1,j,a);
if(j<cols-1 && grid(i,j+1) == a) sum+=pick(i,j+1,a);
return sum;
}

// This function checks whether one ball is connected to an other

int bunch(int i,int j)
{
int a = grid(i,j);
if(i!=0 && grid(i-1,j) == a) return 1;
if(j!=0 && grid(i,j-1) == a) return 1;
if(i<rows-1 && grid(i+1,j) == a) return 1;
if(j<cols-1 && grid(i,j+1) == a) return 1;
return 0;
}

// Draw the screen

void DrawScene()
{
//SDL_ShowCursor(0); // Hide the mouse cursor

SDL_FillRect(screen,NULL,0x000000); // Clear the entire screen with black


// Draw the balls

for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
if(grid(i,j)!=-1) DrawIMG(balls[grid(i,j)],j*45+centx,i*45+centy);
}
}

// Draw some info and the score

drawString(screen,font1,1,scrheight-16,"SPACE restarts, gray + and - change the nr of balls (%d). Score: %d",bls,score);

// Draw the webspace url to the bottom-right of the screen

drawString(screen,font2,scrwidth-stringWidth(font2,"http://cone3d.gamedev.net"),

scrheight-16,"http://cone3d.gamedev.net");

SDL_Flip(screen); // Flip the buffers

//SDL_ShowCursor(1); // Show the cursor again

}

// This function resets the entire grid by adding random balls to it

void newgame()
{
// Reset the score

score=0;

// Fill the grid with random balls

for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
grid(i,j) = rand()%bls;
}
}

// Redraw the screen

DrawScene();
}

// This is our main function

int main(int argc, char *argv[])
{
srand(time(NULL)); // We initalize the random number generator


// Depending on the command line arguments given to this program,

// we change the screen resolution.

if(argc>1 && strcmp(argv[1],"640")==0) {scrwidth=640;scrheight=480;}
if(argc>1 && strcmp(argv[1],"800")==0) {scrwidth=800;scrheight=600;}
if(argc>1 && strcmp(argv[1],"1024")==0) {scrwidth=1024;scrheight=768;}
if(argc>1 && strcmp(argv[1],"1152")==0) {scrwidth=1152;scrheight=864;}
if(argc>1 && strcmp(argv[1],"1280")==0) {scrwidth=1280;scrheight=960;}
if(argc>1 && strcmp(argv[1],"1600")==0) {scrwidth=1600;scrheight=1200;}

// Initalize SDL

if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 )
{
printf("Unable to init SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);

// We load in a random ball image as the icon for this program

char tempstring[100];
sprintf(tempstring,"data/balls/%d.bmp",rand()%9+1);
SDL_WM_SetIcon(SDL_LoadBMP(tempstring),NULL);

// Initalize the video mode

screen=SDL_SetVideoMode(scrwidth,scrheight,32,SDL_HWSURFACE|SDL_HWPALETTE);
if ( screen == NULL )
{
printf("Unable to set %dx%d video: %s\n", scrwidth, scrheight, SDL_GetError());
exit(1);
}

// Load in the fonts

font1 = initFont("data/font1");
font2 = initFont("data/font2",1,1,0);

// Load in all the balls

for(int a=1;a<10;a++)
{
char temp[100];
sprintf(temp,"data/balls/%d.bmp",a);
balls[a-1]=SDL_LoadBMP(temp);
}

// Calculate how much balls fit on the screen with the current

// screen resolution

rows=(scrheight-16)/45;
cols=(scrwidth)/45;

// Calculate how much must the balls be movedso that they would be centered.

centx = (scrwidth-cols*45)/2;
centy = (scrheight-16-rows*45)/2;

// Allocate space for the playfield

playf = new char[rows*cols];

// Reset the score and generate the playfield

newgame();

// Loop a bit

int done=0;
while(done == 0)
{
DrawScene();
SDL_Delay(30);
SDL_Event event;

while ( SDL_PollEvent(&event) )
{
// If someone closes the prorgam, then quit

if ( event.type == SDL_QUIT ) { done = 1; }

if ( event.type == SDL_KEYDOWN )
{
// If someone presses ESC, then quit

if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; }
// Space restarts the game

if ( event.key.keysym.sym == SDLK_SPACE ) { newgame(); }
// The gray keypad + increases the nr. of different balls

if ( event.key.keysym.sym == SDLK_KP_PLUS ) { if(bls<9) {bls++;newgame();} }
// The gray keypad - decreases the nr. of different balls

if ( event.key.keysym.sym == SDLK_KP_MINUS ) { if(bls>3) {bls--;newgame(); } }
}
}

int x,y; // Used to hold the mouse coordinates

int x2,y2; // Used to hold the ball coordinates

float x3,y3; // Used to temporarily hold the ball coordinates

SDL_GetMouseState(&x, &y); // Get the mouse coords

x3=(((float)(x-centx))/45); // Get the ball coords

y3=(((float)(y-centy))/45);
if(x3<0 || y3<0) continue; // If they are negative, restart the loop

else {x2=(int)x3;y2=(int)y3;} // else store them as ints


// If the mouse button is released, make bla equal 1

if(!SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(1))
{
bla=1;
}

// If the mouse button was released the previous frame and is now

// held down, then ...

if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(1) && bla==1)
{
// Make bla equal zero so that we could get here only if we release

// the mouse button and then click it again.

bla=0;
// Investigate the clicked ball

if(x2>=0 && y2>=0 && x2<cols && y2<rows && grid(y2,x2) != -1 && bunch(y2,x2))
{
// If it really is clickable then get rid of the balls

int a=pick(y2,x2,grid(y2,x2));
// Increase the score by the (removed balls-2)^2

score+=(a-2)*(a-2);
// Make the balls fall down

collapse();
// And update the screen


}
}
}

// Let''s clean up...

freeFont(font1);
freeFont(font2);

return 0;
}



Ok its nicked from cone3d, but I made a modification of updating on every iteration of the event loop instead of just when the display gets updated. I know the initial method is more efficient, but I wanted to test something a bit more substantial than my single-bitmap-following-the-mouse-cursor demo.

Share this post


Link to post
Share on other sites
Just a glance at the code, haven''t loaded it yet, but it looks like you are making the cursor flicker on purpose. In your posted code you have the SDL_ShowCursor functions commented out so you shouldn''t have a problem with the flicker. If they were uncommented it would make it flicker becuase it would act like a strobe light.

DrawScene()
turn off
flip
turn on
...repeat.

again, not sure if that is where the problem is but you should turn your cursor back on when you are cleaning up at shut down. I''ll run the code and see what I come up with.

"If you are not willing to try, you will never succeed!"

Grellin

Share this post


Link to post
Share on other sites