OpenGL and SDL

Started by
16 comments, last by _sim 18 years, 6 months ago
Hey everyone, I'm working on a very basic game engine and trying to get some rendering things down but I've run into some problems. I'm using a combo of SDL and OpenGL for the graphics and SDL_ttf for text, but things don't seem to be working properly. I'm guessing the main problem is that I don't fully understand graphics (SDL and OpenGL) and I'm just using code from the NeHe tutorials without understanding what exactly it's doing. For example, calls such as: SDL_GL_SwapBuffers(); SDL_Flip(screen); SDL_BlitSurface(textSurface, NULL, screen, &textLocation); I'm not too sure what they do. I have a semi-idea after doing some reading, but all defenitions involve the term itself. For example, SDL_Flip will be listed in the man pages as Flip the buffer. Or SDL_BlitSurface will be defined as blitting a surface. That really doesn't help me understand what exactly they are doing since I don't know what a "blit" is in the first place. Is there a glossary someone can point out that will help me understand some of the basics of the terminology and how it all works at a hardware/software level? My second question is regarding the problems I'm having. I'm trying to get SDL_ttf to work as well as OpenGL. When I have OpenGL working, the 2D SDL_ttf iterms will not work. I enable SDL in one of 3 ways and each gives a different result with how things will work:

mSurface = SDL_SetVideoMode(640, 480, 32, SDL_OPENGLBLIT | SDL_HWSURFACE | SDL_DOUBLEBUF );
mSurface = SDL_SetVideoMode(640, 480, 32, SDL_OPENGL | SDL_HWSURFACE | SDL_DOUBLEBUF );
mSurface = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );
The first one will allow me to call SDL_GL_SwapBuffers() and SDL_BlitSurface(textSurface, NULL, screen, &textLocation) and SDL_Flip but will only render only a white screen. The second will crash on my SDL_Flip() call in my Renderer. The Third will let me render my SDL_ttf and 2D stuff without any problems, but and OpenGL stuff obviously doesn't work. How do I make it so that I can get both my 2D SDL and 3D OpenGL stuff working at the same time so I can render my FPS counter and my cube at the same time? I know this is very basic stuff, but I'm having problems finding good resources that explain SDL/OpenGL combo for a total beginner. I guess I will also cross post this in the OGL forums as someone there might be able to offer advice on the OGL side. Thanks! Sim
Advertisement
This site gives very in-depth insights into what SDL functions actually do in non-programming terms: http://manuals.thexdershome.com/SDL-1.2.5/html/

This site provides an excellent resource for getting SDL and OpenGL to work together: http://manuals.thexdershome.com/SDL-1.2.5/html/guidevideoopengl.html
these may help if you don't know the terms (not sdl/gl specific):

Blit
Double Buffering
[size="1"]
So does that mean that:

SDL_GL_SwapBuffers();
SDL_Flip(screen);

Are both using double buffering, but SDL_GL_SwapBuffers() swaps the OpenGL Buffers and SDL_Flip() swaps the 2D Buffers?

Should I really have two sets of double buffers (one for OpenGL and one for the 2D stuff?) or should I be able to combine them somehow and only have to swap one set of buffers?

I'm taking a guess, but can I blit my 3D stuff onto the 2d buffer and then just flip that? In that case, what's the benefit of doing 3D at all? Just because it's easier to do the math and do things in actual 3D and then flatten them?

Any ideas with regards to my specific problem of how to get the 3D and 2D stuff working together?

Thanks and guys!

Sim
Here's a complete example of how to use OpenGL with SDL. In addition, there are examples of doing 3D as well as 2D drawing.

