How to troubleshoot invisible OpenGL triangle in ImGui Android app?

Hi, the triangle is drawn perfectly on PC (imgui > example_glfw_opengl3), but it isn’t drawn (invisible) on Android (imgui > example_android_opengl3). What could be the possible cause of that problem? However, the ImGui UI is drawn (visible) on Android, and it’s drawn using OpenGL.

As a beginner, it’s impossible to post something on Stack Overflow that requires a high-quality thread. Similarly, it’s difficult to post the same thing on the ImGui GitHub discussion because they specify that only ImGui-specific thread should be posted there.

Functions from Cxxdroid:

// Originated from Cxxdroid (Android app) > OpenGL ES

#if !defined(__ANDROID__)
    // OpenGL
    #ifdef USE_OPENGL
        #ifdef OPENGL_LOADER_GL3W
            #include "GL/gl3w.h"
        #elif OPENGL_LOADER_GLEW
            #include "GL/glew.h"
        #elif OPENGL_LOADER_GLAD
            // TODO
        #endif
    #endif
#else // ANDROID
    #include <android/log.h>
    #ifdef USE_OPENGL
        #include <EGL/egl.h>
        #include <GLES3/gl3.h>
    #endif
#endif

const char *VERTEX_SHADER =
	"attribute vec4 position;\n"
	"attribute vec4 color;\n"
	"varying vec4 vcolor;\n"
	"void main()\n"
	"{\n"
	"gl_Position = vec4(position.xyz, 1.0);\n"
	"vcolor = color;\n"
	"}";

const char *FRAGMENT_SHADER =
	"precision mediump float;\n"
	"varying vec4 vcolor;\n"
	"void main()\n"
	"{\n"
	"gl_FragColor = vec4 (vcolor.xyz, 1.0);\n"
	"}";

static GLfloat vertexes[] = {0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f};
static GLfloat colors[12] = {};

void triangle_init()
{
	// Load shaders
	GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex, 1, &VERTEX_SHADER, NULL);
	glCompileShader(vertex);

	GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &FRAGMENT_SHADER, NULL);
	glCompileShader(fragment);

	// Combine shaders into program
	GLuint program = glCreateProgram();
	glAttachShader(program, vertex);
	glAttachShader(program, fragment);
	glLinkProgram(program);
	// Use it
	glUseProgram(program);

	// Point position attribute to vertexes
	GLint position = glGetAttribLocation(program, "position");
	glEnableVertexAttribArray(position);
	glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, vertexes);
	// Point color attribute to colors
	GLint color = glGetAttribLocation(program, "color");
	glEnableVertexAttribArray(color);
	glVertexAttribPointer(color, 4, GL_FLOAT, GL_FALSE, 0, colors);
}

void triangle_render() {
	static double timemillis = 0.0;
	timemillis += 1000.0 / 60.0;

	// Animate colors
	for (int i = 0; i < 3; i++)
	{
		colors[i * 4 + 0] = sin(i * M_PI * 2 / 3 + timemillis / 1000) / 2 + 0.5f;
		colors[i * 4 + 1] = sin((i + 1) * M_PI * 2 / 3 + timemillis / 1000) / 2 + 0.5f;
		colors[i * 4 + 2] = sin((i + 2) * M_PI * 2 / 3 + timemillis / 1000) / 2 + 0.5f;
		colors[i * 4 + 3] = 1.0f;
	}
	// Clear screen
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// Draw triangle
	glDrawArrays(GL_TRIANGLES, 0, 3);
}

Other functions:

bool setupGraphics(int renderingApi) {
    if (renderingApi == RENDERINGAPI_OPENGL) {
        #ifdef USE_OPENGL
            // Initialize OpenGL loader - Referenced from [GLSL-PathTracer > "src/Main.cpp"](https://github.com/knightcrawler25/GLSL-PathTracer)
            {
                #if GL_VERSION_3_2
                    #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
                        bool err = gl3wInit() != 0;
                    #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
                    bool err = glewInit() != GLEW_OK;
                #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
                    bool err = gladLoadGL() == 0;
                #endif
                    if (err) {
                        fprintf(stderr, "Failed to initialize OpenGL loader!\n");
                        return false;
                    }
                #endif
            }
        #endif
    } else if (renderingApi == RENDERINGAPI_VULKAN) {
        #ifdef USE_VULKAN
            // TODO
        #endif
    }

    triangle_init();
    return true;
}

void imGuiFrame() {
    ImGui::Begin("Test");
        ImGui::Text("Hello, world!");
    ImGui::End();
}

void renderFrame(int renderingApi) {
    if (renderingApi == RENDERINGAPI_OPENGL) {
        #ifdef USE_OPENGL
            triangle_render();
        #endif
    } else if (renderingApi == RENDERINGAPI_VULKAN) {
        #ifdef USE_VULKAN
            // TODO
        #endif
    }
}

How is the function renderFrame() called?:

    ImGui::Render();
    ImDrawData* mainDrawData = ImGui::GetDrawData();
    const bool mainIsMinimized = (mainDrawData->DisplaySize.x <= 0.0f || mainDrawData->DisplaySize.y <= 0.0f);
    if (renderingApi == RENDERINGAPI_OPENGL) {
        #ifdef USE_OPENGL
            glViewport(0, 0, int(displaySize.x), int(displaySize.y));
            glClearColor(params.clearColor.x * params.clearColor.w, params.clearColor.y * params.clearColor.w, params.clearColor.z * params.clearColor.w, params.clearColor.w);

            //_/--------------------------------------------------\_
            // Callback (renderFrame())
            if (params.mainParams.func_renderFrame) {
                params.mainParams.func_renderFrame(renderingApi);
            }
            // \--------------------------------------------------/

            ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
            #if !defined(__ANDROID__)
                // .
            #else // ANDROID
                eglSwapBuffers(g_EglDisplay, g_EglSurface);
            #endif
        #endif
    } else if (renderingApi == RENDERINGAPI_VULKAN) {
        ...
    }

From:

I added a line that calls the function setupGraphics() in the function android_main() just before the loop. Should I call it in Init()? It’s difficult to do in my code because params is not available there. However, I don’t believe it will fix the problem because I’ve tried as many methods as possible, but I’m not sure.
I added a line that calls the function renderFrame() in the function MainLoopStep() just before calling ImGui_ImplOpenGL3_RenderDrawData().

I found the solution sometimes after being stuck on a problem for a very long time. When I write a thread on a forum like this, I discover the solution instantly.

Solution: Try to use the simplest method possible. Use the official “example_android_opengl3/main.cpp” and add a few lines of code one by one (the functions from Cxxdroid > OpenGL ES). Then the problem is fixed. Call setupGraphics() in Init().

The reason the problem existed was because the code was too extensive, and I couldn’t identify where the problem might be. But when it’s simple, it’s easy to fix.