From 643977abbd9de49e5cd5058c9067169fff3fe6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 10 Nov 2012 22:57:15 +0100 Subject: [PATCH] Platform: support for NaCl applications. --- CMakeLists.txt | 4 +- modules/FindMagnum.cmake | 4 + src/Platform/CMakeLists.txt | 12 +++ src/Platform/NaClApplication.cpp | 97 +++++++++++++++++ src/Platform/NaClApplication.h | 175 +++++++++++++++++++++++++++++++ 5 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 src/Platform/NaClApplication.cpp create mode 100644 src/Platform/NaClApplication.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 17a27416c..4fd72c8ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,9 @@ option(WITH_GLXAPPLICATION "Build GlxApplication library" OFF) cmake_dependent_option(WITH_XEGLAPPLICATION "Build XEglApplication library" OFF "TARGET_GLES" OFF) cmake_dependent_option(WITH_GLUTAPPLICATION "Build GlutApplication library" OFF "NOT TARGET_GLES" OFF) option(WITH_SDL2APPLICATION "Build Sdl2Application library" OFF) - +if(${CMAKE_SYSTEM_NAME} STREQUAL NaCl) + option(WITH_NACLAPPLICATION "Build NaClApplication library" OFF) +endif() option(BUILD_TESTS "Build unit tests." OFF) if(BUILD_TESTS) diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index d325250f6..c6b4fce29 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -25,6 +25,8 @@ # XEglApplication - X/EGL application (depends on EGL and X11 libraries) # GlutApplication - GLUT application (depends on GLUT library) # Sdl2Application - SDL2 application (depends on SDL2 library) +# NaClApplication - NaCl application (only if targetting Google Chrome +# Native Client) # Example usage with specifying additional components is: # find_package(Magnum [REQUIRED|COMPONENTS] # MeshTools Primitives GlutApplication) @@ -134,6 +136,8 @@ foreach(component ${Magnum_FIND_COMPONENTS}) endif() endif() + # NaCl application has no additional dependencies + # GLX application dependencies if(${component} STREQUAL GlxApplication) find_package(X11) diff --git a/src/Platform/CMakeLists.txt b/src/Platform/CMakeLists.txt index abfa827a6..f441d40be 100644 --- a/src/Platform/CMakeLists.txt +++ b/src/Platform/CMakeLists.txt @@ -35,6 +35,18 @@ if(WITH_SDL2APPLICATION) endif() endif() +# NaCl application +if(WITH_NACLAPPLICATION) + if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL NaCl) + message(FATAL_ERROR "NaClApplication is available only when targetting Google Chrome Native Client. Set WITH_NACLAPPLICATION to OFF to skip building it.") + endif() + + add_library(MagnumNaClApplication STATIC + NaClApplication.cpp) + install(FILES NaClApplication.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) + install(TARGETS MagnumNaClApplication DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +endif() + # GLX application if(WITH_GLXAPPLICATION) set(NEED_ABSTRACTXAPPLICATION 1) diff --git a/src/Platform/NaClApplication.cpp b/src/Platform/NaClApplication.cpp new file mode 100644 index 000000000..401233f9d --- /dev/null +++ b/src/Platform/NaClApplication.cpp @@ -0,0 +1,97 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "NaClApplication.h" + +#include +#include +#include + +#include "Context.h" + +namespace Magnum { namespace Platform { + +NaClApplication::NaClApplication(PP_Instance instance, const Math::Vector2& size): Instance(instance), Graphics3DClient(this), viewportSize(size) { + int32_t attributes[] = { + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, + PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8, + PP_GRAPHICS3DATTRIB_SAMPLES, 0, + PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, + PP_GRAPHICS3DATTRIB_WIDTH, size.x(), + PP_GRAPHICS3DATTRIB_HEIGHT, size.y(), + PP_GRAPHICS3DATTRIB_NONE + }; + + graphics = new pp::Graphics3D(this, attributes); + if(graphics->is_null()) { + Error() << "Platform::NaClApplication::NaClApplication(): cannot create graphics"; + exit(1); + } + if(!BindGraphics(*graphics)) { + Error() << "Platform::NaClApplication::NaClApplication(): cannot bind graphics"; + exit(1); + } + + glSetCurrentContextPPAPI(graphics->pp_resource()); + + c = new Context; +} + +NaClApplication::~NaClApplication() { + delete c; + delete graphics; +} + +void NaClApplication::DidChangeView(const pp::View& view) { + Math::Vector2 size(view.GetRect().width(), view.GetRect().height()); + + /* Canvas resized */ + if(viewportSize != size) { + graphics->ResizeBuffers(size.x(), size.y()); + viewportSize = size; + flags |= Flag::ViewportUpdated; + } + + /* Update viewport, if changed */ + if(!(flags & Flag::ViewportUpdated)) { + flags &= ~Flag::ViewportUpdated; + viewportEvent(size); + } + + drawEvent(); +} + +void NaClApplication::swapBuffers() { + /* Swap already in progress, do nothing */ + if(flags & Flag::SwapInProgress) return; + + /* Swap buffers and call swapCallback() when done */ + flags |= Flag::SwapInProgress; + graphics->SwapBuffers(pp::CompletionCallback(&swapCallback, this)); +} + +void NaClApplication::swapCallback(void* applicationInstance, std::int32_t) { + NaClApplication* instance = static_cast(applicationInstance); + instance->flags &= ~Flag::SwapInProgress; + + /* Redraw, if requested */ + if(instance->flags & Flag::Redraw) { + instance->flags &= ~Flag::Redraw; + instance->drawEvent(); + } +} + +}} diff --git a/src/Platform/NaClApplication.h b/src/Platform/NaClApplication.h new file mode 100644 index 000000000..bb0ecd3e0 --- /dev/null +++ b/src/Platform/NaClApplication.h @@ -0,0 +1,175 @@ +#ifndef Magnum_Platform_NaClApplication_h +#define Magnum_Platform_NaClApplication_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Platform::NaClApplication + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "Math/Vector2.h" +#include "Magnum.h" + +#include "magnumCompatibility.h" + +namespace pp { + class Graphics3D; +} + +namespace Magnum { + +class Context; + +namespace Platform { + +/** @nosubgrouping +@brief NaCl application + +@section NaClApplication-usage Usage + +You need to implement at least drawEvent() and viewportEvent() to be able to +draw on the screen. The subclass must be then registered to NaCl API using +MAGNUM_NACLAPPLICATION_MAIN() macro. +@code +class MyApplication: public Magnum::Platform::Sdl2Application { + // implement required methods... +}; +MAGNUM_NACLAPPLICATION_MAIN(MyApplication) +@endcode +*/ +class NaClApplication: public pp::Instance, public pp::Graphics3DClient { + public: + /** + * @brief Constructor + * @param instance Module instance + * @param size Rendering size + * + * Creates double-buffered RGBA canvas with depth and stencil buffers. + */ + explicit NaClApplication(PP_Instance instance, const Math::Vector2& size = Math::Vector2(640, 480)); + + ~NaClApplication(); + + /** @{ @name Drawing functions */ + + protected: + /** + * @brief Viewport event + * + * Called when viewport size changes. You should pass the new size to + * Framebuffer::setViewport() or SceneGraph::Camera::setViewport(), + * if using scene graph. + */ + virtual void viewportEvent(const Math::Vector2& size) = 0; + + /** + * @brief Draw event + * + * Here implement your drawing functions, such as calling + * SceneGraph::Camera::draw(). After drawing is finished, call + * swapBuffers(). If you want to draw immediately again, call also + * redraw(). + */ + virtual void drawEvent() = 0; + + /** + * @brief Swap buffers + * + * Paints currently rendered framebuffer on screen. + */ + void swapBuffers(); + + /** + * @brief Redraw immediately + * + * Marks the window for redrawing, resulting in call of drawEvent() + * in the next iteration. + */ + inline void redraw() { + flags |= Flag::Redraw; + } + + /*@}*/ + + private: + enum class Flag: std::uint8_t { + ViewportUpdated = 1 << 0, + SwapInProgress = 1 << 1, + Redraw = 1 << 2 + }; + typedef Corrade::Containers::EnumSet Flags; + + inline void Graphics3DContextLost() override { + CORRADE_ASSERT(false, "NaClApplication: context unexpectedly lost", ); + } + + void DidChangeView(const pp::View& view) override; + + static void swapCallback(void* applicationInstance, std::int32_t); + + pp::Graphics3D* graphics; + Context* c; + Math::Vector2 viewportSize; + Flags flags; + + CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) +}; + +CORRADE_ENUMSET_OPERATORS(NaClApplication::Flags) + +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template class NaClModule: public pp::Module { + public: + inline ~NaClModule() { + glTerminatePPAPI(); + } + + inline bool Init() override { + return glInitializePPAPI(get_browser_interface()) == GL_TRUE; + } + + inline pp::Instance* CreateInstance(PP_Instance instance) { + return new Application(instance); + } + }; +} +#endif + +/** @hideinitializer +@brief Entry point for NaCl application +@param application Application class name + +See NaClApplication for more information. +*/ +/* look at that insane placement of __attribute__. WTF. */ +#define MAGNUM_NACLAPPLICATION_MAIN(application) \ + namespace pp { \ + Module __attribute__ ((visibility ("default"))) * CreateModule() { \ + return new Magnum::Platform::Implementation::NaClModule(); \ + } \ + } + +}} + +#endif