// We need these header files#include <SDL.h>#include <SDL_OpenGL.h>// Link in all of the required libraries// Don't forget to change the project settings to Multi-theaded DLL as well#pragma comment(lib, "sdlmain.lib")#pragma comment(lib, "sdl.lib")#pragma comment(lib, "opengl32.lib")#pragma comment(lib, "glu32.lib")void Draw2DStuff();void Draw3DStuff();// Set up a 2D vieportvoid Set2DView(GLdouble Left, GLdouble Top, GLdouble Right, GLdouble Bottom, GLdouble zNear = -1, GLdouble zFar = 1){	// Set the current viewport	glViewport((GLint)Left, (GLint)Top, (GLint)Right, (GLint)Bottom);	// Select the projection matrix	glMatrixMode(GL_PROJECTION);	// Reset the projection matrix	glLoadIdentity();	// Set our 2D vieport	glOrtho(Left, Right, Bottom, Top, zNear, zFar);	// Select the modelview matrix	glMatrixMode(GL_MODELVIEW);	// Reset the modelview matrix	glLoadIdentity();}// Set up a 3D vieportvoid Set3DView(GLint X, GLint Y, GLint Width, GLint Height, GLdouble zNear = .1, GLdouble zFar = 100){	// Set the current viewport	glViewport(X, Y, Width, Height);	// Select the projection matrix	glMatrixMode(GL_PROJECTION);	// Reset the projection matrix	glLoadIdentity();	// Calculate the aspect ratio of the window	gluPerspective(45.0f, (GLfloat)Width/(GLfloat)Height, zNear, zFar);	// Select the modelview matrix	glMatrixMode(GL_MODELVIEW);	// Reset the modelview matrix	glLoadIdentity();}// Clears the screen and resets the buffersvoid ClearScreen(){	// Clear the screen	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Resets the current drawing matrix	glLoadIdentity();}// Flips the OpenGL buffervoid FlipScreen(){	// Swap the OpenGL frame buffers	SDL_GL_SwapBuffers();}int main( int argc, char* argv[] ){	// Initialize SDL and check for any errors	if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )		printf("Error: %s", SDL_GetError() );	// Create the main SDL rendering surface and check for any errors	SDL_Surface* screen = SDL_SetVideoMode( 640, 480, 0, SDL_OPENGL );	if( !screen )		printf("Error: %s", SDL_GetError() );	// Holds the current event being processed	SDL_Event event;	// Lets us know when we are done rendering	SDL_bool isRunning = SDL_TRUE;	// Loop while we are running	while(isRunning)	{		// Process all events for this frame		while(SDL_PollEvent(&event))		{			// Handle the window being closed			if(event.type == SDL_QUIT)				isRunning = SDL_FALSE;		}		// Clears and resets the window's buffers		ClearScreen();		// Drawing stuff here		Draw3DStuff();		Draw2DStuff();		// Flip the OpenGL buffer		FlipScreen();	}	// Cleanup SDL	SDL_Quit();	// Standard return value	return 0;}void Draw3DStuff(){	// Save the old matrix	glPushMatrix();	{		// Set the 3D viewport		Set3DView(0, 0, 640, 480);		// Fice units into the screen		glTranslatef(0.0f, 0.0f, -5.0f);		// Begin Drawing Triangles		glBegin(GL_TRIANGLES);		{			// Set The Color To Red			glColor3f(1.0f, 0.0f, 0.0f);			// Move Up One Unit From Center (Top Point)			glVertex3f(0.0f, 1.0f, 0.0f);			// Set The Color To Green			glColor3f(0.0f, 1.0f, 0.0f);			// Left And Down One Unit (Bottom Left)			glVertex3f(-1.0f, -1.0f, 0.0f);			// Set The Color To Blue			glColor3f(0.0f, 0.0f, 1.0f);						// Right And Down One Unit (Bottom Right)			glVertex3f(1.0f, -1.0f, 0.0f);		}		// End drawing		glEnd();	}	// Restore the old matrix	glPopMatrix();}void Draw2DStuff(){	// Save the old matrix	glPushMatrix();	{		// Set the viewport		Set2DView(0, 0, 640, 480);		// Begin Drawing Triangles		glBegin(GL_TRIANGLES);		{			// Set The Color To Red			glColor3f(1.0f, 0.0f, 0.0f);			// Move Up One Unit From Center (Top Point)			glVertex2d(50, 0);			// Set The Color To Blue			glColor3f(0.0f, 0.0f, 1.0f);			// Left And Down One Unit (Bottom Left)			glVertex2d(100, 50);			// Set The Color To Green			glColor3f(0.0f, 1.0f, 0.0f);						// Right And Down One Unit (Bottom Right)			glVertex2d(0, 50);		}		// End drawing		glEnd();	}	// Restore the old matrix	glPopMatrix();}


When you use OpenGL with SDL, you cannot use SDL's blitting functions on the screen. That is why there is no SDL_Flip, that function is just for when you are doing 2D blitting with SDL and not using OpenGL. If you want to do 2D stuff, it must be though OpenGL, as shown in that example.

So, going back to your original post, you shouldn not use the SDL_OPENGLBLIT for it is no longer used in SDL and was considered a "hack". You will be getting massive performance hits if you try to use that. When SDL_OPENGL is not passed in, then you are doing SDL blitting on a 2D surface. When SDL_OPENGL is passed in, you are drawing in OpenGL.

SDL_GL_SwapBuffers(); => Only for OpenGL
SDL_Flip(screen); => Only for SDL
SDL_BlitSurface(textSurface, NULL, screen, &textLocation); => for SDL

Since those tutorials are old, they do show the wrong stuff now. If you want to use SDL_ttf with OpenGL, take a look at this thread. In any event the process of going from a SDL_Surface to an OpenGL texture can be found here as well.

