Skip to content

Commit

Permalink
[Android] Made C99 examples Android ready.
Browse files Browse the repository at this point in the history
- Abstracted asset reading in C99/Texturing example just like in the C++ counterpart.
- Added FileUtils.c/.h files to ExampleBase_C99 library.
- Added llglSet/GetCanvasTitleUTF8 functions to C99 wrapper.
- Added missing declaration of llglGetFormatAttribs() to C99 wrapper.
- Link C99 example projects with C++ semantics to avoid issue with "libc++_shared.so" dependency on Android.
  • Loading branch information
LukasBanana committed Sep 1, 2024
1 parent 6f269c8 commit e452ff5
Show file tree
Hide file tree
Showing 16 changed files with 373 additions and 40 deletions.
9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,14 @@ function(add_llgl_example_project PROJECT_NAME LINKER_LANG SRC_FILES LIB_FILES)
endif()

# Configure linker settings
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE ${LINKER_LANG} DEBUG_POSTFIX "D")
if(LLGL_ANDROID_PLATFORM)
# When linking the libExample*.so library for Android, we link with C++ semantics.
# Otherwise, the libc++_shared.so library will be unintentionally included,
# since the static dependencies like libLLGL.so must be build with C++, regardingless of the example project's language
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX DEBUG_POSTFIX "D")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE ${LINKER_LANG} DEBUG_POSTFIX "D")
endif()

# Configure working directory and project solution folder
if(${PROJECT_NAME} MATCHES "Example_C99_+")
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")

if(LLGL_ANDROID_PLATFORM)
find_source_files(FilesExampleBaseAndroid C "${SHARED_PLATFORM_DIR}/Android")
find_source_files(FilesExampleBaseC99Android C "${SHARED_PLATFORM_DIR}/Android")
endif()

set(FilesExampleBaseAllC99 ${FilesExampleBaseC99})
Expand Down
87 changes: 78 additions & 9 deletions examples/C99/ExampleBase/ExampleBase.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb/stb_image_write.h>

#if defined(ANDROID) || defined(__ANDROID__)
# include "Android/AppUtils.h"
#endif


