Here's the test case and a patch.
Now contacting [email protected].
--
Sylvain
--- SDL_x11gl.c-orig 2010-05-23 20:37:14.000000000 +0200
+++ SDL_x11gl.c 2010-05-23 20:37:45.000000000 +0200
@@ -530,9 +530,9 @@
this->gl_data->glXQueryExtensionsString =
(const char *(*)(Display *, int)) GL_LoadFunction(handle, "glXQueryExtensionsString");
this->gl_data->glXSwapIntervalSGI =
- (int (*)(int)) GL_LoadFunction(handle, "glXSwapIntervalSGI");
+ (int (*)(int)) this->gl_data->glXGetProcAddress("glXSwapIntervalSGI");
this->gl_data->glXSwapIntervalMESA =
- (GLint (*)(unsigned)) GL_LoadFunction(handle, "glXSwapIntervalMESA");
+ (GLint (*)(unsigned)) this->gl_data->glXGetProcAddress("glXSwapIntervalMESA");
if ( (this->gl_data->glXChooseVisual == NULL) ||
(this->gl_data->glXCreateContext == NULL) ||
#include <stdio.h>
#include <stdlib.h>
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_framerate.h"
#include <GL/gl.h>
#include <GL/glu.h>
#define DATADIR "../share/myentry/"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
struct sprite {
double x, y;
int w, h, tex_w, tex_h;
GLuint texture;
GLuint display_list;
};
struct sprite* sprite_new(char* path)
{
struct sprite* self = malloc(sizeof(struct sprite));
SDL_Surface *tmp = IMG_Load(path);
if (tmp == NULL)
fprintf(stderr, "%s\n", IMG_GetError()), exit(1);
// Convert to OpenGL format, without bottom-to-top ordering
// (cf. Ortho2D call)
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
SDL_Surface *rgba = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA, tmp->w, tmp->h,
32, rmask, gmask, bmask, amask);
if (rgba == NULL) {
fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
exit(1);
}
SDL_SetAlpha(tmp, 0, -1); // replace destination alpha channel
SDL_BlitSurface(tmp, NULL, rgba, NULL);
SDL_FreeSurface(tmp);
self->w = tmp->w;
self->h = tmp->h;
// The texture size need to be a power-of-two. Cards that
// support GL_ARB_texture_rectangle can work this around, but
// for now we'll not optimize
self->tex_w = 64;
self->tex_h = 64;
while (self->tex_w < self->w) { self->tex_w *= 2; }
while (self->tex_h < self->h) { self->tex_h *= 2; }
// Allocate a new texture in the 3D card
glGenTextures(1, &self->texture);
// Set current texture
glBindTexture(GL_TEXTURE_2D, self->texture);
// Smooth (linear) algorithm for growing resize
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Quick (nearest) algorithm for shrinking resize
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Avoid getting interpolation artifacts (e.g. semi-transparent
// black lines) on the border of the texture. Only necessary
// when using non-power-of-two textures.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Allocate the (power-of-two) texture
glTexImage2D(GL_TEXTURE_2D, // target
0, // level
GL_RGBA, // internalformat
self->tex_w, // width
self->tex_h, // height
0, // border
GL_RGBA, // format
GL_UNSIGNED_BYTE, // type
NULL); // texels
// Upload the (non-power-of-two) pixel data
// No per-pixel alignement in our pixel data:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Specify pitch:
glPixelStorei(GL_UNPACK_ROW_LENGTH, rgba->pitch / rgba->format->BytesPerPixel);
// Upload pixel data
glTexSubImage2D(GL_TEXTURE_2D, // target
0, // level
0, // x
0, // y
self->w, // width
self->h, // height
GL_RGBA, // format
GL_UNSIGNED_BYTE, // type
rgba->pixels); // texels
// Place the drawing instructions in cache
self->display_list = glGenLists(1);
glNewList(self->display_list, GL_COMPILE);
// Set current texture
glBindTexture(GL_TEXTURE_2D, self->texture);
// Create a quad
glBegin(GL_QUADS);
glTexCoord2i(0, 0);
glVertex2i(0, 0);
glTexCoord2d((self->w*1.0)/self->tex_w, 0);
glVertex2i(self->w, 0);
glTexCoord2d((self->w*1.0)/self->tex_w, (self->h*1.0)/self->tex_h);
glVertex2i(self->w, self->h);
glTexCoord2d(0, (self->h*1.0)/self->tex_h);
glVertex2i(0, self->h);
glEnd(); // GL_QUADS
glEndList();
SDL_FreeSurface(rgba);
self->x = self->y = 0;
return self;
}
void sprite_free(struct sprite* self)
{
if (self->texture != 0)
{
glDeleteTextures(1, &self->texture);
self->texture = 0;
}
if (self->display_list != 0)
{
glDeleteLists(self->display_list, 1);
self->display_list = 0;
}
free(self);
}
void sprite_draw(struct sprite* self)
{
glLoadIdentity();
// Flip Y coordinates to match classic top-bottom 2D screen
// graphics coordinates
// glTranslate(self.x, screen_height-self.y-self.h, 0)
glTranslated(self->x, self->y, 0);
//glRotate(7, 0, 0, -1)
glCallList(self->display_list);
}
void print_GL_attribute(char* attr_str, SDL_GLattr attr)
{
int value = -1;
if (SDL_GL_GetAttribute(attr, &value) < 0)
fprintf(stderr, "SDL_GL_GetAttribute(%s) failed:\t%s\n", attr_str, SDL_GetError());
else
printf("%s\t= %d\n", attr_str, value);
}
#define PRINT_GL_ATTRIBUTE(X) print_GL_attribute(#X, X)
void print_GL_attributes(void)
{
PRINT_GL_ATTRIBUTE(SDL_GL_RED_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_GREEN_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_BLUE_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_ALPHA_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_BUFFER_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_DOUBLEBUFFER);
PRINT_GL_ATTRIBUTE(SDL_GL_DEPTH_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_STENCIL_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_ACCUM_RED_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_ACCUM_GREEN_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_ACCUM_BLUE_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_ACCUM_ALPHA_SIZE);
PRINT_GL_ATTRIBUTE(SDL_GL_STEREO);
PRINT_GL_ATTRIBUTE(SDL_GL_MULTISAMPLEBUFFERS);
PRINT_GL_ATTRIBUTE(SDL_GL_MULTISAMPLESAMPLES);
PRINT_GL_ATTRIBUTE(SDL_GL_SWAP_CONTROL);
PRINT_GL_ATTRIBUTE(SDL_GL_ACCELERATED_VISUAL);
}
int main(void)
{
SDL_Init(SDL_INIT_EVERYTHING);
if (SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1) < 0) // since SDL v1.2.10
fprintf(stderr, "SDL_GL_SWAP_CONTROL: %s\n", SDL_GetError());
SDL_Surface* screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_OPENGL|SDL_DOUBLEBUF);
int swap_control = -1;
if (SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &swap_control) < 0)
fprintf(stderr, "SDL_GL_SWAP_CONTROL: %s\n", SDL_GetError());
else
printf("SDL_GL_SWAP_CONTROL = %d\n", swap_control);
print_GL_attributes();
/* Word-around for SDL 1.14 shamelessly non-working SDL_GL_SWAP_CONTROL */
//GLint (*my_glXSwapIntervalMESA) ( unsigned interval );
//my_glXSwapIntervalMESA = (GLint (*)(unsigned)) glXGetProcAddressARB("glXSwapIntervalMESA");
//my_glXSwapIntervalMESA(1);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* Get a flat display; not that coordinates are reversed to match
the classic 2D coordinates. This means we'll upload surfaces
as-is (normally we should flip them) and we'll need to perform
rotations with z=-1) */
gluOrtho2D(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // optimize transparency
struct sprite* ship = sprite_new(DATADIR "ship.png");
struct sprite* clouds = sprite_new(DATADIR "clouds.png");
FPSmanager framerate_manager;
SDL_initFramerate(&framerate_manager);
SDL_setFramerate(&framerate_manager, 200);
int run = 1;
Uint32 lastcall = SDL_GetTicks();
int dx = 0, dy = 0;
double scroll = 0;
Uint32 fps_start = SDL_GetTicks();
int fps_frames = 0;
while (run)
{
SDL_Event ev;
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
{
run = 0;
}
else if (ev.type == SDL_KEYDOWN)
{
if (ev.key.keysym.sym == SDLK_ESCAPE)
run = 0;
else if (ev.key.keysym.sym == SDLK_LEFT)
dx = -1;
else if (ev.key.keysym.sym == SDLK_RIGHT)
dx = 1;
else if (ev.key.keysym.sym == SDLK_UP)
dy = -1;
else if (ev.key.keysym.sym == SDLK_DOWN)
dy = 1;
}
else if (ev.type == SDL_KEYUP)
{
if (ev.key.keysym.sym == SDLK_LEFT && dx == -1)
dx = 0;
else if (ev.key.keysym.sym == SDLK_RIGHT && dx == 1)
dx = 0;
else if (ev.key.keysym.sym == SDLK_UP)
dy = 0;
else if (ev.key.keysym.sym == SDLK_DOWN)
dy = 0;
}
}
SDL_framerateDelay(&framerate_manager);
double delta = (SDL_GetTicks() - lastcall) / 1000.0;
lastcall = SDL_GetTicks();
scroll -= delta * 800; /* px/s */
if (scroll < -clouds->w)
scroll += clouds->w;
ship->x += dx * delta * 800; /* px/s */
ship->y += dy * delta * 800; /* px/s */
int sy = 0;
while (sy < SCREEN_WIDTH)
{
int sx = - SCREEN_HEIGHT + scroll;
while (sx < SCREEN_WIDTH)
{
clouds->x = sx;
clouds->y = sy;
sprite_draw(clouds);
sx += clouds->w;
}
sy += clouds->h;
}
sprite_draw(ship);
SDL_GL_SwapBuffers();
fps_frames++;
}
printf("FPS: %.2f\n", 1000.0 * fps_frames / (SDL_GetTicks() - fps_start));
sprite_free(ship);
sprite_free(clouds);
SDL_Quit();
}
/**
* Local Variables:
* compile-command: "gcc -ggdb $(sdl-config --cflags --libs) test-gl.c -lSDL_gfx -lSDL_image -lGL -lGLU -o test-gl"
* End:
*/