Browse Source

Trade: camera type, projection size and aspect ratio support.

pull/284/head
Vladimír Vondruš 8 years ago
parent
commit
b93fcd6d9d
  1. 6
      doc/changelog.dox
  2. 1
      src/Magnum/Trade/CMakeLists.txt
  3. 63
      src/Magnum/Trade/CameraData.cpp
  4. 119
      src/Magnum/Trade/CameraData.h
  5. 2
      src/Magnum/Trade/ObjectData2D.h
  6. 2
      src/Magnum/Trade/Test/AbstractImporterTest.cpp
  7. 2
      src/Magnum/Trade/Test/CMakeLists.txt
  8. 136
      src/Magnum/Trade/Test/CameraDataTest.cpp
  9. 1
      src/Magnum/Trade/Trade.h

6
doc/changelog.dox

@ -148,6 +148,9 @@ See also:
- New @ref Trade::AbstractMaterialData::flags(),
@ref Trade::AbstractMaterialData::alphaMode() and
@ref Trade::AbstractMaterialData::alphaMask() material properties
- New @ref Trade::CameraData::type(), @ref Trade::CameraData::aspectRatio()
and @ref Trade::CameraData::size() properties, ability to describe 2D
cameras
- @ref Trade::ObjectData2D and @ref Trade::ObjectData3D now support also
separate translation / rotation / scaling specification instead of a
combined transformation matrix. See @ref Trade::ObjectData2D::transformation()
@ -382,6 +385,9 @@ See also:
deprecated, use @ref Trade::AbstractMaterialData::AbstractMaterialData(MaterialType, Flags, MaterialAlphaMode, Float, const void*)
and @ref Trade::PhongMaterialData::PhongMaterialData(Flags, MaterialAlphaMode, Float, Float, const void*)
instead
- @ref Trade::CameraData constructor not taking an explicit type enum is
deprecated, use @ref Trade::CameraData::CameraData(CameraType, Rad, Float, Float, Float, const void*)
instead
@subsection changelog-latest-compatibility Potential compatibility breakages, removed APIs

1
src/Magnum/Trade/CMakeLists.txt