[edit]Here's an adaption of C-Junkie's code for SDL_ttf and OpenGL
// We need these header files#include <SDL.h>#include <SDL_OpenGL.h>#include <SDL_ttf.h>#include <string>#include <math.h>// Link in all of the required libraries// Don't forget to change the project settings to Multi-theaded DLL as well#pragma comment(lib, "sdlmain.lib")#pragma comment(lib, "sdl.lib")#pragma comment(lib, "SDL_ttf.lib")#pragma comment(lib, "opengl32.lib")#pragma comment(lib, "glu32.lib")void Draw2DStuff(TTF_Font *font);void Draw3DStuff();int nextpoweroftwo(int x);int round(double x);// Set up a 2D vieportvoid Set2DView(GLdouble Left, GLdouble Top, GLdouble Right, GLdouble Bottom, GLdouble zNear = -1, GLdouble zFar = 1){	// Set the current viewport	glViewport((GLint)Left, (GLint)Top, (GLint)Right, (GLint)Bottom);	// Select the projection matrix	glMatrixMode(GL_PROJECTION);	// Reset the projection matrix	glLoadIdentity();	// Set our 2D vieport	glOrtho(Left, Right, Bottom, Top, zNear, zFar);	// Select the modelview matrix	glMatrixMode(GL_MODELVIEW);	// Reset the modelview matrix	glLoadIdentity();}// Set up a 3D vieportvoid Set3DView(GLint X, GLint Y, GLint Width, GLint Height, GLdouble zNear = .1, GLdouble zFar = 100){	// Set the current viewport	glViewport(X, Y, Width, Height);	// Select the projection matrix	glMatrixMode(GL_PROJECTION);	// Reset the projection matrix	glLoadIdentity();	// Calculate the aspect ratio of the window	gluPerspective(45.0f, (GLfloat)Width/(GLfloat)Height, zNear, zFar);	// Select the modelview matrix	glMatrixMode(GL_MODELVIEW);	// Reset the modelview matrix	glLoadIdentity();}// Clears the screen and resets the buffersvoid ClearScreen(){	// Clear the screen	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Resets the current drawing matrix	glLoadIdentity();}// Flips the OpenGL buffervoid FlipScreen(){	// Swap the OpenGL frame buffers	SDL_GL_SwapBuffers();}void SDL_GL_RenderText(const char *text, TTF_Font *font, SDL_Color color, SDL_Rect location){	SDL_Surface *initial;	SDL_Surface *intermediary;	int w, h;	GLuint texture;	// Use SDL_TTF to render our text	initial = TTF_RenderText_Blended(font, text, color);	// Convert the rendered text to a known format	w = nextpoweroftwo(initial->w);	h = nextpoweroftwo(initial->h);	// Create an intermediary surface	intermediary = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);	// Blit the initial surface onto our new one	SDL_BlitSurface(initial, 0, intermediary, 0);	/* Tell GL about our new texture */	glGenTextures(1, &texture);	glBindTexture(GL_TEXTURE_2D, texture);	glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, intermediary->pixels);	// GL_NEAREST looks horrible, if scaled...	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);		// prepare to render our texture	glEnable(GL_TEXTURE_2D);	glBindTexture(GL_TEXTURE_2D, texture);	// Reset the color	glColor3f(1.0f, 1.0f, 1.0f);		// Draw the font now onto a quad, changed the glTexCoord2f's so it's rendered right	glBegin(GL_QUADS);		glTexCoord2f(0.0f, 0.0f); 		glVertex2d(location.x, location.y);		glTexCoord2f(1.0f, 0.0f); 		glVertex2d(location.x + w, location.y);		glTexCoord2f(1.0f, 1.0f); 		glVertex2d(location.x + w, location.y + h);		glTexCoord2f(0.0f, 1.0f); 		glVertex2d(location.x, location.y + h);	glEnd();	// Bad things happen if we delete the texture before it finishes	glFinish();	// Clean up used surfaces and textures	SDL_FreeSurface(initial);	SDL_FreeSurface(intermediary);	glDeleteTextures(1, &texture);}int main( int argc, char* argv[] ){	// Initialize SDL and check for any errors	if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )		printf("Error: %s", SDL_GetError() );	// Set up the SDL_TTF	if( TTF_Init() == -1 )		printf("Error: %s", TTF_GetError() );	// Create the main SDL rendering surface and check for any errors	SDL_Surface* screen = SDL_SetVideoMode( 640, 480, 0, SDL_OPENGL );	if(!screen)		printf("Error: %s", SDL_GetError() );	// Create a font for us, use the windows fonts	TTF_Font *font = TTF_OpenFont( "Arial.ttf", 24 );	if(!font)		return -1;	// Holds the current event being processed	SDL_Event event;	// Lets us know when we are done rendering	SDL_bool isRunning = SDL_TRUE;	// Loop while we are running	while(isRunning)	{		// Process all events for this frame		while(SDL_PollEvent(&event))		{			// Handle the window being closed			if(event.type == SDL_QUIT)				isRunning = SDL_FALSE;		}		// Clears and resets the window's buffers		ClearScreen();		// Drawing stuff here		Draw3DStuff();		Draw2DStuff(font);		// Flip the OpenGL buffer		FlipScreen();	}	// Close the font	TTF_CloseFont(font);	// Cleanup SDL_ttf	TTF_Quit();	// Cleanup SDL	SDL_Quit();	// Standard return value	return 0;}void Draw3DStuff(){	// Save the old matrix	glPushMatrix();	{		// Set the 3D viewport		Set3DView(0, 0, 640, 480);		// Fice units into the screen		glTranslatef(0.0f, 0.0f, -5.0f);		// Begin Drawing Triangles		glBegin(GL_TRIANGLES);		{			// Set The Color To Red			glColor3f(1.0f, 0.0f, 0.0f);			// Move Up One Unit From Center (Top Point)			glVertex3f(0.0f, 1.0f, 0.0f);			// Set The Color To Green			glColor3f(0.0f, 1.0f, 0.0f);			// Left And Down One Unit (Bottom Left)			glVertex3f(-1.0f, -1.0f, 0.0f);			// Set The Color To Blue			glColor3f(0.0f, 0.0f, 1.0f);						// Right And Down One Unit (Bottom Right)			glVertex3f(1.0f, -1.0f, 0.0f);		}		// End drawing		glEnd();	}	// Restore the old matrix	glPopMatrix();}void Draw2DStuff(TTF_Font *font){	// Save the old matrix	glPushMatrix();	{		// Set the viewport		Set2DView(0, 0, 640, 480);		// Yellow font color		SDL_Color color = {255, 255, 0, 0};		// Location to draw the text (last two can be anything)		SDL_Rect location = {0, 0, 0, 0};		// Create the texture here		SDL_GL_RenderText("This is a text", font, color, location);		// Begin Drawing Triangles		glBegin(GL_TRIANGLES);		{			// Set The Color To Red			glColor3f(1.0f, 0.0f, 0.0f);			// Move Up One Unit From Center (Top Point)			glVertex2d(150, 100);			// Set The Color To Blue			glColor3f(0.0f, 0.0f, 1.0f);			// Left And Down One Unit (Bottom Left)			glVertex2d(200, 150);			// Set The Color To Green			glColor3f(0.0f, 1.0f, 0.0f);						// Right And Down One Unit (Bottom Right)			glVertex2d(100, 150);		}		// End drawing		glEnd();	}	// Restore the old matrix	glPopMatrix();}int round(double x){	return (int)(x + 0.5);}int nextpoweroftwo(int x){	double logbase2 = log((double)x) / log((double)2);	return round( pow((double)2, (double)ceil(logbase2)));}


