Browse Source

Merge branch 'master' into compatibility

Conflicts:
	src/AbstractFramebuffer.h
	src/AbstractImage.h
	src/AbstractTexture.cpp
	src/DebugTools/ShapeRenderer.cpp
	src/Primitives/Icosphere.cpp
	src/Primitives/Icosphere.h
	src/ResourceManager.h
	src/SceneGraph/AbstractFeature.hpp
	src/SceneGraph/AbstractTransformation.h
	src/SceneGraph/FeatureGroup.h
	src/SceneGraph/FeatureGroup.hpp
	src/Shader.cpp
	src/Shapes/Implementation/CollisionDispatch.cpp
	src/Text/AbstractFontConverter.cpp
Vladimír Vondruš 13 years ago
parent
commit
8410de02cb
  1. 1
      Doxyfile
  2. 4
      doc/best-practices.dox
  3. 4
      doc/building.dox
  4. 4
      doc/debug-tools.dox
  5. 62
      doc/method-chaining.dox
  6. 2
      doc/required-extensions.dox
  7. 27
      doc/scenegraph.dox
  8. 5219
      external/OpenGL/GL/glcorearb.h
  9. 30
      src/AbstractFramebuffer.cpp
  10. 9
      src/AbstractFramebuffer.h
  11. 14
      src/AbstractImage.h
  12. 92
      src/AbstractResourceLoader.h
  13. 14
      src/AbstractShaderProgram.cpp
  14. 20
      src/AbstractShaderProgram.h
  15. 82
      src/AbstractTexture.cpp
  16. 59
      src/AbstractTexture.h
  17. 44
      src/Array.h
  18. 20
      src/Buffer.cpp
  19. 81
      src/Buffer.h
  20. 2
      src/BufferImage.h
  21. 20
      src/BufferTexture.cpp
  22. 25
      src/BufferTexture.h
  23. 8
      src/CMakeLists.txt
  24. 38
      src/Context.cpp
  25. 5
      src/Context.h
  26. 54
      src/CubeMapTexture.h
  27. 54
      src/CubeMapTextureArray.h
  28. 4
      src/DebugMarker.cpp
  29. 2
      src/DebugMarker.h
  30. 2
      src/DebugTools/CMakeLists.txt
  31. 32
      src/DebugTools/ForceRenderer.cpp
  32. 29
      src/DebugTools/ForceRenderer.h
  33. 4
      src/DebugTools/Implementation/AbstractBoxRenderer.cpp
  34. 36
      src/DebugTools/Implementation/AbstractShapeRenderer.cpp
  35. 10
      src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp
  36. 3
      src/DebugTools/Implementation/AxisAlignedBoxRenderer.h
  37. 10
      src/DebugTools/Implementation/BoxRenderer.cpp
  38. 3
      src/DebugTools/Implementation/BoxRenderer.h
  39. 12
      src/DebugTools/Implementation/LineSegmentRenderer.cpp
  40. 3
      src/DebugTools/Implementation/LineSegmentRenderer.h
  41. 12
      src/DebugTools/Implementation/PointRenderer.cpp
  42. 3
      src/DebugTools/Implementation/PointRenderer.h
  43. 17
      src/DebugTools/Implementation/SphereRenderer.cpp
  44. 10
      src/DebugTools/Implementation/SphereRenderer.h
  45. 32
      src/DebugTools/ObjectRenderer.cpp
  46. 15
      src/DebugTools/ObjectRenderer.h
  47. 49
      src/DebugTools/ShapeRenderer.cpp
  48. 32
      src/DebugTools/ShapeRenderer.h
  49. 13
      src/DefaultFramebuffer.cpp
  50. 24
      src/DefaultFramebuffer.h
  51. 13
      src/Extensions.h
  52. 43
      src/Framebuffer.cpp
  53. 84
      src/Framebuffer.h
  54. 2
      src/Image.h
  55. 7
      src/ImageFormat.h
  56. 7
      src/Magnum.h
  57. 2
      src/Math/Complex.h
  58. 23
      src/Math/DualComplex.h
  59. 13
      src/Math/DualQuaternion.h
  60. 24
      src/Math/Functions.h
  61. 4
      src/Math/Matrix.h
  62. 24
      src/Math/Matrix3.h
  63. 25
      src/Math/Matrix4.h
  64. 2
      src/Math/Quaternion.h
  65. 15
      src/Math/Test/FunctionsTest.cpp
  66. 20
      src/Math/Test/Matrix3Test.cpp
  67. 22
      src/Math/Test/Matrix4Test.cpp
  68. 2
      src/Math/Vector.h
  69. 12
      src/Math/instantiation.cpp
  70. 28
      src/Mesh.cpp
  71. 173
      src/Mesh.h
  72. 2
      src/MeshTools/CMakeLists.txt
  73. 8
      src/MeshTools/CompressIndices.cpp
  74. 2
      src/MeshTools/CompressIndices.h
  75. 18
      src/MeshTools/Interleave.h
  76. 2
      src/MeshTools/Test/InterleaveTest.cpp
  77. 1
      src/MeshTools/Tipsify.h
  78. 4
      src/Platform/AbstractXApplication.h
  79. 1
      src/Platform/magnum-info.cpp
  80. 5
      src/Primitives/CMakeLists.txt
  81. 22
      src/Primitives/Capsule.cpp
  82. 14
      src/Primitives/Capsule.h
  83. 16
      src/Primitives/Cylinder.cpp
  84. 12
      src/Primitives/Cylinder.h
  85. 91
      src/Primitives/Icosphere.cpp
  86. 51
      src/Primitives/Icosphere.h
  87. 6
      src/Primitives/Implementation/Spheroid.h
  88. 115
      src/Primitives/Implementation/WireframeSpheroid.cpp
  89. 54
      src/Primitives/Implementation/WireframeSpheroid.h
  90. 1
      src/Primitives/Test/CMakeLists.txt
  91. 82
      src/Primitives/Test/CapsuleTest.cpp
  92. 64
      src/Primitives/Test/CylinderTest.cpp
  93. 57
      src/Primitives/Test/IcosphereTest.cpp
  94. 56
      src/Primitives/Test/UVSphereTest.cpp
  95. 14
      src/Primitives/UVSphere.cpp
  96. 11
      src/Primitives/UVSphere.h
  97. 33
      src/Query.h
  98. 12
      src/Renderbuffer.cpp
  99. 2
      src/Renderbuffer.h
  100. 10
      src/Renderer.cpp
  101. Some files were not shown because too many files have changed in this diff Show More

1
Doxyfile

@ -216,6 +216,7 @@ ALIASES = \
"requires_gl41=@xrefitem requires-gl41 \"Requires OpenGL 4.1\" \"Functionality requiring OpenGL 4.1\"" \
"requires_gl42=@xrefitem requires-gl42 \"Requires OpenGL 4.2\" \"Functionality requiring OpenGL 4.2\"" \
"requires_gl43=@xrefitem requires-gl43 \"Requires OpenGL 4.3\" \"Functionality requiring OpenGL 4.3\"" \
"requires_gl44=@xrefitem requires-gl44 \"Requires OpenGL 4.4\" \"Functionality requiring OpenGL 4.4\"" \
"requires_extension=@xrefitem requires-extension \"Requires OpenGL extension\" \"Functionality requiring specific OpenGL extension\"" \
"extension{2}=<a href=\"http://www.opengl.org/registry/specs/\1/\2.txt\"><tt>\1_\2</tt></a>" \
"requires_gles30=@xrefitem requires-gles30 \"Requires OpenGL ES 3.0\" \"Functionality requiring OpenGL ES 3.0\"" \

4
doc/best-practices.dox

@ -69,5 +69,9 @@ vertex and index buffers.
- [PowerVR Performance Recommendations](http://www.imgtec.com/powervr/insider/docs/PowerVR.Performance%20Recommendations.1.0.28.External.pdf) [PDF]
@subsection best-practices-tegra NVidia Tegra hardware
- [Optimize OpenGL ES 2.0 Performance for Tegra](http://docs.nvidia.com/tegra/data/Optimize_OpenGL_ES_2_0_Performance_for_Tegra.html)
*/
}

4
doc/building.dox

@ -127,8 +127,8 @@ platform best:
- `WITH_SDL2APPLICATION` - @ref Platform::Sdl2Application "Sdl2Application".
Requires **SDL2** library.
- `WITH_XEGLAPPLICATION` - @ref Platform::XEglApplication "XEglApplication",
available only if targeting OpenGL ES (see above). Requires **X11** and
**EGL** libraries.
available only if targeting OpenGL ES (see above). Requires **X11** and **EGL**
libraries.
- `WITH_WINDOWLESSGLXAPPLICATION` - @ref Platform::WindowlessGlxApplication "WindowlessGlxApplication".
Requires **X11** and **GLX** libraries.

4
doc/debug-tools.dox

@ -63,13 +63,13 @@ SceneGraph::DrawableGroup3D debugDrawables;
// Create renderer options which will be referenced later by "my" resource key
DebugTools::ResourceManager::instance()->set("my",
(new DebugTools::ObjectRendererOptions)->setSize(0.3f));
DebugTools::ObjectRendererOptions().setSize(0.3f));
// Create debug renderer for given object, use "my" options for it. The
// renderer is automatically added to the object features and also to
// specified drawable group.
Object3D* object;
new DebugTools::ObjectRenderer2D(object, "my", debugDrawables);
new DebugTools::ObjectRenderer2D(*object, "my", debugDrawables);
@endcode
See DebugTools::ObjectRenderer and DebugTools::ShapeRenderer for more

62
doc/method-chaining.dox

