Skip to content

Instantly share code, notes, and snippets.

Created Apr 9, 2017
Embed
What would you like to do?
SDL render touch input on Android
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <cmath>
#include <SDL2/SDL.h>
#ifdef ENV_ANDROID_SDL
#include <SDL2/SDL_main.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#else
#include <SDL2/SDL_opengl.h>
#include <glad/glad.h>
#endif
#ifdef ENV_ANDROID_SDL
std::string const k_shader_version_str = "#version 100\n";
#else
std::string const k_shader_version_str = "#version 120\n";
#endif
std::string const k_vsh_source =
k_shader_version_str+
"\n"
"// attributes\n"
"attribute vec4 a_v4_position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = a_v4_position;\n"
"}\n";
std::string const k_fsh_source =
k_shader_version_str+
"\n"
"// varyings\n"
"\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
struct ApplicationData
{
SDL_Window* window{nullptr};
SDL_GLContext gl_context;
GLuint prog_id{0};
GLuint vbo_id{0};
GLint attrib_loc_position{0};
#ifdef ENV_ANDROID_SDL
unsigned int win_width{768};
unsigned int win_height{1134};
#else
unsigned int win_width{384};
unsigned int win_height{567};
#endif
float input_x{0.0f};
float input_y{0.0f};
float input_s{120.0f};
float rads{0.0f};
float disp_x{0.0f};
float disp_y{0.0f};
};
void InitSDL(SDL_Window* &window, SDL_GLContext& context,
unsigned int win_width, unsigned int win_height)
{
// init sdl
SDL_Init(SDL_INIT_VIDEO);
// set requested opengl context params
#ifdef ENV_ANDROID_SDL
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,SDL_GL_CONTEXT_PROFILE_ES);
#else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,1);
#endif
// create a window
window = SDL_CreateWindow(
"OpenGL",0,0,
win_width,
win_height,
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if(!window) {
std::string const err =
"Failed to create window "+
std::string(SDL_GetError());
SDL_Quit();
throw std::runtime_error(err);
}
// get the opengl context
context = SDL_GL_CreateContext(window);
if(!context) {
std::string const err =
"Error: Failed to create context"+
std::string(SDL_GetError());
SDL_Quit();
throw std::runtime_error(err);
}
// load opengl functions (must be done after
// getting a valid context)
#ifndef ENV_ANDROID_SDL
if(!gladLoadGL()) {
std::string const err =
"Error: Error loading OpenGL functions";
SDL_GL_DeleteContext(context);
SDL_Quit();
throw std::runtime_error(err);
}
#endif
#ifdef ENV_ANDROID_SDL
if(SDL_GL_SetSwapInterval(1) < 0) {
std::string const err =
"Error: Failed to set vsync: " +
std::string(SDL_GetError());
SDL_GL_DeleteContext(context);
SDL_Quit();
throw std::runtime_error(err);
}
if(SDL_SetHint(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH,"1") < 0) {
throw std::runtime_error("Failed to set mouse/touch hint");
}
#endif
}
void InitGL(GLuint& prog_id,
GLuint& vbo_id,
GLint& attrib_loc_position)
{
(void)vbo_id;
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
// vertex shader
auto vsh_id = glCreateShader(GL_VERTEX_SHADER);
char const * vsh_source = k_vsh_source.c_str();
glShaderSource(vsh_id,1,&vsh_source,nullptr);
glCompileShader(vsh_id);
GLint vsh_ok = GL_FALSE;
glGetShaderiv(vsh_id,GL_COMPILE_STATUS,&vsh_ok);
if(vsh_ok==GL_FALSE) {
throw std::runtime_error("Failed to compiler vertext shader");
}
// fragment shader
auto fsh_id = glCreateShader(GL_FRAGMENT_SHADER);
char const * fsh_source = k_fsh_source.c_str();
glShaderSource(fsh_id,1,&fsh_source,nullptr);
glCompileShader(fsh_id);
GLint fsh_ok = GL_FALSE;
glGetShaderiv(fsh_id,GL_COMPILE_STATUS,&fsh_ok);
if(fsh_ok==GL_FALSE) {
throw std::runtime_error("Error: Failed to compile fragment shader");
}
// create shader program
prog_id = glCreateProgram();
glAttachShader(prog_id,vsh_id);
glAttachShader(prog_id,fsh_id);
glLinkProgram(prog_id);
GLint link_ok = GL_FALSE;
glGetProgramiv(prog_id,GL_LINK_STATUS,&link_ok);
if(link_ok==GL_FALSE) {
glDeleteProgram(prog_id);
throw std::runtime_error("Error: Failed to link shader");
}
// get attribute locations
attrib_loc_position = glGetAttribLocation(prog_id,"a_v4_position");
// set gl clear color
glClearColor(0,0,0,1);
}
float ToNDCX(float x, float win_width)
{
x /= win_width;
x = x*2.0f - 1.0f;
return x;
}
float ToNDCY(float y, float win_height)
{
y /= win_height;
y = (1.0f-y)*2.0f - 1.0f;
return y;
}
void Render(ApplicationData& app_data)
{
auto& vbo_id = app_data.vbo_id;
auto& input_x = app_data.input_x;
auto& input_y = app_data.input_y;
auto& input_s = app_data.input_s;
auto& rads = app_data.rads;
auto& win_width = app_data.win_width;
auto& win_height = app_data.win_height;
auto& disp_x = app_data.disp_x;
auto& disp_y = app_data.disp_y;
auto& attrib_loc_position = app_data.attrib_loc_position;
auto& window = app_data.window;
auto& prog_id = app_data.prog_id;
if(vbo_id != 0)
{
glDeleteBuffers(1,&vbo_id);
}
// create buffers
float dx = input_x;
float dy = input_y;
GLfloat list_vx[] = {
ToNDCX(0+dx,win_width), ToNDCY(0+dy,win_height), 0.0, 1.0, // tl
ToNDCX(0+dx,win_width), ToNDCY(input_s+dy,win_height), 0.0, 1.0, // bl
ToNDCX(input_s+dx,win_width), ToNDCY(input_s+dy,win_height), 0.0, 1.0, // br
ToNDCX(0+dx,win_width), ToNDCY(0+dy,win_height), 0.0, 1.0, // tl
ToNDCX(input_s+dx,win_width), ToNDCY(input_s+dy,win_height), 0.0, 1.0, // br
ToNDCX(input_s+dx,win_width), ToNDCY(0+dy,win_height), 0.0, 1.0 // tr
};
rads += (6.28f/300.0f)*1.25f;
disp_x = win_width/2 + sin(rads)*200;
disp_y = win_height/2 + sin(rads*0.5)*400;
glGenBuffers(1,&vbo_id);
glBindBuffer(GL_ARRAY_BUFFER,vbo_id);
glBufferData(GL_ARRAY_BUFFER,
4*6*sizeof(GLfloat),
list_vx,
GL_STREAM_DRAW);
// clear color buffer
glViewport(0,0,win_width,win_height);
glClear(GL_COLOR_BUFFER_BIT);
// render tri
glUseProgram(prog_id);
glEnableVertexAttribArray(attrib_loc_position);
glBindBuffer(GL_ARRAY_BUFFER,vbo_id);
glVertexAttribPointer(attrib_loc_position,4,GL_FLOAT,GL_FALSE,0,nullptr);
glDrawArrays(GL_TRIANGLES,0,6);
glDisableVertexAttribArray(attrib_loc_position);
SDL_GL_SwapWindow(window);
}
void Cleanup(SDL_GLContext &context,
GLuint prog_id,
GLuint vbo_id)
{
glUseProgram(0);
glDeleteProgram(prog_id);
glDeleteBuffers(1,&vbo_id);
SDL_GL_DeleteContext(context);
SDL_Quit();
}
int main(int argc, char *argv[])
{
ApplicationData app_data;
InitSDL(app_data.window,app_data.gl_context,app_data.win_width,app_data.win_height);
InitGL(app_data.prog_id,app_data.vbo_id,app_data.attrib_loc_position);
// poll for events from the window
SDL_Event event;
bool keep_running=true;
while(keep_running)
{
// drain all available events
while(SDL_PollEvent(&event) != 0) {
if(event.type == SDL_QUIT) {
keep_running=false;
break;
}
// else if(event.type == SDL_MOUSEMOTION)
// {
// app_data.input_x = event.motion.x;
// app_data.input_y = event.motion.y;
// }
else if(event.type == SDL_FINGERMOTION)
{
app_data.input_x = event.tfinger.x*app_data.win_width;
app_data.input_y = event.tfinger.y*app_data.win_height;
}
}
Render(app_data);
}
Cleanup(app_data.gl_context,app_data.prog_id,app_data.vbo_id);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment