I’m having problems with my SDL OpenGL program. The program loads images
every now and then from a large collection of images. They’re all
800x600 JPEG’s. I’m forced to load the image using SDL_image then move
that onto an OpenGL texture every time.
The problem is it takes too long load each image, so I get a very
distinct lag chunk of about 100ms.
The way I currently load the stuff is along the lines of the following:
tmp = (SDL_Surface *) IMG_Load(file);
surface = SDL_CreateRGBSurface(SDL_SWSURFACE, newW, newH, 32,
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
SDL_BlitSurface(tmp, NULL, surface, NULL);
SDL_FreeSurface(tmp);
The problem is not related to IMG_Load, that is just a bit slower than
SDL_LoadBMP.
What you’re doing can result in compatibility problems:
An universally accepted texture, in fact, must be 64,128 or 256 wide or
high; any other resolution will cause problems.
Refer to NeHe’s OpenGL tutorial #7.
There are some workarounds for this:
1)Resize your images using some art program.
2)Use SDL_gfx to resize them realtime
However, this way stretched images will look awful.
3)If you don’t want to lose resolution, split them in many textures (not
recommended)
3)Use mipmaps. They can have any size.
Just keep in mind that, while mipmaps have absolutely the best quality,
they use a BUNCH of RAM.
I attach some code of mine that uses the third option. It’s based on Sam
Lantinga’s version of NeHe’s tutorials
P3-1GHz:
IMG_Load 53171
SDL_CreateRGBSurface 12885
SDL_BlitSurface 23843
SDL_FreeSurface 927
I tried to load all the images in memory… Bad idea, it basically
crashed my Linux box when it finally ran out of memory! I should have
tried working out the maths for it first 
Obviously. If you use plain textures, every image takes 800x600x4=1.8MB of RAM.
If you use 400x300 textures you will need 450kB of RAM for each texture,
without a considerable resolution loss.
Guido Imperiale
@CRUSADER_KY-------------------------------
CRV?ADER/KY
KnowledgE is PoweR
-------------- next part --------------
/*
myGL - an essential SDL framework for OpenGL - myGL.h
Copyright (C) 2002 Guido Imperiale
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Guido Imperiale
@CRUSADER_KY
*/
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#if defined(APPLE) && defined(MACH)
#include <OpenGL/glaux.h>
//#include <OpenGL/glut.h>
#else
#include <GL/glaux.h>
//#include <GL/glut.h>
#endif
#define NO_FLAGS 0
#define MYGL_TEXTURE 0
#define MYGL_MIPMAP 1
typedef enum __myGL_RGBOrder {UNRECOGNIZED,RGB,BGR,GRB,GBR,RBG,BRG} myGL_RGBOrder;
SDL_Surface * myGL_Init(int width,
int height,
int depth,
Uint32 init_flags,
Uint32 video_flags,
char * caption);
SDL_Surface * myGL_LoadImage(char * filename);
void myGL_LoadTexture(char * filename,
GLuint texture,
GLfloat MinFilter,
GLfloat MagFilter,
BOOL use_mipmap);
void myGL_CreateTextureFrom(SDL_Surface * image,
GLuint texture,
GLfloat MinFilter,
GLfloat MagFilter,
BOOL use_mipmap);
-------------- next part --------------
/*
- myGL - an essential SDL framework for OpenGL - myGL.c
- Copyright (C) 2002 Guido Imperiale
- This code is released under the terms of the GNU LGPL.
- Please refer to myGL.h for more informations.
*/
#include “myGL.h”
SDL_Surface * myGL_Init(int width,
int height,
int depth,
Uint32 init_flags,
Uint32 video_flags,
char * caption)
{
SDL_Surface * screen = NULL;
/* Initialize SDL for video output */
if ( SDL_Init(SDL_INIT_VIDEO | init_flags) < 0 ) {
fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
/* Create an OpenGL screen */
if ( (screen = SDL_SetVideoMode(width, height, depth, SDL_OPENGL | video_flags)) == NULL ) {
fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());
exit(2);
}
/* Set the title bar in environments that support it */
SDL_WM_SetCaption(caption, caption);
/* Projection matrix setup */
glMatrixMode(GL_PROJECTION); //Select The Projection Matrix
glLoadIdentity(); //Reset The Projection Matrix
//Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
/*other setup*/
glMatrixMode(GL_MODELVIEW); //Select The Modelview Matrix
glEnable(GL_TEXTURE_2D); //Enable Texture Mapping
glShadeModel(GL_SMOOTH); //Enable Smooth Color Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //This Will Clear The Background Color To Black
glBlendFunc(GL_SRC_ALPHA,GL_ONE); //Blending Function Based On Source Alpha Value
/*Depth Buffer setup*/
glClearDepth(1.0); //Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); //The Type Of Depth Test To Do FIXME:GL_LEQUAL?
glEnable(GL_DEPTH_TEST); //Enables Depth Testing
/*Quality settings*/
glHint(GL_FOG_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
return screen;
}
SDL_Surface * myGL_LoadImage(char * filename)
{
Uint8 *rowhi, *rowlo, *tmpbuf;
Uint8 tmpch;
SDL_Surface * image;
myGL_RGBOrder order = UNRECOGNIZED;
int i, j;
if ((image = IMG_Load(filename)) == NULL) {
fprintf(stderr, "Unable to load %s: %s\n", filename, SDL_GetError());
return(NULL);
}
if (image->format->BitsPerPixel != 24 || image->format->BytesPerPixel != 3) {
fprintf(stderr,"Image is %d bpp and %d Bpp",image->format->BitsPerPixel,image->format->BytesPerPixel);
return(NULL);
}
//Determine RGB components order
if (image->format->Rshift == 16 && image->format->Gshift == 8)
order = BGR; //BMP
else if (image->format->Bshift == 16 && image->format->Gshift == 8)
order = RGB; //textures, JPEG
//GL textures are upside down and RGB
if ((tmpbuf = malloc(image->pitch)) == NULL ) {
fprintf(stderr, "Out of memory\n");
return(NULL);
}
rowhi = (Uint8 *)image->pixels;
rowlo = rowhi + (image->h-1) * image->pitch; //last line of the image
for (i=0; i<image->h/2; ++i)
{
//Switch the single pixels of a line on themselves from BGR to RGB
switch (order)
{
case RGB: //nothing to do
break;
case BGR: //swap B and R
for ( j=0; j<image->w; ++j ) {
tmpch = rowhi[j*3];
rowhi[j*3] = rowhi[j*3+2];
rowhi[j*3+2] = tmpch;
tmpch = rowlo[j*3];
rowlo[j*3] = rowlo[j*3+2];
rowlo[j*3+2] = tmpch;
}
break;
//I'm too lazy to write support :). Thus, all the image formats supported by SDL_image
//are either RGB or BGR. FIXME: I experienced a green line using a 700x469 BMP photograph,
//while the corresponding JPG works well.
default:
fputs("Unrecognized image format",stderr);
SDL_FreeSurface(image);
return NULL;
break;
}
//switch the line on top and the one on the bottom
memcpy(tmpbuf, rowhi, image->pitch);
memcpy(rowhi, rowlo, image->pitch);
memcpy(rowlo, tmpbuf, image->pitch);
rowhi += image->pitch;
rowlo -= image->pitch;
}
free(tmpbuf);
return(image);
}
// Load Bitmap And Convert To Texture
void myGL_LoadTexture(char * filename, GLuint texture, GLfloat MinFilter, GLfloat MagFilter, BOOL use_mipmap)
{
//Load Texture
SDL_Surface * image;
image = myGL_LoadImage(filename);
if (image==NULL) {
exit(1);
fprintf(stderr,"Error loading image: %s\n",filename);
}
//Create Texture
myGL_CreateTextureFrom(image,texture,MagFilter,MinFilter,use_mipmap);
SDL_FreeSurface(image);
};
// Create a texture from pixel data
void myGL_CreateTextureFrom(SDL_Surface * image, GLuint texture, GLfloat MinFilter, GLfloat MagFilter, BOOL use_mipmap)
{
glBindTexture(GL_TEXTURE_2D, texture); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,MagFilter);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,MinFilter);
if (!use_mipmap)
if (image->w != 64 || image->w != 128 || image->w != 256 ||
image->h != 64 || image->h != 128 || image->h != 256)
use_mipmap = TRUE; //force mipmap for non-standard textures
if (use_mipmap)
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->w, image->h, GL_RGB, GL_UNSIGNED_BYTE, image->pixels);
else
glTexImage2D(GL_TEXTURE_2D, //type of texture
0, //level of detail (used by mipmaps)
3, //components per pixel
image->w, image->h, //image width and height
0, //image border
GL_RGB, //colors order
GL_UNSIGNED_BYTE, //components data type
image->pixels); //pixel data
}