From f31eb234e2099e71ab07a33494454d4abc4876b5 Mon Sep 17 00:00:00 2001 From: Laura Hermanns Date: Sun, 25 Aug 2024 22:19:46 -0400 Subject: [PATCH] [Android] Started making C99 examples and off-screen rendering Android 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. --- BuildAndroid.sh | 1 + examples/C99/CMakeLists.txt | 2 +- examples/C99/ExampleBase/ExampleBase.c | 184 ++++++++++-------- examples/C99/ExampleBase/ExampleBase.h | 71 +++++-- examples/C99/Offscreen/Offscreen.c | 20 +- examples/C99/Texturing/Texturing.c | 153 ++++++++------- include/LLGL-C/LLGLWrapper.h | 19 +- scripts/WrapperGen/llgl_module.py | 2 +- scripts/WrapperGen/llgl_translator_c99.py | 18 +- .../Android/AndroidSharedEGLSurface.cpp | 29 ++- .../Android/AndroidSharedEGLSurface.h | 8 +- .../OpenGL/WebGLProfile/WebGLProfile.cpp | 6 +- 12 files changed, 320 insertions(+), 193 deletions(-) diff --git a/BuildAndroid.sh b/BuildAndroid.sh index bbb6356f15..7569a0ec80 100644 --- a/BuildAndroid.sh +++ b/BuildAndroid.sh @@ -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 diff --git a/examples/C99/CMakeLists.txt b/examples/C99/CMakeLists.txt index 45ea5398a3..f0ca8a2c53 100644 --- a/examples/C99/CMakeLists.txt +++ b/examples/C99/CMakeLists.txt @@ -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" ) diff --git a/examples/C99/ExampleBase/ExampleBase.c b/examples/C99/ExampleBase/ExampleBase.c index 1e026b9a05..e9d7e973f0 100644 --- a/examples/C99/ExampleBase/ExampleBase.c +++ b/examples/C99/ExampleBase/ExampleBase.c @@ -47,52 +47,58 @@ 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; } @@ -100,16 +106,6 @@ static void mouse_motion_event(LLGLWindow sender, const LLGLOffset2D* motion) * 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; @@ -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); @@ -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 = @@ -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); @@ -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(); @@ -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]; } diff --git a/examples/C99/ExampleBase/ExampleBase.h b/examples/C99/ExampleBase/ExampleBase.h index 0f3fa9031b..da4263d470 100644 --- a/examples/C99/ExampleBase/ExampleBase.h +++ b/examples/C99/ExampleBase/ExampleBase.h @@ -11,6 +11,12 @@ #include #include +#include // fprintf() + +#if __ANDROID__ +# include +# include +#endif /* @@ -22,18 +28,56 @@ #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__) + +#define IMPLEMENT_EXAMPLE_MAIN(INIT, LOOP) \ + void android_main(struct android_app* state) \ + { \ + ExampleArgs args = { state }; \ + (void)example_main(INIT, LOOP, &args); \ + } + +#else + +#define LOG_ERROR(...) \ + fprintf(stderr, __VA_ARGS__) + +#define IMPLEMENT_EXAMPLE_MAIN(INIT, LOOP) \ + int main(int argc, char* argv[]) \ + { \ + ExampleArgs args = { argc, argv }; \ + return example_main(INIT, LOOP, &args); \ + } + +#endif + + /* * Structures */ +typedef struct ExampleArgs +{ +#if __ANDROID__ + struct android_app* androidApp; +#else + int argc; + char** argv; +#endif +} +ExampleArgs; + typedef struct ExampleConfig { - const char* rendererModule; - uint32_t windowSize[2]; - uint32_t samples; - bool vsync; - bool debugger; - bool noDepthStencil; + LLGLRenderSystemDescriptor rendererDesc; + uint32_t resolution[2]; + uint32_t samples; + bool vsync; + bool debugger; + bool noDepthStencil; } ExampleConfig; @@ -97,22 +141,19 @@ extern LLGLViewport g_viewport; // Primary camera projection extern float g_projection[4][4]; +// Render system configuraiton. +extern ExampleConfig g_config; + /* * Global functions */ -// Configures the example setup. If used, it must be called before example_init(). If this is NULL, the defualt configuration will be used. -void example_config(const ExampleConfig* config); - // Initializes the example with the specified title and returns a non-zero error code if initialization failed. -int example_init(const wchar_t* title); - -// Releases all example resources. -void example_release(); +int example_init(const char* title); -// Processes all surface events, polls the event list (See mouse_movement_x() etc.) and returns false if the window was closed. -bool example_poll_events(); +// Runs the main loop. +int example_main(int (*pfnInit)(), void (*pfnLoop)(double dt), const ExampleArgs* args); // Builds a perspective projection matrix. void perspective_projection(float outProjection[4][4], float aspectRatio, float nearPlane, float farPlane, float fieldOfView); diff --git a/examples/C99/Offscreen/Offscreen.c b/examples/C99/Offscreen/Offscreen.c index afaaf052cb..a72faed28e 100644 --- a/examples/C99/Offscreen/Offscreen.c +++ b/examples/C99/Offscreen/Offscreen.c @@ -12,11 +12,11 @@ This image should look identical to the "Offscreen.png" image. */ #include +#include #include // printf() #include // malloc()/free() #include // sinf()/cosf() -#define STB_IMAGE_WRITE_IMPLEMENTATION #include "../../../external/stb/stb_image_write.h" // stbi_write_png() #define FRAME_WIDTH 512 @@ -55,13 +55,13 @@ float LerpColorWheel(float t, int component) ); } -int main(int argc, char* argv[]) +int ExampleInit() { // Load render system module - const char* rendererModule = "OpenGL"; - if (llglLoadRenderSystem(rendererModule) == 0) + LLGLReport report = {}; + 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); return 1; } @@ -92,7 +92,7 @@ int main(int argc, char* argv[]) Vertex* vertices = (Vertex*)malloc(vertexBufferSize); if (vertices == NULL) { - fprintf(stderr, "Failed to allocate %zu bytes for vertex buffer\n", vertexBufferSize); + LOG_ERROR("Failed to allocate %zu bytes for vertex buffer\n", vertexBufferSize); return 1; } @@ -186,7 +186,7 @@ int main(int argc, char* argv[]) LLGLReport shaderReport = llglGetShaderReport(shaders[i]); if (llglHasReportErrors(shaderReport)) { - fprintf(stderr, "%s\n", llglGetReportText(shaderReport)); + LOG_ERROR("%s\n", llglGetReportText(shaderReport)); return 1; } } @@ -238,7 +238,7 @@ int main(int argc, char* argv[]) LLGLReport pipelineReport = llglGetPipelineStateReport(pipeline); if (llglHasReportErrors(pipelineReport)) { - fprintf(stderr, "%s\n", llglGetReportText(pipelineReport)); + LOG_ERROR("%s\n", llglGetReportText(pipelineReport)); return 1; } @@ -316,7 +316,7 @@ int main(int argc, char* argv[]) const char* outputFilename = "Offscreen.Results.png"; if (stbi_write_png(outputFilename, FRAME_WIDTH, FRAME_HEIGHT, 4, imageData, (int)imageRowStride) == 0) { - fprintf(stderr, "Failed to save image to disk: %s\n", outputFilename); + LOG_ERROR("Failed to save image to disk: %s\n", outputFilename); return 1; } @@ -328,3 +328,5 @@ int main(int argc, char* argv[]) return 0; } + +IMPLEMENT_EXAMPLE_MAIN(ExampleInit, NULL); diff --git a/examples/C99/Texturing/Texturing.c b/examples/C99/Texturing/Texturing.c index 4bf9433f65..dafd54cc35 100644 --- a/examples/C99/Texturing/Texturing.c +++ b/examples/C99/Texturing/Texturing.c @@ -7,8 +7,6 @@ #include #include -#include // for fprintf() -#include // for memcpy() #include // for loading images @@ -19,19 +17,37 @@ typedef struct SceneConstants } SceneConstants; -int main(int argc, char* argv[]) +struct ExampleData +{ + LLGLBuffer vertexBuffer; + LLGLBuffer indexBuffer; + LLGLBuffer sceneBuffer; + LLGLPipelineState pipeline; + LLGLTexture colorTexture; + LLGLSampler samplers[3]; + float rotation; + size_t indexCount; +} +g_example = +{ + .rotation = -20.0f, + .indexCount = 0, +}; + +void TexturingLoop(double dt); + +int TexturingInit(const LLGLRenderSystemDescriptor* rendererDesc, int argc, char* argv[]) { // Initialize example - if (example_init(L"Texturing") != 0) + if (example_init("Texturing") != 0) return 1; // Create textured cube mesh const TexturedVertex* vertices = NULL; size_t vertexCount = 0; const uint32_t* indices = NULL; - size_t indexCount = 0; - get_textured_cube(&vertices, &vertexCount, &indices, &indexCount); + get_textured_cube(&vertices, &vertexCount, &indices, &g_example.indexCount); // Vertex format with 3D position, normal, and texture-coordinates const LLGLVertexAttribute vertexAttributes[3] = @@ -49,15 +65,15 @@ int main(int argc, char* argv[]) .numVertexAttribs = ARRAY_SIZE(vertexAttributes), .vertexAttribs = vertexAttributes, // Vertex format layout }; - LLGLBuffer vertexBuffer = llglCreateBuffer(&vertexBufferDesc, vertices); + g_example.vertexBuffer = llglCreateBuffer(&vertexBufferDesc, vertices); // Create index buffer const LLGLBufferDescriptor indexBufferDesc = { - .size = sizeof(uint32_t)*indexCount, // Size (in bytes) of the index buffer - .bindFlags = LLGLBindIndexBuffer, // Enables the buffer to be bound to an index buffer slot + .size = sizeof(uint32_t)*g_example.indexCount, // Size (in bytes) of the index buffer + .bindFlags = LLGLBindIndexBuffer, // Enables the buffer to be bound to an index buffer slot }; - LLGLBuffer indexBuffer = llglCreateBuffer(&indexBufferDesc, indices); + g_example.indexBuffer = llglCreateBuffer(&indexBufferDesc, indices); // Create constant buffer const LLGLBufferDescriptor sceneBufferDesc = @@ -65,7 +81,7 @@ int main(int argc, char* argv[]) .size = sizeof(SceneConstants), // Size (in bytes) of the constant buffer .bindFlags = LLGLBindConstantBuffer, // Enables the buffer to be bound as a constant buffer, which is optimized for fast updates per draw call }; - LLGLBuffer sceneBuffer = llglCreateBuffer(&sceneBufferDesc, NULL); + g_example.sceneBuffer = llglCreateBuffer(&sceneBufferDesc, NULL); // Load image data from file (using STBI library, see http://nothings.org/stb_image.h) const char* imageFilename = "../../Media/Textures/Crate.jpg"; @@ -74,7 +90,7 @@ int main(int argc, char* argv[]) unsigned char* imageBuffer = stbi_load(imageFilename, &imageSize[0], &imageSize[1], &texComponents, 0); if (!imageBuffer) { - fprintf(stderr, "Failed to load image: %s\n", imageFilename); + LOG_ERROR("Failed to load image: %s\n", imageFilename); return 1; } @@ -93,22 +109,20 @@ int main(int argc, char* argv[]) .extent = { (uint32_t)imageSize[0], (uint32_t)imageSize[1], 1u }, .miscFlags = LLGLMiscGenerateMips, }; - LLGLTexture colorTexture = llglCreateTexture(&texDesc, &imageView); + g_example.colorTexture = llglCreateTexture(&texDesc, &imageView); // Create samplers - LLGLSampler samplers[3]; - LLGLSamplerDescriptor anisotropySamplerDesc = g_defaultSamplerDesc; { anisotropySamplerDesc.maxAnisotropy = 8; } - samplers[0] = llglCreateSampler(&anisotropySamplerDesc); + g_example.samplers[0] = llglCreateSampler(&anisotropySamplerDesc); LLGLSamplerDescriptor lodSamplerDesc = g_defaultSamplerDesc; { lodSamplerDesc.mipMapLODBias = 3; } - samplers[1] = llglCreateSampler(&lodSamplerDesc); + g_example.samplers[1] = llglCreateSampler(&lodSamplerDesc); LLGLSamplerDescriptor nearestSamplerDesc = g_defaultSamplerDesc; { @@ -117,7 +131,7 @@ int main(int argc, char* argv[]) nearestSamplerDesc.minLOD = 4; nearestSamplerDesc.maxLOD = 4; } - samplers[2] = llglCreateSampler(&nearestSamplerDesc); + g_example.samplers[2] = llglCreateSampler(&nearestSamplerDesc); // Create shaders const LLGLShaderDescriptor vertShaderDesc = @@ -147,7 +161,7 @@ int main(int argc, char* argv[]) LLGLReport shaderReport = llglGetShaderReport(shaders[i]); if (llglHasReportErrors(shaderReport)) { - fprintf(stderr, "%s\n", llglGetReportText(shaderReport)); + LOG_ERROR("%s\n", llglGetReportText(shaderReport)); return 1; } } @@ -180,71 +194,66 @@ int main(int argc, char* argv[]) .rasterizer = { .multiSampleEnabled = true }, .blend.targets[0].colorMask = LLGLColorMaskAll, }; - LLGLPipelineState pipeline = llglCreateGraphicsPipelineState(&pipelineDesc); + g_example.pipeline = llglCreateGraphicsPipelineState(&pipelineDesc); // Link shader program and check for errors - LLGLReport pipelineReport = llglGetPipelineStateReport(pipeline); + LLGLReport pipelineReport = llglGetPipelineStateReport(g_example.pipeline); if (llglHasReportErrors(pipelineReport)) { - fprintf(stderr, "%s\n", llglGetReportText(pipelineReport)); + LOG_ERROR("%s\n", llglGetReportText(pipelineReport)); return 1; } - // Scene state - float rotation = -20.0f; + return 0; +} - // Enter main loop - while (example_poll_events()) - { - // Update scene by mouse events - if (key_pressed(LLGLKeyLButton)) - rotation += mouse_movement_x() * 0.5f; +void TexturingLoop(double dt) +{ + // Update scene by mouse events + if (key_pressed(LLGLKeyLButton)) + g_example.rotation += mouse_movement_x() * 0.5f; - // Begin recording commands - llglBegin(g_commandBuffer); + // Begin recording commands + llglBegin(g_commandBuffer); + { + // Update scene constant buffer + SceneConstants scene; { - // Update scene constant buffer - SceneConstants scene; - { - matrix_load_identity(scene.wMatrix); - matrix_translate(scene.wMatrix, 0.0f, 0.0f, 5.0f); - matrix_rotate(scene.wMatrix, 0.0f, 1.0f, 0.0f, DEG2RAD(rotation)); - - matrix_mul(scene.wvpMatrix, g_projection, scene.wMatrix); - } - llglUpdateBuffer(sceneBuffer, 0, &scene, sizeof(scene)); - - // Set vertex and index buffers - llglSetVertexBuffer(vertexBuffer); - llglSetIndexBuffer(indexBuffer); - - // Set the swap-chain as the initial render target - llglBeginRenderPass(LLGL_GET_AS(LLGLRenderTarget, g_swapChain)); - { - // Clear color and depth buffers - llglClear(LLGLClearColorDepth, &g_defaultClear); - llglSetViewport(&g_viewport); - - // Set graphics pipeline - llglSetPipelineState(pipeline); - - llglSetResource(0, LLGL_GET_AS(LLGLResource, sceneBuffer)); - llglSetResource(1, LLGL_GET_AS(LLGLResource, colorTexture)); - llglSetResource(2, LLGL_GET_AS(LLGLResource, samplers[0])); - - // Draw cube mesh with index and vertex buffers - llglDrawIndexed((uint32_t)indexCount, 0); - } - llglEndRenderPass(); + matrix_load_identity(scene.wMatrix); + matrix_translate(scene.wMatrix, 0.0f, 0.0f, 5.0f); + matrix_rotate(scene.wMatrix, 0.0f, 1.0f, 0.0f, DEG2RAD(g_example.rotation)); + + matrix_mul(scene.wvpMatrix, g_projection, scene.wMatrix); } - llglEnd(); + llglUpdateBuffer(g_example.sceneBuffer, 0, &scene, sizeof(scene)); - // Present the result on the screen - llglPresent(g_swapChain); - } + // Set vertex and index buffers + llglSetVertexBuffer(g_example.vertexBuffer); + llglSetIndexBuffer(g_example.indexBuffer); - // Clean up - example_release(); + // Set the swap-chain as the initial render target + llglBeginRenderPass(LLGL_GET_AS(LLGLRenderTarget, g_swapChain)); + { + // Clear color and depth buffers + llglClear(LLGLClearColorDepth, &g_defaultClear); + llglSetViewport(&g_viewport); - return 0; + // Set graphics pipeline + llglSetPipelineState(g_example.pipeline); + + llglSetResource(0, LLGL_GET_AS(LLGLResource, g_example.sceneBuffer)); + llglSetResource(1, LLGL_GET_AS(LLGLResource, g_example.colorTexture)); + llglSetResource(2, LLGL_GET_AS(LLGLResource, g_example.samplers[0])); + + // Draw cube mesh with index and vertex buffers + llglDrawIndexed((uint32_t)g_example.indexCount, 0); + } + llglEndRenderPass(); + } + llglEnd(); + + // Present the result on the screen + llglPresent(g_swapChain); } + +IMPLEMENT_EXAMPLE_MAIN(TexturingInit, TexturingLoop); diff --git a/include/LLGL-C/LLGLWrapper.h b/include/LLGL-C/LLGLWrapper.h index c883c3a2a4..e220138572 100644 --- a/include/LLGL-C/LLGLWrapper.h +++ b/include/LLGL-C/LLGLWrapper.h @@ -16,9 +16,9 @@ #include #include -#if defined LLGL_OS_ANDROID +#if __ANDROID__ # include -#endif /* defined LLGL_OS_ANDROID */ +#endif /* __ANDROID__ */ /* ----- Constants ----- */ @@ -26,15 +26,18 @@ #define LLGL_RENDERERID_UNDEFINED ( 0x00000000 ) #define LLGL_RENDERERID_NULL ( 0x00000001 ) #define LLGL_RENDERERID_OPENGL ( 0x00000002 ) -#define LLGL_RENDERERID_OPENGLES1 ( 0x00000003 ) -#define LLGL_RENDERERID_OPENGLES2 ( 0x00000004 ) -#define LLGL_RENDERERID_OPENGLES3 ( 0x00000005 ) +#define LLGL_RENDERERID_OPENGLES ( 0x00000003 ) +#define LLGL_RENDERERID_WEBGL ( 0x00000004 ) +#define LLGL_RENDERERID_WEBGPU ( 0x00000005 ) #define LLGL_RENDERERID_DIRECT3D9 ( 0x00000006 ) #define LLGL_RENDERERID_DIRECT3D10 ( 0x00000007 ) #define LLGL_RENDERERID_DIRECT3D11 ( 0x00000008 ) #define LLGL_RENDERERID_DIRECT3D12 ( 0x00000009 ) #define LLGL_RENDERERID_VULKAN ( 0x0000000A ) #define LLGL_RENDERERID_METAL ( 0x0000000B ) +#define LLGL_RENDERERID_OPENGLES1 ( LLGL_RENDERERID_OPENGLES ) +#define LLGL_RENDERERID_OPENGLES2 ( LLGL_RENDERERID_OPENGLES ) +#define LLGL_RENDERERID_OPENGLES3 ( LLGL_RENDERERID_OPENGLES ) #define LLGL_RENDERERID_RESERVED ( 0x000000FF ) @@ -1432,9 +1435,9 @@ typedef struct LLGLRenderSystemDescriptor size_t rendererConfigSize; /* = 0 */ const void* nativeHandle; /* = NULL */ size_t nativeHandleSize; /* = 0 */ -#if defined LLGL_OS_ANDROID - android_app* androidApp; -#endif /* defined LLGL_OS_ANDROID */ +#if __ANDROID__ + struct android_app* androidApp; +#endif /* __ANDROID__ */ } LLGLRenderSystemDescriptor; diff --git a/scripts/WrapperGen/llgl_module.py b/scripts/WrapperGen/llgl_module.py index 52335fdc32..e87efbbaa4 100644 --- a/scripts/WrapperGen/llgl_module.py +++ b/scripts/WrapperGen/llgl_module.py @@ -56,7 +56,7 @@ class LLGLMeta: UTF8STRING = 'UTF8String' STRING = 'string' externals = [ - ConditionalType('android_app', 'defined LLGL_OS_ANDROID', '') + ConditionalType('android_app', '__ANDROID__', '') ] builtins = { 'void': StdType.VOID, diff --git a/scripts/WrapperGen/llgl_translator_c99.py b/scripts/WrapperGen/llgl_translator_c99.py index 67f512676f..80250adb6f 100644 --- a/scripts/WrapperGen/llgl_translator_c99.py +++ b/scripts/WrapperGen/llgl_translator_c99.py @@ -83,14 +83,24 @@ def translateDeprecationMessage(msg): self.statement('/* ----- Constants ----- */') self.statement() + def translateConstFieldToMacroIdent(struct, fieldName): + return f'LLGL_{struct.name.upper()}_{fieldName.upper()}' + + def translateConstInit(struct, init): + structBaseIdent = struct.name + '::' + if init.startswith(structBaseIdent): + return translateConstFieldToMacroIdent(struct, init[len(structBaseIdent):]) + else: + return init + for struct in constStructs: # Write struct field declarations declList = Translator.DeclarationList() for field in struct.fields: - declList.append(Translator.Declaration('', f'LLGL_{struct.name.upper()}_{field.name.upper()}', field.init)) + declList.append(Translator.Declaration('', translateConstFieldToMacroIdent(struct, field.name), field.init)) for decl in declList.decls: - self.statement(f'#define {decl.name}{declList.spaces(1, decl.name)} ( {decl.init} )') + self.statement(f'#define {decl.name}{declList.spaces(1, decl.name)} ( {translateConstInit(struct, decl.init)} )') self.statement() self.statement() @@ -193,8 +203,8 @@ def translateStructField(fieldType, name): else: if fieldType.isConst: typeStr += 'const ' - if fieldType.baseType == StdType.STRUCT and not fieldType.externalCond: - typeStr += 'LLGL' + if fieldType.baseType == StdType.STRUCT: + typeStr += 'struct ' if fieldType.externalCond else 'LLGL' typeStr += fieldType.typename if fieldType.isPointer: typeStr += '*' diff --git a/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.cpp b/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.cpp index 1b88158c72..2846bed657 100644 --- a/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.cpp +++ b/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.cpp @@ -28,12 +28,35 @@ AndroidSharedEGLSurface::~AndroidSharedEGLSurface() void AndroidSharedEGLSurface::InitEGLSurface(ANativeWindow* window) { + /* Destroy previous surface if the window has changed */ + if (window_ != window) + DestroyEGLSurface(); + if (surface_ == nullptr) { + /* Store new window (null or non-null accepted) */ window_ = window; - surface_ = eglCreateWindowSurface(display_, config_, window_, nullptr); - if (!surface_) - LLGL_TRAP("eglCreateWindowSurface failed (%s)", EGLErrorToString()); + if (window != nullptr) + { + /* Create an EGLSurface with a native window */ + surface_ = eglCreateWindowSurface(display_, config_, window_, nullptr); + if (!surface_) + LLGL_TRAP("eglCreateWindowSurface failed (%s)", EGLErrorToString()); + } + else + { + /* Create an EGLSurface with a Pbuffer */ + const EGLint attribs[] = + { + EGL_LARGEST_PBUFFER, EGL_TRUE, + EGL_MIPMAP_TEXTURE, EGL_TRUE, + EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, + EGL_NONE + }; + surface_ = eglCreatePbufferSurface(display_, config_, attribs); + if (!surface_) + LLGL_TRAP("eglCreatePbufferSurface failed (%s)", EGLErrorToString()); + } } } diff --git a/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.h b/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.h index 3e5e481608..81dcd46ed0 100644 --- a/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.h +++ b/sources/Renderer/OpenGL/Platform/Android/AndroidSharedEGLSurface.h @@ -37,13 +37,19 @@ class AndroidSharedEGLSurface void InitEGLSurface(ANativeWindow* window); void DestroyEGLSurface(); + // Returns true if this EGL surface is a Pbuffer. This is the case if this surface was created without a native window. + inline bool IsPbuffer() const + { + return (window_ == nullptr); + } + // Returns the native EGLSurface object. inline EGLSurface GetEGLSurface() const { return surface_; } - // Returns the native ANativeWindow object. + // Returns the native ANativeWindow object. May be null. inline ANativeWindow* GetNativeWindow() const { return window_; diff --git a/sources/Renderer/OpenGL/WebGLProfile/WebGLProfile.cpp b/sources/Renderer/OpenGL/WebGLProfile/WebGLProfile.cpp index a3a669b5e6..e3fbbf3495 100644 --- a/sources/Renderer/OpenGL/WebGLProfile/WebGLProfile.cpp +++ b/sources/Renderer/OpenGL/WebGLProfile/WebGLProfile.cpp @@ -75,17 +75,17 @@ void GetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void* dat void* MapBuffer(GLenum target, GLenum access) { - return nullptr; // dummy + return nullptr; //TODO: allocate intermdiate CPU buffer } void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { - return nullptr; // dummy + return nullptr; //TODO: allocate intermdiate CPU buffer } void UnmapBuffer(GLenum target) { - // dummy + //TODO: release intermediate CPU buffer } void DrawBuffer(GLenum buf)