Skip to content

Commit

Permalink
[Android] Started making C99 examples and off-screen rendering Androi…
Browse files Browse the repository at this point in the history
…d ready.

- Create EGLSurface as Pbuffer when no native window is provided on Android.
- Enabled C99 wrapper and its examples in BuildAndroid.sh script.
- Moved main entry points of C99 examples into ExampleBase to abstract main loop for desktop and mobile platforms.
- Fixed C99 wrapper generator to correctly output 'struct android_app' and aliased macro definitions for RendererID fields.

TODO: The Pbuffer EGLSurface needs testing.
      The Offscreen C99 example should be refactored to write the output to the Android device storage.
  • Loading branch information
LukasBanana committed Aug 26, 2024
1 parent e6a0159 commit f31eb23
Show file tree
Hide file tree
Showing 12 changed files with 320 additions and 193 deletions.
1 change: 1 addition & 0 deletions BuildAndroid.sh
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ BASE_OPTIONS=(
-DANDROID_PLATFORM=$ANDROID_API_LEVEL
-DANDROID_STL=$ANDROID_CXX_LIB
-DANDROID_CPP_FEATURES="rtti exceptions"
-DLLGL_BUILD_WRAPPER_C99=ON
-DLLGL_BUILD_RENDERER_OPENGLES3=ON
-DLLGL_GL_ENABLE_OPENGLES=$GLES_VER
-DLLGL_BUILD_RENDERER_NULL=$ENABLE_NULL
Expand Down
2 changes: 1 addition & 1 deletion examples/C99/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ project(LLGL_ExamplesC99)
find_source_files(FilesExampleBaseC99 C "${EXAMPLE_C99_PROJECTS_DIR}/ExampleBase")

find_project_source_files( FilesExampleC99_HelloTriangle "${EXAMPLE_C99_PROJECTS_DIR}/HelloTriangle" )
find_project_source_files( FilesExampleC99_Offscreen "${EXAMPLE_C99_PROJECTS_DIR}/Offscreen" )
find_project_source_files( FilesExampleC99_Offscreen "${EXAMPLE_C99_PROJECTS_DIR}/Offscreen" )
find_project_source_files( FilesExampleC99_Texturing "${EXAMPLE_C99_PROJECTS_DIR}/Texturing" )


Expand Down
184 changes: 108 additions & 76 deletions examples/C99/ExampleBase/ExampleBase.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,69 +47,65 @@ const LLGLSamplerDescriptor g_defaultSamplerDesc =
* Global variables
*/

int g_renderer = 0;
LLGLSwapChain g_swapChain = LLGL_NULL_OBJECT;
LLGLSurface g_surface = LLGL_NULL_OBJECT;
LLGLCommandBuffer g_commandBuffer = LLGL_NULL_OBJECT;
LLGLCommandQueue g_commandQueue = LLGL_NULL_OBJECT;
LLGLViewport g_viewport;
float g_projection[4][4] = { { 1.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f } };
int g_renderer = 0;
LLGLSwapChain g_swapChain = LLGL_NULL_OBJECT;
LLGLSurface g_surface = LLGL_NULL_OBJECT;
LLGLCommandBuffer g_commandBuffer = LLGL_NULL_OBJECT;
LLGLCommandQueue g_commandQueue = LLGL_NULL_OBJECT;
LLGLViewport g_viewport;
float g_projection[4][4] = { { 1.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f } };
ExampleConfig g_config = { .rendererDesc.moduleName = "OpenGL",
.resolution = { 800, 600 },
.samples = 8,
.vsync = true,
.debugger = false,
.noDepthStencil = false };


/*
* Internals
*/

static struct ExampleEventStatus
static struct ExampleEvents
{
float mouseMotion[2];
bool keyDown[256];
}
g_EventStauts =
g_events =
{
.mouseMotion = { 0.0f, 0.0f }
};

static void reset_event_status()
{
g_EventStauts.mouseMotion[0] = 0.0f;
g_EventStauts.mouseMotion[1] = 0.0f;
g_events.mouseMotion[0] = 0.0f;
g_events.mouseMotion[1] = 0.0f;
}

static void key_down_event(LLGLWindow sender, LLGLKey keyCode)
{
g_EventStauts.keyDown[keyCode] = true;
g_events.keyDown[keyCode] = true;
}

static void key_up_event(LLGLWindow sender, LLGLKey keyCode)
{
g_EventStauts.keyDown[keyCode] = false;
g_events.keyDown[keyCode] = false;
}

static void mouse_motion_event(LLGLWindow sender, const LLGLOffset2D* motion)
{
g_EventStauts.mouseMotion[0] = (float)motion->x;
g_EventStauts.mouseMotion[1] = (float)motion->y;
g_events.mouseMotion[0] = (float)motion->x;
g_events.mouseMotion[1] = (float)motion->y;
}


/*
* Global functions
*/

static struct ExampleConfig g_Config =
{
.rendererModule = "OpenGL",
.windowSize = { 800, 600 },
.samples = 8,
.vsync = true,
.debugger = false,
.noDepthStencil = false
};

static void update_viewport()
{
LLGLExtent2D swapChainResolution;
Expand All @@ -130,54 +126,48 @@ static float aspect_ratio()
return (float)swapChainResolution.width / (float)swapChainResolution.height;
}

void example_config(const ExampleConfig* config)
static void example_config(const ExampleArgs* args)
{
if (config != NULL)
{
if (config->rendererModule != NULL)
g_Config.rendererModule = config->rendererModule;
if (config->windowSize[0] != 0)
g_Config.windowSize[0] = config->windowSize[0];
if (config->windowSize[1] != 0)
g_Config.windowSize[1] = config->windowSize[1];
g_Config.samples = config->samples;
g_Config.vsync = config->vsync;
g_Config.debugger = config->debugger;
g_Config.noDepthStencil = config->noDepthStencil;
}
else
{
g_Config.rendererModule = "OpenGL";
g_Config.windowSize[0] = 800;
g_Config.windowSize[1] = 600;
g_Config.samples = 8;
g_Config.vsync = true;
g_Config.debugger = false;
g_Config.noDepthStencil = false;
}
#if __ANDROID__
g_config.rendererDesc.moduleName = "OpenGLES3";
g_config.rendererDesc.androidApp = args->androidApp;

#else
g_config.rendererDesc.moduleName = "OpenGL";
g_config.resolution[0] = 800;
g_config.resolution[1] = 600;
g_config.samples = 8;
g_config.vsync = true;
g_config.debugger = false;
g_config.noDepthStencil = false;
#endif
}

int example_init(const wchar_t* title)
int example_init(const char* title)
{
// Register standard output as log callback
llglRegisterLogCallbackStd();

// Load render system module
const char* rendererModule = g_Config.rendererModule;
if (llglLoadRenderSystem(rendererModule) == 0)
LLGLReport report = llglAllocReport();
if (llglLoadRenderSystemExt(&(g_config.rendererDesc), report) == 0)
{
fprintf(stderr, "Failed to load render system: %s\n", rendererModule);
LOG_ERROR("Failed to load render system: %s\n", g_config.rendererDesc.moduleName);
if (llglHasReportErrors(report))
LOG_ERROR("%s", llglGetReportText(report));
llglFreeReport(report);
return 1;
}
llglFreeReport(report);

// Create swap-chain
LLGLSwapChainDescriptor swapChainDesc =
{
.resolution = { g_Config.windowSize[0], g_Config.windowSize[1] },
.resolution = { g_config.resolution[0], g_config.resolution[1] },
.colorBits = 32, // 32 bits for color information
.depthBits = (g_Config.noDepthStencil ? 0 : 24), // 24 bits for depth comparison
.stencilBits = (g_Config.noDepthStencil ? 0 : 8), // 8 bits for stencil patterns
.samples = g_Config.samples, // check if LLGL adapts sample count that is too high
.depthBits = (g_config.noDepthStencil ? 0 : 24), // 24 bits for depth comparison
.stencilBits = (g_config.noDepthStencil ? 0 : 8), // 8 bits for stencil patterns
.samples = g_config.samples, // check if LLGL adapts sample count that is too high
};
g_swapChain = llglCreateSwapChain(&swapChainDesc);

Expand All @@ -188,9 +178,9 @@ int example_init(const wchar_t* title)
g_surface = llglGetSurface(g_swapChain);
LLGLWindow window = LLGL_GET_AS(LLGLWindow, g_surface);

wchar_t fullTitle[1024] = { L'\0' };
swprintf(fullTitle, sizeof(fullTitle)/sizeof(fullTitle[0]), L"LLGL C99 Example: %s", title);
llglSetWindowTitle(window, fullTitle);
char fullTitle[1024] = { L'\0' };
snprintf(fullTitle, sizeof(fullTitle), "LLGL C99 Example: %s", title);
llglSetWindowTitleUTF8(window, fullTitle);

// Register event listener to respond to move and keyboard events
const LLGLWindowEventListener windowCallbacks =
Expand Down Expand Up @@ -225,11 +215,62 @@ int example_init(const wchar_t* title)
return 0;
}

void example_release()
static bool example_poll_events()
{
// Reset event status
reset_event_status();

// Process surface and events and check if window was closed
return llglProcessSurfaceEvents() && !llglHasWindowQuit(LLGL_GET_AS(LLGLWindow, g_surface)) && !g_events.keyDown[LLGLKeyEscape];
}

static void example_release()
{
llglUnloadRenderSystem();
}

int example_main(int (*pfnInit)(), void (*pfnLoop)(double dt), const ExampleArgs* args)
{
// Configure initial setup
example_config(args);

// Invoke example initialization callback
if (pfnInit != NULL)
{
int ret = pfnInit();
if (ret != 0)
return ret;
}

// Run main loop
if (pfnLoop != NULL)
{
uint64_t startTick = llglTimerTick();
double tickFrequency = 1.0 / (double)llglTimerFrequency();

while (example_poll_events())
{
// Update frame time
uint64_t endTick = llglTimerTick();
double dt = (double)(endTick - startTick) * tickFrequency;
startTick = endTick;

#if __ANDROID__
if (key_pressed(LLGLKeyBrowserBack))
ANativeActivity_finish(g_config.rendererDesc.androidApp->activity);
#endif

// Tick main loop callback
pfnLoop(dt);
}
}

// Clean up
example_release();

return 0;
}

static void build_perspective_projection(float m[4][4], float aspect, float nearPlane, float farPlane, float fov, bool isUnitCube)
{
const float h = 1.0f / tanf(fov * 0.5f);
Expand All @@ -256,15 +297,6 @@ static void build_perspective_projection(float m[4][4], float aspect, float near
m[3][3] = 0.0f;
}

bool example_poll_events()
{
// Reset event status
reset_event_status();

// Process surface and events and check if window was closed
return llglProcessSurfaceEvents() && !llglHasWindowQuit(LLGL_GET_AS(LLGLWindow, g_surface)) && !g_EventStauts.keyDown[LLGLKeyEscape];
}

void perspective_projection(float outProjection[4][4], float aspectRatio, float nearPlane, float farPlane, float fieldOfView)
{
const int rendererID = llglGetRendererID();
Expand Down Expand Up @@ -412,16 +444,16 @@ void matrix_rotate(float outMatrix[4][4], float x, float y, float z, float angle

bool key_pressed(LLGLKey keyCode)
{
return g_EventStauts.keyDown[keyCode];
return g_events.keyDown[keyCode];
}

float mouse_movement_x()
{
return g_EventStauts.mouseMotion[0];
return g_events.mouseMotion[0];
}

float mouse_movement_y()
{
return g_EventStauts.mouseMotion[1];
return g_events.mouseMotion[1];
}

Loading

0 comments on commit f31eb23

Please sign in to comment.