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:
 */

Reply via email to