Sign in to follow this  
Taymo

Generated surface not blitting

Recommended Posts

I am experimenting with bilinear filtering so I have two surfaces. The "noise" surface is loaded in. It is a bmp of a very noisey b&w. The other is "smoothed" which is where I'm putting the results of the filtering. Now noise will blit but smooth wont. What's weird is that I can pull a pixel from smoothed and it will be a normal value. Anyone see what's wrong? Ask about any functions that look confusing..

#pragma comment(lib,"SDL.lib")
#pragma comment(lib,"SDLMain.lib")


#include <sdl.h>
#include "SDL_Helper.h"

SDL_Surface *g_screen;
SDL_Surface *noise;
SDL_Surface *smoothed;

void BilinearFilter()
{
	unsigned int pixel, right, bottom, dig;
	pixel = right = bottom = dig = 0;

	for(int x = 2; x < noise->w; x++)
	{
		for(int y = 2; y < noise->h; y++)
		{
			pixel = GetPixel(noise, x, y);
			right = GetPixel(noise, x + 1, y);
			bottom = GetPixel(noise, x, y - 1);
			dig = GetPixel(noise, x - 1, y + 1);
			pixel = (pixel + right + bottom + dig) / 4;
			
			SetPixel(smoothed, x, y, pixel);
		}
	}
}
		

void Input()
{
	unsigned char *keys = SDL_GetKeyState(0);
}


void Render()
{
	SDL_FillRect(g_screen, 0, SDL_MapRGB(g_screen->format, 255,255,255));

	SDL_Rect dest;
	dest.x = 0;
	dest.y = 0;
	SDL_BlitSurface(noise, 0, g_screen, &dest);
	dest.x = 300;
	dest.y = 300;
	SDL_BlitSurface(smoothed, 0, g_screen, &dest);

	SDL_Flip(g_screen);
}


bool InitSDL()
{
	noise = SDL_LoadBMP("noise.bmp");

	SDL_Color color = {0,0,0,0};
	smoothed = CreateEmptySurface(noise->w, noise->h, 24);

	if(SDL_Init(SDL_INIT_VIDEO))
	{
		printf("Couldn't initalize SDL!");
		return 0;
	}
	if((g_screen = SDL_SetVideoMode(640,480,24,SDL_SWSURFACE | SDL_DOUBLEBUF)) == NULL)
	{
		printf("Couldn't set video mode! Quitting...");
		SDL_Quit();	
		return 0;
	}
	return 1;
}



bool MainLoop()
{
	SDL_Event event;
	while ( SDL_PollEvent(&event) ) 
	{
		if ( event.type == SDL_QUIT ) 
		{
			return false;
		}
		if ( event.type == SDL_KEYDOWN ) 
		{
			if ( event.key.keysym.sym == SDLK_ESCAPE ) 
			{
				return false;
			}
		}
	}
	Input();
	Render();
	return true;
}

int main(int argc, char** argv)
{
	InitSDL();
	BilinearFilter();
	while(MainLoop())
	
	SDL_FreeSurface(g_screen);
	SDL_Quit();
	return true;

}

Share this post


Link to post
Share on other sites
My guess is that the problem is in the stuff we can't see, like how the smoothed surface is created, the surface format, or how the pixels are written.

As an aside, I hope you're aware that what you've posted isn't actually bilinear filtering, just a windowed average. Generally there would typically be no filtering applied between 2 equally-sized surfaces.

Share this post


Link to post
Share on other sites
Oh yea, I wan't worried about the filter quite yet. I know it's not what bilinear filitering is but it's something I could see. Here is the .cpp for ALL the functions not listed in the previous post.


//These functions are to be incorperated into the engine class

#include <sdl.h>
#include "SDL_Helper.h"

SDL_Color IndexToColor(int index, SDL_PixelFormat *fmt)
{
SDL_Color color;
SDL_GetRGB(index, fmt, &color.r, &color.g, &color.b);
return color;
}

void FPSTest(bool capped)
{
static unsigned long fps;
static long counter;
char buf[50];

counter++;
if(fps + 1000 < SDL_GetTicks())
{
if(capped)
sprintf(buf,"Capped at %d FPS",counter);
else
sprintf(buf,"%d FPS",counter);
SDL_WM_SetCaption(buf,0); //printf("FPS: %d", counter);
fps = SDL_GetTicks();
counter = 0;
}
}

