diff options
author | Tavian Barnes <tavianator@gmail.com> | 2009-07-07 04:23:05 +0000 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2009-07-07 04:23:05 +0000 |
commit | 81c84a38992ce8e38106d86ce85ac3e88ed91a31 (patch) | |
tree | 08fb5913e141b7e208737b799b45921d477d45cc | |
parent | d7b7b4b3391cf99ca63d8311eac3957df7a862ed (diff) | |
download | dimension-81c84a38992ce8e38106d86ce85ac3e88ed91a31.tar.xz |
Add shallow copy semantics to Camera's, Object's, and Scene's.
-rw-r--r-- | libdimensionxx/camera.cpp | 51 | ||||
-rw-r--r-- | libdimensionxx/cameras.cpp | 20 | ||||
-rw-r--r-- | libdimensionxx/dimensionxx/camera.hpp | 20 | ||||
-rw-r--r-- | libdimensionxx/dimensionxx/cameras.hpp | 9 | ||||
-rw-r--r-- | libdimensionxx/dimensionxx/object.hpp | 20 | ||||
-rw-r--r-- | libdimensionxx/dimensionxx/objects.hpp | 18 | ||||
-rw-r--r-- | libdimensionxx/dimensionxx/scene.hpp | 53 | ||||
-rw-r--r-- | libdimensionxx/object.cpp | 56 | ||||
-rw-r--r-- | libdimensionxx/objects.cpp | 36 | ||||
-rw-r--r-- | libdimensionxx/scene.cpp | 42 | ||||
-rw-r--r-- | tests/glxx.cpp | 45 | ||||
-rw-r--r-- | tests/raytracexx.cpp | 31 | ||||
-rw-r--r-- | tests/testsxx.cpp | 35 | ||||
-rw-r--r-- | tests/testsxx.hpp | 4 |
14 files changed, 315 insertions, 125 deletions
diff --git a/libdimensionxx/camera.cpp b/libdimensionxx/camera.cpp index 2897dac..ba2428a 100644 --- a/libdimensionxx/camera.cpp +++ b/libdimensionxx/camera.cpp @@ -22,37 +22,66 @@ namespace Dimension { - // Pure virtual no-op destructor + // Virtual no-op destructor Camera::~Camera() { } + // Return the result of the dmnsn_camera*'s ray callback + Line + Camera::ray(const Canvas& canvas, unsigned int x, unsigned int y) + { + return Line(dmnsn()->ray_fn(dmnsn(), canvas.dmnsn(), x, y)); + } + // Return the wrapped camera dmnsn_camera* Camera::dmnsn() { - return m_camera; + if (!m_camera) { + throw Dimension_Error("Attempt to access NULL camera."); + } + + return *m_camera; } // Return a const version of the wrapped canvas const dmnsn_camera* Camera::dmnsn() const { - return m_camera; + if (!m_camera) { + throw Dimension_Error("Attempt to access NULL camera."); + } + + return *m_camera; } // Protected default no-op constructor Camera::Camera() + : m_camera() + { } + + // Protected copy constructor + Camera::Camera(const Camera& camera) + : m_camera(camera.m_camera) { } // Protected manual constructor Camera::Camera(dmnsn_camera *camera) - : m_camera(camera) + : m_camera(new dmnsn_camera*(camera)) { } - Line - Camera::ray(const Canvas& canvas, unsigned int x, unsigned int y) + // Is m_camera unique? + bool + Camera::unique() const { - return Line(m_camera->ray_fn(m_camera, canvas.dmnsn(), x, y)); + return m_camera.unique(); + } + + // Set the wrapped dmnsn_camera* + void + Camera::dmnsn(dmnsn_camera* camera) + { + m_camera.reset(new dmnsn_camera*(camera)); } // Custom camera callbacks @@ -75,13 +104,15 @@ namespace Dimension Custom_Camera::Custom_Camera() : Camera(dmnsn_new_camera()) { - m_camera->ptr = this; - m_camera->ray_fn = &ray_fn; + dmnsn()->ptr = this; + dmnsn()->ray_fn = &ray_fn; } // Delete the camera Custom_Camera::~Custom_Camera() { - dmnsn_delete_camera(m_camera); + if (unique()) { + dmnsn_delete_camera(dmnsn()); + } } } diff --git a/libdimensionxx/cameras.cpp b/libdimensionxx/cameras.cpp index a7a8255..ea0bca9 100644 --- a/libdimensionxx/cameras.cpp +++ b/libdimensionxx/cameras.cpp @@ -26,7 +26,7 @@ namespace Dimension Perspective_Camera::Perspective_Camera(const Matrix& trans) : Camera(dmnsn_new_perspective_camera(trans.dmnsn())) { - if (!m_camera) { + if (!dmnsn()) { throw Dimension_Error("Failed to allocate perspective camera."); } } @@ -34,18 +34,30 @@ namespace Dimension // Delete a perspective camera Perspective_Camera::~Perspective_Camera() { - dmnsn_delete_perspective_camera(m_camera); + if (unique()) { + dmnsn_delete_perspective_camera(dmnsn()); + } } Matrix Perspective_Camera::trans() { - return Matrix(dmnsn_get_perspective_camera_trans(m_camera)); + return Matrix(dmnsn_get_perspective_camera_trans(dmnsn())); } void Perspective_Camera::trans(const Matrix& trans) { - dmnsn_set_perspective_camera_trans(m_camera, trans.dmnsn()); + dmnsn_set_perspective_camera_trans(dmnsn(), trans.dmnsn()); } + + Camera* + Perspective_Camera::copy() const + { + return new Perspective_Camera(*this); + } + + Perspective_Camera::Perspective_Camera(const Perspective_Camera& camera) + : Camera(camera) + { } } diff --git a/libdimensionxx/dimensionxx/camera.hpp b/libdimensionxx/dimensionxx/camera.hpp index 950e16d..a883969 100644 --- a/libdimensionxx/dimensionxx/camera.hpp +++ b/libdimensionxx/dimensionxx/camera.hpp @@ -29,12 +29,15 @@ namespace Dimension class Camera { public: - // No-op, made pure virtual - virtual ~Camera() = 0; + // No-op + virtual ~Camera(); // Camera callback virtual Line ray(const Canvas& canvas, unsigned int x, unsigned int y); + // Shallow-copy a derived camera + virtual Camera* copy() const = 0; + // Access the wrapped C camera. dmnsn_camera* dmnsn(); const dmnsn_camera* dmnsn() const; @@ -42,15 +45,22 @@ namespace Dimension protected: // No-op Camera(); + // Shallow-copy + Camera(const Camera& camera); // Wrap an existing camera explicit Camera(dmnsn_camera* camera); - dmnsn_camera* m_camera; + // Is m_camera unique? + bool unique() const; + + // Set the wrapped C camera + void dmnsn(dmnsn_camera* camera); private: - // Copying prohibited - Camera(const Camera&); + // Copy-assignment prohibited Camera& operator=(const Camera&); + + std::tr1::shared_ptr<dmnsn_camera*> m_camera; }; // A custom camera abstract base class, for creating your own camera types diff --git a/libdimensionxx/dimensionxx/cameras.hpp b/libdimensionxx/dimensionxx/cameras.hpp index 4e67d64..cabae97 100644 --- a/libdimensionxx/dimensionxx/cameras.hpp +++ b/libdimensionxx/dimensionxx/cameras.hpp @@ -30,10 +30,17 @@ namespace Dimension { public: Perspective_Camera(const Matrix& trans); - virtual ~Perspective_Camera(); + ~Perspective_Camera(); Matrix trans(); void trans(const Matrix& trans); + + Camera* copy() const; + + private: + // Copying prohibited, but used internally + Perspective_Camera(const Perspective_Camera& camera); + Perspective_Camera& operator=(const Perspective_Camera&); }; } diff --git a/libdimensionxx/dimensionxx/object.hpp b/libdimensionxx/dimensionxx/object.hpp index 1b9c848..c56d358 100644 --- a/libdimensionxx/dimensionxx/object.hpp +++ b/libdimensionxx/dimensionxx/object.hpp @@ -29,8 +29,8 @@ namespace Dimension class Object { public: - // No-op, made pure virtual - virtual ~Object() = 0; + // No-op + virtual ~Object(); // Get/set the transformation matrix Matrix trans(); @@ -40,6 +40,9 @@ namespace Dimension virtual Array<double> intersections(const Line& l); virtual bool inside(const Vector& point); + // Shallow-copy a derived + virtual Object* copy() const = 0; + // Access the wrapped C object. dmnsn_object* dmnsn(); const dmnsn_object* dmnsn() const; @@ -47,15 +50,22 @@ namespace Dimension protected: // No-op Object(); + // Shallow copy + Object(const Object& object); // Wrap an existing object. explicit Object(dmnsn_object* object); - dmnsn_object* m_object; + // Is m_object unique? + bool unique() const; + + // Set the wrapped object + void dmnsn(dmnsn_object* object); private: - // Copying prohibited - Object(const Object&); + // Copy-assignment prohibited Object& operator=(const Object&); + + std::tr1::shared_ptr<dmnsn_object*> m_object; }; // A custom object abstract base class, for creating your own object types diff --git a/libdimensionxx/dimensionxx/objects.hpp b/libdimensionxx/dimensionxx/objects.hpp index 89aab14..5b43dc4 100644 --- a/libdimensionxx/dimensionxx/objects.hpp +++ b/libdimensionxx/dimensionxx/objects.hpp @@ -30,7 +30,14 @@ namespace Dimension { public: Sphere(); - virtual ~Sphere(); + ~Sphere(); + + Object* copy() const; + + private: + // Copying prohibited, but used internally + Sphere(const Sphere& sphere); + Sphere& operator=(const Sphere&); }; // A cube @@ -38,7 +45,14 @@ namespace Dimension { public: Cube(); - virtual ~Cube(); + ~Cube(); + + Object* copy() const; + + private: + // Copying prohibited, but used internally + Cube(const Cube& cube); + Cube& operator=(const Cube&); }; } diff --git a/libdimensionxx/dimensionxx/scene.hpp b/libdimensionxx/dimensionxx/scene.hpp index 256de29..b5adde0 100644 --- a/libdimensionxx/dimensionxx/scene.hpp +++ b/libdimensionxx/dimensionxx/scene.hpp @@ -25,14 +25,20 @@ namespace Dimension { + // Iterator class for scene objects + class Scene_Iterator; + // Base scene class. Wraps a dmnsn_scene*. class Scene { public: - // Allocate a dmnsn_scene + typedef Scene_Iterator Iterator; + + // Allocate a dmnsn_scene* Scene(const Color& background, Camera& camera, Canvas& canvas); - // Wrap an existing scene - explicit Scene(dmnsn_scene* scene); + + // Scene(const Scene& scene); + // Delete the scene ~Scene(); @@ -43,7 +49,11 @@ namespace Dimension Canvas& canvas(); const Canvas& canvas() const; - // Add objects + // Object access + + Iterator begin(); + Iterator end(); + void push_object(Object& object); // Access the wrapped C object. @@ -51,13 +61,38 @@ namespace Dimension const dmnsn_scene* dmnsn() const; private: - // Copying prohibited - Scene(const Scene&); + // Copy-assignment prohibited Scene& operator=(const Scene&); - dmnsn_scene* m_scene; - Camera* m_camera; - Canvas* m_canvas; + std::tr1::shared_ptr<dmnsn_scene*> m_scene; + std::tr1::shared_ptr<Camera> m_camera; + std::tr1::shared_ptr<Canvas> m_canvas; + std::list<std::tr1::shared_ptr<Object> > m_objects; + }; + + class Scene_Iterator + { + public: + Scene_Iterator(std::list<std::tr1::shared_ptr<Object> >::iterator i) + : m_i(i) { } + // Scene_Iterator(const Scene_Iterator& i); + // ~Scene_Iterator(); + + // Scene_Iterator& operator=(const Scene_Iterator& i); + + Object& operator*() const { return **m_i; } + Object* operator->() const { return &**m_i; } + + bool operator==(Scene_Iterator i) const { return m_i == i.m_i; } + bool operator!=(Scene_Iterator i) const { return m_i != i.m_i; } + + Scene_Iterator& operator++() { ++m_i; return *this; } + Scene_Iterator operator++(int) { return Scene_Iterator(m_i++); } + Scene_Iterator& operator--() { --m_i; return *this; } + Scene_Iterator operator--(int) { return Scene_Iterator(m_i--); } + + private: + std::list<std::tr1::shared_ptr<Object> >::iterator m_i; }; } diff --git a/libdimensionxx/object.cpp b/libdimensionxx/object.cpp index 7d66206..61b8b7d 100644 --- a/libdimensionxx/object.cpp +++ b/libdimensionxx/object.cpp @@ -22,59 +22,87 @@ namespace Dimension { - // Pure virtual no-op destructor + // Virtual no-op destructor Object::~Object() { } Matrix Object::trans() { - return Matrix(m_object->trans); + return Matrix(dmnsn()->trans); } void Object::trans(const Matrix& trans) { - m_object->trans = trans.dmnsn(); + dmnsn()->trans = trans.dmnsn(); } // Intersection list for the line l Array<double> Object::intersections(const Line& l) { - return Array<double>(m_object->intersections_fn(m_object, l.dmnsn())); + return Array<double>(dmnsn()->intersections_fn(dmnsn(), l.dmnsn())); } // Whether the point `point' is inside the object bool Object::inside(const Vector& point) { - return m_object->inside_fn(m_object, point.dmnsn()); + return dmnsn()->inside_fn(dmnsn(), point.dmnsn()); } // Return the wrapped object dmnsn_object* Object::dmnsn() { - return m_object; + if (!m_object) { + throw Dimension_Error("Attempt to access NULL object."); + } + + return *m_object; } // Return a const version of the wrapped canvas const dmnsn_object* Object::dmnsn() const { - return m_object; + if (!m_object) { + throw Dimension_Error("Attempt to access NULL object."); + } + + return *m_object; } // Protected default no-op constructor Object::Object() + : m_object() + { } + + // Protected copy constructor + Object::Object(const Object& object) + : m_object(object.m_object) { } // Protected manual constructor - Object::Object(dmnsn_object *object) - : m_object(object) + Object::Object(dmnsn_object* object) + : m_object(new dmnsn_object*(object)) { } + // Is m_object unique? + bool + Object::unique() const + { + return m_object.unique(); + } + + // Set the wrapped dmnsn_object* + void + Object::dmnsn(dmnsn_object* object) + { + m_object.reset(new dmnsn_object*(object)); + } + // Custom object callbacks namespace { dmnsn_array * @@ -96,14 +124,16 @@ namespace Dimension Custom_Object::Custom_Object() : Object(dmnsn_new_object()) { - m_object->ptr = this; - m_object->intersections_fn = &intersections_fn; - m_object->inside_fn = &inside_fn; + dmnsn()->ptr = this; + dmnsn()->intersections_fn = &intersections_fn; + dmnsn()->inside_fn = &inside_fn; } // Delete the object Custom_Object::~Custom_Object() { - dmnsn_delete_object(m_object); + if (unique()) { + dmnsn_delete_object(dmnsn()); + } } } diff --git a/libdimensionxx/objects.cpp b/libdimensionxx/objects.cpp index 1b78731..eac642c 100644 --- a/libdimensionxx/objects.cpp +++ b/libdimensionxx/objects.cpp @@ -26,7 +26,7 @@ namespace Dimension Sphere::Sphere() : Object(dmnsn_new_sphere()) { - if (!m_object) { + if (!dmnsn()) { throw Dimension_Error("Failed to allocate sphere."); } } @@ -34,14 +34,28 @@ namespace Dimension // Delete a sphere Sphere::~Sphere() { - dmnsn_delete_sphere(m_object); + if (unique()) { + dmnsn_delete_sphere(dmnsn()); + } } + // Shallow copy a sphere + Object* + Sphere::copy() const + { + return new Sphere(*this); + } + + // Protected copy constructor + Sphere::Sphere(const Sphere& sphere) + : Object(sphere) + { } + // Create a cube Cube::Cube() : Object(dmnsn_new_cube()) { - if (!m_object) { + if (!dmnsn()) { throw Dimension_Error("Failed to allocate cube."); } } @@ -49,6 +63,20 @@ namespace Dimension // Delete a sphere Cube::~Cube() { - dmnsn_delete_cube(m_object); + if (unique()) { + dmnsn_delete_cube(dmnsn()); + } } + + // Shallow copy a cube + Object* + Cube::copy() const + { + return new Cube(*this); + } + + // Protected copy constructor + Cube::Cube(const Cube& sphere) + : Object(sphere) + { } } diff --git a/libdimensionxx/scene.cpp b/libdimensionxx/scene.cpp index f5e4ea8..2b0fba5 100644 --- a/libdimensionxx/scene.cpp +++ b/libdimensionxx/scene.cpp @@ -24,25 +24,24 @@ namespace Dimension { // Allocate a dmnsn_scene Scene::Scene(const Color& background, Camera& camera, Canvas& canvas) - : m_scene(dmnsn_new_scene()), m_camera(&camera), m_canvas(&canvas) + : m_scene(new dmnsn_scene*(dmnsn_new_scene())), m_camera(camera.copy()), + m_canvas(new Canvas(canvas)) { if (!m_scene) { throw Dimension_Error("Couldn't allocate scene."); } - m_scene->background = background.dmnsn(); - m_scene->camera = camera.dmnsn(); - m_scene->canvas = canvas.dmnsn(); + dmnsn()->background = background.dmnsn(); + dmnsn()->camera = this->camera().dmnsn(); + dmnsn()->canvas = this->canvas().dmnsn(); } - // Wrap an existing scene - Scene::Scene(dmnsn_scene* scene) - : m_scene(scene) { } - // Delete the scene Scene::~Scene() { - dmnsn_delete_scene(m_scene); + if (m_scene.unique()) { + dmnsn_delete_scene(dmnsn()); + } } // Element access @@ -50,7 +49,7 @@ namespace Dimension Color Scene::background() const { - return Color(m_scene->background); + return Color(dmnsn()->background); } Camera& @@ -77,12 +76,27 @@ namespace Dimension return *m_canvas; } - // Add objects + // An iterator to the beginning of the object list + Scene::Iterator + Scene::begin() + { + return Iterator(m_objects.begin()); + } + + // An iterator one past the end of the object list + Scene::Iterator + Scene::end() + { + return Iterator(m_objects.end()); + } + + // Add an object void Scene::push_object(Object& object) { + m_objects.push_back(std::tr1::shared_ptr<Object>(object.copy())); dmnsn_object* cobject = object.dmnsn(); - dmnsn_array_push(m_scene->objects, &cobject); + dmnsn_array_push(dmnsn()->objects, &cobject); } // Access the wrapped C object. @@ -90,12 +104,12 @@ namespace Dimension dmnsn_scene* Scene::dmnsn() { - return m_scene; + return *m_scene; } const dmnsn_scene* Scene::dmnsn() const { - return m_scene; + return *m_scene; } } diff --git a/tests/glxx.cpp b/tests/glxx.cpp index eb74209..aaf7b7b 100644 --- a/tests/glxx.cpp +++ b/tests/glxx.cpp @@ -26,37 +26,24 @@ int main() { using namespace Dimension; - // Set the resilience low for tests - resilience(SEVERITY_LOW); - - // Background color - Color background = sRGB(0.0, 0.1, 0.25); - background.filter(0.1); - - // Canvas - Canvas canvas(768, 480); - - // Camera - Perspective_Camera camera( - Matrix::rotation(Vector(0.0, 1.0, 0.0)) - * Matrix::translation(Vector(0.0, 0.0, -4.0)) - * Matrix::scale( - Vector(static_cast<double>(canvas.width())/canvas.height(), 1.0, 1.0) - ) - ); + Scene scene = default_scene(); - // Scene - Scene scene(background, camera, canvas); + Perspective_Camera& camera + = dynamic_cast<Perspective_Camera&>(scene.camera()); - // Objects in scene - - Sphere sphere; - sphere.trans(inverse(Matrix::scale(Vector(1.25, 1.25, 1.25)))); - scene.push_object(sphere); + Cube* cube; + for (Scene::Iterator i = scene.begin(); i != scene.end(); ++i) { + cube = dynamic_cast<Cube*>(&*i); + if (cube) { + break; + } + } + if (!cube) { + throw Dimension_Error("Couldn't find a cube in the default scene."); + } - Cube cube; - cube.trans(inverse(Matrix::rotation(Vector(0.75, 0.0, 0.0)))); - scene.push_object(cube); + // Set the resilience low for tests + resilience(SEVERITY_LOW); Raytracer raytracer(scene); GL_Drawer drawer(scene.canvas()); @@ -71,7 +58,7 @@ main() { drawer.draw(); display.flush(); - cube.trans(inverse(Matrix::rotation(Vector(0.025, 0.0, 0.0)))*cube.trans()); + cube->trans(inverse(Matrix::rotation(Vector(0.025, 0.0, 0.0)))*cube->trans()); camera.trans(Matrix::rotation(Vector(0.0, -0.05, 0.0))*camera.trans()); } diff --git a/tests/raytracexx.cpp b/tests/raytracexx.cpp index c04e525..4202347 100644 --- a/tests/raytracexx.cpp +++ b/tests/raytracexx.cpp @@ -28,34 +28,7 @@ main() { // Set the resilience low for tests resilience(SEVERITY_LOW); - // Background color - Color background = sRGB(0.0, 0.1, 0.25); - background.filter(0.1); - - // Canvas - Canvas canvas(768, 480); - - // Camera - Perspective_Camera camera( - Matrix::rotation(Vector(0.0, 1.0, 0.0)) - * Matrix::translation(Vector(0.0, 0.0, -4.0)) - * Matrix::scale( - Vector(static_cast<double>(canvas.width())/canvas.height(), 1.0, 1.0) - ) - ); - - // Scene - Scene scene(background, camera, canvas); - - // Objects in scene - - Sphere sphere; - sphere.trans(inverse(Matrix::scale(Vector(1.25, 1.25, 1.25)))); - scene.push_object(sphere); - - Cube cube; - cube.trans(inverse(Matrix::rotation(Vector(0.75, 0.0, 0.0)))); - scene.push_object(cube); + Scene scene = default_scene(); // Render the scene { @@ -66,7 +39,7 @@ main() { // Write the canvas std::ofstream file("raytracexx.png"); - PNG_Writer writer(canvas, file); + PNG_Writer writer(scene.canvas(), file); Progress progress = writer.write_async(); std::cout << "Writing PNG file: " << progress << std::endl; diff --git a/tests/testsxx.cpp b/tests/testsxx.cpp index f3dcca5..399e50f 100644 --- a/tests/testsxx.cpp +++ b/tests/testsxx.cpp @@ -21,6 +21,41 @@ namespace Dimension { + Scene + default_scene() + { + // Background color + Color background = sRGB(0.0, 0.1, 0.25); + background.filter(0.1); + + // Canvas + Canvas canvas(768, 480); + + // Camera + Perspective_Camera camera( + Matrix::rotation(Vector(0.0, 1.0, 0.0)) + * Matrix::translation(Vector(0.0, 0.0, -4.0)) + * Matrix::scale( + Vector(static_cast<double>(canvas.width())/canvas.height(), 1.0, 1.0) + ) + ); + + // Scene + Scene scene(background, camera, canvas); + + // Objects in scene + + Sphere sphere; + sphere.trans(inverse(Matrix::scale(Vector(1.25, 1.25, 1.25)))); + scene.push_object(sphere); + + Cube cube; + cube.trans(inverse(Matrix::rotation(Vector(0.75, 0.0, 0.0)))); + scene.push_object(cube); + + return scene; + } + Display::Display(const Canvas& canvas) : m_display(dmnsn_new_display(canvas.dmnsn())) { diff --git a/tests/testsxx.hpp b/tests/testsxx.hpp index 0e522ad..1101196 100644 --- a/tests/testsxx.hpp +++ b/tests/testsxx.hpp @@ -26,6 +26,10 @@ namespace Dimension { + // Helper to return a basic scene + Scene default_scene(); + + // Display abstraction class Display { public: |