The next example draws a triangle using OpenGL ES 2.0 and SDL 3.0 and it works on Infinix Hot 30, Android 13 without problems: https://65c8fc0851792f3dc1fbd7d9--spiffy-trifle-f2dd69.netlify.app/ Short url: t.ly/b9Wbp But it doesn’t work on old phone Redmi 4X, Android 7. Is it possible to solve it? I use the next template with guide: GitHub - Ravbug/sdl3-sample: Minimal HowTo for building and using SDL3 on a variety of platforms, including mobile and web
Note. Open CMakeLists.txt and set target_link_libraries adding android EGL GLESv2 here:
target_link_libraries(${EXECUTABLE_NAME} PUBLIC SDL3::SDL3 android EGL GLESv2)
main.cpp
#include <SDL.h>
#include <cmath>
#include <iostream>
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
// On UWP, we need to not have SDL_main otherwise we'll get a linker error
#define SDL_MAIN_HANDLED
#endif
#include <SDL_main.h>
#if __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include <SDL_opengles2.h>
void SDL_Fail()
{
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
exit(1);
}
static bool app_quit = false;
SDL_Window *window = nullptr;
const float maxFPS = 5.f;
const char *vertexShaderSource =
"attribute vec2 aPosition;\n"
"void main()"
"{\n"
" gl_Position = vec4(aPosition, 0.0, 1.0);\n"
"}\n";
const char *fragmentShaderSource =
"void main()"
"{\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
GLuint createShader(const char *shaderSource, int shaderType)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> errorLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
glDeleteShader(shader); // Don't leak the shader.
std::printf("%s\n", &(errorLog[0]));
// fatalError("Shader failed to compile");
}
return shader;
}
GLuint createShaderProgram()
{
GLuint program = glCreateProgram();
GLuint vShader = createShader(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fShader = createShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
glAttachShader(program, vShader);
glAttachShader(program, fShader);
glLinkProgram(program);
glUseProgram(program);
return program;
}
void initVertexBuffers(GLuint program)
{
float vertPositions[] = {
-1.f, -1.f,
1.f, -1.f,
0.f, 1.f
};
GLuint vertPosBuffer;
glGenBuffers(1, &vertPosBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer);
int amount = sizeof(vertPositions) / sizeof(vertPositions[0]);
glBufferData(GL_ARRAY_BUFFER, amount * sizeof(GLfloat),
vertPositions, GL_STATIC_DRAW);
GLint aPositionLocation = glGetAttribLocation(program, "aPosition");
glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(aPositionLocation);
}
void main_loop()
{
// Get events. If you are making a game, you probably want SDL_PollEvent instead of SDL_WaitEvent.
// you cannot use WaitEvent on Emscripten, because you cannot block the main thread there.
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_EVENT_QUIT)
app_quit = true;
break;
}
float startTicks = SDL_GetTicks();
// draw a color
// auto time = SDL_GetTicks() / 1000.f;
// auto red = (std::sin(time) + 1) / 2.0 * 255;
// auto green = (std::sin(time / 2) + 1) / 2.0 * 255;
// auto blue = (std::sin(time) * 2 + 1) / 2.0 * 255;
// auto red = 50;
// auto green = 255;
// auto blue = 50;
auto red = 0.2f;
auto green = 0.2f;
auto blue = 0.2f;
glClearColor(red, green, blue, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
SDL_GL_SwapWindow(window);
// Limit FPS to the max FPS
float frameTicks = SDL_GetTicks() - startTicks;
if (1000.f / maxFPS > frameTicks)
{
SDL_Delay(1000.f / maxFPS - frameTicks);
}
}
// Note: your main function __must__ take this form, otherwise on nonstandard platforms (iOS, etc), your app will not launch.
int main(int argc, char *argv[])
{
// init the library, here we make a window so we only need the Video capabilities.
if (SDL_Init(SDL_INIT_VIDEO))
{
SDL_Fail();
}
// create a window
SDL_Window *window = SDL_CreateWindow("Window", 352, 430, SDL_WINDOW_OPENGL);
if (!window)
{
SDL_Fail();
}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (!glContext)
{
SDL_Fail();
}
GLuint program = createShaderProgram();
initVertexBuffers(program);
// print some information about the window
SDL_ShowWindow(window);
{
int width, height, bbwidth, bbheight;
SDL_GetWindowSize(window, &width, &height);
SDL_GetWindowSizeInPixels(window, &bbwidth, &bbheight);
SDL_Log("Window size: %ix%i", width, height);
SDL_Log("Backbuffer size: %ix%i", bbwidth, bbheight);
if (width != bbwidth)
{
SDL_Log("This is a highdpi environment.");
}
}
SDL_Log("Application started successfully!");
#if __EMSCRIPTEN__
// on Emscripten, we cannot have an infinite loop in main. Instead, we must
// tell emscripten to call our main loop.
emscripten_set_main_loop(main_loop, 0, 1);
#else
while (!app_quit)
{
main_loop();
}
#endif
// cleanup everything at the end
#if !__EMSCRIPTEN__
SDL_DestroyWindow(window);
SDL_Quit();
SDL_Log("Application quit successfully!");
#endif
return 0;
}