[Edited by - Drew_Benton on October 8, 2005 2:04:14 PM]
Great reply, Drew.

I understand what is being done, but for some reason the text isn't being displayed in my program.

I just took a lot of the stuff you did and modified it and placed it into my program. I'm not executing the exact code you did. Have you tested the code you provided in the second snippet? Does it work without problems?

I guess this brings me to my next question, how do you debug OpenGL? I mean what you wrote makes perfect sense. But how do I know where things are going wrong? All I can test is that the Blit is returning a non-error value, which it is (0). So how exactly do I figure out what is wrong?

Thanks again!
Quote:Original post by _sim
I just took a lot of the stuff you did and modified it and placed it into my program. I'm not executing the exact code you did. Have you tested the code you provided in the second snippet? Does it work without problems?


Yes, and actually that was my project I was working on at the moment before I saw the thread. I just went back to smart idiot's code and integrated it into my project to make it a little more easy to understand.

What problems are you having with that code? It worked flawlessly for me.

Quote:I guess this brings me to my next question, how do you debug OpenGL? I mean what you wrote makes perfect sense. But how do I know where things are going wrong? All I can test is that the Blit is returning a non-error value, which it is (0). So how exactly do I figure out what is wrong?


That just comes with experience really. Just lots of practice and thinking about the problem, and down the line you will be able to know what's going on. I mean most of the time when I have a problem, comment out everything and start slowly adding in stuff to see where the problem is first if I can't find it, then work my way from there. Yesterday when I did that code, it was crashing on the text creation stuff EVERY time and it had me stumped. Then I noticed I was creating the font before I had created the main SDL video mode. Order matters! Remember that with SDL, because it can throw you for a big loop and cause errors that you will have no idea where they are coming from.

When you say Blit is returning 0, are you using SDL_OPENGLBLIT still? If you are, then that code might not work in your case, becasue its for when SDL is using pure OpenGL with SDL_OPENGL (you should be able to copy paste that whole source dump into a new project and compile and run with no problems, just make sure uou set the C++ Code Generation to MultThreaded DLL).

So first off, make sure you are initilizing stuff in this order:
SDL_INITSDL_TTF_INITCreat SDL Video surface with SDL_SetVideoModeCreate fonts and load bmps, etc.. after this point...Free fonts, bmps, etc...DEINIT_TTFDEINIT_SDLEXIT program

