mirror of https://github.com/mosra/magnum.git
120 changed files with 3742 additions and 1659 deletions
@ -1,29 +0,0 @@
|
||||
namespace Magnum { |
||||
|
||||
/** @page modules */ |
||||
|
||||
/** |
||||
@defgroup scene Scene graph |
||||
@brief %Scene hierarchy, cameras, lights and other objects |
||||
*/ |
||||
|
||||
/** |
||||
@defgroup mesh Meshes |
||||
@brief Creating, modifying and rendering meshes |
||||
*/ |
||||
|
||||
/** |
||||
@defgroup rendering Rendering |
||||
@brief %Shader, buffer and mesh management, render queries |
||||
*/ |
||||
|
||||
/** @ingroup rendering |
||||
@defgroup textures Textures |
||||
@brief Access to OpenGL textures, image data wrappers and framebuffer operations |
||||
*/ |
||||
|
||||
/** |
||||
@defgroup utility Utility |
||||
@brief Various supporting utility classes |
||||
*/ |
||||
} |
||||
@ -1,125 +0,0 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "Camera.h" |
||||
#include "Framebuffer.h" |
||||
#include "Scene.h" |
||||
|
||||
using namespace std; |
||||
|
||||
namespace Magnum { |
||||
|
||||
Camera::Camera(Object* parent): Object(parent), _aspectRatioPolicy(AspectRatioPolicy::Extend) {} |
||||
|
||||
void Camera::setOrthographic(GLfloat size, GLfloat near, GLfloat far) { |
||||
_near = near; |
||||
_far = far; |
||||
|
||||
/* Scale the volume down so it fits in (-1, 1) in all directions */ |
||||
GLfloat xyScale = 2/size; |
||||
GLfloat zScale = 2/(far-near); |
||||
rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, -zScale}); |
||||
|
||||
/* Move the volume on z into (-1, 1) range */ |
||||
rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(-1-near*zScale))*rawProjectionMatrix; |
||||
|
||||
fixAspectRatio(); |
||||
} |
||||
|
||||
void Camera::setPerspective(GLfloat fov, GLfloat near, GLfloat far) { |
||||
_near = near; |
||||
_far = far; |
||||
|
||||
/* First move the volume on z in (-1, 1) range */ |
||||
rawProjectionMatrix = Matrix4::translation(Vector3::zAxis(2*far*near/(far+near))); |
||||
|
||||
/* Then apply magic perspective matrix (with reversed Z) */ |
||||
static const Matrix4 a(1.0f, 0.0f, 0.0f, 0.0f, |
||||
0.0f, 1.0f, 0.0f, 0.0f, |
||||
0.0f, 0.0f, -1.0f, -1.0f, |
||||
0.0f, 0.0f, 0.0f, 0.0f); |
||||
rawProjectionMatrix = a*rawProjectionMatrix; |
||||
|
||||
/* Then scale the volume down so it fits in (-1, 1) in all directions */ |
||||
GLfloat xyScale = 1/tan(fov/2); |
||||
GLfloat zScale = 1+2*near/(far-near); |
||||
rawProjectionMatrix = Matrix4::scaling({xyScale, xyScale, zScale})*rawProjectionMatrix; |
||||
|
||||
/* And... another magic */ |
||||
rawProjectionMatrix[3][3] = 0; |
||||
|
||||
fixAspectRatio(); |
||||
} |
||||
|
||||
void Camera::setViewport(const Math::Vector2<GLsizei>& size) { |
||||
Framebuffer::setViewport({0, 0}, size); |
||||
|
||||
_viewport = size; |
||||
fixAspectRatio(); |
||||
} |
||||
|
||||
void Camera::clean(const Matrix4& absoluteTransformation) { |
||||
Object::clean(absoluteTransformation); |
||||
|
||||
_cameraMatrix = absoluteTransformation.inverted(); |
||||
} |
||||
|
||||
void Camera::fixAspectRatio() { |
||||
/* Don't divide by zero */ |
||||
if(_viewport.x() == 0 || _viewport.y() == 0) { |
||||
_projectionMatrix = rawProjectionMatrix; |
||||
return; |
||||
} |
||||
|
||||
/* Extend on larger side = scale larger side down */ |
||||
if(_aspectRatioPolicy == AspectRatioPolicy::Extend) { |
||||
_projectionMatrix = ((_viewport.x() > _viewport.y()) ? |
||||
Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1}) : |
||||
Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1}) |
||||
)*rawProjectionMatrix; |
||||
|
||||
/* Clip on smaller side = scale smaller side up */ |
||||
} else if(_aspectRatioPolicy == AspectRatioPolicy::Clip) { |
||||
_projectionMatrix = ((_viewport.x() > _viewport.y()) ? |
||||
Matrix4::scaling({1, GLfloat(_viewport.x())/_viewport.y(), 1}) : |
||||
Matrix4::scaling({GLfloat(_viewport.y())/_viewport.x(), 1, 1}) |
||||
)*rawProjectionMatrix; |
||||
|
||||
/* Don't preserve anything */ |
||||
} else _projectionMatrix = rawProjectionMatrix; |
||||
} |
||||
|
||||
void Camera::draw() { |
||||
Scene* s = scene(); |
||||
CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", ); |
||||
|
||||
Framebuffer::clear(); |
||||
|
||||
/* Recursively draw child objects */ |
||||
drawChildren(s, cameraMatrix()); |
||||
} |
||||
|
||||
void Camera::drawChildren(Object* object, const Matrix4& transformationMatrix) { |
||||
for(set<Object*>::const_iterator it = object->children().begin(); it != object->children().end(); ++it) { |
||||
/* Transformation matrix for the object */ |
||||
Matrix4 matrix = transformationMatrix*(*it)->transformation(); |
||||
|
||||
/* Draw the object and its children */ |
||||
(*it)->draw(matrix, this); |
||||
drawChildren(*it, matrix); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,156 +0,0 @@
|
||||
#ifndef Magnum_Camera_h |
||||
#define Magnum_Camera_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Camera |
||||
*/ |
||||
|
||||
#include "Object.h" |
||||
|
||||
#ifdef WIN32 /* I so HATE windows.h */ |
||||
#undef near |
||||
#undef far |
||||
#endif |
||||
|
||||
namespace Magnum { |
||||
|
||||
/** @ingroup scene
|
||||
@brief %Camera object |
||||
*/ |
||||
class MAGNUM_EXPORT Camera: public Object { |
||||
public: |
||||
/**
|
||||
* @brief Aspect ratio policy |
||||
* |
||||
* @see aspectRatioPolicy(), setAspectRatioPolicy() |
||||
*/ |
||||
enum class AspectRatioPolicy { |
||||
NotPreserved, /**< Don't preserve aspect ratio */ |
||||
Extend, /**< Extend on larger side of view */ |
||||
Clip /**< Clip on smaller side of view */ |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* @param parent Parent object |
||||
* |
||||
* Sets orthographic projection to the default OpenGL cube (range |
||||
* @f$ [-1; 1] @f$ in all directions) and clear color to black. |
||||
* @see setOrthographic(), setPerspective() |
||||
*/ |
||||
Camera(Object* parent = nullptr); |
||||
|
||||
/** @brief Aspect ratio policy */ |
||||
inline AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; } |
||||
|
||||
/** @brief Set aspect ratio policy */ |
||||
void setAspectRatioPolicy(AspectRatioPolicy policy) { _aspectRatioPolicy = policy; } |
||||
|
||||
/**
|
||||
* @brief Set orthographic projection |
||||
* @param size Size of (square) view |
||||
* @param near Near clipping plane |
||||
* @param far Far clipping plane |
||||
* |
||||
* The volume of given size will be scaled down to range |
||||
* @f$ [-1; 1] @f$ on all directions. |
||||
*/ |
||||
void setOrthographic(GLfloat size, GLfloat near, GLfloat far); |
||||
|
||||
/**
|
||||
* @brief Set perspective projection |
||||
* @param fov Field of view angle |
||||
* @param near Near clipping plane |
||||
* @param far Far clipping plane |
||||
*/ |
||||
void setPerspective(GLfloat fov, GLfloat near, GLfloat far); |
||||
|
||||
/** @brief Near clipping plane */ |
||||
inline GLfloat near() const { return _near; } |
||||
|
||||
/** @brief Far clipping plane */ |
||||
inline GLfloat far() const { return _far; } |
||||
|
||||
/**
|
||||
* @brief Camera matrix |
||||
* |
||||
* Camera matrix describes world position relative to the camera and is |
||||
* applied as first. |
||||
*/ |
||||
inline Matrix4 cameraMatrix() { |
||||
setClean(); |
||||
return _cameraMatrix; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Projection matrix |
||||
* |
||||
* Projection matrix handles e.g. perspective distortion and is applied |
||||
* as last. |
||||
*/ |
||||
inline Matrix4 projectionMatrix() const { return _projectionMatrix; } |
||||
|
||||
/** @brief Viewport size */ |
||||
inline Math::Vector2<GLsizei> viewport() const { return _viewport; } |
||||
|
||||
/**
|
||||
* @brief Set viewport size |
||||
* |
||||
* Call when window size changes. |
||||
* |
||||
* Calls Framebuffer::setViewport() and stores viewport size |
||||
* internally. |
||||
*/ |
||||
virtual void setViewport(const Math::Vector2<GLsizei>& size); |
||||
|
||||
/**
|
||||
* @brief Draw the scene |
||||
* |
||||
* Calls Framebuffer::clear() and draws the scene using drawChildren(). |
||||
*/ |
||||
virtual void draw(); |
||||
|
||||
using Object::draw; /* Don't hide Object's draw() */ |
||||
|
||||
protected: |
||||
/**
|
||||
* Recalculates camera matrix. |
||||
*/ |
||||
void clean(const Matrix4& absoluteTransformation); |
||||
|
||||
/**
|
||||
* @brief Draw object children |
||||
* |
||||
* Recursively draws all children of the object. |
||||
*/ |
||||
void drawChildren(Object* object, const Matrix4& transformationMatrix); |
||||
|
||||
private: |
||||
Matrix4 rawProjectionMatrix; |
||||
Matrix4 _projectionMatrix; |
||||
Matrix4 _cameraMatrix; |
||||
GLfloat _near, _far; |
||||
|
||||
Math::Vector2<GLsizei> _viewport; |
||||
AspectRatioPolicy _aspectRatioPolicy; |
||||
|
||||
MAGNUM_LOCAL void fixAspectRatio(); |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -0,0 +1,64 @@
|
||||
#ifndef Magnum_Contexts_AbstractGlInterface_h |
||||
#define Magnum_Contexts_AbstractGlInterface_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Contexts::AbstractGlInterface |
||||
*/ |
||||
|
||||
#include "ExtensionWrangler.h" |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
/** @brief Base for OpenGL interfaces */ |
||||
template<class Display, class VisualId, class Window> class AbstractGlInterface { |
||||
public: |
||||
/**
|
||||
* @brief Get visual ID |
||||
* |
||||
* Initializes the interface on given display and returns visual ID. |
||||
*/ |
||||
virtual VisualId getVisualId(Display nativeDisplay) = 0; |
||||
|
||||
/**
|
||||
* @brief Destructor |
||||
* |
||||
* Finalizes and closes the interface. |
||||
*/ |
||||
virtual ~AbstractGlInterface() {} |
||||
|
||||
/** @brief Create context */ |
||||
virtual void createContext(Window nativeWindow) = 0; |
||||
|
||||
/**
|
||||
* @brief Whether to enable experimental extension wrangler features |
||||
* |
||||
* Default is to disable. |
||||
*/ |
||||
virtual inline ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const { |
||||
return ExtensionWrangler::ExperimentalFeatures::Disable; |
||||
} |
||||
|
||||
/** @brief Make the context current */ |
||||
virtual void makeCurrent() = 0; |
||||
|
||||
/** @brief Swap buffers */ |
||||
virtual void swapBuffers() = 0; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "AbstractXContext.h" |
||||
|
||||
#include "ExtensionWrangler.h" |
||||
|
||||
#define None 0L // redef Xlib nonsense
|
||||
|
||||
/* Mask for X events */ |
||||
#define INPUT_MASK KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|StructureNotifyMask |
||||
|
||||
using namespace std; |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
AbstractXContext::AbstractXContext(AbstractGlInterface<Display*, VisualID, Window>* glInterface, int&, char**, const string& title, const Math::Vector2<GLsizei>& size): glInterface(glInterface), viewportSize(size), flags(Flag::Redraw) { |
||||
/* Get default X display */ |
||||
display = XOpenDisplay(0); |
||||
|
||||
/* Get visual ID */ |
||||
VisualID visualId = glInterface->getVisualId(display); |
||||
|
||||
/* Get visual info */ |
||||
XVisualInfo *visInfo, visTemplate; |
||||
int visualCount; |
||||
visTemplate.visualid = visualId; |
||||
visInfo = XGetVisualInfo(display, VisualIDMask, &visTemplate, &visualCount); |
||||
if(!visInfo) { |
||||
Error() << "Cannot get X visual"; |
||||
::exit(1); |
||||
} |
||||
|
||||
/* Create X Window */ |
||||
Window root = RootWindow(display, DefaultScreen(display)); |
||||
XSetWindowAttributes attr; |
||||
attr.background_pixel = 0; |
||||
attr.border_pixel = 0; |
||||
attr.colormap = XCreateColormap(display, root, visInfo->visual, AllocNone); |
||||
attr.event_mask = 0; |
||||
unsigned long mask = CWBackPixel|CWBorderPixel|CWColormap|CWEventMask; |
||||
window = XCreateWindow(display, root, 20, 20, size.x(), size.y(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); |
||||
XSetStandardProperties(display, window, title.c_str(), 0, None, 0, 0, 0); |
||||
XFree(visInfo); |
||||
|
||||
/* Be notified about closing the window */ |
||||
deleteWindow = XInternAtom(display, "WM_DELETE_WINDOW", True); |
||||
XSetWMProtocols(display, window, &deleteWindow, 1); |
||||
|
||||
/* Create context */ |
||||
glInterface->createContext(window); |
||||
|
||||
/* Capture exposure, keyboard and mouse button events */ |
||||
XSelectInput(display, window, INPUT_MASK); |
||||
|
||||
/* Set OpenGL context as current */ |
||||
glInterface->makeCurrent(); |
||||
|
||||
/* Initialize extension wrangler */ |
||||
ExtensionWrangler::initialize(glInterface->experimentalExtensionWranglerFeatures()); |
||||
} |
||||
|
||||
AbstractXContext::~AbstractXContext() { |
||||
/* Shut down the interface */ |
||||
delete glInterface; |
||||
|
||||
/* Shut down X */ |
||||
XDestroyWindow(display, window); |
||||
XCloseDisplay(display); |
||||
} |
||||
|
||||
int AbstractXContext::exec() { |
||||
/* Show window */ |
||||
XMapWindow(display, window); |
||||
|
||||
/* Call viewportEvent for the first time */ |
||||
viewportEvent(viewportSize); |
||||
|
||||
while(!(flags & Flag::Exit)) { |
||||
XEvent event; |
||||
|
||||
/* Closed window */ |
||||
if(XCheckTypedWindowEvent(display, window, ClientMessage, &event) && |
||||
Atom(event.xclient.data.l[0]) == deleteWindow) { |
||||
return 0; |
||||
} |
||||
|
||||
while(XCheckWindowEvent(display, window, INPUT_MASK, &event)) { |
||||
switch(event.type) { |
||||
/* Window resizing */ |
||||
case ConfigureNotify: { |
||||
Math::Vector2<GLsizei> size(event.xconfigure.width, event.xconfigure.height); |
||||
if(size != viewportSize) { |
||||
viewportSize = size; |
||||
viewportEvent(size); |
||||
flags |= Flag::Redraw; |
||||
} |
||||
} break; |
||||
|
||||
/* Key/mouse events */ |
||||
case KeyPress: |
||||
keyPressEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), static_cast<Modifier>(event.xkey.state), {event.xkey.x, event.xkey.y}); |
||||
break; |
||||
case KeyRelease: |
||||
keyReleaseEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), static_cast<Modifier>(event.xkey.state), {event.xkey.x, event.xkey.y}); |
||||
break; |
||||
case ButtonPress: |
||||
mousePressEvent(static_cast<MouseButton>(event.xbutton.button), static_cast<Modifier>(event.xkey.state), {event.xbutton.x, event.xbutton.y}); |
||||
break; |
||||
case ButtonRelease: |
||||
mouseReleaseEvent(static_cast<MouseButton>(event.xbutton.button), static_cast<Modifier>(event.xkey.state), {event.xbutton.x, event.xbutton.y}); |
||||
break; |
||||
|
||||
/* Mouse move events */ |
||||
case MotionNotify: |
||||
mouseMotionEvent(static_cast<Modifier>(event.xmotion.state), {event.xmotion.x, event.xmotion.y}); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if(flags & Flag::Redraw) { |
||||
flags &= ~Flag::Redraw; |
||||
drawEvent(); |
||||
} else Corrade::Utility::sleep(5); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
}} |
||||
@ -1,186 +0,0 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "EglContext.h" |
||||
|
||||
#define None 0L // redef Xlib nonsense
|
||||
|
||||
/* Mask for X events */ |
||||
#define INPUT_MASK KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|StructureNotifyMask |
||||
|
||||
using namespace std; |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
EglContext::EglContext(int&, char**, const string& title, const Math::Vector2<GLsizei>& size): viewportSize(size) { |
||||
/* Get default X display and root window, init EGL */ |
||||
xDisplay = XOpenDisplay(0); |
||||
display = eglGetDisplay(xDisplay); |
||||
eglInitialize(display, 0, 0); |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
eglBindAPI(EGL_OPENGL_API); |
||||
#else |
||||
eglBindAPI(EGL_OPENGL_ES_API); |
||||
#endif |
||||
int screenNumber = DefaultScreen(xDisplay); |
||||
Window root = RootWindow(xDisplay, screenNumber); |
||||
|
||||
/* Choose EGL config */ |
||||
static const EGLint attribs[] = { |
||||
EGL_RED_SIZE, 1, |
||||
EGL_GREEN_SIZE, 1, |
||||
EGL_BLUE_SIZE, 1, |
||||
EGL_DEPTH_SIZE, 1, |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, |
||||
#else |
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
||||
#endif |
||||
EGL_NONE |
||||
}; |
||||
EGLConfig config; |
||||
EGLint configCount; |
||||
if(!eglChooseConfig(display, attribs, &config, 1, &configCount)) { |
||||
Error() << "Cannot get EGL visual config"; |
||||
exit(1); |
||||
} |
||||
|
||||
/* Get X visual */ |
||||
EGLint visualId; |
||||
if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) { |
||||
Error() << "Cannot get native visual ID"; |
||||
exit(1); |
||||
} |
||||
XVisualInfo *visInfo, visTemplate; |
||||
int visualCount; |
||||
visTemplate.visualid = visualId; |
||||
visInfo = XGetVisualInfo(xDisplay, VisualIDMask, &visTemplate, &visualCount); |
||||
if(!visInfo) { |
||||
Error() << "Cannot get X visual"; |
||||
exit(1); |
||||
} |
||||
|
||||
/* Create X Window */ |
||||
XSetWindowAttributes attr; |
||||
attr.background_pixel = 0; |
||||
attr.border_pixel = 0; |
||||
attr.colormap = XCreateColormap(xDisplay, root, visInfo->visual, AllocNone); |
||||
attr.event_mask = 0; |
||||
unsigned long mask = CWBackPixel|CWBorderPixel|CWColormap|CWEventMask; |
||||
xWindow = XCreateWindow(xDisplay, root, 20, 20, size.x(), size.y(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); |
||||
XSetStandardProperties(xDisplay, xWindow, title.c_str(), 0, None, 0, 0, 0); |
||||
XFree(visInfo); |
||||
|
||||
/* Be notified about closing the window */ |
||||
deleteWindow = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True); |
||||
XSetWMProtocols(xDisplay, xWindow, &deleteWindow, 1); |
||||
|
||||
/* Create context and window surface */ |
||||
static const EGLint contextAttributes[] = { |
||||
#ifdef MAGNUM_TARGET_GLES |
||||
EGL_CONTEXT_CLIENT_VERSION, 2, |
||||
#endif |
||||
EGL_NONE |
||||
}; |
||||
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes); |
||||
if(!context) { |
||||
Error() << "Cannot create EGL context"; |
||||
exit(1); |
||||
} |
||||
surface = eglCreateWindowSurface(display, config, xWindow, NULL); |
||||
if(!surface) { |
||||
Error() << "Cannot create window surface"; |
||||
exit(1); |
||||
} |
||||
|
||||
/* Capture exposure, keyboard and mouse button events */ |
||||
XSelectInput(xDisplay, xWindow, INPUT_MASK); |
||||
|
||||
/* Set OpenGL context as current */ |
||||
eglMakeCurrent(display, surface, surface, context); |
||||
|
||||
/** @bug Fixme: GLEW initialization fails (thinks that the context is not created) */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
/* Init GLEW */ |
||||
GLenum err = glewInit(); |
||||
if(err != GLEW_OK) { |
||||
Error() << "EglContext: cannot initialize GLEW:" << glewGetErrorString(err); |
||||
exit(1); |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
EglContext::~EglContext() { |
||||
/* Shut down EGL */ |
||||
eglDestroyContext(display, context); |
||||
eglDestroySurface(display, surface); |
||||
eglTerminate(display); |
||||
|
||||
/* Shut down X */ |
||||
XDestroyWindow(xDisplay, xWindow); |
||||
XCloseDisplay(xDisplay); |
||||
} |
||||
|
||||
int EglContext::exec() { |
||||
/* Show window */ |
||||
XMapWindow(xDisplay, xWindow); |
||||
|
||||
/* Call viewportEvent for the first time */ |
||||
viewportEvent(viewportSize); |
||||
|
||||
while(true) { |
||||
XEvent event; |
||||
|
||||
/* Closed window */ |
||||
if(XCheckTypedWindowEvent(xDisplay, xWindow, ClientMessage, &event) && |
||||
Atom(event.xclient.data.l[0]) == deleteWindow) { |
||||
return 0; |
||||
} |
||||
|
||||
while(XCheckWindowEvent(xDisplay, xWindow, INPUT_MASK, &event)) { |
||||
switch(event.type) { |
||||
/* Window resizing */ |
||||
case ConfigureNotify: { |
||||
Math::Vector2<int> size(event.xconfigure.width, event.xconfigure.height); |
||||
if(size != viewportSize) { |
||||
viewportSize = size; |
||||
viewportEvent(size); |
||||
} |
||||
} break; |
||||
|
||||
/* Key/mouse events */ |
||||
case KeyPress: |
||||
keyPressEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), {event.xkey.x, event.xkey.y}); |
||||
break; |
||||
case KeyRelease: |
||||
keyReleaseEvent(static_cast<Key>(XLookupKeysym(&event.xkey, 0)), {event.xkey.x, event.xkey.y}); |
||||
break; |
||||
case ButtonPress: |
||||
mousePressEvent(static_cast<MouseButton>(event.xbutton.button), {event.xbutton.x, event.xbutton.y}); |
||||
break; |
||||
case ButtonRelease: |
||||
mouseReleaseEvent(static_cast<MouseButton>(event.xbutton.button), {event.xbutton.x, event.xbutton.y}); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/** @todo Handle at least window closing and resizing */ |
||||
drawEvent(); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "EglInterface.h" |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
EglInterface::~EglInterface() { |
||||
eglDestroyContext(display, context); |
||||
eglDestroySurface(display, surface); |
||||
eglTerminate(display); |
||||
} |
||||
|
||||
VisualId EglInterface::getVisualId(EGLNativeDisplayType nativeDisplay) { |
||||
/* Initialize */ |
||||
display = eglGetDisplay(nativeDisplay); |
||||
eglInitialize(display, 0, 0); |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
eglBindAPI(EGL_OPENGL_API); |
||||
#else |
||||
eglBindAPI(EGL_OPENGL_ES_API); |
||||
#endif |
||||
|
||||
/* Choose EGL config */ |
||||
static const EGLint attribs[] = { |
||||
EGL_RED_SIZE, 1, |
||||
EGL_GREEN_SIZE, 1, |
||||
EGL_BLUE_SIZE, 1, |
||||
EGL_DEPTH_SIZE, 1, |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, |
||||
#else |
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
||||
#endif |
||||
EGL_NONE |
||||
}; |
||||
EGLint configCount; |
||||
if(!eglChooseConfig(display, attribs, &config, 1, &configCount)) { |
||||
Error() << "Cannot get EGL visual config"; |
||||
exit(1); |
||||
} |
||||
|
||||
/* Get visual ID */ |
||||
EGLint visualId; |
||||
if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) { |
||||
Error() << "Cannot get native visual ID"; |
||||
exit(1); |
||||
} |
||||
|
||||
return visualId; |
||||
} |
||||
|
||||
void EglInterface::createContext(EGLNativeWindowType window) { |
||||
static const EGLint contextAttributes[] = { |
||||
#ifdef MAGNUM_TARGET_GLES |
||||
EGL_CONTEXT_CLIENT_VERSION, 2, |
||||
#endif |
||||
EGL_NONE |
||||
}; |
||||
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes); |
||||
if(!context) { |
||||
Error() << "Cannot create EGL context"; |
||||
exit(1); |
||||
} |
||||
surface = eglCreateWindowSurface(display, config, window, NULL); |
||||
if(!surface) { |
||||
Error() << "Cannot create window surface"; |
||||
exit(1); |
||||
} |
||||
|
||||
/** @bug Fixme: On desktop OpenGL and Mesa EGL implementation OpenGL version is 1.0, which is wrong */ |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,71 @@
|
||||
#ifndef Magnum_Contexts_EglInterface_h |
||||
#define Magnum_Contexts_EglInterface_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Contexts::EglInterface |
||||
*/ |
||||
|
||||
#include "Magnum.h" |
||||
|
||||
#ifndef SUPPORT_X11 |
||||
#define SUPPORT_X11 // OpenGL ES on BeagleBoard needs this (?)
|
||||
#endif |
||||
#include <EGL/egl.h> |
||||
|
||||
#include "AbstractGlInterface.h" |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
/* EGL returns visual ID as int, but Xorg expects long unsigned int */ |
||||
#ifdef __unix__ |
||||
typedef VisualID VisualId; |
||||
#else |
||||
typedef EGLInt VisualId; |
||||
#endif |
||||
#endif |
||||
|
||||
/**
|
||||
@brief EGL interface |
||||
|
||||
Used in XEglContext. |
||||
*/ |
||||
class EglInterface: public AbstractGlInterface<EGLNativeDisplayType, VisualId, EGLNativeWindowType> { |
||||
public: |
||||
~EglInterface(); |
||||
|
||||
VisualId getVisualId(EGLNativeDisplayType nativeDisplay); |
||||
void createContext(EGLNativeWindowType nativeWindow); |
||||
|
||||
inline void makeCurrent() { |
||||
eglMakeCurrent(display, surface, surface, context); |
||||
} |
||||
|
||||
inline void swapBuffers() { |
||||
eglSwapBuffers(display, surface); |
||||
} |
||||
|
||||
private: |
||||
EGLDisplay display; |
||||
EGLConfig config; |
||||
EGLSurface surface; |
||||
EGLContext context; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "ExtensionWrangler.h" |
||||
|
||||
#include "Magnum.h" |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
void ExtensionWrangler::initialize(ExperimentalFeatures experimentalFeatures) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
/* Enable experimental features */ |
||||
if(experimentalFeatures == ExperimentalFeatures::Enable) |
||||
glewExperimental = true; |
||||
|
||||
/* Init GLEW */ |
||||
GLenum err = glewInit(); |
||||
if(err != GLEW_OK) { |
||||
Error() << "ExtensionWrangler: cannot initialize GLEW:" << glewGetErrorString(err); |
||||
exit(1); |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,39 @@
|
||||
#ifndef Magnum_Contexts_ExtensionWrangler_h |
||||
#define Magnum_Contexts_ExtensionWrangler_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Contexts::ExtensionWrangler |
||||
*/ |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
/** @brief Extension wrangler interface */ |
||||
class ExtensionWrangler { |
||||
public: |
||||
/** @brief Whether to enable or disable experimental features */ |
||||
enum class ExperimentalFeatures { |
||||
Disable, |
||||
Enable |
||||
}; |
||||
|
||||
/** @brief Initialize extension wrangler */ |
||||
static void initialize(ExperimentalFeatures experimentalFeatures = ExperimentalFeatures::Disable); |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,49 @@
|
||||
#ifndef Magnum_Contexts_GlxContext_h |
||||
#define Magnum_Contexts_GlxContext_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Contexts::GlxContext |
||||
*/ |
||||
|
||||
#include "AbstractXContext.h" |
||||
#include "GlxInterface.h" |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
/**
|
||||
@brief GLX context |
||||
|
||||
Uses GlxInterface. |
||||
*/ |
||||
class GlxContext: public AbstractXContext { |
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param argc Count of arguments of `main()` function |
||||
* @param argv Arguments of `main()` function |
||||
* @param title Window title |
||||
* @param size Window size |
||||
* |
||||
* Creates window with double-buffered OpenGL 3.3 core context or |
||||
* OpenGL ES 2.0 context, if targetting OpenGL ES. |
||||
*/ |
||||
inline GlxContext(int& argc, char** argv, const std::string& title = "Magnum GLX context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600)): AbstractXContext(new GlxInterface, argc, argv, title, size) {} |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "GlxInterface.h" |
||||
|
||||
#include <GL/glxext.h> |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
VisualID GlxInterface::getVisualId(Display* nativeDisplay) { |
||||
display = nativeDisplay; |
||||
|
||||
/* Check version */ |
||||
int major, minor; |
||||
glXQueryVersion(nativeDisplay, &major, &minor); |
||||
if(major == 1 && minor < 4) { |
||||
Error() << "GlxInterface: GLX version 1.4 or greater is required."; |
||||
exit(1); |
||||
} |
||||
|
||||
/* Choose config */ |
||||
int configCount = 0; |
||||
static const int attributes[] = { |
||||
GLX_RENDER_TYPE, GLX_RGBA_BIT, |
||||
GLX_X_RENDERABLE, True, |
||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, |
||||
GLX_DOUBLEBUFFER, True, |
||||
GLX_RED_SIZE, 8, |
||||
GLX_GREEN_SIZE, 8, |
||||
GLX_BLUE_SIZE, 8, |
||||
0 |
||||
}; |
||||
configs = glXChooseFBConfig(nativeDisplay, DefaultScreen(nativeDisplay), attributes, &configCount); |
||||
if(!configCount) { |
||||
Error() << "GlxInterface: no supported framebuffer configuration found."; |
||||
exit(1); |
||||
} |
||||
|
||||
/* Get visual ID */ |
||||
XVisualInfo* info = glXGetVisualFromFBConfig(display, configs[0]); |
||||
VisualID visualId = info->visualid; |
||||
XFree(info); |
||||
|
||||
return visualId; |
||||
} |
||||
|
||||
void GlxInterface::createContext(Window nativeWindow) { |
||||
window = nativeWindow; |
||||
|
||||
GLint attributes[] = { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 3, |
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 3, |
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, |
||||
#else |
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 2, |
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 0, |
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, |
||||
#endif |
||||
0 |
||||
}; |
||||
|
||||
/** @todo Use some extension wrangler for this, not GLEW, as it apparently needs context to create context, yo dawg wtf. */ |
||||
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); |
||||
context = glXCreateContextAttribsARB(display, configs[0], 0, True, attributes); |
||||
XFree(configs); |
||||
if(!context) { |
||||
Error() << "GlxInterface: cannot create context."; |
||||
exit(1); |
||||
} |
||||
} |
||||
|
||||
GlxInterface::~GlxInterface() { |
||||
glXMakeCurrent(display, None, nullptr); |
||||
glXDestroyContext(display, context); |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,66 @@
|
||||
#ifndef Magnum_Contexts_EglInterface_h |
||||
#define Magnum_Contexts_EglInterface_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Contexts::GlxInterface |
||||
*/ |
||||
|
||||
#include "Magnum.h" |
||||
#include <GL/glx.h> |
||||
|
||||
#include "AbstractGlInterface.h" |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
/**
|
||||
@brief GLX interface |
||||
|
||||
Creates OpenGL 3.3 core context or OpenGL ES 2.0 context, if targetting |
||||
OpenGL ES. |
||||
|
||||
Used in GlxContext. |
||||
*/ |
||||
class GlxInterface: public AbstractGlInterface<Display*, VisualID, Window> { |
||||
public: |
||||
~GlxInterface(); |
||||
|
||||
VisualID getVisualId(Display* nativeDisplay); |
||||
void createContext(Window nativeWindow); |
||||
|
||||
/* This must be enabled, otherwise (on my NVidia) it crashes when creating VAO. WTF. */ |
||||
inline ExtensionWrangler::ExperimentalFeatures experimentalExtensionWranglerFeatures() const { |
||||
return ExtensionWrangler::ExperimentalFeatures::Enable; |
||||
} |
||||
|
||||
inline void makeCurrent() { |
||||
glXMakeCurrent(display, window, context); |
||||
} |
||||
|
||||
inline void swapBuffers() { |
||||
glXSwapBuffers(display, window); |
||||
} |
||||
|
||||
private: |
||||
Display* display; |
||||
Window window; |
||||
GLXFBConfig* configs; |
||||
GLXContext context; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,48 @@
|
||||
#ifndef Magnum_Contexts_XEglContext_h |
||||
#define Magnum_Contexts_XEglContext_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Contexts::XEglContext |
||||
*/ |
||||
|
||||
#include "AbstractXContext.h" |
||||
#include "EglInterface.h" |
||||
|
||||
namespace Magnum { namespace Contexts { |
||||
|
||||
/**
|
||||
@brief X/EGL context |
||||
|
||||
Uses EglInterface. |
||||
*/ |
||||
class XEglContext: public AbstractXContext { |
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param argc Count of arguments of `main()` function |
||||
* @param argv Arguments of `main()` function |
||||
* @param title Window title |
||||
* @param size Window size |
||||
* |
||||
* Creates window with double-buffered OpenGL ES 2 context. |
||||
*/ |
||||
inline XEglContext(int& argc, char** argv, const std::string& title = "Magnum X/EGL context", const Math::Vector2<GLsizei>& size = Math::Vector2<GLsizei>(800, 600)): AbstractXContext(new EglInterface, argc, argv, title, size) {} |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -1,152 +0,0 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "Object.h" |
||||
|
||||
#include <stack> |
||||
#include "Scene.h" |
||||
#include "Camera.h" |
||||
|
||||
using namespace std; |
||||
|
||||
namespace Magnum { |
||||
|
||||
Object* Object::setParent(Object* parent) { |
||||
/* Skip if nothing to do or this is scene */ |
||||
if(_parent == parent || _parent == this) return this; |
||||
|
||||
/* Add the object to children list of new parent */ |
||||
if(parent != nullptr) { |
||||
|
||||
/* Only Fry can be his own grandfather */ |
||||
Object* p = parent; |
||||
while(p != nullptr && p->parent() != p) { |
||||
if(p == this) return this; |
||||
p = p->parent(); |
||||
} |
||||
|
||||
parent->_children.insert(this); |
||||
} |
||||
|
||||
/* Remove the object from old parent children list */ |
||||
if(_parent != nullptr) |
||||
_parent->_children.erase(this); |
||||
|
||||
/* Set new parent */ |
||||
_parent = parent; |
||||
|
||||
setDirty(); |
||||
return this; |
||||
} |
||||
|
||||
Matrix4 Object::absoluteTransformation(Camera* camera) { |
||||
/* Shortcut for absolute transformation of camera relative to itself */ |
||||
if(camera == this) return Matrix4(); |
||||
|
||||
Matrix4 t = _transformation; |
||||
|
||||
Object* p = parent(); |
||||
while(p != nullptr) { |
||||
t = p->transformation()*t; |
||||
|
||||
/* We got to the scene, multiply with camera matrix */ |
||||
if(p->parent() == p) { |
||||
if(camera) { |
||||
CORRADE_ASSERT(camera->scene() == scene(), "Object::absoluteTransformation(): the camera is not part of the same scene as object!", t); |
||||
t = camera->cameraMatrix()*t; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
p = p->parent(); |
||||
} |
||||
|
||||
CORRADE_ASSERT(p != nullptr || camera == nullptr, "Object::absoluteTransformation(): the object is not part of camera scene!", t); |
||||
|
||||
return t; |
||||
} |
||||
|
||||
Object::~Object() { |
||||
/* Remove the object from parent's children */ |
||||
setParent(nullptr); |
||||
|
||||
/* Delete all children */ |
||||
while(!_children.empty()) |
||||
delete *_children.begin(); |
||||
} |
||||
|
||||
Scene* Object::scene() { |
||||
/* Goes up the family tree until it finds object which is parent of itself
|
||||
(that's the scene) */ |
||||
Object* p = parent(); |
||||
while(p != nullptr) { |
||||
if(p->parent() == p) return static_cast<Scene*>(p); |
||||
p = p->parent(); |
||||
} |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
Object* Object::setTransformation(const Matrix4& transformation) { |
||||
if(_parent == this) return this; |
||||
|
||||
_transformation = transformation; |
||||
setDirty(); |
||||
return this; |
||||
} |
||||
|
||||
void Object::setDirty() { |
||||
/* The object (and all its children) are already dirty, nothing to do */ |
||||
if(dirty) return; |
||||
|
||||
dirty = true; |
||||
|
||||
/* Make all children dirty */ |
||||
for(set<Object*>::iterator it = _children.begin(); it != _children.end(); ++it) |
||||
(*it)->setDirty(); |
||||
} |
||||
|
||||
void Object::setClean() { |
||||
/* The object (and all its parents) are already clean, nothing to do */ |
||||
if(!dirty) return; |
||||
|
||||
/* Collect all parents */ |
||||
stack<Object*> objects; |
||||
Object* p = this; |
||||
for(;;) { |
||||
objects.push(p); |
||||
|
||||
/* Stop on root object / scene / clean object */ |
||||
if(p->parent() == nullptr || p->parent() == p || !p->parent()->isDirty()) |
||||
break; |
||||
|
||||
p = p->parent(); |
||||
} |
||||
|
||||
/* Call setClean(const Matrix4&) for every parent and also this object */ |
||||
Object* o = objects.top(); |
||||
objects.pop(); |
||||
Matrix4 absoluteTransformation = o->absoluteTransformation(); |
||||
o->clean(absoluteTransformation); |
||||
while(!objects.empty()) { |
||||
o = objects.top(); |
||||
objects.pop(); |
||||
absoluteTransformation = absoluteTransformation*o->transformation(); |
||||
o->clean(absoluteTransformation); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,274 +0,0 @@
|
||||
#ifndef Magnum_Object_h |
||||
#define Magnum_Object_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Object |
||||
*/ |
||||
|
||||
#include <set> |
||||
|
||||
#include "Magnum.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
class Scene; |
||||
class Camera; |
||||
|
||||
/**
|
||||
@todo User-specified Object implementation: |
||||
- for front-to-back sorting, LoD changes etc. |
||||
- for different parent/children implementation (e.g. no std::set, direct |
||||
access to scene etc.) |
||||
- for using doubles/halves instead of floats |
||||
- for using quat + position instead of matrices (where (asymmetric) scaling is |
||||
not needed) |
||||
*/ |
||||
|
||||
/** @ingroup scene
|
||||
* @brief Base for all positioned objects |
||||
* |
||||
* @todo Transform transformation when changing parent, so the object stays in |
||||
* place. |
||||
*/ |
||||
class MAGNUM_EXPORT Object { |
||||
Object(const Object& other) = delete; |
||||
Object(Object&& other) = delete; |
||||
Object& operator=(const Object& other) = delete; |
||||
Object& operator=(Object&& other) = delete; |
||||
|
||||
friend class Scene; |
||||
|
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param parent Parent object |
||||
* |
||||
* Sets all transformations to their default values. |
||||
*/ |
||||
inline Object(Object* parent = nullptr): _parent(nullptr), dirty(true) { |
||||
setParent(parent); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Destructor |
||||
* |
||||
* Removes itself from parent's children list and destroys all own |
||||
* children. |
||||
*/ |
||||
virtual ~Object(); |
||||
|
||||
/** @{ @name Scene hierarchy */ |
||||
|
||||
/**
|
||||
* @brief %Scene |
||||
* @return If the object is not assigned to any scene, returns nullptr. |
||||
*/ |
||||
Scene* scene(); |
||||
|
||||
/** @brief Parent object */ |
||||
inline Object* parent() { return _parent; } |
||||
|
||||
/** @brief Child objects */ |
||||
inline const std::set<Object*>& children() { return _children; } |
||||
|
||||
/** @brief Set parent object */ |
||||
Object* setParent(Object* parent); |
||||
|
||||
/*@}*/ |
||||
|
||||
/** @{ @name Object transformation
|
||||
* |
||||
* All transformations (except absoluteTransformation()) are relative |
||||
* to parent. |
||||
*/ |
||||
|
||||
/** @brief Transformation type */ |
||||
enum class Transformation: char { |
||||
/** Global transformation, applied after all other transformations. */ |
||||
Global = 0x00, |
||||
|
||||
/** Local transformation, applied before all other transformations. */ |
||||
Local = 0x01 |
||||
}; |
||||
|
||||
/** @brief Transformation */ |
||||
inline Matrix4 transformation() const { |
||||
return _transformation; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Absolute transformation |
||||
* |
||||
* Returns absolute transformation matrix relative to the camera or |
||||
* root object, if no camera is specified. If the camera is specified, |
||||
* it should be part of the same scene as object. |
||||
* |
||||
* Note that the absolute transformation is computed from all parent |
||||
* objects every time it is asked, unless this function is |
||||
* reimplemented in a different way. |
||||
*/ |
||||
virtual Matrix4 absoluteTransformation(Camera* camera = nullptr); |
||||
|
||||
/** @brief Set transformation */ |
||||
Object* setTransformation(const Matrix4& transformation); |
||||
|
||||
/**
|
||||
* @brief Multiply transformation |
||||
* @param transformation Transformation |
||||
* @param type Transformation type |
||||
*/ |
||||
inline Object* multiplyTransformation(const Matrix4& transformation, Transformation type = Transformation::Global) { |
||||
setTransformation(type == Transformation::Global ? |
||||
transformation*_transformation : _transformation*transformation); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Translate object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix4::translation(). |
||||
*/ |
||||
inline Object* translate(Vector3 vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix4::translation(vec), type); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Scale object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix4::scaling(). |
||||
*/ |
||||
inline Object* scale(Vector3 vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix4::scaling(vec), type); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix4::rotation(). |
||||
*/ |
||||
inline Object* rotate(GLfloat angle, Vector3 vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix4::rotation(angle, vec), type); |
||||
return this; |
||||
} |
||||
|
||||
/*@}*/ |
||||
|
||||
/**
|
||||
* @brief Draw object |
||||
* @param transformationMatrix %Matrix specifying object |
||||
* transformation relative to the scene. |
||||
* @param camera Active camera (containing |
||||
* projection matrix) |
||||
* |
||||
* Default implementation does nothing. |
||||
*/ |
||||
virtual void draw(const Matrix4& transformationMatrix, Camera* camera); |
||||
|
||||
/** @{ @name Caching helpers
|
||||
* |
||||
* If the object (absolute) transformation or anything depending on it |
||||
* is used many times when drawing (such as e.g. position of light |
||||
* object), it's good to cache these values, so they don't have to be |
||||
* recalculated again on every request. |
||||
* |
||||
* If setDirty() is called on an object (or the object is transformed), |
||||
* it and all its children are marked as dirty. If any object is |
||||
* already dirty, it and all its children are skipped, because they |
||||
* are already dirty too. |
||||
* |
||||
* If setClean() is called on an object, it and all its parents are |
||||
* cleaned. If any object is already clean, it and all its parents are |
||||
* skipped, because they are already clean too. |
||||
* |
||||
* These functions are used to manage dirty status of the object. If |
||||
* the object doesn't cache anything, it's no need to bother about |
||||
* them, but if does, clean() should be reimplemented and used to |
||||
* regenerate the cache. |
||||
*/ |
||||
|
||||
/**
|
||||
* @brief Whether the object is dirty |
||||
* @return True, if transformation of the object, any parent or camera |
||||
* has changed since last asking, false otherwise. |
||||
*/ |
||||
inline bool isDirty() const { return dirty; } |
||||
|
||||
/**
|
||||
* @brief Set object and all its children as dirty |
||||
* |
||||
* Recursively calls setDirty() on every child. If the object is |
||||
* already marked as dirty, the function does nothing. It is usually |
||||
* not needed to reimplement this function, only if you for example |
||||
* need to reset some state on object which is not child of this. All |
||||
* computations should be done in setClean(). |
||||
* |
||||
* Reimplementations should call this function at the end, i.e.: |
||||
* @code |
||||
* void setDirty() { |
||||
* // ...
|
||||
* |
||||
* Object::setDirty(); |
||||
* } |
||||
* @endcode |
||||
*/ |
||||
virtual void setDirty(); |
||||
|
||||
/**
|
||||
* @brief Set object and all its parents as clean |
||||
* |
||||
* Recursively calls clean() on every parent which is not already |
||||
* clean. |
||||
*/ |
||||
void setClean(); |
||||
|
||||
protected: |
||||
/**
|
||||
* @brief Clean the object |
||||
* |
||||
* When reimplementing, use absolute transformation passed as |
||||
* parameter instead of absoluteTransformation(), which is not |
||||
* efficient. The reimplementation should call this function at the |
||||
* beginning, i.e.: |
||||
* @code |
||||
* void clean(const Matrix4& absoluteTransformation) { |
||||
* Object::clean(absoluteTransformation); |
||||
* |
||||
* // ...
|
||||
* } |
||||
* @endcode |
||||
*/ |
||||
virtual void clean(const Matrix4& absoluteTransformation); |
||||
|
||||
/*@}*/ |
||||
|
||||
private: |
||||
Object* _parent; |
||||
std::set<Object*> _children; |
||||
Matrix4 _transformation; |
||||
bool dirty; |
||||
}; |
||||
|
||||
/* Implementations for inline functions with unused parameters */ |
||||
inline void Object::draw(const Matrix4&, Camera*) {} |
||||
inline void Object::clean(const Matrix4&) { dirty = false; } |
||||
|
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -1,47 +0,0 @@
|
||||
#ifndef Magnum_Scene_h |
||||
#define Magnum_Scene_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::Scene |
||||
*/ |
||||
|
||||
#include "Object.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
/** @ingroup scene
|
||||
@brief %Scene |
||||
*/ |
||||
class MAGNUM_EXPORT Scene: public Object { |
||||
public: |
||||
/** @brief Constructor */ |
||||
inline Scene() { _parent = this; } |
||||
|
||||
void setParent(Object* parent) = delete; |
||||
void setTransformation(const Matrix4& transformation) = delete; |
||||
void multiplyTransformation(const Matrix4& transformation, Transformation type = Transformation::Global) = delete; |
||||
void translate(Vector3 vec, Transformation type = Transformation::Global) = delete; |
||||
void scale(Vector3 vec, Transformation type = Transformation::Global) = delete; |
||||
void rotate(GLfloat angle, Vector3 vec, Transformation type = Transformation::Global) = delete; |
||||
|
||||
private: |
||||
inline void draw(const Magnum::Matrix4&, Camera*) {} |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -0,0 +1,42 @@
|
||||
# Files shared between main library and unit test library |
||||
set(MagnumSceneGraph_SRCS |
||||
Camera.cpp |
||||
Light.cpp) |
||||
set(MagnumSceneGraph_HEADERS |
||||
Camera.h |
||||
Light.h |
||||
Object.h |
||||
Scene.h |
||||
|
||||
magnumSceneGraphVisibility.h) |
||||
add_library(MagnumSceneGraphObjects OBJECT ${MagnumSceneGraph_SRCS}) |
||||
|
||||
# Files compiled with different flags for main library and unit test library |
||||
set(MagnumSceneGraph_GracefulAssert_SRCS |
||||
Object.cpp) |
||||
|
||||
# Set shared library flags for the objects, as they will be part of shared lib |
||||
# TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well |
||||
set_target_properties(MagnumSceneGraphObjects PROPERTIES COMPILE_FLAGS "-DMagnumSceneGraphObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") |
||||
|
||||
# SceneGraph library |
||||
add_library(MagnumSceneGraph SHARED |
||||
$<TARGET_OBJECTS:MagnumSceneGraphObjects> |
||||
${MagnumSceneGraph_GracefulAssert_SRCS}) |
||||
target_link_libraries(MagnumSceneGraph Magnum) |
||||
|
||||
install(TARGETS MagnumSceneGraph DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) |
||||
install(FILES ${MagnumSceneGraph_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/SceneGraph) |
||||
|
||||
if(BUILD_TESTS) |
||||
enable_testing() |
||||
|
||||
# Library with graceful assert for testing |
||||
add_library(MagnumSceneGraphTestLib SHARED |
||||
$<TARGET_OBJECTS:MagnumSceneGraphObjects> |
||||
${MagnumSceneGraph_GracefulAssert_SRCS}) |
||||
set_target_properties(MagnumSceneGraphTestLib PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) |
||||
target_link_libraries(MagnumSceneGraphTestLib Magnum) |
||||
|
||||
add_subdirectory(Test) |
||||
endif() |
||||
@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "Camera.h" |
||||
#include "Framebuffer.h" |
||||
#include "Scene.h" |
||||
|
||||
using namespace std; |
||||
|
||||
namespace Magnum { namespace SceneGraph { |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
namespace Implementation { |
||||
|
||||
template<class MatrixType> MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Vector2& projectionScale, const Math::Vector2<GLsizei>& viewport) { |
||||
/* Don't divide by zero / don't preserve anything */ |
||||
if(projectionScale.x() == 0 || projectionScale.y() == 0 || viewport.x() == 0 || viewport.y() == 0 || aspectRatioPolicy == AspectRatioPolicy::NotPreserved) |
||||
return MatrixType(); |
||||
|
||||
Vector2 relativeAspectRatio = Vector2::from(viewport)*projectionScale; |
||||
|
||||
/* Extend on larger side = scale larger side down
|
||||
Clip on smaller side = scale smaller side up */ |
||||
return Camera<MatrixType::Size-1>::aspectRatioScale( |
||||
(relativeAspectRatio.x() > relativeAspectRatio.y()) == (aspectRatioPolicy == AspectRatioPolicy::Extend) ? |
||||
Vector2(relativeAspectRatio.y()/relativeAspectRatio.x(), 1.0f) : |
||||
Vector2(1.0f, relativeAspectRatio.x()/relativeAspectRatio.y())); |
||||
} |
||||
|
||||
/* Explicitly instantiate the templates */ |
||||
template Matrix3 aspectRatioFix<Matrix3>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&); |
||||
template Matrix4 aspectRatioFix<Matrix4>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&); |
||||
|
||||
} |
||||
#endif |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::Camera(ObjectType* parent): ObjectType(parent), _aspectRatioPolicy(AspectRatioPolicy::NotPreserved) {} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setViewport(const Math::Vector2<GLsizei>& size) { |
||||
Framebuffer::setViewport({0, 0}, size); |
||||
|
||||
_viewport = size; |
||||
fixAspectRatio(); |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::clean(const MatrixType& absoluteTransformation) { |
||||
ObjectType::clean(absoluteTransformation); |
||||
|
||||
_cameraMatrix = absoluteTransformation.inverted(); |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::draw() { |
||||
SceneType* s = this->scene(); |
||||
CORRADE_ASSERT(s, "Camera: cannot draw without camera attached to scene", ); |
||||
|
||||
Framebuffer::clear(); |
||||
|
||||
/* Recursively draw child objects */ |
||||
drawChildren(s, cameraMatrix()); |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Camera<MatrixType, VectorType, ObjectType, SceneType, CameraType>::drawChildren(ObjectType* object, const MatrixType& transformationMatrix) { |
||||
for(ObjectType* i = object->firstChild(); i; i = i->nextSibling()) { |
||||
/* Transformation matrix for the object */ |
||||
MatrixType matrix = transformationMatrix*i->transformation(); |
||||
|
||||
/* Draw the object and its children */ |
||||
i->draw(matrix, static_cast<CameraType*>(this)); |
||||
drawChildren(i, matrix); |
||||
} |
||||
} |
||||
|
||||
void Camera2D::setProjection(const Vector2& size) { |
||||
/* Scale the volume down so it fits in (-1, 1) in all directions */ |
||||
rawProjectionMatrix = Matrix3::scaling(2.0f/size); |
||||
|
||||
fixAspectRatio(); |
||||
} |
||||
|
||||
void Camera3D::setOrthographic(const Vector2& size, GLfloat near, GLfloat far) { |
||||
_near = near; |
||||
_far = far; |
||||
|
||||
Vector2 xyScale = 2.0f/size; |
||||
GLfloat zScale = 2.0f/(near-far); |
||||
|
||||
rawProjectionMatrix = Matrix4( |
||||
xyScale.x(), 0.0f, 0.0f, 0.0f, |
||||
0.0f, xyScale.y(), 0.0f, 0.0f, |
||||
0.0f, 0.0f, zScale, 0.0f, |
||||
0.0f, 0.0f, near*zScale-1, 1.0f |
||||
); |
||||
|
||||
fixAspectRatio(); |
||||
} |
||||
|
||||
void Camera3D::setPerspective(GLfloat fov, GLfloat near, GLfloat far) { |
||||
_near = near; |
||||
_far = far; |
||||
|
||||
GLfloat xyScale = 1.0f/tan(fov/2); /* == near/size */ |
||||
GLfloat zScale = 1.0f/(near-far); |
||||
|
||||
rawProjectionMatrix = Matrix4( |
||||
xyScale, 0.0f, 0.0f, 0.0f, |
||||
0.0f, xyScale, 0.0f, 0.0f, |
||||
0.0f, 0.0f, (far+near)*zScale, -1.0f, |
||||
0.0f, 0.0f, (2*far*near)*zScale, 0.0f |
||||
); |
||||
|
||||
fixAspectRatio(); |
||||
} |
||||
|
||||
/* Explicitly instantiate the templates */ |
||||
template class Camera<Matrix3, Vector2, Object2D, Scene2D, Camera2D>; |
||||
template class Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D>; |
||||
|
||||
}} |
||||
@ -0,0 +1,247 @@
|
||||
#ifndef Magnum_SceneGraph_Camera_h |
||||
#define Magnum_SceneGraph_Camera_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::SceneGraph::Camera, Magnum::SceneGraph::Camera2D, Magnum::SceneGraph::Camera3D |
||||
*/ |
||||
|
||||
#include "Object.h" |
||||
|
||||
#ifdef WIN32 /* I so HATE windows.h */ |
||||
#undef near |
||||
#undef far |
||||
#endif |
||||
|
||||
namespace Magnum { namespace SceneGraph { |
||||
|
||||
/** @todo Export implementation symbols only for tests */ |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
namespace Implementation { |
||||
enum class AspectRatioPolicy { |
||||
NotPreserved, Extend, Clip |
||||
}; |
||||
|
||||
template<size_t dimensions> class Camera {}; |
||||
|
||||
template<class MatrixType> MatrixType aspectRatioFix(AspectRatioPolicy aspectRatioPolicy, const Vector2& projectionScale, const Math::Vector2<GLsizei>& viewport); |
||||
|
||||
/* These templates are instantiated in source file */ |
||||
extern template SCENEGRAPH_EXPORT Matrix3 aspectRatioFix<Matrix3>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&); |
||||
extern template SCENEGRAPH_EXPORT Matrix4 aspectRatioFix<Matrix4>(AspectRatioPolicy, const Vector2&, const Math::Vector2<GLsizei>&); |
||||
} |
||||
#endif |
||||
|
||||
/**
|
||||
@brief %Camera object |
||||
*/ |
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Camera: public ObjectType { |
||||
public: |
||||
/**
|
||||
* @brief Aspect ratio policy |
||||
* |
||||
* @see aspectRatioPolicy(), setAspectRatioPolicy() |
||||
*/ |
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
typedef Implementation::AspectRatioPolicy AspectRatioPolicy; |
||||
#else |
||||
enum class AspectRatioPolicy { |
||||
NotPreserved, /**< Don't preserve aspect ratio (default) */ |
||||
Extend, /**< Extend on larger side of view */ |
||||
Clip /**< Clip on smaller side of view */ |
||||
}; |
||||
#endif |
||||
|
||||
/** @copydoc Object::Object */ |
||||
Camera(ObjectType* parent = nullptr); |
||||
|
||||
/** @brief Aspect ratio policy */ |
||||
inline AspectRatioPolicy aspectRatioPolicy() const { return _aspectRatioPolicy; } |
||||
|
||||
/** @brief Set aspect ratio policy */ |
||||
void setAspectRatioPolicy(AspectRatioPolicy policy) { _aspectRatioPolicy = policy; } |
||||
|
||||
/**
|
||||
* @brief Camera matrix |
||||
* |
||||
* Camera matrix describes world position relative to the camera and is |
||||
* applied as first. |
||||
*/ |
||||
inline MatrixType cameraMatrix() { |
||||
this->setClean(); |
||||
return _cameraMatrix; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Projection matrix |
||||
* |
||||
* Projection matrix handles e.g. perspective distortion and is applied |
||||
* as last. |
||||
* @see projectionSize() |
||||
*/ |
||||
inline MatrixType projectionMatrix() const { return _projectionMatrix; } |
||||
|
||||
/**
|
||||
* @brief Size of (near) XY plane in current projection |
||||
* |
||||
* Returns size of near XY plane computed from projection matrix. |
||||
* @see projectionMatrix() |
||||
*/ |
||||
inline Vector2 projectionSize() const { |
||||
return {2.0f/rawProjectionMatrix[0].x(), 2.0f/rawProjectionMatrix[1].y()}; |
||||
} |
||||
|
||||
/** @brief Viewport size */ |
||||
inline Math::Vector2<GLsizei> viewport() const { return _viewport; } |
||||
|
||||
/**
|
||||
* @brief Set viewport size |
||||
* |
||||
* Call when window size changes. |
||||
* |
||||
* Calls Framebuffer::setViewport() and stores viewport size |
||||
* internally. |
||||
*/ |
||||
virtual void setViewport(const Math::Vector2<GLsizei>& size); |
||||
|
||||
/**
|
||||
* @brief Draw the scene |
||||
* |
||||
* Calls Framebuffer::clear() and draws the scene using drawChildren(). |
||||
*/ |
||||
virtual void draw(); |
||||
|
||||
using ObjectType::draw; /* Don't hide Object's draw() */ |
||||
|
||||
protected: |
||||
/**
|
||||
* Recalculates camera matrix. |
||||
*/ |
||||
void clean(const MatrixType& absoluteTransformation); |
||||
|
||||
/**
|
||||
* @brief Draw object children |
||||
* |
||||
* Recursively draws all children of the object. |
||||
*/ |
||||
void drawChildren(ObjectType* object, const MatrixType& transformationMatrix); |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
inline void fixAspectRatio() { |
||||
_projectionMatrix = Implementation::aspectRatioFix<MatrixType>(_aspectRatioPolicy, {rawProjectionMatrix[0].x(), rawProjectionMatrix[1].y()}, _viewport)*rawProjectionMatrix; |
||||
} |
||||
|
||||
MatrixType rawProjectionMatrix; |
||||
AspectRatioPolicy _aspectRatioPolicy; |
||||
#endif |
||||
|
||||
private: |
||||
MatrixType _projectionMatrix; |
||||
MatrixType _cameraMatrix; |
||||
|
||||
Math::Vector2<GLsizei> _viewport; |
||||
}; |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
/* These templates are instantiated in source file */ |
||||
extern template class SCENEGRAPH_EXPORT Camera<Matrix3, Vector2, Object2D, Scene2D, Camera2D>; |
||||
extern template class SCENEGRAPH_EXPORT Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D>; |
||||
|
||||
namespace Implementation { |
||||
template<> class Camera<2> { |
||||
public: |
||||
inline constexpr static Matrix3 aspectRatioScale(const Vector2& scale) { |
||||
return Matrix3::scaling({scale.x(), scale.y()}); |
||||
} |
||||
}; |
||||
template<> class Camera<3> { |
||||
public: |
||||
inline constexpr static Matrix4 aspectRatioScale(const Vector2& scale) { |
||||
return Matrix4::scaling({scale.x(), scale.y(), 1.0f}); |
||||
} |
||||
}; |
||||
} |
||||
#endif |
||||
|
||||
/** @brief %Camera for two-dimensional scenes */ |
||||
class SCENEGRAPH_EXPORT Camera2D: public Camera<Matrix3, Vector2, Object2D, Scene2D, Camera2D> { |
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param parent Parent object |
||||
* |
||||
* Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions). |
||||
* @see setOrthographic() |
||||
*/ |
||||
inline Camera2D(Object2D* parent = nullptr): Camera(parent) {} |
||||
|
||||
/**
|
||||
* @brief Set projection |
||||
* @param size Size of the view |
||||
* |
||||
* The area of given size will be scaled down to range @f$ [-1; 1] @f$ |
||||
* on all directions. |
||||
*/ |
||||
void setProjection(const Vector2& size); |
||||
}; |
||||
|
||||
/** @brief %Camera for three-dimensional scenes */ |
||||
class SCENEGRAPH_EXPORT Camera3D: public Camera<Matrix4, Vector3, Object3D, Scene3D, Camera3D> { |
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param parent Parent object |
||||
* |
||||
* Sets orthographic projection to the default OpenGL cube (range @f$ [-1; 1] @f$ in all directions). |
||||
* @see setOrthographic(), setPerspective() |
||||
*/ |
||||
inline Camera3D(Object3D* parent = nullptr): Camera(parent), _near(0.0f), _far(0.0f) {} |
||||
|
||||
/**
|
||||
* @brief Set orthographic projection |
||||
* @param size Size of the view |
||||
* @param near Near clipping plane |
||||
* @param far Far clipping plane |
||||
* |
||||
* The volume of given size will be scaled down to range @f$ [-1; 1] @f$ |
||||
* on all directions. |
||||
*/ |
||||
void setOrthographic(const Vector2& size, GLfloat near, GLfloat far); |
||||
|
||||
/**
|
||||
* @brief Set perspective projection |
||||
* @param fov Field of view angle |
||||
* @param near Near clipping plane |
||||
* @param far Far clipping plane |
||||
* |
||||
* @todo Aspect ratio |
||||
*/ |
||||
void setPerspective(GLfloat fov, GLfloat near, GLfloat far); |
||||
|
||||
/** @brief Near clipping plane */ |
||||
inline GLfloat near() const { return _near; } |
||||
|
||||
/** @brief Far clipping plane */ |
||||
inline GLfloat far() const { return _far; } |
||||
|
||||
private: |
||||
GLfloat _near, _far; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,147 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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 "Object.h" |
||||
|
||||
#include <stack> |
||||
|
||||
#include "Scene.h" |
||||
#include "Camera.h" |
||||
|
||||
using namespace std; |
||||
using namespace Magnum::Math; |
||||
|
||||
namespace Magnum { namespace SceneGraph { |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setParent(ObjectType* parent) { |
||||
/* Skip if nothing to do or this is scene */ |
||||
if(this->parent() == parent || isScene()) return static_cast<ObjectType*>(this); |
||||
|
||||
/* Only Fry can be his own grandfather */ |
||||
ObjectType* p = parent; |
||||
while(p) { |
||||
/** @todo Assert for this */ |
||||
if(p == this) return static_cast<ObjectType*>(this); |
||||
p = p->parent(); |
||||
} |
||||
|
||||
/* Remove the object from old parent children list */ |
||||
if(this->parent()) |
||||
this->parent()->cut(static_cast<ObjectType*>(this)); |
||||
|
||||
/* Add the object to list of new parent */ |
||||
if(parent) |
||||
parent->insert(static_cast<ObjectType*>(this)); |
||||
|
||||
setDirty(); |
||||
return static_cast<ObjectType*>(this); |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> MatrixType Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::absoluteTransformation(CameraType* camera) { |
||||
/* Shortcut for absolute transformation of camera relative to itself */ |
||||
if(camera == this) return MatrixType(); |
||||
|
||||
MatrixType t = _transformation; |
||||
|
||||
ObjectType* p = parent(); |
||||
while(p != nullptr) { |
||||
t = p->transformation()*t; |
||||
|
||||
/* We got to the scene, multiply with camera matrix */ |
||||
if(p->isScene()) { |
||||
if(camera) { |
||||
CORRADE_ASSERT(camera->scene() == scene(), "Object::absoluteTransformation(): the camera is not part of the same scene as object!", t); |
||||
t = camera->cameraMatrix()*t; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
p = p->parent(); |
||||
} |
||||
|
||||
CORRADE_ASSERT(p != nullptr || camera == nullptr, "Object::absoluteTransformation(): the object is not part of camera scene!", t); |
||||
|
||||
return t; |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> SceneType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::scene() { |
||||
/* Goes up the family tree until it finds object which is parent of itself
|
||||
(that's the scene) */ |
||||
ObjectType* p = parent(); |
||||
while(p != nullptr) { |
||||
if(p->isScene()) return static_cast<SceneType*>(p); |
||||
p = p->parent(); |
||||
} |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> ObjectType* Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setTransformation(const MatrixType& transformation) { |
||||
/* Setting transformation is forbidden for the scene */ |
||||
/** @todo Assert for this? */ |
||||
if(isScene()) return static_cast<ObjectType*>(this); |
||||
|
||||
_transformation = transformation; |
||||
setDirty(); |
||||
return static_cast<ObjectType*>(this); |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setDirty() { |
||||
/* The object (and all its children) are already dirty, nothing to do */ |
||||
if(dirty) return; |
||||
|
||||
dirty = true; |
||||
|
||||
/* Make all children dirty */ |
||||
for(ObjectType* i = firstChild(); i; i = i->nextSibling()) |
||||
i->setDirty(); |
||||
} |
||||
|
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::setClean() { |
||||
/* The object (and all its parents) are already clean, nothing to do */ |
||||
if(!dirty) return; |
||||
|
||||
/* Collect all parents */ |
||||
stack<ObjectType*> objects; |
||||
ObjectType* p = static_cast<ObjectType*>(this); |
||||
for(;;) { |
||||
objects.push(p); |
||||
|
||||
/* Stop on root object / clean object */ |
||||
if(p->parent() == nullptr || !p->parent()->isDirty()) |
||||
break; |
||||
|
||||
p = p->parent(); |
||||
} |
||||
|
||||
/* Call setClean(const Matrix4&) for every parent and also this object */ |
||||
ObjectType* o = objects.top(); |
||||
objects.pop(); |
||||
MatrixType absoluteTransformation = o->absoluteTransformation(); |
||||
o->clean(absoluteTransformation); |
||||
while(!objects.empty()) { |
||||
o = objects.top(); |
||||
objects.pop(); |
||||
absoluteTransformation = absoluteTransformation*o->transformation(); |
||||
o->clean(absoluteTransformation); |
||||
} |
||||
} |
||||
|
||||
/* Explicitly instantiate the templates */ |
||||
template class Object<Matrix3, Vector2, Object2D, Scene2D, Camera2D>; |
||||
template class Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D>; |
||||
|
||||
}} |
||||
@ -0,0 +1,366 @@
|
||||
#ifndef Magnum_SceneGraph_Object_h |
||||
#define Magnum_SceneGraph_Object_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::SceneGraph::Object, Magnum::SceneGraph::Object2D, Magnum::SceneGraph::Object3D |
||||
*/ |
||||
|
||||
#include <Containers/LinkedList.h> |
||||
|
||||
#include "Magnum.h" |
||||
|
||||
#include "magnumSceneGraphVisibility.h" |
||||
|
||||
namespace Magnum { namespace SceneGraph { |
||||
|
||||
/**
|
||||
@todo User-specified Object implementation: |
||||
- for front-to-back sorting, LoD changes etc. |
||||
- for different parent/children implementation (e.g. no std::set, direct |
||||
access to scene etc.) |
||||
- for using doubles/halves instead of floats |
||||
- for using quat + position instead of matrices (where (asymmetric) scaling is |
||||
not needed) |
||||
*/ |
||||
|
||||
/**
|
||||
* @brief Base for all positioned objects |
||||
* |
||||
* @todo Transform transformation when changing parent, so the object stays in |
||||
* place. |
||||
*/ |
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> class SCENEGRAPH_EXPORT Object: public Corrade::Containers::LinkedList<ObjectType>, public Corrade::Containers::LinkedListItem<ObjectType, ObjectType> { |
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
Object(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete; |
||||
Object(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete; |
||||
Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& operator=(const Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& other) = delete; |
||||
Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>& operator=(Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>&& other) = delete; |
||||
#endif |
||||
|
||||
public: |
||||
/**
|
||||
* @brief Constructor |
||||
* @param parent Parent object |
||||
* |
||||
* Sets all transformations to their default values. |
||||
*/ |
||||
inline Object(ObjectType* parent = nullptr): dirty(true) { |
||||
setParent(parent); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Destructor |
||||
* |
||||
* Removes itself from parent's children list and destroys all own |
||||
* children. |
||||
*/ |
||||
virtual inline ~Object() {} |
||||
|
||||
/** @{ @name Scene hierarchy */ |
||||
|
||||
/** @brief Whether this object is scene */ |
||||
virtual inline bool isScene() const { return false; } |
||||
|
||||
/**
|
||||
* @brief %Scene |
||||
* @return If the object is not assigned to any scene, returns nullptr. |
||||
*/ |
||||
SceneType* scene(); |
||||
|
||||
/** @brief Parent object or `nullptr`, if this is root object */ |
||||
inline ObjectType* parent() { return Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::list(); } |
||||
|
||||
/** @brief Previous sibling object or `nullptr`, if this is first object */ |
||||
inline ObjectType* previousSibling() { return Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::previous(); } |
||||
|
||||
/** @brief Next sibling object or `nullptr`, if this is last object */ |
||||
inline ObjectType* nextSibling() { return Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::next(); } |
||||
|
||||
/** @brief Whether this object has children */ |
||||
inline bool hasChildren() const { return !Corrade::Containers::LinkedList<ObjectType>::isEmpty(); } |
||||
|
||||
/** @brief First child object or `nullptr`, if this object has no children */ |
||||
inline ObjectType* firstChild() { return Corrade::Containers::LinkedList<ObjectType>::first(); } |
||||
|
||||
/** @brief Last child object or `nullptr`, if this object has no children */ |
||||
inline ObjectType* lastChild() { return Corrade::Containers::LinkedList<ObjectType>::last(); } |
||||
|
||||
/** @brief Set parent object */ |
||||
ObjectType* setParent(ObjectType* parent); |
||||
|
||||
/*@}*/ |
||||
|
||||
/** @{ @name Object transformation
|
||||
* |
||||
* All transformations (except absoluteTransformation()) are relative |
||||
* to parent. |
||||
*/ |
||||
|
||||
/** @brief Transformation type */ |
||||
enum class Transformation: char { |
||||
/** Global transformation, applied after all other transformations. */ |
||||
Global = 0x00, |
||||
|
||||
/** Local transformation, applied before all other transformations. */ |
||||
Local = 0x01 |
||||
}; |
||||
|
||||
/** @brief Transformation */ |
||||
inline MatrixType transformation() const { |
||||
return _transformation; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Absolute transformation |
||||
* |
||||
* Returns absolute transformation matrix relative to the camera or |
||||
* root object, if no camera is specified. If the camera is specified, |
||||
* it should be part of the same scene as object. |
||||
* |
||||
* Note that the absolute transformation is computed from all parent |
||||
* objects every time it is asked, unless this function is |
||||
* reimplemented in a different way. |
||||
*/ |
||||
virtual MatrixType absoluteTransformation(CameraType* camera = nullptr); |
||||
|
||||
/** @brief Set transformation */ |
||||
ObjectType* setTransformation(const MatrixType& transformation); |
||||
|
||||
/**
|
||||
* @brief Multiply transformation |
||||
* @param transformation Transformation |
||||
* @param type Transformation type |
||||
*/ |
||||
inline ObjectType* multiplyTransformation(const MatrixType& transformation, Transformation type = Transformation::Global) { |
||||
setTransformation(type == Transformation::Global ? |
||||
transformation*_transformation : _transformation*transformation); |
||||
return static_cast<ObjectType*>(this); |
||||
} |
||||
|
||||
/*@}*/ |
||||
|
||||
/**
|
||||
* @brief Draw object |
||||
* @param transformationMatrix %Matrix specifying object |
||||
* transformation relative to the scene. |
||||
* @param camera Active camera (containing |
||||
* projection matrix) |
||||
* |
||||
* Default implementation does nothing. |
||||
*/ |
||||
virtual void draw(const MatrixType& transformationMatrix, CameraType* camera); |
||||
|
||||
/** @{ @name Caching helpers
|
||||
* |
||||
* If the object (absolute) transformation or anything depending on it |
||||
* is used many times when drawing (such as e.g. position of light |
||||
* object), it's good to cache these values, so they don't have to be |
||||
* recalculated again on every request. |
||||
* |
||||
* If setDirty() is called on an object (or the object is transformed), |
||||
* it and all its children are marked as dirty. If any object is |
||||
* already dirty, it and all its children are skipped, because they |
||||
* are already dirty too. |
||||
* |
||||
* If setClean() is called on an object, it and all its parents are |
||||
* cleaned. If any object is already clean, it and all its parents are |
||||
* skipped, because they are already clean too. |
||||
* |
||||
* These functions are used to manage dirty status of the object. If |
||||
* the object doesn't cache anything, it's no need to bother about |
||||
* them, but if does, clean() should be reimplemented and used to |
||||
* regenerate the cache. |
||||
*/ |
||||
|
||||
/**
|
||||
* @brief Whether the object is dirty |
||||
* @return True, if transformation of the object, any parent or camera |
||||
* has changed since last asking, false otherwise. |
||||
*/ |
||||
inline bool isDirty() const { return dirty; } |
||||
|
||||
/**
|
||||
* @brief Set object and all its children as dirty |
||||
* |
||||
* Recursively calls setDirty() on every child. If the object is |
||||
* already marked as dirty, the function does nothing. It is usually |
||||
* not needed to reimplement this function, only if you for example |
||||
* need to reset some state on object which is not child of this. All |
||||
* computations should be done in setClean(). |
||||
* |
||||
* Reimplementations should call this function at the end, i.e.: |
||||
* @code |
||||
* void setDirty() { |
||||
* // ...
|
||||
* |
||||
* Object::setDirty(); |
||||
* } |
||||
* @endcode |
||||
*/ |
||||
virtual void setDirty(); |
||||
|
||||
/**
|
||||
* @brief Set object and all its parents as clean |
||||
* |
||||
* Recursively calls clean() on every parent which is not already |
||||
* clean. |
||||
*/ |
||||
void setClean(); |
||||
|
||||
protected: |
||||
/**
|
||||
* @brief Clean the object |
||||
* |
||||
* When reimplementing, use absolute transformation passed as |
||||
* parameter instead of absoluteTransformation(), which is not |
||||
* efficient. The reimplementation should call this function at the |
||||
* beginning, i.e.: |
||||
* @code |
||||
* void clean(const Matrix4& absoluteTransformation) { |
||||
* Object::clean(absoluteTransformation); |
||||
* |
||||
* // ...
|
||||
* } |
||||
* @endcode |
||||
*/ |
||||
virtual void clean(const MatrixType& absoluteTransformation); |
||||
|
||||
/*@}*/ |
||||
|
||||
private: |
||||
/* Hide base class members, as they are aliased to more meaningful names */ |
||||
using Corrade::Containers::LinkedList<ObjectType>::first; |
||||
using Corrade::Containers::LinkedList<ObjectType>::last; |
||||
using Corrade::Containers::LinkedList<ObjectType>::isEmpty; |
||||
using Corrade::Containers::LinkedList<ObjectType>::insert; |
||||
using Corrade::Containers::LinkedList<ObjectType>::cut; |
||||
using Corrade::Containers::LinkedList<ObjectType>::move; |
||||
using Corrade::Containers::LinkedList<ObjectType>::erase; |
||||
using Corrade::Containers::LinkedList<ObjectType>::clear; |
||||
using Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::list; |
||||
using Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::previous; |
||||
using Corrade::Containers::LinkedListItem<ObjectType, ObjectType>::next; |
||||
|
||||
MatrixType _transformation; |
||||
bool dirty; |
||||
}; |
||||
|
||||
/* Implementations for inline functions with unused parameters */ |
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> inline void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::draw(const MatrixType&, CameraType*) {} |
||||
template<class MatrixType, class VectorType, class ObjectType, class SceneType, class CameraType> inline void Object<MatrixType, VectorType, ObjectType, SceneType, CameraType>::clean(const MatrixType&) { dirty = false; } |
||||
|
||||
class Camera2D; |
||||
class Camera3D; |
||||
class Object2D; |
||||
class Object3D; |
||||
template<class MatrixType, class VectorType, class ObjectType, class CameraType> class Scene; |
||||
typedef Scene<Matrix3, Vector2, Object2D, Camera2D> Scene2D; |
||||
typedef Scene<Matrix4, Vector3, Object3D, Camera3D> Scene3D; |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
/* These templates are instantiated in source file */ |
||||
extern template class SCENEGRAPH_EXPORT Object<Matrix3, Vector2, Object2D, Scene2D, Camera2D>; |
||||
extern template class SCENEGRAPH_EXPORT Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D>; |
||||
#endif |
||||
|
||||
/** @brief Two-dimensional object */ |
||||
class SCENEGRAPH_EXPORT Object2D: public Object<Matrix3, Vector2, Object2D, Scene2D, Camera2D> { |
||||
public: |
||||
/** @copydoc Object::Object */ |
||||
inline Object2D(Object2D* parent = nullptr): Object(parent) {} |
||||
|
||||
/**
|
||||
* @brief Translate object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix3::translation(). |
||||
*/ |
||||
inline Object2D* translate(const Vector2& vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix3::translation(vec), type); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Scale object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix3::scaling(). |
||||
*/ |
||||
inline Object2D* scale(const Vector2& vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix3::scaling(vec), type); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix3::rotation(). |
||||
*/ |
||||
inline Object2D* rotate(GLfloat angle, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix3::rotation(angle), type); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Move object in stacking order |
||||
* @param under Sibling object under which to move or `nullptr`, |
||||
* if you want to move it above all. |
||||
*/ |
||||
inline Object2D* move(Object2D* under) { |
||||
parent()->Corrade::Containers::LinkedList<Object2D>::move(this, under); |
||||
return this; |
||||
} |
||||
}; |
||||
|
||||
/** @brief Three-dimensional object */ |
||||
class SCENEGRAPH_EXPORT Object3D: public Object<Matrix4, Vector3, Object3D, Scene3D, Camera3D> { |
||||
public: |
||||
/** @copydoc Object::Object */ |
||||
inline Object3D(Object3D* parent = nullptr): Object(parent) {} |
||||
|
||||
/**
|
||||
* @brief Translate object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix4::translation(). |
||||
*/ |
||||
inline Object3D* translate(const Vector3& vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix4::translation(vec), type); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Scale object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix4::scaling(). |
||||
*/ |
||||
inline Object3D* scale(const Vector3& vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix4::scaling(vec), type); |
||||
return this; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Rotate object |
||||
* |
||||
* Same as calling multiplyTransformation() with Matrix4::rotation(). |
||||
*/ |
||||
inline Object3D* rotate(GLfloat angle, const Vector3& vec, Transformation type = Transformation::Global) { |
||||
multiplyTransformation(Matrix4::rotation(angle, vec), type); |
||||
return this; |
||||
} |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,54 @@
|
||||
#ifndef Magnum_SceneGraph_Scene_h |
||||
#define Magnum_SceneGraph_Scene_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
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::SceneGraph::Scene, typedef Magnum::SceneGraph::Scene2D, Magnum::SceneGraph::Scene3D |
||||
*/ |
||||
|
||||
#include "Object.h" |
||||
|
||||
namespace Magnum { namespace SceneGraph { |
||||
|
||||
/** @brief %Scene */ |
||||
template<class MatrixType, class VectorType, class ObjectType, class CameraType> class SCENEGRAPH_EXPORT Scene: public ObjectType { |
||||
public: |
||||
/** @copydoc Object::isScene() */ |
||||
inline bool isScene() const { return true; } |
||||
|
||||
/** @todo Some deleted functions belong only to Scene2D, some only to Scene3D - what to do? */ |
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
void setParent(ObjectType* parent) = delete; |
||||
void setTransformation(const MatrixType& transformation) = delete; |
||||
void multiplyTransformation(const MatrixType& transformation, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete; |
||||
void translate(const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete; |
||||
void scale(const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete; |
||||
void rotate(GLfloat angle, const VectorType& vec, typename ObjectType::Transformation type = ObjectType::Transformation::Global) = delete; |
||||
#endif |
||||
|
||||
private: |
||||
inline void draw(const MatrixType&, CameraType*) {} |
||||
}; |
||||
|
||||
/** @brief Two-dimensional scene */ |
||||
typedef Scene<Matrix3, Vector2, Object2D, Camera2D> Scene2D; |
||||
|
||||
/** @brief Three-dimensional scene */ |
||||
typedef Scene<Matrix4, Vector3, Object3D, Camera3D> Scene3D; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,3 @@
|
||||
corrade_add_test2(SceneGraphObjectTest ObjectTest.cpp LIBRARIES MagnumSceneGraphTestLib) |
||||
corrade_add_test2(SceneGraphCameraTest CameraTest.cpp LIBRARIES MagnumSceneGraph) |
||||
corrade_add_test2(SceneGraphSceneTest SceneTest.cpp LIBRARIES MagnumSceneGraph) |
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue