|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015
|
|
|
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
to deal in the Software without restriction, including without limitation
|
|
|
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Magnum {
|
|
|
|
|
/** @page platform Platform support
|
|
|
|
|
@brief Integration into windowing toolkits and creation of windowless contexts.
|
|
|
|
|
|
|
|
|
|
- Next page: @ref types
|
|
|
|
|
|
|
|
|
|
@ref Platform namespace contains classes integrating Magnum engine into
|
|
|
|
|
various toolkits, both windowed and windowless. Each class has slightly
|
|
|
|
|
different dependencies and platform requirements, see documentation of
|
|
|
|
|
@ref Platform namespace and particular `*Application` classes for more
|
|
|
|
|
information about building and usage with CMake.
|
|
|
|
|
|
|
|
|
|
@tableofcontents
|
|
|
|
|
|
|
|
|
|
All the classes have common API to achieve static polymorphism, so basically
|
|
|
|
|
you can use different toolkits on different platforms and the only thing you
|
|
|
|
|
need to change is the class name, everything else is the same. Basic usage is
|
|
|
|
|
to subclass the chosen `*Application` class and implement required methods.
|
|
|
|
|
|
|
|
|
|
@section platform-windowed Windowed applications
|
|
|
|
|
|
|
|
|
|
Windowed applications provide a window and keyboard and mouse handling. The
|
|
|
|
|
de-facto standard and most widely used toolkit is SDL2, which is implemented in
|
|
|
|
|
@ref Platform::Sdl2Application. As said above, the usage is similar for all
|
|
|
|
|
toolkits, you must provide one-argument constructor and implement at least
|
|
|
|
|
@ref Platform::Sdl2Application::drawEvent() "drawEvent()" function. The class
|
|
|
|
|
can be then used directly in `main()`, but for convenience and portability it's
|
|
|
|
|
better to use @ref MAGNUM_SDL2APPLICATION_MAIN() macro.
|
|
|
|
|
|
|
|
|
|
To simplify the porting, the library provides `Platform::Application` typedef
|
|
|
|
|
and `MAGNUM_APPLICATION_MAIN()` macro (but only if only one application header
|
|
|
|
|
is included, to avoid ambiguity). Changing the code to use different toolkit is
|
|
|
|
|
then matter of replacing only the `#``include` statement (and changing
|
|
|
|
|
one line in CMake build script, as you see later).
|
|
|
|
|
|
|
|
|
|
Barebone application implementation which will just clear the window to dark
|
|
|
|
|
blue color is shown in the following code listing.
|
|
|
|
|
|
|
|
|
|
@note Fully contained base application along with CMake setup is available in
|
|
|
|
|
`base` branch of [Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap)
|
|
|
|
|
repository.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
#include <Magnum/Color.h>
|
|
|
|
|
#include <Magnum/DefaultFramebuffer.h>
|
|
|
|
|
#include <Magnum/Renderer.h>
|
|
|
|
|
#include <Magnum/Platform/Sdl2Application.h>
|
|
|
|
|
|
|
|
|
|
using namespace Magnum;
|
|
|
|
|
|
|
|
|
|
class MyApplication: public Platform::Application {
|
|
|
|
|
public:
|
|
|
|
|
MyApplication(const Arguments& arguments);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void drawEvent() override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
MyApplication::MyApplication(const Arguments& arguments): Platform::Application(arguments) {
|
|
|
|
|
// Set clear color to dark blue
|
|
|
|
|
Renderer::setClearColor({0.0f, 0.0f, 0.4f});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MyApplication::drawEvent() {
|
|
|
|
|
// Clear the window
|
|
|
|
|
defaultFramebuffer.clear(FramebufferClear::Color);
|
|
|
|
|
|
|
|
|
|
// The context is double-buffered, swap buffers
|
|
|
|
|
swapBuffers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// main() function implementation
|
|
|
|
|
MAGNUM_APPLICATION_MAIN(MyApplication)
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection platform-windowed-viewport Responding to viewport size changes
|
|
|
|
|
|
|
|
|
|
By default the application doesn't respond to window size changes in any way,
|
|
|
|
|
as the window has fixed size in most cases. To respond to size change for
|
|
|
|
|
example by resizing the default framebuffer, you need to reimplement
|
|
|
|
|
@ref Platform::Sdl2Application::viewportEvent() "viewportEvent()" function and
|
|
|
|
|
pass the new size to the framebuffer:
|
|
|
|
|
@code
|
|
|
|
|
class MyApplication: public Platform::Application {
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void viewportEvent(const Vector2i& size) override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
void MyApplication::viewportEvent(const Vector2i& size) {
|
|
|
|
|
defaultFramebuffer.setViewport({{}, size});
|
|
|
|
|
}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section platform-windowless Windowless applications
|
|
|
|
|
|
|
|
|
|
Windowless applications provide just a context for ofscreen rendering or
|
|
|
|
|
performing tasks on GPU. There is not yet any platform-independent toolkit
|
|
|
|
|
which could handle this in portable way, thus you have to use platform-specific
|
|
|
|
|
ones. Magnum provides windowless applications for X11-based Unix, OS X and
|
|
|
|
|
Windows. To make things simple, as an example we will use only
|
|
|
|
|
@ref Platform::WindowlessGlxApplication, see link for bootstrap application
|
|
|
|
|
below for fully portable example.
|
|
|
|
|
|
|
|
|
|
You need to implement just @ref Platform::WindowlessGlxApplication::exec() "exec()"
|
|
|
|
|
function. The class can be then used directly in `main()`, but again, for
|
|
|
|
|
convenience and portability it's better to use
|
|
|
|
|
@ref MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN() macro.
|
|
|
|
|
|
|
|
|
|
Similarly as with windowed applications, to simplify the porting, the library
|
|
|
|
|
provides `Platform::WindowlessApplication` typedef and `MAGNUM_WINDOWLESSAPPLICATION_MAIN()`
|
|
|
|
|
macro, but only if just one windowless application header is included. Changing
|
|
|
|
|
the code to use different toolkit is then matter of replacing only the
|
|
|
|
|
`#``include` statement. Aliases for windowless applications are
|
|
|
|
|
separated from aliases for windowed applications, because projects commonly
|
|
|
|
|
contain both graphics application and command-line tools (for data preparation
|
|
|
|
|
etc.).
|
|
|
|
|
|
|
|
|
|
Barebone application which will just print out current OpenGL version and
|
|
|
|
|
renderer string and exits is in the following code listing.
|
|
|
|
|
|
|
|
|
|
@note Fully contained windowless application using @ref Platform::WindowlessCglApplication
|
|
|
|
|
on OS X, @ref Platform::WindowlessGlxApplication on Unix and
|
|
|
|
|
@ref Platform::WindowlessWglApplication on Windows along with CMake setup
|
|
|
|
|
is available in `windowless` branch of [Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap)
|
|
|
|
|
repository.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
#include <Magnum/Context.h>
|
|
|
|
|
#include <Magnum/Platform/WindowlessGlxApplication.h>
|
|
|
|
|
|
|
|
|
|
using namespace Magnum;
|
|
|
|
|
|
|
|
|
|
class MyApplication: public Platform::WindowlessApplication {
|
|
|
|
|
public:
|
|
|
|
|
MyApplication(const Arguments& arguments);
|
|
|
|
|
|
|
|
|
|
int exec() override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
MyApplication::MyApplication(const Arguments& arguments): Platform::WindowlessApplication(arguments) {}
|
|
|
|
|
|
|
|
|
|
int MyApplication::exec() {
|
|
|
|
|
Debug() << "OpenGL version:" << Context::current()->versionString();
|
|
|
|
|
Debug() << "OpenGL renderer:" << Context::current()->rendererString();
|
|
|
|
|
|
|
|
|
|
// Exit with success
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// main() function implementation
|
|
|
|
|
MAGNUM_WINDOWLESSAPPLICATION_MAIN(MyApplication)
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section platform-compilation Compilation with CMake
|
|
|
|
|
|
|
|
|
|
Barebone compilation consists just of finding Magnum library with required
|
|
|
|
|
`*Application` component, adding Magnum's `${MAGNUM_INCLUDE_DIRS}` and
|
|
|
|
|
application-specific `${MAGNUM_SDL2APPLICATION_INCLUDE_DIRS}` to include path,
|
|
|
|
|
compilation of the executable and linking `${MAGNUM_LIBRARIES}` and
|
|
|
|
|
`${MAGNUM_SDL2APPLICATION_LIBRARIES}` to it.
|
|
|
|
|
|
|
|
|
|
Again, to simplify porting, you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}`
|
|
|
|
|
and `${MAGNUM_APPLICATION_LIBRARIES}` aliases (or `${MAGNUM_WINDOWLESSAPPLICATION_INCLUDE_DIRS}`,
|
|
|
|
|
`${MAGNUM_WINDOWLESSAPPLICATION_LIBRARIES}` for windowless applications), but
|
|
|
|
|
only if only one application (windowless application) component is requested to
|
|
|
|
|
avoid ambiguity. Changing the build script to use different toolkit is then
|
|
|
|
|
matter of replacing only the requested `*Application` component (and one
|
|
|
|
|
`#``include` line in the actual code, as said above).
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
find_package(Magnum REQUIRED Sdl2Application)
|
|
|
|
|
|
|
|
|
|
include_directories(${MAGNUM_INCLUDE_DIRS} ${MAGNUM_APPLICATION_INCLUDE_DIRS})
|
|
|
|
|
|
|
|
|
|
add_executable(myapplication MyApplication.cpp)
|
|
|
|
|
target_link_libraries(myapplication
|
|
|
|
|
${MAGNUM_LIBRARIES}
|
|
|
|
|
${MAGNUM_APPLICATION_LIBRARIES})
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section platform-configuration Specifying configuration
|
|
|
|
|
|
|
|
|
|
By default the application is created with some reasonable defaults (e.g.
|
|
|
|
|
window size 800x600 pixels). If you want something else, you can pass
|
|
|
|
|
@ref Platform::Sdl2Application::Configuration "Configuration" instance to
|
|
|
|
|
application constructor. Using method chaining it can be done conveniently like
|
|
|
|
|
this:
|
|
|
|
|
@code
|
|
|
|
|
MyApplication::MyApplication(int& argc, char** argv):
|
|
|
|
|
Platform::Application(argc, argv, Configuration()
|
|
|
|
|
.setTitle("My Application")
|
|
|
|
|
.setSize({800, 600}))
|
|
|
|
|
{
|
|
|
|
|
// ...
|
|
|
|
|
}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
However, sometimes you would need to configure the application based on some
|
|
|
|
|
configuration file or system introspection. In that case you can pass `nullptr`
|
|
|
|
|
instead of @ref Platform::Sdl2Application::Configuration "Configuration"
|
|
|
|
|
instance and then specify it later with @ref Platform::Sdl2Application::createContext() "createContext()":
|
|
|
|
|
@code
|
|
|
|
|
MyApplication::MyApplication(int& argc, char** argv): Platform::Application(argc, argv, nullptr) {
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
createContext(Configuration()
|
|
|
|
|
.setTitle("My Application")
|
|
|
|
|
.setSize(size));
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
If the context creation in constructor or @ref Platform::Sdl2Application::createContext() "createContext()"
|
|
|
|
|
fails, the application exits. However, it is also possible to negotiate the
|
|
|
|
|
context using @ref Platform::Sdl2Application::tryCreateContext() "tryCreateContext()".
|
|
|
|
|
The only difference is that this function returns `false` instead of exiting.
|
|
|
|
|
You can for example try enabling MSAA and if the context creation fails, fall
|
|
|
|
|
back to no-AA rendering:
|
|
|
|
|
@code
|
|
|
|
|
MyApplication::MyApplication(int& argc, char** argv): Platform::Application(argc, argv, nullptr) {
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
Configuration conf;
|
|
|
|
|
conf.setTitle("My Application")
|
|
|
|
|
.setSampleCount(16);
|
|
|
|
|
|
|
|
|
|
if(!tryCreateContext(conf))
|
|
|
|
|
createContext(conf.setSampleCount(0));
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section platform-custom Using custom platform toolkits
|
|
|
|
|
|
|
|
|
|
In case you want to use some not-yet-supported toolkit or you don't want to use
|
|
|
|
|
the application wrappers in @ref Platform namespace, you can initialize Magnum
|
|
|
|
|
manually. First create OpenGL context and then create instance of
|
|
|
|
|
@ref Platform::Context class, which will take care of proper initialization and
|
|
|
|
|
feature detection. The instance must be alive for whole application lifetime.
|
|
|
|
|
Example `main()` function with manual initialization:
|
|
|
|
|
@code
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
|
// Create OpenGL context ...
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Initialize Magnum
|
|
|
|
|
Platform::Context context;
|
|
|
|
|
|
|
|
|
|
// Open window, enter main loop ...
|
|
|
|
|
|
|
|
|
|
// Magnum context gets destroyed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Delete OpenGL context ...
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@attention Currently Magnum is limited to single OpenGL context, which must be
|
|
|
|
|
always set as current.
|
|
|
|
|
|
|
|
|
|
On majority of platforms the @ref Platform::Context class does GL function
|
|
|
|
|
pointer loading using platform-specific APIs. In that case you also need to
|
|
|
|
|
find particular `*Context` library, add its include dir and then link to it.
|
|
|
|
|
These platform-specific libraries are available:
|
|
|
|
|
|
|
|
|
|
- `CglContext` -- CGL context (Mac OS X)
|
|
|
|
|
- `EglContext` -- EGL context (everywhere except Emscripten and NaCl)
|
|
|
|
|
- `GlxContext` -- GLX context (X11-based Unix)
|
|
|
|
|
- `WglContext` -- WGL context (Windows)
|
|
|
|
|
|
|
|
|
|
Systems not listed here (such as Emscripten or NaCl) don't need any `Context`
|
|
|
|
|
library, because dynamic function pointer loading is not available on these.
|
|
|
|
|
|
|
|
|
|
For example, when you create the OpenGL context using GLX, you need to find
|
|
|
|
|
`GlxContext` component, include `${MAGNUM_GLCCONTEXT_INCLUDE_DIRS}` and link to
|
|
|
|
|
`${MAGNUM_GLXCONTEXT_LIBRARIES}`. Similarly to application libraries, you can
|
|
|
|
|
also use generic `${MAGNUM_CONTEXT_INCLUDE_DIRS}` and `${MAGNUM_CONTEXT_LIBRARIES}`,
|
|
|
|
|
providing you requested only one `*Context` component in the `find_package()`
|
|
|
|
|
call. Complete example:
|
|
|
|
|
@code
|
|
|
|
|
find_package(Magnum REQUIRED GlxContext)
|
|
|
|
|
|
|
|
|
|
include_directories(${MAGNUM_INCLUDE_DIRS} ${MAGNUM_CONTEXT_INCLUDE_DIRS})
|
|
|
|
|
|
|
|
|
|
add_executable(myapplication MyCustomApplication.cpp)
|
|
|
|
|
target_link_libraries(myapplication
|
|
|
|
|
${MAGNUM_LIBRARIES}
|
|
|
|
|
${MAGNUM_CONTEXT_LIBRARIES})
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
- Next page: @ref types
|
|
|
|
|
*/
|
|
|
|
|
}
|