I cannot stress how many problems arise from things being in the wrong order, so check that out. Going back to your program, if you are using SDL_OPENGL, then you cannot use that BLitSurface onto the primary display surface, you will have to convert it to a OpenGL texture and draw it that way. Can you paste some sections of revelant code to see what you are doing?

Here's the current code again with a FPS counter:
// We need these header files#include <SDL.h>#include <SDL_OpenGL.h>#include <SDL_ttf.h>#include <string>#include <sstream>#include <math.h>// Link in all of the required libraries// Don't forget to change the project settings to Multi-theaded DLL as well#pragma comment(lib, "sdlmain.lib")#pragma comment(lib, "sdl.lib")#pragma comment(lib, "SDL_ttf.lib")#pragma comment(lib, "opengl32.lib")#pragma comment(lib, "glu32.lib")void Draw2DStuff(TTF_Font *font);void Draw3DStuff();int nextpoweroftwo(int x);int CalculateFrameRate();// Set up a 2D vieportvoid Set2DView(GLdouble Left, GLdouble Top, GLdouble Right, GLdouble Bottom, GLdouble zNear = -1, GLdouble zFar = 1){	// Set the current viewport	glViewport((GLint)Left, (GLint)Top, (GLint)Right, (GLint)Bottom);	// Select the projection matrix	glMatrixMode(GL_PROJECTION);	// Reset the projection matrix	glLoadIdentity();	// Set our 2D vieport	glOrtho(Left, Right, Bottom, Top, zNear, zFar);	// Select the modelview matrix	glMatrixMode(GL_MODELVIEW);	// Reset the modelview matrix	glLoadIdentity();}// Set up a 3D vieportvoid Set3DView(GLint X, GLint Y, GLint Width, GLint Height, GLdouble zNear = .1, GLdouble zFar = 100){	// Set the current viewport	glViewport(X, Y, Width, Height);	// Select the projection matrix	glMatrixMode(GL_PROJECTION);	// Reset the projection matrix	glLoadIdentity();	// Calculate the aspect ratio of the window	gluPerspective(45.0f, (GLfloat)Width/(GLfloat)Height, zNear, zFar);	// Select the modelview matrix	glMatrixMode(GL_MODELVIEW);	// Reset the modelview matrix	glLoadIdentity();}// Clears the screen and resets the buffersvoid ClearScreen(){	// Clear the screen	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Resets the current drawing matrix	glLoadIdentity();}// Flips the OpenGL buffervoid FlipScreen(){	// Swap the OpenGL frame buffers	SDL_GL_SwapBuffers();}void SDL_GL_RenderText(const char *text, TTF_Font *font, SDL_Color color, SDL_Rect location){	SDL_Surface *initial;	SDL_Surface *intermediary;	GLint w, h;	GLuint texture;	// Use SDL_TTF to render our text	initial = TTF_RenderText_Blended(font, text, color);	// Convert the rendered text to a known format	w = nextpoweroftwo(initial->w);	h = nextpoweroftwo(initial->h);	// Create an intermediary surface	intermediary = SDL_CreateRGBSurface(0, w, h, 32, initial->format->Rmask, initial->format->Gmask, initial->format->Bmask, initial->format->Amask);	// Blit the initial surface onto our new one	SDL_BlitSurface(initial, 0, intermediary, 0);	// Create our new texture	glGenTextures(1, &texture);	glBindTexture(GL_TEXTURE_2D, texture);	glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, intermediary->pixels);	// GL_NEAREST looks horrible, if scaled...	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);		// prepare to render our texture	glEnable(GL_TEXTURE_2D);	glBindTexture(GL_TEXTURE_2D, texture);	// Reset the color	glColor3f(1.0f, 1.0f, 1.0f);		// Draw the font now onto a quad, changed the glTexCoord2f's so it's rendered right	glBegin(GL_QUADS);		glTexCoord2f(0.0f, 0.0f); 		glVertex2d(location.x, location.y);		glTexCoord2f(1.0f, 0.0f); 		glVertex2d(location.x + w, location.y);		glTexCoord2f(1.0f, 1.0f); 		glVertex2d(location.x + w, location.y + h);		glTexCoord2f(0.0f, 1.0f); 		glVertex2d(location.x, location.y + h);	glEnd();	// Bad things happen if we delete the texture before it finishes	glFinish();	// Clean up used surfaces and textures	SDL_FreeSurface(initial);	SDL_FreeSurface(intermediary);	glDeleteTextures(1, &texture);}int main( int argc, char* argv[] ){	// Initialize SDL and check for any errors	if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )		printf("Error: %s", SDL_GetError() );	// Set up the SDL_TTF	if( TTF_Init() == -1 )		printf("Error: %s", TTF_GetError() );	// Create the main SDL rendering surface and check for any errors	SDL_Surface* screen = SDL_SetVideoMode( 640, 480, 0, SDL_OPENGL );	if(!screen)		printf("Error: %s", SDL_GetError() );	// Create a font for us, use the windows fonts	TTF_Font *font = TTF_OpenFont( "Arial.ttf", 24 );	if(!font)		return -1;	// Holds the current event being processed	SDL_Event event;	// Lets us know when we are done rendering	SDL_bool isRunning = SDL_TRUE;	// Loop while we are running	while(isRunning)	{		// Process all events for this frame		while(SDL_PollEvent(&event))		{			// Handle the window being closed			if(event.type == SDL_QUIT)				isRunning = SDL_FALSE;		}		// Clears and resets the window's buffers		ClearScreen();		// Drawing stuff here		Draw3DStuff();		Draw2DStuff(font);		// Flip the OpenGL buffer		FlipScreen();	}	// Close the font	TTF_CloseFont(font);	// Cleanup SDL_ttf	TTF_Quit();	// Cleanup SDL	SDL_Quit();	// Standard return value	return 0;}void Draw3DStuff(){	// Save the old matrix	glPushMatrix();	{		// Set the 3D viewport		Set3DView(0, 0, 640, 480);		// Fice units into the screen		glTranslatef(0.0f, 0.0f, -5.0f);		// Begin Drawing Triangles		glBegin(GL_TRIANGLES);		{			// Set The Color To Red			glColor3f(1.0f, 0.0f, 0.0f);			// Move Up One Unit From Center (Top Point)			glVertex3f(0.0f, 1.0f, 0.0f);			// Set The Color To Green			glColor3f(0.0f, 1.0f, 0.0f);			// Left And Down One Unit (Bottom Left)			glVertex3f(-1.0f, -1.0f, 0.0f);			// Set The Color To Blue			glColor3f(0.0f, 0.0f, 1.0f);						// Right And Down One Unit (Bottom Right)			glVertex3f(1.0f, -1.0f, 0.0f);		}		// End drawing		glEnd();	}	// Restore the old matrix	glPopMatrix();}void Draw2DStuff(TTF_Font *font){	int fps = CalculateFrameRate();	// Save the old matrix	glPushMatrix();	{		// Set the viewport		Set2DView(0, 0, 640, 480);		// Yellow font color		SDL_Color color = {255, 255, 0, 0};		// Location to draw the text (last two can be anything)		SDL_Rect location = {0, 0, 0, 0};		std::stringstream ss;		ss << "Frames per second: " << fps;		// Create the texture here		SDL_GL_RenderText(ss.str().c_str(), font, color, location);		// Begin Drawing Triangles		glBegin(GL_TRIANGLES);		{			// Set The Color To Red			glColor3f(1.0f, 0.0f, 0.0f);			// Move Up One Unit From Center (Top Point)			glVertex2d(150, 100);			// Set The Color To Blue			glColor3f(0.0f, 0.0f, 1.0f);			// Left And Down One Unit (Bottom Left)			glVertex2d(200, 150);			// Set The Color To Green			glColor3f(0.0f, 1.0f, 0.0f);						// Right And Down One Unit (Bottom Right)			glVertex2d(100, 150);		}		// End drawing		glEnd();	}	// Restore the old matrix	glPopMatrix();}int nextpoweroftwo(int x){	double logbase2 = log((double)x) / log((double)2);	return (int)( pow((double)2, (double)ceil(logbase2)) + .5);}int CalculateFrameRate(){	static int fps = 0;	static float framesPerSecond    = 0.0f;	static float lastTime			= 0.0f;	float currentTime = SDL_GetTicks() * 0.001f;	++framesPerSecond;	if( currentTime - lastTime > 1.0f )	{		lastTime = currentTime;		fps = int(framesPerSecond);		framesPerSecond = 0;	}	return fps;}