/*
* Global constants
Expand Down Expand Up @@ -43,6 +47,7 @@ const LLGLSamplerDescriptor g_defaultSamplerDesc =
.borderColor = { 0.0f, 0.0f, 0.0f, 0.0f },
};


/*
* Global variables
*/
Expand Down Expand Up @@ -73,6 +78,7 @@ static struct ExampleEvents
{
float mouseMotion[2];
bool keyDown[256];
bool keyPushed[256];
}
g_events =
{
Expand All @@ -83,10 +89,13 @@ static void reset_event_status()
{
g_events.mouseMotion[0] = 0.0f;
g_events.mouseMotion[1] = 0.0f;
memset(g_events.keyPushed, 0, sizeof(g_events.keyPushed));
}

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

Expand Down Expand Up @@ -128,10 +137,15 @@ static float aspect_ratio()

static void example_config(const ExampleArgs* args)
{
#if __ANDROID__
#if defined(ANDROID) || defined(__ANDROID__)
struct android_app* androidApp = args->androidApp;

g_config.rendererDesc.moduleName = "OpenGLES3";
g_config.rendererDesc.androidApp = args->androidApp;
g_config.rendererDesc.androidApp = androidApp;

// Store pointer to asset manager so we can load assets from the APK bundle
if (androidApp->activity != NULL)
AndroidSetAssetManager(androidApp->activity->assetManager);
#else
g_config.rendererDesc.moduleName = "OpenGL";
g_config.resolution[0] = 800;
Expand All @@ -143,6 +157,36 @@ static void example_config(const ExampleArgs* args)
#endif
}

void log_renderer_info()
{
LLGLRendererInfo info;
llglGetRendererInfo(&info);

LLGLExtent2D swapChainRes;
LLGLRenderTarget swapChainRT = LLGL_GET_AS(LLGLRenderTarget, g_swapChain);
llglGetRenderTargetResolution(swapChainRT, &swapChainRes);

llglLogPrintf(
"render system:\n"
" renderer: %s\n"
" device: %s\n"
" vendor: %s\n"
" shading language: %s\n"
"\n"
"swap-chain:\n"
" resolution: %u x %u\n"
" samples: %u\n"
"\n",
info.rendererName,
info.deviceName,
info.vendorName,
info.shadingLanguageName,
swapChainRes.width,
swapChainRes.height,
llglGetRenderTargetSamples(swapChainRT)
);
}

int example_init(const char* title)
{
// Register standard output as log callback
Expand All @@ -152,9 +196,9 @@ int example_init(const char* title)
LLGLReport report = llglAllocReport();
if (llglLoadRenderSystemExt(&(g_config.rendererDesc), report) == 0)
{
LOG_ERROR("Failed to load render system: %s\n", g_config.rendererDesc.moduleName);
llglLogErrorf("Failed to load render system: %s\n", g_config.rendererDesc.moduleName);
if (llglHasReportErrors(report))
LOG_ERROR("%s", llglGetReportText(report));
llglLogErrorf("%s", llglGetReportText(report));
llglFreeReport(report);
return 1;
}
Expand All @@ -170,19 +214,26 @@ int example_init(const char* title)
.samples = g_config.samples, // check if LLGL adapts sample count that is too high
};
g_swapChain = llglCreateSwapChain(&swapChainDesc);
g_surface = llglGetSurface(g_swapChain);

// Enable V-sync
llglSetVsyncInterval(g_swapChain, 1);

// Set window title and show window
g_surface = llglGetSurface(g_swapChain);
LLGLWindow window = LLGL_GET_AS(LLGLWindow, g_surface);

// Set surface title to example name
char fullTitle[1024] = { L'\0' };
snprintf(fullTitle, sizeof(fullTitle), "LLGL C99 Example: %s", title);

#if LLGLEXAMPLE_MOBILE
// Set canvas title
LLGLCanvas canvas = LLGL_GET_AS(LLGLCanvas, g_surface);
llglSetCanvasTitleUTF8(canvas, fullTitle);
#else
// Set window title and show window
LLGLWindow window = LLGL_GET_AS(LLGLWindow, g_surface);
llglSetWindowTitleUTF8(window, fullTitle);

// Register event listener to respond to move and keyboard events
memset(&g_events, 0, sizeof(g_events));
const LLGLWindowEventListener windowCallbacks =
{
.onKeyDown = key_down_event,
Expand All @@ -193,6 +244,7 @@ int example_init(const char* title)

// Show window after its setup is done
llglShowWindow(window, true);
#endif

// Create command buffer to submit subsequent graphics commands to the GPU
LLGLCommandBufferDescriptor cmdBufferDesc =
Expand All @@ -212,16 +264,28 @@ int example_init(const char* title)
const float aspectRatio = aspect_ratio();
perspective_projection(g_projection, aspectRatio, /*nearPlane:*/ 0.1f, /*farPlane;*/ 100.0f, /*fieldOfView:*/ DEG2RAD(45.0f));

// Print information about the render system and swap-chain
log_renderer_info();

return 0;
}

static bool is_example_running()
{
#if LLGLEXAMPLE_MOBILE
return true;
#else
return !llglHasWindowQuit(LLGL_GET_AS(LLGLWindow, g_surface)) && !g_events.keyDown[LLGLKeyEscape];
#endif
}

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];
return llglProcessSurfaceEvents() && is_example_running();
}

static void example_release()
Expand Down Expand Up @@ -447,6 +511,11 @@ bool key_pressed(LLGLKey keyCode)
return g_events.keyDown[keyCode];
}

bool key_pushed(LLGLKey keyCode)
{
return g_events.keyPushed[keyCode];
}