@ -32,26 +32,27 @@ feature which allows you to chain method calls one after another without
repeatedly specifying variable the method is called on. Its primary goal is to
reduce unnecessary repeated names, improving code readability.
%Magnum uses this feature for configuring OpenGL objects (such as various mesh
and framebuffer options, shader uniforms etc.). Because OpenGL was designed with
"bind-to-modify" approach, most configuration calls need to bind the object
first and only after that change the parameters (unless @extension{EXT,direct_state_access}
extension is available to avoid this). To reduce unneeded bind calls, %Magnum
binds the object only if it is not already bound somewhere. Method chaining
encourages you to configure whole object in one run, effectively reducing the
number of needed bindings. Consider the following example:
%Magnum uses this feature mainly for configuring OpenGL objects (such as
various mesh and framebuffer options, shader uniforms etc.). Because OpenGL was
designed with "bind-to-modify" approach, most configuration calls internally
need to bind the object first and only after that change the parameters (unless
@extension{EXT,direct_state_access} extension is available to avoid this). To
reduce unneeded bind calls, %Magnum binds the object only if it is not already
bound somewhere. Method chaining encourages you to configure whole object in
one run, effectively reducing the number of needed bindings. Consider the
following example:
@code
Texture2D *carDiffuseTexture, *carSpecularTexture, *carBumpTexture;
Texture2D carDiffuseTexture, carSpecularTexture, carBumpTexture;
carDiffuseTexture->setStorage(5, TextureFormat::SRGB8);
carSpecularTexture->setStorage(3, TextureFormat::R8);
carBumpTexture->setStorage(5, TextureFormat::RGB8);
carDiffuseTexture->setSubImage(0, {}, diffuse);
carSpecularTexture->setSubImage(0, {}, specular;
carBumpTexture->setSubImage(0, {}, bump);
carDiffuseTexture->generateMipmap();
carSpecularTexture->generateMipmap();
carBumpTexture->generateMipmap();
carDiffuseTexture.setStorage(5, TextureFormat::SRGB8);
carSpecularTexture.setStorage(3, TextureFormat::R8);
carBumpTexture.setStorage(5, TextureFormat::RGB8);
carDiffuseTexture.setSubImage(0, {}, diffuse);
carSpecularTexture.setSubImage(0, {}, specular;
carBumpTexture.setSubImage(0, {}, bump);
carDiffuseTexture.generateMipmap();
carSpecularTexture.generateMipmap();
carBumpTexture.generateMipmap();
@endcode
This code is written that similar configuration steps are grouped together,
@ -61,15 +62,15 @@ names and after each configuration step the texture must be rebound to another.
With method chaining used the code looks much lighter and each object is
configured in one run, reducing count of bind calls from 9 to 3.
@code
carDiffuseTexture->setStorage(5, TextureFormat::SRGB8)
->setSubImage(0, {}, diffuse)
->generateMipmap();
carSpecularTexture->setStorage(3, TextureFormat::R8)
->setSubImage(0, {}, diffuse)
->generateMipmap();
carBumpTexture->setStorage(5, TextureFormat::RGB8)
->setSubImage(0, {}, bump)
->generateMipmap();
carDiffuseTexture.setStorage(5, TextureFormat::SRGB8)
.setSubImage(0, {}, diffuse)
.generateMipmap();
carSpecularTexture.setStorage(3, TextureFormat::R8)
.setSubImage(0, {}, diffuse)
.generateMipmap();
carBumpTexture.setStorage(5, TextureFormat::RGB8)
.setSubImage(0, {}, bump)
.generateMipmap();
@endcode
Method chaining is not used on non-configuring functions, such as Framebuffer::clear()
@ -84,12 +85,7 @@ Scene3D scene;
(new MyObject(&scene))
->rotateX(90.0_degf)
->translate({-1.5f, 0.5f, 7.0f});
.translate({-1.5f, 0.5f, 7.0f});
@endcode
In most cases method chaining methods return pointer to the object, because
most of the objects are commonly created on the heap. The only exception are
Shader methods, which return reference, because the class is commonly created
as local variable in shader constructors.
*/
}

2
doc/required-extensions.dox

@ -46,6 +46,7 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
- @subpage requires-gl41
- @subpage requires-gl42
- @subpage requires-gl43
- @subpage requires-gl44
- @subpage requires-extension
- @subpage requires-gl
- @subpage requires-gles20
@ -61,6 +62,7 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
@page requires-gl41 Functionality requiring OpenGL 4.1
@page requires-gl42 Functionality requiring OpenGL 4.2
@page requires-gl43 Functionality requiring OpenGL 4.3
@page requires-gl44 Functionality requiring OpenGL 4.4
@page requires-extension Functionality requiring specific OpenGL extension

27
doc/scenegraph.dox

@ -82,8 +82,8 @@ Parent object can be either passed in constructor or using Object::setParent().
@code
Scene3D scene;
Object3D* first = new Object3D(&scene);
Object3D* second = new Object3D(first);
auto first = new Object3D(&scene);
auto second = new Object3D(first);
@endcode
%Object children can be accessed using Object::firstChild() and
@ -107,10 +107,10 @@ The object is derived from the transformation you specified earlier in the
transformation implementation. %Scene, as a root object, cannot have any
transformation. For convenience you can use method chaining:
@code
Object3D* next = new Object3D;
auto next = new Object3D;
next->setParent(another)
->translate(Vector3::yAxis(3.0f))
->rotateY(35.0_degf);
.translate(Vector3::yAxis(3.0f))
.rotateY(35.0_degf);
@endcode
@section scenegraph-features Object features
@ -119,11 +119,12 @@ The object itself handles only parent/child relationship and transformation.
To make the object renderable, animatable, add collision shape to it etc., you
have to add a *feature* to it.
Each feature takes pointer to holder object in constructor, so adding a
feature to an object might look like this:
Each feature takes reference to holder object in constructor, so adding a
feature to an object might look just like this, as in some cases you don't even
need to keep the pointer to it:
@code
Object3D* o;
MyFeature* feature = new MyFeature(o);
new MyFeature(o);
@endcode
Features of an object can be accessed using Object::firstFeature() and
@ -149,7 +150,7 @@ Simplified example:
@code
class Bomb: public Object3D, SceneGraph::Drawable3D, SceneGraph:.Animable3D {
public:
Bomb(Object3D* parent): Object3D(parent), SceneGraph::Drawable3D(this), SceneGraph::Animable3D(this) {}
Bomb(Object3D* parent): Object3D(parent), SceneGraph::Drawable3D(*this), SceneGraph::Animable3D(*this) {}
protected:
// drawing implementation for Drawable feature
@ -195,8 +196,8 @@ cleaning function(s):
@code
class CachingObject: public Object3D, SceneGraph::AbstractFeature3D {
public:
CachingObject(Object3D* parent): SceneGraph::AbstractFeature3D(this) {
setCachedTransformations(CachedTransformation::Absolute);
CachingObject(Object3D* parent): SceneGraph::AbstractFeature3D(*this) {
setCachedTransformations(SceneGraph::CachedTransformation::Absolute);
}
protected:
@ -258,7 +259,7 @@ inherited after the %Object class:
@code
class MyObject: public Object3D, MyFeature {
public:
MyObject(Object3D* parent): Object3D(parent), MyFeature(this) {}
MyObject(Object3D* parent): Object3D(parent), MyFeature(*this) {}
};
@endcode
When constructing MyObject, Object3D constructor is called first and then
@ -271,7 +272,7 @@ However, if we would inherit MyFeature first, it will cause problems:
@code
class MyObject: MyFeature, public Object3D {
public:
MyObject(Object3D* parent): MyFeature(this), Object3D(parent) {} // crash!
MyObject(Object3D* parent): MyFeature(*this), Object3D(parent) {} // crash!
};
@endcode
MyFeature tries to add itself to feature list in not-yet-constructed Object3D,

5219
external/OpenGL/GL/glcorearb.h vendored

File diff suppressed because it is too large Load Diff

30
src/AbstractFramebuffer.cpp

@ -53,7 +53,7 @@ void AbstractFramebuffer::bind(FramebufferTarget target) {
}
void AbstractFramebuffer::bindInternal(FramebufferTarget target) {
Implementation::FramebufferState* state = Context::current()->state()->framebuffer;
Implementation::FramebufferState* state = Context::current()->state().framebuffer;
/* If already bound, done, otherwise update tracked state */
if(target == FramebufferTarget::Read) {
@ -71,7 +71,7 @@ void AbstractFramebuffer::bindInternal(FramebufferTarget target) {
}
FramebufferTarget AbstractFramebuffer::bindInternal() {
Implementation::FramebufferState* state = Context::current()->state()->framebuffer;
Implementation::FramebufferState* state = Context::current()->state().framebuffer;
/* Return target to which the framebuffer is already bound */
if(state->readBinding == _id && state->drawBinding == _id)
@ -108,18 +108,18 @@ void AbstractFramebuffer::blit(AbstractFramebuffer& source, AbstractFramebuffer&
#endif
}
AbstractFramebuffer* AbstractFramebuffer::setViewport(const Rectanglei& rectangle) {
AbstractFramebuffer& AbstractFramebuffer::setViewport(const Rectanglei& rectangle) {
_viewport = rectangle;
/* Update the viewport if the framebuffer is currently bound */
if(Context::current()->state()->framebuffer->drawBinding == _id)
if(Context::current()->state().framebuffer->drawBinding == _id)
setViewportInternal();
return this;
return *this;
}
void AbstractFramebuffer::setViewportInternal() {
Implementation::FramebufferState* state = Context::current()->state()->framebuffer;
Implementation::FramebufferState* state = Context::current()->state().framebuffer;
CORRADE_INTERNAL_ASSERT(state->drawBinding == _id);
@ -165,7 +165,7 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Buf
if(image.size() != size)
image.setData(size, image.format(), image.type(), nullptr, usage);
image.buffer()->bind(Buffer::Target::PixelPack);
image.buffer().bind(Buffer::Target::PixelPack);
/** @todo De-duplicate buffer size computation */
readImplementation(offset, size, image.format(), image.type(), image.pixelSize()*size.product(), nullptr);
}
@ -194,9 +194,9 @@ void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attach
#endif
}
void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) {
void AbstractFramebuffer::initializeContextBasedFunctionality(Context& context) {
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDSA;
@ -212,20 +212,20 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context)
readTarget = FramebufferTarget::Read;
drawTarget = FramebufferTarget::Draw;
if(context->isExtensionSupported<Extensions::GL::ANGLE::framebuffer_blit>())
if(context.isExtensionSupported<Extensions::GL::ANGLE::framebuffer_blit>())
Debug() << "AbstractFramebuffer: using" << Extensions::GL::ANGLE::framebuffer_blit::string() << "features";
else if(context->isExtensionSupported<Extensions::GL::APPLE::framebuffer_multisample>())
else if(context.isExtensionSupported<Extensions::GL::APPLE::framebuffer_multisample>())
Debug() << "AbstractFramebuffer: using" << Extensions::GL::APPLE::framebuffer_multisample::string() << "features";
else if(context->isExtensionSupported<Extensions::GL::NV::framebuffer_blit>())
else if(context.isExtensionSupported<Extensions::GL::NV::framebuffer_blit>())
Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_blit::string() << "features";
/* NV_framebuffer_multisample requires NV_framebuffer_blit, which has these
enums. However, on my system only NV_framebuffer_multisample is
supported, but NV_framebuffer_blit isn't. I will hold my breath and
assume these enums are available. */
else if(context->isExtensionSupported<Extensions::GL::NV::framebuffer_multisample>())
else if(context.isExtensionSupported<Extensions::GL::NV::framebuffer_multisample>())
Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features";
/* If no such extension is available, reset back to unified target */
@ -234,9 +234,9 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context)
#ifndef MAGNUM_TARGET_GLES3
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::robustness>())
if(context.isExtensionSupported<Extensions::GL::ARB::robustness>())
#else
if(context->isExtensionSupported<Extensions::GL::EXT::robustness>())
if(context.isExtensionSupported<Extensions::GL::EXT::robustness>())
#endif
{
#ifndef MAGNUM_TARGET_GLES

9
src/AbstractFramebuffer.h

@ -193,8 +193,6 @@ class MAGNUM_EXPORT AbstractFramebuffer {
blit(source, destination, rectangle, rectangle, mask, FramebufferBlitFilter::Nearest);
}
explicit AbstractFramebuffer();
/**
* @brief Bind framebuffer for rendering
*
@ -213,14 +211,14 @@ class MAGNUM_EXPORT AbstractFramebuffer {
/**
* @brief Set viewport
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Saves the viewport to be used at later time in bind(). If the
* framebuffer is currently bound, updates the viewport to given
* rectangle.
* @see @fn_gl{Viewport}
*/
AbstractFramebuffer* setViewport(const Rectanglei& rectangle);
AbstractFramebuffer& setViewport(const Rectanglei& rectangle);
/**
* @brief Clear specified buffers in framebuffer
@ -272,6 +270,7 @@ class MAGNUM_EXPORT AbstractFramebuffer {
#else
protected:
#endif
explicit AbstractFramebuffer();
~AbstractFramebuffer();
void MAGNUM_LOCAL bindInternal(FramebufferTarget target);
@ -302,7 +301,7 @@ class MAGNUM_EXPORT AbstractFramebuffer {
Rectanglei _viewport;
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
GLenum MAGNUM_LOCAL checkStatusImplementationDefault(FramebufferTarget target);
#ifndef MAGNUM_TARGET_GLES

14
src/AbstractImage.h

@ -60,13 +60,6 @@ class MAGNUM_EXPORT AbstractImage {
*/
static std::size_t pixelSize(ImageFormat format, ImageType type);
/**
* @brief Constructor
* @param format Format of pixel data
* @param type Data type of pixel data
*/
constexpr explicit AbstractImage(ImageFormat format, ImageType type): _format(format), _type(type) {}
/** @brief Format of pixel data */
constexpr ImageFormat format() const { return _format; }
@ -81,6 +74,13 @@ class MAGNUM_EXPORT AbstractImage {
std::size_t pixelSize() const { return pixelSize(_format, _type); }
protected:
/**
* @brief Constructor
* @param format Format of pixel data
* @param type Data type of pixel data
*/
constexpr explicit AbstractImage(ImageFormat format, ImageType type): _format(format), _type(type) {}
/* GCC > 4.5 needs to have `= default` in class body, otherwise can't
use constexpr */
#ifndef CORRADE_GCC45_COMPATIBILITY

92
src/AbstractResourceLoader.h

@ -47,52 +47,55 @@ each call to ResourceManager::get() will call load() implementation unless the
resource is already loaded (or loading is in progress). Note that resources
requested before the loader was added are not be affected by the loader.
Subclassing is done by implementing at least load() function. The loading can
Subclassing is done by implementing at least doLoad() function. The loading can
be done synchronously or asynchronously (i.e., in another thread). The base
implementation provides interface to ResourceManager and manages loading
progress (which is then available through functions requestedCount(),
loadedCount() and notFoundCount()). You shouldn't access the ResourceManager
directly when loading the data.
Your load() implementation must call the base implementation at the beginning
so ResourceManager is informed about loading state. Then, after your resources
are loaded, call set() to pass them to ResourceManager or call setNotFound()
to indicate that the resource was not found.
In your doLoad() implementation, after your resources are loaded, call set() to
pass them to ResourceManager or call setNotFound() to indicate that the
resource was not found.
You can also implement name() to provide meaningful names for resource keys.
Example implementation for synchronous mesh loader:
@code
class MeshResourceLoader: public AbstractResourceLoader<Mesh> {
public:
void load(ResourceKey key) {
// Indicate that loading has begun
AbstractResourceLoader<Mesh>::load(key);
// Load the mesh...
void doLoad(ResourceKey key) override {
// Load the mesh...
// Not found
if(!found) {
setNotFound(key);
return;
}
// Found, pass it to resource manager
set(key, mesh, state, policy);
// Not found
if(!found) {
setNotFound(key);
return;
}
// Found, pass it to resource manager
set(key, mesh, state, policy);
}
};
@endcode
You can then add it to resource manager instance like this:
You can then add it to resource manager instance like this. Note that the
manager automatically deletes the all loaders on destruction before unloading
all resources. It allows you to use resources in the loader itself without
having to delete the loader explicitly to ensure proper resource unloading. In
the following code, however, the loader destroys itself (and removes itself
from the manager) before the manager is destroyed.
@code
MyResourceManager manager;
MeshResourceLoader loader;
manager->setLoader(loader);
manager->setLoader(&loader);
// This will now automatically request the mesh from loader by calling load()
Resource<Mesh> myMesh = manager->get<Mesh>("my-mesh");
@endcode
@todoc How about working with resources of different data types (i.e. mesh
buffers), should that be allowed?
*/
template<class T> class AbstractResourceLoader {
friend class Implementation::ResourceManagerData<T>;
@ -129,9 +132,9 @@ template<class T> class AbstractResourceLoader {
* @brief %Resource name corresponding to given key
*
* If no such resource exists or the resource name is not available,
* returns empty string. Default implementation returns empty string.
* returns empty string.
*/
virtual std::string name(ResourceKey key) const;
std::string name(ResourceKey key) const { return doName(key); }
/**
* @brief Request resource to be loaded
@ -141,12 +144,10 @@ template<class T> class AbstractResourceLoader {
* requested features is incremented. Depending on implementation the
* resource might be loaded synchronously or asynchronously.
*
* See class documentation for reimplementation guide.
*
* @see ResourceManager::state(), requestedCount(), notFoundCount(),
* loadedCount()
*/
virtual void load(ResourceKey key) = 0;
void load(ResourceKey key);
protected:
/**
@ -160,6 +161,16 @@ template<class T> class AbstractResourceLoader {
*/
void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy);
/**
* @brief Set loaded resource to resource manager
*
* Same as above function with state set to @ref ResourceDataState "ResourceDataState::Final"
* and policy to @ref ResourcePolicy "ResourcePolicy::Resident".
*/
void set(ResourceKey key, T* data) {
set(key, data, ResourceDataState::Final, ResourcePolicy::Resident);
}
/**
* @brief Mark resource as not found
*
@ -169,23 +180,44 @@ template<class T> class AbstractResourceLoader {
*/
void setNotFound(ResourceKey key);
#ifndef DOXYGEN_GENERATING_OUTPUT
private:
#else
protected:
#endif
/**
* @brief Implementation for name()
*
* Default implementation returns empty string.
*/
virtual std::string doName(ResourceKey key) const;
/**
* @brief Implementation for load()
*
* See class documentation for reimplementation guide.
*/
virtual void doLoad(ResourceKey key) = 0;
private:
Implementation::ResourceManagerData<T>* manager;
std::size_t _requestedCount;
std::size_t _loadedCount;
std::size_t _notFoundCount;
std::size_t _requestedCount,
_loadedCount,
_notFoundCount;
};
template<class T> AbstractResourceLoader<T>::~AbstractResourceLoader() {
if(manager) manager->_loader = nullptr;
}
template<class T> std::string AbstractResourceLoader<T>::name(ResourceKey) const { return {}; }
template<class T> std::string AbstractResourceLoader<T>::doName(ResourceKey) const { return {}; }
template<class T> void AbstractResourceLoader<T>::load(ResourceKey key) {
++_requestedCount;
/** @todo What policy for loading resources? */
manager->set(key, nullptr, ResourceDataState::Loading, ResourcePolicy::Resident);
doLoad(key);
}
template<class T> void AbstractResourceLoader<T>::set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) {

14
src/AbstractShaderProgram.cpp

@ -77,7 +77,7 @@ AbstractShaderProgram::UniformMatrix4x3dvImplementation AbstractShaderProgram::u
#endif
Int AbstractShaderProgram::maxSupportedVertexAttributeCount() {
GLint& value = Context::current()->state()->shaderProgram->maxSupportedVertexAttributeCount;
GLint& value = Context::current()->state().shaderProgram->maxSupportedVertexAttributeCount;
/* Get the value, if not already cached */
if(value == 0)
@ -94,7 +94,7 @@ AbstractShaderProgram::AbstractShaderProgram(AbstractShaderProgram&& other) noex
AbstractShaderProgram::~AbstractShaderProgram() {
/* Remove current usage from the state */
GLuint& current = Context::current()->state()->shaderProgram->current;
GLuint& current = Context::current()->state().shaderProgram->current;
if(current == _id) current = 0;
if(_id) glDeleteProgram(_id);
@ -125,7 +125,7 @@ std::pair<bool, std::string> AbstractShaderProgram::validate() {
void AbstractShaderProgram::use() {
/* Use only if the program isn't already in use */
GLuint& current = Context::current()->state()->shaderProgram->current;
GLuint& current = Context::current()->state().shaderProgram->current;
if(current != _id) glUseProgram(current = _id);
}
@ -189,12 +189,12 @@ Int AbstractShaderProgram::uniformLocation(const std::string& name) {
return location;
}
void AbstractShaderProgram::initializeContextBasedFunctionality(Context* context) {
void AbstractShaderProgram::initializeContextBasedFunctionality(Context& context) {
/** @todo OpenGL ES 2 has extension @es_extension{EXT,separate_shader_objects} for this */
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::separate_shader_objects>() ||
context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "AbstractShaderProgram: using" << (context->isExtensionSupported<Extensions::GL::ARB::separate_shader_objects>() ?
if(context.isExtensionSupported<Extensions::GL::ARB::separate_shader_objects>() ||
context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "AbstractShaderProgram: using" << (context.isExtensionSupported<Extensions::GL::ARB::separate_shader_objects>() ?
Extensions::GL::ARB::separate_shader_objects::string() : Extensions::GL::EXT::direct_state_access::string()) << "features";
uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;
uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA;

20
src/AbstractShaderProgram.h

@ -101,13 +101,13 @@ MyShader() {
protected setUniform() functions. For usability purposes you can implement
also method chaining. Example:
@code
MyShader* setTransformation(const Matrix4& matrix) {
MyShader& setTransformation(const Matrix4& matrix) {
setUniform(TransformationUniform, matrix);
return this;
return *this;
}
MyShader* setProjection(const Matrix4& matrix) {
MyShader& setProjection(const Matrix4& matrix) {
setUniform(ProjectionUniform, matrix);
return this;
return *this;
}
@endcode
@ -219,12 +219,12 @@ specific framebuffer (if needed) and bind required textures to their
respective layers using AbstractTexture::bind(Int). Then call Mesh::draw().
Example:
@code
shader->setTransformation(transformation)
->setProjection(projection)
->use();
shader.setTransformation(transformation)
.setProjection(projection)
.use();
diffuseTexture->bind(MyShader::DiffuseTextureLayer);
specularTexture->bind(MyShader::SpecularTextureLayer);
diffuseTexture.bind(MyShader::DiffuseTextureLayer);
specularTexture.bind(MyShader::SpecularTextureLayer);
mesh.draw();
@endcode
@ -774,7 +774,7 @@ class MAGNUM_EXPORT AbstractShaderProgram {
#endif
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
typedef void(AbstractShaderProgram::*Uniform1fvImplementation)(GLint, GLsizei, const GLfloat*);
typedef void(AbstractShaderProgram::*Uniform2fvImplementation)(GLint, GLsizei, const Math::Vector<2, GLfloat>*);

82
src/AbstractTexture.cpp

@ -81,7 +81,7 @@ AbstractTexture::InvalidateImageImplementation AbstractTexture::invalidateImageI
AbstractTexture::InvalidateSubImageImplementation AbstractTexture::invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationNoOp;
Int AbstractTexture::maxSupportedLayerCount() {
return Context::current()->state()->texture->maxSupportedLayerCount;
return Context::current()->state().texture->maxSupportedLayerCount;
}
void AbstractTexture::destroy() {
@ -89,7 +89,7 @@ void AbstractTexture::destroy() {
if(!_id) return;
/* Remove all bindings */
std::vector<GLuint>& bindings = Context::current()->state()->texture->bindings;
std::vector<GLuint>& bindings = Context::current()->state().texture->bindings;
for(auto it = bindings.begin(); it != bindings.end(); ++it)
if(*it == _id) *it = 0;
@ -100,6 +100,10 @@ void AbstractTexture::move() {
_id = 0;
}
AbstractTexture::AbstractTexture(GLenum target): _target(target) {
glGenTextures(1, &_id);
}
AbstractTexture::~AbstractTexture() { destroy(); }
AbstractTexture::AbstractTexture(AbstractTexture&& other): _target(other._target), _id(other._id) {
@ -117,7 +121,7 @@ AbstractTexture& AbstractTexture::operator=(AbstractTexture&& other) {
}
void AbstractTexture::bind(Int layer) {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
Implementation::TextureState* const textureState = Context::current()->state().texture;
/* If already bound in given layer, nothing to do */
if(textureState->bindings[layer] == _id) return;
@ -126,7 +130,7 @@ void AbstractTexture::bind(Int layer) {
}
void AbstractTexture::bindImplementationDefault(GLint layer) {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
Implementation::TextureState* const textureState = Context::current()->state().texture;
/* Change to given layer, if not already there */
if(textureState->currentLayer != layer)
@ -138,27 +142,27 @@ void AbstractTexture::bindImplementationDefault(GLint layer) {
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::bindImplementationDSA(GLint layer) {
glBindMultiTextureEXT(GL_TEXTURE0 + layer, _target, (Context::current()->state()->texture->bindings[layer] = _id));
glBindMultiTextureEXT(GL_TEXTURE0 + layer, _target, (Context::current()->state().texture->bindings[layer] = _id));
}
#endif
AbstractTexture* AbstractTexture::setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap) {
AbstractTexture& AbstractTexture::setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap) {
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Sampler::Mipmap::Base, "AbstractTexture: rectangle textures cannot have mipmaps", this);
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Sampler::Mipmap::Base, "AbstractTexture: rectangle textures cannot have mipmaps", *this);
#endif
(this->*parameteriImplementation)(GL_TEXTURE_MIN_FILTER,
static_cast<GLint>(filter)|static_cast<GLint>(mipmap));
return this;
return *this;
}
AbstractTexture* AbstractTexture::generateMipmap() {
AbstractTexture& AbstractTexture::generateMipmap() {
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE, "AbstractTexture: rectangle textures cannot have mipmaps", this);
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE, "AbstractTexture: rectangle textures cannot have mipmaps", *this);
#endif
(this->*mipmapImplementation)();
return this;
return *this;
}
void AbstractTexture::mipmapImplementationDefault() {
@ -173,7 +177,7 @@ void AbstractTexture::mipmapImplementationDSA() {
#endif
void AbstractTexture::bindInternal() {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
Implementation::TextureState* const textureState = Context::current()->state().texture;
/* If the texture is already bound in current layer, nothing to do */
if(textureState->bindings[textureState->currentLayer] == _id)
@ -189,8 +193,8 @@ void AbstractTexture::bindInternal() {
glBindTexture(_target, (textureState->bindings[internalLayer] = _id));
}
void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
Implementation::TextureState* const textureState = context->state()->texture;
void AbstractTexture::initializeContextBasedFunctionality(Context& context) {
Implementation::TextureState* const textureState = context.state().texture;
GLint& value = textureState->maxSupportedLayerCount;
/* Get the value and resize bindings array */
@ -198,7 +202,7 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
textureState->bindings.resize(value);
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "AbstractTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
bindImplementation = &AbstractTexture::bindImplementationDSA;
@ -216,24 +220,24 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
subImage3DImplementation = &AbstractTexture::subImageImplementationDSA;
}
if(context->isExtensionSupported<Extensions::GL::ARB::invalidate_subdata>()) {
if(context.isExtensionSupported<Extensions::GL::ARB::invalidate_subdata>()) {
Debug() << "AbstractTexture: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features";
invalidateImageImplementation = &AbstractTexture::invalidateImageImplementationARB;
invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationARB;
}
if(context->isExtensionSupported<Extensions::GL::ARB::robustness>() &&
!context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::ARB::robustness>() &&
!context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "AbstractTexture: using" << Extensions::GL::ARB::robustness::string() << "features";
getImageImplementation = &AbstractTexture::getImageImplementationRobustness;
}
if(context->isExtensionSupported<Extensions::GL::ARB::texture_storage>()) {
if(context.isExtensionSupported<Extensions::GL::ARB::texture_storage>()) {
Debug() << "AbstractTexture: using" << Extensions::GL::ARB::texture_storage::string() << "features";
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
storage1DImplementation = &AbstractTexture::storageImplementationDSA;
storage2DImplementation = &AbstractTexture::storageImplementationDSA;
storage3DImplementation = &AbstractTexture::storageImplementationDSA;
@ -424,6 +428,11 @@ ImageFormat AbstractTexture::imageFormatForInternalFormat(const TextureFormat in
#endif
return ImageFormat::DepthComponent;
#ifndef MAGNUM_TARGET_GLES
case TextureFormat::StencilIndex8:
return ImageFormat::StencilIndex;
#endif
case TextureFormat::DepthStencil:
case TextureFormat::Depth24Stencil8:
#ifndef MAGNUM_TARGET_GLES2
@ -606,6 +615,11 @@ ImageType AbstractTexture::imageTypeForInternalFormat(const TextureFormat intern
return ImageType::Float;
#endif
#ifndef MAGNUM_TARGET_GLES
case TextureFormat::StencilIndex8:
return ImageType::UnsignedByte;
#endif
case TextureFormat::DepthStencil:
case TextureFormat::Depth24Stencil8:
return ImageType::UnsignedInt248;
@ -713,7 +727,7 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G
levelSize = Math::max(Vector2i(1), levelSize/2);
}
/* Cube map additionaly needs to specify all faces */
/* Cube map additionally needs to specify all faces */
} else if(target == GL_TEXTURE_CUBE_MAP) {
Vector2i levelSize = size;
for(GLsizei level = 0; level != levels; ++level) {
@ -961,9 +975,9 @@ template<UnsignedInt dimensions> void AbstractTexture::image(GLenum target, GLin
image.setData(image.format(), image.type(), size, data);
}
template void AbstractTexture::image<1>(GLenum, GLint, Image<1>&);
template void AbstractTexture::image<2>(GLenum, GLint, Image<2>&);
template void AbstractTexture::image<3>(GLenum, GLint, Image<3>&);
template void MAGNUM_EXPORT AbstractTexture::image<1>(GLenum, GLint, Image<1>&);
template void MAGNUM_EXPORT AbstractTexture::image<2>(GLenum, GLint, Image<2>&);
template void MAGNUM_EXPORT AbstractTexture::image<3>(GLenum, GLint, Image<3>&);
template<UnsignedInt dimensions> void AbstractTexture::image(GLenum target, GLint level, BufferImage<dimensions>& image, Buffer::Usage usage) {
const Math::Vector<dimensions, Int> size = DataHelper<dimensions>::imageSize(this, target, level);
@ -971,13 +985,13 @@ template<UnsignedInt dimensions> void AbstractTexture::image(GLenum target, GLin
if(image.size() != size)
image.setData(size, image.format(), image.type(), nullptr, usage);
image.buffer()->bind(Buffer::Target::PixelPack);
image.buffer().bind(Buffer::Target::PixelPack);
(this->*getImageImplementation)(target, level, image.format(), image.type(), dataSize, nullptr);
}
template void AbstractTexture::image<1>(GLenum, GLint, BufferImage<1>&, Buffer::Usage);
template void AbstractTexture::image<2>(GLenum, GLint, BufferImage<2>&, Buffer::Usage);
template void AbstractTexture::image<3>(GLenum, GLint, BufferImage<3>&, Buffer::Usage);
template void MAGNUM_EXPORT AbstractTexture::image<1>(GLenum, GLint, BufferImage<1>&, Buffer::Usage);
template void MAGNUM_EXPORT AbstractTexture::image<2>(GLenum, GLint, BufferImage<2>&, Buffer::Usage);
template void MAGNUM_EXPORT AbstractTexture::image<3>(GLenum, GLint, BufferImage<3>&, Buffer::Usage);
#endif
#endif
@ -1012,7 +1026,7 @@ void AbstractTexture::DataHelper<1>::setImage(AbstractTexture* const texture, co
}
void AbstractTexture::DataHelper<1>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage1D& image) {
image.buffer()->bind(Buffer::Target::PixelUnpack);
image.buffer().bind(Buffer::Target::PixelUnpack);
(texture->*image1DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr);
}
@ -1022,7 +1036,7 @@ void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture* const texture,
}
void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Math::Vector<1, GLint>& offset, BufferImage1D& image) {
image.buffer()->bind(Buffer::Target::PixelUnpack);
image.buffer().bind(Buffer::Target::PixelUnpack);
(texture->*subImage1DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr);
}
#endif
@ -1036,7 +1050,7 @@ void AbstractTexture::DataHelper<2>::setImage(AbstractTexture* const texture, co
#ifndef MAGNUM_TARGET_GLES2
void AbstractTexture::DataHelper<2>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage2D& image) {
image.buffer()->bind(Buffer::Target::PixelUnpack);
image.buffer().bind(Buffer::Target::PixelUnpack);
(texture->*image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr);
}
#endif
@ -1050,7 +1064,7 @@ void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture* const texture,
#ifndef MAGNUM_TARGET_GLES2
void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Vector2i& offset, BufferImage2D& image) {
image.buffer()->bind(Buffer::Target::PixelUnpack);
image.buffer().bind(Buffer::Target::PixelUnpack);
(texture->*subImage2DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr);
}
#endif
@ -1064,7 +1078,7 @@ void AbstractTexture::DataHelper<3>::setImage(AbstractTexture* const texture, co
#ifndef MAGNUM_TARGET_GLES2
void AbstractTexture::DataHelper<3>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage3D& image) {
image.buffer()->bind(Buffer::Target::PixelUnpack);
image.buffer().bind(Buffer::Target::PixelUnpack);
(texture->*image3DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr);
}
#endif
@ -1078,7 +1092,7 @@ void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture* const texture,
#ifndef MAGNUM_TARGET_GLES2
void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Vector3i& offset, BufferImage3D& image) {
image.buffer()->bind(Buffer::Target::PixelUnpack);
image.buffer().bind(Buffer::Target::PixelUnpack);
(texture->*subImage3DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr);
}
#endif

59
src/AbstractTexture.h

@ -112,20 +112,6 @@ class MAGNUM_EXPORT AbstractTexture {
*/
static Int maxSupportedLayerCount();
#ifndef DOXYGEN_GENERATING_OUTPUT
explicit AbstractTexture(GLenum target): _target(target) {
glGenTextures(1, &_id);
}
#endif
/**
* @brief Destructor
*
* Deletes assigned OpenGL texture.
* @see @fn_gl{DeleteTextures}
*/
virtual ~AbstractTexture() = 0;
/** @brief Copying is not allowed */
AbstractTexture(const AbstractTexture&) = delete;
@ -160,7 +146,7 @@ class MAGNUM_EXPORT AbstractTexture {
* @param mipmap Mipmap filtering. If set to anything else than
* BaseMipLevel, make sure textures for all mip levels are set or
* call generateMipmap().
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Sets filter used when the object pixel size is smaller than the
* texture size. If @extension{EXT,direct_state_access} is not
@ -174,12 +160,12 @@ class MAGNUM_EXPORT AbstractTexture {
* or @fn_gl_extension{TextureParameter,EXT,direct_state_access}
* with @def_gl{TEXTURE_MIN_FILTER}
*/
AbstractTexture* setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base);
AbstractTexture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base);
/**
* @brief Set magnification filter
* @param filter Filter
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Sets filter used when the object pixel size is larger than largest
* texture size. If @extension{EXT,direct_state_access} is not
@ -189,15 +175,15 @@ class MAGNUM_EXPORT AbstractTexture {
* or @fn_gl_extension{TextureParameter,EXT,direct_state_access}
* with @def_gl{TEXTURE_MAG_FILTER}
*/
AbstractTexture* setMagnificationFilter(Sampler::Filter filter) {
AbstractTexture& setMagnificationFilter(Sampler::Filter filter) {
(this->*parameteriImplementation)(GL_TEXTURE_MAG_FILTER, static_cast<GLint>(filter));
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES3
/**
* @brief Set border color
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Border color when wrapping is set to @ref Sampler::Wrapping "Sampler::Wrapping::ClampToBorder".
* If @extension{EXT,direct_state_access} is not available, the texture
@ -208,18 +194,18 @@ class MAGNUM_EXPORT AbstractTexture {
* with @def_gl{TEXTURE_BORDER_COLOR}
* @requires_es_extension %Extension @es_extension{NV,texture_border_clamp}
*/
AbstractTexture* setBorderColor(const Color4& color) {
AbstractTexture& setBorderColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES
(this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data());
#else
(this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR_NV, color.data());
#endif
return this;
return *this;
}
/**
* @brief Set max anisotropy
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default value is `1.0f`, which means no anisotropy. Set to value
* greater than `1.0f` for anisotropic filtering. If
@ -232,9 +218,9 @@ class MAGNUM_EXPORT AbstractTexture {
* @requires_extension %Extension @extension{EXT,texture_filter_anisotropic}
* @requires_es_extension %Extension @es_extension2{EXT,texture_filter_anisotropic,texture_filter_anisotropic}
*/
AbstractTexture* setMaxAnisotropy(Float anisotropy) {
AbstractTexture& setMaxAnisotropy(Float anisotropy) {
(this->*parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
return this;
return *this;
}
#endif
@ -253,7 +239,7 @@ class MAGNUM_EXPORT AbstractTexture {
/**
* @brief Generate mipmap
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Can not be used for rectangle textures. If
* @extension{EXT,direct_state_access} is not available, the texture
@ -263,7 +249,24 @@ class MAGNUM_EXPORT AbstractTexture {
* @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access}
* @requires_gl30 %Extension @extension{ARB,framebuffer_object}
*/
AbstractTexture* generateMipmap();
AbstractTexture& generateMipmap();
protected:
/**
* @brief Constructor
*
* Creates new OpenGL texture.
* @see @fn_gl{GenTextures}
*/
explicit AbstractTexture(GLenum target);
/**
* @brief Destructor
*
* Deletes assigned OpenGL texture.
* @see @fn_gl{DeleteTextures}
*/
~AbstractTexture();
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
@ -283,7 +286,7 @@ class MAGNUM_EXPORT AbstractTexture {
GLenum _target;
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
typedef void(AbstractTexture::*BindImplementation)(GLint);
void MAGNUM_LOCAL bindImplementationDefault(GLint layer);

44
src/Array.h

@ -29,8 +29,8 @@
*/
#include <type_traits>
#include <Utility/Debug.h>
#include "Math/BoolVector.h" /* for Math::Implementation::Sequence */
#include "Magnum.h"
namespace Magnum {
@ -48,12 +48,12 @@ Math::Vector this class has non-explicit constructor from one value.
template<UnsignedInt dimensions, class T> class Array {
public:
typedef T Type; /**< @brief Data type */
const static UnsignedInt Dimensions = dimensions; /**< @brief Dimension count */
const static UnsignedInt Dimensions = dimensions; /**< @brief Dimension count */
/**
* @brief Default constructor
*
* Sets all components to their default-constructed values
* Sets all components to their default-constructed values.
*/
constexpr /*implicit*/ Array(): _data() {}
@ -62,23 +62,24 @@ template<UnsignedInt dimensions, class T> class Array {
* @param first First value
* @param next Next values
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> constexpr /*implicit*/ Array(T first, T second, U... next): _data{first, second, next...} {
static_assert(sizeof...(next)+2 == dimensions, "Improper number of arguments passed to Array constructor");
}
template<class U = T> constexpr /*implicit*/ Array(typename std::enable_if<std::is_same<T, U>::value && dimensions == 1, U>::type first): _data{first} {}
#else
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class ...U> constexpr /*implicit*/ Array(T first, U... next);
#else
template<class ...U, class V = typename std::enable_if<sizeof...(U)+1 == dimensions, T>::type> constexpr /*implicit*/ Array(T first, U... next): _data{first, next...} {}
#endif
/**
* @brief Constructor
* @param value Value for all fields
*/
template<class U, class = typename std::enable_if<std::is_same<T, U>::value && dimensions != 1, U>::type> /*implicit*/ Array(U value) {
for(UnsignedInt i = 0; i != dimensions; ++i)
_data[i] = value;
/** @brief Construct array with one value for all fields */
#ifdef DOXYGEN_GENERATING_OUTPUT
constexpr /*implicit*/ Array(T value);
#else
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class U, class V = typename std::enable_if<std::is_same<T, U>::value && dimensions != 1, T>::type> constexpr /*implicit*/ Array(U value): Array(typename Math::Implementation::GenerateSequence<dimensions>::Type(), value) {}
#else
template<class U, class V = typename std::enable_if<std::is_same<T, U>::value && dimensions != 1, T>::type> /*implicit*/ Array(U value) {
*this = Array(typename Math::Implementation::GenerateSequence<dimensions>::Type(), value);
}
#endif
#endif
/** @brief Equality */
bool operator==(const Array<dimensions, T>& other) const {
@ -104,6 +105,10 @@ template<UnsignedInt dimensions, class T> class Array {
constexpr const T* data() const { return _data; } /**< @overload */
private:
/* Implementation for Array<dimensions, T>::Array(U) */
template<std::size_t ...sequence> constexpr explicit Array(Math::Implementation::Sequence<sequence...>, T value): _data{Math::Implementation::repeat(value, sequence)...} {}
T _data[dimensions];
};
@ -186,6 +191,13 @@ template<class T> class Array3D: public Array<3, T> {
constexpr T y() const { return (*this)[1]; } /**< @overload */
T& z() { return (*this)[2]; } /**< @brief Z component */
constexpr T z() const { return (*this)[2]; } /**< @overload */
/**
* @brief XY part of the array
* @return First two components of the array
*/
Array2D<T>& xy() { return reinterpret_cast<Array2D<T>&>(*this); }
constexpr Array2D<T> xy() const { return {(*this)[0], (*this)[1]}; } /**< @overload */
};
/** @debugoperator{Magnum::Array} */

20
src/Buffer.cpp

@ -51,9 +51,9 @@ Buffer::MapRangeImplementation Buffer::mapRangeImplementation = &Buffer::mapRang
Buffer::FlushMappedRangeImplementation Buffer::flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDefault;
Buffer::UnmapImplementation Buffer::unmapImplementation = &Buffer::unmapImplementationDefault;
void Buffer::initializeContextBasedFunctionality(Context* context) {
void Buffer::initializeContextBasedFunctionality(Context& context) {
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "Buffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
copyImplementation = &Buffer::copyImplementationDSA;
@ -67,7 +67,7 @@ void Buffer::initializeContextBasedFunctionality(Context* context) {
unmapImplementation = &Buffer::unmapImplementationDSA;
}
if(context->isExtensionSupported<Extensions::GL::ARB::invalidate_subdata>()) {
if(context.isExtensionSupported<Extensions::GL::ARB::invalidate_subdata>()) {
Debug() << "Buffer: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features";
invalidateImplementation = &Buffer::invalidateImplementationARB;
@ -87,7 +87,7 @@ Buffer::Buffer(Buffer::Target targetHint): _targetHint(targetHint)
}
Buffer::~Buffer() {
GLuint* bindings = Context::current()->state()->buffer->bindings;
GLuint* bindings = Context::current()->state().buffer->bindings;
/* Remove all current bindings from the state */
for(std::size_t i = 1; i != Implementation::BufferState::TargetCount; ++i)
@ -97,7 +97,7 @@ Buffer::~Buffer() {
}
void Buffer::bind(Target target, GLuint id) {
GLuint& bound = Context::current()->state()->buffer->bindings[Implementation::BufferState::indexForTarget(target)];
GLuint& bound = Context::current()->state().buffer->bindings[Implementation::BufferState::indexForTarget(target)];
/* Already bound, nothing to do */
if(bound == id) return;
@ -108,7 +108,7 @@ void Buffer::bind(Target target, GLuint id) {
}
Buffer::Target Buffer::bindInternal(Target hint) {
GLuint* bindings = Context::current()->state()->buffer->bindings;
GLuint* bindings = Context::current()->state().buffer->bindings;
GLuint& hintBinding = bindings[Implementation::BufferState::indexForTarget(hint)];
/* Shortcut - if already bound to hint, return */
@ -161,13 +161,13 @@ void Buffer::unmapSub() {
#endif
#ifndef MAGNUM_TARGET_GLES2
void Buffer::copyImplementationDefault(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
glCopyBufferSubData(static_cast<GLenum>(read->bindInternal(Target::CopyRead)), static_cast<GLenum>(write->bindInternal(Target::CopyWrite)), readOffset, writeOffset, size);
void Buffer::copyImplementationDefault(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
glCopyBufferSubData(static_cast<GLenum>(read.bindInternal(Target::CopyRead)), static_cast<GLenum>(write.bindInternal(Target::CopyWrite)), readOffset, writeOffset, size);
}
#ifndef MAGNUM_TARGET_GLES
void Buffer::copyImplementationDSA(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
glNamedCopyBufferSubDataEXT(read->_id, write->_id, readOffset, writeOffset, size);
void Buffer::copyImplementationDSA(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
glNamedCopyBufferSubDataEXT(read._id, write._id, readOffset, writeOffset, size);
}
#endif
#endif

81
src/Buffer.h

@ -119,7 +119,7 @@ OpenGL in order to preserve the data. If running on OpenGL ES or extension
@extension{ARB,invalidate_subdata} is not available, these functions do
nothing.
@todo Support for AMD's query buffer (@extension{AMD,query_buffer_object})
@todo Support for AMD/ARB's query buffer (@extension{AMD,query_buffer_object}, @extension{ARB,query_buffer_object})
@todo BindBufferRange/BindBufferOffset/BindBufferBase for transform feedback (3.0, @extension{EXT,transform_feedback})
*/
class MAGNUM_EXPORT Buffer {
@ -459,7 +459,7 @@ class MAGNUM_EXPORT Buffer {
* @requires_gl31 %Extension @extension{ARB,copy_buffer}
* @requires_gles30 %Buffer copying is not available in OpenGL ES 2.0.
*/
static void copy(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
static void copy(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
copyImplementation(read, write, readOffset, writeOffset, size);
}
#endif
@ -480,7 +480,7 @@ class MAGNUM_EXPORT Buffer {
* Deletes associated OpenGL buffer.
* @see @fn_gl{DeleteBuffers}
*/
virtual ~Buffer();
~Buffer();
/** @brief OpenGL buffer ID */
GLuint id() const { return _id; }
@ -490,7 +490,7 @@ class MAGNUM_EXPORT Buffer {
/**
* @brief Set target hint
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available, the buffer
* must be internally bound to some target before any operation. You
@ -503,9 +503,9 @@ class MAGNUM_EXPORT Buffer {
* http://www.opengl.org/wiki/Vertex_Specification#Index_buffers
* ... damned GL state
*/
Buffer* setTargetHint(Target hint) {
Buffer& setTargetHint(Target hint) {
_targetHint = hint;
return this;
return *this;
}
/**
@ -569,7 +569,7 @@ class MAGNUM_EXPORT Buffer {
* @param size Data size
* @param data Pointer to data
* @param usage %Buffer usage
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* buffer is not already bound somewhere, it is bound to hinted target
@ -577,25 +577,25 @@ class MAGNUM_EXPORT Buffer {
* @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferData} or
* @fn_gl_extension{NamedBufferData,EXT,direct_state_access}
*/
Buffer* setData(GLsizeiptr size, const GLvoid* data, Usage usage) {
Buffer& setData(GLsizeiptr size, const GLvoid* data, Usage usage) {
(this->*dataImplementation)(size, data, usage);
return this;
return *this;
}
/**
* @brief Set buffer data
* @param data Fixed-size array with data
* @param usage %Buffer usage
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* @see setData(GLsizeiptr, const GLvoid*, Usage).
*/
#ifdef CORRADE_GCC46_COMPATIBILITY
#define size size_ /* With GCC 4.6 it conflicts with size(). WTF. */
#endif
template<std::size_t size, class T> Buffer* setData(const T(&data)[size], Usage usage) {
template<std::size_t size, class T> Buffer& setData(const T(&data)[size], Usage usage) {
setData(size*sizeof(T), data, usage);
return this;
return *this;
}
#ifdef CORRADE_GCC46_COMPATIBILITY
#undef size
@ -605,18 +605,19 @@ class MAGNUM_EXPORT Buffer {
* @brief Set buffer data
* @param data Vector with data
* @param usage %Buffer usage
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* @see setData(GLsizeiptr, const GLvoid*, Usage)
*/
template<class T> Buffer* setData(const std::vector<T>& data, Usage usage) {
template<class T> Buffer& setData(const std::vector<T>& data, Usage usage) {
setData(data.size()*sizeof(T), data.data(), usage);
return this;
return *this;
}
/** @overload */
template<std::size_t size, class T> void setData(const std::array<T, size>& data, Usage usage) {
template<std::size_t size, class T> Buffer& setData(const std::array<T, size>& data, Usage usage) {
setData(data.size()*sizeof(T), data.data(), usage);
return *this;
}
/**
@ -624,7 +625,7 @@ class MAGNUM_EXPORT Buffer {
* @param offset Offset in the buffer
* @param size Data size
* @param data Pointer to data
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* buffer is not already bound somewhere, it is bound to hinted target
@ -632,25 +633,25 @@ class MAGNUM_EXPORT Buffer {
* @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferSubData}
* or @fn_gl_extension{NamedBufferSubData,EXT,direct_state_access}
*/
Buffer* setSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
Buffer& setSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) {
(this->*subDataImplementation)(offset, size, data);
return this;
return *this;
}
/**
* @brief Set buffer subdata
* @param offset Offset in the buffer
* @param data Fixed-size array with data
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* @see setSubData(GLintptr, GLsizeiptr, const GLvoid*)
*/
#ifdef CORRADE_GCC46_COMPATIBILITY
#define size size_ /* With GCC 4.6 it conflicts with size(). WTF. */
#endif
template<std::size_t size, class T> Buffer* setSubData(GLintptr offset, const T(&data)[size]) {
template<std::size_t size, class T> Buffer& setSubData(GLintptr offset, const T(&data)[size]) {
setSubData(offset, size*sizeof(T), data);
return this;
return *this;
}
#ifdef CORRADE_GCC46_COMPATIBILITY
#undef size
@ -660,48 +661,48 @@ class MAGNUM_EXPORT Buffer {
* @brief Set buffer subdata
* @param offset Offset in the buffer
* @param data Vector with data
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* @see setSubData(GLintptr, GLsizeiptr, const GLvoid*)
*/
template<class T> Buffer* setSubData(GLintptr offset, const std::vector<T>& data) {
template<class T> Buffer& setSubData(GLintptr offset, const std::vector<T>& data) {
setSubData(offset, data.size()*sizeof(T), data.data());
return this;
return *this;
}
/** @overload */
template<std::size_t size, class T> Buffer* setSubData(GLintptr offset, const std::array<T, size>& data) {
template<std::size_t size, class T> Buffer& setSubData(GLintptr offset, const std::array<T, size>& data) {
setSubData(offset, data.size()*sizeof(T), data.data());
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Invalidate buffer data
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If running on OpenGL ES or extension @extension{ARB,invalidate_subdata}
* is not available, this function does nothing.
* @see @ref MapFlag "MapFlag::InvalidateBuffer", @fn_gl{InvalidateBufferData}
*/
Buffer* invalidateData() {
Buffer& invalidateData() {
(this->*invalidateImplementation)();
return this;
return *this;
}
/**
* @brief Invalidate buffer subdata
* @param offset Offset into the buffer
* @param length Length of the invalidated range
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If running on OpenGL ES or extension @extension{ARB,invalidate_subdata}
* is not available, this function does nothing.
* @see @ref MapFlag "MapFlag::InvalidateRange", @fn_gl{InvalidateBufferData}
*/
Buffer* invalidateSubData(GLintptr offset, GLsizeiptr length) {
Buffer& invalidateSubData(GLintptr offset, GLsizeiptr length) {
(this->*invalidateSubImplementation)(offset, length);
return this;
return *this;
}
#endif
@ -772,7 +773,7 @@ class MAGNUM_EXPORT Buffer {
* @brief Flush mapped range
* @param offset Offset relative to start of mapped range
* @param length Length of the flushed memory
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Flushes specified subsection of mapped range. Use only if you called
* map() with @ref MapFlag "MapFlag::FlushExplicit" flag. See
@ -786,9 +787,9 @@ class MAGNUM_EXPORT Buffer {
* @requires_gl30 %Extension @extension{ARB,map_buffer_range}
* @requires_gles30 %Extension @es_extension{EXT,map_buffer_range}
*/
Buffer* flushMappedRange(GLintptr offset, GLsizeiptr length) {
Buffer& flushMappedRange(GLintptr offset, GLsizeiptr length) {
(this->*flushMappedRangeImplementation)(offset, length);
return this;
return *this;
}
/**
@ -825,16 +826,16 @@ class MAGNUM_EXPORT Buffer {
#endif
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
static void bind(Target hint, GLuint id);
Target MAGNUM_LOCAL bindInternal(Target hint);
#ifndef MAGNUM_TARGET_GLES2
typedef void(*CopyImplementation)(Buffer*, Buffer*, GLintptr, GLintptr, GLsizeiptr);
static void MAGNUM_LOCAL copyImplementationDefault(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
typedef void(*CopyImplementation)(Buffer&, Buffer&, GLintptr, GLintptr, GLsizeiptr);
static void MAGNUM_LOCAL copyImplementationDefault(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
#ifndef MAGNUM_TARGET_GLES
static void MAGNUM_LOCAL copyImplementationDSA(Buffer* read, Buffer* write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
static void MAGNUM_LOCAL copyImplementationDSA(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
#endif
static CopyImplementation copyImplementation;
#endif

2
src/BufferImage.h

@ -66,7 +66,7 @@ template<UnsignedInt dimensions> class MAGNUM_EXPORT BufferImage: public Abstrac
typename DimensionTraits<Dimensions, Int>::VectorType size() const { return _size; }
/** @brief %Image buffer */
Buffer* buffer() { return &_buffer; }
Buffer& buffer() { return _buffer; }
/**
* @brief Set image data

20
src/BufferTexture.cpp

@ -34,8 +34,8 @@ namespace Magnum {
BufferTexture::SetBufferImplementation BufferTexture::setBufferImplementation = &BufferTexture::setBufferImplementationDefault;
BufferTexture::SetBufferRangeImplementation BufferTexture::setBufferRangeImplementation = &BufferTexture::setBufferRangeImplementationDefault;
void BufferTexture::initializeContextBasedFunctionality(Context* context) {
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
void BufferTexture::initializeContextBasedFunctionality(Context& context) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "BufferTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
setBufferImplementation = &BufferTexture::setBufferImplementationDSA;
@ -43,22 +43,22 @@ void BufferTexture::initializeContextBasedFunctionality(Context* context) {
}
}
void BufferTexture::setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer) {
void BufferTexture::setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer) {
bindInternal();
glTexBuffer(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id());
glTexBuffer(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer.id());
}
void BufferTexture::setBufferImplementationDSA(BufferTextureFormat internalFormat, Buffer* buffer) {
glTextureBufferEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id());
void BufferTexture::setBufferImplementationDSA(BufferTextureFormat internalFormat, Buffer& buffer) {
glTextureBufferEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer.id());
}
void BufferTexture::setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) {
void BufferTexture::setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size) {
bindInternal();
glTexBufferRange(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id(), offset, size);
glTexBufferRange(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer.id(), offset, size);
}
void BufferTexture::setBufferRangeImplementationDSA(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) {
glTextureBufferRangeEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer->id(), offset, size);
void BufferTexture::setBufferRangeImplementationDSA(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size) {
glTextureBufferRangeEXT(id(), GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer.id(), offset, size);
}
}

25
src/BufferTexture.h

@ -164,12 +164,13 @@ using setBuffer(), you can fill the buffer at any time using data setting
functions in Buffer itself.
Note that the buffer is not managed (e.g. deleted on destruction) by the
texture, so you have to manage it on your own. On the other hand it allows you
to use one buffer for more textures or store more than one data in it.
texture, so you have to manage it on your own and ensure that it is available
for whole texture lifetime. On the other hand it allows you to use one buffer
for more textures or store more than one data in it.
Example usage:
@code
Buffer* buffer;
Buffer buffer;
BufferTexture texture;
texture.setBuffer(BufferTextureFormat::RGB32F, buffer);
@ -221,7 +222,7 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture {
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer}
* or @fn_gl_extension{TextureBuffer,EXT,direct_state_access}
*/
void setBuffer(BufferTextureFormat internalFormat, Buffer* buffer) {
void setBuffer(BufferTextureFormat internalFormat, Buffer& buffer) {
(this->*setBufferImplementation)(internalFormat, buffer);
}
@ -239,21 +240,21 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture {
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBufferRange}
* or @fn_gl_extension{TextureBufferRange,EXT,direct_state_access}
*/
void setBuffer(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size) {
void setBuffer(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size) {
(this->*setBufferRangeImplementation)(internalFormat, buffer, offset, size);
}
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
typedef void(BufferTexture::*SetBufferImplementation)(BufferTextureFormat, Buffer*);
void MAGNUM_LOCAL setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer);
void MAGNUM_LOCAL setBufferImplementationDSA(BufferTextureFormat internalFormat, Buffer* buffer);
typedef void(BufferTexture::*SetBufferImplementation)(BufferTextureFormat, Buffer&);
void MAGNUM_LOCAL setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer);
void MAGNUM_LOCAL setBufferImplementationDSA(BufferTextureFormat internalFormat, Buffer& buffer);
static SetBufferImplementation setBufferImplementation;
typedef void(BufferTexture::*SetBufferRangeImplementation)(BufferTextureFormat, Buffer*, GLintptr, GLsizeiptr);
void MAGNUM_LOCAL setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size);
void MAGNUM_LOCAL setBufferRangeImplementationDSA(BufferTextureFormat internalFormat, Buffer* buffer, GLintptr offset, GLsizeiptr size);
typedef void(BufferTexture::*SetBufferRangeImplementation)(BufferTextureFormat, Buffer&, GLintptr, GLsizeiptr);
void MAGNUM_LOCAL setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size);
void MAGNUM_LOCAL setBufferRangeImplementationDSA(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size);
static SetBufferRangeImplementation setBufferRangeImplementation;
};

8
src/CMakeLists.txt

@ -81,7 +81,8 @@ set(Magnum_SRCS
Trade/ObjectData2D.cpp
Trade/ObjectData3D.cpp
Trade/PhongMaterialData.cpp
Trade/SceneData.cpp)
Trade/SceneData.cpp
Trade/TextureData.cpp)
# Desktop-only code
if(NOT TARGET_GLES)
@ -156,7 +157,8 @@ set(MagnumMath_SRCS
# TODO: fix when CMake sets target_EXPORTS for OBJECT targets as well
add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS})
add_library(MagnumObjects OBJECT ${Magnum_SRCS})
set_target_properties(MagnumObjects MagnumMathObjects PROPERTIES COMPILE_FLAGS "-DMagnumObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
set_target_properties(MagnumMathObjects PROPERTIES COMPILE_FLAGS "-DMagnumMathObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
set_target_properties(MagnumObjects PROPERTIES COMPILE_FLAGS "-DMagnumObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
# Main library
add_library(Magnum ${SHARED_OR_STATIC}
@ -164,7 +166,7 @@ add_library(Magnum ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumMathObjects>)
if(BUILD_STATIC_PIC)
# TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property
set_target_properties(Magnum PROPERTIES COMPILE_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS})
set_target_properties(Magnum PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
endif()
set(Magnum_LIBS
${CORRADE_UTILITY_LIBRARY}

38
src/Context.cpp

@ -61,6 +61,7 @@ Debug operator<<(Debug debug, Version value) {
_c(GL410, "OpenGL 4.1")
_c(GL420, "OpenGL 4.2")
_c(GL430, "OpenGL 4.3")
_c(GL440, "OpenGL 4.4")
#else
_c(GLES200, "OpenGL ES 2.0")
_c(GLES300, "OpenGL ES 3.0")
@ -81,7 +82,9 @@ const std::vector<Extension>& Extension::extensions(Version version) {
_extension(GL,AMD,vertex_shader_layer), // done
_extension(GL,AMD,shader_trinary_minmax), // done
_extension(GL,ARB,robustness), // done
_extension(GL,ATI,texture_mirror_once),
_extension(GL,EXT,texture_filter_anisotropic), // done
_extension(GL,EXT,texture_mirror_clamp),
_extension(GL,EXT,direct_state_access),
_extension(GL,GREMEDY,string_marker)}; // done
static const std::vector<Extension> extensions300{
@ -195,6 +198,15 @@ const std::vector<Extension>& Extension::extensions(Version version) {
_extension(GL,ARB,texture_storage_multisample),
_extension(GL,ARB,texture_view),
_extension(GL,ARB,vertex_attrib_binding)};
static const std::vector<Extension> extensions440{
_extension(GL,ARB,buffer_storage),
_extension(GL,ARB,clear_texture),
_extension(GL,ARB,enhanced_layouts),
_extension(GL,ARB,multi_bind),
_extension(GL,ARB,query_buffer_object),
_extension(GL,ARB,texture_mirror_clamp_to_edge),
_extension(GL,ARB,texture_stencil8),
_extension(GL,ARB,vertex_type_10f_11f_11f_rev)};
#undef _extension
#else
static const std::vector<Extension> extensions{
@ -271,13 +283,14 @@ const std::vector<Extension>& Extension::extensions(Version version) {
case Version::GL420: return extensions420;
/* case Version::GLES300: */
case Version::GL430: return extensions430;
case Version::GL440: return extensions440;
#else
case Version::GLES200: return empty;
case Version::GLES300: return extensionsES300;
#endif
}
return empty;
CORRADE_ASSERT_UNREACHABLE();
}
Context* Context::_current = nullptr;
@ -322,6 +335,7 @@ Context::Context() {
Version::GL410,
Version::GL420,
Version::GL430,
Version::GL440,
#else
Version::GLES200,
Version::GLES300,
@ -395,19 +409,19 @@ Context::Context() {
_state = new Implementation::State;
/* Initialize functionality based on current OpenGL version and extensions */
AbstractFramebuffer::initializeContextBasedFunctionality(this);
AbstractShaderProgram::initializeContextBasedFunctionality(this);
AbstractTexture::initializeContextBasedFunctionality(this);
Buffer::initializeContextBasedFunctionality(this);
AbstractFramebuffer::initializeContextBasedFunctionality(*this);
AbstractShaderProgram::initializeContextBasedFunctionality(*this);
AbstractTexture::initializeContextBasedFunctionality(*this);
Buffer::initializeContextBasedFunctionality(*this);
#ifndef MAGNUM_TARGET_GLES
BufferTexture::initializeContextBasedFunctionality(this);
BufferTexture::initializeContextBasedFunctionality(*this);
#endif
DebugMarker::initializeContextBasedFunctionality(this);
DefaultFramebuffer::initializeContextBasedFunctionality(this);
Framebuffer::initializeContextBasedFunctionality(this);
Mesh::initializeContextBasedFunctionality(this);
Renderbuffer::initializeContextBasedFunctionality(this);
Renderer::initializeContextBasedFunctionality(this);
DebugMarker::initializeContextBasedFunctionality(*this);
DefaultFramebuffer::initializeContextBasedFunctionality(*this);
Framebuffer::initializeContextBasedFunctionality(*this);
Mesh::initializeContextBasedFunctionality(*this);
Renderbuffer::initializeContextBasedFunctionality(*this);
Renderer::initializeContextBasedFunctionality(*this);
}
Context::~Context() {

5
src/Context.h

@ -59,6 +59,7 @@ enum class Version: Int {
GL410 = 410, /**< @brief OpenGL 4.1, GLSL 4.10 */
GL420 = 420, /**< @brief OpenGL 4.2, GLSL 4.20 */
GL430 = 430, /**< @brief OpenGL 4.3, GLSL 4.30 */
GL440 = 440, /**< @brief OpenGL 4.4, GLSL 4.40 */
#endif
/**
@ -358,7 +359,7 @@ class MAGNUM_EXPORT Context {
}
#ifndef DOXYGEN_GENERATING_OUTPUT
Implementation::State* state() { return _state; }
Implementation::State& state() { return *_state; }
#endif
private:
@ -369,7 +370,7 @@ class MAGNUM_EXPORT Context {
Int _minorVersion;
Flags _flags;
std::bitset<128> extensionStatus;
std::bitset<160> extensionStatus;
std::vector<Extension> _supportedExtensions;
Implementation::State* _state;

54
src/CubeMapTexture.h

@ -60,9 +60,9 @@ Image2D positiveX({256, 256}, ImageFormat::RGBA, ImageType::UnsignedByte, dataPo
CubeMapTexture texture;
texture.setMagnificationFilter(Sampler::Filter::Linear)
// ...
->setStorage(Math::log2(256)+1, TextureFormat::RGBA8, {256, 256})
->setSubImage(CubeMapTexture::Coordinate::PositiveX, 0, {}, &positiveX)
->setSubImage(CubeMapTexture::Coordinate::NegativeX, 0, {}, &negativeX)
.setStorage(Math::log2(256)+1, TextureFormat::RGBA8, {256, 256})
.setSubImage(CubeMapTexture::Coordinate::PositiveX, 0, {}, positiveX)
.setSubImage(CubeMapTexture::Coordinate::NegativeX, 0, {}, negativeX)
// ...
@endcode
@ -101,9 +101,9 @@ class CubeMapTexture: public AbstractTexture {
*
* See Texture::setWrapping() for more information.
*/
CubeMapTexture* setWrapping(const Array3D<Sampler::Wrapping>& wrapping) {
CubeMapTexture& setWrapping(const Array3D<Sampler::Wrapping>& wrapping) {
DataHelper<3>::setWrapping(this, wrapping);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES
@ -125,9 +125,9 @@ class CubeMapTexture: public AbstractTexture {
*
* See Texture::setStorage() for more information.
*/
CubeMapTexture* setStorage(Int levels, TextureFormat internalFormat, const Vector2i& size) {
CubeMapTexture& setStorage(Int levels, TextureFormat internalFormat, const Vector2i& size) {
DataHelper<2>::setStorage(this, _target, levels, internalFormat, size);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES
@ -166,20 +166,20 @@ class CubeMapTexture: public AbstractTexture {
* @param level Mip level
* @param internalFormat Internal format
* @param image %Image
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* See Texture::setImage() for more information.
*/
CubeMapTexture* setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, const ImageReference2D& image) {
CubeMapTexture& setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, const ImageReference2D& image) {
DataHelper<2>::setImage(this, static_cast<GLenum>(coordinate), level, internalFormat, image);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
/** @overload */
CubeMapTexture* setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, BufferImage2D& image) {
CubeMapTexture& setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, BufferImage2D& image) {
DataHelper<2>::setImage(this, static_cast<GLenum>(coordinate), level, internalFormat, image);
return this;
return *this;
}
#endif
@ -189,20 +189,20 @@ class CubeMapTexture: public AbstractTexture {
* @param level Mip level
* @param offset Offset where to put data in the texture
* @param image %Image
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* See Texture::setSubImage() for more information.
*/
CubeMapTexture* setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, const ImageReference2D& image) {
CubeMapTexture& setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, const ImageReference2D& image) {
DataHelper<2>::setSubImage(this, static_cast<GLenum>(coordinate), level, offset, image);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
/** @overload */
CubeMapTexture* setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, BufferImage2D& image) {
CubeMapTexture& setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, BufferImage2D& image) {
DataHelper<2>::setSubImage(this, static_cast<GLenum>(coordinate), level, offset, image);
return this;
return *this;
}
#endif
@ -224,27 +224,27 @@ class CubeMapTexture: public AbstractTexture {
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
CubeMapTexture* setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) {
CubeMapTexture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) {
AbstractTexture::setMinificationFilter(filter, mipmap);
return this;
return *this;
}
CubeMapTexture* setMagnificationFilter(Sampler::Filter filter) {
CubeMapTexture& setMagnificationFilter(Sampler::Filter filter) {
AbstractTexture::setMagnificationFilter(filter);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES3
CubeMapTexture* setBorderColor(const Color4& color) {
CubeMapTexture& setBorderColor(const Color4& color) {
AbstractTexture::setBorderColor(color);
return this;
return *this;
}
CubeMapTexture* setMaxAnisotropy(Float anisotropy) {
CubeMapTexture& setMaxAnisotropy(Float anisotropy) {
AbstractTexture::setMaxAnisotropy(anisotropy);
return this;
return *this;
}
#endif
CubeMapTexture* generateMipmap() {
CubeMapTexture& generateMipmap() {
AbstractTexture::generateMipmap();
return this;
return *this;
}
#endif
};

54
src/CubeMapTextureArray.h

@ -53,14 +53,14 @@ Image3D dummy({64, 64, 16*6}, ImageFormat::RGBA, ImageType::UnsignedByte, nullpt
CubeMapTextureArray texture;
texture.setMagnificationFilter(Sampler::Filter::Linear)
// ...
->setStorage(Math::log2(64)+1, TextureFormat::RGBA8, {64, 64, 16});
.setStorage(Math::log2(64)+1, TextureFormat::RGBA8, {64, 64, 16});
for(std::size_t i = 0; i != 16; ++i) {
void* dataPositiveX = ...;
Image2D imagePositiveX({64, 64}, ImageFormat::RGBA, ImageType::UnsignedByte, imagePositiveX);
// ...
texture->setSubImage(i, CubeMapTextureArray::Coordinate::PositiveX, 0, {}, imagePositiveX);
texture->setSubImage(i, CubeMapTextureArray::Coordinate::NegativeX, 0, {}, imageNegativeX);
texture.setSubImage(i, CubeMapTextureArray::Coordinate::PositiveX, 0, {}, imagePositiveX);
texture.setSubImage(i, CubeMapTextureArray::Coordinate::NegativeX, 0, {}, imageNegativeX);
// ...
}
@ -105,9 +105,9 @@ class CubeMapTextureArray: public AbstractTexture {
*
* See Texture::setWrapping() for more information.
*/
CubeMapTextureArray* setWrapping(const Array3D<Sampler::Wrapping>& wrapping) {
CubeMapTextureArray& setWrapping(const Array3D<Sampler::Wrapping>& wrapping) {
DataHelper<3>::setWrapping(this, wrapping);
return this;
return *this;
}
/**
@ -126,9 +126,9 @@ class CubeMapTextureArray: public AbstractTexture {
*
* See Texture::setStorage() for more information.
*/
CubeMapTextureArray* setStorage(Int levels, TextureFormat internalFormat, const Vector3i& size) {
CubeMapTextureArray& setStorage(Int levels, TextureFormat internalFormat, const Vector3i& size) {
DataHelper<3>::setStorage(this, _target, levels, internalFormat, size);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES
@ -167,7 +167,7 @@ class CubeMapTextureArray: public AbstractTexture {
* @param internalFormat Internal format
* @param image Image, ImageReference, BufferImage or
* Trade::ImageData of the same dimension count
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Sets texture image data from three-dimensional image for all cube
* faces for all layers. Each group of 6 2D images is one cube map
@ -175,15 +175,15 @@ class CubeMapTextureArray: public AbstractTexture {
*
* See Texture::setImage() for more information.
*/
CubeMapTextureArray* setImage(Int level, TextureFormat internalFormat, const ImageReference3D& image) {
CubeMapTextureArray& setImage(Int level, TextureFormat internalFormat, const ImageReference3D& image) {
DataHelper<3>::setImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image);
return this;
return *this;
}
/** @overload */
CubeMapTextureArray* setImage(Int level, TextureFormat internalFormat, BufferImage3D& image) {
CubeMapTextureArray& setImage(Int level, TextureFormat internalFormat, BufferImage3D& image) {
DataHelper<3>::setImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image);
return this;
return *this;
}
/**
@ -192,7 +192,7 @@ class CubeMapTextureArray: public AbstractTexture {
* @param offset Offset where to put data in the texture
* @param image Image3D, ImageReference3D, BufferImage3D or
* Trade::ImageData3D
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Sets texture image subdata for more than one level/face at once.
*
@ -205,15 +205,15 @@ class CubeMapTextureArray: public AbstractTexture {
*
* @see setSubImage(Int, Coordinate, Int, const Math::Vector<2, Int>&, const Image*)
*/
CubeMapTextureArray* setSubImage(Int level, const Vector3i& offset, const ImageReference3D& image) {
CubeMapTextureArray& setSubImage(Int level, const Vector3i& offset, const ImageReference3D& image) {
DataHelper<3>::setSubImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image);
return this;
return *this;
}
/** @overload */
CubeMapTextureArray* setSubImage(Int level, const Vector3i& offset, BufferImage3D& image) {
CubeMapTextureArray& setSubImage(Int level, const Vector3i& offset, BufferImage3D& image) {
DataHelper<3>::setSubImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image);
return this;
return *this;
}
/**
@ -234,27 +234,27 @@ class CubeMapTextureArray: public AbstractTexture {
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
CubeMapTextureArray* setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) {
CubeMapTextureArray& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) {
AbstractTexture::setMinificationFilter(filter, mipmap);
return this;
return *this;
}
CubeMapTextureArray* setMagnificationFilter(Sampler::Filter filter) {
CubeMapTextureArray& setMagnificationFilter(Sampler::Filter filter) {
AbstractTexture::setMagnificationFilter(filter);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES3
CubeMapTextureArray* setBorderColor(const Color4& color) {
CubeMapTextureArray& setBorderColor(const Color4& color) {
AbstractTexture::setBorderColor(color);
return this;
return *this;
}
CubeMapTextureArray* setMaxAnisotropy(Float anisotropy) {
CubeMapTextureArray& setMaxAnisotropy(Float anisotropy) {
AbstractTexture::setMaxAnisotropy(anisotropy);
return this;
return *this;
}
#endif
CubeMapTextureArray* generateMipmap() {
CubeMapTextureArray& generateMipmap() {
AbstractTexture::generateMipmap();
return this;
return *this;
}
#endif
};

4
src/DebugMarker.cpp

@ -33,10 +33,10 @@ namespace Magnum {
DebugMarker::MarkImplementation DebugMarker::markImplementation = &DebugMarker::markImplementationDefault;
void DebugMarker::initializeContextBasedFunctionality(Context* context) {
void DebugMarker::initializeContextBasedFunctionality(Context& context) {
/** @todo Re-enable when extension wrangler is available for ES */
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::GREMEDY::string_marker>()) {
if(context.isExtensionSupported<Extensions::GL::GREMEDY::string_marker>()) {
Debug() << "DebugMarker: using" << Extensions::GL::GREMEDY::string_marker::string() << "features";
markImplementation = &DebugMarker::markImplementationDebugger;

2
src/DebugMarker.h

@ -58,7 +58,7 @@ class MAGNUM_EXPORT DebugMarker {
}
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
typedef void(*MarkImplementation)(const std::string&);
static MAGNUM_LOCAL void markImplementationDefault(const std::string& string);

2
src/DebugTools/CMakeLists.txt

@ -50,7 +50,7 @@ set(MagnumDebugTools_HEADERS
add_library(MagnumDebugTools ${SHARED_OR_STATIC} ${MagnumDebugTools_SRCS})
if(BUILD_STATIC_PIC)
# TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property
set_target_properties(MagnumDebugTools PROPERTIES COMPILE_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS})
set_target_properties(MagnumDebugTools PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
endif()
target_link_libraries(MagnumDebugTools
Magnum

32
src/DebugTools/ForceRenderer.cpp

@ -64,15 +64,15 @@ const std::array<UnsignedByte, 6> indices{{
}
template<UnsignedInt dimensions> ForceRenderer<dimensions>::ForceRenderer(SceneGraph::AbstractBasicObject<dimensions, Float>* object, const typename DimensionTraits<dimensions, Float>::VectorType& forcePosition, const typename DimensionTraits<dimensions, Float>::VectorType* force, ResourceKey options, SceneGraph::BasicDrawableGroup<dimensions, Float>* drawables): SceneGraph::BasicDrawable<dimensions, Float>(object, drawables), forcePosition(forcePosition), force(force), options(ResourceManager::instance()->get<ForceRendererOptions>(options)) {
template<UnsignedInt dimensions> ForceRenderer<dimensions>::ForceRenderer(SceneGraph::AbstractObject<dimensions, Float>& object, const typename DimensionTraits<dimensions, Float>::VectorType& forcePosition, const typename DimensionTraits<dimensions, Float>::VectorType& force, ResourceKey options, SceneGraph::DrawableGroup<dimensions, Float>* drawables): SceneGraph::Drawable<dimensions, Float>(object, drawables), forcePosition(forcePosition), force(force), options(ResourceManager::instance().get<ForceRendererOptions>(options)) {
/* Shader */
shader = ResourceManager::instance()->get<AbstractShaderProgram, Shaders::Flat<dimensions>>(shaderKey<dimensions>());
if(!shader) ResourceManager::instance()->set<AbstractShaderProgram>(shader.key(), new Shaders::Flat<dimensions>);
shader = ResourceManager::instance().get<AbstractShaderProgram, Shaders::Flat<dimensions>>(shaderKey<dimensions>());
if(!shader) ResourceManager::instance().set<AbstractShaderProgram>(shader.key(), new Shaders::Flat<dimensions>);
/* Mesh and vertex buffer */
mesh = ResourceManager::instance()->get<Mesh>("force");
vertexBuffer = ResourceManager::instance()->get<Buffer>("force-vertices");
indexBuffer = ResourceManager::instance()->get<Buffer>("force-indices");
mesh = ResourceManager::instance().get<Mesh>("force");
vertexBuffer = ResourceManager::instance().get<Buffer>("force-vertices");
indexBuffer = ResourceManager::instance().get<Buffer>("force-indices");
if(mesh) return;
/* Create the mesh */
@ -80,24 +80,24 @@ template<UnsignedInt dimensions> ForceRenderer<dimensions>::ForceRenderer(SceneG
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray);
vertexBuffer->setData(positions, Buffer::Usage::StaticDraw);
ResourceManager::instance()->set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
ResourceManager::instance().set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
indexBuffer->setData(indices, Buffer::Usage::StaticDraw);
ResourceManager::instance()->set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
ResourceManager::instance().set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
Mesh* mesh = new Mesh;
mesh->setPrimitive(Mesh::Primitive::Lines)
->setIndexCount(indices.size())
->addVertexBuffer(vertexBuffer, 0,
.setIndexCount(indices.size())
.addVertexBuffer(*vertexBuffer, 0,
typename Shaders::Flat<dimensions>::Position(Shaders::Flat<dimensions>::Position::Components::Two))
->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, positions.size());
ResourceManager::instance()->set<Mesh>(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
.setIndexBuffer(*indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, positions.size());
ResourceManager::instance().set(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
}
template<UnsignedInt dimensions> void ForceRenderer<dimensions>::draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractBasicCamera<dimensions, Float>* camera) {
shader->setTransformationProjectionMatrix(camera->projectionMatrix()*Implementation::forceRendererTransformation<dimensions>(transformationMatrix.transformPoint(forcePosition), *force)*DimensionTraits<dimensions, Float>::MatrixType::scaling(typename DimensionTraits<dimensions, Float>::VectorType(options->scale())))
->setColor(options->color())
->use();
template<UnsignedInt dimensions> void ForceRenderer<dimensions>::draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractCamera<dimensions, Float>& camera) {
shader->setTransformationProjectionMatrix(camera.projectionMatrix()*Implementation::forceRendererTransformation<dimensions>(transformationMatrix.transformPoint(forcePosition), force)*DimensionTraits<dimensions, Float>::MatrixType::scaling(typename DimensionTraits<dimensions, Float>::VectorType(options->scale())))
.setColor(options->color())
.use();
mesh->draw();
}

29
src/DebugTools/ForceRenderer.h

@ -51,13 +51,13 @@ class ForceRendererOptions {
/**
* @brief Set color of rendered arrow
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is 100% opaque white.
*/
ForceRendererOptions* setColor(const Color4& color) {
ForceRendererOptions& setColor(const Color4& color) {
_color = color;
return this;
return *this;
}
/** @brief Scale of rendered arrow */
@ -65,13 +65,13 @@ class ForceRendererOptions {
/**
* @brief Set scale of rendered arrow
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is `1.0f`.
*/
ForceRendererOptions* setSize(Float size) {
ForceRendererOptions& setSize(Float size) {
_size = size;
return this;
return *this;
}
private:
@ -89,9 +89,9 @@ See @ref debug-tools-renderers for more information.
Example code:
@code
// Create some options
DebugTools::ResourceManager::instance()->set("my", (new DebugTools::ForceRendererOptions)
->setScale(5.0f)->setColor(Color3::fromHSV(120.0_degf, 1.0f, 0.7f)));
DebugTools::ResourceManager::instance()->set("my", DebugTools::ForceRendererOptions()
.setScale(5.0f)
.setColor(Color3::fromHSV(120.0_degf, 1.0f, 0.7f));
// Create debug renderer for given object, use "my" options for it
Object3D* object;
@ -101,7 +101,7 @@ new DebugTools::ForceRenderer2D(object, {0.3f, 1.5f, -0.7f}, &force, "my", debug
@see ForceRenderer2D, ForceRenderer3D
*/
template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ForceRenderer: public SceneGraph::BasicDrawable<dimensions, Float> {
template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ForceRenderer: public SceneGraph::Drawable<dimensions, Float> {
public:
/**
* @brief Constructor
@ -117,14 +117,17 @@ template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ForceRenderer: p
* saved as reference to original vector and thus it must be available
* for the whole lifetime of the renderer.
*/
explicit ForceRenderer(SceneGraph::AbstractBasicObject<dimensions, Float>* object, const typename DimensionTraits<dimensions, Float>::VectorType& forcePosition, const typename DimensionTraits<dimensions, Float>::VectorType* force, ResourceKey options = ResourceKey(), SceneGraph::BasicDrawableGroup<dimensions, Float>* drawables = nullptr);
explicit ForceRenderer(SceneGraph::AbstractObject<dimensions, Float>& object, const typename DimensionTraits<dimensions, Float>::VectorType& forcePosition, const typename DimensionTraits<dimensions, Float>::VectorType& force, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup<dimensions, Float>* drawables = nullptr);
/** @overload */
ForceRenderer(SceneGraph::AbstractObject<dimensions, Float>&, const typename DimensionTraits<dimensions, Float>::VectorType&, typename DimensionTraits<dimensions, Float>::VectorType&&, ResourceKey = ResourceKey(), SceneGraph::DrawableGroup<dimensions, Float>* = nullptr) = delete;
protected:
void draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractBasicCamera<dimensions, Float>* camera) override;
void draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractCamera<dimensions, Float>& camera) override;
private:
const typename DimensionTraits<dimensions, Float>::VectorType forcePosition;
const typename DimensionTraits<dimensions, Float>::VectorType* const force;
const typename DimensionTraits<dimensions, Float>::VectorType& force;
Resource<ForceRendererOptions> options;
Resource<AbstractShaderProgram, Shaders::Flat<dimensions>> shader;

4
src/DebugTools/Implementation/AbstractBoxRenderer.cpp

@ -32,11 +32,11 @@
namespace Magnum { namespace DebugTools { namespace Implementation {
AbstractBoxRenderer<2>::AbstractBoxRenderer(): AbstractShapeRenderer<2>("box2d", "box2d-vertices", {}) {
if(!wireframeMesh) this->createResources(Primitives::Square::wireframe());
if(!wireframeMesh) AbstractShapeRenderer<2>::createResources(Primitives::Square::wireframe());
}
AbstractBoxRenderer<3>::AbstractBoxRenderer(): AbstractShapeRenderer<3>("box3d", "box3d-vertices", "box3d-indices") {
if(!wireframeMesh) this->createResources(Primitives::Cube::wireframe());
if(!wireframeMesh) AbstractShapeRenderer<3>::createResources(Primitives::Cube::wireframe());
}
template class AbstractBoxRenderer<2>;

36
src/DebugTools/Implementation/AbstractShapeRenderer.cpp

@ -47,21 +47,21 @@ template<> void create<2>(Trade::MeshData2D& data, Resource<Mesh>& meshResource,
/* Vertex buffer */
Buffer* buffer = new Buffer(Buffer::Target::Array);
buffer->setData(data.positions(0), Buffer::Usage::StaticDraw);
ResourceManager::instance()->set(vertexBufferResource.key(), buffer, ResourceDataState::Final, ResourcePolicy::Manual);
ResourceManager::instance().set(vertexBufferResource.key(), buffer, ResourceDataState::Final, ResourcePolicy::Manual);
/* Mesh configuration */
Mesh* mesh = new Mesh;
mesh->setPrimitive(data.primitive())
->setVertexCount(data.positions(0).size())
->addVertexBuffer(buffer, 0, Shaders::Flat2D::Position());
ResourceManager::instance()->set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
.setVertexCount(data.positions(0).size())
.addVertexBuffer(*buffer, 0, Shaders::Flat2D::Position());
ResourceManager::instance().set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
/* Index buffer, if needed, if not, resource key doesn't have to be set */
if(data.isIndexed()) {
CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey());
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray);
MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw, data.indices());
ResourceManager::instance()->set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
MeshTools::compressIndices(*mesh, *indexBuffer, Buffer::Usage::StaticDraw, data.indices());
ResourceManager::instance().set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
}
}
@ -69,40 +69,40 @@ template<> void create<3>(Trade::MeshData3D& data, Resource<Mesh>& meshResource,
/* Vertex buffer */
Buffer* vertexBuffer = new Buffer(Buffer::Target::Array);
vertexBuffer->setData(data.positions(0), Buffer::Usage::StaticDraw);
ResourceManager::instance()->set(vertexBufferResource.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
ResourceManager::instance().set(vertexBufferResource.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
/* Mesh configuration */
Mesh* mesh = new Mesh;
mesh->setPrimitive(data.primitive())
->setVertexCount(data.positions(0).size())
->addVertexBuffer(vertexBuffer, 0, Shaders::Flat3D::Position());
ResourceManager::instance()->set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
.setVertexCount(data.positions(0).size())
.addVertexBuffer(*vertexBuffer, 0, Shaders::Flat3D::Position());
ResourceManager::instance().set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
/* Index buffer, if needed, if not, resource key doesn't have to be set */
if(data.isIndexed()) {
CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey());
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray);
MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw, data.indices());
ResourceManager::instance()->set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
MeshTools::compressIndices(*mesh, *indexBuffer, Buffer::Usage::StaticDraw, data.indices());
ResourceManager::instance().set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
}
}
}
template<UnsignedInt dimensions> AbstractShapeRenderer<dimensions>::AbstractShapeRenderer(ResourceKey meshKey, ResourceKey vertexBufferKey, ResourceKey indexBufferKey) {
wireframeShader = ResourceManager::instance()->get<AbstractShaderProgram, Shaders::Flat<dimensions>>(shaderKey<dimensions>());
wireframeMesh = ResourceManager::instance()->get<Mesh>(meshKey);
vertexBuffer = ResourceManager::instance()->get<Buffer>(vertexBufferKey);
indexBuffer = ResourceManager::instance()->get<Buffer>(indexBufferKey);
wireframeShader = ResourceManager::instance().get<AbstractShaderProgram, Shaders::Flat<dimensions>>(shaderKey<dimensions>());
wireframeMesh = ResourceManager::instance().get<Mesh>(meshKey);
vertexBuffer = ResourceManager::instance().get<Buffer>(vertexBufferKey);
indexBuffer = ResourceManager::instance().get<Buffer>(indexBufferKey);
if(!wireframeShader) ResourceManager::instance()->set<AbstractShaderProgram>(shaderKey<dimensions>(),
if(!wireframeShader) ResourceManager::instance().set<AbstractShaderProgram>(shaderKey<dimensions>(),
new Shaders::Flat<dimensions>, ResourceDataState::Final, ResourcePolicy::Resident);
}
template<UnsignedInt dimensions> AbstractShapeRenderer<dimensions>::~AbstractShapeRenderer() {}
template<UnsignedInt dimensions> void AbstractShapeRenderer<dimensions>::createResources(typename MeshData<dimensions>::Type data) {
create<dimensions>(data, this->wireframeMesh, this->vertexBuffer, this->indexBuffer);
create<dimensions>(data, wireframeMesh, vertexBuffer, indexBuffer);
}
template class AbstractShapeRenderer<2>;

10
src/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp

@ -31,15 +31,15 @@
namespace Magnum { namespace DebugTools { namespace Implementation {
template<UnsignedInt dimensions> AxisAlignedBoxRenderer<dimensions>::AxisAlignedBoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>* axisAlignedBox): axisAlignedBox(static_cast<const Shapes::Implementation::Shape<Shapes::AxisAlignedBox<dimensions>>*>(axisAlignedBox)->shape) {}
template<UnsignedInt dimensions> AxisAlignedBoxRenderer<dimensions>::AxisAlignedBoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>& axisAlignedBox): axisAlignedBox(static_cast<const Shapes::Implementation::Shape<Shapes::AxisAlignedBox<dimensions>>&>(axisAlignedBox).shape) {}
template<UnsignedInt dimensions> void AxisAlignedBoxRenderer<dimensions>::draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) {
this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
AbstractBoxRenderer<dimensions>::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
DimensionTraits<dimensions, Float>::MatrixType::translation((axisAlignedBox.min()+axisAlignedBox.max())/2)*
DimensionTraits<dimensions, Float>::MatrixType::scaling(axisAlignedBox.max()-axisAlignedBox.min()))
->setColor(options->color())
->use();
this->wireframeMesh->draw();
.setColor(options->color())
.use();
AbstractBoxRenderer<dimensions>::wireframeMesh->draw();
}
template class AxisAlignedBoxRenderer<2>;

3
src/DebugTools/Implementation/AxisAlignedBoxRenderer.h

@ -34,7 +34,8 @@ namespace Magnum { namespace DebugTools { namespace Implementation {
template<UnsignedInt dimensions> class AxisAlignedBoxRenderer: public AbstractBoxRenderer<dimensions> {
public:
AxisAlignedBoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>* axisAlignedBox);
explicit AxisAlignedBoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>& axisAlignedBox);
AxisAlignedBoxRenderer(Shapes::Implementation::AbstractShape<dimensions>&&) = delete;
void draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) override;

10
src/DebugTools/Implementation/BoxRenderer.cpp

@ -31,13 +31,13 @@
namespace Magnum { namespace DebugTools { namespace Implementation {
template<UnsignedInt dimensions> BoxRenderer<dimensions>::BoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>* box): box(static_cast<const Shapes::Implementation::Shape<Shapes::Box<dimensions>>*>(box)->shape) {}
template<UnsignedInt dimensions> BoxRenderer<dimensions>::BoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>& box): box(static_cast<const Shapes::Implementation::Shape<Shapes::Box<dimensions>>&>(box).shape) {}
template<UnsignedInt dimensions> void BoxRenderer<dimensions>::draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) {
this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix*box.transformation())
->setColor(options->color())
->use();
this->wireframeMesh->draw();
AbstractBoxRenderer<dimensions>::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*box.transformation())
.setColor(options->color())
.use();
AbstractBoxRenderer<dimensions>::wireframeMesh->draw();
}
template class BoxRenderer<2>;

3
src/DebugTools/Implementation/BoxRenderer.h

@ -34,7 +34,8 @@ namespace Magnum { namespace DebugTools { namespace Implementation {
template<UnsignedInt dimensions> class BoxRenderer: public AbstractBoxRenderer<dimensions> {
public:
BoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>* box);
explicit BoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>& box);
BoxRenderer(const Shapes::Implementation::AbstractShape<dimensions>&&) = delete;
void draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) override;

12
src/DebugTools/Implementation/LineSegmentRenderer.cpp

@ -50,16 +50,16 @@ namespace {
template<> inline Trade::MeshData3D meshData<3>() { return Primitives::Line3D::wireframe(); }
}
template<UnsignedInt dimensions> LineSegmentRenderer<dimensions>::LineSegmentRenderer(const Shapes::Implementation::AbstractShape<dimensions>* line): AbstractShapeRenderer<dimensions>(meshKey<dimensions>(), vertexBufferKey<dimensions>(), {}), line(static_cast<const Shapes::Implementation::Shape<Shapes::LineSegment<dimensions>>*>(line)->shape) {
if(!this->wireframeMesh) this->createResources(meshData<dimensions>());
template<UnsignedInt dimensions> LineSegmentRenderer<dimensions>::LineSegmentRenderer(const Shapes::Implementation::AbstractShape<dimensions>& line): AbstractShapeRenderer<dimensions>(meshKey<dimensions>(), vertexBufferKey<dimensions>(), {}), line(static_cast<const Shapes::Implementation::Shape<Shapes::LineSegment<dimensions>>&>(line).shape) {
if(!AbstractShapeRenderer<dimensions>::wireframeMesh) AbstractShapeRenderer<dimensions>::createResources(meshData<dimensions>());
}
template<UnsignedInt dimensions> void LineSegmentRenderer<dimensions>::draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) {
this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
AbstractShapeRenderer<dimensions>::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
Implementation::lineSegmentRendererTransformation<dimensions>(line.a(), line.b()))
->setColor(options->color())
->use();
this->wireframeMesh->draw();
.setColor(options->color())
.use();
AbstractShapeRenderer<dimensions>::wireframeMesh->draw();
}
template class LineSegmentRenderer<2>;

3
src/DebugTools/Implementation/LineSegmentRenderer.h

@ -34,7 +34,8 @@ namespace Magnum { namespace DebugTools { namespace Implementation {
template<UnsignedInt dimensions> class LineSegmentRenderer: public AbstractShapeRenderer<dimensions> {
public:
LineSegmentRenderer(const Shapes::Implementation::AbstractShape<dimensions>* line);
explicit LineSegmentRenderer(const Shapes::Implementation::AbstractShape<dimensions>& line);
LineSegmentRenderer(const Shapes::Implementation::AbstractShape<dimensions>&&) = delete;
void draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) override;

12
src/DebugTools/Implementation/PointRenderer.cpp

@ -48,18 +48,18 @@ namespace {
template<> inline Trade::MeshData3D meshData<3>() { return Primitives::Crosshair3D::wireframe(); }
}
template<UnsignedInt dimensions> PointRenderer<dimensions>::PointRenderer(const Shapes::Implementation::AbstractShape<dimensions>* point): AbstractShapeRenderer<dimensions>(meshKey<dimensions>(), vertexBufferKey<dimensions>(), {}), point(static_cast<const Shapes::Implementation::Shape<Shapes::Point<dimensions>>*>(point)->shape) {
if(!this->wireframeMesh) this->createResources(meshData<dimensions>());
template<UnsignedInt dimensions> PointRenderer<dimensions>::PointRenderer(const Shapes::Implementation::AbstractShape<dimensions>& point): AbstractShapeRenderer<dimensions>(meshKey<dimensions>(), vertexBufferKey<dimensions>(), {}), point(static_cast<const Shapes::Implementation::Shape<Shapes::Point<dimensions>>&>(point).shape) {
if(!AbstractShapeRenderer<dimensions>::wireframeMesh) AbstractShapeRenderer<dimensions>::createResources(meshData<dimensions>());
}
template<UnsignedInt dimensions> void PointRenderer<dimensions>::draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) {
/* Half scale, because the point is 2x2(x2) */
this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
AbstractShapeRenderer<dimensions>::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
DimensionTraits<dimensions, Float>::MatrixType::translation(point.position())*
DimensionTraits<dimensions, Float>::MatrixType::scaling(typename DimensionTraits<dimensions, Float>::VectorType(options->pointSize()/2)))
->setColor(options->color())
->use();
this->wireframeMesh->draw();
.setColor(options->color())
.use();
AbstractShapeRenderer<dimensions>::wireframeMesh->draw();
}
template class PointRenderer<2>;

3
src/DebugTools/Implementation/PointRenderer.h

@ -34,7 +34,8 @@ namespace Magnum { namespace DebugTools { namespace Implementation {
template<UnsignedInt dimensions> class PointRenderer: public AbstractShapeRenderer<dimensions> {
public:
PointRenderer(const Shapes::Implementation::AbstractShape<dimensions>* point);
explicit PointRenderer(const Shapes::Implementation::AbstractShape<dimensions>& point);
PointRenderer(Shapes::Implementation::AbstractShape<dimensions>&&) = delete;
void draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) override;

17
src/DebugTools/Implementation/SphereRenderer.cpp

@ -28,8 +28,10 @@
#include "DebugTools/ShapeRenderer.h"
#include "Shapes/Sphere.h"
#include "Primitives/Circle.h"
#include "Primitives/UVSphere.h"
#include "Shaders/Flat.h"
#include "Trade/MeshData2D.h"
#include "Trade/MeshData3D.h"
namespace Magnum { namespace DebugTools { namespace Implementation {
@ -37,17 +39,22 @@ AbstractSphereRenderer<2>::AbstractSphereRenderer(): AbstractShapeRenderer<2>("s
if(!wireframeMesh) createResources(Primitives::Circle::wireframe(40));
}
template<UnsignedInt dimensions> SphereRenderer<dimensions>::SphereRenderer(const Shapes::Implementation::AbstractShape<dimensions>* sphere): sphere(static_cast<const Shapes::Implementation::Shape<Shapes::Sphere<dimensions>>*>(sphere)->shape) {}
AbstractSphereRenderer<3>::AbstractSphereRenderer(): AbstractShapeRenderer<3>("sphere3d", "sphere3d-vertices", "sphere3d-indices") {
if(!wireframeMesh) createResources(Primitives::UVSphere::wireframe(40, 20));
}
template<UnsignedInt dimensions> SphereRenderer<dimensions>::SphereRenderer(const Shapes::Implementation::AbstractShape<dimensions>& sphere): sphere(static_cast<const Shapes::Implementation::Shape<Shapes::Sphere<dimensions>>&>(sphere).shape) {}
template<UnsignedInt dimensions> void SphereRenderer<dimensions>::draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) {
this->wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
AbstractShapeRenderer<dimensions>::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*
DimensionTraits<dimensions, Float>::MatrixType::translation(sphere.position())*
DimensionTraits<dimensions, Float>::MatrixType::scaling(typename DimensionTraits<dimensions, Float>::VectorType(sphere.radius())))
->setColor(options->color())
->use();
this->wireframeMesh->draw();
.setColor(options->color())
.use();
AbstractShapeRenderer<dimensions>::wireframeMesh->draw();
}
template class SphereRenderer<2>;
template class SphereRenderer<3>;
}}}

10
src/DebugTools/Implementation/SphereRenderer.h

@ -36,12 +36,18 @@ template<UnsignedInt dimensions> class AbstractSphereRenderer;
template<> class AbstractSphereRenderer<2>: public AbstractShapeRenderer<2> {
public:
AbstractSphereRenderer();
explicit AbstractSphereRenderer();
};
template<> class AbstractSphereRenderer<3>: public AbstractShapeRenderer<3> {
public:
explicit AbstractSphereRenderer();
};
template<UnsignedInt dimensions> class SphereRenderer: public AbstractSphereRenderer<dimensions> {
public:
SphereRenderer(const Shapes::Implementation::AbstractShape<dimensions>* sphere);
explicit SphereRenderer(const Shapes::Implementation::AbstractShape<dimensions>& sphere);
SphereRenderer(const Shapes::Implementation::AbstractShape<dimensions>&&) = delete;
void draw(Resource<ShapeRendererOptions>& options, const typename DimensionTraits<dimensions, Float>::MatrixType& projectionMatrix) override;

32
src/DebugTools/ObjectRenderer.cpp

@ -142,15 +142,15 @@ const std::array<UnsignedByte, 18> Renderer<3>::indices{{
}
template<UnsignedInt dimensions> ObjectRenderer<dimensions>::ObjectRenderer(SceneGraph::AbstractBasicObject<dimensions, Float>* object, ResourceKey options, SceneGraph::BasicDrawableGroup<dimensions, Float>* drawables): SceneGraph::BasicDrawable<dimensions, Float>(object, drawables), options(ResourceManager::instance()->get<ObjectRendererOptions>(options)) {
template<UnsignedInt dimensions> ObjectRenderer<dimensions>::ObjectRenderer(SceneGraph::AbstractObject<dimensions, Float>& object, ResourceKey options, SceneGraph::DrawableGroup<dimensions, Float>* drawables): SceneGraph::Drawable<dimensions, Float>(object, drawables), options(ResourceManager::instance().get<ObjectRendererOptions>(options)) {
/* Shader */
shader = ResourceManager::instance()->get<AbstractShaderProgram, Shaders::VertexColor<dimensions>>(Renderer<dimensions>::shader());
if(!shader) ResourceManager::instance()->set<AbstractShaderProgram>(shader.key(), new Shaders::VertexColor<dimensions>);
shader = ResourceManager::instance().get<AbstractShaderProgram, Shaders::VertexColor<dimensions>>(Renderer<dimensions>::shader());
if(!shader) ResourceManager::instance().set<AbstractShaderProgram>(shader.key(), new Shaders::VertexColor<dimensions>);
/* Mesh and vertex buffer */
mesh = ResourceManager::instance()->get<Mesh>(Renderer<dimensions>::mesh());
vertexBuffer = ResourceManager::instance()->get<Buffer>(Renderer<dimensions>::vertexBuffer());
indexBuffer = ResourceManager::instance()->get<Buffer>(Renderer<dimensions>::indexBuffer());
mesh = ResourceManager::instance().get<Mesh>(Renderer<dimensions>::mesh());
vertexBuffer = ResourceManager::instance().get<Buffer>(Renderer<dimensions>::vertexBuffer());
indexBuffer = ResourceManager::instance().get<Buffer>(Renderer<dimensions>::indexBuffer());
if(mesh) return;
/* Create the mesh */
@ -158,24 +158,24 @@ template<UnsignedInt dimensions> ObjectRenderer<dimensions>::ObjectRenderer(Scen
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray);
Mesh* mesh = new Mesh;
MeshTools::interleave(mesh, vertexBuffer, Buffer::Usage::StaticDraw, Renderer<dimensions>::positions, Renderer<dimensions>::colors);
ResourceManager::instance()->set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
MeshTools::interleave(*mesh, *vertexBuffer, Buffer::Usage::StaticDraw, Renderer<dimensions>::positions, Renderer<dimensions>::colors);
ResourceManager::instance().set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
indexBuffer->setData(Renderer<dimensions>::indices, Buffer::Usage::StaticDraw);
ResourceManager::instance()->set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
ResourceManager::instance().set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
mesh->setPrimitive(Mesh::Primitive::Lines)
->setIndexCount(Renderer<dimensions>::indices.size())
->addInterleavedVertexBuffer(vertexBuffer, 0,
.setIndexCount(Renderer<dimensions>::indices.size())
.addInterleavedVertexBuffer(*vertexBuffer, 0,
typename Shaders::VertexColor<dimensions>::Position(),
typename Shaders::VertexColor<dimensions>::Color())
->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, Renderer<dimensions>::positions.size());
ResourceManager::instance()->set<Mesh>(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
.setIndexBuffer(*indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, Renderer<dimensions>::positions.size());
ResourceManager::instance().set<Mesh>(this->mesh.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual);
}
template<UnsignedInt dimensions> void ObjectRenderer<dimensions>::draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractBasicCamera<dimensions, Float>* camera) {
shader->setTransformationProjectionMatrix(camera->projectionMatrix()*transformationMatrix*DimensionTraits<dimensions, Float>::MatrixType::scaling(typename DimensionTraits<dimensions, Float>::VectorType(options->size())))
->use();
template<UnsignedInt dimensions> void ObjectRenderer<dimensions>::draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractCamera<dimensions, Float>& camera) {
shader->setTransformationProjectionMatrix(camera.projectionMatrix()*transformationMatrix*DimensionTraits<dimensions, Float>::MatrixType::scaling(typename DimensionTraits<dimensions, Float>::VectorType(options->size())))
.use();
mesh->draw();
}

15
src/DebugTools/ObjectRenderer.h

@ -50,13 +50,13 @@ class ObjectRendererOptions {
/**
* @brief Set size of the rendered axes
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is `1.0f`.
*/
ObjectRendererOptions* setSize(Float size) {
ObjectRendererOptions& setSize(Float size) {
_size = size;
return this;
return *this;
}
private:
@ -74,8 +74,7 @@ Visualizes object position, rotation and scale using colored axes. See
Example code:
@code
// Create some options
DebugTools::ResourceManager::instance()->set("my", (new DebugTools::ObjectRendererOptions)
->setSize(0.3f));
DebugTools::ResourceManager::instance()->set("my", DebugTools::ObjectRendererOptions().setSize(0.3f));
// Create debug renderer for given object, use "my" options for it
Object3D* object;
@ -84,7 +83,7 @@ new DebugTools::ObjectRenderer2D(object, "my", debugDrawables);
@see ObjectRenderer2D, ObjectRenderer3D
*/
template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ObjectRenderer: public SceneGraph::BasicDrawable<dimensions, Float> {
template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ObjectRenderer: public SceneGraph::Drawable<dimensions, Float> {
public:
/**
* @brief Constructor
@ -96,10 +95,10 @@ template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ObjectRenderer:
*
* The renderer is automatically added to object's features.
*/
explicit ObjectRenderer(SceneGraph::AbstractBasicObject<dimensions, Float>* object, ResourceKey options = ResourceKey(), SceneGraph::BasicDrawableGroup<dimensions, Float>* drawables = nullptr);
explicit ObjectRenderer(SceneGraph::AbstractObject<dimensions, Float>& object, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup<dimensions, Float>* drawables = nullptr);
protected:
void draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractBasicCamera<dimensions, Float>* camera) override;
void draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractCamera<dimensions, Float>& camera) override;
private:
Resource<ObjectRendererOptions> options;

49
src/DebugTools/ShapeRenderer.cpp

@ -39,63 +39,66 @@ namespace Magnum { namespace DebugTools {
namespace Implementation {
template<> void createDebugMesh(ShapeRenderer<2>* renderer, const Shapes::Implementation::AbstractShape<2>* shape) {
switch(shape->type()) {
template<> void createDebugMesh(ShapeRenderer<2>& renderer, const Shapes::Implementation::AbstractShape<2>& shape) {
switch(shape.type()) {
case Shapes::AbstractShape2D::Type::AxisAlignedBox:
renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<2>(shape));
renderer.renderers.push_back(new Implementation::AxisAlignedBoxRenderer<2>(shape));
break;
case Shapes::AbstractShape2D::Type::Box:
renderer->renderers.push_back(new Implementation::BoxRenderer<2>(shape));
renderer.renderers.push_back(new Implementation::BoxRenderer<2>(shape));
break;
case Shapes::AbstractShape2D::Type::LineSegment:
renderer->renderers.push_back(new Implementation::LineSegmentRenderer<2>(shape));
renderer.renderers.push_back(new Implementation::LineSegmentRenderer<2>(shape));
break;
case Shapes::AbstractShape2D::Type::Point:
renderer->renderers.push_back(new Implementation::PointRenderer<2>(shape));
renderer.renderers.push_back(new Implementation::PointRenderer<2>(shape));
break;
case Shapes::AbstractShape2D::Type::Sphere:
renderer.renderers.push_back(new Implementation::SphereRenderer<2>(shape));
break;
case Shapes::AbstractShape2D::Type::Composition: {
const Shapes::Composition2D& composition =
static_cast<const Shapes::Implementation::Shape<Shapes::Composition2D>*>(shape)->shape;
static_cast<const Shapes::Implementation::Shape<Shapes::Composition2D>&>(shape).shape;
for(std::size_t i = 0; i != composition.size(); ++i)
createDebugMesh(renderer, Shapes::Implementation::getAbstractShape(composition, i));
} break;
case Shapes::AbstractShape2D::Type::Sphere:
renderer->renderers.push_back(new Implementation::SphereRenderer<2>(shape));
break;
default:
Warning() << "DebugTools::ShapeRenderer2D::createShapeRenderer(): type" << shape->type() << "not implemented";
Warning() << "DebugTools::ShapeRenderer2D::createShapeRenderer(): type" << shape.type() << "not implemented";
}
}
template<> void createDebugMesh(ShapeRenderer<3>* renderer, const Shapes::Implementation::AbstractShape<3>* shape) {
switch(shape->type()) {
template<> void createDebugMesh(ShapeRenderer<3>& renderer, const Shapes::Implementation::AbstractShape<3>& shape) {
switch(shape.type()) {
case Shapes::AbstractShape3D::Type::AxisAlignedBox:
renderer->renderers.push_back(new Implementation::AxisAlignedBoxRenderer<3>(shape));
renderer.renderers.push_back(new Implementation::AxisAlignedBoxRenderer<3>(shape));
break;
case Shapes::AbstractShape3D::Type::Box:
renderer->renderers.push_back(new Implementation::BoxRenderer<3>(shape));
renderer.renderers.push_back(new Implementation::BoxRenderer<3>(shape));
break;
case Shapes::AbstractShape3D::Type::LineSegment:
renderer->renderers.push_back(new Implementation::LineSegmentRenderer<3>(shape));
renderer.renderers.push_back(new Implementation::LineSegmentRenderer<3>(shape));
break;
case Shapes::AbstractShape3D::Type::Point:
renderer->renderers.push_back(new Implementation::PointRenderer<3>(shape));
renderer.renderers.push_back(new Implementation::PointRenderer<3>(shape));
break;
case Shapes::AbstractShape3D::Type::Sphere:
renderer.renderers.push_back(new Implementation::SphereRenderer<3>(shape));
break;
case Shapes::AbstractShape3D::Type::Composition: {
const Shapes::Composition3D& composition =
static_cast<const Shapes::Implementation::Shape<Shapes::Composition3D>*>(shape)->shape;
static_cast<const Shapes::Implementation::Shape<Shapes::Composition3D>&>(shape).shape;
for(std::size_t i = 0; i != composition.size(); ++i)
createDebugMesh(renderer, Shapes::Implementation::getAbstractShape(composition, i));
} break;
default:
Warning() << "DebugTools::ShapeRenderer3D::createShapeRenderer(): type" << shape->type() << "not implemented";
Warning() << "DebugTools::ShapeRenderer3D::createShapeRenderer(): type" << shape.type() << "not implemented";
}
}
}
template<UnsignedInt dimensions> ShapeRenderer<dimensions>::ShapeRenderer(Shapes::AbstractShape<dimensions>* shape, ResourceKey options, SceneGraph::BasicDrawableGroup<dimensions, Float>* drawables): SceneGraph::BasicDrawable<dimensions, Float>(shape->object(), drawables), options(ResourceManager::instance()->get<ShapeRendererOptions>(options)) {
Implementation::createDebugMesh(this, Shapes::Implementation::getAbstractShape(shape));
template<UnsignedInt dimensions> ShapeRenderer<dimensions>::ShapeRenderer(Shapes::AbstractShape<dimensions>& shape, ResourceKey options, SceneGraph::DrawableGroup<dimensions, Float>* drawables): SceneGraph::Drawable<dimensions, Float>(shape.object(), drawables), options(ResourceManager::instance().get<ShapeRendererOptions>(options)) {
Implementation::createDebugMesh(*this, Shapes::Implementation::getAbstractShape(shape));
}
template<UnsignedInt dimensions> ShapeRenderer<dimensions>::~ShapeRenderer() {
@ -103,8 +106,8 @@ template<UnsignedInt dimensions> ShapeRenderer<dimensions>::~ShapeRenderer() {
delete *it;
}
template<UnsignedInt dimensions> void ShapeRenderer<dimensions>::draw(const typename DimensionTraits<dimensions, Float>::MatrixType&, SceneGraph::AbstractBasicCamera<dimensions, Float>* camera) {
typename DimensionTraits<dimensions, Float>::MatrixType projectionMatrix = camera->projectionMatrix()*camera->cameraMatrix();
template<UnsignedInt dimensions> void ShapeRenderer<dimensions>::draw(const typename DimensionTraits<dimensions, Float>::MatrixType&, SceneGraph::AbstractCamera<dimensions, Float>& camera) {
typename DimensionTraits<dimensions, Float>::MatrixType projectionMatrix = camera.projectionMatrix()*camera.cameraMatrix();
for(auto it = renderers.begin(); it != renderers.end(); ++it)
(*it)->draw(options, projectionMatrix);
}

32
src/DebugTools/ShapeRenderer.h

@ -46,7 +46,7 @@ template<UnsignedInt> class ShapeRenderer;
namespace Implementation {
template<UnsignedInt> class AbstractShapeRenderer;
template<UnsignedInt dimensions> void createDebugMesh(ShapeRenderer<dimensions>* renderer, const Shapes::Implementation::AbstractShape<dimensions>* shape);
template<UnsignedInt dimensions> void createDebugMesh(ShapeRenderer<dimensions>& renderer, const Shapes::Implementation::AbstractShape<dimensions>& shape);
}
/**
@ -73,13 +73,13 @@ class ShapeRendererOptions {
/**
* @brief Set shape rendering mode
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is @ref RenderMode "RenderMode::Wireframe".
*/
ShapeRendererOptions* setRenderMode(RenderMode mode) {
ShapeRendererOptions& setRenderMode(RenderMode mode) {
_renderMode = mode;
return this;
return *this;
}
/** @brief Color of rendered shape */
@ -87,13 +87,13 @@ class ShapeRendererOptions {
/**
* @brief Set color of rendered shape
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is 100% opaque white.
*/
ShapeRendererOptions* setColor(const Color4& color) {
ShapeRendererOptions& setColor(const Color4& color) {
_color = color;
return this;
return *this;
}
/** @brief Point size */
@ -101,14 +101,14 @@ class ShapeRendererOptions {
/**
* @brief Set point size
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Size of rendered crosshairs, representing Shapes::Point shapes.
* Default is `0.25f`.
*/
ShapeRendererOptions* setPointSize(Float size) {
ShapeRendererOptions& setPointSize(Float size) {
_pointSize = size;
return this;
return *this;
}
private:
@ -128,8 +128,8 @@ Visualizes collision shapes using wireframe primitives. See
Example code:
@code
// Create some options
DebugTools::ResourceManager::instance()->set("red", (new DebugTools::ShapeRendererOptions)
->setColor({1.0f, 0.0f, 0.0f}));
DebugTools::ResourceManager::instance()->set("red",
DebugTools::ShapeRendererOptions().setColor({1.0f, 0.0f, 0.0f}));
// Create debug renderer for given shape, use "red" options for it
Shapes::AbstractShape2D* shape;
@ -138,8 +138,8 @@ new DebugTools::ShapeRenderer2D(shape, "red", debugDrawables);
@see ShapeRenderer2D, ShapeRenderer3D
*/
template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ShapeRenderer: public SceneGraph::BasicDrawable<dimensions, Float> {
friend void Implementation::createDebugMesh<>(ShapeRenderer<dimensions>*, const Shapes::Implementation::AbstractShape<dimensions>*);
template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ShapeRenderer: public SceneGraph::Drawable<dimensions, Float> {
friend void Implementation::createDebugMesh<>(ShapeRenderer<dimensions>&, const Shapes::Implementation::AbstractShape<dimensions>&);
public:
/**
@ -154,13 +154,13 @@ template<UnsignedInt dimensions> class MAGNUM_DEBUGTOOLS_EXPORT ShapeRenderer: p
* @p shape must be available for the whole lifetime of the renderer
* and if it is group, it must not change its internal structure.
*/
explicit ShapeRenderer(Shapes::AbstractShape<dimensions>* shape, ResourceKey options = ResourceKey(), SceneGraph::BasicDrawableGroup<dimensions, Float>* drawables = nullptr);
explicit ShapeRenderer(Shapes::AbstractShape<dimensions>& shape, ResourceKey options = ResourceKey(), SceneGraph::DrawableGroup<dimensions, Float>* drawables = nullptr);
~ShapeRenderer();
protected:
/** @todoc Remove Float when Doxygen properly treats this as override */
void draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractBasicCamera<dimensions, Float>* camera) override;
void draw(const typename DimensionTraits<dimensions, Float>::MatrixType& transformationMatrix, SceneGraph::AbstractCamera<dimensions, Float>& camera) override;
private:
Resource<ShapeRendererOptions> options;

13
src/DefaultFramebuffer.cpp

@ -37,13 +37,14 @@ DefaultFramebuffer defaultFramebuffer;
DefaultFramebuffer::DefaultFramebuffer() { _id = 0; }
#ifndef MAGNUM_TARGET_GLES2
DefaultFramebuffer* DefaultFramebuffer::mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments) {
DefaultFramebuffer& DefaultFramebuffer::mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments) {
/* Max attachment location */
std::size_t max = 0;
for(auto it = attachments.begin(); it != attachments.end(); ++it)
if(it->first > max) max = it->first;
/* Create linear array from associative */
/** @todo C++14: use VLA to avoid heap allocation */
GLenum* _attachments = new GLenum[max+1];
std::fill_n(_attachments, max, GL_NONE);
for(auto it = attachments.begin(); it != attachments.end(); ++it)
@ -51,11 +52,12 @@ DefaultFramebuffer* DefaultFramebuffer::mapForDraw(std::initializer_list<std::pa
(this->*drawBuffersImplementation)(max+1, _attachments);
delete[] _attachments;
return this;
return *this;
}
#endif
void DefaultFramebuffer::invalidate(std::initializer_list<InvalidationAttachment> attachments) {
/** @todo C++14: use VLA to avoid heap allocation */
GLenum* _attachments = new GLenum[attachments.size()];
for(std::size_t i = 0; i != attachments.size(); ++i)
_attachments[i] = GLenum(*(attachments.begin()+i));
@ -66,6 +68,7 @@ void DefaultFramebuffer::invalidate(std::initializer_list<InvalidationAttachment
}
void DefaultFramebuffer::invalidate(std::initializer_list<InvalidationAttachment> attachments, const Rectanglei& rectangle) {
/** @todo C++14: use VLA to avoid heap allocation */
GLenum* _attachments = new GLenum[attachments.size()];
for(std::size_t i = 0; i != attachments.size(); ++i)
_attachments[i] = GLenum(*(attachments.begin()+i));
@ -75,8 +78,8 @@ void DefaultFramebuffer::invalidate(std::initializer_list<InvalidationAttachment
delete[] _attachments;
}
void DefaultFramebuffer::initializeContextBasedFunctionality(Context* context) {
Implementation::FramebufferState* state = context->state()->framebuffer;
void DefaultFramebuffer::initializeContextBasedFunctionality(Context& context) {
Implementation::FramebufferState* state = context.state().framebuffer;
/* Initial framebuffer size */
GLint viewport[4];
@ -85,7 +88,7 @@ void DefaultFramebuffer::initializeContextBasedFunctionality(Context* context) {
/* Fake initial glViewport() call for ApiTrace */
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::GREMEDY::string_marker>())
if(context.isExtensionSupported<Extensions::GL::GREMEDY::string_marker>())
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
#endif
}

24
src/DefaultFramebuffer.h

@ -58,7 +58,7 @@ any drawing in your @ref Platform::GlutApplication::drawEvent() "drawEvent()"
implementation, for example:
@code
void drawEvent() {
defaultFramebuffer.clear(AbstractFramebuffer::Clear::Color|AbstractFramebuffer::Clear::Depth);
defaultFramebuffer.clear(FramebufferClear::Color|FramebufferClear::Depth);
// ...
}
@ -309,7 +309,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Map shader outputs to buffer attachment
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* @p attachments is list of shader outputs mapped to buffer
* attachments. %Shader outputs which are not listed are not used, you
@ -328,12 +328,12 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
* @requires_gles30 Draw attachments for default framebuffer are
* available only in OpenGL ES 3.0.
*/
DefaultFramebuffer* mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments);
DefaultFramebuffer& mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments);
/**
* @brief Map shader output to buffer attachment
* @param attachment %Buffer attachment
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Similar to above function, can be used in cases when shader has
* only one (unnamed) output.
@ -347,16 +347,16 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
* @requires_gles30 Draw attachments for default framebuffer are
* available only in OpenGL ES 3.0.
*/
DefaultFramebuffer* mapForDraw(DrawAttachment attachment) {
DefaultFramebuffer& mapForDraw(DrawAttachment attachment) {
(this->*drawBufferImplementation)(static_cast<GLenum>(attachment));
return this;
return *this;
}
#endif
/**
* @brief Map given attachment for reading
* @param attachment %Buffer attachment
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* framebuffer is not currently bound, it is bound before the
@ -365,9 +365,9 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
* @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access}
* @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer}
*/
DefaultFramebuffer* mapForRead(ReadAttachment attachment) {
DefaultFramebuffer& mapForRead(ReadAttachment attachment) {
(this->*readBufferImplementation)(static_cast<GLenum>(attachment));
return this;
return *this;
}
/**
@ -403,14 +403,14 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
DefaultFramebuffer* setViewport(const Rectanglei& rectangle) {
DefaultFramebuffer& setViewport(const Rectanglei& rectangle) {
AbstractFramebuffer::setViewport(rectangle);
return this;
return *this;
}
#endif
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
};
/** @brief Default framebuffer instance */

13
src/Extensions.h

@ -153,10 +153,21 @@ namespace GL {
_extension(GL,ARB,texture_buffer_range, GL210, GL430) // #139
_extension(GL,ARB,texture_query_levels, GL300, GL430) // #140
_extension(GL,ARB,texture_storage_multisample, GL210, GL430) // #141
_extension(GL,ARB,buffer_storage, /*?*/ GL430, GL440) // #144
_extension(GL,ARB,clear_texture, GL210, GL440) // #145
_extension(GL,ARB,enhanced_layouts, GL310, GL440) // #146
_extension(GL,ARB,multi_bind, GL300, GL440) // #147
_extension(GL,ARB,query_buffer_object, GL210, GL440) // #148
_extension(GL,ARB,texture_mirror_clamp_to_edge, GL210, GL440) // #149
_extension(GL,ARB,texture_stencil8, GL210, GL440) // #150
_extension(GL,ARB,vertex_type_10f_11f_11f_rev, GL300, GL440) // #151
} namespace ATI {
_extension(GL,ATI,texture_mirror_once, GL210, None) // #221
} namespace EXT {
_extension(GL,EXT,texture_filter_anisotropic, GL210, None) // #187
/* EXT_framebuffer_object, EXT_packed_depth_stencil, EXT_framebuffer_blit,
EXT_framebuffer_multisample replaced with ARB_framebuffer_object */
_extension(GL,EXT,texture_mirror_clamp, GL210, None) // #298
_extension(GL,EXT,gpu_shader4, GL210, GL300) // #326
_extension(GL,EXT,packed_float, GL210, GL300) // #328
_extension(GL,EXT,texture_array, GL210, GL300) // #329
@ -181,7 +192,7 @@ namespace GL {
_extension(GL,NV,conditional_render, GL210, GL300) // #346
/* NV_draw_texture not supported */ // #430
}
/* IMPORTANT: if this line is > 188 (57 + size), don't forget to update array size in Context.h */
/* IMPORTANT: if this line is > 226 (66 + size), don't forget to update array size in Context.h */
#else
#line 1
namespace ANGLE {

43
src/Framebuffer.cpp

@ -60,20 +60,21 @@ Framebuffer::Framebuffer(const Rectanglei& viewport) {
Framebuffer::~Framebuffer() {
/* If bound, remove itself from state */
Implementation::FramebufferState* state = Context::current()->state()->framebuffer;
Implementation::FramebufferState* state = Context::current()->state().framebuffer;
if(state->readBinding == _id) state->readBinding = 0;
if(state->drawBinding == _id) state->drawBinding = 0;
glDeleteFramebuffers(1, &_id);
}
Framebuffer* Framebuffer::mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments) {
Framebuffer& Framebuffer::mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments) {
/* Max attachment location */
std::size_t max = 0;
for(auto it = attachments.begin(); it != attachments.end(); ++it)
if(it->first > max) max = it->first;
/* Create linear array from associative */
/** @todo C++14: use VLA to avoid heap allocation */
GLenum* _attachments = new GLenum[max+1];
std::fill_n(_attachments, max, GL_NONE);
for(auto it = attachments.begin(); it != attachments.end(); ++it)
@ -81,10 +82,11 @@ Framebuffer* Framebuffer::mapForDraw(std::initializer_list<std::pair<UnsignedInt
(this->*drawBuffersImplementation)(max+1, _attachments);
delete[] _attachments;
return this;
return *this;
}
void Framebuffer::invalidate(std::initializer_list<InvalidationAttachment> attachments) {
/** @todo C++14: use VLA to avoid heap allocation */
GLenum* _attachments = new GLenum[attachments.size()];
for(std::size_t i = 0; i != attachments.size(); ++i)
_attachments[i] = GLenum(*(attachments.begin()+i));
@ -95,6 +97,7 @@ void Framebuffer::invalidate(std::initializer_list<InvalidationAttachment> attac
}
void Framebuffer::invalidate(std::initializer_list<InvalidationAttachment> attachments, const Rectanglei& rectangle) {
/** @todo C++14: use VLA to avoid heap allocation */
GLenum* _attachments = new GLenum[attachments.size()];
for(std::size_t i = 0; i != attachments.size(); ++i)
_attachments[i] = GLenum(*(attachments.begin()+i));
@ -104,15 +107,15 @@ void Framebuffer::invalidate(std::initializer_list<InvalidationAttachment> attac
delete[] _attachments;
}
Framebuffer* Framebuffer::attachTexture2D(BufferAttachment attachment, Texture2D* texture, Int mipLevel) {
Framebuffer& Framebuffer::attachTexture2D(BufferAttachment attachment, Texture2D& texture, Int mipLevel) {
/** @todo Check for texture target compatibility */
(this->*texture2DImplementation)(attachment, GLenum(texture->target()), texture->id(), mipLevel);
return this;
(this->*texture2DImplementation)(attachment, GLenum(texture.target()), texture.id(), mipLevel);
return *this;
}
void Framebuffer::initializeContextBasedFunctionality(Context* context) {
void Framebuffer::initializeContextBasedFunctionality(Context& context) {
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "Framebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA;
@ -125,21 +128,21 @@ void Framebuffer::initializeContextBasedFunctionality(Context* context) {
#endif
}
void Framebuffer::renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer* renderbuffer) {
glFramebufferRenderbuffer(GLenum(bindInternal()), GLenum(attachment), GL_RENDERBUFFER, renderbuffer->id());
void Framebuffer::renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer& renderbuffer) {
glFramebufferRenderbuffer(GLenum(bindInternal()), GLenum(attachment), GL_RENDERBUFFER, renderbuffer.id());
}
#ifndef MAGNUM_TARGET_GLES
void Framebuffer::renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer* renderbuffer) {
glNamedFramebufferRenderbufferEXT(_id, GLenum(attachment), GL_RENDERBUFFER, renderbuffer->id());
void Framebuffer::renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer& renderbuffer) {
glNamedFramebufferRenderbufferEXT(_id, GLenum(attachment), GL_RENDERBUFFER, renderbuffer.id());
}
void Framebuffer::texture1DImplementationDefault(BufferAttachment attachment, Texture1D* texture, GLint mipLevel) {
glFramebufferTexture1D(GLenum(bindInternal()), GLenum(attachment), static_cast<GLenum>(texture->target()), texture->id(), mipLevel);
void Framebuffer::texture1DImplementationDefault(BufferAttachment attachment, Texture1D& texture, GLint mipLevel) {
glFramebufferTexture1D(GLenum(bindInternal()), GLenum(attachment), static_cast<GLenum>(texture.target()), texture.id(), mipLevel);
}
void Framebuffer::texture1DImplementationDSA(BufferAttachment attachment, Texture1D* texture, GLint mipLevel) {
glNamedFramebufferTexture1DEXT(_id, GLenum(attachment), GLenum(texture->target()), texture->id(), mipLevel);
void Framebuffer::texture1DImplementationDSA(BufferAttachment attachment, Texture1D& texture, GLint mipLevel) {
glNamedFramebufferTexture1DEXT(_id, GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel);
}
#endif
@ -153,11 +156,11 @@ void Framebuffer::texture2DImplementationDSA(BufferAttachment attachment, GLenum
}
#endif
void Framebuffer::texture3DImplementationDefault(BufferAttachment attachment, Texture3D* texture, GLint mipLevel, GLint layer) {
void Framebuffer::texture3DImplementationDefault(BufferAttachment attachment, Texture3D& texture, GLint mipLevel, GLint layer) {
/** @todo Check for texture target compatibility */
/** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */
#ifndef MAGNUM_TARGET_GLES
glFramebufferTexture3D(GLenum(bindInternal()), GLenum(attachment), static_cast<GLenum>(texture->target()), texture->id(), mipLevel, layer);
glFramebufferTexture3D(GLenum(bindInternal()), GLenum(attachment), static_cast<GLenum>(texture.target()), texture.id(), mipLevel, layer);
#else
static_cast<void>(attachment);
static_cast<void>(texture);
@ -167,8 +170,8 @@ void Framebuffer::texture3DImplementationDefault(BufferAttachment attachment, Te
}
#ifndef MAGNUM_TARGET_GLES
void Framebuffer::texture3DImplementationDSA(BufferAttachment attachment, Texture3D* texture, GLint mipLevel, GLint layer) {
glNamedFramebufferTexture3DEXT(_id, GLenum(attachment), GLenum(texture->target()), texture->id(), mipLevel, layer);
void Framebuffer::texture3DImplementationDSA(BufferAttachment attachment, Texture3D& texture, GLint mipLevel, GLint layer) {
glNamedFramebufferTexture3DEXT(_id, GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel, layer);
}
#endif

84
src/Framebuffer.h

@ -55,9 +55,9 @@ Renderbuffer depthStencil;
// configure the textures and allocate texture memory...
framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), &color);
framebuffer.attachTexture2D(Framebuffer::ColorAttachment(1), &normal);
framebuffer.attachRenderbuffer(Framebuffer::BufferAttachment::DepthStencil, &depthStencil);
framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), color);
framebuffer.attachTexture2D(Framebuffer::ColorAttachment(1), normal);
framebuffer.attachRenderbuffer(Framebuffer::BufferAttachment::DepthStencil, depthStencil);
@endcode
Then you need to map outputs of your shader to color attachments in the
@ -73,13 +73,13 @@ off-screen framebuffer, then bind the default and render the textures on
screen:
@code
void drawEvent() {
defaultFramebuffer.clear(DefaultFramebuffer::Clear::Color)
framebuffer.clear(Framebuffer::Clear::Color|Framebuffer::Clear::Depth|Framebuffer::Clear::Stencil);
defaultFramebuffer.clear(FramebufferClear::Color)
framebuffer.clear(FramebufferClear::Color|FramebufferClear::Depth|FramebufferClear::Stencil);
framebuffer.bind(Framebuffer::Target::Draw);
framebuffer.bind(FramebufferTarget::Draw);
// ...
defaultFramebuffer.bind(DefaultFramebuffer::Target::Draw);
defaultFramebuffer.bind(Framebuffer::Target::Draw);
// ...
}
@endcode
@ -320,7 +320,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
/**
* @brief Map shader output to attachments
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* @p attachments is list of shader outputs mapped to framebuffer
* color attachment IDs. %Shader outputs which are not listed are not
@ -338,12 +338,12 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access}
* @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers}
*/
Framebuffer* mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments);
Framebuffer& mapForDraw(std::initializer_list<std::pair<UnsignedInt, DrawAttachment>> attachments);
/**
* @brief Map shader output to attachment
* @param attachment Draw attachment
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Similar to above function, can be used in cases when shader has
* only one (unnamed) output.
@ -356,9 +356,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @fn_gl{DrawBuffers} in OpenGL ES 3.0
* @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers}
*/
Framebuffer* mapForDraw(DrawAttachment attachment) {
Framebuffer& mapForDraw(DrawAttachment attachment) {
(this->*drawBufferImplementation)(GLenum(attachment));
return this;
return *this;
}
/**
@ -395,7 +395,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
/**
* @brief Map given color attachment for reading
* @param attachment Color attachment
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* framebufferbuffer is not currently bound, it is bound before the
@ -404,16 +404,16 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access}
* @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer}
*/
Framebuffer* mapForRead(ColorAttachment attachment) {
Framebuffer& mapForRead(ColorAttachment attachment) {
(this->*readBufferImplementation)(GLenum(attachment));
return this;
return *this;
}
/**
* @brief Attach renderbuffer to given buffer
* @param attachment %Buffer attachment
* @param renderbuffer %Renderbuffer
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* framebufferbuffer is not currently bound, it is bound before the
@ -421,9 +421,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or
* @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access}
*/
Framebuffer* attachRenderbuffer(BufferAttachment attachment, Renderbuffer* renderbuffer) {
Framebuffer& attachRenderbuffer(BufferAttachment attachment, Renderbuffer& renderbuffer) {
(this->*renderbufferImplementation)(attachment, renderbuffer);
return this;
return *this;
}
#ifndef MAGNUM_TARGET_GLES
@ -432,7 +432,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @param attachment %Buffer attachment
* @param texture 1D texture
* @param level Mip level
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* framebufferbuffer is not currently bound, it is bound before the
@ -441,9 +441,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access}
* @requires_gl Only 2D and 3D textures are available in OpenGL ES.
*/
Framebuffer* attachTexture1D(BufferAttachment attachment, Texture1D* texture, Int level) {
Framebuffer& attachTexture1D(BufferAttachment attachment, Texture1D& texture, Int level) {
(this->*texture1DImplementation)(attachment, texture, level);
return this;
return *this;
}
#endif
@ -452,7 +452,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @param attachment %Buffer attachment
* @param texture 2D texture
* @param level Mip level
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* framebufferbuffer is not currently bound, it is bound before the
@ -460,7 +460,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture}
* or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access}
*/
Framebuffer* attachTexture2D(BufferAttachment attachment, Texture2D* texture, Int level);
Framebuffer& attachTexture2D(BufferAttachment attachment, Texture2D& texture, Int level);
/**
* @brief Attach cube map texture to given buffer
@ -468,7 +468,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @param texture Cube map texture
* @param coordinate Cube map coordinate
* @param level Mip level
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* framebufferbuffer is not currently bound, it is bound before the
@ -476,9 +476,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @see attachTexture2D(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture}
* or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access}
*/
Framebuffer* attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, Int level) {
(this->*texture2DImplementation)(attachment, GLenum(coordinate), texture->id(), level);
return this;
Framebuffer& attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture& texture, CubeMapTexture::Coordinate coordinate, Int level) {
(this->*texture2DImplementation)(attachment, GLenum(coordinate), texture.id(), level);
return *this;
}
/**
@ -487,7 +487,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @param texture 3D texture
* @param level Mip level
* @param layer Layer of 2D image within a 3D texture
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
* framebufferbuffer is not currently bound, it is bound before the
@ -496,34 +496,34 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
* @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access}
* @requires_es_extension %Extension @es_extension{OES,texture_3D}
*/
Framebuffer* attachTexture3D(BufferAttachment attachment, Texture3D* texture, Int level, Int layer) {
Framebuffer& attachTexture3D(BufferAttachment attachment, Texture3D& texture, Int level, Int layer) {
/** @todo Check for texture target compatibility */
(this->*texture3DImplementation)(attachment, texture, level, layer);
return this;
return *this;
}
/* Overloads to remove WTF-factor from method chaining order */
#ifndef DOXYGEN_GENERATING_OUTPUT
Framebuffer* setViewport(const Rectanglei& rectangle) {
Framebuffer& setViewport(const Rectanglei& rectangle) {
AbstractFramebuffer::setViewport(rectangle);
return this;
return *this;
}
#endif
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
typedef void(Framebuffer::*RenderbufferImplementation)(BufferAttachment, Renderbuffer*);
void MAGNUM_LOCAL renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer* renderbuffer);
typedef void(Framebuffer::*RenderbufferImplementation)(BufferAttachment, Renderbuffer&);
void MAGNUM_LOCAL renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer& renderbuffer);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer* renderbuffer);
void MAGNUM_LOCAL renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer& renderbuffer);
#endif
static RenderbufferImplementation renderbufferImplementation;
#ifndef MAGNUM_TARGET_GLES
typedef void(Framebuffer::*Texture1DImplementation)(BufferAttachment, Texture1D*, GLint);
void MAGNUM_LOCAL texture1DImplementationDefault(BufferAttachment attachment, Texture1D* texture, GLint level);
void MAGNUM_LOCAL texture1DImplementationDSA(BufferAttachment attachment, Texture1D* texture, GLint level);
typedef void(Framebuffer::*Texture1DImplementation)(BufferAttachment, Texture1D&, GLint);
void MAGNUM_LOCAL texture1DImplementationDefault(BufferAttachment attachment, Texture1D& texture, GLint level);
void MAGNUM_LOCAL texture1DImplementationDSA(BufferAttachment attachment, Texture1D& texture, GLint level);
static Texture1DImplementation texture1DImplementation;
#endif
@ -534,10 +534,10 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
#endif
static MAGNUM_LOCAL Texture2DImplementation texture2DImplementation;
typedef void(Framebuffer::*Texture3DImplementation)(BufferAttachment, Texture3D*, GLint, GLint);
void MAGNUM_LOCAL texture3DImplementationDefault(BufferAttachment attachment, Texture3D* texture, GLint level, GLint layer);
typedef void(Framebuffer::*Texture3DImplementation)(BufferAttachment, Texture3D&, GLint, GLint);
void MAGNUM_LOCAL texture3DImplementationDefault(BufferAttachment attachment, Texture3D& texture, GLint level, GLint layer);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL texture3DImplementationDSA(BufferAttachment attachment, Texture3D* texture, GLint level, GLint layer);
void MAGNUM_LOCAL texture3DImplementationDSA(BufferAttachment attachment, Texture3D& texture, GLint level, GLint layer);
#endif
static Texture3DImplementation texture3DImplementation;
};

2
src/Image.h

@ -133,7 +133,7 @@ template<UnsignedInt dimensions> inline Image<dimensions>& Image<dimensions>::op
}
template<UnsignedInt dimensions> inline Image<dimensions>::operator ImageReference<dimensions>() const {
return ImageReference<dimensions>(this->format(), this->type(), _size, _data);
return ImageReference<dimensions>(AbstractImage::format(), AbstractImage::type(), _size, _data);
}
}

7
src/ImageFormat.h

@ -223,8 +223,11 @@ enum class ImageFormat: GLenum {
#ifndef MAGNUM_TARGET_GLES3
/**
* Stencil index. For framebuffer reading only.
* @requires_es_extension %Extension @es_extension2{NV,read_stencil,GL_NV_read_depth_stencil}
* Stencil index.
* @requires_gl44 %Extension @extension{ARB,texture_stencil8} for texture
* data, otherwise for framebuffer reading only.
* @requires_es_extension %Extension @es_extension2{NV,read_stencil,GL_NV_read_depth_stencil},
* for framebuffer reading only.
* @todo Where to get GL_STENCIL_INDEX in ES?
*/
#ifndef MAGNUM_TARGET_GLES

7
src/Magnum.h

@ -431,4 +431,11 @@ class Timeline;
}
namespace std {
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class> struct hash;
#endif
template<> struct hash<Magnum::ResourceKey>;
}
#endif

2
src/Math/Complex.h

@ -150,7 +150,7 @@ template<class T> class Complex {
* @brief Whether the complex number is normalized
*
* Complex number is normalized if it has unit length: @f[
* |c|^2 = |c| = 1
* |c \cdot c - 1| < 2 \epsilon + \epsilon^2 \cong 2 \epsilon
* @f]
* @see dot(), normalized()
*/

23
src/Math/DualComplex.h

@ -133,6 +133,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* |c_0|^2 = |c_0| = 1
* @f]
* @see Complex::dot(), normalized()
* @todoc Improve the equation as in Complex::isNormalized()
*/
bool isNormalized() const {
return Implementation::isNormalizedSquared(lengthSquared());
@ -144,7 +145,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see Complex::angle()
*/
constexpr Complex<T> rotation() const {
return this->real();
return Dual<Complex<T>>::real();
}
/**
@ -156,7 +157,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see translation(const Vector2&)
*/
Vector2<T> translation() const {
return Vector2<T>(this->dual());
return Vector2<T>(Dual<Complex<T>>::dual());
}
/**
@ -165,7 +166,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see fromMatrix(), Complex::toMatrix()
*/
Matrix3<T> toMatrix() const {
return Matrix3<T>::from(this->real().toMatrix(), translation());
return Matrix3<T>::from(Dual<Complex<T>>::real().toMatrix(), translation());
}
/**
@ -177,7 +178,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todo can this be done similarly to dual quaternions?
*/
DualComplex<T> operator*(const DualComplex<T>& other) const {
return {this->real()*other.real(), this->real()*other.dual() + this->dual()};
return {Dual<Complex<T>>::real()*other.real(), Dual<Complex<T>>::real()*other.dual() + Dual<Complex<T>>::dual()};
}
/**
@ -189,7 +190,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see dualConjugated(), conjugated(), Complex::conjugated()
*/
DualComplex<T> complexConjugated() const {
return {this->real().conjugated(), this->dual().conjugated()};
return {Dual<Complex<T>>::real().conjugated(), Dual<Complex<T>>::dual().conjugated()};
}
/**
@ -214,7 +215,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* Dual::conjugated()
*/
DualComplex<T> conjugated() const {
return {this->real().conjugated(), {-this->dual().real(), this->dual().imaginary()}};
return {Dual<Complex<T>>::real().conjugated(), {-Dual<Complex<T>>::dual().real(), Dual<Complex<T>>::dual().imaginary()}};
}
/**
@ -227,7 +228,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todo Can this be done similarly to dual quaternins?
*/
T lengthSquared() const {
return this->real().dot();
return Dual<Complex<T>>::real().dot();
}
/**
@ -240,7 +241,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todo can this be done similarly to dual quaternions?
*/
T length() const {
return this->real().length();
return Dual<Complex<T>>::real().length();
}
/**
@ -253,7 +254,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todo can this be done similarly to dual quaternions?
*/
DualComplex<T> normalized() const {
return {this->real()/length(), this->dual()};
return {Dual<Complex<T>>::real()/length(), Dual<Complex<T>>::dual()};
}
/**
@ -266,7 +267,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todo can this be done similarly to dual quaternions?
*/
DualComplex<T> inverted() const {
return DualComplex<T>(this->real().inverted(), {{}, {}})*DualComplex<T>({}, -this->dual());
return DualComplex<T>(Dual<Complex<T>>::real().inverted(), {{}, {}})*DualComplex<T>({}, -Dual<Complex<T>>::dual());
}
/**
@ -279,7 +280,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todo can this be done similarly to dual quaternions?
*/
DualComplex<T> invertedNormalized() const {
return DualComplex<T>(this->real().invertedNormalized(), {{}, {}})*DualComplex<T>({}, -this->dual());
return DualComplex<T>(Dual<Complex<T>>::real().invertedNormalized(), {{}, {}})*DualComplex<T>({}, -Dual<Complex<T>>::dual());
}
/**

13
src/Math/DualQuaternion.h

@ -139,6 +139,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* |\hat q|^2 = |\hat q| = 1 + \epsilon 0
* @f]
* @see lengthSquared(), normalized()
* @todoc Improve the equation as in Quaternion::isNormalized()
*/
bool isNormalized() const {
/* Comparing dual part classically, as comparing sqrt() of it would
@ -154,7 +155,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see Quaternion::angle(), Quaternion::axis()
*/
constexpr Quaternion<T> rotation() const {
return this->real();
return Dual<Quaternion<T>>::real();
}
/**
@ -166,7 +167,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see translation(const Vector3&)
*/
Vector3<T> translation() const {
return (this->dual()*this->real().conjugated()).vector()*T(2);
return (Dual<Quaternion<T>>::dual()*Dual<Quaternion<T>>::real().conjugated()).vector()*T(2);
}
/**
@ -175,7 +176,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see fromMatrix(), Quaternion::toMatrix()
*/
Matrix4<T> toMatrix() const {
return Matrix4<T>::from(this->real().toMatrix(), translation());
return Matrix4<T>::from(Dual<Quaternion<T>>::real().toMatrix(), translation());
}
/**
@ -187,7 +188,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see dualConjugated(), conjugated(), Quaternion::conjugated()
*/
DualQuaternion<T> quaternionConjugated() const {
return {this->real().conjugated(), this->dual().conjugated()};
return {Dual<Quaternion<T>>::real().conjugated(), Dual<Quaternion<T>>::dual().conjugated()};
}
/**
@ -212,7 +213,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* Dual::conjugated()
*/
DualQuaternion<T> conjugated() const {
return {this->real().conjugated(), {this->dual().vector(), -this->dual().scalar()}};
return {Dual<Quaternion<T>>::real().conjugated(), {Dual<Quaternion<T>>::dual().vector(), -Dual<Quaternion<T>>::dual().scalar()}};
}
/**
@ -224,7 +225,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f]
*/
Dual<T> lengthSquared() const {
return {this->real().dot(), T(2)*Quaternion<T>::dot(this->real(), this->dual())};
return {Dual<Quaternion<T>>::real().dot(), T(2)*Quaternion<T>::dot(Dual<Quaternion<T>>::real(), Dual<Quaternion<T>>::dual())};
}
/**

24
src/Math/Functions.h

@ -279,7 +279,7 @@ template<std::size_t size, class T> Vector<size, T> clamp(const Vector<size, T>&
The interpolation for vectors is done as in following, similarly for scalars: @f[
\boldsymbol v_{LERP} = (1 - t) \boldsymbol v_A + t \boldsymbol v_B
@f]
@see Quaternion::lerp()
@see lerpInverted(), Quaternion::lerp()
@todo http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
(when SIMD is in place)
*/
@ -294,6 +294,28 @@ template<std::size_t size, class T, class U> inline Vector<size, T> lerp(const V
}
#endif
/**
@brief Inverse linear interpolation of two values
@param a First value
@param b Second value
@param lerp Interpolated value
Returns interpolation phase *t*: @f[
t = \frac{\boldsymbol v_{LERP} - \boldsymbol v_A}{\boldsymbol v_B - \boldsymbol v_A}
@f]
@see lerp()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class T> inline T lerpInverted(const T& a, const T& b, const T& lerp);
#else
template<class T> inline T lerpInverted(T a, T b, T lerp) {
return (lerp - a)/(b - a);
}
template<std::size_t size, class T, class U> inline Vector<size, T> lerpInverted(const Vector<size, T>& a, const Vector<size, T>& b, const Vector<size, T>& lerp) {
return (lerp - a)/(b - a);
}
#endif
/**
@brief Fused multiply-add

4
src/Math/Matrix.h

@ -125,7 +125,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* tr(A) = \sum_{i=1}^n a_{i,i}
* @f]
*/
T trace() const { return this->diagonal().sum(); }
T trace() const { return RectangularMatrix<size, size, T>::diagonal().sum(); }
/** @brief %Matrix without given column and row */
Matrix<size-1, T> ij(std::size_t skipCol, std::size_t skipRow) const;
@ -166,7 +166,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
Matrix<size, T> invertedOrthogonal() const {
CORRADE_ASSERT(isOrthogonal(),
"Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {});
return this->transposed();
return RectangularMatrix<size, size, T>::transposed();
}
#ifndef DOXYGEN_GENERATING_OUTPUT

24
src/Math/Matrix3.h

@ -167,20 +167,36 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @brief 2D rotation and scaling part of the matrix
*
* Upper-left 2x2 part of the matrix.
* @see from(const Matrix<2, T>&, const Vector2&), rotation() const,
* rotation(T), Matrix4::rotationScaling() const
* @todo extract rotation with assert for no scaling
* @see from(const Matrix<2, T>&, const Vector2&), rotation() const
* rotationNormalized(), rotation(T),
* Matrix4::rotationScaling() const
*/
constexpr Matrix<2, T> rotationScaling() const {
return {(*this)[0].xy(),
(*this)[1].xy()};
}
/**
* @brief 2D rotation part of the matrix assuming there is no scaling
*
* Similar to @ref rotationScaling(), but additionally checks that the
* base vectors are normalized.
* @see rotation() const, @ref Matrix4::rotationNormalized()
* @todo assert also orthogonality or this is good enough?
*/
Matrix<2, T> rotationNormalized() const {
CORRADE_ASSERT((*this)[0].xy().isNormalized() && (*this)[1].xy().isNormalized(),
"Math::Matrix3::rotationNormalized(): the rotation part is not normalized", {});
return {(*this)[0].xy(),
(*this)[1].xy()};
}
/**
* @brief 2D rotation part of the matrix
*
* Normalized upper-left 2x2 part of the matrix.
* @see rotationScaling() const, rotation(T), Matrix4::rotation() const
* @see rotationNormalized(), rotationScaling() const, rotation(T),
* Matrix4::rotation() const
* @todo assert uniform scaling (otherwise this would be garbage)
*/
Matrix<2, T> rotation() const {

25
src/Math/Matrix4.h

@ -231,8 +231,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
*
* Upper-left 3x3 part of the matrix.
* @see from(const Matrix<3, T>&, const Vector3&), rotation() const,
* rotation(T, const Vector3&), Matrix3::rotationScaling() const
* @todo extract rotation with assert for no scaling
* rotationNormalized(), rotation(T, const Vector3&),
* Matrix3::rotationScaling() const
*/
/* Not Matrix3, because it is for affine 2D transformations */
constexpr Matrix<3, T> rotationScaling() const {
@ -241,12 +241,29 @@ template<class T> class Matrix4: public Matrix<4, T> {
(*this)[2].xyz()};
}
/**
* @brief 3D rotation part of the matrix assuming there is no scaling
*
* Similar to @ref rotationScaling(), but additionally checks that the
* base vectors are normalized.
* @see rotation() const, @ref Matrix3::rotationNormalized()
* @todo assert also orthogonality or this is good enough?
*/
/* Not Matrix3, because it is for affine 2D transformations */
Matrix<3, T> rotationNormalized() const {
CORRADE_ASSERT((*this)[0].xyz().isNormalized() && (*this)[1].xyz().isNormalized() && (*this)[2].xyz().isNormalized(),
"Math::Matrix4::rotationNormalized(): the rotation part is not normalized", {});
return {(*this)[0].xyz(),
(*this)[1].xyz(),
(*this)[2].xyz()};
}
/**
* @brief 3D rotation part of the matrix
*
* Normalized upper-left 3x3 part of the matrix.
* @see rotationScaling() const, rotation(T, const Vector3&),
* Matrix3::rotation() const
* @see rotationNormalized(), rotationScaling() const,
* rotation(T, const Vector3&), Matrix3::rotation() const
* @todo assert uniform scaling (otherwise this would be garbage)
*/
/* Not Matrix3, because it is for affine 2D transformations */

2
src/Math/Quaternion.h

@ -164,7 +164,7 @@ template<class T> class Quaternion {
* @brief Whether the quaternion is normalized
*
* Quaternion is normalized if it has unit length: @f[
* |q|^2 = |q| = 1
* |q \cdot q - 1| < 2 \epsilon + \epsilon^2 \cong 2 \epsilon
* @f]
* @see dot(), normalized()
*/

15
src/Math/Test/FunctionsTest.cpp

@ -43,6 +43,7 @@ class FunctionsTest: public Corrade::TestSuite::Tester {
void sqrtInverted();
void clamp();
void lerp();
void lerpInverted();
void fma();
void normalizeUnsigned();
void normalizeSigned();
@ -79,6 +80,7 @@ FunctionsTest::FunctionsTest() {
&FunctionsTest::sqrtInverted,
&FunctionsTest::clamp,
&FunctionsTest::lerp,
&FunctionsTest::lerpInverted,
&FunctionsTest::fma,
&FunctionsTest::normalizeUnsigned,
&FunctionsTest::normalizeSigned,
@ -166,6 +168,19 @@ void FunctionsTest::lerp() {
Vector3ub c(0, 128, 64);
Vector3ub d(16, 0, 32);
CORRADE_COMPARE(Math::lerp(c, d, 0.25f), Vector3ub(4, 96, 56));
/* Vector as interpolation phase */
CORRADE_COMPARE(Math::lerp(a, b, Vector3(0.25f, 0.5f, 0.75f)), Vector3(0.0f, 0.0f, 9.0f));
}
void FunctionsTest::lerpInverted() {
/* Floating-point scalar */
CORRADE_COMPARE(Math::lerpInverted(2.0f, 5.0f, 3.5f), 0.5f);
/* Floating-point vector */
Vector3 a(-1.0f, 2.0f, 3.0f);
Vector3 b(3.0f, -2.0f, 11.0f);
CORRADE_COMPARE(Math::lerpInverted(a, b, Vector3(0.0f, 0.0f, 9.0f)), Vector3(0.25f, 0.5f, 0.75f));
}
void FunctionsTest::fma() {

20
src/Math/Test/Matrix3Test.cpp

@ -76,6 +76,7 @@ class Matrix3Test: public Corrade::TestSuite::Tester {
void projection();
void fromParts();
void rotationScalingPart();
void rotationNormalizedPart();
void rotationPart();
void vectorParts();
void invertedRigid();
@ -110,6 +111,7 @@ Matrix3Test::Matrix3Test() {
&Matrix3Test::projection,
&Matrix3Test::fromParts,
&Matrix3Test::rotationScalingPart,
&Matrix3Test::rotationNormalizedPart,
&Matrix3Test::rotationPart,
&Matrix3Test::vectorParts,
&Matrix3Test::invertedRigid,
@ -290,6 +292,24 @@ void Matrix3Test::rotationScalingPart() {
Vector2(4.0f, 4.0f)));
}
void Matrix3Test::rotationNormalizedPart() {
std::ostringstream o;
Error::setOutput(&o);
Matrix3 a({1.0f, 0.0f, 8.0f},
{1.0f, 0.1f, 7.0f},
{7.0f, -1.0f, 8.0f});
a.rotationNormalized();
CORRADE_COMPARE(o.str(), "Math::Matrix3::rotationNormalized(): the rotation part is not normalized\n");
Matrix3 b({ 0.965926f, 0.258819f, 1.0f},
{-0.258819f, 0.965926f, 3.0f},
{ 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(b.rotationNormalized(), Matrix2(Vector2( 0.965926f, 0.258819f),
Vector2(-0.258819f, 0.965926f)));
}
void Matrix3Test::rotationPart() {
Matrix3 rotation = Matrix3::rotation(Deg(15.0f));
Matrix2 expectedRotationPart(Vector2( 0.965926f, 0.258819f),

22
src/Math/Test/Matrix4Test.cpp

@ -83,6 +83,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester {
void perspectiveProjectionFov();
void fromParts();
void rotationScalingPart();
void rotationNormalizedPart();
void rotationPart();
void vectorParts();
void invertedRigid();
@ -122,6 +123,7 @@ Matrix4Test::Matrix4Test() {
&Matrix4Test::perspectiveProjectionFov,
&Matrix4Test::fromParts,
&Matrix4Test::rotationScalingPart,
&Matrix4Test::rotationNormalizedPart,
&Matrix4Test::rotationPart,
&Matrix4Test::vectorParts,
&Matrix4Test::invertedRigid,
@ -373,6 +375,26 @@ void Matrix4Test::rotationScalingPart() {
Vector3(7.0f, -1.0f, 8.0f)));
}
void Matrix4Test::rotationNormalizedPart() {
std::ostringstream o;
Error::setOutput(&o);
Matrix4 a({0.0f, 0.0f, 1.0f, 4.0f},
{1.0f, 0.0f, 0.0f, 3.0f},
{0.0f, -1.0f, 0.1f, 0.0f},
{9.0f, 4.0f, 5.0f, 9.0f});
a.rotationNormalized();
CORRADE_COMPARE(o.str(), "Math::Matrix4::rotationNormalized(): the rotation part is not normalized\n");
Matrix4 b({ 0.35612214f, -0.80181062f, 0.47987163f, 1.0f},
{ 0.47987163f, 0.59757638f, 0.6423595f, 3.0f},
{-0.80181062f, 0.0015183985f, 0.59757638f, 4.0f},
{ 0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(b.rotationNormalized(), Matrix3(Vector3( 0.35612214f, -0.80181062f, 0.47987163f),
Vector3( 0.47987163f, 0.59757638f, 0.6423595f),
Vector3(-0.80181062f, 0.0015183985f, 0.59757638f)));
}
void Matrix4Test::rotationPart() {
Matrix4 rotation = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized());
Matrix3 expectedRotationPart(Vector3( 0.35612214f, -0.80181062f, 0.47987163f),

2
src/Math/Vector.h

@ -234,7 +234,7 @@ template<std::size_t size, class T> class Vector {
* @brief Whether the vector is normalized
*
* The vector is normalized if it has unit length: @f[
* |\boldsymbol a|^2 = |\boldsymbol a| = 1
* |\boldsymbol a \cdot \boldsymbol a - 1| < 2 \epsilon + \epsilon^2 \cong 2 \epsilon
* @f]
* @see dot(), normalized()
*/

12
src/Math/instantiation.cpp

@ -52,21 +52,33 @@ template struct ConfigurationValue<Magnum::Math::RectangularMatrix<3, 4, Magnum:
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<4, 3, Magnum::Double>>;
#endif
/* For some reason mingw's GCC instantiates ConfigurationValue<Magnum::Math::Geometry::Rectangle<...>>
(which depends on ConfigurationValue<Magnum::Math::Vector<4, ...>) before
these and then loudly complains about multiple definitions. WTF. */
template struct ConfigurationValue<Magnum::Math::Vector<2, Magnum::Float>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, Magnum::Float>>;
#ifndef _WIN32
template struct ConfigurationValue<Magnum::Math::Vector<4, Magnum::Float>>;
#endif
template struct ConfigurationValue<Magnum::Math::Vector<2, Magnum::Int>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, Magnum::Int>>;
#ifndef _WIN32
template struct ConfigurationValue<Magnum::Math::Vector<4, Magnum::Int>>;
#endif
template struct ConfigurationValue<Magnum::Math::Vector<2, Magnum::UnsignedInt>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, Magnum::UnsignedInt>>;
#ifndef _WIN32
template struct ConfigurationValue<Magnum::Math::Vector<4, Magnum::UnsignedInt>>;
#endif
#ifndef MAGNUM_TARGET_GLES
template struct ConfigurationValue<Magnum::Math::Vector<2, Magnum::Double>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, Magnum::Double>>;
#ifndef _WIN32
template struct ConfigurationValue<Magnum::Math::Vector<4, Magnum::Double>>;
#endif
#endif
#endif
}}

28
src/Mesh.cpp

@ -69,7 +69,7 @@ Mesh::Mesh(Primitive primitive): _primitive(primitive), _vertexCount(0), _indexC
Mesh::~Mesh() {
/* Remove current vao from the state */
GLuint& current = Context::current()->state()->mesh->currentVAO;
GLuint& current = Context::current()->state().mesh->currentVAO;
if(current == vao) current = 0;
(this->*destroyImplementation)();
@ -117,10 +117,10 @@ Mesh& Mesh::operator=(Mesh&& other) {
return *this;
}
Mesh* Mesh::setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end) {
Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end) {
#ifdef CORRADE_TARGET_NACL
CORRADE_ASSERT(buffer->targetHint() == Buffer::Target::ElementArray,
"Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer->targetHint(), this);
CORRADE_ASSERT(buffer.targetHint() == Buffer::Target::ElementArray,
"Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), this);
#endif
indexOffset = offset;
@ -133,7 +133,7 @@ Mesh* Mesh::setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type, Unsi
static_cast<void>(end);
#endif
(this->*bindIndexBufferImplementation)(buffer);
return this;
return *this;
}
void Mesh::draw() {
@ -162,7 +162,7 @@ void Mesh::draw() {
void Mesh::bindVAO(GLuint vao) {
/** @todo Get some extension wrangler instead to avoid linker errors to glBindVertexArray() on ES2 */
#ifndef MAGNUM_TARGET_GLES2
GLuint& current = Context::current()->state()->mesh->currentVAO;
GLuint& current = Context::current()->state().mesh->currentVAO;
if(current != vao) glBindVertexArray(current = vao);
#else
static_cast<void>(vao);
@ -191,16 +191,16 @@ void Mesh::vertexAttribPointer(const LongAttribute& attribute) {
#endif
#endif
void Mesh::initializeContextBasedFunctionality(Context* context) {
void Mesh::initializeContextBasedFunctionality(Context& context) {
/** @todo VAOs are in ES 3.0 and as extension in ES 2.0, enable them when some extension wrangler is available */
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::APPLE::vertex_array_object>()) {
if(context.isExtensionSupported<Extensions::GL::APPLE::vertex_array_object>()) {
Debug() << "Mesh: using" << Extensions::GL::APPLE::vertex_array_object::string() << "features";
createImplementation = &Mesh::createImplementationVAO;
destroyImplementation = &Mesh::destroyImplementationVAO;
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "Mesh: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
attributePointerImplementation = &Mesh::attributePointerImplementationDSA;
@ -299,18 +299,18 @@ void Mesh::attributePointerImplementationDSA(const LongAttribute& attribute) {
#endif
#endif
void Mesh::bindIndexBufferImplementationDefault(Buffer* buffer) {
indexBuffer = buffer;
void Mesh::bindIndexBufferImplementationDefault(Buffer& buffer) {
indexBuffer = &buffer;
}
void Mesh::bindIndexBufferImplementationVAO(Buffer* buffer) {
void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) {
bindVAO(vao);
/* Reset ElementArray binding to force explicit glBindBuffer call later */
/** @todo Do this cleaner way */
Context::current()->state()->buffer->bindings[Implementation::BufferState::indexForTarget(Buffer::Target::ElementArray)] = 0;
Context::current()->state().buffer->bindings[Implementation::BufferState::indexForTarget(Buffer::Target::ElementArray)] = 0;
buffer->bind(Buffer::Target::ElementArray);
buffer.bind(Buffer::Target::ElementArray);
}
void Mesh::bindImplementationDefault() {

173
src/Mesh.h

@ -57,9 +57,10 @@ conveniently compress the indices, fill the index buffer and configure the
mesh instead of calling setIndexCount() and setIndexBuffer() manually.
Note that neither vertex buffers nor index buffer is managed (e.g. deleted on
destruction) by the mesh, so you have to manage them on your own. On the other
hand it allows you to use one buffer for more meshes (each mesh for example
configured for different shader) or store data for more meshes in one buffer.
destruction) by the mesh, so you have to manage them on your own and ensure
that they are available for whole mesh lifetime. On the other hand it allows
you to use one buffer for more meshes (each mesh for example configured for
different shader) or store data for more meshes in one buffer.
If the mesh has non-zero index count, it is treated as indexed mesh, otherwise
it is treated as non-indexed mesh. If both index and vertex count is zero, the
@ -77,37 +78,37 @@ class MyShader: public AbstractShaderProgram {
// ...
};
Mesh* mesh;
Buffer* vertexBuffer;
Buffer vertexBuffer;
Mesh mesh;
// Fill vertex buffer with position data
static constexpr Vector3 positions[30] = {
// ...
};
vertexBuffer->setData(positions, Buffer::Usage::StaticDraw);
vertexBuffer.setData(positions, Buffer::Usage::StaticDraw);
// Set primitive and vertex count, add the buffer and specify its layout
mesh->setPrimitive(Mesh::Primitive::Triangles)
->setVertexCount(30)
->addVertexBuffer(vertexBuffer, 0, MyShader::Position());
mesh.setPrimitive(Mesh::Primitive::Triangles)
.setVertexCount(30)
.addVertexBuffer(vertexBuffer, 0, MyShader::Position());
@endcode
@subsubsection Mesh-configuration-examples-nonindexed-phong Interleaved vertex data
@code
// Non-indexed primitive with positions and normals
Primitives::Plane plane;
Mesh* mesh;
Buffer* vertexBuffer;
Trade::MeshData3D plane = Primitives::Plane::solid();
Buffer vertexBuffer;
Mesh mesh;
// Fill vertex buffer with interleaved position and normal data
MeshTools::interleave(mesh, buffer, Buffer::Usage::StaticDraw,
*plane.positions(0), *plane.normals(0));
plane.positions(0), plane.normals(0));
// Set primitive and specify layout of interleaved vertex buffer, vertex count
// has been already set by MeshTools::interleave()
mesh->setPrimitive(plane.primitive())
->addInterleavedVertexBuffer(buffer, 0,
mesh.setPrimitive(plane.primitive())
.addInterleavedVertexBuffer(buffer, 0,
Shaders::PhongShader::Position(),
Shaders::PhongShader::Normal());
@endcode
@ -122,46 +123,46 @@ class MyShader: public AbstractShaderProgram {
// ...
};
Buffer *vertexBuffer, *indexBuffer;
Mesh* mesh;
Buffer vertexBuffer, indexBuffer;
Mesh mesh;
// Fill vertex buffer with position data
static constexpr Vector3 positions[300] = {
// ...
};
vertexBuffer->setData(positions, Buffer::Usage::StaticDraw);
vertexBuffer.setData(positions, Buffer::Usage::StaticDraw);
// Fill index buffer with index data
static constexpr GLubyte indices[75] = {
// ...
};
indexBuffer->setData(indices, Buffer::Usage::StaticDraw);
indexBuffer.setData(indices, Buffer::Usage::StaticDraw);
// Set primitive, index count, specify the buffers
mesh->setPrimitive(Mesh::Primitive::Triangles)
->setIndexCount(75)
->addVertexBuffer(vertexBuffer, 0, MyShader::Position())
->setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 176, 229);
mesh.setPrimitive(Mesh::Primitive::Triangles)
.setIndexCount(75)
.addVertexBuffer(vertexBuffer, 0, MyShader::Position())
.setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 176, 229);
@endcode
@code
// Indexed primitive
Primitives::Cube cube;
Buffer *vertexBuffer, *indexBuffer;
Mesh* mesh;
Trade::MeshData3D cube = Primitives::Cube::solid();
Buffer vertexBuffer, indexBuffer;
Mesh mesh;
// Fill vertex buffer with interleaved position and normal data
MeshTools::interleave(mesh, vertexBuffer, Buffer::Usage::StaticDraw,
*cube.positions(0), *cube.normals(0));
cube.positions(0), cube.normals(0));
// Fill index buffer with compressed index data
MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw,
*cube.indices());
cube.indices());
// Set primitive and specify layout of interleaved vertex buffer. Index count
// and index buffer has been already specified by MeshTools::compressIndices().
mesh->setPrimitive(plane.primitive())
->addInterleavedVertexBuffer(vertexBuffer, 0,
mesh.setPrimitive(plane.primitive())
.addInterleavedVertexBuffer(vertexBuffer, 0,
Shaders::PhongShader::Position(),
Shaders::PhongShader::Normal());
@endcode
@ -177,23 +178,23 @@ class MyShader: public AbstractShaderProgram {
// ...
};
Mesh* mesh;
Mesh mesh;
// Fill position buffer with positions specified as two-component XY (i.e.,
// no Z component, which is meant to be always 0)
Buffer* positionBuffer;
Buffer positionBuffer;
Vector2 positions[30] = {
// ...
};
// Specify layout of positions buffer -- only two components, unspecified Z
// component will be automatically set to 0
mesh->addVertexBuffer(positionBuffer, 0,
mesh.addVertexBuffer(positionBuffer, 0,
MyShader::Position(MyShader::Position::Components::Two));
// Fill color buffer with colors specified as four-byte BGRA (e.g. directly
// from TGA file)
Buffer* colorBuffer;
Buffer colorBuffer;
GLubyte colors[4*30] = {
// ...
};
@ -201,7 +202,7 @@ colorBuffer.setData(colors, Buffer::Usage::StaticDraw);
// Specify layout of color buffer -- BGRA, each component unsigned byte and we
// want to normalize them from [0, 255] to [0.0f, 1.0f]
mesh->addVertexBuffer(colorBuffer, 0, MyShader::Color(
mesh.addVertexBuffer(colorBuffer, 0, MyShader::Color(
MyShader::Color::Components::BGRA,
MyShader::Color::DataType::UnsignedByte,
MyShader::Color::DataOption::Normalized));
@ -366,15 +367,15 @@ class MAGNUM_EXPORT Mesh {
/**
* @brief Set primitive type
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is @ref Primitive "Primitive::Triangles".
* @see setVertexCount(), addVertexBuffer(),
* addInterleavedVertexBuffer(), addVertexBufferStride()
*/
Mesh* setPrimitive(Primitive primitive) {
Mesh& setPrimitive(Primitive primitive) {
_primitive = primitive;
return this;
return *this;
}
/** @brief Vertex count */
@ -382,15 +383,15 @@ class MAGNUM_EXPORT Mesh {
/**
* @brief Set vertex count
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is zero.
* @see setPrimitive(), addVertexBuffer(), addInterleavedVertexBuffer(),
* addVertexBufferStride(), MeshTools::interleave()
*/
Mesh* setVertexCount(Int vertexCount) {
Mesh& setVertexCount(Int vertexCount) {
_vertexCount = vertexCount;
return this;
return *this;
}
/** @brief Index count */
@ -398,19 +399,19 @@ class MAGNUM_EXPORT Mesh {
/**
* @brief Set index count
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is zero.
* @see setIndexBuffer(), MeshTools::compressIndices()
*/
Mesh* setIndexCount(Int count) {
Mesh& setIndexCount(Int count) {
_indexCount = count;
return this;
return *this;
}
/**
* @brief Add buffer with non-interleaved vertex attributes for use with given shader
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Attribute list is combination of
* @ref AbstractShaderProgram::Attribute "attribute definitions"
@ -425,20 +426,20 @@ class MAGNUM_EXPORT Mesh {
* but it accepts only position and normal, so you have to skip the
* texture coordinate array:
* @code
* Mesh* mesh;
* Buffer* buffer;
* mesh->addVertexBuffer(buffer,
* Buffer buffer;
* Mesh mesh;
* mesh.addVertexBuffer(buffer,
* 35, // offset of the data
* Shaders::PhongShader::Position(), // position array
* sizeof(Vector2)*mesh->vertexCount(), // skip texture coordinate array
* sizeof(Vector2)*mesh.vertexCount(), // skip texture coordinate array
* Shaders::PhongShader::Normal()); // normal array
* @endcode
*
* Vou can also achieve the same effect by calling this function more
* times with absolute offsets:
* @code
* mesh->addVertexBuffer(buffer, 35, Shaders::PhongShader::Position());
* ->addVertexBuffer(buffer, 35 + (sizeof(Shaders::PhongShader::Position::Type) + sizeof(Vector2))*
* mesh.addVertexBuffer(buffer, 35, Shaders::PhongShader::Position());
* .addVertexBuffer(buffer, 35 + (sizeof(Shaders::PhongShader::Position::Type) + sizeof(Vector2))*
* mesh->vertexCount(), Shaders::PhongShader::Normal());
* @endcode
*
@ -457,11 +458,11 @@ class MAGNUM_EXPORT Mesh {
* @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access}
* if @extension{APPLE,vertex_array_object} is available
*/
template<class ...T> Mesh* addVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes);
template<class ...T> Mesh& addVertexBuffer(Buffer& buffer, GLintptr offset, const T&... attributes);
/**
* @brief Add buffer with interleaved vertex attributes for use with given shader
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Parameter @p offset is offset of the interleaved array from the
* beginning, attribute list is combination of
@ -478,9 +479,9 @@ class MAGNUM_EXPORT Mesh {
* position and normal, so you have to skip weight and texture
* coordinate in each vertex:
* @code
* Mesh* mesh;
* Buffer* buffer;
* mesh->addInterleavedVertexBuffer(buffer,
* Buffer buffer;
* Mesh mesh;
* mesh.addInterleavedVertexBuffer(buffer,
* 35, // skip other data
* sizeof(Float), // skip vertex weight
* Shaders::PhongShader::Position(), // vertex position
@ -498,9 +499,9 @@ class MAGNUM_EXPORT Mesh {
* sizeof(Vector2) +
* sizeof(Shaders::PhongShader::Normal::Type);
*
* mesh->addVertexBufferStride(buffer, 35 + sizeof(Float),
* mesh.addVertexBufferStride(buffer, 35 + sizeof(Float),
* stride, Shaders::PhongShader::Position());
* ->addVertexBufferStride(buffer, 35 + sizeof(Float) +
* .addVertexBufferStride(buffer, 35 + sizeof(Float) +
* sizeof(Shaders::PhongShader::Position::Type) + sizeof(Vector2),
* stride, Shaders::PhongShader::Normal());
* @endcode
@ -517,20 +518,20 @@ class MAGNUM_EXPORT Mesh {
* @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access}
* if @extension{APPLE,vertex_array_object} is available
*/
template<class ...T> inline Mesh* addInterleavedVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes) {
template<class ...T> inline Mesh& addInterleavedVertexBuffer(Buffer& buffer, GLintptr offset, const T&... attributes) {
addInterleavedVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), attributes...);
return this;
return *this;
}
/**
* @brief Add buffer with interleaved vertex attributes for use with given shader
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* See addInterleavedVertexBuffer() for more information.
*/
template<UnsignedInt location, class T> inline Mesh* addVertexBufferStride(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>& attribute) {
template<UnsignedInt location, class T> inline Mesh& addVertexBufferStride(Buffer& buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>& attribute) {
addInterleavedVertexBufferInternal(buffer, offset, stride, attribute);
return this;
return *this;
}
/**
@ -540,7 +541,7 @@ class MAGNUM_EXPORT Mesh {
* @param type Index data type
* @param start Minimum array index contained in the buffer
* @param end Maximum array index contained in the buffer
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* The smaller range is specified with @p start and @p end the less
* memory operations are needed (and possibly some optimizations),
@ -553,14 +554,14 @@ class MAGNUM_EXPORT Mesh {
* @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} (if
* @extension{APPLE,vertex_array_object} is available)
*/
Mesh* setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end);
Mesh& setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end);
/**
* @brief Set index buffer
* @param buffer Index buffer
* @param offset Offset into the buffer
* @param type Index data type
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Prefer to use setIndexBuffer(Buffer*, GLintptr, IndexType, UnsignedInt, UnsignedInt)
* for better performance.
@ -568,7 +569,7 @@ class MAGNUM_EXPORT Mesh {
* @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} (if
* @extension{APPLE,vertex_array_object} is available)
*/
Mesh* setIndexBuffer(Buffer* buffer, GLintptr offset, IndexType type) {
Mesh& setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type) {
return setIndexBuffer(buffer, offset, type, 0, 0);
}
@ -620,20 +621,20 @@ class MAGNUM_EXPORT Mesh {
#endif
#endif
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
/* Adding non-interleaved vertex attributes */
template<UnsignedInt location, class T, class ...U> inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
template<UnsignedInt location, class T, class ...U> inline void addVertexBufferInternal(Buffer& buffer, GLintptr offset, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
addVertexAttribute(buffer, attribute, offset, 0);
/* Add size of this attribute array to offset for next attribute */
addVertexBufferInternal(buffer, offset+attribute.dataSize()*_vertexCount, attributes...);
}
template<class ...T> inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, GLintptr gap, const T&... attributes) {
template<class ...T> inline void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLintptr gap, const T&... attributes) {
/* Add the gap to offset for next attribute */
addVertexBufferInternal(buffer, offset+gap, attributes...);
}
inline void addVertexBufferInternal(Buffer*, GLintptr) {}
inline void addVertexBufferInternal(Buffer&, GLintptr) {}
/* Computing stride of interleaved vertex attributes */
template<UnsignedInt location, class T, class ...U> inline static GLsizei strideOfInterleaved(const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
@ -645,22 +646,22 @@ class MAGNUM_EXPORT Mesh {
inline static GLsizei strideOfInterleaved() { return 0; }
/* Adding interleaved vertex attributes */
template<UnsignedInt location, class T, class ...U> inline void addInterleavedVertexBufferInternal(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
template<UnsignedInt location, class T, class ...U> inline void addInterleavedVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
addVertexAttribute(buffer, attribute, offset, stride);
/* Add size of this attribute to offset for next attribute */
addInterleavedVertexBufferInternal(buffer, offset+attribute.dataSize(), stride, attributes...);
}
template<class ...T> inline void addInterleavedVertexBufferInternal(Buffer* buffer, GLintptr offset, GLsizei stride, GLintptr gap, const T&... attributes) {
template<class ...T> inline void addInterleavedVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLintptr gap, const T&... attributes) {
/* Add the gap to offset for next attribute */
addInterleavedVertexBufferInternal(buffer, offset+gap, stride, attributes...);
}
inline void addInterleavedVertexBufferInternal(Buffer*, GLsizei, GLintptr) {}
inline void addInterleavedVertexBufferInternal(Buffer&, GLsizei, GLintptr) {}
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::Type, Float>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::Type, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
for(UnsignedInt i = 0; i != Implementation::Attribute<T>::vectorCount(); ++i)
(this->*attributePointerImplementation)(Attribute{
buffer,
&buffer,
location+i,
static_cast<GLint>(attribute.components()),
static_cast<GLenum>(attribute.dataType()),
@ -671,9 +672,9 @@ class MAGNUM_EXPORT Mesh {
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_integral<typename Implementation::Attribute<T>::Type>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_integral<typename Implementation::Attribute<T>::Type>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
(this->*attributeIPointerImplementation)(IntegerAttribute{
buffer,
&buffer,
location,
static_cast<GLint>(attribute.components()),
static_cast<GLenum>(attribute.dataType()),
@ -683,10 +684,10 @@ class MAGNUM_EXPORT Mesh {
}
#ifndef MAGNUM_TARGET_GLES
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::Type, Double>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
template<UnsignedInt location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename Implementation::Attribute<T>::Type, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
for(UnsignedInt i = 0; i != Implementation::Attribute<T>::vectorCount(); ++i)
(this->*attributeLPointerImplementation)(LongAttribute{
buffer,
&buffer,
location+i,
static_cast<GLint>(attribute.components()),
static_cast<GLenum>(attribute.dataType()),
@ -743,9 +744,9 @@ class MAGNUM_EXPORT Mesh {
#endif
#endif
typedef void(Mesh::*BindIndexBufferImplementation)(Buffer*);
void MAGNUM_LOCAL bindIndexBufferImplementationDefault(Buffer* buffer);
void MAGNUM_LOCAL bindIndexBufferImplementationVAO(Buffer* buffer);
typedef void(Mesh::*BindIndexBufferImplementation)(Buffer&);
void MAGNUM_LOCAL bindIndexBufferImplementationDefault(Buffer& buffer);
void MAGNUM_LOCAL bindIndexBufferImplementationVAO(Buffer& buffer);
static MAGNUM_LOCAL BindIndexBufferImplementation bindIndexBufferImplementation;
typedef void(Mesh::*BindImplementation)();
@ -783,12 +784,12 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, Mesh::Primitive value);
/** @debugoperator{Magnum::Mesh} */
Debug MAGNUM_EXPORT operator<<(Debug debug, Mesh::IndexType value);
template<class ...T> inline Mesh* Mesh::addVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes) {
template<class ...T> inline Mesh& Mesh::addVertexBuffer(Buffer& buffer, GLintptr offset, const T&... attributes) {
CORRADE_ASSERT(sizeof...(attributes) == 1 || _vertexCount != 0,
"Mesh::addVertexBuffer(): vertex count must be set before binding attributes", this);
"Mesh::addVertexBuffer(): vertex count must be set before binding attributes", *this);
addVertexBufferInternal(buffer, offset, attributes...);
return this;
return *this;
}

2
src/MeshTools/CMakeLists.txt

@ -62,7 +62,7 @@ add_library(MagnumMeshTools ${SHARED_OR_STATIC}
${MagnumMeshTools_GracefulAssert_SRCS})
if(BUILD_STATIC_PIC)
# TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property
set_target_properties(MagnumMeshTools PROPERTIES COMPILE_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS})
set_target_properties(MagnumMeshTools PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
endif()
target_link_libraries(MagnumMeshTools Magnum)

8
src/MeshTools/CompressIndices.cpp

@ -69,7 +69,7 @@ std::tuple<std::size_t, Mesh::IndexType, char*> compressIndices(const std::vecto
return compressIndicesInternal(indices, *std::max_element(indices.begin(), indices.end()));
}
void compressIndices(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector<UnsignedInt>& indices) {
void compressIndices(Mesh& mesh, Buffer& buffer, Buffer::Usage usage, const std::vector<UnsignedInt>& indices) {
auto minmax = std::minmax_element(indices.begin(), indices.end());
/** @todo Performance hint when range can be represented by smaller value? */
@ -79,9 +79,9 @@ void compressIndices(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std:
char* data;
std::tie(indexCount, indexType, data) = compressIndicesInternal(indices, *minmax.second);
mesh->setIndexCount(indices.size())
->setIndexBuffer(buffer, 0, indexType, *minmax.first, *minmax.second);
buffer->setData(indexCount*Mesh::indexSize(indexType), data, usage);
mesh.setIndexCount(indices.size())
.setIndexBuffer(buffer, 0, indexType, *minmax.first, *minmax.second);
buffer.setData(indexCount*Mesh::indexSize(indexType), data, usage);
delete[] data;
}

2
src/MeshTools/CompressIndices.h

@ -77,7 +77,7 @@ Mesh::setIndexCount() and Mesh::setIndexBuffer() on your own.
@see MeshTools::interleave()
*/
void MAGNUM_MESHTOOLS_EXPORT compressIndices(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector<UnsignedInt>& indices);
void MAGNUM_MESHTOOLS_EXPORT compressIndices(Mesh& mesh, Buffer& buffer, Buffer::Usage usage, const std::vector<UnsignedInt>& indices);
}}

18
src/MeshTools/Interleave.h

@ -60,23 +60,23 @@ class Interleave {
return std::make_tuple(_attributeCount, _stride, _data);
}
template<class ...T> void operator()(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const T&... attributes) {
template<class ...T> void operator()(Mesh& mesh, Buffer& buffer, Buffer::Usage usage, const T&... attributes) {
operator()(attributes...);
mesh->setVertexCount(_attributeCount);
buffer->setData(_attributeCount*_stride, _data, usage);
mesh.setVertexCount(_attributeCount);
buffer.setData(_attributeCount*_stride, _data, usage);
delete[] _data;
}
/* Specialization for only one attribute array */
template<class T> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, void>::type operator()(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const T& attribute) {
mesh->setVertexCount(attribute.size());
buffer->setData(attribute, usage);
template<class T> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, void>::type operator()(Mesh& mesh, Buffer& buffer, Buffer::Usage usage, const T& attribute) {
mesh.setVertexCount(attribute.size());
buffer.setData(attribute, usage);
}
template<class T, class ...U> static typename std::enable_if<!std::is_convertible<T, std::size_t>::value, std::size_t>::type attributeCount(const T& first, const U&... next) {
CORRADE_ASSERT(sizeof...(next) == 0 || attributeCount(next...) == first.size() || attributeCount(next...) == ~std::size_t(0), "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.", 0);
CORRADE_ASSERT(sizeof...(next) == 0 || attributeCount(next...) == first.size() || attributeCount(next...) == ~std::size_t(0), "MeshTools::interleave(): attribute arrays don't have the same length, expected" << first.size() << "but got" << attributeCount(next...), 0);
return first.size();
}
@ -180,7 +180,7 @@ See also interleave(Mesh*, Buffer*, Buffer::Usage, const T&...),
which writes the interleaved array directly into buffer of given mesh.
*/
/* enable_if to avoid clash with overloaded function below */
template<class T, class ...U> inline typename std::enable_if<!std::is_convertible<T, Mesh*>::value, std::tuple<std::size_t, std::size_t, char*>>::type interleave(const T& first, const U&... next) {
template<class T, class ...U> inline typename std::enable_if<!std::is_same<T, Mesh>::value, std::tuple<std::size_t, std::size_t, char*>>::type interleave(const T& first, const U&... next) {
return Implementation::Interleave()(first, next...);
}
@ -207,7 +207,7 @@ mesh->setVertexCount(attribute.size());
@see MeshTools::compressIndices()
*/
template<class ...T> inline void interleave(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const T&... attributes) {
template<class ...T> inline void interleave(Mesh& mesh, Buffer& buffer, Buffer::Usage usage, const T&... attributes) {
return Implementation::Interleave()(mesh, buffer, usage, attributes...);
}

2
src/MeshTools/Test/InterleaveTest.cpp

@ -57,7 +57,7 @@ void InterleaveTest::attributeCount() {
Error::setOutput(&ss);
CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector<Byte>{0, 1, 2},
std::vector<Byte>{0, 1, 2, 3, 4, 5})), std::size_t(0));
CORRADE_COMPARE(ss.str(), "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.\n");
CORRADE_COMPARE(ss.str(), "MeshTools::interleave(): attribute arrays don't have the same length, expected 3 but got 6\n");
CORRADE_COMPARE((Implementation::Interleave::attributeCount(std::vector<Byte>{0, 1, 2},
std::vector<Byte>{3, 4, 5})), std::size_t(3));

1
src/MeshTools/Tipsify.h

@ -70,6 +70,7 @@ array for beter usage of post-transform vertex cache. Algorithm used:
*Pedro V. Sander, Diego Nehab, and Joshua Barczak - Fast Triangle Reordering
for Vertex Locality and Reduced Overdraw, SIGGRAPH 2007,
http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/index.php*.
@todo Ability to compute vertex count automatically
*/
inline void tipsify(std::vector<UnsignedInt>& indices, UnsignedInt vertexCount, std::size_t cacheSize) {
Implementation::Tipsify(indices, vertexCount)(cacheSize);

4
src/Platform/AbstractXApplication.h

@ -208,7 +208,7 @@ class AbstractXApplication::Configuration {
/**
* @brief Set window title
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is `"Magnum X Application"`.
*/
@ -222,7 +222,7 @@ class AbstractXApplication::Configuration {
/**
* @brief Set window size
* @return Pointer to self (for method chaining)
* @return Reference to self (for method chaining)
*
* Default is `{800, 600}`.
*/

1
src/Platform/magnum-info.cpp

@ -125,6 +125,7 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat
Version::GL410,
Version::GL420,
Version::GL430,
Version::GL440,
#else
Version::GLES200,
Version::GLES300,

5
src/Primitives/CMakeLists.txt

@ -34,7 +34,8 @@ set(MagnumPrimitives_SRCS
Square.cpp
UVSphere.cpp
Implementation/Spheroid.cpp)
Implementation/Spheroid.cpp
Implementation/WireframeSpheroid.cpp)
set(MagnumPrimitives_HEADERS
Capsule.h
@ -53,7 +54,7 @@ set(MagnumPrimitives_HEADERS
add_library(MagnumPrimitives ${SHARED_OR_STATIC} ${MagnumPrimitives_SRCS})
if(BUILD_STATIC_PIC)
# TODO: CMake 2.8.9 has this as POSITION_INDEPENDENT_CODE property
set_target_properties(Magnum PROPERTIES COMPILE_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS})
set_target_properties(Magnum PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
endif()
target_link_libraries(MagnumPrimitives Magnum)

22
src/Primitives/Capsule.cpp

@ -26,6 +26,7 @@
#include "Math/Vector3.h"
#include "Primitives/Implementation/Spheroid.h"
#include "Primitives/Implementation/WireframeSpheroid.h"
#include "Trade/MeshData3D.h"
namespace Magnum { namespace Primitives {
@ -64,4 +65,25 @@ Trade::MeshData3D Capsule::solid(UnsignedInt hemisphereRings, UnsignedInt cylind
return capsule.finalize();
}
Trade::MeshData3D Capsule::wireframe(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float length) {
CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 4 && segments%4 == 0, "Primitives::Capsule::wireframe(): improper parameters", Trade::MeshData3D(Mesh::Primitive::Lines, {}, {}, {}, {}));
Implementation::WireframeSpheroid capsule(segments/4);
/* Bottom hemisphere */
capsule.bottomHemisphere(-length/2, hemisphereRings);
/* Cylinder */
capsule.ring(-length/2);
for(UnsignedInt i = 0; i != cylinderRings; ++i) {
capsule.cylinder();
capsule.ring(-length/2 + (i+1)*(length/cylinderRings));
}
/* Top hemisphere */
capsule.topHemisphere(length/2, hemisphereRings);
return capsule.finalize();
}
}}

14
src/Primitives/Capsule.h

@ -62,6 +62,20 @@ class MAGNUM_PRIMITIVES_EXPORT Capsule {
* vertices of one segment are duplicated for texture wrapping.
*/
static Trade::MeshData3D solid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length, TextureCoords textureCoords = TextureCoords::DontGenerate);
/**
* @brief Wireframe capsule
* @param hemisphereRings Number of (line) rings for each hemisphere.
* Must be larger or equal to 1.
* @param cylinderRings Number of (line) rings for cylinder. Must be
* larger or equal to 1.
* @param segments Number of line segments. Must be larger or
* equal to 4 and multiple of 4.
* @param length Length of the capsule, excluding hemispheres.
*
* Indexed @ref Mesh::Primitive "Lines".
*/
static Trade::MeshData3D wireframe(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float length);
};
}}

16
src/Primitives/Cylinder.cpp

@ -26,6 +26,7 @@
#include "Math/Vector3.h"
#include "Primitives/Implementation/Spheroid.h"
#include "Primitives/Implementation/WireframeSpheroid.h"
#include "Trade/MeshData3D.h"
namespace Magnum { namespace Primitives {
@ -61,4 +62,19 @@ Trade::MeshData3D Cylinder::solid(UnsignedInt rings, UnsignedInt segments, Float
return cylinder.finalize();
}
Trade::MeshData3D Cylinder::wireframe(const UnsignedInt rings, const UnsignedInt segments, const Float length) {
CORRADE_ASSERT(rings >= 1 && segments >= 4 && segments%4 == 0, "Primitives::Cylinder::wireframe(): improper parameters", Trade::MeshData3D(Mesh::Primitive::Lines, {}, {}, {}, {}));
Implementation::WireframeSpheroid cylinder(segments/4);
/* Rings */
cylinder.ring(-length/2);
for(UnsignedInt i = 0; i != rings; ++i) {
cylinder.cylinder();
cylinder.ring(-length/2 + (i+1)*(length/rings));
}
return cylinder.finalize();
}
}}

12
src/Primitives/Cylinder.h

@ -71,6 +71,18 @@ class MAGNUM_PRIMITIVES_EXPORT Cylinder {
* wrapping.
*/
static Trade::MeshData3D solid(UnsignedInt rings, UnsignedInt segments, Float length, Flags flags = Flags());
/**
* @brief Wireframe cylinder
* @param rings Number of (line) rings. Must be larger or equal
* to 1.
* @param segments Number of (line) segments. Must be larger or
* equal to 4 and multiple of 4.
* @param length Cylinder length
*
* Indexed @ref Mesh::Primitive "Lines".
*/
static Trade::MeshData3D wireframe(UnsignedInt rings, UnsignedInt segments, Float length);
};
CORRADE_ENUMSET_OPERATORS(Cylinder::Flags)

91
src/Primitives/Icosphere.cpp

@ -25,45 +25,64 @@
#include "Icosphere.h"
#include "Math/Vector3.h"
#include "Trade/MeshData3D.h"
#include "MeshTools/Subdivide.h"
#include "MeshTools/RemoveDuplicates.h"
namespace Magnum { namespace Primitives {
Icosphere<0>::Icosphere(): MeshData3D(Mesh::Primitive::Triangles, {
1, 2, 6,
1, 7, 2,
3, 4, 5,
4, 3, 8,
6, 5, 11,
5, 6, 10,
9, 10, 2,
10, 9, 3,
7, 8, 9,
8, 7, 0,
11, 0, 1,
0, 11, 4,
6, 2, 10,
1, 6, 11,
3, 5, 10,
5, 4, 11,
2, 7, 9,
7, 1, 0,
3, 9, 8,
4, 8, 0
}, {}, {std::vector<Vector3>{
{0.0f, -0.525731f, 0.850651f},
{0.850651f, 0.0f, 0.525731f},
{0.850651f, 0.0f, -0.525731f},
{-0.850651f, 0.0f, -0.525731f},
{-0.850651f, 0.0f, 0.525731f},
{-0.525731f, 0.850651f, 0.0f},
{0.525731f, 0.850651f, 0.0f},
{0.525731f, -0.850651f, 0.0f},
{-0.525731f, -0.850651f, 0.0f},
{0.0f, -0.525731f, -0.850651f},
{0.0f, 0.525731f, -0.850651f},
{0.0f, 0.525731f, 0.850651f}
}}, {}) {
positions(0).assign(normals(0).begin(), normals(0).end());
namespace {
inline Vector3 interpolator(const Vector3& a, const Vector3& b) {
return (a+b).normalized();
}
}
Trade::MeshData3D Icosphere::solid(const UnsignedInt subdivisions) {
std::vector<UnsignedInt> indices{
1, 2, 6,
1, 7, 2,
3, 4, 5,
4, 3, 8,
6, 5, 11,
5, 6, 10,
9, 10, 2,
10, 9, 3,
7, 8, 9,
8, 7, 0,
11, 0, 1,
0, 11, 4,
6, 2, 10,
1, 6, 11,
3, 5, 10,
5, 4, 11,
2, 7, 9,
7, 1, 0,
3, 9, 8,
4, 8, 0
};
std::vector<Vector3> positions{
{0.0f, -0.525731f, 0.850651f},
{0.850651f, 0.0f, 0.525731f},
{0.850651f, 0.0f, -0.525731f},
{-0.850651f, 0.0f, -0.525731f},
{-0.850651f, 0.0f, 0.525731f},
{-0.525731f, 0.850651f, 0.0f},
{0.525731f, 0.850651f, 0.0f},
{0.525731f, -0.850651f, 0.0f},
{-0.525731f, -0.850651f, 0.0f},
{0.0f, -0.525731f, -0.850651f},
{0.0f, 0.525731f, -0.850651f},
{0.0f, 0.525731f, 0.850651f}
};
for(std::size_t i = 0; i != subdivisions; ++i)
MeshTools::subdivide(indices, positions, interpolator);
MeshTools::removeDuplicates(indices, positions);
std::vector<Vector3> normals(positions);
return Trade::MeshData3D(Mesh::Primitive::Triangles, std::move(indices), {std::move(positions)}, {std::move(normals)}, {});
}
}}

51
src/Primitives/Icosphere.h

@ -28,57 +28,26 @@
* @brief Class Magnum::Primitives::Icosphere
*/
#include "Math/Vector3.h"
#include "MeshTools/RemoveDuplicates.h"
#include "MeshTools/Subdivide.h"
#include "Trade/MeshData3D.h"
#include "Trade/Trade.h"
#include "Primitives/magnumPrimitivesVisibility.h"
namespace Magnum { namespace Primitives {
/** @todoc Remove `ifndef` when Doxygen is sane again */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<std::size_t subdivisions> class MAGNUM_PRIMITIVES_EXPORT Icosphere;
#endif
/**
@brief 3D icosphere primitive with zero subdivisions
Indexed @ref Mesh::Primitive "Triangles" with normals.
*/
template<> class Icosphere<0>: public Trade::MeshData3D {
public:
/** @brief Constructor */
explicit Icosphere();
};
/**
@brief 3D icosphere primitive
@tparam subdivisions Number of subdivisions
Indexed @ref Mesh::Primitive "Triangles" with normals.
Sphere with radius `1`.
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<std::size_t subdivisions> class Icosphere: public Icosphere<0> {
#else
template<std::size_t subdivisions> class Icosphere {
#endif
class MAGNUM_PRIMITIVES_EXPORT Icosphere {
public:
/** @brief Constructor */
explicit Icosphere() {
for(std::size_t i = 0; i != subdivisions; ++i)
MeshTools::subdivide(*indices(), *normals(0), interpolator);
MeshTools::removeDuplicates(*indices(), *normals(0));
positions(0)->assign(normals(0)->begin(), normals(0)->end());
}
#ifndef DOXYGEN_GENERATING_OUTPUT
static Vector3 interpolator(const Vector3& a, const Vector3& b) {
return (a+b).normalized();
}
#endif
/**
* @brief Solid icosphere
* @param subdivisions Number of subdivisions
*
* Indexed @ref Mesh::Primitive "Triangles" with normals.
*/
static Trade::MeshData3D solid(UnsignedInt subdivisions);
};
}}

6
src/Primitives/Implementation/Spheroid.h

@ -1,5 +1,5 @@
#ifndef Magnum_Primitives_Spheroid_h
#define Magnum_Primitives_Spheroid_h
#ifndef Magnum_Primitives_Implementation_Spheroid_h
#define Magnum_Primitives_Implementation_Spheroid_h
/*
This file is part of Magnum.
@ -50,10 +50,10 @@ class Spheroid {
Trade::MeshData3D finalize();
private:
UnsignedInt segments;
TextureCoords textureCoords;
private:
std::vector<UnsignedInt> indices;
std::vector<Vector3> positions;
std::vector<Vector3> normals;

115
src/Primitives/Implementation/WireframeSpheroid.cpp

@ -0,0 +1,115 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "WireframeSpheroid.h"
#include "Math/Functions.h"
#include "Math/Vector3.h"
#include "Trade/MeshData3D.h"
namespace Magnum { namespace Primitives { namespace Implementation {
WireframeSpheroid::WireframeSpheroid(const UnsignedInt segments): _segments(segments) {}
void WireframeSpheroid::bottomHemisphere(const Float endY, const UnsignedInt rings) {
CORRADE_INTERNAL_ASSERT(_positions.empty());
/* Initial vertex */
_positions.push_back(Vector3::yAxis(endY - 1.0f));
/* Connect initial vertex to first ring */
for(UnsignedInt i = 0; i != 4; ++i)
_indices.insert(_indices.end(), {0, i+1});
/* Hemisphere vertices and indices */
const Rad ringAngleIncrement(Constants::pi()/(2*rings));
for(UnsignedInt j = 0; j != rings-1; ++j) {
const Rad angle = (j+1)*ringAngleIncrement;
_positions.emplace_back(0.0f, endY - Math::cos(angle), Math::sin(angle));
_positions.emplace_back(Math::sin(angle), endY - Math::cos(angle), 0.0f);
_positions.emplace_back(0.0f, endY - Math::cos(angle), -Math::sin(angle));
_positions.emplace_back(-Math::sin(angle), endY - Math::cos(angle), 0.0f);
/* Connect vertices to next ring */
for(UnsignedInt i = 0; i != 4; ++i)
_indices.insert(_indices.end(), {UnsignedInt(_positions.size())-4+i, UnsignedInt(_positions.size())+i});
}
}
void WireframeSpheroid::topHemisphere(const Float startY, const UnsignedInt rings) {
/* Connect previous ring to following vertices */
for(UnsignedInt i = 0; i != 4; ++i)
_indices.insert(_indices.end(), {UnsignedInt(_positions.size())-4*_segments+i, UnsignedInt(_positions.size())+i});
/* Hemisphere vertices and indices */
const Rad ringAngleIncrement(Constants::pi()/(2*rings));
for(UnsignedInt j = 0; j != rings-1; ++j) {
const Rad angle = (j+1)*ringAngleIncrement;
/* Connect previous hemisphere ring to current vertices */
if(j != 0) for(UnsignedInt i = 0; i != 4; ++i)
_indices.insert(_indices.end(), {UnsignedInt(_positions.size())-4+i, UnsignedInt(_positions.size())+i});
_positions.emplace_back(0.0f, startY + Math::sin(angle), Math::cos(angle));
_positions.emplace_back(Math::cos(angle), startY + Math::sin(angle), 0.0f);
_positions.emplace_back(0.0f, startY + Math::sin(angle), -Math::cos(angle));
_positions.emplace_back(-Math::cos(angle), startY + Math::sin(angle), 0.0f);
}
/* Final vertex */
_positions.push_back(Vector3::yAxis(startY + 1.0f));
/* Connect last ring to final vertex */
for(UnsignedInt i = 0; i != 4; ++i)
_indices.insert(_indices.end(), {UnsignedInt(_positions.size())-5+i, UnsignedInt(_positions.size())-1});
}
void WireframeSpheroid::ring(const Float y) {
/* Ring vertices and indices */
const Rad segmentAngleIncrement(Constants::pi()/(2*_segments));
for(UnsignedInt j = 0; j != _segments; ++j) {
for(UnsignedInt i = 0; i != 4; ++i) {
const Rad segmentAngle = Rad(i*Constants::pi()/2) + j*segmentAngleIncrement;
if(j != 0) _indices.insert(_indices.end(), {UnsignedInt(_positions.size()-4), UnsignedInt(_positions.size())});
_positions.emplace_back(Math::sin(segmentAngle), y, Math::cos(segmentAngle));
}
}
/* Close the ring */
for(UnsignedInt i = 0; i != 4; ++i)
_indices.insert(_indices.end(), {UnsignedInt(_positions.size())-4+i, UnsignedInt(_positions.size())-4*_segments+(i+1)%4});
}
void WireframeSpheroid::cylinder() {
/* Connect four vertex pairs of previous and next ring */
for(UnsignedInt i = 0; i != 4; ++i)
_indices.insert(_indices.end(), {UnsignedInt(_positions.size())-4*_segments+i, UnsignedInt(_positions.size())+i});
}
Trade::MeshData3D WireframeSpheroid::finalize() {
return Trade::MeshData3D(Mesh::Primitive::Lines, std::move(_indices), {std::move(_positions)}, {}, {});
}
}}}

54
src/Primitives/Implementation/WireframeSpheroid.h

@ -0,0 +1,54 @@
#ifndef Magnum_Primitives_WireframeSpheroid_h
#define Magnum_Primitives_WireframeSpheroid_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <vector>
#include "Magnum.h"
#include "Trade/Trade.h"
namespace Magnum { namespace Primitives { namespace Implementation {
class WireframeSpheroid {
public:
WireframeSpheroid(UnsignedInt segments);
void bottomHemisphere(Float endY, UnsignedInt rings);
void topHemisphere(Float startY, UnsignedInt rings);
void ring(Float y);
void cylinder();
Trade::MeshData3D finalize();
private:
UnsignedInt _segments;
std::vector<UnsignedInt> _indices;
std::vector<Vector3> _positions;
};
}}}
#endif

1
src/Primitives/Test/CMakeLists.txt

@ -25,4 +25,5 @@
corrade_add_test(PrimitivesCapsuleTest CapsuleTest.cpp LIBRARIES MagnumPrimitives)
corrade_add_test(PrimitivesCircleTest CircleTest.cpp LIBRARIES MagnumPrimitives)
corrade_add_test(PrimitivesCylinderTest CylinderTest.cpp LIBRARIES MagnumPrimitives)
corrade_add_test(PrimitivesIcosphereTest IcosphereTest.cpp LIBRARIES MagnumPrimitives)
corrade_add_test(PrimitivesUVSphereTest UVSphereTest.cpp LIBRARIES MagnumPrimitives)

82
src/Primitives/Test/CapsuleTest.cpp

@ -38,16 +38,18 @@ class CapsuleTest: public TestSuite::Tester {
public:
CapsuleTest();
void withoutTextureCoords();
void withTextureCoords();
void solidWithoutTextureCoords();
void solidWithTextureCoords();
void wireframe();
};
CapsuleTest::CapsuleTest() {
addTests({&CapsuleTest::withoutTextureCoords,
&CapsuleTest::withTextureCoords});
addTests({&CapsuleTest::solidWithoutTextureCoords,
&CapsuleTest::solidWithTextureCoords,
&CapsuleTest::wireframe});
}
void CapsuleTest::withoutTextureCoords() {
void CapsuleTest::solidWithoutTextureCoords() {
Trade::MeshData3D capsule = Capsule::solid(2, 2, 3, 1.0f);
CORRADE_COMPARE_AS(capsule.positions(0), (std::vector<Vector3>{
@ -112,7 +114,7 @@ void CapsuleTest::withoutTextureCoords() {
}), TestSuite::Compare::Container);
}
void CapsuleTest::withTextureCoords() {
void CapsuleTest::solidWithTextureCoords() {
Trade::MeshData3D capsule = Capsule::solid(2, 2, 3, 1.0f, Capsule::TextureCoords::Generate);
CORRADE_COMPARE_AS(capsule.positions(0), (std::vector<Vector3>{
@ -187,6 +189,74 @@ void CapsuleTest::withTextureCoords() {
}), TestSuite::Compare::Container);
}
void CapsuleTest::wireframe() {
Trade::MeshData3D capsule = Capsule::wireframe(2, 2, 8, 1.0f);
CORRADE_COMPARE_AS(capsule.positions(0), (std::vector<Vector3>{
{0.0f, -1.5f, 0.0f},
{0.0f, -1.20711f, 0.707107f},
{0.707107f, -1.20711f, 0.0f},
{0.0f, -1.20711f, -0.707107f},
{-0.707107f, -1.20711f, 0.0f},
{0.0f, -0.5f, 1.0f},
{1.0f, -0.5f, 0.0f},
{0.0f, -0.5f, -1.0f},
{-1.0f, -0.5f, 0.0f},
{0.707107f, -0.5f, 0.707107f},
{0.707107f, -0.5f, -0.707107f},
{-0.707107f, -0.5f, -0.707107f},
{-0.707107f, -0.5f, 0.707107f},
{0.0f, 0.0f, 1.0f},
{1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f},
{-1.0f, 0.0f, 0.0f},
{0.707107f, 0.0f, 0.707107f},
{0.707107f, 0.0f, -0.707107f},
{-0.707107f, 0.0f, -0.707107f},
{-0.707107f, 0.0f, 0.707107f},
{0.0f, 0.5f, 1.0f},
{1.0f, 0.5f, 0.0f},
{0.0f, 0.5f, -1.0f},
{-1.0f, 0.5f, 0.0f},
{0.707107f, 0.5f, 0.707107f},
{0.707107f, 0.5f, -0.707107f},
{-0.707107f, 0.5f, -0.707107f},
{-0.707107f, 0.5f, 0.707107f},
{0.0f, 1.20711f, 0.707107f},
{0.707107f, 1.20711f, 0.0f},
{0.0f, 1.20711f, -0.707107f},
{-0.707107f, 1.20711f, 0.0f},
{0.0f, 1.5f, 0.0f}
}), TestSuite::Compare::Container);
CORRADE_COMPARE(capsule.normalArrayCount(), 0);
CORRADE_COMPARE_AS(capsule.indices(), (std::vector<UnsignedInt>{
0, 1, 0, 2, 0, 3, 0, 4,
1, 5, 2, 6, 3, 7, 4, 8,
5, 9, 6, 10, 7, 11, 8, 12,
9, 6, 10, 7, 11, 8, 12, 5,
5, 13, 6, 14, 7, 15, 8, 16,
13, 17, 14, 18, 15, 19, 16, 20,
17, 14, 18, 15, 19, 16, 20, 13,
13, 21, 14, 22, 15, 23, 16, 24,
21, 25, 22, 26, 23, 27, 24, 28,
25, 22, 26, 23, 27, 24, 28, 21,
21, 29, 22, 30, 23, 31, 24, 32,
29, 33, 30, 33, 31, 33, 32, 33
}), TestSuite::Compare::Container);
}
}}}
CORRADE_TEST_MAIN(Magnum::Primitives::Test::CapsuleTest)

64
src/Primitives/Test/CylinderTest.cpp

@ -35,16 +35,18 @@ class CylinderTest: public TestSuite::Tester {
public:
CylinderTest();
void withoutAnything();
void withTextureCoordsAndCaps();
void solidWithoutAnything();
void solidWithTextureCoordsAndCaps();
void wireframe();
};
CylinderTest::CylinderTest() {
addTests({&CylinderTest::withoutAnything,
&CylinderTest::withTextureCoordsAndCaps});
addTests({&CylinderTest::solidWithoutAnything,
&CylinderTest::solidWithTextureCoordsAndCaps,
&CylinderTest::wireframe});
}
void CylinderTest::withoutAnything() {
void CylinderTest::solidWithoutAnything() {
Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 3.0f);
CORRADE_COMPARE_AS(cylinder.positions(0), (std::vector<Vector3>{
@ -81,7 +83,7 @@ void CylinderTest::withoutAnything() {
}), TestSuite::Compare::Container);
}
void CylinderTest::withTextureCoordsAndCaps() {
void CylinderTest::solidWithTextureCoordsAndCaps() {
Trade::MeshData3D cylinder = Cylinder::solid(2, 3, 3.0f, Cylinder::Flag::GenerateTextureCoords|Cylinder::Flag::CapEnds);
CORRADE_COMPARE_AS(cylinder.positions(0), (std::vector<Vector3>{
@ -185,6 +187,56 @@ void CylinderTest::withTextureCoordsAndCaps() {
}), TestSuite::Compare::Container);
}
void CylinderTest::wireframe() {
Trade::MeshData3D cylinder = Cylinder::wireframe(2, 8, 1.0f);
CORRADE_COMPARE_AS(cylinder.positions(0), (std::vector<Vector3>{
{0.0f, -0.5f, 1.0f},
{1.0f, -0.5f, 0.0f},
{0.0f, -0.5f, -1.0f},
{-1.0f, -0.5f, 0.0f},
{0.707107f, -0.5f, 0.707107f},
{0.707107f, -0.5f, -0.707107f},
{-0.707107f, -0.5f, -0.707107f},
{-0.707107f, -0.5f, 0.707107f},
{0.0f, 0.0f, 1.0f},
{1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f},
{-1.0f, 0.0f, 0.0f},
{0.707107f, 0.0f, 0.707107f},
{0.707107f, 0.0f, -0.707107f},
{-0.707107f, 0.0f, -0.707107f},
{-0.707107f, 0.0f, 0.707107f},
{0.0f, 0.5f, 1.0f},
{1.0f, 0.5f, 0.0f},
{0.0f, 0.5f, -1.0f},
{-1.0f, 0.5f, 0.0f},
{0.707107f, 0.5f, 0.707107f},
{0.707107f, 0.5f, -0.707107f},
{-0.707107f, 0.5f, -0.707107f},
{-0.707107f, 0.5f, 0.707107f}
}), TestSuite::Compare::Container);
CORRADE_COMPARE(cylinder.normalArrayCount(), 0);
CORRADE_COMPARE_AS(cylinder.indices(), (std::vector<UnsignedInt>{
0, 4, 1, 5, 2, 6, 3, 7,
4, 1, 5, 2, 6, 3, 7, 0,
0, 8, 1, 9, 2, 10, 3, 11,
8, 12, 9, 13, 10, 14, 11, 15,
12, 9, 13, 10, 14, 11, 15, 8,
8, 16, 9, 17, 10, 18, 11, 19,
16, 20, 17, 21, 18, 22, 19, 23,
20, 17, 21, 18, 22, 19, 23, 16
}), TestSuite::Compare::Container);
}
}}}
CORRADE_TEST_MAIN(Magnum::Primitives::Test::CylinderTest)

57
src/Primitives/Test/IcosphereTest.cpp

@ -0,0 +1,57 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <TestSuite/Tester.h>
#include "Math/Vector3.h"
#include "Primitives/Icosphere.h"
#include "Trade/MeshData3D.h"
namespace Magnum { namespace Primitives { namespace Test {
class IcosphereTest: public TestSuite::Tester {
public:
explicit IcosphereTest();
void count();
};
IcosphereTest::IcosphereTest() {
addTests({&IcosphereTest::count});
}
void IcosphereTest::count() {
Trade::MeshData3D data = Primitives::Icosphere::solid(2);
CORRADE_COMPARE(data.positionArrayCount(), 1);
CORRADE_COMPARE(data.normalArrayCount(), 1);
CORRADE_COMPARE(data.indices().size(), 960);
CORRADE_COMPARE(data.positions(0).size(), 162);
CORRADE_COMPARE(data.normals(0).size(), 162);
}
}}}
CORRADE_TEST_MAIN(Magnum::Primitives::Test::IcosphereTest)

56
src/Primitives/Test/UVSphereTest.cpp

@ -35,16 +35,18 @@ class UVSphereTest: public TestSuite::Tester {
public:
UVSphereTest();
void withoutTextureCoords();
void withTextureCoords();
void solidWithoutTextureCoords();
void solidWithTextureCoords();
void wireframe();
};
UVSphereTest::UVSphereTest() {
addTests({&UVSphereTest::withoutTextureCoords,
&UVSphereTest::withTextureCoords});
addTests({&UVSphereTest::solidWithoutTextureCoords,
&UVSphereTest::solidWithTextureCoords,
&UVSphereTest::wireframe});
}
void UVSphereTest::withoutTextureCoords() {
void UVSphereTest::solidWithoutTextureCoords() {
Trade::MeshData3D sphere = UVSphere::solid(3, 3);
CORRADE_COMPARE_AS(sphere.positions(0), (std::vector<Vector3>{
@ -82,7 +84,7 @@ void UVSphereTest::withoutTextureCoords() {
}), TestSuite::Compare::Container);
}
void UVSphereTest::withTextureCoords() {
void UVSphereTest::solidWithTextureCoords() {
Trade::MeshData3D sphere = UVSphere::solid(3, 3, UVSphere::TextureCoords::Generate);
CORRADE_COMPARE_AS(sphere.positions(0), (std::vector<Vector3>{
@ -124,6 +126,48 @@ void UVSphereTest::withTextureCoords() {
}), TestSuite::Compare::Container);
}
void UVSphereTest::wireframe() {
Trade::MeshData3D sphere = UVSphere::wireframe(4, 8);
CORRADE_COMPARE_AS(sphere.positions(0), (std::vector<Vector3>{
{0.0f, -1.0f, 0.0f},
{0.0f, -0.707107f, 0.707107f},
{0.707107f, -0.707107f, 0.0f},
{0.0f, -0.707107f, -0.707107f},
{-0.707107f, -0.707107f, 0.0f},
{0.0f, 0.0f, 1.0f},
{1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f},
{-1.0f, 0.0f, 0.0f},
{0.707107f, 0.0f, 0.707107f},
{0.707107f, 0.0f, -0.707107f},
{-0.707107f, 0.0f, -0.707107f},
{-0.707107f, 0.0f, 0.707107f},
{0.0f, 0.707107f, 0.707107f},
{0.707107f, 0.707107f, 0.0f},
{0.0f, 0.707107f, -0.707107f},
{-0.707107f, 0.707107f, 0.0f},
{0.0f, 1.0f, 0.0f}
}), TestSuite::Compare::Container);
CORRADE_COMPARE(sphere.normalArrayCount(), 0);
CORRADE_COMPARE_AS(sphere.indices(), (std::vector<UnsignedInt>{
0, 1, 0, 2, 0, 3, 0, 4,
1, 5, 2, 6, 3, 7, 4, 8,
5, 9, 6, 10, 7, 11, 8, 12,
9, 6, 10, 7, 11, 8, 12, 5,
5, 13, 6, 14, 7, 15, 8, 16,
13, 17, 14, 17, 15, 17, 16, 17
}), TestSuite::Compare::Container);
}
}}}
CORRADE_TEST_MAIN(Magnum::Primitives::Test::UVSphereTest)

14
src/Primitives/UVSphere.cpp

@ -26,6 +26,7 @@
#include "Math/Vector3.h"
#include "Primitives/Implementation/Spheroid.h"
#include "Primitives/Implementation/WireframeSpheroid.h"
#include "Trade/MeshData3D.h"
namespace Magnum { namespace Primitives {
@ -57,4 +58,17 @@ Trade::MeshData3D UVSphere::solid(UnsignedInt rings, UnsignedInt segments, Textu
return sphere.finalize();
}
Trade::MeshData3D UVSphere::wireframe(const UnsignedInt rings, const UnsignedInt segments) {
CORRADE_ASSERT(rings >= 2 && rings%2 == 0 && segments >= 4 && segments%2 == 0, "Primitives::UVSphere::wireframe(): improper parameters", Trade::MeshData3D(Mesh::Primitive::Lines, {}, {}, {}, {}));
Implementation::WireframeSpheroid sphere(segments/4);
/* Make sphere */
sphere.bottomHemisphere(0.0f, rings/2);
sphere.ring(0.0f);
sphere.topHemisphere(0.0f, rings/2);
return sphere.finalize();
}
}}

11
src/Primitives/UVSphere.h

@ -59,6 +59,17 @@ class MAGNUM_PRIMITIVES_EXPORT UVSphere {
* vertices of one segment are duplicated for texture wrapping.
*/
static Trade::MeshData3D solid(UnsignedInt rings, UnsignedInt segments, TextureCoords textureCoords = TextureCoords::DontGenerate);
/**
* @brief Wireframe UV sphere
* @param rings Number of (line) rings. Must be larger or equal
* to 2 and multiple of 2.
* @param segments Number of (line) segments. Must be larger or
* equal to 4 and multiple of 4.
*
* Indexed @ref Mesh::Primitive "Lines".
*/
static Trade::MeshData3D wireframe(UnsignedInt rings, UnsignedInt segments);
};
}}

33
src/Query.h

@ -47,24 +47,6 @@ information.
*/
class MAGNUM_EXPORT AbstractQuery {
public:
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Constructor
*
* Generates one OpenGL query.
* @see @fn_gl{GenQueries}
*/
explicit AbstractQuery();
/**
* @brief Destructor
*
* Deletes assigned OpenGL query.
* @see @fn_gl{DeleteQueries}
*/
~AbstractQuery();
#endif
/** @brief OpenGL query ID */
GLuint id() const { return _id; }
@ -101,10 +83,21 @@ class MAGNUM_EXPORT AbstractQuery {
void end();
protected:
#ifndef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Constructor
*
* Generates one OpenGL query.
* @see @fn_gl{GenQueries}
*/
explicit AbstractQuery();
/**
* @brief Destructor
*
* Deletes assigned OpenGL query.
* @see @fn_gl{DeleteQueries}
*/
~AbstractQuery();
#endif
void begin(GLenum target);

12
src/Renderbuffer.cpp

@ -42,14 +42,14 @@ Renderbuffer::StorageMultisampleImplementation Renderbuffer::storageMultisampleI
Renderbuffer::~Renderbuffer() {
/* If bound, remove itself from state */
GLuint& binding = Context::current()->state()->framebuffer->renderbufferBinding;
GLuint& binding = Context::current()->state().framebuffer->renderbufferBinding;
if(binding == _id) binding = 0;
glDeleteRenderbuffers(1, &_id);
}
void Renderbuffer::bind() {
GLuint& binding = Context::current()->state()->framebuffer->renderbufferBinding;
GLuint& binding = Context::current()->state().framebuffer->renderbufferBinding;
if(binding == _id) return;
@ -57,20 +57,20 @@ void Renderbuffer::bind() {
glBindRenderbuffer(GL_RENDERBUFFER, _id);
}
void Renderbuffer::initializeContextBasedFunctionality(Context* context) {
void Renderbuffer::initializeContextBasedFunctionality(Context& context) {
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
if(context.isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "Renderbuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
storageImplementation = &Renderbuffer::storageImplementationDSA;
storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationDSA;
}
#elif !defined(MAGNUM_TARGET_GLES3)
if(context->isExtensionSupported<Extensions::GL::ANGLE::framebuffer_multisample>()) {
if(context.isExtensionSupported<Extensions::GL::ANGLE::framebuffer_multisample>()) {
Debug() << "Renderbuffer: using" << Extensions::GL::ANGLE::framebuffer_multisample::string() << "features";
storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationANGLE;
} else if (context->isExtensionSupported<Extensions::GL::NV::framebuffer_multisample>()) {
} else if (context.isExtensionSupported<Extensions::GL::NV::framebuffer_multisample>()) {
Debug() << "Renderbuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features";
storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationNV;

2
src/Renderbuffer.h

@ -118,7 +118,7 @@ class MAGNUM_EXPORT Renderbuffer {
}
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context);
typedef void(Renderbuffer::*StorageImplementation)(RenderbufferFormat, const Vector2i&);
void MAGNUM_LOCAL storageImplementationDefault(RenderbufferFormat internalFormat, const Vector2i& size);

10
src/Renderer.cpp

@ -164,7 +164,7 @@ void Renderer::setLogicOperation(const LogicOperation operation) {
#ifndef MAGNUM_TARGET_GLES3
Renderer::ResetNotificationStrategy Renderer::resetNotificationStrategy() {
ResetNotificationStrategy& strategy = Context::current()->state()->renderer->resetNotificationStrategy;
ResetNotificationStrategy& strategy = Context::current()->state().renderer->resetNotificationStrategy;
if(strategy == ResetNotificationStrategy()) {
#ifndef MAGNUM_TARGET_GLES
@ -178,9 +178,9 @@ Renderer::ResetNotificationStrategy Renderer::resetNotificationStrategy() {
}
#endif
void Renderer::initializeContextBasedFunctionality(Context* context) {
void Renderer::initializeContextBasedFunctionality(Context& context) {
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::ES2_compatibility>()) {
if(context.isExtensionSupported<Extensions::GL::ARB::ES2_compatibility>()) {
Debug() << "Renderer: using" << Extensions::GL::ARB::ES2_compatibility::string() << "features";
clearDepthfImplementation = &Renderer::clearDepthfImplementationES;
@ -189,9 +189,9 @@ void Renderer::initializeContextBasedFunctionality(Context* context) {
#ifndef MAGNUM_TARGET_GLES3
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported<Extensions::GL::ARB::robustness>())
if(context.isExtensionSupported<Extensions::GL::ARB::robustness>())
#else
if(context->isExtensionSupported<Extensions::GL::EXT::robustness>())
if(context.isExtensionSupported<Extensions::GL::EXT::robustness>())
#endif
{
#ifndef MAGNUM_TARGET_GLES

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save