And here's the screenshot in action: Free Image Hosting at www.ImageShack.us
I am using only the SDL_OPENGL flag when initializing my window. I've tried my best to mimic the code (in a lot of places, copy/paste for now) you provided into my basic engine in order just to get it working. And then I will go from there and make my modifications to make it suit my exact needs/style.

So here's how I init my window at the moment:

	// init the video window stuff	if (SDL_Init(SDL_INIT_VIDEO) == -1)	{		std::cout &lt;&lt; "The applicaiton failed because " &lt;&lt; SDL_GetError() &lt;&lt; std::endl;		exit(1);	}	// init the font stuff	if (TTF_Init() == -1)	{		std::cout &lt;&lt; "The SDL_TTF init failed because " &lt;&lt; TTF_GetError() &lt;&lt; std::endl;	}	// open up a window	//mSurface = SDL_SetVideoMode(mWidth, mHeight, 32, SDL_OPENGLBLIT | SDL_HWSURFACE | SDL_DOUBLEBUF );	//mSurface = SDL_SetVideoMode(mWidth, mHeight, 32, SDL_OPENGL | SDL_HWSURFACE | SDL_DOUBLEBUF );	//mSurface = SDL_SetVideoMode(mWidth, mHeight, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );	mSurface = SDL_SetVideoMode(mWidth, mHeight, 32, SDL_OPENGL );	SDL_WM_SetCaption("ProjectX001", NULL);	// set the appropriate OGL attributes    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 32 );    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );


