Reputation: 5232
I currently need to develop a program that will display a simple texture (which is generated by the program by existing SDL2 code) using a shader. For now to see how it works to combine OpenGL ES 2.0 and SDL (on a raspberry pi framebuffer) I created this sample program (sorry, its missing some error checking and serves as an example). It should for now only display a texture that is loaded from the file "land.png" using SDL2_image.
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#define GL_GLEXT_PROTOTYPES 1
#include <SDL2/SDL_opengles2.h>
#include <iostream>
static const char * vertex =
"attribute vec4 position;"
"attribute vec4 inputTextureCoordinate;"
""
"varying vec2 textureCoordinate;"
""
"void main()"
"{"
" gl_Position = position;"
" textureCoordinate = inputTextureCoordinate.xy;"
"}"
"";
static const char * fragment =
"varying highp vec2 textureCoordinate;"
""
"uniform sampler2D videoFrame;"
""
"void main()"
"{"
" gl_FragColor = texture2D(videoFrame, textureCoordinate);"
"}"
"";
unsigned int program_id = 0;
GLuint TextureID = 0;
bool compile_program()
{
unsigned int vertex_id = 0;
unsigned int fragment_id = 0;
char infoLog[512];
int success;
vertex_id = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_id, 1, &vertex, NULL);
glCompileShader(vertex_id);
glGetShaderiv(vertex_id, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertex_id, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
glDeleteShader(vertex_id);
vertex_id = 0;
return false;
}
std::cout << "Vertex shader compiled successfully! Id = " << vertex_id << std::endl;
fragment_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_id, 1, &fragment, NULL);
glCompileShader(fragment_id);
glGetShaderiv(fragment_id, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(fragment_id, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
glDeleteShader(vertex_id);
glDeleteShader(fragment_id);
vertex_id = 0;
return false;
}
std::cout << "Fragment shader compiled successfully! Id = " << fragment_id << std::endl;
program_id = glCreateProgram();
glAttachShader(program_id, vertex_id);
glAttachShader(program_id, fragment_id);
glLinkProgram(program_id);
glGetProgramiv(program_id, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(program_id, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
glDeleteShader(vertex_id);
glDeleteShader(fragment_id);
return false;
}
TextureID = glGetUniformLocation(program_id, "videoFrame");
glDeleteShader(vertex_id);
glDeleteShader(fragment_id);
return true;
}
int main()
{
if (SDL_Init(SDL_INIT_EVERYTHING | SDL_VIDEO_OPENGL_ES2) != 0){
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *win = SDL_CreateWindow("AnyGlobe", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, 480, 480, 0);
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");
SDL_Renderer *renderer = SDL_CreateRenderer(win, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
SDL_RendererInfo rendererInfo;
SDL_GetRendererInfo(renderer, &rendererInfo);
std::cout << "Renderer: " << rendererInfo.name << std::endl;
if(!strncmp(rendererInfo.name, "opengles2", 9)) {
std::cout << "We have OpenGL ES 2.0" << std::endl;
compile_program();
}
SDL_Texture *land = IMG_LoadTexture(renderer, "land.png");
if (!land)
{
abort();
}
int done = 0;
float position = 0.0;
SDL_Texture *texTarget = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET, 480, 480);
static const GLfloat squareVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
static const GLfloat textureVertices[] = {
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
0.0f, 0.0f,
};
while ( ! done ) {
//Render to the texture
SDL_SetRenderTarget(renderer, texTarget);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, land, NULL, NULL);
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
SDL_RenderClear(renderer);
GLint old_program = 0;
if(program_id != 0) {
glGetIntegerv(GL_CURRENT_PROGRAM, &old_program);
glUseProgram(program_id);
}
glActiveTexture(GL_TEXTURE0);
SDL_GL_BindTexture(texTarget, NULL, NULL);
glUniform1i(TextureID, 0);
glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, textureVertices);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
SDL_GL_SwapWindow(win);
if(program_id != 0) {
glUseProgram(old_program);
}
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
if ( event.type == SDL_QUIT ) {
done = 1;
}
if ( event.type == SDL_KEYDOWN ) {
if ( event.key.keysym.sym == SDLK_ESCAPE ) {
done = 1;
}
}
}
}
return 0;
}
The current status is that only a color background (defined by the RendererDrawColor in SDL) is displayed but not the texture and I cannot put my finger on it why it does not work properly. Can somebody look especially over the OpenGL ES code? I am thankful about every hint.
Upvotes: 2
Views: 2134
Reputation: 7534
I actually have success combining SDL_Renderer
and OpenGL (tho not ES, but theoretically should be fine too). If you just want to apply a fragment shader to an SDL_Texture
this should be doable with some tweaks to your code.
SDL_RenderCopy
or SDL_RenderCopyEx
SDL_RenderPresent
instead of SDL_GL_SwapWindow
SDL_GL_BindTexture
, but you are missing SDL_GL_UnbindTexture
SDL_RenderFlush()
. Depending on if you are using batching or not.I do not know OpenGL ES, but this is the OpenGL vertex shader I use when I want to do this:
varying vec4 v_color;
varying vec2 v_texCoord;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
v_color = gl_Color;
v_texCoord = vec2(gl_MultiTexCoord0);
}
This code came directly from the SDL2 source code, so if there is a different one to use for OpenGL ES/ES2 then check their source.
Upvotes: 1
Reputation: 52162
Don't mix-n-match SDL_Renderer stuff and OpenGL, down that path lies pain and madness, at least at this point in time.
Upvotes: 1