@ -39,6 +39,7 @@ set(MagnumTrade_GracefulAssert_SRCS
AbstractImageConverter.cpp
AbstractImporter.cpp
AnimationData.cpp
CameraData.cpp
ImageData.cpp
ObjectData2D.cpp
ObjectData3D.cpp

63
src/Magnum/Trade/CameraData.cpp

@ -0,0 +1,63 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
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 "CameraData.h"
#include <Corrade/Utility/Assert.h>
#include <Magnum/Math/Functions.h>
namespace Magnum { namespace Trade {
CameraData::CameraData(const CameraType type, const Rad fov, const Float aspectRatio, const Float near, const Float far, const void* const importerState) noexcept: _type{type}, _size{2*near*Math::tan(fov*0.5f)*Vector2::yScale(1.0f/aspectRatio)}, _near{near}, _far{far}, _importerState{importerState} {
CORRADE_ASSERT(type == CameraType::Perspective3D,
"Trade::CameraData: only perspective cameras can have FoV specified", );
}
CameraData::CameraData(const CameraType type, const Vector2& size, const Float near, const Float far, const void* const importerState) noexcept: _type{type}, _size{size}, _near{near}, _far{far}, _importerState{importerState} {
CORRADE_ASSERT(type != CameraType::Orthographic2D || (!near && !far),
"Trade::CameraData: 2D cameras can't be specified with near and far clipping planes", );
}
Rad CameraData::fov() const {
CORRADE_ASSERT(_type == CameraType::Perspective3D,
"Trade::CameraData::fov(): the camera is not perspective", {});
return 2*Math::atan(_size.x()/(2*_near));
}
Debug& operator<<(Debug& debug, const CameraType value) {
switch(value) {
/* LCOV_EXCL_START */
#define _c(value) case CameraType::value: return debug << "Trade::CameraType::" #value;
_c(Orthographic2D)
_c(Orthographic3D)
_c(Perspective3D)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "Trade::CameraType(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
}}

119
src/Magnum/Trade/CameraData.h

@ -30,27 +30,79 @@
*/
#include "Magnum/Magnum.h"
#include "Magnum/Math/Angle.h"
#include "Magnum/Math/Vector2.h"
#include "Magnum/Trade/visibility.h"
namespace Magnum { namespace Trade {
/**
@brief 3D camera data
@brief Camera type
@see @ref CameraData
*/
enum class CameraType: UnsignedByte {
Orthographic2D, /**< 2D orthographic camera */
Orthographic3D, /**< 3D orthographic camera */
Perspective3D /**< 3D perspective camera */
};
/**
@brief Camera data
@see @ref AbstractImporter::camera(),
@ref Math::Matrix4::perspectiveProjection(Rad<T>, T, T, T),
@ref Math::Matrix4::perspectiveProjection(const Vector2<T>&, T, T),
@ref Math::Matrix4::orthographicProjection(const Vector2<T>&, T, T),
@ref Math::Matrix3::projection(const Vector2<T>&)
*/
class CameraData {
class MAGNUM_TRADE_EXPORT CameraData {
public:
/**
* @brief Constructor
* @param fov Field-of-view angle
* @brief Construct a camera using a field of view
* @param type Camera type
* @param fov Horizontal field-of-view angle @f$ \theta @f$
* @param aspectRatio Horizontal:vertical aspect ratio @f$ a @f$
* @param near Near clipping plane @f$ n @f$
* @param far Far clipping plane @f$ f @f$. Set to
* @ref Constants::inf() for an infinite far plane.
* @param importerState Importer-specific state
*
* The constructor converts the @p fov and @p aspectRatio to near plane
* size using the following formula and stores that: @f[
* \boldsymbol{s} = 2n \tan \left(\tfrac{\theta}{2} \right)
* \begin{pmatrix}
* 1 \\
* \frac{1}{a}
* \end{pmatrix}
* @f]
*
* The @p type parameter has to be @ref CameraType::Perspective3D, use
* @ref CameraData(CameraType, const Vector2&, Float, Float, const void*)
* for orthographic and 2D cameras instead.
*/
explicit CameraData(CameraType type, Rad fov, Float aspectRatio, Float near, Float far, const void* importerState = nullptr) noexcept;
/**
* @brief Construct a camera using a projection size
* @param type Camera type
* @param size Size of the near clipping plane
* @param near Near clipping plane
* @param far Far clipping plane
* @param far Far clipping plane. Set to @ref Constants::inf()
* for an infinite far plane.
* @param importerState Importer-specific state
*
* If `NaN` is specified for any parameter, default value is used
* instead, which is `35.0_degf` for @p fov, `0.01f` for @p near and
* `100.0f` for @p far.
* For @ref CameraType::Orthographic2D, @p near and @p far is expected
* to be @cpp 0.0f @ce.
*/
explicit CameraData(Rad fov, Float near, Float far, const void* importerState = nullptr) noexcept;
explicit CameraData(CameraType type, const Vector2& size, Float near, Float far, const void* importerState = nullptr) noexcept;
#ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief CameraData(CameraType, Rad, Float, Float, Float, const void*)
* @deprecated Use @ref CameraData(CameraType, Rad, Float, Float, Float, const void*)
* instead.
*/
explicit CORRADE_DEPRECATED("use CameraData(CameraType, Rad, Float, Float, const void*) instead") CameraData(Rad fov, Float near, Float far, const void* importerState = nullptr) noexcept: CameraData{CameraType::Perspective3D, fov, 1.0f, near, far, importerState} {}
#endif
/** @brief Copying is not allowed */
CameraData(const CameraData&) = delete;
@ -64,13 +116,44 @@ class CameraData {
/** @brief Move assignment */
CameraData& operator=(CameraData&&) noexcept = default;
/** @brief Field-of-view angle */
Rad fov() const { return _fov; }
/** @brief Camera type */
CameraType type() const { return _type; }
/**
* @brief Size of the near clipping plane
*
* For @ref CameraType::Perspective3D, this property is also available
* through @ref fov() and @ref aspectRatio().
*/
Vector2 size() const { return _size; }
/**
* @brief Field-of-view angle
*
* Expects that @ref type() is @ref CameraType::Perspective3D. The
* value is calculated from @ref size() using the following formula: @f[
* \theta = 2 \arctan \left( \frac{s_x}{2n} \right)
* @f]
*/
Rad fov() const;
/**
* @brief Aspect ratio
*
* Similarly to @ref fov(), the value is calculated from @ref size().
*/
Float aspectRatio() const { return _size.aspectRatio(); }
/** @brief Near clipping plane */
Float near() const { return _near; }
/** @brief Far clipping plane */
/**
* @brief Far clipping plane
*
* Can be set to infinity, in which case it denotes a lack of far
* clipping plane.
* @see @ref Constants::inf(), @ref Math::isInf()
*/
Float far() const { return _far; }
/**
@ -81,16 +164,14 @@ class CameraData {
const void* importerState() const { return _importerState; }
private:
Rad _fov;
CameraType _type;
Vector2 _size;
Float _near, _far;
const void* _importerState;
};
inline CameraData::CameraData(const Rad fov, const Float near, const Float far, const void* const importerState) noexcept:
_fov{fov != fov ? Rad{Deg{35.0f}} : fov},
_near{near != near ? 0.01f : near},
_far{far != far ? 100.0f : far},
_importerState{importerState} {}
/** @debugoperatorenum{CameraType} */
MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, CameraType value);
}}

2
src/Magnum/Trade/ObjectData2D.h

@ -44,7 +44,7 @@ namespace Magnum { namespace Trade {
@see @ref ObjectData2D::instanceType()
*/
enum class ObjectInstanceType2D: UnsignedByte {
Camera, /**< Camera instance (see CameraData) */
Camera, /**< Camera instance (see @ref CameraData) */
/**
* Mesh instance. The data can be cast to @ref MeshObjectData2D to provide

2
src/Magnum/Trade/Test/AbstractImporterTest.cpp

@ -1475,7 +1475,7 @@ void AbstractImporterTest::camera() {
else return {};
}
Containers::Optional<CameraData> doCamera(UnsignedInt id) override {
if(id == 7) return CameraData{{}, {}, {}, &state};
if(id == 7) return CameraData{{}, Vector2{}, {}, {}, &state};
else return {};
}
};

2
src/Magnum/Trade/Test/CMakeLists.txt

@ -43,7 +43,7 @@ corrade_add_test(TradeAbstractImporterTest AbstractImporterTest.cpp
target_include_directories(TradeAbstractImporterTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
corrade_add_test(TradeAnimationDataTest AnimationDataTest.cpp LIBRARIES MagnumTradeTestLib)
corrade_add_test(TradeCameraDataTest CameraDataTest.cpp LIBRARIES MagnumTrade)
corrade_add_test(TradeCameraDataTest CameraDataTest.cpp LIBRARIES MagnumTradeTestLib)
corrade_add_test(TradeImageDataTest ImageDataTest.cpp LIBRARIES MagnumTradeTestLib)
corrade_add_test(TradeLightDataTest LightDataTest.cpp LIBRARIES MagnumTrade)
corrade_add_test(TradeMaterialDataTest MaterialDataTest.cpp LIBRARIES MagnumTradeTestLib)

136
src/Magnum/Trade/Test/CameraDataTest.cpp

@ -23,6 +23,7 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Trade/CameraData.h"
@ -32,66 +33,94 @@ namespace Magnum { namespace Trade { namespace Test {
struct CameraDataTest: TestSuite::Tester {
explicit CameraDataTest();
void construct();
void constructDefaults();
void construct3DFoV();
void construct3DSize();
void construct2D();
void construct2DFoV();
void construct2DNearFar();
void constructCopy();
void constructMove();
};
namespace {
using namespace Math::Literals;
void fovNonPerspective();
enum: std::size_t { ConstructDefaultsDataCount = 3 };
struct {
const char* name;
Rad fov, expectedFov;
Float near, expectedNear;
Float far, expectedFar;
} ConstructDefaultsData[ConstructDefaultsDataCount]{
{"fov", Rad{Constants::nan()}, 35.0_degf, 0.5f, 0.5f, 120.0f, 120.0f},
{"near", 25.0_degf, 25.0_degf, Constants::nan(), 0.01f, 120.0f, 120.0f},
{"far", 25.0_degf, 25.0_degf, 0.5f, 0.5f, Constants::nan(), 100.0f}
void debugType();
};
}
CameraDataTest::CameraDataTest() {
addTests({&CameraDataTest::construct});
addTests({&CameraDataTest::construct3DFoV,
&CameraDataTest::construct3DSize,
&CameraDataTest::construct2D,
&CameraDataTest::construct2DFoV,
&CameraDataTest::construct2DNearFar,
&CameraDataTest::constructCopy,
&CameraDataTest::constructMove,
addInstancedTests({&CameraDataTest::constructDefaults}, ConstructDefaultsDataCount);
&CameraDataTest::fovNonPerspective,
addTests({&CameraDataTest::constructCopy,
&CameraDataTest::constructMove});
&CameraDataTest::debugType});
}
void CameraDataTest::construct() {
using namespace Math::Literals;
void CameraDataTest::construct3DFoV() {
const int a{};
CameraData data{25.0_degf, 0.001f, 1000.0f, &a};
CameraData data{CameraType::Perspective3D, 25.0_degf, 4.0f/3.0f, 0.1f, 1000.0f, &a};
CORRADE_COMPARE(data.type(), CameraType::Perspective3D);
CORRADE_COMPARE(data.size(), (Vector2{0.0443389f, 0.0332542f}));
CORRADE_COMPARE(data.fov(), 25.0_degf);
CORRADE_COMPARE(data.near(), 0.001f);
CORRADE_COMPARE(data.aspectRatio(), 1.333333f);
CORRADE_COMPARE(data.near(), 0.1f);
CORRADE_COMPARE(data.far(), 1000.0f);
CORRADE_COMPARE(data.importerState(), &a);
}
void CameraDataTest::constructDefaults() {
setTestCaseDescription(ConstructDefaultsData[testCaseInstanceId()].name);
void CameraDataTest::construct3DSize() {
const int a{};
CameraData data{CameraType::Orthographic3D, {0.03f, 0.04f}, 0.01f, 1000.0f, &a};
CORRADE_COMPARE(data.type(), CameraType::Orthographic3D);
CORRADE_COMPARE(data.size(), (Vector2{0.03f, 0.04f}));
CORRADE_COMPARE(data.aspectRatio(), 0.75f);
CORRADE_COMPARE(data.near(), 0.01f);
CORRADE_COMPARE(data.far(), 1000.0f);
CORRADE_COMPARE(data.importerState(), &a);
}
void CameraDataTest::construct2D() {
const int a{};
CameraData data{
ConstructDefaultsData[testCaseInstanceId()].fov,
ConstructDefaultsData[testCaseInstanceId()].near,
ConstructDefaultsData[testCaseInstanceId()].far,
&a};
CORRADE_COMPARE(data.fov(), ConstructDefaultsData[testCaseInstanceId()].expectedFov);
CORRADE_COMPARE(data.near(), ConstructDefaultsData[testCaseInstanceId()].expectedNear);
CORRADE_COMPARE(data.far(), ConstructDefaultsData[testCaseInstanceId()].expectedFar);
CameraData data{CameraType::Orthographic2D, {4.0f, 2.0f}, {}, {}, &a};
CORRADE_COMPARE(data.type(), CameraType::Orthographic2D);
CORRADE_COMPARE(data.size(), (Vector2{4.0f, 2.0f}));
CORRADE_COMPARE(data.aspectRatio(), 2.0f);
CORRADE_COMPARE(data.near(), 0.0f);
CORRADE_COMPARE(data.far(), 0.0f);
CORRADE_COMPARE(data.importerState(), &a);
}
void CameraDataTest::construct2DFoV() {
std::ostringstream out;
Error redirectError{&out};
CameraData{CameraType::Orthographic2D, 25.0_degf, 1.0f, 0.001f, 1000.0f};
CORRADE_COMPARE(out.str(), "Trade::CameraData: only perspective cameras can have FoV specified\n");
}
void CameraDataTest::construct2DNearFar() {
std::ostringstream out;
Error redirectError{&out};
CameraData{CameraType::Orthographic2D, {3.0f, 4.0f}, 0.001f, 1000.0f};
CORRADE_COMPARE(out.str(), "Trade::CameraData: 2D cameras can't be specified with near and far clipping planes\n");
}
void CameraDataTest::constructCopy() {
CORRADE_VERIFY(!(std::is_constructible<CameraData, const CameraData&>{}));
CORRADE_VERIFY(!(std::is_assignable<CameraData, const CameraData&>{}));
@ -99,23 +128,46 @@ void CameraDataTest::constructCopy() {
void CameraDataTest::constructMove() {
const int a{};
CameraData data{25.0_degf, 0.001f, 1000.0f, &a};
CameraData data{CameraType::Perspective3D, 25.0_degf, 2.35f, 1.0f, 1000.0f, &a};
CameraData b{std::move(data)};
CORRADE_COMPARE(b.type(), CameraType::Perspective3D);
CORRADE_COMPARE(b.size(), (Vector2{0.443389f, 0.188676f}));
CORRADE_COMPARE(b.fov(), 25.0_degf);
CORRADE_COMPARE(b.near(), 0.001f);
CORRADE_COMPARE(b.aspectRatio(), 2.35f);
CORRADE_COMPARE(b.near(), 1.0f);
CORRADE_COMPARE(b.far(), 1000.0f);
CORRADE_COMPARE(b.importerState(), &a);
const int c{};
CameraData d{75.0_degf, 0.5f, 10.0f, &c};
CameraData d{CameraType::Orthographic3D, {2.0f, 1.0f}, 0.5f, 10.0f, &c};
d = std::move(b);
CORRADE_COMPARE(d.fov(), 25.0_degf);
CORRADE_COMPARE(d.near(), 0.001f);
CORRADE_COMPARE(b.type(), CameraType::Perspective3D);
CORRADE_COMPARE(b.size(), (Vector2{0.443389f, 0.188676f}));
CORRADE_COMPARE(b.fov(), 25.0_degf);
CORRADE_COMPARE(b.aspectRatio(), 2.35f);
CORRADE_COMPARE(d.near(), 1.0f);
CORRADE_COMPARE(d.far(), 1000.0f);
CORRADE_COMPARE(d.importerState(), &a);
}
void CameraDataTest::fovNonPerspective() {
std::ostringstream out;
Error redirectError{&out};
CameraData a{CameraType::Orthographic2D, {3.0f, 4.0f}, {}, {}};
a.fov();
CORRADE_COMPARE(out.str(), "Trade::CameraData::fov(): the camera is not perspective\n");
}
void CameraDataTest::debugType() {
std::ostringstream out;
Debug{&out} << CameraType::Orthographic3D << CameraType(0xde);
CORRADE_COMPARE(out.str(), "Trade::CameraType::Orthographic3D Trade::CameraType(0xde)\n");
}
}}}
CORRADE_TEST_MAIN(Magnum::Trade::Test::CameraDataTest)

1
src/Magnum/Trade/Trade.h

@ -48,6 +48,7 @@ enum class AnimationTrackType: UnsignedByte;
class AnimationTrackData;
class AnimationData;
enum class CameraType: UnsignedByte;
class CameraData;
template<UnsignedInt> class ImageData;

Loading…
Cancel
Save