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