As you can see, I was experimenting with loading the VideoMode with different flags, but for now I'm only using OpenGL until I can understand things like HWSURFACE, etc. I've also set the attributes to allow double buffering in OpenGL.

In my Renderer I have tossed a bunch of FPS printing stuff for now, just to test it out and make it work. I'll paste some of those snippets now:

cRender::cRender():	mCurrentTick(SDL_GetTicks()),	mFramesRendered(0)	//mLastRenderTick(SDL_GetTicks()){	sprintf(mFPSStr, "FPS: 0");	mFPSFont = TTF_OpenFont("D:\\Work\\Programming\\ProjectX001\\build\\Debug\\data\\fonts\\ARIAL.TTF", 24);}


I know I have absolute paths right now, but I just tossed it in for the time being. I will fix that later. But as you can see, I have my font loaded. This method was working before when I was using the SDL_OPENGLBLIT, so I'm guessing the font is fine. It must be elsewhere.

void cRender::Render(){	// increase the frame counter	++mFramesRendered;#ifdef DEBUG	PrintFPS();#endif // DEBUG	//SDL_Surface* screen = gWinManager-&gt;GetSurface();	// swap that buffer!  That's right! Uh-huh!	SDL_GL_SwapBuffers();	//SDL_Flip(screen);	// clear the buffer for the next render cycle    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );}


This is my actual render function which just swaps the buffers which were written to by all my render-able objects. If we're in DEBUG it will also print the fps. So let me paste that function:

void cRender::PrintFPS(){	if (SDL_GetTicks() - mCurrentTick &gt; 1000)	{		mCurrentTick = SDL_GetTicks();		sprintf(mFPSStr, "FPS: %d", mFramesRendered);		mFramesRendered = 0;	}	//SDL_Color foregroundColor = { 255, 255, 255 };	//SDL_Color backgroundColor = { 0, 0, 0 };	////SDL_Surface* textSurface = TTF_RenderText_Solid(mFPSFont, mFPSStr, clrBlack );	//SDL_Surface* textSurface = TTF_RenderText_Shaded(mFPSFont, mFPSStr, foregroundColor, backgroundColor);	//SDL_Rect textLocation = { 10, 460, 0, 0 };	//SDL_Surface* screen = gWinManager-&gt;GetSurface();	////SDL_FillRect(screen, NULL, SDL_MapRGB(screen-&gt;format, 255, 255, 255));	//SDL_BlitSurface(textSurface, NULL, screen, &textLocation);	//SDL_UpdateRects(screen, 1, &textLocation);	//SDL_FreeSurface(textSurface);	// Set the viewport	Set2DView();	// white font color	SDL_Color color = {0, 255, 255, 0};	// Location to draw the text (last two can be anything)	SDL_Rect location = {50, 50, 0, 0};	// Create the texture here	SDL_GL_RenderText(mFPSStr, mFPSFont, color, location);}


The stuff that's all commented out is my old version of the FPS using SDL_OPENGLBLIT. I've left that in there because it did work, and I just wanted to show the methodology I used. The stuff at the bottom is basically the new code for the text printing. I'll now show my SDL_GL_RenderText() function which is more or less the same as yours:

void cRender::SDL_GL_RenderText(const char *text, TTF_Font *font, SDL_Color color, SDL_Rect location){	SDL_Surface *initial;	SDL_Surface *intermediary;	int w, h;	GLuint texture;	// Use SDL_TTF to render our text	//initial = TTF_RenderText_Blended(font, text, color);	initial = TTF_RenderText_Solid(font, text, color);		// Convert the rendered text to a known format	w = nextpoweroftwo(initial-&gt;w);	h = nextpoweroftwo(initial-&gt;h);	// Create an intermediary surface	intermediary = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);	// Blit the initial surface onto our new one	int x = SDL_BlitSurface(initial, 0, intermediary, 0);	SDL_UpdateRects(intermediary, 1, &location);	/* Tell GL about our new texture */	glGenTextures(1, &texture);	glBindTexture(GL_TEXTURE_2D, texture);	glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, intermediary-&gt;pixels);	// GL_NEAREST looks horrible, if scaled...	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);		// prepare to render our texture	glEnable(GL_TEXTURE_2D);	glBindTexture(GL_TEXTURE_2D, texture);	// Reset the color	glColor3f(1.0f, 1.0f, 1.0f);		// Draw the font now onto a quad, changed the glTexCoord2f's so it's rendered right	glBegin(GL_QUADS);		glTexCoord2f(0.0f, 0.0f); 		glVertex2d(location.x, location.y);		glTexCoord2f(1.0f, 0.0f); 		glVertex2d(location.x + w, location.y);		glTexCoord2f(1.0f, 1.0f); 		glVertex2d(location.x + w, location.y + h);		glTexCoord2f(0.0f, 1.0f); 		glVertex2d(location.x, location.y + h);	glEnd();	// Bad things happen if we delete the texture before it finishes	glFinish();	// Clean up used surfaces and textures	SDL_FreeSurface(initial);	SDL_FreeSurface(intermediary);	glDeleteTextures(1, &texture);}


Only difference is that I'm currently rendering solid text, which shouldn't make a difference I don't think. But in either case, the blended text didn't work either. I've also tried passing in different locations in case I was messing up on the placement, no luck with that either.

The last piece of code I guess is the Set2DView, which is more or less like yours, but I get the window parameters from my Window Management system:

void cRender::Set2DView(){	int origin = 0;	int width = gWinManager-&gt;GetWidth();	int height = gWinManager-&gt;GetHeight();	int distance = -1;	// Set the current viewport	glViewport((GLint)origin, (GLint)origin, (GLint)width, (GLint)height);	// Select the projection matrix	glMatrixMode(GL_PROJECTION);	// Reset the projection matrix	glLoadIdentity();	// Set our 2D vieport	glOrtho((GLdouble)0, (GLdouble)width, (GLdouble)height, (GLdouble)0, (GLdouble)distance, (GLdouble)distance);	// Select the modelview matrix	glMatrixMode(GL_MODELVIEW);	// Reset the modelview matrix	glLoadIdentity();}


I know the Set3DView works (my adaptation of it) because I can sitll render my nice textured 3D spinning cube without problems. But I've disabled that in case it was interfereing. This should be the only thing being rendered right now (the text).

Do you see anything wrong with anything here? I'm pretty sure I have the order down because it follows this route:

WinManager:
- inits sdl
- inits sdl_ttf

Renderer:
- inits font
- does the drawing of text

and when closing it closes like this:

Renderer:
- closes font

WinManager:
- closes sdl_ttf
- closes sdl

Among a ton of other things also. But no crashes to report, so it looks positive.

Once again, thanks for all your help!! I really appreciate it!

Hmmm.. I just previewed and the code isn't coming up in those nice windows. I surrounded the snippets by the code tags. Is there a different tag for the little windows? I'll edit it if someone can provide me the info!

Thanks!

Sim

------
edit: fixed the tags so that source shows up in the nice little source windows..
I'll take a closer look at it in a bit, but in your cRender class, in your constructor you have a call to TTF_OpenFont. Are you sure that this is being called after SDL is being initialized? Also add a check to make sure that the font was loaded.

Then in your render function it should go like this:
// clear the buffer for the next render cycleglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );// Resets the current drawing matrixglLoadIdentity();#ifdef DEBUG   PrintFPS();#endif // DEBUG// swap that buffer!  That's right! Uh-huh!SDL_GL_SwapBuffers();


You clear the screen first, reset the model matrix, then draw, and finally flip. Start with that and we can go from there.
I fixed my Render function to follow the flow you mentioned. And it makes sense, thanks.

I also checked via breakpoints that the font was being opened after everything was init and I also now check to make sure the font was loaded via a null check..

So things seem to be working, just not drawing.. :(

Thanks again, drew. By the way, definately rating++ for you!

Sim

---------

edit:

Actually, I changed my render function to follow what you said, now my 3D stuff won't render now that I took the comments out. Shouldn't I be calling the:

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

After my render has swapped the buffer? If I call it before, it just clears everything out of my buffer before I swap it into the VRAM, which is bad. I want to swap it, then clear it, then draw, then swap, then clear, then draw, etc... As opposed to what you posted which would draw, then clear, then swap, then draw, then clear, then swap (effectively always drawing a cleared buffer?).

Or maybe I'm confused..

Thanks again!

Another edit:

Sorry, my mistake. You didn't see the rest of my code base. The rest of it calls the render function for all the game objects before the Renderer's Render function (which just swaps the buffers). So that's what I clear the buffer after swapping.. It works as follows:

All game objects updated.
All game objects rendered to buffer.
cRender::Render() called
- FPS drawn if debug
- buffers swapped
- buffers cleared and indentity loaded
Rinse, Lather, Repeat.

That makes more sense. So I fixed the order so my render is as follows:

void cRender::Render(){#ifdef DEBUG	PrintFPS();#endif // DEBUG	// swap that buffer!  That's right! Uh-huh!	SDL_GL_SwapBuffers();	// clear the buffer for the next render cycle	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );	// Resets the current drawing matrix	glLoadIdentity();}


which works well enough for now with my 3d stuff.

[Edited by - _sim on October 9, 2005 4:59:56 PM]

This topic is closed to new replies.

Advertisement