float mouse_movement_x()
{
return g_events.mouseMotion[0];
Expand Down
16 changes: 7 additions & 9 deletions examples/C99/ExampleBase/ExampleBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
#include <LLGL-C/LLGL.h>
#include <stdbool.h>
#include <stdio.h> // fprintf()
#include "FileUtils.h"

#if __ANDROID__
#if defined(ANDROID) || defined(__ANDROID__)
# include <android_native_app_glue.h>
# include <android/log.h>
# define LLGLEXAMPLE_MOBILE 1
#endif


Expand All @@ -28,10 +29,7 @@
#define ARRAY_SIZE(A) (sizeof(A)/sizeof((A)[0]))


#if __ANDROID__

#define LOG_ERROR(...) \
(void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)
#if defined(ANDROID) || defined(__ANDROID__)

#define IMPLEMENT_EXAMPLE_MAIN(INIT, LOOP) \
void android_main(struct android_app* state) \
Expand All @@ -42,9 +40,6 @@

#else

#define LOG_ERROR(...) \
fprintf(stderr, __VA_ARGS__)

#define IMPLEMENT_EXAMPLE_MAIN(INIT, LOOP) \
int main(int argc, char* argv[]) \
{ \
Expand Down Expand Up @@ -179,6 +174,9 @@ void matrix_rotate(float outMatrix[4][4], float x, float y, float z, float angle
// Returns true if the specified key is currently pressed down.
bool key_pressed(LLGLKey keyCode);

// Returns true if the speciifed key was pushed down. Only true during one frame until the key is released again.
bool key_pushed(LLGLKey keyCode);

// Returns the mouse movement on the X-axis.
float mouse_movement_x();

Expand Down
76 changes: 76 additions & 0 deletions examples/C99/ExampleBase/FileUtils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* FileUtils.c (C99)
*
* Copyright (c) 2015 Lukas Hermanns. All rights reserved.
* Licensed under the terms of the BSD 3-Clause license (see LICENSE.txt).
*/

#include "FileUtils.h"
#include <stdlib.h>
#include <string.h>
#include <LLGL-C/Log.h>

#if defined(ANDROID) || defined(__ANDROID__)
# include "Android/AppUtils.h"
#endif


AssetContainer read_asset(const char* name)
{
AssetContainer asset = { NULL, 0 };

char filename[512] = { '\0' };
#if defined(ANDROID) || defined(__ANDROID__)
if (strncmp(name, "Textures/", 9) == 0)
{
sprintf(filename, "%s", name + 9);
}
else if (strncmp(name, "Models/", 7) == 0)
{
sprintf(filename, "%s", name + 7);
}
else
{
llglLogErrorf("unrecognized base path for asset: %s\n", name);
return asset;
}
#else
sprintf(filename, "../../Shared/Assets/%s", name);
#endif

// Read file and all of its content
FILE* file = fopen(filename, "rb");
if (file != NULL)
{
fseek(file, 0, SEEK_END);
size_t len = (size_t)ftell(file);
fseek(file, 0, SEEK_SET);
asset.data = (char*)malloc(len);
if (asset.data != NULL)
{
fread(asset.data, 1, len, file);
asset.size = len;
}
else
{
llglLogErrorf("failed to allocate %u byte(s) to read asset: %s\n", (unsigned)asset.size, name);
}
fclose(file);
}
else
{
llglLogErrorf("failed to load asset: %s\n", name);
return asset;
}

return asset;
}

void free_asset(AssetContainer asset)
{
if (asset.data != NULL)
{
free(asset.data);
}
}

31 changes: 31 additions & 0 deletions examples/C99/ExampleBase/FileUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* FileUtils.h (C99)
*
* Copyright (c) 2015 Lukas Hermanns. All rights reserved.
* Licensed under the terms of the BSD 3-Clause license (see LICENSE.txt).
*/

#ifndef LLGLEXAMPLES_C99_FILE_UTILS_H
#define LLGLEXAMPLES_C99_FILE_UTILS_H


#include <stdio.h>
#include <stddef.h>


typedef struct AssetContainer
{
char* data;
size_t size;
}
AssetContainer;

// Reads an asset from the bundle. This is either from the examples/Shared/Assets/ folder or the mobile app package.
AssetContainer read_asset(const char* name);

// Frees the memory allocated for the specified asset.
void free_asset(AssetContainer asset);


#endif

Loading

0 comments on commit e452ff5

Please sign in to comment.