unsigned long ReturnFPS()
{
static unsigned long fps;
static long counter;
static unsigned long rtn = 0;

counter++;
if(fps + 1000 < SDL_GetTicks())
{
rtn = counter;
fps = SDL_GetTicks();
counter = 0;
}
return rtn;
}

SDL_Surface* CreateEmptySurface(int w, int h, int bpp)
{
SDL_Surface *temp = 0;
//Spcift the color masks
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
int rmask = 0xff000000;
int gmask = 0x00ff0000;
int bmask = 0x0000ff00;
int amask = 0x000000ff;
#else
int rmask = 0x000000ff;
int gmask = 0x0000ff00;
int bmask = 0x00ff0000;
int amask = 0xff000000;
#endif

temp = SDL_CreateRGBSurface(SDL_SWSURFACE, w,h, bpp, rmask,gmask,bmask,amask);
return temp;
}

void SaveScreenShot(const char *name, int count, SDL_Surface *g_screen)
{
char buffer[256];
sprintf(buffer, "%s%d.bmp", name, count);
SDL_SaveBMP(g_screen, buffer);
}

void SetPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{

Lock(surface);
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

switch(bpp)
{
case 1:
*p = pixel;
break;

case 2:
*(Uint16 *)p = pixel;
break;

case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;

case 4:
*(Uint32 *)p = pixel;
break;
}
Unlock(surface);
}

Uint32 GetPixel(SDL_Surface *surface, int x, int y)
{
SDL_Color color = {0,0,0,0};

if(surface->w < x || surface->h < y)
return 0;

Lock(surface);
Uint32 pixel;
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

switch(bpp)
{
case 1:
pixel = *p;
break;

case 2:
pixel = *(Uint16 *)p ;
break;

case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
color.r = p[0];
color.g = p[1];
color.b = p[2];
pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b);
}
else
{
color.r = p[2];
color.g = p[1];
color.b = p[0];
pixel = SDL_MapRGB(surface->format, color.r, color.g, color.b);
}
break;

case 4:
pixel = *(Uint32 *)p;
break;
}
Unlock(surface);
return pixel;
}

void Lock(SDL_Surface *lockee)
{
if(SDL_MUSTLOCK(lockee))
{
SDL_LockSurface(lockee);
}
}

void Unlock(SDL_Surface *lockee)
{
if(SDL_MUSTLOCK(lockee))
{
SDL_UnlockSurface(lockee);
}
}

Share this post


Link to post
Share on other sites
It looks like the 'noise' surface may be an 8-bit surface. If its palette is set properly(smooth gradient) you may be able to manipulate the pixels like that to create a pixel with the average color.

But that pixel won't have the same pixel format as the 'smoothed' surface (8-bit index versus 24-bit RGB).

So you need to extract the RGB components using:
  SDL_GetRGB(pixel,noise->format,&r,&g,&b). 

Then convert/map to 24bit format using:
   pixel = SDL_MapRGB(smooth->format,r,g,b)
SetPixel(smoothed, x, y, pixel);


If the noise image palette runs from black to white, you cheat by using:
pixel = SDL_MapRGB(smooth->format,pixel,pixel,pixel)

Alternatively, if you make the 'smooth' surface 8-bit and set its palette to the same as the noise,you can just use your original code.

If the 'noise' image isn't paletted, you have to get the components of each sample point and manipulate them correspondingly:
redFinal = (r1+r2+r3+r3)/4,blueFinal=(b1+b2+b3+b3)/4,...

Finally, remove or make sure the colorkey on the 'smoothed' surface is not black or white.

Other observations:
(re.main())
If 'g_screen' points to the surface returned by SDL_SetVideoMode(), you should not call SDL_FreeSurface() on it. That will be done automatically by SDL_Quit().

(re.main())
No need to put MainLoop in a 'while' loop

(re.BilinearFilter())
Use SDL_LockSurface() then SDL_UnlockSurface() all surfaces that use getpixel/putpixel since they require pixel level access. Usually you don't have to do this with software surface, but can cause crashes if not done on hardware surfaces

(re.BilinearFilter())
Check your loop extents and other off-by-one situations:
for(int x = 1; x < (noise->w-1); x++){
for(int y = 1; y < (noise->h-1); y++){

(re.InitSDL())
Try not to use any SDL function before calling SDL_Init(). It may work now, but will usually fail when dealing with HW surfaces.

Good Luck.

[Edited by - Jack Sotac on September 28, 2006 6:58:08 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this