A warning upfront: If you want to interact with the OpenGL context that the SDL renderer is using, you have to be very careful what gets used and changed. Some parts of the state are cached by SDL and things will not work correctly if they’re not reset to the value SDL expects. Reading into the SDL renderer source code is recommended.
If you want an OpenGL renderer, you need to ask for one. Passing -1 as the second argument to SDL_CreateRenderer
makes SDL use an automatic selection (unless you have a environment variable or hint set).
Note that sampling from a texture while it is attached to a bound framebuffer object (drawing a texture to itself) is undefined behavior.
The opengl renderer of SDL may use shaders. Did you account for that?
Here’s a simple example I managed to get running by disabling shaders. I don’t have much experience with interfacing with the renderer like this. Seems too unpractical to me anyway as there’s now much more to keep track of.
directglcalls.c
#include <SDL.h>
#include <SDL_opengl.h>
static SDL_Window * window;
static SDL_Renderer * renderer;
static SDL_Texture * texture;
static struct {
void (GLAPIENTRY * ClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void (GLAPIENTRY * Color4b)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);
void (GLAPIENTRY * Clear)(GLbitfield mask);
void (GLAPIENTRY * Begin)(GLenum mode);
void (GLAPIENTRY * End)();
void (GLAPIENTRY * Vertex2f)(GLfloat x, GLfloat y);
void (GLAPIENTRY * Enable)(GLenum cap);
void (GLAPIENTRY * Disable)(GLenum cap);
void (GLAPIENTRY * Color4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
} gl;
static int maxs32(int a, int b) { return a > b ? a : b; }
static float modf32(float x) { return x - SDL_floorf(x); }
#define DICEROLL 0x1B949B6D
static int run()
{
int i, width, height;
SDL_Event e;
int done = 0;
int rendercount, glrender = -1;
SDL_Rect dst_rect1 = {0, 0, 140, 140};
SDL_Rect dst_rect2 = {0, 0, 128, 128};
struct {
float x1, x2, x3;
float y1, y2, y3;
float r1, g1, b1;
} triangle;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) < 0) {
SDL_Log("Failed to initialize SDL: %s", SDL_GetError());
return 1;
}
/* Disable OpenGL shaders so we don't need to change that much of the state. */
SDL_SetHint(SDL_HINT_RENDER_OPENGL_SHADERS, "0");
window = SDL_CreateWindow("GL context test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 500, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
if (window == NULL){
SDL_Log("Failed to create window: %s", SDL_GetError());
return 1;
}
SDL_GetWindowSize(window, &width, &height);
/* Make sure the renderer is OpenGL. */
rendercount = SDL_GetNumRenderDrivers();
for (i = 0; i < rendercount; i++) {
SDL_RendererInfo info;
SDL_GetRenderDriverInfo(i, &info);
if (SDL_strcmp(info.name, "opengl") == 0) {
glrender = i;
break;
}
}
if (glrender == -1) {
SDL_Log("No OpenGL renderer available.");
return 1;
}
renderer = SDL_CreateRenderer(window, glrender, 0);
if (renderer == NULL){
SDL_Log("Failed to create renderer: %s", SDL_GetError());
return 1;
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
gl.ClearColor = SDL_GL_GetProcAddress("glClearColor");
gl.Color4b = SDL_GL_GetProcAddress("glColor4b");
gl.Clear = SDL_GL_GetProcAddress("glClear");
gl.Begin = SDL_GL_GetProcAddress("glBegin");
gl.End = SDL_GL_GetProcAddress("glEnd");
gl.Vertex2f = SDL_GL_GetProcAddress("glVertex2f");
gl.Disable = SDL_GL_GetProcAddress("glDisable");
gl.Enable = SDL_GL_GetProcAddress("glEnable");
gl.Color4f = SDL_GL_GetProcAddress("glColor4f");
if (gl.ClearColor == NULL) {
SDL_Log("Failed to load glClearColor: %s", SDL_GetError());
return 1;
} else if (gl.Color4b == NULL) {
SDL_Log("Failed to load glColor4b: %s", SDL_GetError());
return 1;
} else if (gl.Clear == NULL) {
SDL_Log("Failed to load glClear: %s", SDL_GetError());
return 1;
} else if (gl.Begin == NULL) {
SDL_Log("Failed to load glBegin: %s", SDL_GetError());
return 1;
} else if (gl.End == NULL) {
SDL_Log("Failed to load glEnd: %s", SDL_GetError());
return 1;
} else if (gl.Vertex2f == NULL) {
SDL_Log("Failed to load glVertex2f: %s", SDL_GetError());
return 1;
} else if (gl.Disable == NULL) {
SDL_Log("Failed to load glDisable: %s", SDL_GetError());
return 1;
} else if (gl.Enable == NULL) {
SDL_Log("Failed to load glEnable: %s", SDL_GetError());
return 1;
} else if (gl.Color4f == NULL) {
SDL_Log("Failed to load glColor4f: %s", SDL_GetError());
return 1;
}
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, 128, 128);
if (texture == NULL){
SDL_Log("Failed to create texture: %s", SDL_GetError());
return 1;
}
while (!done) {
Uint32 now;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
done = 1;
} else if (e.type == SDL_KEYDOWN) {
} else if (e.type == SDL_KEYUP) {
Uint32 sym = e.key.keysym.sym;
if (sym == SDLK_ESCAPE) {
done = 1;
} else if (sym == SDLK_f) {
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
SDL_SetWindowFullscreen(window, SDL_FALSE);
} else {
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
}
} else if (e.type == SDL_WINDOWEVENT) {
if (e.window.event == SDL_WINDOWEVENT_RESIZED || e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
SDL_GetWindowSize(window, &width, &height);
}
}
}
now = SDL_GetTicks();
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderTarget(renderer, texture);
{ /* Direct calls to OpenGL. */
gl.ClearColor(modf32(now / 1140.f), modf32(now / 1261.f), modf32(now / 1345.f), 255);
gl.Clear(GL_COLOR_BUFFER_BIT);
triangle.x1 = (float)((now / 1000 * DICEROLL) % dst_rect2.w);
triangle.x2 = (float)((now / 1000 * DICEROLL) / 11 % dst_rect2.w);
triangle.x3 = (float)((now / 1000 * DICEROLL) / 17 % dst_rect2.w);
triangle.y1 = (float)((now / 1000 * DICEROLL) / 7 % dst_rect2.h);
triangle.y2 = (float)((now / 1000 * DICEROLL) / 13 % dst_rect2.h);
triangle.y3 = (float)((now / 1000 * DICEROLL) / 5 % dst_rect2.h);
triangle.r1 = modf32(now / 1000 / 3.f);
triangle.g1 = modf32(now / 1000 / 2.f);
triangle.b1 = modf32(now / 1000 / 4.f);
gl.Begin(GL_TRIANGLES);
gl.Color4f(triangle.r1, triangle.g1, triangle.b1, 1);
gl.Vertex2f(triangle.x1, triangle.y1);
gl.Color4f(triangle.r1, triangle.g1, triangle.b1, 1);
gl.Vertex2f(triangle.x2, triangle.y2);
gl.Color4f(triangle.r1, triangle.g1, triangle.b1, 1);
gl.Vertex2f(triangle.x3, triangle.y3);
gl.End();
}
SDL_SetRenderTarget(renderer, NULL);
dst_rect1.x = now / 18 % maxs32(width - dst_rect1.w, 50);
dst_rect1.y = now / 16 % maxs32(height - dst_rect1.h, 50);
dst_rect2.x = dst_rect1.x + (dst_rect1.w - dst_rect2.w) / 2;
dst_rect2.y = dst_rect1.y + (dst_rect1.h - dst_rect2.h) / 2;
SDL_SetRenderDrawColor(renderer, now / 4 % 256, now / 4 % 256, now / 4 % 256, 255);
SDL_RenderFillRect(renderer, &dst_rect1);
SDL_RenderCopy(renderer, texture, NULL, &dst_rect2);
SDL_RenderPresent(renderer);
}
return 0;
}
int main(int argc, char * argv[])
{
int retval = run();
if (texture)
SDL_DestroyTexture(texture);
if (renderer)
SDL_DestroyRenderer(renderer);
if (window)
SDL_DestroyWindow(window);
if (SDL_WasInit(SDL_INIT_EVERYTHING))
SDL_Quit();
return retval;
}